summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWai-Hong Tam <waihong@google.com>2020-06-17 14:58:27 -0700
committerCommit Bot <commit-bot@chromium.org>2020-06-18 05:19:07 +0000
commit3bb7d7b0e62a5845ba137446b4083c32a83240c9 (patch)
treefabdedaba68769af8daa61c15a4f01ae6b09db62
parent9397f9357992b8719eb42054d0bf1e75a96cfd12 (diff)
downloadchrome-ec-3bb7d7b0e62a5845ba137446b4083c32a83240c9.tar.gz
sc7180: Handle the exception cases of power on
Make the switchcap and PMIC functions return a success or error code. In the power on sequence, an error happening in the middle will make it skip the remaining steps, and then calls the power off sequence to restore back S5. The power off sequence don't care about any error and perform the entire procedure. BRANCH=None BUG=b:159101052 TEST=Manually trigger power on and power off. TEST=Forced to a switchcap error, it went back to S5. > gpioset DA9313_GPIO0 0 > power on Requesting power on > RTC: 0x5ed1d4a7 (1590809767.00 s) [7177.018477 power state 4 = G3->S5, in 0x0005] RTC: 0x5ed1d4a7 (1590809767.00 s) [7177.019409 power state 1 = S5, in 0x0005] [7177.019918 power on 4] RTC: 0x5ed1d4a7 (1590809767.00 s) [7177.021168 power state 5 = S5->S3, in 0x0005] [7177.021700 power button released in time] [7177.024143 set_system_power(1)] [7177.076708 SWITCHCAP NO POWER GOOD!] [7177.187407 set_system_power(0)] RTC: 0x5ed1d4a7 (1590809767.00 s) [7177.188564 power state 1 = S5, in 0x0005] Change-Id: Iaf2676d84513056b3a1deb4f4c554c607e588c37 Signed-off-by: Wai-Hong Tam <waihong@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2250668 Reviewed-by: Alexandru M Stan <amstan@chromium.org> Reviewed-by: Stephen Boyd <swboyd@chromium.org>
-rw-r--r--power/sc7180.c104
1 files changed, 69 insertions, 35 deletions
diff --git a/power/sc7180.c b/power/sc7180.c
index dfd9b192fd..0af461e680 100644
--- a/power/sc7180.c
+++ b/power/sc7180.c
@@ -250,9 +250,11 @@ DECLARE_HOOK(HOOK_POWER_BUTTON_CHANGE, sc7180_powerbtn_changed,
* GPIO0 is configured as PVC_PG.
*
* @param enable 1 to wait the PMIC/AP on.
- 0 to wait the PMIC/AP off.
+ * 0 to wait the PMIC/AP off.
+ *
+ * @return EC_SUCCESS or error
*/
-static void wait_switchcap_power_good(int enable)
+static int wait_switchcap_power_good(int enable)
{
timestamp_t poll_deadline;
@@ -272,8 +274,9 @@ static void wait_switchcap_power_good(int enable)
CPRINTS("SWITCHCAP NO POWER GOOD!");
else
CPRINTS("SWITCHCAP STILL POWER GOOD!");
+ return EC_ERROR_UNKNOWN;
}
-
+ return EC_SUCCESS;
}
/**
@@ -304,16 +307,18 @@ static int is_pmic_pwron(void)
* Wait the PMIC/AP power-on state.
*
* @param enable 1 to wait the PMIC/AP on.
- 0 to wait the PMIC/AP off.
+ * 0 to wait the PMIC/AP off.
* @param timeout Number of microsecond of timeout.
+ *
+ * @return EC_SUCCESS or error
*/
-static void wait_pmic_pwron(int enable, unsigned int timeout)
+static int wait_pmic_pwron(int enable, unsigned int timeout)
{
timestamp_t poll_deadline;
/* Check the AP power status */
if (enable == is_pmic_pwron())
- return;
+ return EC_SUCCESS;
poll_deadline = get_time();
poll_deadline.val += timeout;
@@ -328,7 +333,10 @@ static void wait_pmic_pwron(int enable, unsigned int timeout)
CPRINTS("AP POWER NOT READY!");
else
CPRINTS("AP POWER STILL UP!");
+
+ return EC_ERROR_UNKNOWN;
}
+ return EC_SUCCESS;
}
/**
@@ -351,18 +359,25 @@ static void set_system_power_no_check(int enable)
* They control the power of the set of PMIC chips and the AP.
*
* @param enable 1 to enable or 0 to disable
+ *
+ * @return EC_SUCCESS or error
*/
-static void set_system_power(int enable)
+static int set_system_power(int enable)
{
+ int ret;
+
CPRINTS("%s(%d)", __func__, enable);
set_system_power_no_check(enable);
- wait_switchcap_power_good(enable);
+
+ ret = wait_switchcap_power_good(enable);
+
if (enable) {
usleep(SYSTEM_POWER_ON_DELAY);
} else {
/* Ensure POWER_GOOD drop to low if it is a forced shutdown */
- wait_pmic_pwron(0, FORCE_OFF_RESPONSE_TIMEOUT);
+ ret |= wait_pmic_pwron(0, FORCE_OFF_RESPONSE_TIMEOUT);
}
+ return ret;
}
/**
@@ -371,15 +386,19 @@ static void set_system_power(int enable)
* It triggers the PMIC/AP power-on and power-off sequence.
*
* @param enable 1 to power the PMIC/AP on.
- 0 to power the PMIC/AP off.
+ * 0 to power the PMIC/AP off.
+ *
+ * @return EC_SUCCESS or error
*/
-static void set_pmic_pwron(int enable)
+static int set_pmic_pwron(int enable)
{
+ int ret;
+
CPRINTS("%s(%d)", __func__, enable);
/* Check the PMIC/AP power state */
if (enable == is_pmic_pwron())
- return;
+ return EC_SUCCESS;
/*
* Power-on sequence:
@@ -404,10 +423,12 @@ static void set_pmic_pwron(int enable)
gpio_set_level(GPIO_PMIC_KPD_PWR_ODL, 0);
if (!enable)
gpio_set_level(GPIO_PM845_RESIN_L, 0);
- wait_pmic_pwron(enable, PMIC_POWER_AP_RESPONSE_TIMEOUT);
+ ret = wait_pmic_pwron(enable, PMIC_POWER_AP_RESPONSE_TIMEOUT);
gpio_set_level(GPIO_PMIC_KPD_PWR_ODL, 1);
if (!enable)
gpio_set_level(GPIO_PM845_RESIN_L, 1);
+
+ return ret;
}
enum power_state power_chipset_init(void)
@@ -467,20 +488,25 @@ enum power_state power_chipset_init(void)
*/
static void power_off(void)
{
- /* Check the power off status */
- if (!is_system_powered())
- return;
-
- /* Do a graceful way to shutdown PMIC/AP first */
- set_pmic_pwron(0);
- usleep(PMIC_POWER_OFF_DELAY);
+ /* Check PMIC POWER_GOOD */
+ if (is_pmic_pwron()) {
+ /* Do a graceful way to shutdown PMIC/AP first */
+ set_pmic_pwron(0);
+ usleep(PMIC_POWER_OFF_DELAY);
- /* Disable signal interrupts, as they are floating when switchcap off */
- power_signal_disable_interrupt(GPIO_AP_RST_L);
- power_signal_disable_interrupt(GPIO_PMIC_FAULT_L);
+ /*
+ * Disable signal interrupts, as they are floating when
+ * switchcap off.
+ */
+ power_signal_disable_interrupt(GPIO_AP_RST_L);
+ power_signal_disable_interrupt(GPIO_PMIC_FAULT_L);
+ }
- /* Force to switch off all rails */
- set_system_power(0);
+ /* Check the switchcap status */
+ if (is_system_powered()) {
+ /* Force to switch off all rails */
+ set_system_power(0);
+ }
/* Turn off the 3.3V and 5V rails. */
gpio_set_level(GPIO_EN_PP3300_A, 0);
@@ -519,9 +545,13 @@ static int power_is_enough(void)
/**
* Power on the AP
+ *
+ * @return EC_SUCCESS or error
*/
-static void power_on(void)
+static int power_on(void)
{
+ int ret;
+
/* Enable the 3.3V and 5V rail. */
gpio_set_level(GPIO_EN_PP3300_A, 1);
#ifdef CONFIG_POWER_PP5000_CONTROL
@@ -530,15 +560,23 @@ static void power_on(void)
gpio_set_level(GPIO_EN_PP5000, 1);
#endif /* defined(CONFIG_POWER_PP5000_CONTROL) */
- set_system_power(1);
+ ret = set_system_power(1);
+ if (ret != EC_SUCCESS)
+ return ret;
/* Enable signal interrupts */
power_signal_enable_interrupt(GPIO_AP_RST_L);
power_signal_enable_interrupt(GPIO_PMIC_FAULT_L);
- set_pmic_pwron(1);
+ ret = set_pmic_pwron(1);
+ if (ret != EC_SUCCESS) {
+ CPRINTS("POWER_GOOD not seen in time");
+ return ret;
+ }
+ CPRINTS("POWER_GOOD seen");
disable_sleep(SLEEP_MASK_AP_RUN);
+ return EC_SUCCESS;
}
/**
@@ -742,16 +780,12 @@ enum power_state power_handle_state(enum power_state state)
/* Initialize components to ready state before AP is up. */
hook_notify(HOOK_CHIPSET_PRE_INIT);
- power_on();
- CPRINTS("AP running ...");
-
- if (power_wait_signals(IN_POWER_GOOD) != EC_SUCCESS) {
- CPRINTS("POWER_GOOD not seen in time");
- set_system_power(0);
+ if (power_on() != EC_SUCCESS) {
+ power_off();
return POWER_S5;
}
+ CPRINTS("AP running ...");
- CPRINTS("POWER_GOOD seen");
/* Call hooks now that AP is running */
hook_notify(HOOK_CHIPSET_STARTUP);
return POWER_S3;