npcx: CEC: Add resend-logic to CEC driver

According to the CEC specification, a resend must be
attempted at least once and up to five times after NAK.
This fix does it five times.

Signed-off-by: Stefan Adolfsson <sadolfsson@chromium.org>

BUG=b:76467407
BRANCH=none
TEST=Write CEC message without sink. Verify with logical
analyzer that it resends 5 times.
CQ-DEPEND=CL:1030221

Change-Id: Id296e12b6657b9e7ca0453a2deb06e8aaf17f839
Reviewed-on: https://chromium-review.googlesource.com/1030222
Commit-Ready: Stefan Adolfsson <sadolfsson@chromium.org>
Tested-by: Stefan Adolfsson <sadolfsson@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
Stefan Adolfsson
2018-05-07 00:13:09 +02:00
committed by chrome-bot
parent e89486c9b6
commit 1ddb719bd0

View File

@@ -33,8 +33,15 @@
/* CEC broadcast address. Also the highest possible CEC address */
#define CEC_BROADCAST_ADDR 15
/*
* The CEC specification requires at least one and a maximum of
* five resends attempts
*/
#define CEC_MAX_RESENDS 5
/* Free time timing (us). */
#define NOMINAL_BIT_TIME APB1_TICKS(2400)
#define FREE_TIME_RS (3 * (NOMINAL_BIT_TIME)) /* Resend */
#define FREE_TIME_NI (5 * (NOMINAL_BIT_TIME)) /* New initiator */
/* Start bit timing (us) */
@@ -107,6 +114,8 @@ struct cec_tx {
struct cec_msg_transfer msgt;
/* Message length */
uint8_t len;
/* Number of resends attempted in current send */
uint8_t resends;
/* Acknowledge received from sink? */
uint8_t ack;
};
@@ -181,7 +190,10 @@ void enter_state(enum cec_state new_state)
break;
case CEC_STATE_INITIATOR_FREE_TIME:
gpio = 1;
timeout = FREE_TIME_NI;
if (cec_tx.resends)
timeout = FREE_TIME_RS;
else
timeout = FREE_TIME_NI;
break;
case CEC_STATE_INITIATOR_START_LOW:
cec_tx.msgt.bit = 0;
@@ -301,12 +313,20 @@ static void cec_event_timeout(void)
} else {
/* Transfer completed successfully */
cec_tx.len = 0;
cec_tx.resends = 0;
enter_state(CEC_STATE_IDLE);
}
} else {
/* Transfer failed */
cec_tx.len = 0;
enter_state(CEC_STATE_IDLE);
if (cec_tx.resends < CEC_MAX_RESENDS) {
/* Resend */
cec_tx.resends++;
enter_state(CEC_STATE_INITIATOR_FREE_TIME);
} else {
/* Transfer failed */
cec_tx.len = 0;
cec_tx.resends = 0;
enter_state(CEC_STATE_IDLE);
}
}
break;
case CEC_STATE_INITIATOR_DATA_LOW: