summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Hurst <shurst@google.com>2018-12-28 11:06:01 -0800
committerchrome-bot <chrome-bot@chromium.org>2019-01-07 19:40:45 -0800
commit1f7de7c939c1f0bf318f4d8b6012183d5755df91 (patch)
tree47761cbff48ae0b9a90cfd2c76ccc6cfdab8239e
parentaed008f87c3c880edecf7608ab24eaa4bee1bc46 (diff)
downloadchrome-ec-1f7de7c939c1f0bf318f4d8b6012183d5755df91.tar.gz
pd: Enable USB PD SOP' and SOP'' Communication
Currently, the PD stack ignores messages received from SOP' and SOP'' and this prevents the stack from communicating with VCONN Power Devices and Cable Plugs in general. I propose encoding the message address (SOP*) in the message header. The message header is encoded as a 16-bit value but the TCPC drivers use a 32-bit type for the header. The SOP* address will be stored in bits 31 to 28 of the message header and the PD stack can check those bits to determine the address of the message. BUG=b:122109575 BRANCH=none TEST=manual Change-Id: I2b34c16cae186202c9cf0bc5f940e05151e88cbf Signed-off-by: Sam Hurst <shurst@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1390951 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: Sam Hurst <shurst@google.com> Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r--chip/host/usb_pd_phy.c34
-rw-r--r--common/usb_pd_tcpc.c49
-rw-r--r--driver/tcpm/anx74xx.c58
-rw-r--r--driver/tcpm/anx74xx.h3
-rw-r--r--driver/tcpm/fusb302.c50
-rw-r--r--driver/tcpm/tcpci.c58
-rw-r--r--driver/tcpm/tcpci.h1
-rw-r--r--include/config.h3
-rw-r--r--include/usb_pd.h14
9 files changed, 260 insertions, 10 deletions
diff --git a/chip/host/usb_pd_phy.c b/chip/host/usb_pd_phy.c
index 96d7f06ea8..dd16890e6b 100644
--- a/chip/host/usb_pd_phy.c
+++ b/chip/host/usb_pd_phy.c
@@ -92,6 +92,22 @@ void pd_test_rx_msg_append_sop(int port)
pd_test_rx_msg_append_kcode(port, PD_SYNC2);
}
+void pd_test_rx_msg_append_sop_prime(int port)
+{
+ pd_test_rx_msg_append_kcode(port, PD_SYNC1);
+ pd_test_rx_msg_append_kcode(port, PD_SYNC1);
+ pd_test_rx_msg_append_kcode(port, PD_SYNC3);
+ pd_test_rx_msg_append_kcode(port, PD_SYNC3);
+}
+
+void pd_test_rx_msg_append_sop_prime_prime(int port)
+{
+ pd_test_rx_msg_append_kcode(port, PD_SYNC1);
+ pd_test_rx_msg_append_kcode(port, PD_SYNC3);
+ pd_test_rx_msg_append_kcode(port, PD_SYNC1);
+ pd_test_rx_msg_append_kcode(port, PD_SYNC3);
+}
+
void pd_test_rx_msg_append_eop(int port)
{
pd_test_rx_msg_append_kcode(port, PD_EOP);
@@ -152,6 +168,24 @@ int pd_test_tx_msg_verify_sop(int port)
pd_test_tx_msg_verify_kcode(port, PD_SYNC2);
}
+int pd_test_tx_msg_verify_sop_prime(int port)
+{
+ crc32_init();
+ return pd_test_tx_msg_verify_kcode(port, PD_SYNC1) &&
+ pd_test_tx_msg_verify_kcode(port, PD_SYNC1) &&
+ pd_test_tx_msg_verify_kcode(port, PD_SYNC3) &&
+ pd_test_tx_msg_verify_kcode(port, PD_SYNC3);
+}
+
+int pd_test_tx_msg_verify_sop_prime_prime(int port)
+{
+ crc32_init();
+ return pd_test_tx_msg_verify_kcode(port, PD_SYNC1) &&
+ pd_test_tx_msg_verify_kcode(port, PD_SYNC3) &&
+ pd_test_tx_msg_verify_kcode(port, PD_SYNC1) &&
+ pd_test_tx_msg_verify_kcode(port, PD_SYNC3);
+}
+
int pd_test_tx_msg_verify_eop(int port)
{
return pd_test_tx_msg_verify_kcode(port, PD_EOP);
diff --git a/common/usb_pd_tcpc.c b/common/usb_pd_tcpc.c
index 3e79569e2e..0feabb5b10 100644
--- a/common/usb_pd_tcpc.c
+++ b/common/usb_pd_tcpc.c
@@ -202,6 +202,12 @@ enum pd_tx_errors {
PD_TX_ERR_COLLISION = -5 /* Collision detected during transmit */
};
+/* PD Header with SOP* encoded in bits 31 - 28 */
+union pd_header_sop {
+ uint16_t pd_header;
+ uint32_t head;
+};
+
/*
* If TCPM is not on this chip, and PD low power is defined, then use low
* power task delay logic.
@@ -626,7 +632,7 @@ int pd_analyze_rx(int port, uint32_t *payload)
int bit;
char *msg = "---";
uint32_t val = 0;
- uint16_t header;
+ union pd_header_sop phs;
uint32_t pcrc, ccrc;
int p, cnt;
uint32_t eop;
@@ -646,6 +652,11 @@ int pd_analyze_rx(int port, uint32_t *payload)
/* Find the Start Of Packet sequence */
while (bit > 0) {
bit = pd_dequeue_bits(port, bit, 20, &val);
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ if (val == PD_SOP || val == PD_SOP_PRIME ||
+ val == PD_SOP_PRIME_PRIME)
+ break;
+#else
if (val == PD_SOP) {
break;
} else if (val == PD_SOP_PRIME) {
@@ -655,22 +666,50 @@ int pd_analyze_rx(int port, uint32_t *payload)
CPRINTF("SOP''\n");
return PD_RX_ERR_UNSUPPORTED_SOP;
}
+#endif
}
if (bit < 0) {
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ if (val == PD_SOP)
+ msg = "SOP";
+ else if (val == PD_SOP_PRIME)
+ msg = "SOP'";
+ else if (val == PD_SOP_PRIME_PRIME)
+ msg = "SOP''";
+ else
+ msg = "SOP*";
+#else
msg = "SOP";
+#endif
goto packet_err;
}
+ phs.head = 0;
+
/* read header */
- bit = decode_short(port, bit, &header);
+ bit = decode_short(port, bit, &phs.pd_header);
#ifdef CONFIG_COMMON_RUNTIME
mutex_lock(&pd_crc_lock);
#endif
crc32_init();
- crc32_hash16(header);
- cnt = PD_HEADER_CNT(header);
+ crc32_hash16(phs.pd_header);
+ cnt = PD_HEADER_CNT(phs.pd_header);
+
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ /* Encode message address */
+ if (val == PD_SOP) {
+ phs.head |= PD_HEADER_SOP(PD_MSG_SOP);
+ } else if (val == PD_SOP_PRIME) {
+ phs.head |= PD_HEADER_SOP(PD_MSG_SOPP);
+ } else if (val == PD_SOP_PRIME_PRIME) {
+ phs.head |= PD_HEADER_SOP(PD_MSG_SOPPP);
+ } else {
+ msg = "SOP*";
+ goto packet_err;
+ }
+#endif
/* read payload data */
for (p = 0; p < cnt && bit > 0; p++) {
@@ -710,7 +749,7 @@ int pd_analyze_rx(int port, uint32_t *payload)
goto packet_err;
}
- return header;
+ return phs.head;
packet_err:
if (debug_level >= 2)
pd_dump_packet(port, msg);
diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c
index 4ad5eb67c0..675c4b0bf0 100644
--- a/driver/tcpm/anx74xx.c
+++ b/driver/tcpm/anx74xx.c
@@ -48,12 +48,32 @@ static struct anx_state anx[CONFIG_USB_PD_PORT_COUNT];
/* Save the selected rp value */
static int selected_rp[CONFIG_USB_PD_PORT_COUNT];
+#ifdef CONFIG_USB_PD_DECODE_SOP
+/* Save the message address */
+static int msg_sop[CONFIG_USB_PD_PORT_COUNT];
+#endif
+
static int anx74xx_tcpm_init(int port);
static void anx74xx_tcpm_set_auto_good_crc(int port, int enable)
{
- tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_2,
- enable ? ANX74XX_REG_REPLY_SOP_EN : 0);
+ int reply_sop_en = 0;
+
+ if (enable) {
+ reply_sop_en = ANX74XX_REG_REPLY_SOP_EN;
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ /*
+ * Only the VCONN Source is allowed to communicate
+ * with the Cable Plugs.
+ */
+ if (anx[port].vconn_en) {
+ reply_sop_en |= ANX74XX_REG_REPLY_SOP_1_EN |
+ ANX74XX_REG_REPLY_SOP_2_EN;
+ }
+#endif
+ }
+
+ tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_2, reply_sop_en);
}
static void anx74xx_update_cable_det(int port, int mode)
@@ -765,6 +785,23 @@ static int anx74xx_tcpm_set_vconn(int port, int enable)
rv |= tcpc_write(port, ANX74XX_REG_INTP_VCONN_CTRL, reg);
anx[port].vconn_en = enable;
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ rv |= tcpc_read(port, ANX74XX_REG_TX_AUTO_GOODCRC_2, &reg);
+ if (rv)
+ return EC_ERROR_UNKNOWN;
+
+ if (reg & ANX74XX_REG_REPLY_SOP_EN) {
+ if (enable) {
+ reg |= ANX74XX_REG_REPLY_SOP_1_EN |
+ ANX74XX_REG_REPLY_SOP_2_EN;
+ } else {
+ reg &= ~(ANX74XX_REG_REPLY_SOP_1_EN |
+ ANX74XX_REG_REPLY_SOP_2_EN);
+ }
+
+ tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_2, reg);
+ }
+#endif
return rv;
}
@@ -818,7 +855,10 @@ static int anx74xx_tcpm_get_message_raw(int port, uint32_t *payload, int *head)
clear_recvd_msg_int(port);
return EC_ERROR_UNKNOWN;
}
- *head = reg;
+ *head = reg & 0x0000ffff;
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ *head |= PD_HEADER_SOP(msg_sop[port]);
+#endif
len = PD_HEADER_CNT(*head) * 4;
if (!len) {
@@ -950,6 +990,13 @@ void anx74xx_tcpc_alert(int port)
tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, &reg);
tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, reg);
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ if (reg & ANX74XX_REG_EXT_SOP)
+ msg_sop[port] = PD_MSG_SOP;
+ else if (reg & ANX74XX_REG_EXT_SOP_PRIME)
+ msg_sop[port] = PD_MSG_SOPP;
+#endif
+
/* Check for Hard Reset done bit */
if (reg & ANX74XX_REG_ALERT_TX_HARD_RESETOK)
/* ANX hardware clears the request bit */
@@ -960,6 +1007,11 @@ void anx74xx_tcpc_alert(int port)
tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_2, &reg);
tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_2, reg);
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ if (reg & ANX74XX_REG_EXT_SOP_PRIME_PRIME)
+ msg_sop[port] = PD_MSG_SOPPP;
+#endif
+
if (reg & ANX74XX_REG_EXT_HARD_RST) {
/* hard reset received */
pd_execute_hard_reset(port);
diff --git a/driver/tcpm/anx74xx.h b/driver/tcpm/anx74xx.h
index a8f51232a5..09d3e36771 100644
--- a/driver/tcpm/anx74xx.h
+++ b/driver/tcpm/anx74xx.h
@@ -129,7 +129,10 @@
#define ANX74XX_REG_IRQ_EXT_MASK_1 0x3b
#define ANX74XX_REG_IRQ_EXT_MASK_2 0x3c
#define ANX74XX_REG_IRQ_EXT_SOURCE_1 0x3e
+#define ANX74XX_REG_EXT_SOP (1 << 6)
+#define ANX74XX_REG_EXT_SOP_PRIME (1 << 7)
#define ANX74XX_REG_IRQ_EXT_SOURCE_2 0x4e
+#define ANX74XX_REG_EXT_SOP_PRIME_PRIME (1 << 0)
#define ANX74XX_REG_EXT_HARD_RST (1 << 2)
#define ANX74XX_REG_IRQ_EXT_SOURCE_3 0x4f
#define ANX74XX_REG_CLEAR_SOFT_IRQ (1 << 2)
diff --git a/driver/tcpm/fusb302.c b/driver/tcpm/fusb302.c
index 7b736e5b23..24f7fb6388 100644
--- a/driver/tcpm/fusb302.c
+++ b/driver/tcpm/fusb302.c
@@ -604,6 +604,17 @@ static int fusb302_tcpm_set_vconn(int port, int enable)
if (enable) {
/* set to saved polarity */
tcpm_set_polarity(port, state[port].cc_polarity);
+
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ if (state[port].rx_enable) {
+ if (tcpc_read(port, TCPC_REG_CONTROL1, &reg))
+ return EC_ERROR_UNKNOWN;
+
+ reg |= (TCPC_REG_CONTROL1_ENSOP1 |
+ TCPC_REG_CONTROL1_ENSOP2);
+ tcpc_write(port, TCPC_REG_CONTROL1, reg);
+ }
+#endif
} else {
tcpc_read(port, TCPC_REG_SWITCHES0, &reg);
@@ -613,6 +624,17 @@ static int fusb302_tcpm_set_vconn(int port, int enable)
reg &= ~TCPC_REG_SWITCHES0_VCONN_CC2;
tcpc_write(port, TCPC_REG_SWITCHES0, reg);
+
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ if (state[port].rx_enable) {
+ if (tcpc_read(port, TCPC_REG_CONTROL1, &reg))
+ return EC_ERROR_UNKNOWN;
+
+ reg &= ~(TCPC_REG_CONTROL1_ENSOP1 |
+ TCPC_REG_CONTROL1_ENSOP2);
+ tcpc_write(port, TCPC_REG_CONTROL1, reg);
+ }
+#endif
}
return 0;
@@ -685,6 +707,20 @@ static int fusb302_tcpm_set_rx_enable(int port, int enable)
reg & ~TCPC_REG_MASK_BC_LVL);
}
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ /*
+ * Only the VCONN Source is allowed to communicate
+ * with the Cable Plugs.
+ */
+ if (state[port].vconn_enabled) {
+ if (tcpc_read(port, TCPC_REG_CONTROL1, &reg))
+ return EC_ERROR_UNKNOWN;
+
+ reg |= (TCPC_REG_CONTROL1_ENSOP1 | TCPC_REG_CONTROL1_ENSOP2);
+ tcpc_write(port, TCPC_REG_CONTROL1, reg);
+ }
+#endif
+
fusb302_auto_goodcrc_enable(port, enable);
return 0;
@@ -758,6 +794,20 @@ static int fusb302_tcpm_get_message_raw(int port, uint32_t *payload, int *head)
memcpy(payload, buf, len);
}
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ {
+ int reg;
+
+ if (tcpc_read(port, TCPC_REG_STATUS1, &reg))
+ return EC_ERROR_UNKNOWN;
+
+ if (reg & TCPC_REG_STATUS1_RXSOP1)
+ *head |= PD_HEADER_SOP(PD_MSG_SOPP);
+ else if (reg & TCPC_REG_STATUS1_RXSOP2)
+ *head |= PD_HEADER_SOP(PD_MSG_SOPPP);
+ }
+#endif
+
return rv;
}
diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c
index 60cfa33760..f7d98312cf 100644
--- a/driver/tcpm/tcpci.c
+++ b/driver/tcpm/tcpci.c
@@ -23,6 +23,10 @@
#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
+#ifdef CONFIG_USB_PD_DECODE_SOP
+static int vconn_en[CONFIG_USB_PD_PORT_COUNT];
+static int rx_en[CONFIG_USB_PD_PORT_COUNT];
+#endif
static int tcpc_vbus[CONFIG_USB_PD_PORT_COUNT];
/* Save the selected rp value */
@@ -303,6 +307,22 @@ int tcpci_tcpm_set_vconn(int port, int enable)
rv = tcpc_read(port, TCPC_REG_POWER_CTRL, &reg);
if (rv)
return rv;
+
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ /* save vconn */
+ vconn_en[port] = enable;
+
+ if (rx_en[port]) {
+ int detect_sop_en = TCPC_REG_RX_DETECT_SOP_HRST_MASK;
+
+ if (enable) {
+ detect_sop_en =
+ TCPC_REG_RX_DETECT_SOP_SOPP_SOPPP_HRST_MASK;
+ }
+
+ tcpc_write(port, TCPC_REG_RX_DETECT, detect_sop_en);
+ }
+#endif
reg &= ~TCPC_REG_POWER_CTRL_VCONN(1);
reg |= TCPC_REG_POWER_CTRL_VCONN(enable);
return tcpc_write(port, TCPC_REG_POWER_CTRL, reg);
@@ -322,9 +342,28 @@ static int tcpm_alert_status(int port, int *alert)
int tcpci_tcpm_set_rx_enable(int port, int enable)
{
+ int detect_sop_en = 0;
+
+ if (enable) {
+ detect_sop_en = TCPC_REG_RX_DETECT_SOP_HRST_MASK;
+
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ /* save rx_on */
+ rx_en[port] = enable;
+
+ /*
+ * Only the VCONN Source is allowed to communicate
+ * with the Cable Plugs.
+ */
+
+ if (vconn_en[port])
+ detect_sop_en =
+ TCPC_REG_RX_DETECT_SOP_SOPP_SOPPP_HRST_MASK;
+#endif
+ }
+
/* If enable, then set RX detect for SOP and HRST */
- return tcpc_write(port, TCPC_REG_RX_DETECT,
- enable ? TCPC_REG_RX_DETECT_SOP_HRST_MASK : 0);
+ return tcpc_write(port, TCPC_REG_RX_DETECT, detect_sop_en);
}
#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC
@@ -337,6 +376,9 @@ int tcpci_tcpm_get_vbus_level(int port)
int tcpci_tcpm_get_message_raw(int port, uint32_t *payload, int *head)
{
int rv, cnt, reg = TCPC_REG_RX_DATA;
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ int frm;
+#endif
rv = tcpc_read(port, TCPC_REG_RX_BYTE_CNT, &cnt);
@@ -345,9 +387,21 @@ int tcpci_tcpm_get_message_raw(int port, uint32_t *payload, int *head)
rv = EC_ERROR_UNKNOWN;
goto clear;
}
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ rv = tcpc_read(port, TCPC_REG_RX_BUF_FRAME_TYPE, &frm);
+ if (rv != EC_SUCCESS) {
+ rv = EC_ERROR_UNKNOWN;
+ goto clear;
+ }
+#endif
rv = tcpc_read16(port, TCPC_REG_RX_HDR, (int *)head);
+#ifdef CONFIG_USB_PD_DECODE_SOP
+ /* Encode message address in bits 31 to 28 */
+ *head &= 0x0000ffff;
+ *head |= PD_HEADER_SOP(frm & 7);
+#endif
cnt = cnt - 3;
if (rv == EC_SUCCESS && cnt > 0) {
tcpc_read_block(port, reg, (uint8_t *)payload, cnt);
diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h
index f5fe1a1a0b..52a4d62847 100644
--- a/driver/tcpm/tcpci.h
+++ b/driver/tcpm/tcpci.h
@@ -102,6 +102,7 @@
#define TCPC_REG_RX_DETECT 0x2f
#define TCPC_REG_RX_DETECT_SOP_HRST_MASK 0x21
+#define TCPC_REG_RX_DETECT_SOP_SOPP_SOPPP_HRST_MASK 0x27
#define TCPC_REG_RX_BYTE_CNT 0x30
#define TCPC_REG_RX_BUF_FRAME_TYPE 0x31
diff --git a/include/config.h b/include/config.h
index 16326ae7c7..8163205c02 100644
--- a/include/config.h
+++ b/include/config.h
@@ -3290,6 +3290,9 @@
/* Enable TCPC to enter low power mode */
#undef CONFIG_USB_PD_TCPC_LOW_POWER
+/* Enable the encoding of msg SOP* in bits 31-28 of 32-bit msg header type */
+#undef CONFIG_USB_PD_DECODE_SOP
+
/*
* Track VBUS level in TCPC module. This will only be needed if we're acting
* as an external TCPC.
diff --git a/include/usb_pd.h b/include/usb_pd.h
index f57d8edbb5..d87fcc8fa4 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -954,6 +954,20 @@ enum pd_data_msg_type {
#define PD_HEADER_REV(header) (((header) >> 6) & 3)
#define PD_HEADER_DROLE(header) (((header) >> 5) & 1)
+/*
+ * The message header is a 16-bit value that's stored in a 32-bit data type.
+ * SOP* is encoded in bits 31 to 28 of the 32-bit data type.
+ * NOTE: This is not part of the PD spec.
+ */
+#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
+
/* Used for processing pd extended header */
#define PD_EXT_HEADER_CHUNKED(header) (((header) >> 15) & 1)
#define PD_EXT_HEADER_CHUNK_NUM(header) (((header) >> 11) & 0xf)