summaryrefslogtreecommitdiff
path: root/common/host_event_commands.c
diff options
context:
space:
mode:
authorJenny TC <jenny.tc@intel.com>2017-11-22 09:58:19 +0530
committerchrome-bot <chrome-bot@chromium.org>2017-12-06 03:45:57 -0800
commit67c31eb10bc1ce6e559562aedd2f641de4243bb8 (patch)
tree506d18fd02ac83ec2e89282366a11378c56c984e /common/host_event_commands.c
parentfb32b6d30cf55408f4bdb36b729c99452f6e8e11 (diff)
downloadchrome-ec-67c31eb10bc1ce6e559562aedd2f641de4243bb8.tar.gz
host_events: Introduce unified host event command
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=make buildall -j. And verfieid following scenario 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(making get_feature_flags1() return 0) Change-Id: Idb82ee87fffb475cd3fa9771bf7a5efda67af616 Signed-off-by: Jenny TC <jenny.tc@intel.com> Reviewed-on: https://chromium-review.googlesource.com/576047 Commit-Ready: Jenny Tc <jenny.tc@intel.com> Commit-Ready: Jenny Tc <jenny.tc@intel.corp-partner.google.com> Tested-by: Jenny Tc <jenny.tc@intel.com> Tested-by: Jenny Tc <jenny.tc@intel.corp-partner.google.com> Reviewed-by: Furquan Shaikh <furquan@chromium.org>
Diffstat (limited to 'common/host_event_commands.c')
-rw-r--r--common/host_event_commands.c210
1 files changed, 210 insertions, 0 deletions
diff --git a/common/host_event_commands.c b/common/host_event_commands.c
index 0f092f6bea..587fa12df2 100644
--- a/common/host_event_commands.c
+++ b/common/host_event_commands.c
@@ -11,6 +11,7 @@
#include "host_command.h"
#include "lpc.h"
#include "mkbp_event.h"
+#include "power.h"
#include "system.h"
#include "task.h"
#include "util.h"
@@ -83,10 +84,17 @@ static void host_event_set_bit(host_event_t *ev, uint8_t bit)
static host_event_t lpc_host_events;
static host_event_t lpc_host_event_mask[LPC_HOST_EVENT_COUNT];
+/* Indicates if active wake mask set by host */
+static uint8_t active_wm_set_by_host;
+
void lpc_set_host_event_mask(enum lpc_host_event_type type, host_event_t mask)
{
lpc_host_event_mask[type] = mask;
lpc_update_host_event_status();
+
+ /* mask 0 indicates wake mask not set by host */
+ if ((type == LPC_HOST_EVENT_WAKE) && (mask == 0))
+ active_wm_set_by_host = 0;
}
host_event_t lpc_get_host_event_mask(enum lpc_host_event_type type)
@@ -210,6 +218,17 @@ void lpc_s3_resume_clear_masks(void)
static host_event_t events;
static host_event_t events_copy_b;
+/* Lazy wake masks */
+#ifdef CONFIG_LPC
+static struct lazy_wake_masks {
+ host_event_t s3_lazy_wm;
+ host_event_t s5_lazy_wm;
+#ifdef CONFIG_POWER_S0IX
+ host_event_t s0ix_lazy_wm;
+#endif
+} lazy_wm;
+#endif
+
static void host_events_atomic_or(host_event_t *e, host_event_t m)
{
uint32_t *ptr = (uint32_t *)e;
@@ -512,12 +531,18 @@ static int host_event_set_wake_mask(struct host_cmd_handler_args *args)
const struct ec_params_host_event_mask *p = args->params;
lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, p->mask);
+ active_wm_set_by_host = !!p->mask;
return EC_RES_SUCCESS;
}
DECLARE_HOST_COMMAND(EC_CMD_HOST_EVENT_SET_WAKE_MASK,
host_event_set_wake_mask,
EC_VER_MASK(0));
+uint8_t lpc_is_active_wm_set_by_host(void)
+{
+ return active_wm_set_by_host;
+}
+
#endif /* CONFIG_LPC */
static int host_event_get_b(struct host_cmd_handler_args *args)
@@ -554,3 +579,188 @@ static int host_event_clear_b(struct host_cmd_handler_args *args)
DECLARE_HOST_COMMAND(EC_CMD_HOST_EVENT_CLEAR_B,
host_event_clear_b,
EC_VER_MASK(0));
+
+static int host_event_action_get(struct host_cmd_handler_args *args)
+{
+ struct ec_response_host_event *r = args->response;
+ const struct ec_params_host_event *p = args->params;
+ int result = EC_RES_SUCCESS;
+
+ args->response_size = sizeof(*r);
+ memset(r, 0, sizeof(*r));
+
+ switch (p->mask_type) {
+ case EC_HOST_EVENT_B:
+ r->value = events_copy_b;
+ break;
+#ifdef CONFIG_LPC
+ case EC_HOST_EVENT_SCI_MASK:
+ r->value = lpc_get_host_event_mask(LPC_HOST_EVENT_SCI);
+ break;
+ case EC_HOST_EVENT_SMI_MASK:
+ r->value = lpc_get_host_event_mask(LPC_HOST_EVENT_SMI);
+ break;
+ case EC_HOST_EVENT_ALWAYS_REPORT_MASK:
+ r->value = lpc_get_host_event_mask
+ (LPC_HOST_EVENT_ALWAYS_REPORT);
+ break;
+ case EC_HOST_EVENT_ACTIVE_WAKE_MASK:
+ r->value = lpc_get_host_event_mask(LPC_HOST_EVENT_WAKE);
+ break;
+#ifdef CONFIG_POWER_S0IX
+ case EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX:
+ r->value = lazy_wm.s0ix_lazy_wm;
+ break;
+#endif
+ case EC_HOST_EVENT_LAZY_WAKE_MASK_S3:
+ r->value = lazy_wm.s3_lazy_wm;
+ break;
+ case EC_HOST_EVENT_LAZY_WAKE_MASK_S5:
+ r->value = lazy_wm.s5_lazy_wm;
+ break;
+#endif
+ default:
+ result = EC_RES_INVALID_PARAM;
+ break;
+ }
+
+ return result;
+}
+
+static int host_event_action_set(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_host_event *p = args->params;
+ int result = EC_RES_SUCCESS;
+ host_event_t mask_value __unused = (host_event_t)(p->value);
+
+ switch (p->mask_type) {
+#ifdef CONFIG_LPC
+ case EC_HOST_EVENT_SCI_MASK:
+ lpc_set_host_event_mask(LPC_HOST_EVENT_SCI, mask_value);
+ break;
+ case EC_HOST_EVENT_SMI_MASK:
+ lpc_set_host_event_mask(LPC_HOST_EVENT_SMI, mask_value);
+ break;
+ case EC_HOST_EVENT_ALWAYS_REPORT_MASK:
+ lpc_set_host_event_mask(LPC_HOST_EVENT_ALWAYS_REPORT,
+ mask_value);
+ break;
+ case EC_HOST_EVENT_ACTIVE_WAKE_MASK:
+ active_wm_set_by_host = !!mask_value;
+ lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, mask_value);
+ break;
+#ifdef CONFIG_POWER_S0IX
+ case EC_HOST_EVENT_LAZY_WAKE_MASK_S0IX:
+ lazy_wm.s0ix_lazy_wm = mask_value;
+ break;
+#endif
+ case EC_HOST_EVENT_LAZY_WAKE_MASK_S3:
+ lazy_wm.s3_lazy_wm = mask_value;
+ break;
+ case EC_HOST_EVENT_LAZY_WAKE_MASK_S5:
+ lazy_wm.s5_lazy_wm = mask_value;
+ break;
+#endif
+ default:
+ result = EC_RES_INVALID_PARAM;
+ break;
+ }
+
+ return result;
+}
+
+static int host_event_action_clear(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_host_event *p = args->params;
+ int result = EC_RES_SUCCESS;
+ host_event_t mask_value = (host_event_t)(p->value);
+
+ switch (p->mask_type) {
+ case EC_HOST_EVENT_MAIN:
+ host_clear_events(mask_value);
+ break;
+ case EC_HOST_EVENT_B:
+ host_clear_events_b(mask_value);
+ break;
+ default:
+ result = EC_RES_INVALID_PARAM;
+ }
+
+ return result;
+}
+
+static int host_command_host_event(struct host_cmd_handler_args *args)
+{
+ const struct ec_params_host_event *p = args->params;
+
+ args->response_size = 0;
+
+ switch (p->action) {
+ case EC_HOST_EVENT_GET:
+ return host_event_action_get(args);
+ case EC_HOST_EVENT_SET:
+ return host_event_action_set(args);
+ case EC_HOST_EVENT_CLEAR:
+ return host_event_action_clear(args);
+ default:
+ return EC_RES_INVALID_PARAM;
+ }
+}
+
+DECLARE_HOST_COMMAND(EC_CMD_HOST_EVENT,
+ host_command_host_event,
+ EC_VER_MASK(0));
+
+#define LAZY_WAKE_MASK_SYSJUMP_TAG 0x4C4D /* LM - Lazy Mask*/
+#define LAZY_WAKE_MASK_HOOK_VERSION 1
+
+#ifdef CONFIG_LPC
+int get_lazy_wake_mask(enum power_state state, host_event_t *mask)
+{
+ int ret = EC_SUCCESS;
+
+ switch (state) {
+ case POWER_S5:
+ *mask = lazy_wm.s5_lazy_wm;
+ break;
+ case POWER_S3:
+ *mask = lazy_wm.s3_lazy_wm;
+ break;
+#ifdef CONFIG_POWER_S0IX
+ case POWER_S0ix:
+ *mask = lazy_wm.s0ix_lazy_wm;
+ break;
+#endif
+ default:
+ *mask = 0;
+ ret = EC_ERROR_INVAL;
+ }
+
+ return ret;
+}
+
+static void preserve_lazy_wm(void)
+{
+ system_add_jump_tag(LAZY_WAKE_MASK_SYSJUMP_TAG,
+ LAZY_WAKE_MASK_HOOK_VERSION,
+ sizeof(lazy_wm),
+ &lazy_wm);
+}
+DECLARE_HOOK(HOOK_SYSJUMP, preserve_lazy_wm, HOOK_PRIO_DEFAULT);
+
+static void restore_lazy_wm(void)
+{
+ const struct lazy_wake_masks *wm_state;
+ int version, size;
+
+ wm_state = (const struct lazy_wake_masks *)
+ system_get_jump_tag(LAZY_WAKE_MASK_SYSJUMP_TAG,
+ &version, &size);
+
+ if (wm_state && (version == LAZY_WAKE_MASK_HOOK_VERSION) &&
+ (size == sizeof(lazy_wm))) {
+ lazy_wm = *wm_state;
+ }
+}
+DECLARE_HOOK(HOOK_INIT, restore_lazy_wm, HOOK_PRIO_INIT_CHIPSET + 1);
+#endif