We used to use the ROM API for USB loading only, now with i.MX93 we fully rely on the ROM API also with SD/eMMC and other boot sources. The ROM provides us information about the boot source. There are generally two types of boot sources: seekable for storage devices like SD/eMMC and streamable for USB. the load_image call must be handled slightly different for both types of boot sources, so we fist detect which type we have and call the right load_image function accordingly. Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> --- arch/arm/mach-imx/romapi.c | 156 ++++++++++++++++++++++++++++++++++++- include/mach/imx/romapi.h | 1 + 2 files changed, 153 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-imx/romapi.c b/arch/arm/mach-imx/romapi.c index 29c2d4005c..1b1800f1e0 100644 --- a/arch/arm/mach-imx/romapi.c +++ b/arch/arm/mach-imx/romapi.c @@ -3,6 +3,8 @@ #define pr_fmt(fmt) "romapi: " fmt #include <common.h> +#include <linux/bitfield.h> +#include <soc/imx9/flash_header.h> #include <asm/sections.h> #include <mach/imx/romapi.h> #include <mach/imx/atf.h> @@ -14,7 +16,39 @@ #include <init.h> #include <pbl.h> -static int imx_romapi_load(struct rom_api *rom_api, void *adr, size_t size) +#define BOOTROM_INFO_VERSION 0x1 +#define BOOTROM_INFO_BOOT_DEVICE 0x2 +#define BOOTROM_INFO_DEVICE_PAGE_SIZE 0x3 +#define BOOTROM_INFO_OFFSET_IVT 0x4 +#define BOOTROM_INFO_BOOT_STAGE 0x5 +#define BOOTROM_INFO_OFFSET_IMAGE 0x6 + +#define BOOTROM_BOOT_DEVICE_INTERFACE GENMASK(23, 16) +#define BOOTROM_BOOT_DEVICE_SD 0x1 +#define BOOTROM_BOOT_DEVICE_EMMC 0x2 +#define BOOTROM_BOOT_DEVICE_FLEXSPI_NOR 0x4 +#define BOOTROM_BOOT_DEVICE_LPSPI 0x6 +#define BOOTROM_BOOT_DEVICE_FLEXSPI_NAND 0x8 +#define BOOTROM_BOOT_DEVICE_USB 0xe +#define BOOTROM_BOOT_DEVICE_INSTANCE GENMASK(15, 8) +#define BOOTROM_BOOT_DEVICE_STATE GENMASK(7, 0) + +static int imx_bootrom_query(struct rom_api *rom_api, uint32_t type, uint32_t *__info) +{ + static uint32_t info; + uint32_t xor = type ^ (uintptr_t)&info; + int ret; + + ret = rom_api->query_boot_infor(type, &info, xor); + if (ret != ROM_API_OKAY) + return -EIO; + + *__info = info; + + return 0; +} + +static int imx_romapi_load_stream(struct rom_api *rom_api, void *adr, size_t size) { while (size) { size_t chunksize = min(size, (size_t)1024); @@ -30,6 +64,22 @@ static int imx_romapi_load(struct rom_api *rom_api, void *adr, size_t size) adr += chunksize; size -= chunksize; } + return 0; +} + +static int imx_romapi_load_seekable(struct rom_api *rom_api, void *adr, uint32_t offset, + size_t size) +{ + int ret; + + size = PAGE_ALIGN(size); + + ret = rom_api->download_image(adr, offset, size, + (uintptr_t)adr ^ offset ^ size); + if (ret != ROM_API_OKAY) { + pr_err("Failed to load piggy data (ret = %x)\n", ret); + return -EIO; + } return 0; } @@ -37,9 +87,9 @@ static int imx_romapi_load(struct rom_api *rom_api, void *adr, size_t size) /* read piggydata via a bootrom callback and place it behind our copy in SDRAM */ static int imx_romapi_load_image(struct rom_api *rom_api) { - return imx_romapi_load(rom_api, - (void *)MX8M_ATF_BL33_BASE_ADDR + barebox_pbl_size, - __image_end - __piggydata_start); + return imx_romapi_load_stream(rom_api, + (void *)MX8M_ATF_BL33_BASE_ADDR, + __image_end - __piggydata_start); } int imx8mp_romapi_load_image(void) @@ -56,6 +106,104 @@ int imx8mn_romapi_load_image(void) return imx8mp_romapi_load_image(); } +static int imx_romapi_boot_device_seekable(struct rom_api *rom_api) +{ + uint32_t boot_device, boot_device_type, boot_device_state; + int ret; + bool seekable; + + ret = imx_bootrom_query(rom_api, BOOTROM_INFO_BOOT_DEVICE, &boot_device); + if (ret) + return ret; + + boot_device_type = FIELD_GET(BOOTROM_BOOT_DEVICE_INTERFACE, boot_device); + + switch (boot_device_type) { + case BOOTROM_BOOT_DEVICE_SD: + case BOOTROM_BOOT_DEVICE_FLEXSPI_NOR: + case BOOTROM_BOOT_DEVICE_LPSPI: + case BOOTROM_BOOT_DEVICE_FLEXSPI_NAND: + seekable = true; + break; + case BOOTROM_BOOT_DEVICE_USB: + seekable = false; + break; + case BOOTROM_BOOT_DEVICE_EMMC: + boot_device_state = FIELD_GET(BOOTROM_BOOT_DEVICE_STATE, boot_device); + if (boot_device_state & BIT(0)) + seekable = false; + else + seekable = true; + break; + default: + return -EINVAL; + } + + return seekable; +} + +int imx93_romapi_load_image(void) +{ + struct rom_api *rom_api = (void *)0x1980; + int ret; + int seekable; + uint32_t offset, image_offset; + void *bl33 = (void *)MX93_ATF_BL33_BASE_ADDR; + struct flash_header_v3 *fh; + + OPTIMIZER_HIDE_VAR(rom_api); + + seekable = imx_romapi_boot_device_seekable(rom_api); + if (seekable < 0) + return seekable; + + if (!seekable) { + int align_size = ALIGN(barebox_pbl_size, 1024) - barebox_pbl_size; + void *pbl_size_aligned = bl33 + ALIGN(barebox_pbl_size, 1024); + + /* + * The USB protocol uploads in chunks of 1024 bytes. This means + * the initial piggy data up to the next 1KiB boundary is already + * transferred. Align up the start address to this boundary. + */ + + return imx_romapi_load_stream(rom_api, + pbl_size_aligned, + __image_end - __piggydata_start - align_size); + } + + ret = imx_bootrom_query(rom_api, BOOTROM_INFO_OFFSET_IMAGE, &offset); + if (ret) + return ret; + + pr_debug("%s: IVT offset on boot device: 0x%08x\n", __func__, offset); + + ret = imx_romapi_load_seekable(rom_api, bl33, offset, 4096); + if (ret) + return ret; + + fh = bl33; + + if (fh->tag != 0x87) { + pr_err("Invalid IVT header: 0x%02x, expected 0x87\n", fh->tag); + return -EINVAL; + } + + image_offset = fh->img[0].offset; + + pr_debug("%s: offset in image: 0x%08x\n", __func__, image_offset); + + /* + * We assume the first image in the first container is the barebox image, + * which is what the imx9image call in images/Makefile.imx generates. + */ + ret = imx_romapi_load_seekable(rom_api, bl33, offset + image_offset, barebox_image_size); + if (ret) + return ret; + + return ret; +} + const u32 *imx8m_get_bootrom_log(void) { if (current_el() == 3) { diff --git a/include/mach/imx/romapi.h b/include/mach/imx/romapi.h index 8ea7fbfb04..959d165a33 100644 --- a/include/mach/imx/romapi.h +++ b/include/mach/imx/romapi.h @@ -37,6 +37,7 @@ enum boot_dev_type_e { int imx8mp_romapi_load_image(void); int imx8mn_romapi_load_image(void); +int imx93_romapi_load_image(void); /* only call after DRAM has been configured */ void imx8m_save_bootrom_log(void *dst); -- 2.39.2