blob: 87bb7d36387e457d43534f582b0dd9d057eda5e5 [file] [log] [blame]
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -08001/*
2 * linux/arch/arm/kernel/arch_timer.c
3 *
4 * Copyright (C) 2011 ARM Ltd.
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/delay.h>
Sathish Ambley8a309822011-11-07 14:49:08 -080014#include <linux/timex.h>
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -080015#include <linux/device.h>
16#include <linux/smp.h>
17#include <linux/cpu.h>
18#include <linux/jiffies.h>
19#include <linux/clockchips.h>
20#include <linux/interrupt.h>
Marc Zyngierf2caa512012-01-19 13:53:50 +000021#include <linux/of_irq.h>
Abhimanyu Kapur05b66442012-05-31 23:28:23 -070022#include <linux/of_address.h>
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -080023#include <linux/io.h>
Sathish Ambley8a309822011-11-07 14:49:08 -080024#include <linux/irq.h>
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -080025
26#include <asm/cputype.h>
Marc Zyngierdf590cc2012-01-11 17:25:17 +000027#include <asm/localtimer.h>
28#include <asm/arch_timer.h>
Sathish Ambley8a309822011-11-07 14:49:08 -080029#include <asm/sched_clock.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070030#include <asm/hardware/gic.h>
31#include <asm/system_info.h>
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -080032
33static unsigned long arch_timer_rate;
34static int arch_timer_ppi;
35static int arch_timer_ppi2;
Abhimanyu Kapur05b66442012-05-31 23:28:23 -070036static int is_irq_percpu;
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -080037
Marc Zyngierdf590cc2012-01-11 17:25:17 +000038static struct clock_event_device __percpu **arch_timer_evt;
Abhimanyu Kapur05b66442012-05-31 23:28:23 -070039static void __iomem *timer_base;
40
41static u32 timer_reg_read_cp15(int reg);
42static void timer_reg_write_cp15(int reg, u32 val);
43static inline cycle_t counter_get_cntpct_cp15(void);
44static inline cycle_t counter_get_cntvct_cp15(void);
45
46static u32 timer_reg_read_mem(int reg);
47static void timer_reg_write_mem(int reg, u32 val);
48static inline cycle_t counter_get_cntpct_mem(void);
49static inline cycle_t counter_get_cntvct_mem(void);
50
51struct arch_timer_operations {
52 void (*reg_write)(int, u32);
53 u32 (*reg_read)(int);
54 cycle_t (*get_cntpct)(void);
55 cycle_t (*get_cntvct)(void);
56};
57
58static struct arch_timer_operations arch_timer_ops_cp15 = {
59 .reg_read = &timer_reg_read_cp15,
60 .reg_write = &timer_reg_write_cp15,
61 .get_cntpct = &counter_get_cntpct_cp15,
62 .get_cntvct = &counter_get_cntvct_cp15,
63};
64
65static struct arch_timer_operations arch_timer_ops_mem = {
66 .reg_read = &timer_reg_read_mem,
67 .reg_write = &timer_reg_write_mem,
68 .get_cntpct = &counter_get_cntpct_mem,
69 .get_cntvct = &counter_get_cntvct_mem,
70};
71
72static struct arch_timer_operations *arch_specific_timer = &arch_timer_ops_cp15;
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -080073
74/*
75 * Architected system timer support.
76 */
77
78#define ARCH_TIMER_CTRL_ENABLE (1 << 0)
79#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
Marc Zyngierdf590cc2012-01-11 17:25:17 +000080#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -080081
82#define ARCH_TIMER_REG_CTRL 0
83#define ARCH_TIMER_REG_FREQ 1
84#define ARCH_TIMER_REG_TVAL 2
85
Abhimanyu Kapur05b66442012-05-31 23:28:23 -070086/* Iomapped Register Offsets */
87#define QTIMER_CNTP_LOW_REG 0x000
88#define QTIMER_CNTP_HIGH_REG 0x004
89#define QTIMER_CNTV_LOW_REG 0x008
90#define QTIMER_CNTV_HIGH_REG 0x00C
91#define QTIMER_CTRL_REG 0x02C
92#define QTIMER_FREQ_REG 0x010
93#define QTIMER_CNTP_TVAL_REG 0x028
94#define QTIMER_CNTV_TVAL_REG 0x038
95
96static void timer_reg_write_mem(int reg, u32 val)
97{
98 switch (reg) {
99 case ARCH_TIMER_REG_CTRL:
100 __raw_writel(val, timer_base + QTIMER_CTRL_REG);
101 break;
102 case ARCH_TIMER_REG_TVAL:
103 __raw_writel(val, timer_base + QTIMER_CNTP_TVAL_REG);
104 break;
105 }
106}
107
108static void timer_reg_write_cp15(int reg, u32 val)
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800109{
110 switch (reg) {
111 case ARCH_TIMER_REG_CTRL:
112 asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val));
113 break;
114 case ARCH_TIMER_REG_TVAL:
115 asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val));
116 break;
117 }
118
119 isb();
120}
121
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700122static u32 timer_reg_read_mem(int reg)
123{
124 u32 val;
125
126 switch (reg) {
127 case ARCH_TIMER_REG_CTRL:
128 val = __raw_readl(timer_base + QTIMER_CTRL_REG);
129 break;
130 case ARCH_TIMER_REG_FREQ:
131 val = __raw_readl(timer_base + QTIMER_FREQ_REG);
132 break;
133 case ARCH_TIMER_REG_TVAL:
134 val = __raw_readl(timer_base + QTIMER_CNTP_TVAL_REG);
135 break;
136 default:
137 BUG();
138 }
139
140 return val;
141}
142
143static u32 timer_reg_read_cp15(int reg)
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800144{
145 u32 val;
146
147 switch (reg) {
148 case ARCH_TIMER_REG_CTRL:
149 asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
150 break;
151 case ARCH_TIMER_REG_FREQ:
152 asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val));
153 break;
154 case ARCH_TIMER_REG_TVAL:
155 asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
156 break;
157 default:
158 BUG();
159 }
160
161 return val;
162}
163
164static irqreturn_t arch_timer_handler(int irq, void *dev_id)
165{
Sathish Ambley8a309822011-11-07 14:49:08 -0800166 struct clock_event_device *evt;
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800167 unsigned long ctrl;
168
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700169 ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000170 if (ctrl & ARCH_TIMER_CTRL_IT_STAT) {
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800171 ctrl |= ARCH_TIMER_CTRL_IT_MASK;
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700172 arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL,
173 ctrl);
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000174 evt = *__this_cpu_ptr(arch_timer_evt);
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800175 evt->event_handler(evt);
176 return IRQ_HANDLED;
177 }
178
179 return IRQ_NONE;
180}
181
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000182static void arch_timer_disable(void)
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800183{
184 unsigned long ctrl;
185
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700186 ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800187 ctrl &= ~ARCH_TIMER_CTRL_ENABLE;
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700188 arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800189}
190
191static void arch_timer_set_mode(enum clock_event_mode mode,
192 struct clock_event_device *clk)
193{
194 switch (mode) {
195 case CLOCK_EVT_MODE_UNUSED:
196 case CLOCK_EVT_MODE_SHUTDOWN:
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000197 arch_timer_disable();
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800198 break;
199 default:
200 break;
201 }
202}
203
204static int arch_timer_set_next_event(unsigned long evt,
205 struct clock_event_device *unused)
206{
207 unsigned long ctrl;
208
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700209 ctrl = arch_specific_timer->reg_read(ARCH_TIMER_REG_CTRL);
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800210 ctrl |= ARCH_TIMER_CTRL_ENABLE;
211 ctrl &= ~ARCH_TIMER_CTRL_IT_MASK;
212
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700213 arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, ctrl);
214 arch_specific_timer->reg_write(ARCH_TIMER_REG_TVAL, evt);
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800215
216 return 0;
217}
218
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000219static int __cpuinit arch_timer_setup(struct clock_event_device *clk)
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800220{
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000221 /* setup clock event only once for CPU 0 */
222 if (!smp_processor_id() && clk->irq == arch_timer_ppi)
223 return 0;
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800224
225 /* Be safe... */
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000226 arch_timer_disable();
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800227
228 clk->features = CLOCK_EVT_FEAT_ONESHOT;
229 clk->name = "arch_sys_timer";
230 clk->rating = 450;
231 clk->set_mode = arch_timer_set_mode;
232 clk->set_next_event = arch_timer_set_next_event;
233 clk->irq = arch_timer_ppi;
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800234
235 clockevents_config_and_register(clk, arch_timer_rate,
236 0xf, 0x7fffffff);
237
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000238 *__this_cpu_ptr(arch_timer_evt) = clk;
239
240 enable_percpu_irq(clk->irq, 0);
241 if (arch_timer_ppi2)
Trilok Sonieecb28c2011-07-20 16:24:14 +0100242 enable_percpu_irq(arch_timer_ppi2, 0);
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000243
244 return 0;
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800245}
246
247/* Is the optional system timer available? */
248static int local_timer_is_architected(void)
249{
250 return (cpu_architecture() >= CPU_ARCH_ARMv7) &&
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700251 ((read_cpuid_ext(CPUID_EXT_PFR1) >> 16) & 0xf) == 1;
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800252}
253
254static int arch_timer_available(void)
255{
256 unsigned long freq;
257
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800258 if (arch_timer_rate == 0) {
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700259 arch_specific_timer->reg_write(ARCH_TIMER_REG_CTRL, 0);
260 freq = arch_specific_timer->reg_read(ARCH_TIMER_REG_FREQ);
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800261
262 /* Check the timer frequency. */
263 if (freq == 0) {
264 pr_warn("Architected timer frequency not available\n");
265 return -EINVAL;
266 }
267
268 arch_timer_rate = freq;
269 pr_info("Architected local timer running at %lu.%02luMHz.\n",
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000270 freq / 1000000, (freq / 10000) % 100);
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800271 }
272
273 return 0;
274}
275
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700276static inline cycle_t counter_get_cntpct_mem(void)
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800277{
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700278 u32 cvall, cvalh, thigh;
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800279
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700280 do {
281 cvalh = __raw_readl(timer_base + QTIMER_CNTP_HIGH_REG);
282 cvall = __raw_readl(timer_base + QTIMER_CNTP_LOW_REG);
283 thigh = __raw_readl(timer_base + QTIMER_CNTP_HIGH_REG);
284 } while (cvalh != thigh);
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800285
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000286 return ((cycle_t) cvalh << 32) | cvall;
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800287}
288
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700289static inline cycle_t counter_get_cntpct_cp15(void)
290{
291 u32 cvall, cvalh;
292
293 asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
294 return ((cycle_t) cvalh << 32) | cvall;
295}
296
297static inline cycle_t counter_get_cntvct_mem(void)
298{
299 u32 cvall, cvalh, thigh;
300
301 do {
302 cvalh = __raw_readl(timer_base + QTIMER_CNTV_HIGH_REG);
303 cvall = __raw_readl(timer_base + QTIMER_CNTV_LOW_REG);
304 thigh = __raw_readl(timer_base + QTIMER_CNTV_HIGH_REG);
305 } while (cvalh != thigh);
306
307 return ((cycle_t) cvalh << 32) | cvall;
308}
309
310static inline cycle_t counter_get_cntvct_cp15(void)
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800311{
312 u32 cvall, cvalh;
313
314 asm volatile("mrrc p15, 1, %0, %1, c14" : "=r" (cvall), "=r" (cvalh));
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000315 return ((cycle_t) cvalh << 32) | cvall;
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800316}
317
318static cycle_t arch_counter_read(struct clocksource *cs)
319{
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700320 return arch_specific_timer->get_cntpct();
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800321}
322
Sathish Ambley8a309822011-11-07 14:49:08 -0800323#ifdef ARCH_HAS_READ_CURRENT_TIMER
324int read_current_timer(unsigned long *timer_val)
325{
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700326 *timer_val = (unsigned long)arch_specific_timer->get_cntpct();
Sathish Ambley8a309822011-11-07 14:49:08 -0800327 return 0;
328}
329#endif
330
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800331static struct clocksource clocksource_counter = {
332 .name = "arch_sys_counter",
333 .rating = 400,
334 .read = arch_counter_read,
335 .mask = CLOCKSOURCE_MASK(56),
336 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
337};
338
Marc Zyngier165a4742011-11-11 14:30:44 -0800339static u32 arch_counter_get_cntvct32(void)
340{
341 cycle_t cntvct;
342
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700343 cntvct = arch_specific_timer->get_cntvct();
Marc Zyngier165a4742011-11-11 14:30:44 -0800344
345 /*
346 * The sched_clock infrastructure only knows about counters
347 * with at most 32bits. Forget about the upper 24 bits for the
348 * time being...
349 */
350 return (u32)(cntvct & (u32)~0);
351}
352
Steve Mucklef132c6c2012-06-06 18:30:57 -0700353static u32 notrace arch_timer_update_sched_clock(void)
Marc Zyngier165a4742011-11-11 14:30:44 -0800354{
Steve Mucklef132c6c2012-06-06 18:30:57 -0700355 return arch_counter_get_cntvct32();
Marc Zyngier165a4742011-11-11 14:30:44 -0800356}
357
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000358static void __cpuinit arch_timer_stop(struct clock_event_device *clk)
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800359{
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800360 pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n",
361 clk->irq, smp_processor_id());
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000362 disable_percpu_irq(clk->irq);
363 if (arch_timer_ppi2)
Trilok Sonieecb28c2011-07-20 16:24:14 +0100364 disable_percpu_irq(arch_timer_ppi2);
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800365 arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
366}
367
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000368static struct local_timer_ops arch_timer_ops __cpuinitdata = {
369 .setup = arch_timer_setup,
370 .stop = arch_timer_stop,
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800371};
372
Marc Zyngierf2caa512012-01-19 13:53:50 +0000373static int __init arch_timer_common_register(void)
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800374{
375 int err;
376
Rohit Vaswani67770332012-06-18 13:27:45 -0700377 if (timer_base)
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700378 arch_specific_timer = &arch_timer_ops_mem;
Rohit Vaswani67770332012-06-18 13:27:45 -0700379 else if (!local_timer_is_architected())
380 return -ENXIO;
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700381
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800382 err = arch_timer_available();
383 if (err)
384 return err;
385
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000386 arch_timer_evt = alloc_percpu(struct clock_event_device *);
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800387 if (!arch_timer_evt)
388 return -ENOMEM;
389
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800390 clocksource_register_hz(&clocksource_counter, arch_timer_rate);
391
Steve Mucklef132c6c2012-06-06 18:30:57 -0700392 setup_sched_clock(arch_timer_update_sched_clock, 32, arch_timer_rate);
Sathish Ambley8a309822011-11-07 14:49:08 -0800393
394#ifdef ARCH_HAS_READ_CURRENT_TIMER
395 set_delay_fn(read_current_timer_delay_loop);
396#endif
397
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700398 if (is_irq_percpu)
399 err = request_percpu_irq(arch_timer_ppi, arch_timer_handler,
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000400 "arch_timer", arch_timer_evt);
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700401 else
402 err = request_irq(arch_timer_ppi, arch_timer_handler, 0,
403 "arch_timer", arch_timer_evt);
Sathish Ambley8a309822011-11-07 14:49:08 -0800404 if (err) {
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000405 pr_err("arch_timer: can't register interrupt %d (%d)\n",
406 arch_timer_ppi, err);
407 goto out_free;
Sathish Ambley8a309822011-11-07 14:49:08 -0800408 }
409
Marc Zyngierf2caa512012-01-19 13:53:50 +0000410 if (arch_timer_ppi2) {
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700411 if (is_irq_percpu)
412 err = request_percpu_irq(arch_timer_ppi2,
413 arch_timer_handler, "arch_timer",
414 arch_timer_evt);
415 else
416 err = request_irq(arch_timer_ppi2, arch_timer_handler,
417 0, "arch_timer", arch_timer_evt);
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000418 if (err) {
419 pr_err("arch_timer: can't register interrupt %d (%d)\n",
420 arch_timer_ppi2, err);
421 arch_timer_ppi2 = 0;
422 goto out_free_irq;
423 }
Sathish Ambley8a309822011-11-07 14:49:08 -0800424 }
Marc Zyngier165a4742011-11-11 14:30:44 -0800425
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000426 err = local_timer_register(&arch_timer_ops);
427 if (err)
428 goto out_free_irq;
429 percpu_timer_setup();
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800430
431 return 0;
Marc Zyngierdf590cc2012-01-11 17:25:17 +0000432
433out_free_irq:
434 free_percpu_irq(arch_timer_ppi, arch_timer_evt);
435 if (arch_timer_ppi2)
436 free_percpu_irq(arch_timer_ppi2, arch_timer_evt);
437
438out_free:
439 free_percpu(arch_timer_evt);
440
441 return err;
Marc Zyngierf5b3b2b2011-11-07 14:28:33 -0800442}
Marc Zyngierf2caa512012-01-19 13:53:50 +0000443
444int __init arch_timer_register(struct arch_timer *at)
445{
446 if (at->res[0].start <= 0 || !(at->res[0].flags & IORESOURCE_IRQ))
447 return -EINVAL;
448
449 arch_timer_ppi = at->res[0].start;
450
451 if (at->res[1].start > 0 && (at->res[1].flags & IORESOURCE_IRQ))
452 arch_timer_ppi2 = at->res[1].start;
453
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700454 if (at->res[2].start > 0 && at->res[2].end > 0 &&
455 (at->res[2].flags & IORESOURCE_MEM))
456 timer_base = ioremap(at->res[2].start,
457 resource_size(&at->res[2]));
458
459 if (!timer_base) {
460 pr_err("arch_timer: cant map timer base\n");
461 return -ENOMEM;
462 }
463
Marc Zyngierf2caa512012-01-19 13:53:50 +0000464 return arch_timer_common_register();
465}
466
467#ifdef CONFIG_OF
468static const struct of_device_id arch_timer_of_match[] __initconst = {
469 { .compatible = "arm,armv7-timer", },
470 {},
471};
472
473int __init arch_timer_of_register(void)
474{
475 struct device_node *np;
476 u32 freq;
477 int ret;
478
479 np = of_find_matching_node(NULL, arch_timer_of_match);
480 if (!np) {
481 pr_err("arch_timer: can't find DT node\n");
482 return -ENODEV;
483 }
484
485 /* Try to determine the frequency from the device tree or CNTFRQ */
486 if (!of_property_read_u32(np, "clock-frequency", &freq))
487 arch_timer_rate = freq;
488
489 ret = irq_of_parse_and_map(np, 0);
490 if (ret <= 0) {
491 pr_err("arch_timer: interrupt not specified in timer node\n");
492 return -ENODEV;
493 }
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700494
Rohit Vaswani67770332012-06-18 13:27:45 -0700495 if (of_get_address(np, 0, NULL, NULL)) {
496 timer_base = of_iomap(np, 0);
497 if (!timer_base) {
498 pr_err("arch_timer: cant map timer base\n");
499 return -ENOMEM;
500 }
Abhimanyu Kapur05b66442012-05-31 23:28:23 -0700501 }
502
503 if (of_get_property(np, "irq-is-not-percpu", NULL))
504 is_irq_percpu = 0;
505 else
506 is_irq_percpu = 1;
507
Marc Zyngierf2caa512012-01-19 13:53:50 +0000508 arch_timer_ppi = ret;
509 ret = irq_of_parse_and_map(np, 1);
510 if (ret > 0)
511 arch_timer_ppi2 = ret;
512 pr_info("arch_timer: found %s irqs %d %d\n",
513 np->name, arch_timer_ppi, arch_timer_ppi2);
514
515 return arch_timer_common_register();
516}
517#endif