summaryrefslogtreecommitdiff
path: root/driver
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 /driver
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>
Diffstat (limited to 'driver')
-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
5 files changed, 165 insertions, 5 deletions
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