1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2007
4  * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
5  *
6  * Copyright 2010-2011 Freescale Semiconductor, Inc.
7  */
8 
9 #include <common.h>
10 #include <abuf.h>
11 #include <env.h>
12 #include <log.h>
13 #include <mapmem.h>
14 #include <net.h>
15 #include <stdio_dev.h>
16 #include <linux/ctype.h>
17 #include <linux/types.h>
18 #include <asm/global_data.h>
19 #include <linux/libfdt.h>
20 #include <fdt_support.h>
21 #include <exports.h>
22 #include <fdtdec.h>
23 #include <version.h>
24 
25 /**
26  * fdt_getprop_u32_default_node - Return a node's property or a default
27  *
28  * @fdt: ptr to device tree
29  * @off: offset of node
30  * @cell: cell offset in property
31  * @prop: property name
32  * @dflt: default value if the property isn't found
33  *
34  * Convenience function to return a node's property or a default value if
35  * the property doesn't exist.
36  */
fdt_getprop_u32_default_node(const void * fdt,int off,int cell,const char * prop,const u32 dflt)37 u32 fdt_getprop_u32_default_node(const void *fdt, int off, int cell,
38 				const char *prop, const u32 dflt)
39 {
40 	const fdt32_t *val;
41 	int len;
42 
43 	val = fdt_getprop(fdt, off, prop, &len);
44 
45 	/* Check if property exists */
46 	if (!val)
47 		return dflt;
48 
49 	/* Check if property is long enough */
50 	if (len < ((cell + 1) * sizeof(uint32_t)))
51 		return dflt;
52 
53 	return fdt32_to_cpu(*val);
54 }
55 
56 /**
57  * fdt_getprop_u32_default - Find a node and return it's property or a default
58  *
59  * @fdt: ptr to device tree
60  * @path: path of node
61  * @prop: property name
62  * @dflt: default value if the property isn't found
63  *
64  * Convenience function to find a node and return it's property or a
65  * default value if it doesn't exist.
66  */
fdt_getprop_u32_default(const void * fdt,const char * path,const char * prop,const u32 dflt)67 u32 fdt_getprop_u32_default(const void *fdt, const char *path,
68 				const char *prop, const u32 dflt)
69 {
70 	int off;
71 
72 	off = fdt_path_offset(fdt, path);
73 	if (off < 0)
74 		return dflt;
75 
76 	return fdt_getprop_u32_default_node(fdt, off, 0, prop, dflt);
77 }
78 
79 /**
80  * fdt_find_and_setprop: Find a node and set it's property
81  *
82  * @fdt: ptr to device tree
83  * @node: path of node
84  * @prop: property name
85  * @val: ptr to new value
86  * @len: length of new property value
87  * @create: flag to create the property if it doesn't exist
88  *
89  * Convenience function to directly set a property given the path to the node.
90  */
fdt_find_and_setprop(void * fdt,const char * node,const char * prop,const void * val,int len,int create)91 int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
92 			 const void *val, int len, int create)
93 {
94 	int nodeoff = fdt_path_offset(fdt, node);
95 
96 	if (nodeoff < 0)
97 		return nodeoff;
98 
99 	if ((!create) && (fdt_get_property(fdt, nodeoff, prop, NULL) == NULL))
100 		return 0; /* create flag not set; so exit quietly */
101 
102 	return fdt_setprop(fdt, nodeoff, prop, val, len);
103 }
104 
105 /**
106  * fdt_find_or_add_subnode() - find or possibly add a subnode of a given node
107  *
108  * @fdt: pointer to the device tree blob
109  * @parentoffset: structure block offset of a node
110  * @name: name of the subnode to locate
111  *
112  * fdt_subnode_offset() finds a subnode of the node with a given name.
113  * If the subnode does not exist, it will be created.
114  */
fdt_find_or_add_subnode(void * fdt,int parentoffset,const char * name)115 int fdt_find_or_add_subnode(void *fdt, int parentoffset, const char *name)
116 {
117 	int offset;
118 
119 	offset = fdt_subnode_offset(fdt, parentoffset, name);
120 
121 	if (offset == -FDT_ERR_NOTFOUND)
122 		offset = fdt_add_subnode(fdt, parentoffset, name);
123 
124 	if (offset < 0)
125 		printf("%s: %s: %s\n", __func__, name, fdt_strerror(offset));
126 
127 	return offset;
128 }
129 
130 #if defined(CONFIG_OF_STDOUT_VIA_ALIAS) && defined(CONFIG_CONS_INDEX)
fdt_fixup_stdout(void * fdt,int chosenoff)131 static int fdt_fixup_stdout(void *fdt, int chosenoff)
132 {
133 	int err;
134 	int aliasoff;
135 	char sername[9] = { 0 };
136 	const void *path;
137 	int len;
138 	char tmp[256]; /* long enough */
139 
140 	sprintf(sername, "serial%d", CONFIG_CONS_INDEX - 1);
141 
142 	aliasoff = fdt_path_offset(fdt, "/aliases");
143 	if (aliasoff < 0) {
144 		err = aliasoff;
145 		goto noalias;
146 	}
147 
148 	path = fdt_getprop(fdt, aliasoff, sername, &len);
149 	if (!path) {
150 		err = len;
151 		goto noalias;
152 	}
153 
154 	/* fdt_setprop may break "path" so we copy it to tmp buffer */
155 	memcpy(tmp, path, len);
156 
157 	err = fdt_setprop(fdt, chosenoff, "linux,stdout-path", tmp, len);
158 	if (err < 0)
159 		printf("WARNING: could not set linux,stdout-path %s.\n",
160 		       fdt_strerror(err));
161 
162 	return err;
163 
164 noalias:
165 	printf("WARNING: %s: could not read %s alias: %s\n",
166 	       __func__, sername, fdt_strerror(err));
167 
168 	return 0;
169 }
170 #else
fdt_fixup_stdout(void * fdt,int chosenoff)171 static int fdt_fixup_stdout(void *fdt, int chosenoff)
172 {
173 	return 0;
174 }
175 #endif
176 
fdt_setprop_uxx(void * fdt,int nodeoffset,const char * name,uint64_t val,int is_u64)177 static inline int fdt_setprop_uxx(void *fdt, int nodeoffset, const char *name,
178 				  uint64_t val, int is_u64)
179 {
180 	if (is_u64)
181 		return fdt_setprop_u64(fdt, nodeoffset, name, val);
182 	else
183 		return fdt_setprop_u32(fdt, nodeoffset, name, (uint32_t)val);
184 }
185 
fdt_root(void * fdt)186 int fdt_root(void *fdt)
187 {
188 	char *serial;
189 	int err;
190 
191 	err = fdt_check_header(fdt);
192 	if (err < 0) {
193 		printf("fdt_root: %s\n", fdt_strerror(err));
194 		return err;
195 	}
196 
197 	serial = env_get("serial#");
198 	if (serial) {
199 		err = fdt_setprop(fdt, 0, "serial-number", serial,
200 				  strlen(serial) + 1);
201 
202 		if (err < 0) {
203 			printf("WARNING: could not set serial-number %s.\n",
204 			       fdt_strerror(err));
205 			return err;
206 		}
207 	}
208 
209 	return 0;
210 }
211 
fdt_initrd(void * fdt,ulong initrd_start,ulong initrd_end)212 int fdt_initrd(void *fdt, ulong initrd_start, ulong initrd_end)
213 {
214 	int   nodeoffset;
215 	int   err, j, total;
216 	int is_u64;
217 	uint64_t addr, size;
218 
219 	/* just return if the size of initrd is zero */
220 	if (initrd_start == initrd_end)
221 		return 0;
222 
223 	/* find or create "/chosen" node. */
224 	nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
225 	if (nodeoffset < 0)
226 		return nodeoffset;
227 
228 	total = fdt_num_mem_rsv(fdt);
229 
230 	/*
231 	 * Look for an existing entry and update it.  If we don't find
232 	 * the entry, we will j be the next available slot.
233 	 */
234 	for (j = 0; j < total; j++) {
235 		err = fdt_get_mem_rsv(fdt, j, &addr, &size);
236 		if (addr == initrd_start) {
237 			fdt_del_mem_rsv(fdt, j);
238 			break;
239 		}
240 	}
241 
242 	err = fdt_add_mem_rsv(fdt, initrd_start, initrd_end - initrd_start);
243 	if (err < 0) {
244 		printf("fdt_initrd: %s\n", fdt_strerror(err));
245 		return err;
246 	}
247 
248 	is_u64 = (fdt_address_cells(fdt, 0) == 2);
249 
250 	err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-start",
251 			      (uint64_t)initrd_start, is_u64);
252 
253 	if (err < 0) {
254 		printf("WARNING: could not set linux,initrd-start %s.\n",
255 		       fdt_strerror(err));
256 		return err;
257 	}
258 
259 	err = fdt_setprop_uxx(fdt, nodeoffset, "linux,initrd-end",
260 			      (uint64_t)initrd_end, is_u64);
261 
262 	if (err < 0) {
263 		printf("WARNING: could not set linux,initrd-end %s.\n",
264 		       fdt_strerror(err));
265 
266 		return err;
267 	}
268 
269 	return 0;
270 }
271 
272 /**
273  * board_fdt_chosen_bootargs - boards may override this function to use
274  *                             alternative kernel command line arguments
275  */
board_fdt_chosen_bootargs(void)276 __weak char *board_fdt_chosen_bootargs(void)
277 {
278 	return env_get("bootargs");
279 }
280 
fdt_chosen(void * fdt)281 int fdt_chosen(void *fdt)
282 {
283 	struct abuf buf = {};
284 	int   nodeoffset;
285 	int   err;
286 	char  *str;		/* used to set string properties */
287 
288 	err = fdt_check_header(fdt);
289 	if (err < 0) {
290 		printf("fdt_chosen: %s\n", fdt_strerror(err));
291 		return err;
292 	}
293 
294 	/* find or create "/chosen" node. */
295 	nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
296 	if (nodeoffset < 0)
297 		return nodeoffset;
298 
299 	if (IS_ENABLED(CONFIG_BOARD_RNG_SEED) && !board_rng_seed(&buf)) {
300 		err = fdt_setprop(fdt, nodeoffset, "rng-seed",
301 				  abuf_data(&buf), abuf_size(&buf));
302 		abuf_uninit(&buf);
303 		if (err < 0) {
304 			printf("WARNING: could not set rng-seed %s.\n",
305 			       fdt_strerror(err));
306 			return err;
307 		}
308 	}
309 
310 	str = board_fdt_chosen_bootargs();
311 
312 	if (str) {
313 		err = fdt_setprop(fdt, nodeoffset, "bootargs", str,
314 				  strlen(str) + 1);
315 		if (err < 0) {
316 			printf("WARNING: could not set bootargs %s.\n",
317 			       fdt_strerror(err));
318 			return err;
319 		}
320 	}
321 
322 	/* add u-boot version */
323 	err = fdt_setprop(fdt, nodeoffset, "u-boot,version", PLAIN_VERSION,
324 			  strlen(PLAIN_VERSION) + 1);
325 	if (err < 0) {
326 		printf("WARNING: could not set u-boot,version %s.\n",
327 		       fdt_strerror(err));
328 		return err;
329 	}
330 
331 	return fdt_fixup_stdout(fdt, nodeoffset);
332 }
333 
do_fixup_by_path(void * fdt,const char * path,const char * prop,const void * val,int len,int create)334 void do_fixup_by_path(void *fdt, const char *path, const char *prop,
335 		      const void *val, int len, int create)
336 {
337 #if defined(DEBUG)
338 	int i;
339 	debug("Updating property '%s/%s' = ", path, prop);
340 	for (i = 0; i < len; i++)
341 		debug(" %.2x", *(u8*)(val+i));
342 	debug("\n");
343 #endif
344 	int rc = fdt_find_and_setprop(fdt, path, prop, val, len, create);
345 	if (rc)
346 		printf("Unable to update property %s:%s, err=%s\n",
347 			path, prop, fdt_strerror(rc));
348 }
349 
do_fixup_by_path_u32(void * fdt,const char * path,const char * prop,u32 val,int create)350 void do_fixup_by_path_u32(void *fdt, const char *path, const char *prop,
351 			  u32 val, int create)
352 {
353 	fdt32_t tmp = cpu_to_fdt32(val);
354 	do_fixup_by_path(fdt, path, prop, &tmp, sizeof(tmp), create);
355 }
356 
do_fixup_by_prop(void * fdt,const char * pname,const void * pval,int plen,const char * prop,const void * val,int len,int create)357 void do_fixup_by_prop(void *fdt,
358 		      const char *pname, const void *pval, int plen,
359 		      const char *prop, const void *val, int len,
360 		      int create)
361 {
362 	int off;
363 #if defined(DEBUG)
364 	int i;
365 	debug("Updating property '%s' = ", prop);
366 	for (i = 0; i < len; i++)
367 		debug(" %.2x", *(u8*)(val+i));
368 	debug("\n");
369 #endif
370 	off = fdt_node_offset_by_prop_value(fdt, -1, pname, pval, plen);
371 	while (off != -FDT_ERR_NOTFOUND) {
372 		if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL))
373 			fdt_setprop(fdt, off, prop, val, len);
374 		off = fdt_node_offset_by_prop_value(fdt, off, pname, pval, plen);
375 	}
376 }
377 
do_fixup_by_prop_u32(void * fdt,const char * pname,const void * pval,int plen,const char * prop,u32 val,int create)378 void do_fixup_by_prop_u32(void *fdt,
379 			  const char *pname, const void *pval, int plen,
380 			  const char *prop, u32 val, int create)
381 {
382 	fdt32_t tmp = cpu_to_fdt32(val);
383 	do_fixup_by_prop(fdt, pname, pval, plen, prop, &tmp, 4, create);
384 }
385 
do_fixup_by_compat(void * fdt,const char * compat,const char * prop,const void * val,int len,int create)386 void do_fixup_by_compat(void *fdt, const char *compat,
387 			const char *prop, const void *val, int len, int create)
388 {
389 	int off = -1;
390 #if defined(DEBUG)
391 	int i;
392 	debug("Updating property '%s' = ", prop);
393 	for (i = 0; i < len; i++)
394 		debug(" %.2x", *(u8*)(val+i));
395 	debug("\n");
396 #endif
397 	fdt_for_each_node_by_compatible(off, fdt, -1, compat)
398 		if (create || (fdt_get_property(fdt, off, prop, NULL) != NULL))
399 			fdt_setprop(fdt, off, prop, val, len);
400 }
401 
do_fixup_by_compat_u32(void * fdt,const char * compat,const char * prop,u32 val,int create)402 void do_fixup_by_compat_u32(void *fdt, const char *compat,
403 			    const char *prop, u32 val, int create)
404 {
405 	fdt32_t tmp = cpu_to_fdt32(val);
406 	do_fixup_by_compat(fdt, compat, prop, &tmp, 4, create);
407 }
408 
409 #ifdef CONFIG_ARCH_FIXUP_FDT_MEMORY
410 /*
411  * fdt_pack_reg - pack address and size array into the "reg"-suitable stream
412  */
fdt_pack_reg(const void * fdt,void * buf,u64 * address,u64 * size,int n)413 static int fdt_pack_reg(const void *fdt, void *buf, u64 *address, u64 *size,
414 			int n)
415 {
416 	int i;
417 	int address_cells = fdt_address_cells(fdt, 0);
418 	int size_cells = fdt_size_cells(fdt, 0);
419 	char *p = buf;
420 
421 	for (i = 0; i < n; i++) {
422 		if (address_cells == 2)
423 			*(fdt64_t *)p = cpu_to_fdt64(address[i]);
424 		else
425 			*(fdt32_t *)p = cpu_to_fdt32(address[i]);
426 		p += 4 * address_cells;
427 
428 		if (size_cells == 2)
429 			*(fdt64_t *)p = cpu_to_fdt64(size[i]);
430 		else
431 			*(fdt32_t *)p = cpu_to_fdt32(size[i]);
432 		p += 4 * size_cells;
433 	}
434 
435 	return p - (char *)buf;
436 }
437 
438 #if CONFIG_NR_DRAM_BANKS > 4
439 #define MEMORY_BANKS_MAX CONFIG_NR_DRAM_BANKS
440 #else
441 #define MEMORY_BANKS_MAX 4
442 #endif
443 
444 /**
445  * fdt_fixup_memory_banks - Update DT memory node
446  * @blob: Pointer to DT blob
447  * @start: Pointer to memory start addresses array
448  * @size: Pointer to memory sizes array
449  * @banks: Number of memory banks
450  *
451  * Return: 0 on success, negative value on failure
452  *
453  * Based on the passed number of banks and arrays, the function is able to
454  * update existing DT memory nodes to match run time detected/changed memory
455  * configuration. Implementation is handling one specific case with only one
456  * memory node where multiple tuples could be added/updated.
457  * The case where multiple memory nodes with a single tuple (base, size) are
458  * used, this function is only updating the first memory node without removing
459  * others.
460  */
fdt_fixup_memory_banks(void * blob,u64 start[],u64 size[],int banks)461 int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
462 {
463 	int err, nodeoffset;
464 	int len, i;
465 	u8 tmp[MEMORY_BANKS_MAX * 16]; /* Up to 64-bit address + 64-bit size */
466 
467 	if (banks > MEMORY_BANKS_MAX) {
468 		printf("%s: num banks %d exceeds hardcoded limit %d."
469 		       " Recompile with higher MEMORY_BANKS_MAX?\n",
470 		       __FUNCTION__, banks, MEMORY_BANKS_MAX);
471 		return -1;
472 	}
473 
474 	err = fdt_check_header(blob);
475 	if (err < 0) {
476 		printf("%s: %s\n", __FUNCTION__, fdt_strerror(err));
477 		return err;
478 	}
479 
480 	/* find or create "/memory" node. */
481 	nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory");
482 	if (nodeoffset < 0)
483 			return nodeoffset;
484 
485 	err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
486 			sizeof("memory"));
487 	if (err < 0) {
488 		printf("WARNING: could not set %s %s.\n", "device_type",
489 				fdt_strerror(err));
490 		return err;
491 	}
492 
493 	for (i = 0; i < banks; i++) {
494 		if (start[i] == 0 && size[i] == 0)
495 			break;
496 	}
497 
498 	banks = i;
499 
500 	if (!banks)
501 		return 0;
502 
503 	len = fdt_pack_reg(blob, tmp, start, size, banks);
504 
505 	err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
506 	if (err < 0) {
507 		printf("WARNING: could not set %s %s.\n",
508 				"reg", fdt_strerror(err));
509 		return err;
510 	}
511 	return 0;
512 }
513 
fdt_set_usable_memory(void * blob,u64 start[],u64 size[],int areas)514 int fdt_set_usable_memory(void *blob, u64 start[], u64 size[], int areas)
515 {
516 	int err, nodeoffset;
517 	int len;
518 	u8 tmp[8 * 16]; /* Up to 64-bit address + 64-bit size */
519 
520 	if (areas > 8) {
521 		printf("%s: num areas %d exceeds hardcoded limit %d\n",
522 		       __func__, areas, 8);
523 		return -1;
524 	}
525 
526 	err = fdt_check_header(blob);
527 	if (err < 0) {
528 		printf("%s: %s\n", __func__, fdt_strerror(err));
529 		return err;
530 	}
531 
532 	/* find or create "/memory" node. */
533 	nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory");
534 	if (nodeoffset < 0)
535 		return nodeoffset;
536 
537 	len = fdt_pack_reg(blob, tmp, start, size, areas);
538 
539 	err = fdt_setprop(blob, nodeoffset, "linux,usable-memory", tmp, len);
540 	if (err < 0) {
541 		printf("WARNING: could not set %s %s.\n",
542 		       "reg", fdt_strerror(err));
543 		return err;
544 	}
545 
546 	return 0;
547 }
548 #endif
549 
fdt_fixup_memory(void * blob,u64 start,u64 size)550 int fdt_fixup_memory(void *blob, u64 start, u64 size)
551 {
552 	return fdt_fixup_memory_banks(blob, &start, &size, 1);
553 }
554 
fdt_fixup_ethernet(void * fdt)555 void fdt_fixup_ethernet(void *fdt)
556 {
557 	int i = 0, j, prop;
558 	char *tmp, *end;
559 	char mac[16];
560 	const char *path;
561 	unsigned char mac_addr[ARP_HLEN];
562 	int offset;
563 #ifdef FDT_SEQ_MACADDR_FROM_ENV
564 	int nodeoff;
565 	const struct fdt_property *fdt_prop;
566 #endif
567 
568 	if (fdt_path_offset(fdt, "/aliases") < 0)
569 		return;
570 
571 	/* Cycle through all aliases */
572 	for (prop = 0; ; prop++) {
573 		const char *name;
574 
575 		/* FDT might have been edited, recompute the offset */
576 		offset = fdt_first_property_offset(fdt,
577 			fdt_path_offset(fdt, "/aliases"));
578 		/* Select property number 'prop' */
579 		for (j = 0; j < prop; j++)
580 			offset = fdt_next_property_offset(fdt, offset);
581 
582 		if (offset < 0)
583 			break;
584 
585 		path = fdt_getprop_by_offset(fdt, offset, &name, NULL);
586 		if (!strncmp(name, "ethernet", 8)) {
587 			/* Treat plain "ethernet" same as "ethernet0". */
588 			if (!strcmp(name, "ethernet")
589 #ifdef FDT_SEQ_MACADDR_FROM_ENV
590 			 || !strcmp(name, "ethernet0")
591 #endif
592 			)
593 				i = 0;
594 #ifndef FDT_SEQ_MACADDR_FROM_ENV
595 			else
596 				i = trailing_strtol(name);
597 #endif
598 			if (i != -1) {
599 				if (i == 0)
600 					strcpy(mac, "ethaddr");
601 				else
602 					sprintf(mac, "eth%daddr", i);
603 			} else {
604 				continue;
605 			}
606 #ifdef FDT_SEQ_MACADDR_FROM_ENV
607 			nodeoff = fdt_path_offset(fdt, path);
608 			fdt_prop = fdt_get_property(fdt, nodeoff, "status",
609 						    NULL);
610 			if (fdt_prop && !strcmp(fdt_prop->data, "disabled"))
611 				continue;
612 			i++;
613 #endif
614 			tmp = env_get(mac);
615 			if (!tmp)
616 				continue;
617 
618 			for (j = 0; j < 6; j++) {
619 				mac_addr[j] = tmp ?
620 					      hextoul(tmp, &end) : 0;
621 				if (tmp)
622 					tmp = (*end) ? end + 1 : end;
623 			}
624 
625 			do_fixup_by_path(fdt, path, "mac-address",
626 					 &mac_addr, 6, 0);
627 			do_fixup_by_path(fdt, path, "local-mac-address",
628 					 &mac_addr, 6, 1);
629 		}
630 	}
631 }
632 
fdt_record_loadable(void * blob,u32 index,const char * name,uintptr_t load_addr,u32 size,uintptr_t entry_point,const char * type,const char * os,const char * arch)633 int fdt_record_loadable(void *blob, u32 index, const char *name,
634 			uintptr_t load_addr, u32 size, uintptr_t entry_point,
635 			const char *type, const char *os, const char *arch)
636 {
637 	int err, node;
638 
639 	err = fdt_check_header(blob);
640 	if (err < 0) {
641 		printf("%s: %s\n", __func__, fdt_strerror(err));
642 		return err;
643 	}
644 
645 	/* find or create "/fit-images" node */
646 	node = fdt_find_or_add_subnode(blob, 0, "fit-images");
647 	if (node < 0)
648 		return node;
649 
650 	/* find or create "/fit-images/<name>" node */
651 	node = fdt_find_or_add_subnode(blob, node, name);
652 	if (node < 0)
653 		return node;
654 
655 	fdt_setprop_u64(blob, node, "load", load_addr);
656 	if (entry_point != -1)
657 		fdt_setprop_u64(blob, node, "entry", entry_point);
658 	fdt_setprop_u32(blob, node, "size", size);
659 	if (type)
660 		fdt_setprop_string(blob, node, "type", type);
661 	if (os)
662 		fdt_setprop_string(blob, node, "os", os);
663 	if (arch)
664 		fdt_setprop_string(blob, node, "arch", arch);
665 
666 	return node;
667 }
668 
669 /* Resize the fdt to its actual size + a bit of padding */
fdt_shrink_to_minimum(void * blob,uint extrasize)670 int fdt_shrink_to_minimum(void *blob, uint extrasize)
671 {
672 	int i;
673 	uint64_t addr, size;
674 	int total, ret;
675 	uint actualsize;
676 	int fdt_memrsv = 0;
677 
678 	if (!blob)
679 		return 0;
680 
681 	total = fdt_num_mem_rsv(blob);
682 	for (i = 0; i < total; i++) {
683 		fdt_get_mem_rsv(blob, i, &addr, &size);
684 		if (addr == (uintptr_t)blob) {
685 			fdt_del_mem_rsv(blob, i);
686 			fdt_memrsv = 1;
687 			break;
688 		}
689 	}
690 
691 	/*
692 	 * Calculate the actual size of the fdt
693 	 * plus the size needed for 5 fdt_add_mem_rsv, one
694 	 * for the fdt itself and 4 for a possible initrd
695 	 * ((initrd-start + initrd-end) * 2 (name & value))
696 	 */
697 	actualsize = fdt_off_dt_strings(blob) +
698 		fdt_size_dt_strings(blob) + 5 * sizeof(struct fdt_reserve_entry);
699 
700 	actualsize += extrasize;
701 	/* Make it so the fdt ends on a page boundary */
702 	actualsize = ALIGN(actualsize + ((uintptr_t)blob & 0xfff), 0x1000);
703 	actualsize = actualsize - ((uintptr_t)blob & 0xfff);
704 
705 	/* Change the fdt header to reflect the correct size */
706 	fdt_set_totalsize(blob, actualsize);
707 
708 	if (fdt_memrsv) {
709 		/* Add the new reservation */
710 		ret = fdt_add_mem_rsv(blob, map_to_sysmem(blob), actualsize);
711 		if (ret < 0)
712 			return ret;
713 	}
714 
715 	return actualsize;
716 }
717 
718 /**
719  * fdt_delete_disabled_nodes: Delete all nodes with status == "disabled"
720  *
721  * @blob: ptr to device tree
722  */
fdt_delete_disabled_nodes(void * blob)723 int fdt_delete_disabled_nodes(void *blob)
724 {
725 	while (1) {
726 		int ret, offset;
727 
728 		offset = fdt_node_offset_by_prop_value(blob, -1, "status",
729 						       "disabled", 9);
730 		if (offset < 0)
731 			break;
732 
733 		ret = fdt_del_node(blob, offset);
734 		if (ret < 0)
735 			return ret;
736 	}
737 
738 	return 0;
739 }
740 
741 #ifdef CONFIG_PCI
742 #define CFG_SYS_PCI_NR_INBOUND_WIN 4
743 
744 #define FDT_PCI_PREFETCH	(0x40000000)
745 #define FDT_PCI_MEM32		(0x02000000)
746 #define FDT_PCI_IO		(0x01000000)
747 #define FDT_PCI_MEM64		(0x03000000)
748 
fdt_pci_dma_ranges(void * blob,int phb_off,struct pci_controller * hose)749 int fdt_pci_dma_ranges(void *blob, int phb_off, struct pci_controller *hose) {
750 
751 	int addrcell, sizecell, len, r;
752 	u32 *dma_range;
753 	/* sized based on pci addr cells, size-cells, & address-cells */
754 	u32 dma_ranges[(3 + 2 + 2) * CFG_SYS_PCI_NR_INBOUND_WIN];
755 
756 	addrcell = fdt_getprop_u32_default(blob, "/", "#address-cells", 1);
757 	sizecell = fdt_getprop_u32_default(blob, "/", "#size-cells", 1);
758 
759 	dma_range = &dma_ranges[0];
760 	for (r = 0; r < hose->region_count; r++) {
761 		u64 bus_start, phys_start, size;
762 
763 		/* skip if !PCI_REGION_SYS_MEMORY */
764 		if (!(hose->regions[r].flags & PCI_REGION_SYS_MEMORY))
765 			continue;
766 
767 		bus_start = (u64)hose->regions[r].bus_start;
768 		phys_start = (u64)hose->regions[r].phys_start;
769 		size = (u64)hose->regions[r].size;
770 
771 		dma_range[0] = 0;
772 		if (size >= 0x100000000ull)
773 			dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM64);
774 		else
775 			dma_range[0] |= cpu_to_fdt32(FDT_PCI_MEM32);
776 		if (hose->regions[r].flags & PCI_REGION_PREFETCH)
777 			dma_range[0] |= cpu_to_fdt32(FDT_PCI_PREFETCH);
778 #ifdef CONFIG_SYS_PCI_64BIT
779 		dma_range[1] = cpu_to_fdt32(bus_start >> 32);
780 #else
781 		dma_range[1] = 0;
782 #endif
783 		dma_range[2] = cpu_to_fdt32(bus_start & 0xffffffff);
784 
785 		if (addrcell == 2) {
786 			dma_range[3] = cpu_to_fdt32(phys_start >> 32);
787 			dma_range[4] = cpu_to_fdt32(phys_start & 0xffffffff);
788 		} else {
789 			dma_range[3] = cpu_to_fdt32(phys_start & 0xffffffff);
790 		}
791 
792 		if (sizecell == 2) {
793 			dma_range[3 + addrcell + 0] =
794 				cpu_to_fdt32(size >> 32);
795 			dma_range[3 + addrcell + 1] =
796 				cpu_to_fdt32(size & 0xffffffff);
797 		} else {
798 			dma_range[3 + addrcell + 0] =
799 				cpu_to_fdt32(size & 0xffffffff);
800 		}
801 
802 		dma_range += (3 + addrcell + sizecell);
803 	}
804 
805 	len = dma_range - &dma_ranges[0];
806 	if (len)
807 		fdt_setprop(blob, phb_off, "dma-ranges", &dma_ranges[0], len*4);
808 
809 	return 0;
810 }
811 #endif
812 
fdt_increase_size(void * fdt,int add_len)813 int fdt_increase_size(void *fdt, int add_len)
814 {
815 	int newlen;
816 
817 	newlen = fdt_totalsize(fdt) + add_len;
818 
819 	/* Open in place with a new len */
820 	return fdt_open_into(fdt, fdt, newlen);
821 }
822 
823 #ifdef CONFIG_FDT_FIXUP_PARTITIONS
824 #include <jffs2/load_kernel.h>
825 #include <mtd_node.h>
826 
fdt_del_subnodes(const void * blob,int parent_offset)827 static int fdt_del_subnodes(const void *blob, int parent_offset)
828 {
829 	int off, ndepth;
830 	int ret;
831 
832 	for (ndepth = 0, off = fdt_next_node(blob, parent_offset, &ndepth);
833 	     (off >= 0) && (ndepth > 0);
834 	     off = fdt_next_node(blob, off, &ndepth)) {
835 		if (ndepth == 1) {
836 			debug("delete %s: offset: %x\n",
837 				fdt_get_name(blob, off, 0), off);
838 			ret = fdt_del_node((void *)blob, off);
839 			if (ret < 0) {
840 				printf("Can't delete node: %s\n",
841 					fdt_strerror(ret));
842 				return ret;
843 			} else {
844 				ndepth = 0;
845 				off = parent_offset;
846 			}
847 		}
848 	}
849 	return 0;
850 }
851 
fdt_del_partitions(void * blob,int parent_offset)852 static int fdt_del_partitions(void *blob, int parent_offset)
853 {
854 	const void *prop;
855 	int ndepth = 0;
856 	int off;
857 	int ret;
858 
859 	off = fdt_next_node(blob, parent_offset, &ndepth);
860 	if (off > 0 && ndepth == 1) {
861 		prop = fdt_getprop(blob, off, "label", NULL);
862 		if (prop == NULL) {
863 			/*
864 			 * Could not find label property, nand {}; node?
865 			 * Check subnode, delete partitions there if any.
866 			 */
867 			return fdt_del_partitions(blob, off);
868 		} else {
869 			ret = fdt_del_subnodes(blob, parent_offset);
870 			if (ret < 0) {
871 				printf("Can't remove subnodes: %s\n",
872 					fdt_strerror(ret));
873 				return ret;
874 			}
875 		}
876 	}
877 	return 0;
878 }
879 
fdt_node_set_part_info(void * blob,int parent_offset,struct mtd_device * dev)880 static int fdt_node_set_part_info(void *blob, int parent_offset,
881 				  struct mtd_device *dev)
882 {
883 	struct list_head *pentry;
884 	struct part_info *part;
885 	int off, ndepth = 0;
886 	int part_num, ret;
887 	int sizecell;
888 	char buf[64];
889 
890 	ret = fdt_del_partitions(blob, parent_offset);
891 	if (ret < 0)
892 		return ret;
893 
894 	/*
895 	 * Check if size/address is 1 or 2 cells.
896 	 * We assume #address-cells and #size-cells have same value.
897 	 */
898 	sizecell = fdt_getprop_u32_default_node(blob, parent_offset,
899 						0, "#size-cells", 1);
900 
901 	/*
902 	 * Check if it is nand {}; subnode, adjust
903 	 * the offset in this case
904 	 */
905 	off = fdt_next_node(blob, parent_offset, &ndepth);
906 	if (off > 0 && ndepth == 1)
907 		parent_offset = off;
908 
909 	part_num = 0;
910 	list_for_each_prev(pentry, &dev->parts) {
911 		int newoff;
912 
913 		part = list_entry(pentry, struct part_info, link);
914 
915 		debug("%2d: %-20s0x%08llx\t0x%08llx\t%d\n",
916 			part_num, part->name, part->size,
917 			part->offset, part->mask_flags);
918 
919 		sprintf(buf, "partition@%llx", part->offset);
920 add_sub:
921 		ret = fdt_add_subnode(blob, parent_offset, buf);
922 		if (ret == -FDT_ERR_NOSPACE) {
923 			ret = fdt_increase_size(blob, 512);
924 			if (!ret)
925 				goto add_sub;
926 			else
927 				goto err_size;
928 		} else if (ret < 0) {
929 			printf("Can't add partition node: %s\n",
930 				fdt_strerror(ret));
931 			return ret;
932 		}
933 		newoff = ret;
934 
935 		/* Check MTD_WRITEABLE_CMD flag */
936 		if (part->mask_flags & 1) {
937 add_ro:
938 			ret = fdt_setprop(blob, newoff, "read_only", NULL, 0);
939 			if (ret == -FDT_ERR_NOSPACE) {
940 				ret = fdt_increase_size(blob, 512);
941 				if (!ret)
942 					goto add_ro;
943 				else
944 					goto err_size;
945 			} else if (ret < 0)
946 				goto err_prop;
947 		}
948 
949 add_reg:
950 		if (sizecell == 2) {
951 			ret = fdt_setprop_u64(blob, newoff,
952 					      "reg", part->offset);
953 			if (!ret)
954 				ret = fdt_appendprop_u64(blob, newoff,
955 							 "reg", part->size);
956 		} else {
957 			ret = fdt_setprop_u32(blob, newoff,
958 					      "reg", part->offset);
959 			if (!ret)
960 				ret = fdt_appendprop_u32(blob, newoff,
961 							 "reg", part->size);
962 		}
963 
964 		if (ret == -FDT_ERR_NOSPACE) {
965 			ret = fdt_increase_size(blob, 512);
966 			if (!ret)
967 				goto add_reg;
968 			else
969 				goto err_size;
970 		} else if (ret < 0)
971 			goto err_prop;
972 
973 add_label:
974 		ret = fdt_setprop_string(blob, newoff, "label", part->name);
975 		if (ret == -FDT_ERR_NOSPACE) {
976 			ret = fdt_increase_size(blob, 512);
977 			if (!ret)
978 				goto add_label;
979 			else
980 				goto err_size;
981 		} else if (ret < 0)
982 			goto err_prop;
983 
984 		part_num++;
985 	}
986 	return 0;
987 err_size:
988 	printf("Can't increase blob size: %s\n", fdt_strerror(ret));
989 	return ret;
990 err_prop:
991 	printf("Can't add property: %s\n", fdt_strerror(ret));
992 	return ret;
993 }
994 
995 /*
996  * Update partitions in nor/nand nodes using info from
997  * mtdparts environment variable. The nodes to update are
998  * specified by node_info structure which contains mtd device
999  * type and compatible string: E. g. the board code in
1000  * ft_board_setup() could use:
1001  *
1002  *	struct node_info nodes[] = {
1003  *		{ "fsl,mpc5121-nfc",    MTD_DEV_TYPE_NAND, },
1004  *		{ "cfi-flash",          MTD_DEV_TYPE_NOR,  },
1005  *	};
1006  *
1007  *	fdt_fixup_mtdparts(blob, nodes, ARRAY_SIZE(nodes));
1008  */
fdt_fixup_mtdparts(void * blob,const struct node_info * node_info,int node_info_size)1009 void fdt_fixup_mtdparts(void *blob, const struct node_info *node_info,
1010 			int node_info_size)
1011 {
1012 	struct mtd_device *dev;
1013 	int i, idx;
1014 	int noff, parts;
1015 	bool inited = false;
1016 
1017 	for (i = 0; i < node_info_size; i++) {
1018 		idx = 0;
1019 
1020 		fdt_for_each_node_by_compatible(noff, blob, -1,
1021 						node_info[i].compat) {
1022 			const char *prop;
1023 
1024 			prop = fdt_getprop(blob, noff, "status", NULL);
1025 			if (prop && !strcmp(prop, "disabled"))
1026 				continue;
1027 
1028 			debug("%s: %s, mtd dev type %d\n",
1029 				fdt_get_name(blob, noff, 0),
1030 				node_info[i].compat, node_info[i].type);
1031 
1032 			if (!inited) {
1033 				if (mtdparts_init() != 0)
1034 					return;
1035 				inited = true;
1036 			}
1037 
1038 			dev = device_find(node_info[i].type, idx++);
1039 			if (dev) {
1040 				parts = fdt_subnode_offset(blob, noff,
1041 							   "partitions");
1042 				if (parts < 0)
1043 					parts = noff;
1044 
1045 				if (fdt_node_set_part_info(blob, parts, dev))
1046 					return; /* return on error */
1047 			}
1048 		}
1049 	}
1050 }
1051 #endif
1052 
fdt_del_node_and_alias(void * blob,const char * alias)1053 void fdt_del_node_and_alias(void *blob, const char *alias)
1054 {
1055 	int off = fdt_path_offset(blob, alias);
1056 
1057 	if (off < 0)
1058 		return;
1059 
1060 	fdt_del_node(blob, off);
1061 
1062 	off = fdt_path_offset(blob, "/aliases");
1063 	fdt_delprop(blob, off, alias);
1064 }
1065 
1066 /* Max address size we deal with */
1067 #define OF_MAX_ADDR_CELLS	4
1068 #define OF_BAD_ADDR	FDT_ADDR_T_NONE
1069 #define OF_CHECK_COUNTS(na, ns)	((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
1070 			(ns) > 0)
1071 
1072 /* Debug utility */
1073 #ifdef DEBUG
of_dump_addr(const char * s,const fdt32_t * addr,int na)1074 static void of_dump_addr(const char *s, const fdt32_t *addr, int na)
1075 {
1076 	printf("%s", s);
1077 	while(na--)
1078 		printf(" %08x", *(addr++));
1079 	printf("\n");
1080 }
1081 #else
of_dump_addr(const char * s,const fdt32_t * addr,int na)1082 static void of_dump_addr(const char *s, const fdt32_t *addr, int na) { }
1083 #endif
1084 
1085 /**
1086  * struct of_bus - Callbacks for bus specific translators
1087  * @name:	A string used to identify this bus in debug output.
1088  * @addresses:	The name of the DT property from which addresses are
1089  *		to be read, typically "reg".
1090  * @match:	Return non-zero if the node whose parent is at
1091  *		parentoffset in the FDT blob corresponds to a bus
1092  *		of this type, otherwise return zero. If NULL a match
1093  *		is assumed.
1094  * @count_cells:Count how many cells (be32 values) a node whose parent
1095  *		is at parentoffset in the FDT blob will require to
1096  *		represent its address (written to *addrc) & size
1097  *		(written to *sizec).
1098  * @map:	Map the address addr from the address space of this
1099  *		bus to that of its parent, making use of the ranges
1100  *		read from DT to an array at range. na and ns are the
1101  *		number of cells (be32 values) used to hold and address
1102  *		or size, respectively, for this bus. pna is the number
1103  *		of cells used to hold an address for the parent bus.
1104  *		Returns the address in the address space of the parent
1105  *		bus.
1106  * @translate:	Update the value of the address cells at addr within an
1107  *		FDT by adding offset to it. na specifies the number of
1108  *		cells used to hold the address being translated. Returns
1109  *		zero on success, non-zero on error.
1110  *
1111  * Each bus type will include a struct of_bus in the of_busses array,
1112  * providing implementations of some or all of the functions used to
1113  * match the bus & handle address translation for its children.
1114  */
1115 struct of_bus {
1116 	const char	*name;
1117 	const char	*addresses;
1118 	int		(*match)(const void *blob, int parentoffset);
1119 	void		(*count_cells)(const void *blob, int parentoffset,
1120 				int *addrc, int *sizec);
1121 	u64		(*map)(fdt32_t *addr, const fdt32_t *range,
1122 				int na, int ns, int pna);
1123 	int		(*translate)(fdt32_t *addr, u64 offset, int na);
1124 };
1125 
1126 /* Default translator (generic bus) */
fdt_support_default_count_cells(const void * blob,int parentoffset,int * addrc,int * sizec)1127 void fdt_support_default_count_cells(const void *blob, int parentoffset,
1128 					int *addrc, int *sizec)
1129 {
1130 	const fdt32_t *prop;
1131 
1132 	if (addrc)
1133 		*addrc = fdt_address_cells(blob, parentoffset);
1134 
1135 	if (sizec) {
1136 		prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL);
1137 		if (prop)
1138 			*sizec = be32_to_cpup(prop);
1139 		else
1140 			*sizec = 1;
1141 	}
1142 }
1143 
of_bus_default_map(fdt32_t * addr,const fdt32_t * range,int na,int ns,int pna)1144 static u64 of_bus_default_map(fdt32_t *addr, const fdt32_t *range,
1145 		int na, int ns, int pna)
1146 {
1147 	u64 cp, s, da;
1148 
1149 	cp = fdt_read_number(range, na);
1150 	s  = fdt_read_number(range + na + pna, ns);
1151 	da = fdt_read_number(addr, na);
1152 
1153 	debug("OF: default map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
1154 
1155 	if (da < cp || da >= (cp + s))
1156 		return OF_BAD_ADDR;
1157 	return da - cp;
1158 }
1159 
of_bus_default_translate(fdt32_t * addr,u64 offset,int na)1160 static int of_bus_default_translate(fdt32_t *addr, u64 offset, int na)
1161 {
1162 	u64 a = fdt_read_number(addr, na);
1163 	memset(addr, 0, na * 4);
1164 	a += offset;
1165 	if (na > 1)
1166 		addr[na - 2] = cpu_to_fdt32(a >> 32);
1167 	addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu);
1168 
1169 	return 0;
1170 }
1171 
1172 #ifdef CONFIG_OF_ISA_BUS
1173 
1174 /* ISA bus translator */
of_bus_isa_match(const void * blob,int parentoffset)1175 static int of_bus_isa_match(const void *blob, int parentoffset)
1176 {
1177 	const char *name;
1178 
1179 	name = fdt_get_name(blob, parentoffset, NULL);
1180 	if (!name)
1181 		return 0;
1182 
1183 	return !strcmp(name, "isa");
1184 }
1185 
of_bus_isa_count_cells(const void * blob,int parentoffset,int * addrc,int * sizec)1186 static void of_bus_isa_count_cells(const void *blob, int parentoffset,
1187 				   int *addrc, int *sizec)
1188 {
1189 	if (addrc)
1190 		*addrc = 2;
1191 	if (sizec)
1192 		*sizec = 1;
1193 }
1194 
of_bus_isa_map(fdt32_t * addr,const fdt32_t * range,int na,int ns,int pna)1195 static u64 of_bus_isa_map(fdt32_t *addr, const fdt32_t *range,
1196 			  int na, int ns, int pna)
1197 {
1198 	u64 cp, s, da;
1199 
1200 	/* Check address type match */
1201 	if ((addr[0] ^ range[0]) & cpu_to_be32(1))
1202 		return OF_BAD_ADDR;
1203 
1204 	cp = fdt_read_number(range + 1, na - 1);
1205 	s  = fdt_read_number(range + na + pna, ns);
1206 	da = fdt_read_number(addr + 1, na - 1);
1207 
1208 	debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n", cp, s, da);
1209 
1210 	if (da < cp || da >= (cp + s))
1211 		return OF_BAD_ADDR;
1212 	return da - cp;
1213 }
1214 
of_bus_isa_translate(fdt32_t * addr,u64 offset,int na)1215 static int of_bus_isa_translate(fdt32_t *addr, u64 offset, int na)
1216 {
1217 	return of_bus_default_translate(addr + 1, offset, na - 1);
1218 }
1219 
1220 #endif /* CONFIG_OF_ISA_BUS */
1221 
1222 /* Array of bus specific translators */
1223 static struct of_bus of_busses[] = {
1224 #ifdef CONFIG_OF_ISA_BUS
1225 	/* ISA */
1226 	{
1227 		.name = "isa",
1228 		.addresses = "reg",
1229 		.match = of_bus_isa_match,
1230 		.count_cells = of_bus_isa_count_cells,
1231 		.map = of_bus_isa_map,
1232 		.translate = of_bus_isa_translate,
1233 	},
1234 #endif /* CONFIG_OF_ISA_BUS */
1235 	/* Default */
1236 	{
1237 		.name = "default",
1238 		.addresses = "reg",
1239 		.count_cells = fdt_support_default_count_cells,
1240 		.map = of_bus_default_map,
1241 		.translate = of_bus_default_translate,
1242 	},
1243 };
1244 
of_match_bus(const void * blob,int parentoffset)1245 static struct of_bus *of_match_bus(const void *blob, int parentoffset)
1246 {
1247 	struct of_bus *bus;
1248 
1249 	if (ARRAY_SIZE(of_busses) == 1)
1250 		return of_busses;
1251 
1252 	for (bus = of_busses; bus; bus++) {
1253 		if (!bus->match || bus->match(blob, parentoffset))
1254 			return bus;
1255 	}
1256 
1257 	/*
1258 	 * We should always have matched the default bus at least, since
1259 	 * it has a NULL match field. If we didn't then it somehow isn't
1260 	 * in the of_busses array or something equally catastrophic has
1261 	 * gone wrong.
1262 	 */
1263 	assert(0);
1264 	return NULL;
1265 }
1266 
of_translate_one(const void * blob,int parent,struct of_bus * bus,struct of_bus * pbus,fdt32_t * addr,int na,int ns,int pna,const char * rprop)1267 static int of_translate_one(const void *blob, int parent, struct of_bus *bus,
1268 			    struct of_bus *pbus, fdt32_t *addr,
1269 			    int na, int ns, int pna, const char *rprop)
1270 {
1271 	const fdt32_t *ranges;
1272 	int rlen;
1273 	int rone;
1274 	u64 offset = OF_BAD_ADDR;
1275 
1276 	/* Normally, an absence of a "ranges" property means we are
1277 	 * crossing a non-translatable boundary, and thus the addresses
1278 	 * below the current not cannot be converted to CPU physical ones.
1279 	 * Unfortunately, while this is very clear in the spec, it's not
1280 	 * what Apple understood, and they do have things like /uni-n or
1281 	 * /ht nodes with no "ranges" property and a lot of perfectly
1282 	 * useable mapped devices below them. Thus we treat the absence of
1283 	 * "ranges" as equivalent to an empty "ranges" property which means
1284 	 * a 1:1 translation at that level. It's up to the caller not to try
1285 	 * to translate addresses that aren't supposed to be translated in
1286 	 * the first place. --BenH.
1287 	 */
1288 	ranges = fdt_getprop(blob, parent, rprop, &rlen);
1289 	if (ranges == NULL || rlen == 0) {
1290 		offset = fdt_read_number(addr, na);
1291 		memset(addr, 0, pna * 4);
1292 		debug("OF: no ranges, 1:1 translation\n");
1293 		goto finish;
1294 	}
1295 
1296 	debug("OF: walking ranges...\n");
1297 
1298 	/* Now walk through the ranges */
1299 	rlen /= 4;
1300 	rone = na + pna + ns;
1301 	for (; rlen >= rone; rlen -= rone, ranges += rone) {
1302 		offset = bus->map(addr, ranges, na, ns, pna);
1303 		if (offset != OF_BAD_ADDR)
1304 			break;
1305 	}
1306 	if (offset == OF_BAD_ADDR) {
1307 		debug("OF: not found !\n");
1308 		return 1;
1309 	}
1310 	memcpy(addr, ranges + na, 4 * pna);
1311 
1312  finish:
1313 	of_dump_addr("OF: parent translation for:", addr, pna);
1314 	debug("OF: with offset: %llu\n", offset);
1315 
1316 	/* Translate it into parent bus space */
1317 	return pbus->translate(addr, offset, pna);
1318 }
1319 
1320 /*
1321  * Translate an address from the device-tree into a CPU physical address,
1322  * this walks up the tree and applies the various bus mappings on the
1323  * way.
1324  *
1325  * Note: We consider that crossing any level with #size-cells == 0 to mean
1326  * that translation is impossible (that is we are not dealing with a value
1327  * that can be mapped to a cpu physical address). This is not really specified
1328  * that way, but this is traditionally the way IBM at least do things
1329  */
__of_translate_address(const void * blob,int node_offset,const fdt32_t * in_addr,const char * rprop)1330 static u64 __of_translate_address(const void *blob, int node_offset,
1331 				  const fdt32_t *in_addr, const char *rprop)
1332 {
1333 	int parent;
1334 	struct of_bus *bus, *pbus;
1335 	fdt32_t addr[OF_MAX_ADDR_CELLS];
1336 	int na, ns, pna, pns;
1337 	u64 result = OF_BAD_ADDR;
1338 
1339 	debug("OF: ** translation for device %s **\n",
1340 		fdt_get_name(blob, node_offset, NULL));
1341 
1342 	/* Get parent & match bus type */
1343 	parent = fdt_parent_offset(blob, node_offset);
1344 	if (parent < 0)
1345 		goto bail;
1346 	bus = of_match_bus(blob, parent);
1347 
1348 	/* Cound address cells & copy address locally */
1349 	bus->count_cells(blob, parent, &na, &ns);
1350 	if (!OF_CHECK_COUNTS(na, ns)) {
1351 		printf("%s: Bad cell count for %s\n", __FUNCTION__,
1352 		       fdt_get_name(blob, node_offset, NULL));
1353 		goto bail;
1354 	}
1355 	memcpy(addr, in_addr, na * 4);
1356 
1357 	debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
1358 	    bus->name, na, ns, fdt_get_name(blob, parent, NULL));
1359 	of_dump_addr("OF: translating address:", addr, na);
1360 
1361 	/* Translate */
1362 	for (;;) {
1363 		/* Switch to parent bus */
1364 		node_offset = parent;
1365 		parent = fdt_parent_offset(blob, node_offset);
1366 
1367 		/* If root, we have finished */
1368 		if (parent < 0) {
1369 			debug("OF: reached root node\n");
1370 			result = fdt_read_number(addr, na);
1371 			break;
1372 		}
1373 
1374 		/* Get new parent bus and counts */
1375 		pbus = of_match_bus(blob, parent);
1376 		pbus->count_cells(blob, parent, &pna, &pns);
1377 		if (!OF_CHECK_COUNTS(pna, pns)) {
1378 			printf("%s: Bad cell count for %s\n", __FUNCTION__,
1379 				fdt_get_name(blob, node_offset, NULL));
1380 			break;
1381 		}
1382 
1383 		debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
1384 		    pbus->name, pna, pns, fdt_get_name(blob, parent, NULL));
1385 
1386 		/* Apply bus translation */
1387 		if (of_translate_one(blob, node_offset, bus, pbus,
1388 					addr, na, ns, pna, rprop))
1389 			break;
1390 
1391 		/* Complete the move up one level */
1392 		na = pna;
1393 		ns = pns;
1394 		bus = pbus;
1395 
1396 		of_dump_addr("OF: one level translation:", addr, na);
1397 	}
1398  bail:
1399 
1400 	return result;
1401 }
1402 
fdt_translate_address(const void * blob,int node_offset,const fdt32_t * in_addr)1403 u64 fdt_translate_address(const void *blob, int node_offset,
1404 			  const fdt32_t *in_addr)
1405 {
1406 	return __of_translate_address(blob, node_offset, in_addr, "ranges");
1407 }
1408 
fdt_translate_dma_address(const void * blob,int node_offset,const fdt32_t * in_addr)1409 u64 fdt_translate_dma_address(const void *blob, int node_offset,
1410 			      const fdt32_t *in_addr)
1411 {
1412 	return __of_translate_address(blob, node_offset, in_addr, "dma-ranges");
1413 }
1414 
fdt_get_dma_range(const void * blob,int node,phys_addr_t * cpu,dma_addr_t * bus,u64 * size)1415 int fdt_get_dma_range(const void *blob, int node, phys_addr_t *cpu,
1416 		      dma_addr_t *bus, u64 *size)
1417 {
1418 	bool found_dma_ranges = false;
1419 	struct of_bus *bus_node;
1420 	const fdt32_t *ranges;
1421 	int na, ns, pna, pns;
1422 	int parent = node;
1423 	int ret = 0;
1424 	int len;
1425 
1426 	/* Find the closest dma-ranges property */
1427 	while (parent >= 0) {
1428 		ranges = fdt_getprop(blob, parent, "dma-ranges", &len);
1429 
1430 		/* Ignore empty ranges, they imply no translation required */
1431 		if (ranges && len > 0)
1432 			break;
1433 
1434 		/* Once we find 'dma-ranges', then a missing one is an error */
1435 		if (found_dma_ranges && !ranges) {
1436 			ret = -EINVAL;
1437 			goto out;
1438 		}
1439 
1440 		if (ranges)
1441 			found_dma_ranges = true;
1442 
1443 		parent = fdt_parent_offset(blob, parent);
1444 	}
1445 
1446 	if (!ranges || parent < 0) {
1447 		debug("no dma-ranges found for node %s\n",
1448 		      fdt_get_name(blob, node, NULL));
1449 		ret = -ENOENT;
1450 		goto out;
1451 	}
1452 
1453 	/* switch to that node */
1454 	node = parent;
1455 	parent = fdt_parent_offset(blob, node);
1456 	if (parent < 0) {
1457 		printf("Found dma-ranges in root node, shouldn't happen\n");
1458 		ret = -EINVAL;
1459 		goto out;
1460 	}
1461 
1462 	/* Get the address sizes both for the bus and its parent */
1463 	bus_node = of_match_bus(blob, node);
1464 	bus_node->count_cells(blob, node, &na, &ns);
1465 	if (!OF_CHECK_COUNTS(na, ns)) {
1466 		printf("%s: Bad cell count for %s\n", __FUNCTION__,
1467 		       fdt_get_name(blob, node, NULL));
1468 		return -EINVAL;
1469 		goto out;
1470 	}
1471 
1472 	bus_node = of_match_bus(blob, parent);
1473 	bus_node->count_cells(blob, parent, &pna, &pns);
1474 	if (!OF_CHECK_COUNTS(pna, pns)) {
1475 		printf("%s: Bad cell count for %s\n", __FUNCTION__,
1476 		       fdt_get_name(blob, parent, NULL));
1477 		return -EINVAL;
1478 		goto out;
1479 	}
1480 
1481 	*bus = fdt_read_number(ranges, na);
1482 	*cpu = fdt_translate_dma_address(blob, node, ranges + na);
1483 	*size = fdt_read_number(ranges + na + pna, ns);
1484 out:
1485 	return ret;
1486 }
1487 
1488 /**
1489  * fdt_node_offset_by_compat_reg: Find a node that matches compatible and
1490  * who's reg property matches a physical cpu address
1491  *
1492  * @blob: ptr to device tree
1493  * @compat: compatible string to match
1494  * @compat_off: property name
1495  *
1496  */
fdt_node_offset_by_compat_reg(void * blob,const char * compat,phys_addr_t compat_off)1497 int fdt_node_offset_by_compat_reg(void *blob, const char *compat,
1498 					phys_addr_t compat_off)
1499 {
1500 	int len, off;
1501 
1502 	fdt_for_each_node_by_compatible(off, blob, -1, compat) {
1503 		const fdt32_t *reg = fdt_getprop(blob, off, "reg", &len);
1504 		if (reg && compat_off == fdt_translate_address(blob, off, reg))
1505 			return off;
1506 	}
1507 
1508 	return -FDT_ERR_NOTFOUND;
1509 }
1510 
vnode_offset_by_pathf(void * blob,const char * fmt,va_list ap)1511 static int vnode_offset_by_pathf(void *blob, const char *fmt, va_list ap)
1512 {
1513 	char path[512];
1514 	int len;
1515 
1516 	len = vsnprintf(path, sizeof(path), fmt, ap);
1517 	if (len < 0 || len + 1 > sizeof(path))
1518 		return -FDT_ERR_NOSPACE;
1519 
1520 	return fdt_path_offset(blob, path);
1521 }
1522 
1523 /**
1524  * fdt_node_offset_by_pathf: Find node offset by sprintf formatted path
1525  *
1526  * @blob: ptr to device tree
1527  * @fmt: path format
1528  * @ap: vsnprintf arguments
1529  */
fdt_node_offset_by_pathf(void * blob,const char * fmt,...)1530 int fdt_node_offset_by_pathf(void *blob, const char *fmt, ...)
1531 {
1532 	va_list ap;
1533 	int res;
1534 
1535 	va_start(ap, fmt);
1536 	res = vnode_offset_by_pathf(blob, fmt, ap);
1537 	va_end(ap);
1538 
1539 	return res;
1540 }
1541 
1542 /*
1543  * fdt_set_phandle: Create a phandle property for the given node
1544  *
1545  * @fdt: ptr to device tree
1546  * @nodeoffset: node to update
1547  * @phandle: phandle value to set (must be unique)
1548  */
fdt_set_phandle(void * fdt,int nodeoffset,uint32_t phandle)1549 int fdt_set_phandle(void *fdt, int nodeoffset, uint32_t phandle)
1550 {
1551 	int ret;
1552 
1553 #ifdef DEBUG
1554 	int off = fdt_node_offset_by_phandle(fdt, phandle);
1555 
1556 	if ((off >= 0) && (off != nodeoffset)) {
1557 		char buf[64];
1558 
1559 		fdt_get_path(fdt, nodeoffset, buf, sizeof(buf));
1560 		printf("Trying to update node %s with phandle %u ",
1561 		       buf, phandle);
1562 
1563 		fdt_get_path(fdt, off, buf, sizeof(buf));
1564 		printf("that already exists in node %s.\n", buf);
1565 		return -FDT_ERR_BADPHANDLE;
1566 	}
1567 #endif
1568 
1569 	ret = fdt_setprop_cell(fdt, nodeoffset, "phandle", phandle);
1570 
1571 	return ret;
1572 }
1573 
1574 /*
1575  * fdt_create_phandle: Get or create a phandle property for the given node
1576  *
1577  * @fdt: ptr to device tree
1578  * @nodeoffset: node to update
1579  */
fdt_create_phandle(void * fdt,int nodeoffset)1580 unsigned int fdt_create_phandle(void *fdt, int nodeoffset)
1581 {
1582 	/* see if there is a phandle already */
1583 	uint32_t phandle = fdt_get_phandle(fdt, nodeoffset);
1584 
1585 	/* if we got 0, means no phandle so create one */
1586 	if (phandle == 0) {
1587 		int ret;
1588 
1589 		ret = fdt_generate_phandle(fdt, &phandle);
1590 		if (ret < 0) {
1591 			printf("Can't generate phandle: %s\n",
1592 			       fdt_strerror(ret));
1593 			return 0;
1594 		}
1595 
1596 		ret = fdt_set_phandle(fdt, nodeoffset, phandle);
1597 		if (ret < 0) {
1598 			printf("Can't set phandle %u: %s\n", phandle,
1599 			       fdt_strerror(ret));
1600 			return 0;
1601 		}
1602 	}
1603 
1604 	return phandle;
1605 }
1606 
1607 /**
1608  * fdt_create_phandle_by_compatible: Get or create a phandle for first node with
1609  *				     given compatible
1610  *
1611  * @fdt: ptr to device tree
1612  * @compat: node's compatible string
1613  */
fdt_create_phandle_by_compatible(void * fdt,const char * compat)1614 unsigned int fdt_create_phandle_by_compatible(void *fdt, const char *compat)
1615 {
1616 	int offset = fdt_node_offset_by_compatible(fdt, -1, compat);
1617 
1618 	if (offset < 0) {
1619 		printf("Can't find node with compatible \"%s\": %s\n", compat,
1620 		       fdt_strerror(offset));
1621 		return 0;
1622 	}
1623 
1624 	return fdt_create_phandle(fdt, offset);
1625 }
1626 
1627 /**
1628  * fdt_create_phandle_by_pathf: Get or create a phandle for node given by
1629  *				sprintf-formatted path
1630  *
1631  * @fdt: ptr to device tree
1632  * @fmt, ...: path format string and arguments to pass to sprintf
1633  */
fdt_create_phandle_by_pathf(void * fdt,const char * fmt,...)1634 unsigned int fdt_create_phandle_by_pathf(void *fdt, const char *fmt, ...)
1635 {
1636 	va_list ap;
1637 	int offset;
1638 
1639 	va_start(ap, fmt);
1640 	offset = vnode_offset_by_pathf(fdt, fmt, ap);
1641 	va_end(ap);
1642 
1643 	if (offset < 0) {
1644 		printf("Can't find node by given path: %s\n",
1645 		       fdt_strerror(offset));
1646 		return 0;
1647 	}
1648 
1649 	return fdt_create_phandle(fdt, offset);
1650 }
1651 
1652 /*
1653  * fdt_set_node_status: Set status for the given node
1654  *
1655  * @fdt: ptr to device tree
1656  * @nodeoffset: node to update
1657  * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL
1658  */
fdt_set_node_status(void * fdt,int nodeoffset,enum fdt_status status)1659 int fdt_set_node_status(void *fdt, int nodeoffset, enum fdt_status status)
1660 {
1661 	int ret = 0;
1662 
1663 	if (nodeoffset < 0)
1664 		return nodeoffset;
1665 
1666 	switch (status) {
1667 	case FDT_STATUS_OKAY:
1668 		ret = fdt_setprop_string(fdt, nodeoffset, "status", "okay");
1669 		break;
1670 	case FDT_STATUS_DISABLED:
1671 		ret = fdt_setprop_string(fdt, nodeoffset, "status", "disabled");
1672 		break;
1673 	case FDT_STATUS_FAIL:
1674 		ret = fdt_setprop_string(fdt, nodeoffset, "status", "fail");
1675 		break;
1676 	default:
1677 		printf("Invalid fdt status: %x\n", status);
1678 		ret = -1;
1679 		break;
1680 	}
1681 
1682 	return ret;
1683 }
1684 
1685 /*
1686  * fdt_set_status_by_alias: Set status for the given node given an alias
1687  *
1688  * @fdt: ptr to device tree
1689  * @alias: alias of node to update
1690  * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL
1691  */
fdt_set_status_by_alias(void * fdt,const char * alias,enum fdt_status status)1692 int fdt_set_status_by_alias(void *fdt, const char* alias,
1693 			    enum fdt_status status)
1694 {
1695 	int offset = fdt_path_offset(fdt, alias);
1696 
1697 	return fdt_set_node_status(fdt, offset, status);
1698 }
1699 
1700 /**
1701  * fdt_set_status_by_compatible: Set node status for first node with given
1702  *				 compatible
1703  *
1704  * @fdt: ptr to device tree
1705  * @compat: node's compatible string
1706  * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL
1707  */
fdt_set_status_by_compatible(void * fdt,const char * compat,enum fdt_status status)1708 int fdt_set_status_by_compatible(void *fdt, const char *compat,
1709 				 enum fdt_status status)
1710 {
1711 	int offset = fdt_node_offset_by_compatible(fdt, -1, compat);
1712 
1713 	if (offset < 0)
1714 		return offset;
1715 
1716 	return fdt_set_node_status(fdt, offset, status);
1717 }
1718 
1719 /**
1720  * fdt_set_status_by_pathf: Set node status for node given by sprintf-formatted
1721  *			    path
1722  *
1723  * @fdt: ptr to device tree
1724  * @status: FDT_STATUS_OKAY, FDT_STATUS_DISABLED, FDT_STATUS_FAIL
1725  * @fmt, ...: path format string and arguments to pass to sprintf
1726  */
fdt_set_status_by_pathf(void * fdt,enum fdt_status status,const char * fmt,...)1727 int fdt_set_status_by_pathf(void *fdt, enum fdt_status status, const char *fmt,
1728 			    ...)
1729 {
1730 	va_list ap;
1731 	int offset;
1732 
1733 	va_start(ap, fmt);
1734 	offset = vnode_offset_by_pathf(fdt, fmt, ap);
1735 	va_end(ap);
1736 
1737 	if (offset < 0)
1738 		return offset;
1739 
1740 	return fdt_set_node_status(fdt, offset, status);
1741 }
1742 
1743 /*
1744  * Verify the physical address of device tree node for a given alias
1745  *
1746  * This function locates the device tree node of a given alias, and then
1747  * verifies that the physical address of that device matches the given
1748  * parameter.  It displays a message if there is a mismatch.
1749  *
1750  * Returns 1 on success, 0 on failure
1751  */
fdt_verify_alias_address(void * fdt,int anode,const char * alias,u64 addr)1752 int fdt_verify_alias_address(void *fdt, int anode, const char *alias, u64 addr)
1753 {
1754 	const char *path;
1755 	const fdt32_t *reg;
1756 	int node, len;
1757 	u64 dt_addr;
1758 
1759 	path = fdt_getprop(fdt, anode, alias, NULL);
1760 	if (!path) {
1761 		/* If there's no such alias, then it's not a failure */
1762 		return 1;
1763 	}
1764 
1765 	node = fdt_path_offset(fdt, path);
1766 	if (node < 0) {
1767 		printf("Warning: device tree alias '%s' points to invalid "
1768 		       "node %s.\n", alias, path);
1769 		return 0;
1770 	}
1771 
1772 	reg = fdt_getprop(fdt, node, "reg", &len);
1773 	if (!reg) {
1774 		printf("Warning: device tree node '%s' has no address.\n",
1775 		       path);
1776 		return 0;
1777 	}
1778 
1779 	dt_addr = fdt_translate_address(fdt, node, reg);
1780 	if (addr != dt_addr) {
1781 		printf("Warning: U-Boot configured device %s at address %llu,\n"
1782 		       "but the device tree has it address %llx.\n",
1783 		       alias, addr, dt_addr);
1784 		return 0;
1785 	}
1786 
1787 	return 1;
1788 }
1789 
1790 /*
1791  * Returns the base address of an SOC or PCI node
1792  */
fdt_get_base_address(const void * fdt,int node)1793 u64 fdt_get_base_address(const void *fdt, int node)
1794 {
1795 	int size;
1796 	const fdt32_t *prop;
1797 
1798 	prop = fdt_getprop(fdt, node, "reg", &size);
1799 
1800 	return prop ? fdt_translate_address(fdt, node, prop) : OF_BAD_ADDR;
1801 }
1802 
1803 /*
1804  * Read a property of size <prop_len>. Currently only supports 1 or 2 cells,
1805  * or 3 cells specially for a PCI address.
1806  */
fdt_read_prop(const fdt32_t * prop,int prop_len,int cell_off,uint64_t * val,int cells)1807 static int fdt_read_prop(const fdt32_t *prop, int prop_len, int cell_off,
1808 			 uint64_t *val, int cells)
1809 {
1810 	const fdt32_t *prop32;
1811 	const unaligned_fdt64_t *prop64;
1812 
1813 	if ((cell_off + cells) > prop_len)
1814 		return -FDT_ERR_NOSPACE;
1815 
1816 	prop32 = &prop[cell_off];
1817 
1818 	/*
1819 	 * Special handling for PCI address in PCI bus <ranges>
1820 	 *
1821 	 * PCI child address is made up of 3 cells. Advance the cell offset
1822 	 * by 1 so that the PCI child address can be correctly read.
1823 	 */
1824 	if (cells == 3)
1825 		cell_off += 1;
1826 	prop64 = (const fdt64_t *)&prop[cell_off];
1827 
1828 	switch (cells) {
1829 	case 1:
1830 		*val = fdt32_to_cpu(*prop32);
1831 		break;
1832 	case 2:
1833 	case 3:
1834 		*val = fdt64_to_cpu(*prop64);
1835 		break;
1836 	default:
1837 		return -FDT_ERR_NOSPACE;
1838 	}
1839 
1840 	return 0;
1841 }
1842 
1843 /**
1844  * fdt_read_range - Read a node's n'th range property
1845  *
1846  * @fdt: ptr to device tree
1847  * @node: offset of node
1848  * @n: range index
1849  * @child_addr: pointer to storage for the "child address" field
1850  * @addr: pointer to storage for the CPU view translated physical start
1851  * @len: pointer to storage for the range length
1852  *
1853  * Convenience function that reads and interprets a specific range out of
1854  * a number of the "ranges" property array.
1855  */
fdt_read_range(void * fdt,int node,int n,uint64_t * child_addr,uint64_t * addr,uint64_t * len)1856 int fdt_read_range(void *fdt, int node, int n, uint64_t *child_addr,
1857 		   uint64_t *addr, uint64_t *len)
1858 {
1859 	int pnode = fdt_parent_offset(fdt, node);
1860 	const fdt32_t *ranges;
1861 	int pacells;
1862 	int acells;
1863 	int scells;
1864 	int ranges_len;
1865 	int cell = 0;
1866 	int r = 0;
1867 
1868 	/*
1869 	 * The "ranges" property is an array of
1870 	 * { <child address> <parent address> <size in child address space> }
1871 	 *
1872 	 * All 3 elements can span a diffent number of cells. Fetch their size.
1873 	 */
1874 	pacells = fdt_getprop_u32_default_node(fdt, pnode, 0, "#address-cells", 1);
1875 	acells = fdt_getprop_u32_default_node(fdt, node, 0, "#address-cells", 1);
1876 	scells = fdt_getprop_u32_default_node(fdt, node, 0, "#size-cells", 1);
1877 
1878 	/* Now try to get the ranges property */
1879 	ranges = fdt_getprop(fdt, node, "ranges", &ranges_len);
1880 	if (!ranges)
1881 		return -FDT_ERR_NOTFOUND;
1882 	ranges_len /= sizeof(uint32_t);
1883 
1884 	/* Jump to the n'th entry */
1885 	cell = n * (pacells + acells + scells);
1886 
1887 	/* Read <child address> */
1888 	if (child_addr) {
1889 		r = fdt_read_prop(ranges, ranges_len, cell, child_addr,
1890 				  acells);
1891 		if (r)
1892 			return r;
1893 	}
1894 	cell += acells;
1895 
1896 	/* Read <parent address> */
1897 	if (addr)
1898 		*addr = fdt_translate_address(fdt, node, ranges + cell);
1899 	cell += pacells;
1900 
1901 	/* Read <size in child address space> */
1902 	if (len) {
1903 		r = fdt_read_prop(ranges, ranges_len, cell, len, scells);
1904 		if (r)
1905 			return r;
1906 	}
1907 
1908 	return 0;
1909 }
1910 
1911 /**
1912  * fdt_setup_simplefb_node - Fill and enable a simplefb node
1913  *
1914  * @fdt: ptr to device tree
1915  * @node: offset of the simplefb node
1916  * @base_address: framebuffer base address
1917  * @width: width in pixels
1918  * @height: height in pixels
1919  * @stride: bytes per line
1920  * @format: pixel format string
1921  *
1922  * Convenience function to fill and enable a simplefb node.
1923  */
fdt_setup_simplefb_node(void * fdt,int node,u64 base_address,u32 width,u32 height,u32 stride,const char * format)1924 int fdt_setup_simplefb_node(void *fdt, int node, u64 base_address, u32 width,
1925 			    u32 height, u32 stride, const char *format)
1926 {
1927 	char name[32];
1928 	fdt32_t cells[4];
1929 	int i, addrc, sizec, ret;
1930 
1931 	fdt_support_default_count_cells(fdt, fdt_parent_offset(fdt, node),
1932 					&addrc, &sizec);
1933 	i = 0;
1934 	if (addrc == 2)
1935 		cells[i++] = cpu_to_fdt32(base_address >> 32);
1936 	cells[i++] = cpu_to_fdt32(base_address);
1937 	if (sizec == 2)
1938 		cells[i++] = 0;
1939 	cells[i++] = cpu_to_fdt32(height * stride);
1940 
1941 	ret = fdt_setprop(fdt, node, "reg", cells, sizeof(cells[0]) * i);
1942 	if (ret < 0)
1943 		return ret;
1944 
1945 	snprintf(name, sizeof(name), "framebuffer@%llx", base_address);
1946 	ret = fdt_set_name(fdt, node, name);
1947 	if (ret < 0)
1948 		return ret;
1949 
1950 	ret = fdt_setprop_u32(fdt, node, "width", width);
1951 	if (ret < 0)
1952 		return ret;
1953 
1954 	ret = fdt_setprop_u32(fdt, node, "height", height);
1955 	if (ret < 0)
1956 		return ret;
1957 
1958 	ret = fdt_setprop_u32(fdt, node, "stride", stride);
1959 	if (ret < 0)
1960 		return ret;
1961 
1962 	ret = fdt_setprop_string(fdt, node, "format", format);
1963 	if (ret < 0)
1964 		return ret;
1965 
1966 	ret = fdt_setprop_string(fdt, node, "status", "okay");
1967 	if (ret < 0)
1968 		return ret;
1969 
1970 	return 0;
1971 }
1972 
1973 /*
1974  * Update native-mode in display-timings from display environment variable.
1975  * The node to update are specified by path.
1976  */
fdt_fixup_display(void * blob,const char * path,const char * display)1977 int fdt_fixup_display(void *blob, const char *path, const char *display)
1978 {
1979 	int off, toff;
1980 
1981 	if (!display || !path)
1982 		return -FDT_ERR_NOTFOUND;
1983 
1984 	toff = fdt_path_offset(blob, path);
1985 	if (toff >= 0)
1986 		toff = fdt_subnode_offset(blob, toff, "display-timings");
1987 	if (toff < 0)
1988 		return toff;
1989 
1990 	for (off = fdt_first_subnode(blob, toff);
1991 	     off >= 0;
1992 	     off = fdt_next_subnode(blob, off)) {
1993 		uint32_t h = fdt_get_phandle(blob, off);
1994 		debug("%s:0x%x\n", fdt_get_name(blob, off, NULL),
1995 		      fdt32_to_cpu(h));
1996 		if (strcasecmp(fdt_get_name(blob, off, NULL), display) == 0)
1997 			return fdt_setprop_u32(blob, toff, "native-mode", h);
1998 	}
1999 	return toff;
2000 }
2001 
2002 #ifdef CONFIG_OF_LIBFDT_OVERLAY
2003 /**
2004  * fdt_overlay_apply_verbose - Apply an overlay with verbose error reporting
2005  *
2006  * @fdt: ptr to device tree
2007  * @fdto: ptr to device tree overlay
2008  *
2009  * Convenience function to apply an overlay and display helpful messages
2010  * in the case of an error
2011  */
fdt_overlay_apply_verbose(void * fdt,void * fdto)2012 int fdt_overlay_apply_verbose(void *fdt, void *fdto)
2013 {
2014 	int err;
2015 	bool has_symbols;
2016 
2017 	err = fdt_path_offset(fdt, "/__symbols__");
2018 	has_symbols = err >= 0;
2019 
2020 	err = fdt_overlay_apply(fdt, fdto);
2021 	if (err < 0) {
2022 		printf("failed on fdt_overlay_apply(): %s\n",
2023 				fdt_strerror(err));
2024 		if (!has_symbols) {
2025 			printf("base fdt does did not have a /__symbols__ node\n");
2026 			printf("make sure you've compiled with -@\n");
2027 		}
2028 	}
2029 	return err;
2030 }
2031 #endif
2032 
2033 /**
2034  * fdt_valid() - Check if an FDT is valid. If not, change it to NULL
2035  *
2036  * @blobp: Pointer to FDT pointer
2037  * Return: 1 if OK, 0 if bad (in which case *blobp is set to NULL)
2038  */
fdt_valid(struct fdt_header ** blobp)2039 int fdt_valid(struct fdt_header **blobp)
2040 {
2041 	const void *blob = *blobp;
2042 	int err;
2043 
2044 	if (!blob) {
2045 		printf("The address of the fdt is invalid (NULL).\n");
2046 		return 0;
2047 	}
2048 
2049 	err = fdt_check_header(blob);
2050 	if (err == 0)
2051 		return 1;	/* valid */
2052 
2053 	if (err < 0) {
2054 		printf("libfdt fdt_check_header(): %s", fdt_strerror(err));
2055 		/*
2056 		 * Be more informative on bad version.
2057 		 */
2058 		if (err == -FDT_ERR_BADVERSION) {
2059 			if (fdt_version(blob) <
2060 			    FDT_FIRST_SUPPORTED_VERSION) {
2061 				printf(" - too old, fdt %d < %d",
2062 				       fdt_version(blob),
2063 				       FDT_FIRST_SUPPORTED_VERSION);
2064 			}
2065 			if (fdt_last_comp_version(blob) >
2066 			    FDT_LAST_SUPPORTED_VERSION) {
2067 				printf(" - too new, fdt %d > %d",
2068 				       fdt_version(blob),
2069 				       FDT_LAST_SUPPORTED_VERSION);
2070 			}
2071 		}
2072 		printf("\n");
2073 		*blobp = NULL;
2074 		return 0;
2075 	}
2076 	return 1;
2077 }
2078