summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAseda Aboagye <aaboagye@google.com>2020-01-16 21:29:32 -0800
committerCommit Bot <commit-bot@chromium.org>2020-01-22 12:01:35 +0000
commit5c95136c7fb3acdeaf182727d7417b2a02cdbdfb (patch)
tree601f860f7f8284d0b804f436061a8a2a477c5e4a
parentbe95f2907da12b1d7c94d4e194ac7e5bee185c40 (diff)
downloadchrome-ec-5c95136c7fb3acdeaf182727d7417b2a02cdbdfb.tar.gz
driver/tcpci: Add support for TCPCI Rev2 v1.0
The TCPCI Revision 2.0 made a couple major changes compared to the 1.0 revision. One of these changes was that the method in transmitting and receiving messages from the TCPC had changed. The receive buffer register is now comprised of three sets of registers: READABLE_BYTE_COUNT, RX_BUF_FRAME_TYPE, and RX_BUF_BYTE_x. These registers can only be accessed by reading at a common register address 30h. Similarly, the transmit buffer register holds the I2C_WRITE_BYTE_COUNT and the portion of the SOP* USB PD message payload (including the header) in TX_BUF_BYTE_x. TX_BUF_BYTE_x is "hidden" and can only be accessed by writing to register address 51h. This commit adds support for TCPCI Rev2 v1.0 by adding the new mechanisms for transmitting and receiving messages. A flag was introduced to enable the TCPCI Rev2 handling, TCPC_FLAGS_TCPCI_V2_0. A board should set this flag in their tcpc_config structs for those TCPCI-compliant TCPCs which use TCPCI Rev2. BUG=b:147716486 BRANCH=None TEST=Enable TCPCI Rev2.0 on waddledoo, verify that PD messages are able to be received and transmitted. Change-Id: Ie0117adf56c95f85f9c67ed678cf1e367f83eb7e Signed-off-by: Aseda Aboagye <aaboagye@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2006710 Tested-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Diana Z <dzigterman@chromium.org> Commit-Queue: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r--driver/tcpm/raa489000.c7
-rw-r--r--driver/tcpm/tcpci.c122
-rw-r--r--driver/tcpm/tcpci.h24
-rw-r--r--include/usb_pd_tcpm.h2
4 files changed, 140 insertions, 15 deletions
diff --git a/driver/tcpm/raa489000.c b/driver/tcpm/raa489000.c
index 3948692457..c6911eb913 100644
--- a/driver/tcpm/raa489000.c
+++ b/driver/tcpm/raa489000.c
@@ -95,9 +95,12 @@ int raa489000_init(int port)
if (rv)
CPRINTS("c%d: failed to set PD PHY PARAM1", port);
- /* Enable TCPCIv1.0 */
+ /* Enable the correct TCPCI interface version */
rv = tcpc_read16(port, RAA489000_TCPC_SETTING1, &regval);
- regval |= RAA489000_TCPCV1_0_EN;
+ if (!(tcpc_config[port].flags & TCPC_FLAGS_TCPCI_V2_0))
+ regval |= RAA489000_TCPCV1_0_EN;
+ else
+ regval &= ~RAA489000_TCPCV1_0_EN;
rv = tcpc_write16(port, RAA489000_TCPC_SETTING1, regval);
if (rv)
CPRINTS("c%d: failed to set TCPCIv1.0 mode", port);
diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c
index 0bc86c83cb..64694617c1 100644
--- a/driver/tcpm/tcpci.c
+++ b/driver/tcpm/tcpci.c
@@ -548,7 +548,56 @@ struct cached_tcpm_message {
uint32_t payload[7];
};
-int tcpci_tcpm_get_message_raw(int port, uint32_t *payload, int *head)
+static int tcpci_v2_0_tcpm_get_message_raw(int port, uint32_t *payload,
+ int *head)
+{
+ int rv = 0, cnt, reg = TCPC_REG_RX_BUFFER;
+ int frm;
+ uint8_t tmp[2];
+ /*
+ * Register 0x30 is Readable Byte Count, Buffer frame type, and RX buf
+ * byte X.
+ */
+ tcpc_lock(port, 1);
+ rv = tcpc_xfer_unlocked(port, (uint8_t *)&reg, 1, tmp, 2,
+ I2C_XFER_START);
+ if (rv) {
+ rv = EC_ERROR_UNKNOWN;
+ goto clear;
+ }
+ cnt = tmp[0];
+ frm = tmp[1];
+
+ /* READABLE_BYTE_COUNT includes 3 bytes for frame type and header */
+ cnt -= 3;
+ if (cnt > member_size(struct cached_tcpm_message, payload)) {
+ rv = EC_ERROR_UNKNOWN;
+ goto clear;
+ }
+
+ /* The next two bytes are the header */
+ rv = tcpc_xfer_unlocked(port, NULL, 0, (uint8_t *)head, 2,
+ cnt ? 0 : I2C_XFER_STOP);
+
+ /* Encode message address in bits 31 to 28 */
+ *head &= 0x0000ffff;
+ *head |= PD_HEADER_SOP(frm & 7);
+
+ if (rv == EC_SUCCESS && cnt > 0) {
+ tcpc_xfer_unlocked(port, NULL, 0, (uint8_t *)payload, cnt,
+ I2C_XFER_STOP);
+ }
+
+clear:
+ tcpc_lock(port, 0);
+ /* Read complete, clear RX status alert bit */
+ tcpc_write16(port, TCPC_REG_ALERT, TCPC_REG_ALERT_RX_STATUS);
+
+ return rv;
+}
+
+static int tcpci_v1_0_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
@@ -594,6 +643,14 @@ clear:
return rv;
}
+int tcpci_tcpm_get_message_raw(int port, uint32_t *payload, int *head)
+{
+ if (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_V2_0)
+ return tcpci_v2_0_tcpm_get_message_raw(port, payload, head);
+
+ return tcpci_v1_0_tcpm_get_message_raw(port, payload, head);
+}
+
/* Cache depth needs to be power of 2 */
#define CACHE_DEPTH BIT(2)
#define CACHE_DEPTH_MASK (CACHE_DEPTH - 1)
@@ -697,23 +754,50 @@ int tcpci_tcpm_transmit(int port, enum tcpm_transmit_type type,
TCPC_REG_TRANSMIT_SET_WITHOUT_RETRY(type));
}
- /* TX_BYTE_CNT includes extra bytes for message header */
- rv = tcpc_write(port, TCPC_REG_TX_BYTE_CNT, cnt + sizeof(header));
-
- rv |= tcpc_write16(port, TCPC_REG_TX_HDR, header);
-
- /* If tcpc read fails, return error */
- if (rv)
- return rv;
+ if (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_V2_0) {
+ /*
+ * In TCPCI v2.0, TX_BYTE_CNT and TX_BUF_BYTE_X are the same
+ * register.
+ */
+ reg = TCPC_REG_TX_BUFFER;
+ /* TX_BYTE_CNT includes extra bytes for message header */
+ cnt += sizeof(header);
+ tcpc_lock(port, 1);
+ rv = tcpc_xfer_unlocked(port, (uint8_t *)&reg, 1, NULL, 0,
+ I2C_XFER_START);
+ rv |= tcpc_xfer_unlocked(port, (uint8_t *)&cnt, 1, NULL, 0, 0);
+ rv |= tcpc_xfer_unlocked(port, (uint8_t *)&header,
+ sizeof(header), NULL, 0, 0);
+ rv |= tcpc_xfer_unlocked(port, (uint8_t *)data,
+ cnt-sizeof(header), NULL, 0,
+ I2C_XFER_STOP);
+ tcpc_lock(port, 0);
+
+ /* If tcpc write fails, return error */
+ if (rv)
+ return rv;
+ } else {
+ /* TX_BYTE_CNT includes extra bytes for message header */
+ rv = tcpc_write(port, TCPC_REG_TX_BYTE_CNT,
+ cnt + sizeof(header));
- if (cnt > 0) {
- rv = tcpc_write_block(port, reg, (const uint8_t *)data, cnt);
+ rv |= tcpc_write16(port, TCPC_REG_TX_HDR, header);
- /* If tcpc read fails, return error */
+ /* If tcpc write fails, return error */
if (rv)
return rv;
+
+ if (cnt > 0) {
+ rv = tcpc_write_block(port, reg, (const uint8_t *)data,
+ cnt);
+
+ /* If tcpc write fails, return error */
+ if (rv)
+ return rv;
+ }
}
+
/*
* On receiving a received message on SOP, protocol layer
* discards the pending SOP messages queued for transmission.
@@ -969,6 +1053,7 @@ int tcpci_tcpm_init(int port)
int error;
int power_status;
int tries = TCPM_INIT_TRIES;
+ int regval;
/* Start with an unknown connection */
tcpci_set_cached_pull(port, TYPEC_CC_OPEN);
@@ -990,6 +1075,19 @@ int tcpci_tcpm_init(int port)
msleep(10);
}
+ /*
+ * For TCPCI Rev 2.0, unless the TCPM sets
+ * TCPC_CONTROL.EnableLooking4ConnectionAlert bit, TCPC by default masks
+ * Alert assertion when CC_STATUS.Looking4Connection changes state.
+ */
+ if (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_V2_0) {
+ error = tcpc_read(port, TCPC_REG_TCPC_CTRL, &regval);
+ regval |= TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT;
+ error |= tcpc_write(port, TCPC_REG_TCPC_CTRL, regval);
+ if (error)
+ CPRINTS("C%d: Failed to init TCPC_CTRL!", port);
+ }
+
tcpc_write16(port, TCPC_REG_ALERT, 0xffff);
/* Initialize power_status_mask */
init_power_status_mask(port);
diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h
index bb9860bd57..b96276d243 100644
--- a/driver/tcpm/tcpci.h
+++ b/driver/tcpm/tcpci.h
@@ -56,6 +56,11 @@
#define TCPC_REG_TCPC_CTRL 0x19
#define TCPC_REG_TCPC_CTRL_SET(polarity) (polarity)
#define TCPC_REG_TCPC_CTRL_POLARITY(reg) ((reg) & 0x1)
+/*
+ * In TCPCI Rev 2.0, this bit must be set this to generate CC status alerts when
+ * a connection is found.
+ */
+#define TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT (BIT(6))
#define TCPC_REG_ROLE_CTRL 0x1a
#define TCPC_REG_ROLE_CTRL_DRP_MASK BIT(6)
@@ -151,12 +156,20 @@
#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
+
+/* TCPCI Rev 1.0 receive registers */
#define TCPC_REG_RX_BYTE_CNT 0x30
#define TCPC_REG_RX_BUF_FRAME_TYPE 0x31
-
#define TCPC_REG_RX_HDR 0x32
#define TCPC_REG_RX_DATA 0x34 /* through 0x4f */
+/*
+ * In TCPCI Rev 2.0, the RECEIVE_BUFFER is comprised of three sets of registers:
+ * READABLE_BYTE_COUNT, RX_BUF_FRAME_TYPE and RX_BUF_BYTE_x. These registers can
+ * only be accessed by reading at a common register address 30h.
+ */
+#define TCPC_REG_RX_BUFFER 0x30
+
#define TCPC_REG_TRANSMIT 0x50
#define TCPC_REG_TRANSMIT_SET_WITH_RETRY(type) \
(PD_RETRY_COUNT << 4 | (type))
@@ -164,10 +177,19 @@
#define TCPC_REG_TRANSMIT_RETRY(reg) (((reg) & 0x30) >> 4)
#define TCPC_REG_TRANSMIT_TYPE(reg) ((reg) & 0x7)
+/* TCPCI Rev 1.0 transmit registers */
#define TCPC_REG_TX_BYTE_CNT 0x51
#define TCPC_REG_TX_HDR 0x52
#define TCPC_REG_TX_DATA 0x54 /* through 0x6f */
+/*
+ * In TCPCI Rev 2.0, the TRANSMIT_BUFFER holds the I2C_WRITE_BYTE_COUNT and the
+ * portion of the SOP* USB PD message payload (including the header and/or the
+ * data bytes) most recently written by the TCPM in TX_BUF_BYTE_x. TX_BUF_BYTE_x
+ * is “hidden” and can only be accessed by writing to register address 51h
+ */
+#define TCPC_REG_TX_BUFFER 0x51
+
#define TCPC_REG_VBUS_VOLTAGE 0x70
#define TCPC_REG_VBUS_SINK_DISCONNECT_THRESH 0x72
#define TCPC_REG_VBUS_STOP_DISCHARGE_THRESH 0x74
diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h
index 9d6cbec160..9a4140afb4 100644
--- a/include/usb_pd_tcpm.h
+++ b/include/usb_pd_tcpm.h
@@ -355,10 +355,12 @@ struct tcpm_drv {
* Bit 0 --> Polarity for TCPC alert. Set to 1 if alert is active high.
* Bit 1 --> Set to 1 if TCPC alert line is open-drain instead of push-pull.
* Bit 2 --> Polarity for TCPC reset. Set to 1 if reset line is active high.
+ * Bit 3 --> Set to 1 if TCPC is using TCPCI Version 2.0
*/
#define TCPC_FLAGS_ALERT_ACTIVE_HIGH BIT(0)
#define TCPC_FLAGS_ALERT_OD BIT(1)
#define TCPC_FLAGS_RESET_ACTIVE_HIGH BIT(2)
+#define TCPC_FLAGS_TCPCI_V2_0 BIT(3)
struct tcpc_config_t {
enum ec_bus_type bus_type; /* enum ec_bus_type */