summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/ec/google/chromeec/ec.c209
-rw-r--r--src/ec/google/chromeec/ec.h4
-rw-r--r--src/ec/google/chromeec/ec_commands.h82
-rw-r--r--src/ec/google/chromeec/smihandler.c20
4 files changed, 282 insertions, 33 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)
diff --git a/src/ec/google/chromeec/ec.h b/src/ec/google/chromeec/ec.h
index e1bf6c8e76..90bb6fa9d2 100644
--- a/src/ec/google/chromeec/ec.h
+++ b/src/ec/google/chromeec/ec.h
@@ -31,6 +31,9 @@ int google_chromeec_set_sci_mask(uint64_t mask);
int google_chromeec_set_smi_mask(uint64_t mask);
int google_chromeec_set_wake_mask(uint64_t mask);
u8 google_chromeec_get_event(void);
+
+/* Check if EC supports feature EC_FEATURE_UNIFIED_WAKE_MASKS */
+bool google_chromeec_is_uhepi_supported(void);
int google_ec_running_ro(void);
void google_chromeec_init(void);
@@ -141,6 +144,7 @@ struct google_chromeec_event_info {
uint64_t s3_wake_events;
uint64_t s3_device_events;
uint64_t s5_wake_events;
+ uint64_t s0ix_wake_events;
};
void google_chromeec_events_init(const struct google_chromeec_event_info *info,
bool is_s3_wakeup);
diff --git a/src/ec/google/chromeec/ec_commands.h b/src/ec/google/chromeec/ec_commands.h
index 0fbb1a6b8c..92fb2a8a67 100644
--- a/src/ec/google/chromeec/ec_commands.h
+++ b/src/ec/google/chromeec/ec_commands.h
@@ -3055,6 +3055,8 @@ struct __ec_align1 ec_response_temp_sensor_get_info {
/*****************************************************************************/
/* Host event commands */
+
+/* Obsolete. New implementation should use EC_CMD_PROGRAM_HOST_EVENT instead */
/*
* Host event mask params and response structures, shared by all of the host
* event commands below.
@@ -3080,6 +3082,86 @@ struct __ec_align4 ec_response_host_event_mask {
#define EC_CMD_HOST_EVENT_SET_WAKE_MASK 0x008E
#define EC_CMD_HOST_EVENT_CLEAR_B 0x008F
+/*
+ * Unified host event programming interface - Should be used by newer versions
+ * of BIOS/OS to program host events and masks
+ */
+
+struct __ec_align4 ec_params_host_event {
+
+ /* Action requested by host - one of enum ec_host_event_action. */
+ uint8_t action;
+
+ /*
+ * Mask type that the host requested the action on - one of
+ * enum ec_host_event_mask_type.
+ */
+ uint8_t mask_type;
+
+ /* Set to 0, ignore on read */
+ uint16_t reserved;
+
+ /* Value to be used in case of set operations. */
+ uint64_t value;
+};
+
+/*
+ * Response structure returned by EC_CMD_HOST_EVENT.
+ * Update the value on a GET request. Set to 0 on GET/CLEAR
+ */
+
+struct __ec_align4 ec_response_host_event {
+
+ /* Mask value in case of get operation */
+ uint64_t value;
+};
+
+enum ec_host_event_action {
+ /*
+ * params.value is ignored. Value of mask_type populated
+ * in response.value
+ */
+ EC_HOST_EVENT_GET,
+
+ /* Bits in params.value are set */
+ EC_HOST_EVENT_SET,
+
+ /* Bits in params.value are cleared */
+ EC_HOST_EVENT_CLEAR,
+};
+
+enum ec_host_event_mask_type {
+
+ /* Main host event copy */
+ EC_HOST_EVENT_MAIN,
+
+ /* Copy B of host events */
+ EC_HOST_EVENT_B,
+
+ /* SCI Mask */
+ EC_HOST_EVENT_SCI_MASK,
+
+ /* SMI Mask */
+ EC_HOST_EVENT_SMI_MASK,
+
+ /* Mask of events that should be always reported in hostevents */
+ EC_HOST_EVENT_ALWAYS_REPORT_MASK,
+
+ /* Active wake mask */
+ EC_HOST_EVENT_ACTIVE_WAKE_MASK,
+
+ /* Lazy wake mask for S0ix */
+ EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX,
+
+ /* Lazy wake mask for S3 */
+ EC_HOST_EVENT_LAZY_WAKE_MASK_S3,
+
+ /* Lazy wake mask for S5 */
+ EC_HOST_EVENT_LAZY_WAKE_MASK_S5,
+};
+
+#define EC_CMD_HOST_EVENT 0x00A4
+
/*****************************************************************************/
/* Switch commands */
diff --git a/src/ec/google/chromeec/smihandler.c b/src/ec/google/chromeec/smihandler.c
index 71f0d71b8e..54aa4bfd94 100644
--- a/src/ec/google/chromeec/smihandler.c
+++ b/src/ec/google/chromeec/smihandler.c
@@ -59,15 +59,17 @@ static void clear_pending_events(void)
void chromeec_smi_sleep(int slp_type, uint64_t s3_mask, uint64_t s5_mask)
{
- switch (slp_type) {
- case ACPI_S3:
- /* Enable wake events */
- google_chromeec_set_wake_mask(s3_mask);
- break;
- case ACPI_S5:
- /* Enable wake events */
- google_chromeec_set_wake_mask(s5_mask);
- break;
+ if (!google_chromeec_is_uhepi_supported()) {
+ switch (slp_type) {
+ case ACPI_S3:
+ /* Enable wake events */
+ google_chromeec_set_wake_mask(s3_mask);
+ break;
+ case ACPI_S5:
+ /* Enable wake events */
+ google_chromeec_set_wake_mask(s5_mask);
+ break;
+ }
}
/* Disable SCI and SMI events */