David Hendricks (dhendrix@chromium.org) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/3102
-gerrit
commit f8404bdc9685685f63fdc065b94585248a96e2dc Author: Hung-Te Lin hungte@chromium.org Date: Tue Apr 16 20:03:00 2013 +0800
google/snow: Support sleep/resume.
WIP. Do not submit.
Change-Id: I65681c42eeef2736e55bb906595f42a5b1dfdf11 Signed-off-by: Hung-Te Lin hungte@chromium.org Signed-off-by: David Hendricks dhendrix@chromium.org --- src/cpu/samsung/exynos5250/Makefile.inc | 2 +- src/cpu/samsung/exynos5250/dmc_init_ddr3.c | 14 +++-- src/cpu/samsung/exynos5250/power.c | 7 +-- src/cpu/samsung/exynos5250/setup.h | 4 +- src/mainboard/google/snow/Makefile.inc | 3 + src/mainboard/google/snow/bootblock.c | 12 ++++ src/mainboard/google/snow/mainboard.h | 2 + src/mainboard/google/snow/romstage.c | 97 ++++++++++++++++-------------- src/mainboard/google/snow/wakeup.c | 28 +++++++++ 9 files changed, 113 insertions(+), 56 deletions(-)
diff --git a/src/cpu/samsung/exynos5250/Makefile.inc b/src/cpu/samsung/exynos5250/Makefile.inc index 8788a6c..25d1bc5 100644 --- a/src/cpu/samsung/exynos5250/Makefile.inc +++ b/src/cpu/samsung/exynos5250/Makefile.inc @@ -3,7 +3,7 @@ # image outside of CBFS #INTERMEDIATE += exynos5250_add_bl1
-bootblock-y += pinmux.c mct.c +bootblock-y += pinmux.c mct.c power.c # Clock is required for UART bootblock-$(CONFIG_EARLY_CONSOLE) += clock_init.c bootblock-$(CONFIG_EARLY_CONSOLE) += clock.c diff --git a/src/cpu/samsung/exynos5250/dmc_init_ddr3.c b/src/cpu/samsung/exynos5250/dmc_init_ddr3.c index 5bb8a37..132471d 100644 --- a/src/cpu/samsung/exynos5250/dmc_init_ddr3.c +++ b/src/cpu/samsung/exynos5250/dmc_init_ddr3.c @@ -61,7 +61,8 @@ static void reset_phy_ctrl(void) udelay(500); }
-int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size) +int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size, + int mem_reset) { unsigned int val; struct exynos5_phy_control *phy0_ctrl, *phy1_ctrl; @@ -71,9 +72,14 @@ int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size) phy0_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY0_BASE; phy1_ctrl = (struct exynos5_phy_control *)EXYNOS5_DMC_PHY1_BASE; dmc = (struct exynos5_dmc *)EXYNOS5_DMC_CTRL_BASE; - printk(BIOS_SPEW, "ddr3_mem_ctrl_init: reset phy: "); - reset_phy_ctrl(); - printk(BIOS_SPEW, "done\n"); + + if (mem_reset) { + printk(BIOS_SPEW, "%s: reset phy: ", __func__); + reset_phy_ctrl(); + printk(BIOS_SPEW, "done\n"); + } else { + printk(BIOS_SPEW, "%s: skip mem_reset.\n", __func__); + }
/* Set Impedance Output Driver */ printk(BIOS_SPEW, "ddr3_mem_ctrl_init: Set Impedance Output Driver\n"); diff --git a/src/cpu/samsung/exynos5250/power.c b/src/cpu/samsung/exynos5250/power.c index 8aba0e8..6ed6af7 100644 --- a/src/cpu/samsung/exynos5250/power.c +++ b/src/cpu/samsung/exynos5250/power.c @@ -25,7 +25,7 @@ #include <common.h> #include <arch/hlt.h> #include <arch/io.h> -#include <arch/hlt.h> +#include <arch/stages.h> #include <console/console.h> #include <cpu/samsung/exynos5-common/power.h> #include <cpu/samsung/exynos5250/cpu.h> @@ -122,9 +122,8 @@ void power_exit_wakeup(void) { struct exynos5_power *power = samsung_get_base_power(); - typedef void (*resume_func)(void); - - ((resume_func)power->inform0)(); + ps_hold_setup(); + stage_exit((void *)power->inform0); }
int power_init(void) diff --git a/src/cpu/samsung/exynos5250/setup.h b/src/cpu/samsung/exynos5250/setup.h index 4f7f58c..952c125 100644 --- a/src/cpu/samsung/exynos5250/setup.h +++ b/src/cpu/samsung/exynos5250/setup.h @@ -702,9 +702,11 @@ void mem_ctrl_init(void); * which the DMC uses to decide how to split a memory * chunk into smaller chunks to support concurrent * accesses; may vary across boards. + * @param mem_reset Reset memory when initialization. * @return 0 if ok, SETUP_ERR_... if there is a problem */ -int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size); +int ddr3_mem_ctrl_init(struct mem_timings *mem, unsigned long mem_iv_size, + int mem_reset);
void tzpc_init(void); /* diff --git a/src/mainboard/google/snow/Makefile.inc b/src/mainboard/google/snow/Makefile.inc index 46e366f..84a8c05 100644 --- a/src/mainboard/google/snow/Makefile.inc +++ b/src/mainboard/google/snow/Makefile.inc @@ -17,9 +17,12 @@ ## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ##
+bootblock-y += wakeup.c + romstage-y += mainboard.c romstage-y += memory.c romstage-y += romstage.c +romstage-y += wakeup.c
# ramstage-y += ec.c ramstage-y += ramstage.c diff --git a/src/mainboard/google/snow/bootblock.c b/src/mainboard/google/snow/bootblock.c index d2e0b50..cd617e4 100644 --- a/src/mainboard/google/snow/bootblock.c +++ b/src/mainboard/google/snow/bootblock.c @@ -23,17 +23,29 @@ #include <uart.h> #include <time.h> #include <console/console.h> +#include <cpu/samsung/exynos5-common/exynos5-common.h> #include <cpu/samsung/exynos5250/periph.h> #include <cpu/samsung/exynos5250/pinmux.h> +#include <cpu/samsung/exynos5250/power.h> +#include "mainboard.h"
void bootblock_mainboard_init(void); void bootblock_mainboard_init(void) { + int reset_status; + /* kick off the microsecond timer. We want to do this as early * as we can. */ timer_start();
+ reset_status = power_read_reset_status(); + if (reset_status == S5P_CHECK_DIDLE || + reset_status == S5P_CHECK_LPA) { + if (wakeup_permitted()) + power_exit_wakeup(); + } + exynos_pinmux_config(PERIPH_ID_SPI1, PINMUX_FLAG_NONE); #if CONFIG_EARLY_CONSOLE exynos_pinmux_config(PERIPH_ID_UART3, PINMUX_FLAG_NONE); diff --git a/src/mainboard/google/snow/mainboard.h b/src/mainboard/google/snow/mainboard.h index 6fe371f..17777ad 100644 --- a/src/mainboard/google/snow/mainboard.h +++ b/src/mainboard/google/snow/mainboard.h @@ -35,4 +35,6 @@ enum snow_board_config {
int board_get_config(void);
+int wakeup_permitted(void); + #endif /* MAINBOARD_H */ diff --git a/src/mainboard/google/snow/romstage.c b/src/mainboard/google/snow/romstage.c index 41b88e1..f221055 100644 --- a/src/mainboard/google/snow/romstage.c +++ b/src/mainboard/google/snow/romstage.c @@ -25,6 +25,8 @@
#include <arch/cache.h> #include <arch/gpio.h> +#include <arch/hlt.h> +#include <cpu/samsung/exynos5-common/exynos5-common.h> #include <cpu/samsung/exynos5-common/i2c.h> #include <cpu/samsung/exynos5250/clk.h> #include <cpu/samsung/exynos5250/cpu.h> @@ -46,19 +48,6 @@ #define PMIC_BUS 0 #define MMC0_GPIO_PIN (58)
-#if 0 -static int board_wakeup_permitted(void) -{ - const int gpio = GPIO_Y10; - int is_bad_wake; - - /* We're a bad wakeup if the gpio was defined and was high */ - is_bad_wake = ((gpio != -1) && gpio_get_value(gpio)); - - return !is_bad_wake; -} -#endif - static int setup_pmic(void) { int error = 0; @@ -100,7 +89,22 @@ static int setup_pmic(void) return error; }
-static void initialize_s5p_mshc(void) +static int setup_memory(struct mem_timings *mem, int reset) +{ + int ret; + printk(BIOS_SPEW, "mem: %#x type: %#x, div: %#x, mhz: %#x\n", + mem->mem_manuf, mem->mem_type, mem->mpll_mdiv, + mem->frequency_mhz); + ret = ddr3_mem_ctrl_init(mem, DMC_INTERLEAVE_SIZE, reset); + if (ret) { + printk(BIOS_CRIT, + "%s: Memory controller init failed, err: %#x\n", + __func__, ret); + } + return ret; +} + +static void setup_mmc(void) { /* MMC0: Fixed, 8 bit mode, connected with GPIO. */ if (clock_set_mshci(PERIPH_ID_SDMMC0)) @@ -117,12 +121,12 @@ static void initialize_s5p_mshc(void) exynos_pinmux_config(PERIPH_ID_SDMMC2, 0); }
-static void graphics(void) +static void setup_graphics(void) { exynos_pinmux_config(PERIPH_ID_DPHPD, 0); }
-static void chromeos_gpios(void) +static void setup_chromeos_gpios(void) { struct exynos5_gpio_part1 *gpio_pt1; struct exynos5_gpio_part2 *gpio_pt2; @@ -154,49 +158,50 @@ void main(void) { struct mem_timings *mem; struct arm_clk_ratios *arm_ratios; - int ret; + int is_resume = 0; void *entry; + uint32_t reset_status;
- clock_set_rate(PERIPH_ID_SPI1, 50000000); /* set spi clock to 50Mhz */ + reset_status = power_read_reset_status(); + /* S5P_CHECK_DIDLE / S5P_CHECK_LPA are already handled in bootblock. */ + if (reset_status == S5P_CHECK_SLEEP) + is_resume = 1;
- /* Clock must be initialized before console_init, otherwise you may need - * to re-initialize serial console drivers again. */ + /* Clock must be initialized before console_init, otherwise you + * may need to re-initialize serial console drivers again. */ mem = get_mem_timings(); + if (!mem) + die("Unable to auto-detect memory timings"); arm_ratios = get_arm_clk_ratios(); system_clock_init(mem, arm_ratios); - console_init();
- i2c_init(0, CONFIG_SYS_I2C_SPEED, 0x00); - if (power_init()) - power_shutdown(); - printk(BIOS_DEBUG, "%s: setting up pmic...\n", __func__); - if (setup_pmic()) - power_shutdown(); - - if (!mem) { - printk(BIOS_CRIT, "Unable to auto-detect memory timings\n"); - while(1); + power_init(); + if (!is_resume) { + /* Initialize I2C to program PMIC. */ + i2c_init(0, CONFIG_SYS_I2C_SPEED, 0x00); + printk(BIOS_SPEW, "%s: Set up PMIC.\n", __func__); + if (setup_pmic()) + power_shutdown(); } - printk(BIOS_SPEW, "man: 0x%x type: 0x%x, div: 0x%x, mhz: 0x%x\n", - mem->mem_manuf, - mem->mem_type, - mem->mpll_mdiv, - mem->frequency_mhz);
- ret = ddr3_mem_ctrl_init(mem, DMC_INTERLEAVE_SIZE); - if (ret) { - printk(BIOS_ERR, "Memory controller init failed, err: %x\n", - ret); - while(1); - } - - initialize_s5p_mshc(); + if (setup_memory(mem, !is_resume)) + power_shutdown();
- chromeos_gpios(); + if (is_resume) { + printk(BIOS_SPEW, "%s: Trying to wake up.\n", __func__); + if (!wakeup_permitted()) + power_reset(); + power_exit_wakeup(); + /* Never returns. */ + }
- graphics(); + /* Initialize peripherals. */ + setup_mmc(); + setup_chromeos_gpios(); + setup_graphics();
+ clock_set_rate(PERIPH_ID_SPI1, 50000000); /* set spi clock to 50Mhz */ entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, "fallback/coreboot_ram"); printk(BIOS_INFO, "entry is 0x%p, leaving romstage.\n", entry);
diff --git a/src/mainboard/google/snow/wakeup.c b/src/mainboard/google/snow/wakeup.c new file mode 100644 index 0000000..d5f7a25 --- /dev/null +++ b/src/mainboard/google/snow/wakeup.c @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2012 The Chromium OS Authors. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <arch/gpio.h> +#include <cpu/samsung/exynos5250/gpio.h> + +#include "mainboard.h" + +int wakeup_permitted(void) +{ + /* We're a bad wakeup if the gpio is high */ + return gpio_get_value(GPIO_Y10); +} +