Merge git://git.denx.de/u-boot-x86

This commit is contained in:
Tom Rini 2017-05-17 14:13:16 -04:00
commit ae1b939930
44 changed files with 1006 additions and 115 deletions

View File

@ -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"

View File

@ -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

View File

@ -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/

View File

@ -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

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -5,4 +5,4 @@
#
obj-y += fsp_configs.o irq.o
obj-y += tnc.o topcliff.o
obj-y += tnc.o

View File

@ -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
View 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

View File

@ -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;
};
};
};

View File

@ -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;
};
};
};

View File

@ -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;
};
};
};

View File

@ -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;
};
};
};

View File

@ -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;
};
};
};

View 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__ */

View File

@ -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 *);

View File

@ -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})

View File

@ -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

View 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 */

View 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 */

View File

@ -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

View File

@ -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__

View File

@ -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

View File

@ -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));

View File

@ -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
View 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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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
View 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;
}

View File

@ -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()

View File

@ -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;
}

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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,
};

View File

@ -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,

View File

@ -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,
};
/**

View File

@ -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