summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/usb_pd_protocol.c122
-rw-r--r--test/usb_pd.c6
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);
}