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 <yong.qin@amlogic.com>
This commit is contained in:
Yong Qin
2019-11-06 18:53:44 +08:00
committed by Luke Go
parent 506e6c9215
commit b7b25a0770
3 changed files with 54 additions and 27 deletions

View File

@@ -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();

View File

@@ -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"

View File

@@ -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,