mirror of
https://github.com/u-boot/u-boot.git
synced 2025-01-23 19:23:25 +08:00
Merge git://git.denx.de/u-boot-x86
This commit is contained in:
commit
ae1b939930
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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,21 @@ 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.
|
||||
|
||||
Note for testing S3 resume with Windows, correct graphics driver must be
|
||||
installed for your platform, otherwise you won't find "Sleep" option in
|
||||
the "Power" submenu from the Windows start menu.
|
||||
|
||||
EFI Support
|
||||
-----------
|
||||
U-Boot supports booting as a 32-bit or 64-bit EFI payload, e.g. with UEFI.
|
||||
|
@ -152,6 +152,15 @@ void device_free(struct udevice *dev)
|
||||
devres_release_probe(dev);
|
||||
}
|
||||
|
||||
static bool flags_remove(uint flags, uint drv_flags)
|
||||
{
|
||||
if ((flags & DM_REMOVE_NORMAL) ||
|
||||
(flags & (drv_flags & (DM_FLAG_ACTIVE_DMA | DM_FLAG_OS_PREPARE))))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int device_remove(struct udevice *dev, uint flags)
|
||||
{
|
||||
const struct driver *drv;
|
||||
@ -178,9 +187,7 @@ int device_remove(struct udevice *dev, uint flags)
|
||||
* Remove the device if called with the "normal" remove flag set,
|
||||
* or if the remove flag matches any of the drivers remove flags
|
||||
*/
|
||||
if (drv->remove &&
|
||||
((flags & DM_REMOVE_NORMAL) ||
|
||||
(flags & (drv->flags & DM_FLAG_ACTIVE_DMA)))) {
|
||||
if (drv->remove && flags_remove(flags, drv->flags)) {
|
||||
ret = drv->remove(dev);
|
||||
if (ret)
|
||||
goto err_remove;
|
||||
@ -194,8 +201,7 @@ int device_remove(struct udevice *dev, uint flags)
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & DM_REMOVE_NORMAL) ||
|
||||
(flags & (drv->flags & DM_FLAG_ACTIVE_DMA))) {
|
||||
if (flags_remove(flags, drv->flags)) {
|
||||
device_free(dev);
|
||||
|
||||
dev->seq = -1;
|
||||
|
@ -46,22 +46,31 @@ struct ich6_bank_priv {
|
||||
uint16_t use_sel;
|
||||
uint16_t io_sel;
|
||||
uint16_t lvl;
|
||||
u32 lvl_write_cache;
|
||||
bool use_lvl_write_cache;
|
||||
};
|
||||
|
||||
#define GPIO_USESEL_OFFSET(x) (x)
|
||||
#define GPIO_IOSEL_OFFSET(x) (x + 4)
|
||||
#define GPIO_LVL_OFFSET(x) (x + 8)
|
||||
|
||||
static int _ich6_gpio_set_value(uint16_t base, unsigned offset, int value)
|
||||
static int _ich6_gpio_set_value(struct ich6_bank_priv *bank, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = inl(base);
|
||||
if (bank->use_lvl_write_cache)
|
||||
val = bank->lvl_write_cache;
|
||||
else
|
||||
val = inl(bank->lvl);
|
||||
|
||||
if (value)
|
||||
val |= (1UL << offset);
|
||||
else
|
||||
val &= ~(1UL << offset);
|
||||
outl(val, base);
|
||||
outl(val, bank->lvl);
|
||||
if (bank->use_lvl_write_cache)
|
||||
bank->lvl_write_cache = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -112,6 +121,7 @@ static int ich6_gpio_probe(struct udevice *dev)
|
||||
struct ich6_bank_platdata *plat = dev_get_platdata(dev);
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct ich6_bank_priv *bank = dev_get_priv(dev);
|
||||
const void *prop;
|
||||
|
||||
uc_priv->gpio_count = GPIO_PER_BANK;
|
||||
uc_priv->bank_name = plat->bank_name;
|
||||
@ -119,6 +129,14 @@ static int ich6_gpio_probe(struct udevice *dev)
|
||||
bank->io_sel = plat->base_addr + 4;
|
||||
bank->lvl = plat->base_addr + 8;
|
||||
|
||||
prop = fdt_getprop(gd->fdt_blob, dev->of_offset,
|
||||
"use-lvl-write-cache", NULL);
|
||||
if (prop)
|
||||
bank->use_lvl_write_cache = true;
|
||||
else
|
||||
bank->use_lvl_write_cache = false;
|
||||
bank->lvl_write_cache = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -160,7 +178,7 @@ static int ich6_gpio_direction_output(struct udevice *dev, unsigned offset,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return _ich6_gpio_set_value(bank->lvl, offset, value);
|
||||
return _ich6_gpio_set_value(bank, offset, value);
|
||||
}
|
||||
|
||||
static int ich6_gpio_get_value(struct udevice *dev, unsigned offset)
|
||||
@ -170,6 +188,8 @@ static int ich6_gpio_get_value(struct udevice *dev, unsigned offset)
|
||||
int r;
|
||||
|
||||
tmplong = inl(bank->lvl);
|
||||
if (bank->use_lvl_write_cache)
|
||||
tmplong |= bank->lvl_write_cache;
|
||||
r = (tmplong & (1UL << offset)) ? 1 : 0;
|
||||
return r;
|
||||
}
|
||||
@ -178,7 +198,7 @@ static int ich6_gpio_set_value(struct udevice *dev, unsigned offset,
|
||||
int value)
|
||||
{
|
||||
struct ich6_bank_priv *bank = dev_get_priv(dev);
|
||||
return _ich6_gpio_set_value(bank->lvl, offset, value);
|
||||
return _ich6_gpio_set_value(bank, offset, value);
|
||||
}
|
||||
|
||||
static int ich6_gpio_get_function(struct udevice *dev, unsigned offset)
|
||||
|
@ -6,37 +6,71 @@
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <mapmem.h>
|
||||
#include <sdhci.h>
|
||||
#include <asm/pci.h>
|
||||
|
||||
int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported)
|
||||
struct pci_mmc_plat {
|
||||
struct mmc_config cfg;
|
||||
struct mmc mmc;
|
||||
};
|
||||
|
||||
struct pci_mmc_priv {
|
||||
struct sdhci_host host;
|
||||
void *base;
|
||||
};
|
||||
|
||||
static int pci_mmc_probe(struct udevice *dev)
|
||||
{
|
||||
struct sdhci_host *mmc_host;
|
||||
u32 iobase;
|
||||
struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
|
||||
struct pci_mmc_plat *plat = dev_get_platdata(dev);
|
||||
struct pci_mmc_priv *priv = dev_get_priv(dev);
|
||||
struct sdhci_host *host = &priv->host;
|
||||
u32 ioaddr;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
struct udevice *dev;
|
||||
dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &ioaddr);
|
||||
host->ioaddr = map_sysmem(ioaddr, 0);
|
||||
host->name = dev->name;
|
||||
ret = sdhci_setup_cfg(&plat->cfg, host, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
host->mmc = &plat->mmc;
|
||||
host->mmc->priv = &priv->host;
|
||||
host->mmc->dev = dev;
|
||||
upriv->mmc = host->mmc;
|
||||
|
||||
ret = pci_find_device_id(mmc_supported, i, &dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
mmc_host = malloc(sizeof(struct sdhci_host));
|
||||
if (!mmc_host)
|
||||
return -ENOMEM;
|
||||
|
||||
mmc_host->name = name;
|
||||
dm_pci_read_config32(dev, PCI_BASE_ADDRESS_0, &iobase);
|
||||
mmc_host->ioaddr = (void *)(ulong)iobase;
|
||||
mmc_host->quirks = 0;
|
||||
mmc_host->max_clk = 0;
|
||||
ret = add_sdhci(mmc_host, 0, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return sdhci_probe(dev);
|
||||
}
|
||||
|
||||
static int pci_mmc_bind(struct udevice *dev)
|
||||
{
|
||||
struct pci_mmc_plat *plat = dev_get_platdata(dev);
|
||||
|
||||
return sdhci_bind(dev, &plat->mmc, &plat->cfg);
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(pci_mmc) = {
|
||||
.name = "pci_mmc",
|
||||
.id = UCLASS_MMC,
|
||||
.bind = pci_mmc_bind,
|
||||
.probe = pci_mmc_probe,
|
||||
.ops = &sdhci_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct pci_mmc_priv),
|
||||
.platdata_auto_alloc_size = sizeof(struct pci_mmc_plat),
|
||||
};
|
||||
|
||||
static struct pci_device_id mmc_supported[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SDIO) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_SD) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT_EMMC2) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_QRK_SDIO) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_0) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TCF_SDIO_1) },
|
||||
{},
|
||||
};
|
||||
|
||||
U_BOOT_PCI_DEVICE(pci_mmc, mmc_supported);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -349,7 +349,7 @@ static int serial_pre_remove(struct udevice *dev)
|
||||
#if CONFIG_IS_ENABLED(SYS_STDIO_DEREGISTER)
|
||||
struct serial_dev_priv *upriv = dev_get_uclass_priv(dev);
|
||||
|
||||
if (stdio_deregister_dev(upriv->sdev, 0))
|
||||
if (stdio_deregister_dev(upriv->sdev, true))
|
||||
return -EPERM;
|
||||
#endif
|
||||
|
||||
|
@ -617,6 +617,22 @@ static int ich_spi_probe(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ich_spi_remove(struct udevice *bus)
|
||||
{
|
||||
struct ich_spi_priv *ctlr = dev_get_priv(bus);
|
||||
|
||||
/*
|
||||
* Configure SPI controller so that the Linux MTD driver can fully
|
||||
* access the SPI NOR chip
|
||||
*/
|
||||
ich_writew(ctlr, SPI_OPPREFIX, ctlr->preop);
|
||||
ich_writew(ctlr, SPI_OPTYPE, ctlr->optype);
|
||||
ich_writel(ctlr, SPI_OPMENU_LOWER, ctlr->opmenu);
|
||||
ich_writel(ctlr, SPI_OPMENU_UPPER, ctlr->opmenu + sizeof(u32));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ich_spi_set_speed(struct udevice *bus, uint speed)
|
||||
{
|
||||
struct ich_spi_priv *priv = dev_get_priv(bus);
|
||||
@ -700,4 +716,6 @@ U_BOOT_DRIVER(ich_spi) = {
|
||||
.priv_auto_alloc_size = sizeof(struct ich_spi_priv),
|
||||
.child_pre_probe = ich_spi_child_pre_probe,
|
||||
.probe = ich_spi_probe,
|
||||
.remove = ich_spi_remove,
|
||||
.flags = DM_FLAG_OS_PREPARE,
|
||||
};
|
||||
|
@ -101,13 +101,6 @@ enum {
|
||||
HSFC_FSMIE = 0x8000
|
||||
};
|
||||
|
||||
enum {
|
||||
SPI_OPCODE_TYPE_READ_NO_ADDRESS = 0,
|
||||
SPI_OPCODE_TYPE_WRITE_NO_ADDRESS = 1,
|
||||
SPI_OPCODE_TYPE_READ_WITH_ADDRESS = 2,
|
||||
SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS = 3
|
||||
};
|
||||
|
||||
enum {
|
||||
ICH_MAX_CMD_LEN = 5,
|
||||
};
|
||||
@ -124,8 +117,55 @@ struct spi_trans {
|
||||
uint32_t offset;
|
||||
};
|
||||
|
||||
#define SPI_OPCODE_WRSR 0x01
|
||||
#define SPI_OPCODE_PAGE_PROGRAM 0x02
|
||||
#define SPI_OPCODE_READ 0x03
|
||||
#define SPI_OPCODE_WRDIS 0x04
|
||||
#define SPI_OPCODE_RDSR 0x05
|
||||
#define SPI_OPCODE_WREN 0x06
|
||||
#define SPI_OPCODE_FAST_READ 0x0b
|
||||
#define SPI_OPCODE_ERASE_SECT 0x20
|
||||
#define SPI_OPCODE_READ_ID 0x9f
|
||||
#define SPI_OPCODE_ERASE_BLOCK 0xd8
|
||||
|
||||
#define SPI_OPCODE_TYPE_READ_NO_ADDRESS 0
|
||||
#define SPI_OPCODE_TYPE_WRITE_NO_ADDRESS 1
|
||||
#define SPI_OPCODE_TYPE_READ_WITH_ADDRESS 2
|
||||
#define SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS 3
|
||||
|
||||
#define SPI_OPMENU_0 SPI_OPCODE_WRSR
|
||||
#define SPI_OPTYPE_0 SPI_OPCODE_TYPE_WRITE_NO_ADDRESS
|
||||
|
||||
#define SPI_OPMENU_1 SPI_OPCODE_PAGE_PROGRAM
|
||||
#define SPI_OPTYPE_1 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS
|
||||
|
||||
#define SPI_OPMENU_2 SPI_OPCODE_READ
|
||||
#define SPI_OPTYPE_2 SPI_OPCODE_TYPE_READ_WITH_ADDRESS
|
||||
|
||||
#define SPI_OPMENU_3 SPI_OPCODE_RDSR
|
||||
#define SPI_OPTYPE_3 SPI_OPCODE_TYPE_READ_NO_ADDRESS
|
||||
|
||||
#define SPI_OPMENU_4 SPI_OPCODE_ERASE_SECT
|
||||
#define SPI_OPTYPE_4 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS
|
||||
|
||||
#define SPI_OPMENU_5 SPI_OPCODE_READ_ID
|
||||
#define SPI_OPTYPE_5 SPI_OPCODE_TYPE_READ_NO_ADDRESS
|
||||
|
||||
#define SPI_OPMENU_6 SPI_OPCODE_ERASE_BLOCK
|
||||
#define SPI_OPTYPE_6 SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS
|
||||
|
||||
#define SPI_OPMENU_7 SPI_OPCODE_FAST_READ
|
||||
#define SPI_OPTYPE_7 SPI_OPCODE_TYPE_READ_WITH_ADDRESS
|
||||
|
||||
#define SPI_OPPREFIX ((SPI_OPCODE_WREN << 8) | SPI_OPCODE_WREN)
|
||||
#define SPI_OPTYPE ((SPI_OPTYPE_7 << 14) | (SPI_OPTYPE_6 << 12) | \
|
||||
(SPI_OPTYPE_5 << 10) | (SPI_OPTYPE_4 << 8) | \
|
||||
(SPI_OPTYPE_3 << 6) | (SPI_OPTYPE_2 << 4) | \
|
||||
(SPI_OPTYPE_1 << 2) | (SPI_OPTYPE_0 << 0))
|
||||
#define SPI_OPMENU_UPPER ((SPI_OPMENU_7 << 24) | (SPI_OPMENU_6 << 16) | \
|
||||
(SPI_OPMENU_5 << 8) | (SPI_OPMENU_4 << 0))
|
||||
#define SPI_OPMENU_LOWER ((SPI_OPMENU_3 << 24) | (SPI_OPMENU_2 << 16) | \
|
||||
(SPI_OPMENU_1 << 8) | (SPI_OPMENU_0 << 0))
|
||||
|
||||
enum ich_version {
|
||||
ICHV_7,
|
||||
|
@ -54,6 +54,12 @@ struct driver_info;
|
||||
*/
|
||||
#define DM_FLAG_ACTIVE_DMA (1 << 9)
|
||||
|
||||
/*
|
||||
* Call driver remove function to do some final configuration, before
|
||||
* U-Boot exits and the OS is started
|
||||
*/
|
||||
#define DM_FLAG_OS_PREPARE (1 << 10)
|
||||
|
||||
/*
|
||||
* One or multiple of these flags are passed to device_remove() so that
|
||||
* a selective device removal as specified by the remove-stage and the
|
||||
@ -66,10 +72,13 @@ enum {
|
||||
/* Remove devices with active DMA */
|
||||
DM_REMOVE_ACTIVE_DMA = DM_FLAG_ACTIVE_DMA,
|
||||
|
||||
/* Remove devices which need some final OS preparation steps */
|
||||
DM_REMOVE_OS_PREPARE = DM_FLAG_OS_PREPARE,
|
||||
|
||||
/* Add more use cases here */
|
||||
|
||||
/* Remove devices with any active flag */
|
||||
DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA,
|
||||
DM_REMOVE_ACTIVE_ALL = DM_REMOVE_ACTIVE_DMA | DM_REMOVE_OS_PREPARE,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -585,18 +585,6 @@ int cpu_mmc_init(bd_t *bis);
|
||||
int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr);
|
||||
int mmc_get_env_dev(void);
|
||||
|
||||
struct pci_device_id;
|
||||
|
||||
/**
|
||||
* pci_mmc_init() - set up PCI MMC devices
|
||||
*
|
||||
* This finds all the matching PCI IDs and sets them up as MMC devices.
|
||||
*
|
||||
* @name: Name to use for devices
|
||||
* @mmc_supported: PCI IDs to search for, terminated by {0, 0}
|
||||
*/
|
||||
int pci_mmc_init(const char *name, struct pci_device_id *mmc_supported);
|
||||
|
||||
/* Set block count limit because of 16 bit register limit on some hardware*/
|
||||
#ifndef CONFIG_SYS_MMC_MAX_BLK_COUNT
|
||||
#define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
|
||||
|
Loading…
Reference in New Issue
Block a user