xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/fit.c (revision e3b1b43ef291fbc581595d3bc9a9785318530a6a)
1059c50acSJoseph Chen /*
2059c50acSJoseph Chen  * (C) Copyright 2019 Rockchip Electronics Co., Ltd
3059c50acSJoseph Chen  *
4059c50acSJoseph Chen  * SPDX-License-Identifier:     GPL-2.0+
5059c50acSJoseph Chen  */
6059c50acSJoseph Chen #include <common.h>
7059c50acSJoseph Chen #include <boot_rkimg.h>
8059c50acSJoseph Chen #include <image.h>
9059c50acSJoseph Chen #include <malloc.h>
10059c50acSJoseph Chen #include <sysmem.h>
11059c50acSJoseph Chen #include <asm/arch/fit.h>
12059c50acSJoseph Chen #include <asm/arch/resource_img.h>
13059c50acSJoseph Chen 
14059c50acSJoseph Chen DECLARE_GLOBAL_DATA_PTR;
15059c50acSJoseph Chen 
164e07096aSJoseph Chen #define FIT_PLACEHOLDER_ADDR		0xffffff00
17059c50acSJoseph Chen 
18059c50acSJoseph Chen /*
19059c50acSJoseph Chen  * Must use args '-E -p' for mkimage to generate FIT image, 4K as max assumption.
20059c50acSJoseph Chen  */
21059c50acSJoseph Chen #define FIT_FDT_MAX_SIZE		SZ_4K
22059c50acSJoseph Chen 
fit_is_ext_type(const void * fit)23a1daefc8SJoseph Chen static int fit_is_ext_type(const void *fit)
24059c50acSJoseph Chen {
25059c50acSJoseph Chen 	return fdt_totalsize(fit) < FIT_FDT_MAX_SIZE;
26059c50acSJoseph Chen }
27059c50acSJoseph Chen 
fit_is_signed(const void * fit,const void * sig_blob)28a1daefc8SJoseph Chen static int fit_is_signed(const void *fit, const void *sig_blob)
29059c50acSJoseph Chen {
30059c50acSJoseph Chen 	return fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME) < 0 ? 0 : 1;
31059c50acSJoseph Chen }
32059c50acSJoseph Chen 
fit_image_addr_is_placeholder(ulong addr)33a1daefc8SJoseph Chen static inline int fit_image_addr_is_placeholder(ulong addr)
344e07096aSJoseph Chen {
354e07096aSJoseph Chen 	return (addr & 0xffffff00) == FIT_PLACEHOLDER_ADDR;
364e07096aSJoseph Chen }
374e07096aSJoseph Chen 
fit_sig_require_conf(const void * fit,const void * sig_blob)38a1daefc8SJoseph Chen static int fit_sig_require_conf(const void *fit, const void *sig_blob)
39059c50acSJoseph Chen {
40a1daefc8SJoseph Chen 	const char *required;
41059c50acSJoseph Chen 	int sig_node;
42059c50acSJoseph Chen 	int noffset;
43059c50acSJoseph Chen 
44059c50acSJoseph Chen 	sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
45059c50acSJoseph Chen 	if (sig_node < 0)
46059c50acSJoseph Chen 		return 0;
47059c50acSJoseph Chen 
48059c50acSJoseph Chen 	fdt_for_each_subnode(noffset, sig_blob, sig_node) {
49059c50acSJoseph Chen 		required = fdt_getprop(sig_blob, noffset, "required", NULL);
50059c50acSJoseph Chen 		if (required && !strcmp(required, "conf"))
51059c50acSJoseph Chen 			return 1;
52059c50acSJoseph Chen 	}
53059c50acSJoseph Chen 
54059c50acSJoseph Chen 	return 0;
55059c50acSJoseph Chen }
56059c50acSJoseph Chen 
fit_default_conf_get_node(const void * fit,const char * prop_name)57a1daefc8SJoseph Chen int fit_default_conf_get_node(const void *fit, const char *prop_name)
58a1daefc8SJoseph Chen {
59a1daefc8SJoseph Chen 	int conf_noffset;
60a1daefc8SJoseph Chen 
61a1daefc8SJoseph Chen 	conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */
62a1daefc8SJoseph Chen 	if (conf_noffset < 0)
63a1daefc8SJoseph Chen 		return conf_noffset;
64a1daefc8SJoseph Chen 
65a1daefc8SJoseph Chen 	return fit_conf_get_prop_node(fit, conf_noffset, prop_name);
66a1daefc8SJoseph Chen }
67a1daefc8SJoseph Chen 
fix_image_set_addr(const void * fit,const char * prop_name,ulong old,ulong new)68a1daefc8SJoseph Chen int fix_image_set_addr(const void *fit, const char *prop_name,
69a1daefc8SJoseph Chen 		       ulong old, ulong new)
70a1daefc8SJoseph Chen {
71a1daefc8SJoseph Chen 	int noffset;
72a1daefc8SJoseph Chen 
73a1daefc8SJoseph Chen 	/* do not fix if verified-boot */
74a1daefc8SJoseph Chen 	if (!fit_image_addr_is_placeholder(old) ||
75a1daefc8SJoseph Chen 	     fit_sig_require_conf(fit, gd_fdt_blob()))
76a1daefc8SJoseph Chen 		return 0;
77a1daefc8SJoseph Chen 
78a1daefc8SJoseph Chen 	noffset = fit_default_conf_get_node(fit, prop_name);
79a1daefc8SJoseph Chen 	if (noffset < 0)
80a1daefc8SJoseph Chen 		return noffset;
81a1daefc8SJoseph Chen 
82a1daefc8SJoseph Chen 	/* optional */
83a1daefc8SJoseph Chen 	fit_image_set_entry(fit, noffset, new);
84a1daefc8SJoseph Chen 
85a1daefc8SJoseph Chen 	return fit_image_set_load(fit, noffset, new);
86a1daefc8SJoseph Chen }
87a1daefc8SJoseph Chen 
fdt_image_get_offset_size(const void * fit,const char * prop_name,int * offset,int * size)88a1daefc8SJoseph Chen static int fdt_image_get_offset_size(const void *fit, const char *prop_name,
89a1daefc8SJoseph Chen 				     int *offset, int *size)
90a1daefc8SJoseph Chen {
91a1daefc8SJoseph Chen 	int sz, offs;
92a1daefc8SJoseph Chen 	int noffset;
93a1daefc8SJoseph Chen 	int ret;
94a1daefc8SJoseph Chen 
95a1daefc8SJoseph Chen 	noffset = fit_default_conf_get_node(fit, prop_name);
96a1daefc8SJoseph Chen 	if (noffset < 0)
97a1daefc8SJoseph Chen 		return noffset;
98a1daefc8SJoseph Chen 
99a1daefc8SJoseph Chen 	ret = fit_image_get_data_size(fit, noffset, &sz);
100a1daefc8SJoseph Chen 	if (ret)
101a1daefc8SJoseph Chen 		return ret;
102a1daefc8SJoseph Chen 
103a1daefc8SJoseph Chen 	ret = fit_image_get_data_position(fit, noffset, &offs);
104a1daefc8SJoseph Chen 	if (!ret)
105a1daefc8SJoseph Chen 		offs -= fdt_totalsize(fit);
106a1daefc8SJoseph Chen 	else
107a1daefc8SJoseph Chen 		ret = fit_image_get_data_offset(fit, noffset, &offs);
108a1daefc8SJoseph Chen 
109a1daefc8SJoseph Chen 	*offset = offs;
110a1daefc8SJoseph Chen 	*size = sz;
111a1daefc8SJoseph Chen 
112a1daefc8SJoseph Chen 	return ret;
113a1daefc8SJoseph Chen }
114a1daefc8SJoseph Chen 
fdt_image_get_load(const void * fit,const char * prop_name,ulong * load)115a1daefc8SJoseph Chen static int fdt_image_get_load(const void *fit, const char *prop_name,
116a1daefc8SJoseph Chen 			      ulong *load)
117a1daefc8SJoseph Chen {
118a1daefc8SJoseph Chen 	int noffset;
119a1daefc8SJoseph Chen 
120a1daefc8SJoseph Chen 	noffset = fit_default_conf_get_node(fit, prop_name);
121a1daefc8SJoseph Chen 	if (noffset < 0)
122a1daefc8SJoseph Chen 		return noffset;
123a1daefc8SJoseph Chen 
124a1daefc8SJoseph Chen 	return fit_image_get_load(fit, noffset, load);
125a1daefc8SJoseph Chen }
126a1daefc8SJoseph Chen 
fit_image_get_param(const void * fit,const char * prop_name,ulong * load,int * offset,int * size)127a1daefc8SJoseph Chen static int fit_image_get_param(const void *fit, const char *prop_name,
128a1daefc8SJoseph Chen 			       ulong *load, int *offset, int *size)
129a1daefc8SJoseph Chen {
130a1daefc8SJoseph Chen 	int ret;
131a1daefc8SJoseph Chen 
132a1daefc8SJoseph Chen 	ret = fdt_image_get_offset_size(fit, prop_name, offset, size);
133a1daefc8SJoseph Chen 	if (ret < 0)
134a1daefc8SJoseph Chen 		return ret;
135a1daefc8SJoseph Chen 
136a1daefc8SJoseph Chen 	return fdt_image_get_load(fit, prop_name, load);
137a1daefc8SJoseph Chen }
138a1daefc8SJoseph Chen 
fit_get_blob(struct blk_desc * dev_desc,disk_partition_t * out_part,bool verify)13925a706d2SJoseph Chen static void *fit_get_blob(struct blk_desc *dev_desc,
14025a706d2SJoseph Chen 			  disk_partition_t *out_part,
14125a706d2SJoseph Chen 			  bool verify)
142a1daefc8SJoseph Chen {
14325a706d2SJoseph Chen 	__maybe_unused int conf_noffset;
14425a706d2SJoseph Chen 	disk_partition_t part;
1456ea28a6cSJoseph Chen 	char *part_name = PART_BOOT;
146a1daefc8SJoseph Chen 	void *fit, *fdt;
147a1daefc8SJoseph Chen 	int blk_num;
148a1daefc8SJoseph Chen 
1496ea28a6cSJoseph Chen #ifndef CONFIG_ANDROID_AB
15025a706d2SJoseph Chen 	if (rockchip_get_boot_mode() == BOOT_MODE_RECOVERY)
15125a706d2SJoseph Chen 		part_name = PART_RECOVERY;
1526ea28a6cSJoseph Chen #endif
15325a706d2SJoseph Chen 
15425a706d2SJoseph Chen 	if (part_get_info_by_name(dev_desc, part_name, &part) < 0) {
15525a706d2SJoseph Chen 		FIT_I("No %s partition\n", part_name);
15625a706d2SJoseph Chen 		return NULL;
15725a706d2SJoseph Chen 	}
15825a706d2SJoseph Chen 
15925a706d2SJoseph Chen 	*out_part = part;
160a1daefc8SJoseph Chen 	blk_num = DIV_ROUND_UP(sizeof(struct fdt_header), dev_desc->blksz);
161a1daefc8SJoseph Chen 	fdt = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz);
162a1daefc8SJoseph Chen 	if (!fdt)
163a1daefc8SJoseph Chen 		return NULL;
164a1daefc8SJoseph Chen 
16525a706d2SJoseph Chen 	if (blk_dread(dev_desc, part.start, blk_num, fdt) != blk_num) {
166a1daefc8SJoseph Chen 		debug("Failed to read fdt header\n");
167a1daefc8SJoseph Chen 		goto fail;
168a1daefc8SJoseph Chen 	}
169a1daefc8SJoseph Chen 
170a1daefc8SJoseph Chen 	if (fdt_check_header(fdt)) {
171a1daefc8SJoseph Chen 		debug("No fdt header\n");
172a1daefc8SJoseph Chen 		goto fail;
173a1daefc8SJoseph Chen 	}
174a1daefc8SJoseph Chen 
175a1daefc8SJoseph Chen 	if (!fit_is_ext_type(fdt)) {
176a1daefc8SJoseph Chen 		debug("Not external type\n");
177a1daefc8SJoseph Chen 		goto fail;
178a1daefc8SJoseph Chen 	}
179a1daefc8SJoseph Chen 
180a1daefc8SJoseph Chen 	blk_num = DIV_ROUND_UP(fdt_totalsize(fdt), dev_desc->blksz);
181a1daefc8SJoseph Chen 	fit = memalign(ARCH_DMA_MINALIGN, blk_num * dev_desc->blksz);
182a1daefc8SJoseph Chen 	if (!fit) {
183a1daefc8SJoseph Chen 		debug("No memory\n");
184a1daefc8SJoseph Chen 		goto fail;
185a1daefc8SJoseph Chen 	}
186a1daefc8SJoseph Chen 
18725a706d2SJoseph Chen 	if (blk_dread(dev_desc, part.start, blk_num, fit) != blk_num) {
188a1daefc8SJoseph Chen 		free(fit);
189a1daefc8SJoseph Chen 		debug("Failed to read fit blob\n");
190a1daefc8SJoseph Chen 		goto fail;
191a1daefc8SJoseph Chen 	}
192a1daefc8SJoseph Chen 
19325a706d2SJoseph Chen #ifdef CONFIG_FIT_SIGNATURE
19425a706d2SJoseph Chen 	if (!verify)
19525a706d2SJoseph Chen 		return fit;
19625a706d2SJoseph Chen 
19725a706d2SJoseph Chen 	conf_noffset = fit_conf_get_node(fit, NULL); /* NULL for default conf */
19825a706d2SJoseph Chen 	if (conf_noffset < 0)
19925a706d2SJoseph Chen 		goto fail;
20025a706d2SJoseph Chen 
20125a706d2SJoseph Chen 	printf("%s: ", fdt_get_name(fit, conf_noffset, NULL));
20225a706d2SJoseph Chen 	if (fit_config_verify(fit, conf_noffset)) {
20325a706d2SJoseph Chen 		puts("\n");
20463f38f9dSJoseph Chen 		/* don't remove this failure handle */
20525a706d2SJoseph Chen 		run_command("download", 0);
20625a706d2SJoseph Chen 		hang();
20725a706d2SJoseph Chen 	}
20825a706d2SJoseph Chen 	puts("\n");
20925a706d2SJoseph Chen #endif
210a1daefc8SJoseph Chen 	return fit;
211a1daefc8SJoseph Chen 
212a1daefc8SJoseph Chen fail:
213a1daefc8SJoseph Chen 	free(fdt);
214a1daefc8SJoseph Chen 	return NULL;
215a1daefc8SJoseph Chen }
216a1daefc8SJoseph Chen 
fit_image_fixup_alloc(const void * fit,const char * prop_name,const char * addr_name,enum memblk_id mem)217a1daefc8SJoseph Chen static int fit_image_fixup_alloc(const void *fit, const char *prop_name,
218a1daefc8SJoseph Chen 				 const char *addr_name, enum memblk_id mem)
219a1daefc8SJoseph Chen {
220a1daefc8SJoseph Chen 	ulong load, addr;
221a1daefc8SJoseph Chen 	int offset, size = 0;
222a1daefc8SJoseph Chen 	int ret;
223a1daefc8SJoseph Chen 
224a1daefc8SJoseph Chen 	addr = env_get_ulong(addr_name, 16, 0);
225a1daefc8SJoseph Chen 	if (!addr)
226a1daefc8SJoseph Chen 		return -EINVAL;
227a1daefc8SJoseph Chen 
228a1daefc8SJoseph Chen 	ret = fit_image_get_param(fit, prop_name, &load, &offset, &size);
229a1daefc8SJoseph Chen 	if (ret)
230a1daefc8SJoseph Chen 		return (ret == -FDT_ERR_NOTFOUND) ? 0 : ret;
231a1daefc8SJoseph Chen 
232a1daefc8SJoseph Chen 	if (!size)
233a1daefc8SJoseph Chen 		return 0;
234a1daefc8SJoseph Chen 
235a1daefc8SJoseph Chen 	ret = fix_image_set_addr(fit, prop_name, load, addr);
236a1daefc8SJoseph Chen 	if (ret)
237a1daefc8SJoseph Chen 		return ret;
238a1daefc8SJoseph Chen 
239eac1bc9eSXuhui Lin /*
240eac1bc9eSXuhui Lin  * 1. When need load HWID dtb, gd->fdt_blob points to HWID dtb
241eac1bc9eSXuhui Lin  *    and U-Boot will re-alloc MEM_FDT based on fdt node in
242eac1bc9eSXuhui Lin  *    ITB instead of resource. So alloc the larger size to
243eac1bc9eSXuhui Lin  *    avoid fail in sysmem. It will already skip load DTB in fdt node.
244eac1bc9eSXuhui Lin  *
245eac1bc9eSXuhui Lin  * 2. Additionally increase size with CONFIG_SYS_FDT_PAD to reserve
246eac1bc9eSXuhui Lin  *    some space for adding more props to dtb afterwards.
247eac1bc9eSXuhui Lin  */
248eac1bc9eSXuhui Lin 	if (!strcmp(prop_name, FIT_FDT_PROP) && !fdt_check_header(gd->fdt_blob))
249eac1bc9eSXuhui Lin 		size = ((size > fdt_totalsize(gd->fdt_blob)) ?
250eac1bc9eSXuhui Lin 			 size : fdt_totalsize(gd->fdt_blob)) +
251eac1bc9eSXuhui Lin 			 CONFIG_SYS_FDT_PAD;
252eac1bc9eSXuhui Lin 
253a1daefc8SJoseph Chen 	if (!sysmem_alloc_base(mem, (phys_addr_t)addr,
254a1daefc8SJoseph Chen 			       ALIGN(size, RK_BLK_SIZE)))
255a1daefc8SJoseph Chen 		return -ENOMEM;
256a1daefc8SJoseph Chen 
257a1daefc8SJoseph Chen 	return 0;
258a1daefc8SJoseph Chen }
259a1daefc8SJoseph Chen 
fit_image_pre_process(const void * fit)260a1daefc8SJoseph Chen int fit_image_pre_process(const void *fit)
261a1daefc8SJoseph Chen {
262a1daefc8SJoseph Chen 	int ret;
263a1daefc8SJoseph Chen 
264d7f8cc12SJoseph Chen 	/* free for fit_image_fixup_alloc(FIT_FDT_PROP) to re-alloc */
265d94316bfSJoseph Chen 	if ((gd->flags & GD_FLG_KDTB_READY) && !gd->fdt_blob_kern)
266059c50acSJoseph Chen 		sysmem_free((phys_addr_t)gd->fdt_blob);
267d94316bfSJoseph Chen 
268a1daefc8SJoseph Chen 	ret = fit_image_fixup_alloc(fit, FIT_FDT_PROP,
269a1daefc8SJoseph Chen 				    "fdt_addr_r", MEM_FDT);
2709408949aSXuhui Lin 	if (ret < 0) {
271a1daefc8SJoseph Chen 		return ret;
2729408949aSXuhui Lin 	}
273a1daefc8SJoseph Chen 
274*e3b1b43eSJoseph Chen #if defined(CONFIG_CMD_BOOTZ)
2759408949aSXuhui Lin 	int cfg_noffset, noffset;
2769408949aSXuhui Lin 	const void *buf;
2779408949aSXuhui Lin 	ulong start, end;
2789408949aSXuhui Lin 	size_t size;
2799408949aSXuhui Lin 
2809408949aSXuhui Lin 	cfg_noffset = fit_conf_get_node(fit, NULL);
2819408949aSXuhui Lin 	if (cfg_noffset < 0) {
2829408949aSXuhui Lin 		printf("Could not find configuration node\n");
2839408949aSXuhui Lin 		return -ENOENT;
2849408949aSXuhui Lin 	}
2859408949aSXuhui Lin 
2869408949aSXuhui Lin 	noffset = fit_conf_get_prop_node_index(fit, cfg_noffset, FIT_KERNEL_PROP, 0);
2879408949aSXuhui Lin 	if (noffset < 0) {
288*e3b1b43eSJoseph Chen 		printf("Could not find kernel node\n");
2899408949aSXuhui Lin 		return -ENOENT;
2909408949aSXuhui Lin 	}
2919408949aSXuhui Lin 
292*e3b1b43eSJoseph Chen 	/*
293*e3b1b43eSJoseph Chen 	 * "kernel_addr_r" is for 64-bit kernel Image by default.
294*e3b1b43eSJoseph Chen 	 * Here in case of 64-bit U-Boot load 32-bit kenrel Image.
295*e3b1b43eSJoseph Chen 	 */
296*e3b1b43eSJoseph Chen #ifdef CONFIG_ARM64
297*e3b1b43eSJoseph Chen 	char *kernel_addr_r;
298*e3b1b43eSJoseph Chen 
299*e3b1b43eSJoseph Chen 	if (fit_image_check_arch(fit, noffset, IH_ARCH_ARM)) {
300*e3b1b43eSJoseph Chen 		kernel_addr_r = env_get("kernel_addr_aarch32_r");
301*e3b1b43eSJoseph Chen 		if (kernel_addr_r)
302*e3b1b43eSJoseph Chen 			env_set("kernel_addr_r", kernel_addr_r);
303*e3b1b43eSJoseph Chen 	}
304*e3b1b43eSJoseph Chen #endif
3059408949aSXuhui Lin 	/* get image data address and length */
3069408949aSXuhui Lin 	if (fit_image_get_data(fit, noffset, &buf, &size)) {
3079408949aSXuhui Lin 		printf("Could not find %s subimage data!\n", FIT_KERNEL_PROP);
3089408949aSXuhui Lin 		return -ENOENT;
3099408949aSXuhui Lin 	}
3109408949aSXuhui Lin 
3119408949aSXuhui Lin 	if (!bootz_setup((ulong)buf, &start, &end))
3129408949aSXuhui Lin 		ret = fit_image_fixup_alloc(fit, FIT_KERNEL_PROP,
3139408949aSXuhui Lin 					    "kernel_addr_c", MEM_KERNEL);
3149408949aSXuhui Lin 	else
3159408949aSXuhui Lin #endif
316a1daefc8SJoseph Chen 		ret = fit_image_fixup_alloc(fit, FIT_KERNEL_PROP,
317a1daefc8SJoseph Chen 					    "kernel_addr_r", MEM_KERNEL);
318a1daefc8SJoseph Chen 	if (ret < 0)
319a1daefc8SJoseph Chen 		return ret;
320a1daefc8SJoseph Chen 
321a1daefc8SJoseph Chen 	return fit_image_fixup_alloc(fit, FIT_RAMDISK_PROP,
322a1daefc8SJoseph Chen 				     "ramdisk_addr_r", MEM_RAMDISK);
323059c50acSJoseph Chen }
324059c50acSJoseph Chen 
fit_image_fail_process(const void * fit)325a1daefc8SJoseph Chen int fit_image_fail_process(const void *fit)
326059c50acSJoseph Chen {
327059c50acSJoseph Chen 	ulong raddr, kaddr, faddr;
328059c50acSJoseph Chen 
329059c50acSJoseph Chen 	raddr = env_get_ulong("ramdisk_addr_r", 16, 0);
330059c50acSJoseph Chen 	kaddr = env_get_ulong("kernel_addr_r", 16, 0);
331059c50acSJoseph Chen 	faddr = env_get_ulong("fdt_addr_r", 16, 0);
332059c50acSJoseph Chen 
333059c50acSJoseph Chen 	sysmem_free((phys_addr_t)fit);
334059c50acSJoseph Chen 	sysmem_free((phys_addr_t)raddr);
335059c50acSJoseph Chen 	sysmem_free((phys_addr_t)kaddr);
336059c50acSJoseph Chen 	sysmem_free((phys_addr_t)faddr);
337059c50acSJoseph Chen 
338059c50acSJoseph Chen 	return 0;
339059c50acSJoseph Chen }
340059c50acSJoseph Chen 
fit_image_get_subnode(const void * fit,int noffset,const char * name)34125a706d2SJoseph Chen static int fit_image_get_subnode(const void *fit, int noffset, const char *name)
34225a706d2SJoseph Chen {
34325a706d2SJoseph Chen 	int sub_noffset;
34425a706d2SJoseph Chen 
34525a706d2SJoseph Chen 	fdt_for_each_subnode(sub_noffset, fit, noffset) {
34625a706d2SJoseph Chen 		if (!strncmp(fit_get_name(fit, sub_noffset, NULL),
34725a706d2SJoseph Chen 			     name, strlen(name)))
34825a706d2SJoseph Chen 			return sub_noffset;
34925a706d2SJoseph Chen 	}
35025a706d2SJoseph Chen 
35125a706d2SJoseph Chen 	return -ENOENT;
35225a706d2SJoseph Chen }
35325a706d2SJoseph Chen 
fit_image_load_one(const void * fit,struct blk_desc * dev_desc,disk_partition_t * part,char * prop_name,void * data,int check_hash)35463f38f9dSJoseph Chen static int fit_image_load_one(const void *fit, struct blk_desc *dev_desc,
355a1daefc8SJoseph Chen 			      disk_partition_t *part, char *prop_name,
356a1daefc8SJoseph Chen 			      void *data, int check_hash)
357059c50acSJoseph Chen {
358a1daefc8SJoseph Chen 	u32 blk_num, blk_off;
359059c50acSJoseph Chen 	int offset, size;
360a1daefc8SJoseph Chen 	int noffset, ret;
361a1daefc8SJoseph Chen 	char *msg = "";
362059c50acSJoseph Chen 
363a1daefc8SJoseph Chen 	ret = fdt_image_get_offset_size(fit, prop_name, &offset, &size);
364a1daefc8SJoseph Chen 	if (ret)
365a1daefc8SJoseph Chen 		return ret;
366059c50acSJoseph Chen 
367a1daefc8SJoseph Chen 	blk_off = (FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz;
368a1daefc8SJoseph Chen 	blk_num = DIV_ROUND_UP(size, dev_desc->blksz);
369a1daefc8SJoseph Chen 	if (blk_dread(dev_desc, part->start + blk_off, blk_num, data) != blk_num)
370059c50acSJoseph Chen 		return -EIO;
371059c50acSJoseph Chen 
372a1daefc8SJoseph Chen 	if (check_hash) {
373a1daefc8SJoseph Chen 		int hash_noffset;
374a1daefc8SJoseph Chen 
375a1daefc8SJoseph Chen 		noffset = fit_default_conf_get_node(fit, prop_name);
376a1daefc8SJoseph Chen 		if (noffset < 0)
377a1daefc8SJoseph Chen 			return noffset;
378a1daefc8SJoseph Chen 
379a1daefc8SJoseph Chen 		hash_noffset = fit_image_get_subnode(fit, noffset,
380a1daefc8SJoseph Chen 						     FIT_HASH_NODENAME);
381a1daefc8SJoseph Chen 		if (hash_noffset < 0)
382a1daefc8SJoseph Chen 			return hash_noffset;
383a1daefc8SJoseph Chen 
384a1daefc8SJoseph Chen 		printf("%s: ", fdt_get_name(fit, noffset, NULL));
385a1daefc8SJoseph Chen 		ret = fit_image_check_hash(fit, hash_noffset, data, size, &msg);
386a1daefc8SJoseph Chen 		if (ret)
387a1daefc8SJoseph Chen 			return ret;
388a1daefc8SJoseph Chen 
389a1daefc8SJoseph Chen 		puts("+\n");
390a1daefc8SJoseph Chen 	}
391a1daefc8SJoseph Chen 
392059c50acSJoseph Chen 	return 0;
393059c50acSJoseph Chen }
394059c50acSJoseph Chen 
395a1daefc8SJoseph Chen /* Calculate what we really need */
fit_image_get_bootables_size(const void * fit)396a1daefc8SJoseph Chen ulong fit_image_get_bootables_size(const void *fit)
397059c50acSJoseph Chen {
398059c50acSJoseph Chen 	ulong off[3] = { 0, 0, 0 };
399059c50acSJoseph Chen 	ulong max_off, load;
400059c50acSJoseph Chen 	int offset, size;
401059c50acSJoseph Chen 
4020d2e36b8SJoseph Chen #if 0
4030d2e36b8SJoseph Chen 	if (!fit_get_totalsize(fit, &size))
4040d2e36b8SJoseph Chen 		return size;
4050d2e36b8SJoseph Chen #endif
4060d2e36b8SJoseph Chen 
407a1daefc8SJoseph Chen 	if (!fit_image_get_param(fit, FIT_FDT_PROP, &load, &offset, &size))
408059c50acSJoseph Chen 		off[0] = offset + FIT_ALIGN(size);
409059c50acSJoseph Chen 
410a1daefc8SJoseph Chen 	if (!fit_image_get_param(fit, FIT_KERNEL_PROP, &load, &offset, &size))
411059c50acSJoseph Chen 		off[1] = offset + FIT_ALIGN(size);
412059c50acSJoseph Chen 
413a1daefc8SJoseph Chen 	if (!fit_image_get_param(fit, FIT_RAMDISK_PROP, &load, &offset, &size))
414059c50acSJoseph Chen 		off[2] = offset + FIT_ALIGN(size);
415059c50acSJoseph Chen 
416059c50acSJoseph Chen 	max_off = max(off[0],  off[1]);
417059c50acSJoseph Chen 	max_off = max(max_off, off[2]);
418059c50acSJoseph Chen 
419059c50acSJoseph Chen 	return FIT_ALIGN(fdt_totalsize(fit)) + max_off;
420059c50acSJoseph Chen }
421059c50acSJoseph Chen 
fit_image_load_bootables(ulong * size)422059c50acSJoseph Chen void *fit_image_load_bootables(ulong *size)
423059c50acSJoseph Chen {
424059c50acSJoseph Chen 	struct blk_desc *dev_desc;
425059c50acSJoseph Chen 	disk_partition_t part;
426a1daefc8SJoseph Chen 	int blk_num;
427059c50acSJoseph Chen 	void *fit;
428059c50acSJoseph Chen 
429059c50acSJoseph Chen 	dev_desc = rockchip_get_bootdev();
430a1daefc8SJoseph Chen 	if (!dev_desc)
431059c50acSJoseph Chen 		return NULL;
432059c50acSJoseph Chen 
43325a706d2SJoseph Chen 	fit = fit_get_blob(dev_desc, &part, false);
434059c50acSJoseph Chen 	if (!fit) {
435059c50acSJoseph Chen 		FIT_I("No fit blob\n");
436059c50acSJoseph Chen 		return NULL;
437059c50acSJoseph Chen 	}
438059c50acSJoseph Chen 
439a1daefc8SJoseph Chen 	*size = fit_image_get_bootables_size(fit);
440059c50acSJoseph Chen 	if (*size == 0) {
441a1daefc8SJoseph Chen 		FIT_I("No bootable image\n");
442059c50acSJoseph Chen 		return NULL;
443059c50acSJoseph Chen 	}
444059c50acSJoseph Chen 
445a1daefc8SJoseph Chen 	blk_num = DIV_ROUND_UP(*size, dev_desc->blksz);
446a1daefc8SJoseph Chen 	fit = sysmem_alloc(MEM_FIT, blk_num * dev_desc->blksz);
447059c50acSJoseph Chen 	if (!fit)
448059c50acSJoseph Chen 		return NULL;
449059c50acSJoseph Chen 
450a1daefc8SJoseph Chen 	if (blk_dread(dev_desc, part.start, blk_num, fit) != blk_num) {
451059c50acSJoseph Chen 		FIT_I("Failed to load bootable images\n");
452059c50acSJoseph Chen 		return NULL;
453059c50acSJoseph Chen 	}
454059c50acSJoseph Chen 
455059c50acSJoseph Chen 	return fit;
456059c50acSJoseph Chen }
457059c50acSJoseph Chen 
fit_msg(const void * fit)458a1daefc8SJoseph Chen static void fit_msg(const void *fit)
459059c50acSJoseph Chen {
460a1daefc8SJoseph Chen 	FIT_I("%ssigned, %sconf required\n",
461059c50acSJoseph Chen 	      fit_is_signed(fit, gd_fdt_blob()) ? "" : "no ",
462a1daefc8SJoseph Chen 	      fit_sig_require_conf(fit, gd_fdt_blob()) ? "" : "no ");
463059c50acSJoseph Chen }
464059c50acSJoseph Chen 
46525a706d2SJoseph Chen #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
fit_image_init_resource(struct blk_desc * dev_desc)46663f38f9dSJoseph Chen ulong fit_image_init_resource(struct blk_desc *dev_desc)
46725a706d2SJoseph Chen {
468059c50acSJoseph Chen 	disk_partition_t part;
46963f38f9dSJoseph Chen 	void *fit, *buf;
47063f38f9dSJoseph Chen 	int offset, size;
47125a706d2SJoseph Chen 	int ret = 0;
472059c50acSJoseph Chen 
4736ea28a6cSJoseph Chen 	if (!dev_desc)
474059c50acSJoseph Chen 		return -ENODEV;
475059c50acSJoseph Chen 
47625a706d2SJoseph Chen 	fit = fit_get_blob(dev_desc, &part, true);
47725a706d2SJoseph Chen 	if (!fit)
47863f38f9dSJoseph Chen 		return -EAGAIN;
47963f38f9dSJoseph Chen 
48063f38f9dSJoseph Chen 	ret = fdt_image_get_offset_size(fit, FIT_MULTI_PROP, &offset, &size);
48163f38f9dSJoseph Chen 	if (ret)
482059c50acSJoseph Chen 		return -EINVAL;
483059c50acSJoseph Chen 
48463f38f9dSJoseph Chen 	buf = memalign(ARCH_DMA_MINALIGN, ALIGN(size, dev_desc->blksz));
48563f38f9dSJoseph Chen 	if (!buf)
48663f38f9dSJoseph Chen 		return -ENOMEM;
48725a706d2SJoseph Chen 
48863f38f9dSJoseph Chen 	printf("RESC: '%s', blk@0x%08lx\n", part.name,
48963f38f9dSJoseph Chen 	       part.start + ((FIT_ALIGN(fdt_totalsize(fit)) + offset) / dev_desc->blksz));
49063f38f9dSJoseph Chen 	ret = fit_image_load_one(fit, dev_desc, &part, FIT_MULTI_PROP, buf, 1);
49163f38f9dSJoseph Chen 	if (ret)
49225a706d2SJoseph Chen 		return ret;
493a79e8fe6SJoseph Chen 
49463f38f9dSJoseph Chen 	ret = resource_setup_ram_list(dev_desc, buf);
49563f38f9dSJoseph Chen 	if (ret) {
49663f38f9dSJoseph Chen 		FIT_I("Failed to setup resource ram list, ret=%d\n", ret);
49763f38f9dSJoseph Chen 		free(fit);
49863f38f9dSJoseph Chen 		return ret;
49963f38f9dSJoseph Chen 	}
5006ea28a6cSJoseph Chen 
501a1daefc8SJoseph Chen 	fit_msg(fit);
502059c50acSJoseph Chen 	free(fit);
503059c50acSJoseph Chen 
5046ea28a6cSJoseph Chen 	return 0;
505059c50acSJoseph Chen }
50625a706d2SJoseph Chen #else
fit_image_read_dtb(void * fdt_addr)50725a706d2SJoseph Chen int fit_image_read_dtb(void *fdt_addr)
50825a706d2SJoseph Chen {
50925a706d2SJoseph Chen 	struct blk_desc *dev_desc;
51025a706d2SJoseph Chen 	disk_partition_t part;
51125a706d2SJoseph Chen 	void *fit;
5128b233050SJoseph Chen 
51325a706d2SJoseph Chen 	dev_desc = rockchip_get_bootdev();
51425a706d2SJoseph Chen 	if (!dev_desc) {
51525a706d2SJoseph Chen 		FIT_I("No dev_desc!\n");
51625a706d2SJoseph Chen 		return -ENODEV;;
51725a706d2SJoseph Chen 	}
51825a706d2SJoseph Chen 
51925a706d2SJoseph Chen 	fit = fit_get_blob(dev_desc, &part, true);
52025a706d2SJoseph Chen 	if (!fit)
52125a706d2SJoseph Chen 		return -EINVAL;
52225a706d2SJoseph Chen 
52325a706d2SJoseph Chen 	fit_msg(fit);
52425a706d2SJoseph Chen 
52525a706d2SJoseph Chen 	return fit_image_load_one(fit, dev_desc, &part, FIT_FDT_PROP,
52625a706d2SJoseph Chen 				  (void *)fdt_addr, 1);
52725a706d2SJoseph Chen }
52825a706d2SJoseph Chen #endif
529