diff options
-rw-r--r-- | board/rambi/board.c | 2 | ||||
-rw-r--r-- | board/rambi/board.h | 8 | ||||
-rw-r--r-- | board/rambi/ec.tasklist | 2 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/chipset_baytrail.c | 369 | ||||
-rw-r--r-- | include/config.h | 1 |
6 files changed, 377 insertions, 6 deletions
diff --git a/board/rambi/board.c b/board/rambi/board.c index 38f4262fe4..72be16f3c0 100644 --- a/board/rambi/board.c +++ b/board/rambi/board.c @@ -77,7 +77,7 @@ const struct gpio_info gpio_list[] = { {"LPC_CLKRUN_L", LM4_GPIO_M, (1<<2), GPIO_ODR_HIGH, NULL}, {"PCH_CORE_PWROK", LM4_GPIO_F, (1<<5), GPIO_OUT_LOW, NULL}, {"PCH_PWRBTN_L", LM4_GPIO_H, (1<<0), GPIO_ODR_HIGH, NULL}, - {"PCH_RCIN_L", LM4_GPIO_F, (1<<3), GPIO_ODR_LOW, NULL}, + {"PCH_RCIN_L", LM4_GPIO_F, (1<<3), GPIO_ODR_HIGH, NULL}, {"PCH_RSMRST_L", LM4_GPIO_F, (1<<1), GPIO_OUT_LOW, NULL}, {"PCH_SMI_L", LM4_GPIO_F, (1<<4), GPIO_ODR_HIGH, NULL}, {"PCH_SOC_OVERRIDE_L", LM4_GPIO_G, (1<<1), GPIO_OUT_HIGH, NULL}, diff --git a/board/rambi/board.h b/board/rambi/board.h index deb00abc15..2cc95f1fb1 100644 --- a/board/rambi/board.h +++ b/board/rambi/board.h @@ -11,6 +11,9 @@ /* Optional features */ #define CONFIG_BACKLIGHT_LID #define CONFIG_BOARD_VERSION +#define CONFIG_CHIPSET_BAYTRAIL +#define CONFIG_CHIPSET_CAN_THROTTLE +#define CONFIG_CHIPSET_X86 #define CONFIG_CMD_GSV #define CONFIG_EXTPOWER_GPIO #define CONFIG_KEYBOARD_COL2_INVERTED @@ -35,9 +38,6 @@ #define CONFIG_CHARGER_INPUT_CURRENT 4032 /* mA, about half max */ #define CONFIG_CHARGER_SENSE_RESISTOR 10 /* Charge sense resistor, mOhm */ #define CONFIG_CHARGER_SENSE_RESISTOR_AC 10 /* Input sensor resistor, mOhm */ -#define CONFIG_CHIPSET_CAN_THROTTLE -#define CONFIG_CHIPSET_HASWELL -#define CONFIG_CHIPSET_X86 #define CONFIG_USB_PORT_POWER_DUMB #endif @@ -107,7 +107,7 @@ enum gpio_signal { GPIO_LPC_CLKRUN_L, /* Request that PCH drive LPC clock */ GPIO_PCH_CORE_PWROK, /* Indicate core well power is stable */ GPIO_PCH_PWRBTN_L, /* Power button output to PCH */ - GPIO_PCH_RCIN_L, /* RCIN# line to PCH (for 8042 emulation) */ + GPIO_PCH_RCIN_L, /* Reset line to PCH (for 8042 emulation) */ GPIO_PCH_RSMRST_L, /* Reset PCH resume power plane logic */ GPIO_PCH_SMI_L, /* System management interrupt to PCH */ GPIO_PCH_SOC_OVERRIDE_L, /* SOC override signal to PCH; when high, ME diff --git a/board/rambi/ec.tasklist b/board/rambi/ec.tasklist index a3c01c171b..fd3c29ac1b 100644 --- a/board/rambi/ec.tasklist +++ b/board/rambi/ec.tasklist @@ -22,7 +22,7 @@ TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \ TASK_NOTEST(VBOOTHASH, vboot_hash_task, NULL, LARGER_TASK_STACK_SIZE) \ /* TASK_ALWAYS(CHARGER, charger_task, NULL, TASK_STACK_SIZE) */ \ - /* TASK_NOTEST(CHIPSET, chipset_task, NULL, TASK_STACK_SIZE) */ \ + TASK_NOTEST(CHIPSET, chipset_task, NULL, TASK_STACK_SIZE) \ TASK_NOTEST(KEYPROTO, keyboard_protocol_task, NULL, TASK_STACK_SIZE) \ TASK_ALWAYS(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \ TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \ diff --git a/common/build.mk b/common/build.mk index 7fa8e043d4..6a9cd65aa5 100644 --- a/common/build.mk +++ b/common/build.mk @@ -26,6 +26,7 @@ common-$(CONFIG_CHARGER_BQ24725)+=charger_bq24725.o common-$(CONFIG_CHARGER_BQ24707A)+=charger_bq24707a.o common-$(CONFIG_CHARGER_BQ24738)+=charger_bq24738.o common-$(CONFIG_CHARGER_TPS65090)+=pmu_tps65090_charger.o +common-$(CONFIG_CHIPSET_BAYTRAIL)+=chipset_baytrail.o common-$(CONFIG_CHIPSET_GAIA)+=chipset_gaia.o common-$(CONFIG_CHIPSET_HASWELL)+=chipset_haswell.o common-$(CONFIG_CHIPSET_IVYBRIDGE)+=chipset_ivybridge.o diff --git a/common/chipset_baytrail.c b/common/chipset_baytrail.c new file mode 100644 index 0000000000..c5f17f5a64 --- /dev/null +++ b/common/chipset_baytrail.c @@ -0,0 +1,369 @@ +/* Copyright (c) 2013 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 "chipset.h" +#include "chipset_x86_common.h" +#include "common.h" +#include "console.h" +#include "ec_commands.h" +#include "gpio.h" +#include "hooks.h" +#include "host_command.h" +#include "lid_switch.h" +#include "system.h" +#include "timer.h" +#include "util.h" +#include "wireless.h" + +/* Console output macros */ +#define CPUTS(outstr) cputs(CC_CHIPSET, outstr) +#define CPRINTF(format, args...) cprintf(CC_CHIPSET, format, ## args) + +/* Input state flags */ +#define IN_PGOOD_PP5000 X86_SIGNAL_MASK(X86_PGOOD_PP5000) +#define IN_PGOOD_PP1050 X86_SIGNAL_MASK(X86_PGOOD_PP1050) +#define IN_PGOOD_S5 X86_SIGNAL_MASK(X86_PGOOD_S5) +#define IN_PGOOD_VCORE X86_SIGNAL_MASK(X86_PGOOD_VCORE) +#define IN_PCH_SLP_S3n_DEASSERTED X86_SIGNAL_MASK(X86_PCH_SLP_S3n_DEASSERTED) +#define IN_PCH_SLP_S4n_DEASSERTED X86_SIGNAL_MASK(X86_PCH_SLP_S4n_DEASSERTED) + +/* All always-on supplies */ +#define IN_PGOOD_ALWAYS_ON (IN_PGOOD_S5) +/* All non-core power rails */ +#define IN_PGOOD_ALL_NONCORE (IN_PGOOD_PP5000) +/* All core power rails */ +#define IN_PGOOD_ALL_CORE (IN_PGOOD_VCORE) +/* Rails required for S3 */ +#define IN_PGOOD_S3 (IN_PGOOD_ALWAYS_ON) +/* Rails required for S0 */ +#define IN_PGOOD_S0 (IN_PGOOD_ALWAYS_ON | IN_PGOOD_ALL_NONCORE) + +/* All PM_SLP signals from PCH deasserted */ +#define IN_ALL_PM_SLP_DEASSERTED (IN_PCH_SLP_S3n_DEASSERTED | \ + IN_PCH_SLP_S4n_DEASSERTED) +/* All inputs in the right state for S0 */ +#define IN_ALL_S0 (IN_PGOOD_ALWAYS_ON | IN_PGOOD_ALL_NONCORE | \ + IN_PGOOD_ALL_CORE | IN_ALL_PM_SLP_DEASSERTED) + +static int throttle_cpu; /* Throttle CPU? */ +static int pause_in_s5; /* Pause in S5 when shutting down? */ + +void chipset_force_shutdown(void) +{ + CPRINTF("[%T %s()]\n", __func__); + + /* + * Force x86 off. This condition will reset once the state machine + * transitions to G3. + */ + /* TODO(rspangler): verify this works */ + gpio_set_level(GPIO_PCH_SYS_PWROK, 0); + gpio_set_level(GPIO_PCH_RSMRST_L, 0); +} + +void chipset_reset(int cold_reset) +{ + CPRINTF("[%T %s(%d)]\n", __func__, cold_reset); + if (cold_reset) { + /* + * Drop and restore PWROK. This causes the PCH to reboot, + * regardless of its after-G3 setting. This type of reboot + * causes the PCH to assert PLTRST#, SLP_S3#, and SLP_S5#, so + * we actually drop power to the rest of the system (hence, a + * "cold" reboot). + */ + + /* Ignore if PWROK is already low */ + if (gpio_get_level(GPIO_PCH_SYS_PWROK) == 0) + return; + + /* PWROK must deassert for at least 3 RTC clocks = 91 us */ + gpio_set_level(GPIO_PCH_SYS_PWROK, 0); + udelay(100); + gpio_set_level(GPIO_PCH_SYS_PWROK, 1); + + } else { + /* + * Send a reset pulse to the PCH. This just causes it to + * assert INIT# to the CPU without dropping power or asserting + * PLTRST# to reset the rest of the system. + */ + + /* + * Pulse must be at least 16 PCI clocks long = 500 ns. The gpio + * pin used by the EC (PL6) does not behave in the correct + * manner when configured as open drain. In order to mimic + * open drain, the pin is initially configured as an input. + * When it is needed to drive low, the flags are updated which + * changes the pin to an output and drives the pin low. */ + gpio_set_flags(GPIO_PCH_RCIN_L, GPIO_OUT_LOW); + udelay(10); + gpio_set_flags(GPIO_PCH_RCIN_L, GPIO_INPUT); + } +} + +void chipset_throttle_cpu(int throttle) +{ + if (chipset_in_state(CHIPSET_STATE_ON)) + gpio_set_level(GPIO_CPU_PROCHOT, throttle); +} + +enum x86_state x86_chipset_init(void) +{ + /* + * If we're switching between images without rebooting, see if the x86 + * is already powered on; if so, leave it there instead of cycling + * through G3. + */ + if (system_jumped_to_this_image()) { + if ((x86_get_signals() & IN_ALL_S0) == IN_ALL_S0) { + CPRINTF("[%T x86 already in S0]\n"); + return X86_S0; + } else { + /* Force all signals to their G3 states */ + CPRINTF("[%T x86 forcing G3]\n"); + gpio_set_level(GPIO_PCH_CORE_PWROK, 0); + gpio_set_level(GPIO_VCORE_EN, 0); + gpio_set_level(GPIO_SUSP_VR_EN, 0); + gpio_set_level(GPIO_PP1350_EN, 0); + gpio_set_level(GPIO_PP3300_DX_EN, 0); + gpio_set_level(GPIO_PP5000_EN, 0); + gpio_set_level(GPIO_PCH_RSMRST_L, 0); + gpio_set_level(GPIO_PCH_SYS_PWROK, 0); + wireless_enable(0); + } + } + + return X86_G3; +} + +enum x86_state x86_handle_state(enum x86_state state) +{ + switch (state) { + case X86_G3: + break; + + case X86_S5: + if (gpio_get_level(GPIO_PCH_SLP_S4_L) == 1) + return X86_S5S3; /* Power up to next state */ + break; + + case X86_S3: + /* + * If lid is closed; hold touchscreen in reset to cut power + * usage. If lid is open, take touchscreen out of reset so it + * can wake the processor. Chipset task is awakened on lid + * switch transitions. + */ + gpio_set_level(GPIO_TOUCHSCREEN_RESET_L, lid_is_open()); + + /* Check for state transitions */ + if (!x86_has_signals(IN_PGOOD_S3)) { + /* Required rail went away */ + chipset_force_shutdown(); + return X86_S3S5; + } else if (gpio_get_level(GPIO_PCH_SLP_S3_L) == 1) { + /* Power up to next state */ + return X86_S3S0; + } else if (gpio_get_level(GPIO_PCH_SLP_S4_L) == 0) { + /* Power down to next state */ + return X86_S3S5; + } + break; + + case X86_S0: + if (!x86_has_signals(IN_PGOOD_S0)) { + /* Required rail went away */ + chipset_force_shutdown(); + return X86_S0S3; + } else if (gpio_get_level(GPIO_PCH_SLP_S3_L) == 0) { + /* Power down to next state */ + return X86_S0S3; + } + break; + + case X86_G3S5: + /* TODO(rspangler): temporary hack on Rev.1 boards */ + gpio_set_level(GPIO_PP5000_EN, 1); + + /* + * Wait 10ms after +3VALW good, since that powers VccDSW and + * VccSUS. + */ + msleep(10); + + gpio_set_level(GPIO_SUSP_VR_EN, 1); + if (x86_wait_signals(IN_PGOOD_S5)) { + chipset_force_shutdown(); + return X86_G3; + } + + /* Deassert RSMRST# */ + gpio_set_level(GPIO_PCH_RSMRST_L, 1); + + /* Wait 10ms for SUSCLK to stabilize */ + msleep(10); + return X86_S5; + + case X86_S5S3: + /* Wait for the always-on rails to be good */ + if (x86_wait_signals(IN_PGOOD_ALWAYS_ON)) { + chipset_force_shutdown(); + return X86_S5G3; + } + + /* Turn on power to RAM */ + gpio_set_level(GPIO_PP1350_EN, 1); + if (x86_wait_signals(IN_PGOOD_S3)) { + chipset_force_shutdown(); + return X86_S5G3; + } + + /* + * Enable touchpad power so it can wake the system from + * suspend. + */ + gpio_set_level(GPIO_ENABLE_TOUCHPAD, 1); + + /* Call hooks now that rails are up */ + hook_notify(HOOK_CHIPSET_STARTUP); + return X86_S3; + + case X86_S3S0: + /* Turn on power rails */ + gpio_set_level(GPIO_PP5000_EN, 1); + gpio_set_level(GPIO_PP3300_DX_EN, 1); + + /* Enable wireless */ + wireless_enable(EC_WIRELESS_SWITCH_ALL); + + /* + * Make sure touchscreen is out if reset (even if the lid is + * still closed); it may have been turned off if the lid was + * closed in S3. + */ + gpio_set_level(GPIO_TOUCHSCREEN_RESET_L, 1); + + /* Wait for non-core power rails good */ + if (x86_wait_signals(IN_PGOOD_S0)) { + chipset_force_shutdown(); + wireless_enable(0); + gpio_set_level(GPIO_PP3300_DX_EN, 0); + /* TODO(rspangler) turn off PP5000 after Rev.1 */ + gpio_set_level(GPIO_TOUCHSCREEN_RESET_L, 0); + return X86_S3; + } + + /* + * Enable +CPU_CORE. The CPU itself will request the supplies + * when it's ready. + */ + gpio_set_level(GPIO_VCORE_EN, 1); + + /* Call hooks now that rails are up */ + hook_notify(HOOK_CHIPSET_RESUME); + + /* Wait 100ms after all voltages good */ + msleep(100); + + /* + * Throttle CPU if necessary. This should only be asserted + * when +VCCP is powered (it is by now). + */ + gpio_set_level(GPIO_CPU_PROCHOT, throttle_cpu); + + /* Set SYS and CORE PWROK */ + gpio_set_level(GPIO_PCH_SYS_PWROK, 1); + gpio_set_level(GPIO_PCH_CORE_PWROK, 1); + return X86_S0; + + case X86_S0S3: + /* Call hooks before we remove power rails */ + hook_notify(HOOK_CHIPSET_SUSPEND); + + /* Clear SYS and CORE PWROK */ + gpio_set_level(GPIO_PCH_SYS_PWROK, 0); + gpio_set_level(GPIO_PCH_CORE_PWROK, 0); + + /* Wait 40ns */ + udelay(1); + + /* Disable +CPU_CORE */ + gpio_set_level(GPIO_VCORE_EN, 0); + + /* Disable wireless */ + wireless_enable(0); + + /* + * Deassert prochot since CPU is off and we're about to drop + * +VCCP. + */ + gpio_set_level(GPIO_CPU_PROCHOT, 0); + + /* Turn off power rails */ + gpio_set_level(GPIO_PP3300_DX_EN, 0); + /* TODO(rspangler: turn off PP5000 after rev.1 */ + return X86_S3; + + case X86_S3S5: + /* Call hooks before we remove power rails */ + hook_notify(HOOK_CHIPSET_SHUTDOWN); + + /* Disable touchpad power */ + gpio_set_level(GPIO_ENABLE_TOUCHPAD, 0); + + /* Turn off power to RAM */ + gpio_set_level(GPIO_PP1350_EN, 0); + + /* Start shutting down */ + return pause_in_s5 ? X86_S5 : X86_S5G3; + + case X86_S5G3: + /* Assert RSMRST# */ + gpio_set_level(GPIO_PCH_RSMRST_L, 0); + gpio_set_level(GPIO_SUSP_VR_EN, 0); + + /* TODO(rspangler): temporary hack on rev.1 boards */ + gpio_set_level(GPIO_PP5000_EN, 0); + + return X86_G3; + } + + return state; +} + +static int host_command_gsv(struct host_cmd_handler_args *args) +{ + const struct ec_params_get_set_value *p = args->params; + struct ec_response_get_set_value *r = args->response; + + if (p->flags & EC_GSV_SET) + pause_in_s5 = p->value; + + r->value = pause_in_s5; + + args->response_size = sizeof(*r); + return EC_RES_SUCCESS; +} +DECLARE_HOST_COMMAND(EC_CMD_GSV_PAUSE_IN_S5, + host_command_gsv, + EC_VER_MASK(0)); + +static int console_command_gsv(int argc, char **argv) +{ + if (argc > 1 && !parse_bool(argv[1], &pause_in_s5)) + return EC_ERROR_INVAL; + + ccprintf("pause_in_s5 = %s\n", pause_in_s5 ? "on" : "off"); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(pause_in_s5, console_command_gsv, + "[on|off]", + "Should the AP pause in S5 during shutdown?", + NULL); + diff --git a/include/config.h b/include/config.h index 21821100a7..ce1147a9d6 100644 --- a/include/config.h +++ b/include/config.h @@ -179,6 +179,7 @@ /* Chipset config */ /* Compile support for the AP chipset; pick at most one */ +#undef CONFIG_CHIPSET_BAYTRAIL /* Intel Bay Trail (x86) */ #undef CONFIG_CHIPSET_GAIA /* Gaia and Ares (ARM) */ #undef CONFIG_CHIPSET_HASWELL /* Intel Haswell (x86) */ #undef CONFIG_CHIPSET_IVYBRIDGE /* Intel Ivy Bridge (x86) */ |