diff options
-rw-r--r-- | include/config.h | 11 | ||||
-rw-r--r-- | include/power/alderlake_slg4bd44540.h | 52 | ||||
-rw-r--r-- | include/power/intel_x86.h | 4 | ||||
-rw-r--r-- | power/alderlake_slg4bd44540.c | 276 | ||||
-rw-r--r-- | power/build.mk | 2 |
5 files changed, 128 insertions, 217 deletions
diff --git a/include/config.h b/include/config.h index 0cbcda287d..df235e91f3 100644 --- a/include/config.h +++ b/include/config.h @@ -1159,6 +1159,10 @@ /* AP chipset support; pick at most one */ #undef CONFIG_CHIPSET_ALDERLAKE /* Intel Alderlake (x86) */ +#undef CONFIG_CHIPSET_ALDERLAKE_SLG4BD44540 /* Intel Alderlake (x86) + * with power sequencer + * chip + */ #undef CONFIG_CHIPSET_APOLLOLAKE /* Intel Apollolake (x86) */ #undef CONFIG_CHIPSET_BRASWELL /* Intel Braswell (x86) */ #undef CONFIG_CHIPSET_CANNONLAKE /* Intel Cannonlake (x86) */ @@ -5514,6 +5518,7 @@ #ifndef HAS_TASK_CHIPSET #undef CONFIG_AP_HANG_DETECT #undef CONFIG_CHIPSET_ALDERLAKE +#undef CONFIG_CHIPSET_ALDERLAKE_SLG4BD44540 #undef CONFIG_CHIPSET_APOLLOLAKE #undef CONFIG_CHIPSET_BRASWELL #undef CONFIG_CHIPSET_CANNONLAKE @@ -5640,7 +5645,8 @@ #define CONFIG_CHIPSET_HAS_PRE_INIT_CALLBACK #endif -#if defined(CONFIG_CHIPSET_APOLLOLAKE) || \ +#if defined(CONFIG_CHIPSET_ALDERLAKE_SLG4BD44540) || \ + defined(CONFIG_CHIPSET_APOLLOLAKE) || \ defined(CONFIG_CHIPSET_BRASWELL) || \ defined(CONFIG_CHIPSET_CANNONLAKE) || \ defined(CONFIG_CHIPSET_COMETLAKE) || \ @@ -5651,7 +5657,8 @@ #define CONFIG_POWER_COMMON #endif -#if defined(CONFIG_CHIPSET_CANNONLAKE) || \ +#if defined(CONFIG_CHIPSET_ALDERLAKE_SLG4BD44540) || \ + defined(CONFIG_CHIPSET_CANNONLAKE) || \ defined(CONFIG_CHIPSET_ICELAKE) || \ defined(CONFIG_CHIPSET_SKYLAKE) #define CONFIG_CHIPSET_X86_RSMRST_DELAY diff --git a/include/power/alderlake_slg4bd44540.h b/include/power/alderlake_slg4bd44540.h index 08c14718ec..62c617bd98 100644 --- a/include/power/alderlake_slg4bd44540.h +++ b/include/power/alderlake_slg4bd44540.h @@ -1,14 +1,15 @@ -/* Copyright 2018 The Chromium OS Authors. All rights reserved. +/* Copyright 2021 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. */ -/* Icelake chipset power control module for Chrome EC */ - -#ifndef __CROS_EC_ICELAKE_H -#define __CROS_EC_ICELAKE_H +/* + * Alder Lake chipset power control module using the SLG4BD44540 power + * sequencer chip for Chrome EC + */ -#include "stdbool.h" +#ifndef __CROS_EC_ALDERLAKE_SLG4BD44540_H +#define __CROS_EC_ALDERLAKE_SLG4BD44540_H /* Input state flags. */ #define IN_PCH_SLP_S3_DEASSERTED POWER_SIGNAL_MASK(X86_SLP_S3_DEASSERTED) @@ -42,41 +43,4 @@ enum power_signal { POWER_SIGNAL_COUNT }; -struct intel_x86_pwrok_signal { - enum gpio_signal gpio; - bool active_low; - int delay_ms; -}; - -/* - * Ice Lake/Tiger Lake/Jasper Lake PWROK Generation - * - * The following signals are controlled based on the state of the ALL_SYS_PWRGD - * signal - * - * VCCIN enable (input to the VCCIN voltage rail controller) - * VCCST_PWRGD (input to the SoC) - * PCH_PWROK (input to the SoC) - * SYS_PWROK (input to the SoC) - * - * For any the above signals that are controlled by the EC, create an entry - * in the pwrok_signal_assert_list[] and pwrok_signal_deassert_list[] arrays. - * The typical order for asserting the signals is shown above, the deassert - * order is the reverse. - * - * ALL_SYS_PWRGD indicates when all the following are asserted. - * RSMRST_PWRGD & DPWROK - * S4 voltage rails good (DDR) - * VCCST voltage rail good - * S0 voltage rails good - * - * ALL_SYS_PWRGD can be implemented as a single GPIO if the platform power logic - * combines the above power good signals. Otherwise your board can override - * intel_x86_get_pg_ec_all_sys_pwrgd() to check multiple power good signals. - */ -extern const struct intel_x86_pwrok_signal pwrok_signal_assert_list[]; -extern const int pwrok_signal_assert_count; -extern const struct intel_x86_pwrok_signal pwrok_signal_deassert_list[]; -extern const int pwrok_signal_deassert_count; - -#endif /* __CROS_EC_ICELAKE_H */ +#endif /* __CROS_EC_ALDERLAKE_SLG4BD44540_H */ diff --git a/include/power/intel_x86.h b/include/power/intel_x86.h index d50d6a75da..303db20de7 100644 --- a/include/power/intel_x86.h +++ b/include/power/intel_x86.h @@ -13,8 +13,10 @@ #include "power.h" /* Chipset specific header files */ +#if defined(CONFIG_CHIPSET_ALDERLAKE_SLG4BD44540) +#include "alderlake_slg4bd44540.h" /* Geminilake and apollolake use same power sequencing. */ -#ifdef CONFIG_CHIPSET_APL_GLK +#elif defined(CONFIG_CHIPSET_APL_GLK) #include "apollolake.h" #elif defined(CONFIG_CHIPSET_CANNONLAKE) #include "cannonlake.h" diff --git a/power/alderlake_slg4bd44540.c b/power/alderlake_slg4bd44540.c index f2e62d981d..8bc9ec221e 100644 --- a/power/alderlake_slg4bd44540.c +++ b/power/alderlake_slg4bd44540.c @@ -1,21 +1,40 @@ -/* Copyright 2018 The Chromium OS Authors. All rights reserved. +/* Copyright 2021 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. */ -/* Icelake chipset power control module for Chrome EC */ +/* + * This was originally copied form power/icelake.c (also used on TGL and + * ADL) and adapted to support ADL designs using the Silergy SLG4BD44540 + * power sequencer chip. + */ #include "board_config.h" #include "chipset.h" #include "console.h" #include "gpio.h" -#include "hooks.h" #include "power.h" +#include "power/alderlake_slg4bd44540.h" #include "power/intel_x86.h" -#include "power_button.h" -#include "task.h" #include "timer.h" +/* + * These delays are used by the brya power sequence reference design and + * should be suitable for variants. + */ + +/* SEQ_EC_ALL_SYS_PG high to VCCST_PWRGD high delay */ +#define VCCST_PWRGD_DELAY_MS 2 + +/* IMVP9_VRRDY high to PCH_PWROK high delay */ +#define PCH_PWROK_DELAY_MS 2 + +/* SEQ_EC_ALL_SYS_PG high to EC_PCH_SYS_PWROK high delay */ +#define SYS_PWROK_DELAY_MS 45 + +/* IMVP9_VRRDY high timeout */ +#define VRRDY_TIMEOUT_MS 50 + /* Console output macros */ #define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ## args) @@ -30,8 +49,6 @@ /* The wait time is ~150 msec, allow for safety margin. */ #define IN_PCH_SLP_SUS_WAIT_TIME_USEC (250 * MSEC) -static int forcing_shutdown; /* Forced shutdown in progress? */ - /* Power signals list. Must match order of enum power_signal. */ const struct power_signal_info power_signal_list[] = { [X86_SLP_S0_DEASSERTED] = { @@ -95,27 +112,11 @@ void chipset_force_shutdown(enum chipset_shutdown_reason reason) GPIO_SET_LEVEL(GPIO_PCH_RSMRST_L, 0); board_after_rsmrst(0); - /* Turn off DSW_PWROK to meet tPCH14 */ - GPIO_SET_LEVEL(GPIO_PCH_DSW_PWROK, 0); - - /* Turn off DSW load switch. */ - GPIO_SET_LEVEL(GPIO_EN_PP3300_A, 0); - - /* - * For JSL, we need to wait 60ms before turning off PP5000_U to allow - * VCCIN_AUX time to discharge. - */ - if (IS_ENABLED(CONFIG_CHIPSET_JASPERLAKE)) - msleep(60); - - /* Turn off PP5000 rail */ - if (IS_ENABLED(CONFIG_POWER_PP5000_CONTROL)) - power_5v_enable(task_get_current(), 0); - else - GPIO_SET_LEVEL(GPIO_EN_PP5000, 0); + /* Turn off S5 rails */ + GPIO_SET_LEVEL(GPIO_EN_S5_RAILS, 0); /* - * TODO(b/111810925): Replace this wait with + * TODO(b/179519791): Replace this wait with * power_wait_signals_timeout() */ /* Now wait for DSW_PWROK and RSMRST_ODL to go away. */ @@ -129,19 +130,12 @@ void chipset_force_shutdown(enum chipset_shutdown_reason reason) CPRINTS("DSW_PWROK or RSMRST_ODL didn't go low! Assuming G3."); } +/* + * TODO(b/179524867): do we need to do anything here? + */ + void chipset_handle_espi_reset_assert(void) { - /* - * If eSPI_Reset# pin is asserted without SLP_SUS# being asserted, then - * it means that there is an unexpected power loss (global reset - * event). In this case, check if shutdown was being forced by pressing - * power button. If yes, release power button. - */ - if ((power_get_signals() & IN_PCH_SLP_SUS_DEASSERTED) && - forcing_shutdown) { - power_button_pch_release(); - forcing_shutdown = 0; - } } enum power_state chipset_force_g3(void) @@ -151,112 +145,104 @@ enum power_state chipset_force_g3(void) return POWER_G3; } -static void enable_pp5000_rail(void) -{ - if (IS_ENABLED(CONFIG_POWER_PP5000_CONTROL)) - power_5v_enable(task_get_current(), 1); - else - GPIO_SET_LEVEL(GPIO_EN_PP5000, 1); - -} - -__overridable void intel_x86_dsw_pwrok_pass_thru(void) +static void ap_off(void) { - int dswpwrok_in = intel_x86_get_pg_ec_dsw_pwrok(); - - /* Pass-through DSW_PWROK to ICL. */ - if (dswpwrok_in != gpio_get_level(GPIO_PCH_DSW_PWROK)) { - if (IS_ENABLED(CONFIG_CHIPSET_SLP_S3_L_OVERRIDE) - && dswpwrok_in) { - /* - * Once DSW_PWROK is high, reconfigure SLP_S3_L back to - * an input after a short delay. - */ - msleep(1); - CPRINTS("Release SLP_S3_L"); - gpio_reset(SLP_S3_SIGNAL_L); - power_signal_enable_interrupt(SLP_S3_SIGNAL_L); - } - - CPRINTS("Pass thru GPIO_DSW_PWROK: %d", dswpwrok_in); - /* - * A minimum 10 msec delay is required between PP3300_A being - * stable and the DSW_PWROK signal being passed to the PCH. - */ - msleep(10); - GPIO_SET_LEVEL(GPIO_PCH_DSW_PWROK, dswpwrok_in); - } + GPIO_SET_LEVEL(GPIO_VCCST_PWRGD_OD, 0); + GPIO_SET_LEVEL(GPIO_PCH_PWROK, 0); + GPIO_SET_LEVEL(GPIO_EC_PCH_SYS_PWROK, 0); } -#ifndef CONFIG_PWRGD_PASS_THROUGH_CUSTOM /* - * Return 0 if PWROK signal is deasserted, non-zero if asserted + * We have asserted VCCST_PWRGO_OD, now wait for the IMVP9.1 + * to assert IMVP9_VRRDY_OD. + * + * Returns state of VRRDY. */ -static int pwrok_signal_get(const struct intel_x86_pwrok_signal *signal) -{ - int level = gpio_get_level(signal->gpio); - if (signal->active_low) - level = !level; +static int wait_for_vrrdy(void) +{ + int timeout_ms = VRRDY_TIMEOUT_MS; + int vrrdy; - return level; + for (; timeout_ms > 0; --timeout_ms) { + vrrdy = gpio_get_level(GPIO_IMVP9_VRRDY_OD); + if (vrrdy != 0) + return 1; + msleep(1); + } + return 0; } /* - * Set the PWROK signal state + * The relationship between these signals is described in + * Intel PDG #627205 rev. 0.81. * - * ¶m level 0 deasserts the signal, other values assert the signal + * tCPU16: >= 0 + * VCCST_PWRGD to PCH_PWROK + * tPLT05: >= 0 + * SYS_ALL_PWRGD to SYS_PWROK + * PCH_PWROK to SYS_PWROK */ -static void pwrok_signal_set(const struct intel_x86_pwrok_signal *signal, - int level) -{ - GPIO_SET_LEVEL(signal->gpio, signal->active_low ? !level : level); -} -/* - * Pass through the state of the ALL_SYS_PWRGD input to all the PWROK outputs - * defined by the board. - */ static void all_sys_pwrgd_pass_thru(void) { - int all_sys_pwrgd_in = intel_x86_get_pg_ec_all_sys_pwrgd(); - const struct intel_x86_pwrok_signal *pwrok_signal; - int signal_count; - int i; - - if (all_sys_pwrgd_in) { - pwrok_signal = pwrok_signal_assert_list; - signal_count = pwrok_signal_assert_count; - } else { - pwrok_signal = pwrok_signal_deassert_list; - signal_count = pwrok_signal_deassert_count; + int sys_pg; + int vccst_pg; + int pch_pok; + int sys_pok; + + sys_pg = gpio_get_level(GPIO_SEQ_EC_ALL_SYS_PG); + + if (IS_ENABLED(CONFIG_BRINGUP)) + CPRINTS("SEQ_EC_ALL_SYS_PG is %d", sys_pg); + + if (sys_pg == 0) { + ap_off(); + return; } - /* - * Loop through all PWROK signals defined by the board and set - * to match the current ALL_SYS_PWRGD input. - */ - for (i = 0; i < signal_count; i++, pwrok_signal++) { - if ((!all_sys_pwrgd_in && !pwrok_signal_get(pwrok_signal)) - || (all_sys_pwrgd_in && pwrok_signal_get(pwrok_signal))) - continue; + /* SEQ_EC_ALL_SYS_PG is asserted, enable VCCST_PWRGD_OD. */ - if (pwrok_signal->delay_ms > 0) - msleep(pwrok_signal->delay_ms); + vccst_pg = gpio_get_level(GPIO_VCCST_PWRGD_OD); + if (vccst_pg == 0) { + msleep(VCCST_PWRGD_DELAY_MS); + GPIO_SET_LEVEL(GPIO_VCCST_PWRGD_OD, 1); + } + + /* Enable PCH_PWROK, gated by VRRDY. */ - pwrok_signal_set(pwrok_signal, all_sys_pwrgd_in); + pch_pok = gpio_get_level(GPIO_PCH_PWROK); + if (pch_pok == 0) { + if (wait_for_vrrdy() == 0) { + CPRINTS("Timed out waiting for VRRDY, " + "shutting AP off!"); + ap_off(); + return; + } + msleep(PCH_PWROK_DELAY_MS); + GPIO_SET_LEVEL(GPIO_PCH_PWROK, 1); + } + + /* Enable PCH_SYS_PWROK. */ + + sys_pok = gpio_get_level(GPIO_EC_PCH_SYS_PWROK); + if (sys_pok == 0) { + msleep(SYS_PWROK_DELAY_MS); + /* Check if we lost power while waiting. */ + sys_pg = gpio_get_level(GPIO_SEQ_EC_ALL_SYS_PG); + if (sys_pg == 0) { + CPRINTS("SEQ_EC_ALL_SYS_PG deasserted, " + "shutting AP off!"); + ap_off(); + return; + } + GPIO_SET_LEVEL(GPIO_EC_PCH_SYS_PWROK, 1); + /* PCH will now release PLT_RST */ } } -#endif /* CONFIG_PWRGD_PASS_THROUGH_CUSTOM */ enum power_state power_handle_state(enum power_state state) { -#ifdef CONFIG_CHIPSET_JASPERLAKE - int timeout_ms = 10; -#endif /* CONFIG_CHIPSET_JASPERLAKE */ - - intel_x86_dsw_pwrok_pass_thru(); - all_sys_pwrgd_pass_thru(); common_intel_x86_handle_rsmrst(state); @@ -264,39 +250,11 @@ enum power_state power_handle_state(enum power_state state) switch (state) { case POWER_G3S5: - if (IS_ENABLED(CONFIG_CHIPSET_SLP_S3_L_OVERRIDE)) { - /* - * Prevent glitches on the SLP_S3_L and PCH_PWROK - * signals while when the PP3300_A rail is turned on. - * Drive SLP_S3_L from the EC until DSW_PWROK is high. - */ - CPRINTS("Drive SLP_S3_L low during PP3300_A rampup"); - power_signal_disable_interrupt(SLP_S3_SIGNAL_L); - gpio_set_flags(SLP_S3_SIGNAL_L, GPIO_ODR_LOW); - } - - /* Default behavior - turn on PP5000 rail first */ - if (!IS_ENABLED(CONFIG_CHIPSET_PP3300_RAIL_FIRST)) - enable_pp5000_rail(); + GPIO_SET_LEVEL(GPIO_EN_S5_RAILS, 1); - /* - * TODO(b/111121615): Should modify this to wait until the - * common power state machine indicates that it's ok to try an - * boot the AP prior to turning on the 3300_A rail. This could - * be done using chipset_pre_init_callback() - */ - /* Turn on the PP3300_DSW rail. */ - GPIO_SET_LEVEL(GPIO_EN_PP3300_A, 1); if (power_wait_signals(IN_PGOOD_ALL_CORE)) break; - /* Pass thru DSW_PWROK again since we changed it. */ - intel_x86_dsw_pwrok_pass_thru(); - - /* Turn on PP5000 after PP3300 and DSW PWROK when enabled */ - if (IS_ENABLED(CONFIG_CHIPSET_PP3300_RAIL_FIRST)) - enable_pp5000_rail(); - /* * Now wait for SLP_SUS_L to go high based on tPCH32. If this * signal doesn't go high within 250 msec then go back to G3. @@ -309,33 +267,11 @@ enum power_state power_handle_state(enum power_state state) break; case POWER_S5: - if (forcing_shutdown) { - power_button_pch_release(); - forcing_shutdown = 0; - } /* If SLP_SUS_L is asserted, we're no longer in S5. */ if (!power_has_signals(IN_PCH_SLP_SUS_DEASSERTED)) return POWER_S5G3; break; -#ifdef CONFIG_CHIPSET_JASPERLAKE - case POWER_S3S0: - GPIO_SET_LEVEL(GPIO_EN_VCCIO_EXT, 1); - /* Now wait for ALL_SYS_PWRGD. */ - while (!intel_x86_get_pg_ec_all_sys_pwrgd() && - (timeout_ms > 0)) { - msleep(1); - timeout_ms--; - }; - if (!timeout_ms) - CPRINTS("ALL_SYS_PWRGD not received."); - break; - - case POWER_S0S3: - GPIO_SET_LEVEL(GPIO_EN_VCCIO_EXT, 0); - break; -#endif /* CONFIG_CHIPSET_JASPERLAKE */ - default: break; } diff --git a/power/build.mk b/power/build.mk index b635219d3f..a278c8d32b 100644 --- a/power/build.mk +++ b/power/build.mk @@ -6,6 +6,8 @@ # Power management for application processor and peripherals # +power-$(CONFIG_CHIPSET_ALDERLAKE_SLG4BD44540)+=alderlake_slg4bd44540.o +power-$(CONFIG_CHIPSET_ALDERLAKE_SLG4BD44540)+=intel_x86.o power-$(CONFIG_CHIPSET_APL_GLK)+=apollolake.o intel_x86.o power-$(CONFIG_CHIPSET_BRASWELL)+=braswell.o power-$(CONFIG_CHIPSET_CANNONLAKE)+=cannonlake.o intel_x86.o |