diff options
author | Alec Berg <alecaberg@chromium.org> | 2015-10-22 11:37:05 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2015-10-23 10:10:56 -0700 |
commit | 847978564a3ac343c191be94e7a83076ead33f70 (patch) | |
tree | d2b5292d9b3280b888fc3d8249d70dbe760a18ab /common | |
parent | accc98d7c3fdcad6e35ac2ebeb63fbda3abf8d2e (diff) | |
download | chrome-ec-847978564a3ac343c191be94e7a83076ead33f70.tar.gz |
pd: send soft reset on boot if VBUS is present
On boot, if VBUS is present, then when PD protocol gets to
SNK_DISCOVERY state, if it times out waiting for source cap,
then send attempt to send a soft reset first instead of
directly sending a hard reset. This allows us to not lose
VBUS in the case that we were in a stable contract as a sink
before this boot (for example a sysjump or EC reboot).
BUG=chrome-os-partner:44085, chrome-os-partner:44952
BRANCH=none
TEST=test on glados and samus. test by sysjumping between
RO and RW with zinger plugged in and no battery, and verify
that we don't lose power. also test rebooting with a battery
and verify we don't lose power. also tested with a third
party PD charger.
Change-Id: Ib7ce46d8b9843db66805ba3237d8919d611324e0
Signed-off-by: Alec Berg <alecaberg@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/308201
Reviewed-by: Rong Chang <rongchang@chromium.org>
Diffstat (limited to 'common')
-rw-r--r-- | common/system.c | 14 | ||||
-rw-r--r-- | common/usb_charger.c | 2 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 65 |
3 files changed, 33 insertions, 48 deletions
diff --git a/common/system.c b/common/system.c index 851836effb..fa3a557d8b 100644 --- a/common/system.c +++ b/common/system.c @@ -439,11 +439,6 @@ static void jump_to_image(uintptr_t init_addr) usleep(MSEC); gpio_set_level(GPIO_ENTERING_RW, 0); -#ifdef CONFIG_USB_POWER_DELIVERY - /* Notify USB PD module that we are about to reset */ - pd_prepare_reset(); -#endif - #if defined(CONFIG_I2C) && !defined(CONFIG_I2C_SLAVE_ONLY) /* Prepare I2C module for sysjump */ i2c_prepare_sysjump(); @@ -735,10 +730,6 @@ static int handle_pending_reboot(enum ec_reboot_cmd cmd) case EC_REBOOT_JUMP_RW: return system_run_image_copy(SYSTEM_IMAGE_RW); case EC_REBOOT_COLD: -#ifdef CONFIG_USB_POWER_DELIVERY - /* Notify USB PD module that we are about to reset */ - pd_prepare_reset(); -#endif #ifdef HAS_TASK_PDCMD /* Reboot the PD chip as well */ board_reset_pd_mcu(); @@ -934,11 +925,6 @@ static int command_reboot(int argc, char **argv) ccputs("Rebooting!\n\n\n"); cflush(); -#ifdef CONFIG_USB_POWER_DELIVERY - /* Notify USB PD module that we are about to reset */ - pd_prepare_reset(); -#endif - system_reset(flags); return EC_SUCCESS; } diff --git a/common/usb_charger.c b/common/usb_charger.c index 0474bc18b8..b22e8dc99d 100644 --- a/common/usb_charger.c +++ b/common/usb_charger.c @@ -82,6 +82,8 @@ void usb_charger_set_switches(int port, enum usb_switch setting) void usb_charger_vbus_change(int port, int vbus_level) { + /* If VBUS has transitioned low, notify PD module directly */ + pd_vbus_low(port); /* Update VBUS supplier and signal VBUS change to USB_CHG task */ update_vbus_supplier(port, vbus_level); #if CONFIG_USB_PD_PORT_COUNT == 2 diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 8154d9ecee..4cc0e0259a 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -212,6 +212,11 @@ int pd_is_connected(int port) } #ifdef CONFIG_USB_PD_DUAL_ROLE +void pd_vbus_low(int port) +{ + pd[port].flags &= ~PD_FLAGS_VBUS_NEVER_LOW; +} + static inline int pd_is_vbus_present(int port) { #ifdef CONFIG_USB_PD_TCPM_VBUS @@ -542,12 +547,6 @@ static void execute_soft_reset(int port) pd[port].msg_id = 0; set_state(port, DUAL_ROLE_IF_ELSE(port, PD_STATE_SNK_DISCOVERY, PD_STATE_SRC_DISCOVERY)); -#ifdef CONFIG_COMMON_RUNTIME - /* if flag to disable PD comms after soft reset, then disable comms */ - if (pd[port].flags & PD_FLAGS_SFT_RST_DIS_COMM) - pd_comm_enable(0); -#endif - CPRINTF("C%d Soft Rst\n", port); } @@ -562,32 +561,6 @@ void pd_soft_reset(void) } } -void pd_prepare_reset(void) -{ - int i; - - /* - * On reset, we are most definitely going to drop pings (if any) - * and lose all of our PD state. Instead of trying to remember all - * the states and deal with on-going transmission, let's send soft - * reset here and then disable PD communication until after sysjump - * is complete so that the communication starts over without dropping - * power. - */ - for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; ++i) - if (pd_is_connected(i)) - pd[i].flags |= PD_FLAGS_SFT_RST_DIS_COMM; - - pd_soft_reset(); - - /* - * Give time for soft reset to be sent - * TODO (crosbug.com/p/45133): wait for soft reset to finish instead of - * blind delay. - */ - usleep(8*MSEC); -} - #ifdef CONFIG_USB_PD_DUAL_ROLE static void pd_store_src_cap(int port, int cnt, uint32_t *src_caps) { @@ -1410,6 +1383,15 @@ void pd_task(void) /* Ensure the power supply is in the default state */ pd_power_supply_reset(port); +#ifdef CONFIG_USB_PD_DUAL_ROLE + /* + * If VBUS is high, then initialize flag for VBUS has always been + * present. This flag is used to maintain a PD connection after a + * reset by sending a soft reset. + */ + pd[port].flags = pd_is_vbus_present(port) ? PD_FLAGS_VBUS_NEVER_LOW : 0; +#endif + #ifdef CONFIG_USB_PD_TCPC /* Initialize TCPM driver and wait for TCPC to be ready */ tcpm_init(port); @@ -1427,7 +1409,6 @@ void pd_task(void) /* Initialize PD protocol state variables for each port. */ pd[port].power_role = PD_ROLE_DEFAULT; pd[port].vdm_state = VDM_STATE_DONE; - pd[port].flags = 0; set_state(port, PD_DEFAULT_STATE); tcpm_set_cc(port, PD_ROLE_DEFAULT == PD_ROLE_SOURCE ? TYPEC_CC_RP : TYPEC_CC_RD); @@ -2142,11 +2123,25 @@ void pd_task(void) if ((pd[port].last_state != pd[port].task_state) && pd_comm_enabled) { /* + * If VBUS has never been low, and we timeout + * waiting for source cap, try a soft reset + * first, in case we were already in a stable + * contract before this boot. + */ + if (pd[port].flags & PD_FLAGS_VBUS_NEVER_LOW) { + pd[port].flags &= + ~PD_FLAGS_VBUS_NEVER_LOW; + set_state_timeout(port, + get_time().val + + PD_T_SINK_WAIT_CAP, + PD_STATE_SOFT_RESET); + } + /* * If we haven't passed hard reset counter, * start SinkWaitCapTimer, otherwise start * NoResponseTimer. */ - if (hard_reset_count < PD_HARD_RESET_COUNT) + else if (hard_reset_count < PD_HARD_RESET_COUNT) set_state_timeout(port, get_time().val + PD_T_SINK_WAIT_CAP, @@ -2414,6 +2409,8 @@ void pd_task(void) #endif /* CONFIG_USB_PD_DUAL_ROLE */ case PD_STATE_SOFT_RESET: if (pd[port].last_state != pd[port].task_state) { + /* Message ID of soft reset is always 0 */ + pd[port].msg_id = 0; res = send_control(port, PD_CTRL_SOFT_RESET); /* if soft reset failed, try hard reset. */ |