summaryrefslogtreecommitdiff
path: root/power/mt8183.c
diff options
context:
space:
mode:
Diffstat (limited to 'power/mt8183.c')
-rw-r--r--power/mt8183.c639
1 files changed, 0 insertions, 639 deletions
diff --git a/power/mt8183.c b/power/mt8183.c
deleted file mode 100644
index bdbd319601..0000000000
--- a/power/mt8183.c
+++ /dev/null
@@ -1,639 +0,0 @@
-/* Copyright 2018 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.
- */
-
-/* mt8183 chipset power control module for Chrome EC */
-
-#include "charge_state.h"
-#include "chipset.h"
-#include "common.h"
-#include "console.h"
-#include "ec_commands.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "lid_switch.h"
-#include "power.h"
-#include "power_button.h"
-#include "system.h"
-#include "task.h"
-#include "timer.h"
-#include "util.h"
-
-/*
- * mt8183 has two different power sequence versions
- * 0: for normal tablet and detachable form factor
- * 1: for boards have GPIO_EN_PP1800_S5_L
- * CONFIG_CHIPSET_POWER_SEQ_VERSION defaults to 0, re-define the power seq
- * version if needed.
- */
-
-/* Console output macros */
-#define CPUTS(outstr) cputs(CC_CHIPSET, outstr)
-#define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ## args)
-
-/* Input state flags */
-#define IN_PGOOD_PMIC POWER_SIGNAL_MASK(PMIC_PWR_GOOD)
-#define IN_SUSPEND_ASSERTED POWER_SIGNAL_MASK(AP_IN_S3_L)
-
-/* 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 */
-#ifdef VARIANT_KUKUI_JACUZZI
-#define FORCED_SHUTDOWN_DELAY (8 * SECOND)
-#else
-#define FORCED_SHUTDOWN_DELAY (10 * SECOND)
-#endif
-
-/* Long power key press to boot from S5/G3 state. */
-#ifndef POWERBTN_BOOT_DELAY
-#define POWERBTN_BOOT_DELAY (1 * SECOND)
-#endif
-
-#define CHARGER_INITIALIZED_DELAY_MS 100
-#define CHARGER_INITIALIZED_TRIES 40
-
-#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)
-
-/*
- * Amount of time we need to hold PMIC_FORCE_RESET_ODL to ensure PMIC is really
- * off and will not restart on its own.
- */
-#define PMIC_FORCE_RESET_TIME (10 * SECOND)
-
-/* Time delay in G3 to deassert EN_PP1800_S5_L */
-#define EN_PP1800_S5_L_DEASSERT_TIME (20 * MSEC)
-
-/* Data structure for a GPIO operation for power sequencing */
-struct power_seq_op {
- /* enum gpio_signal in 8 bits */
- uint8_t signal;
- uint8_t level;
- /* Number of milliseconds to delay after setting signal to level */
- uint8_t delay;
-};
-BUILD_ASSERT(GPIO_COUNT < 256);
-
-/*
- * This is the power sequence for POWER_S5S3.
- * The entries in the table are handled sequentially from the top
- * to the bottom.
- */
-
-static const struct power_seq_op s5s3_power_seq[] = {
- /* Release PMIC watchdog. */
- { GPIO_PMIC_WATCHDOG_L, 1, 0 },
- /* Turn on AP. */
- { GPIO_AP_SYS_RST_L, 1, 2 },
-};
-
-/* The power sequence for POWER_S3S0 */
-static const struct power_seq_op s3s0_power_seq[] = {
-};
-
-/* The power sequence for POWER_S0S3 */
-static const struct power_seq_op s0s3_power_seq[] = {
-};
-
-/* The power sequence for POWER_S3S5 */
-static const struct power_seq_op s3s5_power_seq[] = {
- /* Turn off AP. */
- { GPIO_AP_SYS_RST_L, 0, 0 },
- /* Assert watchdog to PMIC (there may be a 1.6ms debounce) */
- { GPIO_PMIC_WATCHDOG_L, 0, 3 },
-};
-
-static int forcing_shutdown;
-static int boot_from_cutoff;
-
-void chipset_reset_request_interrupt(enum gpio_signal signal)
-{
- chipset_reset(CHIPSET_RESET_AP_REQ);
-}
-
-/*
- * 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_AP_SYS_RST_L, 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)
-{
- if (power_get_signals() & IN_PGOOD_PMIC)
- chipset_reset(CHIPSET_RESET_AP_WATCHDOG);
-}
-
-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);
-
-#ifdef CONFIG_POWER_TRACK_HOST_SLEEP_STATE
-static void power_reset_host_sleep_state(void)
-{
- power_set_host_sleep_state(HOST_SLEEP_EVENT_DEFAULT_RESET);
- sleep_reset_tracking();
- power_chipset_handle_host_sleep_event(HOST_SLEEP_EVENT_DEFAULT_RESET,
- NULL);
-}
-
-static void handle_chipset_reset(void)
-{
- if (chipset_in_state(CHIPSET_STATE_SUSPEND)) {
- CPRINTS("Chipset reset: exit s3");
- power_reset_host_sleep_state();
- task_wake(TASK_ID_CHIPSET);
- }
-}
-DECLARE_HOOK(HOOK_CHIPSET_RESET, handle_chipset_reset, HOOK_PRIO_FIRST);
-#endif /* CONFIG_POWER_TRACK_HOST_SLEEP_STATE */
-
-/* If chipset needs to be reset, EC also reboots to RO. */
-void chipset_reset(enum chipset_reset_reason reason)
-{
- int flags = SYSTEM_RESET_HARD;
-
- CPRINTS("%s: %d", __func__, reason);
- report_ap_reset(reason);
-
- cflush();
- if (reason == CHIPSET_RESET_AP_WATCHDOG)
- flags |= SYSTEM_RESET_AP_WATCHDOG;
-
- system_reset(flags);
-
- /* This should not be reachable. */
- while (1)
- ;
-}
-
-enum power_state power_chipset_init(void)
-{
- /* Enable reboot / sleep control inputs from AP */
- gpio_enable_interrupt(GPIO_WARM_RESET_REQ);
- gpio_enable_interrupt(GPIO_AP_IN_SLEEP_L);
-
- if (system_jumped_to_this_image()) {
- if ((power_get_signals() & IN_ALL_S0) == IN_ALL_S0) {
- disable_sleep(SLEEP_MASK_AP_RUN);
- gpio_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;
- }
- } else {
- /* Auto-power on */
- chipset_exit_hard_off();
-
- if (system_get_reset_flags() == EC_RESET_FLAG_RESET_PIN)
- boot_from_cutoff = 1;
- }
-
- /* Start from S5 if the PMIC is already up. */
- if (power_get_signals() & IN_PGOOD_PMIC)
- return POWER_S5;
-
- return POWER_G3;
-}
-
-/*
- * If we have to force reset the PMIC, we only need to do so for a few seconds,
- * then we need to release the GPIO to prevent leakage in G3.
- */
-static void release_pmic_force_reset(void)
-{
- CPRINTS("Releasing PMIC force reset");
- gpio_set_level(GPIO_PMIC_FORCE_RESET_ODL, 1);
-}
-DECLARE_DEFERRED(release_pmic_force_reset);
-
-/**
- * Step through the power sequence table and do corresponding GPIO operations.
- *
- * @param power_seq_ops The pointer to the power sequence table.
- * @param op_count The number of entries of power_seq_ops.
- */
-static void power_seq_run(const struct power_seq_op *power_seq_ops,
- int op_count)
-{
- int i;
-
- for (i = 0; i < op_count; i++) {
- gpio_set_level(power_seq_ops[i].signal,
- power_seq_ops[i].level);
- if (!power_seq_ops[i].delay)
- continue;
- msleep(power_seq_ops[i].delay);
- }
-}
-
-#if CONFIG_CHIPSET_POWER_SEQ_VERSION == 1
-static void deassert_en_pp1800_s5_l(void)
-{
- gpio_set_level(GPIO_EN_PP1800_S5_L, 1);
-}
-DECLARE_DEFERRED(deassert_en_pp1800_s5_l);
-#endif
-
-enum power_state power_handle_state(enum power_state state)
-{
- /*
- * Set if we already had a rising edge on AP_SYS_RST_L. If so, any
- * subsequent boot attempt will require an EC reset.
- */
- static int booted;
-
- /* 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;
- uint16_t tries = 0;
-
- switch (state) {
- case POWER_G3:
-
-#if CONFIG_CHIPSET_POWER_SEQ_VERSION == 1
- hook_call_deferred(&deassert_en_pp1800_s5_l_data,
- EN_PP1800_S5_L_DEASSERT_TIME);
-#endif
-
- /* 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:
- boot_from_cutoff = 0;
-
- /*
- * 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).
- */
- CPRINTS("Forcing shutdown with long press.");
- gpio_set_level(GPIO_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;
-
-#ifdef CONFIG_BATTERY_SMART
- /*
- * b:148045048: With the adapter to activate the smart battery
- * which is shutdown mode, will enable PMIC during activation
- * and have heavy loading, which will prevent the system from
- * powering on. Delay to boot system until the smart battry
- * is ready.
- */
- if (battery_hw_present() && boot_from_cutoff) {
- static int total_sleep_ms;
-
- if (total_sleep_ms < 4000) {
- msleep(10);
- total_sleep_ms += 10;
- return POWER_G3S5;
- }
- }
-#endif
-
- /*
- * Allow time for charger to be initialized, in case we're
- * trying to boot the AP with no battery.
- */
- while (charge_prevent_power_on(0) &&
- tries++ < CHARGER_INITIALIZED_TRIES) {
- msleep(CHARGER_INITIALIZED_DELAY_MS);
- }
-
- /* Return to G3 if battery level is too low. */
- if (charge_want_shutdown() ||
- tries > CHARGER_INITIALIZED_TRIES) {
- CPRINTS("power-up inhibited");
- chipset_force_shutdown(
- CHIPSET_SHUTDOWN_BATTERY_INHIBIT);
- return POWER_G3;
- }
-
-#if CONFIG_CHIPSET_POWER_SEQ_VERSION == 1
- hook_call_deferred(&deassert_en_pp1800_s5_l_data, -1);
-#endif
- hook_call_deferred(&release_pmic_force_reset_data, -1);
- gpio_set_level(GPIO_PMIC_FORCE_RESET_ODL, 1);
-#if CONFIG_CHIPSET_POWER_SEQ_VERSION == 1
- gpio_set_level(GPIO_EN_PP1800_S5_L, 0);
-#endif
-
- /* 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_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_PMIC_EN_ODL, 0);
- msleep(PMIC_EN_PULSE_MS);
- gpio_set_level(GPIO_PMIC_EN_ODL, 1);
- }
-
- /* If EC jumped, or has already booted once, reboot to RO. */
- if (system_jumped_to_this_image() || booted) {
- /*
- * TODO(b:109850749): How quickly does the EC come back
- * up? Would IN_PGOOD_PMIC be ready by the time we are
- * back? According to PMIC spec, it should take ~158 ms
- * after debounce (32 ms), minus PMIC_EN_PULSE_MS above.
- * It would be good to avoid another _EN pulse above.
- */
- chipset_reset(CHIPSET_RESET_AP_REQ);
- }
-
- /*
- * 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;
- }
-
- booted = 1;
- /* Enable S3 power supplies, release AP reset. */
- power_seq_run(s5s3_power_seq, ARRAY_SIZE(s5s3_power_seq));
- gpio_enable_interrupt(GPIO_AP_EC_WATCHDOG_L);
-
- /* Call hooks now that rails are up */
- hook_notify(HOOK_CHIPSET_STARTUP);
-
- /*
- * Clearing the sleep failure detection tracking on the path
- * to S0 to handle any reset conditions.
- */
-#ifdef CONFIG_POWER_SLEEP_FAILURE_DETECTION
- power_reset_host_sleep_state();
-#endif /* CONFIG_POWER_SLEEP_FAILURE_DETECTION */
-
- /* Power up to next state */
- return POWER_S3;
-
- case POWER_S3S0:
- power_seq_run(s3s0_power_seq, ARRAY_SIZE(s3s0_power_seq));
-
- 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);
-
-#ifdef CONFIG_POWER_SLEEP_FAILURE_DETECTION
- sleep_resume_transition();
-#endif /* CONFIG_POWER_SLEEP_FAILURE_DETECTION */
-
- /*
- * 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);
-
-#ifdef CONFIG_POWER_SLEEP_FAILURE_DETECTION
- sleep_suspend_transition();
-#endif /* CONFIG_POWER_SLEEP_FAILURE_DETECTION */
-
- /*
- * TODO(b:109850749): Check if we need some delay here to
- * "debounce" entering suspend (rk3399 uses 20ms delay).
- */
-
- power_seq_run(s0s3_power_seq, ARRAY_SIZE(s0s3_power_seq));
-
- /*
- * 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);
-
- gpio_disable_interrupt(GPIO_AP_EC_WATCHDOG_L);
- power_seq_run(s3s5_power_seq, ARRAY_SIZE(s3s5_power_seq));
-
- /* Call hooks after we remove power rails */
- hook_notify(HOOK_CHIPSET_SHUTDOWN_COMPLETE);
-
- /* 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_PMIC_EN_ODL, 1);
-
- /*
- * If PMIC is still not off, assert PMIC_FORCE_RESET_ODL.
- * This should only happen for forced shutdown where the AP is
- * not able to send a command to the PMIC, and where the long
- * power+home press did not work (if the PMIC is misconfigured).
- * Also, PMIC will lose RTC state, in that case.
- */
- if (power_get_signals() & IN_PGOOD_PMIC) {
- CPRINTS("Forcing PMIC off");
- gpio_set_level(GPIO_PMIC_FORCE_RESET_ODL, 0);
- msleep(5);
- hook_call_deferred(&release_pmic_force_reset_data,
- PMIC_FORCE_RESET_TIME);
-
- return POWER_S5G3;
- }
-
- return POWER_G3;
- }
-
- return state;
-}
-
-#ifdef CONFIG_POWER_TRACK_HOST_SLEEP_STATE
-static void suspend_hang_detected(void)
-{
- CPRINTS("Warning: Detected sleep hang! Waking host up!");
- host_set_single_event(EC_HOST_EVENT_HANG_DETECT);
-}
-
-__override void power_chipset_handle_host_sleep_event(
- enum host_sleep_event state,
- struct host_sleep_event_context *ctx)
-{
- CPRINTS("Handle sleep: %d", state);
-
- if (state == HOST_SLEEP_EVENT_S3_SUSPEND) {
- /*
- * Indicate to power state machine that a new host event for
- * S3 suspend has been received and so chipset suspend
- * notification needs to be sent to listeners.
- */
- sleep_set_notify(SLEEP_NOTIFY_SUSPEND);
- sleep_start_suspend(ctx, suspend_hang_detected);
-
- } else if (state == HOST_SLEEP_EVENT_S3_RESUME) {
- /*
- * Wake up chipset task and indicate to power state machine that
- * listeners need to be notified of chipset resume.
- */
- sleep_set_notify(SLEEP_NOTIFY_RESUME);
- task_wake(TASK_ID_CHIPSET);
- sleep_complete_resume(ctx);
-
- }
-}
-#endif /* CONFIG_POWER_TRACK_HOST_SLEEP_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