From 002bc4278bcfe26ae9c3b6fb5cdd3ddc2d07403e Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Fri, 13 Jan 2012 15:53:29 -0800 Subject: [PATCH] Add x86 power state machine For bringup, this powers on the x86 unconditionally. Signed-off-by: Randall Spangler BUG=chrome-os-partner:7528 TEST=none Change-Id: Ib23e56d38ab42f8d8a4dbd1ba9dce12f0c3eeec9 --- board/bds/board.c | 27 +++- board/bds/board.h | 27 ++++ board/bds/ec.tasklist | 1 + board/link/board.c | 49 ++++--- board/link/ec.tasklist | 1 + chip/lm4/build.mk | 2 +- chip/lm4/x86_power.c | 136 -------------------- common/build.mk | 9 +- common/x86_power.c | 285 +++++++++++++++++++++++++++++++++++++++++ include/x86_power.h | 6 +- 10 files changed, 385 insertions(+), 158 deletions(-) delete mode 100644 chip/lm4/x86_power.c create mode 100644 common/x86_power.c diff --git a/board/bds/board.c b/board/bds/board.c index e1120d4e41..71bc810444 100644 --- a/board/bds/board.c +++ b/board/bds/board.c @@ -21,9 +21,34 @@ const struct gpio_info gpio_list[GPIO_COUNT] = { /* Other inputs */ /* Outputs */ {"DEBUG_LED", LM4_GPIO_A, (1<<7), GPIO_OUT_LOW, NULL}, - /* Unimplemented outputs which we need to emulate for now */ + /* Unimplemented signals which we need to emulate for now */ GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_LID_SWITCHn"), GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_PWRBTNn"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_BKLTEN"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_SLP_An"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_SLP_ME_CSW_DEVn"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_SLP_S3n"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_SLP_S4n"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_SLP_S5n"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_SLP_SUSn"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_SUSWARNn"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PGOOD_1_5V_DDR"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PGOOD_1_5V_PCH"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PGOOD_1_8VS"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PGOOD_5VALW"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PGOOD_CPU_CORE"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PGOOD_VCCP"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PGOOD_VCCSA"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PGOOD_VGFX_CORE"), + GPIO_SIGNAL_NOT_IMPLEMENTED("ENABLE_1_5V_DDR"), + GPIO_SIGNAL_NOT_IMPLEMENTED("ENABLE_BACKLIGHT"), + GPIO_SIGNAL_NOT_IMPLEMENTED("ENABLE_VCORE"), + GPIO_SIGNAL_NOT_IMPLEMENTED("ENABLE_VS"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_DPWROK"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_PWROK"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_RSMRSTn"), + GPIO_SIGNAL_NOT_IMPLEMENTED("PCH_SUSACKn"), + GPIO_SIGNAL_NOT_IMPLEMENTED("SHUNT_1_5V_DDR"), }; diff --git a/board/bds/board.h b/board/bds/board.h index 94a7af9484..dabad57e55 100644 --- a/board/bds/board.h +++ b/board/bds/board.h @@ -66,6 +66,33 @@ enum gpio_signal { GPIO_PCH_LID_SWITCHn, /* Lid switch output to PCH */ GPIO_PCH_PWRBTNn, /* Power button output to PCH */ + GPIO_PCH_BKLTEN, /* Backlight enable signal from PCH */ + GPIO_PCH_SLP_An, /* SLP_A# signal from PCH */ + GPIO_PCH_SLP_ME_CSW_DEVn, /* SLP_ME_CSW_DEV# signal from PCH */ + GPIO_PCH_SLP_S3n, /* SLP_S3# signal from PCH */ + GPIO_PCH_SLP_S4n, /* SLP_S4# signal from PCH */ + GPIO_PCH_SLP_S5n, /* SLP_S5# signal from PCH */ + GPIO_PCH_SLP_SUSn, /* SLP_SUS# signal from PCH */ + GPIO_PCH_SUSWARNn, /* SUSWARN# signal from PCH */ + GPIO_PGOOD_1_5V_DDR, /* Power good on +1.5V_DDR */ + GPIO_PGOOD_1_5V_PCH, /* Power good on +1.5V_PCH */ + GPIO_PGOOD_1_8VS, /* Power good on +1.8VS */ + GPIO_PGOOD_5VALW, /* Power good on +5VALW */ + GPIO_PGOOD_CPU_CORE, /* Power good on +CPU_CORE */ + GPIO_PGOOD_VCCP, /* Power good on +VCCP */ + GPIO_PGOOD_VCCSA, /* Power good on +VCCSA */ + GPIO_PGOOD_VGFX_CORE, /* Power good on +VGFX_CORE */ + GPIO_ENABLE_1_5V_DDR, /* Enable +1.5V_DDR supply */ + GPIO_ENABLE_BACKLIGHT, /* Enable backlight power */ + GPIO_ENABLE_VCORE, /* Enable +CPU_CORE and +VGFX_CORE */ + GPIO_ENABLE_VS, /* Enable VS power supplies */ + GPIO_PCH_DPWROK, /* DPWROK signal to PCH */ + GPIO_PCH_PWROK, /* PWROK / APWROK signals to PCH */ + GPIO_PCH_RSMRSTn, /* Reset PCH resume power plane logic */ + GPIO_PCH_SUSACKn, /* Acknowledge PCH SUSWARN# signal */ + GPIO_SHUNT_1_5V_DDR, /* Shunt +1.5V_DDR; may also enable +3V_TP + * depending on stuffing. */ + /* Number of GPIOs; not an actual GPIO */ GPIO_COUNT }; diff --git a/board/bds/ec.tasklist b/board/bds/ec.tasklist index f036105fb3..fca1be2f40 100644 --- a/board/bds/ec.tasklist +++ b/board/bds/ec.tasklist @@ -17,6 +17,7 @@ TASK(BLINK, UserLedBlink, NULL) \ TASK(KEYSCAN, keyboard_scan_task, NULL) \ TASK(POWERBTN, power_button_task, NULL) \ + TASK(X86POWER, x86_power_task, NULL) \ TASK(CONSOLE, console_task, NULL) \ TASK(HOSTCMD, host_command_task, NULL) \ TASK(I8042CMD, i8042_command_task, NULL) diff --git a/board/link/board.c b/board/link/board.c index 1b0b5a69cb..e5f9651382 100644 --- a/board/link/board.c +++ b/board/link/board.c @@ -9,6 +9,7 @@ #include "power_button.h" #include "registers.h" #include "util.h" +#include "x86_power.h" /* GPIO signal list. Must match order from enum gpio_signal. */ @@ -22,22 +23,38 @@ const struct gpio_info gpio_list[GPIO_COUNT] = { {"POWER_ONEWIRE", LM4_GPIO_H, (1<<2), 0, NULL}, {"THERMAL_DATA_READYn", LM4_GPIO_B, (1<<4), 0, NULL}, {"AC_PRESENT", LM4_GPIO_H, (1<<3), 0, NULL}, - {"PCH_BKLTEN", LM4_GPIO_J, (1<<3), 0, NULL}, - {"PCH_SLP_An", LM4_GPIO_G, (1<<5), 0, NULL}, - {"PCH_SLP_ME_CSW_DEVn", LM4_GPIO_G, (1<<4), 0, NULL}, - {"PCH_SLP_S3n", LM4_GPIO_J, (1<<0), 0, NULL}, - {"PCH_SLP_S4n", LM4_GPIO_J, (1<<1), 0, NULL}, - {"PCH_SLP_S5n", LM4_GPIO_J, (1<<2), 0, NULL}, - {"PCH_SLP_SUSn", LM4_GPIO_G, (1<<3), 0, NULL}, - {"PCH_SUSWARNn", LM4_GPIO_G, (1<<2), 0, NULL}, - {"PGOOD_1_5V_DDR", LM4_GPIO_K, (1<<0), 0, NULL}, - {"PGOOD_1_5V_PCH", LM4_GPIO_K, (1<<1), 0, NULL}, - {"PGOOD_1_8VS", LM4_GPIO_K, (1<<3), 0, NULL}, - {"PGOOD_5VALW", LM4_GPIO_H, (1<<0), 0, NULL}, - {"PGOOD_CPU_CORE", LM4_GPIO_M, (1<<3), 0, NULL}, - {"PGOOD_VCCP", LM4_GPIO_K, (1<<2), 0, NULL}, - {"PGOOD_VCCSA", LM4_GPIO_H, (1<<1), 0, NULL}, - {"PGOOD_VGFX_CORE", LM4_GPIO_D, (1<<2), 0, NULL}, + {"PCH_BKLTEN", LM4_GPIO_J, (1<<3), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PCH_SLP_An", LM4_GPIO_G, (1<<5), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PCH_SLP_ME_CSW_DEVn", LM4_GPIO_G, (1<<4), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PCH_SLP_S3n", LM4_GPIO_J, (1<<0), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PCH_SLP_S4n", LM4_GPIO_J, (1<<1), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PCH_SLP_S5n", LM4_GPIO_J, (1<<2), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PCH_SLP_SUSn", LM4_GPIO_G, (1<<3), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PCH_SUSWARNn", LM4_GPIO_G, (1<<2), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PGOOD_1_5V_DDR", LM4_GPIO_K, (1<<0), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PGOOD_1_5V_PCH", LM4_GPIO_K, (1<<1), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PGOOD_1_8VS", LM4_GPIO_K, (1<<3), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PGOOD_5VALW", LM4_GPIO_H, (1<<0), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PGOOD_CPU_CORE", LM4_GPIO_M, (1<<3), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PGOOD_VCCP", LM4_GPIO_K, (1<<2), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PGOOD_VCCSA", LM4_GPIO_H, (1<<1), GPIO_INT_BOTH, + x86_power_interrupt}, + {"PGOOD_VGFX_CORE", LM4_GPIO_D, (1<<2), GPIO_INT_BOTH, + x86_power_interrupt}, {"RECOVERYn", LM4_GPIO_H, (1<<7), 0, NULL}, {"USB1_STATUSn", LM4_GPIO_E, (1<<7), 0, NULL}, {"USB2_STATUSn", LM4_GPIO_E, (1<<1), 0, NULL}, diff --git a/board/link/ec.tasklist b/board/link/ec.tasklist index f036105fb3..fca1be2f40 100644 --- a/board/link/ec.tasklist +++ b/board/link/ec.tasklist @@ -17,6 +17,7 @@ TASK(BLINK, UserLedBlink, NULL) \ TASK(KEYSCAN, keyboard_scan_task, NULL) \ TASK(POWERBTN, power_button_task, NULL) \ + TASK(X86POWER, x86_power_task, NULL) \ TASK(CONSOLE, console_task, NULL) \ TASK(HOSTCMD, host_command_task, NULL) \ TASK(I8042CMD, i8042_command_task, NULL) diff --git a/chip/lm4/build.mk b/chip/lm4/build.mk index ec91bcc6db..585528f820 100644 --- a/chip/lm4/build.mk +++ b/chip/lm4/build.mk @@ -9,5 +9,5 @@ CFLAGS_CPU=-mcpu=cortex-m4 -mthumb -Os -mno-sched-prolog chip-objs=init.o panic.o switch.o task.o timer.o pwm.o i2c.o adc.o jtag.o -chip-objs+=clock.o gpio.o system.o lpc.o uart.o x86_power.o power_button.o +chip-objs+=clock.o gpio.o system.o lpc.o uart.o power_button.o chip-objs+=flash.o watchdog.o eeprom.o keyboard_scan.o temp_sensor.o diff --git a/chip/lm4/x86_power.c b/chip/lm4/x86_power.c deleted file mode 100644 index 2abeaf2c35..0000000000 --- a/chip/lm4/x86_power.c +++ /dev/null @@ -1,136 +0,0 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* x86 power control module for Chrome EC */ - -#include "registers.h" -#include "x86_power.h" - -/* Signals to/from EC. These are ALL the signals on the schematic - * that seem related. From the 11/14 schematic. */ -#if 0 -enum ec_signal { -}; - -/* Signals from Chief River Platform Power Sequence document. Directions are - * from the EC's point of view. */ -enum x86_signal { - // Schematic GPIO dir Intel doc name - CPU1.5V_S3_GATE, PH5, out /* Connected to SUSP# via resistor. Can - * disable VDDQ when driven low. */ - PBTN_OUT#, PG3, out PWRBTN# - PCH_DPWROK, PG0, out, DPWROK - PCH_PWROK, PC5, out, PWROK /* AND'd with VGATE (CPU_CORE - * good), then connected to - * PWROK. Also * connected to - * APWROK via resistor */ - PCH_RSMRST#, PF1, out, RSMRST# /* Also connected to - * PCH_DPWROK via resistor */ - PM_SLP_SUS#, PD3, inp, SLP_SUS - SLP_A#, PG5, i/o, SLP_A# /* Intel claims inp; why does - * schematic claim I/O? */ - SLP_ME_CSW_DEV#, PG4, i/o, SLP_ME_CSW_DEV# /* Intel also claims - * inp? */ - PM_SLP_S3#, PJ0, inp, SLP_S3# - PM_SLP_S4#, PJ1, inp, SLP_S4# - PM_SLP_S5#, PJ2, inp, SLP_S5# - SUSACK#, PD2, out, SUS_ACK# /* Also connected to SUSWARN# - * via (no-load) resistor */ - SUSWARN#, PH1, inp, SUSWARN# - - /* On EC schematic, but not mentioned directly in doc */ - ACOFF, PG2, inp /* Not connected? */ - BKOFF#, PH4, out /* Turns off display when pulled low. - * Can tri-state when not using. */ - EC_ACIN, PC7, inp /* Connected to ACIN, which comes from - * ACOK on charger */ - EC_KBRST#, PQ7, out, RCIN# - EC_LID_OUT#, PF0, out, GPIO15 - EC_ON, PC6, out - ENBKL, PF4, inp, L_BKLTEN /* From Panther Point LVDS */ - GATEA20, PQ6, out, A20GATE - HDA_SDO, PG1, out, HDA_SDO - H_PROCHOT#_EC, PF2, out, PROCHOT# /* Ivy Bridge. Has pullup. */ - SA_PGOOD, PF3, inp /* Set by power control when VccSA is - * good */ - SMI#, PJ3, out, GPIO8 - SUSP#, PG6, out /* Disables VCCP, VDDQ, +5VS, +3VS, - * +1.5VS, +0.75VS, +1.8VS */ - SYSON, PB6, out /* Enables +1.5VP, VCCP */ - VR_ON, PB7, out /* Enables CPU_CORE, VGFX_CORE */ -}; - - -/* Signals from the Ivy Bridge power sequencing document that aren't connected - * to the EC (at least, directly) */ -enum x86_signal_no_control { - // Platform to PCH - ACPRESENT, /* Comes from ACIN, which comes from ACOK on charger. - * There's an EC_ACIN line mentioned, but it doesn't seem - * to go to the EC(!) */ - IMVP7_VR_EN, /* (not on schematic) */ - RTCRST#, /* Can short to ground via jumper */ - SA_VR_PWROK, /* (not on schematic) */ - SYS_PWROK, - VR_VDDPWRGD, - - // PCH to platform - CL_RST# - SUSCLK, - SUS_STAT#, - SLP_LAN# - - // Platform to platform - ALL_SYS_PWRGD, - - // Power rails - VccASW, - VccAXG, - VccCore (CPU), // aka Vboot - VccCore (PCH), - VccDSW, - VccRTC, - VCCP, // aka VccIO - VccSA, - VccSPI, - VccSUS, - Vcc_WLAN, - VDDQ, - // (+ all platform rails?) -}; - -/* Signals we explicitly don't care about */ -enum x86_signal_dont_care { - SUSPWRDNACK, // Only applicable if deep sleep well not supported - -}; - - -#endif - - - - -/* Signal definitions are messy, split across multiple GPIOs. - * Fortunately, we only need to set them one at a time. */ -struct signal_gpio { - int is_output; - -}; - -struct signal_gpio gpios[] = { - - - -}; - - - - -int x86_power_init(void) -{ - return EC_SUCCESS; -} - diff --git a/common/build.mk b/common/build.mk index 1cdedf64a4..fd17921b08 100644 --- a/common/build.mk +++ b/common/build.mk @@ -1,7 +1,10 @@ +# Copyright (c) 2012 The Chromium OS Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. # -# common files build +# Common files build # -common-objs=main.o util.o console.o vboot.o +common-objs=main.o util.o console.o vboot.o x86_power.o pwm_commands.o common-objs+=flash_commands.o host_command.o port80.o keyboard.o i8042.o -common-objs+=memory_commands.o shared_mem.o temp_sensor_commands.o pwm_commands.o +common-objs+=memory_commands.o shared_mem.o temp_sensor_commands.o diff --git a/common/x86_power.c b/common/x86_power.c new file mode 100644 index 0000000000..7618b69a44 --- /dev/null +++ b/common/x86_power.c @@ -0,0 +1,285 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* X86 chipset power control module for Chrome EC */ + +#include "board.h" +#include "clock.h" +#include "console.h" +#include "gpio.h" +#include "task.h" +#include "timer.h" +#include "uart.h" +#include "util.h" +#include "x86_power.h" + +/* Default timeout in us; if we've been waiting this long for an input + * transition, just jump to the next state. */ +#define DEFAULT_TIMEOUT 1000000 + +enum x86_state { + /* Stable states */ + X86_G3 = 0, /* Initial state */ + X86_S5, /* System is off */ + X86_S0, /* System is on */ + + /* Transitions */ + X86_G3S5, /* G3 -> S5 (at system init time) */ + X86_S5S0, /* S5 -> S0 */ + + /* TODO: S3 state, S0S5, S0S3, S3S0 */ +}; + +static const char * const state_names[] = { + "G3", + "S5", + "S0", + "G3->S5", + "S5->S0", +}; + +/* Input state flags */ +#define IN_PGOOD_5VALW 0x0001 +#define IN_PGOOD_1_5V_DDR 0x0002 +#define IN_PGOOD_1_5V_PCH 0x0004 +#define IN_PGOOD_1_8VS 0x0008 +#define IN_PGOOD_VCCP 0x0010 +#define IN_PGOOD_VCCSA 0x0020 +#define IN_PGOOD_CPU_CORE 0x0040 +#define IN_PGOOD_VGFX_CORE 0x0080 +#define IN_PCH_SLP_S3n_DEASSERTED 0x0100 +#define IN_PCH_SLP_S4n_DEASSERTED 0x0200 +#define IN_PCH_SLP_S5n_DEASSERTED 0x0400 +#define IN_PCH_SLP_An_DEASSERTED 0x0800 +/* All always-on supplies */ +#define IN_PGOOD_ALWAYS_ON (IN_PGOOD_5VALW) +/* All non-core power rails */ +#define IN_PGOOD_ALL_NONCORE (IN_PGOOD_1_5V_DDR | IN_PGOOD_1_5V_PCH | \ + IN_PGOOD_1_8VS | IN_PGOOD_VCCP | IN_PGOOD_VCCSA) +/* All core power rails */ +#define IN_PGOOD_ALL_CORE (IN_PGOOD_CPU_CORE | IN_PGOOD_VGFX_CORE) +/* All PM_SLP signals from PCH deasserted */ +#define IN_ALL_PM_SLP_DEASSERTED (IN_PCH_SLP_S3n_DEASSERTED | \ + IN_PCH_SLP_S4n_DEASSERTED | \ + IN_PCH_SLP_S5n_DEASSERTED | \ + IN_PCH_SLP_An_DEASSERTED) + + +static enum x86_state state; /* Current state */ +static uint32_t in_signals; /* Current input signal states (IN_PGOOD_*) */ +static uint32_t in_want; /* Input signal state we're waiting for */ + + +/* Update input signal state */ +static void update_in_signals(void) +{ + uint32_t inew = 0; + + if (gpio_get_level(GPIO_PGOOD_5VALW)) + inew |= IN_PGOOD_5VALW; + + if (gpio_get_level(GPIO_PGOOD_1_5V_DDR)) + inew |= IN_PGOOD_1_5V_DDR; + if (gpio_get_level(GPIO_PGOOD_1_5V_PCH)) + inew |= IN_PGOOD_1_5V_PCH; + if (gpio_get_level(GPIO_PGOOD_1_8VS)) + inew |= IN_PGOOD_1_8VS; + if (gpio_get_level(GPIO_PGOOD_VCCP)) + inew |= IN_PGOOD_VCCP; + if (gpio_get_level(GPIO_PGOOD_VCCSA)) + inew |= IN_PGOOD_VCCSA; + + if (gpio_get_level(GPIO_PGOOD_CPU_CORE)) + inew |= IN_PGOOD_CPU_CORE; + if (gpio_get_level(GPIO_PGOOD_VGFX_CORE)) + inew |= IN_PGOOD_VGFX_CORE; + + if (gpio_get_level(GPIO_PCH_SLP_An)) + inew |= IN_PCH_SLP_An_DEASSERTED; + if (gpio_get_level(GPIO_PCH_SLP_S3n)) + inew |= IN_PCH_SLP_S3n_DEASSERTED; + if (gpio_get_level(GPIO_PCH_SLP_S4n)) + inew |= IN_PCH_SLP_S4n_DEASSERTED; + if (gpio_get_level(GPIO_PCH_SLP_S5n)) + inew |= IN_PCH_SLP_S5n_DEASSERTED; + + in_signals = inew; +} + + +/* Wait for all the inputs in to be present. Returns EC_ERROR_TIMEOUT + * if timeout before reaching the desired state. */ +static int wait_in_signals(uint32_t want) +{ + in_want = want; + + while ((in_signals & in_want) != in_want) { + if (task_wait_msg(DEFAULT_TIMEOUT) == (1 << TASK_ID_TIMER)) { + uart_printf("[x86 power timeout on input; " + "wanted 0x%04x, got 0x%04x]\n", + in_want, in_signals & in_want); + return EC_ERROR_TIMEOUT; + } + /* TODO: should really shrink the remaining timeout if we woke + * up but didn't have all the signals we wanted. Also need to + * handle aborts if we're no longer in the same state we were + * when we started waiting. */ + } + return EC_SUCCESS; +} + + +/*****************************************************************************/ +/* Interrupts */ + +void x86_power_interrupt(enum gpio_signal signal) +{ + /* Signals we handle specially */ + switch (signal) { + case GPIO_PCH_BKLTEN: + /* Copy backlight enable signal from PCH to BKLTEN */ + gpio_set_level(GPIO_ENABLE_BACKLIGHT, + gpio_get_level(GPIO_PCH_BKLTEN)); + return; + + case GPIO_PCH_SUSWARNn: + /* Copy SUSWARN# signal from PCH to SUSACK# */ + gpio_set_level(GPIO_PCH_SUSACKn, + gpio_get_level(GPIO_PCH_SUSWARNn)); + return; + + default: + /* All other signals we shadow 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); + } +} + +/*****************************************************************************/ +/* Initialization */ + +int x86_power_init(void) +{ + state = X86_G3; + + /* Update input state */ + update_in_signals(); + in_want = 0; + + /* Enable interrupts for our GPIOs */ + gpio_enable_interrupt(GPIO_PCH_BKLTEN); + gpio_enable_interrupt(GPIO_PCH_SLP_An); + gpio_enable_interrupt(GPIO_PCH_SLP_ME_CSW_DEVn); + gpio_enable_interrupt(GPIO_PCH_SLP_S3n); + gpio_enable_interrupt(GPIO_PCH_SLP_S4n); + gpio_enable_interrupt(GPIO_PCH_SLP_S5n); + gpio_enable_interrupt(GPIO_PCH_SLP_SUSn); + gpio_enable_interrupt(GPIO_PCH_SUSWARNn); + gpio_enable_interrupt(GPIO_PGOOD_1_5V_DDR); + gpio_enable_interrupt(GPIO_PGOOD_1_5V_PCH); + gpio_enable_interrupt(GPIO_PGOOD_1_8VS); + gpio_enable_interrupt(GPIO_PGOOD_5VALW); + gpio_enable_interrupt(GPIO_PGOOD_CPU_CORE); + gpio_enable_interrupt(GPIO_PGOOD_VCCP); + gpio_enable_interrupt(GPIO_PGOOD_VCCSA); + gpio_enable_interrupt(GPIO_PGOOD_VGFX_CORE); + + return EC_SUCCESS; +} + +/*****************************************************************************/ +/* Task function */ + +void x86_power_task(void) +{ + x86_power_init(); + + while (1) { + uart_printf("[x86 power state %d = %s]\n", state, + state_names[state]); + + switch (state) { + + case X86_G3: + /* Move to S5 state on boot */ + state = X86_G3S5; + break; + + case X86_S5: + /* For bringup, power on one second after boot */ + /* TODO: remove post-bringup */ + usleep(1000000); + state = X86_S5S0; + break; + + case X86_G3S5: + /* Wait for the always-on rails to be good */ + wait_in_signals(IN_PGOOD_ALWAYS_ON); + + /* Wait 10ms after +5VALW good */ + usleep(10000); + + /* Assert DPWROK, deassert RSMRST# */ + gpio_set_level(GPIO_PCH_DPWROK, 1); + gpio_set_level(GPIO_PCH_RSMRSTn, 1); + + /* Wait 5ms for SUSCLK to stabilize */ + usleep(5000); + + state = X86_S5; + break; + + case X86_S5S0: + /* TODO: this should be in response to a power button + * event, not causing one. For initial bringup, + * simulate the event. */ + /* Assert power button */ + gpio_set_level(GPIO_PCH_PWRBTNn, 0); + /* Wait 16ms after asserting PWRBTN# */ + usleep(16000); + /* Release power button */ + gpio_set_level(GPIO_PCH_PWRBTNn, 1); + + /* 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); + gpio_set_level(GPIO_SHUNT_1_5V_DDR, 0); + gpio_set_level(GPIO_ENABLE_1_5V_DDR, 1); + + /* Wait for non-core power rails good */ + wait_in_signals(IN_PGOOD_ALL_NONCORE); + + /* Enable +CPU_CORE and +VGFX_CORE */ + gpio_set_level(GPIO_ENABLE_VCORE, 1); + + /* Wait for all supplies good */ + wait_in_signals(IN_PGOOD_ALL_NONCORE | + IN_PGOOD_ALL_CORE); + + /* Wait 99ms after all voltages good */ + usleep(99000); + + /* Set PCH_PWROK */ + gpio_set_level(GPIO_PCH_PWROK, 1); + + state = X86_S0; + break; + + case X86_S0: + /* Steady state; wait for a message */ + task_wait_msg(-1); + } + } +} + + + diff --git a/include/x86_power.h b/include/x86_power.h index 3343b237e2..ce28e1b571 100644 --- a/include/x86_power.h +++ b/include/x86_power.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved. +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -9,8 +9,12 @@ #define __CROS_EC_X86_POWER_H #include "common.h" +#include "gpio.h" /* Initializes the module. */ int x86_power_init(void); +/* Interrupt handler for input GPIOs */ +void x86_power_interrupt(enum gpio_signal signal); + #endif /* __CROS_EC_X86_POWER_H */