From 015d9606b30299aff975db8b3096dbf57b3f065f Mon Sep 17 00:00:00 2001 From: Diana Z Date: Wed, 24 Feb 2021 17:02:52 -0700 Subject: TCPMv2: Debounce Vbus loss when FRS is enabled A hub may send a Fast Role Swap signal when Vbus is less than vSafe5V, so allow a 5ms debounce after Vbus loss for the signal to come in before we declare the connection detached. BRANCH=None BUG=b:180453483 TEST=on voxel, confirm FRS behaves normally Signed-off-by: Diana Z Change-Id: If56106660c0a2bf82e28b91129bc9dd367ebc8fe Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2718838 Tested-by: Eric Herrmann Reviewed-by: Eric Herrmann Reviewed-by: Denis Brockus Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2774581 Tested-by: Abe Levkoy Reviewed-by: Abe Levkoy Commit-Queue: Abe Levkoy --- common/usbc/usb_tc_drp_acc_trysrc_sm.c | 49 +++++++++++++++++++++++++++++----- include/usb_pd.h | 7 +++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/common/usbc/usb_tc_drp_acc_trysrc_sm.c b/common/usbc/usb_tc_drp_acc_trysrc_sm.c index 2bb2dd6dd8..cb7f7866b9 100644 --- a/common/usbc/usb_tc_drp_acc_trysrc_sm.c +++ b/common/usbc/usb_tc_drp_acc_trysrc_sm.c @@ -2444,6 +2444,46 @@ static void tc_attached_snk_entry(const int port) tcpm_debug_accessory(port, 1); } +/* + * Check whether Vbus has been removed on this port, accounting for some Vbus + * debounce if FRS is enabled. + * + * Returns true if a new state was set and the calling run should exit. + */ +static bool tc_snk_check_vbus_removed(const int port) +{ + if (IS_ENABLED(CONFIG_USB_PD_FRS)) { + /* + * Debounce Vbus presence when FRS is enabled. Note that we may + * lose Vbus before the FRS signal comes in to let us know + * we're PR swapping, but we must still transition to unattached + * within tSinkDisconnect. + * + * We may safely re-use the Vbus debounce timer here + * since a PR swap would no longer be in progress when Vbus + * removal is checked. + */ + if (pd_check_vbus_level(port, VBUS_REMOVED)) { + if (pd_timer_is_disabled(port, + TC_TIMER_VBUS_DEBOUNCE)) { + pd_timer_enable(port, TC_TIMER_VBUS_DEBOUNCE, + PD_T_FRS_VBUS_DEBOUNCE); + } else if (pd_timer_is_expired(port, + TC_TIMER_VBUS_DEBOUNCE)) { + set_state_tc(port, TC_UNATTACHED_SNK); + return true; + } + } else { + pd_timer_disable(port, TC_TIMER_VBUS_DEBOUNCE); + } + } else if (pd_check_vbus_level(port, VBUS_REMOVED)) { + set_state_tc(port, TC_UNATTACHED_SNK); + return true; + } + + return false; +} + static void tc_attached_snk_run(const int port) { #ifdef CONFIG_USB_PE_SM @@ -2482,6 +2522,7 @@ static void tc_attached_snk_run(const int port) pd_timer_is_expired(port, TC_TIMER_VBUS_DEBOUNCE)) { /* PR Swap is no longer in progress */ TC_CLR_FLAG(port, TC_FLAGS_PR_SWAP_IN_PROGRESS); + pd_timer_disable(port, TC_TIMER_VBUS_DEBOUNCE); /* * AutoDischargeDisconnect was turned off when we @@ -2502,10 +2543,8 @@ static void tc_attached_snk_run(const int port) /* * Detach detection */ - if (pd_check_vbus_level(port, VBUS_REMOVED)) { - set_state_tc(port, TC_UNATTACHED_SNK); + if (tc_snk_check_vbus_removed(port)) return; - } if (!pe_is_explicit_contract(port)) sink_power_sub_states(port); @@ -2594,10 +2633,8 @@ static void tc_attached_snk_run(const int port) #else /* CONFIG_USB_PE_SM */ /* Detach detection */ - if (pd_check_vbus_level(port, VBUS_REMOVED)) { - set_state_tc(port, TC_UNATTACHED_SNK); + if (tc_snk_check_vbus_removed(port)) return; - } /* Run Sink Power Sub-State */ sink_power_sub_states(port); diff --git a/include/usb_pd.h b/include/usb_pd.h index f079cb2701..ee76496235 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -246,6 +246,13 @@ enum pd_rx_errors { #define PD_T_SYSJUMP (1000*MSEC) /* 1s */ #define PD_T_PR_SWAP_WAIT (100*MSEC) /* tPRSwapWait 100ms */ +/* + * Non-spec timer to prevent going Unattached if Vbus drops before a partner FRS + * signal comes through. This timer should be shorter than tSinkDisconnect + * (40ms) to ensure we still transition out of Attached.SNK in time. + */ +#define PD_T_FRS_VBUS_DEBOUNCE (5*MSEC) + /* number of edges and time window to detect CC line is not idle */ #define PD_RX_TRANSITION_COUNT 3 #define PD_RX_TRANSITION_WINDOW 20 /* between 12us and 20us */ -- cgit v1.2.1