diff options
author | Aseda Aboagye <aaboagye@google.com> | 2018-03-23 17:46:43 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-04-25 23:00:02 -0700 |
commit | da3b7696a41ad15981c5a954f0c0f562c1719a52 (patch) | |
tree | 121700079db881c65b2cf6d68646f9a71325e8e4 | |
parent | 36980ec169795231ba5ddaba86decb2e05512581 (diff) | |
download | chrome-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.c | 61 |
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 /* |