diff options
33 files changed, 697 insertions, 184 deletions
diff --git a/Documentation/boards/imx/nxp-imx8mm-evk.rst b/Documentation/boards/imx/nxp-imx8mm-evk.rst index f0dfc53ed0..aa70419139 100644 --- a/Documentation/boards/imx/nxp-imx8mm-evk.rst +++ b/Documentation/boards/imx/nxp-imx8mm-evk.rst @@ -85,5 +85,16 @@ installation to the eMMC boot partition requires special handling: then afterwards, the newly written boot partition is activated (This is controlled by the barebox ``mmcX.boot`` variable). +The following steps are required to write the image to the QSPI NOR flash: + + - The 32KiB preamble MMC preamble must be stripped. + + - The QSPI NOR partition ``barebox`` must be erased before the stripped + image is written. The erase size depends on the stripped image size but + always start at offset 0. + + - Write the stripped barebox image to the QSPI NOR partition ``barebox`` + at offset 0. + The ``barebox_update`` command takes care of this and need just be supplied a barebox image as argument. diff --git a/Documentation/boards/imx/nxp-imx8mn-evk.rst b/Documentation/boards/imx/nxp-imx8mn-evk.rst index 177fc59c10..597db57eaf 100644 --- a/Documentation/boards/imx/nxp-imx8mn-evk.rst +++ b/Documentation/boards/imx/nxp-imx8mn-evk.rst @@ -80,5 +80,17 @@ installation to the eMMC boot partition requires special handling: start at an offset when booting from eMMC boot partitions, thus the first 32KiB must be stripped. +The following steps are required to write the image to the QSPI NOR flash: + + - Strip the 32KiB preamble, like it is done for the eMMC boot partition case + (see above). + + - The QSPI NOR partition ``barebox`` must be erased before the stripped + image is written. The erase size depends on the stripped image size but + always start at offset 0. + + - Write the stripped barebox image to the QSPI NOR partition ``barebox`` + at offset 0. + The ``barebox_update`` command takes care of this and need just be supplied a barebox image as argument. diff --git a/Documentation/boards/imx/nxp-imx8mp-evk.rst b/Documentation/boards/imx/nxp-imx8mp-evk.rst index 53cdd904ab..cfd1153e15 100644 --- a/Documentation/boards/imx/nxp-imx8mp-evk.rst +++ b/Documentation/boards/imx/nxp-imx8mp-evk.rst @@ -88,5 +88,17 @@ installation to the eMMC boot partition requires special handling: start at an offset when booting from eMMC boot partitions, thus the first 32KiB must be stripped. +The following steps are required to write the image to the QSPI NOR flash: + + - Strip the 32KiB preamble, like it is done for the eMMC boot partition case + (see above). + + - The QSPI NOR partition ``barebox`` must be erased before the stripped + image is written. The erase size depends on the stripped image size but + always start at offset 0. + + - Write the stripped barebox image to the QSPI NOR partition ``barebox`` + at offset 0. + The ``barebox_update`` command takes care of this and need just be supplied a barebox image as argument. 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>; + }; + }; + +}; + ®_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>; + }; + }; + +}; + ®_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); diff --git a/common/bbu.c b/common/bbu.c index 3ec17216cb..ed41c92f38 100644 --- a/common/bbu.c +++ b/common/bbu.c @@ -154,36 +154,47 @@ struct bbu_handler *bbu_find_handler_by_device(const char *devicepath) return NULL; } -static int bbu_check_of_compat(struct bbu_data *data) +static int bbu_check_of_compat(struct bbu_data *data, unsigned short of_compat_nr) { + const struct imd_header *imd = data->imd_data; + const struct imd_header *of_compat; struct device_node *root_node; const char *machine, *str; int ret; - const struct imd_header *of_compat; if (!IS_ENABLED(CONFIG_OFDEVICE) || !IS_ENABLED(CONFIG_IMD)) return 0; - of_compat = imd_find_type(data->imd_data, IMD_TYPE_OF_COMPATIBLE); - if (!of_compat) - return 0; - root_node = of_get_root_node(); if (!root_node) return 0; - str = imd_string_data(of_compat, 0); - - if (of_machine_is_compatible(str)) { - pr_info("Devicetree compatible \"%s\" matches current machine\n", str); + if (!of_compat_nr) return 0; - } ret = of_property_read_string(root_node, "compatible", &machine); if (ret) return 0; - if (!bbu_force(data, "machine is incompatible with \"%s\", have \"%s\"\n", str, machine)) + for (; of_compat_nr; of_compat_nr--) { + of_compat = imd_find_type(imd, IMD_TYPE_OF_COMPATIBLE); + if (!of_compat) + return 0; + + str = imd_string_data(of_compat, 0); + + if (of_machine_is_compatible(str)) { + pr_info("Devicetree compatible \"%s\" matches current machine\n", str); + return 0; + } + + pr_debug("machine is incompatible with \"%s\", have \"%s\"\n", + str, machine); + + imd = of_compat; + } + + if (!bbu_force(data, "incompatible machine \"%s\"\n", machine)) return -EINVAL; return 0; @@ -191,6 +202,7 @@ static int bbu_check_of_compat(struct bbu_data *data) static int bbu_check_metadata(struct bbu_data *data) { + unsigned short imd_of_compat_nr = 0; const struct imd_header *imd; int ret; char *str; @@ -211,6 +223,9 @@ static int bbu_check_metadata(struct bbu_data *data) imd_for_each(data->imd_data, imd) { uint32_t type = imd_read_type(imd); + if (imd_read_type(imd) == IMD_TYPE_OF_COMPATIBLE) + imd_of_compat_nr++; + if (!imd_is_string(type)) continue; @@ -220,7 +235,7 @@ static int bbu_check_metadata(struct bbu_data *data) free(str); } - ret = bbu_check_of_compat(data); + ret = bbu_check_of_compat(data, imd_of_compat_nr); if (ret) return ret; diff --git a/common/filetype.c b/common/filetype.c index 68ea45861d..820bc89ea6 100644 --- a/common/filetype.c +++ b/common/filetype.c @@ -69,6 +69,7 @@ static const struct filetype_str filetype_str[] = { [filetype_imx_image_v2] = { "i.MX image (v2)", "imx-image-v2" }, [filetype_layerscape_image] = { "Layerscape image", "layerscape-PBL" }, [filetype_layerscape_qspi_image] = { "Layerscape QSPI image", "layerscape-qspi-PBL" }, + [filetype_nxp_fspi_image] = { "NXP FlexSPI image", "nxp-fspi-image" }, [filetype_ubootvar] = { "U-Boot environmemnt variable data", "ubootvar" }, [filetype_stm32_image_fsbl_v1] = { "STM32MP FSBL image (v1)", "stm32-fsbl-v1" }, @@ -409,6 +410,10 @@ enum filetype file_detect_type(const void *_buf, size_t bufsize) if (is_imx_flash_header_v2(_buf)) return filetype_imx_image_v2; + if (buf[0] == cpu_to_be32(FCFB_HEAD_TAG) && + buf[1] == cpu_to_le32(FCFB_VERSION)) + return filetype_nxp_fspi_image; + if (buf[8] == 0xAA995566 && buf[9] == 0x584C4E58) return filetype_zynq_image; diff --git a/drivers/mci/imx-esdhc-pbl.c b/drivers/mci/imx-esdhc-pbl.c index 40c2882dc4..7c5febb7a8 100644 --- a/drivers/mci/imx-esdhc-pbl.c +++ b/drivers/mci/imx-esdhc-pbl.c @@ -104,117 +104,17 @@ static int esdhc_read_blocks(struct fsl_esdhc_host *host, void *dst, size_t len) } #ifdef CONFIG_ARCH_IMX -static int esdhc_search_header(struct fsl_esdhc_host *host, - struct imx_flash_header_v2 **header_pointer, - void *buffer, u32 *offset, u32 ivt_offset) +static int imx_read_blocks(void *dest, size_t len, 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 = esdhc_read_blocks(host, buf, - *offset + ivt_offset + SECTOR_SIZE); - if (ret) - return ret; - - hdr = buf + *offset + ivt_offset; - - if (!is_imx_flash_header_v2(hdr)) { - pr_debug("IVT header not found on SD card. " - "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; + return esdhc_read_blocks(priv, dest, len); } static int esdhc_load_image(struct fsl_esdhc_host *host, 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(); - len = ALIGN(len, SECTOR_SIZE); - - ret = esdhc_search_header(host, &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); - } - - ret = esdhc_read_blocks(host, buf, offset + len); - 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(); + return imx_load_image(address, entry, offset, ivt_offset, start, + SECTOR_SIZE, imx_read_blocks, host); } static void imx_esdhc_init(struct fsl_esdhc_host *host, diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 05c6473a28..ce3789c096 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -15,7 +15,6 @@ #include <driver.h> #include <of.h> #include <spi/spi.h> -#include <spi/flash.h> #include <xfuncs.h> #include <malloc.h> #include <errno.h> @@ -205,7 +204,6 @@ static int m25p_probe(struct device *dev) { struct spi_device *spi = (struct spi_device *)dev->type_data; struct spi_mem *spimem = spi->mem; - struct flash_platform_data *data; struct m25p *flash; struct spi_nor *nor; struct spi_nor_hwcaps hwcaps = { @@ -218,8 +216,6 @@ static int m25p_probe(struct device *dev) bool use_large_blocks; int ret; - data = dev->platform_data; - flash = xzalloc(sizeof *flash); nor = &flash->spi_nor; @@ -245,14 +241,7 @@ static int m25p_probe(struct device *dev) dev->priv = (void *)flash; - if (data && data->name) - flash->mtd.name = data->name; - - if (data && data->type) - flash_name = data->type; - else if (data && data->name) - flash_name = data->name; - else if (dev->id_entry) + if (dev->id_entry) flash_name = dev->id_entry->name; else flash_name = NULL; /* auto-detect */ @@ -267,8 +256,6 @@ static int m25p_probe(struct device *dev) device_id = DEVICE_ID_SINGLE; if (dev->of_node) flash_name = of_alias_get(dev->of_node); - else if (data && data->name) - flash_name = data->name; if (!flash_name) { device_id = DEVICE_ID_DYNAMIC; diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index b6a0c79d2f..b5dbe4de3e 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -17,7 +17,6 @@ #include <clock.h> #include <spi/spi.h> -#include <spi/flash.h> #include <linux/math64.h> #include <linux/mtd/mtd.h> @@ -599,7 +598,6 @@ add_dataflash_otp(struct spi_device *spi, char *name, { struct dataflash *priv; struct mtd_info *device; - struct flash_platform_data *pdata = spi->dev.platform_data; char *otp_tag = ""; int err = 0; @@ -617,7 +615,7 @@ add_dataflash_otp(struct spi_device *spi, char *name, name); device = &priv->mtd; - device->name = (pdata && pdata->name) ? pdata->name : "dataflash"; + device->name = "dataflash"; device->size = nr_pages * (uint64_t)pagesize; device->erasesize = pagesize; device->writesize = pagesize; diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index f83c3f02a0..8f6726ca4b 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -19,7 +19,6 @@ #include <linux/mtd/cfi.h> #include <linux/mtd/spi-nor.h> #include <of.h> -#include <spi/flash.h> #define SPI_NOR_MAX_ID_LEN 6 #define SPI_NOR_MAX_ADDR_WIDTH 4 diff --git a/include/filetype.h b/include/filetype.h index 1a7d145555..783418c652 100644 --- a/include/filetype.h +++ b/include/filetype.h @@ -59,6 +59,7 @@ enum filetype { filetype_rockchip_rkns_image, filetype_fip, filetype_qemu_fw_cfg, + filetype_nxp_fspi_image, filetype_max, }; diff --git a/include/mach/imx/bbu.h b/include/mach/imx/bbu.h index c9b239c698..451ae15740 100644 --- a/include/mach/imx/bbu.h +++ b/include/mach/imx/bbu.h @@ -26,6 +26,8 @@ struct imx_dcd_v2_entry; */ #define IMX_BBU_FLAG_PARTITION_STARTS_AT_HEADER (1 << 17) +#define IMX_BBU_FLAG_ERASE BIT(30) + /* * The upper 16 bit of the flags passes to the below functions are reserved * for i.MX specific flags @@ -84,6 +86,10 @@ int imx8m_bbu_internal_mmcboot_register_handler(const char *name, const char *de int imx_bbu_external_nor_register_handler(const char *name, const char *devicefile, unsigned long flags); +int imx8m_bbu_internal_flexspi_nor_register_handler(const char *name, + const char *devicefile, + unsigned long flags); + #else static inline int imx51_bbu_internal_mmc_register_handler(const char *name, const char *devicefile, @@ -196,6 +202,13 @@ imx7_bbu_internal_spi_i2c_register_handler(const char *name, char *devicefile, return -ENOSYS; } +static inline int +imx8m_bbu_internal_flexspi_nor_register_handler(const char *name, const char *devicefile, + unsigned long flags); +{ + return -ENOSYS; +} + #endif #if defined(CONFIG_BAREBOX_UPDATE_IMX_EXTERNAL_NAND) diff --git a/include/mach/imx/imx-header.h b/include/mach/imx/imx-header.h index 8e968e6efb..b11b57c372 100644 --- a/include/mach/imx/imx-header.h +++ b/include/mach/imx/imx-header.h @@ -97,6 +97,8 @@ static inline bool is_imx_flash_header_v2(const void *blob) struct config_data { uint32_t image_load_addr; uint32_t image_ivt_offset; + uint32_t image_flexspi_ivt_offset; + uint32_t image_flexspi_fcfb_offset; uint32_t image_size; uint32_t max_load_size; uint32_t load_size; @@ -149,4 +151,120 @@ enum imx_dcd_v2_check_cond { until_any_bit_set = 3, /* until ((*address & mask) != 0) { ...} */ } __attribute__((packed)); +/* FlexSPI conifguration block FCFB */ +#define FCFB_HEAD_TAG 0x46434642 /* "FCFB" */ +#define FCFB_VERSION 0x56010000 /* V<major><minor><bugfix> = V100 */ +#define FCFB_SAMLPE_CLK_SRC_INTERNAL 0 +#define FCFB_DEVTYPE_SERIAL_NOR 1 +#define FCFB_SFLASH_PADS_SINGLE 1 +#define FCFB_SFLASH_PADS_DUAL 2 +#define FCFB_SFLASH_PADS_QUAD 4 +#define FCFB_SFLASH_PADS_OCTAL 8 +#define FCFB_SERIAL_CLK_FREQ_30MHZ 1 +#define FCFB_SERIAL_CLK_FREQ_50MHZ 2 +#define FCFB_SERIAL_CLK_FREQ_60MHZ 3 +#define FCFB_SERIAL_CLK_FREQ_75MHZ 4 +#define FCFB_SERIAL_CLK_FREQ_80MHZ 5 +#define FCFB_SERIAL_CLK_FREQ_100MHZ 6 +#define FCFB_SERIAL_CLK_FREQ_133MHZ 7 +#define FCFB_SERIAL_CLK_FREQ_166MHZ 8 + +/* Instruction set for the LUT register. */ +#define LUT_STOP 0x00 +#define LUT_CMD 0x01 +#define LUT_ADDR 0x02 +#define LUT_CADDR_SDR 0x03 +#define LUT_MODE 0x04 +#define LUT_MODE2 0x05 +#define LUT_MODE4 0x06 +#define LUT_MODE8 0x07 +#define LUT_NXP_WRITE 0x08 +#define LUT_NXP_READ 0x09 +#define LUT_LEARN_SDR 0x0A +#define LUT_DATSZ_SDR 0x0B +#define LUT_DUMMY 0x0C +#define LUT_DUMMY_RWDS_SDR 0x0D +#define LUT_JMP_ON_CS 0x1F +#define LUT_CMD_DDR 0x21 +#define LUT_ADDR_DDR 0x22 +#define LUT_CADDR_DDR 0x23 +#define LUT_MODE_DDR 0x24 +#define LUT_MODE2_DDR 0x25 +#define LUT_MODE4_DDR 0x26 +#define LUT_MODE8_DDR 0x27 +#define LUT_WRITE_DDR 0x28 +#define LUT_READ_DDR 0x29 +#define LUT_LEARN_DDR 0x2A +#define LUT_DATSZ_DDR 0x2B +#define LUT_DUMMY_DDR 0x2C +#define LUT_DUMMY_RWDS_DDR 0x2D + +/* + * Macro for constructing the LUT entries with the following + * register layout: + * + * ----------------------- + * | INSTR | PAD | OPRND | + * ----------------------- + */ +#define PAD_SHIFT 8 +#define INSTR_SHIFT 10 +#define OPRND_SHIFT 16 + +/* Macros for constructing the LUT register. */ +#define LUT_DEF(ins, pad, opr) \ + (((ins) << INSTR_SHIFT) | ((pad) << PAD_SHIFT) | (opr)) + +struct imx_fcfb_common { + uint32_t tag; + uint32_t version; + uint32_t reserved1; + uint8_t read_sample; + uint8_t datahold; + uint8_t datasetup; + uint8_t coladdrwidth; + uint8_t devcfgenable; + uint8_t reserved2[3]; + uint32_t devmodeseq; + uint32_t devmodearg; + uint8_t cmd_enable; + uint8_t reserved3[3]; + uint32_t cmd_seq[4]; + uint32_t cmd_arg[4]; + uint32_t controllermisc; + uint8_t dev_type; + uint8_t sflash_pad; + uint8_t serial_clk; + uint8_t lut_custom; + uint32_t reserved4[2]; + uint32_t sflashA1; + uint32_t sflashA2; + uint32_t sflashB1; + uint32_t sflashB2; + uint32_t cspadover; + uint32_t sclkpadover; + uint32_t datapadover; + uint32_t dqspadover; + uint32_t timeout_ms; + uint32_t commandInt_ns; + uint32_t datavalid_ns; + uint16_t busyoffset; + uint16_t busybitpolarity; + struct { + struct { + uint16_t instr[8]; + } seq[16]; + } lut; + uint16_t lut_custom_seq[24]; + uint8_t reserved5[16]; +} __attribute__((packed)); + +struct imx_fcfb_nor { + struct imx_fcfb_common memcfg; + uint32_t page_sz; + uint32_t sector_sz; + uint32_t ipcmd_serial_clk; + uint8_t reserved[52]; +} __attribute__((packed)); + #endif diff --git a/include/mach/imx/xload.h b/include/mach/imx/xload.h index 88757c7ebf..a52b1e8ea1 100644 --- a/include/mach/imx/xload.h +++ b/include/mach/imx/xload.h @@ -17,6 +17,9 @@ int imx7_nand_start_image(void); int imx8m_esdhc_load_image(int instance, bool start); int imx8mn_esdhc_load_image(int instance, bool start); int imx8mp_esdhc_load_image(int instance, bool start); +int imx8mm_qspi_load_image(int instance, bool start); +int imx8mn_qspi_load_image(int instance, bool start); +int imx8mp_qspi_load_image(int instance, bool start); void imx8mm_load_bl33(void *bl33); void imx8mn_load_bl33(void *bl33); @@ -26,6 +29,11 @@ void __noreturn imx8mm_load_and_start_image_via_tfa(void); void __noreturn imx8mn_load_and_start_image_via_tfa(void); void __noreturn imx8mp_load_and_start_image_via_tfa(void); +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); + int imx_image_size(void); int piggydata_size(void); diff --git a/include/spi/flash.h b/include/spi/flash.h deleted file mode 100644 index 796d649d9a..0000000000 --- a/include/spi/flash.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -#ifndef LINUX_SPI_FLASH_H -#define LINUX_SPI_FLASH_H - -struct mtd_partition; - -/** - * struct flash_platform_data: board-specific flash data - * @name: optional flash device name (eg, as used with mtdparts=) - * @parts: optional array of mtd_partitions for static partitioning - * @nr_parts: number of mtd_partitions for static partitoning - * @type: optional flash device type (e.g. m25p80 vs m25p64), for use - * with chips that can't be queried for JEDEC or other IDs - * - * Board init code (in arch/.../mach-xxx/board-yyy.c files) can - * provide information about SPI flash parts (such as DataFlash) to - * help set up the device and its appropriate default partitioning. - * - * Note that for DataFlash, sizes for pages, blocks, and sectors are - * rarely powers of two; and partitions should be sector-aligned. - */ -struct flash_platform_data { - char *name; - struct mtd_partition *parts; - unsigned int nr_parts; - char *type; - - /* we'll likely add more ... use JEDEC IDs, etc */ -}; - -#endif diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c index 439912a805..1f96b38390 100644 --- a/scripts/imx/imx-image.c +++ b/scripts/imx/imx-image.c @@ -20,6 +20,7 @@ #include "imx.h" #include <include/filetype.h> +#include <include/linux/sizes.h> #define FLASH_HEADER_OFFSET 0x400 #define ARM_HEAD_SIZE_INDEX (ARM_HEAD_SIZE_OFFSET / sizeof(uint32_t)) @@ -34,7 +35,7 @@ static uint32_t dcdtable[MAX_DCD]; static int curdcd; -static int create_usb_image; +static bool create_usb_image; static char *prgname; /* @@ -289,17 +290,30 @@ static int write_mem_v1(uint32_t addr, uint32_t val, int width, int set_bits, in return 0; } +static bool flexspi_image(const struct config_data *data) +{ + /* + * | FlexSPI-FCFB | FlexSPI-IVT + * ----------------------------------------- + * i.MX8MM | 0x0 | 0x1000 + * i.MX8MN/P | 0x400 | 0x0 + */ + + return data->image_flexspi_ivt_offset || data->image_flexspi_fcfb_offset; +} + /* * ============================================================================ * i.MX flash header v2 handling. Found on i.MX50, i.MX53 and i.MX6 * ============================================================================ */ -static size_t add_header_v2(const struct config_data *data, void *buf) +static size_t +add_header_v2(const struct config_data *data, void *buf, uint32_t offset, + size_t header_len) { struct imx_flash_header_v2 *hdr; int dcdsize = curdcd * sizeof(uint32_t); - int offset = data->image_ivt_offset; uint32_t loadaddr = data->image_load_addr; uint32_t imagesize = data->load_size; @@ -308,7 +322,7 @@ static size_t add_header_v2(const struct config_data *data, void *buf) * Restrict the imagesize to the PBL if given. * Also take the alignment for CSF into account. */ - imagesize = roundup(data->pbl_code_size + HEADER_LEN, 0x4); + imagesize = roundup(data->pbl_code_size + header_len, 0x4); if (data->csf) imagesize = roundup(imagesize, 0x1000); } @@ -320,7 +334,7 @@ static size_t add_header_v2(const struct config_data *data, void *buf) hdr->header.length = htobe16(32); hdr->header.version = IVT_VERSION; - hdr->entry = loadaddr + HEADER_LEN; + hdr->entry = loadaddr + header_len; if (dcdsize) hdr->dcd_ptr = loadaddr + offset + offsetof(struct imx_flash_header_v2, dcd_header); if (create_usb_image) { @@ -362,6 +376,114 @@ static size_t add_header_v2(const struct config_data *data, void *buf) return imagesize; } +#define LUT_PAD_1 0 +#define LUT_PAD_2 1 +#define LUT_PAD_4 2 +#define LUT_PAD_8 3 + +static size_t add_flexspi_fcfb_header(const struct config_data *data, void *buf) +{ + uint32_t fcfb_offset = data->image_flexspi_fcfb_offset; + const struct imx_fcfb_nor nor_conf = { + .memcfg = { + .tag = htobe32(FCFB_HEAD_TAG), + .version = htole32(FCFB_VERSION), + .read_sample = FCFB_SAMLPE_CLK_SRC_INTERNAL, + /* flash CS hold time, recommended by RM */ + .datahold = 0x03, + /* flash CS setup time, recommended by RM */ + .datasetup = 0x03, + /* 3 - Hyperflash, 12/13 serial NAND, 0 - other */ + .coladdrwidth = 0, + .devcfgenable = 0, + .cmd_enable = 0, + .controllermisc = 0, + .dev_type = FCFB_DEVTYPE_SERIAL_NOR, + .sflash_pad = FCFB_SFLASH_PADS_SINGLE, + .serial_clk = FCFB_SERIAL_CLK_FREQ_50MHZ, + .sflashA1 = htole32(SZ_256M), + .lut.seq[0] = { + .instr = { + htole16(LUT_DEF(LUT_CMD, LUT_PAD_1, 0x0b)), + htole16(LUT_DEF(LUT_ADDR, LUT_PAD_1, 24)), + htole16(LUT_DEF(LUT_DUMMY, LUT_PAD_1, 8)), + htole16(LUT_DEF(LUT_NXP_READ, LUT_PAD_1, 4)), + htole16(LUT_DEF(LUT_STOP, LUT_PAD_1, 0)), + }, + }, + }, + }; + + buf += fcfb_offset; + memcpy(buf, &nor_conf, sizeof(nor_conf)); + + return sizeof(nor_conf); +} + +#define FLEXSPI_HEADER_LEN HEADER_LEN + +static size_t +add_flexspi_header(const struct config_data *data, void **_buf, size_t *header_len) +{ + uint32_t ivt_offset = data->image_flexspi_ivt_offset; + size_t size; + size_t len; + void *buf; + + if (!flexspi_image(data)) + return 0; + + if (data->signed_hdmi_firmware_file) { + free(*_buf); + fprintf(stderr, "Signed HDMI firmware and FlexSPI compatible image is not supported!\n"); + exit(1); + } + + /* + * Extend the header to be able to build build one image which can be + * used for: USB/SD/eMMC/eMMC-Boot/QSPI/barebox-chainload. + */ + buf = realloc(*_buf, *header_len + FLEXSPI_HEADER_LEN); + if (!buf) + exit(1); + + *_buf = buf; + + size = add_flexspi_fcfb_header(data, buf); + + /* + * The following table list the offsets we need to ensure for + * the one image approach. + * + * | i.MX8MM | i.MX8MN/P | + * -----------------------------+---------+-----------+ + * SD/eMMC primary image offset | 0 | 0/32K | + * FlexSPI primary image offset | 0 | 4K | + * SD/eMMC-IVT offset | 1K | 0 | + * SD/eMMC-IVT image entry | 8K | 8K | + * FlexSPI-IVT offset | 4K | 0 | + * FlexSPI-IVT image entry | 8K | 4K | + * + * According the above table the rom-loader for i.MX8MM will + * search for the image on the same place (8K). On the other + * hand the rom-loader for the i.MX8MN/P will look for it at + * 8K for SD/eMMC case or at 4K for FlexSPI case. + */ + len = *header_len; + if (data->cpu_type == IMX_CPU_IMX8MM) + len += FLEXSPI_HEADER_LEN; + + if (data->cpu_type == IMX_CPU_IMX8MP || + data->cpu_type == IMX_CPU_IMX8MN) + buf += SZ_4K; + + size += add_header_v2(data, buf, ivt_offset, len); + + *header_len += FLEXSPI_HEADER_LEN; + + return size; +} + static void usage(const char *prgname) { fprintf(stderr, "usage: %s [OPTIONS]\n\n" @@ -739,9 +861,9 @@ int main(int argc, char *argv[]) void *infile; struct stat s; int outfd; - int dcd_only = 0; + bool dcd_only = false; int now = 0; - int add_barebox_header = 0; + bool add_barebox_header = false; uint32_t barebox_image_size = 0; struct config_data data = { .image_ivt_offset = 0xffffffff, @@ -771,16 +893,16 @@ int main(int argc, char *argv[]) data.pbl_code_size = strtoul(optarg, NULL, 0); break; case 'b': - add_barebox_header = 1; + add_barebox_header = true; break; case 'd': - dcd_only = 1; + dcd_only = true; break; case 's': data.sign_image = 1; break; case 'u': - create_usb_image = 1; + create_usb_image = true; break; case 'e': data.encrypt_image = 1; @@ -904,8 +1026,10 @@ int main(int argc, char *argv[]) } } + barebox_image_size += add_flexspi_header(&data, &buf, &header_len); barebox_image_size += add_header_v2(&data, buf + - signed_hdmi_firmware_size); + signed_hdmi_firmware_size, + data.image_ivt_offset, header_len); break; default: fprintf(stderr, "Congratulations! You're welcome to implement header version %d\n", diff --git a/scripts/imx/imx.c b/scripts/imx/imx.c index c91dfda214..e3169bace6 100644 --- a/scripts/imx/imx.c +++ b/scripts/imx/imx.c @@ -609,6 +609,26 @@ do_signed_hdmi_firmware(struct config_data *data, int argc, char *argv[]) return 0; } +static int do_flexspi_ivtofs(struct config_data *data, int argc, char *argv[]) +{ + if (argc < 2) + return -EINVAL; + + data->image_flexspi_ivt_offset = strtoul(argv[1], NULL, 0); + + return 0; +} + +static int do_flexspi_fcfbofs(struct config_data *data, int argc, char *argv[]) +{ + if (argc < 2) + return -EINVAL; + + data->image_flexspi_fcfb_offset = strtoul(argv[1], NULL, 0); + + return 0; +} + struct command cmds[] = { { .name = "wm", @@ -667,6 +687,12 @@ struct command cmds[] = { }, { .name = "signed_hdmi_firmware", .parse = do_signed_hdmi_firmware, + }, { + .name = "flexspi_fcfbofs", + .parse = do_flexspi_fcfbofs, + }, { + .name = "flexspi_ivtofs", + .parse = do_flexspi_ivtofs, }, }; |