summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorAyushee <ayushee.shah@intel.com>2020-09-24 15:40:07 -0700
committerCommit Bot <commit-bot@chromium.org>2020-11-05 04:11:47 +0000
commit1a265d194969d8778fdd759e1eed891f0638202b (patch)
tree9644b49b6c118bc0120c051530b16995d4bc5a78 /common
parente609f07eef8b851b19bf4b59b5263ac702d8b871 (diff)
downloadchrome-ec-1a265d194969d8778fdd759e1eed891f0638202b.tar.gz
TCPMv2: Add support for USB4 active cable
USB4 PD flow for active cables: Structured VDM version (cable revision)-- <2.0 -------->| | | >=2.0 | | | VDO version---- <1.3 -------> Modal op? -- N --| (B21:23 of | | Discover ID SOP'- y | Active cable VDO1) | | | TBT SVID? -- N --| >=1.3 | | | y | Cable USB4 support? - N | | | | Gen4 cable? - N - Skip USB4 mode entry y Skip USB4 | | mode entry | Enter USB4 y (SOP',SOP'',SOP) | | |<---- NAK ----- Enter mode TBT SOP'<---| | | | | ACK | | | | |<---- NAK ----- Enter mode TBT SOP'' | | | | Exit TBT mode SOP ACK | | | | ACK/NAK Enter USB4 mode | | SOP | Exit TBT mode SOP'' | | | ACK/NAK | | | Exit TBT mode SOP' | | | ACK/NAK | | | |--------Retry done? ---- N ------------| | y | Skip USB4 mode entry The CL also checks if the port is VCONN source before sending Enter USB SOP' and SOP'' messages and requests for a vconn swap is it isn't In case of reboot, the port sends exit Thunderbolt mode SOP' and SOP'' and skips sending exit Thunderbolt mode for SOP, since it didn't enter Thunderbolt mode SOP prior to reboot. Note: 1. This is only applicable when the port enters USB4 mode SOP and Thunderbolt mode with the cable plug. 2. It is a temporary behaviour until data reset feature is in place (b/141363146) BUG=b:156749387 BRANCH=None TEST=1.Able to enter into USB4 with active cable. 2.Able to exit Thunderbolt mode SOP' and SOP'' on reboot and re-enter into USB4 mode with active cable. Signed-off-by: Ayushee <ayushee.shah@intel.com> Change-Id: I828c7ca0fd9b7b1025f13bcc86c511692b9f9895 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2432868 Reviewed-by: Abe Levkoy <alevkoy@chromium.org>
Diffstat (limited to 'common')
-rw-r--r--common/usb_pd_alt_mode_dfp.c24
-rw-r--r--common/usb_pd_host_cmd.c4
-rw-r--r--common/usbc/tbt_alt_mode.c28
-rw-r--r--common/usbc/usb_mode.c171
-rw-r--r--common/usbc/usb_pd_dpm.c32
-rw-r--r--common/usbc/usb_pe_drp_sm.c20
6 files changed, 232 insertions, 47 deletions
diff --git a/common/usb_pd_alt_mode_dfp.c b/common/usb_pd_alt_mode_dfp.c
index b7d81e2e64..a2dc62afd8 100644
--- a/common/usb_pd_alt_mode_dfp.c
+++ b/common/usb_pd_alt_mode_dfp.c
@@ -929,6 +929,7 @@ uint32_t get_enter_usb_msg_payload(int port)
*/
union enter_usb_data_obj eudo;
struct pd_discovery *disc;
+ union tbt_mode_resp_cable cable_mode_resp;
if (!IS_ENABLED(CONFIG_USB_PD_USB4))
return 0;
@@ -939,13 +940,22 @@ uint32_t get_enter_usb_msg_payload(int port)
eudo.usb3_drd_cap = IS_ENABLED(CONFIG_USB_PD_USB32_DRD);
eudo.cable_speed = get_usb4_cable_speed(port);
- if (is_rev3_vdo(port, TCPC_TX_SOP_PRIME) &&
- (disc->identity.idh.product_type == IDH_PTYPE_ACABLE)) {
- eudo.cable_type =
- (disc->identity.product_t2.a2_rev30.active_elem ==
- ACTIVE_RETIMER) ? CABLE_TYPE_ACTIVE_RETIMER :
- CABLE_TYPE_ACTIVE_REDRIVER;
- /* TODO: Add eudo.cable_type for Revisiosn 2 active cables */
+ if (disc->identity.idh.product_type == IDH_PTYPE_ACABLE) {
+ if (is_rev3_vdo(port, TCPC_TX_SOP_PRIME)) {
+ enum retimer_active_element active_element =
+ disc->identity.product_t2.a2_rev30.active_elem;
+ eudo.cable_type = active_element == ACTIVE_RETIMER ?
+ CABLE_TYPE_ACTIVE_RETIMER :
+ CABLE_TYPE_ACTIVE_REDRIVER;
+ } else {
+ cable_mode_resp.raw_value =
+ pd_get_tbt_mode_vdo(port, TCPC_TX_SOP_PRIME);
+
+ eudo.cable_type =
+ cable_mode_resp.retimer_type == USB_RETIMER ?
+ CABLE_TYPE_ACTIVE_RETIMER :
+ CABLE_TYPE_ACTIVE_REDRIVER;
+ }
} else {
eudo.cable_type = CABLE_TYPE_PASSIVE;
}
diff --git a/common/usb_pd_host_cmd.c b/common/usb_pd_host_cmd.c
index 11174ee7d4..62b7045630 100644
--- a/common/usb_pd_host_cmd.c
+++ b/common/usb_pd_host_cmd.c
@@ -372,7 +372,9 @@ static enum ec_status hc_usb_pd_control(struct host_cmd_handler_args *args)
if (mux_state & USB_PD_MUX_USB4_ENABLED) {
r_v2->cable_speed =
get_usb4_cable_speed(p->port);
- } else if (mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED) {
+ }
+ if (mux_state & USB_PD_MUX_TBT_COMPAT_ENABLED ||
+ mux_state & USB_PD_MUX_USB4_ENABLED) {
r_v2->cable_speed =
get_tbt_cable_speed(p->port);
r_v2->cable_gen =
diff --git a/common/usbc/tbt_alt_mode.c b/common/usbc/tbt_alt_mode.c
index 1319263e74..0785376355 100644
--- a/common/usbc/tbt_alt_mode.c
+++ b/common/usbc/tbt_alt_mode.c
@@ -69,8 +69,9 @@
* with a partner. It may be fixed in b/159495742, in which case this
* logic is unneeded.
*/
-#define TBT_FLAG_RETRY_DONE BIT(0)
-#define TBT_FLAG_EXIT_DONE BIT(1)
+#define TBT_FLAG_RETRY_DONE BIT(0)
+#define TBT_FLAG_EXIT_DONE BIT(1)
+#define TBT_FLAG_CABLE_ENTRY_DONE BIT(2)
static uint8_t tbt_flags[CONFIG_USB_PD_PORT_MAX_COUNT];
@@ -115,6 +116,7 @@ void tbt_init(int port)
tbt_state[port] = TBT_START;
TBT_CLR_FLAG(port, TBT_FLAG_RETRY_DONE);
TBT_SET_FLAG(port, TBT_FLAG_EXIT_DONE);
+ TBT_CLR_FLAG(port, TBT_FLAG_CABLE_ENTRY_DONE);
}
bool tbt_is_active(int port)
@@ -129,10 +131,16 @@ bool tbt_entry_is_done(int port)
tbt_state[port] == TBT_INACTIVE;
}
+bool tbt_cable_entry_is_done(int port)
+{
+ return TBT_CHK_FLAG(port, TBT_FLAG_CABLE_ENTRY_DONE);
+}
+
static void tbt_exit_done(int port)
{
tbt_state[port] = TBT_INACTIVE;
TBT_CLR_FLAG(port, TBT_FLAG_RETRY_DONE);
+ TBT_CLR_FLAG(port, TBT_FLAG_CABLE_ENTRY_DONE);
if (!TBT_CHK_FLAG(port, TBT_FLAG_EXIT_DONE)) {
TBT_SET_FLAG(port, TBT_FLAG_EXIT_DONE);
@@ -147,6 +155,14 @@ void tbt_exit_mode_request(int port)
{
TBT_SET_FLAG(port, TBT_FLAG_RETRY_DONE);
TBT_CLR_FLAG(port, TBT_FLAG_EXIT_DONE);
+ /*
+ * If the port has entered USB4 mode with Thunderbolt mode for the
+ * cable, on request to exit, only exit Thunderbolt mode for the
+ * cable.
+ * TODO (b/156749387): Remove once data reset feature is in place.
+ */
+ if (tbt_state[port] == TBT_ENTER_SOP)
+ tbt_state[port] = TBT_EXIT_SOP_PRIME_PRIME;
}
static bool tbt_response_valid(int port, enum tcpm_transmit_type type,
@@ -203,12 +219,15 @@ void intel_vdm_acked(int port, enum tcpm_transmit_type type, int vdo_count,
switch (tbt_state[port]) {
case TBT_ENTER_SOP_PRIME:
- if (disc->identity.product_t1.a_rev20.sop_p_p)
+ if (disc->identity.product_t1.a_rev20.sop_p_p) {
tbt_state[port] = TBT_ENTER_SOP_PRIME_PRIME;
- else
+ } else {
+ TBT_SET_FLAG(port, TBT_FLAG_CABLE_ENTRY_DONE);
tbt_state[port] = TBT_ENTER_SOP;
+ }
break;
case TBT_ENTER_SOP_PRIME_PRIME:
+ TBT_SET_FLAG(port, TBT_FLAG_CABLE_ENTRY_DONE);
tbt_state[port] = TBT_ENTER_SOP;
break;
case TBT_ENTER_SOP:
@@ -315,6 +334,7 @@ void intel_vdm_naked(int port, enum tcpm_transmit_type type, uint8_t vdm_cmd)
break;
case TBT_EXIT_SOP:
/* Exit SOP got NAK'ed */
+ tbt_prints("exit mode SOP failed", port);
set_usb_mux_with_current_data_role(port);
if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE)
tbt_active_cable_exit_mode(port);
diff --git a/common/usbc/usb_mode.c b/common/usbc/usb_mode.c
index c48002f0d1..818f1e18c3 100644
--- a/common/usbc/usb_mode.c
+++ b/common/usbc/usb_mode.c
@@ -19,7 +19,6 @@
#include "usb_mux.h"
#include "usb_pd.h"
#include "usb_pd_dpm.h"
-#include "usb_pd_tbt.h"
#include "usb_pe_sm.h"
#include "usbc_ppc.h"
@@ -37,11 +36,63 @@ enum usb4_mode_status {
};
enum usb4_states {
+ USB4_START,
USB4_ENTER_SOP,
+ USB4_ENTER_SOP_PRIME,
+ USB4_ENTER_SOP_PRIME_PRIME,
USB4_ACTIVE,
USB4_INACTIVE,
USB4_STATE_COUNT,
};
+
+/*
+ * USB4 flow for Active cable
+ *
+ * Structured
+ * VDM version
+ * (cable revision)-- <2.0 -------->|
+ * | |
+ * >=2.0 |
+ * | |
+ * VDO version---- <1.3 -------> Modal op? -- N --|
+ * (B21:23 of | |
+ * Discover ID SOP'- y |
+ * Active cable VDO1) | |
+ * | TBT SVID? -- N --|
+ * >=1.3 | |
+ * | y |
+ * Cable USB4 support? - N | |
+ * | | Gen4 cable? - N - Skip USB4 mode entry
+ * y Skip USB4 |
+ * | mode entry |
+ * Enter USB4 y
+ * (SOP',SOP'',SOP) |
+ * |
+ * |<---- NAK ----- Enter mode TBT SOP'<---|
+ * | | |
+ * | ACK |
+ * | | |
+ * |<---- NAK ----- Enter mode TBT SOP'' |
+ * | | |
+ * Exit TBT mode SOP ACK |
+ * | | |
+ * ACK/NAK Enter USB4 mode |
+ * | SOP |
+ * Exit TBT mode SOP'' |
+ * | |
+ * ACK/NAK |
+ * | |
+ * Exit TBT mode SOP' |
+ * | |
+ * ACK/NAK |
+ * | |
+ * |--------Retry done? ---- N ------------|
+ * |
+ * y
+ * |
+ * Skip USB4 mode entry
+ */
+
static enum usb4_states usb4_state[CONFIG_USB_PD_PORT_MAX_COUNT];
static void usb4_debug_prints(int port, enum usb4_mode_status usb4_status)
@@ -58,7 +109,7 @@ bool enter_usb_entry_is_done(int port)
void enter_usb_init(int port)
{
- usb4_state[port] = USB4_ENTER_SOP;
+ usb4_state[port] = USB4_START;
}
void enter_usb_failed(int port)
@@ -87,30 +138,86 @@ static bool enter_usb_response_valid(int port, enum tcpm_transmit_type type)
return true;
}
-bool enter_usb_is_capable(int port)
+bool enter_usb_port_partner_is_capable(int port)
{
const struct pd_discovery *disc =
pd_get_am_discovery(port, TCPC_TX_SOP);
- /*
- * TODO: b/156749387 Add support for entering the USB4 mode with an
- * active cable.
- */
- if (!IS_ENABLED(CONFIG_USB_PD_USB4) ||
- !PD_PRODUCT_IS_USB4(disc->identity.product_t1.raw_value) ||
- get_usb4_cable_speed(port) < USB_R30_SS_U32_U40_GEN1 ||
- usb4_state[port] == USB4_INACTIVE ||
- get_usb_pd_cable_type(port) != IDH_PTYPE_PCABLE)
+
+ if (usb4_state[port] == USB4_INACTIVE)
+ return false;
+
+ if (!PD_PRODUCT_IS_USB4(disc->identity.product_t1.raw_value))
return false;
return true;
}
+bool enter_usb_cable_is_capable(int port)
+{
+ /* TODO: b/156749387 Add support for LRD cable */
+
+ if (get_usb_pd_cable_type(port) == IDH_PTYPE_PCABLE) {
+ if (get_usb4_cable_speed(port) < USB_R30_SS_U32_U40_GEN1)
+ return false;
+ } else if (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE) {
+ struct pd_discovery *disc_sop_prime =
+ pd_get_am_discovery(port, TCPC_TX_SOP_PRIME);
+
+ if (pd_get_vdo_ver(port, TCPC_TX_SOP_PRIME) >= VDM_VER20 &&
+ disc_sop_prime->identity.product_t1.a_rev30.vdo_ver >=
+ VDO_VERSION_1_3) {
+ union active_cable_vdo2_rev30 a2_rev30 =
+ disc_sop_prime->identity.product_t2.a2_rev30;
+ /*
+ * For VDM version >= 2.0 and VD0 version is >= 1.3,
+ * do not enter USB4 mode if the cable isn't USB4
+ * capable.
+ */
+ if (a2_rev30.usb_40_support == USB4_NOT_SUPPORTED)
+ return false;
+ /*
+ * For VDM version < 2.0 or VDO version < 1.3, do not enter USB4
+ * mode if the cable -
+ * doesn't support modal operation or
+ * doesn't support Intel SVID or
+ * doesn't have rounded support.
+ */
+ } else {
+ const struct pd_discovery *disc =
+ pd_get_am_discovery(port, TCPC_TX_SOP);
+ union tbt_mode_resp_cable cable_mode_resp = {
+ .raw_value = pd_get_tbt_mode_vdo(port,
+ TCPC_TX_SOP_PRIME) };
+
+ if (!disc->identity.idh.modal_support ||
+ !pd_is_mode_discovered_for_svid(port,
+ TCPC_TX_SOP_PRIME, USB_VID_INTEL) ||
+ cable_mode_resp.tbt_rounded !=
+ TBT_GEN3_GEN4_ROUNDED_NON_ROUNDED)
+ return false;
+ }
+ }
+ return true;
+}
+
void enter_usb_accepted(int port, enum tcpm_transmit_type type)
{
+ struct pd_discovery *disc;
+
if (!enter_usb_response_valid(port, type))
return;
switch (usb4_state[port]) {
+ case USB4_ENTER_SOP_PRIME:
+ disc = pd_get_am_discovery(port, TCPC_TX_SOP_PRIME);
+ if (disc->identity.product_t1.a_rev20.sop_p_p)
+ usb4_state[port] = USB4_ENTER_SOP_PRIME_PRIME;
+ else
+ usb4_state[port] = USB4_ENTER_SOP;
+ break;
+ case USB4_ENTER_SOP_PRIME_PRIME:
+ usb4_state[port] = USB4_ENTER_SOP;
+ break;
case USB4_ENTER_SOP:
/* Connect the SBU and USB lines to the connector */
if (IS_ENABLED(CONFIG_USBC_PPC_SBU))
@@ -140,24 +247,44 @@ void enter_usb_rejected(int port, enum tcpm_transmit_type type)
enter_usb_failed(port);
}
-uint32_t enter_usb_setup_next_msg(int port)
+uint32_t enter_usb_setup_next_msg(int port, enum tcpm_transmit_type *type)
{
+ struct pd_discovery *disc_sop_prime;
+
switch (usb4_state[port]) {
+ case USB4_START:
+ disc_sop_prime = pd_get_am_discovery(port, TCPC_TX_SOP_PRIME);
+
+ if (pd_get_vdo_ver(port, TCPC_TX_SOP_PRIME) < VDM_VER20 ||
+ disc_sop_prime->identity.product_t1.a_rev30.vdo_ver <
+ VDO_VERSION_1_3 ||
+ get_usb_pd_cable_type(port) == IDH_PTYPE_PCABLE) {
+ usb4_state[port] = USB4_ENTER_SOP;
+ /* Ref: TBT4 PD Discover Flow */
+ usb_mux_set_safe_mode(port);
+ } else {
+ usb4_state[port] = USB4_ENTER_SOP_PRIME;
+ *type = TCPC_TX_SOP_PRIME;
+ }
+ break;
+ case USB4_ENTER_SOP_PRIME:
+ *type = TCPC_TX_SOP_PRIME;
+ break;
+ case USB4_ENTER_SOP_PRIME_PRIME:
+ *type = TCPC_TX_SOP_PRIME_PRIME;
+ break;
case USB4_ENTER_SOP:
+ *type = TCPC_TX_SOP;
/*
- * Set the USB mux to safe state to avoid damaging the mux pins
- * since, they are being re-purposed for USB4.
- *
- * TODO: b/141363146 Remove once data reset feature is in place
+ * Set the USB mux to safe state to avoid damaging the mux pins,
+ * since they are being re-purposed for USB4.
*/
usb_mux_set_safe_mode(port);
-
- usb4_state[port] = USB4_ENTER_SOP;
- return get_enter_usb_msg_payload(port);
+ break;
case USB4_ACTIVE:
return -1;
default:
- break;
+ return 0;
}
- return 0;
+ return get_enter_usb_msg_payload(port);
}
diff --git a/common/usbc/usb_pd_dpm.c b/common/usbc/usb_pd_dpm.c
index 69956c3685..193ea9802c 100644
--- a/common/usbc/usb_pd_dpm.c
+++ b/common/usbc/usb_pd_dpm.c
@@ -216,10 +216,28 @@ static void dpm_attempt_mode_entry(int port)
}
/* Check if the device and cable support USB4. */
- if (IS_ENABLED(CONFIG_USB_PD_USB4) && enter_usb_is_capable(port) &&
- dpm_mode_entry_requested(port, TYPEC_MODE_USB4)) {
- pd_dpm_request(port, DPM_REQUEST_ENTER_USB);
- return;
+ if (IS_ENABLED(CONFIG_USB_PD_USB4) &&
+ enter_usb_port_partner_is_capable(port) &&
+ enter_usb_cable_is_capable(port) &&
+ dpm_mode_entry_requested(port, TYPEC_MODE_USB4)) {
+ struct pd_discovery *disc_sop_prime =
+ pd_get_am_discovery(port, TCPC_TX_SOP_PRIME);
+ /*
+ * Enter USB mode if -
+ * 1. It's a passive cable or
+ * 2. It's an active cable with VDM version >= 2.0 and
+ * VDO version >= 1.3 or
+ * 3. The cable has entered Thunderbolt mode.
+ */
+ if (get_usb_pd_cable_type(port) == IDH_PTYPE_PCABLE ||
+ (get_usb_pd_cable_type(port) == IDH_PTYPE_ACABLE &&
+ pd_get_vdo_ver(port, TCPC_TX_SOP_PRIME) >= VDM_VER20 &&
+ disc_sop_prime->identity.product_t1.a_rev30.vdo_ver >=
+ VDO_VERSION_1_3) ||
+ tbt_cable_entry_is_done(port)) {
+ pd_dpm_request(port, DPM_REQUEST_ENTER_USB);
+ return;
+ }
}
/* If not, check if they support Thunderbolt alt mode. */
@@ -284,9 +302,13 @@ static void dpm_attempt_mode_exit(int port)
int vdo_count = 0;
enum tcpm_transmit_type tx_type = TCPC_TX_SOP;
- /* TODO(b/156749387): Support Data Reset for exiting USB4. */
if (IS_ENABLED(CONFIG_USB_PD_TBT_COMPAT_MODE) &&
tbt_is_active(port)) {
+ /*
+ * When the port is in USB4 mode and receives an exit request,
+ * it leaves USB4 SOP in active state.
+ * TODO(b/156749387): Support Data Reset for exiting USB4 SOP.
+ */
CPRINTS("C%d: TBT teardown", port);
tbt_exit_mode_request(port);
vdo_count = tbt_setup_next_vdm(port, VDO_MAX_SIZE, &vdm,
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c
index 37afaa9c0e..139e8454b0 100644
--- a/common/usbc/usb_pe_drp_sm.c
+++ b/common/usbc/usb_pe_drp_sm.c
@@ -5513,28 +5513,32 @@ static void pe_enter_usb_entry(int port)
return;
}
- usb4_payload = enter_usb_setup_next_msg(port);
-
/* Port is already in USB4 mode, do not send enter USB message again */
- if (usb4_payload < 0) {
+ if (enter_usb_entry_is_done(port)) {
pe_set_ready_state(port);
return;
}
+ if ((pe[port].tx_type == TCPC_TX_SOP_PRIME ||
+ pe[port].tx_type == TCPC_TX_SOP_PRIME_PRIME) &&
+ !tc_is_vconn_src(port)) {
+ if (port_try_vconn_swap(port))
+ return;
+ }
+
+ pe[port].tx_type = TCPC_TX_SOP;
+ usb4_payload = enter_usb_setup_next_msg(port, &pe[port].tx_type);
+
if (!usb4_payload) {
enter_usb_failed(port);
pe_set_ready_state(port);
return;
}
- /*
- * TODO: b/156749387 In case of Enter USB SOP'/SOP'', check if the port
- * is the VCONN source, if not, request for a VCONN swap.
- */
tx_emsg[port].len = sizeof(usb4_payload);
memcpy(tx_emsg[port].buf, &usb4_payload, tx_emsg[port].len);
- send_data_msg(port, TCPC_TX_SOP, PD_DATA_ENTER_USB);
+ send_data_msg(port, pe[port].tx_type, PD_DATA_ENTER_USB);
pe_sender_response_msg_entry(port);
}