417 lines
12 KiB
C
417 lines
12 KiB
C
/* 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 "adc.h"
|
|
#include "chipset.h"
|
|
#include "console.h"
|
|
#include "gpio.h"
|
|
#include "power.h"
|
|
#include "power/intel_x86.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",
|
|
},
|
|
[OUT_PCH_RSMRST_DEASSERTED] = {
|
|
GPIO_PCH_RSMRST_L,
|
|
POWER_SIGNAL_ACTIVE_HIGH,
|
|
"OUT_PCH_RSMRST_DEASSERTED",
|
|
},
|
|
[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);
|
|
|
|
/*
|
|
* The EC is responsible for most of the power-on sequence with this driver,
|
|
* enabling rails and waiting for power-good signals from regulators before
|
|
* continuing. The power sequencing works as follows.
|
|
*
|
|
* 1. From G3 (all-off), power is applied and EC power supplies come up.
|
|
* The power button task kicks off platform power-up as desired.
|
|
* 2. Power up the platform to reach S5
|
|
* a. Enable PP5000_A and wait for PP5000_A_PGOOD.
|
|
* b. Enable PP3300_A (EN_ROA_RAILS).
|
|
* c. Wait for PP3300_A power good. This regulator doesn't provide a power
|
|
* good output, so the EC monitors ADC_SNS_PP3300.
|
|
* d. Enable PP1800_A and wait for PP1800_A_PGOOD.
|
|
* e. PP1800_A_PGOOD automatically enables PPVAR_VPRIM_CORE_A, which receives
|
|
* power from PP3300_A (hence PP3300_A must precede PP1800_A, even though
|
|
* PP1800_A draws power from PP3300_G which is guaranteed to already be on)
|
|
* f. PPVAR_VPRIM_CORE_A_PGOOD automatically enables PP1050_A
|
|
* g. Wait for PP1050_A_PGOOD, indicating that both PPVAR_VPRIM_CORE_A and
|
|
* PP1050_A are good.
|
|
* h. Wait 10ms to satisfy tPCH03, then bring the PCH out of reset by
|
|
* deasserting RSMRST.
|
|
* 3. The PCH controls transition from S5 up to S3 and higher-power states.
|
|
* a. PCH deasserts SLP_S4, automatically turning on PP2500_DRAM_U and
|
|
* PP1200_DRAM_U.
|
|
* b. Wait for PP2500_DRAM_PGOOD and PP1200_DRAM_PGOOD.
|
|
* 4. PCH deasserts SLP_S3 to switch to S0
|
|
* a. SLP_S3 transition automatically enables PP1050_ST_S.
|
|
* b. Wait for PP1050_ST_S good. The power good output from this regulator is
|
|
* not connected, so the EC monitors ADC_SNS_PP1050_ST_S.
|
|
* c. Turn on EN_S0_RAILS (enabling PP1200_PLLOC and PP1050_STG).
|
|
* VCCIO must not ramp up before VCCST, VCCSTG and memory rails are good
|
|
* (PDG figure 424, note 14).
|
|
* d. Wait 2ms (for EN_S0_RAILS load switches to turn on).
|
|
* e. Enable PP950_VCCIO.
|
|
* f. Wait for PG_PP950_VCCIO. Although the PCH may be asserting CPU_C10_GATED
|
|
* which holds the VCCIO regulator in a low-power mode, the regulator will
|
|
* turn on normally and assert power good then drop into low power mode
|
|
* and continue asserting power good.
|
|
* 5. Transition fully to S0 following SLP_S0
|
|
* a. Assert VCCST_PWRGD. This notionally tracks PP1050_ST_S but must be
|
|
* deasserted in S3 and lower.
|
|
* b. Enable IMVP8_VR.
|
|
* c. Wait 2ms.
|
|
* d. Assert SYS_PWROK.
|
|
* e. Wait for IMVP8_VRRDY.
|
|
* f. Wait 2ms.
|
|
* g. Assert PCH_PWROK.
|
|
*
|
|
* When CPU_C10_GATED is asserted, we are free to disable PP1200_PLLOC and
|
|
* PP1050_STG by deasserting EN_S0_RAILS to save some power. VCCIO is
|
|
* automatically placed in low-power mode by CPU_C10_GATED, and no further
|
|
* action is required- power-good signals will not change, just the relevant
|
|
* load switches (which are specified to meet the platform's minimum turn-on
|
|
* time when CPU_C10_GATED is deasserted again) are turned off. This gating is
|
|
* done asynchronously directly in the interrupt handler because its timing is
|
|
* very tight.
|
|
*
|
|
* For further reference, Figure 421 and Table 370 in the Comet Lake U PDG
|
|
* summarizes platform power rail requirements in a reasonably easy-to-digest
|
|
* manner, while section 12.11 (containing those diagrams) details the required
|
|
* operation.
|
|
*/
|
|
|
|
/*
|
|
* Reverse of S0->S3 transition.
|
|
*
|
|
* This is a separate function so it can be reused when forcing shutdown due to
|
|
* power failure or other reasons.
|
|
*
|
|
* This function may be called from an ISR (slp_s3_interrupt) so must not
|
|
* assume that it's running in a regular task.
|
|
*/
|
|
static void shutdown_s0_rails(void)
|
|
{
|
|
board_enable_s0_rails(0);
|
|
/*
|
|
* Deassert VCCST_PG as early as possible to satisfy tCPU22; VDDQ is
|
|
* derived directly from SLP_S3.
|
|
*/
|
|
gpio_set_level(GPIO_VCCST_PG_OD, 0);
|
|
gpio_set_level(GPIO_EC_PCH_PWROK, 0);
|
|
gpio_set_level(GPIO_EC_PCH_SYS_PWROK, 0);
|
|
gpio_set_level(GPIO_EN_IMVP8_VR, 0);
|
|
gpio_set_level(GPIO_EN_S0_RAILS, 0);
|
|
/*
|
|
* * tPCH10: PCH_PWROK to VCCIO off >400ns (but only on unexpected
|
|
* power-down)
|
|
* * tPLT18: SLP_S3_L to VCCIO disable <200us
|
|
*
|
|
* tPCH10 is only 7 CPU cycles at 16 MHz so we should satisfy that
|
|
* minimum time with no extra code, and sleeping is likely to cause
|
|
* a delay that exceeds tPLT18.
|
|
*/
|
|
gpio_set_level(GPIO_EN_PP950_VCCIO, 0);
|
|
}
|
|
|
|
/*
|
|
* Reverse of G3->S5 transition.
|
|
*
|
|
* This is a separate function so it can be reused when forcing shutdown due to
|
|
* power failure or other reasons.
|
|
*/
|
|
static void shutdown_s5_rails(void)
|
|
{
|
|
gpio_set_level(GPIO_PCH_RSMRST_L, 0);
|
|
/* tPCH12: RSMRST to VCCPRIM (PPVAR_VPRIM_CORE_A) off >400ns */
|
|
usleep(1);
|
|
gpio_set_level(GPIO_EN_PP1800_A, 0);
|
|
gpio_set_level(GPIO_EN_ROA_RAILS, 0);
|
|
#ifdef CONFIG_POWER_PP5000_CONTROL
|
|
power_5v_enable(task_get_current(), 0);
|
|
#else
|
|
gpio_set_level(GPIO_EN_PP5000_A, 0);
|
|
#endif
|
|
}
|
|
|
|
void chipset_force_shutdown(enum chipset_shutdown_reason reason)
|
|
{
|
|
CPRINTS("%s(%d)", __func__, reason);
|
|
report_ap_reset(reason);
|
|
|
|
shutdown_s0_rails();
|
|
/* S3->S5 is automatic based on SLP_S3 driving memory rails. */
|
|
shutdown_s5_rails();
|
|
}
|
|
|
|
void chipset_handle_espi_reset_assert(void) {}
|
|
|
|
enum power_state chipset_force_g3(void)
|
|
{
|
|
chipset_force_shutdown(CHIPSET_SHUTDOWN_G3);
|
|
|
|
return POWER_G3;
|
|
}
|
|
|
|
/*
|
|
* Wait for a power rail on an analog channel to become good.
|
|
*
|
|
* @param channel ADC channel to read
|
|
* @param min_voltage Minimum required voltage for rail (in mV)
|
|
*
|
|
* @return EC_SUCCESS, or non-zero if error.
|
|
*/
|
|
static int power_wait_analog(enum adc_channel channel, int min_voltage)
|
|
{
|
|
timestamp_t deadline;
|
|
int reading;
|
|
|
|
/* One second timeout */
|
|
deadline = get_time();
|
|
deadline.val += SECOND;
|
|
|
|
do {
|
|
reading = adc_read_channel(channel);
|
|
if (reading == ADC_READ_ERROR)
|
|
return EC_ERROR_HW_INTERNAL;
|
|
if (timestamp_expired(deadline, NULL))
|
|
return EC_ERROR_TIMEOUT;
|
|
} while (reading < min_voltage);
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Force system power state if we time out waiting for a power rail to become
|
|
* good.
|
|
*
|
|
* In general the new state is to transition down to the next lower-power state,
|
|
* so if we time out in G3->S5 we return POWER_G3 to turn things off again and
|
|
* if S3->S0 times out we return POWER_S3S5 for the same reason.
|
|
*
|
|
* Correct sequencing of rails that might already be enabled is handled by
|
|
* chipset_force_shutdown(), so the caller of this function doesn't need to
|
|
* clean up after itself.
|
|
*/
|
|
static enum power_state pgood_timeout(enum power_state new_state)
|
|
{
|
|
chipset_force_shutdown(CHIPSET_SHUTDOWN_WAIT);
|
|
return new_state;
|
|
}
|
|
|
|
/*
|
|
* Called in the chipset task when power signal inputs change state.
|
|
* If this doesn't request a different state, power_common_state handles it.
|
|
*
|
|
* @param state Current power state
|
|
* @return New power state
|
|
*/
|
|
enum power_state power_handle_state(enum power_state state)
|
|
{
|
|
switch (state) {
|
|
case POWER_G3S5:
|
|
if (intel_x86_wait_power_up_ok() != EC_SUCCESS) {
|
|
chipset_force_shutdown(
|
|
CHIPSET_SHUTDOWN_BATTERY_INHIBIT);
|
|
return POWER_G3;
|
|
}
|
|
/* Power-up steps 2a-2h. */
|
|
#ifdef CONFIG_POWER_PP5000_CONTROL
|
|
power_5v_enable(task_get_current(), 1);
|
|
#else
|
|
gpio_set_level(GPIO_EN_PP5000_A, 1);
|
|
#endif
|
|
if (power_wait_signals(POWER_SIGNAL_MASK(PP5000_A_PGOOD)))
|
|
return pgood_timeout(POWER_S5G3);
|
|
gpio_set_level(GPIO_EN_ROA_RAILS, 1);
|
|
if (power_wait_analog(ADC_SNS_PP3300, 3000) != EC_SUCCESS)
|
|
return pgood_timeout(POWER_S5G3);
|
|
gpio_set_level(GPIO_EN_PP1800_A, 1);
|
|
if (power_wait_signals(POWER_SIGNAL_MASK(PP1800_A_PGOOD) |
|
|
POWER_SIGNAL_MASK(PP1050_A_PGOOD)))
|
|
return pgood_timeout(POWER_S5G3);
|
|
msleep(10); /* tPCH03: VCCPRIM good -> RSMRST >10ms */
|
|
gpio_set_level(GPIO_PCH_RSMRST_L, 1);
|
|
break;
|
|
|
|
case POWER_S5G3:
|
|
shutdown_s5_rails();
|
|
break;
|
|
|
|
case POWER_S5S3:
|
|
/* Power-up steps 3a-3b. */
|
|
if (power_wait_signals(POWER_SIGNAL_MASK(PP2500_DRAM_PGOOD) |
|
|
POWER_SIGNAL_MASK(PP1200_DRAM_PGOOD)))
|
|
return pgood_timeout(POWER_S3S5);
|
|
break;
|
|
|
|
case POWER_S3S0:
|
|
/* Power-up steps 4a-4f. */
|
|
if (power_wait_analog(ADC_SNS_PP1050, 1000) != EC_SUCCESS)
|
|
return pgood_timeout(POWER_S3S5);
|
|
gpio_set_level(GPIO_EN_S0_RAILS, 1);
|
|
msleep(2);
|
|
gpio_set_level(GPIO_EN_PP950_VCCIO, 1);
|
|
if (power_wait_signals(POWER_SIGNAL_MASK(PP950_VCCIO_PGOOD)))
|
|
return pgood_timeout(POWER_S3S5);
|
|
|
|
/* Power-up steps 5a-5h */
|
|
gpio_set_level(GPIO_VCCST_PG_OD, 1);
|
|
gpio_set_level(GPIO_EN_IMVP8_VR, 1);
|
|
msleep(2);
|
|
gpio_set_level(GPIO_EC_PCH_SYS_PWROK, 1);
|
|
if (power_wait_signals(POWER_SIGNAL_MASK(IMVP8_READY)))
|
|
return pgood_timeout(POWER_S3S5);
|
|
msleep(2);
|
|
gpio_set_level(GPIO_EC_PCH_PWROK, 1);
|
|
|
|
board_enable_s0_rails(1);
|
|
break;
|
|
|
|
case POWER_S0S3:
|
|
/*
|
|
* Handled in the slp_s3_interrupt fast path, but also run
|
|
* here in case we miss the interrupt somehow.
|
|
*/
|
|
shutdown_s0_rails();
|
|
break;
|
|
|
|
case POWER_S5:
|
|
/*
|
|
* Return to G3 if S5 rails are not on, probably because of
|
|
* a forced power-off.
|
|
*/
|
|
if ((power_get_signals() & CHIPSET_G3S5_POWERUP_SIGNAL) !=
|
|
CHIPSET_G3S5_POWERUP_SIGNAL)
|
|
return POWER_S5G3;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Power-up steps 3a-3b (S5->S3 via IN_PGOOD_ALL_CORE) plus general
|
|
* bookkeeping.
|
|
*/
|
|
return common_intel_x86_power_handle_state(state);
|
|
}
|
|
|
|
#ifdef CONFIG_VBOOT_EFS
|
|
/*
|
|
* Called in main() to ensure chipset power is in a good state.
|
|
*
|
|
* This may be useful because EC reset could happen under unexpected
|
|
* conditions and we want to ensure that if the AP is wedged for some
|
|
* reason (for instance) we unwedge it before continuing.
|
|
*
|
|
* Because power sequencing here is all EC-controlled and this is called
|
|
* as part of the init sequence, we don't need to do anything- EC reset
|
|
* implies power sequencing is all-off and we don't have any external
|
|
* PMIC to synchronize state with.
|
|
*/
|
|
void chipset_handle_reboot(void) {}
|
|
#endif /* CONFIG_VBOOT_EFS */
|
|
|
|
void c10_gate_interrupt(enum gpio_signal signal)
|
|
{
|
|
/*
|
|
* Per PDG, gate VccSTG and VCCIO on (SLP_S3_L && CPU_C10_GATE_L).
|
|
*
|
|
* When in S3 we let the state machine do it since timing is less
|
|
* critical; when in S0/S0ix we do it here because timing is very
|
|
* tight.
|
|
*/
|
|
if (board_is_c10_gate_enabled() && gpio_get_level(GPIO_SLP_S3_L)) {
|
|
int enable_core = gpio_get_level(GPIO_CPU_C10_GATE_L);
|
|
|
|
gpio_set_level(GPIO_EN_S0_RAILS, enable_core);
|
|
}
|
|
|
|
return power_signal_interrupt(signal);
|
|
}
|
|
|
|
void slp_s3_interrupt(enum gpio_signal signal)
|
|
{
|
|
if (!gpio_get_level(GPIO_SLP_S3_L)
|
|
&& chipset_in_state(CHIPSET_STATE_ON)) {
|
|
/* Falling edge on SLP_S3_L means dropping to S3 from S0 */
|
|
shutdown_s0_rails();
|
|
}
|
|
|
|
return power_signal_interrupt(signal);
|
|
}
|