[U-Boot] [PATCH 00/38] x86: Various modifications to prepare for FSP2

Quite a bit of minor refactoring is needed to prepare for using FSP2 in U-Boot. This series consists of a number of small changes to this end.
It is the last series before apollolake support is added.
Changes include: - Allowing drivers to be used in TPL/SPL - Moving common FSP code into a common directory - Support for memory-mapped flash on newer Intel chips - Passing the HOB list from SPL to U-Boot proper
This series is available at u-boot-dm/x86-working
Simon Glass (38): binman: Pass the toolpath to binman from the main Makefile binman: Allow selection of logging verbosity dm: gpio: Allow control of GPIO uclass in SPL mtd: spi: Add 'struct spi_flash {' to the code serial: ns16550: Allow serial to enabled/disabled in SPL spl: Correct priority selection for image loaders spl: Avoid checking for Ctrl-C in SPL with print_buffer() spl: handoff: Correct Kconfig condition for SPL and TPL spl: Add an arch-specific hook for writing to SPL handoff spl: Set up the bloblist in board_init_r() spl: Add a function to determine the U-Boot phase x86: spi: Add a driver for the Intel Fast SPI interface spi: sandbox: Add a test driver for sandbox SPI flash spi: Add support for memory-mapped flash x86: sysreset: Allow reset driver to be included in SPL/TPL x86: Rename some FSP functions to have an fsp_ prefix x86: fsp: Create a common fsp_support.h header x86: fsp: Use if() instead of #ifdef x86: fsp: Tidy up comment style a little x86: fsp: Move common dram functions into a common file x86: Move common fsp functions into a common file x86: fsp: Move common support functions into a common file efi: Move inline functions to unconditional part of header x86: fsp: Add a few more definitions for FSP2 x86: fsp: Add access to variable MRC data x86: Move common Intel CPU info code into a function x86: Add binman symbols to the image x86: pci: Add a function to clear and set PCI config regs x86: spl: Use hang() instead of a while() loop x86: spl: Reduce priority of the basic SPL image loader x86: spl: Move broadwell-specific code out of generic x86 spl x86: fsp: Save usable RAM and hob_list in the handoff area x86: fsp: Allow the HOBs to be used after relocation x86: Change condition for using CAR x86: Add more comments to the start-up code x86: Add support for booting from Fast SPI x86: Add various MTRR indexes and values x86: Rename turbo ratio MSR to MSR_TURBO_RATIO_LIMIT
Makefile | 4 +- arch/sandbox/cpu/spl.c | 7 + arch/sandbox/dts/test.dts | 4 + arch/x86/Kconfig | 8 + arch/x86/cpu/baytrail/fsp_configs.c | 2 +- arch/x86/cpu/braswell/fsp_configs.c | 2 +- arch/x86/cpu/broadwell/cpu.c | 5 + arch/x86/cpu/broadwell/cpu_full.c | 18 +- arch/x86/cpu/cpu.c | 6 + arch/x86/cpu/intel_common/Makefile | 1 + arch/x86/cpu/intel_common/cpu.c | 13 + arch/x86/cpu/intel_common/cpu_from_spl.c | 6 + arch/x86/cpu/intel_common/fast_spi.c | 48 ++++ arch/x86/cpu/ivybridge/fsp_configs.c | 2 +- arch/x86/cpu/ivybridge/model_206ax.c | 8 +- arch/x86/cpu/pci.c | 19 ++ arch/x86/cpu/queensbay/fsp_configs.c | 2 +- arch/x86/cpu/start.S | 16 +- arch/x86/cpu/start_from_spl.S | 5 +- arch/x86/cpu/start_from_tpl.S | 3 +- arch/x86/cpu/u-boot-spl.lds | 6 + arch/x86/include/asm/cpu_common.h | 11 + arch/x86/include/asm/fsp/fsp_hob.h | 4 + arch/x86/include/asm/fsp/fsp_infoheader.h | 15 +- arch/x86/include/asm/fsp/fsp_support.h | 174 +++++++++++++ arch/x86/include/asm/fsp1/fsp_support.h | 147 ++--------- arch/x86/include/asm/handoff.h | 8 + arch/x86/include/asm/hob.h | 26 +- arch/x86/include/asm/msr-index.h | 24 +- arch/x86/include/asm/mtrr.h | 1 + arch/x86/include/asm/pci.h | 40 +++ arch/x86/include/asm/spl.h | 4 +- arch/x86/lib/Makefile | 1 + arch/x86/lib/fsp/Makefile | 7 + arch/x86/lib/fsp/fsp_common.c | 104 ++++++++ arch/x86/lib/fsp/fsp_dram.c | 100 ++++++++ arch/x86/lib/fsp/fsp_support.c | 199 +++++++++++++++ arch/x86/lib/fsp1/fsp_car.S | 10 +- arch/x86/lib/fsp1/fsp_common.c | 96 +------ arch/x86/lib/fsp1/fsp_dram.c | 88 +------ arch/x86/lib/fsp1/fsp_support.c | 181 +------------ arch/x86/lib/hob.c | 19 +- arch/x86/lib/spl.c | 13 +- arch/x86/lib/tpl.c | 7 +- cmd/x86/fsp.c | 2 +- common/spl/Kconfig | 4 +- common/spl/spl.c | 47 ++-- configs/slimbootloader_defconfig | 1 + drivers/gpio/Kconfig | 22 ++ drivers/gpio/Makefile | 2 +- drivers/mtd/spi/Kconfig | 9 + drivers/mtd/spi/Makefile | 3 +- drivers/mtd/spi/intel_fast_spi.c | 294 ++++++++++++++++++++++ drivers/mtd/spi/sandbox_direct.c | 110 ++++++++ drivers/mtd/spi/sf-uclass.c | 11 + drivers/pci/pci-uclass.c | 2 +- drivers/serial/ns16550.c | 6 +- drivers/sysreset/Kconfig | 12 + drivers/sysreset/Makefile | 2 +- include/efi_loader.h | 42 ++-- include/handoff.h | 13 + include/linux/mtd/spi-nor.h | 8 +- include/spi_flash.h | 27 ++ include/spl.h | 64 ++++- lib/display_options.c | 2 + test/dm/sf.c | 51 ++++ tools/binman/README | 6 + 67 files changed, 1612 insertions(+), 592 deletions(-) create mode 100644 arch/x86/cpu/intel_common/fast_spi.c create mode 100644 arch/x86/include/asm/fsp/fsp_support.h create mode 100644 arch/x86/lib/fsp/Makefile create mode 100644 arch/x86/lib/fsp/fsp_common.c create mode 100644 arch/x86/lib/fsp/fsp_dram.c create mode 100644 arch/x86/lib/fsp/fsp_support.c create mode 100644 drivers/mtd/spi/intel_fast_spi.c create mode 100644 drivers/mtd/spi/sandbox_direct.c

Pass in the toolpath in case binman needs to use tools compiled in the U-Boot tools/ directory.
Signed-off-by: Simon Glass sjg@chromium.org ---
Makefile | 1 + 1 file changed, 1 insertion(+)
diff --git a/Makefile b/Makefile index df4a54e204..4413605175 100644 --- a/Makefile +++ b/Makefile @@ -1190,6 +1190,7 @@ u-boot.ldr: u-boot # Use 'make BINMAN_DEBUG=1' to enable debugging quiet_cmd_binman = BINMAN $@ cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \ + --toolpath $(objtree)/tools \ build -u -d u-boot.dtb -O . -m \ -I . -I $(srctree) -I $(srctree)/board/$(BOARDDIR) \ $(BINMAN_$(@F))

Support a new BINMAN_VERBOSE option to the build, to allow passing the -v flag to binman.
Signed-off-by: Simon Glass sjg@chromium.org ---
Makefile | 3 ++- tools/binman/README | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile index 4413605175..60c173cab0 100644 --- a/Makefile +++ b/Makefile @@ -1191,7 +1191,8 @@ u-boot.ldr: u-boot quiet_cmd_binman = BINMAN $@ cmd_binman = $(srctree)/tools/binman/binman $(if $(BINMAN_DEBUG),-D) \ --toolpath $(objtree)/tools \ - build -u -d u-boot.dtb -O . -m \ + $(if $(BINMAN_VERBOSE),-v$(BINMAN_VERBOSE)) \ + build -u -d u-boot.dtb -O . -m \ -I . -I $(srctree) -I $(srctree)/board/$(BOARDDIR) \ $(BINMAN_$(@F))
diff --git a/tools/binman/README b/tools/binman/README index fc0eeaa39e..033b78709c 100644 --- a/tools/binman/README +++ b/tools/binman/README @@ -934,6 +934,12 @@ BINMAN_DEBUG=1 to your build: make sandbox_defconfig make BINMAN_DEBUG=1
+To enable verbose logging from binman, base BINMAN_VERBOSE to your build, which +adds a -v<level> option to the call to binman: + + make sandbox_defconfig + make BINMAN_VERBOSE=5 +
History / Credits -----------------

At present if CONFIG_SPL_GPIO_SUPPORT is enabled then the GPIO uclass is included in SPL/TPL without any control for boards. Some boards may want to disable this to reduce code size where GPIOs are not needed in SPL or TPL.
Add a new Kconfig option to permit this. Default it to 'y' so that existing boards work correctly.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/gpio/Kconfig | 22 ++++++++++++++++++++++ drivers/gpio/Makefile | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 7d9c97f537..73451c9379 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -14,6 +14,28 @@ config DM_GPIO particular GPIOs that they provide. The uclass interface is defined in include/asm-generic/gpio.h.
+config SPL_DM_GPIO + bool "Enable Driver Model for GPIO drivers in SPL" + depends on DM_GPIO && SPL && SPL_GPIO_SUPPORT + default y + help + Enable driver model for GPIO access. The standard GPIO + interface (gpio_get_value(), etc.) is then implemented by + the GPIO uclass. Drivers provide methods to query the + particular GPIOs that they provide. The uclass interface + is defined in include/asm-generic/gpio.h. + +config TPL_DM_GPIO + bool "Enable Driver Model for GPIO drivers in TPL" + depends on DM_GPIO && TPL && TPL_GPIO_SUPPORT + default y + help + Enable driver model for GPIO access. The standard GPIO + interface (gpio_get_value(), etc.) is then implemented by + the GPIO uclass. Drivers provide methods to query the + particular GPIOs that they provide. The uclass interface + is defined in include/asm-generic/gpio.h. + config GPIO_HOG bool "Enable GPIO hog support" depends on DM_GPIO diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 4a8aa0ff6f..56e9374e30 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -7,7 +7,7 @@ ifndef CONFIG_SPL_BUILD obj-$(CONFIG_DWAPB_GPIO) += dwapb_gpio.o obj-$(CONFIG_AXP_GPIO) += axp_gpio.o endif -obj-$(CONFIG_DM_GPIO) += gpio-uclass.o +obj-$(CONFIG_$(SPL_TPL_)DM_GPIO) += gpio-uclass.o
obj-$(CONFIG_$(SPL_)DM_PCA953X) += pca953x_gpio.o obj-$(CONFIG_DM_74X164) += 74x164_gpio.o

At present spi_flash is defined to be spi_nor which is confusing since it is not possible to find the 'spi_flash' by normal text search. Add a comment to help with this.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/linux/mtd/spi-nor.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 88e80af579..06ba5fca11 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -242,7 +242,13 @@ enum spi_nor_option_flags { */ struct flash_info;
-/* TODO: Remove, once all users of spi_flash interface are moved to MTD */ +/* + * TODO: Remove, once all users of spi_flash interface are moved to MTD + * + * struct spi_flash { + * Defined below (keep this text to enable searching for spi_flash decl) + * } + */ #define spi_flash spi_nor
/**

At present this driver uses the wrong condition for including the code and drivers in SPL/TPL. Update it so that the code is only included if DM_SERIAL is enabled for SPL/TPL.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/serial/ns16550.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 6cf2be8f2b..01f334938e 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -21,7 +21,7 @@ DECLARE_GLOBAL_DATA_PTR; #define UART_MCRVAL (UART_MCR_DTR | \ UART_MCR_RTS) /* RTS/DTR */
-#ifndef CONFIG_DM_SERIAL +#if !CONFIG_IS_ENABLED(DM_SERIAL) #ifdef CONFIG_SYS_NS16550_PORT_MAPPED #define serial_out(x, y) outb(x, (ulong)y) #define serial_in(y) inb((ulong)y) @@ -86,7 +86,7 @@ static inline int serial_in_shift(void *addr, int shift) #endif }
-#ifdef CONFIG_DM_SERIAL +#if CONFIG_IS_ENABLED(DM_SERIAL)
#ifndef CONFIG_SYS_NS16550_CLK #define CONFIG_SYS_NS16550_CLK 0 @@ -301,7 +301,7 @@ DEBUG_UART_FUNCS
#endif
-#ifdef CONFIG_DM_SERIAL +#if CONFIG_IS_ENABLED(DM_SERIAL) static int ns16550_serial_putc(struct udevice *dev, const char ch) { struct NS16550 *const com_port = dev_get_priv(dev);

At present the name of the image comes first in the linker-list symbol used. This means that the name of the function sets the sort order, which is not the intention.
Update it to put the board device type first, then the priority. This produces the expected behaviour.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/spl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/spl.h b/include/spl.h index a90f971a23..d446198e07 100644 --- a/include/spl.h +++ b/include/spl.h @@ -254,14 +254,14 @@ struct spl_image_loader { */ #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT #define SPL_LOAD_IMAGE_METHOD(_name, _priority, _boot_device, _method) \ - SPL_LOAD_IMAGE(_method ## _priority ## _boot_device) = { \ + SPL_LOAD_IMAGE(_boot_device ## _priority ## _method) = { \ .name = _name, \ .boot_device = _boot_device, \ .load_image = _method, \ } #else #define SPL_LOAD_IMAGE_METHOD(_name, _priority, _boot_device, _method) \ - SPL_LOAD_IMAGE(_method ## _priority ## _boot_device) = { \ + SPL_LOAD_IMAGE(_boot_device ## _priority ## _method) = { \ .boot_device = _boot_device, \ .load_image = _method, \ }

We don't have a console in SPL so it doesn't make sense to check for Ctrl-C when printing a memory dump. Skip this so that print_buffer() can be used in SPL.
Signed-off-by: Simon Glass sjg@chromium.org ---
lib/display_options.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/lib/display_options.c b/lib/display_options.c index cff20f3755..ec16d75e0e 100644 --- a/lib/display_options.c +++ b/lib/display_options.c @@ -205,8 +205,10 @@ int print_buffer(ulong addr, const void *data, uint width, uint count, addr += thislinelen * width; count -= thislinelen;
+#ifndef CONFIG_SPL_BUILD if (ctrlc()) return -1; +#endif }
return 0;

At present these options can be enabled when bloblist is not enabled for SPL or TPL. This is incorrect as SPL handoff requires bloblist. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/spl/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/common/spl/Kconfig b/common/spl/Kconfig index 630491699c..acb8492559 100644 --- a/common/spl/Kconfig +++ b/common/spl/Kconfig @@ -115,7 +115,7 @@ if SPL
config SPL_HANDOFF bool "Pass hand-off information from SPL to U-Boot proper" - depends on HANDOFF + depends on HANDOFF && SPL_BLOBLIST default y help This option enables SPL to write handoff information. This can be @@ -1157,7 +1157,7 @@ if TPL
config TPL_HANDOFF bool "Pass hand-off information from TPL to SPL and U-Boot proper" - depends on HANDOFF + depends on HANDOFF && TPL_BLOBLIST default y help This option enables TPL to write handoff information. This can be

At present there is an arch-specific area in the SPL handoff area intended for use by arch-specific code, but there is no explicit call to fill in this data. Add a hook for this.
Also use the hook to remove the sandbox-specific test code from write_spl_handoff().
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/cpu/spl.c | 7 +++++++ common/spl/spl.c | 12 +++++++++--- include/handoff.h | 13 +++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/arch/sandbox/cpu/spl.c b/arch/sandbox/cpu/spl.c index 4f415c71d6..44c68a39bc 100644 --- a/arch/sandbox/cpu/spl.c +++ b/arch/sandbox/cpu/spl.c @@ -78,3 +78,10 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) } hang(); } + +int handoff_arch_save(struct spl_handoff *ho) +{ + ho->arch.magic = TEST_HANDOFF_MAGIC; + + return 0; +} diff --git a/common/spl/spl.c b/common/spl/spl.c index 2c696f2a79..21540ac37d 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -356,17 +356,23 @@ static int setup_spl_handoff(void) return 0; }
+__weak int handoff_arch_save(struct spl_handoff *ho) +{ + return 0; +} + static int write_spl_handoff(void) { struct spl_handoff *ho; + int ret;
ho = bloblist_find(BLOBLISTT_SPL_HANDOFF, sizeof(struct spl_handoff)); if (!ho) return -ENOENT; handoff_save_dram(ho); -#ifdef CONFIG_SANDBOX - ho->arch.magic = TEST_HANDOFF_MAGIC; -#endif + ret = handoff_arch_save(ho); + if (ret) + return ret; debug(SPL_TPL_PROMPT "Wrote SPL handoff\n");
return 0; diff --git a/include/handoff.h b/include/handoff.h index aacb0f5ebf..75d19b1f6e 100644 --- a/include/handoff.h +++ b/include/handoff.h @@ -31,6 +31,19 @@ struct spl_handoff { void handoff_save_dram(struct spl_handoff *ho); void handoff_load_dram_size(struct spl_handoff *ho); void handoff_load_dram_banks(struct spl_handoff *ho); + +/** + * handoff_arch_save() - Save arch-specific info into the handoff area + * + * This is defined to an empty function by default, but arch-specific code can + * define it to write to spi_handoff->arch. It is called from + * write_spl_handoff(). + * + * @ho: Handoff area to fill in + * @return 0 if OK, -ve on error + */ +int handoff_arch_save(struct spl_handoff *ho); + #endif
#endif

At present the bloblist is set up in spl_common_init() which can be called from spl_early_init(), i.e. before SDRAM is ready. This prevents the bloblist from being located in SDRAM, which is useful on some platforms where SRAM is inaccessible after U-Boot relocates (e.g. x86 CAR region).
It doesn't serve much purpose to have the bloblist available early, since very little is known about the platform then, and the handoff info is written when SPL is about to jump to U-Boot.
Move the code to board_init_r() to avoid any restrictions.
Signed-off-by: Simon Glass sjg@chromium.org ---
common/spl/spl.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-)
diff --git a/common/spl/spl.c b/common/spl/spl.c index 21540ac37d..bd49e299d1 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -410,23 +410,6 @@ static int spl_common_init(bool setup_malloc) return ret; } #endif - if (CONFIG_IS_ENABLED(BLOBLIST)) { - ret = bloblist_init(); - if (ret) { - debug("%s: Failed to set up bloblist: ret=%d\n", - __func__, ret); - return ret; - } - } - if (CONFIG_IS_ENABLED(HANDOFF)) { - int ret; - - ret = setup_spl_handoff(); - if (ret) { - puts(SPL_TPL_PROMPT "Cannot set up SPL handoff\n"); - hang(); - } - } if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) { ret = fdtdec_setup(); if (ret) { @@ -604,6 +587,24 @@ void board_init_r(gd_t *dummy1, ulong dummy2) */ timer_init(); #endif + if (CONFIG_IS_ENABLED(BLOBLIST)) { + ret = bloblist_init(); + if (ret) { + debug("%s: Failed to set up bloblist: ret=%d\n", + __func__, ret); + puts(SPL_TPL_PROMPT "Cannot set up bloblist\n"); + hang(); + } + } + if (CONFIG_IS_ENABLED(HANDOFF)) { + int ret; + + ret = setup_spl_handoff(); + if (ret) { + puts(SPL_TPL_PROMPT "Cannot set up SPL handoff\n"); + hang(); + } + }
#if CONFIG_IS_ENABLED(BOARD_INIT) spl_board_init();

U-Boot is built in three phases: TPL, SPL and U-Boot proper. Sometimes it is necessary to use different init code depending on the phase. For example, TPL might do very basic CPU init, SPL might do a little more and U-Boot proper might bring the CPU up to full speed and enable all cores.
Add a function which allows easy determination of the current phase being built.
Signed-off-by: Simon Glass sjg@chromium.org ---
include/spl.h | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+)
diff --git a/include/spl.h b/include/spl.h index d446198e07..a52d595578 100644 --- a/include/spl.h +++ b/include/spl.h @@ -49,6 +49,66 @@ static inline bool u_boot_first_phase(void) return false; }
+enum u_boot_phase { + PHASE_TPL, + PHASE_SPL, + PHASE_U_BOOT, +}; + +/** + * spl_phase() - Find out the phase of U-Boot + * + * This can be used to avoid #ifdef logic and use if() instead. + * + * For example, to include code only in TPL, you might do: + * + * #ifdef CONFIG_TPL_BUILD + * ... + * #endif + * + * but with this you can use: + * + * if (spl_phase() == PHASE_TPL) { + * ... + * } + * + * To include code only in SPL, you might do: + * + * #if defined(CONFIG_SPL_BUILD) && !defined(CONFIG_TPL_BUILD) + * ... + * #endif + * + * but with this you can use: + * + * if (spl_phase() == PHASE_SPL) { + * ... + * } + * + * To include code only in U-Boot proper, you might do: + * + * #ifndef CONFIG_SPL_BUILD + * ... + * #endif + * + * but with this you can use: + * + * if (spl_phase() == PHASE_U_BOOT) { + * ... + * } + * + * @return U-Boot phase + */ +static inline enum u_boot_phase spl_phase(void) +{ +#ifdef CONFIG_TPL_BUILD + return PHASE_TPL; +#elif CONFIG_SPL_BUILD + return PHASE_SPL; +#else + return PHASE_U_BOOT; +#endif +} + /* A string name for SPL or TPL */ #ifdef CONFIG_SPL_BUILD # ifdef CONFIG_TPL_BUILD

This provides access to SPI flash both through a read-only memory map and with operations to erase and write flash. It supports 4KB or 64KB erase sizes.
This driver is used by Apollolake.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mtd/spi/Kconfig | 9 + drivers/mtd/spi/Makefile | 1 + drivers/mtd/spi/intel_fast_spi.c | 294 +++++++++++++++++++++++++++++++ 3 files changed, 304 insertions(+) create mode 100644 drivers/mtd/spi/intel_fast_spi.c
diff --git a/drivers/mtd/spi/Kconfig b/drivers/mtd/spi/Kconfig index d3b007a731..4a184bbc82 100644 --- a/drivers/mtd/spi/Kconfig +++ b/drivers/mtd/spi/Kconfig @@ -78,6 +78,15 @@ config SF_DEFAULT_SPEED speed and mode from platdata values computed from available node.
+config SPI_FLASH_INTEL_FAST + bool "Intel Fast SPI interface" + depends on DM_SPI_FLASH + help + Add support for Intel Fast SPI interface, as used on Apollolake. + This current only supports reading from SPI, enough to load SPL or + U-Boot proper from SPI flash. Future work may enable write and erase + operations. + if SPI_FLASH
config SPI_FLASH_SFDP_SUPPORT diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index f99f6cb16e..5bf5ac828f 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -19,5 +19,6 @@ endif
obj-$(CONFIG_SPI_FLASH) += spi-nor.o obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o sf.o +obj-$(CONFIG_SPI_FLASH_INTEL_FAST) += intel_fast_spi.o obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o diff --git a/drivers/mtd/spi/intel_fast_spi.c b/drivers/mtd/spi/intel_fast_spi.c new file mode 100644 index 0000000000..73a1467d47 --- /dev/null +++ b/drivers/mtd/spi/intel_fast_spi.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Intel 'Fast SPI' support + * + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <dm.h> +#include <pci.h> +#include <spi_flash.h> +#include <spl.h> +#include <asm/io.h> +#include <asm/pci.h> +#include <asm/arch/fast_spi_def.h> +#include <asm/arch/pch.h> + +struct fast_spi_priv { + struct fast_spi_regs *regs; + uint page_size; + ulong mmio_base; + uint flash_size; + uint map_offset; + ulong map_base; + size_t map_size; +}; + +enum { + /* Erase size options */ + ERASE_SIZE_SM = 4 << 10, + ERASE_SIZE_LG = 64 << 10, +}; + +/* + * The hardware datasheet is not clear on what HORD values actually do. It + * seems that HORD_SFDP provides access to the first 8 bytes of the SFDP, which + * is the signature and revision fields. HORD_JEDEC provides access to the + * actual flash parameters, and is most likely what you want to use when + * probing the flash from software. + * It's okay to rely on SFDP, since the SPI flash controller requires an SFDP + * 1.5 or newer compliant FAST_SPI flash chip. + * NOTE: Due to the register layout of the hardware, all accesses will be + * aligned to a 4 byte boundary. + */ +static u32 read_sfdp_param(struct fast_spi_priv *priv, uint sfdp_reg) +{ + u32 ptinx_index = sfdp_reg & SPIBAR_PTINX_IDX_MASK; + + writel(ptinx_index | SPIBAR_PTINX_HORD_JEDEC, &priv->regs->ptinx); + + return readl(&priv->regs->ptdata); +} + +/* Fill FDATAn FIFO in preparation for a write transaction */ +static void fill_xfer_fifo(struct fast_spi_priv *priv, const void *data, + size_t len) +{ + memcpy(priv->regs->fdata, data, len); +} + +/* Drain FDATAn FIFO after a read transaction populates data */ +static void drain_xfer_fifo(struct fast_spi_priv *priv, void *dest, size_t len) +{ + memcpy(dest, priv->regs->fdata, len); +} + +/* Fire up a transfer using the hardware sequencer */ +static void start_hwseq_xfer(struct fast_spi_priv *priv, u32 hsfsts_cycle, + u32 offset, size_t len) +{ + /* Make sure all W1C status bits get cleared */ + u32 hsfsts = SPIBAR_HSFSTS_W1C_BITS; + + /* Set up transaction parameters */ + hsfsts |= hsfsts_cycle & SPIBAR_HSFSTS_FCYCLE_MASK; + hsfsts |= SPIBAR_HSFSTS_FDBC(len - 1); + + writel(offset, &priv->regs->faddr); + writel(hsfsts | SPIBAR_HSFSTS_FGO, &priv->regs->hsfsts_ctl); +} + +static int wait_for_hwseq_xfer(struct fast_spi_priv *priv, u32 offset) +{ + ulong start; + u32 hsfsts; + + start = get_timer(0); + do { + hsfsts = readl(&priv->regs->hsfsts_ctl); + + if (hsfsts & SPIBAR_HSFSTS_FCERR) { + debug("SPI transaction error at offset %x HSFSTS = %08x\n", + offset, hsfsts); + return -EIO; + } + + if (hsfsts & SPIBAR_HSFSTS_FDONE) + return 0; + } while ((int)get_timer(start) < SPIBAR_HWSEQ_XFER_TIMEOUT_MS); + + debug("SPI transaction timeout at offset %x HSFSTS = %08x, timer %d\n", + offset, hsfsts, (uint)get_timer(start)); + return -ETIMEDOUT; +} + +/* Execute FAST_SPI flash transfer. This is a blocking call */ +static int exec_sync_hwseq_xfer(struct fast_spi_priv *priv, + u32 hsfsts_cycle, u32 offset, + size_t len) +{ + start_hwseq_xfer(priv, hsfsts_cycle, offset, len); + + return wait_for_hwseq_xfer(priv, offset); +} + +/* + * Ensure read/write xfer len is not greater than SPIBAR_FDATA_FIFO_SIZE and + * that the operation does not cross page boundary. + */ +static size_t get_xfer_len(const struct fast_spi_priv *priv, u32 offset, + size_t len) +{ + size_t xfer_len = min(len, (size_t)SPIBAR_FDATA_FIFO_SIZE); + size_t bytes_left = ALIGN(offset, priv->page_size) - offset; + + if (bytes_left) + xfer_len = min(xfer_len, bytes_left); + + return xfer_len; +} + +static int fast_spi_flash_erase(struct udevice *dev, u32 offset, size_t len) +{ + struct fast_spi_priv *priv = dev_get_priv(dev); + int ret; + size_t erase_size; + u32 erase_cycle; + + if (!IS_ALIGNED(offset, ERASE_SIZE_SM) || + !IS_ALIGNED(len, ERASE_SIZE_SM)) { + debug("SPI erase region not sector-aligned\n"); + return -EINVAL; + } + + while (len) { + if (IS_ALIGNED(offset, ERASE_SIZE_LG) && len >= ERASE_SIZE_LG) { + erase_size = ERASE_SIZE_LG; + erase_cycle = SPIBAR_HSFSTS_CYCLE_64K_ERASE; + } else { + erase_size = ERASE_SIZE_SM; + erase_cycle = SPIBAR_HSFSTS_CYCLE_4K_ERASE; + } + debug("Erasing flash addr %x + %x\n", offset, (uint)erase_size); + + ret = exec_sync_hwseq_xfer(priv, erase_cycle, offset, 0); + if (ret) + return ret; + + offset += erase_size; + len -= erase_size; + } + + return 0; +} + +static int fast_spi_read(struct udevice *dev, u32 offset, size_t len, void *buf) +{ + struct fast_spi_priv *priv = dev_get_priv(dev); + + debug("%s: read at offset %x\n", __func__, offset); + while (len) { + size_t xfer_len = get_xfer_len(priv, offset, len); + int ret; + + ret = exec_sync_hwseq_xfer(priv, SPIBAR_HSFSTS_CYCLE_READ, + offset, xfer_len); + if (ret) + return ret; + + drain_xfer_fifo(priv, buf, xfer_len); + + offset += xfer_len; + buf += xfer_len; + len -= xfer_len; + } + + return 0; +} + +static int fast_spi_flash_write(struct udevice *dev, u32 addr, size_t len, + const void *buf) +{ + struct fast_spi_priv *priv = dev_get_priv(dev); + const u8 *data = buf; + size_t xfer_len; + int ret; + + while (len) { + xfer_len = get_xfer_len(priv, addr, len); + fill_xfer_fifo(priv, data, xfer_len); + + ret = exec_sync_hwseq_xfer(priv, SPIBAR_HSFSTS_CYCLE_WRITE, + addr, xfer_len); + if (ret) + return ret; + + addr += xfer_len; + data += xfer_len; + len -= xfer_len; + } + + return 0; +} + +static int fast_spi_get_mmap(struct udevice *dev, ulong *map_basep, + size_t *map_sizep, u32 *offsetp) +{ + struct fast_spi_priv *priv = dev_get_priv(dev); + + if (priv) { + *map_basep = priv->map_base; + *map_sizep = priv->map_size; + *offsetp = priv->map_offset; + } else { + return fast_spi_get_bios_mmap(map_basep, map_sizep, offsetp); + } + + return 0; +} + +static int fast_spi_probe(struct udevice *dev) +{ + struct spi_flash *flash = dev_get_uclass_priv(dev); + struct fast_spi_priv *priv = dev_get_priv(dev); + u32 flash_bits; + ulong bar, base; + int bdf; + + /* TODO(sjg@chromium.org): Tidy this up when the device tree is ready */ +#if 0 && CONFIG_IS_ENABLED(PCI) + bdf = pci_get_devfn(dev); + if (bdf < 0) + return bdf; +#else + bdf = PCH_DEV_SPI; +#endif + pci_x86_read_config(NULL, bdf, PCI_BASE_ADDRESS_0, &bar, PCI_SIZE_32); + + priv->mmio_base = bar & PCI_BASE_ADDRESS_MEM_MASK; + priv->regs = (struct fast_spi_regs *)priv->mmio_base; + + /* + * bytes = (bits + 1) / 8; + * But we need to do the addition in a way which doesn't overflow for + * 4 Gb devices (flash_bits == 0xffffffff). + */ + flash_bits = read_sfdp_param(priv, 0x04); + flash->size = (flash_bits >> 3) + 1; + + /* Can erase both 4 KiB and 64 KiB chunks. Declare the smaller size */ + flash->sector_size = 4 << 10; + flash->page_size = 256; + + base = fast_spi_get_bios_region(priv->regs, &priv->map_size); + priv->map_base = (u32)-priv->map_size - base; + priv->map_offset = base; + + debug("FAST SPI at %lx, size %x with mapping %x, size %x\n", + priv->mmio_base, flash->size, (uint)priv->map_base, + priv->map_size); + + return 0; +} + +static const struct dm_spi_flash_ops fast_spi_ops = { + .read = fast_spi_read, + .write = fast_spi_flash_write, + .erase = fast_spi_flash_erase, + .get_mmap = fast_spi_get_mmap, +}; + +static const struct udevice_id fast_spi_ids[] = { + { .compatible = "intel,fast-spi" }, + { } +}; + +U_BOOT_DRIVER(intel_fast_spi) = { + .name = "intel_fast_spi", + .id = UCLASS_SPI_FLASH, + .of_match = fast_spi_ids, + .probe = fast_spi_probe, + .priv_auto_alloc_size = sizeof(struct fast_spi_priv), + .ops = &fast_spi_ops, +};

At present SPI-flash testing relies on a sandbox driver which emulates the SPI bus and implements a flash chip behind that emulated bus.
This provides good coverage but can only implement features supported by the SPI bus.
Add a new 'direct' SPI flash which is implemented directly by sandbox. This allows us to write a very simple test of the uclass interface.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/sandbox/dts/test.dts | 4 ++ drivers/mtd/spi/Makefile | 2 +- drivers/mtd/spi/sandbox_direct.c | 99 ++++++++++++++++++++++++++++++++ test/dm/sf.c | 42 ++++++++++++++ 4 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/spi/sandbox_direct.c
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 27b0baab27..208551d7c1 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -619,6 +619,10 @@ }; };
+ spi-flash@0 { + compatible = "sandbox,spi-flash-direct"; + }; + syscon0: syscon@0 { compatible = "sandbox,syscon0"; reg = <0x10 16>; diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile index 5bf5ac828f..7fa03ea614 100644 --- a/drivers/mtd/spi/Makefile +++ b/drivers/mtd/spi/Makefile @@ -21,4 +21,4 @@ obj-$(CONFIG_SPI_FLASH) += spi-nor.o obj-$(CONFIG_SPI_FLASH_DATAFLASH) += sf_dataflash.o sf.o obj-$(CONFIG_SPI_FLASH_INTEL_FAST) += intel_fast_spi.o obj-$(CONFIG_SPI_FLASH_MTD) += sf_mtd.o -obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o +obj-$(CONFIG_SPI_FLASH_SANDBOX) += sandbox.o sandbox_direct.o diff --git a/drivers/mtd/spi/sandbox_direct.c b/drivers/mtd/spi/sandbox_direct.c new file mode 100644 index 0000000000..43d8907710 --- /dev/null +++ b/drivers/mtd/spi/sandbox_direct.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Simulate a flash chip without an underlying SPI layer. Behaviour is only + * useful for testing. + * + * Copyright 2019 Google LLC + * + * Licensed under the GPL-2 or later. + */ + +#define LOG_CATEGORY UCLASS_SPI_FLASH + +#include <common.h> +#include <dm.h> +#include <spi_flash.h> + +/** + * struct sandbox_direct_priv - private data for this driver + * + * @read_byte: Byte to return when reading from the driver + */ +struct sandbox_direct_priv { + char read_byte; + int write_prot; +}; + +static int sandbox_direct_read(struct udevice *dev, u32 offset, size_t len, + void *buf) +{ + struct sandbox_direct_priv *priv = dev_get_priv(dev); + + if (offset == 1) + return -EIO; + memset(buf, priv->read_byte, len); + + return 0; +} + +static int sandbox_direct_write(struct udevice *dev, u32 offset, size_t len, + const void *buf) +{ + struct sandbox_direct_priv *priv = dev_get_priv(dev); + + if (offset == 1) + return -EIO; + if (len > 0) + priv->read_byte = *(u8 *)buf; + + return 0; +} + +static int sandbox_direct_erase(struct udevice *dev, u32 offset, size_t len) +{ + struct sandbox_direct_priv *priv = dev_get_priv(dev); + + if (offset == 1) + return -EIO; + if (len > 0) + priv->read_byte = 'c'; + + return 0; +} + +static int sandbox_direct_get_sw_write_prot(struct udevice *dev) +{ + struct sandbox_direct_priv *priv = dev_get_priv(dev); + + return priv->write_prot++ ? 1 : 0; +} + +static int sandbox_direct_probe(struct udevice *dev) +{ + struct sandbox_direct_priv *priv = dev_get_priv(dev); + + priv->read_byte = 'a'; + + return 0; +} + +static struct dm_spi_flash_ops sandbox_direct_ops = { + .read = sandbox_direct_read, + .write = sandbox_direct_write, + .erase = sandbox_direct_erase, + .get_sw_write_prot = sandbox_direct_get_sw_write_prot, +}; + +static const struct udevice_id sandbox_direct_ids[] = { + { .compatible = "sandbox,spi-flash-direct" }, + { } +}; + +U_BOOT_DRIVER(sandbox_sf_direct) = { + .name = "sandbox_sf_direct", + .id = UCLASS_SPI_FLASH, + .of_match = sandbox_direct_ids, + .probe = sandbox_direct_probe, + .ops = &sandbox_direct_ops, + .priv_auto_alloc_size = sizeof(struct sandbox_direct_priv), +}; diff --git a/test/dm/sf.c b/test/dm/sf.c index 3788d59052..56277954c2 100644 --- a/test/dm/sf.c +++ b/test/dm/sf.c @@ -14,8 +14,13 @@ #include <asm/test.h> #include <dm/test.h> #include <dm/util.h> +#include <dm/uclass.h> #include <test/ut.h>
+enum { + BUF_SIZE = 4, +}; + /* Simple test of sandbox SPI flash */ static int dm_test_spi_flash(struct unit_test_state *uts) { @@ -91,3 +96,40 @@ static int dm_test_spi_flash_func(struct unit_test_state *uts) return 0; } DM_TEST(dm_test_spi_flash_func, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT); + +/* Test of the direct SPI flash interface (no SPI layer) */ +static int dm_test_spi_flash_direct(struct unit_test_state *uts) +{ + struct udevice *dev; + char buf[BUF_SIZE]; + int i; + + ut_assertok(uclass_get_device(UCLASS_SPI_FLASH, 1, &dev)); + + /* Check the read call */ + ut_asserteq(-EIO, spi_flash_read_dm(dev, 1, BUF_SIZE, buf)); + ut_assertok(spi_flash_read_dm(dev, 0, BUF_SIZE, buf)); + for (i = 0; i < BUF_SIZE; i++) + ut_asserteq('a', buf[i]); + + /* Check the write call */ + ut_asserteq(-EIO, spi_flash_write_dm(dev, 1, BUF_SIZE, buf)); + ut_assertok(spi_flash_write_dm(dev, 0, 1, "b")); + ut_assertok(spi_flash_read_dm(dev, 0, BUF_SIZE, buf)); + for (i = 0; i < BUF_SIZE; i++) + ut_asserteq('b', buf[i]); + + /* Check erase */ + ut_asserteq(-EIO, spi_flash_erase_dm(dev, 1, BUF_SIZE)); + ut_assertok(spi_flash_erase_dm(dev, 0, 1)); + ut_assertok(spi_flash_read_dm(dev, 0, BUF_SIZE, buf)); + for (i = 0; i < BUF_SIZE; i++) + ut_asserteq('c', buf[i]); + + /* Check write protection */ + ut_asserteq(0, spl_flash_get_sw_write_prot(dev)); + ut_asserteq(1, spl_flash_get_sw_write_prot(dev)); + + return 0; +} +DM_TEST(dm_test_spi_flash_direct, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

On x86 platforms the SPI flash can be mapped into memory so that the contents can be read with normal memory accesses.
Add a new SPI flash method to find the location of the SPI flash in memory. This differs from the existing device-tree "memory-map" mechanism in that the location can be discovered at run-time.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/mtd/spi/sandbox_direct.c | 11 +++++++++++ drivers/mtd/spi/sf-uclass.c | 11 +++++++++++ include/spi_flash.h | 27 +++++++++++++++++++++++++++ test/dm/sf.c | 9 +++++++++ 4 files changed, 58 insertions(+)
diff --git a/drivers/mtd/spi/sandbox_direct.c b/drivers/mtd/spi/sandbox_direct.c index 43d8907710..fb515edcb7 100644 --- a/drivers/mtd/spi/sandbox_direct.c +++ b/drivers/mtd/spi/sandbox_direct.c @@ -68,6 +68,16 @@ static int sandbox_direct_get_sw_write_prot(struct udevice *dev) return priv->write_prot++ ? 1 : 0; }
+static int sandbox_direct_get_mmap(struct udevice *dev, ulong *map_basep, + size_t *map_sizep, u32 *offsetp) +{ + *map_basep = 0x1000; + *map_sizep = 0x2000; + *offsetp = 0x100; + + return 0; +} + static int sandbox_direct_probe(struct udevice *dev) { struct sandbox_direct_priv *priv = dev_get_priv(dev); @@ -82,6 +92,7 @@ static struct dm_spi_flash_ops sandbox_direct_ops = { .write = sandbox_direct_write, .erase = sandbox_direct_erase, .get_sw_write_prot = sandbox_direct_get_sw_write_prot, + .get_mmap = sandbox_direct_get_mmap, };
static const struct udevice_id sandbox_direct_ids[] = { diff --git a/drivers/mtd/spi/sf-uclass.c b/drivers/mtd/spi/sf-uclass.c index 719a2fd23a..127ec7e7aa 100644 --- a/drivers/mtd/spi/sf-uclass.c +++ b/drivers/mtd/spi/sf-uclass.c @@ -28,6 +28,17 @@ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len) return log_ret(sf_get_ops(dev)->erase(dev, offset, len)); }
+int spi_flash_get_mmap(struct udevice *dev, ulong *map_basep, size_t *map_sizep, + u32 *offsetp) +{ + struct dm_spi_flash_ops *ops = sf_get_ops(dev); + + if (!ops->get_mmap) + return -ENOSYS; + + return ops->get_mmap(dev, map_basep, map_sizep, offsetp); +} + int spl_flash_get_sw_write_prot(struct udevice *dev) { struct dm_spi_flash_ops *ops = sf_get_ops(dev); diff --git a/include/spi_flash.h b/include/spi_flash.h index 55b4721813..840189e22c 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -47,6 +47,19 @@ struct dm_spi_flash_ops { * other -ve value on error */ int (*get_sw_write_prot)(struct udevice *dev); + + /** + * get_mmap() - Get memory-mapped SPI + * + * @dev: SPI flash device + * @map_basep: Returns base memory address for mapped SPI + * @map_sizep: Returns size of mapped SPI + * @offsetp: Returns start offset of SPI flash where the map works + * correctly (offsets before this are not visible) + * @return 0 if OK, -EFAULT if memory mapping is not available + */ + int (*get_mmap)(struct udevice *dev, ulong *map_basep, + size_t *map_sizep, u32 *offsetp); };
/* Access the serial operations for a device */ @@ -88,6 +101,20 @@ int spi_flash_write_dm(struct udevice *dev, u32 offset, size_t len, */ int spi_flash_erase_dm(struct udevice *dev, u32 offset, size_t len);
+/** + * spi_flash_get_mmap() - Get memory-mapped SPI + * + * @dev: SPI flash device + * @map_basep: Returns base memory address for mapped SPI + * @map_sizep: Returns size of mapped SPI + * @offsetp: Returns start offset of SPI flash where the map works + * correctly (offsets before this are not visible) + * @return 0 if OK, -ENOSYS if no operation, -EFAULT if memory mapping is not + * available + */ +int spi_flash_get_mmap(struct udevice *dev, ulong *map_basep, size_t *map_sizep, + u32 *offsetp); + /** * spl_flash_get_sw_write_prot() - Check state of software write-protect feature * diff --git a/test/dm/sf.c b/test/dm/sf.c index 56277954c2..f8f9e71772 100644 --- a/test/dm/sf.c +++ b/test/dm/sf.c @@ -102,6 +102,9 @@ static int dm_test_spi_flash_direct(struct unit_test_state *uts) { struct udevice *dev; char buf[BUF_SIZE]; + size_t map_size; + ulong map_base; + u32 offset; int i;
ut_assertok(uclass_get_device(UCLASS_SPI_FLASH, 1, &dev)); @@ -130,6 +133,12 @@ static int dm_test_spi_flash_direct(struct unit_test_state *uts) ut_asserteq(0, spl_flash_get_sw_write_prot(dev)); ut_asserteq(1, spl_flash_get_sw_write_prot(dev));
+ /* Check mapping */ + ut_assertok(spi_flash_get_mmap(dev, &map_base, &map_size, &offset)); + ut_asserteq(0x1000, map_base); + ut_asserteq(0x2000, map_size); + ut_asserteq(0x100, offset); + return 0; } DM_TEST(dm_test_spi_flash_direct, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);

At present this driver is always included in SPL and TPL, if U-Boot proper enables it. Update the Makefile to provide full control using the existing Kconfig options.
Signed-off-by: Simon Glass sjg@chromium.org ---
drivers/sysreset/Kconfig | 12 ++++++++++++ drivers/sysreset/Makefile | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig index f565ae0310..dcce2be641 100644 --- a/drivers/sysreset/Kconfig +++ b/drivers/sysreset/Kconfig @@ -107,6 +107,18 @@ config SYSRESET_X86 help Reboot support for generic x86 processor reset.
+config SYSRESET_SPL_X86 + bool "Enable support for x86 processor reboot driver in SPL" + depends on X86 + help + Reboot support for generic x86 processor reset. + +config SYSRESET_TPL_X86 + bool "Enable support for x86 processor reboot driver in TPL" + depends on X86 + help + Reboot support for generic x86 processor reset. + config SYSRESET_MCP83XX bool "Enable support MPC83xx SoC family reboot driver" help diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile index cf01492295..fff4a184a0 100644 --- a/drivers/sysreset/Makefile +++ b/drivers/sysreset/Makefile @@ -16,5 +16,5 @@ obj-$(CONFIG_SYSRESET_SOCFPGA_S10) += sysreset_socfpga_s10.o obj-$(CONFIG_SYSRESET_TI_SCI) += sysreset-ti-sci.o obj-$(CONFIG_SYSRESET_SYSCON) += sysreset_syscon.o obj-$(CONFIG_SYSRESET_WATCHDOG) += sysreset_watchdog.o -obj-$(CONFIG_SYSRESET_X86) += sysreset_x86.o +obj-$(CONFIG_$(SPL_TPL_)SYSRESET_X86) += sysreset_x86.o obj-$(CONFIG_TARGET_XTFPGA) += sysreset_xtfpga.o

Given these exported function an fsp_ prefix since they are declared in an fsp.h header.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/baytrail/fsp_configs.c | 2 +- arch/x86/cpu/braswell/fsp_configs.c | 2 +- arch/x86/cpu/ivybridge/fsp_configs.c | 2 +- arch/x86/cpu/queensbay/fsp_configs.c | 2 +- arch/x86/include/asm/fsp1/fsp_support.h | 6 +++--- arch/x86/lib/fsp1/fsp_car.S | 10 +++++----- arch/x86/lib/fsp1/fsp_support.c | 14 +++++++------- cmd/x86/fsp.c | 2 +- 8 files changed, 20 insertions(+), 20 deletions(-)
diff --git a/arch/x86/cpu/baytrail/fsp_configs.c b/arch/x86/cpu/baytrail/fsp_configs.c index 5b5d66aa5e..1d1948c91a 100644 --- a/arch/x86/cpu/baytrail/fsp_configs.c +++ b/arch/x86/cpu/baytrail/fsp_configs.c @@ -27,7 +27,7 @@ __weak void update_fsp_azalia_configs(struct azalia_config **azalia) * If the device tree does not specify an integer setting, use the default * provided in Intel's Baytrail_FSP_Gold4.tgz release FSP/BayleyBayFsp.bsf file. */ -void update_fsp_configs(struct fsp_config_data *config, +void fsp_update_configs(struct fsp_config_data *config, struct fspinit_rtbuf *rt_buf) { struct upd_region *fsp_upd = &config->fsp_upd; diff --git a/arch/x86/cpu/braswell/fsp_configs.c b/arch/x86/cpu/braswell/fsp_configs.c index 607e333f21..60101d742d 100644 --- a/arch/x86/cpu/braswell/fsp_configs.c +++ b/arch/x86/cpu/braswell/fsp_configs.c @@ -40,7 +40,7 @@ __weak void update_fsp_gpio_configs(struct gpio_family **family, * If the device tree does not specify an integer setting, use the default * provided in Intel's Braswell release FSP/BraswellFsp.bsf file. */ -void update_fsp_configs(struct fsp_config_data *config, +void fsp_update_configs(struct fsp_config_data *config, struct fspinit_rtbuf *rt_buf) { struct upd_region *fsp_upd = &config->fsp_upd; diff --git a/arch/x86/cpu/ivybridge/fsp_configs.c b/arch/x86/cpu/ivybridge/fsp_configs.c index 773c2b2a0a..0e6453c847 100644 --- a/arch/x86/cpu/ivybridge/fsp_configs.c +++ b/arch/x86/cpu/ivybridge/fsp_configs.c @@ -9,7 +9,7 @@
DECLARE_GLOBAL_DATA_PTR;
-void update_fsp_configs(struct fsp_config_data *config, +void fsp_update_configs(struct fsp_config_data *config, struct fspinit_rtbuf *rt_buf) { struct platform_config *plat_config = &config->plat_config; diff --git a/arch/x86/cpu/queensbay/fsp_configs.c b/arch/x86/cpu/queensbay/fsp_configs.c index 0dd1901e07..381edd0761 100644 --- a/arch/x86/cpu/queensbay/fsp_configs.c +++ b/arch/x86/cpu/queensbay/fsp_configs.c @@ -7,7 +7,7 @@ #include <common.h> #include <asm/fsp1/fsp_support.h>
-void update_fsp_configs(struct fsp_config_data *config, +void fsp_update_configs(struct fsp_config_data *config, struct fspinit_rtbuf *rt_buf) { /* Initialize runtime buffer for fsp_init() */ diff --git a/arch/x86/include/asm/fsp1/fsp_support.h b/arch/x86/include/asm/fsp1/fsp_support.h index d0f053fea4..945a45c0fe 100644 --- a/arch/x86/include/asm/fsp1/fsp_support.h +++ b/arch/x86/include/asm/fsp1/fsp_support.h @@ -29,7 +29,7 @@ struct fsp_config_data; * * This routine jumps to the C version of FSP continuation function */ -void asm_continuation(void); +void fsp_asm_continuation(void);
/** * FSP initialization complete @@ -56,7 +56,7 @@ void fsp_continue(u32 status, void *hob_list); * * @retval: the offset of FSP header. If signature is invalid, returns 0. */ -struct fsp_header *find_fsp_header(void); +struct fsp_header *fsp_find_header(void);
/** * FSP initialization wrapper function. @@ -176,7 +176,7 @@ void *fsp_get_graphics_info(const void *hob_list, u32 *len); * * @return: None */ -void update_fsp_configs(struct fsp_config_data *config, +void fsp_update_configs(struct fsp_config_data *config, struct fspinit_rtbuf *rt_buf);
/** diff --git a/arch/x86/lib/fsp1/fsp_car.S b/arch/x86/lib/fsp1/fsp_car.S index 8c54cea3db..a64a653435 100644 --- a/arch/x86/lib/fsp1/fsp_car.S +++ b/arch/x86/lib/fsp1/fsp_car.S @@ -20,10 +20,10 @@ car_init:
car_init_start: post_code(POST_CAR_START) - lea find_fsp_header_romstack, %esp - jmp find_fsp_header + lea fsp_find_header_romstack, %esp + jmp fsp_find_header
-find_fsp_header_ret: +fsp_find_header_ret: /* EAX points to FSP_INFO_HEADER */ mov %eax, %ebp
@@ -91,8 +91,8 @@ die: * contain the function return address as well as the parameters. */ .balign 4 -find_fsp_header_romstack: - .long find_fsp_header_ret +fsp_find_header_romstack: + .long fsp_find_header_ret
.balign 4 temp_ram_init_romstack: diff --git a/arch/x86/lib/fsp1/fsp_support.c b/arch/x86/lib/fsp1/fsp_support.c index 019a42f53f..b5b7d664a1 100644 --- a/arch/x86/lib/fsp1/fsp_support.c +++ b/arch/x86/lib/fsp1/fsp_support.c @@ -8,7 +8,7 @@ #include <asm/fsp1/fsp_support.h> #include <asm/post.h>
-struct fsp_header *__attribute__((optimize("O0"))) find_fsp_header(void) +struct fsp_header *__attribute__((optimize("O0"))) fsp_find_header(void) { /* * This function may be called before the a stack is established, @@ -93,7 +93,7 @@ void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf) struct upd_region *fsp_upd; #endif
- fsp_hdr = find_fsp_header(); + fsp_hdr = fsp_find_header(); if (fsp_hdr == NULL) { /* No valid FSP info header was found */ panic("Invalid FSP header"); @@ -124,12 +124,12 @@ void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf) memset(&rt_buf, 0, sizeof(struct fspinit_rtbuf));
/* Override any configuration if required */ - update_fsp_configs(&config_data, &rt_buf); + fsp_update_configs(&config_data, &rt_buf);
memset(¶ms, 0, sizeof(struct fsp_init_params)); params.nvs_buf = nvs_buf; params.rt_buf = (struct fspinit_rtbuf *)&rt_buf; - params.continuation = (fsp_continuation_f)asm_continuation; + params.continuation = (fsp_continuation_f)fsp_asm_continuation;
init = (fsp_init_f)(fsp_hdr->img_base + fsp_hdr->fsp_init); params_ptr = ¶ms; @@ -146,8 +146,8 @@ void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf) asm volatile ( "pushl %0;" "call *%%eax;" - ".global asm_continuation;" - "asm_continuation:;" + ".global fsp_asm_continuation;" + "fsp_asm_continuation:;" "movl 4(%%esp), %%eax;" /* status */ "movl 8(%%esp), %%edx;" /* hob_list */ "jmp fsp_continue;" @@ -173,7 +173,7 @@ u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase) u32 status;
if (!fsp_hdr) - fsp_hdr = (struct fsp_header *)find_fsp_header(); + fsp_hdr = (struct fsp_header *)fsp_find_header();
if (fsp_hdr == NULL) { /* No valid FSP info header */ diff --git a/cmd/x86/fsp.c b/cmd/x86/fsp.c index fb27624422..b3b663021b 100644 --- a/cmd/x86/fsp.c +++ b/cmd/x86/fsp.c @@ -11,7 +11,7 @@ DECLARE_GLOBAL_DATA_PTR;
static int do_hdr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - struct fsp_header *hdr = find_fsp_header(); + struct fsp_header *hdr = fsp_find_header(); u32 img_addr = hdr->img_base; char *sign = (char *)&hdr->sign; int i;

Many support functions are common between FSP1 and FSP2. Add a new header to handle this.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/fsp/fsp_support.h | 128 ++++++++++++++++++++++++ arch/x86/include/asm/fsp1/fsp_support.h | 123 +---------------------- drivers/pci/pci-uclass.c | 2 +- 3 files changed, 132 insertions(+), 121 deletions(-) create mode 100644 arch/x86/include/asm/fsp/fsp_support.h
diff --git a/arch/x86/include/asm/fsp/fsp_support.h b/arch/x86/include/asm/fsp/fsp_support.h new file mode 100644 index 0000000000..0ecd5cb6c5 --- /dev/null +++ b/arch/x86/include/asm/fsp/fsp_support.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: Intel */ +/* + * Copyright (C) 2013, Intel Corporation + * Copyright (C) 2014, Bin Meng bmeng.cn@gmail.com + */ + +#ifndef __FSP_SUPPORT_H__ +#define __FSP_SUPPORT_H__ + +#include <asm/fsp/fsp_bootmode.h> +#include <asm/fsp/fsp_fv.h> +#include <asm/fsp/fsp_hob.h> +#include <asm/fsp/fsp_infoheader.h> +#include <asm/fsp/fsp_types.h> +#include <asm/fsp_arch.h> +#include <asm/fsp/fsp_azalia.h> + +#define FSP_LOWMEM_BASE 0x100000UL +#define FSP_HIGHMEM_BASE 0x100000000ULL +#define UPD_TERMINATOR 0x55AA + +struct fspinit_rtbuf; +struct fsp_config_data; + +/** + * Find FSP header offset in FSP image + * + * @retval: the offset of FSP header. If signature is invalid, returns 0. + */ +struct fsp_header *fsp_find_header(void); + +/** + * FSP notification wrapper function + * + * @fsp_hdr: Pointer to FSP information header + * @phase: FSP initialization phase defined in enum fsp_phase + * + * @retval: compatible status code with EFI_STATUS defined in PI spec + */ +u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase); + +/** + * This function retrieves the top of usable low memory. + * + * @hob_list: A HOB list pointer. + * + * @retval: Usable low memory top. + */ +u32 fsp_get_usable_lowmem_top(const void *hob_list); + +/** + * This function retrieves the top of usable high memory. + * + * @hob_list: A HOB list pointer. + * + * @retval: Usable high memory top. + */ +u64 fsp_get_usable_highmem_top(const void *hob_list); + +/** + * This function retrieves a special reserved memory region. + * + * @hob_list: A HOB list pointer. + * @len: A pointer to the GUID HOB data buffer length. + * If the GUID HOB is located, the length will be updated. + * @guid: A pointer to the owner guild. + * + * @retval: Reserved region start address. + * 0 if this region does not exist. + */ +u64 fsp_get_reserved_mem_from_guid(const void *hob_list, + u64 *len, const efi_guid_t *guid); + +/** + * This function retrieves the FSP reserved normal memory. + * + * @hob_list: A HOB list pointer. + * @len: A pointer to the FSP reserved memory length buffer. + * If the GUID HOB is located, the length will be updated. + * @retval: FSP reserved memory base + * 0 if this region does not exist. + */ +u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len); + +/** + * This function retrieves the TSEG reserved normal memory. + * + * @hob_list: A HOB list pointer. + * @len: A pointer to the TSEG reserved memory length buffer. + * If the GUID HOB is located, the length will be updated. + * + * @retval NULL: Failed to find the TSEG reserved memory. + * @retval others: TSEG reserved memory base. + */ +u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len); + +/** + * This function retrieves FSP Non-volatile Storage HOB buffer and size. + * + * @hob_list: A HOB list pointer. + * @len: A pointer to the NVS data buffer length. + * If the HOB is located, the length will be updated. + * + * @retval NULL: Failed to find the NVS HOB. + * @retval others: FSP NVS data buffer pointer. + */ +void *fsp_get_nvs_data(const void *hob_list, u32 *len); + +/** + * This function retrieves graphics information. + * + * @hob_list: A HOB list pointer. + * @len: A pointer to the graphics info HOB length. + * If the HOB is located, the length will be updated. + * + * @retval NULL: Failed to find the graphics info HOB. + * @retval others: A pointer to struct hob_graphics_info. + */ +void *fsp_get_graphics_info(const void *hob_list, u32 *len); + +/** + * fsp_init_phase_pci() - Tell the FSP that we have completed PCI init + * + * @return 0 if OK, -EPERM if the FSP gave an error. + */ +int fsp_init_phase_pci(void); + +#endif diff --git a/arch/x86/include/asm/fsp1/fsp_support.h b/arch/x86/include/asm/fsp1/fsp_support.h index 945a45c0fe..15c3a462e2 100644 --- a/arch/x86/include/asm/fsp1/fsp_support.h +++ b/arch/x86/include/asm/fsp1/fsp_support.h @@ -4,25 +4,11 @@ * Copyright (C) 2014, Bin Meng bmeng.cn@gmail.com */
-#ifndef __FSP_SUPPORT_H__ -#define __FSP_SUPPORT_H__ +#ifndef __FSP1_SUPPORT_H__ +#define __FSP1_SUPPORT_H__
-#include <asm/fsp/fsp_bootmode.h> -#include <asm/fsp/fsp_fv.h> -#include <asm/fsp/fsp_hob.h> -#include <asm/fsp/fsp_infoheader.h> -#include <asm/fsp/fsp_types.h> +#include <asm/fsp/fsp_support.h> #include "fsp_ffs.h" -#include <asm/fsp_arch.h> -#include <asm/fsp/fsp_azalia.h> - -#define FSP_LOWMEM_BASE 0x100000UL -#define FSP_HIGHMEM_BASE 0x100000000ULL -#define UPD_TERMINATOR 0x55AA - -struct efi_guid; -struct fspinit_rtbuf; -struct fsp_config_data;
/** * FSP Continuation assembly helper routine @@ -51,13 +37,6 @@ void fsp_init_done(void *hob_list); */ void fsp_continue(u32 status, void *hob_list);
-/** - * Find FSP header offset in FSP image - * - * @retval: the offset of FSP header. If signature is invalid, returns 0. - */ -struct fsp_header *fsp_find_header(void); - /** * FSP initialization wrapper function. * @@ -67,83 +46,6 @@ struct fsp_header *fsp_find_header(void); */ void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf);
-/** - * FSP notification wrapper function - * - * @fsp_hdr: Pointer to FSP information header - * @phase: FSP initialization phase defined in enum fsp_phase - * - * @retval: compatible status code with EFI_STATUS defined in PI spec - */ -u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase); - -/** - * This function retrieves the top of usable low memory. - * - * @hob_list: A HOB list pointer. - * - * @retval: Usable low memory top. - */ -u32 fsp_get_usable_lowmem_top(const void *hob_list); - -/** - * This function retrieves the top of usable high memory. - * - * @hob_list: A HOB list pointer. - * - * @retval: Usable high memory top. - */ -u64 fsp_get_usable_highmem_top(const void *hob_list); - -/** - * This function retrieves a special reserved memory region. - * - * @hob_list: A HOB list pointer. - * @len: A pointer to the GUID HOB data buffer length. - * If the GUID HOB is located, the length will be updated. - * @guid: A pointer to the owner guild. - * - * @retval: Reserved region start address. - * 0 if this region does not exist. - */ -u64 fsp_get_reserved_mem_from_guid(const void *hob_list, - u64 *len, const efi_guid_t *guid); - -/** - * This function retrieves the FSP reserved normal memory. - * - * @hob_list: A HOB list pointer. - * @len: A pointer to the FSP reserved memory length buffer. - * If the GUID HOB is located, the length will be updated. - * @retval: FSP reserved memory base - * 0 if this region does not exist. - */ -u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len); - -/** - * This function retrieves the TSEG reserved normal memory. - * - * @hob_list: A HOB list pointer. - * @len: A pointer to the TSEG reserved memory length buffer. - * If the GUID HOB is located, the length will be updated. - * - * @retval NULL: Failed to find the TSEG reserved memory. - * @retval others: TSEG reserved memory base. - */ -u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len); - -/** - * This function retrieves FSP Non-volatile Storage HOB buffer and size. - * - * @hob_list: A HOB list pointer. - * @len: A pointer to the NVS data buffer length. - * If the HOB is located, the length will be updated. - * - * @retval NULL: Failed to find the NVS HOB. - * @retval others: FSP NVS data buffer pointer. - */ -void *fsp_get_nvs_data(const void *hob_list, u32 *len); - /** * This function retrieves Bootloader temporary stack buffer and size. * @@ -156,18 +58,6 @@ void *fsp_get_nvs_data(const void *hob_list, u32 *len); */ void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len);
-/** - * This function retrieves graphics information. - * - * @hob_list: A HOB list pointer. - * @len: A pointer to the graphics info HOB length. - * If the HOB is located, the length will be updated. - * - * @retval NULL: Failed to find the graphics info HOB. - * @retval others: A pointer to struct hob_graphics_info. - */ -void *fsp_get_graphics_info(const void *hob_list, u32 *len); - /** * This function overrides the default configurations of FSP. * @@ -179,11 +69,4 @@ void *fsp_get_graphics_info(const void *hob_list, u32 *len); void fsp_update_configs(struct fsp_config_data *config, struct fspinit_rtbuf *rt_buf);
-/** - * fsp_init_phase_pci() - Tell the FSP that we have completed PCI init - * - * @return 0 if OK, -EPERM if the FSP gave an error. - */ -int fsp_init_phase_pci(void); - #endif diff --git a/drivers/pci/pci-uclass.c b/drivers/pci/pci-uclass.c index b73d0cd70a..ab3e1310eb 100644 --- a/drivers/pci/pci-uclass.c +++ b/drivers/pci/pci-uclass.c @@ -12,7 +12,7 @@ #include <dm/device-internal.h> #include <dm/lists.h> #if defined(CONFIG_X86) && defined(CONFIG_HAVE_FSP) -#include <asm/fsp1/fsp_support.h> +#include <asm/fsp/fsp_support.h> #endif #include "pci_internal.h"

Update a few #ifdefs to if() to improve build coverage.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/fsp1/fsp_common.c | 9 ++++----- arch/x86/lib/fsp1/fsp_dram.c | 8 ++------ 2 files changed, 6 insertions(+), 11 deletions(-)
diff --git a/arch/x86/lib/fsp1/fsp_common.c b/arch/x86/lib/fsp1/fsp_common.c index 591eef7b81..bfd76dccba 100644 --- a/arch/x86/lib/fsp1/fsp_common.c +++ b/arch/x86/lib/fsp1/fsp_common.c @@ -116,11 +116,10 @@ int arch_fsp_init(void) #endif
if (!gd->arch.hob_list) { -#ifdef CONFIG_ENABLE_MRC_CACHE - nvs = fsp_prepare_mrc_cache(); -#else - nvs = NULL; -#endif + if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) + nvs = fsp_prepare_mrc_cache(); + else + nvs = NULL;
#ifdef CONFIG_HAVE_ACPI_RESUME if (prev_sleep_state == ACPI_S3) { diff --git a/arch/x86/lib/fsp1/fsp_dram.c b/arch/x86/lib/fsp1/fsp_dram.c index 3bf65b495c..961e963362 100644 --- a/arch/x86/lib/fsp1/fsp_dram.c +++ b/arch/x86/lib/fsp1/fsp_dram.c @@ -29,13 +29,9 @@ int dram_init(void) hdr = get_next_hob(hdr); }
- gd->ram_size = ram_size; - post_code(POST_DRAM); - -#ifdef CONFIG_ENABLE_MRC_CACHE - gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list, + if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) + gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list, &gd->arch.mrc_output_len); -#endif
return 0; }

Hi Simon,
On Tue, Aug 27, 2019 at 12:03 AM Simon Glass sjg@chromium.org wrote:
Update a few #ifdefs to if() to improve build coverage.
Signed-off-by: Simon Glass sjg@chromium.org
arch/x86/lib/fsp1/fsp_common.c | 9 ++++----- arch/x86/lib/fsp1/fsp_dram.c | 8 ++------ 2 files changed, 6 insertions(+), 11 deletions(-)
diff --git a/arch/x86/lib/fsp1/fsp_common.c b/arch/x86/lib/fsp1/fsp_common.c index 591eef7b81..bfd76dccba 100644 --- a/arch/x86/lib/fsp1/fsp_common.c +++ b/arch/x86/lib/fsp1/fsp_common.c @@ -116,11 +116,10 @@ int arch_fsp_init(void) #endif
if (!gd->arch.hob_list) {
-#ifdef CONFIG_ENABLE_MRC_CACHE
nvs = fsp_prepare_mrc_cache();
-#else
nvs = NULL;
-#endif
if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE))
nvs = fsp_prepare_mrc_cache();
else
nvs = NULL;
#ifdef CONFIG_HAVE_ACPI_RESUME if (prev_sleep_state == ACPI_S3) { diff --git a/arch/x86/lib/fsp1/fsp_dram.c b/arch/x86/lib/fsp1/fsp_dram.c index 3bf65b495c..961e963362 100644 --- a/arch/x86/lib/fsp1/fsp_dram.c +++ b/arch/x86/lib/fsp1/fsp_dram.c @@ -29,13 +29,9 @@ int dram_init(void) hdr = get_next_hob(hdr); }
gd->ram_size = ram_size;
post_code(POST_DRAM);
This does not look right.
-#ifdef CONFIG_ENABLE_MRC_CACHE
gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list,
if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE))
gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list, &gd->arch.mrc_output_len);
-#endif
return 0;
}
Regards, Bin

The comments in the FSP code use a different style from the rest of the x86 code. I am not sure it this is intentional.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/fsp/fsp_support.h | 42 ++++++++++++------------- arch/x86/include/asm/fsp1/fsp_support.h | 30 ++++++++++++------ arch/x86/include/asm/hob.h | 18 +++++------ arch/x86/lib/hob.c | 8 ++--- 4 files changed, 54 insertions(+), 44 deletions(-)
diff --git a/arch/x86/include/asm/fsp/fsp_support.h b/arch/x86/include/asm/fsp/fsp_support.h index 0ecd5cb6c5..8d29f9f5e4 100644 --- a/arch/x86/include/asm/fsp/fsp_support.h +++ b/arch/x86/include/asm/fsp/fsp_support.h @@ -23,98 +23,98 @@ struct fspinit_rtbuf; struct fsp_config_data;
/** - * Find FSP header offset in FSP image + * fsp_find_header() - Find FSP header offset in FSP image * - * @retval: the offset of FSP header. If signature is invalid, returns 0. + * @return the offset of FSP header. If signature is invalid, returns 0. */ struct fsp_header *fsp_find_header(void);
/** - * FSP notification wrapper function + * fsp_notify() - FSP notification wrapper function * * @fsp_hdr: Pointer to FSP information header * @phase: FSP initialization phase defined in enum fsp_phase * - * @retval: compatible status code with EFI_STATUS defined in PI spec + * @return compatible status code with EFI_STATUS defined in PI spec */ u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase);
/** - * This function retrieves the top of usable low memory. + * fsp_get_usable_lowmem_top() - retrieves the top of usable low memory * * @hob_list: A HOB list pointer. * - * @retval: Usable low memory top. + * @return Usable low memory top. */ u32 fsp_get_usable_lowmem_top(const void *hob_list);
/** - * This function retrieves the top of usable high memory. + * fsp_get_usable_highmem_top() - retrieves the top of usable high memory * * @hob_list: A HOB list pointer. * - * @retval: Usable high memory top. + * @return Usable high memory top. */ u64 fsp_get_usable_highmem_top(const void *hob_list);
/** - * This function retrieves a special reserved memory region. + * fsp_get_reserved_mem_from_guid() - retrieves a special reserved memory region * * @hob_list: A HOB list pointer. * @len: A pointer to the GUID HOB data buffer length. * If the GUID HOB is located, the length will be updated. * @guid: A pointer to the owner guild. * - * @retval: Reserved region start address. + * @return Reserved region start address. * 0 if this region does not exist. */ u64 fsp_get_reserved_mem_from_guid(const void *hob_list, u64 *len, const efi_guid_t *guid);
/** - * This function retrieves the FSP reserved normal memory. + * fsp_get_fsp_reserved_mem() - retrieves the FSP reserved normal memory * * @hob_list: A HOB list pointer. * @len: A pointer to the FSP reserved memory length buffer. * If the GUID HOB is located, the length will be updated. - * @retval: FSP reserved memory base + * @return FSP reserved memory base * 0 if this region does not exist. */ u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len);
/** - * This function retrieves the TSEG reserved normal memory. + * fsp_get_tseg_reserved_mem() - retrieves the TSEG reserved normal memory * * @hob_list: A HOB list pointer. * @len: A pointer to the TSEG reserved memory length buffer. * If the GUID HOB is located, the length will be updated. * - * @retval NULL: Failed to find the TSEG reserved memory. - * @retval others: TSEG reserved memory base. + * @return NULL: Failed to find the TSEG reserved memory. + * @return others: TSEG reserved memory base. */ u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len);
/** - * This function retrieves FSP Non-volatile Storage HOB buffer and size. + * fsp_get_nvs_data() - retrieves FSP Non-volatile Storage HOB buffer and size * * @hob_list: A HOB list pointer. * @len: A pointer to the NVS data buffer length. * If the HOB is located, the length will be updated. * - * @retval NULL: Failed to find the NVS HOB. - * @retval others: FSP NVS data buffer pointer. + * @return NULL: Failed to find the NVS HOB. + * @return others: FSP NVS data buffer pointer. */ void *fsp_get_nvs_data(const void *hob_list, u32 *len);
/** - * This function retrieves graphics information. + * fsp_get_graphics_info() - retrieves graphics information. * * @hob_list: A HOB list pointer. * @len: A pointer to the graphics info HOB length. * If the HOB is located, the length will be updated. * - * @retval NULL: Failed to find the graphics info HOB. - * @retval others: A pointer to struct hob_graphics_info. + * @return NULL: Failed to find the graphics info HOB. + * @return others: A pointer to struct hob_graphics_info. */ void *fsp_get_graphics_info(const void *hob_list, u32 *len);
diff --git a/arch/x86/include/asm/fsp1/fsp_support.h b/arch/x86/include/asm/fsp1/fsp_support.h index 15c3a462e2..236c167fc8 100644 --- a/arch/x86/include/asm/fsp1/fsp_support.h +++ b/arch/x86/include/asm/fsp1/fsp_support.h @@ -11,14 +11,14 @@ #include "fsp_ffs.h"
/** - * FSP Continuation assembly helper routine + * fsp_asm_continuation() - FSP Continuation assembly helper routine * * This routine jumps to the C version of FSP continuation function */ void fsp_asm_continuation(void);
/** - * FSP initialization complete + * fsp_init_done() - FSP initialization complete * * This is the function that indicates FSP initialization is complete and jumps * back to the bootloader with HOB list pointer as the parameter. @@ -28,17 +28,17 @@ void fsp_asm_continuation(void); void fsp_init_done(void *hob_list);
/** - * FSP Continuation function + * fsp_continue() - FSP Continuation function * * @status: Always 0 * @hob_list: HOB list pointer * - * @retval: Never returns + * @return Never returns */ void fsp_continue(u32 status, void *hob_list);
/** - * FSP initialization wrapper function. + * fsp_init() - FSP initialization wrapper function * * @stack_top: bootloader stack top address * @boot_mode: boot mode defined in fsp_bootmode.h @@ -47,24 +47,34 @@ void fsp_continue(u32 status, void *hob_list); void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf);
/** - * This function retrieves Bootloader temporary stack buffer and size. + * fsp_notify() - FSP notification wrapper function + * + * @fsp_hdr: Pointer to FSP information header + * @phase: FSP initialization phase defined in enum fsp_phase + * + * @return compatible status code with EFI_STATUS defined in PI spec + */ +u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase); + +/** + * fsp_get_bootloader_tmp_mem() - retrieves temporary stack buffer and size * * @hob_list: A HOB list pointer. * @len: A pointer to the bootloader temporary stack length. * If the HOB is located, the length will be updated. * - * @retval NULL: Failed to find the bootloader temporary stack HOB. - * @retval others: Bootloader temporary stackbuffer pointer. + * @return NULL: Failed to find the bootloader temporary stack HOB. + * @return others: Bootloader temporary stackbuffer pointer. */ void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len);
/** - * This function overrides the default configurations of FSP. + * fsp_update_configs() - overrides the default configurations of FSP * * @config: A pointer to the FSP configuration data structure * @rt_buf: A pointer to the FSP runtime buffer data structure * - * @return: None + * @return None */ void fsp_update_configs(struct fsp_config_data *config, struct fspinit_rtbuf *rt_buf); diff --git a/arch/x86/include/asm/hob.h b/arch/x86/include/asm/hob.h index b4239821aa..72151ea045 100644 --- a/arch/x86/include/asm/hob.h +++ b/arch/x86/include/asm/hob.h @@ -135,7 +135,7 @@ struct hob_guid { * * @hdr: A pointer to a HOB. * - * @return: A pointer to the next HOB in the HOB list. + * @return A pointer to the next HOB in the HOB list. */ static inline const struct hob_header *get_next_hob(const struct hob_header *hdr) @@ -152,8 +152,8 @@ static inline const struct hob_header *get_next_hob(const struct hob_header * * @hdr: A pointer to a HOB. * - * @retval true: The HOB specified by hdr is the last HOB in the HOB list. - * @retval false: The HOB specified by hdr is not the last HOB in the HOB list. + * @return true: The HOB specified by hdr is the last HOB in the HOB list. + * @return false: The HOB specified by hdr is not the last HOB in the HOB list. */ static inline bool end_of_hob(const struct hob_header *hdr) { @@ -169,7 +169,7 @@ static inline bool end_of_hob(const struct hob_header *hdr) * * @hdr: A pointer to a HOB. * - * @return: A pointer to the data buffer in a HOB. + * @return A pointer to the data buffer in a HOB. */ static inline void *get_guid_hob_data(const struct hob_header *hdr) { @@ -185,7 +185,7 @@ static inline void *get_guid_hob_data(const struct hob_header *hdr) * * @hdr: A pointer to a HOB. * - * @return: The size of the data buffer. + * @return The size of the data buffer. */ static inline u16 get_guid_hob_data_size(const struct hob_header *hdr) { @@ -198,7 +198,7 @@ static inline u16 get_guid_hob_data_size(const struct hob_header *hdr) * @type: HOB type to search * @hob_list: A pointer to the HOB list * - * @retval: A HOB object with matching type; Otherwise NULL. + *@return A HOB object with matching type; Otherwise NULL. */ const struct hob_header *hob_get_next_hob(uint type, const void *hob_list);
@@ -208,7 +208,7 @@ const struct hob_header *hob_get_next_hob(uint type, const void *hob_list); * @guid: GUID to search * @hob_list: A pointer to the HOB list * - * @retval: A HOB object with matching GUID; Otherwise NULL. + *@return A HOB object with matching GUID; Otherwise NULL. */ const struct hob_header *hob_get_next_guid_hob(const efi_guid_t *guid, const void *hob_list); @@ -221,8 +221,8 @@ const struct hob_header *hob_get_next_guid_hob(const efi_guid_t *guid, * If the GUID HOB is located, the length will be updated. * @guid A pointer to HOB GUID. * - * @retval NULL: Failed to find the GUID HOB. - * @retval others: GUID HOB data buffer pointer. + * @return NULL: Failed to find the GUID HOB. + * @return others: GUID HOB data buffer pointer. */ void *hob_get_guid_hob_data(const void *hob_list, u32 *len, const efi_guid_t *guid); diff --git a/arch/x86/lib/hob.c b/arch/x86/lib/hob.c index dcee29b04c..f2c47240ee 100644 --- a/arch/x86/lib/hob.c +++ b/arch/x86/lib/hob.c @@ -13,7 +13,7 @@ * @type: HOB type to search * @hob_list: A pointer to the HOB list * - * @retval: A HOB object with matching type; Otherwise NULL. + * @return A HOB object with matching type; Otherwise NULL. */ const struct hob_header *hob_get_next_hob(uint type, const void *hob_list) { @@ -38,7 +38,7 @@ const struct hob_header *hob_get_next_hob(uint type, const void *hob_list) * @guid: GUID to search * @hob_list: A pointer to the HOB list * - * @retval: A HOB object with matching GUID; Otherwise NULL. + * @return A HOB object with matching GUID; Otherwise NULL. */ const struct hob_header *hob_get_next_guid_hob(const efi_guid_t *guid, const void *hob_list) @@ -65,8 +65,8 @@ const struct hob_header *hob_get_next_guid_hob(const efi_guid_t *guid, * If the GUID HOB is located, the length will be updated. * @guid A pointer to HOB GUID. * - * @retval NULL: Failed to find the GUID HOB. - * @retval others: GUID HOB data buffer pointer. + * @return NULL: Failed to find the GUID HOB. + * @return others: GUID HOB data buffer pointer. */ void *hob_get_guid_hob_data(const void *hob_list, u32 *len, const efi_guid_t *guid)

Most of the DRAM functionality can be shared between FSP1 and FSP2. Move it into a shared file.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/fsp/fsp_support.h | 9 +++ arch/x86/lib/Makefile | 1 + arch/x86/lib/fsp/Makefile | 5 ++ arch/x86/lib/fsp/fsp_dram.c | 90 ++++++++++++++++++++++++++ arch/x86/lib/fsp1/fsp_dram.c | 80 ++--------------------- 5 files changed, 111 insertions(+), 74 deletions(-) create mode 100644 arch/x86/lib/fsp/Makefile create mode 100644 arch/x86/lib/fsp/fsp_dram.c
diff --git a/arch/x86/include/asm/fsp/fsp_support.h b/arch/x86/include/asm/fsp/fsp_support.h index 8d29f9f5e4..8f8795415d 100644 --- a/arch/x86/include/asm/fsp/fsp_support.h +++ b/arch/x86/include/asm/fsp/fsp_support.h @@ -125,4 +125,13 @@ void *fsp_get_graphics_info(const void *hob_list, u32 *len); */ int fsp_init_phase_pci(void);
+/** + * fsp_scan_for_ram_size() - Scan the HOB list to find the RAM size + * + * This sets gd->ram_size based on what it finds. + * + * @return 0 if OK, -ve on error + */ +int fsp_scan_for_ram_size(void); + #endif diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index a8c7448ee4..ca0ca1066b 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -43,6 +43,7 @@ ifndef CONFIG_SPL_BUILD obj-$(CONFIG_CMD_ZBOOT) += zimage.o endif obj-$(CONFIG_USE_HOB) += hob.o +obj-$(CONFIG_HAVE_FSP) += fsp/ obj-$(CONFIG_FSP_VERSION1) += fsp1/ obj-$(CONFIG_FSP_VERSION2) += fsp2/
diff --git a/arch/x86/lib/fsp/Makefile b/arch/x86/lib/fsp/Makefile new file mode 100644 index 0000000000..e2160653de --- /dev/null +++ b/arch/x86/lib/fsp/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2019 Google LLC + +obj-y += fsp_dram.o diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c new file mode 100644 index 0000000000..8fe1e0bf73 --- /dev/null +++ b/arch/x86/lib/fsp/fsp_dram.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014, Bin Meng bmeng.cn@gmail.com + */ + +#include <common.h> +#include <handoff.h> +#include <asm/fsp/fsp_support.h> +#include <asm/e820.h> +#include <asm/mrccache.h> +#include <asm/post.h> + +DECLARE_GLOBAL_DATA_PTR; + +int fsp_scan_for_ram_size(void) +{ + phys_size_t ram_size = 0; + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + + hdr = gd->arch.hob_list; + while (!end_of_hob(hdr)) { + if (hdr->type == HOB_TYPE_RES_DESC) { + res_desc = (struct hob_res_desc *)hdr; + if (res_desc->type == RES_SYS_MEM || + res_desc->type == RES_MEM_RESERVED) + ram_size += res_desc->len; + } + hdr = get_next_hob(hdr); + } + + gd->ram_size = ram_size; + post_code(POST_DRAM); + + return 0; +}; + +int dram_init_banksize(void) +{ + gd->bd->bi_dram[0].start = 0; + gd->bd->bi_dram[0].size = gd->ram_size; + + return 0; +} + +unsigned int install_e820_map(unsigned int max_entries, + struct e820_entry *entries) +{ + unsigned int num_entries = 0; + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + + hdr = gd->arch.hob_list; + + while (!end_of_hob(hdr)) { + if (hdr->type == HOB_TYPE_RES_DESC) { + res_desc = (struct hob_res_desc *)hdr; + entries[num_entries].addr = res_desc->phys_start; + entries[num_entries].size = res_desc->len; + + if (res_desc->type == RES_SYS_MEM) + entries[num_entries].type = E820_RAM; + else if (res_desc->type == RES_MEM_RESERVED) + entries[num_entries].type = E820_RESERVED; + + num_entries++; + } + hdr = get_next_hob(hdr); + } + + /* Mark PCIe ECAM address range as reserved */ + entries[num_entries].addr = CONFIG_PCIE_ECAM_BASE; + entries[num_entries].size = CONFIG_PCIE_ECAM_SIZE; + 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; +} diff --git a/arch/x86/lib/fsp1/fsp_dram.c b/arch/x86/lib/fsp1/fsp_dram.c index 961e963362..6a3349b42a 100644 --- a/arch/x86/lib/fsp1/fsp_dram.c +++ b/arch/x86/lib/fsp1/fsp_dram.c @@ -4,30 +4,16 @@ */
#include <common.h> -#include <asm/fsp1/fsp_support.h> -#include <asm/e820.h> -#include <asm/mrccache.h> -#include <asm/post.h> - -DECLARE_GLOBAL_DATA_PTR; +#include <asm/fsp/fsp_support.h>
int dram_init(void) { - phys_size_t ram_size = 0; - const struct hob_header *hdr; - struct hob_res_desc *res_desc; + int ret;
- hdr = gd->arch.hob_list; - while (!end_of_hob(hdr)) { - if (hdr->type == HOB_TYPE_RES_DESC) { - res_desc = (struct hob_res_desc *)hdr; - if (res_desc->type == RES_SYS_MEM || - res_desc->type == RES_MEM_RESERVED) { - ram_size += res_desc->len; - } - } - hdr = get_next_hob(hdr); - } + /* The FSP has already set up DRAM, so grab the info we need */ + ret = fsp_scan_for_ram_size(); + if (ret) + return ret;
if (IS_ENABLED(CONFIG_ENABLE_MRC_CACHE)) gd->arch.mrc_output = fsp_get_nvs_data(gd->arch.hob_list, @@ -36,14 +22,6 @@ int dram_init(void) return 0; }
-int dram_init_banksize(void) -{ - gd->bd->bi_dram[0].start = 0; - gd->bd->bi_dram[0].size = gd->ram_size; - - return 0; -} - /* * This function looks for the highest region of memory lower than 4GB which * has enough space for U-Boot where U-Boot is aligned on a page boundary. @@ -56,49 +34,3 @@ ulong board_get_usable_ram_top(ulong total_size) { return fsp_get_usable_lowmem_top(gd->arch.hob_list); } - -unsigned int install_e820_map(unsigned int max_entries, - struct e820_entry *entries) -{ - unsigned int num_entries = 0; - const struct hob_header *hdr; - struct hob_res_desc *res_desc; - - hdr = gd->arch.hob_list; - - while (!end_of_hob(hdr)) { - if (hdr->type == HOB_TYPE_RES_DESC) { - res_desc = (struct hob_res_desc *)hdr; - entries[num_entries].addr = res_desc->phys_start; - entries[num_entries].size = res_desc->len; - - if (res_desc->type == RES_SYS_MEM) - entries[num_entries].type = E820_RAM; - else if (res_desc->type == RES_MEM_RESERVED) - entries[num_entries].type = E820_RESERVED; - - num_entries++; - } - hdr = get_next_hob(hdr); - } - - /* Mark PCIe ECAM address range as reserved */ - entries[num_entries].addr = CONFIG_PCIE_ECAM_BASE; - entries[num_entries].size = CONFIG_PCIE_ECAM_SIZE; - 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; -}

Some of this file can be shared between FSP1 and FSP2. Move it into a shared file.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/fsp/fsp_support.h | 17 ++++ arch/x86/include/asm/fsp1/fsp_support.h | 10 --- arch/x86/lib/fsp/Makefile | 1 + arch/x86/lib/fsp/fsp_common.c | 104 ++++++++++++++++++++++++ arch/x86/lib/fsp1/fsp_common.c | 87 -------------------- 5 files changed, 122 insertions(+), 97 deletions(-) create mode 100644 arch/x86/lib/fsp/fsp_common.c
diff --git a/arch/x86/include/asm/fsp/fsp_support.h b/arch/x86/include/asm/fsp/fsp_support.h index 8f8795415d..6320fe0906 100644 --- a/arch/x86/include/asm/fsp/fsp_support.h +++ b/arch/x86/include/asm/fsp/fsp_support.h @@ -134,4 +134,21 @@ int fsp_init_phase_pci(void); */ int fsp_scan_for_ram_size(void);
+/** + * fsp_prepare_mrc_cache() - Find the DRAM training data from the MRC cache + * + * @return pointer to data, or NULL if no cache or no data found in the cache + */ +void *fsp_prepare_mrc_cache(void); + +/** + * fsp_notify() - FSP notification wrapper function + * + * @fsp_hdr: Pointer to FSP information header + * @phase: FSP initialization phase defined in enum fsp_phase + * + * @return compatible status code with EFI_STATUS defined in PI spec + */ +u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase); + #endif diff --git a/arch/x86/include/asm/fsp1/fsp_support.h b/arch/x86/include/asm/fsp1/fsp_support.h index 236c167fc8..a44a5504a4 100644 --- a/arch/x86/include/asm/fsp1/fsp_support.h +++ b/arch/x86/include/asm/fsp1/fsp_support.h @@ -46,16 +46,6 @@ void fsp_continue(u32 status, void *hob_list); */ void fsp_init(u32 stack_top, u32 boot_mode, void *nvs_buf);
-/** - * fsp_notify() - FSP notification wrapper function - * - * @fsp_hdr: Pointer to FSP information header - * @phase: FSP initialization phase defined in enum fsp_phase - * - * @return compatible status code with EFI_STATUS defined in PI spec - */ -u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase); - /** * fsp_get_bootloader_tmp_mem() - retrieves temporary stack buffer and size * diff --git a/arch/x86/lib/fsp/Makefile b/arch/x86/lib/fsp/Makefile index e2160653de..e7a8427c2e 100644 --- a/arch/x86/lib/fsp/Makefile +++ b/arch/x86/lib/fsp/Makefile @@ -2,4 +2,5 @@ # # Copyright 2019 Google LLC
+obj-y += fsp_common.o obj-y += fsp_dram.o diff --git a/arch/x86/lib/fsp/fsp_common.c b/arch/x86/lib/fsp/fsp_common.c new file mode 100644 index 0000000000..6678d75ffd --- /dev/null +++ b/arch/x86/lib/fsp/fsp_common.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2014, Bin Meng bmeng.cn@gmail.com + */ + +#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> +#include <asm/processor.h> +#include <asm/fsp/fsp_support.h> + +DECLARE_GLOBAL_DATA_PTR; + +int checkcpu(void) +{ + return 0; +} + +int print_cpuinfo(void) +{ + post_code(POST_CPU_INFO); + return default_print_cpuinfo(); +} + +int fsp_init_phase_pci(void) +{ + u32 status; + + /* call into FspNotify */ + debug("Calling into FSP (notify phase INIT_PHASE_PCI): "); + status = fsp_notify(NULL, INIT_PHASE_PCI); + if (status) + debug("fail, error code %x\n", status); + else + debug("OK\n"); + + return status ? -EPERM : 0; +} + +void board_final_cleanup(void) +{ + u32 status; + + /* call into FspNotify */ + debug("Calling into FSP (notify phase INIT_PHASE_BOOT): "); + status = fsp_notify(NULL, INIT_PHASE_BOOT); + if (status) + debug("fail, error code %x\n", status); + else + debug("OK\n"); +} + +void *fsp_prepare_mrc_cache(void) +{ + struct mrc_data_container *cache; + struct mrc_region entry; + int ret; + + ret = mrccache_get_region(NULL, &entry); + if (ret) + return NULL; + + cache = mrccache_find_current(&entry); + if (!cache) + return NULL; + + debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__, + cache->data, cache->data_size, cache->checksum); + + 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 diff --git a/arch/x86/lib/fsp1/fsp_common.c b/arch/x86/lib/fsp1/fsp_common.c index bfd76dccba..285ef72ebf 100644 --- a/arch/x86/lib/fsp1/fsp_common.c +++ b/arch/x86/lib/fsp1/fsp_common.c @@ -18,93 +18,6 @@
DECLARE_GLOBAL_DATA_PTR;
-int checkcpu(void) -{ - return 0; -} - -int print_cpuinfo(void) -{ - post_code(POST_CPU_INFO); - return default_print_cpuinfo(); -} - -int fsp_init_phase_pci(void) -{ - u32 status; - - /* call into FspNotify */ - debug("Calling into FSP (notify phase INIT_PHASE_PCI): "); - status = fsp_notify(NULL, INIT_PHASE_PCI); - if (status) - debug("fail, error code %x\n", status); - else - debug("OK\n"); - - return status ? -EPERM : 0; -} - -void board_final_cleanup(void) -{ - u32 status; - - /* call into FspNotify */ - debug("Calling into FSP (notify phase INIT_PHASE_BOOT): "); - status = fsp_notify(NULL, INIT_PHASE_BOOT); - if (status) - debug("fail, error code %x\n", status); - else - debug("OK\n"); - - return; -} - -static __maybe_unused void *fsp_prepare_mrc_cache(void) -{ - struct mrc_data_container *cache; - struct mrc_region entry; - int ret; - - ret = mrccache_get_region(NULL, &entry); - if (ret) - return NULL; - - cache = mrccache_find_current(&entry); - if (!cache) - return NULL; - - debug("%s: mrc cache at %p, size %x checksum %04x\n", __func__, - cache->data, cache->data_size, cache->checksum); - - 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;

Some of this file can be shared between FSP1 and FSP2. Move it into a shared file.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/fsp/Makefile | 1 + arch/x86/lib/fsp/fsp_support.c | 176 ++++++++++++++++++++++++++++++++ arch/x86/lib/fsp1/fsp_support.c | 167 ------------------------------ 3 files changed, 177 insertions(+), 167 deletions(-) create mode 100644 arch/x86/lib/fsp/fsp_support.c
diff --git a/arch/x86/lib/fsp/Makefile b/arch/x86/lib/fsp/Makefile index e7a8427c2e..9e34856473 100644 --- a/arch/x86/lib/fsp/Makefile +++ b/arch/x86/lib/fsp/Makefile @@ -4,3 +4,4 @@
obj-y += fsp_common.o obj-y += fsp_dram.o +obj-y += fsp_support.o diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c new file mode 100644 index 0000000000..014de35e56 --- /dev/null +++ b/arch/x86/lib/fsp/fsp_support.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: Intel +/* + * Copyright (C) 2013, Intel Corporation + * Copyright (C) 2014, Bin Meng bmeng.cn@gmail.com + */ + +#include <common.h> +#include <asm/fsp1/fsp_support.h> +#include <asm/post.h> + +u32 fsp_get_usable_lowmem_top(const void *hob_list) +{ + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + phys_addr_t phys_start; + u32 top; +#ifdef CONFIG_FSP_BROKEN_HOB + struct hob_mem_alloc *res_mem; + phys_addr_t mem_base = 0; +#endif + + /* Get the HOB list for processing */ + hdr = hob_list; + + /* * Collect memory ranges */ + top = FSP_LOWMEM_BASE; + while (!end_of_hob(hdr)) { + if (hdr->type == HOB_TYPE_RES_DESC) { + res_desc = (struct hob_res_desc *)hdr; + if (res_desc->type == RES_SYS_MEM) { + phys_start = res_desc->phys_start; + /* Need memory above 1MB to be collected here */ + if (phys_start >= FSP_LOWMEM_BASE && + phys_start < (phys_addr_t)FSP_HIGHMEM_BASE) + top += (u32)(res_desc->len); + } + } + +#ifdef CONFIG_FSP_BROKEN_HOB + /* + * Find out the lowest memory base address allocated by FSP + * for the boot service data + */ + if (hdr->type == HOB_TYPE_MEM_ALLOC) { + res_mem = (struct hob_mem_alloc *)hdr; + if (!mem_base) + mem_base = res_mem->mem_base; + if (res_mem->mem_base < mem_base) + mem_base = res_mem->mem_base; + } +#endif + + hdr = get_next_hob(hdr); + } + +#ifdef CONFIG_FSP_BROKEN_HOB + /* + * Check whether the memory top address is below the FSP HOB list. + * If not, use the lowest memory base address allocated by FSP as + * the memory top address. This is to prevent U-Boot relocation + * overwrites the important boot service data which is used by FSP, + * otherwise the subsequent call to fsp_notify() will fail. + */ + if (top > (u32)hob_list) { + debug("Adjust memory top address due to a buggy FSP\n"); + top = (u32)mem_base; + } +#endif + + return top; +} + +u64 fsp_get_usable_highmem_top(const void *hob_list) +{ + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + phys_addr_t phys_start; + u64 top; + + /* Get the HOB list for processing */ + hdr = hob_list; + + /* Collect memory ranges */ + top = FSP_HIGHMEM_BASE; + while (!end_of_hob(hdr)) { + if (hdr->type == HOB_TYPE_RES_DESC) { + res_desc = (struct hob_res_desc *)hdr; + if (res_desc->type == RES_SYS_MEM) { + phys_start = res_desc->phys_start; + /* Need memory above 4GB to be collected here */ + if (phys_start >= (phys_addr_t)FSP_HIGHMEM_BASE) + top += (u32)(res_desc->len); + } + } + hdr = get_next_hob(hdr); + } + + return top; +} + +u64 fsp_get_reserved_mem_from_guid(const void *hob_list, u64 *len, + const efi_guid_t *guid) +{ + const struct hob_header *hdr; + struct hob_res_desc *res_desc; + + /* Get the HOB list for processing */ + hdr = hob_list; + + /* Collect memory ranges */ + while (!end_of_hob(hdr)) { + if (hdr->type == HOB_TYPE_RES_DESC) { + res_desc = (struct hob_res_desc *)hdr; + if (res_desc->type == RES_MEM_RESERVED) { + if (!guidcmp(&res_desc->owner, guid)) { + if (len) + *len = (u32)(res_desc->len); + + return (u64)(res_desc->phys_start); + } + } + } + hdr = get_next_hob(hdr); + } + + return 0; +} + +u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len) +{ + const efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_FSP_GUID; + u64 length; + u32 base; + + base = (u32)fsp_get_reserved_mem_from_guid(hob_list, + &length, &guid); + if (len && base) + *len = (u32)length; + + return base; +} + +u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len) +{ + const efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_TSEG_GUID; + u64 length; + u32 base; + + base = (u32)fsp_get_reserved_mem_from_guid(hob_list, + &length, &guid); + if (len && base) + *len = (u32)length; + + return base; +} + +void *fsp_get_nvs_data(const void *hob_list, u32 *len) +{ + const efi_guid_t guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID; + + return hob_get_guid_hob_data(hob_list, len, &guid); +} + +void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len) +{ + const efi_guid_t guid = FSP_BOOTLOADER_TEMP_MEM_HOB_GUID; + + return hob_get_guid_hob_data(hob_list, len, &guid); +} + +void *fsp_get_graphics_info(const void *hob_list, u32 *len) +{ + const efi_guid_t guid = FSP_GRAPHICS_INFO_HOB_GUID; + + return hob_get_guid_hob_data(hob_list, len, &guid); +} diff --git a/arch/x86/lib/fsp1/fsp_support.c b/arch/x86/lib/fsp1/fsp_support.c index b5b7d664a1..c7a2c73846 100644 --- a/arch/x86/lib/fsp1/fsp_support.c +++ b/arch/x86/lib/fsp1/fsp_support.c @@ -197,170 +197,3 @@ u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase)
return status; } - -u32 fsp_get_usable_lowmem_top(const void *hob_list) -{ - const struct hob_header *hdr; - struct hob_res_desc *res_desc; - phys_addr_t phys_start; - u32 top; -#ifdef CONFIG_FSP_BROKEN_HOB - struct hob_mem_alloc *res_mem; - phys_addr_t mem_base = 0; -#endif - - /* Get the HOB list for processing */ - hdr = hob_list; - - /* * Collect memory ranges */ - top = FSP_LOWMEM_BASE; - while (!end_of_hob(hdr)) { - if (hdr->type == HOB_TYPE_RES_DESC) { - res_desc = (struct hob_res_desc *)hdr; - if (res_desc->type == RES_SYS_MEM) { - phys_start = res_desc->phys_start; - /* Need memory above 1MB to be collected here */ - if (phys_start >= FSP_LOWMEM_BASE && - phys_start < (phys_addr_t)FSP_HIGHMEM_BASE) - top += (u32)(res_desc->len); - } - } - -#ifdef CONFIG_FSP_BROKEN_HOB - /* - * Find out the lowest memory base address allocated by FSP - * for the boot service data - */ - if (hdr->type == HOB_TYPE_MEM_ALLOC) { - res_mem = (struct hob_mem_alloc *)hdr; - if (!mem_base) - mem_base = res_mem->mem_base; - if (res_mem->mem_base < mem_base) - mem_base = res_mem->mem_base; - } -#endif - - hdr = get_next_hob(hdr); - } - -#ifdef CONFIG_FSP_BROKEN_HOB - /* - * Check whether the memory top address is below the FSP HOB list. - * If not, use the lowest memory base address allocated by FSP as - * the memory top address. This is to prevent U-Boot relocation - * overwrites the important boot service data which is used by FSP, - * otherwise the subsequent call to fsp_notify() will fail. - */ - if (top > (u32)hob_list) { - debug("Adjust memory top address due to a buggy FSP\n"); - top = (u32)mem_base; - } -#endif - - return top; -} - -u64 fsp_get_usable_highmem_top(const void *hob_list) -{ - const struct hob_header *hdr; - struct hob_res_desc *res_desc; - phys_addr_t phys_start; - u64 top; - - /* Get the HOB list for processing */ - hdr = hob_list; - - /* Collect memory ranges */ - top = FSP_HIGHMEM_BASE; - while (!end_of_hob(hdr)) { - if (hdr->type == HOB_TYPE_RES_DESC) { - res_desc = (struct hob_res_desc *)hdr; - if (res_desc->type == RES_SYS_MEM) { - phys_start = res_desc->phys_start; - /* Need memory above 4GB to be collected here */ - if (phys_start >= (phys_addr_t)FSP_HIGHMEM_BASE) - top += (u32)(res_desc->len); - } - } - hdr = get_next_hob(hdr); - } - - return top; -} - -u64 fsp_get_reserved_mem_from_guid(const void *hob_list, u64 *len, - const efi_guid_t *guid) -{ - const struct hob_header *hdr; - struct hob_res_desc *res_desc; - - /* Get the HOB list for processing */ - hdr = hob_list; - - /* Collect memory ranges */ - while (!end_of_hob(hdr)) { - if (hdr->type == HOB_TYPE_RES_DESC) { - res_desc = (struct hob_res_desc *)hdr; - if (res_desc->type == RES_MEM_RESERVED) { - if (!guidcmp(&res_desc->owner, guid)) { - if (len) - *len = (u32)(res_desc->len); - - return (u64)(res_desc->phys_start); - } - } - } - hdr = get_next_hob(hdr); - } - - return 0; -} - -u32 fsp_get_fsp_reserved_mem(const void *hob_list, u32 *len) -{ - const efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_FSP_GUID; - u64 length; - u32 base; - - base = (u32)fsp_get_reserved_mem_from_guid(hob_list, - &length, &guid); - if ((len != 0) && (base != 0)) - *len = (u32)length; - - return base; -} - -u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len) -{ - const efi_guid_t guid = FSP_HOB_RESOURCE_OWNER_TSEG_GUID; - u64 length; - u32 base; - - base = (u32)fsp_get_reserved_mem_from_guid(hob_list, - &length, &guid); - if ((len != 0) && (base != 0)) - *len = (u32)length; - - return base; -} - -void *fsp_get_nvs_data(const void *hob_list, u32 *len) -{ - const efi_guid_t guid = FSP_NON_VOLATILE_STORAGE_HOB_GUID; - - return hob_get_guid_hob_data(hob_list, len, &guid); -} - -void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len) -{ - const efi_guid_t guid = FSP_BOOTLOADER_TEMP_MEM_HOB_GUID; - - return hob_get_guid_hob_data(hob_list, len, &guid); -} - -void *fsp_get_graphics_info(const void *hob_list, u32 *len) -{ - const efi_guid_t guid = FSP_GRAPHICS_INFO_HOB_GUID; - - return hob_get_guid_hob_data(hob_list, len, &guid); -}

At present these two functions are defined in efi_loader.h but only if CONFIG_EFI_LOADER is enabled. But these are functions that are useful to other code, such as that which deals with Intel Handoff Blocks (HOBs).
Move these to the top of the function.
Possibly ascii2unicode() should not be an inline function, since this might impact code size.
Signed-off-by: Simon Glass sjg@chromium.org --- In general it seems to be bad form to include parts of headers conditionally.
include/efi_loader.h | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-)
diff --git a/include/efi_loader.h b/include/efi_loader.h index 5298ea7997..82f236e295 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -12,6 +12,27 @@ #include <part_efi.h> #include <efi_api.h>
+/** + * ascii2unicode() - convert ASCII string to UTF-16 string + * + * A zero terminated ASCII string is converted to a zero terminated UTF-16 + * string. The output buffer must be preassigned. + * + * @unicode: preassigned output buffer for UTF-16 string + * @ascii: ASCII string to be converted + */ +static inline void ascii2unicode(u16 *unicode, const char *ascii) +{ + while (*ascii) + *(unicode++) = *(ascii++); + *unicode = 0; +} + +static inline int guidcmp(const void *g1, const void *g2) +{ + return memcmp(g1, g2, sizeof(efi_guid_t)); +} + /* No need for efi loader support in SPL */ #if CONFIG_IS_ENABLED(EFI_LOADER)
@@ -551,27 +572,6 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr, (((_dp)->type == DEVICE_PATH_TYPE_##_type) && \ ((_dp)->sub_type == DEVICE_PATH_SUB_TYPE_##_subtype))
-/** - * ascii2unicode() - convert ASCII string to UTF-16 string - * - * A zero terminated ASCII string is converted to a zero terminated UTF-16 - * string. The output buffer must be preassigned. - * - * @unicode: preassigned output buffer for UTF-16 string - * @ascii: ASCII string to be converted - */ -static inline void ascii2unicode(u16 *unicode, const char *ascii) -{ - while (*ascii) - *(unicode++) = *(ascii++); - *unicode = 0; -} - -static inline int guidcmp(const void *g1, const void *g2) -{ - return memcmp(g1, g2, sizeof(efi_guid_t)); -} - /* * Use these to indicate that your code / data should go into the EFI runtime * section and thus still be available when the OS is running

Add definitions for the FSP signature and the FSP init phase.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/fsp/fsp_infoheader.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/fsp/fsp_infoheader.h b/arch/x86/include/asm/fsp/fsp_infoheader.h index 86f78014b7..e72c052ed1 100644 --- a/arch/x86/include/asm/fsp/fsp_infoheader.h +++ b/arch/x86/include/asm/fsp/fsp_infoheader.h @@ -33,6 +33,19 @@ struct __packed fsp_header { #define FSP_HEADER_REVISION_1 1 #define FSP_HEADER_REVISION_2 2
-#define FSP_ATTR_GRAPHICS_SUPPORT (1 << 0) +enum fsp_type { + FSP_ATTR_COMP_TYPE_FSP_T = 1, + FSP_ATTR_COMP_TYPE_FSP_M = 2, + FSP_ATTR_COMP_TYPE_FSP_S = 3, +}; + +enum { + FSP_ATTR_GRAPHICS_SUPPORT = 1 << 0, + FSP_ATTR_COMP_TYPE_SHIFT = 28, + FSP_ATTR_COMP_TYPE_MASK = 0xfU << FSP_ATTR_COMP_TYPE_SHIFT, + +}; + +#define EFI_FSPH_SIGNATURE SIGNATURE_32('F', 'S', 'P', 'H')
#endif

With FSP2 the non-volatile storage used by the FSP to init memory can be split into a fixed piece (determined at compile time) and a variable piece (determined at run time). Add support for reading the latter.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/fsp/fsp_hob.h | 4 ++++ arch/x86/include/asm/fsp/fsp_support.h | 12 ++++++++++++ arch/x86/lib/fsp/fsp_support.c | 7 +++++++ 3 files changed, 23 insertions(+)
diff --git a/arch/x86/include/asm/fsp/fsp_hob.h b/arch/x86/include/asm/fsp/fsp_hob.h index 3bb79c4b67..d248520e97 100644 --- a/arch/x86/include/asm/fsp/fsp_hob.h +++ b/arch/x86/include/asm/fsp/fsp_hob.h @@ -69,6 +69,10 @@ struct __packed hob_graphics_info { EFI_GUID(0x721acf02, 0x4d77, 0x4c2a, \ 0xb3, 0xdc, 0x27, 0x0b, 0x7b, 0xa9, 0xe4, 0xb0)
+#define FSP_VARIABLE_NV_DATA_HOB_GUID \ + EFI_GUID(0xa034147d, 0x690c, 0x4154, \ + 0x8d, 0xe6, 0xc0, 0x44, 0x64, 0x1d, 0xe9, 0x42) + #define FSP_BOOTLOADER_TEMP_MEM_HOB_GUID \ EFI_GUID(0xbbcff46c, 0xc8d3, 0x4113, \ 0x89, 0x85, 0xb9, 0xd4, 0xf3, 0xb3, 0xf6, 0x4e) diff --git a/arch/x86/include/asm/fsp/fsp_support.h b/arch/x86/include/asm/fsp/fsp_support.h index 6320fe0906..4f93cb2a13 100644 --- a/arch/x86/include/asm/fsp/fsp_support.h +++ b/arch/x86/include/asm/fsp/fsp_support.h @@ -106,6 +106,18 @@ u32 fsp_get_tseg_reserved_mem(const void *hob_list, u32 *len); */ void *fsp_get_nvs_data(const void *hob_list, u32 *len);
+/** + * fsp_get_var_nvs_data() - get FSP variable Non-volatile Storage HOB buffer + * + * @hob_list: A HOB list pointer. + * @len: A pointer to the NVS data buffer length. + * If the HOB is located, the length will be updated. + * + * @return NULL: Failed to find the NVS HOB. + * @return others: FSP NVS data buffer pointer. + */ +void *fsp_get_var_nvs_data(const void *hob_list, u32 *len); + /** * fsp_get_graphics_info() - retrieves graphics information. * diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c index 014de35e56..82c59befd9 100644 --- a/arch/x86/lib/fsp/fsp_support.c +++ b/arch/x86/lib/fsp/fsp_support.c @@ -161,6 +161,13 @@ void *fsp_get_nvs_data(const void *hob_list, u32 *len) return hob_get_guid_hob_data(hob_list, len, &guid); }
+void *fsp_get_var_nvs_data(const void *hob_list, u32 *len) +{ + const struct efi_guid guid = FSP_VARIABLE_NV_DATA_HOB_GUID; + + return hob_get_guid_hob_data(hob_list, len, &guid); +} + void *fsp_get_bootloader_tmp_mem(const void *hob_list, u32 *len) { const efi_guid_t guid = FSP_BOOTLOADER_TEMP_MEM_HOB_GUID;

Add cpu_intel_get_info() to find out the CPU info on modern Intel CPUs.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/broadwell/cpu_full.c | 9 +-------- arch/x86/cpu/intel_common/cpu.c | 13 +++++++++++++ arch/x86/cpu/ivybridge/model_206ax.c | 8 ++------ arch/x86/include/asm/cpu_common.h | 11 +++++++++++ 4 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c index c1db184549..d8b8482658 100644 --- a/arch/x86/cpu/broadwell/cpu_full.c +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -645,14 +645,7 @@ void cpu_set_power_limits(int power_limit_1_time)
static int broadwell_get_info(struct udevice *dev, struct cpu_info *info) { - msr_t msr; - - msr = msr_read(IA32_PERF_CTL); - info->cpu_freq = ((msr.lo >> 8) & 0xff) * BROADWELL_BCLK * 1000000; - info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU | - 1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID; - - return 0; + return cpu_intel_get_info(info, BROADWELL_BCLK); }
static int broadwell_get_count(struct udevice *dev) diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c index d0ac17808c..9357626b5a 100644 --- a/arch/x86/cpu/intel_common/cpu.c +++ b/arch/x86/cpu/intel_common/cpu.c @@ -4,6 +4,7 @@ */
#include <common.h> +#include <cpu.h> #include <dm.h> #include <errno.h> #include <asm/cpu_common.h> @@ -110,3 +111,15 @@ int cpu_set_flex_ratio_to_tdp_nominal(void) /* Not reached */ return -EINVAL; } + +int cpu_intel_get_info(struct cpu_info *info, int bclk) +{ + msr_t msr; + + msr = msr_read(IA32_PERF_CTL); + info->cpu_freq = ((msr.lo >> 8) & 0xff) * bclk * 1000000; + info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU | + 1 << CPU_FEAT_UCODE | 1 << CPU_FEAT_DEVICE_ID; + + return 0; +} diff --git a/arch/x86/cpu/ivybridge/model_206ax.c b/arch/x86/cpu/ivybridge/model_206ax.c index 6edc3e233c..68e78e9478 100644 --- a/arch/x86/cpu/ivybridge/model_206ax.c +++ b/arch/x86/cpu/ivybridge/model_206ax.c @@ -12,6 +12,7 @@ #include <fdtdec.h> #include <malloc.h> #include <asm/cpu.h> +#include <asm/cpu_common.h> #include <asm/cpu_x86.h> #include <asm/msr.h> #include <asm/msr-index.h> @@ -436,12 +437,7 @@ static int model_206ax_init(struct udevice *dev)
static int model_206ax_get_info(struct udevice *dev, struct cpu_info *info) { - msr_t msr; - - msr = msr_read(MSR_IA32_PERF_CTL); - info->cpu_freq = ((msr.lo >> 8) & 0xff) * SANDYBRIDGE_BCLK * 1000000; - info->features = 1 << CPU_FEAT_L1_CACHE | 1 << CPU_FEAT_MMU | - 1 << CPU_FEAT_UCODE; + return cpu_intel_get_info(info, SANDYBRIDGE_BCLK);
return 0; } diff --git a/arch/x86/include/asm/cpu_common.h b/arch/x86/include/asm/cpu_common.h index 4c91a5dace..0d560262d5 100644 --- a/arch/x86/include/asm/cpu_common.h +++ b/arch/x86/include/asm/cpu_common.h @@ -8,6 +8,8 @@
#define IA32_PERF_CTL 0x199
+struct cpu_info; + /** * cpu_common_init() - Set up common CPU init * @@ -31,4 +33,13 @@ int cpu_common_init(void); */ int cpu_set_flex_ratio_to_tdp_nominal(void);
+/** + * cpu_intel_get_info() - Obtain CPU info for Intel CPUs + * + * Most Intel CPUs use the same MSR to obtain the clock speed, and use the same + * features. This function fills in these values, given the value of the base + * clock in MHz (typically this should be set to 100). + */ +int cpu_intel_get_info(struct cpu_info *info, int bclk_mz); + #endif

It is useful in SPL and TPL to access symbols from binman, such as the position and size of an entry in the ROM. Collect these symbols together in the SPL binaries.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/u-boot-spl.lds | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/x86/cpu/u-boot-spl.lds b/arch/x86/cpu/u-boot-spl.lds index f20c0b810d..c1e9bfbf66 100644 --- a/arch/x86/cpu/u-boot-spl.lds +++ b/arch/x86/cpu/u-boot-spl.lds @@ -35,6 +35,12 @@ SECTIONS . = ALIGN(4); __data_end = .; __init_end = .; + . = ALIGN(4); + .binman_sym_table : { + __binman_sym_start = .; + KEEP(*(SORT(.binman_sym*))); + __binman_sym_end = .; + }
_image_binary_end = .;

At present the x86 pre-DM equivalent of pci_bus_clrset_config32() does not exist. Add it to simplify PCI init code on x86.
Also add the missing functions to this header.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/pci.c | 19 ++++++++++++++++++ arch/x86/include/asm/pci.h | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+)
diff --git a/arch/x86/cpu/pci.c b/arch/x86/cpu/pci.c index c6218250e1..0ccde194d9 100644 --- a/arch/x86/cpu/pci.c +++ b/arch/x86/cpu/pci.c @@ -16,6 +16,10 @@ #include <asm/io.h> #include <asm/pci.h>
+/* + * TODO(sjg@chromium.org): Drop the first parameter from each of these + * functions since it is not used. + */ int pci_x86_read_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep, enum pci_size_t size) { @@ -54,6 +58,21 @@ int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, return 0; }
+int pci_x86_clrset_config(struct udevice *bus, pci_dev_t bdf, uint offset, + ulong clr, ulong set, enum pci_size_t size) +{ + ulong value; + int ret; + + ret = pci_x86_read_config(bus, bdf, offset, &value, size); + if (ret) + return ret; + value &= ~clr; + value |= set; + + return pci_x86_write_config(bus, bdf, offset, value, size); +} + void pci_assign_irqs(int bus, int device, u8 irq[4]) { pci_dev_t bdf; diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index 118ac937d9..fb1edf3df7 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -17,12 +17,52 @@
#ifndef __ASSEMBLY__
+/** + * pci_x86_read_config() - Read a configuration value from a device + * + * This function can be called before PCI is set up in driver model. + * + * @bus: Bus to read from (ignored, can be NULL) + * @bdf: PCI device address: bus, device and function -see PCI_BDF() + * @offset: Register offset to read + * @valuep: Place to put the returned value + * @size: Access size + * @return 0 if OK, -ve on error + */ int pci_x86_read_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong *valuep, enum pci_size_t size);
+/** + * pci_bus_write_config() - Write a configuration value to a device + * + * This function can be called before PCI is set up in driver model. + * + * @bus: Bus to read from (ignored, can be NULL) + * @bdf: PCI device address: bus, device and function -see PCI_BDF() + * @offset: Register offset to write + * @value: Value to write + * @size: Access size + * @return 0 if OK, -ve on error + */ int pci_x86_write_config(struct udevice *bus, pci_dev_t bdf, uint offset, ulong value, enum pci_size_t size);
+/** + * pci_bus_clrset_config32() - Update a configuration value for a device + * + * The register at @offset is updated to (oldvalue & ~clr) | set. This function + * can be called before PCI is set up in driver model. + * + * @bus: Bus to read from (ignored, can be NULL) + * @bdf: PCI device address: bus, device and function -see PCI_BDF() + * @offset: Register offset to update + * @clr: Bits to clear + * @set: Bits to set + * @return 0 if OK, -ve on error + */ +int pci_x86_clrset_config(struct udevice *bus, pci_dev_t bdf, uint offset, + ulong clr, ulong set, enum pci_size_t size); + /** * Assign IRQ number to a PCI device *

Use the standard hang() function when booting fails since this implements the defined U-Boot behaviour for this situation.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/lib/spl.c | 3 +-- arch/x86/lib/tpl.c | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c index 5d5d1a9ca7..01a96d294b 100644 --- a/arch/x86/lib/spl.c +++ b/arch/x86/lib/spl.c @@ -183,8 +183,7 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) printf("Jumping to 64-bit U-Boot: Note many features are missing\n"); ret = cpu_jump_to_64bit_uboot(spl_image->entry_point); debug("ret=%d\n", ret); - while (1) - ; + hang(); } #endif
diff --git a/arch/x86/lib/tpl.c b/arch/x86/lib/tpl.c index 492a2d6521..3e662a8bda 100644 --- a/arch/x86/lib/tpl.c +++ b/arch/x86/lib/tpl.c @@ -108,8 +108,7 @@ void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image) { printf("Jumping to U-Boot SPL at %lx\n", (ulong)spl_image->entry_point); jump_to_spl(spl_image->entry_point); - while (1) - ; + hang(); }
void spl_board_init(void)

This image loader works on systems where the flash is directly mapped to the last part of the 32-bit address space. On recent Intel systems (such as apollolake) this is not the case.
Reduce the priority of this loader so that another one can override it.
While we are here, rename the loader to BOOT_DEVICE_SPI_MMAP since BOOT_DEVICE_BOARD is not very descriptive.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/spl.h | 3 +-- arch/x86/lib/spl.c | 5 +++-- arch/x86/lib/tpl.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/arch/x86/include/asm/spl.h b/arch/x86/include/asm/spl.h index 27432b2897..1bef4877eb 100644 --- a/arch/x86/include/asm/spl.h +++ b/arch/x86/include/asm/spl.h @@ -10,8 +10,7 @@ #define CONFIG_SPL_BOARD_LOAD_IMAGE
enum { - BOOT_DEVICE_SPI = 10, - BOOT_DEVICE_BOARD, + BOOT_DEVICE_SPI_MMAP = 10, BOOT_DEVICE_CROS_VBOOT, };
diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c index 01a96d294b..a739491303 100644 --- a/arch/x86/lib/spl.c +++ b/arch/x86/lib/spl.c @@ -11,6 +11,7 @@ #include <asm/mrccache.h> #include <asm/mtrr.h> #include <asm/processor.h> +#include <asm/spl.h> #include <asm-generic/sections.h>
DECLARE_GLOBAL_DATA_PTR; @@ -142,7 +143,7 @@ void board_init_f_r(void)
u32 spl_boot_device(void) { - return BOOT_DEVICE_BOARD; + return BOOT_DEVICE_SPI_MMAP; }
int spl_start_uboot(void) @@ -168,7 +169,7 @@ static int spl_board_load_image(struct spl_image_info *spl_image,
return 0; } -SPL_LOAD_IMAGE_METHOD("SPI", 0, BOOT_DEVICE_BOARD, spl_board_load_image); +SPL_LOAD_IMAGE_METHOD("SPI", 5, BOOT_DEVICE_SPI_MMAP, spl_board_load_image);
int spl_spi_load_image(void) { diff --git a/arch/x86/lib/tpl.c b/arch/x86/lib/tpl.c index 3e662a8bda..cfefa78045 100644 --- a/arch/x86/lib/tpl.c +++ b/arch/x86/lib/tpl.c @@ -71,7 +71,7 @@ void board_init_f_r(void) u32 spl_boot_device(void) { return IS_ENABLED(CONFIG_CHROMEOS) ? BOOT_DEVICE_CROS_VBOOT : - BOOT_DEVICE_BOARD; + BOOT_DEVICE_SPI_MMAP; }
int spl_start_uboot(void) @@ -97,7 +97,7 @@ static int spl_board_load_image(struct spl_image_info *spl_image,
return 0; } -SPL_LOAD_IMAGE_METHOD("SPI", 0, BOOT_DEVICE_BOARD, spl_board_load_image); +SPL_LOAD_IMAGE_METHOD("SPI", 5, BOOT_DEVICE_SPI_MMAP, spl_board_load_image);
int spl_spi_load_image(void) {

When TPL is running, broadwell needs to do different init from SPL. There is no need for this code to be in the generic x86 SPL file, so move it to arch_cpu_init().
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/broadwell/cpu.c | 5 +++++ arch/x86/cpu/broadwell/cpu_full.c | 7 +++++++ arch/x86/lib/spl.c | 5 ----- 3 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/arch/x86/cpu/broadwell/cpu.c b/arch/x86/cpu/broadwell/cpu.c index bb7c361408..bba8cd1e94 100644 --- a/arch/x86/cpu/broadwell/cpu.c +++ b/arch/x86/cpu/broadwell/cpu.c @@ -67,7 +67,12 @@ int arch_cpu_init(void) { post_code(POST_CPU_INIT);
+#ifdef CONFIG_TPL + /* Do a mini-init if TPL has already done the full init */ + return x86_cpu_reinit_f(); +#else return x86_cpu_init_f(); +#endif }
int checkcpu(void) diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c index d8b8482658..bd0b2037fa 100644 --- a/arch/x86/cpu/broadwell/cpu_full.c +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -81,6 +81,13 @@ static const u8 power_limit_time_msr_to_sec[] = { [0x11] = 128, };
+#if defined(CONFIG_SPL_BUILD) && !defined(CONFIG_TPL_BUILD) +int arch_cpu_init(void) +{ + return 0; +} +#endif + /* * The core 100MHz BLCK is disabled in deeper c-states. One needs to calibrate * the 100MHz BCLCK against the 24MHz BLCK to restore the clocks properly diff --git a/arch/x86/lib/spl.c b/arch/x86/lib/spl.c index a739491303..2baac91383 100644 --- a/arch/x86/lib/spl.c +++ b/arch/x86/lib/spl.c @@ -40,12 +40,7 @@ static int x86_spl_init(void) debug("%s: spl_init() failed\n", __func__); return ret; } -#ifdef CONFIG_TPL - /* Do a mini-init if TPL has already done the full init */ - ret = x86_cpu_reinit_f(); -#else ret = arch_cpu_init(); -#endif if (ret) { debug("%s: arch_cpu_init() failed\n", __func__); return ret;

The useable RAM is calculated when the RAM is inited. Save this value so that it can be easily used in U-Boot proper.
Also save a pointer to the hob list so that it is accessible (before relocation only) in U-Boot proper. This avoids having to scan it in SPL, for everything U-Boot proper might need later.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/intel_common/cpu_from_spl.c | 6 ++++++ arch/x86/include/asm/handoff.h | 8 ++++++++ arch/x86/lib/fsp/fsp_dram.c | 10 ++++++++++ 3 files changed, 24 insertions(+)
diff --git a/arch/x86/cpu/intel_common/cpu_from_spl.c b/arch/x86/cpu/intel_common/cpu_from_spl.c index a6233c75ce..b7bb524162 100644 --- a/arch/x86/cpu/intel_common/cpu_from_spl.c +++ b/arch/x86/cpu/intel_common/cpu_from_spl.c @@ -6,6 +6,7 @@ #include <common.h> #include <dm.h> #include <errno.h> +#include <handoff.h> #include <asm/cpu_common.h> #include <asm/intel_regs.h> #include <asm/lapic.h> @@ -21,6 +22,11 @@ int arch_cpu_init(void) { int ret;
+#if CONFIG_IS_ENABLED(HANDOFF) && IS_ENABLED(CONFIG_USE_HOB) + struct spl_handoff *ho = gd->spl_handoff; + + gd->arch.hob_list = ho->arch.hob_list; +#endif ret = x86_cpu_reinit_f();
return ret; diff --git a/arch/x86/include/asm/handoff.h b/arch/x86/include/asm/handoff.h index 4d18d59efe..aec49b9b81 100644 --- a/arch/x86/include/asm/handoff.h +++ b/arch/x86/include/asm/handoff.h @@ -9,7 +9,15 @@ #ifndef __x86_asm_handoff_h #define __x86_asm_handoff_h
+/** + * struct arch_spl_handoff - architecture-specific handoff info + * + * @usable_ram_top: Value returned by board_get_usable_ram_top() in SPL + * @hob_list: Start of FSP hand-off blocks (HOBs) + */ struct arch_spl_handoff { + ulong usable_ram_top; + void *hob_list; };
#endif diff --git a/arch/x86/lib/fsp/fsp_dram.c b/arch/x86/lib/fsp/fsp_dram.c index 8fe1e0bf73..38cc25839e 100644 --- a/arch/x86/lib/fsp/fsp_dram.c +++ b/arch/x86/lib/fsp/fsp_dram.c @@ -88,3 +88,13 @@ unsigned int install_e820_map(unsigned int max_entries,
return num_entries; } + +#if CONFIG_IS_ENABLED(HANDOFF) +int handoff_arch_save(struct spl_handoff *ho) +{ + ho->arch.usable_ram_top = fsp_get_usable_lowmem_top(gd->arch.hob_list); + ho->arch.hob_list = gd->arch.hob_list; + + return 0; +} +#endif

Allocate memory for the HOBs and copy them before relocation. This ensures that they can still be accessed after relocation.
This is needed when relocating the HOB within U-Boot.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/cpu.c | 6 ++++++ arch/x86/include/asm/fsp/fsp_support.h | 8 ++++++++ arch/x86/include/asm/hob.h | 8 ++++++++ arch/x86/lib/fsp/fsp_support.c | 16 ++++++++++++++++ arch/x86/lib/hob.c | 11 +++++++++++ 5 files changed, 49 insertions(+)
diff --git a/arch/x86/cpu/cpu.c b/arch/x86/cpu/cpu.c index 290ee084e5..e0b24c8df2 100644 --- a/arch/x86/cpu/cpu.c +++ b/arch/x86/cpu/cpu.c @@ -42,6 +42,9 @@ #include <asm/interrupt.h> #include <asm/tables.h> #include <linux/compiler.h> +#ifdef CONFIG_HAVE_FSP +#include <asm/fsp/fsp_support.h> +#endif
DECLARE_GLOBAL_DATA_PTR;
@@ -262,6 +265,9 @@ int reserve_arch(void) #ifdef CONFIG_ENABLE_MRC_CACHE mrccache_reserve(); #endif +#ifdef CONFIG_HAVE_FSP + fsp_reserve(); +#endif
#ifdef CONFIG_SEABIOS high_table_reserve(); diff --git a/arch/x86/include/asm/fsp/fsp_support.h b/arch/x86/include/asm/fsp/fsp_support.h index 4f93cb2a13..2424bc1f5f 100644 --- a/arch/x86/include/asm/fsp/fsp_support.h +++ b/arch/x86/include/asm/fsp/fsp_support.h @@ -163,4 +163,12 @@ void *fsp_prepare_mrc_cache(void); */ u32 fsp_notify(struct fsp_header *fsp_hdr, u32 phase);
+/** + * fsp_reserve() - Relocation the HOBs + * + * Make space for the HOBs in the new memory and copy them there. This must be + * called from board_init_f() along with the 'reserve' functions. + */ +void fsp_reserve(void); + #endif diff --git a/arch/x86/include/asm/hob.h b/arch/x86/include/asm/hob.h index 72151ea045..6b00d24071 100644 --- a/arch/x86/include/asm/hob.h +++ b/arch/x86/include/asm/hob.h @@ -227,4 +227,12 @@ const struct hob_header *hob_get_next_guid_hob(const efi_guid_t *guid, void *hob_get_guid_hob_data(const void *hob_list, u32 *len, const efi_guid_t *guid);
+/** + * hob_get_size() - Get the total size of the HOB data + * + * This scans the list and returns the number of bytes oocupied by the HOB list. + * This can be used to copy the list to somewhere else in memory. + */ +uint hob_get_size(const void *hob_list); + #endif /* __HOB_H__ */ diff --git a/arch/x86/lib/fsp/fsp_support.c b/arch/x86/lib/fsp/fsp_support.c index 82c59befd9..0f0c41fbf8 100644 --- a/arch/x86/lib/fsp/fsp_support.c +++ b/arch/x86/lib/fsp/fsp_support.c @@ -181,3 +181,19 @@ void *fsp_get_graphics_info(const void *hob_list, u32 *len)
return hob_get_guid_hob_data(hob_list, len, &guid); } + +void fsp_reserve(void) +{ + void *new_hobs; + uint hob_size; + + hob_size = hob_get_size(gd->arch.hob_list); + gd->start_addr_sp -= hob_size; + new_hobs = (void *)gd->start_addr_sp; + memcpy(new_hobs, gd->arch.hob_list, hob_size); + + gd->start_addr_sp &= ~0xf; + debug("Copying FSP HOBs from %p to %p, size %x\n", gd->arch.hob_list, + new_hobs, hob_size); + gd->arch.hob_list = new_hobs; +} diff --git a/arch/x86/lib/hob.c b/arch/x86/lib/hob.c index f2c47240ee..43c53f4bbb 100644 --- a/arch/x86/lib/hob.c +++ b/arch/x86/lib/hob.c @@ -82,3 +82,14 @@ void *hob_get_guid_hob_data(const void *hob_list, u32 *len,
return get_guid_hob_data(guid_hob); } + +uint hob_get_size(const void *hob_list) +{ + const struct hob_header *hdr; + + for (hdr = hob_list; !end_of_hob(hdr); hdr = get_next_hob(hdr)) + ; + hdr++; + + return (void *)hdr - hob_list; +}

At present we assume that CAR (Cache-as-RAM) is used if HOBs (Hand-off bLocks) are not, since HOBs typically indicate that an FSP is in use, and FSPs handle the CAR init.
However this is a bit indirect, and for FSP2 machines which use their own CAR implementation (such as apollolake) but use the FSP for other functions, the logic is wrong.
To fix this, add a dedicated Kconfig option to indicate when CAR is used.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/Kconfig | 8 ++++++++ arch/x86/cpu/start.S | 4 ++-- configs/slimbootloader_defconfig | 1 + 3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 314f8def7a..47bf28c434 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -364,6 +364,14 @@ config HAVE_FSP Note: Without this binary U-Boot will not be able to set up its SDRAM so will not boot.
+config USE_CAR + bool "Use Cache-As-RAM (CAR) to get temporary RAM at start-up" + default y if !HAVE_FSP + help + Select this option if your board uses CAR init code, typically in a + car.S file, to get some initial memory for code execution. This is + common with Intel CPUs which don't use FSP. + choice prompt "FSP version" depends on HAVE_FSP diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 3c9bdf2a9d..9b76394274 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -90,7 +90,7 @@ early_board_init_ret: jmp car_init .globl car_init_ret car_init_ret: -#ifndef CONFIG_USE_HOB +#ifdef CONFIG_USE_CAR /* * We now have CONFIG_SYS_CAR_SIZE bytes of Cache-As-RAM (or SRAM, * or fully initialised SDRAM - we really don't care which) @@ -130,7 +130,7 @@ car_init_ret:
/* Get address of global_data */ mov %fs:0, %edx -#ifdef CONFIG_USE_HOB +#if defined(CONFIG_USE_HOB) && !defined(CONFIG_USE_CAR) /* Store the HOB list if we have one */ test %esi, %esi jz skip_hob diff --git a/configs/slimbootloader_defconfig b/configs/slimbootloader_defconfig index f9fecff45e..3cbb83c7a4 100644 --- a/configs/slimbootloader_defconfig +++ b/configs/slimbootloader_defconfig @@ -18,3 +18,4 @@ CONFIG_REGMAP=y CONFIG_SYSCON=y # CONFIG_PCI_PNP is not set CONFIG_CONSOLE_SCROLL_LINES=5 +# CONFIG_USE_CAR is not set

The full start-up sequence (TPL->SPL->U-Boot) can be a bit confusing since each phase has its own 'start' file. Add comments to explain this.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/start.S | 12 ++++++++++++ arch/x86/cpu/start_from_spl.S | 5 +++-- arch/x86/cpu/start_from_tpl.S | 3 ++- 3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/arch/x86/cpu/start.S b/arch/x86/cpu/start.S index 9b76394274..01524635e9 100644 --- a/arch/x86/cpu/start.S +++ b/arch/x86/cpu/start.S @@ -2,6 +2,18 @@ /* * U-Boot - x86 Startup Code * + * This is always the first code to run from the U-Boot source. To spell it out: + * + * 1. When TPL (Tertiary Program Loader) is enabled, the boot flow is + * TPL->SPL->U-Boot and this file is used for TPL. Then start_from_tpl.S is used + * for SPL and start_from_spl.S is used for U-Boot proper. + * + * 2. When SPL (Secondary Program Loader) is enabled, but not TPL, the boot + * flow is SPL->U-Boot and this file is used for SPL. Then start_from_spl.S is + * used for U-Boot proper. + * + * 3. When neither TPL nor SPL is used, this file is used for U-Boot proper. + * * (C) Copyright 2008-2011 * Graeme Russ, graeme.russ@gmail.com * diff --git a/arch/x86/cpu/start_from_spl.S b/arch/x86/cpu/start_from_spl.S index 4d4e5d0758..a73b4d7c45 100644 --- a/arch/x86/cpu/start_from_spl.S +++ b/arch/x86/cpu/start_from_spl.S @@ -1,7 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * 32-bit x86 Startup Code when running from SPL - * + * 32-bit x86 Startup Code when running from SPL. This is the startup code in + * U-Boot proper, when SPL is used. + * Copyright 2018 Google, Inc * Written by Simon Glass sjg@chromium.org */ diff --git a/arch/x86/cpu/start_from_tpl.S b/arch/x86/cpu/start_from_tpl.S index 44b5363a68..9a4974a5f1 100644 --- a/arch/x86/cpu/start_from_tpl.S +++ b/arch/x86/cpu/start_from_tpl.S @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * 32-bit x86 Startup Code when running from TPL + * 32-bit x86 Startup Code when running from TPL. This is the startup code in + * SPL, when TPL is used. * * Copyright 2018 Google, Inc * Written by Simon Glass sjg@chromium.org

Most x86 CPUs use a mechanism where the SPI flash is mapped into the very top of 32-bit address space, so that it can be executed in place and read simply by copying from memory. For an 8MB ROM the mapping starts at 0xff800000.
However some recent Intel CPUs do not use a simple 1:1 memory map. Instead the map starts at a different address and not all of the SPI flash is accessible through the map. This 'Fast SPI' feature requires that U-Boot check the location of the map. It is also possible (optionally) to read from the SPI flash using a driver.
Add support for booting from Fast SPI. The memory-mapped version is used by both TPL and SPL on apollolake.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/intel_common/Makefile | 1 + arch/x86/cpu/intel_common/fast_spi.c | 48 ++++++++++++++++++++++++++++ arch/x86/include/asm/spl.h | 1 + 3 files changed, 50 insertions(+) create mode 100644 arch/x86/cpu/intel_common/fast_spi.c
diff --git a/arch/x86/cpu/intel_common/Makefile b/arch/x86/cpu/intel_common/Makefile index 07f27c29ec..2de567dd9f 100644 --- a/arch/x86/cpu/intel_common/Makefile +++ b/arch/x86/cpu/intel_common/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += report_platform.o obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += mrc.o endif obj-y += cpu.o +obj-$(CONFIG_SPI_FLASH_INTEL_FAST) += fast_spi.o obj-y += lpc.o ifndef CONFIG_TARGET_EFI_APP obj-$(CONFIG_$(SPL_TPL_)X86_32BIT_INIT) += microcode.o diff --git a/arch/x86/cpu/intel_common/fast_spi.c b/arch/x86/cpu/intel_common/fast_spi.c new file mode 100644 index 0000000000..dce3d61b07 --- /dev/null +++ b/arch/x86/cpu/intel_common/fast_spi.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Google LLC + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/pci.h> +#include <asm/arch/fast_spi_def.h> +#include <asm/arch/pch.h> + +/* + * Returns bios_start and fills in size of the BIOS region. + */ +ulong fast_spi_get_bios_region(struct fast_spi_regs *regs, size_t *bios_size) +{ + ulong bios_start, bios_end; + + /* + * BIOS_BFPREG provides info about BIOS-Flash Primary Region Base and + * Limit. Base and Limit fields are in units of 4K. + */ + u32 val = readl(®s->bfp); + + bios_start = (val & SPIBAR_BFPREG_PRB_MASK) << 12; + bios_end = (((val & SPIBAR_BFPREG_PRL_MASK) >> + SPIBAR_BFPREG_PRL_SHIFT) + 1) << 12; + *bios_size = bios_end - bios_start; + + return bios_start; +} + +int fast_spi_get_bios_mmap(ulong *map_basep, size_t *map_sizep, uint *offsetp) +{ + struct fast_spi_regs *regs; + ulong bar, base, mmio_base; + + /* Special case to find mapping without probing the device */ + pci_x86_read_config(NULL, PCH_DEV_SPI, PCI_BASE_ADDRESS_0, &bar, + PCI_SIZE_32); + mmio_base = bar & PCI_BASE_ADDRESS_MEM_MASK; + regs = (struct fast_spi_regs *)mmio_base; + base = fast_spi_get_bios_region(regs, map_sizep); + *map_basep = (u32)-*map_sizep - base; + *offsetp = base; + + return 0; +} diff --git a/arch/x86/include/asm/spl.h b/arch/x86/include/asm/spl.h index 1bef4877eb..cc6cac08f2 100644 --- a/arch/x86/include/asm/spl.h +++ b/arch/x86/include/asm/spl.h @@ -11,6 +11,7 @@
enum { BOOT_DEVICE_SPI_MMAP = 10, + BOOT_DEVICE_FAST_SPI, BOOT_DEVICE_CROS_VBOOT, };

Add some new MTRRs used by Apollolake as well as a mask for the MTRR type.
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/include/asm/msr-index.h | 22 ++++++++++++++++++++++ arch/x86/include/asm/mtrr.h | 1 + 2 files changed, 23 insertions(+)
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 9c1dbe61d5..1a02d8c8fe 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -43,6 +43,12 @@ #define MSR_PIC_MSG_CONTROL 0x2e #define PLATFORM_INFO_SET_TDP (1 << 29)
+#define MSR_MTRR_CAP_MSR 0x0fe +#define MSR_MTRR_CAP_SMRR (1 << 11) +#define MSR_MTRR_CAP_WC (1 << 10) +#define MSR_MTRR_CAP_FIX (1 << 8) +#define MSR_MTRR_CAP_VCNT 0xff + #define MSR_IA32_PERFCTR0 0x000000c1 #define MSR_IA32_PERFCTR1 0x000000c2 #define MSR_FSB_FREQ 0x000000cd @@ -67,6 +73,11 @@ #define ENABLE_ULFM_AUTOCM_MASK (1 << 2) #define ENABLE_INDP_AUTOCM_MASK (1 << 3)
+#define MSR_EMULATE_PM_TIMER 0x121 +#define EMULATE_DELAY_OFFSET_VALUE 20 +#define EMULATE_PM_TMR_EN (1 << 16) +#define EMULATE_DELAY_VALUE 0x13 + #define MSR_IA32_SYSENTER_CS 0x00000174 #define MSR_IA32_SYSENTER_ESP 0x00000175 #define MSR_IA32_SYSENTER_EIP 0x00000176 @@ -78,9 +89,14 @@ #define MSR_FLEX_RATIO 0x194 #define FLEX_RATIO_LOCK (1 << 20) #define FLEX_RATIO_EN (1 << 16) +/* This is burst mode BIT 38 in IA32_MISC_ENABLE MSR at offset 1A0h */ +#define BURST_MODE_DISABLE (1 << 6)
#define MSR_IA32_MISC_ENABLES 0x000001a0 #define MSR_TEMPERATURE_TARGET 0x1a2 +#define MSR_PREFETCH_CTL 0x1a4 +#define PREFETCH_L1_DISABLE (1 << 0) +#define PREFETCH_L2_DISABLE (1 << 2) #define MSR_OFFCORE_RSP_0 0x000001a6 #define MSR_OFFCORE_RSP_1 0x000001a7 #define MSR_MISC_PWR_MGMT 0x1aa @@ -600,6 +616,12 @@ #define MSR_IA32_VMX_TRUE_ENTRY_CTLS 0x00000490 #define MSR_IA32_VMX_VMFUNC 0x00000491
+#define MSR_IA32_PQR_ASSOC 0xc8f +/* MSR bits 33:32 encode slot number 0-3 */ +#define MSR_IA32_PQR_ASSOC_MASK (1 << 0 | 1 << 1) + +#define MSR_L2_QOS_MASK(reg) (0xd10 + (reg)) + /* VMX_BASIC bits and bitmasks */ #define VMX_BASIC_VMCS_SIZE_SHIFT 32 #define VMX_BASIC_64 0x0001000000000000LLU diff --git a/arch/x86/include/asm/mtrr.h b/arch/x86/include/asm/mtrr.h index 2d897f82ef..6f29e75ce6 100644 --- a/arch/x86/include/asm/mtrr.h +++ b/arch/x86/include/asm/mtrr.h @@ -25,6 +25,7 @@ #define MTRR_CAP_FIX (1 << 8) #define MTRR_CAP_VCNT_MASK 0xff
+#define MTRR_DEF_TYPE_MASK 0xff #define MTRR_DEF_TYPE_EN (1 << 11) #define MTRR_DEF_TYPE_FIX_EN (1 << 10)

This MSR number is used on most modern Intel processors, so drop the confusing NHM prefix (which might mean Nehalem).
Signed-off-by: Simon Glass sjg@chromium.org ---
arch/x86/cpu/broadwell/cpu_full.c | 2 +- arch/x86/include/asm/msr-index.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/x86/cpu/broadwell/cpu_full.c b/arch/x86/cpu/broadwell/cpu_full.c index bd0b2037fa..9686cf5e0e 100644 --- a/arch/x86/cpu/broadwell/cpu_full.c +++ b/arch/x86/cpu/broadwell/cpu_full.c @@ -346,7 +346,7 @@ static void set_max_ratio(void)
/* Check for configurable TDP option */ if (turbo_get_state() == TURBO_ENABLED) { - msr = msr_read(MSR_NHM_TURBO_RATIO_LIMIT); + msr = msr_read(MSR_TURBO_RATIO_LIMIT); perf_ctl.lo = (msr.lo & 0xff) << 8; } else if (cpu_config_tdp_levels()) { /* Set to nominal TDP ratio */ diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 1a02d8c8fe..7cb78beafa 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -101,7 +101,7 @@ #define MSR_OFFCORE_RSP_1 0x000001a7 #define MSR_MISC_PWR_MGMT 0x1aa #define MISC_PWR_MGMT_EIST_HW_DIS (1 << 0) -#define MSR_NHM_TURBO_RATIO_LIMIT 0x000001ad +#define MSR_TURBO_RATIO_LIMIT 0x000001ad #define MSR_IVT_TURBO_RATIO_LIMIT 0x000001ae
#define MSR_IA32_ENERGY_PERFORMANCE_BIAS 0x1b0
participants (2)
-
Bin Meng
-
Simon Glass