diff options
author | Marc Zyngier <marc.zyngier@arm.com> | 2012-01-19 08:53:50 -0500 |
---|---|---|
committer | Marc Zyngier <marc.zyngier@arm.com> | 2012-04-27 08:35:34 -0400 |
commit | 0075242b3a2f78901172aaadf73beed762a1f02f (patch) | |
tree | 18a33963355c7dcbba0d6420c2fbefe430ef7907 /arch/arm | |
parent | 3f61c80eb7dff0fb35beb8068852d3fc902315a6 (diff) |
ARM: architected timers: add DT support
Add runtime DT support and documentation for the Cortex A7/A15
architected timers.
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/include/asm/arch_timer.h | 6 | ||||
-rw-r--r-- | arch/arm/kernel/arch_timer.c | 53 |
2 files changed, 52 insertions, 7 deletions
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h index dc008c696b5a..935897f120b6 100644 --- a/arch/arm/include/asm/arch_timer.h +++ b/arch/arm/include/asm/arch_timer.h | |||
@@ -10,12 +10,18 @@ struct arch_timer { | |||
10 | #ifdef CONFIG_ARM_ARCH_TIMER | 10 | #ifdef CONFIG_ARM_ARCH_TIMER |
11 | int arch_timer_register(struct arch_timer *); | 11 | int arch_timer_register(struct arch_timer *); |
12 | int arch_timer_sched_clock_init(void); | 12 | int arch_timer_sched_clock_init(void); |
13 | int arch_timer_of_register(void); | ||
13 | #else | 14 | #else |
14 | static inline int arch_timer_register(struct arch_timer *at) | 15 | static inline int arch_timer_register(struct arch_timer *at) |
15 | { | 16 | { |
16 | return -ENXIO; | 17 | return -ENXIO; |
17 | } | 18 | } |
18 | 19 | ||
20 | static inline int arch_timer_of_register(void) | ||
21 | { | ||
22 | return -ENXIO; | ||
23 | } | ||
24 | |||
19 | static inline int arch_timer_sched_clock_init(void) | 25 | static inline int arch_timer_sched_clock_init(void) |
20 | { | 26 | { |
21 | return -ENXIO; | 27 | return -ENXIO; |
diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c index dd907048f571..1a34eeebc26e 100644 --- a/arch/arm/kernel/arch_timer.c +++ b/arch/arm/kernel/arch_timer.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/jiffies.h> | 17 | #include <linux/jiffies.h> |
18 | #include <linux/clockchips.h> | 18 | #include <linux/clockchips.h> |
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <linux/of_irq.h> | ||
20 | #include <linux/io.h> | 21 | #include <linux/io.h> |
21 | 22 | ||
22 | #include <asm/cputype.h> | 23 | #include <asm/cputype.h> |
@@ -245,13 +246,10 @@ static struct local_timer_ops arch_timer_ops __cpuinitdata = { | |||
245 | .stop = arch_timer_stop, | 246 | .stop = arch_timer_stop, |
246 | }; | 247 | }; |
247 | 248 | ||
248 | int __init arch_timer_register(struct arch_timer *at) | 249 | static int __init arch_timer_common_register(void) |
249 | { | 250 | { |
250 | int err; | 251 | int err; |
251 | 252 | ||
252 | if (at->res[0].start <= 0 || !(at->res[0].flags & IORESOURCE_IRQ)) | ||
253 | return -EINVAL; | ||
254 | |||
255 | err = arch_timer_available(); | 253 | err = arch_timer_available(); |
256 | if (err) | 254 | if (err) |
257 | return err; | 255 | return err; |
@@ -262,7 +260,6 @@ int __init arch_timer_register(struct arch_timer *at) | |||
262 | 260 | ||
263 | clocksource_register_hz(&clocksource_counter, arch_timer_rate); | 261 | clocksource_register_hz(&clocksource_counter, arch_timer_rate); |
264 | 262 | ||
265 | arch_timer_ppi = at->res[0].start; | ||
266 | err = request_percpu_irq(arch_timer_ppi, arch_timer_handler, | 263 | err = request_percpu_irq(arch_timer_ppi, arch_timer_handler, |
267 | "arch_timer", arch_timer_evt); | 264 | "arch_timer", arch_timer_evt); |
268 | if (err) { | 265 | if (err) { |
@@ -271,8 +268,7 @@ int __init arch_timer_register(struct arch_timer *at) | |||
271 | goto out_free; | 268 | goto out_free; |
272 | } | 269 | } |
273 | 270 | ||
274 | if (at->res[1].start > 0 || (at->res[1].flags & IORESOURCE_IRQ)) { | 271 | if (arch_timer_ppi2) { |
275 | arch_timer_ppi2 = at->res[1].start; | ||
276 | err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler, | 272 | err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler, |
277 | "arch_timer", arch_timer_evt); | 273 | "arch_timer", arch_timer_evt); |
278 | if (err) { | 274 | if (err) { |
@@ -300,6 +296,49 @@ out_free: | |||
300 | return err; | 296 | return err; |
301 | } | 297 | } |
302 | 298 | ||
299 | int __init arch_timer_register(struct arch_timer *at) | ||
300 | { | ||
301 | if (at->res[0].start <= 0 || !(at->res[0].flags & IORESOURCE_IRQ)) | ||
302 | return -EINVAL; | ||
303 | |||
304 | arch_timer_ppi = at->res[0].start; | ||
305 | |||
306 | if (at->res[1].start > 0 || (at->res[1].flags & IORESOURCE_IRQ)) | ||
307 | arch_timer_ppi2 = at->res[1].start; | ||
308 | |||
309 | return arch_timer_common_register(); | ||
310 | } | ||
311 | |||
312 | #ifdef CONFIG_OF | ||
313 | static const struct of_device_id arch_timer_of_match[] __initconst = { | ||
314 | { .compatible = "arm,armv7-timer", }, | ||
315 | {}, | ||
316 | }; | ||
317 | |||
318 | int __init arch_timer_of_register(void) | ||
319 | { | ||
320 | struct device_node *np; | ||
321 | u32 freq; | ||
322 | |||
323 | np = of_find_matching_node(NULL, arch_timer_of_match); | ||
324 | if (!np) { | ||
325 | pr_err("arch_timer: can't find DT node\n"); | ||
326 | return -ENODEV; | ||
327 | } | ||
328 | |||
329 | /* Try to determine the frequency from the device tree or CNTFRQ */ | ||
330 | if (!of_property_read_u32(np, "clock-frequency", &freq)) | ||
331 | arch_timer_rate = freq; | ||
332 | |||
333 | arch_timer_ppi = irq_of_parse_and_map(np, 0); | ||
334 | arch_timer_ppi2 = irq_of_parse_and_map(np, 1); | ||
335 | pr_info("arch_timer: found %s irqs %d %d\n", | ||
336 | np->name, arch_timer_ppi, arch_timer_ppi2); | ||
337 | |||
338 | return arch_timer_common_register(); | ||
339 | } | ||
340 | #endif | ||
341 | |||
303 | int __init arch_timer_sched_clock_init(void) | 342 | int __init arch_timer_sched_clock_init(void) |
304 | { | 343 | { |
305 | int err; | 344 | int err; |