summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2023-04-19 08:58:58 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2023-04-19 08:58:58 +0200
commitc46996d29b49b9d7fc33aa4ae59ea90596da068f (patch)
treea6cd5e98fbb2a6e47061cb3071fb4a4b083373f4 /arch
parentdc4f31b6c0d121402aead43cb7c13121ad9a3d9d (diff)
parentc20cf77b26f230d40aef3f086f305dfc35a01a9e (diff)
downloadbarebox-c46996d29b49b9d7fc33aa4ae59ea90596da068f.tar.gz
Merge branch 'for-next/imx-image'
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/boards/nxp-imx8mm-evk/board.c1
-rw-r--r--arch/arm/boards/nxp-imx8mm-evk/flash-header-imx8mm-evk.imxcfg3
-rw-r--r--arch/arm/boards/nxp-imx8mm-evk/lowlevel.c1
-rw-r--r--arch/arm/boards/nxp-imx8mn-evk/board.c1
-rw-r--r--arch/arm/boards/nxp-imx8mn-evk/flash-header-imx8mn-evk.imxcfg3
-rw-r--r--arch/arm/boards/nxp-imx8mn-evk/lowlevel.c4
-rw-r--r--arch/arm/boards/nxp-imx8mp-evk/board.c1
-rw-r--r--arch/arm/boards/nxp-imx8mp-evk/flash-header-imx8mp-evk.imxcfg3
-rw-r--r--arch/arm/dts/imx8mm-evk.dtsi19
-rw-r--r--arch/arm/dts/imx8mn-evk.dtsi19
-rw-r--r--arch/arm/dts/imx8mp-evk.dts19
-rw-r--r--arch/arm/mach-imx/Makefile1
-rw-r--r--arch/arm/mach-imx/atf.c9
-rw-r--r--arch/arm/mach-imx/boot.c19
-rw-r--r--arch/arm/mach-imx/imx-bbu-internal.c49
-rw-r--r--arch/arm/mach-imx/xload-common.c120
-rw-r--r--arch/arm/mach-imx/xload-qspi.c57
17 files changed, 322 insertions, 7 deletions
diff --git a/arch/arm/boards/nxp-imx8mm-evk/board.c b/arch/arm/boards/nxp-imx8mm-evk/board.c
index fd748262f7..c8e17570ca 100644
--- a/arch/arm/boards/nxp-imx8mm-evk/board.c
+++ b/arch/arm/boards/nxp-imx8mm-evk/board.c
@@ -53,6 +53,7 @@ static int imx8mm_evk_probe(struct device *dev)
imx8m_bbu_internal_mmc_register_handler("SD", "/dev/mmc1.barebox", sd_bbu_flag);
imx8m_bbu_internal_mmcboot_register_handler("eMMC", "/dev/mmc2", emmc_bbu_flag);
+ imx8m_bbu_internal_flexspi_nor_register_handler("QSPI", "/dev/m25p0.barebox", 0);
phy_register_fixup_for_uid(PHY_ID_AR8031, AR_PHY_ID_MASK,
ar8031_phy_fixup);
diff --git a/arch/arm/boards/nxp-imx8mm-evk/flash-header-imx8mm-evk.imxcfg b/arch/arm/boards/nxp-imx8mm-evk/flash-header-imx8mm-evk.imxcfg
index 10606ce29c..d6a536053e 100644
--- a/arch/arm/boards/nxp-imx8mm-evk/flash-header-imx8mm-evk.imxcfg
+++ b/arch/arm/boards/nxp-imx8mm-evk/flash-header-imx8mm-evk.imxcfg
@@ -5,3 +5,6 @@ soc imx8mm
loadaddr 0x007e1000
max_load_size 0x3f000
ivtofs 0x400
+
+flexspi_ivtofs 0x1000
+flexspi_fcfbofs 0x0
diff --git a/arch/arm/boards/nxp-imx8mm-evk/lowlevel.c b/arch/arm/boards/nxp-imx8mm-evk/lowlevel.c
index 9983f78bab..46b5f317b5 100644
--- a/arch/arm/boards/nxp-imx8mm-evk/lowlevel.c
+++ b/arch/arm/boards/nxp-imx8mm-evk/lowlevel.c
@@ -161,6 +161,7 @@ ENTRY_FUNCTION(start_nxp_imx8mm_evk, r0, r1, r2)
setup_c();
IMD_USED_OF(imx8mm_evk);
+ IMD_USED_OF(imx8mm_evkb);
nxp_imx8mm_evk_start();
}
diff --git a/arch/arm/boards/nxp-imx8mn-evk/board.c b/arch/arm/boards/nxp-imx8mn-evk/board.c
index 13efc62a58..3e90ba284c 100644
--- a/arch/arm/boards/nxp-imx8mn-evk/board.c
+++ b/arch/arm/boards/nxp-imx8mn-evk/board.c
@@ -51,6 +51,7 @@ static int imx8mn_evk_probe(struct device *dev)
imx8m_bbu_internal_mmc_register_handler("SD", "/dev/mmc1.barebox", sd_bbu_flag);
imx8m_bbu_internal_mmcboot_register_handler("eMMC", "/dev/mmc2", emmc_bbu_flag);
+ imx8m_bbu_internal_flexspi_nor_register_handler("QSPI", "/dev/m25p0.barebox", 0);
phy_register_fixup_for_uid(PHY_ID_AR8031, AR_PHY_ID_MASK,
ar8031_phy_fixup);
diff --git a/arch/arm/boards/nxp-imx8mn-evk/flash-header-imx8mn-evk.imxcfg b/arch/arm/boards/nxp-imx8mn-evk/flash-header-imx8mn-evk.imxcfg
index 27a2138e43..a9b592e624 100644
--- a/arch/arm/boards/nxp-imx8mn-evk/flash-header-imx8mn-evk.imxcfg
+++ b/arch/arm/boards/nxp-imx8mn-evk/flash-header-imx8mn-evk.imxcfg
@@ -5,3 +5,6 @@ soc imx8mn
loadaddr 0x912000
max_load_size 0x3f000
ivtofs 0x0
+
+flexspi_ivtofs 0x0
+flexspi_fcfbofs 0x400
diff --git a/arch/arm/boards/nxp-imx8mn-evk/lowlevel.c b/arch/arm/boards/nxp-imx8mn-evk/lowlevel.c
index 8e7383c9d2..398dfb33ae 100644
--- a/arch/arm/boards/nxp-imx8mn-evk/lowlevel.c
+++ b/arch/arm/boards/nxp-imx8mn-evk/lowlevel.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <io.h>
+#include <image-metadata.h>
#include <common.h>
#include <debug_ll.h>
#include <mach/imx/debug_ll.h>
@@ -154,5 +155,8 @@ ENTRY_FUNCTION(start_nxp_imx8mn_evk, r0, r1, r2)
relocate_to_current_adr();
setup_c();
+ IMD_USED_OF(imx8mn_evk);
+ IMD_USED_OF(imx8mn_ddr4_evk);
+
nxp_imx8mn_evk_start();
}
diff --git a/arch/arm/boards/nxp-imx8mp-evk/board.c b/arch/arm/boards/nxp-imx8mp-evk/board.c
index 0c9fe7835b..2aa551e504 100644
--- a/arch/arm/boards/nxp-imx8mp-evk/board.c
+++ b/arch/arm/boards/nxp-imx8mp-evk/board.c
@@ -36,6 +36,7 @@ static int nxp_imx8mp_evk_probe(struct device *dev)
imx8m_bbu_internal_mmc_register_handler("SD", "/dev/mmc1.barebox", sd_bbu_flag);
imx8m_bbu_internal_mmcboot_register_handler("eMMC", "/dev/mmc2", emmc_bbu_flag);
+ imx8m_bbu_internal_flexspi_nor_register_handler("QSPI", "/dev/m25p0.barebox", 0);
/* Enable RGMII TX clk output */
val = readl(MX8MP_IOMUXC_GPR_BASE_ADDR + MX8MP_IOMUXC_GPR1);
diff --git a/arch/arm/boards/nxp-imx8mp-evk/flash-header-imx8mp-evk.imxcfg b/arch/arm/boards/nxp-imx8mp-evk/flash-header-imx8mp-evk.imxcfg
index 663bd102e9..3bb44d199c 100644
--- a/arch/arm/boards/nxp-imx8mp-evk/flash-header-imx8mp-evk.imxcfg
+++ b/arch/arm/boards/nxp-imx8mp-evk/flash-header-imx8mp-evk.imxcfg
@@ -5,3 +5,6 @@ soc imx8mp
loadaddr 0x920000
max_load_size 0x3f000
ivtofs 0x0
+
+flexspi_ivtofs 0x0
+flexspi_fcfbofs 0x400
diff --git a/arch/arm/dts/imx8mm-evk.dtsi b/arch/arm/dts/imx8mm-evk.dtsi
index 4d64dcad1c..a657faa6bc 100644
--- a/arch/arm/dts/imx8mm-evk.dtsi
+++ b/arch/arm/dts/imx8mm-evk.dtsi
@@ -19,6 +19,25 @@
};
};
+&{flexspi/flash@0} {
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "barebox";
+ reg = <0x0 0xe0000>;
+ };
+
+ partition@e0000 {
+ label = "barebox-environment";
+ reg = <0xe0000 0x20000>;
+ };
+ };
+
+};
+
&reg_usdhc2_vmmc {
off-on-delay-us = <20000>;
};
diff --git a/arch/arm/dts/imx8mn-evk.dtsi b/arch/arm/dts/imx8mn-evk.dtsi
index d15f66ff40..c23075216e 100644
--- a/arch/arm/dts/imx8mn-evk.dtsi
+++ b/arch/arm/dts/imx8mn-evk.dtsi
@@ -21,6 +21,25 @@
};
};
+&flash0 {
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "barebox";
+ reg = <0x0 0xe0000>;
+ };
+
+ partition@e0000 {
+ label = "barebox-environment";
+ reg = <0xe0000 0x20000>;
+ };
+ };
+
+};
+
&usdhc2 {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/dts/imx8mp-evk.dts b/arch/arm/dts/imx8mp-evk.dts
index ecec4d2a66..c7e1f35d2d 100644
--- a/arch/arm/dts/imx8mp-evk.dts
+++ b/arch/arm/dts/imx8mp-evk.dts
@@ -37,6 +37,25 @@
reset-deassert-us = <100000>;
};
+&{flexspi/flash@0} {
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "barebox";
+ reg = <0x0 0xe0000>;
+ };
+
+ partition@e0000 {
+ label = "barebox-environment";
+ reg = <0xe0000 0x20000>;
+ };
+ };
+
+};
+
&reg_usdhc2_vmmc {
off-on-delay-us = <20000>;
};
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 5d70e79b57..f49bbea2b4 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -31,3 +31,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/atf.c b/arch/arm/mach-imx/atf.c
index 2b667cf583..92820d9392 100644
--- a/arch/arm/mach-imx/atf.c
+++ b/arch/arm/mach-imx/atf.c
@@ -112,6 +112,9 @@ void imx8mm_load_bl33(void *bl33)
}
break;
+ case BOOTSOURCE_SPI:
+ imx8mm_qspi_load_image(instance, false);
+ break;
default:
printf("Unhandled bootsource BOOTSOURCE_%d\n", src);
hang();
@@ -156,6 +159,9 @@ void imx8mp_load_bl33(void *bl33)
case BOOTSOURCE_SERIAL:
imx8mp_bootrom_load_image();
break;
+ case BOOTSOURCE_SPI:
+ imx8mp_qspi_load_image(instance, false);
+ break;
default:
printf("Unhandled bootsource BOOTSOURCE_%d\n", src);
hang();
@@ -202,6 +208,9 @@ void imx8mn_load_bl33(void *bl33)
case BOOTSOURCE_SERIAL:
imx8mn_bootrom_load_image();
break;
+ case BOOTSOURCE_SPI:
+ imx8mn_qspi_load_image(instance, false);
+ break;
default:
printf("Unhandled bootsource BOOTSOURCE_%d\n", src);
hang();
diff --git a/arch/arm/mach-imx/boot.c b/arch/arm/mach-imx/boot.c
index a6322e4850..c6134f35b6 100644
--- a/arch/arm/mach-imx/boot.c
+++ b/arch/arm/mach-imx/boot.c
@@ -243,6 +243,11 @@ static unsigned int imx8mp_get_bmod(uint32_t r)
return FIELD_GET(IMX8MP_SRC_SBMR_BMOD, r);
}
+static unsigned int imx8mm_get_bcfg(uint32_t r)
+{
+ return FIELD_GET(BOOT_CFG2(6, 4), r);
+}
+
static int imx53_bootsource_internal(uint32_t r)
{
return FIELD_GET(BOOT_CFG1(7, 4), r);
@@ -323,6 +328,7 @@ void imx53_boot_save_loc(void)
#define IMX6_SRC_GPR10 0x44
#define IMX6_BMOD_SERIAL 0b01
#define IMX6_BMOD_RESERVED 0b11
+#define IMX8MM_BCFG_FSPI 0b100
#define IMX8MP_BMOD_FUSES 0b0000
#define IMX8MP_BMOD_SERIAL 0b0001
#define IMX6_BMOD_FUSES 0b00
@@ -358,6 +364,11 @@ static bool imx8mp_bootsource_serial(uint32_t sbmr2)
!(sbmr2 & BT_FUSE_SEL));
}
+static bool imx8mm_bootsource_qspi(uint32_t sbmr1)
+{
+ return imx8mm_get_bcfg(sbmr1) == IMX8MM_BCFG_FSPI;
+}
+
static bool imx6_bootsource_serial_forced(uint32_t bootmode)
{
if (cpu_mx6_is_mx6ul() || cpu_mx6_is_mx6ull())
@@ -535,6 +546,7 @@ static void __imx7_get_boot_source(enum bootsource *src, int *instance,
break;
case 4:
*src = BOOTSOURCE_SPI; /* Really: qspi */
+ *instance = info->boot_device_instance;
break;
case 5:
*src = BOOTSOURCE_NOR;
@@ -691,6 +703,7 @@ void imx8mm_get_boot_source(enum bootsource *src, int *instance)
{
unsigned long addr;
void __iomem *src_base = IOMEM(MX8MM_SRC_BASE_ADDR);
+ uint32_t sbmr1 = readl(src_base + 0x58);
uint32_t sbmr2 = readl(src_base + 0x70);
if (imx6_bootsource_serial(sbmr2)) {
@@ -698,6 +711,12 @@ void imx8mm_get_boot_source(enum bootsource *src, int *instance)
return;
}
+ if (imx8mm_bootsource_qspi(sbmr1)) {
+ *src = BOOTSOURCE_SPI; /* Really: qspi */
+ *instance = 0;
+ return;
+ }
+
addr = IMX8M_BOOT_SW_INFO_POINTER_ADDR_A0;
__imx7_get_boot_source(src, instance, addr, sbmr2);
diff --git a/arch/arm/mach-imx/imx-bbu-internal.c b/arch/arm/mach-imx/imx-bbu-internal.c
index a86bd75253..8cdaab5c16 100644
--- a/arch/arm/mach-imx/imx-bbu-internal.c
+++ b/arch/arm/mach-imx/imx-bbu-internal.c
@@ -19,15 +19,15 @@
#include <environment.h>
#include <mach/imx/bbu.h>
#include <mach/imx/generic.h>
+#include <mach/imx/imx-header.h>
#include <libfile.h>
-#define IMX_INTERNAL_FLAG_ERASE BIT(30)
-
struct imx_internal_bbu_handler {
struct bbu_handler handler;
int (*write_device)(struct imx_internal_bbu_handler *,
struct bbu_data *);
unsigned long flash_header_offset;
+ unsigned long filetype_offset;
size_t device_size;
enum filetype expected_type;
};
@@ -35,7 +35,7 @@ struct imx_internal_bbu_handler {
static bool
imx_bbu_erase_required(struct imx_internal_bbu_handler *imx_handler)
{
- return imx_handler->handler.flags & IMX_INTERNAL_FLAG_ERASE;
+ return imx_handler->handler.flags & IMX_BBU_FLAG_ERASE;
}
static int imx_bbu_protect(int fd, struct imx_internal_bbu_handler *imx_handler,
@@ -163,8 +163,8 @@ static int imx_bbu_check_prereq(struct imx_internal_bbu_handler *imx_handler,
if (expected_type == filetype_unknown)
break;
- blob = data->image + imx_handler->flash_header_offset;
- len = data->len - imx_handler->flash_header_offset;
+ blob = data->image + imx_handler->filetype_offset;
+ len = data->len - imx_handler->filetype_offset;
type = file_detect_type(blob, len);
if (type != expected_type) {
@@ -472,6 +472,7 @@ imx_bbu_internal_mmc_register_handler(const char *name, const char *devicefile,
imx_handler = __init_handler(name, devicefile, flags |
IMX_BBU_FLAG_KEEP_HEAD);
imx_handler->flash_header_offset = imx_bbu_flash_header_offset_mmc();
+ imx_handler->filetype_offset = imx_handler->flash_header_offset;
return __register_handler(imx_handler);
}
@@ -484,8 +485,9 @@ imx_bbu_internal_spi_i2c_register_handler(const char *name,
struct imx_internal_bbu_handler *imx_handler;
imx_handler = __init_handler(name, devicefile, flags |
- IMX_INTERNAL_FLAG_ERASE);
+ IMX_BBU_FLAG_ERASE);
imx_handler->flash_header_offset = imx_bbu_flash_header_offset_mmc();
+ imx_handler->filetype_offset = imx_handler->flash_header_offset;
return __register_handler(imx_handler);
}
@@ -531,6 +533,7 @@ int imx53_bbu_internal_nand_register_handler(const char *name,
imx_handler = __init_handler(name, "/dev/nand0", flags);
imx_handler->flash_header_offset = imx_bbu_flash_header_offset_mmc();
+ imx_handler->filetype_offset = imx_handler->flash_header_offset;
imx_handler->device_size = partition_size;
imx_handler->write_device = imx_bbu_internal_v2_write_nand_dbbt;
@@ -582,6 +585,7 @@ static int imx_bbu_internal_mmcboot_register_handler(const char *name,
imx_handler = __init_handler(name, devicefile, flags);
imx_handler->flash_header_offset = flash_header_offset;
+ imx_handler->filetype_offset = flash_header_offset;
imx_handler->handler.handler = imx_bbu_internal_mmcboot_update;
@@ -646,9 +650,40 @@ int imx_bbu_external_nor_register_handler(const char *name,
struct imx_internal_bbu_handler *imx_handler;
imx_handler = __init_handler(name, devicefile, flags |
- IMX_INTERNAL_FLAG_ERASE);
+ IMX_BBU_FLAG_ERASE);
imx_handler->expected_type = filetype_unknown;
return __register_handler(imx_handler);
}
+
+static unsigned long imx_bbu_filetype_offset_flexspi(void)
+{
+ unsigned int sd_flash_header_gap = SZ_32K;
+
+ if (cpu_is_mx8mm())
+ return sd_flash_header_gap;
+
+ return sd_flash_header_gap + SZ_1K;
+}
+
+static int
+imx_bbu_internal_flexspi_nor_register_handler(const char *name,
+ const char *devicefile,
+ unsigned long flags)
+{
+ struct imx_internal_bbu_handler *imx_handler;
+
+ flags |= IMX_BBU_FLAG_ERASE | IMX_BBU_FLAG_PARTITION_STARTS_AT_HEADER;
+ imx_handler = __init_handler(name, devicefile, flags);
+ imx_handler->flash_header_offset = SZ_32K;
+ imx_handler->expected_type = filetype_nxp_fspi_image;
+ imx_handler->filetype_offset = imx_bbu_filetype_offset_flexspi();
+
+ return __register_handler(imx_handler);
+}
+
+int imx8m_bbu_internal_flexspi_nor_register_handler(const char *name,
+ const char *devicefile,
+ unsigned long flags)
+ __alias(imx_bbu_internal_flexspi_nor_register_handler);
diff --git a/arch/arm/mach-imx/xload-common.c b/arch/arm/mach-imx/xload-common.c
index 5a437b185d..0d3e6be1b1 100644
--- a/arch/arm/mach-imx/xload-common.c
+++ b/arch/arm/mach-imx/xload-common.c
@@ -1,11 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <common.h>
+#include <asm/cache.h>
#include <asm/sections.h>
#include <linux/sizes.h>
#include <mach/imx/xload.h>
#include <mach/imx/esdctl.h>
#include <mach/imx/imx8m-regs.h>
+#include <mach/imx/imx-header.h>
#include <asm/barebox-arm.h>
int imx_image_size(void)
@@ -26,3 +28,121 @@ struct imx_scratch_space *__imx8m_scratch_space(int ddr_buswidth)
return (void *)__arm_mem_scratch(endmem);
}
+
+#define HDR_SIZE 512
+
+static int
+imx_search_header(struct imx_flash_header_v2 **header_pointer,
+ void *buffer, u32 *offset, u32 ivt_offset,
+ int (*read)(void *dest, size_t len, void *priv),
+ void *priv)
+{
+ int ret;
+ int i, header_count = 1;
+ void *buf = buffer;
+ struct imx_flash_header_v2 *hdr;
+
+ for (i = 0; i < header_count; i++) {
+ ret = read(buf, *offset + ivt_offset + HDR_SIZE, priv);
+ if (ret)
+ return ret;
+
+ hdr = buf + *offset + ivt_offset;
+
+ if (!is_imx_flash_header_v2(hdr)) {
+ pr_debug("No IVT header! "
+ "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;
+}
+
+int imx_load_image(ptrdiff_t address, ptrdiff_t entry, u32 offset,
+ u32 ivt_offset, bool start, unsigned int alignment,
+ int (*read)(void *dest, size_t len, void *priv),
+ void *priv)
+{
+
+ 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();
+ if (alignment)
+ len = ALIGN(len, alignment);
+
+ ret = imx_search_header(&hdr, buf, &offset, ivt_offset, read, priv);
+ 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);
+ }
+
+ ret = read(buf, ofs + len, priv);
+ if (ret) {
+ pr_err("Loading image failed with %d\n", ret);
+ return ret;
+ }
+
+ pr_debug("Image loaded successfully\n");
+
+ if (!start)
+ return 0;
+
+ bb = buf + ofs;
+
+ sync_caches_for_execution();
+
+ bb();
+}
diff --git a/arch/arm/mach-imx/xload-qspi.c b/arch/arm/mach-imx/xload-qspi.c
new file mode 100644
index 0000000000..6bf5bba5e6
--- /dev/null
+++ b/arch/arm/mach-imx/xload-qspi.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <linux/sizes.h>
+#include <mach/imx/atf.h>
+#include <mach/imx/imx8m-regs.h>
+#include <mach/imx/xload.h>
+
+#define IMX8M_QSPI_MMAP 0x8000000
+
+/* Make use of AHB reads */
+static
+int imx8m_qspi_read(void *dest, size_t len, void *priv)
+{
+ void __iomem *qspi_ahb = priv;
+
+ memcpy(dest, qspi_ahb, len);
+
+ return 0;
+}
+
+/**
+ * imx8mm_qspi_start_image - Load and optionally start an image from the
+ * FlexSPI controller.
+ * @instance: The FlexSPI controller instance
+ * @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.
+ */
+static
+int imx8m_qspi_load_image(int instance, bool start, off_t offset, off_t ivt_offset)
+{
+ void __iomem *qspi_ahb = IOMEM(IMX8M_QSPI_MMAP);
+
+ return imx_load_image(MX8M_DDR_CSD1_BASE_ADDR, MX8M_ATF_BL33_BASE_ADDR,
+ offset, ivt_offset, start, 0,
+ imx8m_qspi_read, qspi_ahb);
+}
+
+int imx8mm_qspi_load_image(int instance, bool start)
+{
+ return imx8m_qspi_load_image(instance, start, 0, SZ_4K);
+}
+
+int imx8mn_qspi_load_image(int instance, bool start)
+{
+ return imx8m_qspi_load_image(instance, start, SZ_4K, 0);
+}
+
+int imx8mp_qspi_load_image(int instance, bool start)
+ __alias(imx8mn_qspi_load_image);