summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/config.h11
-rw-r--r--include/power/alderlake_slg4bd44540.h52
-rw-r--r--include/power/intel_x86.h4
-rw-r--r--power/alderlake_slg4bd44540.c276
-rw-r--r--power/build.mk2
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.
*
- * &param 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