diff options
Diffstat (limited to 'common/usb_pd_protocol.c')
-rw-r--r-- | common/usb_pd_protocol.c | 107 |
1 files changed, 105 insertions, 2 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 542d388a3e..a22d22fd4f 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -630,7 +630,19 @@ static inline void set_state(int port, enum pd_states next_state) #ifdef CONFIG_USB_PD_TCPC_LOW_POWER if (next_state != PD_STATE_DRP_AUTO_TOGGLE) exit_low_power_mode(port); -#endif + +#ifdef CONFIG_USBC_PPC + /* If we're entering DRP_AUTO_TOGGLE, there is no sink connected. */ + if (next_state == PD_STATE_DRP_AUTO_TOGGLE) { + ppc_sink_is_connected(port, 0); + /* + * Clear the overcurrent event counter + * since we've detected a disconnect. + */ + ppc_clear_oc_event_counter(port); + } +#endif /* CONFIG_USBC_PPC */ +#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */ #ifdef CONFIG_USB_PD_DUAL_ROLE #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE @@ -648,6 +660,23 @@ static inline void set_state(int port, enum pd_states next_state) if (next_state == PD_STATE_SRC_DISCONNECTED || next_state == PD_STATE_SNK_DISCONNECTED) { +#ifdef CONFIG_USBC_PPC + int cc1, cc2; + + tcpm_get_cc(port, &cc1, &cc2); + /* + * Neither a debug accessory nor UFP attached. + * Tell the PPC module that there is no sink connected. + */ + if (cc1 != TYPEC_CC_VOLT_RD && cc2 != TYPEC_CC_VOLT_RD) { + ppc_sink_is_connected(port, 0); + /* + * Clear the overcurrent event counter + * since we've detected a disconnect. + */ + ppc_clear_oc_event_counter(port); + } +#endif /* CONFIG_USBC_PPC */ /* Clear the input current limit */ pd_set_input_current_limit(port, 0, 0); #ifdef CONFIG_CHARGE_MANAGER @@ -2841,6 +2870,15 @@ void pd_task(void *u) } #endif +#ifdef CONFIG_USBC_PPC + /* + * TODO: Useful for non-PPC cases as well, but only needed + * for PPC cases right now. Revisit later. + */ + if (evt & PD_EVENT_SEND_HARD_RESET) + set_state(port, PD_STATE_HARD_RESET_SEND); +#endif /* defined(CONFIG_USBC_PPC) */ + /* process any potential incoming message */ incoming_packet = tcpm_has_pending_message(port); if (incoming_packet) { @@ -2985,9 +3023,23 @@ void pd_task(void *u) if (get_time().val < pd[port].cc_debounce) break; - /* Debounce complete. UFP is attached */ + /* Debounce complete */ +#ifdef CONFIG_USBC_PPC + /* + * If the port is latched off, just continue to + * monitor for a detach. + */ + if (ppc_is_port_latched_off(port)) + break; +#endif /* CONFIG_USBC_PPC */ + + /* UFP is attached */ if (new_cc_state == PD_CC_UFP_ATTACHED || new_cc_state == PD_CC_DEBUG_ACC) { +#ifdef CONFIG_USBC_PPC + /* Inform PPC that a sink is connected. */ + ppc_sink_is_connected(port, 1); +#endif /* CONFIG_USBC_PPC */ pd[port].polarity = (cc1 != TYPEC_CC_VOLT_RD); set_polarity(port, pd[port].polarity); @@ -4453,6 +4505,57 @@ void pd_update_contract(int port) #endif /* CONFIG_USB_PD_DUAL_ROLE */ +#ifdef CONFIG_USBC_PPC +static void pd_send_hard_reset(int port) +{ + task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_SEND_HARD_RESET, 0); +} + +static uint32_t port_oc_reset_req; + +static void re_enable_ports(void) +{ + uint32_t ports = atomic_read_clear(&port_oc_reset_req); + + while (ports) { + int port = __fls(ports); + + ports &= ~(1 << port); + + /* + * Let the board know that the overcurrent is + * over since we're going to attempt re-enabling + * the port. + */ + board_overcurrent_event(port, 0); + + pd_send_hard_reset(port); + /* + * TODO(b/117854867): PD3.0 to send an alert message + * indicating OCP after explicit contract. + */ + } +} +DECLARE_DEFERRED(re_enable_ports); + +void pd_handle_overcurrent(int port) +{ + /* Keep track of the overcurrent events. */ + CPRINTS("C%d: overcurrent!", port); +#ifdef CONFIG_USB_PD_LOGGING + pd_log_event(PD_EVENT_PS_FAULT, PD_LOG_PORT_SIZE(port, 0), PS_FAULT_OCP, + NULL); +#endif /* defined(CONFIG_USB_PD_LOGGING) */ + ppc_add_oc_event(port); + /* Let the board specific code know about the OC event. */ + board_overcurrent_event(port, 1); + + /* Wait 1s before trying to re-enable the port. */ + atomic_or(&port_oc_reset_req, (1 << port)); + hook_call_deferred(&re_enable_ports_data, SECOND); +} +#endif /* defined(CONFIG_USBC_PPC) */ + static int command_pd(int argc, char **argv) { int port; |