diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ec/google/chromeec/ec.c | 209 | ||||
-rw-r--r-- | src/ec/google/chromeec/ec.h | 4 | ||||
-rw-r--r-- | src/ec/google/chromeec/ec_commands.h | 82 | ||||
-rw-r--r-- | src/ec/google/chromeec/smihandler.c | 20 |
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 */ |