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>
This commit is contained in:
Jenny TC 2017-12-14 14:24:39 +05:30 committed by Martin Roth
parent 0a4e0fd913
commit 1dfc2c3e54
4 changed files with 282 additions and 33 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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 */

View File

@ -59,6 +59,7 @@ static void clear_pending_events(void)
void chromeec_smi_sleep(int slp_type, uint64_t s3_mask, uint64_t s5_mask)
{
if (!google_chromeec_is_uhepi_supported()) {
switch (slp_type) {
case ACPI_S3:
/* Enable wake events */
@ -69,6 +70,7 @@ void chromeec_smi_sleep(int slp_type, uint64_t s3_mask, uint64_t s5_mask)
google_chromeec_set_wake_mask(s5_mask);
break;
}
}
/* Disable SCI and SMI events */
google_chromeec_set_smi_mask(0);