diff options
author | Divya Sasidharan <divya.s.sasidharan@intel.com> | 2022-01-07 10:37:51 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2022-02-14 20:11:50 +0000 |
commit | 2826cac033b6233a96792af9c7171e61fda5e5ac (patch) | |
tree | 28e06bb085fda44a12454a85fce5fa5cc8dae532 | |
parent | b10b4e0a16b8310e6bd7786615b0497044946eca (diff) | |
download | chrome-ec-2826cac033b6233a96792af9c7171e61fda5e5ac.tar.gz |
zephyr: subsys/ap_pwrseq: Add inbuilt power sequencing support
Add inbuilt AP power sequencing support.
This patch adds power up sequence for AP.
Built on top of below reference:
https://github.com/zephyrproject-rtos/zephyr/pull/29245
TODO:
* b:216764983: Create separate .yaml for common and chipset
specific GPIOS.
* b:217952699: Subsys to driver model, override to callback
implementation change.
BUG=b:203446068
BRANCH=None
TEST=zmake testall; make buildall; brya boots up to S0
and display is up.
Change-Id: I84ce803d4e1b4594dc3f61bd2d8bcd1f94fd2be8
Signed-off-by: Divya Sasidharan <divya.s.sasidharan@intel.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3377810
Reviewed-by: Peter Marheine <pmarheine@chromium.org>
Reviewed-by: Andrew McRae <amcrae@google.com>
-rw-r--r-- | zephyr/CMakeLists.txt | 1 | ||||
-rw-r--r-- | zephyr/Kconfig | 1 | ||||
-rw-r--r-- | zephyr/dts/bindings/power/intel,ap-pwrseq.yaml | 159 | ||||
-rw-r--r-- | zephyr/subsys/CMakeLists.txt | 3 | ||||
-rw-r--r-- | zephyr/subsys/Kconfig | 5 | ||||
-rw-r--r-- | zephyr/subsys/ap_pwrseq/CMakeLists.txt | 6 | ||||
-rw-r--r-- | zephyr/subsys/ap_pwrseq/Kconfig | 41 | ||||
-rw-r--r-- | zephyr/subsys/ap_pwrseq/include/x86_common_pwrseq.h | 63 | ||||
-rw-r--r-- | zephyr/subsys/ap_pwrseq/include/x86_non_dsx_adlp_pwrseq_sm.h | 25 | ||||
-rw-r--r-- | zephyr/subsys/ap_pwrseq/include/x86_non_dsx_common_pwrseq_sm_handler.h | 49 | ||||
-rw-r--r-- | zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_nonpwrseq_sm.c | 20 | ||||
-rw-r--r-- | zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_pwrseq_sm.c | 221 | ||||
-rw-r--r-- | zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_sm_handler.c | 290 |
13 files changed, 884 insertions, 0 deletions
diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 17fd538f3a..712875234a 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -91,6 +91,7 @@ endif() add_subdirectory("app") add_subdirectory("drivers") add_subdirectory("emul") +add_subdirectory("subsys") add_subdirectory_ifdef(CONFIG_PLATFORM_EC "shim") # Creates a phony target all.libraries in case you only want to build the diff --git a/zephyr/Kconfig b/zephyr/Kconfig index 24fd0d8f3b..06ac209925 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -5,6 +5,7 @@ rsource "app/Kconfig" rsource "drivers/Kconfig" rsource "emul/Kconfig" +rsource "subsys/Kconfig" if ZTEST diff --git a/zephyr/dts/bindings/power/intel,ap-pwrseq.yaml b/zephyr/dts/bindings/power/intel,ap-pwrseq.yaml new file mode 100644 index 0000000000..f584c19df7 --- /dev/null +++ b/zephyr/dts/bindings/power/intel,ap-pwrseq.yaml @@ -0,0 +1,159 @@ + # 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. + +description: Common fields for AP power sequence + +compatible: "intel,ap-pwrseq" + +properties: + dsw-pwrok-delay: + type: int + required: false + default: 10 + description: | + Delay to set DSW_PWROK high to PCH after 3.3V rail stable, + in milliseconds. + + rsmrst-delay: + type: int + required: false + default: 10 + description: | + Delay to set RSMRST from EC to SoC, in milliseconds. + + sys-pwrok-delay: + type: int + required: false + default: 45 + description: | + Delay from PG_EC_ALL_SYS_PWRGD high to set EC_PCH_SYS_PWROK high, + in milliseconds. + + pm-pwrbtn-delay: + type: int + required: false + default: 200 + description: | + Power button delay, in milliseconds. + + pch-pwrok-delay: + type: int + required: false + default: 2 + description: | + Delay in ms from IMVP9_VRRDY high to PCH_PWROK high delay. + + vccst-pwrgd-delay: + type: int + required: false + default: 2 + description: | + Delay in ms from PG_EC_ALL_SYS_PWRGD high + to VCCST_PWRGD high. + + sys-reset-delay: + type: int + required: false + default: 32 + description: Debounce time for SYS_RESET_L. + + vrrdy-timeout: + type: int + required: false + default: 50 + description: | + Timeout in ms for IMVP9_VRRDY high. + + all-sys-pwrgd-timeout: + type: int + required: false + default: 0 + description: | + Timeout in ms for ALL_SYS_PWRGD input to EC to be high. + + wait-signal-timeout: + type: int + required: false + default: 1000 + description: | + Timeout in ms for monitoring power signals. + + pg-ec-dsw-pwrok-gpios: + type: phandle-array + required: false + description: | + VR/Circuit input to EC 3.3V power good signal. + + ec-pch-rsmrst-odl-gpios: + type: phandle-array + required: true + description: | + EC output to PCH, indicating RSMRST power good signal. + + en-pp5000-s5-gpios: + type: phandle-array + required: false + description: | + Output from EC to enable 5V rail. + + pg-ec-rsmrst-odl-gpios: + type: phandle-array + required: true + description: | + VR/Circuit input to EC RSMRST power good for + VCCPRIM rails and other S5 rails. + + slp-s3-l-gpios: + type: phandle-array + required: true + description: | + SLP_S3 signal input to EC for S3 sleep control from SoC. + + pg-ec-all-sys-pwrgd-gpios: + type: phandle-array + required: true + description: | + This represents the power good for all + the platform voltage rails input to EC. + + sys-rst-l-gpios: + type: phandle-array + required: false + description: | + SYS Reset signal output from EC. + + ec-pch-sys-pwrok-gpios: + type: phandle-array + required: true + description: | + SYS_PWROK is a generic power good input to the PCH from EC, + driven and utilized in a platform specific manner. + + pch-pwrok-gpios: + type: phandle-array + required: true + description: | + PCH PWROK assertion indicates all the main PCH + primary rails and all the CPU rails are up from EC to PCH. + + imvp9-vrrdy-od-gpios: + type: phandle-array + required: true + description: | + IMVP VRRDY input signal to EC indicates that the IMVP + start-up sequence is complete. + + vccst-pwrgd-od-gpios: + type: phandle-array + required: true + description: | + VCCST PWRGD signal output from EC to indicate that the + VCC1P05_PROC/VDDQ power supplies are stable and + within specification. + + slp-sus-l-gpios: + type: phandle-array + required: true + description: | + SLP_SUS signal from SoC to EC. diff --git a/zephyr/subsys/CMakeLists.txt b/zephyr/subsys/CMakeLists.txt new file mode 100644 index 0000000000..4e1389b729 --- /dev/null +++ b/zephyr/subsys/CMakeLists.txt @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: Apache-2.0 + +add_subdirectory_ifdef(CONFIG_AP_PWRSEQ ap_pwrseq) diff --git a/zephyr/subsys/Kconfig b/zephyr/subsys/Kconfig new file mode 100644 index 0000000000..f35a942afc --- /dev/null +++ b/zephyr/subsys/Kconfig @@ -0,0 +1,5 @@ +# 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. + +rsource "ap_pwrseq/Kconfig" diff --git a/zephyr/subsys/ap_pwrseq/CMakeLists.txt b/zephyr/subsys/ap_pwrseq/CMakeLists.txt new file mode 100644 index 0000000000..c1761e6824 --- /dev/null +++ b/zephyr/subsys/ap_pwrseq/CMakeLists.txt @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: Apache-2.0 + +zephyr_include_directories(include) +zephyr_sources_ifdef(CONFIG_X86_NON_DSX_PWRSEQ + x86_non_dsx_common_pwrseq_sm_handler.c) +zephyr_sources_ifdef(CONFIG_X86_NON_DSX_PWRSEQ_ADL x86_non_dsx_adlp_pwrseq_sm.c) diff --git a/zephyr/subsys/ap_pwrseq/Kconfig b/zephyr/subsys/ap_pwrseq/Kconfig new file mode 100644 index 0000000000..6d2b7ddfb2 --- /dev/null +++ b/zephyr/subsys/ap_pwrseq/Kconfig @@ -0,0 +1,41 @@ +# 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. + +menuconfig AP_PWRSEQ + bool "AP Power sequencing support" + help + Enables AP power sequencing support with + embedded controller. This includes normal shutdown, critical + shutdown and reset handling. + +if AP_PWRSEQ + +config X86_NON_DSX_PWRSEQ + bool + default n + help + This option enables Non Deep Sleep Well power sequencing for + Intel x86 chips. + +config X86_NON_DSX_PWRSEQ_ADL + bool "x86 Non Deep Sx power sequencing on ADL" + depends on AP_X86_INTEL_ADL + select X86_NON_DSX_PWRSEQ + default n + help + This enables AP power sequecing support for Intel Alderlake + family of chipset. + +config X86_NON_DSW_PWRSEQ_STACK_SIZE + int "AP pwrseq stack size (in bytes)" + default 1024 + help + This option specifies the size of the stack used by the + AP power sequencing state machine thread handler. + +endif + +module = AP_PWRSEQ +module-str = ap_pwrseq +source "subsys/logging/Kconfig.template.log_config" diff --git a/zephyr/subsys/ap_pwrseq/include/x86_common_pwrseq.h b/zephyr/subsys/ap_pwrseq/include/x86_common_pwrseq.h new file mode 100644 index 0000000000..b468508c37 --- /dev/null +++ b/zephyr/subsys/ap_pwrseq/include/x86_common_pwrseq.h @@ -0,0 +1,63 @@ +/* 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 __X86_COMMON_PWRSEQ_H__ +#define __X86_COMMON_PWRSEQ_H__ + +#include <drivers/espi.h> +#include <drivers/gpio.h> +#include <logging/log.h> + +/** + * @brief System power states for Non Deep Sleep Well + * EC is an always on device in a Non Deep Sx system except when EC + * is hibernated or all the VRs are turned off. + */ +enum power_states_ndsx { + /* + * Actual power states + */ + /* AP is off & EC is on */ + SYS_POWER_STATE_G3, + /* AP is in soft off state */ + SYS_POWER_STATE_S5, + /* AP is suspended to Non-volatile disk */ + SYS_POWER_STATE_S4, + /* AP is suspended to RAM */ + SYS_POWER_STATE_S3, + /* AP is in active state */ + SYS_POWER_STATE_S0, + + /* + * Intermediate power up states + */ + /* Determine if the AP's power rails are turned on */ + SYS_POWER_STATE_G3S5, + /* Determine if AP is suspended from sleep */ + SYS_POWER_STATE_S5S4, + /* Determine if Suspend to Disk is de-asserted */ + SYS_POWER_STATE_S4S3, + /* Determine if Suspend to RAM is de-asserted */ + SYS_POWER_STATE_S3S0, + + /* + * Intermediate power down states + */ + /* Determine if the AP's power rails are turned off */ + SYS_POWER_STATE_S5G3, + /* Determine if AP is suspended to sleep */ + SYS_POWER_STATE_S4S5, + /* Determine if Suspend to Disk is asserted */ + SYS_POWER_STATE_S3S4, + /* Determine if Suspend to RAM is asserted */ + SYS_POWER_STATE_S0S3, +}; + +/* This encapsulates the attributes of the state machine */ +struct pwrseq_context { + /* On power-on start boot up sequence */ + enum power_states_ndsx power_state; +}; +#endif /* __X86_COMMON_H__ */ diff --git a/zephyr/subsys/ap_pwrseq/include/x86_non_dsx_adlp_pwrseq_sm.h b/zephyr/subsys/ap_pwrseq/include/x86_non_dsx_adlp_pwrseq_sm.h new file mode 100644 index 0000000000..94d6766a72 --- /dev/null +++ b/zephyr/subsys/ap_pwrseq/include/x86_non_dsx_adlp_pwrseq_sm.h @@ -0,0 +1,25 @@ +/* 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 __X86_NON_DSX_ADLP_PWRSEQ_SM_H__ +#define __X86_NON_DSX_ADLP_PWRSEQ_SM_H__ + +#include <x86_common_pwrseq.h> +#include <x86_non_dsx_common_pwrseq_sm_handler.h> + +struct chipset_pwrseq_config { + int pch_pwrok_delay_ms; + int sys_pwrok_delay_ms; + int sys_reset_delay_ms; + int vccst_pwrgd_delay_ms; + int vrrdy_timeout_ms; + int all_sys_pwrgd_timeout; + const struct gpio_dt_spec vccst_pwrgd_od; + const struct gpio_dt_spec imvp9_vrrdy_od; + const struct gpio_dt_spec pch_pwrok; + const struct gpio_dt_spec ec_pch_sys_pwrok; + const struct gpio_dt_spec sys_rst_l; +}; +#endif /* __X86_NON_DSX_ADLP_H__ */ diff --git a/zephyr/subsys/ap_pwrseq/include/x86_non_dsx_common_pwrseq_sm_handler.h b/zephyr/subsys/ap_pwrseq/include/x86_non_dsx_common_pwrseq_sm_handler.h new file mode 100644 index 0000000000..4212443366 --- /dev/null +++ b/zephyr/subsys/ap_pwrseq/include/x86_non_dsx_common_pwrseq_sm_handler.h @@ -0,0 +1,49 @@ +/* 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 __X86_NON_DSX_COMMON_PWRSEQ_SM_HANDLER_H__ +#define __X86_NON_DSX_COMMON_PWRSEQ_SM_HANDLER_H__ + +#include <x86_common_pwrseq.h> + +#define DT_DRV_COMPAT intel_ap_pwrseq +#define INTEL_COM_POWER_NODE DT_INST(0, intel_ap_pwrseq) + +/* Check if the gpio is needed for the power sequence */ +#define PWRSEQ_GPIO_PRESENT(pha) \ + DT_PHA_HAS_CELL(INTEL_COM_POWER_NODE, pha, flags) + +/* Common device tree configurable attributes */ +struct common_pwrseq_config { + int pch_dsw_pwrok_delay_ms; + int pch_pm_pwrbtn_delay_ms; + int pch_rsmrst_delay_ms; +#if PWRSEQ_GPIO_PRESENT(en_pp5000_s5_gpios) + const struct gpio_dt_spec enable_pp5000_a; +#endif +#if PWRSEQ_GPIO_PRESENT(en_pp3300_s5_gpios) + const struct gpio_dt_spec enable_pp3300_a; +#endif + const struct gpio_dt_spec pg_ec_rsmrst_odl; + const struct gpio_dt_spec ec_pch_rsmrst_odl; +#if PWRSEQ_GPIO_PRESENT(pg_ec_dsw_pwrok_gpios) + const struct gpio_dt_spec pg_ec_dsw_pwrok; +#endif +#if PWRSEQ_GPIO_PRESENT(ec_soc_dsw_pwrok_gpios) + const struct gpio_dt_spec ec_soc_dsw_pwrok; +#endif + const struct gpio_dt_spec slp_s3_l; + const struct gpio_dt_spec all_sys_pwrgd; + const struct gpio_dt_spec slp_sus_l; +}; + +enum power_states_ndsx chipset_pwr_sm_run( + enum power_states_ndsx curr_state, + const struct common_pwrseq_config *com_cfg); +void init_chipset_pwr_seq_state(void); +void all_sig_pass_thru_handler(void); +void common_rsmrst_pass_thru_handler(void); + +#endif /* __X86_NON_DSX_COMMON_H__ */ diff --git a/zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_nonpwrseq_sm.c b/zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_nonpwrseq_sm.c new file mode 100644 index 0000000000..3f6bfa3027 --- /dev/null +++ b/zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_nonpwrseq_sm.c @@ -0,0 +1,20 @@ +/* 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_pwrseq/x86_non_dsx_adlp_pwrseq_sm.h> + +LOG_MODULE_DECLARE(ap_pwrseq, 4); + +__override int all_sys_pwrgd_handler(void) +{ + /* Add signal handling */ + return 0; +} + +__override int intel_x86_get_pg_ec_dsw_pwrok(void) +{ + /* Add signal handling */ + return 0; +} diff --git a/zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_pwrseq_sm.c b/zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_pwrseq_sm.c new file mode 100644 index 0000000000..fed8240788 --- /dev/null +++ b/zephyr/subsys/ap_pwrseq/x86_non_dsx_adlp_pwrseq_sm.c @@ -0,0 +1,221 @@ +/* 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 <x86_non_dsx_adlp_pwrseq_sm.h> + +LOG_MODULE_DECLARE(ap_pwrseq, 4); + +static const struct chipset_pwrseq_config chip_cfg = { + .pch_pwrok_delay_ms = DT_INST_PROP(0, pch_pwrok_delay), + .sys_pwrok_delay_ms = DT_INST_PROP(0, sys_pwrok_delay), + .vccst_pwrgd_delay_ms = DT_INST_PROP(0, vccst_pwrgd_delay), + .vrrdy_timeout_ms = DT_INST_PROP(0, vrrdy_timeout), + .sys_reset_delay_ms = DT_INST_PROP(0, sys_reset_delay), + .all_sys_pwrgd_timeout = DT_INST_PROP(0, all_sys_pwrgd_timeout), + .vccst_pwrgd_od = GPIO_DT_SPEC_GET(DT_DRV_INST(0), + vccst_pwrgd_od_gpios), + .imvp9_vrrdy_od = GPIO_DT_SPEC_GET(DT_DRV_INST(0), + imvp9_vrrdy_od_gpios), + .pch_pwrok = GPIO_DT_SPEC_GET(DT_DRV_INST(0), pch_pwrok_gpios), + .ec_pch_sys_pwrok = GPIO_DT_SPEC_GET(DT_DRV_INST(0), + ec_pch_sys_pwrok_gpios), + .sys_rst_l = GPIO_DT_SPEC_GET(DT_DRV_INST(0), sys_rst_l_gpios), +}; + +void ap_off(void) +{ + /* TODO: This could be added as g3action handler */ + gpio_pin_set_dt(&chip_cfg.vccst_pwrgd_od, 0); + gpio_pin_set_dt(&chip_cfg.pch_pwrok, 0); + gpio_pin_set_dt(&chip_cfg.ec_pch_sys_pwrok, 0); +} + +/* This should be overridden if there is no power sequencer chip */ +__attribute__((weak)) int intel_x86_get_pg_ec_all_sys_pwrgd( + const struct common_pwrseq_config *com_cfg) +{ + return gpio_pin_get_dt(&com_cfg->all_sys_pwrgd); +} + +/* Handle ALL_SYS_PWRGD signal + * This will be overridden if the custom signal handler is needed + */ +__attribute__((weak)) int all_sys_pwrgd_handler( + const struct common_pwrseq_config *com_cfg) +{ + int retry = 0; + + /* TODO: Add condition for no power sequencer */ + k_msleep(chip_cfg.all_sys_pwrgd_timeout); + + if (intel_x86_get_pg_ec_all_sys_pwrgd(com_cfg) == 0) { + /* Todo: Remove workaround for the retry + * without this change the system hits G3 as it detects + * ALL_SYS_PWRGD as 0 and then 1 as a glitch + */ + while (!intel_x86_get_pg_ec_all_sys_pwrgd(com_cfg)) { + if (++retry > 2) { + LOG_ERR("PG_EC_ALL_SYS_PWRGD not ok\n"); + ap_off(); + return -1; + } + k_msleep(10); + } + } + + /* PG_EC_ALL_SYS_PWRGD is asserted, enable VCCST_PWRGD_OD. */ + + if (gpio_pin_get_dt(&chip_cfg.vccst_pwrgd_od) == 0) { + k_msleep(chip_cfg.vccst_pwrgd_delay_ms); + gpio_pin_set_dt(&chip_cfg.vccst_pwrgd_od, 1); + } + return 0; +} + +/* + * We have asserted VCCST_PWRGO_OD, now wait for the IMVP9.1 + * to assert IMVP9_VRRDY_OD. + * + * Returns state of VRRDY. + */ + +static int wait_for_vrrdy(void) +{ + int timeout_ms = chip_cfg.vrrdy_timeout_ms; + + for (; timeout_ms > 0; --timeout_ms) { + if (gpio_pin_get_dt(&chip_cfg.imvp9_vrrdy_od) != 0) + return 1; + k_msleep(1); + } + return 0; +} + +/* PCH_PWROK to PCH from EC */ +int generate_pch_pwrok_handler(void) +{ + /* Enable PCH_PWROK, gated by VRRDY. */ + if (gpio_pin_get_dt(&chip_cfg.pch_pwrok) == 0) { + if (wait_for_vrrdy() == 0) { + LOG_DBG("Timed out waiting for VRRDY, " + "shutting AP off!"); + ap_off(); + return -1; + } + k_msleep(chip_cfg.pch_pwrok_delay_ms); + gpio_pin_set_dt(&chip_cfg.pch_pwrok, 1); + LOG_DBG("Set PCH_PWROK\n"); + } + + return 0; +} + +/* Generate SYS_PWROK->SOC if needed by system */ +void generate_sys_pwrok_handler(const struct common_pwrseq_config *com_cfg) +{ + /* Enable PCH_SYS_PWROK. */ + if (gpio_pin_get_dt(&chip_cfg.ec_pch_sys_pwrok) == 0) { + k_msleep(chip_cfg.sys_pwrok_delay_ms); + /* Check if we lost power while waiting. */ + if (intel_x86_get_pg_ec_all_sys_pwrgd(com_cfg) == 0) { + LOG_DBG("PG_EC_ALL_SYS_PWRGD deasserted, " + "shutting AP off!"); + ap_off(); + return; + } + gpio_pin_set_dt(&chip_cfg.ec_pch_sys_pwrok, 1); + /* PCH will now release PLT_RST */ + } +} + +/* Chipset specific power state machine handler */ + +/* TODO: Separate with and without power sequencer logic here */ + +void s0_action_handler(const struct common_pwrseq_config *com_cfg) +{ + int ret; + + /* Handle DSW_PWROK passthrough */ + /* This is not needed for alderlake silego, guarded by CONFIG? */ + + /* Check ALL_SYS_PWRGD and take action */ + ret = all_sys_pwrgd_handler(com_cfg); + if (ret) { + LOG_DBG("ALL_SYS_PWRGD handling failed err= %d\n", ret); + return; + } + + /* Send PCH_PWROK->SoC if conditions met */ + /* TODO: There is possibility of EC not needing to generate + * this as power sequencer may do it + */ + ret = generate_pch_pwrok_handler(); + if (ret) { + LOG_DBG("PCH_PWROK handling failed err=%d\n", ret); + return; + } + + /* SYS_PWROK may be optional and the delay must be + * configurable as it is variable with platform + */ + /* Send SYS_PWROK->SoC if conditions met */ + generate_sys_pwrok_handler(com_cfg); +} + +void intel_x86_sys_reset_delay(void) +{ + /* + * Debounce time for SYS_RESET_L is 16 ms. Wait twice that period + * to be safe. + */ + k_msleep(chip_cfg.sys_reset_delay_ms); +} + +void g3s5_action_handler(const struct common_pwrseq_config *com_cfg) +{ + gpio_pin_set_dt(&com_cfg->enable_pp5000_a, 1); +} + +void init_chipset_pwr_seq_state(void) +{ + int ret = 0; + + /* Configure gpios specific to the chipset */ + ret |= gpio_pin_configure_dt(&chip_cfg.vccst_pwrgd_od, + GPIO_OUTPUT_LOW); + ret |= gpio_pin_configure_dt(&chip_cfg.imvp9_vrrdy_od, + GPIO_INPUT); + ret |= gpio_pin_configure_dt(&chip_cfg.pch_pwrok, + GPIO_OUTPUT_LOW); + ret |= gpio_pin_configure_dt(&chip_cfg.ec_pch_sys_pwrok, + GPIO_OUTPUT_LOW); + ret |= gpio_pin_configure_dt(&chip_cfg.sys_rst_l, + GPIO_OUTPUT_HIGH); + + if (!ret) + LOG_INF("Configuring GPIO complete"); + else + LOG_ERR("Power seq gpio configuration failed\n"); +} + +enum power_states_ndsx chipset_pwr_sm_run(enum power_states_ndsx curr_state, + const struct common_pwrseq_config *com_cfg) +{ +/* Add chipset specific state handling if any */ + switch (curr_state) { + case SYS_POWER_STATE_G3S5: + g3s5_action_handler(com_cfg); + break; + case SYS_POWER_STATE_S5: + break; + case SYS_POWER_STATE_S0: + s0_action_handler(com_cfg); + break; + default: + break; + } + return curr_state; +} diff --git a/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_sm_handler.c b/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_sm_handler.c new file mode 100644 index 0000000000..cdb4e63cdd --- /dev/null +++ b/zephyr/subsys/ap_pwrseq/x86_non_dsx_common_pwrseq_sm_handler.c @@ -0,0 +1,290 @@ +/* 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 <x86_non_dsx_common_pwrseq_sm_handler.h> + +static K_KERNEL_STACK_DEFINE(pwrseq_thread_stack, + CONFIG_X86_NON_DSW_PWRSEQ_STACK_SIZE); +static struct k_thread pwrseq_thread_data; +static struct pwrseq_context pwrseq_ctx; + +LOG_MODULE_REGISTER(ap_pwrseq, 4); + +static const struct common_pwrseq_config com_cfg = { + .pch_dsw_pwrok_delay_ms = DT_INST_PROP(0, dsw_pwrok_delay), + .pch_pm_pwrbtn_delay_ms = DT_INST_PROP(0, pm_pwrbtn_delay), + .pch_rsmrst_delay_ms = DT_INST_PROP(0, rsmrst_delay), +#if PWRSEQ_GPIO_PRESENT(en_pp5000_s5_gpios) + .enable_pp5000_a = GPIO_DT_SPEC_GET(DT_DRV_INST(0), + en_pp5000_s5_gpios), +#endif +#if PWRSEQ_GPIO_PRESENT(en_pp3300_s5_gpios) + .enable_pp3300_a = GPIO_DT_SPEC_GET(DT_DRV_INST(0), + en_pp3300_s5_gpios), +#endif + .pg_ec_rsmrst_odl = GPIO_DT_SPEC_GET(DT_DRV_INST(0), + pg_ec_rsmrst_odl_gpios), + .ec_pch_rsmrst_odl = GPIO_DT_SPEC_GET(DT_DRV_INST(0), + ec_pch_rsmrst_odl_gpios), +#if PWRSEQ_GPIO_PRESENT(pg_ec_dsw_pwrok_gpios) + .pg_ec_dsw_pwrok = GPIO_DT_SPEC_GET(DT_DRV_INST(0), + pg_ec_dsw_pwrok_gpios), +#endif +#if PWRSEQ_GPIO_PRESENT(ec_soc_dsw_pwrok_gpios) + .ec_soc_dsw_pwrok = GPIO_DT_SPEC_GET(DT_DRV_INST(0), + ec_soc_dsw_pwrok_gpios), +#endif + .slp_s3_l = GPIO_DT_SPEC_GET(DT_DRV_INST(0), slp_s3_l_gpios), + .all_sys_pwrgd = GPIO_DT_SPEC_GET(DT_DRV_INST(0), + pg_ec_all_sys_pwrgd_gpios), + .slp_sus_l = GPIO_DT_SPEC_GET(DT_DRV_INST(0), slp_sus_l_gpios), +}; + +#ifdef CONFIG_LOG +/** + * @brief power_state names for debug + */ +const char pwrsm_dbg[][25] = { + [SYS_POWER_STATE_G3] = "STATE_G3", + [SYS_POWER_STATE_S5] = "STATE_S5", + [SYS_POWER_STATE_S4] = "STATE_S4", + [SYS_POWER_STATE_S3] = "STATE_S3", + [SYS_POWER_STATE_S0] = "STATE_S0", + [SYS_POWER_STATE_G3S5] = "STATE_G3S5", + [SYS_POWER_STATE_S5S4] = "STATE_S5S4", + [SYS_POWER_STATE_S4S3] = "STATE_S4S3", + [SYS_POWER_STATE_S3S0] = "STATE_S3S0", + [SYS_POWER_STATE_S5G3] = "STATE_S5G3", + [SYS_POWER_STATE_S4S5] = "STATE_S4S5", + [SYS_POWER_STATE_S3S4] = "STATE_S3S4", + [SYS_POWER_STATE_S0S3] = "STATE_S0S3", +}; +#endif + +void power_signal_interrupt(void) +{ + /* TODO: Add handling */ +} + +static int check_power_rails_enabled(void) +{ + int out = 1; + +#if PWRSEQ_GPIO_PRESENT(en_pp3300_s5_gpios) + out &= gpio_pin_get_dt(&com_cfg.enable_pp3300_a); +#endif +#if PWRSEQ_GPIO_PRESENT(en_pp5000_s5_gpios) + out &= gpio_pin_get_dt(&com_cfg.enable_pp5000_a); +#endif +#if PWRSEQ_GPIO_PRESENT(pg_ec_dsw_pwrok_gpios) + out &= gpio_pin_get_dt(&com_cfg.pg_ec_dsw_pwrok); +#endif + return out; +} + +static void pwrseq_gpio_init(void) +{ + int ret = 0; + + /* Configure the GPIO */ +#if PWRSEQ_GPIO_PRESENT(en_pp5000_s5_gpios) + ret = gpio_pin_configure_dt(&com_cfg.enable_pp5000_a, + GPIO_OUTPUT_LOW); +#endif +#if PWRSEQ_GPIO_PRESENT(en_pp3300_s5_gpios) + ret |= gpio_pin_configure_dt(&com_cfg.enable_pp3300_a, + GPIO_OUTPUT_LOW); +#endif + ret |= gpio_pin_configure_dt(&com_cfg.pg_ec_rsmrst_odl, + GPIO_INPUT); + ret |= gpio_pin_configure_dt(&com_cfg.ec_pch_rsmrst_odl, + GPIO_OUTPUT_LOW); +#if PWRSEQ_GPIO_PRESENT(pg_ec_dsw_pwrok_gpios) + ret |= gpio_pin_configure_dt(&com_cfg.pg_ec_dsw_pwrok, + GPIO_INPUT); +#endif +#if PWRSEQ_GPIO_PRESENT(ec_soc_dsw_pwrok_gpios) + ret |= gpio_pin_configure_dt(&com_cfg.ec_soc_dsw_pwrok, + GPIO_OUTPUT_LOW); +#endif + ret |= gpio_pin_configure_dt(&com_cfg.slp_s3_l, GPIO_INPUT); + ret |= gpio_pin_configure_dt(&com_cfg.slp_sus_l, GPIO_INPUT); + ret |= gpio_pin_configure_dt(&com_cfg.all_sys_pwrgd, GPIO_INPUT); + + if (!ret) + LOG_INF("Configuring GPIO complete"); + else + LOG_ERR("GPIO configure failed\n"); +} + +enum power_states_ndsx pwr_sm_get_state(void) +{ + return pwrseq_ctx.power_state; +} + +void pwr_sm_set_state(enum power_states_ndsx new_state) +{ + /* Add locking mechanism if multiple thread can update it */ + LOG_DBG("Power state: %s --> %s\n", pwrsm_dbg[pwrseq_ctx.power_state], + pwrsm_dbg[new_state]); + pwrseq_ctx.power_state = new_state; +} + +/* Check RSMRST is fine to move from S5 to higher state */ +int check_rsmrst_ok(void) +{ + /* TODO: Check if this is still intact*/ + return gpio_pin_get_dt(&com_cfg.pg_ec_rsmrst_odl); +} + +int check_pch_out_of_suspend(void) +{ + return gpio_pin_get_dt(&com_cfg.slp_sus_l); +} + +/* Handling RSMRST signal is mostly common across x86 chipsets */ +__attribute__((weak)) void rsmrst_pass_thru_handler(void) +{ + /* Handle RSMRST passthrough */ + /* TODO: Add additional conditions for RSMRST handling */ + int in_sig_val = gpio_pin_get_dt(&com_cfg.pg_ec_rsmrst_odl); + int out_sig_val = gpio_pin_get_dt(&com_cfg.ec_pch_rsmrst_odl); + + if (in_sig_val != out_sig_val) { + if (in_sig_val) + k_msleep(com_cfg.pch_rsmrst_delay_ms); + gpio_pin_set_dt(&com_cfg.ec_pch_rsmrst_odl, in_sig_val); + } +} + +/* TODO: + * Add power down sequence + * Add power signal monitoring + * Add logic to suspend and resume the thread + */ +static int common_pwr_sm_run(int state) +{ + switch (state) { + case SYS_POWER_STATE_G3: + /* Nothing to do */ + break; + + case SYS_POWER_STATE_G3S5: + /* TODO: Check if we are good to move to S5*/ + if (check_pch_out_of_suspend()) + return SYS_POWER_STATE_S5; + break; + + case SYS_POWER_STATE_S5: + /* If A-rails are stable move to higher state */ + if (check_power_rails_enabled() && check_rsmrst_ok()) { + /* rsmrst is intact */ + rsmrst_pass_thru_handler(); + return SYS_POWER_STATE_S5S4; + } + break; + + case SYS_POWER_STATE_S5S4: + /* Check if the PCH has come out of suspend state */ + if (check_rsmrst_ok()) { + LOG_DBG("RSMRST is ok"); + return SYS_POWER_STATE_S4; + } + break; + + case SYS_POWER_STATE_S4: + return SYS_POWER_STATE_S3; + + case SYS_POWER_STATE_S3: + /* AP is out of suspend to RAM */ + if (gpio_pin_get_dt(&com_cfg.slp_s3_l)) + return SYS_POWER_STATE_S3S0; + break; + + case SYS_POWER_STATE_S3S0: + /* All the power rails must be stable */ + if (gpio_pin_get_dt(&com_cfg.all_sys_pwrgd)) + return SYS_POWER_STATE_S0; + break; + + case SYS_POWER_STATE_S0: + /* Stay in S0 */ + break; + + case SYS_POWER_STATE_S4S5: + case SYS_POWER_STATE_S3S4: + case SYS_POWER_STATE_S0S3: + case SYS_POWER_STATE_S5G3: + break; + + default: + break; + } + + return state; +} + +static void pwrseq_loop_thread(void *p1, void *p2, void *p3) +{ + int32_t t_wait_ms = 10; + enum power_states_ndsx curr_state, new_state; + + while (1) { + curr_state = pwr_sm_get_state(); + /* Run chipset specific state machine */ + new_state = chipset_pwr_sm_run(curr_state, &com_cfg); + + /* + * Run common power state machine + * if the state has changed in chipset state + * machine then skip running common state + * machine + */ + if (curr_state == new_state) + new_state = common_pwr_sm_run(curr_state); + + if (curr_state != new_state) + pwr_sm_set_state(new_state); + + k_msleep(t_wait_ms); + } +} + +static inline void create_pwrseq_thread(void) +{ + k_thread_create(&pwrseq_thread_data, + pwrseq_thread_stack, + K_KERNEL_STACK_SIZEOF(pwrseq_thread_stack), + (k_thread_entry_t)pwrseq_loop_thread, + NULL, NULL, NULL, + K_PRIO_COOP(8), 0, K_NO_WAIT); + + k_thread_name_set(&pwrseq_thread_data, "pwrseq_task"); +} + +void init_pwr_seq_state(void) +{ + init_chipset_pwr_seq_state(); + + pwr_sm_set_state(SYS_POWER_STATE_G3S5); +} + +/* Initialize power sequence system state */ +static int pwrseq_init() +{ + LOG_ERR("Pwrseq Init\n"); + + /* Configure gpio from device tree */ + pwrseq_gpio_init(); + LOG_DBG("Done gpio init"); + /* TODO: Define initial state of power sequence */ + LOG_DBG("Init pwr seq state"); + init_pwr_seq_state(); + /* Create power sequence state handler core function thread */ + create_pwrseq_thread(); + return 0; +} + +SYS_INIT(pwrseq_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY); |