From d12fb951bc0efbd8fc1ef366cbc835e4147faf92 Mon Sep 17 00:00:00 2001 From: Li Feng Date: Wed, 30 Mar 2022 16:59:52 -0700 Subject: 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 Change-Id: Id972b904add5b3170fb91a8aa180736b42923dfd Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3562042 Reviewed-by: Andrew McRae --- zephyr/CMakeLists.txt | 3 +- zephyr/shim/include/config_chip.h | 6 +- zephyr/shim/include/power_host_sleep.h | 69 +++++++++++++ zephyr/shim/src/CMakeLists.txt | 2 +- zephyr/shim/src/power_host_sleep_api.c | 45 +++++++++ zephyr/subsys/ap_pwrseq/CMakeLists.txt | 1 + zephyr/subsys/ap_pwrseq/Kconfig | 13 ++- .../subsys/ap_pwrseq/include/ap_power_host_sleep.h | 35 +++++++ zephyr/subsys/ap_pwrseq/power_host_sleep.c | 111 +++++++++++++++++++++ 9 files changed, 279 insertions(+), 6 deletions(-) create mode 100644 zephyr/shim/include/power_host_sleep.h create mode 100644 zephyr/shim/src/power_host_sleep_api.c create mode 100644 zephyr/subsys/ap_pwrseq/include/ap_power_host_sleep.h create mode 100644 zephyr/subsys/ap_pwrseq/power_host_sleep.c 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 + +#include +#include + +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 +#include + +/* + * 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 +#include +#include + +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 */ -- cgit v1.2.1