aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of/fdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of/fdt.c')
-rw-r--r--drivers/of/fdt.c430
1 files changed, 272 insertions, 158 deletions
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index c1360e02f921..c787c3d95c60 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -11,10 +11,12 @@
11 11
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/initrd.h> 13#include <linux/initrd.h>
14#include <linux/module.h>
14#include <linux/of.h> 15#include <linux/of.h>
15#include <linux/of_fdt.h> 16#include <linux/of_fdt.h>
16#include <linux/string.h> 17#include <linux/string.h>
17#include <linux/errno.h> 18#include <linux/errno.h>
19#include <linux/slab.h>
18 20
19#ifdef CONFIG_PPC 21#ifdef CONFIG_PPC
20#include <asm/machdep.h> 22#include <asm/machdep.h>
@@ -22,104 +24,19 @@
22 24
23#include <asm/page.h> 25#include <asm/page.h>
24 26
25int __initdata dt_root_addr_cells; 27char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
26int __initdata dt_root_size_cells;
27
28struct boot_param_header *initial_boot_params;
29
30char *find_flat_dt_string(u32 offset)
31{ 28{
32 return ((char *)initial_boot_params) + 29 return ((char *)blob) +
33 be32_to_cpu(initial_boot_params->off_dt_strings) + offset; 30 be32_to_cpu(blob->off_dt_strings) + offset;
34}
35
36/**
37 * of_scan_flat_dt - scan flattened tree blob and call callback on each.
38 * @it: callback function
39 * @data: context data pointer
40 *
41 * This function is used to scan the flattened device-tree, it is
42 * used to extract the memory information at boot before we can
43 * unflatten the tree
44 */
45int __init of_scan_flat_dt(int (*it)(unsigned long node,
46 const char *uname, int depth,
47 void *data),
48 void *data)
49{
50 unsigned long p = ((unsigned long)initial_boot_params) +
51 be32_to_cpu(initial_boot_params->off_dt_struct);
52 int rc = 0;
53 int depth = -1;
54
55 do {
56 u32 tag = be32_to_cpup((__be32 *)p);
57 char *pathp;
58
59 p += 4;
60 if (tag == OF_DT_END_NODE) {
61 depth--;
62 continue;
63 }
64 if (tag == OF_DT_NOP)
65 continue;
66 if (tag == OF_DT_END)
67 break;
68 if (tag == OF_DT_PROP) {
69 u32 sz = be32_to_cpup((__be32 *)p);
70 p += 8;
71 if (be32_to_cpu(initial_boot_params->version) < 0x10)
72 p = ALIGN(p, sz >= 8 ? 8 : 4);
73 p += sz;
74 p = ALIGN(p, 4);
75 continue;
76 }
77 if (tag != OF_DT_BEGIN_NODE) {
78 pr_err("Invalid tag %x in flat device tree!\n", tag);
79 return -EINVAL;
80 }
81 depth++;
82 pathp = (char *)p;
83 p = ALIGN(p + strlen(pathp) + 1, 4);
84 if ((*pathp) == '/') {
85 char *lp, *np;
86 for (lp = NULL, np = pathp; *np; np++)
87 if ((*np) == '/')
88 lp = np+1;
89 if (lp != NULL)
90 pathp = lp;
91 }
92 rc = it(p, pathp, depth, data);
93 if (rc != 0)
94 break;
95 } while (1);
96
97 return rc;
98} 31}
99 32
100/** 33/**
101 * of_get_flat_dt_root - find the root node in the flat blob 34 * of_fdt_get_property - Given a node in the given flat blob, return
35 * the property ptr
102 */ 36 */
103unsigned long __init of_get_flat_dt_root(void) 37void *of_fdt_get_property(struct boot_param_header *blob,
104{ 38 unsigned long node, const char *name,
105 unsigned long p = ((unsigned long)initial_boot_params) + 39 unsigned long *size)
106 be32_to_cpu(initial_boot_params->off_dt_struct);
107
108 while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
109 p += 4;
110 BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
111 p += 4;
112 return ALIGN(p + strlen((char *)p) + 1, 4);
113}
114
115/**
116 * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
117 *
118 * This function can be used within scan_flattened_dt callback to get
119 * access to properties
120 */
121void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
122 unsigned long *size)
123{ 40{
124 unsigned long p = node; 41 unsigned long p = node;
125 42
@@ -137,10 +54,10 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
137 sz = be32_to_cpup((__be32 *)p); 54 sz = be32_to_cpup((__be32 *)p);
138 noff = be32_to_cpup((__be32 *)(p + 4)); 55 noff = be32_to_cpup((__be32 *)(p + 4));
139 p += 8; 56 p += 8;
140 if (be32_to_cpu(initial_boot_params->version) < 0x10) 57 if (be32_to_cpu(blob->version) < 0x10)
141 p = ALIGN(p, sz >= 8 ? 8 : 4); 58 p = ALIGN(p, sz >= 8 ? 8 : 4);
142 59
143 nstr = find_flat_dt_string(noff); 60 nstr = of_fdt_get_string(blob, noff);
144 if (nstr == NULL) { 61 if (nstr == NULL) {
145 pr_warning("Can't find property index name !\n"); 62 pr_warning("Can't find property index name !\n");
146 return NULL; 63 return NULL;
@@ -156,21 +73,28 @@ void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
156} 73}
157 74
158/** 75/**
159 * of_flat_dt_is_compatible - Return true if given node has compat in compatible list 76 * of_fdt_is_compatible - Return true if given node from the given blob has
77 * compat in its compatible list
78 * @blob: A device tree blob
160 * @node: node to test 79 * @node: node to test
161 * @compat: compatible string to compare with compatible list. 80 * @compat: compatible string to compare with compatible list.
81 *
82 * On match, returns a non-zero value with smaller values returned for more
83 * specific compatible values.
162 */ 84 */
163int __init of_flat_dt_is_compatible(unsigned long node, const char *compat) 85int of_fdt_is_compatible(struct boot_param_header *blob,
86 unsigned long node, const char *compat)
164{ 87{
165 const char *cp; 88 const char *cp;
166 unsigned long cplen, l; 89 unsigned long cplen, l, score = 0;
167 90
168 cp = of_get_flat_dt_prop(node, "compatible", &cplen); 91 cp = of_fdt_get_property(blob, node, "compatible", &cplen);
169 if (cp == NULL) 92 if (cp == NULL)
170 return 0; 93 return 0;
171 while (cplen > 0) { 94 while (cplen > 0) {
95 score++;
172 if (of_compat_cmp(cp, compat, strlen(compat)) == 0) 96 if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
173 return 1; 97 return score;
174 l = strlen(cp) + 1; 98 l = strlen(cp) + 1;
175 cp += l; 99 cp += l;
176 cplen -= l; 100 cplen -= l;
@@ -179,7 +103,28 @@ int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
179 return 0; 103 return 0;
180} 104}
181 105
182static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, 106/**
107 * of_fdt_match - Return true if node matches a list of compatible values
108 */
109int of_fdt_match(struct boot_param_header *blob, unsigned long node,
110 const char **compat)
111{
112 unsigned int tmp, score = 0;
113
114 if (!compat)
115 return 0;
116
117 while (*compat) {
118 tmp = of_fdt_is_compatible(blob, node, *compat);
119 if (tmp && (score == 0 || (tmp < score)))
120 score = tmp;
121 compat++;
122 }
123
124 return score;
125}
126
127static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size,
183 unsigned long align) 128 unsigned long align)
184{ 129{
185 void *res; 130 void *res;
@@ -193,16 +138,18 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
193 138
194/** 139/**
195 * unflatten_dt_node - Alloc and populate a device_node from the flat tree 140 * unflatten_dt_node - Alloc and populate a device_node from the flat tree
141 * @blob: The parent device tree blob
196 * @p: pointer to node in flat tree 142 * @p: pointer to node in flat tree
197 * @dad: Parent struct device_node 143 * @dad: Parent struct device_node
198 * @allnextpp: pointer to ->allnext from last allocated device_node 144 * @allnextpp: pointer to ->allnext from last allocated device_node
199 * @fpsize: Size of the node path up at the current depth. 145 * @fpsize: Size of the node path up at the current depth.
200 */ 146 */
201unsigned long __init unflatten_dt_node(unsigned long mem, 147unsigned long unflatten_dt_node(struct boot_param_header *blob,
202 unsigned long *p, 148 unsigned long mem,
203 struct device_node *dad, 149 unsigned long *p,
204 struct device_node ***allnextpp, 150 struct device_node *dad,
205 unsigned long fpsize) 151 struct device_node ***allnextpp,
152 unsigned long fpsize)
206{ 153{
207 struct device_node *np; 154 struct device_node *np;
208 struct property *pp, **prev_pp = NULL; 155 struct property *pp, **prev_pp = NULL;
@@ -298,10 +245,10 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
298 sz = be32_to_cpup((__be32 *)(*p)); 245 sz = be32_to_cpup((__be32 *)(*p));
299 noff = be32_to_cpup((__be32 *)((*p) + 4)); 246 noff = be32_to_cpup((__be32 *)((*p) + 4));
300 *p += 8; 247 *p += 8;
301 if (be32_to_cpu(initial_boot_params->version) < 0x10) 248 if (be32_to_cpu(blob->version) < 0x10)
302 *p = ALIGN(*p, sz >= 8 ? 8 : 4); 249 *p = ALIGN(*p, sz >= 8 ? 8 : 4);
303 250
304 pname = find_flat_dt_string(noff); 251 pname = of_fdt_get_string(blob, noff);
305 if (pname == NULL) { 252 if (pname == NULL) {
306 pr_info("Can't find property name in list !\n"); 253 pr_info("Can't find property name in list !\n");
307 break; 254 break;
@@ -380,7 +327,8 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
380 if (tag == OF_DT_NOP) 327 if (tag == OF_DT_NOP)
381 *p += 4; 328 *p += 4;
382 else 329 else
383 mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); 330 mem = unflatten_dt_node(blob, mem, p, np, allnextpp,
331 fpsize);
384 tag = be32_to_cpup((__be32 *)(*p)); 332 tag = be32_to_cpup((__be32 *)(*p));
385 } 333 }
386 if (tag != OF_DT_END_NODE) { 334 if (tag != OF_DT_END_NODE) {
@@ -391,6 +339,211 @@ unsigned long __init unflatten_dt_node(unsigned long mem,
391 return mem; 339 return mem;
392} 340}
393 341
342/**
343 * __unflatten_device_tree - create tree of device_nodes from flat blob
344 *
345 * unflattens a device-tree, creating the
346 * tree of struct device_node. It also fills the "name" and "type"
347 * pointers of the nodes so the normal device-tree walking functions
348 * can be used.
349 * @blob: The blob to expand
350 * @mynodes: The device_node tree created by the call
351 * @dt_alloc: An allocator that provides a virtual address to memory
352 * for the resulting tree
353 */
354void __unflatten_device_tree(struct boot_param_header *blob,
355 struct device_node **mynodes,
356 void * (*dt_alloc)(u64 size, u64 align))
357{
358 unsigned long start, mem, size;
359 struct device_node **allnextp = mynodes;
360
361 pr_debug(" -> unflatten_device_tree()\n");
362
363 if (!blob) {
364 pr_debug("No device tree pointer\n");
365 return;
366 }
367
368 pr_debug("Unflattening device tree:\n");
369 pr_debug("magic: %08x\n", be32_to_cpu(blob->magic));
370 pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize));
371 pr_debug("version: %08x\n", be32_to_cpu(blob->version));
372
373 if (be32_to_cpu(blob->magic) != OF_DT_HEADER) {
374 pr_err("Invalid device tree blob header\n");
375 return;
376 }
377
378 /* First pass, scan for size */
379 start = ((unsigned long)blob) +
380 be32_to_cpu(blob->off_dt_struct);
381 size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
382 size = (size | 3) + 1;
383
384 pr_debug(" size is %lx, allocating...\n", size);
385
386 /* Allocate memory for the expanded device tree */
387 mem = (unsigned long)
388 dt_alloc(size + 4, __alignof__(struct device_node));
389
390 ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
391
392 pr_debug(" unflattening %lx...\n", mem);
393
394 /* Second pass, do actual unflattening */
395 start = ((unsigned long)blob) +
396 be32_to_cpu(blob->off_dt_struct);
397 unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
398 if (be32_to_cpup((__be32 *)start) != OF_DT_END)
399 pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
400 if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
401 pr_warning("End of tree marker overwritten: %08x\n",
402 be32_to_cpu(((__be32 *)mem)[size / 4]));
403 *allnextp = NULL;
404
405 pr_debug(" <- unflatten_device_tree()\n");
406}
407
408static void *kernel_tree_alloc(u64 size, u64 align)
409{
410 return kzalloc(size, GFP_KERNEL);
411}
412
413/**
414 * of_fdt_unflatten_tree - create tree of device_nodes from flat blob
415 *
416 * unflattens the device-tree passed by the firmware, creating the
417 * tree of struct device_node. It also fills the "name" and "type"
418 * pointers of the nodes so the normal device-tree walking functions
419 * can be used.
420 */
421void of_fdt_unflatten_tree(unsigned long *blob,
422 struct device_node **mynodes)
423{
424 struct boot_param_header *device_tree =
425 (struct boot_param_header *)blob;
426 __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc);
427}
428EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
429
430/* Everything below here references initial_boot_params directly. */
431int __initdata dt_root_addr_cells;
432int __initdata dt_root_size_cells;
433
434struct boot_param_header *initial_boot_params;
435
436#ifdef CONFIG_OF_EARLY_FLATTREE
437
438/**
439 * of_scan_flat_dt - scan flattened tree blob and call callback on each.
440 * @it: callback function
441 * @data: context data pointer
442 *
443 * This function is used to scan the flattened device-tree, it is
444 * used to extract the memory information at boot before we can
445 * unflatten the tree
446 */
447int __init of_scan_flat_dt(int (*it)(unsigned long node,
448 const char *uname, int depth,
449 void *data),
450 void *data)
451{
452 unsigned long p = ((unsigned long)initial_boot_params) +
453 be32_to_cpu(initial_boot_params->off_dt_struct);
454 int rc = 0;
455 int depth = -1;
456
457 do {
458 u32 tag = be32_to_cpup((__be32 *)p);
459 char *pathp;
460
461 p += 4;
462 if (tag == OF_DT_END_NODE) {
463 depth--;
464 continue;
465 }
466 if (tag == OF_DT_NOP)
467 continue;
468 if (tag == OF_DT_END)
469 break;
470 if (tag == OF_DT_PROP) {
471 u32 sz = be32_to_cpup((__be32 *)p);
472 p += 8;
473 if (be32_to_cpu(initial_boot_params->version) < 0x10)
474 p = ALIGN(p, sz >= 8 ? 8 : 4);
475 p += sz;
476 p = ALIGN(p, 4);
477 continue;
478 }
479 if (tag != OF_DT_BEGIN_NODE) {
480 pr_err("Invalid tag %x in flat device tree!\n", tag);
481 return -EINVAL;
482 }
483 depth++;
484 pathp = (char *)p;
485 p = ALIGN(p + strlen(pathp) + 1, 4);
486 if ((*pathp) == '/') {
487 char *lp, *np;
488 for (lp = NULL, np = pathp; *np; np++)
489 if ((*np) == '/')
490 lp = np+1;
491 if (lp != NULL)
492 pathp = lp;
493 }
494 rc = it(p, pathp, depth, data);
495 if (rc != 0)
496 break;
497 } while (1);
498
499 return rc;
500}
501
502/**
503 * of_get_flat_dt_root - find the root node in the flat blob
504 */
505unsigned long __init of_get_flat_dt_root(void)
506{
507 unsigned long p = ((unsigned long)initial_boot_params) +
508 be32_to_cpu(initial_boot_params->off_dt_struct);
509
510 while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
511 p += 4;
512 BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
513 p += 4;
514 return ALIGN(p + strlen((char *)p) + 1, 4);
515}
516
517/**
518 * of_get_flat_dt_prop - Given a node in the flat blob, return the property ptr
519 *
520 * This function can be used within scan_flattened_dt callback to get
521 * access to properties
522 */
523void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
524 unsigned long *size)
525{
526 return of_fdt_get_property(initial_boot_params, node, name, size);
527}
528
529/**
530 * of_flat_dt_is_compatible - Return true if given node has compat in compatible list
531 * @node: node to test
532 * @compat: compatible string to compare with compatible list.
533 */
534int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
535{
536 return of_fdt_is_compatible(initial_boot_params, node, compat);
537}
538
539/**
540 * of_flat_dt_match - Return true if node matches a list of compatible values
541 */
542int __init of_flat_dt_match(unsigned long node, const char **compat)
543{
544 return of_fdt_match(initial_boot_params, node, compat);
545}
546
394#ifdef CONFIG_BLK_DEV_INITRD 547#ifdef CONFIG_BLK_DEV_INITRD
395/** 548/**
396 * early_init_dt_check_for_initrd - Decode initrd location from flat tree 549 * early_init_dt_check_for_initrd - Decode initrd location from flat tree
@@ -539,6 +692,12 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
539 return 1; 692 return 1;
540} 693}
541 694
695static void *__init early_device_tree_alloc(u64 size, u64 align)
696{
697 unsigned long mem = early_init_dt_alloc_memory_arch(size, align);
698 return __va(mem);
699}
700
542/** 701/**
543 * unflatten_device_tree - create tree of device_nodes from flat blob 702 * unflatten_device_tree - create tree of device_nodes from flat blob
544 * 703 *
@@ -549,58 +708,13 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
549 */ 708 */
550void __init unflatten_device_tree(void) 709void __init unflatten_device_tree(void)
551{ 710{
552 unsigned long start, mem, size; 711 __unflatten_device_tree(initial_boot_params, &allnodes,
553 struct device_node **allnextp = &allnodes; 712 early_device_tree_alloc);
554
555 pr_debug(" -> unflatten_device_tree()\n");
556
557 if (!initial_boot_params) {
558 pr_debug("No device tree pointer\n");
559 return;
560 }
561
562 pr_debug("Unflattening device tree:\n");
563 pr_debug("magic: %08x\n", be32_to_cpu(initial_boot_params->magic));
564 pr_debug("size: %08x\n", be32_to_cpu(initial_boot_params->totalsize));
565 pr_debug("version: %08x\n", be32_to_cpu(initial_boot_params->version));
566
567 if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
568 pr_err("Invalid device tree blob header\n");
569 return;
570 }
571
572 /* First pass, scan for size */
573 start = ((unsigned long)initial_boot_params) +
574 be32_to_cpu(initial_boot_params->off_dt_struct);
575 size = unflatten_dt_node(0, &start, NULL, NULL, 0);
576 size = (size | 3) + 1;
577
578 pr_debug(" size is %lx, allocating...\n", size);
579
580 /* Allocate memory for the expanded device tree */
581 mem = early_init_dt_alloc_memory_arch(size + 4,
582 __alignof__(struct device_node));
583 mem = (unsigned long) __va(mem);
584
585 ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
586
587 pr_debug(" unflattening %lx...\n", mem);
588
589 /* Second pass, do actual unflattening */
590 start = ((unsigned long)initial_boot_params) +
591 be32_to_cpu(initial_boot_params->off_dt_struct);
592 unflatten_dt_node(mem, &start, NULL, &allnextp, 0);
593 if (be32_to_cpup((__be32 *)start) != OF_DT_END)
594 pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
595 if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
596 pr_warning("End of tree marker overwritten: %08x\n",
597 be32_to_cpu(((__be32 *)mem)[size / 4]));
598 *allnextp = NULL;
599 713
600 /* Get pointer to OF "/chosen" node for use everywhere */ 714 /* Get pointer to OF "/chosen" node for use everywhere */
601 of_chosen = of_find_node_by_path("/chosen"); 715 of_chosen = of_find_node_by_path("/chosen");
602 if (of_chosen == NULL) 716 if (of_chosen == NULL)
603 of_chosen = of_find_node_by_path("/chosen@0"); 717 of_chosen = of_find_node_by_path("/chosen@0");
604
605 pr_debug(" <- unflatten_device_tree()\n");
606} 718}
719
720#endif /* CONFIG_OF_EARLY_FLATTREE */