diff options
author | Daniel Hellstrom <daniel@gaisler.com> | 2011-01-03 20:41:32 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-01-04 14:16:37 -0500 |
commit | 2791c1a4390085789e37347fc49f7d189fedae88 (patch) | |
tree | 4d5f22601d8a764c377f4378c7e3e8fb5884d343 /arch/sparc | |
parent | 9742e72cd1e24ede007daa8f3eb1cece66f0fd0f (diff) |
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 <daniel@gaisler.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc')
-rw-r--r-- | arch/sparc/kernel/leon_kernel.c | 80 |
1 files changed, 54 insertions, 26 deletions
diff --git a/arch/sparc/kernel/leon_kernel.c b/arch/sparc/kernel/leon_kernel.c index 88ade07f976c..fdab7f854f80 100644 --- a/arch/sparc/kernel/leon_kernel.c +++ b/arch/sparc/kernel/leon_kernel.c | |||
@@ -32,6 +32,7 @@ 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 */ | 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,10 +106,11 @@ 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; |
108 | struct device_node *rootnp, *np; | 109 | struct device_node *rootnp, *np, *nnp; |
109 | struct property *pp; | 110 | struct property *pp; |
110 | int len; | 111 | int len; |
111 | int cpu, icsel; | 112 | int cpu, icsel; |
113 | int ampopts; | ||
112 | 114 | ||
113 | leondebug_irq_disable = 0; | 115 | leondebug_irq_disable = 0; |
114 | leon_debug_irqout = 0; | 116 | leon_debug_irqout = 0; |
@@ -131,30 +133,52 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
131 | leon3_irqctrl_regs = *(struct leon3_irqctrl_regs_map **)pp->value; | 133 | leon3_irqctrl_regs = *(struct leon3_irqctrl_regs_map **)pp->value; |
132 | 134 | ||
133 | /* Find GPTIMER Timer Registers base address otherwise bail out. */ | 135 | /* Find GPTIMER Timer Registers base address otherwise bail out. */ |
134 | np = of_find_node_by_name(rootnp, "GAISLER_GPTIMER"); | 136 | nnp = rootnp; |
135 | if (!np) { | 137 | do { |
136 | np = of_find_node_by_name(np, "01_011"); | 138 | np = of_find_node_by_name(nnp, "GAISLER_GPTIMER"); |
137 | if (!np) | 139 | if (!np) { |
138 | goto bad; | 140 | np = of_find_node_by_name(nnp, "01_011"); |
139 | } | 141 | if (!np) |
140 | pp = of_find_property(np, "reg", &len); | 142 | goto bad; |
141 | if (!pp) | 143 | } |
142 | goto bad; | 144 | |
143 | leon3_gptimer_regs = *(struct leon3_gptimer_regs_map **)pp->value; | 145 | ampopts = 0; |
144 | pp = of_find_property(np, "interrupts", &len); | 146 | pp = of_find_property(np, "ampopts", &len); |
145 | if (!pp) | 147 | if (pp) { |
146 | goto bad; | 148 | ampopts = *(int *)pp->value; |
147 | leon3_gptimer_irq = *(unsigned 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); | ||
148 | 168 | ||
149 | if (leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq) { | 169 | if (leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq) { |
150 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].val, 0); | 170 | LEON3_BYPASS_STORE_PA( |
151 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].rld, | 171 | &leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0); |
152 | (((1000000 / HZ) - 1))); | 172 | LEON3_BYPASS_STORE_PA( |
153 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, 0); | 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); | ||
154 | 177 | ||
155 | #ifdef CONFIG_SMP | 178 | #ifdef CONFIG_SMP |
156 | leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs; | 179 | leon_percpu_timer_dev[0].start = (int)leon3_gptimer_regs; |
157 | 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; | ||
158 | 182 | ||
159 | if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) & | 183 | if (!(LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->config) & |
160 | (1<<LEON3_GPTIMER_SEPIRQ))) { | 184 | (1<<LEON3_GPTIMER_SEPIRQ))) { |
@@ -162,9 +186,13 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
162 | BUG(); | 186 | BUG(); |
163 | } | 187 | } |
164 | 188 | ||
165 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].val, 0); | 189 | LEON3_BYPASS_STORE_PA( |
166 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].rld, (((1000000/HZ) - 1))); | 190 | &leon3_gptimer_regs->e[leon3_gptimer_idx+1].val, 0); |
167 | 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); | ||
168 | # endif | 196 | # endif |
169 | 197 | ||
170 | /* | 198 | /* |
@@ -184,7 +212,7 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
184 | goto bad; | 212 | goto bad; |
185 | } | 213 | } |
186 | 214 | ||
187 | irq = request_irq(leon3_gptimer_irq, | 215 | irq = request_irq(leon3_gptimer_irq+leon3_gptimer_idx, |
188 | counter_fn, | 216 | counter_fn, |
189 | (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); | 217 | (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); |
190 | 218 | ||
@@ -216,13 +244,13 @@ void __init leon_init_timers(irq_handler_t counter_fn) | |||
216 | # endif | 244 | # endif |
217 | 245 | ||
218 | if (leon3_gptimer_regs) { | 246 | if (leon3_gptimer_regs) { |
219 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[0].ctrl, | 247 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl, |
220 | LEON3_GPTIMER_EN | | 248 | LEON3_GPTIMER_EN | |
221 | LEON3_GPTIMER_RL | | 249 | LEON3_GPTIMER_RL | |
222 | LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); | 250 | LEON3_GPTIMER_LD | LEON3_GPTIMER_IRQEN); |
223 | 251 | ||
224 | #ifdef CONFIG_SMP | 252 | #ifdef CONFIG_SMP |
225 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[1].ctrl, | 253 | LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx+1].ctrl, |
226 | LEON3_GPTIMER_EN | | 254 | LEON3_GPTIMER_EN | |
227 | LEON3_GPTIMER_RL | | 255 | LEON3_GPTIMER_RL | |
228 | LEON3_GPTIMER_LD | | 256 | LEON3_GPTIMER_LD | |