diff --git a/arch/arm/include/asm/arch-rockchip/uimage.h b/arch/arm/include/asm/arch-rockchip/uimage.h new file mode 100644 index 0000000000..a95090bffc --- /dev/null +++ b/arch/arm/include/asm/arch-rockchip/uimage.h @@ -0,0 +1,18 @@ +/* + * (C) Copyright 2019 Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __ROCKCHIP_UIMAGE_H_ +#define __ROCKCHIP_UIMAGE_H_ + +#define UIMG_I(fmt, args...) printf("uImage: "fmt, ##args) + +void *uimage_load_bootables(void); +int uimage_sysmem_free_each(image_header_t *img); +int uimage_sysmem_reserve_each(image_header_t *hdr); +int rockchip_read_uimage_dtb(void *fdt_addr, char **hash, int *hash_size); + +#endif + diff --git a/arch/arm/mach-rockchip/Kconfig b/arch/arm/mach-rockchip/Kconfig index 18b2d05cd8..f78d27c3a9 100644 --- a/arch/arm/mach-rockchip/Kconfig +++ b/arch/arm/mach-rockchip/Kconfig @@ -592,6 +592,14 @@ config ROCKCHIP_FIT_IMAGE help This enables loading dtb from fit image. +config ROCKCHIP_UIMAGE + bool "Enable support for legacy uImage" + depends on !FIT_SIGNATURE && USING_KERNEL_DTB + select CMD_BOOT_UIMAGE + default n + help + This enables loading dtb from uImage image. + config ROCKCHIP_EARLY_DISTRO_DTB bool "Enable support for distro dtb early" depends on DISTRO_DEFAULTS && USING_KERNEL_DTB && CMD_FS_GENERIC diff --git a/arch/arm/mach-rockchip/Makefile b/arch/arm/mach-rockchip/Makefile index a7a200c4dd..32c50e65d9 100644 --- a/arch/arm/mach-rockchip/Makefile +++ b/arch/arm/mach-rockchip/Makefile @@ -30,6 +30,7 @@ obj-y += hotkey.o obj-$(CONFIG_USING_KERNEL_DTB) += kernel_dtb.o obj-$(CONFIG_ROCKCHIP_FIT_IMAGE) += fit.o +obj-$(CONFIG_ROCKCHIP_UIMAGE) += uimage.o obj-$(CONFIG_ROCKCHIP_SMCCC) += rockchip_smccc.o obj-$(CONFIG_ROCKCHIP_VENDOR_PARTITION) += vendor.o obj-$(CONFIG_ROCKCHIP_RESOURCE_IMAGE) += resource_img.o diff --git a/arch/arm/mach-rockchip/uimage.c b/arch/arm/mach-rockchip/uimage.c new file mode 100644 index 0000000000..dced46f20e --- /dev/null +++ b/arch/arm/mach-rockchip/uimage.c @@ -0,0 +1,257 @@ +/* + * (C) Copyright 2019 Rockchip Electronics Co., Ltd + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +static int uimage_load_one(struct blk_desc *dev_desc, disk_partition_t *part, + int pos_off, int size, void *dst) +{ + u32 blknum, blkoff; + u32 unused; + ulong blksz; + void *buf; + + blksz = dev_desc->blksz; + blkoff = pos_off / blksz; + unused = pos_off - blkoff * blksz; + blknum = DIV_ROUND_UP(size, blksz) + !!unused; + + if (!size) + return -EINVAL; + + if (!IS_ALIGNED(unused, ARCH_DMA_MINALIGN)) { + buf = memalign(ARCH_DMA_MINALIGN, blknum * blksz); + if (!buf) + return -ENOMEM; + + if (blk_dread(dev_desc, part->start + blkoff, + blknum, buf) != blknum) { + free(buf); + return -EIO; + } + + memcpy(dst, buf + unused, size); + free(buf); + } else { + if (blk_dread(dev_desc, part->start + blkoff, + blknum, (void *)((ulong)dst - unused)) != blknum) + return -EIO; + } + + return 0; +} + +static image_header_t *uimage_get_hdr(struct blk_desc *dev_desc, + disk_partition_t *part) +{ + image_header_t *hdr; + + hdr = memalign(ARCH_DMA_MINALIGN, RK_BLK_SIZE); + if (!hdr) + return NULL; + + if (blk_dread(dev_desc, part->start, 1, hdr) != 1) + goto err; + + if (!image_check_magic(hdr) || (image_get_type(hdr) != IH_TYPE_MULTI)) + goto err; + + return hdr; +err: + free(hdr); + return NULL; +} + +void *uimage_load_bootables(void) +{ + struct blk_desc *dev_desc; + disk_partition_t part; + image_header_t *hdr; + char *part_name; + ulong raddr; + ulong kaddr; + ulong faddr; + int blknum; + + raddr = env_get_ulong("ramdisk_addr_r", 16, 0); + kaddr = env_get_ulong("kernel_addr_r", 16, 0); + faddr = env_get_ulong("fdt_addr_r", 16, 0); + + if (!faddr || !kaddr || !raddr) + return NULL; + + dev_desc = rockchip_get_bootdev(); + if (!dev_desc) { + UIMG_I("No dev_desc\n"); + return NULL; + } + + if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) + part_name = PART_RECOVERY; + else + part_name = PART_BOOT; + + if (part_get_info_by_name(dev_desc, part_name, &part) < 0) { + UIMG_I("No %s partition\n", part_name); + return NULL; + } + + hdr = uimage_get_hdr(dev_desc, &part); + if (!hdr) + return NULL; + + /* load */ + blknum = DIV_ROUND_UP(image_get_image_size(hdr), dev_desc->blksz); + hdr = sysmem_alloc(MEM_UIMAGE, blknum * dev_desc->blksz); + if (!hdr) + return NULL; + + if (blk_dread(dev_desc, part.start, blknum, (void *)hdr) != blknum) { + UIMG_I("Failed to read %s data\n", part.name); + return NULL; + } + + return hdr; +} + +int uimage_sysmem_reserve_each(image_header_t *hdr) +{ + ulong raddr, kaddr, faddr; + ulong data, size; + int blknum; + int blksz = RK_BLK_SIZE; + + raddr = env_get_ulong("ramdisk_addr_r", 16, 0); + kaddr = env_get_ulong("kernel_addr_r", 16, 0); + faddr = env_get_ulong("fdt_addr_r", 16, 0); + + if (!faddr || !kaddr || !raddr) + return -EINVAL; + + /* kernel */ + image_multi_getimg(hdr, 0, &data, &size); + blknum = DIV_ROUND_UP(size, blksz); + if (!sysmem_alloc_base(MEM_KERNEL, (phys_addr_t)kaddr, + blknum * blksz)) + return -ENOMEM; + + /* ramdisk */ + image_multi_getimg(hdr, 1, &data, &size); + blknum = DIV_ROUND_UP(size, blksz); + if (!sysmem_alloc_base(MEM_RAMDISK, (phys_addr_t)raddr, + blknum * blksz)) + return -ENOMEM; + + /* fdt */ + image_multi_getimg(hdr, 2, &data, &size); + blknum = DIV_ROUND_UP(size, blksz); + if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)faddr, + blknum * blksz)) + return -ENOMEM; + + env_set_hex("fdt_high", faddr); + env_set_hex("initrd_high", raddr); + env_set("bootm-reloc-at", "y"); + + return 0; +} + +int uimage_sysmem_free_each(image_header_t *img) +{ + ulong raddr, kaddr, faddr; + + raddr = env_get_ulong("ramdisk_addr_r", 16, 0); + kaddr = env_get_ulong("kernel_addr_r", 16, 0); + faddr = env_get_ulong("fdt_addr_r", 16, 0); + + sysmem_free((phys_addr_t)img); + sysmem_free((phys_addr_t)raddr); + sysmem_free((phys_addr_t)kaddr); + sysmem_free((phys_addr_t)faddr); + + return 0; +} + +int rockchip_read_uimage_dtb(void *fdt_addr, char **hash, int *hash_size) +{ + struct blk_desc *dev_desc; + disk_partition_t part; + image_header_t *hdr; + char *part_name; + ulong data, offset; + ulong size; +#ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE + ulong dst; + int idx = 3; +#else + int idx = 2; +#endif + int ret; + + dev_desc = rockchip_get_bootdev(); + if (!dev_desc) { + printf("No dev_desc!\n"); + return ENODEV; + } + + if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY) + part_name = PART_RECOVERY; + else + part_name = PART_BOOT; + + if (part_get_info_by_name(dev_desc, part_name, &part) < 0) { + UIMG_I("No %s partition\n", part_name); + return -ENODEV; + } + + hdr = uimage_get_hdr(dev_desc, &part); + if (!hdr) + return -ENODEV; + + image_multi_getimg(hdr, idx, &data, &size); + offset = data - (ulong)hdr; + free(hdr); + +#ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE + /* reserve enough space before fdt */ + dst = (ulong)fdt_addr - + ALIGN(size, dev_desc->blksz) - CONFIG_SYS_FDT_PAD; + + ret = uimage_load_one(dev_desc, &part, offset, size, (void *)dst); + if (ret) { + UIMG_I("Failed to load resource file, ret=%d\n", ret); + return ret; + } + + if (!sysmem_alloc_base(MEM_RESOURCE, (phys_addr_t)dst, + ALIGN(size, RK_BLK_SIZE))) + return -ENOMEM; + + ret = resource_create_ram_list(dev_desc, (void *)dst); + if (ret) { + UIMG_I("Failed to create resource list, ret=%d\n", ret); + return ret; + } + + printf("Found DTB in uImage.%d\n", idx); + ret = rockchip_read_resource_dtb(fdt_addr, hash, hash_size); +#else + printf("DTB(uimage.%d): rk-kernel.dtb\n", idx); + ret = uimage_load_one(dev_desc, &part, offset, size, fdt_addr); +#endif + if (ret) { + UIMG_I("Failed to load fdt, ret=%d\n", ret); + return ret; + } + + return 0; +}