summaryrefslogtreecommitdiff
path: root/src/ec/google/chromeec/ec.c
diff options
context:
space:
mode:
authorJenny TC <jenny.tc@intel.com>2017-12-14 14:24:39 +0530
committerMartin Roth <martinroth@google.com>2018-01-17 17:10:32 +0000
commit1dfc2c3e54468f52bd7f2b204758bac2625a36e6 (patch)
treecb45d78f1f1f11a1fd509b15caf8e8b04165d317 /src/ec/google/chromeec/ec.c
parent0a4e0fd913006de8f5d0a4ea24e013f30243cf5c (diff)
downloadcoreboot-1dfc2c3e54468f52bd7f2b204758bac2625a36e6.tar.xz
google/chromeec: Enable unified host event programming interface
Unified Host Event Programming Interface (UHEPI) enables a unified host command EC_CMD_PROGRAM_HOST_EVENT to set/get/clear different host events. Old host event commands (0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F) is supported for backward compatibility. But newer version of BIOS/OS is expected to use UHEPI command (EC_CMD_PROGRAM_HOST_EVENT) The UHEPI also enables the active and lazy wake masks. Active wake mask is the mask that is programmed in the LPC driver (i.e. the mask that is actively used by LPC driver for waking the host during suspended state). It is same as the current wake mask that is set by the smihandler on host just before entering sleep state S3/S5. On the other hand, lazy wake masks are per-sleep masks (S0ix, S3, S5) so that they can be used by EC to set the active wake mask depending upon the type of sleep that the host has entered. This allows the host BIOS to perform one-time programming of the wake masks for each supported sleep type and then EC can take care of appropriately setting the active mask when host enters a particular sleep state. BRANCH=none BUG=b:63969337 TEST=verify masks with ec hostevent command on S0,S3,S5 and S0ix 1). Verified wake masks with ec hostevent command on S0,S3,S5 and S0ix 2). suspend_stress_test with S3 and S0ix 3). Verified "mosys eventlog list" in S3 and s0ix resume to confirm wake sources (Lid, power buttton and Mode change) 4). Verified "mosys eventlog list" in S5 resume to confirm wake sources (Power Button) 5). Verified above scenarios with combination of Old BIOS + New EC and New BIOS + Old EC Change-Id: I4917a222c79b6aaecb71d7704ffde57bf3bc99d9 Signed-off-by: Jenny TC <jenny.tc@intel.com> Reviewed-on: https://review.coreboot.org/21085 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Furquan Shaikh <furquan@google.com>
Diffstat (limited to 'src/ec/google/chromeec/ec.c')
-rw-r--r--src/ec/google/chromeec/ec.c209
1 files changed, 185 insertions, 24 deletions
diff --git a/src/ec/google/chromeec/ec.c b/src/ec/google/chromeec/ec.c
index 588d11528b..89241daaa1 100644
--- a/src/ec/google/chromeec/ec.c
+++ b/src/ec/google/chromeec/ec.c
@@ -17,7 +17,9 @@
#include <string.h>
#include <cbmem.h>
#include <console/console.h>
+#include <arch/early_variables.h>
#include <arch/io.h>
+#include <assert.h>
#include <bootmode.h>
#include <bootstate.h>
#include <delay.h>
@@ -32,6 +34,42 @@
#include "ec.h"
#include "ec_commands.h"
+#define INVALID_HCMD 0xFF
+
+/*
+ * Map UHEPI masks to non UHEPI commands in order to support old EC FW
+ * which does not support UHEPI command.
+ */
+static const struct {
+ uint8_t set_cmd;
+ uint8_t clear_cmd;
+ uint8_t get_cmd;
+} event_map[] = {
+ [EC_HOST_EVENT_MAIN] = {
+ INVALID_HCMD, EC_CMD_HOST_EVENT_CLEAR,
+ INVALID_HCMD,
+ },
+ [EC_HOST_EVENT_B] = {
+ INVALID_HCMD, EC_CMD_HOST_EVENT_CLEAR_B,
+ EC_CMD_HOST_EVENT_GET_B,
+ },
+ [EC_HOST_EVENT_SCI_MASK] = {
+ EC_CMD_HOST_EVENT_SET_SCI_MASK, INVALID_HCMD,
+ EC_CMD_HOST_EVENT_GET_SCI_MASK,
+ },
+ [EC_HOST_EVENT_SMI_MASK] = {
+ EC_CMD_HOST_EVENT_SET_SMI_MASK, INVALID_HCMD,
+ EC_CMD_HOST_EVENT_GET_SMI_MASK,
+ },
+ [EC_HOST_EVENT_ALWAYS_REPORT_MASK] = {
+ INVALID_HCMD, INVALID_HCMD, INVALID_HCMD,
+ },
+ [EC_HOST_EVENT_ACTIVE_WAKE_MASK] = {
+ EC_CMD_HOST_EVENT_SET_WAKE_MASK, INVALID_HCMD,
+ EC_CMD_HOST_EVENT_GET_WAKE_MASK,
+ },
+};
+
void log_recovery_mode_switch(void)
{
uint64_t *events;
@@ -111,13 +149,21 @@ void google_chromeec_post(u8 postcode)
* Query the EC for specified mask indicating enabled events.
* The EC maintains separate event masks for SMI, SCI and WAKE.
*/
-static uint64_t google_chromeec_get_mask(u8 type)
+static int google_chromeec_uhepi_cmd(uint8_t mask, uint8_t action,
+ uint64_t *value)
{
- struct ec_params_host_event_mask req;
- struct ec_response_host_event_mask rsp;
+ int ret;
+ struct ec_params_host_event req;
+ struct ec_response_host_event rsp;
struct chromeec_command cmd;
- cmd.cmd_code = type;
+ req.action = action;
+ req.mask_type = mask;
+ if (action != EC_HOST_EVENT_GET)
+ req.value = *value;
+ else
+ *value = 0;
+ cmd.cmd_code = EC_CMD_HOST_EVENT;
cmd.cmd_version = 0;
cmd.cmd_data_in = &req;
cmd.cmd_size_in = sizeof(req);
@@ -125,19 +171,32 @@ static uint64_t google_chromeec_get_mask(u8 type)
cmd.cmd_size_out = sizeof(rsp);
cmd.cmd_dev_index = 0;
- if (google_chromeec_command(&cmd) == 0)
- return rsp.mask;
- return 0;
+ ret = google_chromeec_command(&cmd);
+
+ if (action != EC_HOST_EVENT_GET)
+ return ret;
+ if (ret == 0)
+ *value = rsp.value;
+ return ret;
}
-static int google_chromeec_set_mask(uint8_t type, uint64_t mask)
+static int google_chromeec_handle_non_uhepi_cmd(uint8_t hcmd, uint8_t action,
+ uint64_t *value)
{
+ int ret = -1;
struct ec_params_host_event_mask req;
struct ec_response_host_event_mask rsp;
struct chromeec_command cmd;
- req.mask = (uint32_t)mask;
- cmd.cmd_code = type;
+ if (hcmd == INVALID_HCMD)
+ return ret;
+
+ if (action != EC_HOST_EVENT_GET)
+ req.mask = (uint32_t)*value;
+ else
+ *value = 0;
+
+ cmd.cmd_code = hcmd;
cmd.cmd_version = 0;
cmd.cmd_data_in = &req;
cmd.cmd_size_in = sizeof(req);
@@ -145,19 +204,115 @@ static int google_chromeec_set_mask(uint8_t type, uint64_t mask)
cmd.cmd_size_out = sizeof(rsp);
cmd.cmd_dev_index = 0;
- return google_chromeec_command(&cmd);
+ ret = google_chromeec_command(&cmd);
+
+ if (action != EC_HOST_EVENT_GET)
+ return ret;
+ if (ret == 0)
+ *value = rsp.mask;
+
+ return ret;
+}
+
+bool google_chromeec_is_uhepi_supported(void)
+{
+#define UHEPI_SUPPORTED 1
+#define UHEPI_NOT_SUPPORTED 2
+
+ static int uhepi_support CAR_GLOBAL;
+
+ if (!uhepi_support) {
+ uhepi_support = google_chromeec_check_feature
+ (EC_FEATURE_UNIFIED_WAKE_MASKS) ? UHEPI_SUPPORTED :
+ UHEPI_NOT_SUPPORTED;
+ printk(BIOS_DEBUG, "Chrome EC: UHEPI %s\n",
+ uhepi_support == UHEPI_SUPPORTED ?
+ "supported" : "not supported");
+ }
+ return uhepi_support == UHEPI_SUPPORTED;
+}
+
+static uint64_t google_chromeec_get_mask(u8 type)
+{
+ u64 value = 0;
+
+ if (google_chromeec_is_uhepi_supported()) {
+ google_chromeec_uhepi_cmd(type, EC_HOST_EVENT_GET, &value);
+ } else {
+ assert(type < ARRAY_SIZE(event_map));
+ google_chromeec_handle_non_uhepi_cmd(
+ event_map[type].get_cmd,
+ EC_HOST_EVENT_GET, &value);
+ }
+ return value;
+}
+static int google_chromeec_clear_mask(u8 type, u64 mask)
+{
+ if (google_chromeec_is_uhepi_supported())
+ return google_chromeec_uhepi_cmd(type,
+ EC_HOST_EVENT_CLEAR, &mask);
+
+ assert(type < ARRAY_SIZE(event_map));
+ return google_chromeec_handle_non_uhepi_cmd(
+ event_map[type].clear_cmd,
+ EC_HOST_EVENT_CLEAR, &mask);
+}
+static int __unused google_chromeec_set_mask(u8 type, u64 mask)
+{
+ if (google_chromeec_is_uhepi_supported())
+ return google_chromeec_uhepi_cmd(type,
+ EC_HOST_EVENT_SET, &mask);
+
+ assert(type < ARRAY_SIZE(event_map));
+ return google_chromeec_handle_non_uhepi_cmd(
+ event_map[type].set_cmd,
+ EC_HOST_EVENT_SET, &mask);
+}
+
+static int google_chromeec_set_s3_lazy_wake_mask(uint64_t mask)
+{
+ printk(BIOS_DEBUG, "Chrome EC: Set S3 LAZY WAKE mask to 0x%016llx\n\n",
+ mask);
+ return google_chromeec_set_mask
+ (EC_HOST_EVENT_LAZY_WAKE_MASK_S3, mask);
+}
+
+static int google_chromeec_set_s5_lazy_wake_mask(uint64_t mask)
+{
+ printk(BIOS_DEBUG, "Chrome EC: Set S5 LAZY WAKE mask to 0x%016llx\n\n",
+ mask);
+ return google_chromeec_set_mask
+ (EC_HOST_EVENT_LAZY_WAKE_MASK_S5, mask);
+}
+
+static int google_chromeec_set_s0ix_lazy_wake_mask(uint64_t mask)
+{
+ printk(BIOS_DEBUG, "Chrome EC: Set S0iX LAZY WAKE mask to 0x%016llx\n\n",
+ mask);
+ return google_chromeec_set_mask
+ (EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX, mask);
+}
+static void google_chromeec_set_lazy_wake_masks(uint64_t s5_mask,
+ uint64_t s3_mask, uint64_t s0ix_mask)
+{
+ if (google_chromeec_set_s5_lazy_wake_mask(s5_mask))
+ printk(BIOS_DEBUG, "Error: Set S5 LAZY WAKE mask failed\n");
+ if (google_chromeec_set_s3_lazy_wake_mask(s3_mask))
+ printk(BIOS_DEBUG, "Error: Set S3 LAZY WAKE mask failed\n");
+ if (google_chromeec_set_s0ix_lazy_wake_mask(s0ix_mask))
+ printk(BIOS_DEBUG, "Error: Set S0iX LAZY WAKE mask failed\n");
}
uint64_t google_chromeec_get_events_b(void)
{
- return google_chromeec_get_mask(EC_CMD_HOST_EVENT_GET_B);
+ return google_chromeec_get_mask(EC_HOST_EVENT_B);
}
int google_chromeec_clear_events_b(uint64_t mask)
{
- printk(BIOS_DEBUG, "Chrome EC: clear events_b mask to 0x%016llx\n", mask);
- return google_chromeec_set_mask(
- EC_CMD_HOST_EVENT_CLEAR_B, mask);
+ printk(BIOS_DEBUG,
+ "Chrome EC: clear events_b mask to 0x%016llx\n", mask);
+ return google_chromeec_clear_mask(EC_HOST_EVENT_B, mask);
}
int google_chromeec_get_mkbp_event(struct ec_response_get_next_event *event)
@@ -304,12 +459,21 @@ void google_chromeec_events_init(const struct google_chromeec_event_info *info,
/* Restore SCI event mask. */
google_chromeec_set_sci_mask(info->sci_events);
- } else
+
+ } else {
google_chromeec_log_events(info->log_events |
info->s5_wake_events);
+ if (google_chromeec_is_uhepi_supported())
+ google_chromeec_set_lazy_wake_masks
+ (info->s5_wake_events,
+ info->s3_wake_events,
+ info->s0ix_wake_events);
+
+ }
/* Clear wake event mask. */
google_chromeec_set_wake_mask(0);
+
}
int google_chromeec_check_feature(int feature)
@@ -566,28 +730,25 @@ int google_chromeec_i2c_xfer(uint8_t chip, uint8_t addr, int alen,
int google_chromeec_set_sci_mask(uint64_t mask)
{
printk(BIOS_DEBUG, "Chrome EC: Set SCI mask to 0x%016llx\n", mask);
- return google_chromeec_set_mask(
- EC_CMD_HOST_EVENT_SET_SCI_MASK, mask);
+ return google_chromeec_set_mask(EC_HOST_EVENT_SCI_MASK, mask);
}
int google_chromeec_set_smi_mask(uint64_t mask)
{
printk(BIOS_DEBUG, "Chrome EC: Set SMI mask to 0x%016llx\n", mask);
- return google_chromeec_set_mask(
- EC_CMD_HOST_EVENT_SET_SMI_MASK, mask);
+ return google_chromeec_set_mask(EC_HOST_EVENT_SMI_MASK, mask);
}
int google_chromeec_set_wake_mask(uint64_t mask)
{
printk(BIOS_DEBUG, "Chrome EC: Set WAKE mask to 0x%016llx\n", mask);
- return google_chromeec_set_mask(
- EC_CMD_HOST_EVENT_SET_WAKE_MASK, mask);
+ return google_chromeec_set_mask
+ (EC_HOST_EVENT_ACTIVE_WAKE_MASK, mask);
}
uint64_t google_chromeec_get_wake_mask(void)
{
- return google_chromeec_get_mask(
- EC_CMD_HOST_EVENT_GET_WAKE_MASK);
+ return google_chromeec_get_mask(EC_HOST_EVENT_ACTIVE_WAKE_MASK);
}
int google_chromeec_set_usb_charge_mode(u8 port_id, enum usb_charge_mode mode)