summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2015-10-22 11:37:05 -0700
committerchrome-bot <chrome-bot@chromium.org>2015-10-23 10:10:56 -0700
commit847978564a3ac343c191be94e7a83076ead33f70 (patch)
treed2b5292d9b3280b888fc3d8249d70dbe760a18ab /common
parentaccc98d7c3fdcad6e35ac2ebeb63fbda3abf8d2e (diff)
downloadchrome-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.c14
-rw-r--r--common/usb_charger.c2
-rw-r--r--common/usb_pd_protocol.c65
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. */