summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaoliang Wang <swang@analogixsemi.com>2016-09-02 18:53:44 -0700
committerchrome-bot <chrome-bot@chromium.org>2016-09-24 13:53:28 -0700
commite29005abe7497988e14e0ef87f602a5417d003e6 (patch)
tree2fe0e91397b1621ce648f8fbe78cbe1021e41603
parentb94747d501ad7e4347b50c3ea55e615422d96212 (diff)
downloadchrome-ec-e29005abe7497988e14e0ef87f602a5417d003e6.tar.gz
anx74xx: fix hard reset issue.
1.ANX3429 have CC Rx buffer, when the partner sent one message,ANX3429 received this message into Rx buffer and triggered an interrupt to inform (TCPM), at this moment Reef sends a CC message before reading CC Rx buffer. After Reef sends this CC message successfully, it receives the message the partner sent. So (TCPM) sees an unexpected message was received, that`s why sends out hard reset. Root cause: ANX3429 use a normal R/W register as a interrupt status register. Between EC read interrupt status and clear interrupt status, if ANX3429 change interrupt status, it causes interrupt status is incorrect on EC side. Solution: ANX3429 FW use two normal R/W registers for interrupt status reg, one is for FW interrupt status,other is for EC control register. Note: Since cc messages conflict between TCPM and the Partner,ANX3429 shall discard the TCPM message, (TCPM) sometimes send soft reset depend on the discarded message type. 2. Sometimes TCPM (Reef) does not response GoodCRC for a received mesg. Root Cause: Reef send message conflict with ANX3429 send auto GoodCRC. Solution: This is fixed in the 1.5 ANX 3429 firmware. BUG=chrome-os-partner:53936 BRANCH=none TEST=On Reef tested with ANX3429 FW v1.5, did not see HARD RST on ec log with Zinger. Change-Id: I81da95433e7a0cc71e7ed121b925afccbcd84b06 Signed-off-by: Swang <swang@analogixsemi.com> Signed-off-by: Divya Sasidharan <divya.s.sasidharan@intel.com> Reviewed-on: https://chromium-review.googlesource.com/381014 Commit-Ready: Kevin K Wong <kevin.k.wong@intel.com> Tested-by: Kevin K Wong <kevin.k.wong@intel.com> Reviewed-by: Kevin K Wong <kevin.k.wong@intel.com> Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r--driver/tcpm/anx74xx.c148
-rw-r--r--driver/tcpm/anx74xx.h17
2 files changed, 84 insertions, 81 deletions
diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c
index 889d4f0bd4..229e79a7c2 100644
--- a/driver/tcpm/anx74xx.c
+++ b/driver/tcpm/anx74xx.c
@@ -23,6 +23,14 @@ struct anx_state {
int vconn_en;
int mux_state;
};
+#define clear_recvd_msg_int(port) do {\
+ int reg, rv; \
+ rv = tcpc_read(port, ANX74XX_REG_RECVD_MSG_INT, &reg); \
+ if (!rv) \
+ tcpc_write(port, ANX74XX_REG_RECVD_MSG_INT, \
+ reg | 0x01); \
+ } while (0)
+
static struct anx_state anx[CONFIG_USB_PD_PORT_COUNT];
static int anx74xx_set_mux(int port, int polarity);
@@ -294,8 +302,20 @@ static int anx74xx_send_message(int port, uint16_t header,
int reg, rv = EC_SUCCESS;
uint8_t *buf = NULL;
int num_retry = 0, i = 0;
-
-
+ /* If sending Soft_reset, clear received message */
+ /* Soft Reset Message type = 1101 and Number of Data Object = 0 */
+ if ((header & 0x700f) == 0x000d) {
+ /*
+ * When sending soft reset,
+ * the Rx buffer of ANX3429 shall be clear
+ */
+ rv = tcpc_read(port, ANX74XX_REG_CTRL_FW, &reg);
+ rv |= tcpc_write(
+ port, ANX74XX_REG_CTRL_FW, reg | CLEAR_RX_BUFFER);
+ if (rv)
+ return EC_ERROR_UNKNOWN;
+ tcpc_write(port, ANX74XX_REG_RECVD_MSG_INT, 0xFF);
+ }
/* Inform chip about message length and TX type
* type->bit-0..2, len->bit-3..7
*/
@@ -375,12 +395,7 @@ static int anx74xx_read_pd_obj(int port,
break;
buf[i] = reg;
}
-
- /* Clear receive message interrupt bit(bit-0) */
- rv |= tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, &reg);
- rv |= tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG,
- reg & (~0x01));
-
+ clear_recvd_msg_int(port);
return rv;
}
@@ -388,58 +403,41 @@ static int anx74xx_tcpm_get_cc(int port, int *cc1, int *cc2)
{
int rv = EC_SUCCESS;
int reg = 0;
- int status = 0;
-
- rv |= tcpc_read(port, ANX74XX_REG_ANALOG_STATUS, &reg);
-
+ rv |= tcpc_read(port, ANX74XX_REG_CC_STATUS, &reg);
if (!anx[port].pull) {/* get CC in sink mode */
- rv |= tcpc_read(port, ANX74XX_REG_POWER_DOWN_CTRL, &reg);
- if (rv)
- return EC_ERROR_UNKNOWN;
/* CC1 */
- if (reg & ANX74XX_REG_STATUS_CC1_VRD_USB)
+ if (reg & BIT_VALUE_OF_SNK_CC1_DEFAULT)
*cc1 = TYPEC_CC_VOLT_SNK_DEF;
- else if (reg & ANX74XX_REG_STATUS_CC1_VRD_1P5)
+ else if (reg & BIT_VALUE_OF_SNK_CC1_1_P_5)
*cc1 = TYPEC_CC_VOLT_SNK_1_5;
- else if (reg & ANX74XX_REG_STATUS_CC1_VRD_3P0)
+ else if (reg & BIT_VALUE_OF_SNK_CC1_3_P_0)
*cc1 = TYPEC_CC_VOLT_SNK_3_0;
else
*cc1 = TYPEC_CC_VOLT_OPEN;
/* CC2 */
- if (reg & ANX74XX_REG_STATUS_CC2_VRD_USB)
+ if (reg & BIT_VALUE_OF_SNK_CC2_DEFAULT)
*cc2 = TYPEC_CC_VOLT_SNK_DEF;
- else if (reg & ANX74XX_REG_STATUS_CC2_VRD_1P5)
+ else if (reg & BIT_VALUE_OF_SNK_CC2_1_P_5)
*cc2 = TYPEC_CC_VOLT_SNK_1_5;
- else if (reg & ANX74XX_REG_STATUS_CC2_VRD_3P0)
+ else if (reg & BIT_VALUE_OF_SNK_CC2_3_P_0)
*cc2 = TYPEC_CC_VOLT_SNK_3_0;
else
*cc2 = TYPEC_CC_VOLT_OPEN;
} else {/* get CC in source mode */
- rv |= tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_7, &reg);
- if (rv)
- return EC_ERROR_UNKNOWN;
/* CC1 */
- status = ANX74XX_REG_STATUS_CC1(reg);
- if (status) {
- if ((status & ANX74XX_REG_STATUS_CC_RA) ==
- ANX74XX_REG_STATUS_CC_RA)
- *cc1 = TYPEC_CC_VOLT_RA;
- else if (status & ANX74XX_REG_STATUS_CC_RD)
- *cc1 = TYPEC_CC_VOLT_RD;
- } else {
- *cc1 = TYPEC_CC_VOLT_OPEN;
- }
+ if (reg & BIT_VALUE_OF_SRC_CC1_RA)
+ *cc1 = TYPEC_CC_VOLT_RA;
+ else if (reg & BIT_VALUE_OF_SRC_CC1_RD)
+ *cc1 = TYPEC_CC_VOLT_RD;
+ else
+ *cc1 = TYPEC_CC_VOLT_OPEN;
/* CC2 */
- status = ANX74XX_REG_STATUS_CC2(reg);
- if (status) {
- if ((status & ANX74XX_REG_STATUS_CC_RA) ==
- ANX74XX_REG_STATUS_CC_RA)
- *cc2 = TYPEC_CC_VOLT_RA;
- else if (status & ANX74XX_REG_STATUS_CC_RD)
- *cc2 = TYPEC_CC_VOLT_RD;
- } else {
- *cc2 = TYPEC_CC_VOLT_OPEN;
- }
+ if (reg & BIT_VALUE_OF_SRC_CC2_RA)
+ *cc2 = TYPEC_CC_VOLT_RA;
+ else if (reg & BIT_VALUE_OF_SRC_CC2_RD)
+ *cc2 = TYPEC_CC_VOLT_RD;
+ else
+ *cc2 = TYPEC_CC_VOLT_OPEN;
}
/* clear HPD status*/
if (!(*cc1) && !(*cc2)) {
@@ -600,41 +598,32 @@ static int anx74xx_alert_status(int port, int *alert)
/* Clear soft irq bit */
rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_3,
ANX74XX_REG_CLEAR_SOFT_IRQ);
-
- /* Read TCPC Alert register1 */
- rv |= tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, &reg);
- if (rv)
- return EC_ERROR_UNKNOWN;
-
- /* Clears interrupt bits */
- rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, reg);
-
- *alert = reg;
+ *alert = 0;
rv = tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, &reg);
if (rv)
return EC_ERROR_UNKNOWN;
- rv |= tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, 0);
+
+ /*Clear msg received bit, until read it by TCPM*/
+ rv |= tcpc_write(port, ANX74XX_REG_RECVD_MSG_INT, (reg & 0xFE));
if (reg & ANX74XX_REG_IRQ_CC_MSG_INT)
*alert |= ANX74XX_REG_ALERT_MSG_RECV;
- else
- *alert &= (~ANX74XX_REG_ALERT_MSG_RECV);
- if (reg & ANX74XX_REG_IRQ_CC_STATUS_INT) {
+ if (reg & ANX74XX_REG_IRQ_CC_STATUS_INT)
*alert |= ANX74XX_REG_ALERT_CC_CHANGE;
- } else {
- *alert &= (~ANX74XX_REG_ALERT_CC_CHANGE);
- }
- if (reg & ANX74XX_REG_IRQ_GOOD_CRC_INT) {
+ if (reg & ANX74XX_REG_IRQ_GOOD_CRC_INT)
*alert |= ANX74XX_REG_ALERT_TX_ACK_RECV;
- } else {
- *alert &= (~ANX74XX_REG_ALERT_TX_ACK_RECV);
- }
- if (reg & ANX74XX_REG_IRQ_TX_FAIL_INT) {
+ if (reg & ANX74XX_REG_IRQ_TX_FAIL_INT)
*alert |= ANX74XX_REG_ALERT_TX_MSG_ERROR;
- }
+
+ rv |= tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, &reg);
+ if (rv)
+ return EC_ERROR_UNKNOWN;
+ /* Clears interrupt bits */
+ rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, reg);
+
/* Read TCPC Alert register2 */
rv |= tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_2, &reg);
@@ -643,8 +632,6 @@ static int anx74xx_alert_status(int port, int *alert)
if (reg & ANX74XX_REG_EXT_HARD_RST)
*alert |= ANX74XX_REG_ALERT_HARD_RST_RECV;
- else
- *alert &= (~ANX74XX_REG_ALERT_HARD_RST_RECV);
return rv;
}
@@ -661,11 +648,14 @@ static int anx74xx_tcpm_set_rx_enable(int port, int enable)
anx74xx_tcpm_set_auto_good_crc(port, 1);
anx74xx_rp_control(port, selected_rp);
} else {
- /* Disable RX message by masking interrupt */
+ /* Disable RX message by masking interrupt */
reg |= (ANX74XX_REG_IRQ_CC_MSG_INT);
anx74xx_tcpm_set_auto_good_crc(port, 0);
anx74xx_rp_control(port, TYPEC_RP_USB);
}
+ /*When this function was call, the interrupt status shall be cleared*/
+ tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, 0);
+
return tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG_MASK, reg);
}
@@ -688,21 +678,15 @@ static int anx74xx_tcpm_get_message(int port, uint32_t *payload, int *head)
rv |= tcpc_read16(port, ANX74XX_REG_PD_HEADER, &reg);
if (rv) {
*head = 0;
- /* Clear receive message interrupt bit(bit-0) */
- tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, &reg);
- tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG,
- reg & (~0x01));
-
+ clear_recvd_msg_int(port);
return EC_ERROR_UNKNOWN;
}
*head = reg;
+
len = PD_HEADER_CNT(*head) * 4;
if (!len) {
- /* Clear receive message interrupt bit(bit-0) */
- tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, &reg);
- tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG,
- reg & (~0x01));
- return EC_SUCCESS;
+ clear_recvd_msg_int(port);
+ return EC_SUCCESS;
}
/* Receive message : assuming payload have enough
@@ -738,6 +722,8 @@ static int anx74xx_tcpm_transmit(int port, enum tcpm_transmit_type type,
tcpc_read(port, ANX74XX_REG_TX_CTRL_1, &reg);
reg |= ANX74XX_REG_TX_HARD_RESET_REQ;
ret = tcpc_write(port, ANX74XX_REG_TX_CTRL_1, reg);
+ /*After Hard Reset, TCPM shall disable goodCRC*/
+ anx74xx_tcpm_set_auto_good_crc(port, 0);
break;
case TCPC_TX_CABLE_RESET:
/* Request CABLE RESET */
@@ -772,7 +758,7 @@ void anx74xx_tcpc_alert(int port)
{
int status;
- /* Check the alert status */
+ /* Check the alert status from anx74xx */
if (anx74xx_alert_status(port, &status))
status = 0;
if (status) {
diff --git a/driver/tcpm/anx74xx.h b/driver/tcpm/anx74xx.h
index 8fc81c0bc0..6e31dbdf7d 100644
--- a/driver/tcpm/anx74xx.h
+++ b/driver/tcpm/anx74xx.h
@@ -152,6 +152,10 @@
#define ANX74XX_REG_PWR_ROLE_BIT_POS (2)
#define ANX74XX_REG_DATA_ROLE_BIT_POS (1)
+#define ANX74XX_REG_RECVD_MSG_INT 0x98
+#define ANX74XX_REG_CC_STATUS 0x99
+#define ANX74XX_REG_CTRL_FW 0x2E
+#define CLEAR_RX_BUFFER (1)
#define ANX74XX_REG_POWER_DOWN_CTRL 0x0d
#define ANX74XX_REG_STATUS_CC1_VRD_USB (1 << 7)
#define ANX74XX_REG_STATUS_CC1_VRD_1P5 (1 << 6)
@@ -160,6 +164,19 @@
#define ANX74XX_REG_STATUS_CC2_VRD_1P5 (1 << 3)
#define ANX74XX_REG_STATUS_CC2_VRD_3P0 (1 << 2)
+/* defined in the inter-bock Spec: 4.2.10 CC Detect Status */
+
+#define BIT_VALUE_OF_SRC_CC1_RD 0x01
+#define BIT_VALUE_OF_SRC_CC1_RA 0x02
+#define BIT_VALUE_OF_SNK_CC1_DEFAULT 0x04
+#define BIT_VALUE_OF_SNK_CC1_1_P_5 0x08
+#define BIT_VALUE_OF_SNK_CC1_3_P_0 0x0C
+#define BIT_VALUE_OF_SRC_CC2_RD 0x10
+#define BIT_VALUE_OF_SRC_CC2_RA 0x20
+#define BIT_VALUE_OF_SNK_CC2_DEFAULT 0x40
+#define BIT_VALUE_OF_SNK_CC2_1_P_5 0x80
+#define BIT_VALUE_OF_SNK_CC2_3_P_0 0xC0
+
extern const struct tcpm_drv anx74xx_tcpm_drv;
extern const struct usb_mux_driver anx74xx_tcpm_usb_mux_driver;
void anx74xx_tcpc_set_vbus(int port, int enable);