diff options
author | Jett Rink <jettrink@chromium.org> | 2019-10-17 10:14:24 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-10-24 00:44:31 +0000 |
commit | cb2fa8b437cb14e652f0e6374d3caf8e568a04ac (patch) | |
tree | bcb51a9ea792f8d2d40305ec78dbbe6afaf9f4fa | |
parent | 664d4e781063463923376bb9b557dc765d37b7e3 (diff) | |
download | chrome-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.c | 161 | ||||
-rw-r--r-- | test/test_config.h | 9 | ||||
-rw-r--r-- | test/usb_typec_drp_acc_trysrc.c | 130 | ||||
-rw-r--r-- | test/usb_typec_drp_acc_trysrc.mocklist | 8 |
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) |