aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arc')
-rw-r--r--arch/arc/include/asm/mach_desc.h85
-rw-r--r--arch/arc/include/asm/prom.h1
-rw-r--r--arch/arc/kernel/devtree.c47
-rw-r--r--arch/arc/kernel/irq.c7
-rw-r--r--arch/arc/kernel/setup.c28
-rw-r--r--arch/arc/kernel/smp.c3
-rw-r--r--arch/arc/kernel/time.c4
-rw-r--r--arch/arc/kernel/vmlinux.lds.S6
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 */
36struct 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 */
54extern struct machine_desc *machine_desc;
55
56/*
57 * Machine type table - also only accessible during boot
58 */
59extern 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
63static 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) \
76static 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
84extern 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
13extern 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 */
21void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) 22void * __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 */
33int __init setup_machine_fdt(void *dt) 34struct 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
31int running_on_hw = 1; /* vs. on ISS */ 32int running_on_hw = 1; /* vs. on ISS */
32 33
33char __initdata command_line[COMMAND_LINE_SIZE]; 34char __initdata command_line[COMMAND_LINE_SIZE];
35struct machine_desc *machine_desc __initdata;
34 36
35struct task_struct *_current_task[NR_CPUS]; /* For stack switching */ 37struct 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
324void __init setup_arch(char **cmdline_p) 326void __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
379static 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}
387arch_initcall(customize_machine);
388
389static int __init init_late_machine(void)
390{
391 if (machine_desc->init_late)
392 machine_desc->init_late();
393
394 return 0;
395}
396late_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
36arch_spinlock_t smp_atomic_ops_lock = __ARCH_SPIN_LOCK_UNLOCKED; 37arch_spinlock_t smp_atomic_ops_lock = __ARCH_SPIN_LOCK_UNLOCKED;
37arch_spinlock_t smp_bitops_lock = __ARCH_SPIN_LOCK_UNLOCKED; 38arch_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 /*