diff options
Diffstat (limited to 'arch/arm/mach-imx/imx8')
-rw-r--r-- | arch/arm/mach-imx/imx8/Kconfig | 13 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8/Makefile | 7 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8/cpu.c | 189 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8/fdt.c | 292 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8/image.c | 246 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8/lowlevel_init.S | 36 | ||||
-rw-r--r-- | arch/arm/mach-imx/imx8/parse-container.c | 120 |
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); +} |