diff options
-rw-r--r-- | common/usbc/usb_pe_drp_sm.c | 27 | ||||
-rw-r--r-- | common/usbc/usb_tc_drp_acc_trysrc_sm.c | 87 | ||||
-rw-r--r-- | include/usb_tc_sm.h | 12 | ||||
-rw-r--r-- | test/fake_usbc.c | 5 |
4 files changed, 84 insertions, 47 deletions
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c index e30bea81c9..5702d83fee 100644 --- a/common/usbc/usb_pe_drp_sm.c +++ b/common/usbc/usb_pe_drp_sm.c @@ -2057,7 +2057,7 @@ static void pe_src_transition_to_default_entry(int port) * Request Device Policy Manager to set Port Data * Role to DFP and turn off VCONN */ - tc_hard_reset(port); + tc_hard_reset_request(port); } static void pe_src_transition_to_default_run(int port) @@ -2076,8 +2076,8 @@ static void pe_src_transition_to_default_run(int port) static void pe_src_transition_to_default_exit(int port) { - /* Inform the TC Layer the Hard Reset is complete */ - tc_hard_reset_complete(port); + /* TC layer can now go unattached */ + tc_hard_reset_allow_unattach(port); } /** @@ -2181,6 +2181,11 @@ static void pe_snk_wait_for_capabilities_entry(int port) { print_current_state(port); + /* USB TCPCI Spec R2V1p1 4.4.5.4.4 + * Enable AutoDischargeDisconnect since vbus is present + */ + tcpm_enable_auto_discharge_disconnect(port, 1); + /* Initialize and start the SinkWaitCapTimer */ pe[port].timeout = get_time().val + PD_T_SINK_WAIT_CAP; } @@ -2229,15 +2234,15 @@ static void pe_snk_evaluate_capability_entry(int port) /* Reset Hard Reset counter to zero */ pe[port].hard_reset_counter = 0; - /* USB TCPCI Spec R2V1p1 4.4.5.4.4 Enable AutoDischargeDisconnect */ - tcpm_enable_auto_discharge_disconnect(port, 1); - /* * If we were in a Hard Reset condition we have to delay until * now to let the TC know we are back to a stable connection. - * Inform the TC Layer the Hard Reset is complete + * Up to this point we have sent the reset and there is no + * conversation from the other side until we receive the + * capabilities message + * TC layer can now go unattached */ - tc_hard_reset_complete(port); + tc_hard_reset_allow_unattach(port); /* Set to highest revision supported by both ports. */ prl_set_rev(port, TCPC_TX_SOP, @@ -2746,11 +2751,13 @@ static void pe_snk_transition_to_default_entry(int port) { print_current_state(port); - /* USB TCPCI Spec R2V1p1 4.4.5.4.4 Disable AutoDischargeDisconnect */ + /* USB TCPCI Spec R2V1p1 4.4.5.4.4 + * Disable AutoDischargeDisconnect as vbus will drop in HardReset + */ tcpm_enable_auto_discharge_disconnect(port, 0); /* Inform the TC Layer of Hard Reset */ - tc_hard_reset(port); + tc_hard_reset_request(port); } static void pe_snk_transition_to_default_run(int port) diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c index 93ac545031..431afaa585 100644 --- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c +++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c @@ -66,10 +66,13 @@ #define TC_FLAGS_PARTNER_DR_POWER BIT(14) /* Flag to note port partner is Power Delivery capable */ #define TC_FLAGS_PARTNER_PD_CAPABLE BIT(15) -/* Flag to note hard reset has been triggered */ -#define TC_FLAGS_HARD_RESET BIT(16) -/* Flag to note we are currently performing hard reset */ -#define TC_FLAGS_HARD_RESET_IN_PROGRESS BIT(17) +/* Flag to note hard reset has been requested */ +#define TC_FLAGS_HARD_RESET_REQUESTED BIT(16) +/* + * Flag to note hard reset has been performed and we can't go to unattached + * until we have a source-sink connection again + */ +#define TC_FLAGS_HARD_RESET_NO_UNATTACH BIT(17) /* Flag to note port partner is USB comms capable */ #define TC_FLAGS_PARTNER_USB_COMM BIT(18) /* Flag to note we are currently performing PR Swap */ @@ -624,16 +627,33 @@ void tc_prs_snk_src_assert_rp(int port) } } -void tc_hard_reset(int port) +/* + * Hard Reset is being requested. This should not allow a TC connection + * to go to an unattached state until the connection is recovered from + * the hard reset. It is possible for a Hard Reset to cause a timeout + * in trying to recover and an additional Hard Reset would be issued. + * During this entire process it is important that the TC is not allowed + * to go to an unattached state. + * + * Type-C Spec Rev 2.0 section 4.5.2.2.5.2 + * Exiting from Attached.SNK State + * A port that is not a V CONN-Powered USB Device and is not in the + * process of a USB PD PR_Swap or a USB PD Hard Reset or a USB PD + * FR_Swap shall transition to Unattached.SNK + */ +void tc_hard_reset_request(int port) { - TC_SET_FLAG(port, TC_FLAGS_HARD_RESET); + TC_SET_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED); task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_SM, 0); } -void tc_hard_reset_complete(int port) +/* + * Hard Reset happened and this is how the PE will unblock leaving + * the attached state. + */ +void tc_hard_reset_allow_unattach(int port) { - TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_IN_PROGRESS); - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_SM, 0); + TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_NO_UNATTACH); } /****************************************************************************/ @@ -1597,8 +1617,8 @@ static void tc_unattached_snk_run(const int port) */ if (IS_ENABLED(CONFIG_USB_PE_SM)) { - if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET)) { - TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET); + if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) { + TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED); tc_set_data_role(port, PD_ROLE_UFP); /* Inform Policy Engine that hard reset is complete */ pe_ps_reset_complete(port); @@ -1828,9 +1848,9 @@ static void tc_attached_snk_run(const int port) /* * Perform Hard Reset */ - if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET)) { - TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET); - TC_SET_FLAG(port, TC_FLAGS_HARD_RESET_IN_PROGRESS); + if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) { + TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED); + TC_SET_FLAG(port, TC_FLAGS_HARD_RESET_NO_UNATTACH); tc_perform_snk_hard_reset(port); } @@ -1842,7 +1862,7 @@ static void tc_attached_snk_run(const int port) */ if (!TC_CHK_FLAG(port, TC_FLAGS_POWER_OFF_SNK) && !TC_CHK_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS) && - !TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_IN_PROGRESS)) { + !TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_NO_UNATTACH)) { /* Detach detection */ if (!pd_is_vbus_present(port)) { if (IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP)) @@ -2026,13 +2046,13 @@ static void tc_unoriented_dbg_acc_src_run(const int port) /* * Handle Hard Reset from Policy Engine */ - if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET)) { + if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) { /* Ignoring Hard Resets while the power supply is resetting.*/ if (get_time().val < tc[port].timeout) return; if (tc_perform_src_hard_reset(port)) - TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET); + TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED); return; } @@ -2184,24 +2204,21 @@ static void tc_dbg_acc_snk_run(const int port) /* * Perform Hard Reset */ - if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET)) { - TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET); - TC_SET_FLAG(port, TC_FLAGS_HARD_RESET_IN_PROGRESS); + if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) { + TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED); + TC_SET_FLAG(port, TC_FLAGS_HARD_RESET_NO_UNATTACH); tc_perform_snk_hard_reset(port); } /* - * HARD RESET in progress, don't disconnect - */ - if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_IN_PROGRESS)) - return; - - /* * The sink will be powered off during a power role swap but we * don't want to trigger a disconnect + * If we are working on a Hard Reset we have to remain attached + * even when vbus drops. */ if (!TC_CHK_FLAG(port, TC_FLAGS_POWER_OFF_SNK) && - !TC_CHK_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS)) { + !TC_CHK_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS) && + !TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_NO_UNATTACH)) { /* Detach detection */ if (!pd_is_vbus_present(port)) { if (IS_ENABLED(CONFIG_USB_PD_ALT_MODE_DFP)) @@ -2297,8 +2314,8 @@ static void tc_unattached_src_run(const int port) enum tcpc_cc_voltage_status cc1, cc2; if (IS_ENABLED(CONFIG_USB_PE_SM)) { - if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET)) { - TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET); + if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) { + TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED); tc_set_data_role(port, PD_ROLE_DFP); /* Inform Policy Engine that hard reset is complete */ pe_ps_reset_complete(port); @@ -2565,13 +2582,13 @@ static void tc_attached_src_run(const int port) /* * Handle Hard Reset from Policy Engine */ - if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET)) { + if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) { /* Ignoring Hard Resets while the power supply is resetting.*/ if (get_time().val < tc[port].timeout) return; if (tc_perform_src_hard_reset(port)) - TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET); + TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED); return; } @@ -2994,8 +3011,8 @@ static void tc_ct_unattached_snk_run(int port) * Hard Reset is sent when the PE layer is disabled due to a * CTVPD connection. */ - if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET)) { - TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET); + if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) { + TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED); /* Nothing to do. Just signal hard reset completion */ pe_ps_reset_complete(port); } @@ -3053,8 +3070,8 @@ static void tc_ct_attached_snk_run(int port) * Hard Reset is sent when the PE layer is disabled due to a * CTVPD connection. */ - if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET)) { - TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET); + if (TC_CHK_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED)) { + TC_CLR_FLAG(port, TC_FLAGS_HARD_RESET_REQUESTED); /* Nothing to do. Just signal hard reset completion */ pe_ps_reset_complete(port); } diff --git a/include/usb_tc_sm.h b/include/usb_tc_sm.h index 47013d56a1..a96ab05b1a 100644 --- a/include/usb_tc_sm.h +++ b/include/usb_tc_sm.h @@ -317,7 +317,17 @@ void tc_start_error_recovery(int port); * * @param port USB-C port number */ -void tc_hard_reset(int port); +void tc_hard_reset_request(int port); + +/** + * Hard Reset was sent and we are required to remain attached until we have + * restored our connection for the TypeC port. + * A call to tc_hard_reset_allow_unattach will allow the connection to go + * to an unattached state + * + * @param port USB-C port number + */ +void tc_hard_reset_allow_unattach(int port); /** * Hard Reset is complete for the TypeC port diff --git a/test/fake_usbc.c b/test/fake_usbc.c index fb572c59e3..731e15c3de 100644 --- a/test/fake_usbc.c +++ b/test/fake_usbc.c @@ -84,7 +84,10 @@ int tc_is_vconn_src(int port) return 0; } -void tc_hard_reset(int port) +void tc_hard_reset_request(int port) +{} + +void tc_hard_reset_allow_unattach(int port) {} void tc_hard_reset_complete(int port) |