diff options
-rw-r--r-- | common/usb_pd_protocol.c | 122 | ||||
-rw-r--r-- | test/usb_pd.c | 6 |
2 files changed, 105 insertions, 23 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 0c86180bbb..857a6b7a46 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -642,11 +642,7 @@ static inline void set_state(int port, enum pd_states next_state) if (last_state == next_state) return; -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - if (next_state != PD_STATE_DRP_AUTO_TOGGLE) - exit_low_power_mode(port); - -#ifdef CONFIG_USBC_PPC +#if defined(CONFIG_USBC_PPC) && defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) /* 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); @@ -656,8 +652,7 @@ static inline void set_state(int port, enum pd_states next_state) */ ppc_clear_oc_event_counter(port); } -#endif /* CONFIG_USBC_PPC */ -#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */ +#endif /* CONFIG_USBC_PPC && CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE */ #ifdef CONFIG_USB_PD_DUAL_ROLE #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE @@ -2414,10 +2409,39 @@ static enum pd_states drp_auto_toggle_next_state(int port, int cc1, int cc2) enum pd_states next_state; /* Set to appropriate port state */ - if (cc_is_open(cc1, cc2)) - /* nothing connected, keep toggling*/ - next_state = PD_STATE_DRP_AUTO_TOGGLE; - else if ((cc_is_rp(cc1) || cc_is_rp(cc2)) && + if (cc_is_open(cc1, cc2)) { + /* + * If nothing is attached then use drp_state to determine next + * state. If DRP auto toggle is still on, then remain in the + * DRP_AUTO_TOGGLE state. Otherwise, stop dual role toggling + * and go to a disconnected state. + */ + switch (drp_state[port]) { + case PD_DRP_TOGGLE_OFF: + next_state = PD_DEFAULT_STATE(port); + break; + + case PD_DRP_FREEZE: + if (pd[port].power_role == PD_ROLE_SINK) + next_state = PD_STATE_SNK_DISCONNECTED; + else + next_state = PD_STATE_SRC_DISCONNECTED; + break; + + case PD_DRP_FORCE_SINK: + next_state = PD_STATE_SNK_DISCONNECTED; + break; + + case PD_DRP_FORCE_SOURCE: + next_state = PD_STATE_SRC_DISCONNECTED; + break; + + case PD_DRP_TOGGLE_ON: + default: + next_state = PD_STATE_DRP_AUTO_TOGGLE; + break; + } + } else if ((cc_is_rp(cc1) || cc_is_rp(cc2)) && drp_state[port] != PD_DRP_FORCE_SOURCE) { /* SNK allowed unless ForceSRC */ next_state = PD_STATE_SNK_DISCONNECTED; @@ -3053,7 +3077,22 @@ void pd_task(void *u) break; case PD_STATE_SRC_DISCONNECTED: timeout = 10*MSEC; + +#ifdef CONFIG_USB_PD_TCPC_LOW_POWER + /* + * If SW decided we should be in a low power state and + * the CC lines did not change, then don't talk with the + * TCPC otherwise we might wake it up. + */ + if (pd[port].flags & PD_FLAGS_LPM_REQUESTED && + !(evt & PD_EVENT_CC)) { + timeout = -1; + break; + } +#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */ + tcpm_get_cc(port, &cc1, &cc2); + #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE /* * Attempt TCPC auto DRP toggle if it is @@ -3650,17 +3689,33 @@ void pd_task(void *u) #else timeout = 10*MSEC; #endif + +#ifdef CONFIG_USB_PD_TCPC_LOW_POWER + /* + * If SW decided we should be in a low power state and + * the CC lines did not change, then don't talk with the + * TCPC otherwise we might wake it up. + */ + if (pd[port].flags & PD_FLAGS_LPM_REQUESTED && + !(evt & PD_EVENT_CC)) { + timeout = -1; + break; + } +#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */ + tcpm_get_cc(port, &cc1, &cc2); #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE /* - * Attempt TCPC auto DRP toggle if it is - * not already auto toggling and not try.src + * Attempt TCPC auto DRP toggle if it is not already + * auto toggling and not try.src, and dual role toggling + * is allowed. */ if (auto_toggle_supported && !(pd[port].flags & PD_FLAGS_TCPC_DRP_TOGGLE) && !is_try_src(port) && - cc_is_open(cc1, cc2)) { + cc_is_open(cc1, cc2) && + (drp_state[port] == PD_DRP_TOGGLE_ON)) { set_state(port, PD_STATE_DRP_AUTO_TOGGLE); timeout = 2*MSEC; break; @@ -3701,10 +3756,29 @@ void pd_task(void *u) tcpm_set_cc(port, TYPEC_CC_RP); next_role_swap = get_time().val + PD_T_DRP_SRC; +#ifdef CONFIG_USB_PD_TCPC_LOW_POWER + /* + * Clear low power mode flag as we are swapping + * states quickly. + */ + pd[port].flags &= ~PD_FLAGS_LPM_REQUESTED; +#endif + /* Swap states quickly */ timeout = 2*MSEC; + break; } + +#ifdef CONFIG_USB_PD_TCPC_LOW_POWER + /* + * If we are remaining in the SNK_DISCONNECTED state, + * let's go into low power mode and wait for a change on + * CC status. + */ + pd[port].flags |= PD_FLAGS_LPM_REQUESTED; +#endif/* CONFIG_USB_PD_TCPC_LOW_POWER */ break; + case PD_STATE_SNK_DISCONNECTED_DEBOUNCE: tcpm_get_cc(port, &cc1, &cc2); @@ -4304,6 +4378,14 @@ void pd_task(void *u) next_state = drp_auto_toggle_next_state(port, cc1, cc2); +#ifdef CONFIG_USB_PD_TCPC_LOW_POWER + /* + * Always stay in low power mode since we are waiting + * for a connection. + */ + pd[port].flags |= PD_FLAGS_LPM_REQUESTED; +#endif + if (next_state == PD_STATE_SNK_DISCONNECTED) { tcpm_set_cc(port, TYPEC_CC_RD); pd_set_power_role(port, PD_ROLE_SINK); @@ -4314,16 +4396,10 @@ void pd_task(void *u) timeout = 2*MSEC; } else { /* - * Staying in PD_STATE_DRP_AUTO_TOGGLE, - * always enter low power mode, and auto-toggle - * while in low power mode if drp_state allows - * us to be dual role. + * We are staying in PD_STATE_DRP_AUTO_TOGGLE, + * therefore enable auto-toggle. */ - if (drp_state[port] == PD_DRP_TOGGLE_ON) - tcpm_enable_drp_toggle(port); -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - pd[port].flags |= PD_FLAGS_LPM_REQUESTED; -#endif + tcpm_enable_drp_toggle(port); pd[port].flags |= PD_FLAGS_TCPC_DRP_TOGGLE; timeout = -1; } diff --git a/test/usb_pd.c b/test/usb_pd.c index ec9b834679..6ec9b3ffda 100644 --- a/test/usb_pd.c +++ b/test/usb_pd.c @@ -276,6 +276,8 @@ static void plug_in_source(int port, int polarity) pd_port[port].has_vbus = 1; pd_port[port].partner_role = PD_ROLE_SOURCE; pd_port[port].partner_polarity = polarity; + /* Indicate that the CC lines have changed. */ + task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0); } static void plug_in_sink(int port, int polarity) @@ -283,6 +285,8 @@ static void plug_in_sink(int port, int polarity) pd_port[port].has_vbus = 0; pd_port[port].partner_role = PD_ROLE_SINK; pd_port[port].partner_polarity = polarity; + /* Indicate that the CC lines have changed. */ + task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0); } static void unplug(int port) @@ -291,6 +295,8 @@ static void unplug(int port) pd_port[port].msg_rx_id = 0; pd_port[port].has_vbus = 0; pd_port[port].partner_role = -1; + /* Indicate that the CC lines have changed. */ + task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0); task_wake(PD_PORT_TO_TASK_ID(port)); usleep(30 * MSEC); } |