mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-15 00:56:22 +00:00
npcx: CEC: Add bus-contention handling
If low-impedance is detected during the time from free-time until the end of the initiator address, the current send is postponed until the bus is free again. Signed-off-by: Stefan Adolfsson <sadolfsson@chromium.org> BUG=b:76467407 BRANCH=none TEST=none CQ-DEPEND=CL:1030224 Change-Id: If4b9ed43306cf2e38770085603f7fa83a1f76ddc Reviewed-on: https://chromium-review.googlesource.com/1030225 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:
committed by
chrome-bot
parent
e317b78cd3
commit
ea5d72e85b
103
chip/npcx/cec.c
103
chip/npcx/cec.c
@@ -101,6 +101,12 @@ enum cec_state {
|
||||
CEC_STATE_INITIATOR_ACK_VERIFY,
|
||||
};
|
||||
|
||||
/* Edge to trigger capture timer interrupt on */
|
||||
enum cap_edge {
|
||||
CAP_EDGE_FALLING,
|
||||
CAP_EDGE_RISING
|
||||
};
|
||||
|
||||
/* CEC message during transfer */
|
||||
struct cec_msg_transfer {
|
||||
/* The CEC message */
|
||||
@@ -141,6 +147,43 @@ static void send_mkbp_event(uint32_t event)
|
||||
mkbp_send_event(EC_MKBP_EVENT_CEC);
|
||||
}
|
||||
|
||||
static void tmr_cap_start(enum cap_edge edge, int timeout)
|
||||
{
|
||||
int mdl = NPCX_MFT_MODULE_1;
|
||||
|
||||
/* Select edge to trigger capture on */
|
||||
UPDATE_BIT(NPCX_TMCTRL(mdl), NPCX_TMCTRL_TAEDG,
|
||||
edge == CAP_EDGE_RISING);
|
||||
|
||||
/*
|
||||
* Set capture timeout. If we don't have a timeout, we
|
||||
* turn the timeout interrupt off and only care about
|
||||
* the edge change.
|
||||
*/
|
||||
if (timeout > 0) {
|
||||
NPCX_TCNT1(mdl) = timeout;
|
||||
SET_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TCIEN);
|
||||
} else {
|
||||
CLEAR_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TCIEN);
|
||||
NPCX_TCNT1(mdl) = 0;
|
||||
}
|
||||
|
||||
/* Clear out old events */
|
||||
SET_BIT(NPCX_TECLR(mdl), NPCX_TECLR_TACLR);
|
||||
SET_BIT(NPCX_TECLR(mdl), NPCX_TECLR_TCCLR);
|
||||
NPCX_TCRA(mdl) = 0;
|
||||
/* Start the capture timer */
|
||||
SET_FIELD(NPCX_TCKC(mdl), NPCX_TCKC_C1CSEL_FIELD, 1);
|
||||
}
|
||||
|
||||
static void tmr_cap_stop(void)
|
||||
{
|
||||
int mdl = NPCX_MFT_MODULE_1;
|
||||
|
||||
CLEAR_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TCIEN);
|
||||
SET_FIELD(NPCX_TCKC(mdl), NPCX_TCKC_C1CSEL_FIELD, 0);
|
||||
}
|
||||
|
||||
static void tmr_oneshot_start(int timeout)
|
||||
{
|
||||
int mdl = NPCX_MFT_MODULE_1;
|
||||
@@ -192,6 +235,7 @@ static int msgt_is_eom(const struct cec_msg_transfer *msgt, int len)
|
||||
void enter_state(enum cec_state new_state)
|
||||
{
|
||||
int gpio = -1, timeout = -1;
|
||||
enum cap_edge cap_edge = -1;
|
||||
|
||||
cec_state = new_state;
|
||||
switch (new_state) {
|
||||
@@ -203,9 +247,14 @@ void enter_state(enum cec_state new_state)
|
||||
case CEC_STATE_IDLE:
|
||||
cec_tx.msgt.bit = 0;
|
||||
cec_tx.msgt.byte = 0;
|
||||
if (cec_tx.len > 0) {
|
||||
/* Execute a postponed send */
|
||||
enter_state(CEC_STATE_INITIATOR_FREE_TIME);
|
||||
}
|
||||
break;
|
||||
case CEC_STATE_INITIATOR_FREE_TIME:
|
||||
gpio = 1;
|
||||
cap_edge = CAP_EDGE_FALLING;
|
||||
if (cec_tx.resends)
|
||||
timeout = FREE_TIME_RS;
|
||||
else
|
||||
@@ -219,6 +268,7 @@ void enter_state(enum cec_state new_state)
|
||||
break;
|
||||
case CEC_STATE_INITIATOR_START_HIGH:
|
||||
gpio = 1;
|
||||
cap_edge = CAP_EDGE_FALLING;
|
||||
timeout = START_BIT_HIGH;
|
||||
break;
|
||||
case CEC_STATE_INITIATOR_HEADER_INIT_LOW:
|
||||
@@ -228,6 +278,10 @@ void enter_state(enum cec_state new_state)
|
||||
timeout = DATA_LOW(msgt_get_bit(&cec_tx.msgt));
|
||||
break;
|
||||
case CEC_STATE_INITIATOR_HEADER_INIT_HIGH:
|
||||
gpio = 1;
|
||||
cap_edge = CAP_EDGE_FALLING;
|
||||
timeout = DATA_HIGH(msgt_get_bit(&cec_tx.msgt));
|
||||
break;
|
||||
case CEC_STATE_INITIATOR_HEADER_DEST_HIGH:
|
||||
case CEC_STATE_INITIATOR_DATA_HIGH:
|
||||
gpio = 1;
|
||||
@@ -271,8 +325,12 @@ void enter_state(enum cec_state new_state)
|
||||
|
||||
if (gpio >= 0)
|
||||
gpio_set_level(CEC_GPIO_OUT, gpio);
|
||||
if (timeout >= 0)
|
||||
tmr_oneshot_start(timeout);
|
||||
if (timeout >= 0) {
|
||||
if (cap_edge >= 0)
|
||||
tmr_cap_start(cap_edge, timeout);
|
||||
else
|
||||
tmr_oneshot_start(timeout);
|
||||
}
|
||||
}
|
||||
|
||||
static void cec_event_timeout(void)
|
||||
@@ -361,6 +419,25 @@ static void cec_event_timeout(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void cec_event_cap(void)
|
||||
{
|
||||
switch (cec_state) {
|
||||
case CEC_STATE_INITIATOR_FREE_TIME:
|
||||
case CEC_STATE_INITIATOR_START_HIGH:
|
||||
case CEC_STATE_INITIATOR_HEADER_INIT_HIGH:
|
||||
/*
|
||||
* A falling edge during free-time, postpone
|
||||
* this send
|
||||
*/
|
||||
cec_tx.msgt.bit = 0;
|
||||
cec_tx.msgt.byte = 0;
|
||||
enter_state(CEC_STATE_IDLE);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void cec_event_tx(void)
|
||||
{
|
||||
enter_state(CEC_STATE_INITIATOR_FREE_TIME);
|
||||
@@ -374,10 +451,19 @@ static void cec_isr(void)
|
||||
/* Retrieve events NPCX_TECTRL_TAXND */
|
||||
events = GET_FIELD(NPCX_TECTRL(mdl), FIELD(0, 4));
|
||||
|
||||
/* Timer event for bit-flipping */
|
||||
if (events & (1 << NPCX_TECTRL_TCPND))
|
||||
cec_event_timeout();
|
||||
|
||||
if (events & (1 << NPCX_TECTRL_TAPND)) {
|
||||
/* Capture event */
|
||||
cec_event_cap();
|
||||
} else {
|
||||
/*
|
||||
* Capture timeout
|
||||
* We only care about this if the capture event is not
|
||||
* happening, since we will get both events in the
|
||||
* edge-trigger case
|
||||
*/
|
||||
if (events & (1 << NPCX_TECTRL_TCPND))
|
||||
cec_event_timeout();
|
||||
}
|
||||
/* Oneshot timer, a transfer has been initiated from AP */
|
||||
if (events & (1 << NPCX_TECTRL_TDPND)) {
|
||||
tmr2_stop();
|
||||
@@ -446,7 +532,7 @@ static int cec_set_enable(uint8_t enable)
|
||||
enter_state(CEC_STATE_IDLE);
|
||||
|
||||
/* Enable timer interrupts */
|
||||
SET_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TCIEN);
|
||||
SET_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TAIEN);
|
||||
SET_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TDIEN);
|
||||
|
||||
/* Enable multifunction timer interrupt */
|
||||
@@ -455,10 +541,11 @@ static int cec_set_enable(uint8_t enable)
|
||||
CPRINTF("CEC enabled\n");
|
||||
} else {
|
||||
/* Disable timer interrupts */
|
||||
CLEAR_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TCIEN);
|
||||
CLEAR_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TAIEN);
|
||||
CLEAR_BIT(NPCX_TIEN(mdl), NPCX_TIEN_TDIEN);
|
||||
|
||||
tmr2_stop();
|
||||
tmr_cap_stop();
|
||||
|
||||
task_disable_irq(NPCX_IRQ_MFT_1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user