xref: /rk3399_rockchip-uboot/common/spl/spl_rkfw.c (revision 6177e32d3d4c09f1cd997a8cf6edf0acbb090765)
113c5d8ecSJoseph Chen // SPDX-License-Identifier: GPL-2.0
213c5d8ecSJoseph Chen /*
313c5d8ecSJoseph Chen  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
413c5d8ecSJoseph Chen  */
513c5d8ecSJoseph Chen 
613c5d8ecSJoseph Chen #include <common.h>
7e3460df7SJason Zhu #include <android_image.h>
8e3460df7SJason Zhu #include <errno.h>
913c5d8ecSJoseph Chen #include <malloc.h>
10*6177e32dSJason Zhu #include <misc_decompress.h>
11aa415ed9SJoseph Chen #include <spl.h>
1213c5d8ecSJoseph Chen #include <spl_rkfw.h>
13e3460df7SJason Zhu #include <linux/kernel.h>
142241fc0fSJason Zhu #include <asm/arch/spl_resource_img.h>
1513c5d8ecSJoseph Chen 
161cb393f1SJason Zhu #ifdef CONFIG_SPL_ATF
1713c5d8ecSJoseph Chen static const __aligned(16) struct s_fip_name_id fip_name_id[] = {
1813c5d8ecSJoseph Chen 	{ BL30_IMAGE_NAME, UUID_SCP_FIRMWARE_BL30 },		/* optional */
1913c5d8ecSJoseph Chen 	{ BL31_IMAGE_NAME, UUID_EL3_RUNTIME_FIRMWARE_BL31 },	/* mandatory */
2013c5d8ecSJoseph Chen 	{ BL32_IMAGE_NAME, UUID_SECURE_PAYLOAD_BL32 },		/* optional */
2113c5d8ecSJoseph Chen };
2213c5d8ecSJoseph Chen 
2313c5d8ecSJoseph Chen static int file2comp_id(const char *file_name, u32 *comp_id)
2413c5d8ecSJoseph Chen {
2513c5d8ecSJoseph Chen 	int i;
2613c5d8ecSJoseph Chen 
2713c5d8ecSJoseph Chen 	for (i = 0; i < ARRAY_SIZE(fip_name_id); i++) {
2813c5d8ecSJoseph Chen 		if (!strcmp(file_name, fip_name_id[i].name)) {
2913c5d8ecSJoseph Chen 			*comp_id = fip_name_id[i].id;
3013c5d8ecSJoseph Chen 			return 0;
3113c5d8ecSJoseph Chen 		}
3213c5d8ecSJoseph Chen 	}
3313c5d8ecSJoseph Chen 
3413c5d8ecSJoseph Chen 	return -ENOENT;
3513c5d8ecSJoseph Chen }
3613c5d8ecSJoseph Chen 
3713c5d8ecSJoseph Chen static int open_image(const char *image_name, tboot_entry *entry,
3813c5d8ecSJoseph Chen 		      struct tag_tboot_header_2k *hdr)
3913c5d8ecSJoseph Chen {
4013c5d8ecSJoseph Chen 	u32 i, component_num, sign_offset;
4113c5d8ecSJoseph Chen 	component_data *pcompdata;
4213c5d8ecSJoseph Chen 	boot_component *pcomp;
4313c5d8ecSJoseph Chen 	int n_found = 0;
4413c5d8ecSJoseph Chen 	u32 comp_id;
4513c5d8ecSJoseph Chen 	int ret;
4613c5d8ecSJoseph Chen 
4713c5d8ecSJoseph Chen 	ret = file2comp_id(image_name, &comp_id);
4813c5d8ecSJoseph Chen 	if (ret) {
4913c5d8ecSJoseph Chen 		printf("Can't find unknown image: %s\n", image_name);
5013c5d8ecSJoseph Chen 		return ret;
5113c5d8ecSJoseph Chen 	}
5213c5d8ecSJoseph Chen 
5313c5d8ecSJoseph Chen 	component_num = (hdr->size >> 16) & 0xffff;
5413c5d8ecSJoseph Chen 	sign_offset = (hdr->size & 0xffff) << 2;
5513c5d8ecSJoseph Chen 	pcompdata = (component_data *)((char *)hdr + sizeof(tboot_header));
5613c5d8ecSJoseph Chen 	pcomp = (boot_component *)((char *)hdr + sign_offset + SIGNATURE_SIZE);
5713c5d8ecSJoseph Chen 
5813c5d8ecSJoseph Chen 	for (i = 0; i < component_num; i++) {
5913c5d8ecSJoseph Chen 		if (comp_id == pcomp->component_id) {
6013c5d8ecSJoseph Chen 			if (n_found < MAX_BL_CODE_NUM) {
6113c5d8ecSJoseph Chen 				memcpy(&entry[n_found].component, pcomp,
6213c5d8ecSJoseph Chen 				       sizeof(boot_component));
6313c5d8ecSJoseph Chen 				memcpy(&entry[n_found].compdata, pcompdata,
6413c5d8ecSJoseph Chen 				       sizeof(component_data));
6513c5d8ecSJoseph Chen 				n_found++;
6613c5d8ecSJoseph Chen 			} else {
6713c5d8ecSJoseph Chen 				printf("Image num excess max: %d!\n",
6813c5d8ecSJoseph Chen 				       MAX_BL_CODE_NUM);
6913c5d8ecSJoseph Chen 				return -EINVAL;
7013c5d8ecSJoseph Chen 			}
7113c5d8ecSJoseph Chen 		} else {
7213c5d8ecSJoseph Chen 			if (n_found > 0)
7313c5d8ecSJoseph Chen 				break;
7413c5d8ecSJoseph Chen 		}
7513c5d8ecSJoseph Chen 
7613c5d8ecSJoseph Chen 		pcomp++;
7713c5d8ecSJoseph Chen 		pcompdata++;
7813c5d8ecSJoseph Chen 	}
7913c5d8ecSJoseph Chen 
8013c5d8ecSJoseph Chen 	if (!n_found) {
8113c5d8ecSJoseph Chen 		printf("No find %s\n", image_name);
8213c5d8ecSJoseph Chen 		return -ENONET;
8313c5d8ecSJoseph Chen 	}
8413c5d8ecSJoseph Chen 
8513c5d8ecSJoseph Chen 	return n_found;
8613c5d8ecSJoseph Chen }
8713c5d8ecSJoseph Chen 
8813c5d8ecSJoseph Chen static int check_image(struct tag_tboot_header_2k *hdr)
8913c5d8ecSJoseph Chen {
9013c5d8ecSJoseph Chen 	u32 hash_format[] = { 0, 160, 256, 256 };
9113c5d8ecSJoseph Chen 
9213c5d8ecSJoseph Chen 	/* HASH format identifier */
9313c5d8ecSJoseph Chen 	return (hash_format[hdr->flags & 0x3] == 0) ? -EINVAL : 0;
9413c5d8ecSJoseph Chen }
9513c5d8ecSJoseph Chen 
9613c5d8ecSJoseph Chen static int load_image(struct spl_load_info *info,
9713c5d8ecSJoseph Chen 		      struct tag_tboot_header_2k *hdr,
9813c5d8ecSJoseph Chen 		      u32 image_sector,
9913c5d8ecSJoseph Chen 		      const char *image_name,
10013c5d8ecSJoseph Chen 		      uintptr_t *entry_point)
10113c5d8ecSJoseph Chen {
10213c5d8ecSJoseph Chen 	tboot_entry entry[MAX_BL_CODE_NUM];
10313c5d8ecSJoseph Chen 	void *image_buf = NULL;
10413c5d8ecSJoseph Chen 	ulong load_addr;
10513c5d8ecSJoseph Chen 	u32 sect_off;
10613c5d8ecSJoseph Chen 	u32 sect_cnt;
10713c5d8ecSJoseph Chen 	int image_num;
10813c5d8ecSJoseph Chen 	int i, ret;
10913c5d8ecSJoseph Chen 
11013c5d8ecSJoseph Chen 	/* Parse components from image header */
11113c5d8ecSJoseph Chen 	image_num = open_image(image_name, entry, hdr);
11213c5d8ecSJoseph Chen 	if (image_num < 0)
11313c5d8ecSJoseph Chen 		return image_num;
11413c5d8ecSJoseph Chen 
11513c5d8ecSJoseph Chen 	/* Get all component */
11613c5d8ecSJoseph Chen 	for (i = 0; i < image_num; i++) {
11713c5d8ecSJoseph Chen 		load_addr = entry[i].compdata.load_addr;
11813c5d8ecSJoseph Chen 		sect_cnt = entry[i].component.image_size;
11913c5d8ecSJoseph Chen 		sect_off = entry[i].component.storage_addr;
12013c5d8ecSJoseph Chen 
12113c5d8ecSJoseph Chen 		printf("%s[%d]: addr=0x%lx, size=0x%lx\n",
12213c5d8ecSJoseph Chen 		       image_name, i, load_addr, (ulong)sect_cnt * 512);
12313c5d8ecSJoseph Chen 
12413c5d8ecSJoseph Chen 		/*
12513c5d8ecSJoseph Chen 		 * MMC/NAND controller DMA can't access sram region, so:
12613c5d8ecSJoseph Chen 		 * data -> ddr buffer -> memcpy to sram region.
12713c5d8ecSJoseph Chen 		 */
128b35a1137SJoseph Chen 		if (load_addr < CONFIG_SYS_SDRAM_BASE ||
129b35a1137SJoseph Chen 		    load_addr >= CONFIG_SYS_SDRAM_BASE + SDRAM_MAX_SIZE) {
13013c5d8ecSJoseph Chen 			image_buf = memalign(ARCH_DMA_MINALIGN, sect_cnt * 512);
13113c5d8ecSJoseph Chen 			if (!image_buf) {
13213c5d8ecSJoseph Chen 				printf("%s: malloc failed\n", __func__);
13313c5d8ecSJoseph Chen 				return -ENOMEM;
13413c5d8ecSJoseph Chen 			}
13513c5d8ecSJoseph Chen 		} else {
13613c5d8ecSJoseph Chen 			image_buf = (void *)load_addr;
13713c5d8ecSJoseph Chen 		}
13813c5d8ecSJoseph Chen 
13913c5d8ecSJoseph Chen 		ret = info->read(info, image_sector + sect_off,
14013c5d8ecSJoseph Chen 				 sect_cnt, image_buf);
14113c5d8ecSJoseph Chen 		if (ret != sect_cnt) {
14213c5d8ecSJoseph Chen 			printf("Read '%s' failed at sector: %ld, ret=%d\n",
14313c5d8ecSJoseph Chen 			       image_name, (ulong)image_sector + sect_off, ret);
14413c5d8ecSJoseph Chen 			return -EIO;
14513c5d8ecSJoseph Chen 		}
14613c5d8ecSJoseph Chen 
14713c5d8ecSJoseph Chen 		/* Verify component */
14813c5d8ecSJoseph Chen 		ret = check_image(hdr);
14913c5d8ecSJoseph Chen 		if (ret) {
15013c5d8ecSJoseph Chen 			printf("%s[%d]: verify image fail!\n", image_name, i);
15113c5d8ecSJoseph Chen 			return ret;
15213c5d8ecSJoseph Chen 		}
15313c5d8ecSJoseph Chen 
15413c5d8ecSJoseph Chen 		/* Handle sram region */
15513c5d8ecSJoseph Chen 		if ((ulong)image_buf != load_addr) {
15613c5d8ecSJoseph Chen 			memcpy((void *)load_addr, image_buf, sect_cnt << 9);
15713c5d8ecSJoseph Chen 			free(image_buf);
15813c5d8ecSJoseph Chen 		}
15913c5d8ecSJoseph Chen 
16013c5d8ecSJoseph Chen 		/* Fill entry_point by first component */
16113c5d8ecSJoseph Chen 		if (i == 0)
16213c5d8ecSJoseph Chen 			*entry_point = (uintptr_t)load_addr;
16313c5d8ecSJoseph Chen 	}
16413c5d8ecSJoseph Chen 
16513c5d8ecSJoseph Chen 	return ret;
16613c5d8ecSJoseph Chen }
16713c5d8ecSJoseph Chen 
16813c5d8ecSJoseph Chen static int rkfw_load_trust(struct spl_load_info *info, u32 image_sector,
1691cb393f1SJason Zhu 			   struct spl_image_info *spl_image,
17013c5d8ecSJoseph Chen 			   int *found_rkfw, u32 try_count)
17113c5d8ecSJoseph Chen {
17213c5d8ecSJoseph Chen 	struct tag_tboot_header_2k hdr;
17313c5d8ecSJoseph Chen 	u32 sect_addr = image_sector;
17413c5d8ecSJoseph Chen 	int blkcnt = 4;	/* header sectors, 2KB */
17513c5d8ecSJoseph Chen 	int i, ret = 0;
17613c5d8ecSJoseph Chen 
17713c5d8ecSJoseph Chen 	/* Find valid image header */
17813c5d8ecSJoseph Chen 	for (i = 0; i < try_count; i++) {
17913c5d8ecSJoseph Chen 		sect_addr = image_sector + (i * RKFW_RETRY_SECTOR_SIZE);
18013c5d8ecSJoseph Chen 		if (blkcnt != info->read(info, sect_addr, blkcnt, &hdr))
18113c5d8ecSJoseph Chen 			continue;
18213c5d8ecSJoseph Chen 
18313c5d8ecSJoseph Chen 		if (hdr.tag == TBOOT_HEAD_TAG) {
18413c5d8ecSJoseph Chen 			/* Mark it */
18513c5d8ecSJoseph Chen 			*found_rkfw = 1;
18613c5d8ecSJoseph Chen 
18713c5d8ecSJoseph Chen 			/* bl31 is mandatory */
18813c5d8ecSJoseph Chen 			ret = load_image(info, &hdr, sect_addr,
1891cb393f1SJason Zhu 					 BL31_IMAGE_NAME, &spl_image->entry_point);
19013c5d8ecSJoseph Chen 			if (ret)
19113c5d8ecSJoseph Chen 				continue;
19213c5d8ecSJoseph Chen 
19313c5d8ecSJoseph Chen 			/* bl32 is optional */
19413c5d8ecSJoseph Chen 			ret = load_image(info, &hdr, sect_addr,
1951cb393f1SJason Zhu 					 BL32_IMAGE_NAME, &spl_image->entry_point_bl32);
19613c5d8ecSJoseph Chen 			if (ret) {
19713c5d8ecSJoseph Chen 				if (ret == -ENONET) {
1981cb393f1SJason Zhu 					spl_image->entry_point_bl32 = -1;	/* Not exist */
19913c5d8ecSJoseph Chen 					ret = 0;
20013c5d8ecSJoseph Chen 				} else {
20113c5d8ecSJoseph Chen 					continue;
20213c5d8ecSJoseph Chen 				}
20313c5d8ecSJoseph Chen 			}
20413c5d8ecSJoseph Chen 			break;
20513c5d8ecSJoseph Chen 		}
20613c5d8ecSJoseph Chen 	}
20713c5d8ecSJoseph Chen 
20813c5d8ecSJoseph Chen 	return ret;
20913c5d8ecSJoseph Chen }
2101cb393f1SJason Zhu #else
2111cb393f1SJason Zhu static int rkfw_load_trust(struct spl_load_info *info, u32 image_sector,
2121cb393f1SJason Zhu 			   struct spl_image_info *spl_image,
2131cb393f1SJason Zhu 			   int *found_rkfw, u32 try_count)
2141cb393f1SJason Zhu {
2151cb393f1SJason Zhu 	struct tag_second_loader_hdr hdr;
2161cb393f1SJason Zhu 	int i, ret, blkcnt = 4;	/* header sectors, 2KB */
2171cb393f1SJason Zhu 	char *load_addr;
2181cb393f1SJason Zhu 	u32 sect_addr;
2191cb393f1SJason Zhu 
2201cb393f1SJason Zhu 	/* Detect valid image header */
2211cb393f1SJason Zhu 	for (i = 0; i < try_count; i++) {
2221cb393f1SJason Zhu 		sect_addr = image_sector + (i * RKFW_RETRY_SECTOR_SIZE);
2231cb393f1SJason Zhu 		ret = info->read(info, sect_addr, blkcnt, &hdr);
2241cb393f1SJason Zhu 		if (ret != blkcnt)
2251cb393f1SJason Zhu 			continue;
2261cb393f1SJason Zhu 
2271cb393f1SJason Zhu 		if (!memcmp(hdr.magic, TBOOT_HEAD_TAG, 6)) {
2281cb393f1SJason Zhu 			*found_rkfw = 1;
2291cb393f1SJason Zhu 			spl_image->entry_point = (uintptr_t)hdr.loader_load_addr;
2301cb393f1SJason Zhu 			/* Load full binary image(right behind header) */
2311cb393f1SJason Zhu 			sect_addr += blkcnt;
2321cb393f1SJason Zhu 			load_addr = (char *)((size_t)hdr.loader_load_addr);
2331cb393f1SJason Zhu 			blkcnt = DIV_ROUND_UP(hdr.loader_load_size, 512);
2341cb393f1SJason Zhu 
2351cb393f1SJason Zhu 			printf("tee.bin: addr=0x%lx, size=0x%lx\n",
2361cb393f1SJason Zhu 			       (ulong)load_addr, (ulong)blkcnt * 512);
2371cb393f1SJason Zhu 			ret = info->read(info, sect_addr, blkcnt, load_addr);
2381cb393f1SJason Zhu 			if (ret != blkcnt)
2391cb393f1SJason Zhu 				continue;
2401cb393f1SJason Zhu 
2411cb393f1SJason Zhu 			break;
2421cb393f1SJason Zhu 		}
2431cb393f1SJason Zhu 	}
2441cb393f1SJason Zhu 
2451cb393f1SJason Zhu 	if (i == try_count) {
2461cb393f1SJason Zhu 		printf("Can not find usable uboot\n");
2471cb393f1SJason Zhu 		return -ENONET;
2481cb393f1SJason Zhu 	}
2491cb393f1SJason Zhu 
2501cb393f1SJason Zhu 	return 0;
2511cb393f1SJason Zhu }
2521cb393f1SJason Zhu #endif
25313c5d8ecSJoseph Chen 
25413c5d8ecSJoseph Chen static int rkfw_load_uboot(struct spl_load_info *info, u32 image_sector,
2551cb393f1SJason Zhu 			   struct spl_image_info *spl_image, u32 try_count)
25613c5d8ecSJoseph Chen {
25713c5d8ecSJoseph Chen 	struct tag_second_loader_hdr hdr;
25813c5d8ecSJoseph Chen 	int i, ret, blkcnt = 4;	/* header sectors, 2KB */
25913c5d8ecSJoseph Chen 	char *load_addr;
26013c5d8ecSJoseph Chen 	u32 sect_addr;
26113c5d8ecSJoseph Chen 
26213c5d8ecSJoseph Chen 	/* Detect valid image header */
26313c5d8ecSJoseph Chen 	for (i = 0; i < try_count; i++) {
26413c5d8ecSJoseph Chen 		sect_addr = image_sector + (i * RKFW_RETRY_SECTOR_SIZE);
26513c5d8ecSJoseph Chen 		ret = info->read(info, sect_addr, blkcnt, &hdr);
26613c5d8ecSJoseph Chen 		if (ret != blkcnt)
26713c5d8ecSJoseph Chen 			continue;
26813c5d8ecSJoseph Chen 
26913c5d8ecSJoseph Chen 		if (!memcmp(hdr.magic, LOADER_HARD_STR, 6)) {
27013c5d8ecSJoseph Chen 			/* Load full binary image(right behind header) */
27113c5d8ecSJoseph Chen 			sect_addr += blkcnt;
27213c5d8ecSJoseph Chen 			load_addr = (char *)((size_t)hdr.loader_load_addr);
27313c5d8ecSJoseph Chen 			blkcnt = DIV_ROUND_UP(hdr.loader_load_size, 512);
27413c5d8ecSJoseph Chen 
27513c5d8ecSJoseph Chen 			printf("u-boot.bin: addr=0x%lx, size=0x%lx\n",
27613c5d8ecSJoseph Chen 			       (ulong)load_addr, (ulong)blkcnt * 512);
27713c5d8ecSJoseph Chen 			ret = info->read(info, sect_addr, blkcnt, load_addr);
27813c5d8ecSJoseph Chen 			if (ret != blkcnt)
27913c5d8ecSJoseph Chen 				continue;
28013c5d8ecSJoseph Chen 
28113c5d8ecSJoseph Chen 			break;
28213c5d8ecSJoseph Chen 		}
28313c5d8ecSJoseph Chen 	}
28413c5d8ecSJoseph Chen 
28513c5d8ecSJoseph Chen 	if (i == try_count) {
28613c5d8ecSJoseph Chen 		printf("Can not find usable uboot\n");
28713c5d8ecSJoseph Chen 		return -ENONET;
28813c5d8ecSJoseph Chen 	}
28913c5d8ecSJoseph Chen 
29013c5d8ecSJoseph Chen 	/* Fill entry point */
2911cb393f1SJason Zhu #ifdef CONFIG_SPL_ATF
2921cb393f1SJason Zhu 	spl_image->entry_point_bl33 = (uintptr_t)hdr.loader_load_addr;
2931cb393f1SJason Zhu #endif
2941cb393f1SJason Zhu #ifdef CONFIG_SPL_OPTEE
2951cb393f1SJason Zhu 	spl_image->entry_point_os = (uintptr_t)hdr.loader_load_addr;
2961cb393f1SJason Zhu #endif
29713c5d8ecSJoseph Chen 	return 0;
29813c5d8ecSJoseph Chen }
29913c5d8ecSJoseph Chen 
300e3460df7SJason Zhu static int rkfw_load_kernel(struct spl_load_info *info, u32 image_sector,
3011cb393f1SJason Zhu 			    struct spl_image_info *spl_image, u32 try_count)
302e3460df7SJason Zhu {
303e3460df7SJason Zhu 	struct andr_img_hdr *hdr;
304e3460df7SJason Zhu 	int ret, cnt;
3052241fc0fSJason Zhu 	int dtb_sector, ramdisk_sector, resource_sector;
306e3460df7SJason Zhu 
307e3460df7SJason Zhu 	cnt = ALIGN(sizeof(struct andr_img_hdr), 512) >> 9;
308e3460df7SJason Zhu 	hdr = malloc(cnt * 512);
309e3460df7SJason Zhu 	if (!hdr)
310e3460df7SJason Zhu 		return -ENOMEM;
311e3460df7SJason Zhu 
312e3460df7SJason Zhu 	ret = info->read(info, image_sector, cnt, (void *)hdr);
313e3460df7SJason Zhu 	if (ret != cnt) {
314e3460df7SJason Zhu 		ret = -EIO;
315e3460df7SJason Zhu 		goto out;
316e3460df7SJason Zhu 	}
317e3460df7SJason Zhu 
318e3460df7SJason Zhu 	if (memcmp(hdr->magic, ANDR_BOOT_MAGIC, strlen(ANDR_BOOT_MAGIC)) != 0) {
319e3460df7SJason Zhu 		printf("SPL: boot image head magic error\n");
320e3460df7SJason Zhu 		ret = -EINVAL;
321e3460df7SJason Zhu 		goto out;
322e3460df7SJason Zhu 	}
323e3460df7SJason Zhu 
324e3460df7SJason Zhu 	ramdisk_sector = ALIGN(hdr->kernel_size, hdr->page_size);
3252241fc0fSJason Zhu 	resource_sector = ALIGN(hdr->kernel_size, hdr->page_size)
3262241fc0fSJason Zhu 			+ ALIGN(hdr->ramdisk_size, hdr->page_size);
327e3460df7SJason Zhu 	dtb_sector = ALIGN(hdr->kernel_size, hdr->page_size)
328e3460df7SJason Zhu 			+ ALIGN(hdr->ramdisk_size, hdr->page_size)
329e3460df7SJason Zhu 			+ ALIGN(hdr->second_size, hdr->page_size);
330e3460df7SJason Zhu 	image_sector = image_sector + cnt;
331e3460df7SJason Zhu 	cnt = ALIGN(hdr->kernel_size, hdr->page_size) >> 9;
332e3460df7SJason Zhu 
333e3460df7SJason Zhu 	/* Load kernel image */
334*6177e32dSJason Zhu #ifdef CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS
335*6177e32dSJason Zhu 	ret = info->read(info, image_sector, cnt,
336*6177e32dSJason Zhu 			 (void *)CONFIG_SPL_KERNEL_COMPRESS_ADDR);
337*6177e32dSJason Zhu #else
338e3460df7SJason Zhu 	ret = info->read(info, image_sector, cnt, (void *)CONFIG_SPL_KERNEL_ADDR);
339*6177e32dSJason Zhu #endif
340e3460df7SJason Zhu 	if (ret != cnt) {
341e3460df7SJason Zhu 		ret = -EIO;
342e3460df7SJason Zhu 		goto out;
343e3460df7SJason Zhu 	}
344*6177e32dSJason Zhu #ifdef CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS
345*6177e32dSJason Zhu 	struct udevice *dev;
346*6177e32dSJason Zhu 	u32 cap = GZIP_MOD;
347*6177e32dSJason Zhu 
348*6177e32dSJason Zhu 	dev = misc_decompress_get_device(cap);
349*6177e32dSJason Zhu 
350*6177e32dSJason Zhu 	if (!dev)
351*6177e32dSJason Zhu 		goto out;
352*6177e32dSJason Zhu 
353*6177e32dSJason Zhu 	ret = misc_decompress_start(dev, CONFIG_SPL_KERNEL_COMPRESS_ADDR,
354*6177e32dSJason Zhu 				    CONFIG_SPL_KERNEL_ADDR, hdr->kernel_size);
355*6177e32dSJason Zhu 	if (ret)
356*6177e32dSJason Zhu 		goto out;
357*6177e32dSJason Zhu 
358*6177e32dSJason Zhu #endif
359e3460df7SJason Zhu 
360e3460df7SJason Zhu 	/* Load ramdisk image */
361e3460df7SJason Zhu 	if (hdr->ramdisk_size) {
362*6177e32dSJason Zhu #ifdef CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS
363*6177e32dSJason Zhu 		ret = info->read(info, (ramdisk_sector >> 9) + image_sector,
364*6177e32dSJason Zhu 				 ALIGN(hdr->ramdisk_size, hdr->page_size) >> 9,
365*6177e32dSJason Zhu 				 (void *)CONFIG_SPL_RAMDISK_COMPRESS_ADDR);
366*6177e32dSJason Zhu #else
367e3460df7SJason Zhu 		ret = info->read(info, (ramdisk_sector >> 9) + image_sector,
368e3460df7SJason Zhu 				 ALIGN(hdr->ramdisk_size, hdr->page_size) >> 9,
369e3460df7SJason Zhu 				 (void *)CONFIG_SPL_RAMDISK_ADDR);
370*6177e32dSJason Zhu #endif
371e3460df7SJason Zhu 		if (ret != (ALIGN(hdr->ramdisk_size, hdr->page_size) >> 9)) {
372e3460df7SJason Zhu 			ret = -EIO;
373e3460df7SJason Zhu 			goto out;
374e3460df7SJason Zhu 		}
375*6177e32dSJason Zhu #ifdef CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS
376*6177e32dSJason Zhu 		int timeout = 10000;
377*6177e32dSJason Zhu 
378*6177e32dSJason Zhu 		while (misc_decompress_is_complete(dev)) {
379*6177e32dSJason Zhu 			if (timeout < 0) {
380*6177e32dSJason Zhu 				ret = -EIO;
381*6177e32dSJason Zhu 				goto out;
382*6177e32dSJason Zhu 			}
383*6177e32dSJason Zhu 
384*6177e32dSJason Zhu 			timeout--;
385*6177e32dSJason Zhu 			udelay(10);
386*6177e32dSJason Zhu 		}
387*6177e32dSJason Zhu 
388*6177e32dSJason Zhu 		ret = misc_decompress_start(dev,
389*6177e32dSJason Zhu 					    CONFIG_SPL_RAMDISK_COMPRESS_ADDR,
390*6177e32dSJason Zhu 					    CONFIG_SPL_RAMDISK_ADDR,
391*6177e32dSJason Zhu 					    hdr->kernel_size);
392*6177e32dSJason Zhu 		if (ret)
393*6177e32dSJason Zhu 			goto out;
394*6177e32dSJason Zhu #endif
395e3460df7SJason Zhu 	}
396e3460df7SJason Zhu 
3972241fc0fSJason Zhu 	/* Load resource, and checkout the dtb */
3982241fc0fSJason Zhu 	if (hdr->second_size) {
3992241fc0fSJason Zhu 		struct resource_img_hdr *head =
4002241fc0fSJason Zhu 		   (struct resource_img_hdr *)(CONFIG_SPL_FDT_ADDR + 0x100000);
4012241fc0fSJason Zhu 
4022241fc0fSJason Zhu 		ret = info->read(info, (resource_sector >> 9) + image_sector,
4032241fc0fSJason Zhu 				 ALIGN(hdr->second_size, hdr->page_size) >> 9,
4042241fc0fSJason Zhu 				 (void *)head);
4052241fc0fSJason Zhu 		if (ret != (ALIGN(hdr->second_size, hdr->page_size) >> 9)) {
4062241fc0fSJason Zhu 			ret = -EIO;
4072241fc0fSJason Zhu 			goto out;
4082241fc0fSJason Zhu 		}
4091cb393f1SJason Zhu #ifdef CONFIG_SPL_KERNEL_BOOT
4102241fc0fSJason Zhu 		if (spl_resource_image_check_header(head)) {
4112241fc0fSJason Zhu 			printf("Can't find kernel dtb in spl.");
4122241fc0fSJason Zhu 		} else {
4132241fc0fSJason Zhu 			struct resource_entry *entry;
4142241fc0fSJason Zhu 			char *dtb_temp;
4152241fc0fSJason Zhu 
4162241fc0fSJason Zhu 			entry = spl_resource_image_get_dtb_entry(head);
4172241fc0fSJason Zhu 			if (!entry) {
4182241fc0fSJason Zhu 				ret = -EIO;
4192241fc0fSJason Zhu 				goto out;
4202241fc0fSJason Zhu 			}
4212241fc0fSJason Zhu 
4222241fc0fSJason Zhu 			dtb_temp = (char *)((char *)head + entry->f_offset * 512);
4232241fc0fSJason Zhu 			memcpy((char *)CONFIG_SPL_FDT_ADDR, dtb_temp,
4242241fc0fSJason Zhu 			       entry->f_size);
4252241fc0fSJason Zhu 		}
4261cb393f1SJason Zhu #endif
4272241fc0fSJason Zhu 	} else {
428e3460df7SJason Zhu 		/* Load dtb image */
429e3460df7SJason Zhu 		ret = info->read(info, (dtb_sector >> 9) + image_sector,
430e3460df7SJason Zhu 				 ALIGN(hdr->dtb_size, hdr->page_size) >> 9,
431e3460df7SJason Zhu 				 (void *)CONFIG_SPL_FDT_ADDR);
432e3460df7SJason Zhu 		if (ret != (ALIGN(hdr->dtb_size, hdr->page_size) >> 9)) {
433e3460df7SJason Zhu 			ret = -EIO;
434e3460df7SJason Zhu 			goto out;
435e3460df7SJason Zhu 		}
4362241fc0fSJason Zhu 	}
437e3460df7SJason Zhu 
4381cb393f1SJason Zhu 	spl_image->fdt_addr = (void *)CONFIG_SPL_FDT_ADDR;
4391cb393f1SJason Zhu #ifdef CONFIG_SPL_OPTEE
4401cb393f1SJason Zhu 	spl_image->entry_point_os = (uintptr_t)CONFIG_SPL_KERNEL_ADDR;
4411cb393f1SJason Zhu #endif
4421cb393f1SJason Zhu #ifdef CONFIG_SPL_ATF
4431cb393f1SJason Zhu 	spl_image->entry_point_bl33 = CONFIG_SPL_KERNEL_ADDR;
4441cb393f1SJason Zhu #endif
445e3460df7SJason Zhu 	ret = 0;
446e3460df7SJason Zhu out:
447e3460df7SJason Zhu 	free(hdr);
448e3460df7SJason Zhu 
449e3460df7SJason Zhu 	return ret;
450e3460df7SJason Zhu }
451e3460df7SJason Zhu 
45213c5d8ecSJoseph Chen int spl_load_rkfw_image(struct spl_image_info *spl_image,
45313c5d8ecSJoseph Chen 			struct spl_load_info *info,
454aa415ed9SJoseph Chen 			u32 trust_sector, u32 uboot_sector,
455aa415ed9SJoseph Chen 			u32 boot_sector)
45613c5d8ecSJoseph Chen {
45713c5d8ecSJoseph Chen 	int ret, try_count = RKFW_RETRY_SECTOR_TIMES;
45813c5d8ecSJoseph Chen 	int found_rkfw = 0;
45913c5d8ecSJoseph Chen 
4601cb393f1SJason Zhu 	ret = rkfw_load_trust(info, trust_sector, spl_image,
46113c5d8ecSJoseph Chen 			      &found_rkfw, try_count);
46213c5d8ecSJoseph Chen 	if (ret) {
46313c5d8ecSJoseph Chen 		printf("Load trust image failed! ret=%d\n", ret);
46413c5d8ecSJoseph Chen 		goto out;
46513c5d8ecSJoseph Chen 	}
466aa415ed9SJoseph Chen #ifdef CONFIG_SPL_KERNEL_BOOT
467aa415ed9SJoseph Chen 	if (spl_image->next_stage == SPL_NEXT_STAGE_UBOOT) {
468aa415ed9SJoseph Chen #endif
469aa415ed9SJoseph Chen 		ret = rkfw_load_uboot(info, uboot_sector, spl_image, try_count);
470e3460df7SJason Zhu 		if (ret)
47113c5d8ecSJoseph Chen 			printf("Load uboot image failed! ret=%d\n", ret);
4724ef4c8bfSJason Zhu 		else
4734ef4c8bfSJason Zhu 			goto boot;
474aa415ed9SJoseph Chen #ifdef CONFIG_SPL_KERNEL_BOOT
475aa415ed9SJoseph Chen 	} else if (spl_image->next_stage == SPL_NEXT_STAGE_KERNEL) {
476aa415ed9SJoseph Chen #endif
477aa415ed9SJoseph Chen 		ret = rkfw_load_kernel(info, boot_sector, spl_image, try_count);
478e3460df7SJason Zhu 		if (ret) {
479e3460df7SJason Zhu 			printf("Load kernel image failed! ret=%d\n", ret);
48013c5d8ecSJoseph Chen 			goto out;
48113c5d8ecSJoseph Chen 		}
482aa415ed9SJoseph Chen #ifdef CONFIG_SPL_KERNEL_BOOT
483aa415ed9SJoseph Chen 	}
484aa415ed9SJoseph Chen #endif
48513c5d8ecSJoseph Chen 
4864ef4c8bfSJason Zhu boot:
48713c5d8ecSJoseph Chen #if CONFIG_IS_ENABLED(LOAD_FIT)
48813c5d8ecSJoseph Chen 	spl_image->fdt_addr = 0;
48913c5d8ecSJoseph Chen #endif
4901cb393f1SJason Zhu #ifdef CONFIG_SPL_ATF
49113c5d8ecSJoseph Chen 	spl_image->os = IH_OS_ARM_TRUSTED_FIRMWARE;
4921cb393f1SJason Zhu #else
4931cb393f1SJason Zhu 	spl_image->os = IH_OS_OP_TEE;
4941cb393f1SJason Zhu #endif
49513c5d8ecSJoseph Chen 
49613c5d8ecSJoseph Chen out:
49713c5d8ecSJoseph Chen 	/* If not found rockchip firmware, try others outside */
49813c5d8ecSJoseph Chen 	return found_rkfw ? ret : -EAGAIN;
49913c5d8ecSJoseph Chen }
500