From b7b25a077006e701493e77d8fe2e1334b27774ae Mon Sep 17 00:00:00 2001 From: Yong Qin Date: Wed, 6 Nov 2019 18:53:44 +0800 Subject: [PATCH] cec: sometime got err ack when send ping msg [1/1] PD#SWPL-16005 Problem: Sometime got err ack when send ping msg Solution: When ping and got no ack, but irq sts is tx done and initial error, need return a err code. and app leayer will retry ping msg. Verify: tl1 Change-Id: I0aea99878bb3924f6699d34821de0740c223f933 Signed-off-by: Yong Qin --- drivers/amlogic/cec/hdmi_ao_cec.c | 69 +++++++++++++------ drivers/amlogic/cec/hdmi_ao_cec.h | 2 +- .../media/vout/hdmi_tx/hdmi_tx_cec_20.h | 10 +-- 3 files changed, 54 insertions(+), 27 deletions(-) diff --git a/drivers/amlogic/cec/hdmi_ao_cec.c b/drivers/amlogic/cec/hdmi_ao_cec.c index 5a41d25d6af1..49944c538b4d 100644 --- a/drivers/amlogic/cec/hdmi_ao_cec.c +++ b/drivers/amlogic/cec/hdmi_ao_cec.c @@ -118,7 +118,7 @@ struct ao_cec_dev { struct completion rx_ok; struct completion tx_ok; spinlock_t cec_reg_lock; - struct mutex cec_mutex; + struct mutex cec_tx_mutex;/*pretect tx cec msg*/ struct mutex cec_ioctl_mutex; struct cec_wakeup_t wakup_data; unsigned int wakeup_reason; @@ -154,7 +154,7 @@ enum { }; static struct ao_cec_dev *cec_dev; -static int cec_tx_result; +static enum cec_tx_ret cec_tx_result; static int cec_line_cnt; static struct hrtimer start_bit_check; @@ -393,6 +393,21 @@ static inline void hdmirx_set_bits_dwc(uint32_t reg, uint32_t bits, hdmirx_cec_write(reg, tmp); } +const char *cec_tx_ret_str(int ret) +{ + switch (ret) { + case CEC_FAIL_NONE: + return "RET_NONE"; + case CEC_FAIL_NACK: + return "RET_NACK"; + case CEC_FAIL_BUSY: + return "RET_BUSY"; + case CEC_FAIL_OTHER: + default: + return "RET_OTHER"; + } +} + void cec_dbg_init(void) { stdbgflg.hal_cmd_bypass = 0; @@ -574,14 +589,16 @@ void cecb_irq_handle(void) if (cec_dev->plat_data->ee_to_ao) shift = 16; /* TX DONE irq, increase tx buffer pointer */ - if (intr_cec & CEC_IRQ_TX_DONE) { + if (intr_cec == CEC_IRQ_TX_DONE) { cec_tx_result = CEC_FAIL_NONE; + CEC_INFO_L(L_2, "irqflg:TX_DONE\n"); complete(&cec_dev->tx_ok); } lock = hdmirx_cec_read(DWC_CEC_LOCK); /* EOM irq, message is coming */ if ((intr_cec & CEC_IRQ_RX_EOM) || lock) { cecb_pick_msg(rx_msg, &rx_len); + CEC_INFO_L(L_2, "irqflg:RX_EOM\n"); complete(&cec_dev->rx_ok); new_msg = 1; dwork = &cec_dev->cec_work; @@ -594,31 +611,33 @@ void cecb_irq_handle(void) (intr_cec & CEC_IRQ_TX_ERR_INITIATOR)) { if (intr_cec & CEC_IRQ_TX_NACK) { cec_tx_result = CEC_FAIL_NACK; - CEC_INFO_L(L_2, "warning:TX_NACK\n"); + CEC_INFO_L(L_2, "irqflg:TX_NACK\n"); } else if (intr_cec & CEC_IRQ_TX_ARB_LOST) { cec_tx_result = CEC_FAIL_BUSY; /* clear start */ hdmirx_cec_write(DWC_CEC_TX_CNT, 0); hdmirx_set_bits_dwc(DWC_CEC_CTRL, 0, 0, 3); - CEC_INFO("warning:ARB_LOST\n"); + CEC_INFO_L(L_2, "irqflg:ARB_LOST\n"); } else if (intr_cec & CEC_IRQ_TX_ERR_INITIATOR) { - CEC_INFO("warning:INITIATOR\n"); + CEC_INFO_L(L_2, "irqflg:INITIATOR\n"); cec_tx_result = CEC_FAIL_OTHER; - } else + } else { + CEC_INFO_L(L_2, "irqflg:Other\n"); cec_tx_result = CEC_FAIL_OTHER; + } complete(&cec_dev->tx_ok); } /* RX error irq flag */ if (intr_cec & CEC_IRQ_RX_ERR_FOLLOWER) { - CEC_INFO("warning:FOLLOWER\n"); + CEC_INFO_L(L_2, "warning:FOLLOWER\n"); hdmirx_cec_write(DWC_CEC_LOCK, 0); /* TODO: need reset cec hw logic? */ } /* wakeup op code will triger this int*/ if (intr_cec & CEC_IRQ_RX_WAKEUP) { - CEC_ERR("warning:RX_WAKEUP\n"); + CEC_INFO_L(L_2, "warning:RX_WAKEUP\n"); hdmirx_cec_write(DWC_CEC_WKUPCTRL, WAKEUP_EN_MASK); /* TODO: wake up system if needed */ } @@ -626,7 +645,6 @@ void cecb_irq_handle(void) static irqreturn_t cecb_isr(int irq, void *dev_instance) { - CEC_INFO_L(L_2, "cecb_isr\n"); cecb_irq_handle(); return IRQ_HANDLED; } @@ -1509,6 +1527,7 @@ int cec_ll_tx(const unsigned char *msg, unsigned char len) int retry = 2; unsigned int cec_sel; + mutex_lock(&cec_dev->cec_tx_mutex); /* only use cec a send msg */ if (cec_dev->cec_num > ENABLE_ONE_CEC) cec_sel = CEC_A; @@ -1517,9 +1536,11 @@ int cec_ll_tx(const unsigned char *msg, unsigned char len) t = msecs_to_jiffies((cec_sel == CEC_B) ? 2000 : 5000); - if (len == 0) + if (len == 0) { + CEC_INFO("err len 0\n"); + mutex_unlock(&cec_dev->cec_tx_mutex); return CEC_FAIL_NONE; - + } /* * AO CEC controller will ack poll message itself if logical * address already set. Must clear it before poll again @@ -1537,11 +1558,11 @@ int cec_ll_tx(const unsigned char *msg, unsigned char len) if ((cec_sel == CEC_A) && need_nack_repeat_msg(msg, len, t)) { if (!memcmp(msg, last_cec_msg->msg, len)) { CEC_INFO("NACK repeat message:%x\n", len); + mutex_unlock(&cec_dev->cec_tx_mutex); return CEC_FAIL_NACK; } } - mutex_lock(&cec_dev->cec_mutex); /* make sure we got valid physical address */ if (len >= 2 && msg[1] == CEC_OC_REPORT_PHYSICAL_ADDRESS) check_physical_addr_valid(3); @@ -1556,7 +1577,7 @@ try_again: */ if (check_confilct()) { CEC_ERR("bus confilct too long\n"); - mutex_unlock(&cec_dev->cec_mutex); + mutex_unlock(&cec_dev->cec_tx_mutex); return CEC_FAIL_BUSY; } @@ -1570,9 +1591,10 @@ try_again: if (retry > 0) { retry--; msleep(100 + (prandom_u32() & 0x07) * 10); + CEC_INFO_L(L_2, "retry0 %d\n", retry); goto try_again; } - mutex_unlock(&cec_dev->cec_mutex); + mutex_unlock(&cec_dev->cec_tx_mutex); return CEC_FAIL_BUSY; } cec_tx_result = -1; @@ -1591,10 +1613,10 @@ try_again: if (retry > 0) { retry--; msleep(100 + (prandom_u32() & 0x07) * 10); + CEC_INFO_L(L_2, "retry1 %d\n", retry); goto try_again; } } - mutex_unlock(&cec_dev->cec_mutex); if (cec_sel == CEC_A) { last_cec_msg->last_result = ret; @@ -1604,6 +1626,9 @@ try_again: last_cec_msg->last_jiffies = jiffies; } } + + CEC_INFO_L(L_2, "%s ret:%d, %s\n", __func__, ret, cec_tx_ret_str(ret)); + mutex_unlock(&cec_dev->cec_tx_mutex); return ret; } @@ -2517,7 +2542,7 @@ static ssize_t cmd_store(struct class *cla, struct class_attribute *attr, int tmpbuf[20] = {}; int i; int cnt; - + int ret; cnt = sscanf(bu, "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", &tmpbuf[0], &tmpbuf[1], &tmpbuf[2], &tmpbuf[3], &tmpbuf[4], &tmpbuf[5], &tmpbuf[6], &tmpbuf[7], @@ -2532,7 +2557,8 @@ static ssize_t cmd_store(struct class *cla, struct class_attribute *attr, buf[i] = (char)tmpbuf[i]; /*CEC_ERR("cnt=%d\n", cnt);*/ - cec_ll_tx(buf, cnt); + ret = cec_ll_tx(buf, cnt); + CEC_INFO_L(L_2, "%s ret:%d, %s\n", __func__, ret, cec_tx_ret_str(ret)); return count; } @@ -2938,7 +2964,6 @@ static ssize_t hdmitx_cec_write(struct file *f, const char __user *buf, } else { CEC_ERR("err:cec module disabled\n"); } - return ret; } @@ -3455,7 +3480,7 @@ static const struct cec_platform_data_s cec_tl1_data = { static const struct cec_platform_data_s cec_sm1_data = { .chip_id = CEC_CHIP_SM1, .line_reg = 1, - .line_bit = 3, + .line_bit = 10, .ee_to_ao = 1, .ceca_sts_reg = 1, .ceca_ver = CECA_VER_1, @@ -3466,7 +3491,7 @@ static const struct cec_platform_data_s cec_sm1_data = { static const struct cec_platform_data_s cec_tm2_data = { .chip_id = CEC_CHIP_TM2, .line_reg = 0, - .line_bit = 3, + .line_bit = 10, .ee_to_ao = 1, .ceca_sts_reg = 1, .ceca_ver = CECA_VER_1, @@ -3595,7 +3620,7 @@ static int aml_cec_probe(struct platform_device *pdev) cec_node_val_init(); init_completion(&cec_dev->rx_ok); init_completion(&cec_dev->tx_ok); - mutex_init(&cec_dev->cec_mutex); + mutex_init(&cec_dev->cec_tx_mutex); mutex_init(&cec_dev->cec_ioctl_mutex); spin_lock_init(&cec_dev->cec_reg_lock); cec_dev->cec_info.remote_cec_dev = input_allocate_device(); diff --git a/drivers/amlogic/cec/hdmi_ao_cec.h b/drivers/amlogic/cec/hdmi_ao_cec.h index a7c70f5b1bdc..26b46b4a1431 100644 --- a/drivers/amlogic/cec/hdmi_ao_cec.h +++ b/drivers/amlogic/cec/hdmi_ao_cec.h @@ -18,7 +18,7 @@ #ifndef __AO_CEC_H__ #define __AO_CEC_H__ -#define CEC_DRIVER_VERSION "2019/10/22: finetune ARB rising time\n" +#define CEC_DRIVER_VERSION "2019/11/11: sometime ping got wrong ack\n" #define CEC_FRAME_DELAY msecs_to_jiffies(400) #define CEC_DEV_NAME "cec" diff --git a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h index e0b18435187a..2da284a14e69 100644 --- a/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h +++ b/include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_cec_20.h @@ -103,10 +103,12 @@ enum _cec_log_dev_addr_e { #define CEC_IOC_SET_FREEZE_MODE _IOW(CEC_IOC_MAGIC, 0x12, uint32_t) #define CEC_IOC_GET_BOOT_PORT _IOW(CEC_IOC_MAGIC, 0x13, uint32_t) -#define CEC_FAIL_NONE 0 -#define CEC_FAIL_NACK 1 -#define CEC_FAIL_BUSY 2 -#define CEC_FAIL_OTHER 3 +enum cec_tx_ret { + CEC_FAIL_NONE = 0, + CEC_FAIL_NACK = 1, + CEC_FAIL_BUSY = 2, + CEC_FAIL_OTHER = 3 +}; enum hdmi_port_type { HDMI_INPUT = 0,