aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-imx/imx8
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-imx/imx8')
-rw-r--r--arch/arm/mach-imx/imx8/Kconfig13
-rw-r--r--arch/arm/mach-imx/imx8/Makefile7
-rw-r--r--arch/arm/mach-imx/imx8/cpu.c189
-rw-r--r--arch/arm/mach-imx/imx8/fdt.c292
-rw-r--r--arch/arm/mach-imx/imx8/image.c246
-rw-r--r--arch/arm/mach-imx/imx8/lowlevel_init.S36
-rw-r--r--arch/arm/mach-imx/imx8/parse-container.c120
7 files changed, 727 insertions, 176 deletions
diff --git a/arch/arm/mach-imx/imx8/Kconfig b/arch/arm/mach-imx/imx8/Kconfig
index bbe323d5ca4..d17760e3337 100644
--- a/arch/arm/mach-imx/imx8/Kconfig
+++ b/arch/arm/mach-imx/imx8/Kconfig
@@ -23,6 +23,19 @@ config IMX8QXP
config SYS_SOC
default "imx8"
+config SPL_LOAD_IMX_CONTAINER
+ bool "Enable SPL loading U-Boot as a i.MX Container image"
+ depends on SPL
+ help
+ This is to let SPL could load i.MX8 Container image
+
+config IMX_CONTAINER_CFG
+ string "i.MX Container config file"
+ depends on SPL
+ help
+ This is to specific the cfg file for generating container
+ image which will be loaded by SPL.
+
choice
prompt "i.MX8 board select"
optional
diff --git a/arch/arm/mach-imx/imx8/Makefile b/arch/arm/mach-imx/imx8/Makefile
index 92b5c56acb2..39e384d5c75 100644
--- a/arch/arm/mach-imx/imx8/Makefile
+++ b/arch/arm/mach-imx/imx8/Makefile
@@ -4,4 +4,9 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-y += cpu.o iomux.o misc.o
+obj-y += cpu.o iomux.o misc.o lowlevel_init.o
+obj-$(CONFIG_OF_SYSTEM_SETUP) += fdt.o
+
+ifdef CONFIG_SPL_BUILD
+obj-$(CONFIG_SPL_LOAD_IMX_CONTAINER) += image.o parse-container.o
+endif
diff --git a/arch/arm/mach-imx/imx8/cpu.c b/arch/arm/mach-imx/imx8/cpu.c
index f2fa262ac89..d393a011782 100644
--- a/arch/arm/mach-imx/imx8/cpu.c
+++ b/arch/arm/mach-imx/imx8/cpu.c
@@ -60,18 +60,18 @@ int arch_cpu_init_dm(void)
int node, ret;
node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "fsl,imx8-mu");
- ret = device_bind_driver_to_node(gd->dm_root, "imx8_scu", "imx8_scu",
- offset_to_ofnode(node), &devp);
+ ret = uclass_get_device_by_of_offset(UCLASS_MISC, node, &devp);
if (ret) {
- printf("could not find scu %d\n", ret);
+ printf("could not get scu %d\n", ret);
return ret;
}
- ret = device_probe(devp);
- if (ret) {
- printf("scu probe failed %d\n", ret);
- return ret;
+ if (is_imx8qm()) {
+ ret = sc_pm_set_resource_power_mode(-1, SC_R_SMMU,
+ SC_PM_PW_MODE_ON);
+ if (ret)
+ return ret;
}
return 0;
@@ -475,10 +475,17 @@ u64 get_page_table_size(void)
}
#endif
+#if defined(CONFIG_IMX8QM)
+#define FUSE_MAC0_WORD0 452
+#define FUSE_MAC0_WORD1 453
+#define FUSE_MAC1_WORD0 454
+#define FUSE_MAC1_WORD1 455
+#elif defined(CONFIG_IMX8QXP)
#define FUSE_MAC0_WORD0 708
#define FUSE_MAC0_WORD1 709
#define FUSE_MAC1_WORD0 710
#define FUSE_MAC1_WORD1 711
+#endif
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
{
@@ -528,171 +535,3 @@ u32 get_cpu_rev(void)
return (id << 12) | rev;
}
-#if CONFIG_IS_ENABLED(CPU)
-struct cpu_imx_platdata {
- const char *name;
- const char *rev;
- const char *type;
- u32 cpurev;
- u32 freq_mhz;
-};
-
-const char *get_imx8_type(u32 imxtype)
-{
- switch (imxtype) {
- case MXC_CPU_IMX8QXP:
- case MXC_CPU_IMX8QXP_A0:
- return "QXP";
- case MXC_CPU_IMX8QM:
- return "QM";
- default:
- return "??";
- }
-}
-
-const char *get_imx8_rev(u32 rev)
-{
- switch (rev) {
- case CHIP_REV_A:
- return "A";
- case CHIP_REV_B:
- return "B";
- default:
- return "?";
- }
-}
-
-const char *get_core_name(void)
-{
- if (is_cortex_a35())
- return "A35";
- else if (is_cortex_a53())
- return "A53";
- else if (is_cortex_a72())
- return "A72";
- else
- return "?";
-}
-
-#if IS_ENABLED(CONFIG_IMX_SCU_THERMAL)
-static int cpu_imx_get_temp(void)
-{
- struct udevice *thermal_dev;
- int cpu_tmp, ret;
-
- ret = uclass_get_device_by_name(UCLASS_THERMAL, "cpu-thermal0",
- &thermal_dev);
-
- if (!ret) {
- ret = thermal_get_temp(thermal_dev, &cpu_tmp);
- if (ret)
- return 0xdeadbeef;
- } else {
- return 0xdeadbeef;
- }
-
- return cpu_tmp;
-}
-#else
-static int cpu_imx_get_temp(void)
-{
- return 0;
-}
-#endif
-
-int cpu_imx_get_desc(struct udevice *dev, char *buf, int size)
-{
- struct cpu_imx_platdata *plat = dev_get_platdata(dev);
- int ret;
-
- if (size < 100)
- return -ENOSPC;
-
- ret = snprintf(buf, size, "NXP i.MX8%s Rev%s %s at %u MHz",
- plat->type, plat->rev, plat->name, plat->freq_mhz);
-
- if (IS_ENABLED(CONFIG_IMX_SCU_THERMAL)) {
- buf = buf + ret;
- size = size - ret;
- ret = snprintf(buf, size, " at %dC", cpu_imx_get_temp());
- }
-
- snprintf(buf + ret, size - ret, "\n");
-
- return 0;
-}
-
-static int cpu_imx_get_info(struct udevice *dev, struct cpu_info *info)
-{
- struct cpu_imx_platdata *plat = dev_get_platdata(dev);
-
- info->cpu_freq = plat->freq_mhz * 1000;
- info->features = BIT(CPU_FEAT_L1_CACHE) | BIT(CPU_FEAT_MMU);
- return 0;
-}
-
-static int cpu_imx_get_count(struct udevice *dev)
-{
- return 4;
-}
-
-static int cpu_imx_get_vendor(struct udevice *dev, char *buf, int size)
-{
- snprintf(buf, size, "NXP");
- return 0;
-}
-
-static const struct cpu_ops cpu_imx8_ops = {
- .get_desc = cpu_imx_get_desc,
- .get_info = cpu_imx_get_info,
- .get_count = cpu_imx_get_count,
- .get_vendor = cpu_imx_get_vendor,
-};
-
-static const struct udevice_id cpu_imx8_ids[] = {
- { .compatible = "arm,cortex-a35" },
- { .compatible = "arm,cortex-a53" },
- { }
-};
-
-static ulong imx8_get_cpu_rate(void)
-{
- ulong rate;
- int ret;
- int type = is_cortex_a35() ? SC_R_A35 : is_cortex_a53() ?
- SC_R_A53 : SC_R_A72;
-
- ret = sc_pm_get_clock_rate(-1, type, SC_PM_CLK_CPU,
- (sc_pm_clock_rate_t *)&rate);
- if (ret) {
- printf("Could not read CPU frequency: %d\n", ret);
- return 0;
- }
-
- return rate;
-}
-
-static int imx8_cpu_probe(struct udevice *dev)
-{
- struct cpu_imx_platdata *plat = dev_get_platdata(dev);
- u32 cpurev;
-
- cpurev = get_cpu_rev();
- plat->cpurev = cpurev;
- plat->name = get_core_name();
- plat->rev = get_imx8_rev(cpurev & 0xFFF);
- plat->type = get_imx8_type((cpurev & 0xFF000) >> 12);
- plat->freq_mhz = imx8_get_cpu_rate() / 1000000;
- return 0;
-}
-
-U_BOOT_DRIVER(cpu_imx8_drv) = {
- .name = "imx8x_cpu",
- .id = UCLASS_CPU,
- .of_match = cpu_imx8_ids,
- .ops = &cpu_imx8_ops,
- .probe = imx8_cpu_probe,
- .platdata_auto_alloc_size = sizeof(struct cpu_imx_platdata),
- .flags = DM_FLAG_PRE_RELOC,
-};
-#endif
diff --git a/arch/arm/mach-imx/imx8/fdt.c b/arch/arm/mach-imx/imx8/fdt.c
new file mode 100644
index 00000000000..65c8ac1a7e2
--- /dev/null
+++ b/arch/arm/mach-imx/imx8/fdt.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <asm/arch/sci/sci.h>
+#include <asm/arch/sys_proto.h>
+#include <dm/ofnode.h>
+#include <fdt_support.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static bool check_owned_resource(sc_rsrc_t rsrc_id)
+{
+ bool owned;
+
+ owned = sc_rm_is_resource_owned(-1, rsrc_id);
+
+ return owned;
+}
+
+static int disable_fdt_node(void *blob, int nodeoffset)
+{
+ int rc, ret;
+ const char *status = "disabled";
+
+ do {
+ rc = fdt_setprop(blob, nodeoffset, "status", status,
+ strlen(status) + 1);
+ if (rc) {
+ if (rc == -FDT_ERR_NOSPACE) {
+ ret = fdt_increase_size(blob, 512);
+ if (ret)
+ return ret;
+ }
+ }
+ } while (rc == -FDT_ERR_NOSPACE);
+
+ return rc;
+}
+
+static void update_fdt_with_owned_resources(void *blob)
+{
+ /*
+ * Traverses the fdt nodes, check its power domain and use
+ * the resource id in the power domain for checking whether
+ * it is owned by current partition
+ */
+ struct fdtdec_phandle_args args;
+ int offset = 0, depth = 0;
+ u32 rsrc_id;
+ int rc, i;
+
+ for (offset = fdt_next_node(blob, offset, &depth); offset > 0;
+ offset = fdt_next_node(blob, offset, &depth)) {
+ debug("Node name: %s, depth %d\n",
+ fdt_get_name(blob, offset, NULL), depth);
+
+ if (!fdt_get_property(blob, offset, "power-domains", NULL)) {
+ debug(" - ignoring node %s\n",
+ fdt_get_name(blob, offset, NULL));
+ continue;
+ }
+
+ if (!fdtdec_get_is_enabled(blob, offset)) {
+ debug(" - ignoring node %s\n",
+ fdt_get_name(blob, offset, NULL));
+ continue;
+ }
+
+ i = 0;
+ while (true) {
+ rc = fdtdec_parse_phandle_with_args(blob, offset,
+ "power-domains",
+ "#power-domain-cells",
+ 0, i++, &args);
+ if (rc == -ENOENT) {
+ break;
+ } else if (rc) {
+ printf("Parse power-domains of %s wrong: %d\n",
+ fdt_get_name(blob, offset, NULL), rc);
+ continue;
+ }
+
+ rsrc_id = args.args[0];
+
+ if (!check_owned_resource(rsrc_id)) {
+ rc = disable_fdt_node(blob, offset);
+ if (!rc) {
+ printf("Disable %s rsrc %u not owned\n",
+ fdt_get_name(blob, offset, NULL),
+ rsrc_id);
+ } else {
+ printf("Unable to disable %s, err=%s\n",
+ fdt_get_name(blob, offset, NULL),
+ fdt_strerror(rc));
+ }
+ }
+ }
+ }
+}
+
+static int config_smmu_resource_sid(int rsrc, int sid)
+{
+ int err;
+
+ if (!check_owned_resource(rsrc)) {
+ printf("%s rsrc[%d] not owned\n", __func__, rsrc);
+ return -1;
+ }
+ err = sc_rm_set_master_sid(-1, rsrc, sid);
+ debug("set_master_sid rsrc=%d sid=0x%x err=%d\n", rsrc, sid, err);
+ if (err != SC_ERR_NONE) {
+ pr_err("fail set_master_sid rsrc=%d sid=0x%x err=%d\n", rsrc, sid, err);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int config_smmu_fdt_device_sid(void *blob, int device_offset, int sid)
+{
+ const char *name = fdt_get_name(blob, device_offset, NULL);
+ struct fdtdec_phandle_args args;
+ int rsrc, ret;
+ int proplen;
+ const fdt32_t *prop;
+ int i;
+
+ prop = fdt_getprop(blob, device_offset, "fsl,sc_rsrc_id", &proplen);
+ if (prop) {
+ int i;
+
+ debug("configure node %s sid 0x%x for %d resources\n",
+ name, sid, (int)(proplen / sizeof(fdt32_t)));
+ for (i = 0; i < proplen / sizeof(fdt32_t); ++i) {
+ ret = config_smmu_resource_sid(fdt32_to_cpu(prop[i]),
+ sid);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+ }
+
+ i = 0;
+ while (true) {
+ ret = fdtdec_parse_phandle_with_args(blob, device_offset,
+ "power-domains",
+ "#power-domain-cells",
+ 0, i++, &args);
+ if (ret == -ENOENT) {
+ break;
+ } else if (ret) {
+ printf("Parse power-domains of node %s wrong: %d\n",
+ fdt_get_name(blob, device_offset, NULL), ret);
+ continue;
+ }
+
+ debug("configure node %s sid 0x%x rsrc=%d\n",
+ name, sid, rsrc);
+ rsrc = args.args[0];
+
+ ret = config_smmu_resource_sid(rsrc, sid);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+
+static int config_smmu_fdt(void *blob)
+{
+ int offset, proplen, i, ret;
+ const fdt32_t *prop;
+ const char *name;
+
+ /* Legacy smmu bindings, still used by xen. */
+ offset = fdt_node_offset_by_compatible(blob, 0, "arm,mmu-500");
+ prop = fdt_getprop(blob, offset, "mmu-masters", &proplen);
+ if (offset > 0 && prop) {
+ debug("found legacy mmu-masters property\n");
+
+ for (i = 0; i < proplen / 8; ++i) {
+ u32 phandle = fdt32_to_cpu(prop[2 * i]);
+ int sid = fdt32_to_cpu(prop[2 * i + 1]);
+ int device_offset;
+
+ device_offset = fdt_node_offset_by_phandle(blob,
+ phandle);
+ if (device_offset < 0) {
+ pr_err("Not find device from mmu_masters: %d",
+ device_offset);
+ continue;
+ }
+ ret = config_smmu_fdt_device_sid(blob, device_offset,
+ sid);
+ if (ret)
+ return ret;
+ }
+
+ /* Ignore new bindings if old bindings found, just like linux. */
+ return 0;
+ }
+
+ /* Generic smmu bindings */
+ offset = 0;
+ while ((offset = fdt_next_node(blob, offset, NULL)) > 0) {
+ name = fdt_get_name(blob, offset, NULL);
+ prop = fdt_getprop(blob, offset, "iommus", &proplen);
+ if (!prop)
+ continue;
+ debug("node %s iommus proplen %d\n", name, proplen);
+
+ if (proplen == 12) {
+ int sid = fdt32_to_cpu(prop[1]);
+
+ config_smmu_fdt_device_sid(blob, offset, sid);
+ } else if (proplen != 4) {
+ debug("node %s ignore unexpected iommus proplen=%d\n",
+ name, proplen);
+ }
+ }
+
+ return 0;
+}
+
+static int ft_add_optee_node(void *fdt, bd_t *bd)
+{
+ const char *path, *subpath;
+ int offs;
+
+ /*
+ * No TEE space allocated indicating no TEE running, so no
+ * need to add optee node in dts
+ */
+ if (!boot_pointer[1])
+ return 0;
+
+ offs = fdt_increase_size(fdt, 512);
+ if (offs) {
+ printf("No Space for dtb\n");
+ return 1;
+ }
+
+ path = "/firmware";
+ offs = fdt_path_offset(fdt, path);
+ if (offs < 0) {
+ path = "/";
+ offs = fdt_path_offset(fdt, path);
+
+ if (offs < 0) {
+ printf("Could not find root node.\n");
+ return offs;
+ }
+
+ subpath = "firmware";
+ offs = fdt_add_subnode(fdt, offs, subpath);
+ if (offs < 0) {
+ printf("Could not create %s node.\n", subpath);
+ return offs;
+ }
+ }
+
+ subpath = "optee";
+ offs = fdt_add_subnode(fdt, offs, subpath);
+ if (offs < 0) {
+ printf("Could not create %s node.\n", subpath);
+ return offs;
+ }
+
+ fdt_setprop_string(fdt, offs, "compatible", "linaro,optee-tz");
+ fdt_setprop_string(fdt, offs, "method", "smc");
+
+ return 0;
+}
+
+int ft_system_setup(void *blob, bd_t *bd)
+{
+ int ret;
+
+ update_fdt_with_owned_resources(blob);
+
+ if (is_imx8qm()) {
+ ret = config_smmu_fdt(blob);
+ if (ret)
+ return ret;
+ }
+
+ return ft_add_optee_node(blob, bd);
+}
diff --git a/arch/arm/mach-imx/imx8/image.c b/arch/arm/mach-imx/imx8/image.c
new file mode 100644
index 00000000000..58a29e8a03c
--- /dev/null
+++ b/arch/arm/mach-imx/imx8/image.c
@@ -0,0 +1,246 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <mmc.h>
+#include <spi_flash.h>
+#include <nand.h>
+#include <asm/arch/image.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/mach-imx/boot_mode.h>
+
+#define MMC_DEV 0
+#define QSPI_DEV 1
+#define NAND_DEV 2
+#define QSPI_NOR_DEV 3
+
+static int __get_container_size(ulong addr)
+{
+ struct container_hdr *phdr;
+ struct boot_img_t *img_entry;
+ struct signature_block_hdr *sign_hdr;
+ u8 i = 0;
+ u32 max_offset = 0, img_end;
+
+ phdr = (struct container_hdr *)addr;
+ if (phdr->tag != 0x87 && phdr->version != 0x0) {
+ debug("Wrong container header\n");
+ return -EFAULT;
+ }
+
+ max_offset = sizeof(struct container_hdr);
+
+ img_entry = (struct boot_img_t *)(addr + sizeof(struct container_hdr));
+ for (i = 0; i < phdr->num_images; i++) {
+ img_end = img_entry->offset + img_entry->size;
+ if (img_end > max_offset)
+ max_offset = img_end;
+
+ debug("img[%u], end = 0x%x\n", i, img_end);
+
+ img_entry++;
+ }
+
+ if (phdr->sig_blk_offset != 0) {
+ sign_hdr = (struct signature_block_hdr *)(addr + phdr->sig_blk_offset);
+ u16 len = sign_hdr->length_lsb + (sign_hdr->length_msb << 8);
+
+ if (phdr->sig_blk_offset + len > max_offset)
+ max_offset = phdr->sig_blk_offset + len;
+
+ debug("sigblk, end = 0x%x\n", phdr->sig_blk_offset + len);
+ }
+
+ return max_offset;
+}
+
+static int get_container_size(void *dev, int dev_type, unsigned long offset)
+{
+ u8 *buf = malloc(CONTAINER_HDR_ALIGNMENT);
+ int ret = 0;
+
+ if (!buf) {
+ printf("Malloc buffer failed\n");
+ return -ENOMEM;
+ }
+
+#ifdef CONFIG_SPL_MMC_SUPPORT
+ if (dev_type == MMC_DEV) {
+ unsigned long count = 0;
+ struct mmc *mmc = (struct mmc *)dev;
+
+ count = blk_dread(mmc_get_blk_desc(mmc),
+ offset / mmc->read_bl_len,
+ CONTAINER_HDR_ALIGNMENT / mmc->read_bl_len,
+ buf);
+ if (count == 0) {
+ printf("Read container image from MMC/SD failed\n");
+ return -EIO;
+ }
+ }
+#endif
+
+#ifdef CONFIG_SPL_SPI_LOAD
+ if (dev_type == QSPI_DEV) {
+ struct spi_flash *flash = (struct spi_flash *)dev;
+
+ ret = spi_flash_read(flash, offset,
+ CONTAINER_HDR_ALIGNMENT, buf);
+ if (ret != 0) {
+ printf("Read container image from QSPI failed\n");
+ return -EIO;
+ }
+ }
+#endif
+
+#ifdef CONFIG_SPL_NAND_SUPPORT
+ if (dev_type == NAND_DEV) {
+ ret = nand_spl_load_image(offset, CONTAINER_HDR_ALIGNMENT,
+ buf);
+ if (ret != 0) {
+ printf("Read container image from NAND failed\n");
+ return -EIO;
+ }
+ }
+#endif
+
+#ifdef CONFIG_SPL_NOR_SUPPORT
+ if (dev_type == QSPI_NOR_DEV)
+ memcpy(buf, (const void *)offset, CONTAINER_HDR_ALIGNMENT);
+#endif
+
+ ret = __get_container_size((ulong)buf);
+
+ free(buf);
+
+ return ret;
+}
+
+static unsigned long get_boot_device_offset(void *dev, int dev_type)
+{
+ unsigned long offset = 0;
+
+ if (dev_type == MMC_DEV) {
+ struct mmc *mmc = (struct mmc *)dev;
+
+ if (IS_SD(mmc) || mmc->part_config == MMCPART_NOAVAILABLE) {
+ offset = CONTAINER_HDR_MMCSD_OFFSET;
+ } else {
+ u8 part = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);
+
+ if (part == 1 || part == 2) {
+ if (is_imx8qxp() && is_soc_rev(CHIP_REV_B))
+ offset = CONTAINER_HDR_MMCSD_OFFSET;
+ else
+ offset = CONTAINER_HDR_EMMC_OFFSET;
+ } else {
+ offset = CONTAINER_HDR_MMCSD_OFFSET;
+ }
+ }
+ } else if (dev_type == QSPI_DEV) {
+ offset = CONTAINER_HDR_QSPI_OFFSET;
+ } else if (dev_type == NAND_DEV) {
+ offset = CONTAINER_HDR_NAND_OFFSET;
+ } else if (dev_type == QSPI_NOR_DEV) {
+ offset = CONTAINER_HDR_QSPI_OFFSET + 0x08000000;
+ }
+
+ return offset;
+}
+
+static int get_imageset_end(void *dev, int dev_type)
+{
+ unsigned long offset1 = 0, offset2 = 0;
+ int value_container[2];
+
+ offset1 = get_boot_device_offset(dev, dev_type);
+ offset2 = CONTAINER_HDR_ALIGNMENT + offset1;
+
+ value_container[0] = get_container_size(dev, dev_type, offset1);
+ if (value_container[0] < 0) {
+ printf("Parse seco container failed %d\n", value_container[0]);
+ return value_container[0];
+ }
+
+ debug("seco container size 0x%x\n", value_container[0]);
+
+ value_container[1] = get_container_size(dev, dev_type, offset2);
+ if (value_container[1] < 0) {
+ debug("Parse scu container failed %d, only seco container\n",
+ value_container[1]);
+ /* return seco container total size */
+ return value_container[0] + offset1;
+ }
+
+ debug("scu container size 0x%x\n", value_container[1]);
+
+ return value_container[1] + offset2;
+}
+
+#ifdef CONFIG_SPL_SPI_LOAD
+unsigned long spl_spi_get_uboot_offs(struct spi_flash *flash)
+{
+ int end;
+
+ end = get_imageset_end(flash, QSPI_DEV);
+ end = ROUND(end, SZ_1K);
+
+ printf("Load image from QSPI 0x%x\n", end);
+
+ return end;
+}
+#endif
+
+#ifdef CONFIG_SPL_MMC_SUPPORT
+unsigned long spl_mmc_get_uboot_raw_sector(struct mmc *mmc)
+{
+ int end;
+
+ end = get_imageset_end(mmc, MMC_DEV);
+ end = ROUND(end, SZ_1K);
+
+ printf("Load image from MMC/SD 0x%x\n", end);
+
+ return end / mmc->read_bl_len;
+}
+#endif
+
+#ifdef CONFIG_SPL_NAND_SUPPORT
+uint32_t spl_nand_get_uboot_raw_page(void)
+{
+ int end;
+
+ end = get_imageset_end((void *)NULL, NAND_DEV);
+ end = ROUND(end, SZ_16K);
+
+ printf("Load image from NAND 0x%x\n", end);
+
+ return end;
+}
+#endif
+
+#ifdef CONFIG_SPL_NOR_SUPPORT
+unsigned long spl_nor_get_uboot_base(void)
+{
+ int end;
+
+ /* Calculate the image set end,
+ * if it is less than CONFIG_SYS_UBOOT_BASE(0x8281000),
+ * we use CONFIG_SYS_UBOOT_BASE
+ * Otherwise, use the calculated address
+ */
+ end = get_imageset_end((void *)NULL, QSPI_NOR_DEV);
+ if (end <= CONFIG_SYS_UBOOT_BASE)
+ end = CONFIG_SYS_UBOOT_BASE;
+ else
+ end = ROUND(end, SZ_1K);
+
+ printf("Load image from NOR 0x%x\n", end);
+
+ return end;
+}
+#endif
diff --git a/arch/arm/mach-imx/imx8/lowlevel_init.S b/arch/arm/mach-imx/imx8/lowlevel_init.S
new file mode 100644
index 00000000000..a66243c5e4f
--- /dev/null
+++ b/arch/arm/mach-imx/imx8/lowlevel_init.S
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2019 NXP
+ */
+
+#include <config.h>
+
+.align 8
+.global boot_pointer
+boot_pointer:
+ .space 32
+
+/*
+ * Routine: save_boot_params (called after reset from start.S)
+ */
+
+.global save_boot_params
+save_boot_params:
+ /* The firmware provided ATAG/FDT address can be found in r2/x0 */
+ adr x0, boot_pointer
+ stp x1, x2, [x0], #16
+ stp x3, x4, [x0], #16
+
+ /*
+ * We use absolute address not PC relative address for return.
+ * When running SPL on iMX8, the A core starts at address 0,
+ * an alias to OCRAM 0x100000, our linker address for SPL is
+ * from 0x100000. So using absolute address can jump to the OCRAM
+ * address from the alias. The alias only map first 96KB of OCRAM,
+ * so this require the SPL size can't beyond 96KB.
+ * But when using SPL DM, the size increase significantly and
+ * always beyonds 96KB. That's why we have to jump to OCRAM.
+ * Normal u-boot also runs into this codes, but there is no impact.
+ */
+ ldr x1, =save_boot_params_ret
+ br x1
diff --git a/arch/arm/mach-imx/imx8/parse-container.c b/arch/arm/mach-imx/imx8/parse-container.c
new file mode 100644
index 00000000000..32f78bdddfb
--- /dev/null
+++ b/arch/arm/mach-imx/imx8/parse-container.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018-2019 NXP
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <spl.h>
+#include <asm/arch/image.h>
+
+static struct boot_img_t *read_auth_image(struct spl_image_info *spl_image,
+ struct spl_load_info *info,
+ struct container_hdr *container,
+ int image_index,
+ u32 container_sector)
+{
+ struct boot_img_t *images;
+ ulong sector;
+ u32 sectors;
+
+ if (image_index > container->num_images) {
+ debug("Invalid image number\n");
+ return NULL;
+ }
+
+ images = (struct boot_img_t *)((u8 *)container +
+ sizeof(struct container_hdr));
+
+ if (images[image_index].offset % info->bl_len) {
+ printf("%s: image%d offset not aligned to %u\n",
+ __func__, image_index, info->bl_len);
+ return NULL;
+ }
+
+ sectors = roundup(images[image_index].size, info->bl_len) /
+ info->bl_len;
+ sector = images[image_index].offset / info->bl_len +
+ container_sector;
+
+ debug("%s: container: %p sector: %lu sectors: %u\n", __func__,
+ container, sector, sectors);
+ if (info->read(info, sector, sectors,
+ (void *)images[image_index].entry) != sectors) {
+ printf("%s wrong\n", __func__);
+ return NULL;
+ }
+
+ return &images[image_index];
+}
+
+static int read_auth_container(struct spl_image_info *spl_image,
+ struct spl_load_info *info, ulong sector)
+{
+ struct container_hdr *container = NULL;
+ u16 length;
+ u32 sectors;
+ int i, size;
+
+ size = roundup(CONTAINER_HDR_ALIGNMENT, info->bl_len);
+ sectors = size / info->bl_len;
+
+ /*
+ * It will not override the ATF code, so safe to use it here,
+ * no need malloc
+ */
+ container = (struct container_hdr *)spl_get_load_buffer(-size, size);
+
+ debug("%s: container: %p sector: %lu sectors: %u\n", __func__,
+ container, sector, sectors);
+ if (info->read(info, sector, sectors, container) != sectors)
+ return -EIO;
+
+ if (container->tag != 0x87 && container->version != 0x0) {
+ printf("Wrong container header");
+ return -ENOENT;
+ }
+
+ if (!container->num_images) {
+ printf("Wrong container, no image found");
+ return -ENOENT;
+ }
+
+ length = container->length_lsb + (container->length_msb << 8);
+ debug("Container length %u\n", length);
+
+ if (length > CONTAINER_HDR_ALIGNMENT) {
+ size = roundup(length, info->bl_len);
+ sectors = size / info->bl_len;
+
+ container = (struct container_hdr *)spl_get_load_buffer(-size, size);
+
+ debug("%s: container: %p sector: %lu sectors: %u\n",
+ __func__, container, sector, sectors);
+ if (info->read(info, sector, sectors, container) !=
+ sectors)
+ return -EIO;
+ }
+
+ for (i = 0; i < container->num_images; i++) {
+ struct boot_img_t *image = read_auth_image(spl_image, info,
+ container, i,
+ sector);
+
+ if (!image)
+ return -EINVAL;
+
+ if (i == 0) {
+ spl_image->load_addr = image->dst;
+ spl_image->entry_point = image->entry;
+ }
+ }
+
+ return 0;
+}
+
+int spl_load_imx_container(struct spl_image_info *spl_image,
+ struct spl_load_info *info, ulong sector)
+{
+ return read_auth_container(spl_image, info, sector);
+}