summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2015-01-13 18:41:06 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-01-16 18:12:21 +0000
commit7893715cb7ef471002893ed128c241a8e8dfdacb (patch)
treee5c3e1929b2612b6d1991ab3d0294469e3d89866
parent7627bd21d0b6ed8a176439ab0240b9fb75a903bf (diff)
downloadchrome-ec-7893715cb7ef471002893ed128c241a8e8dfdacb.tar.gz
pd: updates to new connection state machine
More updates to connection state machine. Adds CONFIG option for backwards compatible DFP (used on zinger), and change UFP state machine to debounce CC while VBUS is not present. BUG=chrome-os-partner:33680 BRANCH=samus TEST=load on samus and zinger and connect a bunch of times. also test samus to samus connection. Change-Id: Ia967eb6a17b10aa0c05a30686235fbf8a24e9a7b Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/240587 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--board/zinger/board.h1
-rw-r--r--common/usb_pd_protocol.c209
-rw-r--r--include/config.h3
-rw-r--r--include/usb_pd.h2
4 files changed, 111 insertions, 104 deletions
diff --git a/board/zinger/board.h b/board/zinger/board.h
index 8eba23e214..ba1709850b 100644
--- a/board/zinger/board.h
+++ b/board/zinger/board.h
@@ -55,6 +55,7 @@
#define CONFIG_USB_PD_LOG_SIZE 256
#undef CONFIG_USB_PD_RX_COMP_IRQ
#define CONFIG_USB_PD_SIMPLE_DFP
+#define CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP
#undef CONFIG_WATCHDOG_HELP
#undef CONFIG_WATCHDOG_PERIOD_MS
#define CONFIG_WATCHDOG_PERIOD_MS 2300
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 1b45d5e0c4..1cecaf89b3 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -227,7 +227,7 @@ static int pd_src_cap_cnt[PD_PORT_COUNT];
#define PD_FLAGS_PREVIOUS_PD_CONN (1 << 8) /* previously PD connected */
#define PD_FLAGS_CHECK_PR_ROLE (1 << 9) /* check power role in READY */
#define PD_FLAGS_CHECK_DR_ROLE (1 << 10)/* check data role in READY */
-#define PD_FLAGS_CURR_LIM_INIT (1 << 11)/* input curr limit initialized */
+#define PD_FLAGS_VBUS_PRESENT (1 << 11)/* vbus present in sink disconn. */
/* Flags to clear on a disconnect */
#define PD_FLAGS_RESET_ON_DISCONNECT_MASK (PD_FLAGS_PARTNER_DR_POWER | \
PD_FLAGS_PARTNER_DR_DATA | \
@@ -237,7 +237,8 @@ static int pd_src_cap_cnt[PD_PORT_COUNT];
PD_FLAGS_EXPLICIT_CONTRACT | \
PD_FLAGS_PREVIOUS_PD_CONN | \
PD_FLAGS_CHECK_PR_ROLE | \
- PD_FLAGS_CHECK_DR_ROLE)
+ PD_FLAGS_CHECK_DR_ROLE | \
+ PD_FLAGS_VBUS_PRESENT)
static struct pd_protocol {
/* current port power role (SOURCE or SINK) */
@@ -320,7 +321,7 @@ static const char * const pd_state_names[] = {
"SRC_TRANSITION", "SRC_READY", "SRC_GET_SNK_CAP", "SRC_DR_SWAP",
#ifdef CONFIG_USB_PD_DUAL_ROLE
"SRC_SWAP_INIT", "SRC_SWAP_SNK_DISABLE", "SRC_SWAP_SRC_DISABLE",
- "SRC_SWAP_STANDBY", "SRC_TO_FORCE_SINK",
+ "SRC_SWAP_STANDBY",
#endif /* CONFIG_USB_PD_DUAL_ROLE */
"SOFT_RESET", "HARD_RESET_SEND", "HARD_RESET_EXECUTE", "BIST",
};
@@ -1573,7 +1574,9 @@ void pd_set_dual_role(enum pd_dual_role_states state)
(drp_state == PD_DRP_FORCE_SINK ||
(drp_state == PD_DRP_TOGGLE_OFF
&& pd[i].task_state == PD_STATE_SRC_DISCONNECTED))) {
- set_state(i, PD_STATE_SRC_TO_FORCE_SINK);
+ pd[i].power_role = PD_ROLE_SINK;
+ set_state(i, PD_STATE_SNK_DISCONNECTED);
+ pd_set_host_mode(i, 0);
task_wake(PORT_TO_TASK_ID(i));
}
@@ -1687,6 +1690,15 @@ void pd_set_new_power_request(int port)
}
#endif /* CONFIG_CHARGE_MANAGER */
+#if defined(CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP) && defined(CONFIG_USBC_SS_MUX)
+/*
+ * Backwards compatible DFP does not support USB SS because it applies VBUS
+ * before debouncing CC and setting USB SS muxes, but SS detection will fail
+ * before we are done debouncing CC.
+ */
+#error "Backwards compatible DFP does not support USB"
+#endif
+
void pd_task(void)
{
int head;
@@ -1731,6 +1743,21 @@ void pd_task(void)
pd_dfp_pe_init(port);
#endif
+#ifdef CONFIG_CHARGE_MANAGER
+ /* Initialize PD supplier current limit to 0 */
+ pd_set_input_current_limit(port, 0, 0);
+#ifdef CONFIG_USB_PD_DUAL_ROLE
+ /* If sink, set initial type-C current limit based on vbus */
+ if (pd_snk_is_vbus_provided(port)) {
+ typec_set_input_current_limit(port, 500, TYPE_C_VOLTAGE);
+ pd[port].flags |= PD_FLAGS_VBUS_PRESENT;
+ } else {
+ typec_set_input_current_limit(port, 0, 0);
+ pd[port].flags &= ~PD_FLAGS_VBUS_PRESENT;
+ }
+#endif
+#endif
+
while (1) {
/* process VDM messages last */
pd_vdm_send_state_machine(port);
@@ -1794,34 +1821,19 @@ void pd_task(void)
cc1_volt = pd_adc_read(port, 0);
cc2_volt = pd_adc_read(port, 1);
if (!CC_NC(cc1_volt) || !CC_NC(cc2_volt)) {
-#ifdef CONFIG_USBC_SS_MUX
- /*
- * Set to USB SS based on current plarity
- * (might change after the debounce).
- */
- board_set_usb_mux(port, TYPEC_MUX_USB,
- DFP_GET_POLARITY(cc1_volt,
- cc2_volt));
-#endif
+#ifdef CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP
/* Enable VBUS */
- if (pd_set_power_supply_ready(port)) {
-#ifdef CONFIG_USBC_SS_MUX
- board_set_usb_mux(port, TYPEC_MUX_NONE,
- DFP_GET_POLARITY(
- cc1_volt,
- cc2_volt));
-#endif
+ if (pd_set_power_supply_ready(port))
break;
- }
+#endif
pd[port].cc_state = PD_CC_NONE;
set_state(port,
PD_STATE_SRC_DISCONNECTED_DEBOUNCE);
}
#ifdef CONFIG_USB_PD_DUAL_ROLE
- /* Swap roles if time expired or VBUS is present */
+ /* Swap roles if time expired */
else if (drp_state != PD_DRP_FORCE_SOURCE &&
- (get_time().val >= next_role_swap ||
- pd_snk_is_vbus_provided(port))) {
+ get_time().val >= next_role_swap) {
pd[port].power_role = PD_ROLE_SINK;
set_state(port, PD_STATE_SNK_DISCONNECTED);
pd_set_host_mode(port, 0);
@@ -1838,8 +1850,10 @@ void pd_task(void)
cc2_volt = pd_adc_read(port, 1);
if (CC_NC(cc1_volt) && CC_NC(cc2_volt)) {
+#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;
@@ -1877,6 +1891,16 @@ void pd_task(void)
board_set_usb_mux(port, TYPEC_MUX_USB,
pd[port].polarity);
#endif
+#ifndef CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP
+ /* Enable VBUS */
+ if (pd_set_power_supply_ready(port)) {
+#ifdef CONFIG_USBC_SS_MUX
+ board_set_usb_mux(port, TYPEC_MUX_NONE,
+ pd[port].polarity);
+#endif
+ break;
+ }
+#endif
/* initial data role for source is DFP */
pd_set_data_role(port, PD_ROLE_DFP);
@@ -1893,8 +1917,10 @@ void pd_task(void)
/* Accessory is attached */
else if (new_cc_state == PD_CC_AUDIO_ACC ||
new_cc_state == PD_CC_DEBUG_ACC) {
+#ifdef CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP
/* Remove VBUS */
pd_power_supply_reset(port);
+#endif
set_state(port, PD_STATE_SRC_ACCESSORY);
}
break;
@@ -1942,6 +1968,7 @@ void pd_task(void)
pd[port].msg_id = 0;
set_state_timeout(
port,
+#ifdef CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP
/*
* delay for power supply to start up.
* subtract out debounce time if coming
@@ -1953,6 +1980,10 @@ void pd_task(void)
(pd[port].last_state ==
PD_STATE_SRC_DISCONNECTED_DEBOUNCE
? PD_T_CC_DEBOUNCE : 0),
+#else
+ get_time().val +
+ PD_POWER_SUPPLY_TRANSITION_DELAY,
+#endif
PD_STATE_SRC_DISCOVERY);
}
break;
@@ -2189,22 +2220,6 @@ void pd_task(void)
PD_STATE_SNK_DISCONNECTED);
}
break;
- case PD_STATE_SRC_TO_FORCE_SINK:
- /*
- * Transition from Source to force sink role. Disable
- * VBUS and wait for VBUS to turn off
- */
- if (pd[port].last_state != pd[port].task_state)
- pd_power_supply_reset(port);
-
- if (pd_snk_is_vbus_provided(port)) {
- /* When VBUS is off, go to SNK_DISCONNECTED */
- pd_set_host_mode(port, 0);
- pd[port].power_role = PD_ROLE_SINK;
- set_state(port, PD_STATE_SNK_DISCONNECTED);
- timeout = 10*MSEC;
- }
- break;
case PD_STATE_SUSPENDED:
pd_rx_disable_monitoring(port);
pd_hw_release(port);
@@ -2219,41 +2234,45 @@ void pd_task(void)
case PD_STATE_SNK_DISCONNECTED:
timeout = 10*MSEC;
+#ifdef CONFIG_CHARGE_MANAGER
/*
- * Source connection monitoring
- * Note, if we just turned VBUS off, we may still see
- * VBUS present, but that should be safe because we
- * will wait in the debounce state until vbus is
- * removed.
+ * If VBUS, use default 500mA limit, otherwise
+ * set current limit to 0. This is necessary for
+ * an accessory that provides power with no Rp.
*/
- if (pd_snk_is_vbus_provided(port)) {
+ if (pd_snk_is_vbus_provided(port) &&
+ !(pd[port].flags & PD_FLAGS_VBUS_PRESENT)) {
+ typec_set_input_current_limit(port, 500,
+ TYPE_C_VOLTAGE);
+ pd[port].flags |= PD_FLAGS_VBUS_PRESENT;
+ } else if (!pd_snk_is_vbus_provided(port) &&
+ (pd[port].flags & PD_FLAGS_VBUS_PRESENT)) {
+ typec_set_input_current_limit(port, 0, 0);
+ pd[port].flags &= ~PD_FLAGS_VBUS_PRESENT;
+ }
+#endif
+
+ /* Source connection monitoring */
+ cc1_volt = pd_adc_read(port, 0);
+ cc2_volt = pd_adc_read(port, 1);
+ if (CC_RP(cc1_volt) || CC_RP(cc2_volt)) {
pd[port].cc_state = PD_CC_NONE;
hard_reset_count = 0;
+ new_cc_state = PD_CC_DFP_ATTACHED;
+ pd[port].cc_debounce = get_time().val +
+ PD_T_CC_DEBOUNCE;
set_state(port,
PD_STATE_SNK_DISCONNECTED_DEBOUNCE);
break;
}
-#ifdef CONFIG_CHARGE_MANAGER
- /*
- * If no VBUS, set charge limit to zero if we have
- * yet to set a limit for this port.
- */
- if (!(pd[port].flags & PD_FLAGS_CURR_LIM_INIT)) {
- pd[port].flags |= PD_FLAGS_CURR_LIM_INIT;
- typec_set_input_current_limit(port, 0, 0);
- pd_set_input_current_limit(port, 0, 0);
- }
-#endif
/*
* If no source detected, check for role toggle.
- * Do not role toggle if Rp is detected.
+ * Do not toggle if VBUS is present.
*/
- cc1_volt = pd_adc_read(port, 0);
- cc2_volt = pd_adc_read(port, 1);
if (drp_state == PD_DRP_TOGGLE_ON &&
get_time().val >= next_role_swap &&
- !CC_RP(cc1_volt) && !CC_RP(cc2_volt)) {
+ !pd_snk_is_vbus_provided(port)) {
/* Swap roles to source */
pd[port].power_role = PD_ROLE_SOURCE;
set_state(port, PD_STATE_SRC_DISCONNECTED);
@@ -2265,7 +2284,9 @@ void pd_task(void)
}
break;
case PD_STATE_SNK_DISCONNECTED_DEBOUNCE:
- if (!pd_snk_is_vbus_provided(port)) {
+ cc1_volt = pd_adc_read(port, 0);
+ cc2_volt = pd_adc_read(port, 1);
+ if (!CC_RP(cc1_volt) && !CC_RP(cc2_volt)) {
/* No connection any more */
set_state(port, PD_STATE_SNK_DISCONNECTED);
timeout = 5*MSEC;
@@ -2273,50 +2294,34 @@ void pd_task(void)
}
timeout = 20*MSEC;
- cc1_volt = pd_adc_read(port, 0);
- cc2_volt = pd_adc_read(port, 1);
- if (!CC_RP(cc1_volt) && !CC_RP(cc2_volt))
- /* Accessory */
- new_cc_state = PD_CC_ACC_PRESENT;
- else
- /* DFP attached */
- new_cc_state = PD_CC_DFP_ATTACHED;
- /* Debounce the cc state */
- if (new_cc_state != pd[port].cc_state) {
- pd[port].cc_debounce = get_time().val +
- PD_T_CC_DEBOUNCE;
- pd[port].cc_state = new_cc_state;
- break;
- } else if (get_time().val < pd[port].cc_debounce) {
+ /* Wait for CC debounce and VBUS present */
+ if (get_time().val < pd[port].cc_debounce ||
+ !pd_snk_is_vbus_provided(port))
break;
- }
- /* Debounce complete */
- if (new_cc_state == PD_CC_DFP_ATTACHED) {
- pd[port].polarity =
- UFP_GET_POLARITY(cc1_volt, cc2_volt);
- pd_select_polarity(port, pd[port].polarity);
- /* reset message ID on connection */
- pd[port].msg_id = 0;
- /* initial data role for sink is UFP */
- pd_set_data_role(port, PD_ROLE_UFP);
+ /* We are attached */
+ pd[port].polarity =
+ UFP_GET_POLARITY(cc1_volt, cc2_volt);
+ pd_select_polarity(port, pd[port].polarity);
+ /* reset message ID on connection */
+ pd[port].msg_id = 0;
+ /* initial data role for sink is UFP */
+ pd_set_data_role(port, PD_ROLE_UFP);
#ifdef CONFIG_CHARGE_MANAGER
- pd[port].flags |= PD_FLAGS_CURR_LIM_INIT;
- typec_curr = get_typec_current_limit(
- pd[port].polarity ? cc2_volt :
- cc1_volt);
- typec_set_input_current_limit(
- port, typec_curr, TYPE_C_VOLTAGE);
-#endif
- pd[port].flags |= PD_FLAGS_CHECK_PR_ROLE |
- PD_FLAGS_CHECK_DR_ROLE;
- set_state(port, PD_STATE_SNK_DISCOVERY);
- timeout = 10*MSEC;
- hook_call_deferred(
- pd_usb_billboard_deferred,
- PD_T_AME);
- }
+ typec_curr = get_typec_current_limit(
+ pd[port].polarity ? cc2_volt :
+ cc1_volt);
+ typec_set_input_current_limit(
+ port, typec_curr, TYPE_C_VOLTAGE);
+#endif
+ pd[port].flags |= PD_FLAGS_CHECK_PR_ROLE |
+ PD_FLAGS_CHECK_DR_ROLE;
+ set_state(port, PD_STATE_SNK_DISCOVERY);
+ timeout = 10*MSEC;
+ hook_call_deferred(
+ pd_usb_billboard_deferred,
+ PD_T_AME);
break;
case PD_STATE_SNK_HARD_RESET_RECOVER:
if (pd[port].last_state != pd[port].task_state)
diff --git a/include/config.h b/include/config.h
index 7d2bca04d9..88369b427c 100644
--- a/include/config.h
+++ b/include/config.h
@@ -1209,6 +1209,9 @@
/* Support for USB type-c superspeed mux */
#undef CONFIG_USBC_SS_MUX
+/* Support v1.1 type-C connection state machine */
+#undef CONFIG_USBC_BACKWARDS_COMPATIBLE_DFP
+
/* Support for USB type-c vconn. Not needed for captive cables. */
#undef CONFIG_USBC_VCONN
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 51f23fba39..72206dc54f 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -605,7 +605,6 @@ enum pd_states {
PD_STATE_SRC_SWAP_SNK_DISABLE,
PD_STATE_SRC_SWAP_SRC_DISABLE,
PD_STATE_SRC_SWAP_STANDBY,
- PD_STATE_SRC_TO_FORCE_SINK,
#endif /* CONFIG_USB_PD_DUAL_ROLE */
PD_STATE_SOFT_RESET,
@@ -629,7 +628,6 @@ enum pd_cc_states {
PD_CC_UFP_ATTACHED,
/* From UFP perspective */
- PD_CC_ACC_PRESENT,
PD_CC_DFP_ATTACHED
};