summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)