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