diff options
author | Keith Short <keithshort@chromium.org> | 2020-12-16 20:45:41 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-01-09 00:44:44 +0000 |
commit | 88d46d61c3081b7fc32225f3aed7426a1d62e36e (patch) | |
tree | 82368a4b5a93e6eba6eb7d2c121a50fcdf7515c6 | |
parent | 6be1ff9b14b3593cfc6b657a41334cc8a7f5811d (diff) | |
download | chrome-ec-88d46d61c3081b7fc32225f3aed7426a1d62e36e.tar.gz |
tcpmv2: always issue SOP' soft reset
After entering a PD contract, always issue an SOP' soft reset before
sending any discovery VDMs to the cable.
BUG=b:172364575
BRANCH=volteer
TEST=connect monitor with emarked cable, verify SOP' soft reset is sent
when EC starts as SNK/DFP.
TEST=Connect monitor with non-emark cable. Verify SOP' soft reset is
sent once regardless of starting role.
TEST=Connect USB4 dock, verify USB4 entry.
Signed-off-by: Keith Short <keithshort@chromium.org>
Change-Id: Id5026a2c8c9877b860e1356dd33763bad3e51841
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2596838
Reviewed-by: Diana Z <dzigterman@chromium.org>
Reviewed-by: Abe Levkoy <alevkoy@chromium.org>
-rw-r--r-- | common/usbc/usb_pe_drp_sm.c | 114 | ||||
-rw-r--r-- | include/usb_pd.h | 41 | ||||
-rw-r--r-- | test/usb_pe.h | 1 | ||||
-rw-r--r-- | test/usb_pe_drp.c | 20 | ||||
-rw-r--r-- | test/usb_tcpmv2_compliance_common.c | 9 |
5 files changed, 164 insertions, 21 deletions
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c index de8be98707..9659614d49 100644 --- a/common/usbc/usb_pe_drp_sm.c +++ b/common/usbc/usb_pe_drp_sm.c @@ -297,6 +297,7 @@ enum usb_pe_state { PE_VCS_TURN_ON_VCONN_SWAP, PE_VCS_TURN_OFF_VCONN_SWAP, PE_VCS_SEND_PS_RDY_SWAP, + PE_VCS_CBL_SEND_SOFT_RESET, PE_VDM_IDENTITY_REQUEST_CBL, PE_INIT_PORT_VDM_IDENTITY_REQUEST, PE_INIT_VDM_SVIDS_REQUEST, @@ -413,6 +414,7 @@ __maybe_unused static const char * const pe_state_names[] = { [PE_VCS_TURN_ON_VCONN_SWAP] = "PE_VCS_Turn_On_Vconn_Swap", [PE_VCS_TURN_OFF_VCONN_SWAP] = "PE_VCS_Turn_Off_Vconn_Swap", [PE_VCS_SEND_PS_RDY_SWAP] = "PE_VCS_Send_Ps_Rdy_Swap", + [PE_VCS_CBL_SEND_SOFT_RESET] = "PE_VCS_CBL_Send_Soft_Reset", #endif [PE_VDM_IDENTITY_REQUEST_CBL] = "PE_VDM_Identity_Request_Cbl", [PE_INIT_PORT_VDM_IDENTITY_REQUEST] = @@ -1248,6 +1250,7 @@ void pe_report_error(int port, enum pe_error e, enum tcpm_transmit_type type) get_state_pe(port) == PE_PRS_SRC_SNK_WAIT_SOURCE_ON || get_state_pe(port) == PE_SRC_DISABLED || get_state_pe(port) == PE_SRC_DISCOVERY || + get_state_pe(port) == PE_VCS_CBL_SEND_SOFT_RESET || get_state_pe(port) == PE_VDM_IDENTITY_REQUEST_CBL) || (PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_PATH) && get_state_pe(port) == PE_PRS_SNK_SRC_SEND_SWAP) || @@ -1685,6 +1688,18 @@ __maybe_unused static bool pe_attempt_port_discovery(int port) } } + /* + * TODO(b/177001425): TCPMv2 - move SOP' soft reset check into + * common_src_snk_dpm_requests() + */ + if (PE_CHK_DPM_REQUEST(port, DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND)) { + pe_set_dpm_curr_request(port, + DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND); + pe[port].tx_type = TCPC_TX_SOP_PRIME; + set_state_pe(port, PE_VCS_CBL_SEND_SOFT_RESET); + return true; + } + /* If mode entry was successful, disable the timer */ if (PE_CHK_FLAG(port, PE_FLAGS_VDM_SETUP_DONE)) { pe[port].discover_identity_timer = TIMER_DISABLED; @@ -1894,6 +1909,13 @@ static void pe_src_startup_entry(int port) /* Reset the protocol layer */ prl_reset(port); + /* + * Protocol layer reset clears the message IDs for all SOP types. + * Indicate that a SOP' soft reset is required before any other + * messages are sent to the cable. + */ + pd_dpm_request(port, DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND); + /* Set initial data role */ pe[port].data_role = pd_get_data_role(port); @@ -2770,6 +2792,13 @@ static void pe_snk_startup_entry(int port) /* Reset the protocol layer */ prl_reset(port); + /* + * Protocol layer reset clears the message IDs for all SOP types. + * Indicate that a SOP' soft reset is required before any other + * messages are sent to the cable. + */ + pd_dpm_request(port, DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND); + /* Set initial data role */ pe[port].data_role = pd_get_data_role(port); @@ -6169,6 +6198,13 @@ static void pe_vcs_send_ps_rdy_swap_run(int port) /* TODO(b/152058087): TCPMv2: Break up pe_vcs_send_ps_rdy_swap */ switch (pe[port].sub) { case PE_SUB0: + + /* + * TODO: use DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND to + * send cable soft reset. + */ + PE_CLR_DPM_REQUEST(port, DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND); + /* * After a VCONN Swap the VCONN Source needs to reset * the Cable Plug’s Protocol Layer in order to ensure @@ -6233,6 +6269,80 @@ static void pe_vcs_send_ps_rdy_swap_run(int port) } } } + +/* + * PE_VCS_CBL_SEND_SOFT_RESET + * Note - Entry is only when directed by the DPM. Protocol errors are handled + * by the PE_SEND_SOFT_RESET state. + */ +static void pe_vcs_cbl_send_soft_reset_entry(int port) +{ + print_current_state(port); + + if (!pe_can_send_sop_prime(port)) { + /* + * If we're not VCONN source, return the appropriate state. + * A VCONN swap re-triggers sending SOP' soft reset + */ + if (pe_is_explicit_contract(port)) { + /* Return to PE_{SRC,SNK}_Ready state */ + pe_set_ready_state(port); + } else { + /* + * Not in Explicit Contract, so we must be a SRC, + * return to PE_Src_Send_Capabilities. + */ + set_state_pe(port, PE_SRC_SEND_CAPABILITIES); + } + return; + } + + send_ctrl_msg(port, TCPC_TX_SOP_PRIME, PD_CTRL_SOFT_RESET); + pe[port].sender_response_timer = TIMER_DISABLED; +} + +static void pe_vcs_cbl_send_soft_reset_run(int port) +{ + bool cable_soft_reset_complete = false; + + if (PE_CHK_FLAG(port, PE_FLAGS_TX_COMPLETE)) { + PE_CLR_FLAG(port, PE_FLAGS_TX_COMPLETE); + pe[port].sender_response_timer = get_time().val + + PD_T_SENDER_RESPONSE; + } + + /* Got ACCEPT or REJECT from Cable Plug */ + if (PE_CHK_FLAG(port, PE_FLAGS_MSG_RECEIVED)) { + PE_CLR_FLAG(port, PE_FLAGS_MSG_RECEIVED); + cable_soft_reset_complete = true; + } + + /* No GoodCRC received, cable is not present */ + if (PE_CHK_FLAG(port, PE_FLAGS_PROTOCOL_ERROR)) { + PE_CLR_FLAG(port, PE_FLAGS_PROTOCOL_ERROR); + /* + * TODO(b/171823328): TCPMv2: Implement cable reset + * Cable reset will only be done here if we know for certain + * a cable is present (we've received the SOP' DiscId response). + */ + cable_soft_reset_complete = true; + } + + if (cable_soft_reset_complete || + get_time().val > pe[port].sender_response_timer) { + if (pe_is_explicit_contract(port)) { + /* Return to PE_{SRC,SNK}_Ready state */ + pe_set_ready_state(port); + } else { + /* + * Not in Explicit Contract, so we must be a SRC, + * return to PE_Src_Send_Capabilities. + */ + set_state_pe(port, PE_SRC_SEND_CAPABILITIES); + } + } +} + #endif /* CONFIG_USBC_VCONN */ /* @@ -6749,6 +6859,10 @@ static const struct usb_state pe_states[] = { .entry = pe_vcs_send_ps_rdy_swap_entry, .run = pe_vcs_send_ps_rdy_swap_run, }, + [PE_VCS_CBL_SEND_SOFT_RESET] = { + .entry = pe_vcs_cbl_send_soft_reset_entry, + .run = pe_vcs_cbl_send_soft_reset_run, + }, #endif /* CONFIG_USBC_VCONN */ [PE_VDM_IDENTITY_REQUEST_CBL] = { .entry = pe_vdm_identity_request_cbl_entry, diff --git a/include/usb_pd.h b/include/usb_pd.h index e0f0ac0e28..f0997de7b0 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -956,26 +956,27 @@ enum pd_dual_role_states { * NOTE: These are usually set by host commands from the AP. */ enum pd_dpm_request { - DPM_REQUEST_DR_SWAP = BIT(0), - DPM_REQUEST_PR_SWAP = BIT(1), - DPM_REQUEST_VCONN_SWAP = BIT(2), - DPM_REQUEST_GOTO_MIN = BIT(3), - DPM_REQUEST_SRC_CAP_CHANGE = BIT(4), - DPM_REQUEST_GET_SNK_CAPS = BIT(5), - DPM_REQUEST_SEND_PING = BIT(6), - DPM_REQUEST_SOURCE_CAP = BIT(7), - DPM_REQUEST_NEW_POWER_LEVEL = BIT(8), - DPM_REQUEST_VDM = BIT(9), - DPM_REQUEST_BIST_TX = BIT(10), - DPM_REQUEST_SNK_STARTUP = BIT(11), - DPM_REQUEST_SRC_STARTUP = BIT(12), - DPM_REQUEST_HARD_RESET_SEND = BIT(13), - DPM_REQUEST_SOFT_RESET_SEND = BIT(14), - DPM_REQUEST_PORT_DISCOVERY = BIT(15), - DPM_REQUEST_SEND_ALERT = BIT(16), - DPM_REQUEST_ENTER_USB = BIT(17), - DPM_REQUEST_GET_SRC_CAPS = BIT(18), - DPM_REQUEST_EXIT_MODES = BIT(19), + DPM_REQUEST_DR_SWAP = BIT(0), + DPM_REQUEST_PR_SWAP = BIT(1), + DPM_REQUEST_VCONN_SWAP = BIT(2), + DPM_REQUEST_GOTO_MIN = BIT(3), + DPM_REQUEST_SRC_CAP_CHANGE = BIT(4), + DPM_REQUEST_GET_SNK_CAPS = BIT(5), + DPM_REQUEST_SEND_PING = BIT(6), + DPM_REQUEST_SOURCE_CAP = BIT(7), + DPM_REQUEST_NEW_POWER_LEVEL = BIT(8), + DPM_REQUEST_VDM = BIT(9), + DPM_REQUEST_BIST_TX = BIT(10), + DPM_REQUEST_SNK_STARTUP = BIT(11), + DPM_REQUEST_SRC_STARTUP = BIT(12), + DPM_REQUEST_HARD_RESET_SEND = BIT(13), + DPM_REQUEST_SOFT_RESET_SEND = BIT(14), + DPM_REQUEST_PORT_DISCOVERY = BIT(15), + DPM_REQUEST_SEND_ALERT = BIT(16), + DPM_REQUEST_ENTER_USB = BIT(17), + DPM_REQUEST_GET_SRC_CAPS = BIT(18), + DPM_REQUEST_EXIT_MODES = BIT(19), + DPM_REQUEST_SOP_PRIME_SOFT_RESET_SEND = BIT(20), }; /** diff --git a/test/usb_pe.h b/test/usb_pe.h index 373bf9f5b2..a4967d02e5 100644 --- a/test/usb_pe.h +++ b/test/usb_pe.h @@ -120,6 +120,7 @@ enum usb_pe_state { PE_VCS_TURN_ON_VCONN_SWAP, PE_VCS_TURN_OFF_VCONN_SWAP, PE_VCS_SEND_PS_RDY_SWAP, + PE_VCS_CBL_SEND_SOFT_RESET, PE_VDM_IDENTITY_REQUEST_CBL, PE_INIT_PORT_VDM_IDENTITY_REQUEST, PE_INIT_VDM_SVIDS_REQUEST, diff --git a/test/usb_pe_drp.c b/test/usb_pe_drp.c index 10269db779..8138bb5ddf 100644 --- a/test/usb_pe_drp.c +++ b/test/usb_pe_drp.c @@ -189,6 +189,16 @@ test_static int test_send_caps_error_before_connected(void) EC_SUCCESS, "%d"); mock_prl_message_sent(PORT0); + /* + * Cable soft reset is always issued after entry into Src/Snk_Ready + * simulate no cable response. + */ + TEST_EQ(mock_prl_wait_for_tx_msg(PORT0, TCPC_TX_SOP_PRIME, + PD_CTRL_SOFT_RESET, 0, + 60 * MSEC), + EC_SUCCESS, "%d"); + mock_prl_report_error(PORT0, ERR_TCH_XMIT, TCPC_TX_SOP_PRIME); + TEST_EQ(finish_src_discovery(), EC_SUCCESS, "%d"); task_wait_event(5 * SECOND); @@ -225,6 +235,16 @@ test_static int test_send_caps_error_when_connected(void) mock_prl_message_sent(PORT0); /* + * Cable soft reset is always issued after entry into Src/Snk_Ready + * simulate no cable response. + */ + TEST_EQ(mock_prl_wait_for_tx_msg(PORT0, TCPC_TX_SOP_PRIME, + PD_CTRL_SOFT_RESET, 0, + 60 * MSEC), + EC_SUCCESS, "%d"); + mock_prl_report_error(PORT0, ERR_TCH_XMIT, TCPC_TX_SOP_PRIME); + + /* * Expect VENDOR_DEF for cable identity, simulate no cable (so no * GoodCRC, so ERR_TCH_XMIT). Don't reply NOT_SUPPORTED, since the spec * says a cable never does that. diff --git a/test/usb_tcpmv2_compliance_common.c b/test/usb_tcpmv2_compliance_common.c index 92efe5a616..a5ff2348d4 100644 --- a/test/usb_tcpmv2_compliance_common.c +++ b/test/usb_tcpmv2_compliance_common.c @@ -320,7 +320,6 @@ int proc_pd_e1(enum pd_data_role data_role, enum proc_pd_e1_attach attach) PD_CTRL_PS_RDY, 0), EC_SUCCESS, "%d"); mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); - task_wait_event(1 * MSEC); TEST_EQ(tc_is_attached_src(PORT0), true, "%d"); break; @@ -366,6 +365,14 @@ int proc_pd_e3(void) int handle_attach_expected_msgs(enum pd_data_role data_role) { if (data_role == PD_ROLE_DFP) { + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP_PRIME, + PD_CTRL_SOFT_RESET, 0), + EC_SUCCESS, "%d"); + mock_set_alert(TCPC_REG_ALERT_TX_SUCCESS); + task_wait_event(10 * MSEC); + partner_send_msg(PD_MSG_SOP_PRIME, PD_CTRL_NOT_SUPPORTED, 0, 0, + NULL); + TEST_EQ(verify_tcpci_transmit(TCPC_TX_SOP_PRIME, 0, PD_DATA_VENDOR_DEF), EC_SUCCESS, "%d"); |