From 0d7346d351d64724ab475ac3769829ed2ec9a7a2 Mon Sep 17 00:00:00 2001 From: Ayushee Date: Fri, 21 Jun 2019 02:42:32 -0700 Subject: TCPMv1: Add support for Thunderbolt-compatible mode Thunderbolt is a hardware interface that allows connection of external peripherals to a computer. This code enables thunderbolt 3 over Type-C interface. Thunderbolt provides concurrent support for PCIe transactions and DisplayPort and the thunderbolt controller provides isochronous communication on a single network style interface, allowing a Host computer to communicate at high bandwidth with multiple data/display devices through a single physical connection. The USB Type-C specification allows for Alternate Modes to be supported on the connector and cables. This CL adds a Discovery flow to determine if an Thunderbolt Alternate Mode is supported and a mechanism for switching in thunderbolt mode. TBT USB PD flow: -------------------Explicit contact--------------------- Discover Identity(SOP) ---- Modal operation supported? | ---------- ACK -----|---- NACK --- Disable TBT | Discover Identity(SOP') --- Check and store response (CL:1707851 and CL:1553898) | Is cable super speed? -------- Yes -------|----- No ---- Disable TBT | Discover SVID (SOP) -------- SVID == 0x8087? | ------------- Yes -----|------ No ---- Disable TBT | Discover SVID (SOP') -------- SVID == 0x8087? | ----------- yes------- | - No - Limit TBT to passive Gen 2 | Discover Mode (SOP) ------ Store device response ---------------| | Discover Mode (SOP') ----- Store cable response | Enter Safe mode | Active cable? --------- Yes -----|-------- No --------- | | Enter TBT mode (SOP' SOP" SOP) Enter TBT mode SOP (Note: This is not implemented in this CL) BUG=b:140643923 BRANCH=none TEST=Tested on Tglrvp-u able to enter into Thunderbolt-compatible mode & Non Thunderbolt-compatible devices are detected as per their spec. Change-Id: I65ed86e9f32d36fe8e30c3285f516b9871f3e119 Signed-off-by: Ayushee Signed-off-by: Vijay Hiremath Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1926379 Reviewed-by: Diana Z Commit-Queue: Keith Short --- common/usb_common.c | 46 +++++++++- common/usb_pd_policy.c | 231 +++++++++++++++++++++++++++++++++++++++++++++-- common/usb_pd_protocol.c | 11 ++- driver/usb_mux/usb_mux.c | 5 +- driver/usb_mux/virtual.c | 2 +- include/config.h | 7 ++ include/ec_commands.h | 13 +-- include/usb_mux.h | 9 +- include/usb_pd.h | 182 ++++++++++++++++++++++++++++++++++++- util/ectool.c | 1 + 10 files changed, 483 insertions(+), 24 deletions(-) diff --git a/common/usb_common.c b/common/usb_common.c index dc7a40a08e..760ffc2063 100644 --- a/common/usb_common.c +++ b/common/usb_common.c @@ -936,6 +936,40 @@ __overridable int svdm_gfu_attention(int port, uint32_t *payload) return 0; } +#ifdef CONFIG_USB_PD_TBT_COMPAT_MODE +__overridable int svdm_tbt_compat_enter_mode(int port, uint32_t mode_caps) +{ + /* + * Before entering into alternate mode, state of the USB-C MUX needs to + * be in safe mode Ref: USB Type-C Cable and Connector Specification + * Section E.2.2 Alternate Mode Electrical Requirements + */ + usb_mux_set(port, IS_ENABLED(CONFIG_USB_MUX_VIRTUAL) ? + TYPEC_MUX_SAFE : TYPEC_MUX_NONE, USB_SWITCH_CONNECT, + pd_get_polarity(port)); + return 0; +} + +__overridable void svdm_tbt_compat_exit_mode(int port) +{ +} + +__overridable int svdm_tbt_compat_status(int port, uint32_t *payload) +{ + return 0; +} + +__overridable int svdm_tbt_compat_config(int port, uint32_t *payload) +{ + return 0; +} + +__overridable int svdm_tbt_compat_attention(int port, uint32_t *payload) +{ + return 0; +} +#endif /* CONFIG_USB_PD_TBT_COMPAT_MODE */ + const struct svdm_amode_fx supported_modes[] = { { .svid = USB_SID_DISPLAYPORT, @@ -954,7 +988,17 @@ const struct svdm_amode_fx supported_modes[] = { .config = &svdm_gfu_config, .attention = &svdm_gfu_attention, .exit = &svdm_exit_gfu_mode, - } + }, +#ifdef CONFIG_USB_PD_TBT_COMPAT_MODE + { + .svid = USB_VID_INTEL, + .enter = &svdm_tbt_compat_enter_mode, + .status = &svdm_tbt_compat_status, + .config = &svdm_tbt_compat_config, + .attention = &svdm_tbt_compat_attention, + .exit = &svdm_tbt_compat_exit_mode, + }, +#endif /* CONFIG_USB_PD_TBT_COMPAT_MODE */ }; const int supported_modes_cnt = ARRAY_SIZE(supported_modes); #endif /* CONFIG_USB_PD_ALT_MODE_DFP */ diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c index f31f859641..c648016a83 100644 --- a/common/usb_pd_policy.c +++ b/common/usb_pd_policy.c @@ -166,12 +166,10 @@ int pd_charge_from_device(uint16_t vid, uint16_t pid) static struct pd_cable cable[CONFIG_USB_PD_PORT_MAX_COUNT]; -static uint8_t is_transmit_msg_sop_prime(int port) +static bool is_transmit_msg_sop_prime(int port) { - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - return !!(cable[port].flags & CABLE_FLAGS_SOP_PRIME_ENABLE); - - return 0; + return (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP) && + (cable[port].flags & CABLE_FLAGS_SOP_PRIME_ENABLE)); } uint8_t is_sop_prime_ready(int port, uint8_t data_role, uint32_t pd_flags) @@ -218,12 +216,119 @@ static int is_vdo_present(int cnt, int index) static void enable_transmit_sop_prime(int port) { - cable[port].flags |= CABLE_FLAGS_SOP_PRIME_ENABLE; + if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) + cable[port].flags |= CABLE_FLAGS_SOP_PRIME_ENABLE; } static void disable_transmit_sop_prime(int port) { - cable[port].flags &= ~CABLE_FLAGS_SOP_PRIME_ENABLE; + if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) + cable[port].flags &= ~CABLE_FLAGS_SOP_PRIME_ENABLE; +} + +static bool is_tbt_compat_enabled(int port) +{ + return (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) && + (cable[port].flags & CABLE_FLAGS_TBT_COMPAT_ENABLE)); +} + +static void enable_tbt_compat_mode(int port) +{ + if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE)) + cable[port].flags |= CABLE_FLAGS_TBT_COMPAT_ENABLE; +} + +static inline void disable_tbt_compat_mode(int port) +{ + if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE)) + cable[port].flags &= ~CABLE_FLAGS_TBT_COMPAT_ENABLE; +} + +/* + * TODO (b/146006708): Make the below three functions independent of + * Thunderbolt-compatible mode enabled as these USB PD 3.0 VDO responses + * can be used to identify other cable attributes like cable speed. + */ +static bool is_cable_superspeed(int port) +{ + if (is_tbt_compat_enabled(port) && + IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { + /* + * Bit 4 gives if USB SS is supported for active cables + * for Rev 3.0 + * Ref: PD Spec 3.0 Active Cable VDO 2 + */ + if (IS_ENABLED(CONFIG_USB_PD_REV30) && + (cable[port].type == IDH_PTYPE_ACABLE)) + return !!cable[port].attr2.a2_rev30.usb_ss_support; + + /* + * Bits 2:0 gives USB SS support for passive cable + * for both Rev2.0 and Rev3.0 + * Ref: PD Spec 3.0 Passive cable VDO and + * Spec 2.0 Passive cable VDO + * + * For rev2.0 active cable, bits 2:0 give USB SS support + * (Ref: spec 2.0 Passive cable VDO) + */ + return !!(cable[port].attr.rev20.ss & USB_SS_U31_GEN2); + } + return false; +} + +/* Check if product supports any Modal Operation (Alternate Modes) */ +static bool is_modal(int port, int cnt, uint32_t *payload) +{ + return (is_tbt_compat_enabled(port) && + is_vdo_present(cnt, VDO_INDEX_IDH) && + PD_IDH_IS_MODAL(payload[VDO_INDEX_IDH])); +} + +static bool is_intel_svid(int port, uint32_t *payload) +{ + /* + * Check if SVID0 = USB_VID_INTEL + * (Ref: USB Type-C cable and connector specification, Table F-9) + * + * TODO (b/146081601): For the Discover SVIDs, responder may present + * the SVIDs in any order in the VDOs. Modify the code to check + * Intel SVID in all the VDOs. + */ + if (is_tbt_compat_enabled(port)) { + /* + * errata: All the Thunderbolt certified cables and docks + * tested have SVID1 = 0x8087 + */ + if (is_transmit_msg_sop_prime(port)) + return PD_VDO_SVID_SVID1(payload[VDO_INDEX_IDH]) == + USB_VID_INTEL; + + return PD_VDO_SVID_SVID0(payload[VDO_INDEX_IDH]) == + USB_VID_INTEL; + } + return false; +} + +static inline bool is_tbt_compat_mode(int port, int cnt, uint32_t *payload) +{ + /* + * Ref: USB Type-C cable and connector specification + * F.2.5 TBT3 Device Discover Mode Responses + */ + + return is_tbt_compat_enabled(port) && + is_vdo_present(cnt, VDO_INDEX_IDH) && + PD_VDO_RESP_MODE_INTEL_TBT(payload[VDO_INDEX_IDH]); +} + +static inline void limit_cable_speed(int port) +{ + cable[port].flags |= CABLE_FLAGS_TBT_COMPAT_LIMIT_SPEED; +} + +static inline bool is_limit_cable_speed(int port) +{ + return !!(cable[port].flags & CABLE_FLAGS_TBT_COMPAT_LIMIT_SPEED); } void pd_dfp_pe_init(int port) @@ -238,6 +343,12 @@ static void dfp_consume_identity(int port, int cnt, uint32_t *payload) (cnt - 1) * sizeof(uint32_t)); pd_dfp_pe_init(port); memcpy(&pe[port].identity, payload + 1, identity_size); + /* + * Enable Thunderbolt-compatible mode to further check if the + * cable and the port partner support Thunderbolt-compatible mode. + */ + enable_tbt_compat_mode(port); + switch (ptype) { case IDH_PTYPE_AMA: /* Leave vbus ON if the following macro is false */ @@ -444,6 +555,18 @@ uint32_t pd_dfp_enter_mode(int port, uint16_t svid, int opos) return VDO(modep->fx->svid, 1, CMD_ENTER_MODE | VDO_OPOS(modep->opos)); } +static int enter_tbt_compat_mode(int port, uint32_t *payload) +{ + /* If Passive cable Enter mode SOP */ + if (get_usb_pd_mux_cable_type(port) == IDH_PTYPE_PCABLE) + disable_transmit_sop_prime(port); + + /* Enter Thunderbolt-compatible mode */ + payload[0] = pd_dfp_enter_mode(port, USB_VID_INTEL, 1); + + return !!payload[0]; +} + static int validate_mode_request(struct svdm_amode_data *modep, uint16_t svid, int opos) { @@ -642,6 +765,40 @@ DECLARE_CONSOLE_COMMAND(pe, command_pe, "USB PE"); #endif /* CONFIG_CMD_USB_PD_PE */ +static int process_tbt_compat_discover_modes(int port, uint32_t *payload) +{ + int rsize; + + /* + * For active cables, Enter mode: SOP', SOP'', SOP + * Ref: USB Type-C Cable and Connector Specification, figure F-1: TBT3 + * Discovery Flow and Section F.2.7 TBT3 Cable Enter Mode Command. + */ + /* + * TODO: Support for entering Thunderbolt-compatible mode for + * active cables. + */ + if (is_transmit_msg_sop_prime(port)) { + /* Store Discover Mode SOP' response */ + cable[port].cable_mode_resp.raw_value = payload[1]; + if (is_limit_cable_speed(port)) + cable[port].cable_mode_resp.tbt_cable_speed = + USB3_GEN1_USB4_GEN2; + + rsize = enter_tbt_compat_mode(port, payload); + disable_transmit_sop_prime(port); + } else { + /* Store Discover Mode SOP response */ + cable[port].dev_mode_resp.raw_value = payload[1]; + + /* Discover modes for SOP' */ + pe[port].svid_idx--; + rsize = dfp_discover_modes(port, payload); + enable_transmit_sop_prime(port); + } + + return rsize; +} #endif /* CONFIG_USB_PD_ALT_MODE_DFP */ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) @@ -720,6 +877,13 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) if (is_transmit_msg_sop_prime(port)) { /* Store cable type */ dfp_consume_cable_response(port, cnt, payload); + /* + * Disable Thunderbolt-compatible mode if cable + * doesn't support superspeed + */ + if (!is_cable_superspeed(port)) + disable_tbt_compat_mode(port); + disable_transmit_sop_prime(port); rsize = dfp_discover_svids(payload); /* Received a SOP Discover Ident Message */ @@ -729,6 +893,13 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) if (!cable[port].is_identified) { rsize = dfp_discover_ident(payload); enable_transmit_sop_prime(port); + /* + * Disable Thunderbolt-compatible mode + * if modal op not supported + */ + } else if (!is_modal(port, cnt, payload)) { + disable_tbt_compat_mode(port); + rsize = dfp_discover_svids(payload); } } else { dfp_consume_identity(port, cnt, payload); @@ -743,10 +914,42 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) break; case CMD_DISCOVER_SVID: dfp_consume_svids(port, cnt, payload); + /* + * Check if 0x8087 is received for Discover SVID SOP. + * If not, disable Thunderbolt-compatible mode + * Ref: USB Type-C Cable and Connector Specification, + * figure F-1: TBT3 Discovery Flow + */ + if (is_intel_svid(port, payload)) { + if (!is_transmit_msg_sop_prime(port)) { + rsize = dfp_discover_svids(payload); + enable_transmit_sop_prime(port); + break; + } + /* + * If 0x8087 is not received for Discover SVID SOP' + * limit to TBT passive Gen 2 cable + * Ref: USB Type-C Cable and Connector Specification, + * figure F-1: TBT3 Discovery Flow + */ + } else if (is_tbt_compat_enabled(port) && + is_transmit_msg_sop_prime(port)) { + limit_cable_speed(port); + } else { + disable_tbt_compat_mode(port); + } + rsize = dfp_discover_modes(port, payload); + disable_transmit_sop_prime(port); break; case CMD_DISCOVER_MODES: dfp_consume_modes(port, cnt, payload); + if (is_tbt_compat_mode(port, cnt, payload)) { + rsize = process_tbt_compat_discover_modes( + port, payload); + break; + } + rsize = dfp_discover_modes(port, payload); /* enter the default mode for DFP */ if (!rsize) { @@ -756,7 +959,19 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) } break; case CMD_ENTER_MODE: - if (!modep) { + /* No response once device (and cable) acks */ + if (is_tbt_compat_enabled(port)) { + /* + * Update Mux state to Thunderbolt-compatible + * mode. + */ + set_tbt_compat_mode_ready(port); + rsize = 0; + /* + * Continue with PD flow if Thunderbolt-compatible mode + * is disabled. + */ + } else if (!modep) { rsize = 0; } else { if (!modep->opos) diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 5e7e181141..3c2b36d744 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -2240,7 +2240,7 @@ static void pd_vdm_send_state_machine(int port) * 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_svid so the pd flow remains intact. + * discover_identity so the pd flow remains intact. */ if (res < 0) { header = PD_HEADER(PD_DATA_VENDOR_DEF, @@ -2812,6 +2812,15 @@ void pd_interrupt_handler_task(void *p) } #endif /* HAS_TASK_PD_INT_C0 || HAS_TASK_PD_INT_C1 || HAS_TASK_PD_INT_C2 */ +void set_tbt_compat_mode_ready(int port) +{ + if (IS_ENABLED(CONFIG_USBC_SS_MUX) && + IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE)) + /* Set usb mux to Thunderbolt-compatible mode */ + usb_mux_set(port, TYPEC_MUX_TBT_COMPAT, USB_SWITCH_CONNECT, + pd[port].polarity); +} + void pd_task(void *u) { int head; diff --git a/driver/usb_mux/usb_mux.c b/driver/usb_mux/usb_mux.c index 93c741c1e9..7fc4934001 100644 --- a/driver/usb_mux/usb_mux.c +++ b/driver/usb_mux/usb_mux.c @@ -238,14 +238,15 @@ static int command_typec(int argc, char **argv) mux_state = usb_mux_get(port); ccprintf("Port %d: USB=%d DP=%d POLARITY=%s HPD_IRQ=%d " - "HPD_LVL=%d SAFE=%d\n", port, + "HPD_LVL=%d SAFE=%d TBT=%d\n", port, !!(mux_state & USB_PD_MUX_USB_ENABLED), !!(mux_state & USB_PD_MUX_DP_ENABLED), mux_state & USB_PD_MUX_POLARITY_INVERTED ? "INVERTED" : "NORMAL", !!(mux_state & USB_PD_MUX_HPD_IRQ), !!(mux_state & USB_PD_MUX_HPD_LVL), - !!(mux_state & USB_PD_MUX_SAFE_MODE)); + !!(mux_state & USB_PD_MUX_SAFE_MODE), + !!(mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED)); return EC_SUCCESS; } diff --git a/driver/usb_mux/virtual.c b/driver/usb_mux/virtual.c index a6e8377ce8..cef3e89ca2 100644 --- a/driver/usb_mux/virtual.c +++ b/driver/usb_mux/virtual.c @@ -19,7 +19,7 @@ #define USB_PD_MUX_HPD_STATE (USB_PD_MUX_HPD_LVL | USB_PD_MUX_HPD_IRQ) #define USB_PD_MUX_USB_DP_STATE (USB_PD_MUX_USB_ENABLED | \ USB_PD_MUX_DP_ENABLED | USB_PD_MUX_POLARITY_INVERTED | \ - USB_PD_MUX_SAFE_MODE) + USB_PD_MUX_SAFE_MODE | USB_PD_MUX_TBT_COMPAT_ENABLED) static mux_state_t virtual_mux_state[CONFIG_USB_PD_PORT_MAX_COUNT]; diff --git a/include/config.h b/include/config.h index cb70f896b9..a8e70d0ccf 100644 --- a/include/config.h +++ b/include/config.h @@ -3835,6 +3835,13 @@ /* Enable the encoding of msg SOP* in bits 31-28 of 32-bit msg header type */ #undef CONFIG_USB_PD_DECODE_SOP +/* + * The USB4 specification defines compatibility support for USB4 products to + * interact with existing Thunderbolt 3 products. Enable this config to enter + * into Thunderbolt-compatible mode between two port partners. + */ +#undef CONFIG_USB_PD_TBT_COMPAT_MODE + /* * Track VBUS level in TCPC module. This will only be needed if we're acting * as an external TCPC. diff --git a/include/ec_commands.h b/include/ec_commands.h index dcb4d3f68e..331223b7df 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -5467,12 +5467,13 @@ struct ec_params_usb_pd_mux_info { } __ec_align1; /* Flags representing mux state */ -#define USB_PD_MUX_USB_ENABLED BIT(0) /* USB connected */ -#define USB_PD_MUX_DP_ENABLED BIT(1) /* DP connected */ -#define USB_PD_MUX_POLARITY_INVERTED BIT(2) /* CC line Polarity inverted */ -#define USB_PD_MUX_HPD_IRQ BIT(3) /* HPD IRQ is asserted */ -#define USB_PD_MUX_HPD_LVL BIT(4) /* HPD level is asserted */ -#define USB_PD_MUX_SAFE_MODE BIT(5) /* DP is in safe mode */ +#define USB_PD_MUX_USB_ENABLED BIT(0) /* USB connected */ +#define USB_PD_MUX_DP_ENABLED BIT(1) /* DP connected */ +#define USB_PD_MUX_POLARITY_INVERTED BIT(2) /* CC line Polarity inverted */ +#define USB_PD_MUX_HPD_IRQ BIT(3) /* HPD IRQ is asserted */ +#define USB_PD_MUX_HPD_LVL BIT(4) /* HPD level is asserted */ +#define USB_PD_MUX_SAFE_MODE BIT(5) /* DP is in safe mode */ +#define USB_PD_MUX_TBT_COMPAT_ENABLED BIT(6) /* TBT compat enabled */ struct ec_response_usb_pd_mux_info { uint8_t flags; /* USB_PD_MUX_*-encoded USB mux state */ diff --git a/include/usb_mux.h b/include/usb_mux.h index 2b2d091470..d4e19e579d 100644 --- a/include/usb_mux.h +++ b/include/usb_mux.h @@ -29,8 +29,11 @@ typedef uint8_t mux_state_t; #define MUX_PORT(port) (usb_muxes[port].port_addr >> 8) #define MUX_ADDR(port) (usb_muxes[port].port_addr & 0xFF) -/* Mux state attributes */ -/* TODO: Directly use USB_PD_MUX_* everywhere and remove these 3 defines */ +/* + * Mux state attributes + * TODO (b:145796172): Directly use USB_PD_MUX_* everywhere, + * remove the below defines and enum typec_mux. + */ #define MUX_USB_ENABLED USB_PD_MUX_USB_ENABLED #define MUX_DP_ENABLED USB_PD_MUX_DP_ENABLED #define MUX_POLARITY_INVERTED USB_PD_MUX_POLARITY_INVERTED @@ -44,6 +47,8 @@ enum typec_mux { TYPEC_MUX_DOCK = MUX_USB_ENABLED | /* Both USB and DP */ MUX_DP_ENABLED, TYPEC_MUX_SAFE = MUX_SAFE_MODE, /* Safe mode */ + /* Thunderbolt-compatible only */ + TYPEC_MUX_TBT_COMPAT = USB_PD_MUX_TBT_COMPAT_ENABLED, }; /* Mux driver function pointers */ diff --git a/include/usb_pd.h b/include/usb_pd.h index 08858f7935..eb58b9c58e 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -8,6 +8,7 @@ #ifndef __CROS_EC_USB_PD_H #define __CROS_EC_USB_PD_H +#include #include "common.h" #include "usb_pd_tcpm.h" @@ -307,6 +308,7 @@ enum hpd_event { enum pd_alternate_modes { PD_AMODE_GOOGLE, PD_AMODE_DISPLAYPORT, + PD_AMODE_INTEL, /* not a real mode */ PD_AMODE_COUNT, }; @@ -455,8 +457,9 @@ enum idh_ptype { ((usbh) << 31 | (usbd) << 30 | ((ptype) & 0x7) << 27 \ | (is_modal) << 26 | ((vid) & 0xffff)) -#define PD_IDH_PTYPE(vdo) (((vdo) >> 27) & 0x7) -#define PD_IDH_VID(vdo) ((vdo) & 0xffff) +#define PD_IDH_PTYPE(vdo) (((vdo) >> 27) & 0x7) +#define PD_IDH_IS_MODAL(vdo) (((vdo) >> 26) & 0x1) +#define PD_IDH_VID(vdo) ((vdo) & 0xffff) /* * Cert Stat VDO @@ -716,6 +719,114 @@ struct active_cable_vdo2 { }; }; +/* + * Thunderbolt 3 Device Discover mode responses + * (Reference: USB Type-C cable and connector specification, Table F-13) + * ------------------------------------------------------------- + * <31> : Intel Control Vendor Specific B1 Support (0b == No, 1b == Yes) + * <30> : Intel Control Vendor Specific B0 Support (0b == No, 1b == Yes) + * <29:27> : Reserved + * <26> : Intel Specific B0 Support (0b == No, 1b == Yes) + * <25:17> : Reserved + * <16> : TBT Adapter (0b == TBT2 Legacy, 1b == TBT3) + * <15:0> : TBT Alternate Mode + */ +enum tbt_adapter_type { + TBT_ADAPTER_LEGACY, + TBT_ADAPTER_TBT3, +}; + +enum tbt_intel_b0_type { + TBT_INTEL_B0_NOT_SUPPORTED, + TBT_INTEL_B0_SUPPORTED, +}; + +enum tbt_vendor_b0_type { + TBT_VENDOR_B0_NOT_SUPPORTED, + TBT_VENDOR_B0_SUPPORTED, +}; + +enum tbt_vendor_b1_type { + TBT_VENDOR_B1_NOT_SUPPORTED, + TBT_VENDOR_B1_SUPPORTED, +}; + +/* TBT Alternate Mode */ +#define PD_VDO_RESP_MODE_INTEL_TBT(x) (((x) & 0xff) == 0x0001) + +struct tbt_mode_resp_device { + union { + struct { + uint16_t tbt_alt_mode : 16; + enum tbt_adapter_type tbt_adapter : 1; + uint16_t reserved0 : 9; + enum tbt_intel_b0_type intel_spec_b0 : 1; + uint8_t reserved1 : 3; + enum tbt_vendor_b0_type vendor_spec_b0 : 1; + enum tbt_vendor_b1_type vendor_spec_b1 : 1; + }; + uint32_t raw_value; + }; +}; + +/* + * Thunderbolt 3 cable Discover mode responses + * (Reference: USB Type-C cable and connector specification, Table F-14) + * ------------------------------------------------------------- + * <31:24> : Reserved + * <23> : Active cable plug link training + * (0b == bi-directional, 1b == uni-directional) + * <22> : Re-timer (0b == Not retimer, 1b == Retimer) + * <21> : Cable type (0b == Non-optical, 1b == Optical) + * <20:19> : TBT Rounded Support (00b == 3rd Gen Non-Rounded TBT, + * 01b == 3rd & 4th Gen Rounded and Non-Rounded TBT, + * 10b...11b == Reserved) + * <18:16> : Cable Speed (001b = USB3.2 Gen 1, + * 010b = USB3.2 Gen 1 and USB4 Gen 2 + * 011b = USB4 Gen 3) + * <15:0> : TBT alternate mode + */ +enum tbt_compat_cable_speed { + USB3_GEN1 = 1, + USB3_GEN1_USB4_GEN2, + USB4_GEN3, +}; + +enum tbt_cable_type { + TBT_CABLE_ELECTRICAL, + TBT_CABLE_OPTICAL, +}; + +enum link_lsrx_comm { + BIDIR_LSRX_COMM, + UNIDIR_LSRX_COMM, +}; + +enum tbt_compat_rounded_support { + TBT_GEN3_NON_ROUNDED, + TBT_GEN3_GEN4_ROUNDED_NON_ROUNDED, +}; + +enum usb_retimer_type { + USB_REDRIVER, + USB_RETIMER, +}; + +struct tbt_mode_resp_cable { + union { + struct { + uint16_t tbt_alt_mode : 16; + enum tbt_compat_cable_speed tbt_cable_speed : 3; + enum tbt_compat_rounded_support tbt_rounded : 2; + enum tbt_cable_type tbt_cable : 1; + enum usb_retimer_type retimer_type : 1; + enum link_lsrx_comm lsrx_comm : 1; + uint8_t reserved0 : 8; + }; + uint32_t raw_value; + }; +}; + /* Cable structure for storing cable attributes */ struct pd_cable { uint8_t is_identified; @@ -729,10 +840,22 @@ struct pd_cable { uint8_t rev; /* For USB PD REV3, active cable has 2 VDOs */ struct active_cable_vdo2 attr2; + /* For storing Discover mode response from device */ + struct tbt_mode_resp_device dev_mode_resp; + /* For storing Discover mode response from cable */ + struct tbt_mode_resp_cable cable_mode_resp; }; /* Flag for sending SOP Prime packet */ -#define CABLE_FLAGS_SOP_PRIME_ENABLE BIT(0) +#define CABLE_FLAGS_SOP_PRIME_ENABLE BIT(0) +/* Flag for sending SOP Prime Prime packet */ +#define CABLE_FLAGS_SOP_PRIME_PRIME_ENABLE BIT(1) +/* Check if Thunderbolt-compatible mode enabled */ +#define CABLE_FLAGS_TBT_COMPAT_ENABLE BIT(2) +/* Check if Thunderbolt-compatible mode is ready */ +#define CABLE_FLAGS_TBT_COMPAT_READY BIT(3) +/* Flag to limit speed to TBT Gen 2 passive cable */ +#define CABLE_FLAGS_TBT_COMPAT_LIMIT_SPEED BIT(4) /* * AMA VDO @@ -987,6 +1110,7 @@ struct pd_cable { #define USB_VID_APPLE 0x05ac #define USB_PID1_APPLE 0x1012 #define USB_PID2_APPLE 0x1013 +#define USB_VID_INTEL 0x8087 /* Timeout for message receive in microseconds */ #define USB_PD_RX_TMOUT_US 1800 @@ -1814,6 +1938,13 @@ void reset_pd_cable(int port); */ enum idh_ptype get_usb_pd_mux_cable_type(int port); +/** + * Update Mux on entering Thunderbolt-compatible mode + * + * @param port USB-C port number + */ +void set_tbt_compat_mode_ready(int port); + /** * Store Device ID & RW hash of device * @@ -2497,4 +2628,49 @@ __override_proto int svdm_gfu_config(int port, uint32_t *payload); * @return The number of VDOs */ __override_proto int svdm_gfu_attention(int port, uint32_t *payload); + +/* Thunderbolt-compatible Alternate Mode */ +/** + * Enter Thunderbolt-compatible Mode. + * + * @param port The PD port number + * @param mode_caps Unused + * @return 0 on success else -1 + */ +__override_proto int svdm_tbt_compat_enter_mode(int port, uint32_t mode_caps); + +/** + * Exit Thunderbolt-compatible Mode. + * + * @param port The PD port number + */ +__override_proto void svdm_tbt_compat_exit_mode(int port); + +/** + * Called to get Thunderbolt-compatible mode status + * + * @param port The PD port number + * @param payload Unused + * @return 0 on success else -1 + */ +__override_proto int svdm_tbt_compat_status(int port, uint32_t *payload); + +/** + * Called to configure Thunderbolt-compatible mode + * + * @param port The PD port number + * @param payload Unused + * @return 0 on success else -1 + */ +__override_proto int svdm_tbt_compat_config(int port, uint32_t *payload); + +/** + * Called when Thunderbolt-compatible Attention Message is received + * + * @param port The PD port number + * @param payload Unusued + * @return 0 on success else -1 + */ +__override_proto int svdm_tbt_compat_attention(int port, uint32_t *payload); + #endif /* __CROS_EC_USB_PD_H */ diff --git a/util/ectool.c b/util/ectool.c index 4f8d292e11..c95fcf606e 100644 --- a/util/ectool.c +++ b/util/ectool.c @@ -5693,6 +5693,7 @@ int cmd_usb_pd_mux_info(int argc, char *argv[]) printf("HPD_IRQ=%d ", !!(r.flags & USB_PD_MUX_HPD_IRQ)); printf("HPD_LVL=%d ", !!(r.flags & USB_PD_MUX_HPD_LVL)); printf("SAFE=%d ", !!(r.flags & USB_PD_MUX_SAFE_MODE)); + printf("TBT=%d ", !!(r.flags & USB_PD_MUX_TBT_COMPAT_ENABLED)); printf("\n"); } -- cgit v1.2.1