mt8192: add MediaTek MT8192 power sequencing support

Add power sequencing for asurada rev0 board.

Craft mt8192 PS from mt8183. Mostly are the same, except
that MT8192 doesn't use EC reset as AP reset.

BRANCH=none
BUG=b:150341779
TEST=TEST=Tried the following cases:
* Cold reset:
  $ dut-control cold_reset:on sleep:0.2 cold_reset:off
  Result: G3 -> S0
* Long power press to shutdown:
  $ dut-control pwr_button:press sleep:8.2 pwr_button:release
  Result: S0 -> S5 -> G3
* Long power press to power-on but then shutdown:
  $ dut-control pwr_button:press sleep:8.2 pwr_button:release
  Result: G3 -> S0 -> S5 -> G3
* Short power press to power-on:
  $ dut-control pwr_button:press sleep:0.2 pwr_button:release
  Result: G3 -> S0
* Console command: apreset
  Result: S0, AP reboots
* Console command: apshutdown
  Result: S0 -> S5 -> G3
* Lid open to power-on:
  $ dut-control lid_open:no sleep:0.2 lid_open:yes
  Result: G3 -> S0

Change-Id: Ib8ac1ed700fc0a46fe8a1e6e40e1fefa3401d3c0
Signed-off-by: Eric Yilun Lin <yllin@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2120114
Reviewed-by: Ting Shen <phoenixshen@chromium.org>
Reviewed-by: Wai-Hong Tam <waihong@google.com>
This commit is contained in:
Eric Yilun Lin 2020-04-06 16:12:10 +08:00 committed by Commit Bot
parent bf7f4a3e51
commit 1c1ce953d6
7 changed files with 503 additions and 15 deletions

View File

@ -8,6 +8,7 @@
#include "adc_chip.h"
#include "button.h"
#include "charger.h"
#include "chipset.h"
#include "common.h"
#include "console.h"
#include "chip/it83xx/intc.h"
@ -18,6 +19,7 @@
#include "i2c.h"
#include "keyboard_scan.h"
#include "lid_switch.h"
#include "power.h"
#include "power_button.h"
#include "pwm.h"
#include "pwm_chip.h"
@ -53,6 +55,16 @@ const enum gpio_signal hibernate_wake_pins[] = {
};
const int hibernate_wake_pins_used = ARRAY_SIZE(hibernate_wake_pins);
/* power signal list. Must match order of enum power_signal. */
const struct power_signal_info power_signal_list[] = {
{GPIO_PMIC_EC_PWRGD, POWER_SIGNAL_ACTIVE_HIGH, "PMIC_PWR_GOOD"},
{GPIO_AP_IN_SLEEP_L, POWER_SIGNAL_ACTIVE_LOW, "AP_IN_S3_L"},
{GPIO_AP_EC_WATCHDOG_L,
POWER_SIGNAL_ACTIVE_LOW | POWER_SIGNAL_DISABLE_AT_BOOT,
"AP_WDT_ASSERTED"},
};
BUILD_ASSERT(ARRAY_SIZE(power_signal_list) == POWER_SIGNAL_COUNT);
/* Initialize board. */
static void board_init(void)
{

View File

@ -8,6 +8,10 @@
#define __CROS_EC_BOARD_H
/* Chipset config */
#define CONFIG_BRINGUP
#define CONFIG_CHIPSET_MT8192
#define CONFIG_CMD_POWERINDEBUG
#define CONFIG_POWER_COMMON
/* Optional features */
#define CONFIG_BOARD_VERSION_CUSTOM
@ -95,6 +99,13 @@ enum adc_channel {
ADC_CH_COUNT,
};
enum power_signal {
PMIC_PWR_GOOD,
AP_IN_S3_L,
AP_WDT_ASSERTED,
POWER_SIGNAL_COUNT,
};
int board_get_version(void);
#endif /* !__ASSEMBLER__ */

View File

@ -7,10 +7,11 @@
* See CONFIG_TASK_LIST in config.h for details.
*/
/**
TODO: missing CHIPSET and MOTIONSENSE task
TODO: missing MOTIONSENSE task
*/
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_NOTEST(CHIPSET, chipset_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_ALWAYS(CHARGER, charger_task, NULL, VENTI_TASK_STACK_SIZE) \
TASK_ALWAYS(HOSTCMD, host_command_task, NULL, 1024) \
TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \

View File

@ -16,7 +16,17 @@ GPIO_INT(LID_OPEN, PIN(E, 2), GPIO_INT_BOTH | GPIO_PULL_DOWN,
GPIO_INT(TABLET_MODE_L, PIN(J, 7), GPIO_INT_BOTH | GPIO_PULL_UP,
gmr_tablet_switch_isr)
/* Chipset interrupts */
GPIO_INT(AP_EC_WARM_RST_REQ, PIN(D, 3), GPIO_INT_RISING | GPIO_SEL_1P8V,
chipset_reset_request_interrupt)
/* Power sequencing interrupts */
GPIO_INT(AP_EC_WATCHDOG_L, PIN(C, 7), GPIO_INT_BOTH | GPIO_SEL_1P8V,
chipset_watchdog_interrupt)
GPIO_INT(AP_IN_SLEEP_L, PIN(F, 2),
GPIO_INT_BOTH | GPIO_PULL_DOWN | GPIO_SEL_1P8V, power_signal_interrupt)
GPIO_INT(PMIC_EC_PWRGD, PIN(F, 3),
GPIO_INT_BOTH | GPIO_PULL_DOWN | GPIO_SEL_1P8V, power_signal_interrupt)
/* Sensor Interrupts */
@ -37,6 +47,17 @@ GPIO_INT(VOLUME_UP_L, PIN(D, 5), GPIO_INT_BOTH | GPIO_PULL_UP,
button_interrupt) /* EC_VOLUP_BTN_ODL */
/* Power Sequencing Signals */
GPIO(EC_PMIC_EN_ODL, PIN(D, 0), GPIO_ODR_HIGH | GPIO_SEL_1P8V)
GPIO(EC_PMIC_WATCHDOG_L, PIN(H, 0), GPIO_ODR_LOW | GPIO_SEL_1P8V)
GPIO(EN_PP1800_U, PIN(D, 7), GPIO_OUT_LOW)
GPIO(EN_PP3300_U, PIN(G, 3), GPIO_OUT_LOW)
/* b/154775121: default on, because PPCs need the PP5000 to init in G3. */
GPIO(EN_PP5000_A, PIN(C, 6), GPIO_OUT_HIGH)
GPIO(PG_MT6315_PROC_ODL, PIN(E, 1), GPIO_INPUT)
GPIO(PG_MT6360_ODL, PIN(F, 1), GPIO_INPUT)
GPIO(PG_PP5000_A_ODL, PIN(A, 6), GPIO_INPUT)
GPIO(PMIC_FORCE_RESET, PIN(E, 3), GPIO_OUT_LOW | GPIO_SEL_1P8V)
GPIO(SYS_RST_ODL, PIN(B, 6), GPIO_ODR_LOW)
/* MKBP event synchronization */
GPIO(EC_INT_L, PIN(E, 6), GPIO_ODR_HIGH) /* EC_AP_INT_ODL */
@ -87,7 +108,6 @@ UNIMPLEMENTED(PCH_PLTRST_L)
#define UNIMPLEMENTED_GPIO(name, pin) UNIMPLEMENTED(name)
UNIMPLEMENTED_GPIO(SYS_RST_ODL, PIN(B, 6))
UNIMPLEMENTED_GPIO(PACKET_MODE_EN, PIN(M, 6))
UNIMPLEMENTED_GPIO(AP_SPI_EC_CS_L, PIN(M, 5))
UNIMPLEMENTED_GPIO(EC_GPM3, PIN(M, 3))
@ -96,19 +116,14 @@ UNIMPLEMENTED_GPIO(AP_SPI_EC_MOSI, PIN(M, 0))
UNIMPLEMENTED_GPIO(AP_SPI_EC_CLK, PIN(M, 4))
UNIMPLEMENTED_GPIO(EC_RST_ODL, PIN(L, 1))
UNIMPLEMENTED_GPIO(SET_VMC_VOLT_AT_1V8, PIN(D, 4))
UNIMPLEMENTED_GPIO(AP_EC_WATCHDOG_L, PIN(C, 7))
UNIMPLEMENTED_GPIO(EC_PMIC_EN_ODL, PIN(D, 0))
UNIMPLEMENTED_GPIO(USB_C0_PPC_INT_ODL, PIN(D, 1))
UNIMPLEMENTED_GPIO(EN_PP3000_VMC_PMU, PIN(D, 2))
UNIMPLEMENTED_GPIO(AP_EC_WARM_RST_REQ, PIN(D, 3))
UNIMPLEMENTED_GPIO(PWR_LED_ODL, PIN(A, 0))
UNIMPLEMENTED_GPIO(EC_LED_PWM1, PIN(A, 1))
UNIMPLEMENTED_GPIO(EC_LED_PWM2, PIN(A, 2))
UNIMPLEMENTED_GPIO(EC_LED_PWM3, PIN(A, 3))
UNIMPLEMENTED_GPIO(PG_PP5000_A_ODL, PIN(A, 6))
UNIMPLEMENTED_GPIO(USB_A0_FAULT_ODL, PIN(A, 7))
UNIMPLEMENTED_GPIO(USB_C1_MUX_INT_ODL, PIN(E, 5))
UNIMPLEMENTED_GPIO(EN_PP1800_U, PIN(D, 7))
UNIMPLEMENTED_GPIO(CHARGER_PROCHOT_ODL, PIN(C, 3))
UNIMPLEMENTED_GPIO(ENTERING_RW, PIN(C, 5)) /* EC_ENTERING_RW */
UNIMPLEMENTED_GPIO(EC_TEMP_SENSOR_SUBPMIC, PIN(I, 0))
@ -124,15 +139,9 @@ UNIMPLEMENTED_GPIO(BASE_IMU_INT_L, PIN(J, 2))
UNIMPLEMENTED_GPIO(LID_ACCEL_INT_L, PIN(J, 3))
UNIMPLEMENTED_GPIO(USB_C1_BC12_INT_L, PIN(J, 4))
UNIMPLEMENTED_GPIO(EN_USB_C0_BC12_DET, PIN(J, 5))
UNIMPLEMENTED_GPIO(PG_MT6315_PROC_ODL, PIN(E, 1))
UNIMPLEMENTED_GPIO(PMIC_FORCE_RESET, PIN(E, 3))
UNIMPLEMENTED_GPIO(ALS_RGB_INT_ODL, PIN(F, 0))
UNIMPLEMENTED_GPIO(PG_MT6360_ODL, PIN(F, 1))
UNIMPLEMENTED_GPIO(AP_IN_SLEEP_L, PIN(F, 2))
UNIMPLEMENTED_GPIO(PMIC_EC_PWRGD, PIN(F, 3))
UNIMPLEMENTED_GPIO(EC_USB_C0_CC1, PIN(F, 4))
UNIMPLEMENTED_GPIO(EC_USB_C0_CC2, PIN(F, 5))
UNIMPLEMENTED_GPIO(EC_PMIC_WATCHDOG_L, PIN(H, 0))
UNIMPLEMENTED_GPIO(EC_USB_C1_CC1, PIN(H, 1))
UNIMPLEMENTED_GPIO(EC_USB_C1_CC2, PIN(H, 2))
UNIMPLEMENTED_GPIO(USB_C0_FRS_EN, PIN(H, 3))
@ -140,7 +149,6 @@ UNIMPLEMENTED_GPIO(EC_X_GPIO1, PIN(H, 4))
UNIMPLEMENTED_GPIO(EN_EC_ID_DOL, PIN(H, 5))
UNIMPLEMENTED_GPIO(PG_MT6315_GPU_ODL, PIN(H, 6))
UNIMPLEMENTED_GPIO(EC_GPG2, PIN(G, 2))
UNIMPLEMENTED_GPIO(EN_PP3300_U, PIN(G, 3))
UNIMPLEMENTED_GPIO(EC_SPI_FLASH_MOSI, PIN(G, 4))
UNIMPLEMENTED_GPIO(EC_SPI_FLASH_MISO, PIN(G, 5))
UNIMPLEMENTED_GPIO(EC_SPI_FLASH_CLK, PIN(G, 6))
@ -151,7 +159,6 @@ UNIMPLEMENTED_GPIO(UART1_TX, PIN(B, 1)) /* UART_EC_TX_DEBUG_RX */
UNIMPLEMENTED_GPIO(EN_PP5000_USB_A0_VBUS, PIN(B, 7))
UNIMPLEMENTED_GPIO(CCD_MODE_ODL, PIN(C, 4))
UNIMPLEMENTED_GPIO(X_EC_GPIO2, PIN(B, 2))
UNIMPLEMENTED_GPIO(EN_PP5000_S5, PIN(C, 6))
UNIMPLEMENTED_GPIO(EC_BL_EN_OD, PIN(B, 5))
UNIMPLEMENTED_GPIO(CLK_EC_RTC_32K, PIN(J, 6))

View File

@ -1070,6 +1070,7 @@
#undef CONFIG_CHIPSET_JASPERLAKE /* Intel Jasperlake (x86) */
#undef CONFIG_CHIPSET_MT817X /* MediaTek MT817x */
#undef CONFIG_CHIPSET_MT8183 /* MediaTek MT8183 */
#undef CONFIG_CHIPSET_MT8192 /* MediaTek MT8192 */
#undef CONFIG_CHIPSET_RK3288 /* Rockchip rk3288 */
#undef CONFIG_CHIPSET_RK3399 /* Rockchip rk3399 */
#undef CONFIG_CHIPSET_SKYLAKE /* Intel Skylake (x86) */
@ -4937,6 +4938,7 @@
#undef CONFIG_CHIPSET_JASPERLAKE
#undef CONFIG_CHIPSET_MT817X
#undef CONFIG_CHIPSET_MT8183
#undef CONFIG_CHIPSET_MT8192
#undef CONFIG_CHIPSET_RK3399
#undef CONFIG_CHIPSET_RK3288
#undef CONFIG_CHIPSET_SDM845

View File

@ -15,6 +15,7 @@ power-$(CONFIG_CHIPSET_ECDRIVEN)+=ec_driven.o
power-$(CONFIG_CHIPSET_ICELAKE)+=icelake.o intel_x86.o
power-$(CONFIG_CHIPSET_MT817X)+=mt817x.o
power-$(CONFIG_CHIPSET_MT8183)+=mt8183.o
power-$(CONFIG_CHIPSET_MT8192)+=mt8192.o
power-$(CONFIG_CHIPSET_RK3288)+=rk3288.o
power-$(CONFIG_CHIPSET_RK3399)+=rk3399.o
power-$(CONFIG_CHIPSET_SC7180)+=sc7180.o

454
power/mt8192.c Normal file
View File

@ -0,0 +1,454 @@
/* Copyright 2020 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.
*/
/*
* MT8192 SoC power sequencing module for Chrome EC
*
* This implements the following features:
*
* - Cold reset powers on the AP
*
* When powered off:
* - Press power button turns on the AP
* - Hold power button turns on the AP, and then 8s later turns it off and
* leaves it off until pwron is released and press again.
* - Lid open turns on the AP
*
* When powered on:
* - Holding power button for 8s powers off the AP
* - Pressing and releaseing pwron within that 8s is ignored
*/
#include "battery.h"
#include "chipset.h"
#include "common.h"
#include "hooks.h"
#include "lid_switch.h"
#include "power.h"
#include "power_button.h"
#include "system.h"
#include "task.h"
#include "timer.h"
#ifdef CONFIG_BRINGUP
#define GPIO_SET_LEVEL(signal, value) \
gpio_set_level_verbose(CC_CHIPSET, signal, value)
#else
#define GPIO_SET_LEVEL(signal, value) gpio_set_level(signal, value)
#endif
/* Console output macros */
#define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ##args)
/* Input state flags */
#define IN_SUSPEND_ASSERTED POWER_SIGNAL_MASK(AP_IN_S3_L)
#define IN_PGOOD_PMIC POWER_SIGNAL_MASK(PMIC_PWR_GOOD)
#define IN_AP_WDT_ASSERTED POWER_SIGNAL_MASK(AP_WDT_ASSERTED)
/* Rails required for S3 and S0 */
#define IN_PGOOD_S0 (IN_PGOOD_PMIC)
#define IN_PGOOD_S3 (IN_PGOOD_PMIC)
/* All inputs in the right state for S0 */
#define IN_ALL_S0 (IN_PGOOD_S0 & ~IN_SUSPEND_ASSERTED)
/* Long power key press to force shutdown in S0. go/crosdebug */
#define FORCED_SHUTDOWN_DELAY (8 * SECOND)
/* Long power key press to boot from S5/G3 state. */
#ifndef POWERBTN_BOOT_DELAY
#define POWERBTN_BOOT_DELAY (10 * MSEC)
#endif
#define PMIC_EN_PULSE_MS 50
/* Maximum time it should for PMIC to turn on after toggling PMIC_EN_ODL. */
#define PMIC_EN_TIMEOUT (300 * MSEC)
/* Time delay in G3 to deassert EN_PP1800_S5_L */
#define EN_PP1800_S5_L_DEASSERT_TIME (20 * MSEC)
/*
* Time delay for AP on/off the AP_EC_WDT when received SYS_RST_ODL.
* Generally it can be done within 3 ms.
*/
#define AP_EC_WDT_TIMEOUT (100 * MSEC)
/* 30 ms for hard reset, we hold it longer to prevent TPM false alarm. */
#define SYS_RST_PULSE_LENGTH (50 * MSEC)
static int forcing_shutdown;
static void watchdog_interrupt_deferred(void)
{
chipset_reset(CHIPSET_RESET_AP_WATCHDOG);
}
DECLARE_DEFERRED(watchdog_interrupt_deferred);
static void reset_request_interrupt_deferred(void)
{
chipset_reset(CHIPSET_RESET_AP_REQ);
}
DECLARE_DEFERRED(reset_request_interrupt_deferred);
void chipset_reset_request_interrupt(enum gpio_signal signal)
{
hook_call_deferred(&reset_request_interrupt_deferred_data, 0);
}
/*
* Triggers on falling edge of AP watchdog line only. The falling edge can
* happen in these 3 cases:
* - AP asserts watchdog while the AP is on: this is a real AP-initiated reset.
* - EC asserted GPIO_SYS_RST_ODL, so the AP is in reset and AP watchdog falls
* as well. This is _not_ a watchdog reset. We mask these cases by disabling
* the interrupt just before shutting down the AP, and re-enabling it just
* after starting the AP.
* - PMIC has shut down (e.g. the AP powered off by itself), this is not a
* watchdog reset either. This should be covered by the case above if the
* EC reacts quickly enough, but we mask those cases as well by testing if
* the PMIC is still on when the watchdog line falls.
*/
void chipset_watchdog_interrupt(enum gpio_signal signal)
{
/* Pass AP_EC_WATCHDOG_L signal to PMIC */
GPIO_SET_LEVEL(GPIO_EC_PMIC_WATCHDOG_L, gpio_get_level(signal));
/* Update power signals */
power_signal_interrupt(signal);
/*
* case 1: PMIC is good, WDT asserts, and EC is not asserting
* SYS_RST_ODL. This is AP initiated real WDT.
*/
if (gpio_get_level(GPIO_SYS_RST_ODL) &&
power_get_signals() & IN_PGOOD_PMIC &&
power_get_signals() & IN_AP_WDT_ASSERTED)
hook_call_deferred(&watchdog_interrupt_deferred_data, 0);
/*
* case 2&3: Fall through. The chipset_reset should have been
* invoked.
*/
}
void chipset_force_shutdown(enum chipset_shutdown_reason reason)
{
CPRINTS("%s(%d)", __func__, reason);
report_ap_reset(reason);
/*
* Force power off. This condition will reset once the state machine
* transitions to G3.
*/
forcing_shutdown = 1;
task_wake(TASK_ID_CHIPSET);
}
void chipset_force_shutdown_button(void)
{
chipset_force_shutdown(CHIPSET_SHUTDOWN_BUTTON);
}
DECLARE_DEFERRED(chipset_force_shutdown_button);
void chipset_exit_hard_off_button(void)
{
/* Power up from off */
forcing_shutdown = 0;
chipset_exit_hard_off();
}
DECLARE_DEFERRED(chipset_exit_hard_off_button);
void chipset_reset(enum chipset_reset_reason reason)
{
CPRINTS("%s: %d", __func__, reason);
report_ap_reset(reason);
GPIO_SET_LEVEL(GPIO_SYS_RST_ODL, 0);
usleep(SYS_RST_PULSE_LENGTH);
GPIO_SET_LEVEL(GPIO_SYS_RST_ODL, 1);
}
enum power_state power_chipset_init(void)
{
/* Enable reboot / sleep control inputs from AP */
gpio_enable_interrupt(GPIO_AP_EC_WARM_RST_REQ);
gpio_enable_interrupt(GPIO_AP_IN_SLEEP_L);
if (system_get_reset_flags() & EC_RESET_FLAG_SYSJUMP) {
if ((power_get_signals() & IN_ALL_S0) == IN_ALL_S0) {
disable_sleep(SLEEP_MASK_AP_RUN);
power_signal_enable_interrupt(GPIO_AP_EC_WATCHDOG_L);
CPRINTS("already in S0");
return POWER_S0;
}
} else if (system_get_reset_flags() & EC_RESET_FLAG_AP_OFF) {
/* Force shutdown from S5 if the PMIC is already up. */
if (power_get_signals() & IN_PGOOD_PMIC) {
forcing_shutdown = 1;
return POWER_S5;
}
}
if (battery_is_present() == BP_YES)
/*
* (crosbug.com/p/28289): Wait battery stable.
* Some batteries use clock stretching feature, which requires
* more time to be stable.
*/
battery_wait_for_stable();
if (!(system_get_reset_flags() & EC_RESET_FLAG_AP_OFF))
/* Auto-power on */
chipset_exit_hard_off();
/* Start from S5 if the PMIC is already up. */
if (power_get_signals() & IN_PGOOD_PMIC)
return POWER_S5;
return POWER_G3;
}
enum power_state power_handle_state(enum power_state state)
{
/* Retry S5->S3 transition, if not zero. */
static int s5s3_retry;
/*
* PMIC power went away (AP most likely decided to shut down):
* transition to S5, G3.
*/
static int ap_shutdown;
switch (state) {
case POWER_G3:
/* Go back to S5->G3 if the PMIC unexpectedly starts again. */
if (power_get_signals() & IN_PGOOD_PMIC)
return POWER_S5G3;
break;
case POWER_S5:
/*
* If AP initiated shutdown, PMIC is off, and we can transition
* to G3 immediately.
*/
if (ap_shutdown) {
ap_shutdown = 0;
return POWER_S5G3;
} else if (!forcing_shutdown) {
/* Powering up. */
s5s3_retry = 1;
return POWER_S5S3;
}
/* Forcing shutdown */
/* Long press has worked, transition to G3. */
if (!(power_get_signals() & IN_PGOOD_PMIC))
return POWER_S5G3;
/*
* Try to force PMIC shutdown with a long press. This takes 8s,
* shorter than the common code S5->G3 timeout (10s).
*
* Note: We might run twice at this line because we
* deasserts SYS_RST_ODL in S5->S3 and then WDT interrupt
* handler sets the wake event for chipset_task. This should be
* no harm, but to prevent misunderstanding in the console, we
* check EC_PMIC_EN_ODL before set.
*/
if (gpio_get_level(GPIO_EC_PMIC_EN_ODL)) {
CPRINTS("Forcing shutdown with long press.");
GPIO_SET_LEVEL(GPIO_EC_PMIC_EN_ODL, 0);
}
/*
* Stay in S5, common code will drop to G3 after timeout
* if the long press does not work.
*/
return POWER_S5;
case POWER_S3:
if (!power_has_signals(IN_PGOOD_S3) || forcing_shutdown)
return POWER_S3S5;
else if (!(power_get_signals() & IN_SUSPEND_ASSERTED))
return POWER_S3S0;
break;
case POWER_S0:
if (!power_has_signals(IN_PGOOD_S0) || forcing_shutdown ||
power_get_signals() & IN_SUSPEND_ASSERTED)
return POWER_S0S3;
break;
case POWER_G3S5:
forcing_shutdown = 0;
GPIO_SET_LEVEL(GPIO_EN_PP5000_A, 1);
/* Power up to next state */
return POWER_S5;
case POWER_S5S3:
hook_notify(HOOK_CHIPSET_PRE_INIT);
/*
* Release power button in case it was pressed by force shutdown
* sequence.
*/
GPIO_SET_LEVEL(GPIO_EC_PMIC_EN_ODL, 1);
/* If PMIC is off, switch it on by pulsing PMIC enable. */
if (!(power_get_signals() & IN_PGOOD_PMIC)) {
msleep(PMIC_EN_PULSE_MS);
GPIO_SET_LEVEL(GPIO_EC_PMIC_EN_ODL, 0);
msleep(PMIC_EN_PULSE_MS);
GPIO_SET_LEVEL(GPIO_EC_PMIC_EN_ODL, 1);
}
/*
* Wait for PMIC to bring up rails. Retry if it fails
* (it may take 2 attempts on restart after we use
* force reset).
*/
if (power_wait_signals_timeout(IN_PGOOD_PMIC,
PMIC_EN_TIMEOUT)) {
if (s5s3_retry) {
s5s3_retry = 0;
return POWER_S5S3;
}
/* Give up, go back to G3. */
return POWER_S5G3;
}
GPIO_SET_LEVEL(GPIO_EN_PP1800_U, 1);
GPIO_SET_LEVEL(GPIO_EN_PP3300_U, 1);
/* Release AP reset and waits for AP pulling WDT up. */
power_signal_enable_interrupt(GPIO_AP_EC_WATCHDOG_L);
GPIO_SET_LEVEL(GPIO_SYS_RST_ODL, 1);
if (power_wait_mask_signals_timeout(0, IN_AP_WDT_ASSERTED,
AP_EC_WDT_TIMEOUT)) {
if (s5s3_retry) {
s5s3_retry = 0;
return POWER_S5S3;
}
/* Give up, go back to G3. */
return POWER_S5G3;
}
/* Call hooks now that rails are up */
hook_notify(HOOK_CHIPSET_STARTUP);
/* Power up to next state */
return POWER_S3;
case POWER_S3S0:
if (power_wait_signals(IN_PGOOD_S0)) {
chipset_force_shutdown(CHIPSET_SHUTDOWN_WAIT);
return POWER_S0S3;
}
/* Call hooks now that rails are up */
hook_notify(HOOK_CHIPSET_RESUME);
/*
* Disable idle task deep sleep. This means that the low
* power idle task will not go into deep sleep while in S0.
*/
disable_sleep(SLEEP_MASK_AP_RUN);
/* Power up to next state */
return POWER_S0;
case POWER_S0S3:
/* Call hooks before we remove power rails */
hook_notify(HOOK_CHIPSET_SUSPEND);
/*
* Enable idle task deep sleep. Allow the low power idle task
* to go into deep sleep in S3 or lower.
*/
enable_sleep(SLEEP_MASK_AP_RUN);
/*
* In case the power button is held awaiting power-off timeout,
* power off immediately now that we're entering S3.
*/
if (power_button_is_pressed()) {
forcing_shutdown = 1;
hook_call_deferred(&chipset_force_shutdown_button_data,
-1);
}
return POWER_S3;
case POWER_S3S5:
/* PMIC has shutdown, transition to G3. */
if (!(power_get_signals() & IN_PGOOD_PMIC))
ap_shutdown = 1;
/* Call hooks before we remove power rails */
hook_notify(HOOK_CHIPSET_SHUTDOWN);
/*
* Assert SYS_RST_ODL, and waits for AP finishing epilogue and
* asserting WDT.
*/
GPIO_SET_LEVEL(GPIO_SYS_RST_ODL, 0);
if (EC_ERROR_TIMEOUT ==
power_wait_signals_timeout(IN_AP_WDT_ASSERTED,
AP_EC_WDT_TIMEOUT)) {
CPRINTS("Timeout waitting AP watchdog, force if off");
GPIO_SET_LEVEL(GPIO_EC_PMIC_WATCHDOG_L, 0);
}
power_signal_disable_interrupt(GPIO_AP_EC_WATCHDOG_L);
GPIO_SET_LEVEL(GPIO_EN_PP1800_U, 0);
GPIO_SET_LEVEL(GPIO_EN_PP3300_U, 0);
/* Start shutting down */
return POWER_S5;
case POWER_S5G3:
/* Release the power button, in case it was long pressed. */
if (forcing_shutdown)
GPIO_SET_LEVEL(GPIO_EC_PMIC_EN_ODL, 1);
GPIO_SET_LEVEL(GPIO_EN_PP5000_A, 0);
return POWER_G3;
}
return state;
}
static void power_button_changed(void)
{
if (power_button_is_pressed()) {
if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
hook_call_deferred(&chipset_exit_hard_off_button_data,
POWERBTN_BOOT_DELAY);
/* Delayed power down from S0/S3, cancel on PB release */
hook_call_deferred(&chipset_force_shutdown_button_data,
FORCED_SHUTDOWN_DELAY);
} else {
/* Power button released, cancel deferred shutdown/boot */
hook_call_deferred(&chipset_exit_hard_off_button_data, -1);
hook_call_deferred(&chipset_force_shutdown_button_data, -1);
}
}
DECLARE_HOOK(HOOK_POWER_BUTTON_CHANGE, power_button_changed, HOOK_PRIO_DEFAULT);
#ifdef CONFIG_LID_SWITCH
static void lid_changed(void)
{
/* Power-up from off on lid open */
if (lid_is_open() && chipset_in_state(CHIPSET_STATE_ANY_OFF))
chipset_exit_hard_off();
}
DECLARE_HOOK(HOOK_LID_CHANGE, lid_changed, HOOK_PRIO_DEFAULT);
#endif