summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/lm4/lpc.c7
-rw-r--r--common/power_button_x86.c43
-rw-r--r--include/lpc.h7
-rw-r--r--include/power_button.h10
-rw-r--r--power/baytrail.c62
5 files changed, 116 insertions, 13 deletions
diff --git a/chip/lm4/lpc.c b/chip/lm4/lpc.c
index 0593570b61..99f212af19 100644
--- a/chip/lm4/lpc.c
+++ b/chip/lm4/lpc.c
@@ -427,6 +427,11 @@ uint32_t lpc_get_host_event_mask(enum lpc_host_event_type type)
return event_mask[type];
}
+int lpc_get_pltrst_asserted(void)
+{
+ return (LM4_LPC_LPCSTS & (1<<10)) ? 1 : 0;
+}
+
/**
* Handle write to ACPI I/O port
*
@@ -619,7 +624,7 @@ static void lpc_interrupt(void)
}
CPRINTF("[%T LPC RESET# %sasserted]\n",
- (LM4_LPC_LPCSTS & (1<<10)) ? "" : "de");
+ lpc_get_pltrst_asserted() ? "" : "de");
}
}
DECLARE_IRQ(LM4_IRQ_LPC, lpc_interrupt, 2);
diff --git a/common/power_button_x86.c b/common/power_button_x86.c
index c8854e99fe..954427aa5e 100644
--- a/common/power_button_x86.c
+++ b/common/power_button_x86.c
@@ -127,6 +127,34 @@ static void set_pwrbtn_to_pch(int high)
gpio_set_level(GPIO_PCH_PWRBTN_L, high);
}
+void power_button_pch_release(void)
+{
+ CPRINTF("[%T PB PCH force release]\n");
+
+ /* Deassert power button signal to PCH */
+ set_pwrbtn_to_pch(1);
+
+ /*
+ * If power button is actually pressed, eat the next release so we
+ * don't send an extra release.
+ */
+ if (power_button_is_pressed())
+ pwrbtn_state = PWRBTN_STATE_EAT_RELEASE;
+ else
+ pwrbtn_state = PWRBTN_STATE_IDLE;
+}
+
+void power_button_pch_pulse(void)
+{
+ CPRINTF("[%T PB PCH pulse]\n");
+
+ chipset_exit_hard_off();
+ set_pwrbtn_to_pch(0);
+ pwrbtn_state = PWRBTN_STATE_LID_OPEN;
+ tnext_state = get_time().val + PWRBTN_INITIAL_US;
+ task_wake(TASK_ID_POWERBTN);
+}
+
/**
* Handle debounced power button down.
*/
@@ -180,11 +208,7 @@ static void set_initial_pwrbtn_state(void)
* Otherwise, it might power on.
*/
CPRINTF("[%T PB init-off]\n");
- set_pwrbtn_to_pch(1);
- if (power_button_is_pressed())
- pwrbtn_state = PWRBTN_STATE_EAT_RELEASE;
- else
- pwrbtn_state = PWRBTN_STATE_IDLE;
+ power_button_pch_release();
} else {
/*
* All other EC reset conditions power on the main processor so
@@ -363,13 +387,8 @@ DECLARE_HOOK(HOOK_INIT, powerbtn_x86_init, HOOK_PRIO_DEFAULT);
static void powerbtn_x86_lid_change(void)
{
/* If chipset is off, pulse the power button on lid open to wake it. */
- if (lid_is_open() && chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
- chipset_exit_hard_off();
- set_pwrbtn_to_pch(0);
- pwrbtn_state = PWRBTN_STATE_LID_OPEN;
- tnext_state = get_time().val + PWRBTN_INITIAL_US;
- task_wake(TASK_ID_POWERBTN);
- }
+ if (lid_is_open() && chipset_in_state(CHIPSET_STATE_ANY_OFF))
+ power_button_pch_pulse();
}
DECLARE_HOOK(HOOK_LID_CHANGE, powerbtn_x86_lid_change, HOOK_PRIO_DEFAULT);
diff --git a/include/lpc.h b/include/lpc.h
index 0ecaa6b822..c16b1bc5d4 100644
--- a/include/lpc.h
+++ b/include/lpc.h
@@ -96,4 +96,11 @@ void lpc_set_host_event_mask(enum lpc_host_event_type type, uint32_t mask);
*/
uint32_t lpc_get_host_event_mask(enum lpc_host_event_type type);
+/**
+ * Return the state of platform reset.
+ *
+ * @return non-zero if PLTRST# is asserted (low); 0 if not asserted (high).
+ */
+int lpc_get_pltrst_asserted(void);
+
#endif /* __CROS_EC_LPC_H */
diff --git a/include/power_button.h b/include/power_button.h
index f3da24da9b..190073812e 100644
--- a/include/power_button.h
+++ b/include/power_button.h
@@ -24,4 +24,14 @@ int power_button_is_pressed(void);
*/
void power_button_interrupt(enum gpio_signal signal);
+/**
+ * For x86 systems, force-deassert the power button signal to the PCH.
+ */
+void power_button_pch_release(void);
+
+/**
+ * For x86 systems, force a pulse of the power button signal to the PCH.
+ */
+void power_button_pch_pulse(void);
+
#endif /* __CROS_EC_POWER_BUTTON_H */
diff --git a/power/baytrail.c b/power/baytrail.c
index d4c5fb1d1a..d0289aabc2 100644
--- a/power/baytrail.c
+++ b/power/baytrail.c
@@ -13,7 +13,9 @@
#include "hooks.h"
#include "host_command.h"
#include "lid_switch.h"
+#include "lpc.h"
#include "power.h"
+#include "power_button.h"
#include "system.h"
#include "timer.h"
#include "usb_charge.h"
@@ -51,6 +53,8 @@
static int throttle_cpu; /* Throttle CPU? */
static int pause_in_s5 = 1; /* Pause in S5 when shutting down? */
+static int restart_from_s5; /* Force system back on from S5 */
+static int fake_pltrst_timeout; /* Fake PLTRST# timeout at next power-on */
void chipset_force_shutdown(void)
{
@@ -282,6 +286,31 @@ enum power_state power_handle_state(enum power_state state)
/* Set SYS and CORE PWROK */
gpio_set_level(GPIO_PCH_SYS_PWROK, 1);
gpio_set_level(GPIO_PCH_CORE_PWROK, 1);
+
+ /* Wait 50 ms for platform reset to deassert */
+ {
+ int i;
+
+ for (i = 0; i < 50; i++) {
+ usleep(MSEC);
+ if (!lpc_get_pltrst_asserted())
+ break;
+ }
+
+ if (i < 50 && !fake_pltrst_timeout) {
+ /* Deasserted in time */
+ CPRINTF("[%T power PLTRST# deasserted]\n");
+ } else {
+ /* Force a reset. See crosbug.com/p/28422 */
+ CPRINTF("[%T power PLTRST# timeout]\n");
+ power_button_pch_release();
+ chipset_force_shutdown();
+ restart_from_s5 = 1;
+
+ fake_pltrst_timeout = 0;
+ }
+ }
+
return POWER_S0;
case POWER_S0S3:
@@ -347,6 +376,29 @@ enum power_state power_handle_state(enum power_state state)
/* Turn off power to RAM */
gpio_set_level(GPIO_PP1350_EN, 0);
+ /*
+ * If restarting from S5, delay and fake power button press.
+ * See crosbug.com/p/28422.
+ */
+ if (restart_from_s5) {
+ CPRINTF("[%T power restart from S5]\n");
+
+ restart_from_s5 = 0;
+
+ /* Delay for system to shut down after rails dropped */
+ msleep(100);
+
+ /* Restart system via power button press */
+ power_button_pch_pulse();
+
+ /*
+ * Force system to start back up from scratch. This is
+ * needed to undo the effects of a previous call to
+ * chipset_force_shutdown().
+ */
+ return POWER_G3S5;
+ }
+
/* Start shutting down */
return pause_in_s5 ? POWER_S5 : POWER_S5G3;
@@ -392,3 +444,13 @@ DECLARE_CONSOLE_COMMAND(pause_in_s5, console_command_gsv,
"Should the AP pause in S5 during shutdown?",
NULL);
+static int console_command_powerfail(int argc, char **argv)
+{
+ ccprintf("Faking a failure of next power-on event\n");
+ fake_pltrst_timeout = 1;
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(powerfail, console_command_powerfail,
+ NULL,
+ "Fake PLTRST# failure during next power-on",
+ NULL);