]> git.sur5r.net Git - u-boot/commitdiff
Merge git://git.denx.de/u-boot-uniphier
authorTom Rini <trini@konsulko.com>
Wed, 17 May 2017 18:13:58 +0000 (14:13 -0400)
committerTom Rini <trini@konsulko.com>
Wed, 17 May 2017 18:13:58 +0000 (14:13 -0400)
- Add workaround code to make LD20 SoC boot from ARM Trusted Firmware
- Sync DT with Linux to fix DTC warnings
- Add new SoC support code
- Misc fix, updates

46 files changed:
arch/Kconfig
arch/powerpc/cpu/mpc85xx/t1024_serdes.c
arch/powerpc/include/asm/immap_85xx.h
arch/x86/Kconfig
arch/x86/cpu/Makefile
arch/x86/cpu/baytrail/acpi.c
arch/x86/cpu/baytrail/valleyview.c
arch/x86/cpu/cpu.c
arch/x86/cpu/quark/quark.c
arch/x86/cpu/queensbay/Makefile
arch/x86/cpu/queensbay/topcliff.c [deleted file]
arch/x86/cpu/wakeup.S [new file with mode: 0644]
arch/x86/dts/bayleybay.dts
arch/x86/dts/baytrail_som-db5800-som-6867.dts
arch/x86/dts/conga-qeval20-qa3-e3845.dts
arch/x86/dts/dfi-bt700.dtsi
arch/x86/dts/minnowmax.dts
arch/x86/include/asm/acpi_s3.h [new file with mode: 0644]
arch/x86/include/asm/acpi_table.h
arch/x86/include/asm/arch-baytrail/acpi/sleepstates.asl
arch/x86/include/asm/arch-baytrail/iomap.h
arch/x86/include/asm/cmos_layout.h [new file with mode: 0644]
arch/x86/include/asm/early_cmos.h [new file with mode: 0644]
arch/x86/include/asm/global_data.h
arch/x86/include/asm/post.h
arch/x86/include/asm/tables.h
arch/x86/include/asm/u-boot-x86.h
arch/x86/lib/Makefile
arch/x86/lib/acpi_s3.c [new file with mode: 0644]
arch/x86/lib/acpi_table.c
arch/x86/lib/bootm.c
arch/x86/lib/coreboot_table.c
arch/x86/lib/early_cmos.c [new file with mode: 0644]
arch/x86/lib/fsp/fsp_common.c
arch/x86/lib/fsp/fsp_dram.c
configs/minnowmax_defconfig
doc/README.x86
drivers/core/device-remove.c
drivers/gpio/intel_ich6_gpio.c
drivers/mmc/pci_mmc.c
drivers/pci/pci_rom.c
drivers/serial/serial-uclass.c
drivers/spi/ich.c
drivers/spi/ich.h
include/dm/device.h
include/mmc.h

index 826e346f9803106bf85e1f143a85cd8115cd5565..2528f50efa73e8e59546a6e00ca7be999fef382f 100644 (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"
index 2ba314a7f67043c5774c6e269efff25cb66a7f05..7c4519e4a4ca6b06c4de55b5297db0299abeb50d 100644 (file)
@@ -10,7 +10,7 @@
 #include <asm/io.h>
 
 
-static u8 serdes_cfg_tbl[][4] = {
+static u8 serdes_cfg_tbl[][SRDS_MAX_LANES] = {
        [0x40] = {PCIE1, PCIE1, PCIE1, PCIE1},
        [0xD5] = {QSGMII_FM1_A, PCIE3, PCIE2, PCIE1},
        [0xD6] = {QSGMII_FM1_A, PCIE3, PCIE2, SATA1},
@@ -45,7 +45,7 @@ int is_serdes_prtcl_valid(int serdes, u32 prtcl)
        if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl))
                return 0;
 
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < SRDS_MAX_LANES; i++) {
                if (serdes_cfg_tbl[prtcl][i] != NONE)
                        return 1;
        }
index 762b174b2d64213602f3e2e3d214dce0fbc93928..ee537f4ac9cb4c84a241f4c78d9e1d23211624f4 100644 (file)
@@ -2523,7 +2523,11 @@ typedef struct ccsr_gur {
 
 #ifdef CONFIG_SYS_FSL_QORIQ_CHASSIS2
 #define MAX_SERDES 4
+#if defined(CONFIG_ARCH_T1024) || defined(CONFIG_ARCH_T1023)
+#define SRDS_MAX_LANES 4
+#else
 #define SRDS_MAX_LANES 8
+#endif
 #define SRDS_MAX_BANK 2
 typedef struct serdes_corenet {
        struct {
index 9ead3ebccf89d1c8737058000528e7e99c78e0c0..0cd981e73e43f7293a83f71ea2056ac185c0f1ff 100644 (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
index 92a9023b0b2f1369a82c817b5a83c2104eef54fb..e1c84ce097addc330228cd3284b56333653e5193 100644 (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/
index fa92d8852eadba38a7a584c6d824153399c451e8..55ed7de781fd4cfcbc1b1d3f03bf13f944165b45 100644 (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
index 87ba849c1c4e58efa515cc947742eeb8970b180a..c58f6a86a8fd6b3542f7c8ba0d37df19b4a01da5 100644 (file)
 #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)
 {
index 8fa6953588b51537c90dc81aa662b1694f2d208e..e13786efa590018e2a8b9357d12caad66095a4d6 100644 (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
index 0c2cea4ee9dd1bf479ac04bb43374094ed8a7acf..c36a5892d5fcfabc6e4761ba3da27e4ef5a3f608 100644 (file)
 #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
index af3ffad385222ffb8ecafaca28d71d3b13eaba0e..c0681995bdf026748ad016fc53787d2e00f265a1 100644 (file)
@@ -5,4 +5,4 @@
 #
 
 obj-y += fsp_configs.o irq.o
-obj-y += tnc.o topcliff.o
+obj-y += tnc.o
diff --git a/arch/x86/cpu/queensbay/topcliff.c b/arch/x86/cpu/queensbay/topcliff.c
deleted file mode 100644 (file)
index b76dd7d..0000000
+++ /dev/null
@@ -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);
-}
diff --git a/arch/x86/cpu/wakeup.S b/arch/x86/cpu/wakeup.S
new file mode 100644 (file)
index 0000000..066c9b1
--- /dev/null
@@ -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
index 18b310d39e884224fa0d37eea61ca06e0d0f86d9..1ae058d7a94f5b609f2f2920460accea3a736185 100644 (file)
                                u-boot,dm-pre-reloc;
                                reg = <0 0x20>;
                                bank-name = "A";
+                               use-lvl-write-cache;
                        };
 
                        gpiob {
                                u-boot,dm-pre-reloc;
                                reg = <0x20 0x20>;
                                bank-name = "B";
+                               use-lvl-write-cache;
                        };
 
                        gpioc {
                                u-boot,dm-pre-reloc;
                                reg = <0x40 0x20>;
                                bank-name = "C";
+                               use-lvl-write-cache;
                        };
 
                        gpiod {
                                u-boot,dm-pre-reloc;
                                reg = <0x60 0x20>;
                                bank-name = "D";
+                               use-lvl-write-cache;
                        };
 
                        gpioe {
                                u-boot,dm-pre-reloc;
                                reg = <0x80 0x20>;
                                bank-name = "E";
+                               use-lvl-write-cache;
                        };
 
                        gpiof {
                                u-boot,dm-pre-reloc;
                                reg = <0xA0 0x20>;
                                bank-name = "F";
+                               use-lvl-write-cache;
                        };
                };
        };
index e1d81a7283a5717e49857b12125c8a1aa75c687f..aa8bfb86513c4fa9571a548058616e911b445c45 100644 (file)
                                u-boot,dm-pre-reloc;
                                reg = <0 0x20>;
                                bank-name = "A";
+                               use-lvl-write-cache;
                        };
 
                        gpiob {
                                u-boot,dm-pre-reloc;
                                reg = <0x20 0x20>;
                                bank-name = "B";
+                               use-lvl-write-cache;
                        };
 
                        gpioc {
                                u-boot,dm-pre-reloc;
                                reg = <0x40 0x20>;
                                bank-name = "C";
+                               use-lvl-write-cache;
                        };
 
                        gpiod {
                                u-boot,dm-pre-reloc;
                                reg = <0x60 0x20>;
                                bank-name = "D";
+                               use-lvl-write-cache;
                        };
 
                        gpioe {
                                u-boot,dm-pre-reloc;
                                reg = <0x80 0x20>;
                                bank-name = "E";
+                               use-lvl-write-cache;
                        };
 
                        gpiof {
                                u-boot,dm-pre-reloc;
                                reg = <0xA0 0x20>;
                                bank-name = "F";
+                               use-lvl-write-cache;
                        };
                };
        };
index f0efe908e2c5b8d938e93319b7cc8937e3d21042..898e9c9b5f7537dae2e7fe8822f3307b9430e6c5 100644 (file)
                                u-boot,dm-pre-reloc;
                                reg = <0 0x20>;
                                bank-name = "A";
+                               use-lvl-write-cache;
                        };
 
                        gpiob {
                                u-boot,dm-pre-reloc;
                                reg = <0x20 0x20>;
                                bank-name = "B";
+                               use-lvl-write-cache;
                        };
 
                        gpioc {
                                u-boot,dm-pre-reloc;
                                reg = <0x40 0x20>;
                                bank-name = "C";
+                               use-lvl-write-cache;
                        };
 
                        gpiod {
                                u-boot,dm-pre-reloc;
                                reg = <0x60 0x20>;
                                bank-name = "D";
+                               use-lvl-write-cache;
                        };
 
                        gpioe {
                                u-boot,dm-pre-reloc;
                                reg = <0x80 0x20>;
                                bank-name = "E";
+                               use-lvl-write-cache;
                        };
 
                        gpiof {
                                u-boot,dm-pre-reloc;
                                reg = <0xA0 0x20>;
                                bank-name = "F";
+                               use-lvl-write-cache;
                        };
                };
        };
index 75ee6ade7c16e6e18a515600bb8b93b294e41217..546981a9ac1c38bd96756889a3a2ec314f096bba 100644 (file)
                                u-boot,dm-pre-reloc;
                                reg = <0 0x20>;
                                bank-name = "A";
+                               use-lvl-write-cache;
                        };
 
                        gpiob {
                                u-boot,dm-pre-reloc;
                                reg = <0x20 0x20>;
                                bank-name = "B";
+                               use-lvl-write-cache;
                        };
 
                        gpioc {
                                u-boot,dm-pre-reloc;
                                reg = <0x40 0x20>;
                                bank-name = "C";
+                               use-lvl-write-cache;
                        };
 
                        gpiod {
                                u-boot,dm-pre-reloc;
                                reg = <0x60 0x20>;
                                bank-name = "D";
+                               use-lvl-write-cache;
                        };
 
                        gpioe {
                                u-boot,dm-pre-reloc;
                                reg = <0x80 0x20>;
                                bank-name = "E";
+                               use-lvl-write-cache;
                        };
 
                        gpiof {
                                u-boot,dm-pre-reloc;
                                reg = <0xA0 0x20>;
                                bank-name = "F";
+                               use-lvl-write-cache;
                        };
                };
        };
index d51318bdf60757cf6ff4ad3026de4211fff2a1b4..af64c6859ce77ccfcce20daf42745da00e577173 100644 (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>;
                                u-boot,dm-pre-reloc;
                                reg = <0 0x20>;
                                bank-name = "A";
+                               use-lvl-write-cache;
                        };
 
                        gpiob {
                                u-boot,dm-pre-reloc;
                                reg = <0x20 0x20>;
                                bank-name = "B";
+                               use-lvl-write-cache;
                        };
 
                        gpioc {
                                u-boot,dm-pre-reloc;
                                reg = <0x40 0x20>;
                                bank-name = "C";
+                               use-lvl-write-cache;
                        };
 
                        gpiod {
                                u-boot,dm-pre-reloc;
                                reg = <0x60 0x20>;
                                bank-name = "D";
+                               use-lvl-write-cache;
                        };
 
                        gpioe {
                                u-boot,dm-pre-reloc;
                                reg = <0x80 0x20>;
                                bank-name = "E";
+                               use-lvl-write-cache;
                        };
 
                        gpiof {
                                u-boot,dm-pre-reloc;
                                reg = <0xA0 0x20>;
                                bank-name = "F";
+                               use-lvl-write-cache;
                        };
                };
        };
diff --git a/arch/x86/include/asm/acpi_s3.h b/arch/x86/include/asm/acpi_s3.h
new file mode 100644 (file)
index 0000000..86aec0a
--- /dev/null
@@ -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__ */
index bbd80a1dd9aa9707a643a5ffef6017ee0a63db43..dd7a946b6c44c6b09fb66ae8133cffd210b50afd 100644 (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 *);
index eb5ae76186f1d61286fb6cdee185e6e298510930..56007230843a496907b143157b64c54ef4efde0e 100644 (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})
index 62a91051e47897eb813fae04df03a523e9a5eaad..ec4e9d5212a351d63897781be80cf4e25c7b17f3 100644 (file)
 #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
 
diff --git a/arch/x86/include/asm/cmos_layout.h b/arch/x86/include/asm/cmos_layout.h
new file mode 100644 (file)
index 0000000..0a0a51e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __CMOS_LAYOUT_H
+#define __CMOS_LAYOUT_H
+
+/*
+ * The RTC internal registers and RAM is organized as two banks of 128 bytes
+ * each, called the standard and extended banks. The first 14 bytes of the
+ * standard bank contain the RTC time and date information along with four
+ * registers, A - D, that are used for configuration of the RTC. The extended
+ * bank contains a full 128 bytes of battery backed SRAM.
+ *
+ * For simplicity in U-Boot we only support CMOS in the standard bank, and
+ * its base address starts from offset 0x10, which leaves us 112 bytes space.
+ */
+#define CMOS_BASE              0x10
+
+/*
+ * The file records all offsets off CMOS_BASE that is currently used by
+ * U-Boot for various reasons. It is put in such a unified place in order
+ * to be consistent across platforms.
+ */
+
+/* stack address for S3 boot in a FSP configuration, 4 bytes */
+#define CMOS_FSP_STACK_ADDR    CMOS_BASE
+
+#endif /* __CMOS_LAYOUT_H */
diff --git a/arch/x86/include/asm/early_cmos.h b/arch/x86/include/asm/early_cmos.h
new file mode 100644 (file)
index 0000000..cd2634d
--- /dev/null
@@ -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 */
index 4570bc7a4ad6a94b8b8b3981bca3fb83c5ec8306..93a80fe2b6c325d31e65caa37c2222bd0c3b8e68 100644 (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
index 6b774bdbe8a43efcc640b2d3301def49b5b0f03a..f627663f319b452357c4cf7c2523ccd3b10c2511 100644 (file)
 #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__
index d1b23880219ebc6f28be102c86834d7e72de3be4..9e8208ba2b7f2620b6270e53f56fb7386cce3b39 100644 (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
 
index d2d603967ef24f7932e504d7ca96528855d972f0..d55455f2d09a022c0cd000fd22ab30eeb3acb5d4 100644 (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));
 
index d1ad37af64861779132bd561bcd01137fd251116..fe00d7573f5147c5efa09dd45194e34e23c487ff 100644 (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
diff --git a/arch/x86/lib/acpi_s3.c b/arch/x86/lib/acpi_s3.c
new file mode 100644 (file)
index 0000000..3175da8
--- /dev/null
@@ -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;
+}
index 355456dc19e50366534137a6e977a883c013436a..01d5b6fff09329bf6a741d50a1e4fcde1d7f7a20 100644 (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;
+}
index 75bab902251d90d68585a1d0d742c4d0eee8bf98..ecd4f4e6c61fdc9a028598400670435a975ebffd 100644 (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)
index ceab3cf5e4f1bab37022c4bf520f13eb27d9ac6d..b1b4cd961312df8972f7cec528cae70283458b51 100644 (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;
 
diff --git a/arch/x86/lib/early_cmos.c b/arch/x86/lib/early_cmos.c
new file mode 100644 (file)
index 0000000..fa0b327
--- /dev/null
@@ -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;
+}
index 66a388d601f5fa046940c564d135fb1c64c3d64c..3397bb83eaf1191bc7a5cffdab3bf216fb10e174 100644 (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()
index 8b880cd59455a5d1a710fe5fab63c8f6478e1f33..1a7af576d549c55c06b930bad34eb60c3b383a44 100644 (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;
 }
index 8dac1d72fb973027e4469d4f1a1460d12cab694a..aa50e8842261ee4829c19fde23742147e03fc3da 100644 (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
index a38cc1bc6ca9b7b7a00036961f606bc4d1e48bf9..c69dc1c511341501d3a3e5c5ae904c2ee2e10fcb 100644 (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.
index cc0043b990b77400f29374f06b48ca07e87c8ada..3c6ab42f7d620a2aac9763f07cdbdb909072030d 100644 (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;
index 8b782260bc336cd1117531820f0aedc1cc2ed31b..0a9eb03fd0500c9cfc7d3a1605dbf46ff11c1da9 100644 (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)
index e39b476834e650d187cfa25278ac48e7cfe87232..6db89779ba3c1fada496030f533e533bc9a24262 100644 (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;
-
-               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;
+
+       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;
+
+       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);
index 57204c4f3f1ca098b19d60767320aa9542f081a1..75fb0933371583da12cf3e9f03154f3326d7d7ac 100644 (file)
 #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;
 }
 
index 43c028ebe63dfd22c72b5023ad79b6ec53fa59e7..c2b9c5f12f5791ee6e255d053d811be74b517bf2 100644 (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
 
index 893fe33b66f77572870397d17d45a077c2075b9a..bf2e99b5ccbd6c8a18afc5d7513bbeee984f6ab6 100644 (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,
 };
index bd0a82080962ae41f42b4bab36cf7ef2db787359..dcb8a9048f86960bb24eff93804e35383c9b5382 100644 (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,
index 079ec5700302657b16b9eb094e0ec609a95b6801..df02e41df3d3007cbdece2cb26092ce7a3c685b1 100644 (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,
 };
 
 /**
index fad12d608cef8194f8e6443de9ad97026291989d..8346b0e19e2cd6309e3dbc374d4b100f88a8be0e 100644 (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