xref: /openbmc/u-boot/common/spl/spl_fit.c (revision b7d9107f)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2f1dcee59SSimon Glass /*
3f1dcee59SSimon Glass  * Copyright (C) 2016 Google, Inc
4f1dcee59SSimon Glass  * Written by Simon Glass <sjg@chromium.org>
5f1dcee59SSimon Glass  */
6f1dcee59SSimon Glass 
7f1dcee59SSimon Glass #include <common.h>
8f1dcee59SSimon Glass #include <errno.h>
93313ae66SMichal Simek #include <fpga.h>
10f1dcee59SSimon Glass #include <image.h>
11b08c8c48SMasahiro Yamada #include <linux/libfdt.h>
12f1dcee59SSimon Glass #include <spl.h>
13f1dcee59SSimon Glass 
147264f292SYork Sun #ifndef CONFIG_SYS_BOOTM_LEN
157264f292SYork Sun #define CONFIG_SYS_BOOTM_LEN	(64 << 20)
167264f292SYork Sun #endif
177264f292SYork Sun 
board_spl_fit_post_load(ulong load_addr,size_t length)18e246bfcfSYe Li __weak void board_spl_fit_post_load(ulong load_addr, size_t length)
19e246bfcfSYe Li {
20e246bfcfSYe Li }
21e246bfcfSYe Li 
board_spl_fit_size_align(ulong size)22e246bfcfSYe Li __weak ulong board_spl_fit_size_align(ulong size)
23e246bfcfSYe Li {
24e246bfcfSYe Li 	return size;
25e246bfcfSYe Li }
26e246bfcfSYe Li 
27736806fbSAndre Przywara /**
28a616c783SPhilipp Tomsich  * spl_fit_get_image_name(): By using the matching configuration subnode,
29736806fbSAndre Przywara  * retrieve the name of an image, specified by a property name and an index
30736806fbSAndre Przywara  * into that.
31736806fbSAndre Przywara  * @fit:	Pointer to the FDT blob.
32736806fbSAndre Przywara  * @images:	Offset of the /images subnode.
33736806fbSAndre Przywara  * @type:	Name of the property within the configuration subnode.
34736806fbSAndre Przywara  * @index:	Index into the list of strings in this property.
35a616c783SPhilipp Tomsich  * @outname:	Name of the image
36736806fbSAndre Przywara  *
37a616c783SPhilipp Tomsich  * Return:	0 on success, or a negative error number
38736806fbSAndre Przywara  */
spl_fit_get_image_name(const void * fit,int images,const char * type,int index,char ** outname)39a616c783SPhilipp Tomsich static int spl_fit_get_image_name(const void *fit, int images,
40a616c783SPhilipp Tomsich 				  const char *type, int index,
41a616c783SPhilipp Tomsich 				  char **outname)
424b9340abSAndre Przywara {
434b9340abSAndre Przywara 	const char *name, *str;
44a616c783SPhilipp Tomsich 	__maybe_unused int node;
45a616c783SPhilipp Tomsich 	int conf_node;
464b9340abSAndre Przywara 	int len, i;
47f1dcee59SSimon Glass 
483863f840SCooper Jr., Franklin 	conf_node = fit_find_config_node(fit);
494b9340abSAndre Przywara 	if (conf_node < 0) {
50f1dcee59SSimon Glass #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
51f1dcee59SSimon Glass 		printf("No matching DT out of these options:\n");
524b9340abSAndre Przywara 		for (node = fdt_first_subnode(fit, conf_node);
53f1dcee59SSimon Glass 		     node >= 0;
544b9340abSAndre Przywara 		     node = fdt_next_subnode(fit, node)) {
554b9340abSAndre Przywara 			name = fdt_getprop(fit, node, "description", &len);
56f1dcee59SSimon Glass 			printf("   %s\n", name);
57f1dcee59SSimon Glass 		}
58f1dcee59SSimon Glass #endif
594b9340abSAndre Przywara 		return conf_node;
604b9340abSAndre Przywara 	}
61f1dcee59SSimon Glass 
624b9340abSAndre Przywara 	name = fdt_getprop(fit, conf_node, type, &len);
634b9340abSAndre Przywara 	if (!name) {
644b9340abSAndre Przywara 		debug("cannot find property '%s': %d\n", type, len);
654b9340abSAndre Przywara 		return -EINVAL;
664b9340abSAndre Przywara 	}
674b9340abSAndre Przywara 
684b9340abSAndre Przywara 	str = name;
694b9340abSAndre Przywara 	for (i = 0; i < index; i++) {
704b9340abSAndre Przywara 		str = strchr(str, '\0') + 1;
714b9340abSAndre Przywara 		if (!str || (str - name >= len)) {
724b9340abSAndre Przywara 			debug("no string for index %d\n", index);
734b9340abSAndre Przywara 			return -E2BIG;
744b9340abSAndre Przywara 		}
754b9340abSAndre Przywara 	}
764b9340abSAndre Przywara 
77a616c783SPhilipp Tomsich 	*outname = (char *)str;
78a616c783SPhilipp Tomsich 	return 0;
79a616c783SPhilipp Tomsich }
80a616c783SPhilipp Tomsich 
81a616c783SPhilipp Tomsich /**
82a616c783SPhilipp Tomsich  * spl_fit_get_image_node(): By using the matching configuration subnode,
83a616c783SPhilipp Tomsich  * retrieve the name of an image, specified by a property name and an index
84a616c783SPhilipp Tomsich  * into that.
85a616c783SPhilipp Tomsich  * @fit:	Pointer to the FDT blob.
86a616c783SPhilipp Tomsich  * @images:	Offset of the /images subnode.
87a616c783SPhilipp Tomsich  * @type:	Name of the property within the configuration subnode.
88a616c783SPhilipp Tomsich  * @index:	Index into the list of strings in this property.
89a616c783SPhilipp Tomsich  *
90a616c783SPhilipp Tomsich  * Return:	the node offset of the respective image node or a negative
91a616c783SPhilipp Tomsich  *		error number.
92a616c783SPhilipp Tomsich  */
spl_fit_get_image_node(const void * fit,int images,const char * type,int index)93a616c783SPhilipp Tomsich static int spl_fit_get_image_node(const void *fit, int images,
94a616c783SPhilipp Tomsich 				  const char *type, int index)
95a616c783SPhilipp Tomsich {
96a616c783SPhilipp Tomsich 	char *str;
97a616c783SPhilipp Tomsich 	int err;
98a616c783SPhilipp Tomsich 	int node;
99a616c783SPhilipp Tomsich 
100a616c783SPhilipp Tomsich 	err = spl_fit_get_image_name(fit, images, type, index, &str);
101a616c783SPhilipp Tomsich 	if (err)
102a616c783SPhilipp Tomsich 		return err;
103a616c783SPhilipp Tomsich 
1044b9340abSAndre Przywara 	debug("%s: '%s'\n", type, str);
105a616c783SPhilipp Tomsich 
1064b9340abSAndre Przywara 	node = fdt_subnode_offset(fit, images, str);
1074b9340abSAndre Przywara 	if (node < 0) {
1084b9340abSAndre Przywara 		debug("cannot find image node '%s': %d\n", str, node);
1094b9340abSAndre Przywara 		return -EINVAL;
1104b9340abSAndre Przywara 	}
1114b9340abSAndre Przywara 
112736806fbSAndre Przywara 	return node;
113f1dcee59SSimon Glass }
114f1dcee59SSimon Glass 
get_aligned_image_offset(struct spl_load_info * info,int offset)115eafd5410SLokesh Vutla static int get_aligned_image_offset(struct spl_load_info *info, int offset)
116eafd5410SLokesh Vutla {
117eafd5410SLokesh Vutla 	/*
118eafd5410SLokesh Vutla 	 * If it is a FS read, get the first address before offset which is
119eafd5410SLokesh Vutla 	 * aligned to ARCH_DMA_MINALIGN. If it is raw read return the
120eafd5410SLokesh Vutla 	 * block number to which offset belongs.
121eafd5410SLokesh Vutla 	 */
122eafd5410SLokesh Vutla 	if (info->filename)
123eafd5410SLokesh Vutla 		return offset & ~(ARCH_DMA_MINALIGN - 1);
124eafd5410SLokesh Vutla 
125eafd5410SLokesh Vutla 	return offset / info->bl_len;
126eafd5410SLokesh Vutla }
127eafd5410SLokesh Vutla 
get_aligned_image_overhead(struct spl_load_info * info,int offset)128eafd5410SLokesh Vutla static int get_aligned_image_overhead(struct spl_load_info *info, int offset)
129eafd5410SLokesh Vutla {
130eafd5410SLokesh Vutla 	/*
131eafd5410SLokesh Vutla 	 * If it is a FS read, get the difference between the offset and
132eafd5410SLokesh Vutla 	 * the first address before offset which is aligned to
133eafd5410SLokesh Vutla 	 * ARCH_DMA_MINALIGN. If it is raw read return the offset within the
134eafd5410SLokesh Vutla 	 * block.
135eafd5410SLokesh Vutla 	 */
136eafd5410SLokesh Vutla 	if (info->filename)
137eafd5410SLokesh Vutla 		return offset & (ARCH_DMA_MINALIGN - 1);
138eafd5410SLokesh Vutla 
139eafd5410SLokesh Vutla 	return offset % info->bl_len;
140eafd5410SLokesh Vutla }
141eafd5410SLokesh Vutla 
get_aligned_image_size(struct spl_load_info * info,int data_size,int offset)142eafd5410SLokesh Vutla static int get_aligned_image_size(struct spl_load_info *info, int data_size,
143eafd5410SLokesh Vutla 				  int offset)
144eafd5410SLokesh Vutla {
1453cc1f380SLokesh Vutla 	data_size = data_size + get_aligned_image_overhead(info, offset);
1463cc1f380SLokesh Vutla 
147eafd5410SLokesh Vutla 	if (info->filename)
1483cc1f380SLokesh Vutla 		return data_size;
149eafd5410SLokesh Vutla 
150eafd5410SLokesh Vutla 	return (data_size + info->bl_len - 1) / info->bl_len;
151eafd5410SLokesh Vutla }
152eafd5410SLokesh Vutla 
1538baa3818SAndre Przywara /**
1548baa3818SAndre Przywara  * spl_load_fit_image(): load the image described in a certain FIT node
1558baa3818SAndre Przywara  * @info:	points to information about the device to load data from
1568baa3818SAndre Przywara  * @sector:	the start sector of the FIT image on the device
1578baa3818SAndre Przywara  * @fit:	points to the flattened device tree blob describing the FIT
1588baa3818SAndre Przywara  *		image
1598baa3818SAndre Przywara  * @base_offset: the beginning of the data area containing the actual
1608baa3818SAndre Przywara  *		image data, relative to the beginning of the FIT
1618baa3818SAndre Przywara  * @node:	offset of the DT node describing the image to load (relative
1628baa3818SAndre Przywara  *		to @fit)
1638baa3818SAndre Przywara  * @image_info:	will be filled with information about the loaded image
1648baa3818SAndre Przywara  *		If the FIT node does not contain a "load" (address) property,
1658baa3818SAndre Przywara  *		the image gets loaded to the address pointed to by the
1668baa3818SAndre Przywara  *		load_addr member in this struct.
1678baa3818SAndre Przywara  *
1688baa3818SAndre Przywara  * Return:	0 on success or a negative error number.
1698baa3818SAndre Przywara  */
spl_load_fit_image(struct spl_load_info * info,ulong sector,void * fit,ulong base_offset,int node,struct spl_image_info * image_info)1708baa3818SAndre Przywara static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
1718baa3818SAndre Przywara 			      void *fit, ulong base_offset, int node,
1728baa3818SAndre Przywara 			      struct spl_image_info *image_info)
1738baa3818SAndre Przywara {
1743313ae66SMichal Simek 	int offset;
1758baa3818SAndre Przywara 	size_t length;
1765fd13d97SYork Sun 	int len;
177933f67aaSYork Sun 	ulong size;
1788baa3818SAndre Przywara 	ulong load_addr, load_ptr;
1798baa3818SAndre Przywara 	void *src;
1808baa3818SAndre Przywara 	ulong overhead;
1818baa3818SAndre Przywara 	int nr_sectors;
1828baa3818SAndre Przywara 	int align_len = ARCH_DMA_MINALIGN - 1;
1837264f292SYork Sun 	uint8_t image_comp = -1, type = -1;
1845fd13d97SYork Sun 	const void *data;
185a1be94b6SPeng Fan 	bool external_data = false;
1867264f292SYork Sun 
18756419ea5SMarek Vasut 	if (IS_ENABLED(CONFIG_SPL_FPGA_SUPPORT) ||
18856419ea5SMarek Vasut 	    (IS_ENABLED(CONFIG_SPL_OS_BOOT) && IS_ENABLED(CONFIG_SPL_GZIP))) {
18956419ea5SMarek Vasut 		if (fit_image_get_type(fit, node, &type))
19056419ea5SMarek Vasut 			puts("Cannot get image type.\n");
19156419ea5SMarek Vasut 		else
19256419ea5SMarek Vasut 			debug("%s ", genimg_get_type_name(type));
19356419ea5SMarek Vasut 	}
19456419ea5SMarek Vasut 
1957264f292SYork Sun 	if (IS_ENABLED(CONFIG_SPL_OS_BOOT) && IS_ENABLED(CONFIG_SPL_GZIP)) {
1967264f292SYork Sun 		if (fit_image_get_comp(fit, node, &image_comp))
1977264f292SYork Sun 			puts("Cannot get image compression format.\n");
1987264f292SYork Sun 		else
1997264f292SYork Sun 			debug("%s ", genimg_get_comp_name(image_comp));
2007264f292SYork Sun 	}
2018baa3818SAndre Przywara 
2025fd13d97SYork Sun 	if (fit_image_get_load(fit, node, &load_addr))
2038baa3818SAndre Przywara 		load_addr = image_info->load_addr;
2045fd13d97SYork Sun 
205a1be94b6SPeng Fan 	if (!fit_image_get_data_position(fit, node, &offset)) {
206a1be94b6SPeng Fan 		external_data = true;
207a1be94b6SPeng Fan 	} else if (!fit_image_get_data_offset(fit, node, &offset)) {
2085fd13d97SYork Sun 		offset += base_offset;
209a1be94b6SPeng Fan 		external_data = true;
210a1be94b6SPeng Fan 	}
211a1be94b6SPeng Fan 
212a1be94b6SPeng Fan 	if (external_data) {
213a1be94b6SPeng Fan 		/* External data */
2145fd13d97SYork Sun 		if (fit_image_get_data_size(fit, node, &len))
2155fd13d97SYork Sun 			return -ENOENT;
2165fd13d97SYork Sun 
2178baa3818SAndre Przywara 		load_ptr = (load_addr + align_len) & ~align_len;
2185fd13d97SYork Sun 		length = len;
2198baa3818SAndre Przywara 
2208baa3818SAndre Przywara 		overhead = get_aligned_image_overhead(info, offset);
2218baa3818SAndre Przywara 		nr_sectors = get_aligned_image_size(info, length, offset);
2228baa3818SAndre Przywara 
2233313ae66SMichal Simek 		if (info->read(info,
2243313ae66SMichal Simek 			       sector + get_aligned_image_offset(info, offset),
2258baa3818SAndre Przywara 			       nr_sectors, (void *)load_ptr) != nr_sectors)
2268baa3818SAndre Przywara 			return -EIO;
2278baa3818SAndre Przywara 
2285fd13d97SYork Sun 		debug("External data: dst=%lx, offset=%x, size=%lx\n",
2295fd13d97SYork Sun 		      load_ptr, offset, (unsigned long)length);
2308baa3818SAndre Przywara 		src = (void *)load_ptr + overhead;
2315fd13d97SYork Sun 	} else {
2325fd13d97SYork Sun 		/* Embedded data */
2335fd13d97SYork Sun 		if (fit_image_get_data(fit, node, &data, &length)) {
2345fd13d97SYork Sun 			puts("Cannot get image data/size\n");
2355fd13d97SYork Sun 			return -ENOENT;
2365fd13d97SYork Sun 		}
2375fd13d97SYork Sun 		debug("Embedded data: dst=%lx, size=%lx\n", load_addr,
2385fd13d97SYork Sun 		      (unsigned long)length);
2395fd13d97SYork Sun 		src = (void *)data;
2405fd13d97SYork Sun 	}
2415fd13d97SYork Sun 
242d154ca60SBen Whitten #ifdef CONFIG_SPL_FIT_SIGNATURE
243d154ca60SBen Whitten 	printf("## Checking hash(es) for Image %s ... ",
244d154ca60SBen Whitten 	       fit_get_name(fit, node, NULL));
245d154ca60SBen Whitten 	if (!fit_image_verify_with_data(fit, node,
246d154ca60SBen Whitten 					 src, length))
247d154ca60SBen Whitten 		return -EPERM;
248d154ca60SBen Whitten 	puts("OK\n");
249d154ca60SBen Whitten #endif
250d154ca60SBen Whitten 
2518baa3818SAndre Przywara #ifdef CONFIG_SPL_FIT_IMAGE_POST_PROCESS
252*b7d9107fSChia-Wei Wang 	board_fit_image_post_process(fit, node, &src, &length);
2538baa3818SAndre Przywara #endif
2548baa3818SAndre Przywara 
255975e7893SMichal Simek 	if (IS_ENABLED(CONFIG_SPL_GZIP) && image_comp == IH_COMP_GZIP) {
256933f67aaSYork Sun 		size = length;
2577264f292SYork Sun 		if (gunzip((void *)load_addr, CONFIG_SYS_BOOTM_LEN,
258933f67aaSYork Sun 			   src, &size)) {
2597264f292SYork Sun 			puts("Uncompressing error\n");
2607264f292SYork Sun 			return -EIO;
2617264f292SYork Sun 		}
262933f67aaSYork Sun 		length = size;
2637264f292SYork Sun 	} else {
2648baa3818SAndre Przywara 		memcpy((void *)load_addr, src, length);
2657264f292SYork Sun 	}
2668baa3818SAndre Przywara 
2678baa3818SAndre Przywara 	if (image_info) {
2688baa3818SAndre Przywara 		image_info->load_addr = load_addr;
2698baa3818SAndre Przywara 		image_info->size = length;
2708baa3818SAndre Przywara 		image_info->entry_point = fdt_getprop_u32(fit, node, "entry");
2718baa3818SAndre Przywara 	}
2728baa3818SAndre Przywara 
2738baa3818SAndre Przywara 	return 0;
2748baa3818SAndre Przywara }
2758baa3818SAndre Przywara 
spl_fit_append_fdt(struct spl_image_info * spl_image,struct spl_load_info * info,ulong sector,void * fit,int images,ulong base_offset)276d879616eSPhilipp Tomsich static int spl_fit_append_fdt(struct spl_image_info *spl_image,
277d879616eSPhilipp Tomsich 			      struct spl_load_info *info, ulong sector,
278d879616eSPhilipp Tomsich 			      void *fit, int images, ulong base_offset)
279d879616eSPhilipp Tomsich {
280d879616eSPhilipp Tomsich 	struct spl_image_info image_info;
281d879616eSPhilipp Tomsich 	int node, ret;
282d879616eSPhilipp Tomsich 
283d879616eSPhilipp Tomsich 	/* Figure out which device tree the board wants to use */
284d879616eSPhilipp Tomsich 	node = spl_fit_get_image_node(fit, images, FIT_FDT_PROP, 0);
285d879616eSPhilipp Tomsich 	if (node < 0) {
286d879616eSPhilipp Tomsich 		debug("%s: cannot find FDT node\n", __func__);
287d879616eSPhilipp Tomsich 		return node;
288d879616eSPhilipp Tomsich 	}
289d879616eSPhilipp Tomsich 
290d879616eSPhilipp Tomsich 	/*
291d879616eSPhilipp Tomsich 	 * Read the device tree and place it after the image.
292d879616eSPhilipp Tomsich 	 * Align the destination address to ARCH_DMA_MINALIGN.
293d879616eSPhilipp Tomsich 	 */
294d879616eSPhilipp Tomsich 	image_info.load_addr = spl_image->load_addr + spl_image->size;
295d879616eSPhilipp Tomsich 	ret = spl_load_fit_image(info, sector, fit, base_offset, node,
296d879616eSPhilipp Tomsich 				 &image_info);
297a616c783SPhilipp Tomsich 
298a616c783SPhilipp Tomsich 	if (ret < 0)
299a616c783SPhilipp Tomsich 		return ret;
300a616c783SPhilipp Tomsich 
301a616c783SPhilipp Tomsich 	/* Make the load-address of the FDT available for the SPL framework */
302a616c783SPhilipp Tomsich 	spl_image->fdt_addr = (void *)image_info.load_addr;
303337bbb62SPhilipp Tomsich #if !CONFIG_IS_ENABLED(FIT_IMAGE_TINY)
304a616c783SPhilipp Tomsich 	/* Try to make space, so we can inject details on the loadables */
305a616c783SPhilipp Tomsich 	ret = fdt_shrink_to_minimum(spl_image->fdt_addr, 8192);
306337bbb62SPhilipp Tomsich #endif
307a616c783SPhilipp Tomsich 
308a616c783SPhilipp Tomsich 	return ret;
309a616c783SPhilipp Tomsich }
310a616c783SPhilipp Tomsich 
spl_fit_record_loadable(const void * fit,int images,int index,void * blob,struct spl_image_info * image)311a616c783SPhilipp Tomsich static int spl_fit_record_loadable(const void *fit, int images, int index,
312a616c783SPhilipp Tomsich 				   void *blob, struct spl_image_info *image)
313a616c783SPhilipp Tomsich {
314337bbb62SPhilipp Tomsich 	int ret = 0;
315337bbb62SPhilipp Tomsich #if !CONFIG_IS_ENABLED(FIT_IMAGE_TINY)
316a616c783SPhilipp Tomsich 	char *name;
317337bbb62SPhilipp Tomsich 	int node;
318a616c783SPhilipp Tomsich 
319a616c783SPhilipp Tomsich 	ret = spl_fit_get_image_name(fit, images, "loadables",
320a616c783SPhilipp Tomsich 				     index, &name);
321a616c783SPhilipp Tomsich 	if (ret < 0)
322a616c783SPhilipp Tomsich 		return ret;
323a616c783SPhilipp Tomsich 
324a616c783SPhilipp Tomsich 	node = spl_fit_get_image_node(fit, images, "loadables", index);
325a616c783SPhilipp Tomsich 
326a616c783SPhilipp Tomsich 	ret = fdt_record_loadable(blob, index, name, image->load_addr,
327a616c783SPhilipp Tomsich 				  image->size, image->entry_point,
328a616c783SPhilipp Tomsich 				  fdt_getprop(fit, node, "type", NULL),
329a616c783SPhilipp Tomsich 				  fdt_getprop(fit, node, "os", NULL));
330337bbb62SPhilipp Tomsich #endif
331d879616eSPhilipp Tomsich 	return ret;
332d879616eSPhilipp Tomsich }
333d879616eSPhilipp Tomsich 
spl_fit_image_get_os(const void * fit,int noffset,uint8_t * os)334337bbb62SPhilipp Tomsich static int spl_fit_image_get_os(const void *fit, int noffset, uint8_t *os)
335337bbb62SPhilipp Tomsich {
336337bbb62SPhilipp Tomsich #if CONFIG_IS_ENABLED(FIT_IMAGE_TINY)
337337bbb62SPhilipp Tomsich 	return -ENOTSUPP;
338337bbb62SPhilipp Tomsich #else
339337bbb62SPhilipp Tomsich 	return fit_image_get_os(fit, noffset, os);
340337bbb62SPhilipp Tomsich #endif
341337bbb62SPhilipp Tomsich }
342337bbb62SPhilipp Tomsich 
34365f2e689SAndreas Dannenberg /*
34465f2e689SAndreas Dannenberg  * Weak default function to allow customizing SPL fit loading for load-only
34565f2e689SAndreas Dannenberg  * use cases by allowing to skip the parsing/processing of the FIT contents
34665f2e689SAndreas Dannenberg  * (so that this can be done separately in a more customized fashion)
34765f2e689SAndreas Dannenberg  */
spl_load_simple_fit_skip_processing(void)34865f2e689SAndreas Dannenberg __weak bool spl_load_simple_fit_skip_processing(void)
34965f2e689SAndreas Dannenberg {
35065f2e689SAndreas Dannenberg 	return false;
35165f2e689SAndreas Dannenberg }
35265f2e689SAndreas Dannenberg 
spl_load_simple_fit(struct spl_image_info * spl_image,struct spl_load_info * info,ulong sector,void * fit)3536b2936f2SChia-Wei, Wang int spl_load_simple_fit(struct spl_image_info *spl_image,
3546b2936f2SChia-Wei, Wang 			struct spl_load_info *info, ulong sector, void *fit)
355f1dcee59SSimon Glass {
3566b2936f2SChia-Wei, Wang 	int sectors;
3576b2936f2SChia-Wei, Wang 	ulong size;
3586b2936f2SChia-Wei, Wang 	unsigned long count;
3597e52eee8SChia-Wei, Wang 	struct spl_image_info image_info;
3606b2936f2SChia-Wei, Wang 	int node = -1;
3616b2936f2SChia-Wei, Wang 	int images, ret;
3626b2936f2SChia-Wei, Wang 	int base_offset, hsize, align_len = ARCH_DMA_MINALIGN - 1;
3636b2936f2SChia-Wei, Wang 	int index = 0;
36447cd0118SJean-Jacques Hiblot 	int firmware_node;
365f1dcee59SSimon Glass 
366f1dcee59SSimon Glass 	/*
367c8bc3c0cSYork Sun 	 * For FIT with external data, figure out where the external images
368c8bc3c0cSYork Sun 	 * start. This is the base for the data-offset properties in each
369c8bc3c0cSYork Sun 	 * image.
370f1dcee59SSimon Glass 	 */
3716b2936f2SChia-Wei, Wang 	size = fdt_totalsize(fit);
3726b2936f2SChia-Wei, Wang 	size = (size + 3) & ~3;
3736b2936f2SChia-Wei, Wang 	size = board_spl_fit_size_align(size);
3746b2936f2SChia-Wei, Wang 	base_offset = (size + 3) & ~3;
3756b2936f2SChia-Wei, Wang 
3766b2936f2SChia-Wei, Wang 	/*
3776b2936f2SChia-Wei, Wang 	 * So far we only have one block of data from the FIT. Read the entire
3786b2936f2SChia-Wei, Wang 	 * thing, including that first block, placing it so it finishes before
3796b2936f2SChia-Wei, Wang 	 * where we will load the image.
3806b2936f2SChia-Wei, Wang 	 *
3816b2936f2SChia-Wei, Wang 	 * Note that we will load the image such that its first byte will be
3826b2936f2SChia-Wei, Wang 	 * at the load address. Since that byte may be part-way through a
3836b2936f2SChia-Wei, Wang 	 * block, we may load the image up to one block before the load
3846b2936f2SChia-Wei, Wang 	 * address. So take account of that here by subtracting an addition
3856b2936f2SChia-Wei, Wang 	 * block length from the FIT start position.
3866b2936f2SChia-Wei, Wang 	 *
3876b2936f2SChia-Wei, Wang 	 * In fact the FIT has its own load address, but we assume it cannot
3886b2936f2SChia-Wei, Wang 	 * be before CONFIG_SYS_TEXT_BASE.
3896b2936f2SChia-Wei, Wang 	 *
3906b2936f2SChia-Wei, Wang 	 * For FIT with data embedded, data is loaded as part of FIT image.
3916b2936f2SChia-Wei, Wang 	 * For FIT with external data, data is not loaded in this step.
3926b2936f2SChia-Wei, Wang 	 */
3936b2936f2SChia-Wei, Wang 	hsize = (size + info->bl_len + align_len) & ~align_len;
3946b2936f2SChia-Wei, Wang 	fit = spl_get_load_buffer(-hsize, hsize);
3956b2936f2SChia-Wei, Wang 	sectors = get_aligned_image_size(info, size, 0);
3966b2936f2SChia-Wei, Wang 	count = info->read(info, sector, sectors, fit);
3976b2936f2SChia-Wei, Wang 	debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu, size=0x%lx\n",
3986b2936f2SChia-Wei, Wang 	      sector, sectors, fit, count, size);
3996b2936f2SChia-Wei, Wang 
4006b2936f2SChia-Wei, Wang 	if (count == 0)
4016b2936f2SChia-Wei, Wang 		return -EIO;
402f1dcee59SSimon Glass 
40365f2e689SAndreas Dannenberg 	/* skip further processing if requested to enable load-only use cases */
40465f2e689SAndreas Dannenberg 	if (spl_load_simple_fit_skip_processing())
40565f2e689SAndreas Dannenberg 		return 0;
40665f2e689SAndreas Dannenberg 
407736806fbSAndre Przywara 	/* find the node holding the images information */
408f1dcee59SSimon Glass 	images = fdt_path_offset(fit, FIT_IMAGES_PATH);
409f1dcee59SSimon Glass 	if (images < 0) {
410f1dcee59SSimon Glass 		debug("%s: Cannot find /images node: %d\n", __func__, images);
411f1dcee59SSimon Glass 		return -1;
412f1dcee59SSimon Glass 	}
413736806fbSAndre Przywara 
41426a64223SMarek Vasut #ifdef CONFIG_SPL_FPGA_SUPPORT
41526a64223SMarek Vasut 	node = spl_fit_get_image_node(fit, images, "fpga", 0);
41626a64223SMarek Vasut 	if (node >= 0) {
41726a64223SMarek Vasut 		/* Load the image and set up the spl_image structure */
41826a64223SMarek Vasut 		ret = spl_load_fit_image(info, sector, fit, base_offset, node,
41926a64223SMarek Vasut 					 spl_image);
42026a64223SMarek Vasut 		if (ret) {
42126a64223SMarek Vasut 			printf("%s: Cannot load the FPGA: %i\n", __func__, ret);
42226a64223SMarek Vasut 			return ret;
42326a64223SMarek Vasut 		}
4243313ae66SMichal Simek 
4253313ae66SMichal Simek 		debug("FPGA bitstream at: %x, size: %x\n",
4263313ae66SMichal Simek 		      (u32)spl_image->load_addr, spl_image->size);
4273313ae66SMichal Simek 
4283313ae66SMichal Simek 		ret = fpga_load(0, (const void *)spl_image->load_addr,
4293313ae66SMichal Simek 				spl_image->size, BIT_FULL);
4303313ae66SMichal Simek 		if (ret) {
4313313ae66SMichal Simek 			printf("%s: Cannot load the image to the FPGA\n",
4323313ae66SMichal Simek 			       __func__);
4333313ae66SMichal Simek 			return ret;
4343313ae66SMichal Simek 		}
4353313ae66SMichal Simek 
4363907eef1SLuis Araneda 		puts("FPGA image loaded from FIT\n");
43726a64223SMarek Vasut 		node = -1;
43826a64223SMarek Vasut 	}
43926a64223SMarek Vasut #endif
44026a64223SMarek Vasut 
441d879616eSPhilipp Tomsich 	/*
442d879616eSPhilipp Tomsich 	 * Find the U-Boot image using the following search order:
443d879616eSPhilipp Tomsich 	 *   - start at 'firmware' (e.g. an ARM Trusted Firmware)
444d879616eSPhilipp Tomsich 	 *   - fall back 'kernel' (e.g. a Falcon-mode OS boot
445d879616eSPhilipp Tomsich 	 *   - fall back to using the first 'loadables' entry
446d879616eSPhilipp Tomsich 	 */
447c8bc3c0cSYork Sun 	if (node < 0)
4481f8e4bf5SMichal Simek 		node = spl_fit_get_image_node(fit, images, FIT_FIRMWARE_PROP,
4491f8e4bf5SMichal Simek 					      0);
450d879616eSPhilipp Tomsich #ifdef CONFIG_SPL_OS_BOOT
451d879616eSPhilipp Tomsich 	if (node < 0)
452d879616eSPhilipp Tomsich 		node = spl_fit_get_image_node(fit, images, FIT_KERNEL_PROP, 0);
453d879616eSPhilipp Tomsich #endif
454f1dcee59SSimon Glass 	if (node < 0) {
455736806fbSAndre Przywara 		debug("could not find firmware image, trying loadables...\n");
456736806fbSAndre Przywara 		node = spl_fit_get_image_node(fit, images, "loadables", 0);
457411cf32dSAndre Przywara 		/*
458411cf32dSAndre Przywara 		 * If we pick the U-Boot image from "loadables", start at
459411cf32dSAndre Przywara 		 * the second image when later loading additional images.
460411cf32dSAndre Przywara 		 */
461411cf32dSAndre Przywara 		index = 1;
462736806fbSAndre Przywara 	}
463736806fbSAndre Przywara 	if (node < 0) {
464736806fbSAndre Przywara 		debug("%s: Cannot find u-boot image node: %d\n",
465736806fbSAndre Przywara 		      __func__, node);
466f1dcee59SSimon Glass 		return -1;
467f1dcee59SSimon Glass 	}
468f1dcee59SSimon Glass 
4698baa3818SAndre Przywara 	/* Load the image and set up the spl_image structure */
4708baa3818SAndre Przywara 	ret = spl_load_fit_image(info, sector, fit, base_offset, node,
4718baa3818SAndre Przywara 				 spl_image);
4728baa3818SAndre Przywara 	if (ret)
4738baa3818SAndre Przywara 		return ret;
4748baa3818SAndre Przywara 
475d879616eSPhilipp Tomsich 	/*
476d879616eSPhilipp Tomsich 	 * For backward compatibility, we treat the first node that is
477d879616eSPhilipp Tomsich 	 * as a U-Boot image, if no OS-type has been declared.
478d879616eSPhilipp Tomsich 	 */
479337bbb62SPhilipp Tomsich 	if (!spl_fit_image_get_os(fit, node, &spl_image->os))
480c8bc3c0cSYork Sun 		debug("Image OS is %s\n", genimg_get_os_name(spl_image->os));
481d879616eSPhilipp Tomsich #if !defined(CONFIG_SPL_OS_BOOT)
482d879616eSPhilipp Tomsich 	else
483f4d7d859SSimon Glass 		spl_image->os = IH_OS_U_BOOT;
484c8bc3c0cSYork Sun #endif
485f1dcee59SSimon Glass 
486f1dcee59SSimon Glass 	/*
487d879616eSPhilipp Tomsich 	 * Booting a next-stage U-Boot may require us to append the FDT.
488d879616eSPhilipp Tomsich 	 * We allow this to fail, as the U-Boot image might embed its FDT.
489f1dcee59SSimon Glass 	 */
490d879616eSPhilipp Tomsich 	if (spl_image->os == IH_OS_U_BOOT)
491d879616eSPhilipp Tomsich 		spl_fit_append_fdt(spl_image, info, sector, fit,
492d879616eSPhilipp Tomsich 				   images, base_offset);
493411cf32dSAndre Przywara 
49447cd0118SJean-Jacques Hiblot 	firmware_node = node;
495411cf32dSAndre Przywara 	/* Now check if there are more images for us to load */
496411cf32dSAndre Przywara 	for (; ; index++) {
497d879616eSPhilipp Tomsich 		uint8_t os_type = IH_OS_INVALID;
498d879616eSPhilipp Tomsich 
499411cf32dSAndre Przywara 		node = spl_fit_get_image_node(fit, images, "loadables", index);
500411cf32dSAndre Przywara 		if (node < 0)
501411cf32dSAndre Przywara 			break;
502411cf32dSAndre Przywara 
50347cd0118SJean-Jacques Hiblot 		/*
50447cd0118SJean-Jacques Hiblot 		 * if the firmware is also a loadable, skip it because
50547cd0118SJean-Jacques Hiblot 		 * it already has been loaded. This is typically the case with
50647cd0118SJean-Jacques Hiblot 		 * u-boot.img generated by mkimage.
50747cd0118SJean-Jacques Hiblot 		 */
50847cd0118SJean-Jacques Hiblot 		if (firmware_node == node)
50947cd0118SJean-Jacques Hiblot 			continue;
51047cd0118SJean-Jacques Hiblot 
511411cf32dSAndre Przywara 		ret = spl_load_fit_image(info, sector, fit, base_offset, node,
512411cf32dSAndre Przywara 					 &image_info);
513411cf32dSAndre Przywara 		if (ret < 0)
514411cf32dSAndre Przywara 			continue;
515411cf32dSAndre Przywara 
516337bbb62SPhilipp Tomsich 		if (!spl_fit_image_get_os(fit, node, &os_type))
517d879616eSPhilipp Tomsich 			debug("Loadable is %s\n", genimg_get_os_name(os_type));
518cf8dcc5dSAbel Vesa #if CONFIG_IS_ENABLED(FIT_IMAGE_TINY)
519cf8dcc5dSAbel Vesa 		else
520cf8dcc5dSAbel Vesa 			os_type = IH_OS_U_BOOT;
521cf8dcc5dSAbel Vesa #endif
522d879616eSPhilipp Tomsich 
523a616c783SPhilipp Tomsich 		if (os_type == IH_OS_U_BOOT) {
524a616c783SPhilipp Tomsich 			spl_fit_append_fdt(&image_info, info, sector,
525d879616eSPhilipp Tomsich 					   fit, images, base_offset);
526a616c783SPhilipp Tomsich 			spl_image->fdt_addr = image_info.fdt_addr;
527a616c783SPhilipp Tomsich 		}
528d879616eSPhilipp Tomsich 
529411cf32dSAndre Przywara 		/*
530411cf32dSAndre Przywara 		 * If the "firmware" image did not provide an entry point,
531411cf32dSAndre Przywara 		 * use the first valid entry point from the loadables.
532411cf32dSAndre Przywara 		 */
533411cf32dSAndre Przywara 		if (spl_image->entry_point == FDT_ERROR &&
534411cf32dSAndre Przywara 		    image_info.entry_point != FDT_ERROR)
535411cf32dSAndre Przywara 			spl_image->entry_point = image_info.entry_point;
536a616c783SPhilipp Tomsich 
537a616c783SPhilipp Tomsich 		/* Record our loadables into the FDT */
538a616c783SPhilipp Tomsich 		if (spl_image->fdt_addr)
539a616c783SPhilipp Tomsich 			spl_fit_record_loadable(fit, images, index,
540a616c783SPhilipp Tomsich 						spl_image->fdt_addr,
541a616c783SPhilipp Tomsich 						&image_info);
542411cf32dSAndre Przywara 	}
543411cf32dSAndre Przywara 
544411cf32dSAndre Przywara 	/*
545411cf32dSAndre Przywara 	 * If a platform does not provide CONFIG_SYS_UBOOT_START, U-Boot's
546411cf32dSAndre Przywara 	 * Makefile will set it to 0 and it will end up as the entry point
547411cf32dSAndre Przywara 	 * here. What it actually means is: use the load address.
548411cf32dSAndre Przywara 	 */
549411cf32dSAndre Przywara 	if (spl_image->entry_point == FDT_ERROR || spl_image->entry_point == 0)
550411cf32dSAndre Przywara 		spl_image->entry_point = spl_image->load_addr;
551411cf32dSAndre Przywara 
552e246bfcfSYe Li 	spl_image->flags |= SPL_FIT_FOUND;
553e246bfcfSYe Li 
5546b2936f2SChia-Wei, Wang #ifdef CONFIG_SECURE_BOOT
555e246bfcfSYe Li 	board_spl_fit_post_load((ulong)fit, size);
5566b2936f2SChia-Wei, Wang #endif
557e246bfcfSYe Li 
558411cf32dSAndre Przywara 	return 0;
559f1dcee59SSimon Glass }
560