diff options
Diffstat (limited to 'arch/arc/kernel/devtree.c')
-rw-r--r-- | arch/arc/kernel/devtree.c | 47 |
1 files changed, 39 insertions, 8 deletions
diff --git a/arch/arc/kernel/devtree.c b/arch/arc/kernel/devtree.c index c8166dc02c38..a7d98b30358b 100644 --- a/arch/arc/kernel/devtree.c +++ b/arch/arc/kernel/devtree.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/of_fdt.h> | 16 | #include <linux/of_fdt.h> |
17 | #include <asm/prom.h> | 17 | #include <asm/prom.h> |
18 | #include <asm/clk.h> | 18 | #include <asm/clk.h> |
19 | #include <asm/mach_desc.h> | ||
19 | 20 | ||
20 | /* called from unflatten_device_tree() to bootstrap devicetree itself */ | 21 | /* called from unflatten_device_tree() to bootstrap devicetree itself */ |
21 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) | 22 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) |
@@ -30,27 +31,57 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) | |||
30 | * If a dtb was passed to the kernel, then use it to choose the correct | 31 | * If a dtb was passed to the kernel, then use it to choose the correct |
31 | * machine_desc and to setup the system. | 32 | * machine_desc and to setup the system. |
32 | */ | 33 | */ |
33 | int __init setup_machine_fdt(void *dt) | 34 | struct machine_desc * __init setup_machine_fdt(void *dt) |
34 | { | 35 | { |
35 | struct boot_param_header *devtree = dt; | 36 | struct boot_param_header *devtree = dt; |
37 | struct machine_desc *mdesc = NULL, *mdesc_best = NULL; | ||
38 | unsigned int score, mdesc_score = ~1; | ||
36 | unsigned long dt_root; | 39 | unsigned long dt_root; |
37 | char *model, *compat; | 40 | const char *model, *compat; |
38 | void *clk; | 41 | void *clk; |
39 | char manufacturer[16]; | 42 | char manufacturer[16]; |
40 | unsigned long len; | 43 | unsigned long len; |
41 | 44 | ||
42 | /* check device tree validity */ | 45 | /* check device tree validity */ |
43 | if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) | 46 | if (be32_to_cpu(devtree->magic) != OF_DT_HEADER) |
44 | return 1; | 47 | return NULL; |
45 | 48 | ||
46 | /* Search the mdescs for the 'best' compatible value match */ | ||
47 | initial_boot_params = devtree; | 49 | initial_boot_params = devtree; |
48 | dt_root = of_get_flat_dt_root(); | 50 | dt_root = of_get_flat_dt_root(); |
49 | 51 | ||
52 | /* | ||
53 | * The kernel could be multi-platform enabled, thus could have many | ||
54 | * "baked-in" machine descriptors. Search thru all for the best | ||
55 | * "compatible" string match. | ||
56 | */ | ||
57 | for_each_machine_desc(mdesc) { | ||
58 | score = of_flat_dt_match(dt_root, mdesc->dt_compat); | ||
59 | if (score > 0 && score < mdesc_score) { | ||
60 | mdesc_best = mdesc; | ||
61 | mdesc_score = score; | ||
62 | } | ||
63 | } | ||
64 | if (!mdesc_best) { | ||
65 | const char *prop; | ||
66 | long size; | ||
67 | |||
68 | pr_err("\n unrecognized device tree list:\n[ "); | ||
69 | |||
70 | prop = of_get_flat_dt_prop(dt_root, "compatible", &size); | ||
71 | if (prop) { | ||
72 | while (size > 0) { | ||
73 | printk("'%s' ", prop); | ||
74 | size -= strlen(prop) + 1; | ||
75 | prop += strlen(prop) + 1; | ||
76 | } | ||
77 | } | ||
78 | printk("]\n\n"); | ||
79 | |||
80 | machine_halt(); | ||
81 | } | ||
82 | |||
50 | /* compat = "<manufacturer>,<model>" */ | 83 | /* compat = "<manufacturer>,<model>" */ |
51 | compat = of_get_flat_dt_prop(dt_root, "compatible", NULL); | 84 | compat = mdesc_best->dt_compat[0]; |
52 | if (!compat) | ||
53 | compat = "<unknown>"; | ||
54 | 85 | ||
55 | model = strchr(compat, ','); | 86 | model = strchr(compat, ','); |
56 | if (model) | 87 | if (model) |
@@ -73,5 +104,5 @@ int __init setup_machine_fdt(void *dt) | |||
73 | if (clk) | 104 | if (clk) |
74 | arc_set_core_freq(of_read_ulong(clk, len/4)); | 105 | arc_set_core_freq(of_read_ulong(clk, len/4)); |
75 | 106 | ||
76 | return 0; | 107 | return mdesc_best; |
77 | } | 108 | } |