summaryrefslogtreecommitdiff
path: root/driver/tcpm/tcpci.c
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 /driver/tcpm/tcpci.c
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>
Diffstat (limited to 'driver/tcpm/tcpci.c')
-rw-r--r--driver/tcpm/tcpci.c122
1 files changed, 110 insertions, 12 deletions
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);