Merge git://git.denx.de/u-boot-x86
This commit is contained in:
@@ -85,6 +85,7 @@ config X86
|
||||
select DM_SPI
|
||||
select DM_SPI_FLASH
|
||||
select USB_EHCI_HCD
|
||||
select DM_MMC if MMC
|
||||
|
||||
config XTENSA
|
||||
bool "Xtensa architecture"
|
||||
|
||||
@@ -589,6 +589,38 @@ 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 restoring the machine state as it was before sleep.
|
||||
It needs restore the memory controller, without 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 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
|
||||
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
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,18 +11,6 @@
|
||||
#include <asm/mrccache.h>
|
||||
#include <asm/post.h>
|
||||
|
||||
static struct pci_device_id mmc_supported[] = {
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SDIO },
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SD },
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_EMMC2 },
|
||||
{},
|
||||
};
|
||||
|
||||
int cpu_mmc_init(bd_t *bis)
|
||||
{
|
||||
return pci_mmc_init("ValleyView SDHCI", mmc_supported);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_EFI_APP
|
||||
int arch_cpu_init(void)
|
||||
{
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <errno.h>
|
||||
#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>
|
||||
@@ -179,6 +181,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
|
||||
debug("ACPI previous sleep state: %s\n",
|
||||
acpi_ss_string(gd->arch.prev_sleep_state));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -198,10 +205,17 @@ __weak void board_final_cleanup(void)
|
||||
|
||||
int last_stage_init(void)
|
||||
{
|
||||
write_tables();
|
||||
|
||||
board_final_cleanup();
|
||||
|
||||
#if CONFIG_HAVE_ACPI_RESUME
|
||||
struct acpi_fadt *fadt = acpi_find_fadt();
|
||||
|
||||
if (fadt != NULL && gd->arch.prev_sleep_state == ACPI_S3)
|
||||
acpi_resume(fadt);
|
||||
#endif
|
||||
|
||||
write_tables();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -264,6 +278,18 @@ int reserve_arch(void)
|
||||
high_table_reserve();
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAVE_ACPI_RESUME
|
||||
acpi_s3_reserve();
|
||||
|
||||
#ifdef 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 /* CONFIG_HAVE_FSP */
|
||||
#endif /* CONFIG_HAVE_ACPI_RESUME */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -16,11 +16,6 @@
|
||||
#include <asm/arch/msg_port.h>
|
||||
#include <asm/arch/quark.h>
|
||||
|
||||
static struct pci_device_id mmc_supported[] = {
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_SDIO },
|
||||
{},
|
||||
};
|
||||
|
||||
static void quark_setup_mtrr(void)
|
||||
{
|
||||
u32 base, mask;
|
||||
@@ -328,11 +323,6 @@ int arch_early_init_r(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cpu_mmc_init(bd_t *bis)
|
||||
{
|
||||
return pci_mmc_init("Quark SDHCI", mmc_supported);
|
||||
}
|
||||
|
||||
int arch_misc_init(void)
|
||||
{
|
||||
#ifdef CONFIG_ENABLE_MRC_CACHE
|
||||
|
||||
@@ -5,4 +5,4 @@
|
||||
#
|
||||
|
||||
obj-y += fsp_configs.o irq.o
|
||||
obj-y += tnc.o topcliff.o
|
||||
obj-y += tnc.o
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0+
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <mmc.h>
|
||||
#include <pci_ids.h>
|
||||
|
||||
static struct pci_device_id mmc_supported[] = {
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_0 },
|
||||
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_1 },
|
||||
{},
|
||||
};
|
||||
|
||||
int cpu_mmc_init(bd_t *bis)
|
||||
{
|
||||
return pci_mmc_init("Topcliff SDHCI", mmc_supported);
|
||||
}
|
||||
78
arch/x86/cpu/wakeup.S
Normal file
78
arch/x86/cpu/wakeup.S
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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 changes the address to be correct.
|
||||
*/
|
||||
.byte 0xea
|
||||
|
||||
__wakeup_offset = RELOCATED(.)
|
||||
.word 0x0000
|
||||
|
||||
__wakeup_segment = RELOCATED(.)
|
||||
.word 0x0000
|
||||
|
||||
.globl __wakeup_size
|
||||
__wakeup_size:
|
||||
.long . - __wakeup
|
||||
@@ -189,6 +189,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0 0x20>;
|
||||
bank-name = "A";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiob {
|
||||
@@ -196,6 +197,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x20 0x20>;
|
||||
bank-name = "B";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpioc {
|
||||
@@ -203,6 +205,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x40 0x20>;
|
||||
bank-name = "C";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiod {
|
||||
@@ -210,6 +213,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x60 0x20>;
|
||||
bank-name = "D";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpioe {
|
||||
@@ -217,6 +221,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x80 0x20>;
|
||||
bank-name = "E";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiof {
|
||||
@@ -224,6 +229,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0xA0 0x20>;
|
||||
bank-name = "F";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -212,6 +212,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0 0x20>;
|
||||
bank-name = "A";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiob {
|
||||
@@ -219,6 +220,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x20 0x20>;
|
||||
bank-name = "B";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpioc {
|
||||
@@ -226,6 +228,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x40 0x20>;
|
||||
bank-name = "C";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiod {
|
||||
@@ -233,6 +236,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x60 0x20>;
|
||||
bank-name = "D";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpioe {
|
||||
@@ -240,6 +244,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x80 0x20>;
|
||||
bank-name = "E";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiof {
|
||||
@@ -247,6 +252,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0xA0 0x20>;
|
||||
bank-name = "F";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -199,6 +199,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0 0x20>;
|
||||
bank-name = "A";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiob {
|
||||
@@ -206,6 +207,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x20 0x20>;
|
||||
bank-name = "B";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpioc {
|
||||
@@ -213,6 +215,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x40 0x20>;
|
||||
bank-name = "C";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiod {
|
||||
@@ -220,6 +223,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x60 0x20>;
|
||||
bank-name = "D";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpioe {
|
||||
@@ -227,6 +231,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x80 0x20>;
|
||||
bank-name = "E";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiof {
|
||||
@@ -234,6 +239,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0xA0 0x20>;
|
||||
bank-name = "F";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -201,6 +201,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0 0x20>;
|
||||
bank-name = "A";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiob {
|
||||
@@ -208,6 +209,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x20 0x20>;
|
||||
bank-name = "B";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpioc {
|
||||
@@ -215,6 +217,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x40 0x20>;
|
||||
bank-name = "C";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiod {
|
||||
@@ -222,6 +225,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x60 0x20>;
|
||||
bank-name = "D";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpioe {
|
||||
@@ -229,6 +233,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x80 0x20>;
|
||||
bank-name = "E";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiof {
|
||||
@@ -236,6 +241,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0xA0 0x20>;
|
||||
bank-name = "F";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
/* GPIO E0 */
|
||||
soc_gpio_s5_0@0 {
|
||||
gpio-offset = <0x80 0>;
|
||||
pad-offset = <0x1d0>;
|
||||
mode-gpio;
|
||||
output-value = <0>;
|
||||
direction = <PIN_OUTPUT>;
|
||||
@@ -44,7 +43,6 @@
|
||||
/* GPIO E1 */
|
||||
soc_gpio_s5_1@0 {
|
||||
gpio-offset = <0x80 1>;
|
||||
pad-offset = <0x210>;
|
||||
mode-gpio;
|
||||
output-value = <0>;
|
||||
direction = <PIN_OUTPUT>;
|
||||
@@ -53,7 +51,6 @@
|
||||
/* GPIO E2 */
|
||||
soc_gpio_s5_2@0 {
|
||||
gpio-offset = <0x80 2>;
|
||||
pad-offset = <0x1e0>;
|
||||
mode-gpio;
|
||||
output-value = <0>;
|
||||
direction = <PIN_OUTPUT>;
|
||||
@@ -61,7 +58,6 @@
|
||||
|
||||
pin_usb_host_en0@0 {
|
||||
gpio-offset = <0x80 8>;
|
||||
pad-offset = <0x260>;
|
||||
mode-gpio;
|
||||
output-value = <1>;
|
||||
direction = <PIN_OUTPUT>;
|
||||
@@ -69,7 +65,6 @@
|
||||
|
||||
pin_usb_host_en1@0 {
|
||||
gpio-offset = <0x80 9>;
|
||||
pad-offset = <0x250>;
|
||||
mode-gpio;
|
||||
output-value = <1>;
|
||||
direction = <PIN_OUTPUT>;
|
||||
@@ -218,6 +213,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0 0x20>;
|
||||
bank-name = "A";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiob {
|
||||
@@ -225,6 +221,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x20 0x20>;
|
||||
bank-name = "B";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpioc {
|
||||
@@ -232,6 +229,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x40 0x20>;
|
||||
bank-name = "C";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiod {
|
||||
@@ -239,6 +237,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x60 0x20>;
|
||||
bank-name = "D";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpioe {
|
||||
@@ -246,6 +245,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0x80 0x20>;
|
||||
bank-name = "E";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
|
||||
gpiof {
|
||||
@@ -253,6 +253,7 @@
|
||||
u-boot,dm-pre-reloc;
|
||||
reg = <0xA0 0x20>;
|
||||
bank-name = "F";
|
||||
use-lvl-write-cache;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
131
arch/x86/include/asm/acpi_s3.h
Normal file
131
arch/x86/include/asm/acpi_s3.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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__
|
||||
|
||||
#define WAKEUP_BASE 0x600
|
||||
|
||||
/* 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
|
||||
|
||||
/* Memory size reserved for S3 resume */
|
||||
#define S3_RESERVE_SIZE 0x1000
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
extern char __wakeup[];
|
||||
extern int __wakeup_size;
|
||||
|
||||
enum acpi_sleep_state {
|
||||
ACPI_S0,
|
||||
ACPI_S1,
|
||||
ACPI_S2,
|
||||
ACPI_S3,
|
||||
ACPI_S4,
|
||||
ACPI_S5,
|
||||
};
|
||||
|
||||
/**
|
||||
* acpi_ss_string() - get ACPI-defined sleep state string
|
||||
*
|
||||
* @pm1_cnt: ACPI-defined sleep state
|
||||
* @return: a pointer to the sleep state string.
|
||||
*/
|
||||
static inline char *acpi_ss_string(enum acpi_sleep_state state)
|
||||
{
|
||||
char *ss_string[] = { "S0", "S1", "S2", "S3", "S4", "S5"};
|
||||
|
||||
return ss_string[state];
|
||||
}
|
||||
|
||||
/**
|
||||
* acpi_sleep_from_pm1() - get ACPI-defined sleep state from PM1_CNT register
|
||||
*
|
||||
* @pm1_cnt: PM1_CNT register value
|
||||
* @return: ACPI-defined sleep state if given valid PM1_CNT register value,
|
||||
* -EINVAL otherwise.
|
||||
*/
|
||||
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 -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
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.
|
||||
*
|
||||
* @fadt: FADT table pointer in the ACPI table
|
||||
* @return: Never returns
|
||||
*/
|
||||
void acpi_resume(struct acpi_fadt *fadt);
|
||||
|
||||
/**
|
||||
* acpi_s3_reserve() - Reserve memory for ACPI S3 resume
|
||||
*
|
||||
* This copies memory where real mode interrupt handler stubs reside to the
|
||||
* reserved place on the stack.
|
||||
*
|
||||
* This routine should be called by reserve_arch() before U-Boot is relocated
|
||||
* when ACPI S3 resume is enabled.
|
||||
*
|
||||
* @return: 0 always
|
||||
*/
|
||||
int acpi_s3_reserve(void);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __ASM_ACPI_S3_H__ */
|
||||
@@ -316,4 +316,32 @@ 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);
|
||||
/**
|
||||
* enter_acpi_mode() - enter into ACPI mode
|
||||
*
|
||||
* This programs the ACPI-defined PM1_CNT register to enable SCI interrupt
|
||||
* so that the whole system swiches to ACPI mode.
|
||||
*
|
||||
* @pm1_cnt: PM1_CNT register I/O address
|
||||
*/
|
||||
void enter_acpi_mode(int pm1_cnt);
|
||||
ulong write_acpi_tables(ulong start);
|
||||
|
||||
/**
|
||||
* acpi_find_fadt() - find ACPI FADT table in the sytem memory
|
||||
*
|
||||
* This routine parses the ACPI table to locate the ACPI FADT table.
|
||||
*
|
||||
* @return: a pointer to the ACPI FADT table in the system memory
|
||||
*/
|
||||
struct acpi_fadt *acpi_find_fadt(void);
|
||||
|
||||
/**
|
||||
* acpi_find_wakeup_vector() - find OS installed wake up vector address
|
||||
*
|
||||
* This routine parses the ACPI table to locate the wake up vector installed
|
||||
* by the OS previously.
|
||||
*
|
||||
* @return: wake up vector address installed by the OS
|
||||
*/
|
||||
void *acpi_find_wakeup_vector(struct acpi_fadt *);
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
31
arch/x86/include/asm/cmos_layout.h
Normal file
31
arch/x86/include/asm/cmos_layout.h
Normal file
@@ -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 */
|
||||
43
arch/x86/include/asm/early_cmos.h
Normal file
43
arch/x86/include/asm/early_cmos.h
Normal file
@@ -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 */
|
||||
@@ -99,6 +99,10 @@ 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 ACPI_S0/1../5 */
|
||||
ulong backup_mem; /* Backup memory address for S3 */
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -54,6 +54,19 @@ u32 isa_map_rom(u32 bus_addr, int size);
|
||||
/* arch/x86/lib/... */
|
||||
int video_bios_init(void);
|
||||
|
||||
/* arch/x86/lib/fsp/... */
|
||||
|
||||
/**
|
||||
* fsp_save_s3_stack() - save stack address to CMOS for next S3 boot
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @return: 0 if OK, -ve on error
|
||||
*/
|
||||
int fsp_save_s3_stack(void);
|
||||
|
||||
void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn));
|
||||
void board_init_f_r(void) __attribute__ ((noreturn));
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -37,6 +38,7 @@ obj-$(CONFIG_INTEL_MID) += scu.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
|
||||
|
||||
82
arch/x86/lib/acpi_s3.c
Normal file
82
arch/x86/lib/acpi_s3.c
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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/acpi_table.h>
|
||||
#include <asm/post.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
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(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);
|
||||
|
||||
/*
|
||||
* Restore the memory content starting from address 0x1000 which is
|
||||
* used for the real mode interrupt handler stubs.
|
||||
*/
|
||||
memcpy((void *)0x1000, (const void *)gd->arch.backup_mem,
|
||||
S3_RESERVE_SIZE);
|
||||
|
||||
post_code(POST_OS_RESUME);
|
||||
acpi_jump_to_wakeup(wake_vec);
|
||||
}
|
||||
|
||||
int acpi_s3_reserve(void)
|
||||
{
|
||||
/* adjust stack pointer for ACPI S3 resume backup memory */
|
||||
gd->start_addr_sp -= S3_RESERVE_SIZE;
|
||||
gd->arch.backup_mem = gd->start_addr_sp;
|
||||
|
||||
gd->start_addr_sp &= ~0xf;
|
||||
|
||||
/*
|
||||
* U-Boot sets up the real mode interrupt handler stubs starting from
|
||||
* address 0x1000. In most cases, the first 640K (0x00000 - 0x9ffff)
|
||||
* system memory is reported as system RAM in E820 table to the OS.
|
||||
* (see install_e820_map() implementation for each platform). So OS
|
||||
* can use these memories whatever it wants.
|
||||
*
|
||||
* If U-Boot is in an S3 resume path, care must be taken not to corrupt
|
||||
* these memorie otherwise OS data gets lost. Testing shows that, on
|
||||
* Microsoft Windows 10 on Intel Baytrail its wake up vector happens to
|
||||
* be installed at the same address 0x1000. While on Linux its wake up
|
||||
* vector does not overlap this memory range, but after resume kernel
|
||||
* 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 (it's harmless, but warnings are shown
|
||||
* in the kernel dmesg logs).
|
||||
*
|
||||
* We cannot simply mark the these memory as reserved in E820 table
|
||||
* because such configuration makes GRUB complain: unable to allocate
|
||||
* real mode page. Hence we choose to back up these memories to the
|
||||
* place where we reserved on our stack for our S3 resume work.
|
||||
* Before jumping to OS wake up vector, we need restore the original
|
||||
* content there (see acpi_resume() above).
|
||||
*/
|
||||
if (gd->arch.prev_sleep_state == ACPI_S3)
|
||||
memcpy((void *)gd->arch.backup_mem, (const void *)0x1000,
|
||||
S3_RESERVE_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -304,8 +304,10 @@ 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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -438,3 +440,81 @@ 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;
|
||||
}
|
||||
|
||||
struct acpi_fadt *acpi_find_fadt(void)
|
||||
{
|
||||
char *p, *end;
|
||||
struct acpi_rsdp *rsdp = NULL;
|
||||
struct acpi_rsdt *rsdt;
|
||||
struct acpi_fadt *fadt = NULL;
|
||||
int i;
|
||||
|
||||
/* 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);
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm/device.h>
|
||||
#include <dm/root.h>
|
||||
#include <errno.h>
|
||||
#include <fdt_support.h>
|
||||
#include <image.h>
|
||||
@@ -46,6 +48,13 @@ void bootm_announce_and_cleanup(void)
|
||||
#ifdef CONFIG_BOOTSTAGE_REPORT
|
||||
bootstage_report();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Call remove function of all devices with a removal flag set.
|
||||
* This may be useful for last-stage operations, like cancelling
|
||||
* of DMA operation or releasing device internal buffers.
|
||||
*/
|
||||
dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF_LIBFDT) && !defined(CONFIG_OF_NO_KERNEL)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <common.h>
|
||||
#include <vbe.h>
|
||||
#include <asm/acpi_s3.h>
|
||||
#include <asm/coreboot_tables.h>
|
||||
#include <asm/e820.h>
|
||||
|
||||
@@ -19,7 +20,11 @@ int high_table_reserve(void)
|
||||
gd->arch.high_table_ptr = gd->start_addr_sp;
|
||||
|
||||
/* clear the memory */
|
||||
memset((void *)gd->arch.high_table_ptr, 0, CONFIG_HIGH_TABLE_SIZE);
|
||||
#ifdef CONFIG_HAVE_ACPI_RESUME
|
||||
if (gd->arch.prev_sleep_state != ACPI_S3)
|
||||
#endif
|
||||
memset((void *)gd->arch.high_table_ptr, 0,
|
||||
CONFIG_HIGH_TABLE_SIZE);
|
||||
|
||||
gd->start_addr_sp &= ~0xf;
|
||||
|
||||
|
||||
51
arch/x86/lib/early_cmos.c
Normal file
51
arch/x86/lib/early_cmos.c
Normal file
@@ -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;
|
||||
}
|
||||
@@ -5,7 +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>
|
||||
@@ -75,9 +80,41 @@ 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 */
|
||||
ret = rtc_write32(dev, CMOS_FSP_STACK_ADDR, gd->start_addr_sp);
|
||||
if (ret) {
|
||||
debug("Save stack address to CMOS: err=%d\n", ret);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int arch_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();
|
||||
gd->arch.prev_sleep_state = prev_sleep_state;
|
||||
#endif
|
||||
|
||||
if (!gd->arch.hob_list) {
|
||||
#ifdef CONFIG_ENABLE_MRC_CACHE
|
||||
@@ -85,12 +122,36 @@ int arch_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");
|
||||
}
|
||||
|
||||
/*
|
||||
* DM is not avaiable yet at this point, hence call
|
||||
* CMOS access library which does not depend on DM.
|
||||
*/
|
||||
stack = cmos_read32(CMOS_FSP_STACK_ADDR);
|
||||
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(stack, boot_mode, nvs);
|
||||
} else {
|
||||
/*
|
||||
* The second time we enter here, adjust the size of malloc()
|
||||
|
||||
@@ -92,5 +92,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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user