summaryrefslogtreecommitdiff
path: root/driver/tcpm/anx74xx.c
diff options
context:
space:
mode:
authorJett Rink <jettrink@chromium.org>2018-08-17 13:33:02 -0600
committerchrome-bot <chrome-bot@chromium.org>2018-09-07 18:36:36 -0700
commite8070b44b088e99e38ec741ed8091c7e4a033bef (patch)
treededc7bce6201fba05b92f4e48ec4405366fbc76b /driver/tcpm/anx74xx.c
parente6a13850e9b5a6b2889549c03caddf2944e7fc63 (diff)
downloadchrome-ec-e8070b44b088e99e38ec741ed8091c7e4a033bef.tar.gz
tcpm: add TCPC RX circular buffer in EC
The alert line for TCPC will stay asserted as long as there are RX messages for the TCPM (i.e. EC) to pull from the TCPC. We should clear all of the RX messages we know about during a single alert handling session. This CL can stand on its own, but it is a part of a CL stack that will tighten the critical section of time between received messages from the TCPC and sending follow up message out through the TCPC. See go/usb-pd-slow-response-time for more details. BRANCH=none BUG=b:112088135,b:112344286,b:111909282,b:112848644,b:113124761 BUG=b:113057273,b:112825261 TEST=Reduces reset issue in most cases for phaser, bobba. Does not seem to adversely affect state machine negotiation. Full CL stack consistently sends a REQUEST at 18ms after a SRC_CAP GoodCRC, which is well below the 24 ms threshold we need to be under for USB PD spec compliance. Also testing pd_suspend scenario manually and EC was responsive after port 1 suspend because of "bad behavior" Change-Id: I1654b46400e9881f2927a5f6d6ace589edd182de Signed-off-by: Jett Rink <jettrink@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1185727
Diffstat (limited to 'driver/tcpm/anx74xx.c')
-rw-r--r--driver/tcpm/anx74xx.c71
1 files changed, 51 insertions, 20 deletions
diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c
index 669966ddee..9164b9a313 100644
--- a/driver/tcpm/anx74xx.c
+++ b/driver/tcpm/anx74xx.c
@@ -7,6 +7,7 @@
/* Type-C port manager for Analogix's anx74xx chips */
+#include "console.h"
#include "anx74xx.h"
#include "task.h"
#include "tcpci.h"
@@ -23,6 +24,9 @@
#error "Please upgrade your board configuration"
#endif
+#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
+#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
+
struct anx_state {
int polarity;
int vconn_en;
@@ -828,7 +832,7 @@ static int anx74xx_tcpm_get_vbus_level(int port)
}
#endif
-static int anx74xx_tcpm_get_message(int port, uint32_t *payload, int *head)
+static int anx74xx_tcpm_get_message_raw(int port, uint32_t *payload, int *head)
{
int reg = 0, rv = EC_SUCCESS;
int len = 0;
@@ -910,37 +914,63 @@ static int anx74xx_tcpm_transmit(int port, enum tcpm_transmit_type type,
return ret;
}
+/*
+ * Don't let the TCPC try to pull from the RX buffer forever. We typical only
+ * have 1 or 2 messages waiting.
+ */
+#define MAX_ALLOW_FAILED_RX_READS 10
+
void anx74xx_tcpc_alert(int port)
{
int reg;
+ int failed_attempts;
/* Clear soft irq bit */
tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_3,
- ANX74XX_REG_CLEAR_SOFT_IRQ);
-
- if (tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, &reg))
- return;
-
- /* Don't clear msg received bit, until read it is by TCPM */
- tcpc_write(port, ANX74XX_REG_RECVD_MSG_INT, (reg & 0xFE));
-
- if (reg & ANX74XX_REG_IRQ_CC_MSG_INT)
- /* Set a PD_EVENT_RX */
- task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0);
+ ANX74XX_REG_CLEAR_SOFT_IRQ);
- if (reg & ANX74XX_REG_IRQ_CC_STATUS_INT)
- /* CC status changed, wake task */
- task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
+ /* Read main alert register for pending alerts */
+ reg = 0;
+ tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, &reg);
+ /* Prioritize TX completion because PD state machine is waiting */
if (reg & ANX74XX_REG_IRQ_GOOD_CRC_INT)
- /* Inform PD about this TX success */
pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS);
if (reg & ANX74XX_REG_IRQ_TX_FAIL_INT)
- /* let PD does not wait for this */
pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED);
- /* Read and Clear register1 */
+ /* Pull all RX messages from TCPC into EC memory */
+ failed_attempts = 0;
+ while (reg & ANX74XX_REG_IRQ_CC_MSG_INT) {
+ if (tcpm_enqueue_message(port))
+ ++failed_attempts;
+ if (tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, &reg))
+ ++failed_attempts;
+
+ /* Ensure we don't loop endlessly */
+ if (failed_attempts >= MAX_ALLOW_FAILED_RX_READS) {
+ CPRINTF("C%d Cannot consume RX buffer after %d failed "
+ "attempts!",
+ failed_attempts);
+ /*
+ * The port is in a bad state, we don't want to consume
+ * all EC resources so suspend port forever.
+ */
+ pd_set_suspend(port, 1);
+ return;
+ }
+ }
+
+ /* Clear all pending alerts */
+ tcpc_write(port, ANX74XX_REG_RECVD_MSG_INT, reg);
+
+ if (reg & ANX74XX_REG_IRQ_CC_STATUS_INT)
+ /* CC status changed, wake task */
+ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
+
+ /* Read and clear extended alert register 1 */
+ reg = 0;
tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, &reg);
tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, reg);
@@ -949,7 +979,8 @@ void anx74xx_tcpc_alert(int port)
/* ANX hardware clears the request bit */
pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS);
- /* Read and Clear TCPC Alert register2 */
+ /* Read and clear TCPC extended alert register 2 */
+ reg = 0;
tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_2, &reg);
tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_2, reg);
@@ -1054,7 +1085,7 @@ const struct tcpm_drv anx74xx_tcpm_drv = {
.set_vconn = &anx74xx_tcpm_set_vconn,
.set_msg_header = &anx74xx_tcpm_set_msg_header,
.set_rx_enable = &anx74xx_tcpm_set_rx_enable,
- .get_message = &anx74xx_tcpm_get_message,
+ .get_message_raw = &anx74xx_tcpm_get_message_raw,
.transmit = &anx74xx_tcpm_transmit,
.tcpc_alert = &anx74xx_tcpc_alert,
#ifdef CONFIG_USB_PD_DISCHARGE_TCPC