aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/arch_timer.txt27
-rw-r--r--arch/arm/include/asm/arch_timer.h6
-rw-r--r--arch/arm/kernel/arch_timer.c53
3 files changed, 79 insertions, 7 deletions
diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
new file mode 100644
index 000000000000..52478c83d0cc
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
@@ -0,0 +1,27 @@
1* ARM architected timer
2
3ARM Cortex-A7 and Cortex-A15 have a per-core architected timer, which
4provides per-cpu timers.
5
6The timer is attached to a GIC to deliver its per-processor interrupts.
7
8** Timer node properties:
9
10- compatible : Should at least contain "arm,armv7-timer".
11
12- interrupts : Interrupt list for secure, non-secure, virtual and
13 hypervisor timers, in that order.
14
15- clock-frequency : The frequency of the main counter, in Hz. Optional.
16
17Example:
18
19 timer {
20 compatible = "arm,cortex-a15-timer",
21 "arm,armv7-timer";
22 interrupts = <1 13 0xf08>,
23 <1 14 0xf08>,
24 <1 11 0xf08>,
25 <1 10 0xf08>;
26 clock-frequency = <100000000>;
27 };
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
11int arch_timer_register(struct arch_timer *); 11int arch_timer_register(struct arch_timer *);
12int arch_timer_sched_clock_init(void); 12int arch_timer_sched_clock_init(void);
13int arch_timer_of_register(void);
13#else 14#else
14static inline int arch_timer_register(struct arch_timer *at) 15static inline int arch_timer_register(struct arch_timer *at)
15{ 16{
16 return -ENXIO; 17 return -ENXIO;
17} 18}
18 19
20static inline int arch_timer_of_register(void)
21{
22 return -ENXIO;
23}
24
19static inline int arch_timer_sched_clock_init(void) 25static 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
248int __init arch_timer_register(struct arch_timer *at) 249static 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
299int __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
313static const struct of_device_id arch_timer_of_match[] __initconst = {
314 { .compatible = "arm,armv7-timer", },
315 {},
316};
317
318int __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
303int __init arch_timer_sched_clock_init(void) 342int __init arch_timer_sched_clock_init(void)
304{ 343{
305 int err; 344 int err;