diff options
-rw-r--r-- | Documentation/devicetree/bindings/arm/arch_timer.txt | 27 | ||||
-rw-r--r-- | arch/arm/include/asm/arch_timer.h | 6 | ||||
-rw-r--r-- | arch/arm/kernel/arch_timer.c | 53 |
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 | |||
3 | ARM Cortex-A7 and Cortex-A15 have a per-core architected timer, which | ||
4 | provides per-cpu timers. | ||
5 | |||
6 | The 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 | |||
17 | Example: | ||
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 |
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; |