summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Hill <ecgh@chromium.org>2018-08-27 19:29:04 -0600
committerchrome-bot <chrome-bot@chromium.org>2018-09-17 13:17:34 -0700
commitb2e389668c7e027dd184c59f7319d4379f04a809 (patch)
treefaa77b645a84243594a014e8b102e1eab4efa5e8
parent40c522b2dbfd3392f708fd58e3de9e6bc66d07a4 (diff)
downloadchrome-ec-b2e389668c7e027dd184c59f7319d4379f04a809.tar.gz
pd: Add PD_FLAGS_LPM_TRANSITION
Add PD_FLAGS_LPM_TRANSITION and use this to allow the PD task to call tcpc_read/tcpc_write from tcpm_enter_low_power_mode() and tcpm_init(). BRANCH=none BUG=b:111663127 TEST=PD and TCPC low power still work on Grunt Change-Id: I12ddb58667c171068e1be6d136f22f2062959c8c Signed-off-by: Edward Hill <ecgh@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1194351 Reviewed-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r--common/usb_pd_protocol.c37
-rw-r--r--driver/tcpm/tcpci.c5
-rw-r--r--include/usb_pd.h5
3 files changed, 21 insertions, 26 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 967b7acfed..7a4f543858 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -379,15 +379,15 @@ static void handle_device_access(int port)
}
}
-/* This can be called from any task. */
+/*
+ * This can be called from any task. If we are in the PD task, we can handle
+ * immediately. Otherwise, we need to notify the PD task via event.
+ */
void pd_device_accessed(int port)
{
- const int current_task = task_get_current();
-
- /* If not in the PD TASK that owns data, marshal to that task */
- if (current_task == PD_PORT_TO_TASK_ID(port)) {
+ if (port == TASK_ID_TO_PD_PORT(task_get_current())) {
/* Ignore any access to device while it is waking up */
- if (pd[port].tasks_waiting_on_reset & (1 << current_task))
+ if (pd[port].flags & PD_FLAGS_LPM_TRANSITION)
return;
handle_device_access(port);
@@ -399,14 +399,12 @@ void pd_device_accessed(int port)
int pd_device_in_low_power(int port)
{
- const int current_task = task_get_current();
-
/*
* If we are actively waking the device up in the PD task, do not
* let TCPC operation wait or retry because we are in low power mode.
*/
- if (port == TASK_ID_TO_PD_PORT(current_task) &&
- pd[port].tasks_waiting_on_reset & (1 << current_task))
+ if (port == TASK_ID_TO_PD_PORT(task_get_current()) &&
+ (pd[port].flags & PD_FLAGS_LPM_TRANSITION))
return 0;
return pd[port].flags & PD_FLAGS_LPM_ENGAGED;
@@ -416,19 +414,14 @@ static int reset_device_and_notify(int port)
{
int rv;
int task, waiting_tasks;
- const int current_task_mask = 1 << task_get_current();
/* This should only be called from the PD task */
assert(port == TASK_ID_TO_PD_PORT(task_get_current()));
- /*
- * Signal that this task is actively waiting for a wake up, which we
- * use to skip recursive wake calls within the tcpc_init method and
- * prevent pd_access from changing the HW status until we are done.
- */
- atomic_or(&pd[port].tasks_waiting_on_reset, current_task_mask);
-
+ pd[port].flags |= PD_FLAGS_LPM_TRANSITION;
rv = tcpm_init(port);
+ pd[port].flags &= ~PD_FLAGS_LPM_TRANSITION;
+
if (rv == EC_SUCCESS)
CPRINTS("TCPC p%d init ready", port);
else
@@ -445,8 +438,7 @@ static int reset_device_and_notify(int port)
/* Clear SW LPM state; the state machine will set it again if needed */
pd[port].flags &= ~PD_FLAGS_LPM_REQUESTED;
- /* Wake up all waiting tasks (except this task). */
- waiting_tasks &= ~current_task_mask;
+ /* Wake up all waiting tasks. */
while (waiting_tasks) {
task = __fls(waiting_tasks);
waiting_tasks &= ~(1 << task);
@@ -458,7 +450,7 @@ static int reset_device_and_notify(int port)
void pd_wait_for_wakeup(int port)
{
- if (task_get_current() == PD_PORT_TO_TASK_ID(port)) {
+ if (port == TASK_ID_TO_PD_PORT(task_get_current())) {
/* If we are in the PD task, we can directly reset */
reset_device_and_notify(port);
} else {
@@ -2107,6 +2099,7 @@ void pd_set_dual_role(int port, enum pd_dual_role_states state)
PD_EVENT_UPDATE_DUAL_ROLE, 0);
}
+/* This must only be called from the PD task */
static void pd_update_dual_role_config(int port)
{
/*
@@ -3877,7 +3870,9 @@ void pd_task(void *u)
pd[port].low_power_time - now.val;
if (time_left <= 0) {
pd[port].flags |= PD_FLAGS_LPM_ENGAGED;
+ pd[port].flags |= PD_FLAGS_LPM_TRANSITION;
tcpm_enter_low_power_mode(port);
+ pd[port].flags &= ~PD_FLAGS_LPM_TRANSITION;
CPRINTS("TCPC p%d Enter Low Power Mode", port);
timeout = -1;
} else if (timeout < 0 || timeout > time_left) {
diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c
index c22d995d71..250673b44a 100644
--- a/driver/tcpm/tcpci.c
+++ b/driver/tcpm/tcpci.c
@@ -274,10 +274,7 @@ int tcpci_tcpc_drp_toggle(int port, int enable)
#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
int tcpci_enter_low_power_mode(int port)
{
- /* This uses the raw i2c write to bypass the pd_device_accessed call */
- return i2c_write8(tcpc_config[port].i2c_host_port,
- tcpc_config[port].i2c_slave_addr,
- TCPC_REG_COMMAND, TCPC_REG_COMMAND_I2CIDLE);
+ return tcpc_write(port, TCPC_REG_COMMAND, TCPC_REG_COMMAND_I2CIDLE);
}
#endif
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 0bf3b15ffe..29299b8acf 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -724,10 +724,13 @@ enum pd_states {
#define PD_FLAGS_TS_DTS_PARTNER (1 << 16)/* partner has rp/rp or rd/rd */
/*
* These PD_FLAGS_LPM* flags track the software state (PD_LPM_FLAGS_REQUESTED)
- * and hardware state (PD_LPM_FLAGS_ENGAGED) of the TCPC lower power mode.
+ * and hardware state (PD_LPM_FLAGS_ENGAGED) of the TCPC low power mode.
+ * PD_FLAGS_LPM_TRANSITION is set while the HW is transitioning into or out of
+ * low power (when PD_LPM_FLAGS_ENGAGED is changing).
*/
#define PD_FLAGS_LPM_REQUESTED (1 << 17)/* Tracks SW LPM state */
#define PD_FLAGS_LPM_ENGAGED (1 << 18)/* Tracks HW LPM state */
+#define PD_FLAGS_LPM_TRANSITION (1 << 19)/* Tracks HW LPM transition */
/* Flags to clear on a disconnect */
#define PD_FLAGS_RESET_ON_DISCONNECT_MASK (PD_FLAGS_PARTNER_DR_POWER | \
PD_FLAGS_PARTNER_DR_DATA | \