diff options
Diffstat (limited to 'arch/arm/mach-imx/spl_imx_romapi.c')
-rw-r--r-- | arch/arm/mach-imx/spl_imx_romapi.c | 409 |
1 files changed, 409 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/spl_imx_romapi.c b/arch/arm/mach-imx/spl_imx_romapi.c new file mode 100644 index 00000000000..9a86f5c133f --- /dev/null +++ b/arch/arm/mach-imx/spl_imx_romapi.c @@ -0,0 +1,409 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + */ + +#include <errno.h> +#include <image.h> +#include <imx_container.h> +#include <log.h> +#include <asm/global_data.h> +#include <linux/libfdt.h> +#include <spl.h> +#include <asm/arch/sys_proto.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Caller need ensure the offset and size to align with page size */ +ulong spl_romapi_raw_seekable_read(u32 offset, u32 size, void *buf) +{ + int ret; + + debug("%s 0x%x, size 0x%x\n", __func__, offset, size); + + ret = rom_api_download_image(buf, offset, size); + + if (ret == ROM_API_OKAY) + return size; + + printf("%s Failure when load 0x%x, size 0x%x\n", __func__, offset, size); + + return 0; +} + +ulong __weak spl_romapi_get_uboot_base(u32 image_offset, u32 rom_bt_dev) +{ + return image_offset + + (CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR * 512 - 0x8000); +} + +static int is_boot_from_stream_device(u32 boot) +{ + u32 interface; + + interface = boot >> 16; + if (interface >= BT_DEV_TYPE_USB) + return 1; + + if (interface == BT_DEV_TYPE_MMC && (boot & 1)) + return 1; + + return 0; +} + +static ulong spl_romapi_read_seekable(struct spl_load_info *load, + ulong offset, ulong byte, + void *buf) +{ + return spl_romapi_raw_seekable_read(offset, byte, buf); +} + +static int spl_romapi_load_image_seekable(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev, + u32 rom_bt_dev) +{ + int ret; + u32 offset; + u32 pagesize, size; + struct legacy_img_hdr *header; + u32 image_offset; + + ret = rom_api_query_boot_infor(QUERY_IVT_OFF, &offset); + if (ret != ROM_API_OKAY) + goto err; + + ret = rom_api_query_boot_infor(QUERY_PAGE_SZ, &pagesize); + if (ret != ROM_API_OKAY) + goto err; + + ret = rom_api_query_boot_infor(QUERY_IMG_OFF, &image_offset); + if (ret != ROM_API_OKAY) + goto err; + + header = (struct legacy_img_hdr *)(CONFIG_SPL_IMX_ROMAPI_LOADADDR); + + printf("image offset 0x%x, pagesize 0x%x, ivt offset 0x%x\n", + image_offset, pagesize, offset); + + offset = spl_romapi_get_uboot_base(image_offset, rom_bt_dev); + + size = ALIGN(sizeof(struct legacy_img_hdr), pagesize); + ret = rom_api_download_image((u8 *)header, offset, size); + + if (ret != ROM_API_OKAY) { + printf("ROMAPI: download failure offset 0x%x size 0x%x\n", + offset, size); + return -1; + } + + if (IS_ENABLED(CONFIG_SPL_LOAD_FIT) && image_get_magic(header) == FDT_MAGIC) { + struct spl_load_info load; + + memset(&load, 0, sizeof(load)); + spl_set_bl_len(&load, pagesize); + load.read = spl_romapi_read_seekable; + return spl_load_simple_fit(spl_image, &load, offset, header); + } else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) && + valid_container_hdr((void *)header)) { + struct spl_load_info load; + + memset(&load, 0, sizeof(load)); + spl_set_bl_len(&load, pagesize); + load.read = spl_romapi_read_seekable; + + ret = spl_load_imx_container(spl_image, &load, offset); + } else { + /* TODO */ + puts("Can't support legacy image\n"); + return -1; + } + + return 0; + +err: + puts("ROMAPI: Failure query boot infor pagesize/offset\n"); + return -1; +} + +struct stream_state { + u8 *base; + u8 *end; + u32 pagesize; +}; + +static ulong spl_romapi_read_stream(struct spl_load_info *load, ulong sector, + ulong count, void *buf) +{ + struct stream_state *ss = load->priv; + u8 *end = (u8*)(sector + count); + u32 bytes; + int ret; + + if (end > ss->end) { + bytes = end - ss->end; + bytes += ss->pagesize - 1; + bytes /= ss->pagesize; + bytes *= ss->pagesize; + + debug("downloading another 0x%x bytes\n", bytes); + ret = rom_api_download_image(ss->end, 0, bytes); + + if (ret != ROM_API_OKAY) { + printf("Failure download %d\n", bytes); + return 0; + } + + ss->end += bytes; + } + + memcpy(buf, (void *)(sector), count); + return count; +} + +static ulong spl_ram_load_read(struct spl_load_info *load, ulong sector, + ulong count, void *buf) +{ + memcpy(buf, (void *)(sector), count); + + if (load->priv) { + ulong *p = (ulong *)load->priv; + ulong total = sector + count; + + if (total > *p) + *p = total; + } + + return count; +} + +static u8 *search_fit_header(u8 *p, int size) +{ + int i; + + for (i = 0; i < size; i += 4) + if (genimg_get_format(p + i) == IMAGE_FORMAT_FIT) + return p + i; + + return NULL; +} + +static u8 *search_container_header(u8 *p, int size) +{ + int i = 0; + u8 *hdr; + + for (i = 0; i < size; i += 4) { + hdr = p + i; + if (valid_container_hdr((void *)hdr) && + (*(hdr + 1) != 0 || *(hdr + 2) != 0)) + return p + i; + } + + return NULL; +} + +static u8 *search_img_header(u8 *p, int size) +{ + if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) + return search_fit_header(p, size); + else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) + return search_container_header(p, size); + + return NULL; +} + +static u32 img_header_size(void) +{ + if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) + return sizeof(struct fdt_header); + else if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) + return sizeof(struct container_hdr); + + return 0; +} + +static int img_info_size(void *img_hdr) +{ +#ifdef CONFIG_SPL_LOAD_FIT + return fit_get_size(img_hdr); +#elif defined CONFIG_SPL_LOAD_IMX_CONTAINER + struct container_hdr *container = img_hdr; + + return (container->length_lsb + (container->length_msb << 8)); +#else + return 0; +#endif +} + +static int img_total_size(void *img_hdr) +{ + if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) { + int total = get_container_size((ulong)img_hdr, NULL); + + if (total < 0) { + printf("invalid container image\n"); + return 0; + } + + return total; + } + + return 0; +} + +static int spl_romapi_load_image_stream(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev) +{ + struct spl_load_info load; + u32 pagesize, pg; + int ret; + int i = 0; + u8 *p = (u8 *)CONFIG_SPL_IMX_ROMAPI_LOADADDR; + u8 *phdr = NULL; + int imagesize; + int total; + + ret = rom_api_query_boot_infor(QUERY_PAGE_SZ, &pagesize); + + if (ret != ROM_API_OKAY) + puts("failure at query_boot_info\n"); + + pg = pagesize; + if (pg < 1024) + pg = 1024; + + for (i = 0; i < 640; i++) { + ret = rom_api_download_image(p, 0, pg); + + if (ret != ROM_API_OKAY) { + puts("Stream(USB) download failure\n"); + return -1; + } + + phdr = search_img_header(p, pg); + p += pg; + + if (phdr) + break; + } + + if (!phdr) { + puts("Can't found uboot image in 640K range\n"); + return -1; + } + + if (p - phdr < img_header_size()) { + ret = rom_api_download_image(p, 0, pg); + + if (ret != ROM_API_OKAY) { + puts("Stream(USB) download failure\n"); + return -1; + } + + p += pg; + } + + imagesize = img_info_size(phdr); + printf("Find img info 0x%p, size %d\n", phdr, imagesize); + + if (p - phdr < imagesize) { + imagesize -= p - phdr; + /*need pagesize hear after ROM fix USB problme*/ + imagesize += pg - 1; + imagesize /= pg; + imagesize *= pg; + + printf("Need continue download %d\n", imagesize); + + ret = rom_api_download_image(p, 0, imagesize); + + p += imagesize; + + if (ret != ROM_API_OKAY) { + printf("Failure download %d\n", imagesize); + return -1; + } + } + + if (IS_ENABLED(CONFIG_SPL_LOAD_FIT)) { + struct stream_state ss; + + ss.base = phdr; + ss.end = p; + ss.pagesize = pagesize; + + memset(&load, 0, sizeof(load)); + spl_set_bl_len(&load, 1); + load.read = spl_romapi_read_stream; + load.priv = &ss; + + return spl_load_simple_fit(spl_image, &load, (ulong)phdr, phdr); + } + + total = img_total_size(phdr); + total += 3; + total &= ~0x3; + + imagesize = total - (p - phdr); + + imagesize += pagesize - 1; + imagesize /= pagesize; + imagesize *= pagesize; + + printf("Download %d, Total size %d\n", imagesize, total); + + ret = rom_api_download_image(p, 0, imagesize); + if (ret != ROM_API_OKAY) + printf("ROM download failure %d\n", imagesize); + + memset(&load, 0, sizeof(load)); + spl_set_bl_len(&load, 1); + load.read = spl_ram_load_read; + + if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER)) + return spl_load_imx_container(spl_image, &load, (ulong)phdr); + + return -1; +} + +int board_return_to_bootrom(struct spl_image_info *spl_image, + struct spl_boot_device *bootdev) +{ + int ret; + u32 boot, bstage; + + ret = rom_api_query_boot_infor(QUERY_BT_DEV, &boot); + if (ret != ROM_API_OKAY) + goto err; + + ret = rom_api_query_boot_infor(QUERY_BT_STAGE, &bstage); + if (ret != ROM_API_OKAY) + goto err; + + printf("Boot Stage: "); + + switch (bstage) { + case BT_STAGE_PRIMARY: + printf("Primary boot\n"); + break; + case BT_STAGE_SECONDARY: + printf("Secondary boot\n"); + break; + case BT_STAGE_RECOVERY: + printf("Recovery boot\n"); + break; + case BT_STAGE_USB: + printf("USB boot\n"); + break; + default: + printf("Unknown (0x%x)\n", bstage); + } + + if (is_boot_from_stream_device(boot)) + return spl_romapi_load_image_stream(spl_image, bootdev); + + return spl_romapi_load_image_seekable(spl_image, bootdev, boot); +err: + puts("ROMAPI: failure at query_boot_info\n"); + return -1; +} |