summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Nematbakhsh <shawnn@chromium.org>2015-09-28 15:07:11 -0700
committerchrome-bot <chrome-bot@chromium.org>2015-10-05 20:31:18 -0700
commit1870b30a634db0f9299877380083c8b42561adbf (patch)
treede90cfff562dae9c75a8d334233e3a4144ac77e3
parent5d82dbc4910fcbcfceb8911864790c146a461684 (diff)
downloadchrome-ec-1870b30a634db0f9299877380083c8b42561adbf.tar.gz
pd: Allow EC to request PD hibernate via host command
On some systems, we may wish to have the PD follow the EC into hibernate. Add a status field to EC_CMD_PD_EXCHANGE_STATUS to support this. BUG=chrome-os-partner:45010 TEST=Manual on glados with subsequent commit. Run 'hibernate' on EC console, verify that both EC and PD go to hibernate. Plug zinger and verify that both EC and PD wake, AP boots, and battery begins charging. BRANCH=None Change-Id: I0476bc8a47ffb0fe113dccda9d4f8074105c1c84 Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/302712 Commit-Ready: Shawn N <shawnn@chromium.org> Tested-by: Shawn N <shawnn@chromium.org> Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r--board/glados_pd/board.c2
-rw-r--r--board/oak_pd/board.c2
-rw-r--r--board/samus_pd/board.c112
-rw-r--r--chip/mec1322/system.c7
-rw-r--r--chip/stm32/system.c8
-rw-r--r--common/host_command_pd.c42
-rw-r--r--include/config.h4
-rw-r--r--include/ec_commands.h10
-rw-r--r--include/host_command.h6
9 files changed, 109 insertions, 84 deletions
diff --git a/board/glados_pd/board.c b/board/glados_pd/board.c
index 42e8958538..38c3668b15 100644
--- a/board/glados_pd/board.c
+++ b/board/glados_pd/board.c
@@ -140,5 +140,5 @@ static int ec_status_host_cmd(struct host_cmd_handler_args *args)
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_PD_EXCHANGE_STATUS, ec_status_host_cmd,
- EC_VER_MASK(1));
+ EC_VER_MASK(EC_VER_PD_EXCHANGE_STATUS));
diff --git a/board/oak_pd/board.c b/board/oak_pd/board.c
index a2b1d09d78..b02e9ad877 100644
--- a/board/oak_pd/board.c
+++ b/board/oak_pd/board.c
@@ -133,5 +133,5 @@ static int ec_status_host_cmd(struct host_cmd_handler_args *args)
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_PD_EXCHANGE_STATUS, ec_status_host_cmd,
- EC_VER_MASK(1));
+ EC_VER_MASK(EC_VER_PD_EXCHANGE_STATUS));
diff --git a/board/samus_pd/board.c b/board/samus_pd/board.c
index e59646058c..8b86994b72 100644
--- a/board/samus_pd/board.c
+++ b/board/samus_pd/board.c
@@ -56,8 +56,10 @@ static enum pd_charge_state charge_state = PD_CHARGE_5V;
* Note: these vars must be aligned on 4-byte boundary because we pass the
* address to atomic_ functions which use assembly to access them.
*/
-static struct ec_response_pd_status pd_status __aligned(4);
-static struct ec_response_host_event_status host_event_status __aligned(4);
+static int32_t host_event_status_flags __aligned(4);
+static int32_t pd_status_flags __aligned(4);
+
+static struct ec_response_pd_status pd_status;
/* Desired input current limit */
static int desired_charge_rate_ma = -1;
@@ -252,9 +254,9 @@ static void board_init(void)
/* Set PD MCU system status bits */
if (system_jumped_to_this_image())
- pd_status.status |= PD_STATUS_JUMPED_TO_IMAGE;
+ pd_status_flags |= PD_STATUS_JUMPED_TO_IMAGE;
if (system_get_image_copy() == SYSTEM_IMAGE_RW)
- pd_status.status |= PD_STATUS_IN_RW;
+ pd_status_flags |= PD_STATUS_IN_RW;
/*
* Do not enable PD communication in RO as a security measure.
@@ -536,8 +538,8 @@ void pd_send_host_event(int mask)
if (!mask)
return;
- atomic_or(&(host_event_status.status), mask);
- atomic_or(&(pd_status.status), PD_STATUS_HOST_EVENT);
+ atomic_or(&(host_event_status_flags), mask);
+ atomic_or(&(pd_status_flags), PD_STATUS_HOST_EVENT);
pd_send_ec_int();
}
@@ -585,84 +587,74 @@ static int ec_status_host_cmd(struct host_cmd_handler_args *args)
/* update battery soc */
board_update_battery_soc(p->batt_soc);
- if (args->version == 1) {
- if (p->charge_state != charge_state) {
- switch (p->charge_state) {
- case PD_CHARGE_NONE:
- /*
- * No current allowed in, set new power request
- * so that PD negotiates down to vSafe5V.
- */
+ if (p->charge_state != charge_state) {
+ switch (p->charge_state) {
+ case PD_CHARGE_NONE:
+ /*
+ * No current allowed in, set new power request
+ * so that PD negotiates down to vSafe5V.
+ */
+ charge_state = p->charge_state;
+ gpio_set_level(GPIO_USB_C0_CHARGE_EN_L, 1);
+ gpio_set_level(GPIO_USB_C1_CHARGE_EN_L, 1);
+ pd_set_new_power_request(
+ pd_status.active_charge_port);
+ /*
+ * Wake charge ramp task so that it will check
+ * board_is_vbus_too_low() and stop ramping up.
+ */
+ task_wake(TASK_ID_CHG_RAMP);
+ CPRINTS("Chg: None");
+ break;
+ case PD_CHARGE_5V:
+ /* Allow current on the active charge port */
+ charge_state = p->charge_state;
+ gpio_set_level(GPIO_USB_C0_CHARGE_EN_L,
+ !(pd_status.active_charge_port == 0));
+ gpio_set_level(GPIO_USB_C1_CHARGE_EN_L,
+ !(pd_status.active_charge_port == 1));
+ CPRINTS("Chg: 5V");
+ break;
+ case PD_CHARGE_MAX:
+ /*
+ * Allow negotiation above vSafe5V. Should only
+ * ever get this command when 5V charging is
+ * already allowed.
+ */
+ if (charge_state == PD_CHARGE_5V) {
charge_state = p->charge_state;
- gpio_set_level(GPIO_USB_C0_CHARGE_EN_L, 1);
- gpio_set_level(GPIO_USB_C1_CHARGE_EN_L, 1);
pd_set_new_power_request(
pd_status.active_charge_port);
- /*
- * Wake charge ramp task so that it will check
- * board_is_vbus_too_low() and stop ramping up.
- */
- task_wake(TASK_ID_CHG_RAMP);
- CPRINTS("Chg: None");
- break;
- case PD_CHARGE_5V:
- /* Allow current on the active charge port */
- charge_state = p->charge_state;
- gpio_set_level(GPIO_USB_C0_CHARGE_EN_L,
- !(pd_status.active_charge_port == 0));
- gpio_set_level(GPIO_USB_C1_CHARGE_EN_L,
- !(pd_status.active_charge_port == 1));
- CPRINTS("Chg: 5V");
- break;
- case PD_CHARGE_MAX:
- /*
- * Allow negotiation above vSafe5V. Should only
- * ever get this command when 5V charging is
- * already allowed.
- */
- if (charge_state == PD_CHARGE_5V) {
- charge_state = p->charge_state;
- pd_set_new_power_request(
- pd_status.active_charge_port);
- CPRINTS("Chg: Max");
- }
- break;
- default:
- break;
+ CPRINTS("Chg: Max");
}
+ break;
+ default:
+ break;
}
- } else {
- /*
- * If the EC is using this command version, then it won't ever
- * set charging allowed, so we should just assume charging at
- * the max is allowed.
- */
- charge_state = PD_CHARGE_MAX;
- pd_set_new_power_request(pd_status.active_charge_port);
- CPRINTS("Chg: Max");
}
*r = pd_status;
+ r->status = pd_status_flags;
/* Clear host event */
- atomic_clear(&(pd_status.status), PD_STATUS_HOST_EVENT);
+ atomic_clear(&(pd_status_flags), PD_STATUS_HOST_EVENT);
args->response_size = sizeof(*r);
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_PD_EXCHANGE_STATUS, ec_status_host_cmd,
- EC_VER_MASK(0) | EC_VER_MASK(1));
+ EC_VER_MASK(EC_VER_PD_EXCHANGE_STATUS));
static int host_event_status_host_cmd(struct host_cmd_handler_args *args)
{
struct ec_response_host_event_status *r = args->response;
/* Clear host event bit to avoid sending more unnecessary events */
- atomic_clear(&(pd_status.status), PD_STATUS_HOST_EVENT);
+ atomic_clear(&(pd_status_flags), PD_STATUS_HOST_EVENT);
/* Read and clear the host event status to return to AP */
- r->status = atomic_read_clear(&(host_event_status.status));
+ r->status = atomic_read_clear(&(host_event_status_flags));
args->response_size = sizeof(*r);
return EC_RES_SUCCESS;
diff --git a/chip/mec1322/system.c b/chip/mec1322/system.c
index fe68777241..071cb96e80 100644
--- a/chip/mec1322/system.c
+++ b/chip/mec1322/system.c
@@ -281,6 +281,13 @@ void system_hibernate(uint32_t seconds, uint32_t microseconds)
uint32_t nvic_status[3];
char *backup_gpio_ctl;
+#ifdef CONFIG_HOSTCMD_PD
+ /* Inform the PD MCU that we are going to hibernate. */
+ host_command_pd_request_hibernate();
+ /* Wait to ensure exchange with PD before hibernating. */
+ msleep(100);
+#endif
+
cflush();
/* Disable interrupts */
diff --git a/chip/stm32/system.c b/chip/stm32/system.c
index 5e486ea20b..b1daf1ce4c 100644
--- a/chip/stm32/system.c
+++ b/chip/stm32/system.c
@@ -9,6 +9,7 @@
#include "console.h"
#include "cpu.h"
#include "flash.h"
+#include "host_command.h"
#include "registers.h"
#include "panic.h"
#include "system.h"
@@ -104,6 +105,13 @@ void __enter_hibernate(uint32_t seconds, uint32_t microseconds)
void system_hibernate(uint32_t seconds, uint32_t microseconds)
{
+#ifdef CONFIG_HOSTCMD_PD
+ /* Inform the PD MCU that we are going to hibernate. */
+ host_command_pd_request_hibernate();
+ /* Wait to ensure exchange with PD before hibernating. */
+ msleep(100);
+#endif
+
/* Flush console before hibernating */
cflush();
/* chip specific standby mode */
diff --git a/common/host_command_pd.c b/common/host_command_pd.c
index fe1ccc014c..477b602796 100644
--- a/common/host_command_pd.c
+++ b/common/host_command_pd.c
@@ -21,6 +21,7 @@
#define CPRINTS(format, args...) cprints(CC_PD_HOST_CMD, format, ## args)
#define TASK_EVENT_EXCHANGE_PD_STATUS TASK_EVENT_CUSTOM(1)
+#define TASK_EVENT_HIBERNATING TASK_EVENT_CUSTOM(2)
/* Define local option for if we are a TCPM with an off chip TCPC */
#if defined(CONFIG_USB_POWER_DELIVERY) && !defined(CONFIG_USB_PD_TCPM_STUB)
@@ -51,26 +52,23 @@ void host_command_pd_send_status(enum pd_charge_state new_chg_state)
task_set_event(TASK_ID_PDCMD, TASK_EVENT_EXCHANGE_PD_STATUS, 0);
}
+void host_command_pd_request_hibernate(void)
+{
+ task_set_event(TASK_ID_PDCMD, TASK_EVENT_HIBERNATING, 0);
+}
#ifdef CONFIG_HOSTCMD_PD
static int pd_send_host_command(struct ec_params_pd_status *ec_status,
struct ec_response_pd_status *pd_status)
{
- int rv;
-
- rv = pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 1, ec_status,
- sizeof(struct ec_params_pd_status), pd_status,
- sizeof(struct ec_response_pd_status));
-
- /* If PD doesn't support new command version, try old version */
- if (rv == -EC_RES_INVALID_VERSION)
- rv = pd_host_command(EC_CMD_PD_EXCHANGE_STATUS, 0, ec_status,
- sizeof(struct ec_params_pd_status), pd_status,
- sizeof(struct ec_response_pd_status));
- return rv;
+ return pd_host_command(EC_CMD_PD_EXCHANGE_STATUS,
+ EC_VER_PD_EXCHANGE_STATUS, ec_status,
+ sizeof(struct ec_params_pd_status), pd_status,
+ sizeof(struct ec_response_pd_status));
}
-static void pd_exchange_update_ec_status(struct ec_params_pd_status *ec_status)
+static void pd_exchange_update_ec_status(struct ec_params_pd_status *ec_status,
+ uint32_t ec_state)
{
/* Send PD charge state and battery state of charge */
#ifdef CONFIG_HOSTCMD_PD_CHG_CTRL
@@ -80,6 +78,7 @@ static void pd_exchange_update_ec_status(struct ec_params_pd_status *ec_status)
ec_status->batt_soc = charge_get_percent();
else
ec_status->batt_soc = -1;
+ ec_status->status = ec_state;
}
#ifdef CONFIG_HOSTCMD_PD_PANIC
@@ -146,14 +145,14 @@ static void pd_check_tcpc_alert(struct ec_response_pd_status *pd_status)
}
#endif /* USB_TCPM_WITH_OFF_CHIP_TCPC */
-static void pd_exchange_status(void)
+static void pd_exchange_status(uint32_t ec_state)
{
#ifdef CONFIG_HOSTCMD_PD
struct ec_params_pd_status ec_status;
struct ec_response_pd_status pd_status;
int rv;
- pd_exchange_update_ec_status(&ec_status);
+ pd_exchange_update_ec_status(&ec_status, ec_state);
#endif
#ifdef USB_TCPM_WITH_OFF_CHIP_TCPC
@@ -165,7 +164,7 @@ static void pd_exchange_status(void)
#ifdef CONFIG_HOSTCMD_PD
rv = pd_send_host_command(&ec_status, &pd_status);
if (rv < 0) {
- CPRINTS("Host command to PD MCU failed");
+ CPRINTS("Host command to PD MCU failed: %d", rv);
return;
}
@@ -196,14 +195,19 @@ static void pd_exchange_status(void)
void pd_command_task(void)
{
/* On startup exchange status with the PD */
- pd_exchange_status();
+ pd_exchange_status(0);
while (1) {
/* Wait for the next command event */
int evt = task_wait_event(-1);
+ uint32_t ec_state = 0;
+
+ if (evt & TASK_EVENT_HIBERNATING)
+ ec_state = EC_STATUS_HIBERNATING;
/* Process event to send status to PD */
- if (evt & TASK_EVENT_EXCHANGE_PD_STATUS)
- pd_exchange_status();
+ if ((evt & TASK_EVENT_EXCHANGE_PD_STATUS) ||
+ (evt & TASK_EVENT_HIBERNATING))
+ pd_exchange_status(ec_state);
}
}
diff --git a/include/config.h b/include/config.h
index 7dfd2779e1..dd54cd23c8 100644
--- a/include/config.h
+++ b/include/config.h
@@ -2000,6 +2000,10 @@
#undef CONFIG_KEYBOARD_PROTOCOL_MKBP
#endif
+#ifndef HAS_TASK_PDCMD
+#undef CONFIG_HOSTCMD_PD
+#endif
+
/*****************************************************************************/
/*
* Apply test config overrides last, since tests need to override some of the
diff --git a/include/ec_commands.h b/include/ec_commands.h
index b2eb3fe385..0fd2093b64 100644
--- a/include/ec_commands.h
+++ b/include/ec_commands.h
@@ -3166,6 +3166,7 @@ struct ec_params_reboot_ec {
/* EC to PD MCU exchange status command */
#define EC_CMD_PD_EXCHANGE_STATUS 0x100
+#define EC_VER_PD_EXCHANGE_STATUS 2
enum pd_charge_state {
PD_CHARGE_NO_CHANGE = 0, /* Don't change charge state */
@@ -3175,7 +3176,10 @@ enum pd_charge_state {
};
/* Status of EC being sent to PD */
+#define EC_STATUS_HIBERNATING (1 << 0)
+
struct ec_params_pd_status {
+ uint8_t status; /* EC status */
int8_t batt_soc; /* battery state of charge */
uint8_t charge_state; /* charging state (from enum pd_charge_state) */
} __packed;
@@ -3192,9 +3196,9 @@ struct ec_params_pd_status {
PD_STATUS_TCPC_ALERT_1 | \
PD_STATUS_HOST_EVENT)
struct ec_response_pd_status {
- uint32_t status; /* PD MCU status */
- uint32_t curr_lim_ma; /* input current limit */
- int32_t active_charge_port; /* active charging port */
+ uint32_t curr_lim_ma; /* input current limit */
+ uint16_t status; /* PD MCU status */
+ int8_t active_charge_port; /* active charging port */
} __packed;
/* AP to PD MCU host event status command, cleared on read */
diff --git a/include/host_command.h b/include/host_command.h
index 08141e2204..c987df561b 100644
--- a/include/host_command.h
+++ b/include/host_command.h
@@ -216,6 +216,12 @@ void host_throttle_cpu(int throttle);
void host_command_pd_send_status(enum pd_charge_state new_chg_state);
/**
+ * Signal host command task to inform PD MCU that the EC is going to hibernate,
+ * which will normally cause the PD MCU to hibernate also.
+ */
+void host_command_pd_request_hibernate(void);
+
+/**
* Get the active charge port from the PD
*
* @return -1 == none/unknown, 0 == left, 1 == right.