From 53aea7caf2e27108912b9b9dbc5bfe18dbbaec9d Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Tue, 4 Jan 2011 01:41:29 +0000 Subject: SPARC/LEON: find IRQCTRL and Timer via OF-Tree, instead of hardcoded. Signed-off-by: Daniel Hellstrom Signed-off-by: David S. Miller --- arch/sparc/kernel/leon_kernel.c | 44 +++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) (limited to 'arch/sparc/kernel') diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index f01c426..80ba8f5 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -23,15 +23,15 @@ #include "prom.h" #include "irq.h" -struct leon3_irqctrl_regs_map *leon3_irqctrl_regs; /* interrupt controller base address, initialized by amba_init() */ -struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base address, initialized by amba_init() */ +struct leon3_irqctrl_regs_map *leon3_irqctrl_regs; /* interrupt controller base address */ +struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base address */ struct amba_apb_device leon_percpu_timer_dev[16]; int leondebug_irq_disable; int leon_debug_irqout; static int dummy_master_l10_counter; -unsigned long leon3_gptimer_irq; /* interrupt controller irq number, initialized by amba_init() */ +unsigned long leon3_gptimer_irq; /* interrupt controller irq number */ unsigned int sparc_leon_eirq; #define LEON_IMASK ((&leon3_irqctrl_regs->mask[0])) @@ -105,13 +105,41 @@ static void leon_disable_irq(unsigned int irq_nr) void __init leon_init_timers(irq_handler_t counter_fn) { int irq; + struct device_node *rootnp, *np; + struct property *pp; + int len; leondebug_irq_disable = 0; leon_debug_irqout = 0; master_l10_counter = (unsigned int *)&dummy_master_l10_counter; dummy_master_l10_counter = 0; - if (leon3_gptimer_regs && leon3_irqctrl_regs) { + /*Find IRQMP IRQ Controller Registers base address otherwise bail out.*/ + rootnp = of_find_node_by_path("/ambapp0"); + if (!rootnp) + goto bad; + np = of_find_node_by_name(rootnp, "GAISLER_IRQMP"); + if (!np) + goto bad; + pp = of_find_property(np, "reg", &len); + if (!pp) + goto bad; + leon3_irqctrl_regs = *(struct leon3_irqctrl_regs_map **)pp->value; + + /* Find GPTIMER Timer Registers base address otherwise bail out. */ + np = of_find_node_by_name(rootnp, "GAISLER_GPTIMER"); + if (!np) + goto bad; + pp = of_find_property(np, "reg", &len); + if (!pp) + goto bad; + leon3_gptimer_regs = *(struct leon3_gptimer_regs_map **)pp->value; + pp = of_find_property(np, "interrupts", &len); + if (!pp) + goto bad; + leon3_gptimer_irq = *(unsigned int *)pp->value; + + if (leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq) { LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].val, 0); LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].rld, (((1000000 / HZ) - 1))); @@ -133,8 +161,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) # endif } else { - printk(KERN_ERR "No Timer/irqctrl found\n"); - BUG(); + goto bad; } irq = request_irq(leon3_gptimer_irq, @@ -183,6 +210,11 @@ void __init leon_init_timers(irq_handler_t counter_fn) #endif } + return; +bad: + printk(KERN_ERR "No Timer/irqctrl found\n"); + BUG(); + return; } void leon_clear_clock_irq(void) -- cgit v1.1 From e2305e37d4c82ef55be54e9edc8a7e2250739b4f Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Tue, 4 Jan 2011 01:41:30 +0000 Subject: SPARC/LEON: added support for IRQAMP IRQ Controller Needed for LEON AMP systems where different CPUs are routed to different IRQ controllers. This patch selects the IRQ Controller which has been routed to the boot CPU, it is up to the boot loader to configure the IRQ controller. Signed-off-by: Daniel Hellstrom Signed-off-by: David S. Miller --- arch/sparc/kernel/leon_kernel.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'arch/sparc/kernel') diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 80ba8f5..91a978f 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -108,6 +108,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) struct device_node *rootnp, *np; struct property *pp; int len; + int cpu, icsel; leondebug_irq_disable = 0; leon_debug_irqout = 0; @@ -160,6 +161,19 @@ void __init leon_init_timers(irq_handler_t counter_fn) LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0); # endif + /* + * The IRQ controller may (if implemented) consist of multiple + * IRQ controllers, each mapped on a 4Kb boundary. + * Each CPU may be routed to different IRQCTRLs, however + * we assume that all CPUs (in SMP system) is routed to the + * same IRQ Controller, and for non-SMP only one IRQCTRL is + * accessed anyway. + * In AMP systems, Linux must run on CPU0 for the time being. + */ + cpu = sparc_leon3_cpuid(); + icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[cpu/8]); + icsel = (icsel >> ((7 - (cpu&0x7)) * 4)) & 0xf; + leon3_irqctrl_regs += icsel; } else { goto bad; } -- cgit v1.1 From 9742e72cd1e24ede007daa8f3eb1cece66f0fd0f Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Tue, 4 Jan 2011 01:41:31 +0000 Subject: LEON: added raw AMBA vendor/device number to find TIMER, IRQCTRL Signed-off-by: Daniel Hellstrom Signed-off-by: David S. Miller --- arch/sparc/kernel/leon_kernel.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'arch/sparc/kernel') diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 91a978f..88ade07 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -120,8 +120,11 @@ void __init leon_init_timers(irq_handler_t counter_fn) if (!rootnp) goto bad; np = of_find_node_by_name(rootnp, "GAISLER_IRQMP"); - if (!np) - goto bad; + if (!np) { + np = of_find_node_by_name(rootnp, "01_00d"); + if (!np) + goto bad; + } pp = of_find_property(np, "reg", &len); if (!pp) goto bad; @@ -129,8 +132,11 @@ void __init leon_init_timers(irq_handler_t counter_fn) /* Find GPTIMER Timer Registers base address otherwise bail out. */ np = of_find_node_by_name(rootnp, "GAISLER_GPTIMER"); - if (!np) - goto bad; + if (!np) { + np = of_find_node_by_name(np, "01_011"); + if (!np) + goto bad; + } pp = of_find_property(np, "reg", &len); if (!pp) goto bad; -- cgit v1.1 From 2791c1a4390085789e37347fc49f7d189fedae88 Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Tue, 4 Jan 2011 01:41:32 +0000 Subject: SPARC/LEON: added support for selecting Timer Core and Timer within core The ability to select Timer Core and Timer instance for system clock makes it possible for multiple AMP systems to coexist. Signed-off-by: Daniel Hellstrom Signed-off-by: David S. Miller --- arch/sparc/kernel/leon_kernel.c | 80 +++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 26 deletions(-) (limited to 'arch/sparc/kernel') diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 88ade07..fdab7f8 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c @@ -32,6 +32,7 @@ int leon_debug_irqout; static int dummy_master_l10_counter; unsigned long leon3_gptimer_irq; /* interrupt controller irq number */ +unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ unsigned int sparc_leon_eirq; #define LEON_IMASK ((&leon3_irqctrl_regs->mask[0])) @@ -105,10 +106,11 @@ static void leon_disable_irq(unsigned int irq_nr) void __init leon_init_timers(irq_handler_t counter_fn) { int irq; - struct device_node *rootnp, *np; + struct device_node *rootnp, *np, *nnp; struct property *pp; int len; int cpu, icsel; + int ampopts; leondebug_irq_disable = 0; leon_debug_irqout = 0; @@ -131,30 +133,52 @@ void __init leon_init_timers(irq_handler_t counter_fn) leon3_irqctrl_regs = *(struct leon3_irqctrl_regs_map **)pp->value; /* Find GPTIMER Timer Registers base address otherwise bail out. */ - np = of_find_node_by_name(rootnp, "GAISLER_GPTIMER"); - if (!np) { - np = of_find_node_by_name(np, "01_011"); - if (!np) - goto bad; - } - pp = of_find_property(np, "reg", &len); - if (!pp) - goto bad; - leon3_gptimer_regs = *(struct leon3_gptimer_regs_map **)pp->value; - pp = of_find_property(np, "interrupts", &len); - if (!pp) - goto bad; - leon3_gptimer_irq = *(unsigned int *)pp->value; + nnp = rootnp; + do { + np = of_find_node_by_name(nnp, "GAISLER_GPTIMER"); + if (!np) { + np = of_find_node_by_name(nnp, "01_011"); + if (!np) + goto bad; + } + + ampopts = 0; + pp = of_find_property(np, "ampopts", &len); + if (pp) { + ampopts = *(int *)pp->value; + if (ampopts == 0) { + /* Skip this instance, resource already + * allocated by other OS */ + nnp = np; + continue; + } + } + + /* Select Timer-Instance on Timer Core. Default is zero */ + leon3_gptimer_idx = ampopts & 0x7; + + pp = of_find_property(np, "reg", &len); + if (pp) + leon3_gptimer_regs = *(struct leon3_gptimer_regs_map **) + pp->value; + pp = of_find_property(np, "interrupts", &len); + if (pp) + leon3_gptimer_irq = *(unsigned int *)pp->value; + } while (0); if (leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq) { - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].val, 0); - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].rld, - (((1000000 / HZ) - 1))); - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0); + LEON3_BYPASS_STORE_PA( + &leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0); + LEON3_BYPASS_STORE_PA( + &leon3_gptimer_regs->e[leon3_gptimer_idx].rld, + (((1000000 / HZ) - 1))); + LEON3_BYPASS_STORE_PA( + &leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0); #ifdef CONFIG_SMP leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs; - leon_percpu_timer_dev[0].irq = leon3_gptimer_irq+1; + leon_percpu_timer_dev[0].irq = leon3_gptimer_irq + 1 + + leon3_gptimer_idx; if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) & (1<e[1].val, 0); - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/HZ) - 1))); - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0); + LEON3_BYPASS_STORE_PA( + &leon3_gptimer_regs->e[leon3_gptimer_idx+1].val, 0); + LEON3_BYPASS_STORE_PA( + &leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld, + (((1000000/HZ) - 1))); + LEON3_BYPASS_STORE_PA( + &leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, 0); # endif /* @@ -184,7 +212,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) goto bad; } - irq = request_irq(leon3_gptimer_irq, + irq = request_irq(leon3_gptimer_irq+leon3_gptimer_idx, counter_fn, (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); @@ -216,13 +244,13 @@ void __init leon_init_timers(irq_handler_t counter_fn) # endif if (leon3_gptimer_regs) { - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, LEON3_GPTIMER_EN | LEON3_GPTIMER_RL | LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); #ifdef CONFIG_SMP - LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, + LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, LEON3_GPTIMER_EN | LEON3_GPTIMER_RL | LEON3_GPTIMER_LD | -- cgit v1.1 From 9663eb21fcfeb1ed9afd73d14bbc4198796cfc7b Mon Sep 17 00:00:00 2001 From: Daniel Hellstrom Date: Tue, 4 Jan 2011 01:41:33 +0000 Subject: SPARC/LEON: avoid AMBAPP name duplicates in openprom fs when REG is missing When the REG property is not available the NODE-ID is used as an unique identifier in order to avoid filesystem name duplicates in /proc/openprom filesystem Signed-off-by: Daniel Hellstrom Signed-off-by: David S. Miller --- arch/sparc/kernel/prom_32.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'arch/sparc/kernel') diff --git a/arch/sparc/kernel/prom_32.c b/arch/sparc/kernel/prom_32.c index 0a37e8c..05fb253 100644 --- a/arch/sparc/kernel/prom_32.c +++ b/arch/sparc/kernel/prom_32.c @@ -136,18 +136,29 @@ static void __init ebus_path_component(struct device_node *dp, char *tmp_buf) /* "name:vendor:device@irq,addrlo" */ static void __init ambapp_path_component(struct device_node *dp, char *tmp_buf) { - struct amba_prom_registers *regs; unsigned int *intr; - unsigned int *device, *vendor; + struct amba_prom_registers *regs; + unsigned int *intr, *device, *vendor, reg0; struct property *prop; + int interrupt = 0; + /* In order to get a unique ID in the device tree (multiple AMBA devices + * may have the same name) the node number is printed + */ prop = of_find_property(dp, "reg", NULL); - if (!prop) - return; - regs = prop->value; + if (!prop) { + reg0 = (unsigned int)dp->phandle; + } else { + regs = prop->value; + reg0 = regs->phys_addr; + } + + /* Not all cores have Interrupt */ prop = of_find_property(dp, "interrupts", NULL); if (!prop) - return; - intr = prop->value; + intr = &interrupt; /* IRQ0 does not exist */ + else + intr = prop->value; + prop = of_find_property(dp, "vendor", NULL); if (!prop) return; @@ -159,7 +170,7 @@ static void __init ambapp_path_component(struct device_node *dp, char *tmp_buf) sprintf(tmp_buf, "%s:%d:%d@%x,%x", dp->name, *vendor, *device, - *intr, regs->phys_addr); + *intr, reg0); } static void __init __build_path_component(struct device_node *dp, char *tmp_buf) -- cgit v1.1 From e405ae76af19cd2c85335b842f880a2bc98ba785 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Tue, 4 Jan 2011 11:39:11 +0000 Subject: sparc: use trapbase in setup_arch start and trapbase point to the same address. But using start to assing to sparc_ttable looked confusing. Replace this with the use of trapbase. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller --- arch/sparc/kernel/setup_32.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/sparc/kernel') diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index b22ce61..648f216 100644 --- a/arch/sparc/kernel/setup_32.c +++ b/arch/sparc/kernel/setup_32.c @@ -185,7 +185,6 @@ static void __init boot_flags_init(char *commands) extern void sun4c_probe_vac(void); extern char cputypval; -extern unsigned long start, end; extern unsigned short root_flags; extern unsigned short root_dev; @@ -210,7 +209,7 @@ void __init setup_arch(char **cmdline_p) int i; unsigned long highest_paddr; - sparc_ttable = (struct tt_entry *) &start; + sparc_ttable = (struct tt_entry *) &trapbase; /* Initialize PROM console and command line. */ *cmdline_p = prom_getbootargs(); -- cgit v1.1 From b2a39b0d8ec2ce2bdcff4e01572b4e885220254d Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Tue, 4 Jan 2011 11:39:12 +0000 Subject: sparc: use _start for the start entry (like 64 bit does) We use "_start" in 64 bit - do the same in 32 bit. It is always good to be consistent. Signed-off-by: Sam Ravnborg Signed-off-by: David S. Miller --- arch/sparc/kernel/head_32.S | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/sparc/kernel') diff --git a/arch/sparc/kernel/head_32.S b/arch/sparc/kernel/head_32.S index 21bb259..5942349 100644 --- a/arch/sparc/kernel/head_32.S +++ b/arch/sparc/kernel/head_32.S @@ -73,12 +73,11 @@ sun4e_notsup: /* The Sparc trap table, bootloader gives us control at _start. */ __HEAD - .globl start, _stext, _start, __stext + .globl _stext, _start, __stext .globl trapbase _start: /* danger danger */ __stext: _stext: -start: trapbase: #ifdef CONFIG_SMP trapbase_cpu0: -- cgit v1.1