diff options
-rw-r--r-- | arch/arc/include/asm/mach_desc.h | 85 | ||||
-rw-r--r-- | arch/arc/include/asm/prom.h | 1 | ||||
-rw-r--r-- | arch/arc/kernel/devtree.c | 47 | ||||
-rw-r--r-- | arch/arc/kernel/irq.c | 7 | ||||
-rw-r--r-- | arch/arc/kernel/setup.c | 28 | ||||
-rw-r--r-- | arch/arc/kernel/smp.c | 3 | ||||
-rw-r--r-- | arch/arc/kernel/time.c | 4 | ||||
-rw-r--r-- | arch/arc/kernel/vmlinux.lds.S | 6 |
8 files changed, 169 insertions, 12 deletions
diff --git a/arch/arc/include/asm/mach_desc.h b/arch/arc/include/asm/mach_desc.h new file mode 100644 index 000000000000..eaebaf835f85 --- /dev/null +++ b/arch/arc/include/asm/mach_desc.h | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com) | ||
3 | * | ||
4 | * based on METAG mach/arch.h (which in turn was based on ARM) | ||
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 | #ifndef _ASM_ARC_MACH_DESC_H_ | ||
12 | #define _ASM_ARC_MACH_DESC_H_ | ||
13 | |||
14 | /** | ||
15 | * struct machine_desc - Board specific callbacks, called from ARC common code | ||
16 | * Provided by each ARC board using MACHINE_START()/MACHINE_END(), so | ||
17 | * a multi-platform kernel builds with array of such descriptors. | ||
18 | * We extend the early DT scan to also match the DT's "compatible" string | ||
19 | * against the @dt_compat of all such descriptors, and one with highest | ||
20 | * "DT score" is selected as global @machine_desc. | ||
21 | * | ||
22 | * @name: Board/SoC name | ||
23 | * @dt_compat: Array of device tree 'compatible' strings | ||
24 | * (XXX: although only 1st entry is looked at) | ||
25 | * @init_early: Very early callback [called from setup_arch()] | ||
26 | * @init_irq: setup external IRQ controllers [called from init_IRQ()] | ||
27 | * @init_smp: for each CPU (e.g. setup IPI) | ||
28 | * [(M):init_IRQ(), (o):start_kernel_secondary()] | ||
29 | * @init_time: platform specific clocksource/clockevent registration | ||
30 | * [called from time_init()] | ||
31 | * @init_machine: arch initcall level callback (e.g. populate static | ||
32 | * platform devices or parse Devicetree) | ||
33 | * @init_late: Late initcall level callback | ||
34 | * | ||
35 | */ | ||
36 | struct machine_desc { | ||
37 | const char *name; | ||
38 | const char **dt_compat; | ||
39 | |||
40 | void (*init_early)(void); | ||
41 | void (*init_irq)(void); | ||
42 | #ifdef CONFIG_SMP | ||
43 | void (*init_smp)(unsigned int); | ||
44 | #endif | ||
45 | void (*init_time)(void); | ||
46 | void (*init_machine)(void); | ||
47 | void (*init_late)(void); | ||
48 | |||
49 | }; | ||
50 | |||
51 | /* | ||
52 | * Current machine - only accessible during boot. | ||
53 | */ | ||
54 | extern struct machine_desc *machine_desc; | ||
55 | |||
56 | /* | ||
57 | * Machine type table - also only accessible during boot | ||
58 | */ | ||
59 | extern struct machine_desc __arch_info_begin[], __arch_info_end[]; | ||
60 | #define for_each_machine_desc(p) \ | ||
61 | for (p = __arch_info_begin; p < __arch_info_end; p++) | ||
62 | |||
63 | static inline struct machine_desc *default_machine_desc(void) | ||
64 | { | ||
65 | /* the default machine is the last one linked in */ | ||
66 | if (__arch_info_end - 1 < __arch_info_begin) | ||
67 | return NULL; | ||
68 | return __arch_info_end - 1; | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * Set of macros to define architecture features. | ||
73 | * This is built into a table by the linker. | ||
74 | */ | ||
75 | #define MACHINE_START(_type, _name) \ | ||
76 | static const struct machine_desc __mach_desc_##_type \ | ||
77 | __used \ | ||
78 | __attribute__((__section__(".arch.info.init"))) = { \ | ||
79 | .name = _name, | ||
80 | |||
81 | #define MACHINE_END \ | ||
82 | }; | ||
83 | |||
84 | extern struct machine_desc *setup_machine_fdt(void *dt); | ||
85 | #endif | ||
diff --git a/arch/arc/include/asm/prom.h b/arch/arc/include/asm/prom.h index f54489bc4eca..692d0d0789a7 100644 --- a/arch/arc/include/asm/prom.h +++ b/arch/arc/include/asm/prom.h | |||
@@ -10,6 +10,5 @@ | |||
10 | #define _ASM_ARC_PROM_H_ | 10 | #define _ASM_ARC_PROM_H_ |
11 | 11 | ||
12 | #define HAVE_ARCH_DEVTREE_FIXUPS | 12 | #define HAVE_ARCH_DEVTREE_FIXUPS |
13 | extern int __init setup_machine_fdt(void *dt); | ||
14 | 13 | ||
15 | #endif | 14 | #endif |
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 | } |
diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c index df7da2b5a5bd..1198168850e8 100644 --- a/arch/arc/kernel/irq.c +++ b/arch/arc/kernel/irq.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/irqdomain.h> | 13 | #include <linux/irqdomain.h> |
14 | #include <asm/sections.h> | 14 | #include <asm/sections.h> |
15 | #include <asm/irq.h> | 15 | #include <asm/irq.h> |
16 | #include <asm/mach_desc.h> | ||
16 | 17 | ||
17 | /* | 18 | /* |
18 | * Early Hardware specific Interrupt setup | 19 | * Early Hardware specific Interrupt setup |
@@ -125,9 +126,15 @@ void __init init_IRQ(void) | |||
125 | init_onchip_IRQ(); | 126 | init_onchip_IRQ(); |
126 | plat_init_IRQ(); | 127 | plat_init_IRQ(); |
127 | 128 | ||
129 | /* Any external intc can be setup here */ | ||
130 | if (machine_desc->init_irq) | ||
131 | machine_desc->init_irq(); | ||
132 | |||
128 | #ifdef CONFIG_SMP | 133 | #ifdef CONFIG_SMP |
129 | /* Master CPU can initialize it's side of IPI */ | 134 | /* Master CPU can initialize it's side of IPI */ |
130 | arc_platform_smp_init_cpu(); | 135 | arc_platform_smp_init_cpu(); |
136 | if (machine_desc->init_smp) | ||
137 | machine_desc->init_smp(smp_processor_id()); | ||
131 | #endif | 138 | #endif |
132 | } | 139 | } |
133 | 140 | ||
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c index 6cc361c6751a..20273b89e545 100644 --- a/arch/arc/kernel/setup.c +++ b/arch/arc/kernel/setup.c | |||
@@ -25,12 +25,14 @@ | |||
25 | #include <asm/prom.h> | 25 | #include <asm/prom.h> |
26 | #include <asm/unwind.h> | 26 | #include <asm/unwind.h> |
27 | #include <asm/clk.h> | 27 | #include <asm/clk.h> |
28 | #include <asm/mach_desc.h> | ||
28 | 29 | ||
29 | #define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x)) | 30 | #define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x)) |
30 | 31 | ||
31 | int running_on_hw = 1; /* vs. on ISS */ | 32 | int running_on_hw = 1; /* vs. on ISS */ |
32 | 33 | ||
33 | char __initdata command_line[COMMAND_LINE_SIZE]; | 34 | char __initdata command_line[COMMAND_LINE_SIZE]; |
35 | struct machine_desc *machine_desc __initdata; | ||
34 | 36 | ||
35 | struct task_struct *_current_task[NR_CPUS]; /* For stack switching */ | 37 | struct task_struct *_current_task[NR_CPUS]; /* For stack switching */ |
36 | 38 | ||
@@ -323,8 +325,6 @@ void __init __attribute__((weak)) arc_platform_early_init(void) | |||
323 | 325 | ||
324 | void __init setup_arch(char **cmdline_p) | 326 | void __init setup_arch(char **cmdline_p) |
325 | { | 327 | { |
326 | int rc; | ||
327 | |||
328 | #ifdef CONFIG_CMDLINE_UBOOT | 328 | #ifdef CONFIG_CMDLINE_UBOOT |
329 | /* Make sure that a whitespace is inserted before */ | 329 | /* Make sure that a whitespace is inserted before */ |
330 | strlcat(command_line, " ", sizeof(command_line)); | 330 | strlcat(command_line, " ", sizeof(command_line)); |
@@ -339,13 +339,17 @@ void __init setup_arch(char **cmdline_p) | |||
339 | strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); | 339 | strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE); |
340 | *cmdline_p = command_line; | 340 | *cmdline_p = command_line; |
341 | 341 | ||
342 | rc = setup_machine_fdt(__dtb_start); | 342 | machine_desc = setup_machine_fdt(__dtb_start); |
343 | if (!machine_desc) | ||
344 | panic("Embedded DT invalid\n"); | ||
343 | 345 | ||
344 | /* To force early parsing of things like mem=xxx */ | 346 | /* To force early parsing of things like mem=xxx */ |
345 | parse_early_param(); | 347 | parse_early_param(); |
346 | 348 | ||
347 | /* Platform/board specific: e.g. early console registration */ | 349 | /* Platform/board specific: e.g. early console registration */ |
348 | arc_platform_early_init(); | 350 | arc_platform_early_init(); |
351 | if (machine_desc->init_early) | ||
352 | machine_desc->init_early(); | ||
349 | 353 | ||
350 | setup_processor(); | 354 | setup_processor(); |
351 | 355 | ||
@@ -372,6 +376,24 @@ void __init setup_arch(char **cmdline_p) | |||
372 | arc_unwind_setup(); | 376 | arc_unwind_setup(); |
373 | } | 377 | } |
374 | 378 | ||
379 | static int __init customize_machine(void) | ||
380 | { | ||
381 | /* Add platform devices */ | ||
382 | if (machine_desc->init_machine) | ||
383 | machine_desc->init_machine(); | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | arch_initcall(customize_machine); | ||
388 | |||
389 | static int __init init_late_machine(void) | ||
390 | { | ||
391 | if (machine_desc->init_late) | ||
392 | machine_desc->init_late(); | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | late_initcall(init_late_machine); | ||
375 | /* | 397 | /* |
376 | * Get CPU information for use by the procfs. | 398 | * Get CPU information for use by the procfs. |
377 | */ | 399 | */ |
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c index 1f762ad6969b..ea15f073452f 100644 --- a/arch/arc/kernel/smp.c +++ b/arch/arc/kernel/smp.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/reboot.h> | 32 | #include <linux/reboot.h> |
33 | #include <asm/processor.h> | 33 | #include <asm/processor.h> |
34 | #include <asm/setup.h> | 34 | #include <asm/setup.h> |
35 | #include <asm/mach_desc.h> | ||
35 | 36 | ||
36 | arch_spinlock_t smp_atomic_ops_lock = __ARCH_SPIN_LOCK_UNLOCKED; | 37 | arch_spinlock_t smp_atomic_ops_lock = __ARCH_SPIN_LOCK_UNLOCKED; |
37 | arch_spinlock_t smp_bitops_lock = __ARCH_SPIN_LOCK_UNLOCKED; | 38 | arch_spinlock_t smp_bitops_lock = __ARCH_SPIN_LOCK_UNLOCKED; |
@@ -127,6 +128,8 @@ void __cpuinit start_kernel_secondary(void) | |||
127 | pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu); | 128 | pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu); |
128 | 129 | ||
129 | arc_platform_smp_init_cpu(); | 130 | arc_platform_smp_init_cpu(); |
131 | if (machine_desc->init_smp) | ||
132 | machine_desc->init_smp(smp_processor_id()); | ||
130 | 133 | ||
131 | arc_local_timer_setup(cpu); | 134 | arc_local_timer_setup(cpu); |
132 | 135 | ||
diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c index 05dba11fdb2d..0ce0e6f76eb0 100644 --- a/arch/arc/kernel/time.c +++ b/arch/arc/kernel/time.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <asm/irq.h> | 43 | #include <asm/irq.h> |
44 | #include <asm/arcregs.h> | 44 | #include <asm/arcregs.h> |
45 | #include <asm/clk.h> | 45 | #include <asm/clk.h> |
46 | #include <asm/mach_desc.h> | ||
46 | 47 | ||
47 | #define ARC_TIMER_MAX 0xFFFFFFFF | 48 | #define ARC_TIMER_MAX 0xFFFFFFFF |
48 | 49 | ||
@@ -258,6 +259,9 @@ void __init time_init(void) | |||
258 | 259 | ||
259 | /* sets up the periodic event timer */ | 260 | /* sets up the periodic event timer */ |
260 | arc_local_timer_setup(smp_processor_id()); | 261 | arc_local_timer_setup(smp_processor_id()); |
262 | |||
263 | if (machine_desc->init_time) | ||
264 | machine_desc->init_time(); | ||
261 | } | 265 | } |
262 | 266 | ||
263 | #ifdef CONFIG_ARC_HAS_RTSC | 267 | #ifdef CONFIG_ARC_HAS_RTSC |
diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S index 8d3b0d447498..622d8b665a68 100644 --- a/arch/arc/kernel/vmlinux.lds.S +++ b/arch/arc/kernel/vmlinux.lds.S | |||
@@ -75,6 +75,12 @@ SECTIONS | |||
75 | SECURITY_INITCALL | 75 | SECURITY_INITCALL |
76 | } | 76 | } |
77 | 77 | ||
78 | .init.arch.info : { | ||
79 | __arch_info_begin = .; | ||
80 | *(.arch.info.init) | ||
81 | __arch_info_end = .; | ||
82 | } | ||
83 | |||
78 | PERCPU_SECTION(L1_CACHE_BYTES) | 84 | PERCPU_SECTION(L1_CACHE_BYTES) |
79 | 85 | ||
80 | /* | 86 | /* |