aboutsummaryrefslogtreecommitdiff
path: root/arch/arc/kernel
diff options
context:
space:
mode:
authorVineet Gupta <vgupta@synopsys.com>2013-01-18 15:12:26 +0530
committerVineet Gupta <vgupta@synopsys.com>2013-02-15 23:16:13 +0530
commit03a6d28cdddfbd11b338c23e7fe51d0816b9bdef (patch)
tree740383bea378fd680c35ff9b8c074ac36e2781ee /arch/arc/kernel
parent93ad700de2abc111c50bb961c150a9968d5b3982 (diff)
downloadvexpress-lsk-03a6d28cdddfbd11b338c23e7fe51d0816b9bdef.tar.gz
ARC: [Review] Multi-platform image #2: Board callback Infrastructure
The orig platform code orgnaization was singleton design pattern - only one platform (and board thereof) would build at a time. Thus any platform/board specific code (e.g. irq init, early init ...) expected by ARC common code was exported as well defined set of APIs, with only ONE instance building ever. Now with multiple-platform build requirement, that design of code no longer holds - multiple board specific calls need to build at the same time - so ARC common code can't use the API approach, it needs a callback based design where each board registers it's specific set of functions, and at runtime, depending on board detection, the callbacks are used from the registry. This commit adds all the infrastructure, where board specific callbacks are specified as a "maThine description". All the hooks are placed in right spots, no board callbacks registered yet (with MACHINE_STARt/END constructs) so the hooks will not run. Next commit will actually convert the platform to this infrastructure. Signed-off-by: Vineet Gupta <vgupta@synopsys.com> Cc: Arnd Bergmann <arnd@arndb.de> Acked-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'arch/arc/kernel')
-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
6 files changed, 84 insertions, 11 deletions
diff --git a/arch/arc/kernel/devtree.c b/arch/arc/kernel/devtree.c
index c8166dc02c3..a7d98b30358 100644
--- a/arch/arc/kernel/devtree.c
+++ b/arch/arc/kernel/devtree.c
@@ -16,6 +16,7 @@
#include <linux/of_fdt.h>
#include <asm/prom.h>
#include <asm/clk.h>
+#include <asm/mach_desc.h>
/* called from unflatten_device_tree() to bootstrap devicetree itself */
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)
* If a dtb was passed to the kernel, then use it to choose the correct
* machine_desc and to setup the system.
*/
-int __init setup_machine_fdt(void *dt)
+struct machine_desc * __init setup_machine_fdt(void *dt)
{
struct boot_param_header *devtree = dt;
+ struct machine_desc *mdesc = NULL, *mdesc_best = NULL;
+ unsigned int score, mdesc_score = ~1;
unsigned long dt_root;
- char *model, *compat;
+ const char *model, *compat;
void *clk;
char manufacturer[16];
unsigned long len;
/* check device tree validity */
if (be32_to_cpu(devtree->magic) != OF_DT_HEADER)
- return 1;
+ return NULL;
- /* Search the mdescs for the 'best' compatible value match */
initial_boot_params = devtree;
dt_root = of_get_flat_dt_root();
+ /*
+ * The kernel could be multi-platform enabled, thus could have many
+ * "baked-in" machine descriptors. Search thru all for the best
+ * "compatible" string match.
+ */
+ for_each_machine_desc(mdesc) {
+ score = of_flat_dt_match(dt_root, mdesc->dt_compat);
+ if (score > 0 && score < mdesc_score) {
+ mdesc_best = mdesc;
+ mdesc_score = score;
+ }
+ }
+ if (!mdesc_best) {
+ const char *prop;
+ long size;
+
+ pr_err("\n unrecognized device tree list:\n[ ");
+
+ prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
+ if (prop) {
+ while (size > 0) {
+ printk("'%s' ", prop);
+ size -= strlen(prop) + 1;
+ prop += strlen(prop) + 1;
+ }
+ }
+ printk("]\n\n");
+
+ machine_halt();
+ }
+
/* compat = "<manufacturer>,<model>" */
- compat = of_get_flat_dt_prop(dt_root, "compatible", NULL);
- if (!compat)
- compat = "<unknown>";
+ compat = mdesc_best->dt_compat[0];
model = strchr(compat, ',');
if (model)
@@ -73,5 +104,5 @@ int __init setup_machine_fdt(void *dt)
if (clk)
arc_set_core_freq(of_read_ulong(clk, len/4));
- return 0;
+ return mdesc_best;
}
diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c
index df7da2b5a5b..1198168850e 100644
--- a/arch/arc/kernel/irq.c
+++ b/arch/arc/kernel/irq.c
@@ -13,6 +13,7 @@
#include <linux/irqdomain.h>
#include <asm/sections.h>
#include <asm/irq.h>
+#include <asm/mach_desc.h>
/*
* Early Hardware specific Interrupt setup
@@ -125,9 +126,15 @@ void __init init_IRQ(void)
init_onchip_IRQ();
plat_init_IRQ();
+ /* Any external intc can be setup here */
+ if (machine_desc->init_irq)
+ machine_desc->init_irq();
+
#ifdef CONFIG_SMP
/* Master CPU can initialize it's side of IPI */
arc_platform_smp_init_cpu();
+ if (machine_desc->init_smp)
+ machine_desc->init_smp(smp_processor_id());
#endif
}
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index 6cc361c6751..20273b89e54 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -25,12 +25,14 @@
#include <asm/prom.h>
#include <asm/unwind.h>
#include <asm/clk.h>
+#include <asm/mach_desc.h>
#define FIX_PTR(x) __asm__ __volatile__(";" : "+r"(x))
int running_on_hw = 1; /* vs. on ISS */
char __initdata command_line[COMMAND_LINE_SIZE];
+struct machine_desc *machine_desc __initdata;
struct task_struct *_current_task[NR_CPUS]; /* For stack switching */
@@ -323,8 +325,6 @@ void __init __attribute__((weak)) arc_platform_early_init(void)
void __init setup_arch(char **cmdline_p)
{
- int rc;
-
#ifdef CONFIG_CMDLINE_UBOOT
/* Make sure that a whitespace is inserted before */
strlcat(command_line, " ", sizeof(command_line));
@@ -339,13 +339,17 @@ void __init setup_arch(char **cmdline_p)
strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
- rc = setup_machine_fdt(__dtb_start);
+ machine_desc = setup_machine_fdt(__dtb_start);
+ if (!machine_desc)
+ panic("Embedded DT invalid\n");
/* To force early parsing of things like mem=xxx */
parse_early_param();
/* Platform/board specific: e.g. early console registration */
arc_platform_early_init();
+ if (machine_desc->init_early)
+ machine_desc->init_early();
setup_processor();
@@ -372,6 +376,24 @@ void __init setup_arch(char **cmdline_p)
arc_unwind_setup();
}
+static int __init customize_machine(void)
+{
+ /* Add platform devices */
+ if (machine_desc->init_machine)
+ machine_desc->init_machine();
+
+ return 0;
+}
+arch_initcall(customize_machine);
+
+static int __init init_late_machine(void)
+{
+ if (machine_desc->init_late)
+ machine_desc->init_late();
+
+ return 0;
+}
+late_initcall(init_late_machine);
/*
* Get CPU information for use by the procfs.
*/
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c
index 1f762ad6969..ea15f073452 100644
--- a/arch/arc/kernel/smp.c
+++ b/arch/arc/kernel/smp.c
@@ -32,6 +32,7 @@
#include <linux/reboot.h>
#include <asm/processor.h>
#include <asm/setup.h>
+#include <asm/mach_desc.h>
arch_spinlock_t smp_atomic_ops_lock = __ARCH_SPIN_LOCK_UNLOCKED;
arch_spinlock_t smp_bitops_lock = __ARCH_SPIN_LOCK_UNLOCKED;
@@ -127,6 +128,8 @@ void __cpuinit start_kernel_secondary(void)
pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu);
arc_platform_smp_init_cpu();
+ if (machine_desc->init_smp)
+ machine_desc->init_smp(smp_processor_id());
arc_local_timer_setup(cpu);
diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c
index 05dba11fdb2..0ce0e6f76eb 100644
--- a/arch/arc/kernel/time.c
+++ b/arch/arc/kernel/time.c
@@ -43,6 +43,7 @@
#include <asm/irq.h>
#include <asm/arcregs.h>
#include <asm/clk.h>
+#include <asm/mach_desc.h>
#define ARC_TIMER_MAX 0xFFFFFFFF
@@ -258,6 +259,9 @@ void __init time_init(void)
/* sets up the periodic event timer */
arc_local_timer_setup(smp_processor_id());
+
+ if (machine_desc->init_time)
+ machine_desc->init_time();
}
#ifdef CONFIG_ARC_HAS_RTSC
diff --git a/arch/arc/kernel/vmlinux.lds.S b/arch/arc/kernel/vmlinux.lds.S
index 8d3b0d44749..622d8b665a6 100644
--- a/arch/arc/kernel/vmlinux.lds.S
+++ b/arch/arc/kernel/vmlinux.lds.S
@@ -75,6 +75,12 @@ SECTIONS
SECURITY_INITCALL
}
+ .init.arch.info : {
+ __arch_info_begin = .;
+ *(.arch.info.init)
+ __arch_info_end = .;
+ }
+
PERCPU_SECTION(L1_CACHE_BYTES)
/*