xref: /rk3399_rockchip-uboot/common/spl/spl_rkfw.c (revision cd081a9734e770ed882a7039883c5bb97325ae79)
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>
7a5f4ae85SJason Zhu #include <android_image.h>
8a5f4ae85SJason Zhu #include <errno.h>
913c5d8ecSJoseph Chen #include <malloc.h>
105b7d3298SJason Zhu #include <misc.h>
11aa415ed9SJoseph Chen #include <spl.h>
1213c5d8ecSJoseph Chen #include <spl_rkfw.h>
13a5f4ae85SJason Zhu #include <linux/kernel.h>
14e64dfb02SJason Zhu #include <asm/arch/spl_resource_img.h>
158a5f71e4SJoseph Chen #include <boot_rkimg.h>
1613c5d8ecSJoseph Chen 
17a64fd729SJason Zhu #ifdef CONFIG_SPL_ATF
1813c5d8ecSJoseph Chen static const __aligned(16) struct s_fip_name_id fip_name_id[] = {
1913c5d8ecSJoseph Chen 	{ BL30_IMAGE_NAME, UUID_SCP_FIRMWARE_BL30 },		/* optional */
2013c5d8ecSJoseph Chen 	{ BL31_IMAGE_NAME, UUID_EL3_RUNTIME_FIRMWARE_BL31 },	/* mandatory */
2113c5d8ecSJoseph Chen 	{ BL32_IMAGE_NAME, UUID_SECURE_PAYLOAD_BL32 },		/* optional */
2213c5d8ecSJoseph Chen };
2313c5d8ecSJoseph Chen 
file2comp_id(const char * file_name,u32 * comp_id)2413c5d8ecSJoseph Chen static int file2comp_id(const char *file_name, u32 *comp_id)
2513c5d8ecSJoseph Chen {
2613c5d8ecSJoseph Chen 	int i;
2713c5d8ecSJoseph Chen 
2813c5d8ecSJoseph Chen 	for (i = 0; i < ARRAY_SIZE(fip_name_id); i++) {
2913c5d8ecSJoseph Chen 		if (!strcmp(file_name, fip_name_id[i].name)) {
3013c5d8ecSJoseph Chen 			*comp_id = fip_name_id[i].id;
3113c5d8ecSJoseph Chen 			return 0;
3213c5d8ecSJoseph Chen 		}
3313c5d8ecSJoseph Chen 	}
3413c5d8ecSJoseph Chen 
3513c5d8ecSJoseph Chen 	return -ENOENT;
3613c5d8ecSJoseph Chen }
3713c5d8ecSJoseph Chen 
open_image(const char * image_name,tboot_entry * entry,struct tag_tboot_header_2k * hdr)3813c5d8ecSJoseph Chen static int open_image(const char *image_name, tboot_entry *entry,
3913c5d8ecSJoseph Chen 		      struct tag_tboot_header_2k *hdr)
4013c5d8ecSJoseph Chen {
4113c5d8ecSJoseph Chen 	u32 i, component_num, sign_offset;
4213c5d8ecSJoseph Chen 	component_data *pcompdata;
4313c5d8ecSJoseph Chen 	boot_component *pcomp;
4413c5d8ecSJoseph Chen 	int n_found = 0;
4513c5d8ecSJoseph Chen 	u32 comp_id;
4613c5d8ecSJoseph Chen 	int ret;
4713c5d8ecSJoseph Chen 
4813c5d8ecSJoseph Chen 	ret = file2comp_id(image_name, &comp_id);
4913c5d8ecSJoseph Chen 	if (ret) {
5013c5d8ecSJoseph Chen 		printf("Can't find unknown image: %s\n", image_name);
5113c5d8ecSJoseph Chen 		return ret;
5213c5d8ecSJoseph Chen 	}
5313c5d8ecSJoseph Chen 
5413c5d8ecSJoseph Chen 	component_num = (hdr->size >> 16) & 0xffff;
5513c5d8ecSJoseph Chen 	sign_offset = (hdr->size & 0xffff) << 2;
5613c5d8ecSJoseph Chen 	pcompdata = (component_data *)((char *)hdr + sizeof(tboot_header));
5713c5d8ecSJoseph Chen 	pcomp = (boot_component *)((char *)hdr + sign_offset + SIGNATURE_SIZE);
5813c5d8ecSJoseph Chen 
5913c5d8ecSJoseph Chen 	for (i = 0; i < component_num; i++) {
6013c5d8ecSJoseph Chen 		if (comp_id == pcomp->component_id) {
6113c5d8ecSJoseph Chen 			if (n_found < MAX_BL_CODE_NUM) {
6213c5d8ecSJoseph Chen 				memcpy(&entry[n_found].component, pcomp,
6313c5d8ecSJoseph Chen 				       sizeof(boot_component));
6413c5d8ecSJoseph Chen 				memcpy(&entry[n_found].compdata, pcompdata,
6513c5d8ecSJoseph Chen 				       sizeof(component_data));
6613c5d8ecSJoseph Chen 				n_found++;
6713c5d8ecSJoseph Chen 			} else {
6813c5d8ecSJoseph Chen 				printf("Image num excess max: %d!\n",
6913c5d8ecSJoseph Chen 				       MAX_BL_CODE_NUM);
7013c5d8ecSJoseph Chen 				return -EINVAL;
7113c5d8ecSJoseph Chen 			}
7213c5d8ecSJoseph Chen 		} else {
7313c5d8ecSJoseph Chen 			if (n_found > 0)
7413c5d8ecSJoseph Chen 				break;
7513c5d8ecSJoseph Chen 		}
7613c5d8ecSJoseph Chen 
7713c5d8ecSJoseph Chen 		pcomp++;
7813c5d8ecSJoseph Chen 		pcompdata++;
7913c5d8ecSJoseph Chen 	}
8013c5d8ecSJoseph Chen 
8113c5d8ecSJoseph Chen 	if (!n_found) {
8213c5d8ecSJoseph Chen 		printf("No find %s\n", image_name);
8313c5d8ecSJoseph Chen 		return -ENONET;
8413c5d8ecSJoseph Chen 	}
8513c5d8ecSJoseph Chen 
8613c5d8ecSJoseph Chen 	return n_found;
8713c5d8ecSJoseph Chen }
8813c5d8ecSJoseph Chen 
check_image(struct tag_tboot_header_2k * hdr)8913c5d8ecSJoseph Chen static int check_image(struct tag_tboot_header_2k *hdr)
9013c5d8ecSJoseph Chen {
9113c5d8ecSJoseph Chen 	u32 hash_format[] = { 0, 160, 256, 256 };
9213c5d8ecSJoseph Chen 
9313c5d8ecSJoseph Chen 	/* HASH format identifier */
9413c5d8ecSJoseph Chen 	return (hash_format[hdr->flags & 0x3] == 0) ? -EINVAL : 0;
9513c5d8ecSJoseph Chen }
9613c5d8ecSJoseph Chen 
load_image(struct spl_load_info * info,struct tag_tboot_header_2k * hdr,u32 image_sector,const char * image_name,uintptr_t * entry_point)9713c5d8ecSJoseph Chen static int load_image(struct spl_load_info *info,
9813c5d8ecSJoseph Chen 		      struct tag_tboot_header_2k *hdr,
9913c5d8ecSJoseph Chen 		      u32 image_sector,
10013c5d8ecSJoseph Chen 		      const char *image_name,
10113c5d8ecSJoseph Chen 		      uintptr_t *entry_point)
10213c5d8ecSJoseph Chen {
10313c5d8ecSJoseph Chen 	tboot_entry entry[MAX_BL_CODE_NUM];
10413c5d8ecSJoseph Chen 	void *image_buf = NULL;
10513c5d8ecSJoseph Chen 	ulong load_addr;
10613c5d8ecSJoseph Chen 	u32 sect_off;
10713c5d8ecSJoseph Chen 	u32 sect_cnt;
10813c5d8ecSJoseph Chen 	int image_num;
10913c5d8ecSJoseph Chen 	int i, ret;
11013c5d8ecSJoseph Chen 
11113c5d8ecSJoseph Chen 	/* Parse components from image header */
11213c5d8ecSJoseph Chen 	image_num = open_image(image_name, entry, hdr);
11313c5d8ecSJoseph Chen 	if (image_num < 0)
11413c5d8ecSJoseph Chen 		return image_num;
11513c5d8ecSJoseph Chen 
11613c5d8ecSJoseph Chen 	/* Get all component */
11713c5d8ecSJoseph Chen 	for (i = 0; i < image_num; i++) {
11813c5d8ecSJoseph Chen 		load_addr = entry[i].compdata.load_addr;
11913c5d8ecSJoseph Chen 		sect_cnt = entry[i].component.image_size;
12013c5d8ecSJoseph Chen 		sect_off = entry[i].component.storage_addr;
12113c5d8ecSJoseph Chen 
12213c5d8ecSJoseph Chen 		printf("%s[%d]: addr=0x%lx, size=0x%lx\n",
12313c5d8ecSJoseph Chen 		       image_name, i, load_addr, (ulong)sect_cnt * 512);
12413c5d8ecSJoseph Chen 
12513c5d8ecSJoseph Chen 		/*
12613c5d8ecSJoseph Chen 		 * MMC/NAND controller DMA can't access sram region, so:
12713c5d8ecSJoseph Chen 		 * data -> ddr buffer -> memcpy to sram region.
12813c5d8ecSJoseph Chen 		 */
129b35a1137SJoseph Chen 		if (load_addr < CONFIG_SYS_SDRAM_BASE ||
130b35a1137SJoseph Chen 		    load_addr >= CONFIG_SYS_SDRAM_BASE + SDRAM_MAX_SIZE) {
13113c5d8ecSJoseph Chen 			image_buf = memalign(ARCH_DMA_MINALIGN, sect_cnt * 512);
13213c5d8ecSJoseph Chen 			if (!image_buf) {
13313c5d8ecSJoseph Chen 				printf("%s: malloc failed\n", __func__);
13413c5d8ecSJoseph Chen 				return -ENOMEM;
13513c5d8ecSJoseph Chen 			}
13613c5d8ecSJoseph Chen 		} else {
13713c5d8ecSJoseph Chen 			image_buf = (void *)load_addr;
13813c5d8ecSJoseph Chen 		}
13913c5d8ecSJoseph Chen 
14013c5d8ecSJoseph Chen 		ret = info->read(info, image_sector + sect_off,
14113c5d8ecSJoseph Chen 				 sect_cnt, image_buf);
14213c5d8ecSJoseph Chen 		if (ret != sect_cnt) {
14313c5d8ecSJoseph Chen 			printf("Read '%s' failed at sector: %ld, ret=%d\n",
14413c5d8ecSJoseph Chen 			       image_name, (ulong)image_sector + sect_off, ret);
14513c5d8ecSJoseph Chen 			return -EIO;
14613c5d8ecSJoseph Chen 		}
14713c5d8ecSJoseph Chen 
14813c5d8ecSJoseph Chen 		/* Verify component */
14913c5d8ecSJoseph Chen 		ret = check_image(hdr);
15013c5d8ecSJoseph Chen 		if (ret) {
15113c5d8ecSJoseph Chen 			printf("%s[%d]: verify image fail!\n", image_name, i);
15213c5d8ecSJoseph Chen 			return ret;
15313c5d8ecSJoseph Chen 		}
15413c5d8ecSJoseph Chen 
15513c5d8ecSJoseph Chen 		/* Handle sram region */
15613c5d8ecSJoseph Chen 		if ((ulong)image_buf != load_addr) {
15713c5d8ecSJoseph Chen 			memcpy((void *)load_addr, image_buf, sect_cnt << 9);
15813c5d8ecSJoseph Chen 			free(image_buf);
15913c5d8ecSJoseph Chen 		}
16013c5d8ecSJoseph Chen 
16113c5d8ecSJoseph Chen 		/* Fill entry_point by first component */
16213c5d8ecSJoseph Chen 		if (i == 0)
16313c5d8ecSJoseph Chen 			*entry_point = (uintptr_t)load_addr;
16413c5d8ecSJoseph Chen 	}
16513c5d8ecSJoseph Chen 
16613c5d8ecSJoseph Chen 	return ret;
16713c5d8ecSJoseph Chen }
16813c5d8ecSJoseph Chen 
rkfw_load_trust(struct spl_load_info * info,u32 image_sector,struct spl_image_info * spl_image,int * found_rkfw,u32 try_count)16913c5d8ecSJoseph Chen static int rkfw_load_trust(struct spl_load_info *info, u32 image_sector,
170a64fd729SJason Zhu 			   struct spl_image_info *spl_image,
17113c5d8ecSJoseph Chen 			   int *found_rkfw, u32 try_count)
17213c5d8ecSJoseph Chen {
17313c5d8ecSJoseph Chen 	struct tag_tboot_header_2k hdr;
17413c5d8ecSJoseph Chen 	u32 sect_addr = image_sector;
17513c5d8ecSJoseph Chen 	int blkcnt = 4;	/* header sectors, 2KB */
17613c5d8ecSJoseph Chen 	int i, ret = 0;
17713c5d8ecSJoseph Chen 
17813c5d8ecSJoseph Chen 	/* Find valid image header */
17913c5d8ecSJoseph Chen 	for (i = 0; i < try_count; i++) {
18013c5d8ecSJoseph Chen 		sect_addr = image_sector + (i * RKFW_RETRY_SECTOR_SIZE);
18113c5d8ecSJoseph Chen 		if (blkcnt != info->read(info, sect_addr, blkcnt, &hdr))
18213c5d8ecSJoseph Chen 			continue;
18313c5d8ecSJoseph Chen 
18413c5d8ecSJoseph Chen 		if (hdr.tag == TBOOT_HEAD_TAG) {
18513c5d8ecSJoseph Chen 			/* Mark it */
18613c5d8ecSJoseph Chen 			*found_rkfw = 1;
18713c5d8ecSJoseph Chen 
18813c5d8ecSJoseph Chen 			/* bl31 is mandatory */
18913c5d8ecSJoseph Chen 			ret = load_image(info, &hdr, sect_addr,
190a64fd729SJason Zhu 					 BL31_IMAGE_NAME, &spl_image->entry_point);
19113c5d8ecSJoseph Chen 			if (ret)
19213c5d8ecSJoseph Chen 				continue;
19313c5d8ecSJoseph Chen 
19413c5d8ecSJoseph Chen 			/* bl32 is optional */
19513c5d8ecSJoseph Chen 			ret = load_image(info, &hdr, sect_addr,
196a64fd729SJason Zhu 					 BL32_IMAGE_NAME, &spl_image->entry_point_bl32);
19713c5d8ecSJoseph Chen 			if (ret) {
19813c5d8ecSJoseph Chen 				if (ret == -ENONET) {
199a64fd729SJason Zhu 					spl_image->entry_point_bl32 = -1;	/* Not exist */
20013c5d8ecSJoseph Chen 					ret = 0;
20113c5d8ecSJoseph Chen 				} else {
20213c5d8ecSJoseph Chen 					continue;
20313c5d8ecSJoseph Chen 				}
20413c5d8ecSJoseph Chen 			}
20513c5d8ecSJoseph Chen 			break;
20613c5d8ecSJoseph Chen 		}
20713c5d8ecSJoseph Chen 	}
20813c5d8ecSJoseph Chen 
20913c5d8ecSJoseph Chen 	return ret;
21013c5d8ecSJoseph Chen }
2118a5f71e4SJoseph Chen #else /* op-tee */
rkfw_load_trust(struct spl_load_info * info,u32 image_sector,struct spl_image_info * spl_image,int * found_rkfw,u32 try_count)212a64fd729SJason Zhu static int rkfw_load_trust(struct spl_load_info *info, u32 image_sector,
213a64fd729SJason Zhu 			   struct spl_image_info *spl_image,
214a64fd729SJason Zhu 			   int *found_rkfw, u32 try_count)
215a64fd729SJason Zhu {
216a64fd729SJason Zhu 	struct tag_second_loader_hdr hdr;
217a64fd729SJason Zhu 	int i, ret, blkcnt = 4;	/* header sectors, 2KB */
218a64fd729SJason Zhu 	char *load_addr;
219a64fd729SJason Zhu 	u32 sect_addr;
220a64fd729SJason Zhu 
221a64fd729SJason Zhu 	/* Detect valid image header */
222a64fd729SJason Zhu 	for (i = 0; i < try_count; i++) {
223a64fd729SJason Zhu 		sect_addr = image_sector + (i * RKFW_RETRY_SECTOR_SIZE);
224a64fd729SJason Zhu 		ret = info->read(info, sect_addr, blkcnt, &hdr);
225a64fd729SJason Zhu 		if (ret != blkcnt)
226a64fd729SJason Zhu 			continue;
227a64fd729SJason Zhu 
228a64fd729SJason Zhu 		if (!memcmp(hdr.magic, TBOOT_HEAD_TAG, 6)) {
229a64fd729SJason Zhu 			*found_rkfw = 1;
230a64fd729SJason Zhu 			spl_image->entry_point = (uintptr_t)hdr.loader_load_addr;
231a64fd729SJason Zhu 			/* Load full binary image(right behind header) */
232a64fd729SJason Zhu 			sect_addr += blkcnt;
233a64fd729SJason Zhu 			load_addr = (char *)((size_t)hdr.loader_load_addr);
234a64fd729SJason Zhu 			blkcnt = DIV_ROUND_UP(hdr.loader_load_size, 512);
235a64fd729SJason Zhu 
236a64fd729SJason Zhu 			printf("tee.bin: addr=0x%lx, size=0x%lx\n",
237a64fd729SJason Zhu 			       (ulong)load_addr, (ulong)blkcnt * 512);
238a64fd729SJason Zhu 			ret = info->read(info, sect_addr, blkcnt, load_addr);
239a64fd729SJason Zhu 			if (ret != blkcnt)
240a64fd729SJason Zhu 				continue;
241a64fd729SJason Zhu 
242a64fd729SJason Zhu 			break;
243a64fd729SJason Zhu 		}
244a64fd729SJason Zhu 	}
245a64fd729SJason Zhu 
246a64fd729SJason Zhu 	if (i == try_count) {
247*cd081a97SJason Zhu 		printf("Can not find usable trust\n");
248a64fd729SJason Zhu 		return -ENONET;
249a64fd729SJason Zhu 	}
250a64fd729SJason Zhu 
251a64fd729SJason Zhu 	return 0;
252a64fd729SJason Zhu }
253a64fd729SJason Zhu #endif
25413c5d8ecSJoseph Chen 
rkfw_load_uboot(struct spl_load_info * info,u32 image_sector,struct spl_image_info * spl_image,u32 try_count)25513c5d8ecSJoseph Chen static int rkfw_load_uboot(struct spl_load_info *info, u32 image_sector,
256a64fd729SJason Zhu 			   struct spl_image_info *spl_image, u32 try_count)
25713c5d8ecSJoseph Chen {
25813c5d8ecSJoseph Chen 	struct tag_second_loader_hdr hdr;
25913c5d8ecSJoseph Chen 	int i, ret, blkcnt = 4;	/* header sectors, 2KB */
26013c5d8ecSJoseph Chen 	char *load_addr;
26113c5d8ecSJoseph Chen 	u32 sect_addr;
26213c5d8ecSJoseph Chen 
26313c5d8ecSJoseph Chen 	/* Detect valid image header */
26413c5d8ecSJoseph Chen 	for (i = 0; i < try_count; i++) {
26513c5d8ecSJoseph Chen 		sect_addr = image_sector + (i * RKFW_RETRY_SECTOR_SIZE);
26613c5d8ecSJoseph Chen 		ret = info->read(info, sect_addr, blkcnt, &hdr);
26713c5d8ecSJoseph Chen 		if (ret != blkcnt)
26813c5d8ecSJoseph Chen 			continue;
26913c5d8ecSJoseph Chen 
27013c5d8ecSJoseph Chen 		if (!memcmp(hdr.magic, LOADER_HARD_STR, 6)) {
27113c5d8ecSJoseph Chen 			/* Load full binary image(right behind header) */
27213c5d8ecSJoseph Chen 			sect_addr += blkcnt;
27313c5d8ecSJoseph Chen 			load_addr = (char *)((size_t)hdr.loader_load_addr);
27413c5d8ecSJoseph Chen 			blkcnt = DIV_ROUND_UP(hdr.loader_load_size, 512);
27513c5d8ecSJoseph Chen 
27613c5d8ecSJoseph Chen 			printf("u-boot.bin: addr=0x%lx, size=0x%lx\n",
27713c5d8ecSJoseph Chen 			       (ulong)load_addr, (ulong)blkcnt * 512);
27813c5d8ecSJoseph Chen 			ret = info->read(info, sect_addr, blkcnt, load_addr);
27913c5d8ecSJoseph Chen 			if (ret != blkcnt)
28013c5d8ecSJoseph Chen 				continue;
28113c5d8ecSJoseph Chen 
28213c5d8ecSJoseph Chen 			break;
28313c5d8ecSJoseph Chen 		}
28413c5d8ecSJoseph Chen 	}
28513c5d8ecSJoseph Chen 
28613c5d8ecSJoseph Chen 	if (i == try_count) {
28713c5d8ecSJoseph Chen 		printf("Can not find usable uboot\n");
28813c5d8ecSJoseph Chen 		return -ENONET;
28913c5d8ecSJoseph Chen 	}
29013c5d8ecSJoseph Chen 
29113c5d8ecSJoseph Chen 	/* Fill entry point */
292a64fd729SJason Zhu #ifdef CONFIG_SPL_ATF
293a64fd729SJason Zhu 	spl_image->entry_point_bl33 = (uintptr_t)hdr.loader_load_addr;
294a64fd729SJason Zhu #endif
295a64fd729SJason Zhu #ifdef CONFIG_SPL_OPTEE
296a64fd729SJason Zhu 	spl_image->entry_point_os = (uintptr_t)hdr.loader_load_addr;
297a64fd729SJason Zhu #endif
29813c5d8ecSJoseph Chen 	return 0;
29913c5d8ecSJoseph Chen }
30013c5d8ecSJoseph Chen 
rkfw_load_kernel(struct spl_load_info * info,u32 image_sector,struct spl_image_info * spl_image,u32 try_count)301a5f4ae85SJason Zhu static int rkfw_load_kernel(struct spl_load_info *info, u32 image_sector,
302a64fd729SJason Zhu 			    struct spl_image_info *spl_image, u32 try_count)
303a5f4ae85SJason Zhu {
304a5f4ae85SJason Zhu 	struct andr_img_hdr *hdr;
305a5f4ae85SJason Zhu 	int ret, cnt;
306e64dfb02SJason Zhu 	int dtb_sector, ramdisk_sector, resource_sector;
307a5f4ae85SJason Zhu 
308a5f4ae85SJason Zhu 	cnt = ALIGN(sizeof(struct andr_img_hdr), 512) >> 9;
309a5f4ae85SJason Zhu 	hdr = malloc(cnt * 512);
310a5f4ae85SJason Zhu 	if (!hdr)
311a5f4ae85SJason Zhu 		return -ENOMEM;
312a5f4ae85SJason Zhu 
313a5f4ae85SJason Zhu 	ret = info->read(info, image_sector, cnt, (void *)hdr);
314a5f4ae85SJason Zhu 	if (ret != cnt) {
315a5f4ae85SJason Zhu 		ret = -EIO;
316a5f4ae85SJason Zhu 		goto out;
317a5f4ae85SJason Zhu 	}
318a5f4ae85SJason Zhu 
319a5f4ae85SJason Zhu 	if (memcmp(hdr->magic, ANDR_BOOT_MAGIC, strlen(ANDR_BOOT_MAGIC)) != 0) {
320a5f4ae85SJason Zhu 		printf("SPL: boot image head magic error\n");
321a5f4ae85SJason Zhu 		ret = -EINVAL;
322a5f4ae85SJason Zhu 		goto out;
323a5f4ae85SJason Zhu 	}
324a5f4ae85SJason Zhu 
325a5f4ae85SJason Zhu 	ramdisk_sector = ALIGN(hdr->kernel_size, hdr->page_size);
326e64dfb02SJason Zhu 	resource_sector = ALIGN(hdr->kernel_size, hdr->page_size)
327e64dfb02SJason Zhu 			+ ALIGN(hdr->ramdisk_size, hdr->page_size);
328a5f4ae85SJason Zhu 	dtb_sector = ALIGN(hdr->kernel_size, hdr->page_size)
329a5f4ae85SJason Zhu 			+ ALIGN(hdr->ramdisk_size, hdr->page_size)
330a5f4ae85SJason Zhu 			+ ALIGN(hdr->second_size, hdr->page_size);
331a5f4ae85SJason Zhu 	image_sector = image_sector + cnt;
332a5f4ae85SJason Zhu 	cnt = ALIGN(hdr->kernel_size, hdr->page_size) >> 9;
333a5f4ae85SJason Zhu 
334a5f4ae85SJason Zhu 	/* Load kernel image */
3356177e32dSJason Zhu #ifdef CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS
3366177e32dSJason Zhu 	ret = info->read(info, image_sector, cnt,
3376177e32dSJason Zhu 			 (void *)CONFIG_SPL_KERNEL_COMPRESS_ADDR);
3386177e32dSJason Zhu #else
339a5f4ae85SJason Zhu 	ret = info->read(info, image_sector, cnt, (void *)CONFIG_SPL_KERNEL_ADDR);
3406177e32dSJason Zhu #endif
341a5f4ae85SJason Zhu 	if (ret != cnt) {
342a5f4ae85SJason Zhu 		ret = -EIO;
343a5f4ae85SJason Zhu 		goto out;
344a5f4ae85SJason Zhu 	}
3456177e32dSJason Zhu #ifdef CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS
3466177e32dSJason Zhu 	struct udevice *dev;
3475b7d3298SJason Zhu 	u32 cap = DECOM_GZIP;
3486177e32dSJason Zhu 
3496177e32dSJason Zhu 	dev = misc_decompress_get_device(cap);
3506177e32dSJason Zhu 
3516177e32dSJason Zhu 	if (!dev)
3526177e32dSJason Zhu 		goto out;
3536177e32dSJason Zhu 
3546177e32dSJason Zhu 	ret = misc_decompress_start(dev, CONFIG_SPL_KERNEL_COMPRESS_ADDR,
355a6f23aeaSJason Zhu 				    CONFIG_SPL_KERNEL_ADDR,
356a6f23aeaSJason Zhu 				    CONFIG_SPL_KERNEL_DECOM_LIMIT_SIZE);
3576177e32dSJason Zhu 	if (ret)
3586177e32dSJason Zhu 		goto out;
3596177e32dSJason Zhu 
3606177e32dSJason Zhu #endif
361a5f4ae85SJason Zhu 
362a5f4ae85SJason Zhu 	/* Load ramdisk image */
363a5f4ae85SJason Zhu 	if (hdr->ramdisk_size) {
3646177e32dSJason Zhu #ifdef CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS
3656177e32dSJason Zhu 		ret = info->read(info, (ramdisk_sector >> 9) + image_sector,
3666177e32dSJason Zhu 				 ALIGN(hdr->ramdisk_size, hdr->page_size) >> 9,
3676177e32dSJason Zhu 				 (void *)CONFIG_SPL_RAMDISK_COMPRESS_ADDR);
3686177e32dSJason Zhu #else
369a5f4ae85SJason Zhu 		ret = info->read(info, (ramdisk_sector >> 9) + image_sector,
370a5f4ae85SJason Zhu 				 ALIGN(hdr->ramdisk_size, hdr->page_size) >> 9,
371a5f4ae85SJason Zhu 				 (void *)CONFIG_SPL_RAMDISK_ADDR);
3726177e32dSJason Zhu #endif
373a5f4ae85SJason Zhu 		if (ret != (ALIGN(hdr->ramdisk_size, hdr->page_size) >> 9)) {
374a5f4ae85SJason Zhu 			ret = -EIO;
375a5f4ae85SJason Zhu 			goto out;
376a5f4ae85SJason Zhu 		}
3776177e32dSJason Zhu #ifdef CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS
3786177e32dSJason Zhu 		int timeout = 10000;
3796177e32dSJason Zhu 
380e6832242SJason Zhu 		while (!misc_decompress_is_complete(dev)) {
3816177e32dSJason Zhu 			if (timeout < 0) {
3826177e32dSJason Zhu 				ret = -EIO;
3836177e32dSJason Zhu 				goto out;
3846177e32dSJason Zhu 			}
3856177e32dSJason Zhu 
3866177e32dSJason Zhu 			timeout--;
3876177e32dSJason Zhu 			udelay(10);
3886177e32dSJason Zhu 		}
3896177e32dSJason Zhu 
39069808149SJason Zhu 		ret = misc_decompress_stop(dev);
39169808149SJason Zhu 		if (ret)
39269808149SJason Zhu 			goto out;
39369808149SJason Zhu 
3946177e32dSJason Zhu 		ret = misc_decompress_start(dev,
3956177e32dSJason Zhu 					    CONFIG_SPL_RAMDISK_COMPRESS_ADDR,
3966177e32dSJason Zhu 					    CONFIG_SPL_RAMDISK_ADDR,
397a6f23aeaSJason Zhu 					    CONFIG_SPL_RAMDISK_DECOM_LIMIT_SIZE);
3986177e32dSJason Zhu 		if (ret)
3996177e32dSJason Zhu 			goto out;
4006177e32dSJason Zhu #endif
401a5f4ae85SJason Zhu 	}
4021258f25bSJason Zhu #ifdef CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS
4031258f25bSJason Zhu 	else {
4041258f25bSJason Zhu 		int timeout = 10000;
405a5f4ae85SJason Zhu 
406e6832242SJason Zhu 		while (!misc_decompress_is_complete(dev)) {
4071258f25bSJason Zhu 			if (timeout < 0) {
4081258f25bSJason Zhu 				ret = -EIO;
4091258f25bSJason Zhu 				goto out;
4101258f25bSJason Zhu 			}
4111258f25bSJason Zhu 
4121258f25bSJason Zhu 			timeout--;
4131258f25bSJason Zhu 			udelay(10);
4141258f25bSJason Zhu 		}
4151258f25bSJason Zhu 	}
4161258f25bSJason Zhu #endif
417e64dfb02SJason Zhu 	/* Load resource, and checkout the dtb */
418e64dfb02SJason Zhu 	if (hdr->second_size) {
419e64dfb02SJason Zhu 		struct resource_img_hdr *head =
420e64dfb02SJason Zhu 		   (struct resource_img_hdr *)(CONFIG_SPL_FDT_ADDR + 0x100000);
421e64dfb02SJason Zhu 
422e64dfb02SJason Zhu 		ret = info->read(info, (resource_sector >> 9) + image_sector,
423e64dfb02SJason Zhu 				 ALIGN(hdr->second_size, hdr->page_size) >> 9,
424e64dfb02SJason Zhu 				 (void *)head);
425e64dfb02SJason Zhu 		if (ret != (ALIGN(hdr->second_size, hdr->page_size) >> 9)) {
426e64dfb02SJason Zhu 			ret = -EIO;
427e64dfb02SJason Zhu 			goto out;
428e64dfb02SJason Zhu 		}
429a64fd729SJason Zhu #ifdef CONFIG_SPL_KERNEL_BOOT
430e64dfb02SJason Zhu 		if (spl_resource_image_check_header(head)) {
431e64dfb02SJason Zhu 			printf("Can't find kernel dtb in spl.");
432e64dfb02SJason Zhu 		} else {
433e64dfb02SJason Zhu 			struct resource_entry *entry;
434e64dfb02SJason Zhu 			char *dtb_temp;
435e64dfb02SJason Zhu 
436e64dfb02SJason Zhu 			entry = spl_resource_image_get_dtb_entry(head);
437e64dfb02SJason Zhu 			if (!entry) {
438e64dfb02SJason Zhu 				ret = -EIO;
439e64dfb02SJason Zhu 				goto out;
440e64dfb02SJason Zhu 			}
441e64dfb02SJason Zhu 
442e64dfb02SJason Zhu 			dtb_temp = (char *)((char *)head + entry->f_offset * 512);
443e64dfb02SJason Zhu 			memcpy((char *)CONFIG_SPL_FDT_ADDR, dtb_temp,
444e64dfb02SJason Zhu 			       entry->f_size);
445e64dfb02SJason Zhu 		}
446a64fd729SJason Zhu #endif
447e64dfb02SJason Zhu 	} else {
448a5f4ae85SJason Zhu 		/* Load dtb image */
449a5f4ae85SJason Zhu 		ret = info->read(info, (dtb_sector >> 9) + image_sector,
450a5f4ae85SJason Zhu 				 ALIGN(hdr->dtb_size, hdr->page_size) >> 9,
451a5f4ae85SJason Zhu 				 (void *)CONFIG_SPL_FDT_ADDR);
452a5f4ae85SJason Zhu 		if (ret != (ALIGN(hdr->dtb_size, hdr->page_size) >> 9)) {
453a5f4ae85SJason Zhu 			ret = -EIO;
454a5f4ae85SJason Zhu 			goto out;
455a5f4ae85SJason Zhu 		}
456e64dfb02SJason Zhu 	}
457a5f4ae85SJason Zhu 
458a64fd729SJason Zhu 	spl_image->fdt_addr = (void *)CONFIG_SPL_FDT_ADDR;
459a64fd729SJason Zhu #ifdef CONFIG_SPL_OPTEE
460a64fd729SJason Zhu 	spl_image->entry_point_os = (uintptr_t)CONFIG_SPL_KERNEL_ADDR;
461a64fd729SJason Zhu #endif
462a64fd729SJason Zhu #ifdef CONFIG_SPL_ATF
463a64fd729SJason Zhu 	spl_image->entry_point_bl33 = CONFIG_SPL_KERNEL_ADDR;
464a64fd729SJason Zhu #endif
465a5f4ae85SJason Zhu 	ret = 0;
466a5f4ae85SJason Zhu out:
467a5f4ae85SJason Zhu 	free(hdr);
468a5f4ae85SJason Zhu 
469a5f4ae85SJason Zhu 	return ret;
470a5f4ae85SJason Zhu }
471a5f4ae85SJason Zhu 
spl_load_rkfw_image(struct spl_image_info * spl_image,struct spl_load_info * info)47213c5d8ecSJoseph Chen int spl_load_rkfw_image(struct spl_image_info *spl_image,
4738a5f71e4SJoseph Chen 			struct spl_load_info *info)
47413c5d8ecSJoseph Chen {
4758a5f71e4SJoseph Chen 	u32 uboot_sector = CONFIG_RKFW_U_BOOT_SECTOR;
4768a5f71e4SJoseph Chen 	u32 trust_sector = CONFIG_RKFW_TRUST_SECTOR;
4778a5f71e4SJoseph Chen 	u32 boot_sector  = CONFIG_RKFW_BOOT_SECTOR;
47813c5d8ecSJoseph Chen 	int ret, try_count = RKFW_RETRY_SECTOR_TIMES;
47913c5d8ecSJoseph Chen 	int found_rkfw = 0;
4808a5f71e4SJoseph Chen 	char *part_name;
4818a5f71e4SJoseph Chen #ifdef CONFIG_SPL_LIBDISK_SUPPORT
4828a5f71e4SJoseph Chen 	struct blk_desc *dev_desc = info->dev;
4838a5f71e4SJoseph Chen 	disk_partition_t part_info;
4848a5f71e4SJoseph Chen 
4858a5f71e4SJoseph Chen 	if (dev_desc) {
4868a5f71e4SJoseph Chen 		if (part_get_info_by_name(dev_desc, PART_UBOOT, &part_info) > 0)
4878a5f71e4SJoseph Chen 			uboot_sector = part_info.start;
4888a5f71e4SJoseph Chen 		if (part_get_info_by_name(dev_desc, PART_TRUST, &part_info) > 0)
4898a5f71e4SJoseph Chen 			trust_sector = part_info.start;
4908a5f71e4SJoseph Chen 		if (part_get_info_by_name(dev_desc, PART_BOOT, &part_info) > 0)
4918a5f71e4SJoseph Chen 			boot_sector = part_info.start;
4928a5f71e4SJoseph Chen 	}
4938a5f71e4SJoseph Chen #endif
4948a5f71e4SJoseph Chen 	/* u-boot or boot */
4958a5f71e4SJoseph Chen 	if (spl_image->next_stage != SPL_NEXT_STAGE_UBOOT)
4968a5f71e4SJoseph Chen 		uboot_sector = 0;
49713c5d8ecSJoseph Chen 
498a64fd729SJason Zhu 	ret = rkfw_load_trust(info, trust_sector, spl_image,
49913c5d8ecSJoseph Chen 			      &found_rkfw, try_count);
50013c5d8ecSJoseph Chen 	if (ret) {
5018a5f71e4SJoseph Chen 		part_name = PART_TRUST;
50213c5d8ecSJoseph Chen 		goto out;
50313c5d8ecSJoseph Chen 	}
50413c5d8ecSJoseph Chen 
5058a5f71e4SJoseph Chen 	if (uboot_sector) {
506aa415ed9SJoseph Chen 		ret = rkfw_load_uboot(info, uboot_sector, spl_image, try_count);
5078a5f71e4SJoseph Chen 		if (ret) {
5088a5f71e4SJoseph Chen 			part_name = PART_UBOOT;
5098a5f71e4SJoseph Chen 			goto out;
5108a5f71e4SJoseph Chen 		}
5118a5f71e4SJoseph Chen 	} else {
512aa415ed9SJoseph Chen 		ret = rkfw_load_kernel(info, boot_sector, spl_image, try_count);
513a5f4ae85SJason Zhu 		if (ret) {
5148a5f71e4SJoseph Chen 			part_name = PART_BOOT;
51513c5d8ecSJoseph Chen 			goto out;
51613c5d8ecSJoseph Chen 		}
517aa415ed9SJoseph Chen 	}
51813c5d8ecSJoseph Chen 
51913c5d8ecSJoseph Chen #if CONFIG_IS_ENABLED(LOAD_FIT)
52013c5d8ecSJoseph Chen 	spl_image->fdt_addr = 0;
52113c5d8ecSJoseph Chen #endif
522a64fd729SJason Zhu #ifdef CONFIG_SPL_ATF
52313c5d8ecSJoseph Chen 	spl_image->os = IH_OS_ARM_TRUSTED_FIRMWARE;
524a64fd729SJason Zhu #else
525a64fd729SJason Zhu 	spl_image->os = IH_OS_OP_TEE;
526a64fd729SJason Zhu #endif
52713c5d8ecSJoseph Chen 
52813c5d8ecSJoseph Chen out:
5298a5f71e4SJoseph Chen 	if (ret)
5308a5f71e4SJoseph Chen 		printf("Load %s part failed! ret=%d\n", part_name, ret);
5318a5f71e4SJoseph Chen 
53213c5d8ecSJoseph Chen 	/* If not found rockchip firmware, try others outside */
53313c5d8ecSJoseph Chen 	return found_rkfw ? ret : -EAGAIN;
53413c5d8ecSJoseph Chen }
535