blob: 5e5b24674d376de931fe98045e9c17d1478b7c82 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass44d3a302013-05-08 08:06:00 +00002/*
3 * Copyright (c) 2013, Google Inc.
4 *
5 * (C) Copyright 2008 Semihalf
6 *
7 * (C) Copyright 2000-2006
8 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
Simon Glass44d3a302013-05-08 08:06:00 +00009 */
10
11#include <common.h>
12#include <fdt_support.h>
Simon Goldschmidte2237a22019-01-14 22:38:17 +010013#include <fdtdec.h>
Simon Glasscdbff9f2019-08-01 09:46:50 -060014#include <env.h>
Simon Glass44d3a302013-05-08 08:06:00 +000015#include <errno.h>
16#include <image.h>
Simon Glass4d72caa2020-05-10 11:40:01 -060017#include <lmb.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060018#include <log.h>
Simon Glass336d4612020-02-03 07:36:16 -070019#include <malloc.h>
Simon Glass401d1c42020-10-30 21:38:53 -060020#include <asm/global_data.h>
Masahiro Yamadab08c8c42018-03-05 01:20:11 +090021#include <linux/libfdt.h>
Joe Hershberger0eb25b62015-03-22 17:08:59 -050022#include <mapmem.h>
Simon Glass44d3a302013-05-08 08:06:00 +000023#include <asm/io.h>
Simon Glass98887ab2022-07-30 15:52:31 -060024#include <dm/ofnode.h>
Heiko Stuebner6ccb05e2019-10-23 16:46:40 +020025#include <tee/optee.h>
Simon Glass44d3a302013-05-08 08:06:00 +000026
27#ifndef CONFIG_SYS_FDT_PAD
28#define CONFIG_SYS_FDT_PAD 0x3000
29#endif
30
Masahiro Yamadac960a682018-03-21 18:03:33 +090031/* adding a ramdisk needs 0x44 bytes in version 2008.10 */
32#define FDT_RAMDISK_OVERHEAD 0x80
33
Simon Glass44d3a302013-05-08 08:06:00 +000034DECLARE_GLOBAL_DATA_PTR;
35
36static void fdt_error(const char *msg)
37{
38 puts("ERROR: ");
39 puts(msg);
40 puts(" - must RESET the board to recover.\n");
41}
42
Tom Rinic76c93a2019-05-23 07:14:07 -040043#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
Simon Glass44d3a302013-05-08 08:06:00 +000044static const image_header_t *image_get_fdt(ulong fdt_addr)
45{
46 const image_header_t *fdt_hdr = map_sysmem(fdt_addr, 0);
47
48 image_print_contents(fdt_hdr);
49
50 puts(" Verifying Checksum ... ");
51 if (!image_check_hcrc(fdt_hdr)) {
52 fdt_error("fdt header checksum invalid");
53 return NULL;
54 }
55
56 if (!image_check_dcrc(fdt_hdr)) {
57 fdt_error("fdt checksum invalid");
58 return NULL;
59 }
60 puts("OK\n");
61
62 if (!image_check_type(fdt_hdr, IH_TYPE_FLATDT)) {
63 fdt_error("uImage is not a fdt");
64 return NULL;
65 }
66 if (image_get_comp(fdt_hdr) != IH_COMP_NONE) {
67 fdt_error("uImage is compressed");
68 return NULL;
69 }
Masahiro Yamada2f0877c2013-09-19 12:10:18 +090070 if (fdt_check_header((void *)image_get_data(fdt_hdr)) != 0) {
Simon Glass44d3a302013-05-08 08:06:00 +000071 fdt_error("uImage data is not a fdt");
72 return NULL;
73 }
74 return fdt_hdr;
75}
Heiko Schocher21d29f72014-05-28 11:33:33 +020076#endif
Simon Glass44d3a302013-05-08 08:06:00 +000077
Simon Goldschmidte2237a22019-01-14 22:38:17 +010078static void boot_fdt_reserve_region(struct lmb *lmb, uint64_t addr,
Patrick Delaunayf46959c2021-05-07 14:50:33 +020079 uint64_t size, enum lmb_flags flags)
Simon Goldschmidte2237a22019-01-14 22:38:17 +010080{
Patrick Delaunaye1d7ed32019-03-06 14:23:52 +010081 long ret;
Simon Goldschmidte2237a22019-01-14 22:38:17 +010082
Patrick Delaunayf46959c2021-05-07 14:50:33 +020083 ret = lmb_reserve_flags(lmb, addr, size, flags);
Patrick Delaunaye1d7ed32019-03-06 14:23:52 +010084 if (ret >= 0) {
Patrick Delaunayf46959c2021-05-07 14:50:33 +020085 debug(" reserving fdt memory region: addr=%llx size=%llx flags=%x\n",
86 (unsigned long long)addr,
87 (unsigned long long)size, flags);
Simon Goldschmidte2237a22019-01-14 22:38:17 +010088 } else {
89 puts("ERROR: reserving fdt memory region failed ");
Patrick Delaunayf46959c2021-05-07 14:50:33 +020090 printf("(addr=%llx size=%llx flags=%x)\n",
91 (unsigned long long)addr,
92 (unsigned long long)size, flags);
Simon Goldschmidte2237a22019-01-14 22:38:17 +010093 }
94}
95
Simon Glass44d3a302013-05-08 08:06:00 +000096/**
Simon Goldschmidte2237a22019-01-14 22:38:17 +010097 * boot_fdt_add_mem_rsv_regions - Mark the memreserve and reserved-memory
98 * sections as unusable
Simon Glass44d3a302013-05-08 08:06:00 +000099 * @lmb: pointer to lmb handle, will be used for memory mgmt
100 * @fdt_blob: pointer to fdt blob base address
101 *
Simon Goldschmidte2237a22019-01-14 22:38:17 +0100102 * Adds the and reserved-memorymemreserve regions in the dtb to the lmb block.
103 * Adding the memreserve regions prevents u-boot from using them to store the
104 * initrd or the fdt blob.
Simon Glass44d3a302013-05-08 08:06:00 +0000105 */
106void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob)
107{
108 uint64_t addr, size;
Simon Goldschmidte2237a22019-01-14 22:38:17 +0100109 int i, total, ret;
110 int nodeoffset, subnode;
111 struct fdt_resource res;
Patrick Delaunayf46959c2021-05-07 14:50:33 +0200112 enum lmb_flags flags;
Simon Glass44d3a302013-05-08 08:06:00 +0000113
114 if (fdt_check_header(fdt_blob) != 0)
115 return;
116
Simon Goldschmidte2237a22019-01-14 22:38:17 +0100117 /* process memreserve sections */
Simon Glass44d3a302013-05-08 08:06:00 +0000118 total = fdt_num_mem_rsv(fdt_blob);
119 for (i = 0; i < total; i++) {
120 if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0)
121 continue;
Patrick Delaunayf46959c2021-05-07 14:50:33 +0200122 boot_fdt_reserve_region(lmb, addr, size, LMB_NONE);
Simon Goldschmidte2237a22019-01-14 22:38:17 +0100123 }
124
125 /* process reserved-memory */
126 nodeoffset = fdt_subnode_offset(fdt_blob, 0, "reserved-memory");
127 if (nodeoffset >= 0) {
128 subnode = fdt_first_subnode(fdt_blob, nodeoffset);
129 while (subnode >= 0) {
130 /* check if this subnode has a reg property */
131 ret = fdt_get_resource(fdt_blob, subnode, "reg", 0,
132 &res);
Thirupathaiah Annapureddy28b417c2020-01-06 22:21:42 -0800133 if (!ret && fdtdec_get_is_enabled(fdt_blob, subnode)) {
Patrick Delaunayf46959c2021-05-07 14:50:33 +0200134 flags = LMB_NONE;
135 if (fdtdec_get_bool(fdt_blob, subnode,
136 "no-map"))
137 flags = LMB_NOMAP;
Simon Goldschmidte2237a22019-01-14 22:38:17 +0100138 addr = res.start;
139 size = res.end - res.start + 1;
Patrick Delaunayf46959c2021-05-07 14:50:33 +0200140 boot_fdt_reserve_region(lmb, addr, size, flags);
Simon Goldschmidte2237a22019-01-14 22:38:17 +0100141 }
142
143 subnode = fdt_next_subnode(fdt_blob, subnode);
144 }
Simon Glass44d3a302013-05-08 08:06:00 +0000145 }
146}
147
148/**
149 * boot_relocate_fdt - relocate flat device tree
150 * @lmb: pointer to lmb handle, will be used for memory mgmt
151 * @of_flat_tree: pointer to a char* variable, will hold fdt start address
152 * @of_size: pointer to a ulong variable, will hold fdt length
153 *
154 * boot_relocate_fdt() allocates a region of memory within the bootmap and
155 * relocates the of_flat_tree into that region, even if the fdt is already in
156 * the bootmap. It also expands the size of the fdt by CONFIG_SYS_FDT_PAD
157 * bytes.
158 *
159 * of_flat_tree and of_size are set to final (after relocation) values
160 *
161 * returns:
162 * 0 - success
163 * 1 - failure
164 */
165int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
166{
167 void *fdt_blob = *of_flat_tree;
168 void *of_start = NULL;
Marek Vasuta96d5652022-04-08 02:09:19 +0200169 u64 start, size, usable;
Simon Glass44d3a302013-05-08 08:06:00 +0000170 char *fdt_high;
Marek Vasuta96d5652022-04-08 02:09:19 +0200171 ulong mapsize, low;
Simon Glass44d3a302013-05-08 08:06:00 +0000172 ulong of_len = 0;
Marek Vasuta96d5652022-04-08 02:09:19 +0200173 int bank;
Simon Glass44d3a302013-05-08 08:06:00 +0000174 int err;
175 int disable_relocation = 0;
176
177 /* nothing to do */
178 if (*of_size == 0)
179 return 0;
180
181 if (fdt_check_header(fdt_blob) != 0) {
182 fdt_error("image is not a fdt");
183 goto error;
184 }
185
186 /* position on a 4K boundary before the alloc_current */
187 /* Pad the FDT by a specified amount */
188 of_len = *of_size + CONFIG_SYS_FDT_PAD;
189
190 /* If fdt_high is set use it to select the relocation address */
Simon Glass00caae62017-08-03 12:22:12 -0600191 fdt_high = env_get("fdt_high");
Simon Glass44d3a302013-05-08 08:06:00 +0000192 if (fdt_high) {
Simon Glass7e5f4602021-07-24 09:03:29 -0600193 void *desired_addr = (void *)hextoul(fdt_high, NULL);
Simon Glass44d3a302013-05-08 08:06:00 +0000194
195 if (((ulong) desired_addr) == ~0UL) {
196 /* All ones means use fdt in place */
197 of_start = fdt_blob;
198 lmb_reserve(lmb, (ulong)of_start, of_len);
199 disable_relocation = 1;
200 } else if (desired_addr) {
201 of_start =
202 (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
203 (ulong)desired_addr);
204 if (of_start == NULL) {
205 puts("Failed using fdt_high value for Device Tree");
206 goto error;
207 }
208 } else {
209 of_start =
210 (void *)(ulong) lmb_alloc(lmb, of_len, 0x1000);
211 }
212 } else {
Marek Vasuta96d5652022-04-08 02:09:19 +0200213 mapsize = env_get_bootm_mapsize();
214 low = env_get_bootm_low();
215 of_start = NULL;
216
217 for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
218 start = gd->bd->bi_dram[bank].start;
219 size = gd->bd->bi_dram[bank].size;
220
221 /* DRAM bank addresses are too low, skip it. */
222 if (start + size < low)
223 continue;
224
225 usable = min(size, (u64)mapsize);
226
227 /*
228 * At least part of this DRAM bank is usable, try
229 * using it for LMB allocation.
230 */
231 of_start =
232 (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
233 start + usable);
234 /* Allocation succeeded, use this block. */
235 if (of_start != NULL)
236 break;
237
238 /*
239 * Reduce the mapping size in the next bank
240 * by the size of attempt in current bank.
241 */
242 mapsize -= usable - max(start, (u64)low);
243 if (!mapsize)
244 break;
245 }
Simon Glass44d3a302013-05-08 08:06:00 +0000246 }
247
248 if (of_start == NULL) {
249 puts("device tree - allocation error\n");
250 goto error;
251 }
252
253 if (disable_relocation) {
254 /*
255 * We assume there is space after the existing fdt to use
256 * for padding
257 */
258 fdt_set_totalsize(of_start, of_len);
259 printf(" Using Device Tree in place at %p, end %p\n",
260 of_start, of_start + of_len - 1);
261 } else {
262 debug("## device tree at %p ... %p (len=%ld [0x%lX])\n",
263 fdt_blob, fdt_blob + *of_size - 1, of_len, of_len);
264
265 printf(" Loading Device Tree to %p, end %p ... ",
266 of_start, of_start + of_len - 1);
267
268 err = fdt_open_into(fdt_blob, of_start, of_len);
269 if (err != 0) {
270 fdt_error("fdt move failed");
271 goto error;
272 }
273 puts("OK\n");
274 }
275
276 *of_flat_tree = of_start;
277 *of_size = of_len;
278
Simon Goldschmidt596be5f2018-12-17 20:14:42 +0100279 if (CONFIG_IS_ENABLED(CMD_FDT))
280 set_working_fdt_addr(map_to_sysmem(*of_flat_tree));
Simon Glass44d3a302013-05-08 08:06:00 +0000281 return 0;
282
283error:
284 return 1;
285}
286
Simon Glass44d3a302013-05-08 08:06:00 +0000287/**
Simon Glass4cb35b72021-09-25 19:43:41 -0600288 * select_fdt() - Select and locate the FDT to use
289 *
290 * @images: pointer to the bootm images structure
291 * @select: name of FDT to select, or NULL for any
292 * @arch: expected FDT architecture
293 * @fdt_addrp: pointer to a ulong variable, will hold FDT pointer
Heinrich Schuchardt185f8122022-01-19 18:05:50 +0100294 * Return: 0 if OK, -ENOPKG if no FDT (but an error should not be reported),
Simon Glass4cb35b72021-09-25 19:43:41 -0600295 * other -ve value on other error
296 */
297
298static int select_fdt(bootm_headers_t *images, const char *select, u8 arch,
299 ulong *fdt_addrp)
300{
301 const char *buf;
302 ulong fdt_addr;
303
304#if CONFIG_IS_ENABLED(FIT)
305 const char *fit_uname_config = images->fit_uname_cfg;
306 const char *fit_uname_fdt = NULL;
307 ulong default_addr;
308 int fdt_noffset;
309
310 if (select) {
311 /*
312 * If the FDT blob comes from the FIT image and the
313 * FIT image address is omitted in the command line
314 * argument, try to use ramdisk or os FIT image
315 * address or default load address.
316 */
317 if (images->fit_uname_rd)
318 default_addr = (ulong)images->fit_hdr_rd;
319 else if (images->fit_uname_os)
320 default_addr = (ulong)images->fit_hdr_os;
321 else
322 default_addr = image_load_addr;
323
324 if (fit_parse_conf(select, default_addr, &fdt_addr,
325 &fit_uname_config)) {
326 debug("* fdt: config '%s' from image at 0x%08lx\n",
327 fit_uname_config, fdt_addr);
328 } else if (fit_parse_subimage(select, default_addr, &fdt_addr,
329 &fit_uname_fdt)) {
330 debug("* fdt: subimage '%s' from image at 0x%08lx\n",
331 fit_uname_fdt, fdt_addr);
332 } else
333#endif
334 {
335 fdt_addr = hextoul(select, NULL);
336 debug("* fdt: cmdline image address = 0x%08lx\n",
337 fdt_addr);
338 }
339#if CONFIG_IS_ENABLED(FIT)
340 } else {
341 /* use FIT configuration provided in first bootm
342 * command argument
343 */
344 fdt_addr = map_to_sysmem(images->fit_hdr_os);
345 fdt_noffset = fit_get_node_from_config(images, FIT_FDT_PROP,
346 fdt_addr);
347 if (fdt_noffset == -ENOENT)
348 return -ENOPKG;
349 else if (fdt_noffset < 0)
350 return fdt_noffset;
351 }
352#endif
353 debug("## Checking for 'FDT'/'FDT Image' at %08lx\n",
354 fdt_addr);
355
356 /*
357 * Check if there is an FDT image at the
358 * address provided in the second bootm argument
359 * check image type, for FIT images get a FIT node.
360 */
361 buf = map_sysmem(fdt_addr, 0);
362 switch (genimg_get_format(buf)) {
363#if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT)
364 case IMAGE_FORMAT_LEGACY: {
365 const image_header_t *fdt_hdr;
366 ulong load, load_end;
367 ulong image_start, image_data, image_end;
368
369 /* verify fdt_addr points to a valid image header */
370 printf("## Flattened Device Tree from Legacy Image at %08lx\n",
371 fdt_addr);
372 fdt_hdr = image_get_fdt(fdt_addr);
373 if (!fdt_hdr)
374 return -ENOPKG;
375
376 /*
377 * move image data to the load address,
378 * make sure we don't overwrite initial image
379 */
380 image_start = (ulong)fdt_hdr;
381 image_data = (ulong)image_get_data(fdt_hdr);
382 image_end = image_get_image_end(fdt_hdr);
383
384 load = image_get_load(fdt_hdr);
385 load_end = load + image_get_data_size(fdt_hdr);
386
387 if (load == image_start ||
388 load == image_data) {
389 fdt_addr = load;
390 break;
391 }
392
393 if ((load < image_end) && (load_end > image_start)) {
394 fdt_error("fdt overwritten");
395 return -EFAULT;
396 }
397
398 debug(" Loading FDT from 0x%08lx to 0x%08lx\n",
399 image_data, load);
400
401 memmove((void *)load,
402 (void *)image_data,
403 image_get_data_size(fdt_hdr));
404
405 fdt_addr = load;
406 break;
407 }
408#endif
409 case IMAGE_FORMAT_FIT:
410 /*
411 * This case will catch both: new uImage format
412 * (libfdt based) and raw FDT blob (also libfdt
413 * based).
414 */
415#if CONFIG_IS_ENABLED(FIT)
416 /* check FDT blob vs FIT blob */
417 if (!fit_check_format(buf, IMAGE_SIZE_INVAL)) {
418 ulong load, len;
419
420 fdt_noffset = boot_get_fdt_fit(images, fdt_addr,
421 &fit_uname_fdt,
422 &fit_uname_config,
423 arch, &load, &len);
424
425 if (fdt_noffset < 0)
426 return -ENOENT;
427
428 images->fit_hdr_fdt = map_sysmem(fdt_addr, 0);
429 images->fit_uname_fdt = fit_uname_fdt;
430 images->fit_noffset_fdt = fdt_noffset;
431 fdt_addr = load;
432
433 break;
434 } else
435#endif
436 {
437 /*
438 * FDT blob
439 */
440 debug("* fdt: raw FDT blob\n");
441 printf("## Flattened Device Tree blob at %08lx\n",
442 (long)fdt_addr);
443 }
444 break;
445 default:
446 puts("ERROR: Did not find a cmdline Flattened Device Tree\n");
447 return -ENOENT;
448 }
449 *fdt_addrp = fdt_addr;
450
451 return 0;
452}
453
454/**
Simon Glass44d3a302013-05-08 08:06:00 +0000455 * boot_get_fdt - main fdt handling routine
456 * @argc: command argument count
457 * @argv: command argument list
Simon Glass53f375f2013-05-16 13:53:23 +0000458 * @arch: architecture (IH_ARCH_...)
Simon Glass44d3a302013-05-08 08:06:00 +0000459 * @images: pointer to the bootm images structure
460 * @of_flat_tree: pointer to a char* variable, will hold fdt start address
461 * @of_size: pointer to a ulong variable, will hold fdt length
462 *
463 * boot_get_fdt() is responsible for finding a valid flat device tree image.
Simon Glass4cb35b72021-09-25 19:43:41 -0600464 * Currently supported are the following ramdisk sources:
Simon Glass44d3a302013-05-08 08:06:00 +0000465 * - multicomponent kernel/ramdisk image,
466 * - commandline provided address of decicated ramdisk image.
467 *
468 * returns:
469 * 0, if fdt image was found and valid, or skipped
470 * of_flat_tree and of_size are set to fdt start address and length if
471 * fdt image is found and valid
472 *
473 * 1, if fdt image is found but corrupted
474 * of_flat_tree and of_size are set to 0 if no fdt exists
475 */
Simon Glass09140112020-05-10 11:40:03 -0600476int boot_get_fdt(int flag, int argc, char *const argv[], uint8_t arch,
477 bootm_headers_t *images, char **of_flat_tree, ulong *of_size)
Simon Glass44d3a302013-05-08 08:06:00 +0000478{
Shawn Guo6a7b4062019-01-15 22:26:37 +0800479 ulong img_addr;
Simon Glass44d3a302013-05-08 08:06:00 +0000480 ulong fdt_addr;
481 char *fdt_blob = NULL;
Simon Glass44d3a302013-05-08 08:06:00 +0000482 void *buf;
Simon Glass983c72f2013-06-11 11:14:46 -0700483 const char *select = NULL;
Simon Glass44d3a302013-05-08 08:06:00 +0000484
485 *of_flat_tree = NULL;
486 *of_size = 0;
487
Simon Glass4cb35b72021-09-25 19:43:41 -0600488 img_addr = (argc == 0) ? image_load_addr : hextoul(argv[0], NULL);
Shawn Guo6a7b4062019-01-15 22:26:37 +0800489 buf = map_sysmem(img_addr, 0);
490
Simon Glass983c72f2013-06-11 11:14:46 -0700491 if (argc > 2)
492 select = argv[2];
493 if (select || genimg_has_config(images)) {
Simon Glass4cb35b72021-09-25 19:43:41 -0600494 int ret;
Simon Glassa2198cd2021-09-25 19:43:40 -0600495
Simon Glass4cb35b72021-09-25 19:43:41 -0600496 ret = select_fdt(images, select, arch, &fdt_addr);
497 if (ret == -ENOPKG)
498 goto no_fdt;
499 else if (ret)
500 return 1;
Simon Glass53f375f2013-05-16 13:53:23 +0000501 printf(" Booting using the fdt blob at %#08lx\n", fdt_addr);
502 fdt_blob = map_sysmem(fdt_addr, 0);
Simon Glass44d3a302013-05-08 08:06:00 +0000503 } else if (images->legacy_hdr_valid &&
504 image_check_type(&images->legacy_hdr_os_copy,
505 IH_TYPE_MULTI)) {
506 ulong fdt_data, fdt_len;
507
508 /*
509 * Now check if we have a legacy multi-component image,
510 * get second entry data start address and len.
511 */
512 printf("## Flattened Device Tree from multi component Image at %08lX\n",
513 (ulong)images->legacy_hdr_os);
514
515 image_multi_getimg(images->legacy_hdr_os, 2, &fdt_data,
516 &fdt_len);
517 if (fdt_len) {
518 fdt_blob = (char *)fdt_data;
519 printf(" Booting using the fdt at 0x%p\n", fdt_blob);
520
521 if (fdt_check_header(fdt_blob) != 0) {
522 fdt_error("image is not a fdt");
523 goto error;
524 }
525
526 if (fdt_totalsize(fdt_blob) != fdt_len) {
527 fdt_error("fdt size != image size");
528 goto error;
529 }
530 } else {
531 debug("## No Flattened Device Tree\n");
Suriyan Ramasami48aead72014-11-27 13:24:16 -0800532 goto no_fdt;
Simon Glass44d3a302013-05-08 08:06:00 +0000533 }
Shawn Guo6a7b4062019-01-15 22:26:37 +0800534#ifdef CONFIG_ANDROID_BOOT_IMAGE
535 } else if (genimg_get_format(buf) == IMAGE_FORMAT_ANDROID) {
536 struct andr_img_hdr *hdr = buf;
chenshuo6e314582020-07-20 08:48:15 +0800537 ulong fdt_data, fdt_len;
538 u32 fdt_size, dtb_idx;
539 /*
540 * Firstly check if this android boot image has dtb field.
541 */
542 dtb_idx = (u32)env_get_ulong("adtb_idx", 10, 0);
543 if (android_image_get_dtb_by_index((ulong)hdr, dtb_idx, &fdt_addr, &fdt_size)) {
544 fdt_blob = (char *)map_sysmem(fdt_addr, 0);
545 if (fdt_check_header(fdt_blob))
546 goto no_fdt;
Shawn Guo6a7b4062019-01-15 22:26:37 +0800547
chenshuo6e314582020-07-20 08:48:15 +0800548 debug("## Using FDT in Android image dtb area with idx %u\n", dtb_idx);
549 } else if (!android_image_get_second(hdr, &fdt_data, &fdt_len) &&
550 !fdt_check_header((char *)fdt_data)) {
Eugeniu Rosca18b8f2c2019-04-01 12:45:36 +0200551 fdt_blob = (char *)fdt_data;
552 if (fdt_totalsize(fdt_blob) != fdt_len)
553 goto error;
Shawn Guo6a7b4062019-01-15 22:26:37 +0800554
Eugeniu Rosca18b8f2c2019-04-01 12:45:36 +0200555 debug("## Using FDT in Android image second area\n");
556 } else {
Eugeniu Rosca62392672019-04-01 12:52:52 +0200557 fdt_addr = env_get_hex("fdtaddr", 0);
558 if (!fdt_addr)
559 goto no_fdt;
Shawn Guo6a7b4062019-01-15 22:26:37 +0800560
Eugeniu Rosca62392672019-04-01 12:52:52 +0200561 fdt_blob = map_sysmem(fdt_addr, 0);
562 if (fdt_check_header(fdt_blob))
563 goto no_fdt;
Shawn Guo6a7b4062019-01-15 22:26:37 +0800564
Eugeniu Rosca62392672019-04-01 12:52:52 +0200565 debug("## Using FDT at ${fdtaddr}=Ox%lx\n", fdt_addr);
Eugeniu Rosca18b8f2c2019-04-01 12:45:36 +0200566 }
Shawn Guo6a7b4062019-01-15 22:26:37 +0800567#endif
Simon Glass44d3a302013-05-08 08:06:00 +0000568 } else {
569 debug("## No Flattened Device Tree\n");
Suriyan Ramasami48aead72014-11-27 13:24:16 -0800570 goto no_fdt;
Simon Glass44d3a302013-05-08 08:06:00 +0000571 }
572
573 *of_flat_tree = fdt_blob;
574 *of_size = fdt_totalsize(fdt_blob);
575 debug(" of_flat_tree at 0x%08lx size 0x%08lx\n",
576 (ulong)*of_flat_tree, *of_size);
577
578 return 0;
579
Suriyan Ramasami48aead72014-11-27 13:24:16 -0800580no_fdt:
Eugeniu Rosca80281822019-04-01 12:45:35 +0200581 debug("Continuing to boot without FDT\n");
582 return 0;
Simon Glass44d3a302013-05-08 08:06:00 +0000583error:
Simon Glass44d3a302013-05-08 08:06:00 +0000584 return 1;
585}
Simon Glass13d06982013-05-08 08:06:01 +0000586
587/*
588 * Verify the device tree.
589 *
590 * This function is called after all device tree fix-ups have been enacted,
591 * so that the final device tree can be verified. The definition of "verified"
592 * is up to the specific implementation. However, it generally means that the
593 * addresses of some of the devices in the device tree are compared with the
594 * actual addresses at which U-Boot has placed them.
595 *
Bin Menga1875592016-02-05 19:30:11 -0800596 * Returns 1 on success, 0 on failure. If 0 is returned, U-Boot will halt the
Simon Glass13d06982013-05-08 08:06:01 +0000597 * boot process.
598 */
599__weak int ft_verify_fdt(void *fdt)
600{
601 return 1;
602}
603
Alexey Brodkin42803422018-01-24 20:47:09 +0300604__weak int arch_fixup_fdt(void *blob)
605{
606 return 0;
607}
608
Simon Glass13d06982013-05-08 08:06:01 +0000609int image_setup_libfdt(bootm_headers_t *images, void *blob,
610 int of_size, struct lmb *lmb)
611{
612 ulong *initrd_start = &images->initrd_start;
613 ulong *initrd_end = &images->initrd_end;
Simon Glass6f4dbc22014-10-23 18:58:53 -0600614 int ret = -EPERM;
615 int fdt_ret;
Simon Glass13d06982013-05-08 08:06:01 +0000616
Paul Kocialkowski10be5b52015-05-21 11:27:03 +0200617 if (fdt_root(blob) < 0) {
618 printf("ERROR: root node setup failed\n");
619 goto err;
620 }
Masahiro Yamadabc6ed0f2014-04-18 17:41:00 +0900621 if (fdt_chosen(blob) < 0) {
Simon Glass6f4dbc22014-10-23 18:58:53 -0600622 printf("ERROR: /chosen node create failed\n");
623 goto err;
Simon Glass13d06982013-05-08 08:06:01 +0000624 }
Ma Haijune29607e2014-07-12 14:24:06 +0100625 if (arch_fixup_fdt(blob) < 0) {
Simon Glass6f4dbc22014-10-23 18:58:53 -0600626 printf("ERROR: arch-specific fdt fixup failed\n");
627 goto err;
Ma Haijune29607e2014-07-12 14:24:06 +0100628 }
Etienne Carriere5f9070a2020-06-05 09:22:54 +0200629
Patrick Delaunaya2535242021-02-08 13:54:31 +0100630 fdt_ret = optee_copy_fdt_nodes(blob);
Etienne Carriere5f9070a2020-06-05 09:22:54 +0200631 if (fdt_ret) {
632 printf("ERROR: transfer of optee nodes to new fdt failed: %s\n",
633 fdt_strerror(fdt_ret));
634 goto err;
635 }
636
Daniel Golle5f2d5912022-04-12 21:00:43 +0100637 /* Store name of configuration node as u-boot,bootconf in /chosen node */
638 if (images->fit_uname_cfg)
639 fdt_find_and_setprop(blob, "/chosen", "u-boot,bootconf",
640 images->fit_uname_cfg,
641 strlen(images->fit_uname_cfg) + 1, 1);
642
Tom Rini26d61192017-04-28 08:51:44 -0400643 /* Update ethernet nodes */
644 fdt_fixup_ethernet(blob);
Frédéric Danis9ea0a1e2020-03-20 10:59:24 +0100645#if CONFIG_IS_ENABLED(CMD_PSTORE)
646 /* Append PStore configuration */
647 fdt_fixup_pstore(blob);
648#endif
Simon Glass30ba2822021-09-25 19:43:26 -0600649 if (IS_ENABLED(CONFIG_OF_BOARD_SETUP)) {
Wasim Khan402558b2021-02-04 15:44:04 +0100650 const char *skip_board_fixup;
651
652 skip_board_fixup = env_get("skip_board_fixup");
653 if (skip_board_fixup && ((int)simple_strtol(skip_board_fixup, NULL, 10) == 1)) {
654 printf("skip board fdt fixup\n");
655 } else {
656 fdt_ret = ft_board_setup(blob, gd->bd);
657 if (fdt_ret) {
658 printf("ERROR: board-specific fdt fixup failed: %s\n",
659 fdt_strerror(fdt_ret));
660 goto err;
661 }
Simon Glass6f4dbc22014-10-23 18:58:53 -0600662 }
663 }
Simon Glass3ac0f502021-09-25 19:43:27 -0600664 if (IS_ENABLED(CONFIG_OF_SYSTEM_SETUP)) {
Max Krummenacherd89212b2015-08-05 17:17:03 +0200665 fdt_ret = ft_system_setup(blob, gd->bd);
666 if (fdt_ret) {
Simon Glassc654b512014-10-23 18:58:54 -0600667 printf("ERROR: system-specific fdt fixup failed: %s\n",
668 fdt_strerror(fdt_ret));
669 goto err;
670 }
671 }
Simon Glass98887ab2022-07-30 15:52:31 -0600672 if (CONFIG_IS_ENABLED(EVENT)) {
673 struct event_ft_fixup fixup;
674
675 fixup.tree = oftree_default();
676 ret = event_notify(EVT_FT_FIXUP, &fixup, sizeof(fixup));
677 if (ret) {
678 printf("ERROR: fdt fixup event failed: %d\n", ret);
679 goto err;
680 }
681 }
Simon Glass13d06982013-05-08 08:06:01 +0000682
683 /* Delete the old LMB reservation */
Alexander Grafdea21742016-03-04 01:10:13 +0100684 if (lmb)
685 lmb_free(lmb, (phys_addr_t)(u32)(uintptr_t)blob,
686 (phys_size_t)fdt_totalsize(blob));
Simon Glass13d06982013-05-08 08:06:01 +0000687
Hannes Schmelzeref476832016-09-20 18:10:43 +0200688 ret = fdt_shrink_to_minimum(blob, 0);
Simon Glass13d06982013-05-08 08:06:01 +0000689 if (ret < 0)
Simon Glass6f4dbc22014-10-23 18:58:53 -0600690 goto err;
Simon Glass13d06982013-05-08 08:06:01 +0000691 of_size = ret;
692
693 if (*initrd_start && *initrd_end) {
694 of_size += FDT_RAMDISK_OVERHEAD;
695 fdt_set_totalsize(blob, of_size);
696 }
697 /* Create a new LMB reservation */
Alexander Grafdea21742016-03-04 01:10:13 +0100698 if (lmb)
699 lmb_reserve(lmb, (ulong)blob, of_size);
Simon Glass13d06982013-05-08 08:06:01 +0000700
Masahiro Yamadadbe963a2014-04-18 17:40:59 +0900701 fdt_initrd(blob, *initrd_start, *initrd_end);
Simon Glass13d06982013-05-08 08:06:01 +0000702 if (!ft_verify_fdt(blob))
Simon Glass6f4dbc22014-10-23 18:58:53 -0600703 goto err;
Simon Glass13d06982013-05-08 08:06:01 +0000704
Tom Rinif899cc12021-09-12 20:32:32 -0400705#if defined(CONFIG_ARCH_KEYSTONE)
Simon Glass30ba2822021-09-25 19:43:26 -0600706 if (IS_ENABLED(CONFIG_OF_BOARD_SETUP))
Vitaly Andrianov00c200f2014-04-04 13:16:47 -0400707 ft_board_setup_ex(blob, gd->bd);
708#endif
709
Simon Glass13d06982013-05-08 08:06:01 +0000710 return 0;
Simon Glass6f4dbc22014-10-23 18:58:53 -0600711err:
712 printf(" - must RESET the board to recover.\n\n");
713
714 return ret;
Simon Glass13d06982013-05-08 08:06:01 +0000715}