summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorJett Rink <jettrink@chromium.org>2018-06-28 15:31:40 -0600
committerchrome-bot <chrome-bot@chromium.org>2018-07-18 18:15:26 -0700
commit16a8f8f4fa5bce677f202ff78892f3f50978065b (patch)
tree5b2b2b9bbe9c79632b00dc1c1d893a598add556a /common
parentd22bdeeaecd864835eacb9c22e05f09050fb0237 (diff)
downloadchrome-ec-16a8f8f4fa5bce677f202ff78892f3f50978065b.tar.gz
tcpc: debounce entry into low-power mode
We need to keep track of the low-power mode hardware state for each TCPC so we can put a TCPC back into low power mode when it exits low power mode before the software TCPM state machine wants it out of low power mode. This change also breaks the low power mode entry out of the drp_toggle method into its own method: enter_low_power_mode. BRANCH=none BUG=b:77544959 TEST=Verified Analogix does not get into low-power mode loop. Tested other SRC/SNK capabilities as well. Tested the device will go back into low power mode if the AP access the TCPC via the 'ectool usbpdmuxinfo' command. Change-Id: I2fdefeda2bf13c2b79d988f0017629115438d313 Signed-off-by: Jett Rink <jettrink@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1119255 Reviewed-by: Scott Collyer <scollyer@chromium.org>
Diffstat (limited to 'common')
-rw-r--r--common/usb_pd_protocol.c95
1 files changed, 86 insertions, 9 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 42742888a2..03ed5b777c 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -351,6 +351,54 @@ static void set_vconn(int port, int enable)
}
#endif /* defined(CONFIG_USBC_VCONN) */
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+
+/* 10 ms is enough time for any TCPC transaction to complete. */
+#define PD_LPM_DEBOUNCE_US (10 * MSEC)
+static timestamp_t lpm_debounce_deadlines[CONFIG_USB_PD_PORT_COUNT];
+
+/* This is only called from the PD tasks that owns the port. */
+static void handle_device_access(int port)
+{
+ lpm_debounce_deadlines[port].val = get_time().val + PD_LPM_DEBOUNCE_US;
+ if (pd[port].flags & PD_FLAGS_LPM_ENGAGED) {
+ CPRINTS("TCPC p%d Exited Low Power Mode via bus access", port);
+ pd[port].flags &= ~PD_FLAGS_LPM_ENGAGED;
+ }
+}
+
+/* This can be called from any task. */
+void pd_device_accessed(int port)
+{
+ /* If not in the PD TASK that owns data, marshal to that task */
+ if (task_get_current() == PD_PORT_TO_TASK_ID(port))
+ handle_device_access(port);
+ else
+ task_set_event(PD_PORT_TO_TASK_ID(port),
+ PD_EVENT_DEVICE_ACCESSED, 0);
+}
+
+/* This is only called from the PD tasks that owns the port. */
+static void request_low_power_mode(int port, int enable)
+{
+ if (enable)
+ pd[port].flags |= PD_FLAGS_LPM_REQUESTED;
+ else
+ pd[port].flags &= ~PD_FLAGS_LPM_REQUESTED;
+}
+#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */
+
+/* Local convenience method for two method currently always called together. */
+#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
+static void pd_set_drp_toggle(int port, int enable)
+{
+ tcpm_set_drp_toggle(port, enable);
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ request_low_power_mode(port, enable);
+#endif
+}
+#endif /* CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE */
+
#ifdef CONFIG_USB_PD_DUAL_ROLE
static int get_bbram_idx(int port)
{
@@ -1920,7 +1968,7 @@ void pd_update_dual_role_config(int port)
#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \
defined(CONFIG_USB_PD_TCPC_LOW_POWER)
/* When switching drp mode, make sure tcpc is out of standby mode */
- tcpm_set_drp_toggle(port, 0);
+ pd_set_drp_toggle(port, 0);
#endif
}
@@ -2333,6 +2381,11 @@ void pd_task(void *u)
/* wait for next event/packet or timeout expiration */
evt = task_wait_event(timeout);
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ if (evt & PD_EVENT_DEVICE_ACCESSED)
+ handle_device_access(port);
+#endif
+
#ifdef CONFIG_USB_PD_DUAL_ROLE
if (evt & PD_EVENT_UPDATE_DUAL_ROLE)
pd_update_dual_role_config(port);
@@ -2347,6 +2400,10 @@ void pd_task(void *u)
#else
/* if TCPC has reset, then need to initialize it again */
if (evt & PD_EVENT_TCPC_RESET) {
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ /* Reset LPM software state after a reset */
+ request_low_power_mode(port, 0);
+#endif
CPRINTS("TCPC p%d reset!", port);
if (tcpm_init(port) != EC_SUCCESS)
CPRINTS("TCPC p%d init failed", port);
@@ -3508,6 +3565,15 @@ void pd_task(void *u)
assert(auto_toggle_supported);
+ /*
+ * If SW decided we should be in a low power state and
+ * the CC lines did not change, then don't talk with the
+ * TCPC otherwise we might wake it up.
+ */
+ if (pd[port].flags & PD_FLAGS_LPM_REQUESTED &&
+ !(evt & PD_EVENT_CC))
+ break;
+
/* Check for connection */
tcpm_get_cc(port, &cc1, &cc2);
@@ -3533,10 +3599,7 @@ void pd_task(void *u)
next_state = PD_STATE_DRP_AUTO_TOGGLE;
if (next_state != PD_STATE_DRP_AUTO_TOGGLE) {
- tcpm_set_drp_toggle(port, 0);
-#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
- CPRINTS("TCPC p%d Exit Low Power Mode", port);
-#endif
+ pd_set_drp_toggle(port, 0);
}
if (next_state == PD_STATE_SNK_DISCONNECTED) {
@@ -3548,12 +3611,9 @@ void pd_task(void *u)
pd_set_power_role(port, PD_ROLE_SOURCE);
timeout = 2*MSEC;
} else {
- tcpm_set_drp_toggle(port, 1);
+ pd_set_drp_toggle(port, 1);
pd[port].flags |= PD_FLAGS_TCPC_DRP_TOGGLE;
timeout = -1;
-#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
- CPRINTS("TCPC p%d Low Power Mode", port);
-#endif
}
set_state(port, next_state);
@@ -3581,6 +3641,23 @@ void pd_task(void *u)
}
}
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ /* Determine if we need to put the TCPC in low power mode */
+ if (pd[port].flags & PD_FLAGS_LPM_REQUESTED &&
+ !(pd[port].flags & PD_FLAGS_LPM_ENGAGED)) {
+ const int64_t time_left =
+ lpm_debounce_deadlines[port].val - now.val;
+ if (time_left <= 0) {
+ pd[port].flags |= PD_FLAGS_LPM_ENGAGED;
+ tcpm_enter_low_power_mode(port);
+ CPRINTS("TCPC p%d Enter Low Power Mode", port);
+ timeout = -1;
+ } else if (timeout < 0 || timeout > time_left) {
+ timeout = time_left;
+ }
+ }
+#endif
+
/* Check for disconnection if we're connected */
if (!pd_is_connected(port))
continue;