summaryrefslogtreecommitdiff
path: root/common/x86_power.c
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2012-02-07 14:56:10 -0800
committerRandall Spangler <rspangler@chromium.org>2012-02-07 15:01:50 -0800
commit7423b63ea3a60e1b2328f87e64aae85f9f329b9d (patch)
tree738295f00d585c0fb52ea302fa18d901d71f5df1 /common/x86_power.c
parentf214e47717b153ffb154795ca7d482db35ef4d3e (diff)
downloadchrome-ec-7423b63ea3a60e1b2328f87e64aae85f9f329b9d.tar.gz
More complete x86 power module
Supports turning system on and off via power button. Also added 'powerbtn' command, which sends a power button press of the specified duration, and deprecated the 'x86power s0' command, since pressing the power button is a more correct way of powering on/off the system. Note that current coreboot doesn't seem to boot reliably; when it fails, the x86 asks for S5 and then S0 a second later. It boots about every 3rd try. No indication this is due to the EC; the EC just was ignoring these requests until this CL. Signed-off-by: Randall Spangler <rspangler@chromium.org> BUG=chrome-os-partner:7851 TEST=reboot, 'powerbtn', system should power on 'powerbtn', system should power off 'powerbtn 5000', system should power off regardless of previous state press power button, system should power on press power button again, system should power off hold power button 8 sec, system should power off regardless of previous state Change-Id: I89f419553289b20c78a57bc8cb1699932b095aa1
Diffstat (limited to 'common/x86_power.c')
-rw-r--r--common/x86_power.c120
1 files changed, 77 insertions, 43 deletions
diff --git a/common/x86_power.c b/common/x86_power.c
index 68f30cdaf4..a911ae436b 100644
--- a/common/x86_power.c
+++ b/common/x86_power.c
@@ -20,14 +20,17 @@
#define DEFAULT_TIMEOUT 1000000
enum x86_state {
- /* Stable states */
X86_G3 = 0, /* Initial state */
X86_S5, /* System is off */
+ X86_S3, /* RAM is on; processor is asleep */
X86_S0, /* System is on */
/* Transitions */
X86_G3S5, /* G3 -> S5 (at system init time) */
- X86_S5S0, /* S5 -> S0 */
+ X86_S5S3, /* S5 -> S3 */
+ X86_S3S0, /* S3 -> S0 */
+ X86_S0S3, /* S0 -> S3 */
+ X86_S3S5, /* S3 -> S5 */
/* TODO: S3 state, S0S5, S0S3, S3S0 */
};
@@ -35,9 +38,13 @@ enum x86_state {
static const char * const state_names[] = {
"G3",
"S5",
+ "S3",
"S0",
"G3->S5",
- "S5->S0",
+ "S5->S3",
+ "S3->S0",
+ "S0->S3",
+ "S3->S5",
};
/* Input state flags */
@@ -162,10 +169,8 @@ void x86_power_interrupt(enum gpio_signal signal)
/* Shadow signals and compare with our desired signal state. */
update_in_signals();
- /* Wake task if we want at least one signal, and all all the inputs we
- * want are present */
- if (in_want && (in_signals & in_want) == in_want)
- task_send_msg(TASK_ID_X86POWER, TASK_ID_X86POWER, 0);
+ /* Wake up the task */
+ task_send_msg(TASK_ID_X86POWER, TASK_ID_X86POWER, 0);
}
/*****************************************************************************/
@@ -212,7 +217,6 @@ void x86_power_task(void)
state, state_names[state], in_signals);
switch (state) {
-
case X86_G3:
/* Move to S5 state on boot */
state = X86_G3S5;
@@ -235,15 +239,19 @@ void x86_power_task(void)
state = X86_S5;
break;
- case X86_S5S0:
- /* Wait for PM_SLP_S3n to be asserted */
- wait_in_signals(IN_ALL_PM_SLP_DEASSERTED);
- /* Turn on power rails */
- gpio_set_level(GPIO_ENABLE_VS, 1);
+ case X86_S5S3:
+ /* Turn on power to RAM */
gpio_set_level(GPIO_SHUNT_1_5V_DDR, 0);
gpio_set_level(GPIO_ENABLE_1_5V_DDR, 1);
+ state = X86_S3;
+ break;
+
+ case X86_S3S0:
+ /* Turn on power rails */
+ gpio_set_level(GPIO_ENABLE_VS, 1);
+
/* Wait for non-core power rails good */
wait_in_signals(IN_PGOOD_ALL_NONCORE);
@@ -263,20 +271,67 @@ void x86_power_task(void)
state = X86_S0;
break;
+ case X86_S0S3:
+ /* Clear PCH_PWROK */
+ gpio_set_level(GPIO_PCH_PWROK, 0);
+
+ /* Wait 40ns */
+ udelay(1);
+
+ /* Disable +CPU_CORE and +VGFX_CORE */
+ gpio_set_level(GPIO_ENABLE_VCORE, 0);
+
+ /* Turn off power rails */
+ gpio_set_level(GPIO_ENABLE_VS, 0);
+
+ state = X86_S3;
+ break;
+
+ case X86_S3S5:
+ /* Turn off power to RAM */
+ gpio_set_level(GPIO_ENABLE_1_5V_DDR, 0);
+ gpio_set_level(GPIO_SHUNT_1_5V_DDR, 1);
+
+ state = X86_S5;
+ break;
+
case X86_S5:
- /* If PM_SLP_S3# is deasserted, system is trying to
- * power on. */
+ if (gpio_get_level(GPIO_PCH_SLP_S5n) == 1) {
+ /* Power up to next state */
+ state = X86_S5S3;
+ break;
+ }
+
+ /* Otherwise, steady state; wait for a message */
+ in_want = 0;
+ task_wait_msg(-1);
+ break;
+
+ case X86_S3:
if (gpio_get_level(GPIO_PCH_SLP_S3n) == 1) {
- state = X86_S5S0;
+ /* Power up to next state */
+ state = X86_S3S0;
+ break;
+ } else if (gpio_get_level(GPIO_PCH_SLP_S5n) == 0) {
+ /* Power down to next state */
+ state = X86_S3S5;
break;
}
/* Otherwise, steady state; wait for a message */
+ in_want = 0;
task_wait_msg(-1);
break;
case X86_S0:
- /* Steady state; wait for a message */
+ if (gpio_get_level(GPIO_PCH_SLP_S3n) == 0) {
+ /* Power down to next state */
+ state = X86_S0S3;
+ break;
+ }
+
+ /* Otherwise, steady state; wait for a message */
+ in_want = 0;
task_wait_msg(-1);
}
}
@@ -287,33 +342,12 @@ void x86_power_task(void)
static int command_x86power(int argc, char **argv)
{
- enum x86_state current = state;
- /* If no args provided, print current state */
- if (argc < 2) {
- uart_printf("Current X86 state: %d (%s)\n",
- state, state_names[state]);
- return EC_SUCCESS;
- }
+ /* Print current state */
+ uart_printf("Current X86 state: %d (%s)\n", state, state_names[state]);
- /* Get state to move to */
- if (!strcasecmp(argv[1], "S0")) {
- if (state == X86_S5) {
- /* Simulate a 100ms power button press */
- uart_puts("Simulating power button press.\n");
- gpio_set_level(GPIO_PCH_PWRBTNn, 0);
- usleep(100000);
- gpio_set_level(GPIO_PCH_PWRBTNn, 1);
- }
- }
-
- if (current == state)
- uart_puts("State not changed.\n");
- else {
- uart_printf("New X86 state: %d (%s)\n",
- state, state_names[state]);
- /* Wake up the task if it's asleep */
- task_send_msg(TASK_ID_X86POWER, TASK_ID_X86POWER, 0);
- }
+ /* Forcing a power state from EC is deprecated */
+ if (argc > 1)
+ uart_puts("Use 'powerbtn' instead of 'x86power s0'.\n");
return EC_SUCCESS;
}