diff options
author | Peter Marheine <pmarheine@chromium.org> | 2019-11-11 11:01:30 +1100 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-11-18 01:20:29 +0000 |
commit | 5162094fe4be16ffc6255ac46102b536c2fbc96f (patch) | |
tree | 05a067b451916a2a69c7d0da96d8ee53fb4aa2be /power/cometlake-discrete.c | |
parent | 0554955a51b0e7e4eff63f475b51d8e3aabc9c26 (diff) | |
download | chrome-ec-5162094fe4be16ffc6255ac46102b536c2fbc96f.tar.gz |
Create cometlake-discrete power driver
This sets up the driver (mostly copied from cometlake for now), to be
used by puff.
BUG=b:143188569
TEST=make buildall still succeeds
BRANCH=none
Change-Id: I4a4b70dd8ba58c070e2c6ad5941911bab16bafe6
Signed-off-by: Peter Marheine <pmarheine@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1906391
Reviewed-by: Andrew McRae <amcrae@chromium.org>
Diffstat (limited to 'power/cometlake-discrete.c')
-rw-r--r-- | power/cometlake-discrete.c | 214 |
1 files changed, 214 insertions, 0 deletions
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); +} |