summaryrefslogtreecommitdiff
path: root/power/skylake.c
diff options
context:
space:
mode:
authorDuncan Laurie <dlaurie@chromium.org>2016-01-20 16:23:43 -0800
committerchrome-bot <chrome-bot@chromium.org>2016-01-20 23:21:53 -0800
commitbbe2d886dcd81e608d58f9cd945551ddd385f6d4 (patch)
treeeb3ea00c8c62ccc47c715eef7702edf521ccc105 /power/skylake.c
parentebd29d455793d048daadc2dcfef7e26edee9d46b (diff)
downloadchrome-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/skylake.c')
-rw-r--r--power/skylake.c101
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;