diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-06 18:30:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-06 18:30:54 -0500 |
commit | f70f5b9dc74ca7d0a64c4ead3fb28da09dc1b234 (patch) | |
tree | 01f79ae109966d2ec515358481c151cda549d9ab /arch/sparc/kernel | |
parent | b69fc2efc9205d58c820eb2eb1caa6bf873b4b0d (diff) | |
parent | 09798eb9479da3413bdf96e7d22a84d8b21e05e1 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6: (25 commits)
atyfb: Fix bootup hangs on sparc64.
sparc: update copyright in piggyback.c
sparc: unify strip command in boot/Makefile
sparc: rename piggyback_32 to piggyback
sparc: fix tftpboot.img for sparc64 on little-endian host
sparc: add $BITS to piggyback arguments
sparc: remove obsolete ELF support in piggyback_32.c
sparc: additional comments to piggyback_32.c
sparc: use _start for the start entry (like 64 bit does)
sparc: use trapbase in setup_arch
sparc: refactor piggy_32.c
Added support for ampopts in APBUART driver. Used in AMP systems.
APBUART: added raw AMBA vendor/device number to match against.
SPARC/LEON: avoid AMBAPP name duplicates in openprom fs when REG is missing
SPARC/LEON: added support for selecting Timer Core and Timer within core
LEON: added raw AMBA vendor/device number to find TIMER, IRQCTRL
SPARC/LEON: added support for IRQAMP IRQ Controller
SPARC/LEON: find IRQCTRL and Timer via OF-Tree, instead of hardcoded.
sparc: fix sparse warnings in arch/sparc/prom for 32 bit build
sparc: remove unused prom tree functions
...
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r-- | arch/sparc/kernel/head_32.S | 3 | ||||
-rw-r--r-- | arch/sparc/kernel/leon_kernel.c | 114 | ||||
-rw-r--r-- | arch/sparc/kernel/prom_32.c | 27 | ||||
-rw-r--r-- | arch/sparc/kernel/setup_32.c | 3 |
4 files changed, 118 insertions, 29 deletions
diff --git a/arch/sparc/kernel/head_32.S b/arch/sparc/kernel/head_32.S index 21bb2590d4ae..59423491cef8 100644 --- a/arch/sparc/kernel/head_32.S +++ b/arch/sparc/kernel/head_32.S | |||
@@ -73,12 +73,11 @@ sun4e_notsup: | |||
73 | 73 | ||
74 | /* The Sparc trap table, bootloader gives us control at _start. */ | 74 | /* The Sparc trap table, bootloader gives us control at _start. */ |
75 | __HEAD | 75 | __HEAD |
76 | .globl start, _stext, _start, __stext | 76 | .globl _stext, _start, __stext |
77 | .globl trapbase | 77 | .globl trapbase |
78 | _start: /* danger danger */ | 78 | _start: /* danger danger */ |
79 | __stext: | 79 | __stext: |
80 | _stext: | 80 | _stext: |
81 | start: | ||
82 | trapbase: | 81 | trapbase: |
83 | #ifdef CONFIG_SMP | 82 | #ifdef CONFIG_SMP |
84 | trapbase_cpu0: | 83 | trapbase_cpu0: |
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index f01c42661ee5..fdab7f854f80 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c | |||
@@ -23,15 +23,16 @@ | |||
23 | #include "prom.h" | 23 | #include "prom.h" |
24 | #include "irq.h" | 24 | #include "irq.h" |
25 | 25 | ||
26 | struct leon3_irqctrl_regs_map *leon3_irqctrl_regs; /* interrupt controller base address, initialized by amba_init() */ | 26 | struct leon3_irqctrl_regs_map *leon3_irqctrl_regs; /* interrupt controller base address */ |
27 | struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base address, initialized by amba_init() */ | 27 | struct leon3_gptimer_regs_map *leon3_gptimer_regs; /* timer controller base address */ |
28 | struct amba_apb_device leon_percpu_timer_dev[16]; | 28 | struct amba_apb_device leon_percpu_timer_dev[16]; |
29 | 29 | ||
30 | int leondebug_irq_disable; | 30 | int leondebug_irq_disable; |
31 | int leon_debug_irqout; | 31 | int leon_debug_irqout; |
32 | static int dummy_master_l10_counter; | 32 | static int dummy_master_l10_counter; |
33 | 33 | ||
34 | unsigned long leon3_gptimer_irq; /* interrupt controller irq number, initialized by amba_init() */ | 34 | unsigned long leon3_gptimer_irq; /* interrupt controller irq number */ |
35 | unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ | ||
35 | unsigned int sparc_leon_eirq; | 36 | unsigned int sparc_leon_eirq; |
36 | #define LEON_IMASK ((&leon3_irqctrl_regs->mask[0])) | 37 | #define LEON_IMASK ((&leon3_irqctrl_regs->mask[0])) |
37 | 38 | ||
@@ -105,21 +106,79 @@ static void leon_disable_irq(unsigned int irq_nr) | |||
105 | void __init leon_init_timers(irq_handler_t counter_fn) | 106 | void __init leon_init_timers(irq_handler_t counter_fn) |
106 | { | 107 | { |
107 | int irq; | 108 | int irq; |
109 | struct device_node *rootnp, *np, *nnp; | ||
110 | struct property *pp; | ||
111 | int len; | ||
112 | int cpu, icsel; | ||
113 | int ampopts; | ||
108 | 114 | ||
109 | leondebug_irq_disable = 0; | 115 | leondebug_irq_disable = 0; |
110 | leon_debug_irqout = 0; | 116 | leon_debug_irqout = 0; |
111 | master_l10_counter = (unsigned int *)&dummy_master_l10_counter; | 117 | master_l10_counter = (unsigned int *)&dummy_master_l10_counter; |
112 | dummy_master_l10_counter = 0; | 118 | dummy_master_l10_counter = 0; |
113 | 119 | ||
114 | if (leon3_gptimer_regs && leon3_irqctrl_regs) { | 120 | /*Find IRQMP IRQ Controller Registers base address otherwise bail out.*/ |
115 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].val, 0); | 121 | rootnp = of_find_node_by_path("/ambapp0"); |
116 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].rld, | 122 | if (!rootnp) |
117 | (((1000000 / HZ) - 1))); | 123 | goto bad; |
118 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0); | 124 | np = of_find_node_by_name(rootnp, "GAISLER_IRQMP"); |
125 | if (!np) { | ||
126 | np = of_find_node_by_name(rootnp, "01_00d"); | ||
127 | if (!np) | ||
128 | goto bad; | ||
129 | } | ||
130 | pp = of_find_property(np, "reg", &len); | ||
131 | if (!pp) | ||
132 | goto bad; | ||
133 | leon3_irqctrl_regs = *(struct leon3_irqctrl_regs_map **)pp->value; | ||
134 | |||
135 | /* Find GPTIMER Timer Registers base address otherwise bail out. */ | ||
136 | nnp = rootnp; | ||
137 | do { | ||
138 | np = of_find_node_by_name(nnp, "GAISLER_GPTIMER"); | ||
139 | if (!np) { | ||
140 | np = of_find_node_by_name(nnp, "01_011"); | ||
141 | if (!np) | ||
142 | goto bad; | ||
143 | } | ||
144 | |||
145 | ampopts = 0; | ||
146 | pp = of_find_property(np, "ampopts", &len); | ||
147 | if (pp) { | ||
148 | ampopts = *(int *)pp->value; | ||
149 | if (ampopts == 0) { | ||
150 | /* Skip this instance, resource already | ||
151 | * allocated by other OS */ | ||
152 | nnp = np; | ||
153 | continue; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | /* Select Timer-Instance on Timer Core. Default is zero */ | ||
158 | leon3_gptimer_idx = ampopts & 0x7; | ||
159 | |||
160 | pp = of_find_property(np, "reg", &len); | ||
161 | if (pp) | ||
162 | leon3_gptimer_regs = *(struct leon3_gptimer_regs_map **) | ||
163 | pp->value; | ||
164 | pp = of_find_property(np, "interrupts", &len); | ||
165 | if (pp) | ||
166 | leon3_gptimer_irq = *(unsigned int *)pp->value; | ||
167 | } while (0); | ||
168 | |||
169 | if (leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq) { | ||
170 | LEON3_BYPASS_STORE_PA( | ||
171 | &leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0); | ||
172 | LEON3_BYPASS_STORE_PA( | ||
173 | &leon3_gptimer_regs->e[leon3_gptimer_idx].rld, | ||
174 | (((1000000 / HZ) - 1))); | ||
175 | LEON3_BYPASS_STORE_PA( | ||
176 | &leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, 0); | ||
119 | 177 | ||
120 | #ifdef CONFIG_SMP | 178 | #ifdef CONFIG_SMP |
121 | leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs; | 179 | leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs; |
122 | leon_percpu_timer_dev[0].irq = leon3_gptimer_irq+1; | 180 | leon_percpu_timer_dev[0].irq = leon3_gptimer_irq + 1 + |
181 | leon3_gptimer_idx; | ||
123 | 182 | ||
124 | if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) & | 183 | if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) & |
125 | (1<<LEON3_GPTIMER_SEPIRQ))) { | 184 | (1<<LEON3_GPTIMER_SEPIRQ))) { |
@@ -127,17 +186,33 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
127 | BUG(); | 186 | BUG(); |
128 | } | 187 | } |
129 | 188 | ||
130 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].val, 0); | 189 | LEON3_BYPASS_STORE_PA( |
131 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/HZ) - 1))); | 190 | &leon3_gptimer_regs->e[leon3_gptimer_idx+1].val, 0); |
132 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, 0); | 191 | LEON3_BYPASS_STORE_PA( |
192 | &leon3_gptimer_regs->e[leon3_gptimer_idx+1].rld, | ||
193 | (((1000000/HZ) - 1))); | ||
194 | LEON3_BYPASS_STORE_PA( | ||
195 | &leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, 0); | ||
133 | # endif | 196 | # endif |
134 | 197 | ||
198 | /* | ||
199 | * The IRQ controller may (if implemented) consist of multiple | ||
200 | * IRQ controllers, each mapped on a 4Kb boundary. | ||
201 | * Each CPU may be routed to different IRQCTRLs, however | ||
202 | * we assume that all CPUs (in SMP system) is routed to the | ||
203 | * same IRQ Controller, and for non-SMP only one IRQCTRL is | ||
204 | * accessed anyway. | ||
205 | * In AMP systems, Linux must run on CPU0 for the time being. | ||
206 | */ | ||
207 | cpu = sparc_leon3_cpuid(); | ||
208 | icsel = LEON3_BYPASS_LOAD_PA(&leon3_irqctrl_regs->icsel[cpu/8]); | ||
209 | icsel = (icsel >> ((7 - (cpu&0x7)) * 4)) & 0xf; | ||
210 | leon3_irqctrl_regs += icsel; | ||
135 | } else { | 211 | } else { |
136 | printk(KERN_ERR "No Timer/irqctrl found\n"); | 212 | goto bad; |
137 | BUG(); | ||
138 | } | 213 | } |
139 | 214 | ||
140 | irq = request_irq(leon3_gptimer_irq, | 215 | irq = request_irq(leon3_gptimer_irq+leon3_gptimer_idx, |
141 | counter_fn, | 216 | counter_fn, |
142 | (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); | 217 | (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); |
143 | 218 | ||
@@ -169,13 +244,13 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
169 | # endif | 244 | # endif |
170 | 245 | ||
171 | if (leon3_gptimer_regs) { | 246 | if (leon3_gptimer_regs) { |
172 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, | 247 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, |
173 | LEON3_GPTIMER_EN | | 248 | LEON3_GPTIMER_EN | |
174 | LEON3_GPTIMER_RL | | 249 | LEON3_GPTIMER_RL | |
175 | LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); | 250 | LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); |
176 | 251 | ||
177 | #ifdef CONFIG_SMP | 252 | #ifdef CONFIG_SMP |
178 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, | 253 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, |
179 | LEON3_GPTIMER_EN | | 254 | LEON3_GPTIMER_EN | |
180 | LEON3_GPTIMER_RL | | 255 | LEON3_GPTIMER_RL | |
181 | LEON3_GPTIMER_LD | | 256 | LEON3_GPTIMER_LD | |
@@ -183,6 +258,11 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
183 | #endif | 258 | #endif |
184 | 259 | ||
185 | } | 260 | } |
261 | return; | ||
262 | bad: | ||
263 | printk(KERN_ERR "No Timer/irqctrl found\n"); | ||
264 | BUG(); | ||
265 | return; | ||
186 | } | 266 | } |
187 | 267 | ||
188 | void leon_clear_clock_irq(void) | 268 | void leon_clear_clock_irq(void) |
diff --git a/arch/sparc/kernel/prom_32.c b/arch/sparc/kernel/prom_32.c index 0a37e8cfd160..05fb25330583 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) | |||
136 | /* "name:vendor:device@irq,addrlo" */ | 136 | /* "name:vendor:device@irq,addrlo" */ |
137 | static void __init ambapp_path_component(struct device_node *dp, char *tmp_buf) | 137 | static void __init ambapp_path_component(struct device_node *dp, char *tmp_buf) |
138 | { | 138 | { |
139 | struct amba_prom_registers *regs; unsigned int *intr; | 139 | struct amba_prom_registers *regs; |
140 | unsigned int *device, *vendor; | 140 | unsigned int *intr, *device, *vendor, reg0; |
141 | struct property *prop; | 141 | struct property *prop; |
142 | int interrupt = 0; | ||
142 | 143 | ||
144 | /* In order to get a unique ID in the device tree (multiple AMBA devices | ||
145 | * may have the same name) the node number is printed | ||
146 | */ | ||
143 | prop = of_find_property(dp, "reg", NULL); | 147 | prop = of_find_property(dp, "reg", NULL); |
144 | if (!prop) | 148 | if (!prop) { |
145 | return; | 149 | reg0 = (unsigned int)dp->phandle; |
146 | regs = prop->value; | 150 | } else { |
151 | regs = prop->value; | ||
152 | reg0 = regs->phys_addr; | ||
153 | } | ||
154 | |||
155 | /* Not all cores have Interrupt */ | ||
147 | prop = of_find_property(dp, "interrupts", NULL); | 156 | prop = of_find_property(dp, "interrupts", NULL); |
148 | if (!prop) | 157 | if (!prop) |
149 | return; | 158 | intr = &interrupt; /* IRQ0 does not exist */ |
150 | intr = prop->value; | 159 | else |
160 | intr = prop->value; | ||
161 | |||
151 | prop = of_find_property(dp, "vendor", NULL); | 162 | prop = of_find_property(dp, "vendor", NULL); |
152 | if (!prop) | 163 | if (!prop) |
153 | return; | 164 | return; |
@@ -159,7 +170,7 @@ static void __init ambapp_path_component(struct device_node *dp, char *tmp_buf) | |||
159 | 170 | ||
160 | sprintf(tmp_buf, "%s:%d:%d@%x,%x", | 171 | sprintf(tmp_buf, "%s:%d:%d@%x,%x", |
161 | dp->name, *vendor, *device, | 172 | dp->name, *vendor, *device, |
162 | *intr, regs->phys_addr); | 173 | *intr, reg0); |
163 | } | 174 | } |
164 | 175 | ||
165 | static void __init __build_path_component(struct device_node *dp, char *tmp_buf) | 176 | static void __init __build_path_component(struct device_node *dp, char *tmp_buf) |
diff --git a/arch/sparc/kernel/setup_32.c b/arch/sparc/kernel/setup_32.c index b22ce6100403..648f2161b851 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) | |||
185 | 185 | ||
186 | extern void sun4c_probe_vac(void); | 186 | extern void sun4c_probe_vac(void); |
187 | extern char cputypval; | 187 | extern char cputypval; |
188 | extern unsigned long start, end; | ||
189 | 188 | ||
190 | extern unsigned short root_flags; | 189 | extern unsigned short root_flags; |
191 | extern unsigned short root_dev; | 190 | extern unsigned short root_dev; |
@@ -210,7 +209,7 @@ void __init setup_arch(char **cmdline_p) | |||
210 | int i; | 209 | int i; |
211 | unsigned long highest_paddr; | 210 | unsigned long highest_paddr; |
212 | 211 | ||
213 | sparc_ttable = (struct tt_entry *) &start; | 212 | sparc_ttable = (struct tt_entry *) &trapbase; |
214 | 213 | ||
215 | /* Initialize PROM console and command line. */ | 214 | /* Initialize PROM console and command line. */ |
216 | *cmdline_p = prom_getbootargs(); | 215 | *cmdline_p = prom_getbootargs(); |