diff options
author | Sam Hurst <shurst@google.com> | 2018-12-28 11:06:01 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-01-07 19:40:45 -0800 |
commit | 1f7de7c939c1f0bf318f4d8b6012183d5755df91 (patch) | |
tree | 47761cbff48ae0b9a90cfd2c76ccc6cfdab8239e /driver | |
parent | aed008f87c3c880edecf7608ab24eaa4bee1bc46 (diff) | |
download | chrome-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.c | 58 | ||||
-rw-r--r-- | driver/tcpm/anx74xx.h | 3 | ||||
-rw-r--r-- | driver/tcpm/fusb302.c | 50 | ||||
-rw-r--r-- | driver/tcpm/tcpci.c | 58 | ||||
-rw-r--r-- | driver/tcpm/tcpci.h | 1 |
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, ®); + 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, ®); 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, ®); 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, ®)) + 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, ®); @@ -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, ®)) + 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, ®)) + 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, ®)) + 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, ®); 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 |