summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Feng <li1.feng@intel.com>2022-03-30 16:59:52 -0700
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-04-13 02:30:57 +0000
commitd12fb951bc0efbd8fc1ef366cbc835e4147faf92 (patch)
tree4c9102ade019a87b26c5630db65c651a9da749d1
parent229bb8111cd47592ac2cc012683f4f7169705d6a (diff)
downloadchrome-ec-d12fb951bc0efbd8fc1ef366cbc835e4147faf92.tar.gz
zephyr: ap_pwrseq: support host sleep event and wake mask
S0ix enablement has multiple patches, this is second one of the series. HC EC_CMD_HOST_SLEEP_EVENT implementation in legacy EC code is reused. This will be migrated to Zephyr implementation. ap_pwrseq provides ap_power_chipset_handle_host_sleep_event() to process host sleep event changes. BIOS sets wake masks for each sleep state (S3/S5/S0ix) only once during boot up. EC has to take care wake mask update when power state changes. Updating wake mask at run time is added to ap_pwrseq. HC get/set wake mask in legacy EC code is resued. This should migrate to Zephyr implementation too. Refer to CL:576047 for original design. BUG=b:203446068 b:203446865 BRANCH=none TEST=zmake testall Signed-off-by: Li Feng <li1.feng@intel.com> Change-Id: Id972b904add5b3170fb91a8aa180736b42923dfd Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3562042 Reviewed-by: Andrew McRae <amcrae@google.com>
-rw-r--r--zephyr/CMakeLists.txt3
-rw-r--r--zephyr/shim/include/config_chip.h6
-rw-r--r--zephyr/shim/include/power_host_sleep.h69
-rw-r--r--zephyr/shim/src/CMakeLists.txt2
-rw-r--r--zephyr/shim/src/power_host_sleep_api.c45
-rw-r--r--zephyr/subsys/ap_pwrseq/CMakeLists.txt1
-rw-r--r--zephyr/subsys/ap_pwrseq/Kconfig13
-rw-r--r--zephyr/subsys/ap_pwrseq/include/ap_power_host_sleep.h35
-rw-r--r--zephyr/subsys/ap_pwrseq/power_host_sleep.c111
9 files changed, 279 insertions, 6 deletions
diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt
index df54406fa2..9a14c93731 100644
--- a/zephyr/CMakeLists.txt
+++ b/zephyr/CMakeLists.txt
@@ -516,7 +516,8 @@ zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_RTC
"${PLATFORM_EC}/common/rtc.c")
zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_MATH_UTIL
"${PLATFORM_EC}/common/math_util.c")
-
+zephyr_library_sources_ifdef(CONFIG_AP_PWRSEQ_HOST_SLEEP
+ "${PLATFORM_EC}/power/host_sleep.c")
# Switch to ec_shim library for all Zephyr sources
set(ZEPHYR_CURRENT_LIBRARY ec_shim)
diff --git a/zephyr/shim/include/config_chip.h b/zephyr/shim/include/config_chip.h
index 2900acd9aa..5f865c3fa7 100644
--- a/zephyr/shim/include/config_chip.h
+++ b/zephyr/shim/include/config_chip.h
@@ -804,7 +804,8 @@ extern struct jump_data mock_jump_data;
#endif
#undef CONFIG_POWER_TRACK_HOST_SLEEP_STATE
-#ifdef CONFIG_PLATFORM_EC_POWERSEQ_HOST_SLEEP
+#if defined(CONFIG_PLATFORM_EC_POWERSEQ_HOST_SLEEP) || \
+ defined(CONFIG_AP_PWRSEQ_HOST_SLEEP)
#define CONFIG_POWER_TRACK_HOST_SLEEP_STATE
#endif
@@ -840,7 +841,8 @@ extern struct jump_data mock_jump_data;
#endif
#undef CONFIG_POWER_S0IX
-#ifdef CONFIG_PLATFORM_EC_POWERSEQ_S0IX
+#if defined(CONFIG_PLATFORM_EC_POWERSEQ_S0IX) || \
+ defined(CONFIG_AP_PWRSEQ_S0IX)
#define CONFIG_POWER_S0IX
#endif
diff --git a/zephyr/shim/include/power_host_sleep.h b/zephyr/shim/include/power_host_sleep.h
new file mode 100644
index 0000000000..44034e4274
--- /dev/null
+++ b/zephyr/shim/include/power_host_sleep.h
@@ -0,0 +1,69 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __POWER_HOST_SLEEP_H
+#define __POWER_HOST_SLEEP_H
+
+/*
+ * This file is for Zephyr ap_pwrseq to reuse legacy EC code.
+ * Eventually this file should be removed.
+ *
+ * TODO: Declaration in this file should be removed once it can be replaced
+ * by implementation in Zephyr code.
+ */
+#if CONFIG_AP_PWRSEQ
+#include "ec_commands.h"
+#include "host_command.h"
+#include "lpc.h"
+
+/********************************************************************/
+/* power.h */
+enum power_state {
+ /* Steady states */
+ POWER_G3 = 0, /*
+ * System is off (not technically all the way into G3,
+ * which means totally unpowered...)
+ */
+ POWER_S5, /* System is soft-off */
+ POWER_S4, /* System is suspended to disk */
+ POWER_S3, /* Suspend; RAM on, processor is asleep */
+ POWER_S0, /* System is on */
+#if CONFIG_AP_PWRSEQ_S0IX
+ POWER_S0ix,
+#endif
+ /* Transitions */
+ POWER_G3S5, /* G3 -> S5 (at system init time) */
+ POWER_S5S3, /* S5 -> S3 (skips S4 on non-Intel systems) */
+ POWER_S3S0, /* S3 -> S0 */
+ POWER_S0S3, /* S0 -> S3 */
+ POWER_S3S5, /* S3 -> S5 (skips S4 on non-Intel systems) */
+ POWER_S5G3, /* S5 -> G3 */
+ POWER_S3S4, /* S3 -> S4 */
+ POWER_S4S3, /* S4 -> S3 */
+ POWER_S4S5, /* S4 -> S5 */
+ POWER_S5S4, /* S5 -> S4 */
+#if CONFIG_AP_PWRSEQ_S0IX
+ POWER_S0ixS0, /* S0ix -> S0 */
+ POWER_S0S0ix, /* S0 -> S0ix */
+#endif
+};
+
+#if CONFIG_AP_PWRSEQ_HOST_SLEEP
+/* Context to pass to a host sleep command handler. */
+struct host_sleep_event_context {
+ uint32_t sleep_transitions; /* Number of sleep transitions observed */
+ uint16_t sleep_timeout_ms; /* Timeout in milliseconds */
+};
+
+void ap_power_chipset_handle_host_sleep_event(
+ enum host_sleep_event state,
+ struct host_sleep_event_context *ctx);
+enum host_sleep_event power_get_host_sleep_state(void);
+void power_set_host_sleep_state(enum host_sleep_event state);
+#endif /* CONFIG_AP_PWRSEQ_HOST_SLEEP */
+
+#endif /* CONFIG_AP_PWRSEQ */
+
+#endif /* __POWER_HOST_SLEEP_H */
diff --git a/zephyr/shim/src/CMakeLists.txt b/zephyr/shim/src/CMakeLists.txt
index 57c3748a6e..bc9729abae 100644
--- a/zephyr/shim/src/CMakeLists.txt
+++ b/zephyr/shim/src/CMakeLists.txt
@@ -67,4 +67,4 @@ zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_USB_PD_TCPM_TCPCI
tcpc.c)
zephyr_library_sources_ifdef(CONFIG_PLATFORM_EC_USBA usba.c)
-
+zephyr_library_sources_ifdef(CONFIG_AP_PWRSEQ power_host_sleep_api.c)
diff --git a/zephyr/shim/src/power_host_sleep_api.c b/zephyr/shim/src/power_host_sleep_api.c
new file mode 100644
index 0000000000..d22f4fe4c4
--- /dev/null
+++ b/zephyr/shim/src/power_host_sleep_api.c
@@ -0,0 +1,45 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include <kernel.h>
+
+#include <ap_power/ap_power_interface.h>
+#include <power_host_sleep.h>
+
+static enum power_state translate_ap_power_state(
+ enum power_states_ndsx ap_power_state)
+{
+ switch (ap_power_state) {
+ case SYS_POWER_STATE_S5:
+ return POWER_S5;
+ case SYS_POWER_STATE_S3:
+ return POWER_S3;
+#if CONFIG_AP_PWRSEQ_S0IX
+ case SYS_POWER_STATE_S0ix:
+ return POWER_S0ix;
+#endif
+ default:
+ return 0;
+ }
+}
+
+int ap_power_get_lazy_wake_mask(
+ enum power_states_ndsx state, host_event_t *mask)
+{
+ enum power_state st;
+
+ st = translate_ap_power_state(state);
+ if (!st)
+ return -EINVAL;
+ return get_lazy_wake_mask(st, mask);
+}
+
+#if CONFIG_AP_PWRSEQ_HOST_SLEEP
+void power_chipset_handle_host_sleep_event(
+ enum host_sleep_event state,
+ struct host_sleep_event_context *ctx)
+{
+ ap_power_chipset_handle_host_sleep_event(state, ctx);
+}
+#endif
diff --git a/zephyr/subsys/ap_pwrseq/CMakeLists.txt b/zephyr/subsys/ap_pwrseq/CMakeLists.txt
index 2eba5ae67a..2cea0a992a 100644
--- a/zephyr/subsys/ap_pwrseq/CMakeLists.txt
+++ b/zephyr/subsys/ap_pwrseq/CMakeLists.txt
@@ -6,6 +6,7 @@ zephyr_library_sources(
)
zephyr_library_sources_ifdef(CONFIG_AP_PWRSEQ
ap_power_interface.c
+ power_host_sleep.c
power_signals.c
signal_gpio.c
signal_vw.c
diff --git a/zephyr/subsys/ap_pwrseq/Kconfig b/zephyr/subsys/ap_pwrseq/Kconfig
index 1de6d7251d..99ad4c819d 100644
--- a/zephyr/subsys/ap_pwrseq/Kconfig
+++ b/zephyr/subsys/ap_pwrseq/Kconfig
@@ -64,10 +64,19 @@ config X86_NON_DSX_PWRSEQ_CONSOLE
This option enables Non Deep Sleep Well power sequencing shell
console commands to debug.
+config AP_PWRSEQ_HOST_SLEEP
+ bool "Handle host sleep state changes"
+ help
+ Enable AP power sequencing to receive and process host command
+ host sleep state changes.
+
config AP_PWRSEQ_S0IX
- bool "Enable S0ix power state"
+ bool "Enable power state S0ix for Intel x86 chipset"
+ select AP_PWRSEQ_HOST_SLEEP
default n
help
- This option enables power state S0ix for Intel x86 chipset.
+ This option enables power state S0ix for Intel x86 chipset. As
+ required, AP_PWRSEQ_HOST_SLEEP for host sleep event handling is
+ enabled.
endif
diff --git a/zephyr/subsys/ap_pwrseq/include/ap_power_host_sleep.h b/zephyr/subsys/ap_pwrseq/include/ap_power_host_sleep.h
new file mode 100644
index 0000000000..e16816d185
--- /dev/null
+++ b/zephyr/subsys/ap_pwrseq/include/ap_power_host_sleep.h
@@ -0,0 +1,35 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __AP_POWER_HOST_SLEEP_H
+#define __AP_POWER_HOST_SLEEP_H
+
+#include <ap_power/ap_power_interface.h>
+#include <power_host_sleep.h>
+
+/*
+ * Deferred call to set active mask according to current power state
+ */
+void ap_power_set_active_wake_mask(void);
+
+/*
+ * Get lazy wake masks for the sleep state provided
+ *
+ * @param state Power state
+ * @param mask Lazy wake mask.
+ *
+ * @return 0 for success; -EINVAL if power state is not S3/S5/S0ix
+ */
+int ap_power_get_lazy_wake_mask(
+ enum power_states_ndsx state, host_event_t *mask);
+
+#if CONFIG_AP_PWRSEQ_S0IX
+/*
+ * Reset host sleep state and clean up
+ */
+void ap_power_reset_host_sleep_state(void);
+#endif /* CONFIG_AP_PWRSEQ_S0IX */
+
+#endif /* __AP_PWRSEQ_HOST_SLEEP_H */
diff --git a/zephyr/subsys/ap_pwrseq/power_host_sleep.c b/zephyr/subsys/ap_pwrseq/power_host_sleep.c
new file mode 100644
index 0000000000..dcaa3a55d1
--- /dev/null
+++ b/zephyr/subsys/ap_pwrseq/power_host_sleep.c
@@ -0,0 +1,111 @@
+/* Copyright 2022 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <ap_power/ap_power_interface.h>
+#include <ap_power_host_sleep.h>
+#include <x86_non_dsx_common_pwrseq_sm_handler.h>
+
+LOG_MODULE_DECLARE(ap_pwrseq, CONFIG_AP_PWRSEQ_LOG_LEVEL);
+
+#if CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI
+
+/* If host doesn't program S0ix lazy wake mask, use default S0ix mask */
+#define DEFAULT_WAKE_MASK_S0IX (EC_HOST_EVENT_MASK(EC_HOST_EVENT_LID_OPEN) | \
+ EC_HOST_EVENT_MASK(EC_HOST_EVENT_MODE_CHANGE))
+
+/*
+ * Set the wake mask according to the current power state:
+ * 1. On transition to S0, wake mask is reset.
+ * 2. In non-S0 states, active mask set by host gets a higher preference.
+ * 3. If host has not set any active mask, then check if a lazy mask exists
+ * for the current power state.
+ * 4. If state is S0ix and no lazy or active wake mask is set, then use default
+ * S0ix mask to be compatible with older BIOS versions.
+ */
+void power_update_wake_mask(void)
+{
+ host_event_t wake_mask;
+ enum power_states_ndsx state;
+
+ state = pwr_sm_get_state();
+
+ if (state == SYS_POWER_STATE_S0)
+ wake_mask = 0;
+ else if (lpc_is_active_wm_set_by_host() ||
+ ap_power_get_lazy_wake_mask(state, &wake_mask))
+ return;
+#if CONFIG_AP_PWRSEQ_S0IX
+ if ((state == SYS_POWER_STATE_S0ix) && (wake_mask == 0))
+ wake_mask = DEFAULT_WAKE_MASK_S0IX;
+#endif
+
+ lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, wake_mask);
+}
+
+static void power_update_wake_mask_deferred(struct k_work *work)
+{
+ power_update_wake_mask();
+}
+
+static K_WORK_DELAYABLE_DEFINE(
+ power_update_wake_mask_deferred_data, power_update_wake_mask_deferred);
+
+void ap_power_set_active_wake_mask(void)
+{
+ int rv;
+
+ /*
+ * Allow state machine to stabilize and update wake mask after 5msec. It
+ * was observed that on platforms where host wakes up periodically from
+ * S0ix for hardware book-keeping activities, there is a small window
+ * where host is not really up and running software, but still SLP_S0#
+ * is de-asserted and hence setting wake mask right away can cause user
+ * wake events to be missed.
+ *
+ * Time for deferred callback was chosen to be 5msec based on the fact
+ * that it takes ~2msec for the periodic wake cycle to complete on the
+ * host for KBL.
+ */
+ rv = k_work_schedule(&power_update_wake_mask_deferred_data, K_MSEC(5));
+ if (rv == 0) {
+ /*
+ * A work is already scheduled or submitted, since power state
+ * has changed again and the work is not processed, we should
+ * reschedule it.
+ */
+ rv = k_work_reschedule(
+ &power_update_wake_mask_deferred_data, K_MSEC(5));
+ }
+ __ASSERT(rv >= 0, "Set wake mask work queue error");
+}
+
+#else /* CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI */
+static void ap_power_set_active_wake_mask(void) { }
+#endif /* CONFIG_PLATFORM_EC_HOST_INTERFACE_ESPI */
+
+#if CONFIG_AP_PWRSEQ_HOST_SLEEP
+#define HOST_SLEEP_EVENT_DEFAULT_RESET 0
+
+void ap_power_reset_host_sleep_state(void)
+{
+ power_set_host_sleep_state(HOST_SLEEP_EVENT_DEFAULT_RESET);
+ ap_power_chipset_handle_host_sleep_event(
+ HOST_SLEEP_EVENT_DEFAULT_RESET, NULL);
+}
+
+/* TODO: hook to reset event */
+void ap_power_handle_chipset_reset(void)
+{
+ if (ap_power_in_state(AP_POWER_STATE_STANDBY))
+ ap_power_reset_host_sleep_state();
+}
+
+void ap_power_chipset_handle_host_sleep_event(
+ enum host_sleep_event state,
+ struct host_sleep_event_context *ctx)
+{
+ LOG_DBG("host sleep event = %d!", state);
+}
+#endif /* CONFIG_AP_PWRSEQ_HOST_SLEEP */