1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2013, Google Inc.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * (C) Copyright 2008 Semihalf
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * (C) Copyright 2000-2006
7*4882a593Smuzhiyun * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <common.h>
13*4882a593Smuzhiyun #include <fdtdec.h>
14*4882a593Smuzhiyun #include <fdt_support.h>
15*4882a593Smuzhiyun #include <errno.h>
16*4882a593Smuzhiyun #include <image.h>
17*4882a593Smuzhiyun #include <linux/libfdt.h>
18*4882a593Smuzhiyun #include <mapmem.h>
19*4882a593Smuzhiyun #include <asm/io.h>
20*4882a593Smuzhiyun #include <sysmem.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #ifndef CONFIG_SYS_FDT_PAD
23*4882a593Smuzhiyun #define CONFIG_SYS_FDT_PAD 0x3000
24*4882a593Smuzhiyun #endif
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /* adding a ramdisk needs 0x44 bytes in version 2008.10 */
27*4882a593Smuzhiyun #define FDT_RAMDISK_OVERHEAD 0x80
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
30*4882a593Smuzhiyun
fdt_error(const char * msg)31*4882a593Smuzhiyun static void fdt_error(const char *msg)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun puts("ERROR: ");
34*4882a593Smuzhiyun puts(msg);
35*4882a593Smuzhiyun puts(" - must RESET the board to recover.\n");
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
image_get_fdt(ulong fdt_addr)39*4882a593Smuzhiyun static const image_header_t *image_get_fdt(ulong fdt_addr)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun const image_header_t *fdt_hdr = map_sysmem(fdt_addr, 0);
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun image_print_contents(fdt_hdr);
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun puts(" Verifying Checksum ... ");
46*4882a593Smuzhiyun if (!image_check_hcrc(fdt_hdr)) {
47*4882a593Smuzhiyun fdt_error("fdt header checksum invalid");
48*4882a593Smuzhiyun return NULL;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun if (!image_check_dcrc(fdt_hdr)) {
52*4882a593Smuzhiyun fdt_error("fdt checksum invalid");
53*4882a593Smuzhiyun return NULL;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun puts("OK\n");
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /*
58*4882a593Smuzhiyun * default image mkimage conflicts with fit mkimage on param: -T "flat_dt".
59*4882a593Smuzhiyun *
60*4882a593Smuzhiyun * error message:
61*4882a593Smuzhiyun * "./tools/mkimage: Can't set header for FIT Image support: Success"
62*4882a593Smuzhiyun */
63*4882a593Smuzhiyun #if 0
64*4882a593Smuzhiyun if (!image_check_type(fdt_hdr, IH_TYPE_FLATDT)) {
65*4882a593Smuzhiyun fdt_error("uImage is not a fdt");
66*4882a593Smuzhiyun return NULL;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun #endif
69*4882a593Smuzhiyun if (image_get_comp(fdt_hdr) != IH_COMP_NONE) {
70*4882a593Smuzhiyun fdt_error("uImage is compressed");
71*4882a593Smuzhiyun return NULL;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun if (fdt_check_header((void *)image_get_data(fdt_hdr)) != 0) {
74*4882a593Smuzhiyun fdt_error("uImage data is not a fdt");
75*4882a593Smuzhiyun return NULL;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun return fdt_hdr;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun #endif
80*4882a593Smuzhiyun
boot_mem_rsv_regions(struct lmb * lmb,void * fdt_blob)81*4882a593Smuzhiyun void boot_mem_rsv_regions(struct lmb *lmb, void *fdt_blob)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun int rsv_offset, offset;
84*4882a593Smuzhiyun fdt_size_t rsv_size;
85*4882a593Smuzhiyun fdt_addr_t rsv_addr;
86*4882a593Smuzhiyun const void *prop;
87*4882a593Smuzhiyun int i = 0;
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (fdt_check_header(fdt_blob) != 0)
90*4882a593Smuzhiyun return;
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun rsv_offset = fdt_subnode_offset(fdt_blob, 0, "reserved-memory");
93*4882a593Smuzhiyun if (rsv_offset == -FDT_ERR_NOTFOUND)
94*4882a593Smuzhiyun return;
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun for (offset = fdt_first_subnode(fdt_blob, rsv_offset);
97*4882a593Smuzhiyun offset >= 0;
98*4882a593Smuzhiyun offset = fdt_next_subnode(fdt_blob, offset)) {
99*4882a593Smuzhiyun prop = fdt_getprop(fdt_blob, offset, "status", NULL);
100*4882a593Smuzhiyun if (prop && !strcmp(prop, "disabled"))
101*4882a593Smuzhiyun continue;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun rsv_addr = fdtdec_get_addr_size_auto_noparent(fdt_blob, offset,
104*4882a593Smuzhiyun "reg", 0,
105*4882a593Smuzhiyun &rsv_size, false);
106*4882a593Smuzhiyun if (rsv_addr == FDT_ADDR_T_NONE || !rsv_size)
107*4882a593Smuzhiyun continue;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun i++;
110*4882a593Smuzhiyun /* be quiet while reserve */
111*4882a593Smuzhiyun if (lmb) {
112*4882a593Smuzhiyun lmb_reserve(lmb, rsv_addr, rsv_size);
113*4882a593Smuzhiyun } else {
114*4882a593Smuzhiyun if (i == 1)
115*4882a593Smuzhiyun printf("## reserved-memory:\n");
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun printf(" %s: addr=%llx size=%llx\n",
118*4882a593Smuzhiyun fdt_get_name(fdt_blob, offset, NULL),
119*4882a593Smuzhiyun (unsigned long long)rsv_addr, (unsigned long long)rsv_size);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /**
125*4882a593Smuzhiyun * boot_fdt_add_mem_rsv_regions - Mark the memreserve sections as unusable
126*4882a593Smuzhiyun * @lmb: pointer to lmb handle, will be used for memory mgmt
127*4882a593Smuzhiyun * @fdt_blob: pointer to fdt blob base address
128*4882a593Smuzhiyun *
129*4882a593Smuzhiyun * Adds the memreserve regions in the dtb to the lmb block. Adding the
130*4882a593Smuzhiyun * memreserve regions prevents u-boot from using them to store the initrd
131*4882a593Smuzhiyun * or the fdt blob.
132*4882a593Smuzhiyun */
boot_fdt_add_mem_rsv_regions(struct lmb * lmb,void * fdt_blob)133*4882a593Smuzhiyun void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun uint64_t addr, size;
136*4882a593Smuzhiyun int i, total;
137*4882a593Smuzhiyun /* we needn't repeat do reserve, do_bootm_linux would call this again */
138*4882a593Smuzhiyun static int rsv_done;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun if (fdt_check_header(fdt_blob) != 0 || rsv_done)
141*4882a593Smuzhiyun return;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun rsv_done = 1;
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun total = fdt_num_mem_rsv(fdt_blob);
146*4882a593Smuzhiyun for (i = 0; i < total; i++) {
147*4882a593Smuzhiyun if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0)
148*4882a593Smuzhiyun continue;
149*4882a593Smuzhiyun printf(" reserving fdt memory region: addr=%llx size=%llx\n",
150*4882a593Smuzhiyun (unsigned long long)addr, (unsigned long long)size);
151*4882a593Smuzhiyun lmb_reserve(lmb, addr, size);
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun /* lmb_reserve() for "reserved-memory" */
155*4882a593Smuzhiyun boot_mem_rsv_regions(lmb, fdt_blob);
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun #ifdef CONFIG_SYSMEM
159*4882a593Smuzhiyun /**
160*4882a593Smuzhiyun * boot_fdt_add_mem_rsv_regions - Mark the memreserve sections as unusable
161*4882a593Smuzhiyun * @sysmem: pointer to sysmem handle, will be used for memory mgmt
162*4882a593Smuzhiyun * @fdt_blob: pointer to fdt blob base address
163*4882a593Smuzhiyun */
boot_fdt_add_sysmem_rsv_regions(void * fdt_blob)164*4882a593Smuzhiyun int boot_fdt_add_sysmem_rsv_regions(void *fdt_blob)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun uint64_t addr, size;
167*4882a593Smuzhiyun int i, total;
168*4882a593Smuzhiyun int rsv_offset, offset;
169*4882a593Smuzhiyun fdt_size_t rsv_size;
170*4882a593Smuzhiyun fdt_addr_t rsv_addr;
171*4882a593Smuzhiyun static int rsv_done;
172*4882a593Smuzhiyun char resvname[32];
173*4882a593Smuzhiyun const void *prop;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (fdt_check_header(fdt_blob) != 0 || rsv_done)
176*4882a593Smuzhiyun return -EINVAL;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun rsv_done = 1;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun total = fdt_num_mem_rsv(fdt_blob);
181*4882a593Smuzhiyun for (i = 0; i < total; i++) {
182*4882a593Smuzhiyun if (fdt_get_mem_rsv(fdt_blob, i, &addr, &size) != 0)
183*4882a593Smuzhiyun continue;
184*4882a593Smuzhiyun debug(" sysmem: reserving fdt memory region: addr=%llx size=%llx\n",
185*4882a593Smuzhiyun (unsigned long long)addr, (unsigned long long)size);
186*4882a593Smuzhiyun sprintf(resvname, "fdt-memory-reserved%d", i);
187*4882a593Smuzhiyun if (!sysmem_fdt_reserve_alloc_base(resvname, addr, size))
188*4882a593Smuzhiyun return -ENOMEM;
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun rsv_offset = fdt_subnode_offset(fdt_blob, 0, "reserved-memory");
192*4882a593Smuzhiyun if (rsv_offset == -FDT_ERR_NOTFOUND)
193*4882a593Smuzhiyun return -EINVAL;
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun for (offset = fdt_first_subnode(fdt_blob, rsv_offset);
196*4882a593Smuzhiyun offset >= 0;
197*4882a593Smuzhiyun offset = fdt_next_subnode(fdt_blob, offset)) {
198*4882a593Smuzhiyun prop = fdt_getprop(fdt_blob, offset, "status", NULL);
199*4882a593Smuzhiyun if (prop && !strcmp(prop, "disabled"))
200*4882a593Smuzhiyun continue;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun rsv_addr = fdtdec_get_addr_size_auto_noparent(fdt_blob, offset,
203*4882a593Smuzhiyun "reg", 0,
204*4882a593Smuzhiyun &rsv_size, false);
205*4882a593Smuzhiyun /*
206*4882a593Smuzhiyun * kernel will alloc reserved memory dynamically for the node
207*4882a593Smuzhiyun * with start address from 0.
208*4882a593Smuzhiyun */
209*4882a593Smuzhiyun if (rsv_addr == FDT_ADDR_T_NONE || !rsv_addr || !rsv_size)
210*4882a593Smuzhiyun continue;
211*4882a593Smuzhiyun debug(" sysmem: 'reserved-memory' %s: addr=%llx size=%llx\n",
212*4882a593Smuzhiyun fdt_get_name(fdt_blob, offset, NULL),
213*4882a593Smuzhiyun (unsigned long long)rsv_addr, (unsigned long long)rsv_size);
214*4882a593Smuzhiyun if (!sysmem_fdt_reserve_alloc_base(fdt_get_name(fdt_blob, offset, NULL),
215*4882a593Smuzhiyun rsv_addr, rsv_size))
216*4882a593Smuzhiyun return -ENOMEM;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun return 0;
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun #endif
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun /**
224*4882a593Smuzhiyun * boot_relocate_fdt - relocate flat device tree
225*4882a593Smuzhiyun * @lmb: pointer to lmb handle, will be used for memory mgmt
226*4882a593Smuzhiyun * @of_flat_tree: pointer to a char* variable, will hold fdt start address
227*4882a593Smuzhiyun * @of_size: pointer to a ulong variable, will hold fdt length
228*4882a593Smuzhiyun *
229*4882a593Smuzhiyun * boot_relocate_fdt() allocates a region of memory within the bootmap and
230*4882a593Smuzhiyun * relocates the of_flat_tree into that region, even if the fdt is already in
231*4882a593Smuzhiyun * the bootmap. It also expands the size of the fdt by CONFIG_SYS_FDT_PAD
232*4882a593Smuzhiyun * bytes.
233*4882a593Smuzhiyun *
234*4882a593Smuzhiyun * of_flat_tree and of_size are set to final (after relocation) values
235*4882a593Smuzhiyun *
236*4882a593Smuzhiyun * returns:
237*4882a593Smuzhiyun * 0 - success
238*4882a593Smuzhiyun * 1 - failure
239*4882a593Smuzhiyun */
boot_relocate_fdt(struct lmb * lmb,char ** of_flat_tree,ulong * of_size)240*4882a593Smuzhiyun int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun void *fdt_blob = *of_flat_tree;
243*4882a593Smuzhiyun void *of_start = NULL;
244*4882a593Smuzhiyun char *fdt_high;
245*4882a593Smuzhiyun ulong of_len = 0;
246*4882a593Smuzhiyun int err;
247*4882a593Smuzhiyun int disable_relocation = 0;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun /* nothing to do */
250*4882a593Smuzhiyun if (*of_size == 0)
251*4882a593Smuzhiyun return 0;
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun if (fdt_check_header(fdt_blob) != 0) {
254*4882a593Smuzhiyun fdt_error("image is not a fdt");
255*4882a593Smuzhiyun goto error;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun /* position on a 4K boundary before the alloc_current */
259*4882a593Smuzhiyun /* Pad the FDT by a specified amount */
260*4882a593Smuzhiyun of_len = *of_size + CONFIG_SYS_FDT_PAD;
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /* If fdt_high is set use it to select the relocation address */
263*4882a593Smuzhiyun fdt_high = env_get("fdt_high");
264*4882a593Smuzhiyun if (fdt_high) {
265*4882a593Smuzhiyun void *desired_addr = (void *)simple_strtoul(fdt_high, NULL, 16);
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun if (((ulong) desired_addr) == ~0UL) {
268*4882a593Smuzhiyun /* All ones means use fdt in place */
269*4882a593Smuzhiyun of_start = fdt_blob;
270*4882a593Smuzhiyun lmb_reserve(lmb, (ulong)of_start, of_len);
271*4882a593Smuzhiyun disable_relocation = 1;
272*4882a593Smuzhiyun } else if (desired_addr) {
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun if (desired_addr && env_get_yesno("bootm-reloc-at"))
275*4882a593Smuzhiyun desired_addr += of_len;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun of_start =
278*4882a593Smuzhiyun (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
279*4882a593Smuzhiyun (ulong)desired_addr);
280*4882a593Smuzhiyun if (of_start == NULL) {
281*4882a593Smuzhiyun puts("Failed using fdt_high value for Device Tree");
282*4882a593Smuzhiyun goto error;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun } else {
285*4882a593Smuzhiyun of_start =
286*4882a593Smuzhiyun (void *)(ulong) lmb_alloc(lmb, of_len, 0x1000);
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun } else {
289*4882a593Smuzhiyun of_start =
290*4882a593Smuzhiyun (void *)(ulong) lmb_alloc_base(lmb, of_len, 0x1000,
291*4882a593Smuzhiyun env_get_bootm_mapsize()
292*4882a593Smuzhiyun + env_get_bootm_low());
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun if (of_start == NULL) {
296*4882a593Smuzhiyun puts("device tree - allocation error\n");
297*4882a593Smuzhiyun goto error;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun if (disable_relocation) {
301*4882a593Smuzhiyun /*
302*4882a593Smuzhiyun * We assume there is space after the existing fdt to use
303*4882a593Smuzhiyun * for padding
304*4882a593Smuzhiyun */
305*4882a593Smuzhiyun fdt_set_totalsize(of_start, of_len);
306*4882a593Smuzhiyun printf(" Using Device Tree in place at %p, end %p\n",
307*4882a593Smuzhiyun of_start, of_start + of_len - 1);
308*4882a593Smuzhiyun } else {
309*4882a593Smuzhiyun debug("## device tree at %p ... %p (len=%ld [0x%lX])\n",
310*4882a593Smuzhiyun fdt_blob, fdt_blob + *of_size - 1, of_len, of_len);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun printf(" Loading Device Tree to %p, end %p ... ",
313*4882a593Smuzhiyun of_start, of_start + of_len - 1);
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun err = fdt_open_into(fdt_blob, of_start, of_len);
316*4882a593Smuzhiyun if (err != 0) {
317*4882a593Smuzhiyun fdt_error("fdt move failed");
318*4882a593Smuzhiyun goto error;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun puts("OK\n");
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun *of_flat_tree = of_start;
324*4882a593Smuzhiyun *of_size = of_len;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun #ifdef CONFIG_CMD_FDT
327*4882a593Smuzhiyun set_working_fdt_addr((ulong)*of_flat_tree);
328*4882a593Smuzhiyun #endif
329*4882a593Smuzhiyun return 0;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun error:
332*4882a593Smuzhiyun return 1;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun /**
336*4882a593Smuzhiyun * boot_get_fdt - main fdt handling routine
337*4882a593Smuzhiyun * @argc: command argument count
338*4882a593Smuzhiyun * @argv: command argument list
339*4882a593Smuzhiyun * @arch: architecture (IH_ARCH_...)
340*4882a593Smuzhiyun * @images: pointer to the bootm images structure
341*4882a593Smuzhiyun * @of_flat_tree: pointer to a char* variable, will hold fdt start address
342*4882a593Smuzhiyun * @of_size: pointer to a ulong variable, will hold fdt length
343*4882a593Smuzhiyun *
344*4882a593Smuzhiyun * boot_get_fdt() is responsible for finding a valid flat device tree image.
345*4882a593Smuzhiyun * Curently supported are the following ramdisk sources:
346*4882a593Smuzhiyun * - multicomponent kernel/ramdisk image,
347*4882a593Smuzhiyun * - commandline provided address of decicated ramdisk image.
348*4882a593Smuzhiyun *
349*4882a593Smuzhiyun * returns:
350*4882a593Smuzhiyun * 0, if fdt image was found and valid, or skipped
351*4882a593Smuzhiyun * of_flat_tree and of_size are set to fdt start address and length if
352*4882a593Smuzhiyun * fdt image is found and valid
353*4882a593Smuzhiyun *
354*4882a593Smuzhiyun * 1, if fdt image is found but corrupted
355*4882a593Smuzhiyun * of_flat_tree and of_size are set to 0 if no fdt exists
356*4882a593Smuzhiyun */
boot_get_fdt(int flag,int argc,char * const argv[],uint8_t arch,bootm_headers_t * images,char ** of_flat_tree,ulong * of_size)357*4882a593Smuzhiyun int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch,
358*4882a593Smuzhiyun bootm_headers_t *images, char **of_flat_tree, ulong *of_size)
359*4882a593Smuzhiyun {
360*4882a593Smuzhiyun #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
361*4882a593Smuzhiyun const image_header_t *fdt_hdr;
362*4882a593Smuzhiyun ulong load, load_end;
363*4882a593Smuzhiyun ulong image_start, image_data, image_end;
364*4882a593Smuzhiyun #endif
365*4882a593Smuzhiyun ulong fdt_addr;
366*4882a593Smuzhiyun char *fdt_blob = NULL;
367*4882a593Smuzhiyun void *buf;
368*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(FIT)
369*4882a593Smuzhiyun const char *fit_uname_config = images->fit_uname_cfg;
370*4882a593Smuzhiyun const char *fit_uname_fdt = NULL;
371*4882a593Smuzhiyun ulong default_addr;
372*4882a593Smuzhiyun int fdt_noffset;
373*4882a593Smuzhiyun #endif
374*4882a593Smuzhiyun const char *select = NULL;
375*4882a593Smuzhiyun int ok_no_fdt = 0;
376*4882a593Smuzhiyun
377*4882a593Smuzhiyun *of_flat_tree = NULL;
378*4882a593Smuzhiyun *of_size = 0;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun if (argc > 2)
381*4882a593Smuzhiyun select = argv[2];
382*4882a593Smuzhiyun if (select || genimg_has_config(images)) {
383*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(FIT)
384*4882a593Smuzhiyun if (select) {
385*4882a593Smuzhiyun /*
386*4882a593Smuzhiyun * If the FDT blob comes from the FIT image and the
387*4882a593Smuzhiyun * FIT image address is omitted in the command line
388*4882a593Smuzhiyun * argument, try to use ramdisk or os FIT image
389*4882a593Smuzhiyun * address or default load address.
390*4882a593Smuzhiyun */
391*4882a593Smuzhiyun if (images->fit_uname_rd)
392*4882a593Smuzhiyun default_addr = (ulong)images->fit_hdr_rd;
393*4882a593Smuzhiyun else if (images->fit_uname_os)
394*4882a593Smuzhiyun default_addr = (ulong)images->fit_hdr_os;
395*4882a593Smuzhiyun else
396*4882a593Smuzhiyun default_addr = load_addr;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun if (fit_parse_conf(select, default_addr,
399*4882a593Smuzhiyun &fdt_addr, &fit_uname_config)) {
400*4882a593Smuzhiyun debug("* fdt: config '%s' from image at 0x%08lx\n",
401*4882a593Smuzhiyun fit_uname_config, fdt_addr);
402*4882a593Smuzhiyun } else if (fit_parse_subimage(select, default_addr,
403*4882a593Smuzhiyun &fdt_addr, &fit_uname_fdt)) {
404*4882a593Smuzhiyun debug("* fdt: subimage '%s' from image at 0x%08lx\n",
405*4882a593Smuzhiyun fit_uname_fdt, fdt_addr);
406*4882a593Smuzhiyun } else
407*4882a593Smuzhiyun #endif
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun fdt_addr = simple_strtoul(select, NULL, 16);
410*4882a593Smuzhiyun debug("* fdt: cmdline image address = 0x%08lx\n",
411*4882a593Smuzhiyun fdt_addr);
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(FIT)
414*4882a593Smuzhiyun } else {
415*4882a593Smuzhiyun /* use FIT configuration provided in first bootm
416*4882a593Smuzhiyun * command argument
417*4882a593Smuzhiyun */
418*4882a593Smuzhiyun fdt_addr = map_to_sysmem(images->fit_hdr_os);
419*4882a593Smuzhiyun fdt_noffset = fit_get_node_from_config(images,
420*4882a593Smuzhiyun FIT_FDT_PROP,
421*4882a593Smuzhiyun fdt_addr);
422*4882a593Smuzhiyun if (fdt_noffset == -ENOENT)
423*4882a593Smuzhiyun return 0;
424*4882a593Smuzhiyun else if (fdt_noffset < 0)
425*4882a593Smuzhiyun return 1;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun #endif
428*4882a593Smuzhiyun debug("## Checking for 'FDT'/'FDT Image' at %08lx\n",
429*4882a593Smuzhiyun fdt_addr);
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun /*
432*4882a593Smuzhiyun * Check if there is an FDT image at the
433*4882a593Smuzhiyun * address provided in the second bootm argument
434*4882a593Smuzhiyun * check image type, for FIT images get a FIT node.
435*4882a593Smuzhiyun */
436*4882a593Smuzhiyun buf = map_sysmem(fdt_addr, 0);
437*4882a593Smuzhiyun switch (genimg_get_format(buf)) {
438*4882a593Smuzhiyun #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
439*4882a593Smuzhiyun case IMAGE_FORMAT_LEGACY:
440*4882a593Smuzhiyun /* verify fdt_addr points to a valid image header */
441*4882a593Smuzhiyun printf("## Flattened Device Tree from Legacy Image at %08lx\n",
442*4882a593Smuzhiyun fdt_addr);
443*4882a593Smuzhiyun fdt_hdr = image_get_fdt(fdt_addr);
444*4882a593Smuzhiyun if (!fdt_hdr)
445*4882a593Smuzhiyun goto no_fdt;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun /*
448*4882a593Smuzhiyun * move image data to the load address,
449*4882a593Smuzhiyun * make sure we don't overwrite initial image
450*4882a593Smuzhiyun */
451*4882a593Smuzhiyun image_start = (ulong)fdt_hdr;
452*4882a593Smuzhiyun image_data = (ulong)image_get_data(fdt_hdr);
453*4882a593Smuzhiyun image_end = image_get_image_end(fdt_hdr);
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun load = image_get_load(fdt_hdr);
456*4882a593Smuzhiyun load_end = load + image_get_data_size(fdt_hdr);
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun if (load == image_start ||
459*4882a593Smuzhiyun load == image_data) {
460*4882a593Smuzhiyun fdt_addr = load;
461*4882a593Smuzhiyun break;
462*4882a593Smuzhiyun }
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun if ((load < image_end) && (load_end > image_start)) {
465*4882a593Smuzhiyun fdt_error("fdt overwritten");
466*4882a593Smuzhiyun goto error;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun debug(" Loading FDT from 0x%08lx to 0x%08lx\n",
470*4882a593Smuzhiyun image_data, load);
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun memmove((void *)load,
473*4882a593Smuzhiyun (void *)image_data,
474*4882a593Smuzhiyun image_get_data_size(fdt_hdr));
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun fdt_addr = load;
477*4882a593Smuzhiyun break;
478*4882a593Smuzhiyun #endif
479*4882a593Smuzhiyun case IMAGE_FORMAT_FIT:
480*4882a593Smuzhiyun /*
481*4882a593Smuzhiyun * This case will catch both: new uImage format
482*4882a593Smuzhiyun * (libfdt based) and raw FDT blob (also libfdt
483*4882a593Smuzhiyun * based).
484*4882a593Smuzhiyun */
485*4882a593Smuzhiyun #if CONFIG_IS_ENABLED(FIT)
486*4882a593Smuzhiyun /* check FDT blob vs FIT blob */
487*4882a593Smuzhiyun if (fit_check_format(buf)) {
488*4882a593Smuzhiyun ulong load, len;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun fdt_noffset = boot_get_fdt_fit(images,
491*4882a593Smuzhiyun fdt_addr, &fit_uname_fdt,
492*4882a593Smuzhiyun &fit_uname_config,
493*4882a593Smuzhiyun arch, &load, &len);
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun images->fit_hdr_fdt = map_sysmem(fdt_addr, 0);
496*4882a593Smuzhiyun images->fit_uname_fdt = fit_uname_fdt;
497*4882a593Smuzhiyun images->fit_noffset_fdt = fdt_noffset;
498*4882a593Smuzhiyun fdt_addr = load;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun break;
501*4882a593Smuzhiyun } else
502*4882a593Smuzhiyun #endif
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun /*
505*4882a593Smuzhiyun * FDT blob
506*4882a593Smuzhiyun */
507*4882a593Smuzhiyun debug("* fdt: raw FDT blob\n");
508*4882a593Smuzhiyun printf("## Flattened Device Tree blob at %#010lx\n",
509*4882a593Smuzhiyun (long)fdt_addr);
510*4882a593Smuzhiyun }
511*4882a593Smuzhiyun break;
512*4882a593Smuzhiyun default:
513*4882a593Smuzhiyun puts("ERROR: Did not find a cmdline Flattened Device Tree\n");
514*4882a593Smuzhiyun goto no_fdt;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun printf(" Booting using the fdt blob at %#010lx\n", fdt_addr);
518*4882a593Smuzhiyun fdt_blob = map_sysmem(fdt_addr, 0);
519*4882a593Smuzhiyun } else if (images->legacy_hdr_valid &&
520*4882a593Smuzhiyun image_check_type(&images->legacy_hdr_os_copy,
521*4882a593Smuzhiyun IH_TYPE_MULTI)) {
522*4882a593Smuzhiyun ulong fdt_data, fdt_len;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun /*
525*4882a593Smuzhiyun * Now check if we have a legacy multi-component image,
526*4882a593Smuzhiyun * get second entry data start address and len.
527*4882a593Smuzhiyun */
528*4882a593Smuzhiyun printf("## Flattened Device Tree from multi component Image at %08lX\n",
529*4882a593Smuzhiyun (ulong)images->legacy_hdr_os);
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun image_multi_getimg(images->legacy_hdr_os, 2, &fdt_data,
532*4882a593Smuzhiyun &fdt_len);
533*4882a593Smuzhiyun if (fdt_len) {
534*4882a593Smuzhiyun fdt_blob = (char *)fdt_data;
535*4882a593Smuzhiyun printf(" Booting using the fdt at 0x%p\n", fdt_blob);
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun if (fdt_check_header(fdt_blob) != 0) {
538*4882a593Smuzhiyun fdt_error("image is not a fdt");
539*4882a593Smuzhiyun goto error;
540*4882a593Smuzhiyun }
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun if (fdt_totalsize(fdt_blob) != fdt_len) {
543*4882a593Smuzhiyun fdt_error("fdt size != image size");
544*4882a593Smuzhiyun goto error;
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun } else {
547*4882a593Smuzhiyun debug("## No Flattened Device Tree\n");
548*4882a593Smuzhiyun goto no_fdt;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun } else {
551*4882a593Smuzhiyun debug("## No Flattened Device Tree\n");
552*4882a593Smuzhiyun goto no_fdt;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun *of_flat_tree = fdt_blob;
556*4882a593Smuzhiyun *of_size = fdt_totalsize(fdt_blob);
557*4882a593Smuzhiyun debug(" of_flat_tree at 0x%08lx size 0x%08lx\n",
558*4882a593Smuzhiyun (ulong)*of_flat_tree, *of_size);
559*4882a593Smuzhiyun
560*4882a593Smuzhiyun return 0;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun no_fdt:
563*4882a593Smuzhiyun ok_no_fdt = 1;
564*4882a593Smuzhiyun error:
565*4882a593Smuzhiyun *of_flat_tree = NULL;
566*4882a593Smuzhiyun *of_size = 0;
567*4882a593Smuzhiyun if (!select && ok_no_fdt) {
568*4882a593Smuzhiyun debug("Continuing to boot without FDT\n");
569*4882a593Smuzhiyun return 0;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun return 1;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun /*
575*4882a593Smuzhiyun * Verify the device tree.
576*4882a593Smuzhiyun *
577*4882a593Smuzhiyun * This function is called after all device tree fix-ups have been enacted,
578*4882a593Smuzhiyun * so that the final device tree can be verified. The definition of "verified"
579*4882a593Smuzhiyun * is up to the specific implementation. However, it generally means that the
580*4882a593Smuzhiyun * addresses of some of the devices in the device tree are compared with the
581*4882a593Smuzhiyun * actual addresses at which U-Boot has placed them.
582*4882a593Smuzhiyun *
583*4882a593Smuzhiyun * Returns 1 on success, 0 on failure. If 0 is returned, U-Boot will halt the
584*4882a593Smuzhiyun * boot process.
585*4882a593Smuzhiyun */
ft_verify_fdt(void * fdt)586*4882a593Smuzhiyun __weak int ft_verify_fdt(void *fdt)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun return 1;
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun
arch_fixup_fdt(void * blob)591*4882a593Smuzhiyun __weak int arch_fixup_fdt(void *blob)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun return 0;
594*4882a593Smuzhiyun }
595*4882a593Smuzhiyun
image_setup_libfdt(bootm_headers_t * images,void * blob,int of_size,struct lmb * lmb)596*4882a593Smuzhiyun int image_setup_libfdt(bootm_headers_t *images, void *blob,
597*4882a593Smuzhiyun int of_size, struct lmb *lmb)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun ulong *initrd_start = &images->initrd_start;
600*4882a593Smuzhiyun ulong *initrd_end = &images->initrd_end;
601*4882a593Smuzhiyun int ret = -EPERM;
602*4882a593Smuzhiyun int fdt_ret;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun if (arch_fixup_fdt(blob) < 0) {
605*4882a593Smuzhiyun printf("ERROR: arch-specific fdt fixup failed\n");
606*4882a593Smuzhiyun goto err;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun #if defined(CONFIG_PASS_DEVICE_SERIAL_BY_FDT)
610*4882a593Smuzhiyun if (fdt_root(blob) < 0) {
611*4882a593Smuzhiyun printf("ERROR: root node setup failed\n");
612*4882a593Smuzhiyun goto err;
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun #endif
615*4882a593Smuzhiyun if (fdt_chosen(blob) < 0) {
616*4882a593Smuzhiyun printf("ERROR: /chosen node create failed\n");
617*4882a593Smuzhiyun goto err;
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun
620*4882a593Smuzhiyun /* Update ethernet nodes */
621*4882a593Smuzhiyun fdt_fixup_ethernet(blob);
622*4882a593Smuzhiyun if (IMAGE_OF_BOARD_SETUP) {
623*4882a593Smuzhiyun fdt_ret = ft_board_setup(blob, gd->bd);
624*4882a593Smuzhiyun if (fdt_ret) {
625*4882a593Smuzhiyun printf("ERROR: board-specific fdt fixup failed: %s\n",
626*4882a593Smuzhiyun fdt_strerror(fdt_ret));
627*4882a593Smuzhiyun goto err;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun if (IMAGE_OF_SYSTEM_SETUP) {
631*4882a593Smuzhiyun fdt_ret = ft_system_setup(blob, gd->bd);
632*4882a593Smuzhiyun if (fdt_ret) {
633*4882a593Smuzhiyun printf("ERROR: system-specific fdt fixup failed: %s\n",
634*4882a593Smuzhiyun fdt_strerror(fdt_ret));
635*4882a593Smuzhiyun goto err;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun /* Delete the old LMB reservation */
640*4882a593Smuzhiyun if (lmb)
641*4882a593Smuzhiyun lmb_free(lmb, (phys_addr_t)(u32)(uintptr_t)blob,
642*4882a593Smuzhiyun (phys_size_t)fdt_totalsize(blob));
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun ret = fdt_shrink_to_minimum(blob, 0);
645*4882a593Smuzhiyun if (ret < 0)
646*4882a593Smuzhiyun goto err;
647*4882a593Smuzhiyun of_size = ret;
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun if (*initrd_start && *initrd_end) {
650*4882a593Smuzhiyun of_size += FDT_RAMDISK_OVERHEAD;
651*4882a593Smuzhiyun fdt_set_totalsize(blob, of_size);
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun /* Create a new LMB reservation */
654*4882a593Smuzhiyun if (lmb)
655*4882a593Smuzhiyun lmb_reserve(lmb, (ulong)blob, of_size);
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun fdt_initrd(blob, *initrd_start, *initrd_end);
658*4882a593Smuzhiyun if (!ft_verify_fdt(blob))
659*4882a593Smuzhiyun goto err;
660*4882a593Smuzhiyun
661*4882a593Smuzhiyun #if defined(CONFIG_SOC_KEYSTONE)
662*4882a593Smuzhiyun if (IMAGE_OF_BOARD_SETUP)
663*4882a593Smuzhiyun ft_board_setup_ex(blob, gd->bd);
664*4882a593Smuzhiyun #endif
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun return 0;
667*4882a593Smuzhiyun err:
668*4882a593Smuzhiyun printf(" - must RESET the board to recover.\n\n");
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun return ret;
671*4882a593Smuzhiyun }
672