diff options
author | Duncan Laurie <dlaurie@chromium.org> | 2016-01-20 16:23:43 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-01-20 23:21:53 -0800 |
commit | bbe2d886dcd81e608d58f9cd945551ddd385f6d4 (patch) | |
tree | eb3ea00c8c62ccc47c715eef7702edf521ccc105 /power | |
parent | ebd29d455793d048daadc2dcfef7e26edee9d46b (diff) | |
download | chrome-ec-bbe2d886dcd81e608d58f9cd945551ddd385f6d4.tar.gz |
skylake: Add support for asserting RTCRST if power sequencing fails
In order to pulse RTC reset to the PCH when power sequencing exit fails we
need to watch for SLP_S4 to deassert and if it does not then assert RTCRST
using a board specific method. This is attempted up to 5 times before giving
up and staying in G3.
On skylake the RSMRST passthru needs to be honored when the task is woken up,
so while waiting call handle_rsmrst() if woken up early. This is needed
because it is RSMRST that actually tells the PCH to try and wake.
This is all wrapped in a config option and board specific method because not all
boards have a GPIO to control RTCRST and if they do they may not all use the
same method to assert it.
BUG=chrome-os-partner:49564
BRANCH=glados
TEST=manually tested on chell EVT:
First, ensure board sequences properly if everything is OK for a normal boot.
Next, modify handle_rsmrst() to not pass through the signal in order to
simulate being stuck in S5, and ensure that the EC attempts to assert RTCRST
and power up again 5 times before giving up and staying in G3.
Change-Id: Ia3c13069c92762b51beb682a19e5a074194a3c26
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/322724
Reviewed-by: Shawn N <shawnn@chromium.org>
Diffstat (limited to 'power')
-rw-r--r-- | power/skylake.c | 101 |
1 files changed, 69 insertions, 32 deletions
diff --git a/power/skylake.c b/power/skylake.c index c15c26d1f7..d149d0d873 100644 --- a/power/skylake.c +++ b/power/skylake.c @@ -130,6 +130,69 @@ enum power_state power_chipset_init(void) return POWER_G3; } +static void handle_rsmrst(enum power_state state) +{ + /* + * Pass through RSMRST asynchronously, as PCH may not react + * immediately to power changes. + */ + int rsmrst_in = gpio_get_level(GPIO_RSMRST_L_PGOOD); + int rsmrst_out = gpio_get_level(GPIO_PCH_RSMRST_L); + + /* Nothing to do. */ + if (rsmrst_in == rsmrst_out) + return; + /* + * Wait at least 10ms between power signals going high + * and deasserting RSMRST to PCH. + */ + if (rsmrst_in) + msleep(10); + gpio_set_level(GPIO_PCH_RSMRST_L, rsmrst_in); + CPRINTS("RSMRST: %d", rsmrst_in); +} + +static void handle_slp_sus(enum power_state state) +{ + /* If we're down or going down don't do anythin with SLP_SUS_L. */ + if (state == POWER_G3 || state == POWER_S5G3) + return; + + /* Always mimic PCH SLP_SUS request for all other states. */ + gpio_set_level(GPIO_PMIC_SLP_SUS_L, gpio_get_level(GPIO_PCH_SLP_SUS_L)); +} + +#ifdef CONFIG_BOARD_HAS_RTC_RESET +static enum power_state power_wait_s5_rtc_reset(void) +{ + static int s5_exit_tries; + + /* Wait for S5 exit and then attempt RTC reset */ + while ((power_get_signals() & IN_PCH_SLP_S4_DEASSERTED) == 0) { + /* Handle RSMRST passthru event while waiting */ + handle_rsmrst(POWER_S5); + if (task_wait_event(SECOND*4) == TASK_EVENT_TIMER) { + CPRINTS("timeout waiting for S5 exit"); + chipset_force_g3(); + + /* Assert RTCRST# and retry 5 times */ + board_rtc_reset(); + + if (++s5_exit_tries > 4) { + s5_exit_tries = 0; + return POWER_G3; /* Stay off */ + } + + udelay(10 * MSEC); + return POWER_G3S5; /* Power up again */ + } + } + + s5_exit_tries = 0; + return POWER_S5S3; /* Power up to next state */ +} +#endif + static enum power_state _power_handle_state(enum power_state state) { int tries = 0; @@ -143,8 +206,14 @@ static enum power_state _power_handle_state(enum power_state state) power_button_pch_release(); forcing_shutdown = 0; } + +#ifdef CONFIG_BOARD_HAS_RTC_RESET + /* Wait for S5 exit and attempt RTC reset it supported */ + return power_wait_s5_rtc_reset(); +#else if (gpio_get_level(GPIO_PCH_SLP_S4_L) == 1) return POWER_S5S3; /* Power up to next state */ +#endif break; case POWER_S3: @@ -325,38 +394,6 @@ static enum power_state _power_handle_state(enum power_state state) return state; } -static void handle_rsmrst(enum power_state state) -{ - /* - * Pass through RSMRST asynchronously, as PCH may not react - * immediately to power changes. - */ - int rsmrst_in = gpio_get_level(GPIO_RSMRST_L_PGOOD); - int rsmrst_out = gpio_get_level(GPIO_PCH_RSMRST_L); - - /* Nothing to do. */ - if (rsmrst_in == rsmrst_out) - return; - /* - * Wait at least 10ms between power signals going high - * and deasserting RSMRST to PCH. - */ - if (rsmrst_in) - msleep(10); - gpio_set_level(GPIO_PCH_RSMRST_L, rsmrst_in); - CPRINTS("RSMRST: %d", rsmrst_in); -} - -static void handle_slp_sus(enum power_state state) -{ - /* If we're down or going down don't do anythin with SLP_SUS_L. */ - if (state == POWER_G3 || state == POWER_S5G3) - return; - - /* Always mimic PCH SLP_SUS request for all other states. */ - gpio_set_level(GPIO_PMIC_SLP_SUS_L, gpio_get_level(GPIO_PCH_SLP_SUS_L)); -} - enum power_state power_handle_state(enum power_state state) { enum power_state new_state; |