summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAseda Aboagye <aaboagye@google.com>2018-03-23 17:46:43 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-04-25 23:00:02 -0700
commitda3b7696a41ad15981c5a954f0c0f562c1719a52 (patch)
tree121700079db881c65b2cf6d68646f9a71325e8e4
parent36980ec169795231ba5ddaba86decb2e05512581 (diff)
downloadchrome-ec-da3b7696a41ad15981c5a954f0c0f562c1719a52.tar.gz
USB PD: Send SoftReset if in explicit contract at init.
Currently, if a board supports dual role power ports, the EC will briefly apply Rp resistors on the CC lines upon initializing the PD tasks. This was put in place such that the partner port is a known state. In the case of an external PD charger, the presence of the Rp will cause the charger to stop sourcing VBUS. We only apply the pull up for reset cases where the EC did not just loose power (e.g. power on reset or brownout). This however presents a problem when booting off of AC only. If a user types 'reboot ap-off', there will be an extra reset because VBUS is dropped and the "ap-off" flag will be lost. This commit simply checks to see if there is an explicit contract in place for a port. If an explicit contract is in place and PD communications are allowed, we will not apply the Rp resistors. The PD state machine will then attempt to send a SoftReset to the port partner in order to reset the PD protocol layer. If an explicit contract is not in place, or if PD communications are not allowed, the Rp's will be asserted briefly as before. BUG=b:72838807,b:35587129,chromium:712746 BRANCH=None TEST=Flash zoombini; Remove battery and plug in just AC; Enter `reboot ap-off` and verify that AP remains off in the subsequent boot and there is no extra reset. TEST=Make zoombini locked. Have a PD contract in RW, reboot to RO and verify that VBUS is dropped from a PD charger. TEST=Repeat test on meowth. CQ-DEPEND=CL:905922 Change-Id: Ie2e3fe5b6b318e166b2a42dfa3241646369ec571 Signed-off-by: Aseda Aboagye <aaboagye@google.com> Reviewed-on: https://chromium-review.googlesource.com/905390 Commit-Ready: Aseda Aboagye <aaboagye@chromium.org> Tested-by: Aseda Aboagye <aaboagye@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r--common/usb_pd_protocol.c61
1 files changed, 55 insertions, 6 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index a02203c0c8..1d8b82f19d 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -1940,12 +1940,16 @@ static void pd_partner_port_reset(int port)
explicit_contract_in_place = (flags & PD_BBRMFLG_EXPLICIT_CONTRACT);
/*
- * Check our battery-backed previous port state. If PD comms were
- * active, and we didn't just lose power, make sure we
- * don't boot into RO with a pre-existing power contract.
+ * If an explicit contract is in place and PD communications are
+ * allowed, don't apply Rp. We'll issue a SoftReset later on and
+ * renegotiate our contract. This particular condition only applies to
+ * unlocked RO images with an explicit contract in place.
*/
+ if (explicit_contract_in_place && pd_comm_is_enabled(port))
+ return;
+
+ /* If we just lost power, don't apply Rp. */
if (!explicit_contract_in_place ||
- system_get_image_copy() != SYSTEM_IMAGE_RO ||
system_get_reset_flags() &
(RESET_FLAG_BROWNOUT | RESET_FLAG_POWER_ON))
return;
@@ -1957,6 +1961,8 @@ static void pd_partner_port_reset(int port)
pd_update_saved_port_flags(port, PD_BBRMFLG_EXPLICIT_CONTRACT, 0);
/* Provide Rp for 200 msec. or until we no longer have VBUS. */
+ CPRINTF("C%d Apply Rp!\n");
+ cflush();
tcpm_set_cc(port, TYPEC_CC_RP);
timeout = get_time().val + 200 * MSEC;
@@ -2148,6 +2154,7 @@ void pd_task(void *u)
int hard_reset_count = 0;
#ifdef CONFIG_USB_PD_DUAL_ROLE
uint64_t next_role_swap = PD_T_DRP_SNK;
+ uint8_t saved_flgs = 0;
#ifndef CONFIG_USB_PD_VBUS_DETECT_NONE
int snk_hard_reset_vbus_off = 0;
#endif
@@ -2216,6 +2223,41 @@ void pd_task(void *u)
/* Initialize PD protocol state variables for each port. */
pd_set_power_role(port, PD_ROLE_DEFAULT(port));
+#ifdef CONFIG_USB_PD_DUAL_ROLE
+ /*
+ * If there's an explicit contract in place, let's restore the data and
+ * power roles such that any messages we send to the port partner will
+ * still be valid.
+ */
+ if (pd_comm_is_enabled(port) &&
+ (pd_get_saved_port_flags(port, &saved_flgs) == EC_SUCCESS)) {
+ if (saved_flgs & PD_BBRMFLG_EXPLICIT_CONTRACT) {
+ pd_set_power_role(port,
+ (saved_flgs & PD_BBRMFLG_POWER_ROLE) ?
+ PD_ROLE_SOURCE : PD_ROLE_SINK);
+ pd_set_data_role(port,
+ (saved_flgs & PD_BBRMFLG_DATA_ROLE) ?
+ PD_ROLE_DFP : PD_ROLE_UFP);
+ /* Set the terminations to match our power role. */
+ tcpm_set_cc(port, pd[port].power_role ?
+ TYPEC_CC_RP : TYPEC_CC_RD);
+
+ /*
+ * Since there is an explicit contract in place, let's
+ * issue a SoftReset such that we can renegotiate with
+ * our port partner in order to synchronize our state
+ * machines.
+ */
+ this_state = PD_STATE_SOFT_RESET;
+
+ /*
+ * Enable TCPC RX so we can hear back from our port
+ * partner.
+ */
+ tcpm_set_rx_enable(port, 1);
+ }
+ }
+#endif /* defined(CONFIG_USB_PD_DUAL_ROLE) */
pd[port].vdm_state = VDM_STATE_DONE;
set_state(port, this_state);
#ifdef CONFIG_USB_PD_MAX_SINGLE_SOURCE_CURRENT
@@ -2224,8 +2266,15 @@ void pd_task(void *u)
#else
tcpm_select_rp_value(port, CONFIG_USB_PD_PULLUP);
#endif
- tcpm_set_cc(port, PD_ROLE_DEFAULT(port) == PD_ROLE_SOURCE ?
- TYPEC_CC_RP : TYPEC_CC_RD);
+#ifdef CONFIG_USB_PD_DUAL_ROLE
+ /*
+ * If we're not in an explicit contract, set our terminations to match
+ * our default power role.
+ */
+ if (!(saved_flgs & PD_BBRMFLG_EXPLICIT_CONTRACT))
+#endif /* CONFIG_USB_PD_DUAL_ROLE */
+ tcpm_set_cc(port, PD_ROLE_DEFAULT(port) == PD_ROLE_SOURCE ?
+ TYPEC_CC_RP : TYPEC_CC_RD);
#ifdef CONFIG_USBC_PPC
/*