diff options
-rw-r--r-- | chip/host/usb_pd_phy.c | 34 | ||||
-rw-r--r-- | common/usb_pd_tcpc.c | 49 | ||||
-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 | ||||
-rw-r--r-- | include/config.h | 3 | ||||
-rw-r--r-- | include/usb_pd.h | 14 |
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, ®); + 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 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) |