summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usb_pd_protocol.c42
-rw-r--r--common/usb_pd_tcpc.c18
-rw-r--r--driver/tcpm/stub.c13
-rw-r--r--driver/tcpm/tcpci.c39
-rw-r--r--driver/tcpm/tcpci.h2
-rw-r--r--include/usb_pd.h10
6 files changed, 96 insertions, 28 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 9ddccb80c4..8154d9ecee 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -285,6 +285,10 @@ static inline void set_state(int port, enum pd_states next_state)
#else /* CONFIG_USB_PD_DUAL_ROLE */
if (next_state == PD_STATE_SRC_DISCONNECTED) {
#endif
+ /* If we are source, make sure VBUS is off */
+ if (pd[port].power_role == PD_ROLE_SOURCE)
+ pd_power_supply_reset(port);
+
pd[port].dev_id = 0;
pd[port].flags &= ~PD_FLAGS_RESET_ON_DISCONNECT_MASK;
#ifdef CONFIG_CHARGE_MANAGER
@@ -1406,9 +1410,11 @@ void pd_task(void)
/* Ensure the power supply is in the default state */
pd_power_supply_reset(port);
+#ifdef CONFIG_USB_PD_TCPC
/* Initialize TCPM driver and wait for TCPC to be ready */
tcpm_init(port);
CPRINTF("[%T TCPC p%d ready]\n", port);
+#endif
/* Disable TCPC RX until connection is established */
tcpm_set_rx_enable(port, 0);
@@ -1460,6 +1466,36 @@ void pd_task(void)
* messages
*/
tcpc_run(port, evt);
+#else
+ /* if TCPC has reset, then need to initialize it again */
+ if (evt & PD_EVENT_TCPC_RESET) {
+ CPRINTF("[%T TCPC p%d reset!]\n", port);
+ tcpm_init(port);
+
+ /* Ensure CC termination is default */
+ tcpm_set_cc(port, PD_ROLE_DEFAULT == PD_ROLE_SOURCE ?
+ TYPEC_CC_RP :
+ TYPEC_CC_RD);
+
+ /*
+ * If we have a stable contract in the default role,
+ * then simply update TCPC with some missing info
+ * so that we can continue without resetting PD comms.
+ * Otherwise, go to the default disconnected state
+ * and force renegotiation.
+ */
+ if ((PD_ROLE_DEFAULT == PD_ROLE_SINK &&
+ pd[port].task_state == PD_STATE_SNK_READY) ||
+ (PD_ROLE_DEFAULT == PD_ROLE_SOURCE &&
+ pd[port].task_state == PD_STATE_SRC_READY)) {
+ tcpm_set_polarity(port, pd[port].polarity);
+ tcpm_set_msg_header(port, pd[port].power_role,
+ pd[port].data_role);
+ tcpm_set_rx_enable(port, 1);
+ } else {
+ set_state(port, PD_DEFAULT_STATE);
+ }
+ }
#endif
/* process any potential incoming message */
@@ -1538,10 +1574,6 @@ void pd_task(void)
new_cc_state = PD_CC_AUDIO_ACC;
} else {
/* No UFP */
-#ifdef CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP
- /* No connection any more, remove VBUS */
- pd_power_supply_reset(port);
-#endif
set_state(port, PD_STATE_SRC_DISCONNECTED);
timeout = 5*MSEC;
break;
@@ -1761,7 +1793,6 @@ void pd_task(void)
set_state(port, PD_STATE_SRC_READY);
} else {
/* The sink did not ack, cut the power... */
- pd_power_supply_reset(port);
set_state(port, PD_STATE_SRC_DISCONNECTED);
}
break;
@@ -2510,7 +2541,6 @@ void pd_task(void)
if (pd[port].polarity)
cc1 = cc2;
if (cc1 == TYPEC_CC_VOLT_OPEN) {
- pd_power_supply_reset(port);
set_state(port, PD_STATE_SRC_DISCONNECTED);
/* Debouncing */
timeout = 10*MSEC;
diff --git a/common/usb_pd_tcpc.c b/common/usb_pd_tcpc.c
index cad272f9a3..99867e338a 100644
--- a/common/usb_pd_tcpc.c
+++ b/common/usb_pd_tcpc.c
@@ -1069,6 +1069,13 @@ void tcpc_init(int port)
tcpc_set_power_status(port, !gpio_get_level(GPIO_USB_C0_VBUS_WAKE_L));
#endif /* CONFIG_USB_PD_PORT_COUNT >= 2 */
#endif /* CONFIG_USB_PD_TCPM_VBUS */
+
+ /* set default alert and power mask register values */
+ pd[port].alert_mask = TCPC_REG_ALERT_MASK_ALL;
+ pd[port].power_status_mask = TCPC_REG_POWER_STATUS_MASK_ALL;
+
+ /* set power status alert since the UNINIT bit has been set */
+ alert(port, TCPC_REG_ALERT_POWER_STATUS);
}
#ifdef CONFIG_USB_PD_TCPM_VBUS
@@ -1201,6 +1208,9 @@ static int tcpc_i2c_read(int port, int reg, uint8_t *payload)
case TCPC_REG_POWER_STATUS:
payload[0] = pd[port].power_status;
return 1;
+ case TCPC_REG_POWER_STATUS_MASK:
+ payload[0] = pd[port].power_status_mask;
+ return 1;
case TCPC_REG_TX_BYTE_CNT:
payload[0] = PD_HEADER_CNT(pd[port].tx_head);
return 1;
@@ -1299,12 +1309,14 @@ static int command_tcpc(int argc, char **argv)
ccprintf("set TX frequency to %d Hz\n", freq);
return EC_SUCCESS;
} else if (!strncasecmp(argv[2], "state", 5)) {
- ccprintf("Port C%d, %s - CC:%d, CC0:%d, CC1:%d, "
- "Alert: 0x%02x\n", port,
+ ccprintf("Port C%d, %s - CC:%d, CC0:%d, CC1:%d\n"
+ "Alert: 0x%02x Mask: 0x%04x\n"
+ "Power Status: 0x%02x Mask: 0x%02x\n", port,
pd[port].rx_enabled ? "Ena" : "Dis",
pd[port].cc_pull,
pd[port].cc_status[0], pd[port].cc_status[1],
- pd[port].alert);
+ pd[port].alert, pd[port].alert_mask,
+ pd[port].power_status, pd[port].power_status_mask);
}
return EC_SUCCESS;
diff --git a/driver/tcpm/stub.c b/driver/tcpm/stub.c
index 35f0329484..08c5f37a35 100644
--- a/driver/tcpm/stub.c
+++ b/driver/tcpm/stub.c
@@ -43,10 +43,21 @@ static int init_alert_mask(int port)
return rv;
}
+static int init_power_status_mask(int port)
+{
+ return tcpm_set_power_status_mask(port, 0);
+}
+
int tcpm_init(int port)
{
+ int rv;
+
tcpc_init(port);
- return init_alert_mask(port);
+ rv = init_alert_mask(port);
+ if (rv)
+ return rv;
+
+ return init_power_status_mask(port);
}
int tcpm_get_cc(int port, int *cc1, int *cc2)
diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c
index 149e7c9f5e..6d0a38f3c1 100644
--- a/driver/tcpm/tcpci.c
+++ b/driver/tcpm/tcpci.c
@@ -42,18 +42,20 @@ static int init_alert_mask(int port)
return rv;
}
-#ifdef CONFIG_USB_PD_TCPM_VBUS
static int init_power_status_mask(int port)
{
uint8_t mask;
int rv;
+#ifdef CONFIG_USB_PD_TCPM_VBUS
mask = TCPC_REG_POWER_STATUS_VBUS_PRES;
+#else
+ mask = 0;
+#endif
rv = tcpm_set_power_status_mask(port, mask);
return rv;
}
-#endif
int tcpm_get_cc(int port, int *cc1, int *cc2)
{
@@ -220,7 +222,6 @@ int tcpm_transmit(int port, enum tcpm_transmit_type type, uint16_t header,
void tcpc_alert(int port)
{
int status;
- int power_status;
/* Read the Alert register from the TCPC */
tcpm_alert_status(port, &status);
@@ -238,16 +239,30 @@ void tcpc_alert(int port)
task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
}
if (status & TCPC_REG_ALERT_POWER_STATUS) {
- /* Read Power Status register */
- tcpm_get_power_status(port, &power_status);
- /* Update VBUS status */
- tcpc_vbus[port] = power_status &
- TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0;
+ int reg = 0;
+
+ i2c_read8(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
+ TCPC_REG_POWER_STATUS_MASK, &reg);
+
+ if (reg == TCPC_REG_POWER_STATUS_MASK_ALL) {
+ /*
+ * If power status mask has been reset, then the TCPC
+ * has reset.
+ */
+ task_set_event(PD_PORT_TO_TASK_ID(port),
+ PD_EVENT_TCPC_RESET, 0);
+ } else {
+ /* Read Power Status register */
+ tcpm_get_power_status(port, &reg);
+ /* Update VBUS status */
+ tcpc_vbus[port] = reg &
+ TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0;
#if defined(CONFIG_USB_PD_TCPM_VBUS) && defined(CONFIG_USB_CHARGER)
- /* Update charge manager with new VBUS state */
- usb_charger_vbus_change(port, tcpc_vbus[port]);
+ /* Update charge manager with new VBUS state */
+ usb_charger_vbus_change(port, tcpc_vbus[port]);
#endif /* CONFIG_USB_PD_TCPM_VBUS && CONFIG_USB_CHARGER */
- task_wake(PD_PORT_TO_TASK_ID(port));
+ task_wake(PD_PORT_TO_TASK_ID(port));
+ }
}
if (status & TCPC_REG_ALERT_RX_STATUS) {
/* message received */
@@ -283,13 +298,11 @@ int tcpm_init(int port)
!(power_status & TCPC_REG_POWER_STATUS_UNINIT)) {
i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
TCPC_REG_ALERT, 0xffff);
-#ifdef CONFIG_USB_PD_TCPM_VBUS
/* Initialize power_status_mask */
init_power_status_mask(port);
/* Update VBUS status */
tcpc_vbus[port] = power_status &
TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0;
-#endif
return init_alert_mask(port);
}
msleep(10);
diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h
index da6e412669..d105ea5361 100644
--- a/driver/tcpm/tcpci.h
+++ b/driver/tcpm/tcpci.h
@@ -16,6 +16,7 @@
#define TCPC_REG_PD_INT_REV 0xa
#define TCPC_REG_ALERT 0x10
+#define TCPC_REG_ALERT_MASK_ALL 0xfff
#define TCPC_REG_ALERT_VBUS_DISCNCT (1<<11)
#define TCPC_REG_ALERT_RX_BUF_OVF (1<<10)
#define TCPC_REG_ALERT_FAULT (1<<9)
@@ -59,6 +60,7 @@
#define TCPC_REG_CC_STATUS_CC1(reg) ((reg) & 0x3)
#define TCPC_REG_POWER_STATUS 0x1e
+#define TCPC_REG_POWER_STATUS_MASK_ALL 0xff
#define TCPC_REG_POWER_STATUS_VBUS_PRES (1<<2)
#define TCPC_REG_POWER_STATUS_VBUS_DET (1<<3)
#define TCPC_REG_POWER_STATUS_UNINIT (1<<6)
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 3a1d306c86..f6a1e1b72e 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -42,11 +42,11 @@ enum pd_rx_errors {
PD_RX_ERR_CABLE_RESET = -6 /* Got a Cable-Reset packet */
};
-/* incoming/outgoing packet event (for the USB PD task) */
-#define PD_EVENT_RX (1<<2)
-#define PD_EVENT_TX (1<<3)
-/* CC line change event */
-#define PD_EVENT_CC (1<<4)
+/* Events for USB PD task */
+#define PD_EVENT_RX (1<<2) /* Incoming packet event */
+#define PD_EVENT_TX (1<<3) /* Outgoing packet event */
+#define PD_EVENT_CC (1<<4) /* CC line change event */
+#define PD_EVENT_TCPC_RESET (1<<5) /* TCPC has reset */
/* --- PD data message helpers --- */
#define PDO_MAX_OBJECTS 7