summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Marheine <pmarheine@chromium.org>2020-11-30 15:36:48 +1100
committerCommit Bot <commit-bot@chromium.org>2020-12-08 01:07:38 +0000
commitde6407f867863eb2976194b3d55d0fe4d4e33a6f (patch)
treeed385ce397e608f5e2d9bd90dfe2db48f44ba860
parent527cde447564514e237da26396236a8134310809 (diff)
downloadchrome-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.c112
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 ||