diff options
author | Peter Marheine <pmarheine@chromium.org> | 2020-11-30 15:36:48 +1100 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-12-08 01:07:38 +0000 |
commit | de6407f867863eb2976194b3d55d0fe4d4e33a6f (patch) | |
tree | ed385ce397e608f5e2d9bd90dfe2db48f44ba860 | |
parent | 527cde447564514e237da26396236a8134310809 (diff) | |
download | chrome-ec-de6407f867863eb2976194b3d55d0fe4d4e33a6f.tar.gz |
TCPMv2 DRP: always try sink caps on PE_SNK_Ready for FRS
Prior to this change, device policy was inhibited from requesting
partner sink capabilities when entering SNK.Ready out of a power role
swap (because the flag gets cleared while invalidating the old contract
in the PRS process), which prevents Fast Role Swap from being enabled
in most situations- for instance Section E.2 of the USB-PD specification
revision 3.0 version 2.0 states that a PRS is a normal part of
connecting to a hub and the device should request sink caps via device
policy in order to enable FRS.
This change attempts to get sink caps from the port partner in
PE_SNK_Ready, then use them to evaluate support for FRS. By moving
partner capabilities evaluation to PE_SNK_Ready, we also prevent
FRS from being enabled when operating as a source: we don't expect
sinks to send FRS, and this helps avoid detecting (and attempting to
act on) spurious FRS signaling.
BUG=b:146393213
TEST=Morphius connects to a hub supporting FRS as expected and successfully
completes a fast role swap when power is removed from the hub.
BRANCH=zork
Signed-off-by: Peter Marheine <pmarheine@chromium.org>
Change-Id: Icf402b4ded99d35e23b51b168cb7f306c3ac156b
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2564978
Reviewed-by: Diana Z <dzigterman@chromium.org>
-rw-r--r-- | common/usbc/usb_pe_drp_sm.c | 112 |
1 files changed, 77 insertions, 35 deletions
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c index 9a764cb716..a947ae3da5 100644 --- a/common/usbc/usb_pe_drp_sm.c +++ b/common/usbc/usb_pe_drp_sm.c @@ -1064,6 +1064,48 @@ uint8_t pd_get_snk_cap_cnt(int port) } /* + * Evaluate a sink PDO for reported FRS support on the given port. + * + * If the requirements in the PDO are compatible with what we can supply, + * FRS will be enabled on the port. If the provided PDO does not specify + * FRS requirements (because it is not a fixed PDO) or PD 3.0 and FRS support + * are not enabled, do nothing. + */ +__maybe_unused static void pe_evaluate_frs_snk_pdo(int port, uint32_t pdo) +{ + if (!(IS_ENABLED(CONFIG_USB_PD_REV30) && IS_ENABLED(CONFIG_USB_PD_FRS))) + return; + + if ((pdo & PDO_TYPE_MASK) != PDO_TYPE_FIXED) { + /* + * PDO must be a fixed supply: either the caller chose the + * wrong PDO or the partner is not compliant. + */ + CPRINTS("C%d: Sink PDO %x is not a fixed supply," + " cannot support FRS", port, pdo); + return; + } + /* + * TODO(b/14191267): Make sure we can handle the required current + * before we enable FRS. + */ + if ((pdo & PDO_FIXED_DUAL_ROLE)) { + switch (pdo & PDO_FIXED_FRS_CURR_MASK) { + case PDO_FIXED_FRS_CURR_NOT_SUPPORTED: + break; + case PDO_FIXED_FRS_CURR_DFLT_USB_POWER: + case PDO_FIXED_FRS_CURR_1A5_AT_5V: + case PDO_FIXED_FRS_CURR_3A0_AT_5V: + CPRINTS("C%d: Partner FRS is OK: enabling PE support", + port); + typec_set_source_current_limit(port, TYPEC_RP_3A0); + pe_set_frs_enable(port, 1); + break; + } + } +} + +/* * Determine if this port may communicate with the cable plug. * * In both PD 2.0 and 3.0 (2.5.4 SOP'/SOP'' Communication with Cable Plugs): @@ -2757,10 +2799,7 @@ static void pe_snk_startup_entry(int port) PE_SET_FLAG(port, PE_FLAGS_DR_SWAP_TO_DFP); PE_SET_FLAG(port, PE_FLAGS_VCONN_SWAP_TO_ON); - /* - * Set up to get Device Policy Manager to - * request Sink Capabilities - */ + /* Opportunistically request sink caps for FRS evaluation. */ pd_dpm_request(port, DPM_REQUEST_GET_SNK_CAPS); } } @@ -3111,6 +3150,40 @@ static void pe_snk_ready_entry(int port) } /* + * If port partner sink capabilities are known (because we requested + * and got them earlier), evaluate them for FRS support and enable + * if appropriate. If not known, request that we get them through DPM + * which will eventually come back here with known capabilities. Don't + * do anything if FRS is already enabled. + */ + if (IS_ENABLED(CONFIG_USB_PD_FRS) && + !PE_CHK_FLAG(port, PE_FLAGS_FAST_ROLE_SWAP_ENABLED)) { + if (pd_get_snk_cap_cnt(port) > 0) { + /* + * Have partner sink caps. FRS support is only specified + * in fixed PDOs, and "the vSafe5V Fixed Supply Object + * Shall always be the first object" in a capabilities + * message so take the first one. + */ + const uint32_t *snk_caps = pd_get_snk_caps(port); + + pe_evaluate_frs_snk_pdo(port, snk_caps[0]); + } else { + /* + * Don't have caps; request them. A sink port "shall + * minimally offer one Power Data Object," so a + * compliant partner that supports sink operation will + * never fail to return sink capabilities in a way which + * would cause us to endlessly request them. Non-DRPs + * will never support FRS and may not support sink + * operation, so avoid requesting caps from them. + */ + if (pd_is_port_partner_dualrole(port)) + pd_dpm_request(port, DPM_REQUEST_GET_SNK_CAPS); + } + } + + /* * Wait and add jitter if we are operating in PD2.0 mode and no messages * have been sent since enter this state. */ @@ -6169,7 +6242,6 @@ static void pe_dr_get_sink_cap_run(int port) int type; int cnt; int ext; - int rev; enum pe_msg_check msg_check; enum tcpm_transmit_type sop; @@ -6179,8 +6251,6 @@ static void pe_dr_get_sink_cap_run(int port) msg_check = pe_sender_response_msg_run(port); /* - * Determine if FRS is possible based on the returned Sink Caps - * * Transition to PE_[SRC,SNK]_Ready when: * 1) A Sink_Capabilities Message is received * 2) Or SenderResponseTimer times out @@ -6196,7 +6266,6 @@ static void pe_dr_get_sink_cap_run(int port) type = PD_HEADER_TYPE(rx_emsg[port].header); cnt = PD_HEADER_CNT(rx_emsg[port].header); ext = PD_HEADER_EXT(rx_emsg[port].header); - rev = PD_HEADER_REV(rx_emsg[port].header); sop = PD_HEADER_GET_SOP(rx_emsg[port].header); if (ext == 0 && sop == TCPC_TX_SOP) { @@ -6207,33 +6276,6 @@ static void pe_dr_get_sink_cap_run(int port) sizeof(uint32_t); pe_set_snk_caps(port, cap_cnt, payload); - - /* - * Check message to see if we can handle - * FRS for this connection. Multiple PDOs - * may be returned, for FRS only Fixed PDOs - * shall be used, and this shall be the 1st - * PDO returned. - * - * TODO(b/14191267): Make sure we can handle - * the required current before we enable FRS. - */ - if (IS_ENABLED(CONFIG_USB_PD_REV30) && - (rev > PD_REV20) && - (payload[0] & PDO_FIXED_DUAL_ROLE)) { - switch (payload[0] & - PDO_FIXED_FRS_CURR_MASK) { - case PDO_FIXED_FRS_CURR_NOT_SUPPORTED: - break; - case PDO_FIXED_FRS_CURR_DFLT_USB_POWER: - case PDO_FIXED_FRS_CURR_1A5_AT_5V: - case PDO_FIXED_FRS_CURR_3A0_AT_5V: - typec_set_source_current_limit( - port, TYPEC_RP_3A0); - pe_set_frs_enable(port, 1); - break; - } - } pe_set_ready_state(port); return; } else if (cnt == 0 && (type == PD_CTRL_REJECT || |