summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiana Z <dzigterman@chromium.org>2019-03-06 11:40:27 -0700
committerchrome-bot <chrome-bot@chromium.org>2019-04-18 19:51:29 -0700
commitf8206fabf1cefaccd4e4393588ae2e3613bfb97d (patch)
treed2270e5024e8641911fe54e68ea62be32cad81bf
parent8fce0a9a7d19f040feaec666c58b2c0871db7fc9 (diff)
downloadchrome-ec-f8206fabf1cefaccd4e4393588ae2e3613bfb97d.tar.gz
USB PD: Re-discover port partner when a contract was in place
When the pd_task starts up with an explicit contract previously in place, re-check the partner's identity. This will happen automatically when we EC reset into RO since pd_chipset_startup sets the flag, but for a RO->RW jump the flag needs to be set again. Additionally, exit DP modes before sysjumping, in order to not confuse the port partner with a second enter mode when it had previously been in that mode. BUG=b:125552060 BRANCH=octopus TEST=on unlocked octopus board, plugged in powered HDMI dongle from hibernate state and confirmed display worked after RO->RW jump. Also turned off software sync and confirmed console "sysjump" worked. Change-Id: Idcde6f04deeb8f409a9b4d0a4b3fc924bdb644c7 Signed-off-by: Diana Z <dzigterman@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1506434 Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r--common/system.c5
-rw-r--r--common/usb_pd_protocol.c49
-rw-r--r--include/task.h5
-rw-r--r--include/usb_pd.h12
4 files changed, 69 insertions, 2 deletions
diff --git a/common/system.c b/common/system.c
index 7b91b84eba..813c0b6399 100644
--- a/common/system.c
+++ b/common/system.c
@@ -554,6 +554,11 @@ static void jump_to_image(uintptr_t init_addr)
usleep(MSEC);
gpio_set_level(GPIO_ENTERING_RW, 0);
+#ifdef CONFIG_USB_PD_ALT_MODE_DFP
+ /* Note: must be before i2c module is locked down */
+ pd_prepare_sysjump();
+#endif
+
#ifdef CONFIG_I2C_MASTER
/* Prepare I2C module for sysjump */
i2c_prepare_sysjump();
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 389c43a8a2..ff9d710e64 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -152,6 +152,11 @@ static const uint8_t vdo_ver[] = {
#define VDO_VER(v) VDM_VER10
#endif
+#ifdef CONFIG_USB_PD_ALT_MODE_DFP
+/* Tracker for which task is waiting on sysjump prep to finish */
+static volatile task_id_t sysjump_task_waiting = TASK_ID_INVALID;
+#endif
+
static struct pd_protocol {
/* current port power role (SOURCE or SINK) */
uint8_t power_role;
@@ -2165,7 +2170,7 @@ int pd_dev_store_rw_hash(int port, uint16_t dev_id, uint32_t *rw_hash,
return 0;
}
-#ifdef CONFIG_POWER_COMMON /* Needed b/c CONFIG_POWER_COMMON is only caller */
+#if defined(CONFIG_POWER_COMMON) || defined(CONFIG_USB_PD_ALT_MODE_DFP)
static void exit_dp_mode(int port)
{
#ifdef CONFIG_USB_PD_ALT_MODE_DFP
@@ -2768,6 +2773,12 @@ void pd_task(void *u)
this_state = PD_STATE_SOFT_RESET;
/*
+ * Re-discover any alternate modes we may have been
+ * using with this port partner.
+ */
+ pd[port].flags |= PD_FLAGS_CHECK_IDENTITY;
+
+ /*
* Set the TCPC reset event such that we can set our CC
* terminations, determine polarity, and enable RX so we
* can hear back from our port partner.
@@ -2859,6 +2870,20 @@ void pd_task(void *u)
if (evt & PD_EVENT_POWER_STATE_CHANGE)
handle_new_power_state(port);
#endif
+
+#if defined(CONFIG_USB_PD_ALT_MODE_DFP)
+ if (evt & PD_EVENT_SYSJUMP) {
+ exit_dp_mode(port);
+ /*
+ * If event was set from pd_prepare_sysjump, wake the
+ * task waiting on us to complete.
+ */
+ if (sysjump_task_waiting != TASK_ID_INVALID)
+ task_set_event(sysjump_task_waiting,
+ TASK_EVENT_SYSJUMP_READY, 0);
+ }
+#endif
+
#ifdef CONFIG_USB_PD_DUAL_ROLE
if (evt & PD_EVENT_UPDATE_DUAL_ROLE)
pd_update_dual_role_config(port);
@@ -4371,6 +4396,28 @@ DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, pd_chipset_shutdown, HOOK_PRIO_DEFAULT);
#endif /* CONFIG_USB_PD_DUAL_ROLE */
+#ifdef CONFIG_USB_PD_ALT_MODE_DFP
+void pd_prepare_sysjump(void)
+{
+ int i;
+
+ /* Exit modes before sysjump so we can cleanly enter again later */
+ for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) {
+ /*
+ * We can't be in an alternate mode if PD comm is disabled, so
+ * no need to send the event
+ */
+ if (!pd_comm_is_enabled(i))
+ continue;
+
+ sysjump_task_waiting = task_get_current();
+ task_set_event(PD_PORT_TO_TASK_ID(i), PD_EVENT_SYSJUMP, 0);
+ task_wait_event_mask(TASK_EVENT_SYSJUMP_READY, -1);
+ sysjump_task_waiting = TASK_ID_INVALID;
+ }
+}
+#endif
+
#ifdef CONFIG_COMMON_RUNTIME
/*
diff --git a/include/task.h b/include/task.h
index 46a340b898..32e62a8384 100644
--- a/include/task.h
+++ b/include/task.h
@@ -14,7 +14,10 @@
/* Task event bitmasks */
/* Tasks may use the bits in TASK_EVENT_CUSTOM for their own events */
-#define TASK_EVENT_CUSTOM(x) (x & 0x0001ffff)
+#define TASK_EVENT_CUSTOM(x) (x & 0x0000ffff)
+
+/* Used to signal that sysjump preparation has completed */
+#define TASK_EVENT_SYSJUMP_READY BIT(16)
/* Used to signal that IPC layer is available for sending new data */
#define TASK_EVENT_IPC_READY BIT(17)
diff --git a/include/usb_pd.h b/include/usb_pd.h
index b3888dae7f..a8f1dab008 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -50,6 +50,7 @@ enum pd_rx_errors {
#define PD_EVENT_POWER_STATE_CHANGE (1<<8) /* Chipset power state changed */
#define PD_EVENT_SEND_HARD_RESET (1<<9) /* Issue a Hard Reset. */
#define PD_EVENT_SM (1<<10) /* PD State machine event */
+#define PD_EVENT_SYSJUMP (1<<11) /* Prepare for sysjump */
/* Ensure TCPC is out of low power mode before handling these events. */
#define PD_EXIT_LOW_POWER_EVENT_MASK \
@@ -1978,4 +1979,15 @@ static inline void pd_log_event(uint8_t type, uint8_t size_port,
static inline int pd_vdm_get_log_entry(uint32_t *payload) { return 0; }
#endif /* CONFIG_USB_PD_LOGGING */
+#ifdef CONFIG_USB_PD_ALT_MODE_DFP
+/**
+ * Prepare for a sysjump by exiting any alternate modes, if PD communication is
+ * allowed.
+ *
+ * Note: this call will block until the PD task has finished its exit mode and
+ * re-awoken the calling task.
+ */
+void pd_prepare_sysjump(void);
+#endif
+
#endif /* __CROS_EC_USB_PD_H */