[PATCH 1/3] arch: arm: imx: spi: Add QSPI boot support to the IMX8 platforms

Joacim Zetterling joacim.zetterling at westermo.com
Tue Mar 8 08:07:59 PST 2022


The IMX8 platforms does only support boot from a SD or an EMMC
device. With this functionality also a boot from a QSPI device
is possible. For the moment only the IMX8MN platform is supported.

Signed-off-by: Joacim Zetterling <joacim.zetterling at westermo.com>
---
 arch/arm/mach-imx/Makefile             |   1 +
 arch/arm/mach-imx/include/mach/xload.h |   1 +
 arch/arm/mach-imx/xload-qspi.c         | 145 +++++++++++++++++++++++++
 3 files changed, 147 insertions(+)
 create mode 100644 arch/arm/mach-imx/xload-qspi.c

diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 2cafcd77e00d..d844196422df 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND) += imx-bbu-external-nand.o
 obj-$(CONFIG_RESET_IMX_SRC) += src.o
 lwl-y += cpu_init.o
 pbl-y += xload-spi.o xload-common.o xload-imx-nand.o xload-gpmi-nand.o
+pbl-y += xload-qspi.o
diff --git a/arch/arm/mach-imx/include/mach/xload.h b/arch/arm/mach-imx/include/mach/xload.h
index 03ec23ebbdb0..1876f3a4bd18 100644
--- a/arch/arm/mach-imx/include/mach/xload.h
+++ b/arch/arm/mach-imx/include/mach/xload.h
@@ -11,6 +11,7 @@ int imx6_nand_start_image(void);
 int imx7_esdhc_start_image(int instance);
 int imx8m_esdhc_load_image(int instance, bool start);
 int imx8mn_esdhc_load_image(int instance, bool start);
+int imx8mn_qspi_start_image(int instance, bool start);
 int imx8mp_esdhc_load_image(int instance, bool start);
 
 int imx_image_size(void);
diff --git a/arch/arm/mach-imx/xload-qspi.c b/arch/arm/mach-imx/xload-qspi.c
new file mode 100644
index 000000000000..c8305f15ee0a
--- /dev/null
+++ b/arch/arm/mach-imx/xload-qspi.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <asm-generic/sections.h>
+#include <asm/cache.h>
+#include <mach/xload.h>
+#include <mach/imx8mn-regs.h>
+#include <mach/imx-header.h>
+
+#include <io.h>
+#include <regmap.h>
+#include <linux/sizes.h>
+
+#include <mach/atf.h>
+
+#define HDR_SIZE		512
+
+#define IMX8M_QSPI_MMAP		0x8000000
+
+
+static int check_ivt_header_v2(struct imx_flash_header_v2 **header_pointer,
+			    void *buf, u32 offset, u32 ivt_offset)
+{
+	int i, header_count = 1;
+	struct imx_flash_header_v2 *hdr;
+
+	for (i = 0; i < header_count; i++) {
+		hdr = buf + offset + ivt_offset;
+
+		if (!is_imx_flash_header_v2(hdr)) {
+			pr_debug("IVT header not found in QSPI. "
+				 "Found tag: 0x%02x length: 0x%04x "
+				 "version: %02x\n",
+				 hdr->header.tag, hdr->header.length,
+				 hdr->header.version);
+			return -EINVAL;
+		}
+
+		if (IS_ENABLED(CONFIG_ARCH_IMX8MQ) &&
+		    hdr->boot_data.plugin & PLUGIN_HDMI_IMAGE) {
+			/*
+			 * In images that include signed HDMI
+			 * firmware, first v2 header would be
+			 * dedicated to that and would not contain any
+			 * useful for us information. In order for us
+			 * to pull the rest of the bootloader image
+			 * in, we need to re-read header from SD/MMC,
+			 * this time skipping anything HDMI firmware
+			 * related.
+			 */
+			offset += hdr->boot_data.size + hdr->header.length;
+			header_count++;
+		}
+	}
+
+	*header_pointer = hdr;
+	return 0;
+}
+
+static int
+imx8m_qspi_load_image(void __iomem *ahb_addr, ptrdiff_t address,
+		 ptrdiff_t entry, u32 offset, u32 ivt_offset, bool start)
+{
+	void *buf = (void *)address;
+	struct imx_flash_header_v2 *hdr = NULL;
+	int ret, len;
+	void __noreturn (*bb)(void);
+	unsigned int ofs;
+
+	len = imx_image_size();
+
+	/* Read out the data directly from the AHB buffer. */
+	memcpy(buf, __io_virt((void *)ahb_addr), 0x2000);
+
+	ret = check_ivt_header_v2(&hdr, buf, offset, ivt_offset);
+	if (ret)
+		return ret;
+
+	pr_debug("Check ok, loading image\n");
+
+	ofs = offset + hdr->entry - hdr->boot_data.start;
+
+	if (entry != address) {
+		/*
+		 * Passing entry different from address is interpreted
+		 * as a request to place the image such that its entry
+		 * point would be exactly at 'entry', that is:
+		 *
+		 *     buf + ofs = entry
+		 *
+		 * solving the above for 'buf' gives us the
+		 * adjustment that needs to be made:
+		 *
+		 *     buf = entry - ofs
+		 *
+		 */
+		if (WARN_ON(entry - ofs < address)) {
+			/*
+			 * We want to make sure we won't try to place
+			 * the start of the image before the beginning
+			 * of the memory buffer we were given in
+			 * address.
+			 */
+			return -EINVAL;
+		}
+
+		buf = (void *)(entry - ofs);
+	}
+
+	/* Read out the data directly from the AHB buffer. */
+	memcpy(buf, __io_virt((void *)ahb_addr), len + SZ_4K);
+
+	pr_debug("Image loaded successfully\n");
+
+	if (!start)
+		return 0;
+
+	bb = buf + ofs;
+
+	sync_caches_for_execution();
+
+	bb();
+}
+
+/**
+ * imx8mn_qspi_start_image - Load and optionally start an image from the
+ * FlexSPI controller.
+ * @instance: The FlexSPI controller instance (0)
+ * @start: Whether to directly start the loaded image
+ *
+ * This uses imx8m_qspi_load_image() to load an image from QSPI. It is assumed
+ * that the image is the currently running barebox image (This information
+ * is used to calculate the length of the image).
+ * The image is started afterwards.
+ *
+ * Return: If successful, this function does not return (if directly started)
+ * or 0. A negative error code is returned when this function fails.
+ */
+int imx8mn_qspi_start_image(int instance, bool start)
+{
+	void __iomem *ahb_addr = IOMEM(IMX8M_QSPI_MMAP);
+
+	return imx8m_qspi_load_image(ahb_addr, MX8M_DDR_CSD1_BASE_ADDR,
+				MX8M_ATF_BL33_BASE_ADDR, SZ_4K, 0, start);
+}
-- 
2.25.1




More information about the barebox mailing list