diff options
-rw-r--r-- | include/config.h | 4 | ||||
-rw-r--r-- | power/build.mk | 1 | ||||
-rw-r--r-- | power/cometlake-discrete.c | 214 | ||||
-rw-r--r-- | power/cometlake-discrete.h | 60 | ||||
-rw-r--r-- | power/intel_x86.h | 2 |
5 files changed, 281 insertions, 0 deletions
diff --git a/include/config.h b/include/config.h index cc12e94673..aef854ff62 100644 --- a/include/config.h +++ b/include/config.h @@ -1083,6 +1083,9 @@ #undef CONFIG_CHIPSET_BRASWELL /* Intel Braswell (x86) */ #undef CONFIG_CHIPSET_CANNONLAKE /* Intel Cannonlake (x86) */ #undef CONFIG_CHIPSET_COMETLAKE /* Intel Cometlake (x86) */ +#undef CONFIG_CHIPSET_COMETLAKE_DISCRETE /* Intel Cometlake (x86), + * discrete EC control + */ #undef CONFIG_CHIPSET_ECDRIVEN /* Dummy power module */ #undef CONFIG_CHIPSET_GEMINILAKE /* Intel Geminilake (x86) */ #undef CONFIG_CHIPSET_ICELAKE /* Intel Icelake (x86) */ @@ -4852,6 +4855,7 @@ defined(CONFIG_CHIPSET_BRASWELL) || \ defined(CONFIG_CHIPSET_CANNONLAKE) || \ defined(CONFIG_CHIPSET_COMETLAKE) || \ + defined(CONFIG_CHIPSET_COMETLAKE_DISCRETE) || \ defined(CONFIG_CHIPSET_GEMINILAKE) || \ defined(CONFIG_CHIPSET_ICELAKE) || \ defined(CONFIG_CHIPSET_SKYLAKE) || \ diff --git a/power/build.mk b/power/build.mk index 8a75b86b6b..4dfa240a99 100644 --- a/power/build.mk +++ b/power/build.mk @@ -10,6 +10,7 @@ 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 power-$(CONFIG_CHIPSET_COMETLAKE)+=cometlake.o intel_x86.o +power-$(CONFIG_CHIPSET_COMETLAKE_DISCRETE)+=cometlake-discrete.o intel_x86.o power-$(CONFIG_CHIPSET_ECDRIVEN)+=ec_driven.o power-$(CONFIG_CHIPSET_ICL_TGL)+=icelake.o intel_x86.o power-$(CONFIG_CHIPSET_MT817X)+=mt817x.o diff --git a/power/cometlake-discrete.c b/power/cometlake-discrete.c new file mode 100644 index 0000000000..3b5d7575ac --- /dev/null +++ b/power/cometlake-discrete.c @@ -0,0 +1,214 @@ +/* Copyright 2019 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. + */ + +/* Chrome EC chipset power control for Cometlake with platform-controlled + * discrete sequencing. + */ + +#include "chipset.h" +#include "console.h" +#include "gpio.h" +#include "intel_x86.h" +#include "power.h" +#include "power_button.h" +#include "task.h" +#include "timer.h" + +/* Console output macros */ +#define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ## args) + +/* Power signals list. Must match order of enum power_signal. */ +const struct power_signal_info power_signal_list[] = { + [PP5000_A_PGOOD] = { + GPIO_PG_PP5000_A_OD, + POWER_SIGNAL_ACTIVE_HIGH, + "PP5000_A_PGOOD", + }, + [PP1800_A_PGOOD] = { + GPIO_PG_PP1800_A_OD, + POWER_SIGNAL_ACTIVE_HIGH, + "PP1800_A_PGOOD", + }, + [VPRIM_CORE_A_PGOOD] = { + GPIO_PG_VPRIM_CORE_A_OD, + POWER_SIGNAL_ACTIVE_HIGH, + "VPRIM_CORE_A_PGOOD", + }, + [PP1050_A_PGOOD] = { + GPIO_PG_PP1050_A_OD, + POWER_SIGNAL_ACTIVE_HIGH, + "PP1050_A_PGOOD", + }, + [X86_SLP_S4_DEASSERTED] = { + SLP_S4_SIGNAL_L, + POWER_SIGNAL_ACTIVE_HIGH, + "SLP_S4_DEASSERTED", + }, + [PP2500_DRAM_PGOOD] = { + GPIO_PG_PP2500_DRAM_U_OD, + POWER_SIGNAL_ACTIVE_HIGH, + "PP2500_DRAM_PGOOD", + }, + [PP1200_DRAM_PGOOD] = { + GPIO_PG_PP1200_U_OD, + POWER_SIGNAL_ACTIVE_HIGH, + "PP1200_DRAM_PGOOD", + }, + [X86_SLP_S3_DEASSERTED] = { + SLP_S3_SIGNAL_L, + POWER_SIGNAL_ACTIVE_HIGH, + "SLP_S3_DEASSERTED", + }, + [PP950_VCCIO_PGOOD] = { + GPIO_PG_PP950_VCCIO_OD, + POWER_SIGNAL_ACTIVE_HIGH, + "PP950_VCCIO_PGOOD", + }, + [X86_SLP_S0_DEASSERTED] = { + GPIO_PCH_SLP_S0_L, + POWER_SIGNAL_ACTIVE_HIGH | POWER_SIGNAL_DISABLE_AT_BOOT, + "SLP_S0_DEASSERTED", + }, + [CPU_C10_GATE_DEASSERTED] = { + GPIO_CPU_C10_GATE_L, + POWER_SIGNAL_ACTIVE_HIGH, + "CPU_C10_GATE_DEASSERTED", + }, + [IMVP8_READY] = { + GPIO_IMVP8_VRRDY_OD, + POWER_SIGNAL_ACTIVE_HIGH, + "IMVP8_READY", + }, +}; +BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT); + +void chipset_force_shutdown(enum chipset_shutdown_reason reason) +{ + /* TODO(b/143188569) update from base driver */ + int timeout_ms = 50; + + CPRINTS("%s(%d)", __func__, reason); + report_ap_reset(reason); + + /* Turn off RSMRST_L to meet tPCH12 */ + gpio_set_level(GPIO_PCH_RSMRST_L, 0); + + /* Turn off A (except PP5000_A) rails*/ + gpio_set_level(GPIO_EN_A_RAILS, 0); + +#ifdef CONFIG_POWER_PP5000_CONTROL + /* Issue a request to turn off the rail. */ + power_5v_enable(task_get_current(), 0); +#else + /* Turn off PP5000_A rail */ + gpio_set_level(GPIO_EN_PP5000_A, 0); +#endif + + /* Need to wait a min of 10 msec before check for power good */ + msleep(10); + + /* Now wait for PP5000_A and RSMRST_L to go low */ + while ((gpio_get_level(GPIO_PP5000_A_PG_OD) || + power_has_signals(IN_PGOOD_ALL_CORE)) && (timeout_ms > 0)) { + msleep(1); + timeout_ms--; + }; + + if (!timeout_ms) + CPRINTS("PP5000_A rail still up! Assuming G3."); +} + +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_PGOOD_ALL_CORE)) + power_button_pch_release(); +} + +enum power_state chipset_force_g3(void) +{ + chipset_force_shutdown(CHIPSET_SHUTDOWN_G3); + + return POWER_G3; +} + +/* Called by APL power state machine when transitioning from G3 to S5 */ +void chipset_pre_init_callback(void) +{ + /* TODO(b/143188569) update from base driver */ + /* Enable 5.0V and 3.3V rails, and wait for Power Good */ +#ifdef CONFIG_POWER_PP5000_CONTROL + power_5v_enable(task_get_current(), 1); +#else + /* Turn on PP5000_A rail */ + gpio_set_level(GPIO_EN_PP5000_A, 1); +#endif + /* Turn on A (except PP5000_A) rails*/ + gpio_set_level(GPIO_EN_A_RAILS, 1); + + /* + * The status of the 5000_A rail is verified in the calling function via + * power_wait_signals() as PP5000_A_PGOOD is included in the + * CHIPSET_G3S5_POWERUP_SIGNAL macro. + */ +} + +enum power_state power_handle_state(enum power_state state) +{ + /* TODO(b/143188569) update from base driver */ + int all_sys_pwrgd_in; + int all_sys_pwrgd_out; + + /* + * Check if RSMRST_L signal state has changed and if so, pass the new + * value along to the PCH. However, if the new transition of RSMRST_L + * from the Sielgo is from low to high, then gate this transition to the + * AP by the PP5000_A rail. If the new transition is from high to low, + * then pass that through regardless of the PP5000_A value. + * + * The PP5000_A power good signal will float high if the + * regulator is not powered, so checking both that the EN and the PG + * signals are high. + */ + if ((gpio_get_level(GPIO_PP5000_A_PG_OD) && + gpio_get_level(GPIO_EN_PP5000_A)) || + gpio_get_level(GPIO_PCH_RSMRST_L)) + common_intel_x86_handle_rsmrst(state); + + switch (state) { + + case POWER_S5: + /* If RSMRST_L is asserted, we're no longer in S5. */ + if (!power_has_signals(IN_PGOOD_ALL_CORE)) + return POWER_S5G3; + break; + + case POWER_S0: + /* + * Check value of PG_EC_ALL_SYS_PWRGD to see if PCH_SYS_PWROK + * needs to be changed. If it's low->high transition, requires a + * 2msec delay. + */ + all_sys_pwrgd_in = gpio_get_level(GPIO_PG_EC_ALL_SYS_PWRGD); + all_sys_pwrgd_out = gpio_get_level(GPIO_PCH_SYS_PWROK); + + if (all_sys_pwrgd_in != all_sys_pwrgd_out) { + if (all_sys_pwrgd_in) + msleep(2); + gpio_set_level(GPIO_PCH_SYS_PWROK, all_sys_pwrgd_in); + } + break; + + default: + break; + } + + return common_intel_x86_power_handle_state(state); +} diff --git a/power/cometlake-discrete.h b/power/cometlake-discrete.h new file mode 100644 index 0000000000..ad423126df --- /dev/null +++ b/power/cometlake-discrete.h @@ -0,0 +1,60 @@ +/* Copyright 2019 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. + */ + +/* Chrome EC chipset power control for Cometlake with platform-controlled + * discrete sequencing. + */ + +#ifndef __CROS_EC_COMETLAKE_DISCRETE_H +#define __CROS_EC_COMETLATE_DISCRETE_H + +/* Input state flags. */ +#define IN_PCH_SLP_S3_DEASSERTED POWER_SIGNAL_MASK(X86_SLP_S3_DEASSERTED) +#define IN_PCH_SLP_S4_DEASSERTED POWER_SIGNAL_MASK(X86_SLP_S4_DEASSERTED) + +#define IN_ALL_PM_SLP_DEASSERTED \ + (IN_PCH_SLP_S3_DEASSERTED | IN_PCH_SLP_S4_DEASSERTED) + +/* TODO(b/143188569) RSMRST_L is an EC output, can't use POWER_SIGNAL_MASK */ +#define IN_PGOOD_ALL_CORE \ + POWER_SIGNAL_MASK(/*X86_RSMRST_L_PGOOD*/ POWER_SIGNAL_COUNT) + +#define IN_ALL_S0 \ + (IN_PGOOD_ALL_CORE | IN_ALL_PM_SLP_DEASSERTED | \ + PP5000_PGOOD_POWER_SIGNAL_MASK) + +/* TODO(b/143188569) RSMRST_L is an EC output, can't use POWER_SIGNAL_MASK */ +#define CHIPSET_G3S5_POWERUP_SIGNAL \ + (POWER_SIGNAL_MASK(/*X86_RSMRST_L_PGOOD*/ POWER_SIGNAL_COUNT) | \ + POWER_SIGNAL_MASK(PP5000_A_PGOOD)) + +#define CHARGER_INITIALIZED_DELAY_MS 100 +#define CHARGER_INITIALIZED_TRIES 40 + +/* Power signals, in power-on sequence order. */ +enum power_signal { + PP5000_A_PGOOD, + /* PP3300 monitoring is analog */ + PP1800_A_PGOOD, + VPRIM_CORE_A_PGOOD, + PP1050_A_PGOOD, + /* S5 ready */ + X86_SLP_S4_DEASSERTED, + PP2500_DRAM_PGOOD, + PP1200_DRAM_PGOOD, + /* S3 ready */ + X86_SLP_S3_DEASSERTED, + /* PP1050 monitoring is analog */ + PP950_VCCIO_PGOOD, + /* S0 ready */ + X86_SLP_S0_DEASSERTED, + CPU_C10_GATE_DEASSERTED, + IMVP8_READY, + + /* Number of X86 signals */ + POWER_SIGNAL_COUNT +}; + +#endif /* __CROS_EC_COMETLAKE_DISCRETE_H */ diff --git a/power/intel_x86.h b/power/intel_x86.h index 794ac28af5..b54c60e2c3 100644 --- a/power/intel_x86.h +++ b/power/intel_x86.h @@ -20,6 +20,8 @@ #include "cannonlake.h" #elif defined(CONFIG_CHIPSET_COMETLAKE) #include "cometlake.h" +#elif defined(CONFIG_CHIPSET_COMETLAKE_DISCRETE) +#include "cometlake-discrete.h" #elif defined(CONFIG_CHIPSET_ICL_TGL) #include "icelake.h" #elif defined(CONFIG_CHIPSET_SKYLAKE) |