[U-Boot] [PATCH 00/22] x86: Add ACPI S3 resume support

This adds ACPI S3 (suspend to ram) resume capability in U-Boot. With S3 support within U-Boot, the board wakes up and resumes to OS very quickly.
This so far is enabled and tested on Intel MinnowMax board. Please check README.x86 for how to test it with a plain Linux kernel. Note testing with Ubuntu or Windows has some issues and fixes are still being worked out.
This series is available for testing in u-boot-x86/s3-working.
Bin Meng (22): dm: rtc: Add 16-bit read/write support x86: acpi: Add Kconfig option and header file for ACPI resume x86: baytrail: acpi: Add APIs for determining/clearing sleep state x86: Add post codes for OS resume x86: fsp: acpi: Pass different boot mode to FSP init x86: Store and display previous sleep state x86: baytrail: Conditionally report S3 in the ACPI table x86: fsp: Mark memory used by U-Boot as reserved in the E820 table for S3 x86: acpi: Add wake up assembly stub x86: acpi: Add one API to find OS wakeup vector x86: acpi: Resume OS if resume vector is found x86: Add an early CMOS access library x86: fsp: Save stack address to CMOS for next S3 boot x86: fsp: Mark the first 64K low memory as reserved x86: Adjust board_final_cleanup() order x86: apci: Change PM1_CNT register access to RMW x86: acpi: Make enter_acpi_mode() public x86: acpi: Refactor acpi_resume() x86: acpi: Turn on ACPI mode for S3 x86: pci: Allow conditionally run VGA rom in S3 x86: minnowmax: Enable ACPI S3 resume x86: Document ACPI S3 support
arch/x86/Kconfig | 32 ++++++ arch/x86/cpu/Makefile | 1 + arch/x86/cpu/baytrail/acpi.c | 47 +++++++++ arch/x86/cpu/cpu.c | 26 ++++- arch/x86/cpu/wakeup.S | 79 ++++++++++++++ arch/x86/include/asm/acpi_s3.h | 116 +++++++++++++++++++++ arch/x86/include/asm/acpi_table.h | 3 + .../include/asm/arch-baytrail/acpi/sleepstates.asl | 2 + arch/x86/include/asm/arch-baytrail/iomap.h | 24 +++++ arch/x86/include/asm/cmos_layout.h | 31 ++++++ arch/x86/include/asm/early_cmos.h | 43 ++++++++ arch/x86/include/asm/global_data.h | 3 + arch/x86/include/asm/post.h | 2 + arch/x86/include/asm/tables.h | 1 + arch/x86/include/asm/u-boot-x86.h | 1 + arch/x86/lib/Makefile | 2 + arch/x86/lib/acpi_s3.c | 34 ++++++ arch/x86/lib/acpi_table.c | 84 ++++++++++++++- arch/x86/lib/early_cmos.c | 51 +++++++++ arch/x86/lib/fsp/fsp_common.c | 55 +++++++++- arch/x86/lib/fsp/fsp_dram.c | 24 +++++ configs/minnowmax_defconfig | 1 + doc/README.x86 | 20 ++-- drivers/pci/pci_rom.c | 14 +++ drivers/rtc/rtc-uclass.c | 30 ++++++ include/rtc.h | 20 ++++ 26 files changed, 735 insertions(+), 11 deletions(-) create mode 100644 arch/x86/cpu/wakeup.S create mode 100644 arch/x86/include/asm/acpi_s3.h create mode 100644 arch/x86/include/asm/cmos_layout.h create mode 100644 arch/x86/include/asm/early_cmos.h create mode 100644 arch/x86/lib/acpi_s3.c create mode 100644 arch/x86/lib/early_cmos.c

At present there are only 8-bit and 32-bit read/write routines in the rtc uclass driver. This adds the 16-bit support.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
drivers/rtc/rtc-uclass.c | 30 ++++++++++++++++++++++++++++++ include/rtc.h | 20 ++++++++++++++++++++ 2 files changed, 50 insertions(+)
diff --git a/drivers/rtc/rtc-uclass.c b/drivers/rtc/rtc-uclass.c index 300e9b3..89312c5 100644 --- a/drivers/rtc/rtc-uclass.c +++ b/drivers/rtc/rtc-uclass.c @@ -60,6 +60,36 @@ int rtc_write8(struct udevice *dev, unsigned int reg, int val) return ops->write8(dev, reg, val); }
+int rtc_read16(struct udevice *dev, unsigned int reg, u16 *valuep) +{ + u16 value = 0; + int ret; + int i; + + for (i = 0; i < sizeof(value); i++) { + ret = rtc_read8(dev, reg + i); + if (ret < 0) + return ret; + value |= ret << (i << 3); + } + + *valuep = value; + return 0; +} + +int rtc_write16(struct udevice *dev, unsigned int reg, u16 value) +{ + int i, ret; + + for (i = 0; i < sizeof(value); i++) { + ret = rtc_write8(dev, reg + i, (value >> (i << 3)) & 0xff); + if (ret) + return ret; + } + + return 0; +} + int rtc_read32(struct udevice *dev, unsigned int reg, u32 *valuep) { u32 value = 0; diff --git a/include/rtc.h b/include/rtc.h index 69fe8d4..49142b6 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -128,6 +128,26 @@ int rtc_read8(struct udevice *dev, unsigned int reg); int rtc_write8(struct udevice *dev, unsigned int reg, int val);
/** + * rtc_read16() - Read a 16-bit value from the RTC + * + * @dev: Device to read from + * @reg: Offset to start reading from + * @valuep: Place to put the value that is read + * @return 0 if OK, -ve on error + */ +int rtc_read16(struct udevice *dev, unsigned int reg, u16 *valuep); + +/** + * rtc_write16() - Write a 16-bit value to the RTC + * + * @dev: Device to write to + * @reg: Register to start writing to + * @value: Value to write + * @return 0 if OK, -ve on error + */ +int rtc_write16(struct udevice *dev, unsigned int reg, u16 value); + +/** * rtc_read32() - Read a 32-bit value from the RTC * * @dev: Device to read from

On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
At present there are only 8-bit and 32-bit read/write routines in the rtc uclass driver. This adds the 16-bit support.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
drivers/rtc/rtc-uclass.c | 30 ++++++++++++++++++++++++++++++ include/rtc.h | 20 ++++++++++++++++++++ 2 files changed, 50 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

On Fri, Mar 17, 2017 at 11:26 AM, Simon Glass sjg@chromium.org wrote:
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
At present there are only 8-bit and 32-bit read/write routines in the rtc uclass driver. This adds the 16-bit support.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
drivers/rtc/rtc-uclass.c | 30 ++++++++++++++++++++++++++++++ include/rtc.h | 20 ++++++++++++++++++++ 2 files changed, 50 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
applied to u-boot-x86, thanks!

This introduces a Kconfig option for ACPI S3 resume, as well as a header file to include anything related to ACPI S3 resume.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/Kconfig | 12 +++++++++ arch/x86/include/asm/acpi_s3.h | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 arch/x86/include/asm/acpi_s3.h
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index dfdd756..7ea9148 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -571,6 +571,18 @@ config GENERATE_ACPI_TABLE
endmenu
+config HAVE_ACPI_RESUME + bool "Enable ACPI S3 resume" + help + Select this to enable ACPI S3 resume. S3 is an ACPI defined sleeping + state where all system context is lost except system memory. U-Boot + is responsible for restore the machine state as it is before sleep. + It needs restore the memory controller, not overwriting memory which + is not marked as reserved. For the peripherals which lose their + registers, U-Boot needs to write the original value. When everything + is done, U-Boot needs to find out the wakeup vector provided by OSes + and jump there. + config MAX_PIRQ_LINKS int default 8 diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h new file mode 100644 index 0000000..6fbfc3e --- /dev/null +++ b/arch/x86/include/asm/acpi_s3.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ASM_ACPI_S3_H__ +#define __ASM_ACPI_S3_H__ + +/* PM1_STATUS register */ +#define WAK_STS (1 << 15) +#define PCIEXPWAK_STS (1 << 14) +#define RTC_STS (1 << 10) +#define SLPBTN_STS (1 << 9) +#define PWRBTN_STS (1 << 8) +#define GBL_STS (1 << 5) +#define BM_STS (1 << 4) +#define TMR_STS (1 << 0) + +/* PM1_CNT register */ +#define SLP_EN (1 << 13) +#define SLP_TYP_SHIFT 10 +#define SLP_TYP (7 << SLP_TYP_SHIFT) +#define SLP_TYP_S0 0 +#define SLP_TYP_S1 1 +#define SLP_TYP_S3 5 +#define SLP_TYP_S4 6 +#define SLP_TYP_S5 7 + +enum acpi_sleep_state { + ACPI_S0, + ACPI_S1, + ACPI_S2, + ACPI_S3, + ACPI_S4, + ACPI_S5, +}; + +/* Given the provided PM1 control register return the ACPI sleep type */ +static inline enum acpi_sleep_state acpi_sleep_from_pm1(u32 pm1_cnt) +{ + switch ((pm1_cnt & SLP_TYP) >> SLP_TYP_SHIFT) { + case SLP_TYP_S0: + return ACPI_S0; + case SLP_TYP_S1: + return ACPI_S1; + case SLP_TYP_S3: + return ACPI_S3; + case SLP_TYP_S4: + return ACPI_S4; + case SLP_TYP_S5: + return ACPI_S5; + } + + return -1; +} + +#endif /* __ASM_ACPI_S3_H__ */

Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
This introduces a Kconfig option for ACPI S3 resume, as well as a header file to include anything related to ACPI S3 resume.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/Kconfig | 12 +++++++++ arch/x86/include/asm/acpi_s3.h | 58 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 arch/x86/include/asm/acpi_s3.h
Reviewed-by: Simon Glass sjg@chromium.org
A few nits below
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index dfdd756..7ea9148 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -571,6 +571,18 @@ config GENERATE_ACPI_TABLE
endmenu
+config HAVE_ACPI_RESUME
bool "Enable ACPI S3 resume"
help
Select this to enable ACPI S3 resume. S3 is an ACPI defined sleeping
ACPI-defined
state where all system context is lost except system memory. U-Boot
is responsible for restore the machine state as it is before sleep.
restoring
as it was before
It needs restore the memory controller, not overwriting memory which
s/not/without/ ?
is not marked as reserved. For the peripherals which lose their
registers, U-Boot needs to write the original value. When everything
is done, U-Boot needs to find out the wakeup vector provided by OSes
and jump there.
config MAX_PIRQ_LINKS int default 8 diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h new file mode 100644 index 0000000..6fbfc3e --- /dev/null +++ b/arch/x86/include/asm/acpi_s3.h @@ -0,0 +1,58 @@ +/*
- Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __ASM_ACPI_S3_H__ +#define __ASM_ACPI_S3_H__
+/* PM1_STATUS register */ +#define WAK_STS (1 << 15) +#define PCIEXPWAK_STS (1 << 14) +#define RTC_STS (1 << 10) +#define SLPBTN_STS (1 << 9) +#define PWRBTN_STS (1 << 8) +#define GBL_STS (1 << 5) +#define BM_STS (1 << 4) +#define TMR_STS (1 << 0)
+/* PM1_CNT register */ +#define SLP_EN (1 << 13) +#define SLP_TYP_SHIFT 10 +#define SLP_TYP (7 << SLP_TYP_SHIFT) +#define SLP_TYP_S0 0 +#define SLP_TYP_S1 1 +#define SLP_TYP_S3 5 +#define SLP_TYP_S4 6 +#define SLP_TYP_S5 7
+enum acpi_sleep_state {
ACPI_S0,
ACPI_S1,
ACPI_S2,
ACPI_S3,
ACPI_S4,
ACPI_S5,
+};
+/* Given the provided PM1 control register return the ACPI sleep type */
@return ...
Does this need to be inline?
+static inline enum acpi_sleep_state acpi_sleep_from_pm1(u32 pm1_cnt) +{
switch ((pm1_cnt & SLP_TYP) >> SLP_TYP_SHIFT) {
case SLP_TYP_S0:
return ACPI_S0;
case SLP_TYP_S1:
return ACPI_S1;
case SLP_TYP_S3:
return ACPI_S3;
case SLP_TYP_S4:
return ACPI_S4;
case SLP_TYP_S5:
return ACPI_S5;
}
return -1;
-EINVAL ?
+}
+#endif /* __ASM_ACPI_S3_H__ */
2.9.2
Regards, Simon

This adds APIs for determining previous sleep state from ACPI I/O registers, as well as clearing sleep state on BayTrail SoC.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/cpu/baytrail/acpi.c | 47 ++++++++++++++++++++++++++++++ arch/x86/include/asm/arch-baytrail/iomap.h | 24 +++++++++++++++ 2 files changed, 71 insertions(+)
diff --git a/arch/x86/cpu/baytrail/acpi.c b/arch/x86/cpu/baytrail/acpi.c index fa92d88..55ed7de 100644 --- a/arch/x86/cpu/baytrail/acpi.c +++ b/arch/x86/cpu/baytrail/acpi.c @@ -8,7 +8,9 @@ #include <cpu.h> #include <dm.h> #include <dm/uclass-internal.h> +#include <asm/acpi_s3.h> #include <asm/acpi_table.h> +#include <asm/io.h> #include <asm/ioapic.h> #include <asm/mpspec.h> #include <asm/tables.h> @@ -187,3 +189,48 @@ void acpi_create_gnvs(struct acpi_global_nvs *gnvs) else gnvs->iuart_en = 0; } + +#ifdef CONFIG_HAVE_ACPI_RESUME +/* + * The following two routines are called at a very early stage, even before + * FSP 2nd phase API fsp_init() is called. Registers off ACPI_BASE_ADDRESS + * and PMC_BASE_ADDRESS are accessed, so we need make sure the base addresses + * of these two blocks are programmed by either U-Boot or FSP. + * + * It has been verified that 1st phase API (see arch/x86/lib/fsp/fsp_car.S) + * on Intel BayTrail SoC already initializes these two base addresses so + * we are safe to access these registers here. + */ + +enum acpi_sleep_state chipset_prev_sleep_state(void) +{ + u32 pm1_sts; + u32 pm1_cnt; + u32 gen_pmcon1; + enum acpi_sleep_state prev_sleep_state = ACPI_S0; + + /* Read Power State */ + pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS); + pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT); + gen_pmcon1 = readl(PMC_BASE_ADDRESS + GEN_PMCON1); + + debug("PM1_STS = 0x%x PM1_CNT = 0x%x GEN_PMCON1 = 0x%x\n", + pm1_sts, pm1_cnt, gen_pmcon1); + + if (pm1_sts & WAK_STS) + prev_sleep_state = acpi_sleep_from_pm1(pm1_cnt); + + if (gen_pmcon1 & (PWR_FLR | SUS_PWR_FLR)) + prev_sleep_state = ACPI_S5; + + return prev_sleep_state; +} + +void chipset_clear_sleep_state(void) +{ + u32 pm1_cnt; + + pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT); + outl(pm1_cnt & ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT); +} +#endif diff --git a/arch/x86/include/asm/arch-baytrail/iomap.h b/arch/x86/include/asm/arch-baytrail/iomap.h index 62a9105..ec4e9d5 100644 --- a/arch/x86/include/asm/arch-baytrail/iomap.h +++ b/arch/x86/include/asm/arch-baytrail/iomap.h @@ -35,6 +35,27 @@ #define PMC_BASE_ADDRESS 0xfed03000 #define PMC_BASE_SIZE 0x400
+#define GEN_PMCON1 0x20 +#define UART_EN (1 << 24) +#define DISB (1 << 23) +#define MEM_SR (1 << 21) +#define SRS (1 << 20) +#define CTS (1 << 19) +#define MS4V (1 << 18) +#define PWR_FLR (1 << 16) +#define PME_B0_S5_DIS (1 << 15) +#define SUS_PWR_FLR (1 << 14) +#define WOL_EN_OVRD (1 << 13) +#define DIS_SLP_X_STRCH_SUS_UP (1 << 12) +#define GEN_RST_STS (1 << 9) +#define RPS (1 << 2) +#define AFTERG3_EN (1 << 0) +#define GEN_PMCON2 0x24 +#define SLPSX_STR_POL_LOCK (1 << 18) +#define BIOS_PCI_EXP_EN (1 << 10) +#define PWRBTN_LVL (1 << 9) +#define SMI_LOCK (1 << 4) + /* Power Management Unit */ #define PUNIT_BASE_ADDRESS 0xfed05000 #define PUNIT_BASE_SIZE 0x800 @@ -62,6 +83,9 @@ #define ACPI_BASE_ADDRESS 0x0400 #define ACPI_BASE_SIZE 0x80
+#define PM1_STS 0x00 +#define PM1_CNT 0x04 + #define GPIO_BASE_ADDRESS 0x0500 #define GPIO_BASE_SIZE 0x100

On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
This adds APIs for determining previous sleep state from ACPI I/O registers, as well as clearing sleep state on BayTrail SoC.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/baytrail/acpi.c | 47 ++++++++++++++++++++++++++++++ arch/x86/include/asm/arch-baytrail/iomap.h | 24 +++++++++++++++ 2 files changed, 71 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

This adds OS_RESUME (0x40) and RESUME_FAILURE (0xed) post codes.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/include/asm/post.h | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/x86/include/asm/post.h b/arch/x86/include/asm/post.h index 6b774bd..f627663 100644 --- a/arch/x86/include/asm/post.h +++ b/arch/x86/include/asm/post.h @@ -31,10 +31,12 @@ #define POST_MRC 0x2f #define POST_DRAM 0x30 #define POST_LAPIC 0x31 +#define POST_OS_RESUME 0x40
#define POST_RAM_FAILURE 0xea #define POST_BIST_FAILURE 0xeb #define POST_CAR_FAILURE 0xec +#define POST_RESUME_FAILURE 0xed
/* Output a post code using al - value must be 0 to 0xff */ #ifdef __ASSEMBLY__

On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
This adds OS_RESUME (0x40) and RESUME_FAILURE (0xed) post codes.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/include/asm/post.h | 2 ++ 1 file changed, 2 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

When ACPI S3 resume is turned on, we should pass different boot mode to FSP init instead of default BOOT_FULL_CONFIG.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/include/asm/acpi_s3.h | 18 ++++++++++++++++++ arch/x86/lib/fsp/fsp_common.c | 26 +++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index 6fbfc3e..74878c1 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -55,4 +55,22 @@ static inline enum acpi_sleep_state acpi_sleep_from_pm1(u32 pm1_cnt) return -1; }
+/** + * chipset_prev_sleep_state() - Get chipset previous sleep state + * + * This returns chipset previous sleep state from ACPI registers. + * Platform codes must supply this routine in order to support ACPI S3. + * + * @return ACPI_S0/S1/S2/S3/S4/S5. + */ +enum acpi_sleep_state chipset_prev_sleep_state(void); + +/** + * chipset_clear_sleep_state() - Clear chipset sleep state + * + * This clears chipset sleep state in ACPI registers. + * Platform codes must supply this routine in order to support ACPI S3. + */ +void chipset_clear_sleep_state(void); + #endif /* __ASM_ACPI_S3_H__ */ diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 8479af1..2058ee3 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -6,6 +6,7 @@
#include <common.h> #include <errno.h> +#include <asm/acpi_s3.h> #include <asm/io.h> #include <asm/mrccache.h> #include <asm/post.h> @@ -73,6 +74,10 @@ static __maybe_unused void *fsp_prepare_mrc_cache(void) int x86_fsp_init(void) { void *nvs; + int boot_mode = BOOT_FULL_CONFIG; +#ifdef CONFIG_HAVE_ACPI_RESUME + int prev_sleep_state = chipset_prev_sleep_state(); +#endif
if (!gd->arch.hob_list) { #ifdef CONFIG_ENABLE_MRC_CACHE @@ -80,12 +85,31 @@ int x86_fsp_init(void) #else nvs = NULL; #endif + +#ifdef CONFIG_HAVE_ACPI_RESUME + if (prev_sleep_state == ACPI_S3) { + if (nvs == NULL) { + /* If waking from S3 and no cache then */ + debug("No MRC cache found in S3 resume path\n"); + post_code(POST_RESUME_FAILURE); + /* Clear Sleep Type */ + chipset_clear_sleep_state(); + /* Reboot */ + debug("Rebooting..\n"); + reset_cpu(0); + /* Should not reach here.. */ + panic("Reboot System"); + } + + boot_mode = BOOT_ON_S3_RESUME; + } +#endif /* * The first time we enter here, call fsp_init(). * Note the execution does not return to this function, * instead it jumps to fsp_continue(). */ - fsp_init(CONFIG_FSP_TEMP_RAM_ADDR, BOOT_FULL_CONFIG, nvs); + fsp_init(CONFIG_FSP_TEMP_RAM_ADDR, boot_mode, nvs); } else { /* * The second time we enter here, adjust the size of malloc()

On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
When ACPI S3 resume is turned on, we should pass different boot mode to FSP init instead of default BOOT_FULL_CONFIG.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/include/asm/acpi_s3.h | 18 ++++++++++++++++++ arch/x86/lib/fsp/fsp_common.c | 26 +++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org

Add one member in the global data to store previous sleep state, and display the state during boot in print_cpuinfo().
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/cpu/cpu.c | 6 ++++++ arch/x86/include/asm/acpi_s3.h | 20 ++++++++++++++++++++ arch/x86/include/asm/global_data.h | 3 +++ arch/x86/lib/fsp/fsp_common.c | 1 + 4 files changed, 30 insertions(+)
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 8fa6953..9dde54c 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -25,6 +25,7 @@ #include <errno.h> #include <malloc.h> #include <syscon.h> +#include <asm/acpi_s3.h> #include <asm/control_regs.h> #include <asm/coreboot_tables.h> #include <asm/cpu.h> @@ -179,6 +180,11 @@ int default_print_cpuinfo(void) cpu_has_64bit() ? "x86_64" : "x86", cpu_vendor_name(gd->arch.x86_vendor), gd->arch.x86_device);
+#ifdef CONFIG_HAVE_ACPI_RESUME + printf("ACPI previous sleep state: %s\n", + acpi_ss_string(gd->arch.prev_sleep_state)); +#endif + return 0; }
diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index 74878c1..c1cdbd0 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -36,6 +36,26 @@ enum acpi_sleep_state { ACPI_S5, };
+/* Given the ACPI sleep state return the state string */ +static inline char *acpi_ss_string(enum acpi_sleep_state state) +{ + switch (state) { + case ACPI_S0: + return "S0"; + case ACPI_S1: + return "S1"; + case ACPI_S2: + return "S2"; + case ACPI_S3: + return "S3"; + case ACPI_S4: + return "S4"; + case ACPI_S5: + default: + return "S5"; + } +} + /* Given the provided PM1 control register return the ACPI sleep type */ static inline enum acpi_sleep_state acpi_sleep_from_pm1(u32 pm1_cnt) { diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 4570bc7..7d5efea 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -99,6 +99,9 @@ struct arch_global_data { u32 high_table_ptr; u32 high_table_limit; #endif +#ifdef CONFIG_HAVE_ACPI_RESUME + int prev_sleep_state; /* Previous sleep state */ +#endif };
#endif diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 2058ee3..2b33fba 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -77,6 +77,7 @@ int x86_fsp_init(void) int boot_mode = BOOT_FULL_CONFIG; #ifdef CONFIG_HAVE_ACPI_RESUME int prev_sleep_state = chipset_prev_sleep_state(); + gd->arch.prev_sleep_state = prev_sleep_state; #endif
if (!gd->arch.hob_list) {

Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
Add one member in the global data to store previous sleep state, and display the state during boot in print_cpuinfo().
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/cpu.c | 6 ++++++ arch/x86/include/asm/acpi_s3.h | 20 ++++++++++++++++++++ arch/x86/include/asm/global_data.h | 3 +++ arch/x86/lib/fsp/fsp_common.c | 1 + 4 files changed, 30 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 8fa6953..9dde54c 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -25,6 +25,7 @@ #include <errno.h> #include <malloc.h> #include <syscon.h> +#include <asm/acpi_s3.h> #include <asm/control_regs.h> #include <asm/coreboot_tables.h> #include <asm/cpu.h> @@ -179,6 +180,11 @@ int default_print_cpuinfo(void) cpu_has_64bit() ? "x86_64" : "x86", cpu_vendor_name(gd->arch.x86_vendor), gd->arch.x86_device);
+#ifdef CONFIG_HAVE_ACPI_RESUME
printf("ACPI previous sleep state: %s\n",
acpi_ss_string(gd->arch.prev_sleep_state));
+#endif
return 0;
}
diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index 74878c1..c1cdbd0 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -36,6 +36,26 @@ enum acpi_sleep_state { ACPI_S5, };
+/* Given the ACPI sleep state return the state string */ +static inline char *acpi_ss_string(enum acpi_sleep_state state) +{
switch (state) {
case ACPI_S0:
return "S0";
Since this is your own enum can you use a string array for this?
case ACPI_S1:
return "S1";
case ACPI_S2:
return "S2";
case ACPI_S3:
return "S3";
case ACPI_S4:
return "S4";
case ACPI_S5:
default:
return "S5";
}
+}
/* Given the provided PM1 control register return the ACPI sleep type */ static inline enum acpi_sleep_state acpi_sleep_from_pm1(u32 pm1_cnt) { diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 4570bc7..7d5efea 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -99,6 +99,9 @@ struct arch_global_data { u32 high_table_ptr; u32 high_table_limit; #endif +#ifdef CONFIG_HAVE_ACPI_RESUME
int prev_sleep_state; /* Previous sleep state */
What kind of value does this have? Can you add a little detail>
+#endif };
#endif diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 2058ee3..2b33fba 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -77,6 +77,7 @@ int x86_fsp_init(void) int boot_mode = BOOT_FULL_CONFIG; #ifdef CONFIG_HAVE_ACPI_RESUME int prev_sleep_state = chipset_prev_sleep_state();
gd->arch.prev_sleep_state = prev_sleep_state;
#endif
if (!gd->arch.hob_list) {
-- 2.9.2
Regard, Simon

When U-Boot is built without ACPI S3 support, it should not report S3 in the ACPI table otherwise when kernel does STR it won't work.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/include/asm/arch-baytrail/acpi/sleepstates.asl | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/arch/x86/include/asm/arch-baytrail/acpi/sleepstates.asl b/arch/x86/include/asm/arch-baytrail/acpi/sleepstates.asl index eb5ae76..5600723 100644 --- a/arch/x86/include/asm/arch-baytrail/acpi/sleepstates.asl +++ b/arch/x86/include/asm/arch-baytrail/acpi/sleepstates.asl @@ -8,6 +8,8 @@ */
Name(_S0, Package() {0x0, 0x0, 0x0, 0x0}) +#ifdef CONFIG_HAVE_ACPI_RESUME Name(_S3, Package() {0x5, 0x0, 0x0, 0x0}) +#endif Name(_S4, Package() {0x6, 0x0, 0x0, 0x0}) Name(_S5, Package() {0x7, 0x0, 0x0, 0x0})

On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
When U-Boot is built without ACPI S3 support, it should not report S3 in the ACPI table otherwise when kernel does STR it won't work.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/include/asm/arch-baytrail/acpi/sleepstates.asl | 2 ++ 1 file changed, 2 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

U-Boot itself as well as everything that is consumed by U-Boot (like heap, stack, dtb, etc) needs to be reserved and reported in the E820 table when S3 resume is on.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/Kconfig | 8 ++++++++ arch/x86/lib/fsp/fsp_dram.c | 12 ++++++++++++ 2 files changed, 20 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7ea9148..95a65ff 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -583,6 +583,14 @@ config HAVE_ACPI_RESUME is done, U-Boot needs to find out the wakeup vector provided by OSes and jump there.
+config STACK_SIZE + hex + depends on HAVE_ACPI_RESUME + default 0x1000 + help + Estimated U-Boot's runtime stack size that needs to be reserved + during an ACPI S3 resume. + config MAX_PIRQ_LINKS int default 8 diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c index fcfe693..417c611 100644 --- a/arch/x86/lib/fsp/fsp_dram.c +++ b/arch/x86/lib/fsp/fsp_dram.c @@ -90,5 +90,17 @@ unsigned install_e820_map(unsigned max_entries, struct e820entry *entries) entries[num_entries].type = E820_RESERVED; num_entries++;
+#ifdef CONFIG_HAVE_ACPI_RESUME + /* + * Everything between U-Boot's stack and ram top needs to be + * reserved in order for ACPI S3 resume to work. + */ + entries[num_entries].addr = gd->start_addr_sp - CONFIG_STACK_SIZE; + entries[num_entries].size = gd->ram_top - gd->start_addr_sp + \ + CONFIG_STACK_SIZE; + entries[num_entries].type = E820_RESERVED; + num_entries++; +#endif + return num_entries; }

Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
U-Boot itself as well as everything that is consumed by U-Boot (like heap, stack, dtb, etc) needs to be reserved and reported in the E820 table when S3 resume is on.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/Kconfig | 8 ++++++++ arch/x86/lib/fsp/fsp_dram.c | 12 ++++++++++++ 2 files changed, 20 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
Can you detect if the stack space is too small?
It should be possible to measure the stack size easily enough - e.g. using cpu_get_sp().
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 7ea9148..95a65ff 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -583,6 +583,14 @@ config HAVE_ACPI_RESUME is done, U-Boot needs to find out the wakeup vector provided by OSes and jump there.
+config STACK_SIZE
hex
depends on HAVE_ACPI_RESUME
default 0x1000
help
Estimated U-Boot's runtime stack size that needs to be reserved
during an ACPI S3 resume.
config MAX_PIRQ_LINKS int default 8 diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c index fcfe693..417c611 100644 --- a/arch/x86/lib/fsp/fsp_dram.c +++ b/arch/x86/lib/fsp/fsp_dram.c @@ -90,5 +90,17 @@ unsigned install_e820_map(unsigned max_entries, struct e820entry *entries) entries[num_entries].type = E820_RESERVED; num_entries++;
+#ifdef CONFIG_HAVE_ACPI_RESUME
/*
* Everything between U-Boot's stack and ram top needs to be
* reserved in order for ACPI S3 resume to work.
*/
entries[num_entries].addr = gd->start_addr_sp - CONFIG_STACK_SIZE;
entries[num_entries].size = gd->ram_top - gd->start_addr_sp + \
CONFIG_STACK_SIZE;
entries[num_entries].type = E820_RESERVED;
num_entries++;
+#endif
return num_entries;
}
2.9.2
Regaeds, Simon

Hi Simon,
On Wed, Mar 22, 2017 at 4:06 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
U-Boot itself as well as everything that is consumed by U-Boot (like heap, stack, dtb, etc) needs to be reserved and reported in the E820 table when S3 resume is on.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/Kconfig | 8 ++++++++ arch/x86/lib/fsp/fsp_dram.c | 12 ++++++++++++ 2 files changed, 20 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
Can you detect if the stack space is too small?
It should be possible to measure the stack size easily enough - e.g. using cpu_get_sp().
I suspect we can fill the stack memory with some magic number, and then after U-Boot boots to shell check the stack to see where the pattern ends. This practice should be done periodically as U-Boot's code base changes very rapidly.
Regards, Bin

This adds a wake up stub before jumping to OS wake up vector.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/cpu/Makefile | 1 + arch/x86/cpu/wakeup.S | 79 ++++++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/acpi_s3.h | 9 +++++ 3 files changed, 89 insertions(+) create mode 100644 arch/x86/cpu/wakeup.S
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 92a9023..e1c84ce 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -45,6 +45,7 @@ ifndef CONFIG_$(SPL_)X86_64 obj-$(CONFIG_SMP) += sipi_vector.o endif obj-y += turbo.o +obj-$(CONFIG_HAVE_ACPI_RESUME) += wakeup.o
ifeq ($(CONFIG_$(SPL_)X86_64),y) obj-y += x86_64/ diff --git a/arch/x86/cpu/wakeup.S b/arch/x86/cpu/wakeup.S new file mode 100644 index 0000000..97b1c21 --- /dev/null +++ b/arch/x86/cpu/wakeup.S @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com + * + * From coreboot src/arch/x86/wakeup.S + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <asm/acpi_s3.h> +#include <asm/processor.h> +#include <asm/processor-flags.h> + +#define RELOCATED(x) (x - __wakeup + WAKEUP_BASE) + +#define CODE_SEG (X86_GDT_ENTRY_16BIT_CS * X86_GDT_ENTRY_SIZE) +#define DATA_SEG (X86_GDT_ENTRY_16BIT_DS * X86_GDT_ENTRY_SIZE) + + .code32 + .globl __wakeup +__wakeup: + /* First prepare the jmp to the resume vector */ + mov 0x4(%esp), %eax /* vector */ + /* last 4 bits of linear addr are taken as offset */ + andw $0x0f, %ax + movw %ax, (__wakeup_offset) + mov 0x4(%esp), %eax + /* the rest is taken as segment */ + shr $4, %eax + movw %ax, (__wakeup_segment) + + /* Activate the right segment descriptor real mode */ + ljmp $CODE_SEG, $RELOCATED(1f) +1: + /* 16 bit code from here on... */ + .code16 + + /* + * Load the segment registers w/ properly configured + * segment descriptors. They will retain these + * configurations (limits, writability, etc.) once + * protected mode is turned off. + */ + mov $DATA_SEG, %ax + mov %ax, %ds + mov %ax, %es + mov %ax, %fs + mov %ax, %gs + mov %ax, %ss + + /* Turn off protection */ + movl %cr0, %eax + andl $~X86_CR0_PE, %eax + movl %eax, %cr0 + + /* Now really going into real mode */ + ljmp $0, $RELOCATED(1f) +1: + movw $0x0, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movw %ax, %fs + movw %ax, %gs + + /* + * This is a FAR JMP to the OS waking vector. + * The C code changed the address to be correct. + */ + .byte 0xea + +__wakeup_offset = RELOCATED(.) + .word 0x0000 + +__wakeup_segment = RELOCATED(.) + .word 0x0000 + + .globl __wakeup_size +__wakeup_size: + .long . - __wakeup diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index c1cdbd0..f9d4739 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -7,6 +7,8 @@ #ifndef __ASM_ACPI_S3_H__ #define __ASM_ACPI_S3_H__
+#define WAKEUP_BASE 0x600 + /* PM1_STATUS register */ #define WAK_STS (1 << 15) #define PCIEXPWAK_STS (1 << 14) @@ -27,6 +29,11 @@ #define SLP_TYP_S4 6 #define SLP_TYP_S5 7
+#ifndef __ASSEMBLY__ + +extern char __wakeup[]; +extern int __wakeup_size; + enum acpi_sleep_state { ACPI_S0, ACPI_S1, @@ -93,4 +100,6 @@ enum acpi_sleep_state chipset_prev_sleep_state(void); */ void chipset_clear_sleep_state(void);
+#endif /* __ASSEMBLY__ */ + #endif /* __ASM_ACPI_S3_H__ */

Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
This adds a wake up stub before jumping to OS wake up vector.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/Makefile | 1 + arch/x86/cpu/wakeup.S | 79 ++++++++++++++++++++++++++++++++++++++++++ arch/x86/include/asm/acpi_s3.h | 9 +++++ 3 files changed, 89 insertions(+) create mode 100644 arch/x86/cpu/wakeup.S
Reviewed-by: Simon Glass sjg@chromium.org
nits below.
diff --git a/arch/x86/cpu/Makefile b/arch/x86/cpu/Makefile index 92a9023..e1c84ce 100644 --- a/arch/x86/cpu/Makefile +++ b/arch/x86/cpu/Makefile @@ -45,6 +45,7 @@ ifndef CONFIG_$(SPL_)X86_64 obj-$(CONFIG_SMP) += sipi_vector.o endif obj-y += turbo.o +obj-$(CONFIG_HAVE_ACPI_RESUME) += wakeup.o
ifeq ($(CONFIG_$(SPL_)X86_64),y) obj-y += x86_64/ diff --git a/arch/x86/cpu/wakeup.S b/arch/x86/cpu/wakeup.S new file mode 100644 index 0000000..97b1c21 --- /dev/null +++ b/arch/x86/cpu/wakeup.S @@ -0,0 +1,79 @@ +/*
- Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com
- From coreboot src/arch/x86/wakeup.S
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <asm/acpi_s3.h> +#include <asm/processor.h> +#include <asm/processor-flags.h>
+#define RELOCATED(x) (x - __wakeup + WAKEUP_BASE)
How about brackets around the second x
+#define CODE_SEG (X86_GDT_ENTRY_16BIT_CS * X86_GDT_ENTRY_SIZE) +#define DATA_SEG (X86_GDT_ENTRY_16BIT_DS * X86_GDT_ENTRY_SIZE)
.code32
.globl __wakeup
+__wakeup:
/* First prepare the jmp to the resume vector */
mov 0x4(%esp), %eax /* vector */
/* last 4 bits of linear addr are taken as offset */
andw $0x0f, %ax
movw %ax, (__wakeup_offset)
mov 0x4(%esp), %eax
/* the rest is taken as segment */
shr $4, %eax
movw %ax, (__wakeup_segment)
/* Activate the right segment descriptor real mode */
ljmp $CODE_SEG, $RELOCATED(1f)
+1:
/* 16 bit code from here on... */
.code16
/*
* Load the segment registers w/ properly configured
* segment descriptors. They will retain these
* configurations (limits, writability, etc.) once
* protected mode is turned off.
Can you word-wrap to use more columns?
*/
mov $DATA_SEG, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
mov %ax, %ss
/* Turn off protection */
movl %cr0, %eax
andl $~X86_CR0_PE, %eax
movl %eax, %cr0
/* Now really going into real mode */
ljmp $0, $RELOCATED(1f)
+1:
movw $0x0, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %ss
movw %ax, %fs
movw %ax, %gs
/*
* This is a FAR JMP to the OS waking vector.
* The C code changed the address to be correct.
s/changed/changes/
*/
.byte 0xea
+__wakeup_offset = RELOCATED(.)
.word 0x0000
+__wakeup_segment = RELOCATED(.)
.word 0x0000
.globl __wakeup_size
+__wakeup_size:
.long . - __wakeup
diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index c1cdbd0..f9d4739 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -7,6 +7,8 @@ #ifndef __ASM_ACPI_S3_H__ #define __ASM_ACPI_S3_H__
+#define WAKEUP_BASE 0x600
/* PM1_STATUS register */ #define WAK_STS (1 << 15) #define PCIEXPWAK_STS (1 << 14) @@ -27,6 +29,11 @@ #define SLP_TYP_S4 6 #define SLP_TYP_S5 7
+#ifndef __ASSEMBLY__
+extern char __wakeup[]; +extern int __wakeup_size;
Comments?
enum acpi_sleep_state { ACPI_S0, ACPI_S1, @@ -93,4 +100,6 @@ enum acpi_sleep_state chipset_prev_sleep_state(void); */ void chipset_clear_sleep_state(void);
+#endif /* __ASSEMBLY__ */
#endif /* __ASM_ACPI_S3_H__ */
2.9.2
Regards, Simon

This adds one API acpi_find_wakeup_vector() to locate OS wakeup vector from the ACPI FACS table, to be used in the S3 boot path.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/include/asm/acpi_table.h | 1 + arch/x86/include/asm/tables.h | 1 + arch/x86/lib/acpi_table.c | 72 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+)
diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h index bbd80a1..6cadd90 100644 --- a/arch/x86/include/asm/acpi_table.h +++ b/arch/x86/include/asm/acpi_table.h @@ -317,3 +317,4 @@ int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, u32 acpi_fill_madt(u32 current); void acpi_create_gnvs(struct acpi_global_nvs *gnvs); ulong write_acpi_tables(ulong start); +void *acpi_find_wakeup_vector(void); diff --git a/arch/x86/include/asm/tables.h b/arch/x86/include/asm/tables.h index d1b2388..9e8208b 100644 --- a/arch/x86/include/asm/tables.h +++ b/arch/x86/include/asm/tables.h @@ -15,6 +15,7 @@ * PIRQ routing table, Multi-Processor table and ACPI table. */ #define ROM_TABLE_ADDR 0xf0000 +#define ROM_TABLE_END 0xfffff
#define ROM_TABLE_ALIGN 1024
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index 355456d..f118345 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -438,3 +438,75 @@ ulong write_acpi_tables(ulong start)
return current; } + +static struct acpi_rsdp *acpi_valid_rsdp(struct acpi_rsdp *rsdp) +{ + if (strncmp((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) + return NULL; + + debug("Looking on %p for valid checksum\n", rsdp); + + if (table_compute_checksum((void *)rsdp, 20) != 0) + return NULL; + debug("acpi rsdp checksum 1 passed\n"); + + if ((rsdp->revision > 1) && + (table_compute_checksum((void *)rsdp, rsdp->length) != 0)) + return NULL; + debug("acpi rsdp checksum 2 passed\n"); + + return rsdp; +} + +void *acpi_find_wakeup_vector(void) +{ + char *p, *end; + struct acpi_rsdp *rsdp = NULL; + struct acpi_rsdt *rsdt; + struct acpi_fadt *fadt = NULL; + struct acpi_facs *facs; + void *wake_vec; + int i; + + debug("Trying to find the wakeup vector...\n"); + + /* Find RSDP */ + for (p = (char *)ROM_TABLE_ADDR; p < (char *)ROM_TABLE_END; p += 16) { + rsdp = acpi_valid_rsdp((struct acpi_rsdp *)p); + if (rsdp) + break; + } + + if (rsdp == NULL) + return NULL; + + debug("RSDP found at %p\n", rsdp); + rsdt = (struct acpi_rsdt *)rsdp->rsdt_address; + + end = (char *)rsdt + rsdt->header.length; + debug("RSDT found at %p ends at %p\n", rsdt, end); + + for (i = 0; ((char *)&rsdt->entry[i]) < end; i++) { + fadt = (struct acpi_fadt *)rsdt->entry[i]; + if (strncmp((char *)fadt, "FACP", 4) == 0) + break; + fadt = NULL; + } + + if (fadt == NULL) + return NULL; + + debug("FADT found at %p\n", fadt); + facs = (struct acpi_facs *)fadt->firmware_ctrl; + + if (facs == NULL) { + debug("No FACS found, wake up from S3 not possible.\n"); + return NULL; + } + + debug("FACS found at %p\n", facs); + wake_vec = (void *)facs->firmware_waking_vector; + debug("OS waking vector is %p\n", wake_vec); + + return wake_vec; +}

Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
This adds one API acpi_find_wakeup_vector() to locate OS wakeup vector from the ACPI FACS table, to be used in the S3 boot path.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/include/asm/acpi_table.h | 1 + arch/x86/include/asm/tables.h | 1 + arch/x86/lib/acpi_table.c | 72 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+)
diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h index bbd80a1..6cadd90 100644 --- a/arch/x86/include/asm/acpi_table.h +++ b/arch/x86/include/asm/acpi_table.h @@ -317,3 +317,4 @@ int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, u32 acpi_fill_madt(u32 current); void acpi_create_gnvs(struct acpi_global_nvs *gnvs); ulong write_acpi_tables(ulong start); +void *acpi_find_wakeup_vector(void);
Function comment? [...]
Regards, Simon

In an S3 resume path, U-Boot does everything like a cold boot except in the last_stage_init() it jumps to the OS resume vector.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/cpu/cpu.c | 8 ++++++++ arch/x86/include/asm/acpi_s3.h | 10 ++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_s3.c | 26 ++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 arch/x86/lib/acpi_s3.c
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 9dde54c..afc8645 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -26,6 +26,7 @@ #include <malloc.h> #include <syscon.h> #include <asm/acpi_s3.h> +#include <asm/acpi_table.h> #include <asm/control_regs.h> #include <asm/coreboot_tables.h> #include <asm/cpu.h> @@ -204,6 +205,13 @@ __weak void board_final_cleanup(void)
int last_stage_init(void) { +#if CONFIG_HAVE_ACPI_RESUME + void *wake_vector = acpi_find_wakeup_vector(); + + if (wake_vector != NULL && gd->arch.prev_sleep_state == ACPI_S3) + acpi_resume(wake_vector); +#endif + write_tables();
board_final_cleanup(); diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index f9d4739..5892a8b 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -100,6 +100,16 @@ enum acpi_sleep_state chipset_prev_sleep_state(void); */ void chipset_clear_sleep_state(void);
+/** + * acpi_resume() - Do ACPI S3 resume + * + * This calls U-Boot wake up assembly stub and jumps to OS's wake up vector. + * + * @wake_vec: OS wake up vector + * @return: Never returns + */ +void acpi_resume(void *wake_vec); + #endif /* __ASSEMBLY__ */
#endif /* __ASM_ACPI_S3_H__ */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 1c2c085..c61f931 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sections.o obj-y += sfi.o obj-y += string.o +obj-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.o ifndef CONFIG_QEMU obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o endif diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c new file mode 100644 index 0000000..f679c06 --- /dev/null +++ b/arch/x86/lib/acpi_s3.c @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/acpi_s3.h> +#include <asm/post.h> + +static void asmlinkage (*acpi_do_wakeup)(void *vector) = (void *)WAKEUP_BASE; + +static void acpi_jump_to_wakeup(void *vector) +{ + /* Copy wakeup trampoline in place */ + memcpy((void *)WAKEUP_BASE, __wakeup, __wakeup_size); + + printf("Jumping to OS waking vector %p\n", vector); + acpi_do_wakeup(vector); +} + +void acpi_resume(void *wake_vec) +{ + post_code(POST_OS_RESUME); + acpi_jump_to_wakeup(wake_vec); +}

Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
In an S3 resume path, U-Boot does everything like a cold boot except in the last_stage_init() it jumps to the OS resume vector.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/cpu.c | 8 ++++++++ arch/x86/include/asm/acpi_s3.h | 10 ++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_s3.c | 26 ++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 arch/x86/lib/acpi_s3.c
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 9dde54c..afc8645 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -26,6 +26,7 @@ #include <malloc.h> #include <syscon.h> #include <asm/acpi_s3.h> +#include <asm/acpi_table.h> #include <asm/control_regs.h> #include <asm/coreboot_tables.h> #include <asm/cpu.h> @@ -204,6 +205,13 @@ __weak void board_final_cleanup(void)
int last_stage_init(void) { +#if CONFIG_HAVE_ACPI_RESUME
void *wake_vector = acpi_find_wakeup_vector();
if (wake_vector != NULL && gd->arch.prev_sleep_state == ACPI_S3)
acpi_resume(wake_vector);
+#endif
write_tables(); board_final_cleanup();
diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index f9d4739..5892a8b 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -100,6 +100,16 @@ enum acpi_sleep_state chipset_prev_sleep_state(void); */ void chipset_clear_sleep_state(void);
+/**
- acpi_resume() - Do ACPI S3 resume
- This calls U-Boot wake up assembly stub and jumps to OS's wake up vector.
- @wake_vec: OS wake up vector
- @return: Never returns
- */
+void acpi_resume(void *wake_vec);
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ACPI_S3_H__ */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 1c2c085..c61f931 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sections.o obj-y += sfi.o obj-y += string.o +obj-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.o ifndef CONFIG_QEMU obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o endif diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c new file mode 100644 index 0000000..f679c06 --- /dev/null +++ b/arch/x86/lib/acpi_s3.c @@ -0,0 +1,26 @@ +/*
- Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <asm/acpi_s3.h> +#include <asm/post.h>
+static void asmlinkage (*acpi_do_wakeup)(void *vector) = (void *)WAKEUP_BASE;
+static void acpi_jump_to_wakeup(void *vector) +{
/* Copy wakeup trampoline in place */
memcpy((void *)WAKEUP_BASE, __wakeup, __wakeup_size);
printf("Jumping to OS waking vector %p\n", vector);
Should this be debug()?
acpi_do_wakeup(vector);
+}
+void acpi_resume(void *wake_vec) +{
post_code(POST_OS_RESUME);
acpi_jump_to_wakeup(wake_vec);
+}
2.9.2
Regards, Simon

Hi Simon,
On Wed, Mar 22, 2017 at 4:06 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
In an S3 resume path, U-Boot does everything like a cold boot except in the last_stage_init() it jumps to the OS resume vector.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/cpu.c | 8 ++++++++ arch/x86/include/asm/acpi_s3.h | 10 ++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_s3.c | 26 ++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 arch/x86/lib/acpi_s3.c
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 9dde54c..afc8645 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -26,6 +26,7 @@ #include <malloc.h> #include <syscon.h> #include <asm/acpi_s3.h> +#include <asm/acpi_table.h> #include <asm/control_regs.h> #include <asm/coreboot_tables.h> #include <asm/cpu.h> @@ -204,6 +205,13 @@ __weak void board_final_cleanup(void)
int last_stage_init(void) { +#if CONFIG_HAVE_ACPI_RESUME
void *wake_vector = acpi_find_wakeup_vector();
if (wake_vector != NULL && gd->arch.prev_sleep_state == ACPI_S3)
acpi_resume(wake_vector);
+#endif
write_tables(); board_final_cleanup();
diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index f9d4739..5892a8b 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -100,6 +100,16 @@ enum acpi_sleep_state chipset_prev_sleep_state(void); */ void chipset_clear_sleep_state(void);
+/**
- acpi_resume() - Do ACPI S3 resume
- This calls U-Boot wake up assembly stub and jumps to OS's wake up vector.
- @wake_vec: OS wake up vector
- @return: Never returns
- */
+void acpi_resume(void *wake_vec);
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ACPI_S3_H__ */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 1c2c085..c61f931 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sections.o obj-y += sfi.o obj-y += string.o +obj-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.o ifndef CONFIG_QEMU obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o endif diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c new file mode 100644 index 0000000..f679c06 --- /dev/null +++ b/arch/x86/lib/acpi_s3.c @@ -0,0 +1,26 @@ +/*
- Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <asm/acpi_s3.h> +#include <asm/post.h>
+static void asmlinkage (*acpi_do_wakeup)(void *vector) = (void *)WAKEUP_BASE;
+static void acpi_jump_to_wakeup(void *vector) +{
/* Copy wakeup trampoline in place */
memcpy((void *)WAKEUP_BASE, __wakeup, __wakeup_size);
printf("Jumping to OS waking vector %p\n", vector);
Should this be debug()?
I wanted to explicitly print this to show that we are in S3 and jumping to OS vector. Actually I was even thinking we should introduce a log level for U-Boot, just like coreboot/linux.
Regards, Bin

Hi Bin,
On 12 April 2017 at 02:14, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Mar 22, 2017 at 4:06 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
In an S3 resume path, U-Boot does everything like a cold boot except in the last_stage_init() it jumps to the OS resume vector.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/cpu.c | 8 ++++++++ arch/x86/include/asm/acpi_s3.h | 10 ++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_s3.c | 26 ++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 arch/x86/lib/acpi_s3.c
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 9dde54c..afc8645 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -26,6 +26,7 @@ #include <malloc.h> #include <syscon.h> #include <asm/acpi_s3.h> +#include <asm/acpi_table.h> #include <asm/control_regs.h> #include <asm/coreboot_tables.h> #include <asm/cpu.h> @@ -204,6 +205,13 @@ __weak void board_final_cleanup(void)
int last_stage_init(void) { +#if CONFIG_HAVE_ACPI_RESUME
void *wake_vector = acpi_find_wakeup_vector();
if (wake_vector != NULL && gd->arch.prev_sleep_state == ACPI_S3)
acpi_resume(wake_vector);
+#endif
write_tables(); board_final_cleanup();
diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index f9d4739..5892a8b 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -100,6 +100,16 @@ enum acpi_sleep_state chipset_prev_sleep_state(void); */ void chipset_clear_sleep_state(void);
+/**
- acpi_resume() - Do ACPI S3 resume
- This calls U-Boot wake up assembly stub and jumps to OS's wake up vector.
- @wake_vec: OS wake up vector
- @return: Never returns
- */
+void acpi_resume(void *wake_vec);
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ACPI_S3_H__ */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 1c2c085..c61f931 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sections.o obj-y += sfi.o obj-y += string.o +obj-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.o ifndef CONFIG_QEMU obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o endif diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c new file mode 100644 index 0000000..f679c06 --- /dev/null +++ b/arch/x86/lib/acpi_s3.c @@ -0,0 +1,26 @@ +/*
- Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <asm/acpi_s3.h> +#include <asm/post.h>
+static void asmlinkage (*acpi_do_wakeup)(void *vector) = (void *)WAKEUP_BASE;
+static void acpi_jump_to_wakeup(void *vector) +{
/* Copy wakeup trampoline in place */
memcpy((void *)WAKEUP_BASE, __wakeup, __wakeup_size);
printf("Jumping to OS waking vector %p\n", vector);
Should this be debug()?
I wanted to explicitly print this to show that we are in S3 and jumping to OS vector. Actually I was even thinking we should introduce a log level for U-Boot, just like coreboot/linux.
OK sounds good.
Since you are thinking about logging, here are the features I'd love to see:
- Log messages have category, log level, filename and line number (but many people would continue to just use debug()) - Ability to enable at build time on a per-file basis (as now) or globally. - Separately, be able to enable/disable per file at run-time (assuming enabled at build time) - Ability to filter log messages that go to console - Collection of log messages in a buffer (perhaps a circular membuff or a plain buffer) - A command to access the log
Regards, Simon

Hi Bin,
On 12.04.2017 10:14, Bin Meng wrote:
On Wed, Mar 22, 2017 at 4:06 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
In an S3 resume path, U-Boot does everything like a cold boot except in the last_stage_init() it jumps to the OS resume vector.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/cpu.c | 8 ++++++++ arch/x86/include/asm/acpi_s3.h | 10 ++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_s3.c | 26 ++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 arch/x86/lib/acpi_s3.c
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 9dde54c..afc8645 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -26,6 +26,7 @@ #include <malloc.h> #include <syscon.h> #include <asm/acpi_s3.h> +#include <asm/acpi_table.h> #include <asm/control_regs.h> #include <asm/coreboot_tables.h> #include <asm/cpu.h> @@ -204,6 +205,13 @@ __weak void board_final_cleanup(void)
int last_stage_init(void) { +#if CONFIG_HAVE_ACPI_RESUME
void *wake_vector = acpi_find_wakeup_vector();
if (wake_vector != NULL && gd->arch.prev_sleep_state == ACPI_S3)
acpi_resume(wake_vector);
+#endif
write_tables(); board_final_cleanup();
diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index f9d4739..5892a8b 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -100,6 +100,16 @@ enum acpi_sleep_state chipset_prev_sleep_state(void); */ void chipset_clear_sleep_state(void);
+/**
- acpi_resume() - Do ACPI S3 resume
- This calls U-Boot wake up assembly stub and jumps to OS's wake up vector.
- @wake_vec: OS wake up vector
- @return: Never returns
- */
+void acpi_resume(void *wake_vec);
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ACPI_S3_H__ */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 1c2c085..c61f931 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sections.o obj-y += sfi.o obj-y += string.o +obj-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.o ifndef CONFIG_QEMU obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o endif diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c new file mode 100644 index 0000000..f679c06 --- /dev/null +++ b/arch/x86/lib/acpi_s3.c @@ -0,0 +1,26 @@ +/*
- Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <asm/acpi_s3.h> +#include <asm/post.h>
+static void asmlinkage (*acpi_do_wakeup)(void *vector) = (void *)WAKEUP_BASE;
+static void acpi_jump_to_wakeup(void *vector) +{
/* Copy wakeup trampoline in place */
memcpy((void *)WAKEUP_BASE, __wakeup, __wakeup_size);
printf("Jumping to OS waking vector %p\n", vector);
Should this be debug()?
I wanted to explicitly print this to show that we are in S3 and jumping to OS vector.
I also vote for this explicit print line in this case.
Actually I was even thinking we should introduce a log level for U-Boot, just like coreboot/linux.
Interesting idea. How could the log-level be configured in U-Boot? Via some env variable?
Thanks, Stefan

Hi Stefan,
On 17 April 2017 at 03:37, Stefan Roese sr@denx.de wrote:
Hi Bin,
On 12.04.2017 10:14, Bin Meng wrote:
On Wed, Mar 22, 2017 at 4:06 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
In an S3 resume path, U-Boot does everything like a cold boot except in the last_stage_init() it jumps to the OS resume vector.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/cpu.c | 8 ++++++++ arch/x86/include/asm/acpi_s3.h | 10 ++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_s3.c | 26 ++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 arch/x86/lib/acpi_s3.c
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 9dde54c..afc8645 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -26,6 +26,7 @@ #include <malloc.h> #include <syscon.h> #include <asm/acpi_s3.h> +#include <asm/acpi_table.h> #include <asm/control_regs.h> #include <asm/coreboot_tables.h> #include <asm/cpu.h> @@ -204,6 +205,13 @@ __weak void board_final_cleanup(void)
int last_stage_init(void) { +#if CONFIG_HAVE_ACPI_RESUME
void *wake_vector = acpi_find_wakeup_vector();
if (wake_vector != NULL && gd->arch.prev_sleep_state == ACPI_S3)
acpi_resume(wake_vector);
+#endif
write_tables(); board_final_cleanup();
diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index f9d4739..5892a8b 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -100,6 +100,16 @@ enum acpi_sleep_state chipset_prev_sleep_state(void); */ void chipset_clear_sleep_state(void);
+/**
- acpi_resume() - Do ACPI S3 resume
- This calls U-Boot wake up assembly stub and jumps to OS's wake up vector.
- @wake_vec: OS wake up vector
- @return: Never returns
- */
+void acpi_resume(void *wake_vec);
#endif /* __ASSEMBLY__ */
#endif /* __ASM_ACPI_S3_H__ */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 1c2c085..c61f931 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sections.o obj-y += sfi.o obj-y += string.o +obj-$(CONFIG_HAVE_ACPI_RESUME) += acpi_s3.o ifndef CONFIG_QEMU obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o endif diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c new file mode 100644 index 0000000..f679c06 --- /dev/null +++ b/arch/x86/lib/acpi_s3.c @@ -0,0 +1,26 @@ +/*
- Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <asm/acpi_s3.h> +#include <asm/post.h>
+static void asmlinkage (*acpi_do_wakeup)(void *vector) = (void *)WAKEUP_BASE;
+static void acpi_jump_to_wakeup(void *vector) +{
/* Copy wakeup trampoline in place */
memcpy((void *)WAKEUP_BASE, __wakeup, __wakeup_size);
printf("Jumping to OS waking vector %p\n", vector);
Should this be debug()?
I wanted to explicitly print this to show that we are in S3 and jumping to OS vector.
I also vote for this explicit print line in this case.
Actually I was even thinking we should introduce a log level for U-Boot, just like coreboot/linux.
Interesting idea. How could the log-level be configured in U-Boot? Via some env variable?
Yes I suppose so.
Regards, Simon

This adds a library that provides CMOS (inside RTC SRAM) access at a very early stage when driver model is not available yet.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/include/asm/early_cmos.h | 43 +++++++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/early_cmos.c | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 arch/x86/include/asm/early_cmos.h create mode 100644 arch/x86/lib/early_cmos.c
diff --git a/arch/x86/include/asm/early_cmos.h b/arch/x86/include/asm/early_cmos.h new file mode 100644 index 0000000..cd2634d --- /dev/null +++ b/arch/x86/include/asm/early_cmos.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __EARLY_CMOS_H +#define __EARLY_CMOS_H + +/* CMOS actually resides in the RTC SRAM */ +#define CMOS_IO_PORT 0x70 + +/** + * cmos_read8() - Get 8-bit data stored at the given address + * + * This reads from CMOS for the 8-bit data stored at the given address. + * + * @addr: RTC SRAM address + * @return: 8-bit data stored at the given address + */ +u8 cmos_read8(u8 addr); + +/** + * cmos_read16() - Get 16-bit data stored at the given address + * + * This reads from CMOS for the 16-bit data stored at the given address. + * + * @addr: RTC SRAM address + * @return: 16-bit data stored at the given address + */ +u16 cmos_read16(u8 addr); + +/** + * cmos_read32() - Get 32-bit data stored at the given address + * + * This reads from CMOS for the 32-bit data stored at the given address. + * + * @addr: RTC SRAM address + * @return: 32-bit data stored at the given address + */ +u32 cmos_read32(u8 addr); + +#endif /* __EARLY_CMOS_H */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index c61f931..cd4e976 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o endif obj-y += cmd_boot.o obj-$(CONFIG_SEABIOS) += coreboot_table.o +obj-y += early_cmos.o obj-$(CONFIG_EFI) += efi/ obj-y += e820.o obj-y += gcc.o diff --git a/arch/x86/lib/early_cmos.c b/arch/x86/lib/early_cmos.c new file mode 100644 index 0000000..fa0b327 --- /dev/null +++ b/arch/x86/lib/early_cmos.c @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * This library provides CMOS (inside RTC SRAM) access routines at a very + * early stage when driver model is not available yet. Only read access is + * provided. The 16-bit/32-bit read are compatible with driver model RTC + * uclass write ops, that data is stored in little-endian mode. + */ + +#include <common.h> +#include <asm/early_cmos.h> +#include <asm/io.h> + +u8 cmos_read8(u8 addr) +{ + outb(addr, CMOS_IO_PORT); + + return inb(CMOS_IO_PORT + 1); +} + +u16 cmos_read16(u8 addr) +{ + u16 value = 0; + u16 data; + int i; + + for (i = 0; i < sizeof(value); i++) { + data = cmos_read8(addr + i); + value |= data << (i << 3); + } + + return value; +} + +u32 cmos_read32(u8 addr) +{ + u32 value = 0; + u32 data; + int i; + + for (i = 0; i < sizeof(value); i++) { + data = cmos_read8(addr + i); + value |= data << (i << 3); + } + + return value; +}

Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
This adds a library that provides CMOS (inside RTC SRAM) access at a very early stage when driver model is not available yet.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/include/asm/early_cmos.h | 43 +++++++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/early_cmos.c | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 arch/x86/include/asm/early_cmos.h create mode 100644 arch/x86/lib/early_cmos.c
Is it possible to share code with the existing driver, like we do with DEBUG_UART?
Regards, Simon

Hi Simon,
On Wed, Mar 22, 2017 at 4:06 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
This adds a library that provides CMOS (inside RTC SRAM) access at a very early stage when driver model is not available yet.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/include/asm/early_cmos.h | 43 +++++++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/early_cmos.c | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 arch/x86/include/asm/early_cmos.h create mode 100644 arch/x86/lib/early_cmos.c
Is it possible to share code with the existing driver, like we do with DEBUG_UART?
DEBUG_UART requires every serial driver provides APIs like _debug_uart_putc(), while this early cmos library wants to share codes with rtc-uclass.c. Looks not possible to get rid of the udevice parameter.
Regards, Bin

On 18 April 2017 at 03:46, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Mar 22, 2017 at 4:06 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
This adds a library that provides CMOS (inside RTC SRAM) access at a very early stage when driver model is not available yet.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/include/asm/early_cmos.h | 43 +++++++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/early_cmos.c | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 arch/x86/include/asm/early_cmos.h create mode 100644 arch/x86/lib/early_cmos.c
Is it possible to share code with the existing driver, like we do with DEBUG_UART?
DEBUG_UART requires every serial driver provides APIs like _debug_uart_putc(), while this early cmos library wants to share codes with rtc-uclass.c. Looks not possible to get rid of the udevice parameter.
Regards, Bin
Reviewed-by: Simon Glass sjg@chromium.org

At the end of pre-relocation phase, save the new stack address to CMOS and use it as the stack on next S3 boot for fsp_init() continuation function.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/cpu/cpu.c | 8 ++++++++ arch/x86/include/asm/cmos_layout.h | 31 +++++++++++++++++++++++++++++++ arch/x86/include/asm/u-boot-x86.h | 1 + arch/x86/lib/fsp/fsp_common.c | 30 +++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 arch/x86/include/asm/cmos_layout.h
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index afc8645..9e2aee2 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -278,6 +278,14 @@ int reserve_arch(void) high_table_reserve(); #endif
+#if defined(CONFIG_HAVE_ACPI_RESUME) && defined(CONFIG_HAVE_FSP) + /* + * Save stack address to CMOS so that at next S3 boot, + * we can use it as the stack address for fsp_contiue() + */ + fsp_save_s3_stack(); +#endif + return 0; } #endif diff --git a/arch/x86/include/asm/cmos_layout.h b/arch/x86/include/asm/cmos_layout.h new file mode 100644 index 0000000..0a0a51e --- /dev/null +++ b/arch/x86/include/asm/cmos_layout.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __CMOS_LAYOUT_H +#define __CMOS_LAYOUT_H + +/* + * The RTC internal registers and RAM is organized as two banks of 128 bytes + * each, called the standard and extended banks. The first 14 bytes of the + * standard bank contain the RTC time and date information along with four + * registers, A - D, that are used for configuration of the RTC. The extended + * bank contains a full 128 bytes of battery backed SRAM. + * + * For simplicity in U-Boot we only support CMOS in the standard bank, and + * its base address starts from offset 0x10, which leaves us 112 bytes space. + */ +#define CMOS_BASE 0x10 + +/* + * The file records all offsets off CMOS_BASE that is currently used by + * U-Boot for various reasons. It is put in such a unified place in order + * to be consistent across platforms. + */ + +/* stack address for S3 boot in a FSP configuration, 4 bytes */ +#define CMOS_FSP_STACK_ADDR CMOS_BASE + +#endif /* __CMOS_LAYOUT_H */ diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 4f901f9..024aaf4 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -56,6 +56,7 @@ u32 isa_map_rom(u32 bus_addr, int size); int video_bios_init(void);
/* arch/x86/lib/fsp/... */ +int fsp_save_s3_stack(void); int x86_fsp_init(void);
void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 2b33fba..df73a2a 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -5,8 +5,12 @@ */
#include <common.h> +#include <dm.h> #include <errno.h> +#include <rtc.h> #include <asm/acpi_s3.h> +#include <asm/cmos_layout.h> +#include <asm/early_cmos.h> #include <asm/io.h> #include <asm/mrccache.h> #include <asm/post.h> @@ -71,9 +75,32 @@ static __maybe_unused void *fsp_prepare_mrc_cache(void) return cache->data; }
+#ifdef CONFIG_HAVE_ACPI_RESUME +int fsp_save_s3_stack(void) +{ + struct udevice *dev; + int ret; + + if (gd->arch.prev_sleep_state == ACPI_S3) + return 0; + + ret = uclass_get_device(UCLASS_RTC, 0, &dev); + if (ret) { + debug("Cannot find RTC: err=%d\n", ret); + return -ENODEV; + } + + /* Save the stack address to CMOS */ + rtc_write32(dev, CMOS_FSP_STACK_ADDR, gd->start_addr_sp); + + return 0; +} +#endif + int x86_fsp_init(void) { void *nvs; + int stack = CONFIG_FSP_TEMP_RAM_ADDR; int boot_mode = BOOT_FULL_CONFIG; #ifdef CONFIG_HAVE_ACPI_RESUME int prev_sleep_state = chipset_prev_sleep_state(); @@ -102,6 +129,7 @@ int x86_fsp_init(void) panic("Reboot System"); }
+ stack = cmos_read32(CMOS_FSP_STACK_ADDR); boot_mode = BOOT_ON_S3_RESUME; } #endif @@ -110,7 +138,7 @@ int x86_fsp_init(void) * Note the execution does not return to this function, * instead it jumps to fsp_continue(). */ - fsp_init(CONFIG_FSP_TEMP_RAM_ADDR, boot_mode, nvs); + fsp_init(stack, boot_mode, nvs); } else { /* * The second time we enter here, adjust the size of malloc()

Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
At the end of pre-relocation phase, save the new stack address to CMOS and use it as the stack on next S3 boot for fsp_init() continuation function.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/cpu.c | 8 ++++++++ arch/x86/include/asm/cmos_layout.h | 31 +++++++++++++++++++++++++++++++ arch/x86/include/asm/u-boot-x86.h | 1 + arch/x86/lib/fsp/fsp_common.c | 30 +++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 arch/x86/include/asm/cmos_layout.h
Reviewed-by: Simon Glass sjg@chromium.org
nits below
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index afc8645..9e2aee2 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -278,6 +278,14 @@ int reserve_arch(void) high_table_reserve(); #endif
+#if defined(CONFIG_HAVE_ACPI_RESUME) && defined(CONFIG_HAVE_FSP)
/*
* Save stack address to CMOS so that at next S3 boot,
* we can use it as the stack address for fsp_contiue()
*/
fsp_save_s3_stack();
+#endif
return 0;
} #endif diff --git a/arch/x86/include/asm/cmos_layout.h b/arch/x86/include/asm/cmos_layout.h new file mode 100644 index 0000000..0a0a51e --- /dev/null +++ b/arch/x86/include/asm/cmos_layout.h @@ -0,0 +1,31 @@ +/*
- Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __CMOS_LAYOUT_H +#define __CMOS_LAYOUT_H
+/*
- The RTC internal registers and RAM is organized as two banks of 128 bytes
- each, called the standard and extended banks. The first 14 bytes of the
- standard bank contain the RTC time and date information along with four
- registers, A - D, that are used for configuration of the RTC. The extended
- bank contains a full 128 bytes of battery backed SRAM.
- For simplicity in U-Boot we only support CMOS in the standard bank, and
- its base address starts from offset 0x10, which leaves us 112 bytes space.
- */
+#define CMOS_BASE 0x10
+/*
- The file records all offsets off CMOS_BASE that is currently used by
- U-Boot for various reasons. It is put in such a unified place in order
- to be consistent across platforms.
- */
+/* stack address for S3 boot in a FSP configuration, 4 bytes */ +#define CMOS_FSP_STACK_ADDR CMOS_BASE
+#endif /* __CMOS_LAYOUT_H */ diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 4f901f9..024aaf4 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -56,6 +56,7 @@ u32 isa_map_rom(u32 bus_addr, int size); int video_bios_init(void);
/* arch/x86/lib/fsp/... */ +int fsp_save_s3_stack(void); int x86_fsp_init(void);
Function comment?
void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 2b33fba..df73a2a 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -5,8 +5,12 @@ */
#include <common.h> +#include <dm.h> #include <errno.h> +#include <rtc.h> #include <asm/acpi_s3.h> +#include <asm/cmos_layout.h> +#include <asm/early_cmos.h> #include <asm/io.h> #include <asm/mrccache.h> #include <asm/post.h> @@ -71,9 +75,32 @@ static __maybe_unused void *fsp_prepare_mrc_cache(void) return cache->data; }
+#ifdef CONFIG_HAVE_ACPI_RESUME +int fsp_save_s3_stack(void) +{
struct udevice *dev;
int ret;
if (gd->arch.prev_sleep_state == ACPI_S3)
return 0;
ret = uclass_get_device(UCLASS_RTC, 0, &dev);
You need to use uclass_get_device_err() to get an error I think.
if (ret) {
debug("Cannot find RTC: err=%d\n", ret);
return -ENODEV;
}
/* Save the stack address to CMOS */
rtc_write32(dev, CMOS_FSP_STACK_ADDR, gd->start_addr_sp);
Check error?
return 0;
+} +#endif
int x86_fsp_init(void) { void *nvs;
int stack = CONFIG_FSP_TEMP_RAM_ADDR; int boot_mode = BOOT_FULL_CONFIG;
#ifdef CONFIG_HAVE_ACPI_RESUME int prev_sleep_state = chipset_prev_sleep_state(); @@ -102,6 +129,7 @@ int x86_fsp_init(void) panic("Reboot System"); }
stack = cmos_read32(CMOS_FSP_STACK_ADDR);
Perhaps you should comment why you are using this instead of rtc_...() ?
boot_mode = BOOT_ON_S3_RESUME; }
#endif @@ -110,7 +138,7 @@ int x86_fsp_init(void) * Note the execution does not return to this function, * instead it jumps to fsp_continue(). */
fsp_init(CONFIG_FSP_TEMP_RAM_ADDR, boot_mode, nvs);
fsp_init(stack, boot_mode, nvs); } else { /* * The second time we enter here, adjust the size of malloc()
-- 2.9.2
Regards, Simon

Hi Simon,
On Wed, Mar 22, 2017 at 4:06 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
At the end of pre-relocation phase, save the new stack address to CMOS and use it as the stack on next S3 boot for fsp_init() continuation function.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/cpu.c | 8 ++++++++ arch/x86/include/asm/cmos_layout.h | 31 +++++++++++++++++++++++++++++++ arch/x86/include/asm/u-boot-x86.h | 1 + arch/x86/lib/fsp/fsp_common.c | 30 +++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 arch/x86/include/asm/cmos_layout.h
Reviewed-by: Simon Glass sjg@chromium.org
nits below
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index afc8645..9e2aee2 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -278,6 +278,14 @@ int reserve_arch(void) high_table_reserve(); #endif
+#if defined(CONFIG_HAVE_ACPI_RESUME) && defined(CONFIG_HAVE_FSP)
/*
* Save stack address to CMOS so that at next S3 boot,
* we can use it as the stack address for fsp_contiue()
*/
fsp_save_s3_stack();
+#endif
return 0;
} #endif diff --git a/arch/x86/include/asm/cmos_layout.h b/arch/x86/include/asm/cmos_layout.h new file mode 100644 index 0000000..0a0a51e --- /dev/null +++ b/arch/x86/include/asm/cmos_layout.h @@ -0,0 +1,31 @@ +/*
- Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __CMOS_LAYOUT_H +#define __CMOS_LAYOUT_H
+/*
- The RTC internal registers and RAM is organized as two banks of 128 bytes
- each, called the standard and extended banks. The first 14 bytes of the
- standard bank contain the RTC time and date information along with four
- registers, A - D, that are used for configuration of the RTC. The extended
- bank contains a full 128 bytes of battery backed SRAM.
- For simplicity in U-Boot we only support CMOS in the standard bank, and
- its base address starts from offset 0x10, which leaves us 112 bytes space.
- */
+#define CMOS_BASE 0x10
+/*
- The file records all offsets off CMOS_BASE that is currently used by
- U-Boot for various reasons. It is put in such a unified place in order
- to be consistent across platforms.
- */
+/* stack address for S3 boot in a FSP configuration, 4 bytes */ +#define CMOS_FSP_STACK_ADDR CMOS_BASE
+#endif /* __CMOS_LAYOUT_H */ diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 4f901f9..024aaf4 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -56,6 +56,7 @@ u32 isa_map_rom(u32 bus_addr, int size); int video_bios_init(void);
/* arch/x86/lib/fsp/... */ +int fsp_save_s3_stack(void); int x86_fsp_init(void);
Function comment?
void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 2b33fba..df73a2a 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -5,8 +5,12 @@ */
#include <common.h> +#include <dm.h> #include <errno.h> +#include <rtc.h> #include <asm/acpi_s3.h> +#include <asm/cmos_layout.h> +#include <asm/early_cmos.h> #include <asm/io.h> #include <asm/mrccache.h> #include <asm/post.h> @@ -71,9 +75,32 @@ static __maybe_unused void *fsp_prepare_mrc_cache(void) return cache->data; }
+#ifdef CONFIG_HAVE_ACPI_RESUME +int fsp_save_s3_stack(void) +{
struct udevice *dev;
int ret;
if (gd->arch.prev_sleep_state == ACPI_S3)
return 0;
ret = uclass_get_device(UCLASS_RTC, 0, &dev);
You need to use uclass_get_device_err() to get an error I think.
There is no such API in current mainline.
if (ret) {
debug("Cannot find RTC: err=%d\n", ret);
return -ENODEV;
}
/* Save the stack address to CMOS */
rtc_write32(dev, CMOS_FSP_STACK_ADDR, gd->start_addr_sp);
Check error?
return 0;
+} +#endif
int x86_fsp_init(void) { void *nvs;
int stack = CONFIG_FSP_TEMP_RAM_ADDR; int boot_mode = BOOT_FULL_CONFIG;
#ifdef CONFIG_HAVE_ACPI_RESUME int prev_sleep_state = chipset_prev_sleep_state(); @@ -102,6 +129,7 @@ int x86_fsp_init(void) panic("Reboot System"); }
stack = cmos_read32(CMOS_FSP_STACK_ADDR);
Perhaps you should comment why you are using this instead of rtc_...() ?
Regards, Bin

Hi Bin,
On 13 April 2017 at 03:25, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Mar 22, 2017 at 4:06 AM, Simon Glass sjg@chromium.org wrote:
Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
At the end of pre-relocation phase, save the new stack address to CMOS and use it as the stack on next S3 boot for fsp_init() continuation function.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/cpu.c | 8 ++++++++ arch/x86/include/asm/cmos_layout.h | 31 +++++++++++++++++++++++++++++++ arch/x86/include/asm/u-boot-x86.h | 1 + arch/x86/lib/fsp/fsp_common.c | 30 +++++++++++++++++++++++++++++- 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 arch/x86/include/asm/cmos_layout.h
Reviewed-by: Simon Glass sjg@chromium.org
nits below
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index afc8645..9e2aee2 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -278,6 +278,14 @@ int reserve_arch(void) high_table_reserve(); #endif
+#if defined(CONFIG_HAVE_ACPI_RESUME) && defined(CONFIG_HAVE_FSP)
/*
* Save stack address to CMOS so that at next S3 boot,
* we can use it as the stack address for fsp_contiue()
*/
fsp_save_s3_stack();
+#endif
return 0;
} #endif diff --git a/arch/x86/include/asm/cmos_layout.h b/arch/x86/include/asm/cmos_layout.h new file mode 100644 index 0000000..0a0a51e --- /dev/null +++ b/arch/x86/include/asm/cmos_layout.h @@ -0,0 +1,31 @@ +/*
- Copyright (C) 2017, Bin Meng bmeng.cn@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#ifndef __CMOS_LAYOUT_H +#define __CMOS_LAYOUT_H
+/*
- The RTC internal registers and RAM is organized as two banks of 128 bytes
- each, called the standard and extended banks. The first 14 bytes of the
- standard bank contain the RTC time and date information along with four
- registers, A - D, that are used for configuration of the RTC. The extended
- bank contains a full 128 bytes of battery backed SRAM.
- For simplicity in U-Boot we only support CMOS in the standard bank, and
- its base address starts from offset 0x10, which leaves us 112 bytes space.
- */
+#define CMOS_BASE 0x10
+/*
- The file records all offsets off CMOS_BASE that is currently used by
- U-Boot for various reasons. It is put in such a unified place in order
- to be consistent across platforms.
- */
+/* stack address for S3 boot in a FSP configuration, 4 bytes */ +#define CMOS_FSP_STACK_ADDR CMOS_BASE
+#endif /* __CMOS_LAYOUT_H */ diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 4f901f9..024aaf4 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -56,6 +56,7 @@ u32 isa_map_rom(u32 bus_addr, int size); int video_bios_init(void);
/* arch/x86/lib/fsp/... */ +int fsp_save_s3_stack(void); int x86_fsp_init(void);
Function comment?
void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c index 2b33fba..df73a2a 100644 --- a/arch/x86/lib/fsp/fsp_common.c +++ b/arch/x86/lib/fsp/fsp_common.c @@ -5,8 +5,12 @@ */
#include <common.h> +#include <dm.h> #include <errno.h> +#include <rtc.h> #include <asm/acpi_s3.h> +#include <asm/cmos_layout.h> +#include <asm/early_cmos.h> #include <asm/io.h> #include <asm/mrccache.h> #include <asm/post.h> @@ -71,9 +75,32 @@ static __maybe_unused void *fsp_prepare_mrc_cache(void) return cache->data; }
+#ifdef CONFIG_HAVE_ACPI_RESUME +int fsp_save_s3_stack(void) +{
struct udevice *dev;
int ret;
if (gd->arch.prev_sleep_state == ACPI_S3)
return 0;
ret = uclass_get_device(UCLASS_RTC, 0, &dev);
You need to use uclass_get_device_err() to get an error I think.
There is no such API in current mainline.
Sorry, I mean uclass_first_device_err(). It may not be suitable if you need to use device 0, but if you just want the first device it should be OK. Anyway I will leave this up to you.
Regards, Simon

Mark the first 64K memory as reserved as well since U-Boot uses this memory region for things like VBIOS execution in real mode. After kernel resumes, it checks low memory range per config option CONFIG_X86_RESERVE_LOW which is 64K by default to see whether a memory corruption occurs during the suspend/resume.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/lib/fsp/fsp_dram.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c index 417c611..2b383ef 100644 --- a/arch/x86/lib/fsp/fsp_dram.c +++ b/arch/x86/lib/fsp/fsp_dram.c @@ -100,6 +100,18 @@ unsigned install_e820_map(unsigned max_entries, struct e820entry *entries) CONFIG_STACK_SIZE; entries[num_entries].type = E820_RESERVED; num_entries++; + + /* + * Mark the first 64K memory as reserved as well since U-Boot uses + * this memory region for things like VBIOS execution in real mode. + * After kernel resumes, it checks low memory range per config option + * CONFIG_X86_RESERVE_LOW which is 64K by default to see whether a + * memory corruption occurs during the suspend/resume. + */ + entries[num_entries].addr = 0; + entries[num_entries].size = 0x10000; + entries[num_entries].type = E820_RESERVED; + num_entries++; #endif
return num_entries;

On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
Mark the first 64K memory as reserved as well since U-Boot uses this memory region for things like VBIOS execution in real mode. After kernel resumes, it checks low memory range per config option CONFIG_X86_RESERVE_LOW which is 64K by default to see whether a memory corruption occurs during the suspend/resume.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/lib/fsp/fsp_dram.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org

Call board_final_cleanup() before write_tables(), so that anything done in board_final_cleanup() on a normal boot path is also done on an S3 resume path.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/cpu/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 9e2aee2..bd5aeb8 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -205,6 +205,8 @@ __weak void board_final_cleanup(void)
int last_stage_init(void) { + board_final_cleanup(); + #if CONFIG_HAVE_ACPI_RESUME void *wake_vector = acpi_find_wakeup_vector();
@@ -214,8 +216,6 @@ int last_stage_init(void)
write_tables();
- board_final_cleanup(); - return 0; } #endif

On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
Call board_final_cleanup() before write_tables(), so that anything done in board_final_cleanup() on a normal boot path is also done on an S3 resume path.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

In enter_acpi_mode() PM1_CNT register is changed to PM1_CNT_SCI_EN directly without preserving its previous value. Update to change the register access to read-modify-write (RMW).
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/lib/acpi_table.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index f118345..8be8120 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -306,6 +306,8 @@ static void acpi_create_mcfg(struct acpi_mcfg *mcfg)
static void enter_acpi_mode(int pm1_cnt) { + u16 val = inw(pm1_cnt); + /* * PM1_CNT register bit0 selects the power management event to be * either an SCI or SMI interrupt. When this bit is set, then power @@ -320,7 +322,7 @@ static void enter_acpi_mode(int pm1_cnt) * system, and expose ourselves to OSPM as working under ACPI mode * already, turn this bit on. */ - outw(PM1_CNT_SCI_EN, pm1_cnt); + outw(val | PM1_CNT_SCI_EN, pm1_cnt); }
/*

On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
In enter_acpi_mode() PM1_CNT register is changed to PM1_CNT_SCI_EN directly without preserving its previous value. Update to change the register access to read-modify-write (RMW).
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/lib/acpi_table.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org

enter_acpi_mode() is useful on other boot path like S3 resume, so make it public.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/include/asm/acpi_table.h | 1 + arch/x86/lib/acpi_table.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h index 6cadd90..3e11362 100644 --- a/arch/x86/include/asm/acpi_table.h +++ b/arch/x86/include/asm/acpi_table.h @@ -316,5 +316,6 @@ int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, u8 cpu, u16 flags, u8 lint); u32 acpi_fill_madt(u32 current); void acpi_create_gnvs(struct acpi_global_nvs *gnvs); +void enter_acpi_mode(int pm1_cnt); ulong write_acpi_tables(ulong start); void *acpi_find_wakeup_vector(void); diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index 8be8120..87a71ca 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -304,7 +304,7 @@ static void acpi_create_mcfg(struct acpi_mcfg *mcfg) header->checksum = table_compute_checksum((void *)mcfg, header->length); }
-static void enter_acpi_mode(int pm1_cnt) +void enter_acpi_mode(int pm1_cnt) { u16 val = inw(pm1_cnt);

Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
enter_acpi_mode() is useful on other boot path like S3 resume, so make it public.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/include/asm/acpi_table.h | 1 + arch/x86/lib/acpi_table.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
Reviewed-by: Simon Glass sjg@chromium.org
But please can you add a function comment?
diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h index 6cadd90..3e11362 100644 --- a/arch/x86/include/asm/acpi_table.h +++ b/arch/x86/include/asm/acpi_table.h @@ -316,5 +316,6 @@ int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, u8 cpu, u16 flags, u8 lint); u32 acpi_fill_madt(u32 current); void acpi_create_gnvs(struct acpi_global_nvs *gnvs); +void enter_acpi_mode(int pm1_cnt); ulong write_acpi_tables(ulong start); void *acpi_find_wakeup_vector(void); diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index 8be8120..87a71ca 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -304,7 +304,7 @@ static void acpi_create_mcfg(struct acpi_mcfg *mcfg) header->checksum = table_compute_checksum((void *)mcfg, header->length); }
-static void enter_acpi_mode(int pm1_cnt) +void enter_acpi_mode(int pm1_cnt) { u16 val = inw(pm1_cnt);
-- 2.9.2
Regards, Simon

To do something more in acpi_resume() like turning on ACPI mode, we need locate ACPI FADT table pointer first. But currently this is done in acpi_find_wakeup_vector().
This changes acpi_resume() signature to accept ACPI FADT pointer as the parameter. A new API acpi_find_fadt() is introduced, and acpi_find_wakeup_vector() is updated to use FADT pointer as the parameter as well.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/cpu/cpu.c | 6 +++--- arch/x86/include/asm/acpi_s3.h | 5 +++-- arch/x86/include/asm/acpi_table.h | 3 ++- arch/x86/lib/acpi_s3.c | 7 ++++++- arch/x86/lib/acpi_table.c | 16 +++++++++++----- 5 files changed, 25 insertions(+), 12 deletions(-)
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index bd5aeb8..42fe8a2 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -208,10 +208,10 @@ int last_stage_init(void) board_final_cleanup();
#if CONFIG_HAVE_ACPI_RESUME - void *wake_vector = acpi_find_wakeup_vector(); + struct acpi_fadt *fadt = acpi_find_fadt();
- if (wake_vector != NULL && gd->arch.prev_sleep_state == ACPI_S3) - acpi_resume(wake_vector); + if (fadt != NULL && gd->arch.prev_sleep_state == ACPI_S3) + acpi_resume(fadt); #endif
write_tables(); diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h index 5892a8b..567ed3e 100644 --- a/arch/x86/include/asm/acpi_s3.h +++ b/arch/x86/include/asm/acpi_s3.h @@ -100,15 +100,16 @@ enum acpi_sleep_state chipset_prev_sleep_state(void); */ void chipset_clear_sleep_state(void);
+struct acpi_fadt; /** * acpi_resume() - Do ACPI S3 resume * * This calls U-Boot wake up assembly stub and jumps to OS's wake up vector. * - * @wake_vec: OS wake up vector + * @fadt: FADT table pointer in the ACPI table * @return: Never returns */ -void acpi_resume(void *wake_vec); +void acpi_resume(struct acpi_fadt *fadt);
#endif /* __ASSEMBLY__ */
diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h index 3e11362..c9eba42 100644 --- a/arch/x86/include/asm/acpi_table.h +++ b/arch/x86/include/asm/acpi_table.h @@ -318,4 +318,5 @@ u32 acpi_fill_madt(u32 current); void acpi_create_gnvs(struct acpi_global_nvs *gnvs); void enter_acpi_mode(int pm1_cnt); ulong write_acpi_tables(ulong start); -void *acpi_find_wakeup_vector(void); +struct acpi_fadt *acpi_find_fadt(void); +void *acpi_find_wakeup_vector(struct acpi_fadt *); diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c index f679c06..e5cc3b0 100644 --- a/arch/x86/lib/acpi_s3.c +++ b/arch/x86/lib/acpi_s3.c @@ -6,6 +6,7 @@
#include <common.h> #include <asm/acpi_s3.h> +#include <asm/acpi_table.h> #include <asm/post.h>
static void asmlinkage (*acpi_do_wakeup)(void *vector) = (void *)WAKEUP_BASE; @@ -19,8 +20,12 @@ static void acpi_jump_to_wakeup(void *vector) acpi_do_wakeup(vector); }
-void acpi_resume(void *wake_vec) +void acpi_resume(struct acpi_fadt *fadt) { + void *wake_vec; + + wake_vec = acpi_find_wakeup_vector(fadt); + post_code(POST_OS_RESUME); acpi_jump_to_wakeup(wake_vec); } diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c index 87a71ca..01d5b6f 100644 --- a/arch/x86/lib/acpi_table.c +++ b/arch/x86/lib/acpi_table.c @@ -460,18 +460,14 @@ static struct acpi_rsdp *acpi_valid_rsdp(struct acpi_rsdp *rsdp) return rsdp; }
-void *acpi_find_wakeup_vector(void) +struct acpi_fadt *acpi_find_fadt(void) { char *p, *end; struct acpi_rsdp *rsdp = NULL; struct acpi_rsdt *rsdt; struct acpi_fadt *fadt = NULL; - struct acpi_facs *facs; - void *wake_vec; int i;
- debug("Trying to find the wakeup vector...\n"); - /* Find RSDP */ for (p = (char *)ROM_TABLE_ADDR; p < (char *)ROM_TABLE_END; p += 16) { rsdp = acpi_valid_rsdp((struct acpi_rsdp *)p); @@ -499,6 +495,16 @@ void *acpi_find_wakeup_vector(void) return NULL;
debug("FADT found at %p\n", fadt); + return fadt; +} + +void *acpi_find_wakeup_vector(struct acpi_fadt *fadt) +{ + struct acpi_facs *facs; + void *wake_vec; + + debug("Trying to find the wakeup vector...\n"); + facs = (struct acpi_facs *)fadt->firmware_ctrl;
if (facs == NULL) {

Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
To do something more in acpi_resume() like turning on ACPI mode, we need locate ACPI FADT table pointer first. But currently this is done in acpi_find_wakeup_vector().
This changes acpi_resume() signature to accept ACPI FADT pointer as the parameter. A new API acpi_find_fadt() is introduced, and acpi_find_wakeup_vector() is updated to use FADT pointer as the parameter as well.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/cpu/cpu.c | 6 +++--- arch/x86/include/asm/acpi_s3.h | 5 +++-- arch/x86/include/asm/acpi_table.h | 3 ++- arch/x86/lib/acpi_s3.c | 7 ++++++- arch/x86/lib/acpi_table.c | 16 +++++++++++----- 5 files changed, 25 insertions(+), 12 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
Can you add a few function comments in the header file?
Regards, Simon

Before jumping to OS waking up vector, we need turn on ACPI mode for S3, just like what we do for a normal boot.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/lib/acpi_s3.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c index e5cc3b0..0b62b75 100644 --- a/arch/x86/lib/acpi_s3.c +++ b/arch/x86/lib/acpi_s3.c @@ -24,6 +24,9 @@ void acpi_resume(struct acpi_fadt *fadt) { void *wake_vec;
+ /* Turn on ACPI mode for S3 */ + enter_acpi_mode(fadt->pm1a_cnt_blk); + wake_vec = acpi_find_wakeup_vector(fadt);
post_code(POST_OS_RESUME);

On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
Before jumping to OS waking up vector, we need turn on ACPI mode for S3, just like what we do for a normal boot.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/lib/acpi_s3.c | 3 +++ 1 file changed, 3 insertions(+)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c index e5cc3b0..0b62b75 100644 --- a/arch/x86/lib/acpi_s3.c +++ b/arch/x86/lib/acpi_s3.c @@ -24,6 +24,9 @@ void acpi_resume(struct acpi_fadt *fadt) { void *wake_vec;
/* Turn on ACPI mode for S3 */
enter_acpi_mode(fadt->pm1a_cnt_blk);
wake_vec = acpi_find_wakeup_vector(fadt); post_code(POST_OS_RESUME);
-- 2.9.2

Introduce a new CONFIG_S3_VGA_ROM_RUN option so that U-Boot can bypass executing VGA roms in S3.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
arch/x86/Kconfig | 12 ++++++++++++ drivers/pci/pci_rom.c | 14 ++++++++++++++ 2 files changed, 26 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 95a65ff..29a1634 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -583,6 +583,18 @@ config HAVE_ACPI_RESUME is done, U-Boot needs to find out the wakeup vector provided by OSes and jump there.
+config S3_VGA_ROM_RUN + bool "Re-run VGA option ROMs on S3 resume" + depends on HAVE_ACPI_RESUME + default y if HAVE_ACPI_RESUME + help + Execute VGA option ROMs in U-Boot when resuming from S3. Normally + this is needed when graphics console is being used in the kernel. + + Turning it off can reduce some resume time, but be aware that your + graphics console won't work without VGA options ROMs. Set it to N + if your kernel is only on a serial console. + config STACK_SIZE hex depends on HAVE_ACPI_RESUME diff --git a/drivers/pci/pci_rom.c b/drivers/pci/pci_rom.c index 57204c4..75fb093 100644 --- a/drivers/pci/pci_rom.c +++ b/drivers/pci/pci_rom.c @@ -35,8 +35,22 @@ #include <video_fb.h> #include <linux/screen_info.h>
+#ifdef CONFIG_X86 +#include <asm/acpi_s3.h> +DECLARE_GLOBAL_DATA_PTR; +#endif + __weak bool board_should_run_oprom(struct udevice *dev) { +#if defined(CONFIG_X86) && defined(CONFIG_HAVE_ACPI_RESUME) + if (gd->arch.prev_sleep_state == ACPI_S3) { + if (IS_ENABLED(CONFIG_S3_VGA_ROM_RUN)) + return true; + else + return false; + } +#endif + return true; }

Hi,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
Introduce a new CONFIG_S3_VGA_ROM_RUN option so that U-Boot can bypass executing VGA roms in S3.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/Kconfig | 12 ++++++++++++ drivers/pci/pci_rom.c | 14 ++++++++++++++ 2 files changed, 26 insertions(+)
Can this be handled at run-time, based on whether we have already run the ROM?
At present, at least on ivybridge (non-FSP), the ROM execution happens when the device comes up. So do we actually need to run the ROM in S3 Or can we do it later by re-probing the driver?
Regards Simon

Hi Simon,
On Wed, Mar 22, 2017 at 4:07 AM, Simon Glass sjg@chromium.org wrote:
Hi,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
Introduce a new CONFIG_S3_VGA_ROM_RUN option so that U-Boot can bypass executing VGA roms in S3.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/Kconfig | 12 ++++++++++++ drivers/pci/pci_rom.c | 14 ++++++++++++++ 2 files changed, 26 insertions(+)
Can this be handled at run-time, based on whether we have already run the ROM?
I am not sure if this is what you want:
1). If on previous cold boot, VGA ROM has been run. Then on next S3 boot, VGA ROM should also be run. 2). If on previous cold boot, VGA ROM has not been run. Then on next S3 boot, VGA ROM should not be run.
So this is actually controlled by the CONFIG_VIDEO_VESA driver. But this new Kconfig option aims to solve: even CONFIG_VIDEO_VESA driver is used in a normal boot, U-Boot can still bypass the driver probe (ROM execution) in an S3 boot to save some resume time.
At present, at least on ivybridge (non-FSP), the ROM execution happens when the device comes up. So do we actually need to run the ROM in S3 Or can we do it later by re-probing the driver?
Regards, Bin

Hi Bin,
On 13 April 2017 at 04:00, Bin Meng bmeng.cn@gmail.com wrote:
Hi Simon,
On Wed, Mar 22, 2017 at 4:07 AM, Simon Glass sjg@chromium.org wrote:
Hi,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
Introduce a new CONFIG_S3_VGA_ROM_RUN option so that U-Boot can bypass executing VGA roms in S3.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
arch/x86/Kconfig | 12 ++++++++++++ drivers/pci/pci_rom.c | 14 ++++++++++++++ 2 files changed, 26 insertions(+)
Can this be handled at run-time, based on whether we have already run the ROM?
I am not sure if this is what you want:
1). If on previous cold boot, VGA ROM has been run. Then on next S3 boot, VGA ROM should also be run. 2). If on previous cold boot, VGA ROM has not been run. Then on next S3 boot, VGA ROM should not be run.
So this is actually controlled by the CONFIG_VIDEO_VESA driver. But this new Kconfig option aims to solve: even CONFIG_VIDEO_VESA driver is used in a normal boot, U-Boot can still bypass the driver probe (ROM execution) in an S3 boot to save some resume time.
At present, at least on ivybridge (non-FSP), the ROM execution happens when the device comes up. So do we actually need to run the ROM in S3 Or can we do it later by re-probing the driver?
With ivybridge the ROM runs when the video driver starts up. If there is no 'vidconsole' in stdout then this won't happen until someone does:
setenv stdout vidconsole,serial
or similar. I am not sure if this is possible with FSP machines.
However in practice we are generally returning from sleep to Linux, not U-Boot.
Do we have a way to know whether the ROM needs to be run (i.e. it was run before)?
Regards, Simon

This turns on ACPI S3 resume for minnowmax board.
Signed-off-by: Bin Meng bmeng.cn@gmail.com ---
configs/minnowmax_defconfig | 1 + 1 file changed, 1 insertion(+)
diff --git a/configs/minnowmax_defconfig b/configs/minnowmax_defconfig index 5f61f2a..d8e4090 100644 --- a/configs/minnowmax_defconfig +++ b/configs/minnowmax_defconfig @@ -10,6 +10,7 @@ CONFIG_HAVE_VGA_BIOS=y CONFIG_GENERATE_PIRQ_TABLE=y CONFIG_GENERATE_MP_TABLE=y CONFIG_GENERATE_ACPI_TABLE=y +CONFIG_HAVE_ACPI_RESUME=y CONFIG_SEABIOS=y CONFIG_FIT=y CONFIG_FIT_SIGNATURE=y

On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
This turns on ACPI S3 resume for minnowmax board.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
configs/minnowmax_defconfig | 1 + 1 file changed, 1 insertion(+)
Reviewed-by: Simon Glass sjg@chromium.org
diff --git a/configs/minnowmax_defconfig b/configs/minnowmax_defconfig index 5f61f2a..d8e4090 100644 --- a/configs/minnowmax_defconfig +++ b/configs/minnowmax_defconfig @@ -10,6 +10,7 @@ CONFIG_HAVE_VGA_BIOS=y CONFIG_GENERATE_PIRQ_TABLE=y CONFIG_GENERATE_MP_TABLE=y CONFIG_GENERATE_ACPI_TABLE=y +CONFIG_HAVE_ACPI_RESUME=y CONFIG_SEABIOS=y CONFIG_FIT=y CONFIG_FIT_SIGNATURE=y -- 2.9.2

Now that we have ACPI S3 support on Intel MinnowMax board, document some generic information of S3 and how to test it.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
---
doc/README.x86 | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/doc/README.x86 b/doc/README.x86 index a38cc1b..65fd646 100644 --- a/doc/README.x86 +++ b/doc/README.x86 @@ -1014,12 +1014,12 @@ compile ACPI DSDT table written in ASL format to AML format. You can get the compiler via "apt-get install iasl" if you are on Ubuntu or download the source from [17] to compile one by yourself.
-Current ACPI support in U-Boot is not complete. More features will be added -in the future. The status as of today is: +Current ACPI support in U-Boot is basically complete. More optional features +can be added in the future. The status as of today is:
* Support generating RSDT, XSDT, FACS, FADT, MADT, MCFG tables. * Support one static DSDT table only, compiled by Intel ACPI compiler. - * Support S0/S5, reboot and shutdown from OS. + * Support S0/S3/S4/S5, reboot and shutdown from OS. * Support booting a pre-installed Ubuntu distribution via 'zboot' command. * Support installing and booting Ubuntu 14.04 (or above) from U-Boot with the help of SeaBIOS using legacy interface (non-UEFI mode). @@ -1027,9 +1027,6 @@ in the future. The status as of today is: of SeaBIOS using legacy interface (non-UEFI mode). * Support ACPI interrupts with SCI only.
-Features not supported so far (to make it a complete ACPI solution): - * S3 (Suspend to RAM), S4 (Suspend to Disk). - Features that are optional: * Dynamic AML bytecodes insertion at run-time. We may need this to support SSDT table generation and DSDT fix up. @@ -1046,6 +1043,17 @@ command from the OS. For other platform boards, ACPI support status can be checked by examining their board defconfig files to see if CONFIG_GENERATE_ACPI_TABLE is set to y.
+The S3 sleeping state is a low wake latency sleeping state defined by ACPI +spec where all system context is lost except system memory. To test S3 resume +with a Linux kernel, simply run "echo mem > /sys/power/state" and kernel will +put the board to S3 state where the power is off. So when the power button is +pressed again, U-Boot runs as it does in cold boot and detects the sleeping +state via ACPI register to see if it is S3, if yes it means we are waking up. +U-Boot is responsible for restoring the machine state as it is before sleep. +When everything is done, U-Boot finds out the wakeup vector provided by OSes +and jump there. To determine whether ACPI S3 resume is supported, check to +see if CONFIG_HAVE_ACPI_RESUME is set for that specific board. + EFI Support ----------- U-Boot supports booting as a 32-bit or 64-bit EFI payload, e.g. with UEFI.

On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
Now that we have ACPI S3 support on Intel MinnowMax board, document some generic information of S3 and how to test it.
Signed-off-by: Bin Meng bmeng.cn@gmail.com
doc/README.x86 | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org
Great!

Hi Bin,
On 16 March 2017 at 08:26, Bin Meng bmeng.cn@gmail.com wrote:
This adds ACPI S3 (suspend to ram) resume capability in U-Boot. With S3 support within U-Boot, the board wakes up and resumes to OS very quickly.
This so far is enabled and tested on Intel MinnowMax board. Please check README.x86 for how to test it with a plain Linux kernel. Note testing with Ubuntu or Windows has some issues and fixes are still being worked out.
This series is available for testing in u-boot-x86/s3-working.
It's great to see this! Nice work. I'll try it out at some point.
Regards, SImon
participants (3)
-
Bin Meng
-
Simon Glass
-
Stefan Roese