summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAyushee <ayushee.shah@intel.com>2019-06-21 02:42:32 -0700
committerCommit Bot <commit-bot@chromium.org>2019-12-17 21:06:36 +0000
commit0d7346d351d64724ab475ac3769829ed2ec9a7a2 (patch)
tree4ea8d416cc36e8ada03edbbdbb515d869bd846db
parente0d99a923236fb2f65fb8301e6ac631ba4d4267b (diff)
downloadchrome-ec-0d7346d351d64724ab475ac3769829ed2ec9a7a2.tar.gz
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 <ayushee.shah@intel.com> Signed-off-by: Vijay Hiremath <vijay.p.hiremath@intel.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1926379 Reviewed-by: Diana Z <dzigterman@chromium.org> Commit-Queue: Keith Short <keithshort@chromium.org>
-rw-r--r--common/usb_common.c46
-rw-r--r--common/usb_pd_policy.c231
-rw-r--r--common/usb_pd_protocol.c11
-rw-r--r--driver/usb_mux/usb_mux.c5
-rw-r--r--driver/usb_mux/virtual.c2
-rw-r--r--include/config.h7
-rw-r--r--include/ec_commands.h13
-rw-r--r--include/usb_mux.h9
-rw-r--r--include/usb_pd.h182
-rw-r--r--util/ectool.c1
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
@@ -3836,6 +3836,13 @@
#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 <stdbool.h>
#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
@@ -1815,6 +1939,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
*
* @param port USB-C port number
@@ -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");
}