diff options
-rw-r--r-- | common/usb_pd_protocol.c | 42 | ||||
-rw-r--r-- | common/usb_pd_tcpc.c | 18 | ||||
-rw-r--r-- | driver/tcpm/stub.c | 13 | ||||
-rw-r--r-- | driver/tcpm/tcpci.c | 39 | ||||
-rw-r--r-- | driver/tcpm/tcpci.h | 2 | ||||
-rw-r--r-- | include/usb_pd.h | 10 |
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, ®); + + 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, ®); + /* 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 |