Commit | Line | Data |
---|---|---|
9eb8f674 GL |
1 | /* |
2 | * linux/arch/arm/kernel/devtree.c | |
3 | * | |
4 | * Copyright (C) 2009 Canonical Ltd. <jeremy.kerr@canonical.com> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 as | |
8 | * published by the Free Software Foundation. | |
9 | */ | |
10 | ||
11 | #include <linux/init.h> | |
ecea4ab6 | 12 | #include <linux/export.h> |
9eb8f674 GL |
13 | #include <linux/errno.h> |
14 | #include <linux/types.h> | |
15 | #include <linux/bootmem.h> | |
16 | #include <linux/memblock.h> | |
17 | #include <linux/of.h> | |
18 | #include <linux/of_fdt.h> | |
19 | #include <linux/of_irq.h> | |
20 | #include <linux/of_platform.h> | |
21 | ||
22 | #include <asm/setup.h> | |
23 | #include <asm/page.h> | |
93c02ab4 GL |
24 | #include <asm/mach/arch.h> |
25 | #include <asm/mach-types.h> | |
9eb8f674 GL |
26 | |
27 | void __init early_init_dt_add_memory_arch(u64 base, u64 size) | |
28 | { | |
29 | arm_add_memory(base, size); | |
30 | } | |
31 | ||
32 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) | |
33 | { | |
34 | return alloc_bootmem_align(size, align); | |
35 | } | |
36 | ||
93c02ab4 GL |
37 | void __init arm_dt_memblock_reserve(void) |
38 | { | |
39 | u64 *reserve_map, base, size; | |
40 | ||
41 | if (!initial_boot_params) | |
42 | return; | |
43 | ||
44 | /* Reserve the dtb region */ | |
45 | memblock_reserve(virt_to_phys(initial_boot_params), | |
46 | be32_to_cpu(initial_boot_params->totalsize)); | |
47 | ||
48 | /* | |
49 | * Process the reserve map. This will probably overlap the initrd | |
50 | * and dtb locations which are already reserved, but overlaping | |
51 | * doesn't hurt anything | |
52 | */ | |
53 | reserve_map = ((void*)initial_boot_params) + | |
54 | be32_to_cpu(initial_boot_params->off_mem_rsvmap); | |
55 | while (1) { | |
56 | base = be64_to_cpup(reserve_map++); | |
57 | size = be64_to_cpup(reserve_map++); | |
58 | if (!size) | |
59 | break; | |
60 | memblock_reserve(base, size); | |
61 | } | |
62 | } | |
63 | ||
64 | /** | |
65 | * setup_machine_fdt - Machine setup when an dtb was passed to the kernel | |
66 | * @dt_phys: physical address of dt blob | |
67 | * | |
68 | * If a dtb was passed to the kernel in r2, then use it to choose the | |
69 | * correct machine_desc and to setup the system. | |
70 | */ | |
71 | struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys) | |
72 | { | |
73 | struct boot_param_header *devtree; | |
74 | struct machine_desc *mdesc, *mdesc_best = NULL; | |
75 | unsigned int score, mdesc_score = ~1; | |
76 | unsigned long dt_root; | |
77 | const char *model; | |
78 | ||
f506cd48 NP |
79 | if (!dt_phys) |
80 | return NULL; | |
81 | ||
93c02ab4 GL |
82 | devtree = phys_to_virt(dt_phys); |
83 | ||
84 | /* check device tree validity */ | |
85 | if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) | |
86 | return NULL; | |
87 | ||
88 | /* Search the mdescs for the 'best' compatible value match */ | |
89 | initial_boot_params = devtree; | |
90 | dt_root = of_get_flat_dt_root(); | |
91 | for_each_machine_desc(mdesc) { | |
92 | score = of_flat_dt_match(dt_root, mdesc->dt_compat); | |
93 | if (score > 0 && score < mdesc_score) { | |
94 | mdesc_best = mdesc; | |
95 | mdesc_score = score; | |
96 | } | |
97 | } | |
98 | if (!mdesc_best) { | |
99 | const char *prop; | |
100 | long size; | |
101 | ||
102 | early_print("\nError: unrecognized/unsupported " | |
103 | "device tree compatible list:\n[ "); | |
104 | ||
105 | prop = of_get_flat_dt_prop(dt_root, "compatible", &size); | |
106 | while (size > 0) { | |
107 | early_print("'%s' ", prop); | |
108 | size -= strlen(prop) + 1; | |
109 | prop += strlen(prop) + 1; | |
110 | } | |
111 | early_print("]\n\n"); | |
112 | ||
113 | dump_machine_table(); /* does not return */ | |
114 | } | |
115 | ||
116 | model = of_get_flat_dt_prop(dt_root, "model", NULL); | |
117 | if (!model) | |
118 | model = of_get_flat_dt_prop(dt_root, "compatible", NULL); | |
119 | if (!model) | |
120 | model = "<unknown>"; | |
121 | pr_info("Machine: %s, model: %s\n", mdesc_best->name, model); | |
122 | ||
123 | /* Retrieve various information from the /chosen node */ | |
124 | of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line); | |
125 | /* Initialize {size,address}-cells info */ | |
126 | of_scan_flat_dt(early_init_dt_scan_root, NULL); | |
127 | /* Setup memory, calling early_init_dt_add_memory_arch */ | |
128 | of_scan_flat_dt(early_init_dt_scan_memory, NULL); | |
129 | ||
130 | /* Change machine number to match the mdesc we're using */ | |
131 | __machine_arch_type = mdesc_best->nr; | |
132 | ||
133 | return mdesc_best; | |
134 | } |