diff options
-rw-r--r-- | common/usb_pd_policy.c | 87 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 72 | ||||
-rw-r--r-- | include/usb_pd.h | 28 |
3 files changed, 142 insertions, 45 deletions
diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c index 7ff9c3342d..93ce6fccb4 100644 --- a/common/usb_pd_policy.c +++ b/common/usb_pd_policy.c @@ -173,6 +173,12 @@ bool is_transmit_msg_sop_prime(int port) (cable[port].flags & CABLE_FLAGS_SOP_PRIME_ENABLE)); } +static bool is_transmit_msg_sop_prime_prime(int port) +{ + return (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP) && + (cable[port].flags & CABLE_FLAGS_SOP_PRIME_PRIME_ENABLE)); +} + int cable_consume_repeat_message(int port, uint8_t msg_id) { @@ -182,7 +188,6 @@ int cable_consume_repeat_message(int port, uint8_t msg_id) } CPRINTF("C%d Cable repeat msg_id %d\n", port, msg_id); return 1; - } static void disable_transmit_sop_prime(int port) @@ -191,9 +196,14 @@ static void disable_transmit_sop_prime(int port) cable[port].flags &= ~CABLE_FLAGS_SOP_PRIME_ENABLE; } -uint8_t is_sop_prime_ready(int port, - enum pd_data_role data_role, - uint32_t pd_flags) +static void disable_transmit_sop_prime_prime(int port) +{ + if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) + cable[port].flags &= ~CABLE_FLAGS_SOP_PRIME_PRIME_ENABLE; +} + +enum pd_msg_type pd_msg_tx_type(int port, enum pd_data_role data_role, + uint32_t pd_flags) { /* * Ref: USB PD 3.0 sec 2.5.4: When an Explicit Contract is in place the @@ -208,17 +218,27 @@ uint8_t is_sop_prime_ready(int port, */ if (pd_flags & PD_FLAGS_VCONN_ON && (IS_ENABLED(CONFIG_USB_PD_REV30) || data_role == PD_ROLE_DFP)) { - return is_transmit_msg_sop_prime(port); + if (is_transmit_msg_sop_prime(port)) + return PD_MSG_SOP_PRIME; + if (is_transmit_msg_sop_prime_prime(port)) + return PD_MSG_SOP_PRIME_PRIME; } + if (is_transmit_msg_sop_prime(port)) { /* * Clear the CABLE_FLAGS_SOP_PRIME_ENABLE flag if the port is * unable to communicate with the cable plug. */ disable_transmit_sop_prime(port); + } else if (is_transmit_msg_sop_prime_prime(port)) { + /* + * Clear the CABLE_FLAGS_SOP_PRIME_PRIME_ENABLE flag if the port + * is unable to communicate with the cable plug. + */ + disable_transmit_sop_prime_prime(port); } - return 0; + return PD_MSG_SOP; } void reset_pd_cable(int port) @@ -368,6 +388,12 @@ static void enable_transmit_sop_prime(int port) cable[port].flags |= CABLE_FLAGS_SOP_PRIME_ENABLE; } +static void enable_transmit_sop_prime_prime(int port) +{ + if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) + cable[port].flags |= CABLE_FLAGS_SOP_PRIME_PRIME_ENABLE; +} + static bool is_tbt_compat_enabled(int port) { return (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) && @@ -850,7 +876,8 @@ static int enter_tbt_compat_mode(int port, uint32_t *payload) VDO_SVDM_VERS(VDM_VER20); /* For TBT3 Cable Enter Mode Command, number of Objects is 1 */ - if (is_transmit_msg_sop_prime(port)) + if (is_transmit_msg_sop_prime(port) || + is_transmit_msg_sop_prime_prime(port)) return 1; usb_mux_set_safe_mode(port); @@ -1195,6 +1222,36 @@ static int process_tbt_compat_discover_modes(int port, uint32_t *payload) return rsize; } + +/* + * This function returns number of objects required to enter + * Thunderbolt-Compatible mode i.e. + * 2 - When SOP is enabled. + * 1 - When SOP' or SOP'' is enabled. + * 0 - Acknowledge. + */ +static int enter_mode_tbt_compat(int port, uint32_t *payload) +{ + /* Enter mode SOP' for active cables */ + if (is_transmit_msg_sop_prime(port)) { + disable_transmit_sop_prime(port); + /* Check if the cable has a SOP'' controller */ + if (cable[port].attr.a_rev20.sop_p_p) + enable_transmit_sop_prime_prime(port); + return enter_tbt_compat_mode(port, payload); + } + + /* Enter Mode SOP'' for active cables with SOP'' controller */ + if (is_transmit_msg_sop_prime_prime(port)) { + disable_transmit_sop_prime_prime(port); + return enter_tbt_compat_mode(port, payload); + } + + /* Update Mux state to Thunderbolt-compatible mode. */ + set_tbt_compat_mode_ready(port); + /* No response once device (and cable) acks */ + return 0; +} #endif /* CONFIG_USB_PD_ALT_MODE_DFP */ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload, @@ -1270,7 +1327,7 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload, switch (cmd) { #ifdef CONFIG_USB_PD_ALT_MODE_DFP case CMD_DISCOVER_IDENT: - /* Received a SOP Prime Discover Ident msg */ + /* Received a SOP' Discover Ident msg */ if (is_transmit_msg_sop_prime(port)) { /* Store cable type */ dfp_consume_cable_response(port, cnt, payload, @@ -1406,20 +1463,8 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload, } break; case CMD_ENTER_MODE: - /* No response once device (and cable) acks */ if (is_tbt_compat_enabled(port)) { - if (is_transmit_msg_sop_prime(port)) { - disable_transmit_sop_prime(port); - rsize = enter_tbt_compat_mode(port, - payload); - } else { - /* - * Update Mux state to - * Thunderbolt-compatible mode. - */ - set_tbt_compat_mode_ready(port); - rsize = 0; - } + rsize = enter_mode_tbt_compat(port, payload); /* * Continue with PD flow if Thunderbolt-compatible mode * is disabled. diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 18a6afdfbb..ea18fd05d4 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -2210,10 +2210,43 @@ static uint64_t vdm_get_ready_timeout(uint32_t vdm_hdr) return timeout; } +static void exit_tbt_mode_sop_prime(int port) +{ + /* Exit Thunderbolt-Compatible mode SOP' */ + uint16_t header; + int opos; + + if (!IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE)) + return; + + opos = pd_alt_mode(port, USB_VID_INTEL); + if (opos <= 0) + return; + + CPRINTS("C%d Cable exiting TBT Compat mode", port); + if (!pd_dfp_exit_mode(port, USB_VID_INTEL, opos)) + return; + + header = PD_HEADER(PD_DATA_VENDOR_DEF, pd[port].power_role, + pd[port].data_role, pd[port].msg_id, + (int)pd[port].vdo_count, pd_get_rev(port), 0); + + pd[port].vdo_data[0] = VDO(USB_VID_INTEL, 1, + CMD_EXIT_MODE | VDO_OPOS(opos)); + + pd_transmit(port, TCPC_TX_SOP_PRIME, header, pd[port].vdo_data, + AMS_START); + + usb_mux_set(port, USB_PD_MUX_USB_ENABLED, USB_SWITCH_CONNECT, + pd_get_polarity(port)); +} + static void pd_vdm_send_state_machine(int port) { int res; uint16_t header; + enum pd_msg_type msg_type = + pd_msg_tx_type(port, pd[port].data_role, pd[port].flags); switch (pd[port].vdm_state) { case VDM_STATE_READY: @@ -2241,8 +2274,8 @@ static void pd_vdm_send_state_machine(int port) * data role swap takes place during source and sink * negotiation and in case of failure, a soft reset is issued. */ - if (is_sop_prime_ready(port, pd[port].data_role, - pd[port].flags)) { + if ((msg_type == PD_MSG_SOP_PRIME) || + (msg_type == PD_MSG_SOP_PRIME_PRIME)) { /* Prepare SOP'/SOP'' header and send VDM */ header = PD_HEADER( PD_DATA_VENDOR_DEF, @@ -2252,13 +2285,26 @@ static void pd_vdm_send_state_machine(int port) (int)pd[port].vdo_count, pd_get_rev(port), 0); - res = pd_transmit(port, TCPC_TX_SOP_PRIME, header, - pd[port].vdo_data, AMS_START); + res = pd_transmit(port, + (msg_type == PD_MSG_SOP_PRIME) ? + TCPC_TX_SOP_PRIME : + TCPC_TX_SOP_PRIME_PRIME, + header, + pd[port].vdo_data, + AMS_START); /* - * If there is no ack from the cable, its a non-emark - * cable and since, the pd flow should continue - * irrespective of cable response, sending - * discover_identity so the pd flow remains intact. + * In the case of SOP', if there is no response from + * the cable, it's a non-emark cable and therefore the + * pd flow should continue irrespective of cable + * response, sending discover_identity so the pd flow + * remains intact. + * + * In the case of SOP'', if there is no response from + * the cable, exit Thunderbolt-Compatible mode + * discovery, reset the mux state since, the mux will + * be set to a safe state before entering + * Thunderbolt-Compatible mode and enter the default + * mode. */ if (res < 0) { header = PD_HEADER(PD_DATA_VENDOR_DEF, @@ -2267,8 +2313,14 @@ static void pd_vdm_send_state_machine(int port) pd[port].msg_id, (int)pd[port].vdo_count, pd_get_rev(port), 0); - pd[port].vdo_data[0] = - VDO(USB_SID_PD, 1, CMD_DISCOVER_SVID); + + if ((msg_type == PD_MSG_SOP_PRIME_PRIME) && + IS_ENABLED(CONFIG_USBC_SS_MUX)) { + exit_tbt_mode_sop_prime(port); + } else if (msg_type == PD_MSG_SOP_PRIME) { + pd[port].vdo_data[0] = VDO(USB_SID_PD, + 1, CMD_DISCOVER_SVID); + } res = pd_transmit(port, TCPC_TX_SOP, header, pd[port].vdo_data, AMS_START); reset_pd_cable(port); diff --git a/include/usb_pd.h b/include/usb_pd.h index 8ce6335b7d..812dc98e3d 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -1184,12 +1184,15 @@ enum cable_outlet { */ #define PD_HEADER_GET_SOP(header) (((header) >> 28) & 0xf) #define PD_HEADER_SOP(sop) ((sop) << 28) -#define PD_MSG_SOP 0 -#define PD_MSG_SOPP 1 -#define PD_MSG_SOPPP 2 -#define PD_MSG_SOP_DBGP 3 -#define PD_MSG_SOP_DBGPP 4 -#define PD_MSG_SOP_CBL_RST 5 + +enum pd_msg_type { + PD_MSG_SOP, + PD_MSG_SOP_PRIME, + PD_MSG_SOP_PRIME_PRIME, + PD_MSG_SOP_DBG_PRIME, + PD_MSG_SOP_DBG_PRIME_PRIME, + PD_MSG_SOP_CBL_RST, +}; /* Used for processing pd extended header */ #define PD_EXT_HEADER_CHUNKED(header) (((header) >> 15) & 1) @@ -1697,7 +1700,7 @@ struct svdm_amode_data *pd_get_amode_data(int port, uint16_t svid); int cable_consume_repeat_message(int port, uint8_t msg_id); /** - * Returns status of CABLE_FLAGS_SOP_PRIME_ENABLE flag + * Returns the status of cable flag - CABLE_FLAGS_SOP_PRIME_ENABLE * * @param port USB-C port number * @return Status of CABLE_FLAGS_SOP_PRIME_ENABLE flag @@ -1705,18 +1708,15 @@ int cable_consume_repeat_message(int port, uint8_t msg_id); bool is_transmit_msg_sop_prime(int port); /** - * Returns the status of cable flag - CABLE_FLAGS_SOP_PRIME_ENABLE + * Returns the type of communication (SOP/SOP'/SOP'') * * @param port USB-C port number * @param data_role current data role * @param pd_flags current pd flags - * @return For rev3.0, true if vconn is on - * For rev2.0, true if vconn is on and data_role is dfp - * False otherwise + * @return Type of message to be transmitted */ -uint8_t is_sop_prime_ready(int port, - enum pd_data_role data_role, - uint32_t pd_flags); +enum pd_msg_type pd_msg_tx_type(int port, enum pd_data_role data_role, + uint32_t pd_flags); /** * Reset Cable type, Cable attributes and cable flags |