x86: apl: Add SPL loaders
authorSimon Glass <sjg@chromium.org>
Mon, 9 Dec 2019 00:40:13 +0000 (17:40 -0700)
committerBin Meng <bmeng.cn@gmail.com>
Sun, 15 Dec 2019 03:44:29 +0000 (11:44 +0800)
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@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
arch/x86/cpu/apollolake/Makefile
arch/x86/cpu/apollolake/spl.c [new file with mode: 0644]

index 875d454157fa2bf29802f6f8fb8fe6d1fa1dcc5d..1fde400d77ce2fe8725c32700afa2e5ab5ec4cb4 100644 (file)
@@ -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 (file)
index 0000000..7ab7243
--- /dev/null
@@ -0,0 +1,178 @@
+// 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>
+
+/* 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 = spl_get_image_pos();
+       ulong spl_size = spl_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 = spl_get_image_pos();
+       ulong spl_size = spl_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 = IS_ENABLED(CONFIG_APL_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