summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAyushee <ayushee.shah@intel.com>2020-01-14 18:08:15 -0800
committerCommit Bot <commit-bot@chromium.org>2020-01-31 20:57:57 +0000
commit42ca68d3cdf74193dd041d336b698bfe3ae1221a (patch)
treee6375405bf02fff7dbd65827b543fdcbaf5870bc
parenta0d6b40c49c7615cddded5e6811a550468eba7b2 (diff)
downloadchrome-ec-42ca68d3cdf74193dd041d336b698bfe3ae1221a.tar.gz
TCPMv1: Add support for Thunderbolt active cables
For entering into Thunderbolt-Compatible mode with active cable, the port sends Enter mode command for SOP', SOP'' (if the cable has a SOP'' controller) and SOP respectively. If the port doesn't receive GoodCRC from Enter Mode SOP'', the port resets the cable characteristic and exits the Thunderbolt-Compatible mode discovery. This CL enables SOP'' communication with the cable plug and adds support to enter into Thunderbolt-compatible mode with active cables. BUG=b:140643923 BRANCH=None TEST=Able to enter into Thunderbolt-Compatible mode for active cables. Change-Id: Iea0c652043933047e0158265c911775d4afe5758 Signed-off-by: Ayushee <ayushee.shah@intel.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2001938 Reviewed-by: Diana Z <dzigterman@chromium.org>
-rw-r--r--common/usb_pd_policy.c87
-rw-r--r--common/usb_pd_protocol.c72
-rw-r--r--include/usb_pd.h28
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