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>
This commit is contained in:
Duncan Laurie
2016-01-20 16:23:43 -08:00
committed by chrome-bot
parent ebd29d4557
commit bbe2d886dc
2 changed files with 72 additions and 32 deletions

View File

@@ -257,6 +257,9 @@
/*****************************************************************************/
/* EC has GPIOs to allow board to reset RTC */
#undef CONFIG_BOARD_HAS_RTC_RESET
/*
* Call board_config_post_gpio_init() after GPIOs are initialized. See
* include/board_config.h for more information.

View File

@@ -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;