summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJett Rink <jettrink@chromium.org>2019-10-17 10:14:24 -0600
committerCommit Bot <commit-bot@chromium.org>2019-10-24 00:44:31 +0000
commitcb2fa8b437cb14e652f0e6374d3caf8e568a04ac (patch)
treebcb51a9ea792f8d2d40305ec78dbbe6afaf9f4fa
parent664d4e781063463923376bb9b557dc765d37b7e3 (diff)
downloadchrome-ec-cb2fa8b437cb14e652f0e6374d3caf8e568a04ac.tar.gz
usb: call pd_execute_data_swap within tc_set_data
We need to let board specific code run any time we change the data role on our USB-C connection. When looking at all of the calls to tc_set_data_role, I realized that we don't really reset any data role until we start a new contract with SNK/SRC ready. We will do need to call into the code that disables the MUX lines when we detach. To do this, I created a super state for SNK/SRC unattached. BRANCH=none BUG=none TEST=builds. No board has an OTG signal using the new stack yet Change-Id: I017d20b2e1973b31ebf2b8925a7f8c5488a8ee24 Signed-off-by: Jett Rink <jettrink@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1864427
-rw-r--r--common/usbc/usb_tc_drp_acc_trysrc_sm.c161
-rw-r--r--test/test_config.h9
-rw-r--r--test/usb_typec_drp_acc_trysrc.c130
-rw-r--r--test/usb_typec_drp_acc_trysrc.mocklist8
4 files changed, 230 insertions, 78 deletions
diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
index 310ed0d76f..693a489a0f 100644
--- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c
+++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c
@@ -87,6 +87,7 @@ enum usb_tc_state {
TC_CC_OPEN,
TC_CC_RD,
TC_CC_RP,
+ TC_UNATTACHED,
};
/* Forward declare the full list of states. This is indexed by usb_tc_state */
static const struct usb_state tc_states[];
@@ -708,12 +709,6 @@ test_export_static enum usb_tc_state get_state_tc(const int port)
return tc[port].ctx.current - &tc_states[0];
}
-/* Get the previous TypeC state. */
-static enum usb_tc_state get_last_state_tc(const int port)
-{
- return tc[port].ctx.previous - &tc_states[0];
-}
-
static void print_current_state(const int port)
{
CPRINTS("C%d: %s", port, tc_state_names[get_state_tc(port)]);
@@ -794,6 +789,12 @@ void tc_set_data_role(int port, int role)
if (IS_ENABLED(CONFIG_USBC_SS_MUX))
set_usb_mux_with_current_data_role(port);
+ /*
+ * Run any board-specific code for role swap (e.g. setting OTG signals
+ * to SoC).
+ */
+ pd_execute_data_swap(port, role);
+
/* Notify TCPC of role update */
tcpm_set_msg_header(port, tc[port].power_role, tc[port].data_role);
}
@@ -1630,29 +1631,34 @@ static void tc_error_recovery_run(const int port)
}
}
+/* Set the CC resistors to Rd and update the TCPC power role header */
+static void set_rd(const int port)
+{
+ /*
+ * Both CC1 and CC2 pins shall be independently terminated to
+ * ground through Rd. Reset last cc change time.
+ */
+ tcpm_set_cc(port, TYPEC_CC_RD);
+ tc[port].cc_last_change = get_time().val;
+
+ /* Set power role to sink */
+ tc_set_power_role(port, PD_ROLE_SINK);
+ tcpm_set_msg_header(port, tc[port].power_role, tc[port].data_role);
+}
+
/**
* Unattached.SNK
*
- * Super State Entry Actions:
- * Vconn Off
- * Place Rd on CC
- * Set power role to SINK
+ * Super State is Unattached state
*/
static void tc_unattached_snk_entry(const int port)
{
- if (get_last_state_tc(port) != TC_UNATTACHED_SRC)
- print_current_state(port);
+ /* Set Rd since we are not in the Rd superstate */
+ set_rd(port);
if (IS_ENABLED(CONFIG_CHARGE_MANAGER))
charge_manager_update_dualrole(port, CAP_UNKNOWN);
- /*
- * Indicate that the port is disconnected so the board
- * can restore state from any previous data swap.
- *
- * NOTE: This is no-op change. This is cleaned up further in a child CL
- */
- pd_execute_data_swap(port, PD_ROLE_DFP);
tc[port].next_role_swap = get_time().val + PD_T_DRP_SNK;
if (IS_ENABLED(CONFIG_USB_PE_SM)) {
@@ -2002,18 +2008,31 @@ static void tc_dbg_acc_snk_run(const int port)
}
}
+/* Set the CC resistors to Rp and update the TCPC power role header */
+static void set_rp(const int port)
+{
+ /*
+ * Both CC1 and CC2 pins shall be independently pulled
+ * up through Rp. Reset last cc change time.
+ */
+ tcpm_select_rp_value(port, CONFIG_USB_PD_PULLUP);
+ tcpm_set_cc(port, TYPEC_CC_RP);
+ tc[port].cc_last_change = get_time().val;
+
+ /* Set power role to source */
+ tc_set_power_role(port, PD_ROLE_SOURCE);
+ tcpm_set_msg_header(port, tc[port].power_role, tc[port].data_role);
+}
+
/**
* Unattached.SRC
*
- * Super State Entry Actions:
- * Vconn Off
- * Place Rp on CC
- * Set power role to SOURCE
+ * Super State is Unattached state
*/
static void tc_unattached_src_entry(const int port)
{
- if (get_last_state_tc(port) != TC_UNATTACHED_SNK)
- print_current_state(port);
+ /* Set Rd since we are not in the Rd superstate */
+ set_rp(port);
if (IS_ENABLED(CONFIG_USBC_PPC)) {
/* There is no sink connected. */
@@ -2029,16 +2048,6 @@ static void tc_unattached_src_entry(const int port)
if (IS_ENABLED(CONFIG_CHARGE_MANAGER))
charge_manager_update_dualrole(port, CAP_UNKNOWN);
- tc_set_data_role(port, PD_ROLE_DFP);
-
- /*
- * Indicate that the port is disconnected so the board
- * can restore state from any previous data swap.
- *
- * NOTE: This is no-op change. This is cleaned up further in a child CL
- */
- pd_execute_data_swap(port, PD_ROLE_DFP);
-
if (IS_ENABLED(CONFIG_USB_PE_SM)) {
tc[port].flags = 0;
tc[port].pd_enable = 0;
@@ -2557,42 +2566,6 @@ static void tc_ct_attached_snk_exit(int port)
#endif /* CONFIG_USB_PE_SM */
/**
- * Super State CC_RD
- */
-static void tc_cc_rd_entry(const int port)
-{
- /*
- * Both CC1 and CC2 pins shall be independently terminated to
- * ground through Rd. Reset last cc change time.
- */
- tcpm_set_cc(port, TYPEC_CC_RD);
- tc[port].cc_last_change = get_time().val;
-
- /* Set power role to sink */
- tc_set_power_role(port, PD_ROLE_SINK);
- tcpm_set_msg_header(port, tc[port].power_role, tc[port].data_role);
-}
-
-
-/**
- * Super State CC_RP
- */
-static void tc_cc_rp_entry(const int port)
-{
- /* Set power role to source */
- tc_set_power_role(port, PD_ROLE_SOURCE);
- tcpm_set_msg_header(port, tc[port].power_role, tc[port].data_role);
-
- /*
- * Both CC1 and CC2 pins shall be independently pulled
- * up through Rp. Reset last cc change time.
- */
- tcpm_select_rp_value(port, CONFIG_USB_PD_PULLUP);
- tcpm_set_cc(port, TYPEC_CC_RP);
- tc[port].cc_last_change = get_time().val;
-}
-
-/**
* Super State CC_OPEN
*/
static void tc_cc_open_entry(const int port)
@@ -2619,6 +2592,38 @@ static void tc_cc_open_entry(const int port)
}
}
+/**
+ * Super State CC_RD
+ */
+static void tc_cc_rd_entry(const int port)
+{
+ set_rd(port);
+}
+
+/**
+ * Super State CC_RP
+ */
+static void tc_cc_rp_entry(const int port)
+{
+ set_rp(port);
+}
+
+/**
+ * Super State Unattached
+ *
+ * Ensures that any time we unattached we can perform an action without
+ * repeating it during DRP toggle
+ */
+static void tc_unattached_entry(const int port)
+{
+ /* This only prints the first time we enter a unattached state */
+ print_current_state(port);
+
+ /* This disables the mux when we disconnect on a port */
+ if (IS_ENABLED(CONFIG_USBC_SS_MUX))
+ set_usb_mux_with_current_data_role(port);
+}
+
void tc_run(const int port)
{
run_state(port, &tc[port].ctx);
@@ -2627,9 +2632,14 @@ void tc_run(const int port)
/*
* Type-C State Hierarchy (Sub-States are listed inside the boxes)
*
+ * |TC_UNATTACHED ---------|
+ * | |
+ * | TC_UNATTACHED_SNK |
+ * | TC_UNATTACHED_SRC |
+ * |-----------------------|
+ *
* |TC_CC_RD --------------| |TC_CC_RP ------------------------|
* | | | |
- * | TC_UNATTACHED_SNK | | TC_UNATTACHED_SRC |
* | TC_ATTACH_WAIT_SNK | | TC_ATTACH_WAIT_SRC |
* | TC_TRY_WAIT_SNK | | TC_TRY_SRC |
* | TC_DBG_ACC_SNK | | TC_UNORIENTED_DBG_ACC_SRC |
@@ -2654,6 +2664,9 @@ static const struct usb_state tc_states[] = {
[TC_CC_RP] = {
.entry = tc_cc_rp_entry,
},
+ [TC_UNATTACHED] = {
+ .entry = tc_unattached_entry,
+ },
/* Normal States */
[TC_DISABLED] = {
.entry = tc_disabled_entry,
@@ -2669,7 +2682,7 @@ static const struct usb_state tc_states[] = {
[TC_UNATTACHED_SNK] = {
.entry = tc_unattached_snk_entry,
.run = tc_unattached_snk_run,
- .parent = &tc_states[TC_CC_RD],
+ .parent = &tc_states[TC_UNATTACHED],
},
[TC_ATTACH_WAIT_SNK] = {
.entry = tc_attach_wait_snk_entry,
@@ -2695,7 +2708,7 @@ static const struct usb_state tc_states[] = {
[TC_UNATTACHED_SRC] = {
.entry = tc_unattached_src_entry,
.run = tc_unattached_src_run,
- .parent = &tc_states[TC_CC_RP],
+ .parent = &tc_states[TC_UNATTACHED],
},
[TC_ATTACH_WAIT_SRC] = {
.entry = tc_attach_wait_src_entry,
diff --git a/test/test_config.h b/test/test_config.h
index 7771a05c0f..30a82ba863 100644
--- a/test/test_config.h
+++ b/test/test_config.h
@@ -299,8 +299,7 @@ int ncp15wb_calculate_temp(uint16_t adc);
/* Common TypeC tests defines */
#if defined(TEST_USB_TYPEC_VPD) || \
- defined(TEST_USB_TYPEC_CTVPD) || \
- defined(TEST_USB_TYPEC_DRP_ACC_TRYSRC)
+ defined(TEST_USB_TYPEC_CTVPD)
#define CONFIG_USB_PID 0x5036
#define VPD_HW_VERSION 0x0001
#define VPD_FW_VERSION 0x0001
@@ -335,6 +334,12 @@ int ncp15wb_calculate_temp(uint16_t adc);
#define CONFIG_USB_TYPEC_DRP_ACC_TRYSRC
#define CONFIG_USB_PD_DUAL_ROLE
#define CONFIG_USB_PD_TRY_SRC
+#define CONFIG_USB_TYPEC_SM
+#define CONFIG_USB_SM_FRAMEWORK
+#define CONFIG_USB_PD_PORT_COUNT 1
+#define CONFIG_USBC_SS_MUX
+#define CONFIG_USB_PD_VBUS_DETECT_TCPC
+#define CONFIG_USB_POWER_DELIVERY
#undef CONFIG_USB_PRL_SM
#undef CONFIG_USB_PE_SM
#endif
diff --git a/test/usb_typec_drp_acc_trysrc.c b/test/usb_typec_drp_acc_trysrc.c
index cce747e94c..5981001344 100644
--- a/test/usb_typec_drp_acc_trysrc.c
+++ b/test/usb_typec_drp_acc_trysrc.c
@@ -4,11 +4,133 @@
*
* Test USB Type-C VPD and CTVPD module.
*/
+#include "charge_manager.h"
+#include "mock/tcpc_mock.h"
+#include "mock/usb_mux_mock.h"
#include "task.h"
-#include "timer.h"
#include "test_util.h"
+#include "timer.h"
+#include "usb_mux.h"
+#include "usb_pd_tcpm.h"
#include "usb_sm_checks.h"
-#include "charge_manager.h"
+
+#define PORT0 0
+
+/* Install Mock TCPC and MUX drivers */
+const struct tcpc_config_t tcpc_config[CONFIG_USB_PD_PORT_COUNT] = {
+ {
+ .drv = &mock_tcpc_driver,
+ },
+};
+
+struct usb_mux usb_muxes[CONFIG_USB_PD_PORT_COUNT] = {
+ {
+ .driver = &mock_usb_mux_driver,
+ }
+};
+
+void charge_manager_set_ceil(int port, enum ceil_requestor requestor, int ceil)
+{
+ /* Do Nothing, but needed for linking */
+}
+
+__maybe_unused static int test_mux_con_dis_as_src(void)
+{
+ /* Update CC lines send state machine event to process */
+ mock_tcpc.cc1 = TYPEC_CC_VOLT_RD;
+ mock_tcpc.cc2 = TYPEC_CC_VOLT_OPEN;
+ task_set_event(TASK_ID_PD_C0, PD_EVENT_CC, 0);
+
+ /* This wait trainsitions through AttachWait.SRC then Attached.SRC */
+ task_wait_event(SECOND);
+
+ /* We are in Attached.SRC now */
+ TEST_EQ(mock_usb_mux.state, TYPEC_MUX_USB, "%d");
+ TEST_EQ(mock_usb_mux.num_set_calls, 1, "%d");
+
+ mock_tcpc.cc1 = TYPEC_CC_VOLT_OPEN;
+ mock_tcpc.cc2 = TYPEC_CC_VOLT_OPEN;
+ task_set_event(TASK_ID_PD_C0, PD_EVENT_CC, 0);
+
+ /* This wait will go through TryWait.SNK then to Unattached.SNK */
+ task_wait_event(10 * SECOND);
+
+ /* We are in Unattached.SNK. The mux should have detached */
+ TEST_EQ(mock_usb_mux.state, TYPEC_MUX_NONE, "%d");
+ TEST_EQ(mock_usb_mux.num_set_calls, 2, "%d");
+
+ return EC_SUCCESS;
+}
+
+__maybe_unused static int test_mux_con_dis_as_snk(void)
+{
+ /* Update CC lines send state machine event to process */
+ mock_tcpc.cc1 = TYPEC_CC_VOLT_RP_3_0;
+ mock_tcpc.cc2 = TYPEC_CC_VOLT_OPEN;
+ mock_tcpc.vbus_level = 1;
+ task_set_event(TASK_ID_PD_C0, PD_EVENT_CC, 0);
+
+ /* This wait will go through AttachWait.SNK to Attached.SNK */
+ task_wait_event(5 * SECOND);
+
+ /* We are in Attached.SNK now */
+ TEST_EQ(mock_usb_mux.state, TYPEC_MUX_USB, "%d");
+ TEST_EQ(mock_usb_mux.num_set_calls, 1, "%d");
+
+ mock_tcpc.cc1 = TYPEC_CC_VOLT_OPEN;
+ mock_tcpc.cc2 = TYPEC_CC_VOLT_OPEN;
+ mock_tcpc.vbus_level = 0;
+ task_set_event(TASK_ID_PD_C0, PD_EVENT_CC, 0);
+
+ /* This wait will go through TryWait.SNK then to Unattached.SNK */
+ task_wait_event(10 * SECOND);
+
+ /* We are in Unattached.SNK. The mux should have detached */
+ TEST_EQ(mock_usb_mux.state, TYPEC_MUX_NONE, "%d");
+ TEST_EQ(mock_usb_mux.num_set_calls, 2, "%d");
+
+ return EC_SUCCESS;
+}
+
+__maybe_unused static int test_power_role_set(void)
+{
+ /* Print out header changes for easier debugging */
+ mock_tcpc.should_print_header_changes = true;
+
+ /* Update CC lines send state machine event to process */
+ mock_tcpc.cc1 = TYPEC_CC_VOLT_OPEN;
+ mock_tcpc.cc2 = TYPEC_CC_VOLT_RD;
+ task_set_event(TASK_ID_PD_C0, PD_EVENT_CC, 0);
+ task_wait_event(10 * SECOND);
+
+ /* We are in Attached.SRC now */
+ TEST_EQ(mock_tcpc.power_role, PD_ROLE_SOURCE, "%d");
+ TEST_EQ(mock_tcpc.data_role, PD_ROLE_DFP, "%d");
+
+ /*
+ * We allow 2 separate calls to update the header since power and data
+ * role updates can be separate calls depending on the state is came
+ * from.
+ */
+ TEST_LE(mock_tcpc.num_calls_to_set_header, 2, "%d");
+
+ return EC_SUCCESS;
+}
+
+/* Reset the mocks before each test */
+void before_test(void)
+{
+ mock_usb_mux_reset();
+ mock_tcpc_reset();
+}
+
+void after_test(void)
+{
+ /* Disconnect any CC lines */
+ mock_tcpc.cc1 = TYPEC_CC_VOLT_OPEN;
+ mock_tcpc.cc2 = TYPEC_CC_VOLT_OPEN;
+ task_set_event(TASK_ID_PD_C0, PD_EVENT_CC, 0);
+}
void run_test(void)
{
@@ -18,6 +140,10 @@ void run_test(void)
task_wake(TASK_ID_PD_C0);
task_wait_event(5 * MSEC);
+ RUN_TEST(test_mux_con_dis_as_src);
+ RUN_TEST(test_mux_con_dis_as_snk);
+ RUN_TEST(test_power_role_set);
+
/* Do basic state machine sanity checks last. */
RUN_TEST(test_tc_no_parent_cycles);
RUN_TEST(test_tc_no_empty_state);
diff --git a/test/usb_typec_drp_acc_trysrc.mocklist b/test/usb_typec_drp_acc_trysrc.mocklist
new file mode 100644
index 0000000000..71c2e2cee9
--- /dev/null
+++ b/test/usb_typec_drp_acc_trysrc.mocklist
@@ -0,0 +1,8 @@
+/* Copyright 2019 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+ #define CONFIG_TEST_MOCK_LIST \
+ MOCK(USB_MUX) \
+ MOCK(TCPC)