diff options
author | Scott Collyer <scollyer@google.com> | 2018-05-01 10:58:14 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-05-14 23:56:58 -0700 |
commit | f11169fa8d1ec6f6982306727f0bf0c8a7bd410b (patch) | |
tree | 4890f1f0579b263592ec52915a363ed9b7f90d7f | |
parent | 163263c9a3eedacff191b50a9da55fd1454fcc86 (diff) | |
download | chrome-ec-f11169fa8d1ec6f6982306727f0bf0c8a7bd410b.tar.gz |
tcpci: Adjust pd task event/wake when processing alerts
Processing of TCPC alerts takes place in the PDCMD task and the result
of processing alerts is to wake the PD task. When the PD task runs,
it's possible that it may attempt to put the TCPC into low power mode
prior to the remainder of the alert processing function completing. So
there may be pending TCPC accesses in the alert handler function which
called subsequent to the PD task putting the TCPC into low power
mode. The TCPC access in the PDCMD task will cause the TCPC to exit
low power mode. With the ANX7447 TCPC, this process will repeat
indefinitely.
This CL replaces the calls to task_set_event and task_wake with
indications stored in a local variable. Then at the end of the
function the task_set_event is made if necessary. This change in order
removes one guaranteed source of pending TCPC accesses from causing
the TCPC to exit low power mode.
BRANCH=none
BUG=b:77544959
TEST=Was using Salea logic analyzer and testing in conjunction with
low power mode. Verified that prior to this change I2C accesses were
attempted and NAKd after the command I2CIDLE was sent on the bus. Also
tested basic type C operation as both SNK/SRC.
Change-Id: I8879c655a48a2b16e0445522497002482dc9ca33
Signed-off-by: Scott Collyer <scollyer@google.com>
Reviewed-on: https://chromium-review.googlesource.com/1044868
Commit-Ready: Scott Collyer <scollyer@chromium.org>
Tested-by: Scott Collyer <scollyer@chromium.org>
Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r-- | driver/tcpm/tcpci.c | 22 |
1 files changed, 16 insertions, 6 deletions
diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c index 76d01adeae..d4518ae608 100644 --- a/driver/tcpm/tcpci.c +++ b/driver/tcpm/tcpci.c @@ -309,6 +309,7 @@ static int register_mask_reset(int port) void tcpci_tcpc_alert(int port) { int status; + uint32_t pd_event = 0; /* Read the Alert register from the TCPC */ tcpm_alert_status(port, &status); @@ -317,8 +318,7 @@ void tcpci_tcpc_alert(int port) * so, perform tcpc_init inline. */ if (register_mask_reset(port)) - task_set_event(PD_PORT_TO_TASK_ID(port), - PD_EVENT_TCPC_RESET, 0); + pd_event |= PD_EVENT_TCPC_RESET; /* * Clear alert status for everything except RX_STATUS, which shouldn't @@ -330,7 +330,7 @@ void tcpci_tcpc_alert(int port) if (status & TCPC_REG_ALERT_CC_STATUS) { /* CC status changed, wake task */ - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0); + pd_event |= PD_EVENT_CC; } if (status & TCPC_REG_ALERT_POWER_STATUS) { int reg = 0; @@ -342,17 +342,17 @@ void tcpci_tcpc_alert(int port) #if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) && defined(CONFIG_USB_CHARGER) /* Update charge manager with new VBUS state */ usb_charger_vbus_change(port, tcpc_vbus[port]); - task_wake(PD_PORT_TO_TASK_ID(port)); + pd_event |= TASK_EVENT_WAKE; #endif /* CONFIG_USB_PD_VBUS_DETECT_TCPC && CONFIG_USB_CHARGER */ } if (status & TCPC_REG_ALERT_RX_STATUS) { /* message received */ - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0); + pd_event |= PD_EVENT_RX; } if (status & TCPC_REG_ALERT_RX_HARD_RST) { /* hard reset received */ pd_execute_hard_reset(port); - task_wake(PD_PORT_TO_TASK_ID(port)); + pd_event |= TASK_EVENT_WAKE; } if (status & TCPC_REG_ALERT_TX_COMPLETE) { /* transmit complete */ @@ -360,6 +360,16 @@ void tcpci_tcpc_alert(int port) TCPC_TX_COMPLETE_SUCCESS : TCPC_TX_COMPLETE_FAILED); } + + /* + * Wait until all possible TCPC accesses in this function are complete + * prior to setting events and/or waking the pd task. When the PD + * task is woken and runs (which will happen during I2C transactions in + * this function), the pd task may put the TCPC into low power mode and + * the next I2C transaction to the TCPC will cause it to wake again. + */ + if (pd_event) + task_set_event(PD_PORT_TO_TASK_ID(port), pd_event, 0); } /* |