[U-Boot] [PATCH v5 094/101] x86: apl: Add SPL loaders

Bin Meng bmeng.cn at gmail.com
Mon Dec 2 08:06:53 CET 2019


Hi Simon,

On Mon, Nov 25, 2019 at 12:12 PM Simon Glass <sjg at chromium.org> wrote:
>
> Add loaders for SPL and TPL so that the next stage can be loaded from
> memory-mapped SPI or, failing that, the Fast SPI driver.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
>
> ---
>
> Changes in v5:
> - Add L2 cache flush functoin
> - Drop SAFETY_MARGIN
>
> Changes in v4: None
> Changes in v3:
> - Add a driver for APL SPI for TPL (using of-platdata)
> - Support TPL without CONFIG_TPL_SPI_SUPPORT
> - Support bootstage timing
>
> Changes in v2: None
>
>  arch/x86/cpu/apollolake/Makefile |   2 +
>  arch/x86/cpu/apollolake/spl.c    | 197 +++++++++++++++++++++++++++++++
>  2 files changed, 199 insertions(+)
>  create mode 100644 arch/x86/cpu/apollolake/spl.c
>
> diff --git a/arch/x86/cpu/apollolake/Makefile b/arch/x86/cpu/apollolake/Makefile
> index 875d454157..1fde400d77 100644
> --- a/arch/x86/cpu/apollolake/Makefile
> +++ b/arch/x86/cpu/apollolake/Makefile
> @@ -2,7 +2,9 @@
>  #
>  # Copyright 2019 Google LLC
>
> +obj-$(CONFIG_SPL_BUILD) += spl.o
>  obj-$(CONFIG_SPL_BUILD) += systemagent.o
> +
>  ifndef CONFIG_TPL_BUILD
>  obj-y += punit.o
>  endif
> diff --git a/arch/x86/cpu/apollolake/spl.c b/arch/x86/cpu/apollolake/spl.c
> new file mode 100644
> index 0000000000..2c8222524e
> --- /dev/null
> +++ b/arch/x86/cpu/apollolake/spl.c
> @@ -0,0 +1,197 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2019 Google LLC
> + */
> +
> +#include <common.h>
> +#include <binman_sym.h>
> +#include <dm.h>
> +#include <spi.h>
> +#include <spl.h>
> +#include <spi_flash.h>
> +#include <asm/fast_spi.h>
> +#include <asm/spl.h>
> +#include <asm/arch/cpu.h>
> +#include <asm/arch/iomap.h>
> +#include <dm/device-internal.h>
> +#include <dm/uclass-internal.h>
> +
> +binman_sym_declare(ulong, u_boot_spl, image_pos);
> +binman_sym_declare(ulong, u_boot_spl, size);
> +/* U-Boot image_pos is declared by common/spl/spl.c */
> +binman_sym_declare(ulong, u_boot_any, size);

So should the above 3 symbols be declared in common/spl/spl.c too?

> +
> +static ulong get_image_pos(void)
> +{
> +       return spl_phase() == PHASE_TPL ?
> +               binman_sym(ulong, u_boot_spl, image_pos) :
> +               binman_sym(ulong, u_boot_any, image_pos);
> +}
> +
> +static ulong get_image_size(void)
> +{
> +       return spl_phase() == PHASE_TPL ?
> +               binman_sym(ulong, u_boot_spl, size) :
> +               binman_sym(ulong, u_boot_any, size);
> +}

Looks these 2 functions are generic, so can we move these to common/spl/spl.c?

> +
> +/* This reads the next phase from mapped SPI flash */
> +static int rom_load_image(struct spl_image_info *spl_image,
> +                         struct spl_boot_device *bootdev)
> +{
> +       ulong spl_pos = get_image_pos();
> +       ulong spl_size = get_image_size();
> +       struct udevice *dev;
> +       ulong map_base;
> +       size_t map_size;
> +       uint offset;
> +       int ret;
> +
> +       spl_image->size = CONFIG_SYS_MONITOR_LEN;  /* We don't know SPL size */
> +       spl_image->entry_point = spl_phase() == PHASE_TPL ?
> +               CONFIG_SPL_TEXT_BASE : CONFIG_SYS_TEXT_BASE;
> +       spl_image->load_addr = spl_image->entry_point;
> +       spl_image->os = IH_OS_U_BOOT;
> +       spl_image->name = "U-Boot";
> +       debug("Reading from mapped SPI %lx, size %lx", spl_pos, spl_size);
> +
> +       if (CONFIG_IS_ENABLED(SPI_FLASH_SUPPORT)) {
> +               ret = uclass_find_first_device(UCLASS_SPI_FLASH, &dev);
> +               if (ret)
> +                       return log_msg_ret("spi_flash", ret);
> +               if (!dev)
> +                       return log_msg_ret("spi_flash dev", -ENODEV);
> +               ret = dm_spi_get_mmap(dev, &map_base, &map_size, &offset);
> +               if (ret)
> +                       return log_msg_ret("mmap", ret);
> +       } else {
> +               ret = fast_spi_get_bios_mmap(PCH_DEV_SPI, &map_base, &map_size,
> +                                            &offset);
> +               if (ret)
> +                       return ret;
> +       }
> +       spl_pos += map_base & ~0xff000000;
> +       debug(", base %lx, pos %lx\n", map_base, spl_pos);
> +       bootstage_start(BOOTSTAGE_ID_ACCUM_MMAP_SPI, "mmap_spi");
> +       memcpy((void *)spl_image->load_addr, (void *)spl_pos, spl_size);
> +       cpu_flush_l1d_to_l2();
> +       bootstage_accum(BOOTSTAGE_ID_ACCUM_MMAP_SPI);
> +
> +       return 0;
> +}
> +SPL_LOAD_IMAGE_METHOD("Mapped SPI", 2, BOOT_DEVICE_SPI_MMAP, rom_load_image);
> +
> +#if CONFIG_IS_ENABLED(SPI_FLASH_SUPPORT)
> +
> +static int apl_flash_std_read(struct udevice *dev, u32 offset, size_t len,
> +                             void *buf)
> +{
> +       struct spi_flash *flash = dev_get_uclass_priv(dev);
> +       struct mtd_info *mtd = &flash->mtd;
> +       size_t retlen;
> +
> +       return log_ret(mtd->_read(mtd, offset, len, &retlen, buf));
> +}
> +
> +static int apl_flash_probe(struct udevice *dev)
> +{
> +       return spi_flash_std_probe(dev);
> +}
> +
> +/*
> + * Manually set the parent of the SPI flash to SPI, since dtoc doesn't. We also
> + * need to allocate the parent_platdata since by the time this function is
> + * called device_bind() has already gone past that step.
> + */
> +static int apl_flash_bind(struct udevice *dev)
> +{
> +       if (CONFIG_IS_ENABLED(OF_PLATDATA)) {
> +               struct dm_spi_slave_platdata *plat;
> +               struct udevice *spi;
> +               int ret;
> +
> +               ret = uclass_first_device_err(UCLASS_SPI, &spi);
> +               if (ret)
> +                       return ret;
> +               dev->parent = spi;
> +
> +               plat = calloc(sizeof(*plat), 1);
> +               if (!plat)
> +                       return -ENOMEM;
> +               dev->parent_platdata = plat;
> +       }
> +
> +       return 0;
> +}
> +
> +static const struct dm_spi_flash_ops apl_flash_ops = {
> +       .read           = apl_flash_std_read,
> +};
> +
> +static const struct udevice_id apl_flash_ids[] = {
> +       { .compatible = "jedec,spi-nor" },
> +       { }
> +};
> +
> +U_BOOT_DRIVER(winbond_w25q128fw) = {
> +       .name           = "winbond_w25q128fw",
> +       .id             = UCLASS_SPI_FLASH,
> +       .of_match       = apl_flash_ids,
> +       .bind           = apl_flash_bind,
> +       .probe          = apl_flash_probe,
> +       .priv_auto_alloc_size = sizeof(struct spi_flash),
> +       .ops            = &apl_flash_ops,
> +};
> +
> +/* This uses a SPI flash device to read the next phase */
> +static int spl_fast_spi_load_image(struct spl_image_info *spl_image,
> +                                  struct spl_boot_device *bootdev)
> +{
> +       ulong spl_pos = get_image_pos();
> +       ulong spl_size = get_image_size();
> +       struct udevice *dev;
> +       int ret;
> +
> +       ret = uclass_first_device_err(UCLASS_SPI_FLASH, &dev);
> +       if (ret)
> +               return ret;
> +
> +       spl_image->size = CONFIG_SYS_MONITOR_LEN;  /* We don't know SPL size */
> +       spl_image->entry_point = spl_phase() == PHASE_TPL ?
> +               CONFIG_SPL_TEXT_BASE : CONFIG_SYS_TEXT_BASE;
> +       spl_image->load_addr = spl_image->entry_point;
> +       spl_image->os = IH_OS_U_BOOT;
> +       spl_image->name = "U-Boot";
> +       spl_pos &= ~0xff000000;
> +       debug("Reading from flash %lx, size %lx\n", spl_pos, spl_size);
> +       ret = spi_flash_read_dm(dev, spl_pos, spl_size,
> +                               (void *)spl_image->load_addr);
> +       cpu_flush_l1d_to_l2();
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +SPL_LOAD_IMAGE_METHOD("Fast SPI", 1, BOOT_DEVICE_FAST_SPI,
> +                     spl_fast_spi_load_image);
> +
> +void board_boot_order(u32 *spl_boot_list)
> +{
> +       bool use_spi_flash = BOOT_FROM_FAST_SPI_FLASH;
> +
> +       if (use_spi_flash) {
> +               spl_boot_list[0] = BOOT_DEVICE_FAST_SPI;
> +               spl_boot_list[1] = BOOT_DEVICE_SPI_MMAP;
> +       } else {
> +               spl_boot_list[0] = BOOT_DEVICE_SPI_MMAP;
> +               spl_boot_list[1] = BOOT_DEVICE_FAST_SPI;
> +       }
> +}
> +
> +#else
> +
> +void board_boot_order(u32 *spl_boot_list)
> +{
> +       spl_boot_list[0] = BOOT_DEVICE_SPI_MMAP;
> +}
> +#endif
> --

Regards,
Bin


More information about the U-Boot mailing list