summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJett Rink <jettrink@chromium.org>2020-08-07 09:50:11 -0600
committerCommit Bot <commit-bot@chromium.org>2020-08-13 22:32:15 +0000
commit39a526023e435a776639d68271eed593598e9106 (patch)
tree743fa4d30fa2ad4dfbdbcc8b8f52f0ae8ffa84fe
parent0212d4a3ce01452ddaba46f076f90e9a5e90e589 (diff)
downloadchrome-ec-39a526023e435a776639d68271eed593598e9106.tar.gz
tcpmv2: wait before enabling HW auto toggle
We need to ensure that the previous Rd or Rp has been held long enough before we transition into hardware auto toggle otherwise the first toggle might be too short and violate the DRP timing spec BRANCH=none BUG=b:163095971 TEST=Verify on scope Signed-off-by: Jett Rink <jettrink@chromium.org> Change-Id: I92e9f5ca7dbca2b347e438d774551cc11476195b Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2343176 Reviewed-by: Edward Hill <ecgh@chromium.org>
-rw-r--r--common/mock/tcpc_mock.c10
-rw-r--r--common/usbc/usb_tc_drp_acc_trysrc_sm.c26
-rw-r--r--include/mock/tcpc_mock.h1
-rw-r--r--test/test_config.h1
-rw-r--r--test/usb_typec_drp_acc_trysrc.c26
5 files changed, 59 insertions, 5 deletions
diff --git a/common/mock/tcpc_mock.c b/common/mock/tcpc_mock.c
index 71be5ca281..64a1ce01cf 100644
--- a/common/mock/tcpc_mock.c
+++ b/common/mock/tcpc_mock.c
@@ -9,6 +9,7 @@
#include "memory.h"
#include "mock/tcpc_mock.h"
#include "tests/enum_strings.h"
+#include "timer.h"
#include "usb_pd_tcpm.h"
#ifndef CONFIG_COMMON_RUNTIME
@@ -142,6 +143,15 @@ void mock_tcpc_discharge_vbus(int port, int enable)
__maybe_unused static int mock_drp_toggle(int port)
{
+ /* Only set the time the first time this is called. */
+ if (mock_tcpc.first_call_to_enable_auto_toggle == 0)
+ mock_tcpc.first_call_to_enable_auto_toggle = get_time().val;
+
+ if (!mock_tcpc.should_print_call)
+ return EC_SUCCESS;
+
+ ccprints("[TCPC] Enabling Auto Toggle");
+
return EC_SUCCESS;
}
diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
index 4be631bedf..864976da4c 100644
--- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c
+++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
@@ -152,6 +152,9 @@
*/
#define PD_DISABLED_BY_POLICY BIT(1)
+/* Unreachable time in future */
+#define TIMER_DISABLED 0xffffffffffffffff
+
enum ps_reset_sequence {
PS_STATE0,
PS_STATE1,
@@ -2890,15 +2893,28 @@ static void tc_drp_auto_toggle_entry(const int port)
{
print_current_state(port);
- tcpm_enable_drp_toggle(port);
+ /*
+ * We need to ensure that we are waiting in the previous Rd or Rp state
+ * for the minimum of DRP SNK or SRC so the first toggle cause by
+ * transition into auto toggle doesn't violate spec timing.
+ */
+ tc[port].timeout = get_time().val + MAX(PD_T_DRP_SNK, PD_T_DRP_SRC);
}
static void tc_drp_auto_toggle_run(const int port)
{
-#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
- set_state_tc(port, TC_LOW_POWER_MODE);
- return;
-#endif
+ if (tc[port].timeout != TIMER_DISABLED) {
+ if (tc[port].timeout > get_time().val)
+ return;
+
+ tc[port].timeout = TIMER_DISABLED;
+ tcpm_enable_drp_toggle(port);
+
+ if (IS_ENABLED(CONFIG_USB_PD_TCPC_LOW_POWER)) {
+ set_state_tc(port, TC_LOW_POWER_MODE);
+ return;
+ }
+ }
if (TC_CHK_FLAG(port, TC_FLAGS_CHECK_CONNECTION))
check_drp_connection(port);
diff --git a/include/mock/tcpc_mock.h b/include/mock/tcpc_mock.h
index 543c89862a..9098fe1ba3 100644
--- a/include/mock/tcpc_mock.h
+++ b/include/mock/tcpc_mock.h
@@ -14,6 +14,7 @@ struct mock_tcpc_ctrl {
int vbus_level;
int num_calls_to_set_header;
bool should_print_call;
+ uint64_t first_call_to_enable_auto_toggle;
/* Set to function pointer if callback is needed for test code */
struct tcpm_drv callbacks;
diff --git a/test/test_config.h b/test/test_config.h
index e52d9b8995..0c74657d2a 100644
--- a/test/test_config.h
+++ b/test/test_config.h
@@ -414,6 +414,7 @@ int ncp15wb_calculate_temp(uint16_t adc);
#define CONFIG_USB_PD_TCPMV2
#define CONFIG_USB_PD_PORT_MAX_COUNT 1
#define CONFIG_USBC_SS_MUX
+#define CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
#define CONFIG_USB_PD_VBUS_DETECT_TCPC
#define CONFIG_USB_POWER_DELIVERY
#undef CONFIG_USB_PRL_SM
diff --git a/test/usb_typec_drp_acc_trysrc.c b/test/usb_typec_drp_acc_trysrc.c
index 1578a04390..ce1b02e5bc 100644
--- a/test/usb_typec_drp_acc_trysrc.c
+++ b/test/usb_typec_drp_acc_trysrc.c
@@ -660,6 +660,31 @@ __maybe_unused static int test_cc_rd_on_por_reset(void)
return EC_SUCCESS;
}
+__maybe_unused static int test_auto_toggle_delay(void)
+{
+ uint64_t time;
+
+ /* Start with auto toggle disabled so we can time the transition */
+ pd_set_dual_role(PORT0, PD_DRP_TOGGLE_OFF);
+ task_wait_event(SECOND);
+
+ /* Enabled auto toggle and start the timer for the transition */
+ pd_set_dual_role(PORT0, PD_DRP_TOGGLE_ON);
+ time = get_time().val;
+
+ /*
+ * Ensure we do not transition to auto toggle from Rd or Rp in less time
+ * than tDRP minimum (50 ms) * dcSRC.DRP minimum (30%) = 15 ms.
+ * Otherwise we can confuse external partners with the first transition
+ * to auto toggle.
+ */
+ task_wait_event(SECOND);
+ TEST_GT(mock_tcpc.first_call_to_enable_auto_toggle - time,
+ 15ul * MSEC, "%lu");
+
+ return EC_SUCCESS;
+}
+
/* TODO(b/153071799): test as SNK monitor for Vbus disconnect (not CC line) */
/* TODO(b/153071799): test as SRC monitor for CC line state change */
@@ -708,6 +733,7 @@ void run_test(int argc, char **argv)
RUN_TEST(test_cc_open_on_normal_reset);
RUN_TEST(test_cc_rd_on_por_reset);
+ RUN_TEST(test_auto_toggle_delay);
/* Do basic state machine validity checks last. */
RUN_TEST(test_tc_no_parent_cycles);