diff options
Diffstat (limited to 'drivers/of/fdt.c')
-rw-r--r-- | drivers/of/fdt.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 6852ecf6d1e1..43d236cbc17b 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c | |||
@@ -9,6 +9,8 @@ | |||
9 | * version 2 as published by the Free Software Foundation. | 9 | * version 2 as published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/lmb.h> | ||
12 | #include <linux/of.h> | 14 | #include <linux/of.h> |
13 | #include <linux/of_fdt.h> | 15 | #include <linux/of_fdt.h> |
14 | 16 | ||
@@ -366,3 +368,53 @@ unsigned long __init unflatten_dt_node(unsigned long mem, | |||
366 | *p += 4; | 368 | *p += 4; |
367 | return mem; | 369 | return mem; |
368 | } | 370 | } |
371 | |||
372 | /** | ||
373 | * unflatten_device_tree - create tree of device_nodes from flat blob | ||
374 | * | ||
375 | * unflattens the device-tree passed by the firmware, creating the | ||
376 | * tree of struct device_node. It also fills the "name" and "type" | ||
377 | * pointers of the nodes so the normal device-tree walking functions | ||
378 | * can be used. | ||
379 | */ | ||
380 | void __init unflatten_device_tree(void) | ||
381 | { | ||
382 | unsigned long start, mem, size; | ||
383 | struct device_node **allnextp = &allnodes; | ||
384 | |||
385 | pr_debug(" -> unflatten_device_tree()\n"); | ||
386 | |||
387 | /* First pass, scan for size */ | ||
388 | start = ((unsigned long)initial_boot_params) + | ||
389 | initial_boot_params->off_dt_struct; | ||
390 | size = unflatten_dt_node(0, &start, NULL, NULL, 0); | ||
391 | size = (size | 3) + 1; | ||
392 | |||
393 | pr_debug(" size is %lx, allocating...\n", size); | ||
394 | |||
395 | /* Allocate memory for the expanded device tree */ | ||
396 | mem = lmb_alloc(size + 4, __alignof__(struct device_node)); | ||
397 | mem = (unsigned long) __va(mem); | ||
398 | |||
399 | ((u32 *)mem)[size / 4] = 0xdeadbeef; | ||
400 | |||
401 | pr_debug(" unflattening %lx...\n", mem); | ||
402 | |||
403 | /* Second pass, do actual unflattening */ | ||
404 | start = ((unsigned long)initial_boot_params) + | ||
405 | initial_boot_params->off_dt_struct; | ||
406 | unflatten_dt_node(mem, &start, NULL, &allnextp, 0); | ||
407 | if (*((u32 *)start) != OF_DT_END) | ||
408 | pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start)); | ||
409 | if (((u32 *)mem)[size / 4] != 0xdeadbeef) | ||
410 | pr_warning("End of tree marker overwritten: %08x\n", | ||
411 | ((u32 *)mem)[size / 4]); | ||
412 | *allnextp = NULL; | ||
413 | |||
414 | /* Get pointer to OF "/chosen" node for use everywhere */ | ||
415 | of_chosen = of_find_node_by_path("/chosen"); | ||
416 | if (of_chosen == NULL) | ||
417 | of_chosen = of_find_node_by_path("/chosen@0"); | ||
418 | |||
419 | pr_debug(" <- unflatten_device_tree()\n"); | ||
420 | } | ||