Commit | Line | Data |
---|---|---|
022c03a2 MZ |
1 | /* |
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> | |
14 | #include <linux/device.h> | |
15 | #include <linux/smp.h> | |
16 | #include <linux/cpu.h> | |
17 | #include <linux/jiffies.h> | |
18 | #include <linux/clockchips.h> | |
19 | #include <linux/interrupt.h> | |
0075242b | 20 | #include <linux/of_irq.h> |
022c03a2 MZ |
21 | #include <linux/io.h> |
22 | ||
23 | #include <asm/cputype.h> | |
24 | #include <asm/localtimer.h> | |
25 | #include <asm/arch_timer.h> | |
26 | #include <asm/system_info.h> | |
3f61c80e | 27 | #include <asm/sched_clock.h> |
022c03a2 MZ |
28 | |
29 | static unsigned long arch_timer_rate; | |
30 | static int arch_timer_ppi; | |
31 | static int arch_timer_ppi2; | |
32 | ||
33 | static struct clock_event_device __percpu **arch_timer_evt; | |
34 | ||
35 | /* | |
36 | * Architected system timer support. | |
37 | */ | |
38 | ||
39 | #define ARCH_TIMER_CTRL_ENABLE (1 << 0) | |
40 | #define ARCH_TIMER_CTRL_IT_MASK (1 << 1) | |
41 | #define ARCH_TIMER_CTRL_IT_STAT (1 << 2) | |
42 | ||
43 | #define ARCH_TIMER_REG_CTRL 0 | |
44 | #define ARCH_TIMER_REG_FREQ 1 | |
45 | #define ARCH_TIMER_REG_TVAL 2 | |
46 | ||
47 | static void arch_timer_reg_write(int reg, u32 val) | |
48 | { | |
49 | switch (reg) { | |
50 | case ARCH_TIMER_REG_CTRL: | |
51 | asm volatile("mcr p15, 0, %0, c14, c2, 1" : : "r" (val)); | |
52 | break; | |
53 | case ARCH_TIMER_REG_TVAL: | |
54 | asm volatile("mcr p15, 0, %0, c14, c2, 0" : : "r" (val)); | |
55 | break; | |
56 | } | |
57 | ||
58 | isb(); | |
59 | } | |
60 | ||
61 | static u32 arch_timer_reg_read(int reg) | |
62 | { | |
63 | u32 val; | |
64 | ||
65 | switch (reg) { | |
66 | case ARCH_TIMER_REG_CTRL: | |
67 | asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val)); | |
68 | break; | |
69 | case ARCH_TIMER_REG_FREQ: | |
70 | asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val)); | |
71 | break; | |
72 | case ARCH_TIMER_REG_TVAL: | |
73 | asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val)); | |
74 | break; | |
75 | default: | |
76 | BUG(); | |
77 | } | |
78 | ||
79 | return val; | |
80 | } | |
81 | ||
82 | static irqreturn_t arch_timer_handler(int irq, void *dev_id) | |
83 | { | |
84 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; | |
85 | unsigned long ctrl; | |
86 | ||
87 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | |
88 | if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { | |
89 | ctrl |= ARCH_TIMER_CTRL_IT_MASK; | |
90 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | |
91 | evt->event_handler(evt); | |
92 | return IRQ_HANDLED; | |
93 | } | |
94 | ||
95 | return IRQ_NONE; | |
96 | } | |
97 | ||
98 | static void arch_timer_disable(void) | |
99 | { | |
100 | unsigned long ctrl; | |
101 | ||
102 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | |
103 | ctrl &= ~ARCH_TIMER_CTRL_ENABLE; | |
104 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | |
105 | } | |
106 | ||
107 | static void arch_timer_set_mode(enum clock_event_mode mode, | |
108 | struct clock_event_device *clk) | |
109 | { | |
110 | switch (mode) { | |
111 | case CLOCK_EVT_MODE_UNUSED: | |
112 | case CLOCK_EVT_MODE_SHUTDOWN: | |
113 | arch_timer_disable(); | |
114 | break; | |
115 | default: | |
116 | break; | |
117 | } | |
118 | } | |
119 | ||
120 | static int arch_timer_set_next_event(unsigned long evt, | |
121 | struct clock_event_device *unused) | |
122 | { | |
123 | unsigned long ctrl; | |
124 | ||
125 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | |
126 | ctrl |= ARCH_TIMER_CTRL_ENABLE; | |
127 | ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; | |
128 | ||
129 | arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt); | |
130 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | |
131 | ||
132 | return 0; | |
133 | } | |
134 | ||
135 | static int __cpuinit arch_timer_setup(struct clock_event_device *clk) | |
136 | { | |
137 | /* Be safe... */ | |
138 | arch_timer_disable(); | |
139 | ||
140 | clk->features = CLOCK_EVT_FEAT_ONESHOT; | |
141 | clk->name = "arch_sys_timer"; | |
142 | clk->rating = 450; | |
143 | clk->set_mode = arch_timer_set_mode; | |
144 | clk->set_next_event = arch_timer_set_next_event; | |
145 | clk->irq = arch_timer_ppi; | |
146 | ||
147 | clockevents_config_and_register(clk, arch_timer_rate, | |
148 | 0xf, 0x7fffffff); | |
149 | ||
150 | *__this_cpu_ptr(arch_timer_evt) = clk; | |
151 | ||
152 | enable_percpu_irq(clk->irq, 0); | |
153 | if (arch_timer_ppi2) | |
154 | enable_percpu_irq(arch_timer_ppi2, 0); | |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
159 | /* Is the optional system timer available? */ | |
160 | static int local_timer_is_architected(void) | |
161 | { | |
162 | return (cpu_architecture() >= CPU_ARCH_ARMv7) && | |
163 | ((read_cpuid_ext(CPUID_EXT_PFR1) >> 16) & 0xf) == 1; | |
164 | } | |
165 | ||
166 | static int arch_timer_available(void) | |
167 | { | |
168 | unsigned long freq; | |
169 | ||
170 | if (!local_timer_is_architected()) | |
171 | return -ENXIO; | |
172 | ||
173 | if (arch_timer_rate == 0) { | |
174 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0); | |
175 | freq = arch_timer_reg_read(ARCH_TIMER_REG_FREQ); | |
176 | ||
177 | /* Check the timer frequency. */ | |
178 | if (freq == 0) { | |
179 | pr_warn("Architected timer frequency not available\n"); | |
180 | return -EINVAL; | |
181 | } | |
182 | ||
183 | arch_timer_rate = freq; | |
184 | } | |
185 | ||
186 | pr_info_once("Architected local timer running at %lu.%02luMHz.\n", | |
187 | arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100); | |
188 | return 0; | |
189 | } | |
190 | ||
191 | static inline cycle_t arch_counter_get_cntpct(void) | |
192 | { | |
193 | u32 cvall, cvalh; | |
194 | ||
195 | asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (cvall), "=r" (cvalh)); | |
196 | ||
197 | return ((cycle_t) cvalh << 32) | cvall; | |
198 | } | |
199 | ||
200 | static inline cycle_t arch_counter_get_cntvct(void) | |
201 | { | |
202 | u32 cvall, cvalh; | |
203 | ||
204 | asm volatile("mrrc p15, 1, %0, %1, c14" : "=r" (cvall), "=r" (cvalh)); | |
205 | ||
206 | return ((cycle_t) cvalh << 32) | cvall; | |
207 | } | |
208 | ||
3f61c80e MZ |
209 | static u32 notrace arch_counter_get_cntvct32(void) |
210 | { | |
211 | cycle_t cntvct = arch_counter_get_cntvct(); | |
212 | ||
213 | /* | |
214 | * The sched_clock infrastructure only knows about counters | |
215 | * with at most 32bits. Forget about the upper 24 bits for the | |
216 | * time being... | |
217 | */ | |
218 | return (u32)(cntvct & (u32)~0); | |
219 | } | |
220 | ||
022c03a2 MZ |
221 | static cycle_t arch_counter_read(struct clocksource *cs) |
222 | { | |
223 | return arch_counter_get_cntpct(); | |
224 | } | |
225 | ||
226 | static struct clocksource clocksource_counter = { | |
227 | .name = "arch_sys_counter", | |
228 | .rating = 400, | |
229 | .read = arch_counter_read, | |
230 | .mask = CLOCKSOURCE_MASK(56), | |
231 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | |
232 | }; | |
233 | ||
234 | static void __cpuinit arch_timer_stop(struct clock_event_device *clk) | |
235 | { | |
236 | pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n", | |
237 | clk->irq, smp_processor_id()); | |
238 | disable_percpu_irq(clk->irq); | |
239 | if (arch_timer_ppi2) | |
240 | disable_percpu_irq(arch_timer_ppi2); | |
241 | arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk); | |
242 | } | |
243 | ||
244 | static struct local_timer_ops arch_timer_ops __cpuinitdata = { | |
245 | .setup = arch_timer_setup, | |
246 | .stop = arch_timer_stop, | |
247 | }; | |
248 | ||
0075242b | 249 | static int __init arch_timer_common_register(void) |
022c03a2 MZ |
250 | { |
251 | int err; | |
252 | ||
022c03a2 MZ |
253 | err = arch_timer_available(); |
254 | if (err) | |
255 | return err; | |
256 | ||
257 | arch_timer_evt = alloc_percpu(struct clock_event_device *); | |
258 | if (!arch_timer_evt) | |
259 | return -ENOMEM; | |
260 | ||
261 | clocksource_register_hz(&clocksource_counter, arch_timer_rate); | |
262 | ||
022c03a2 MZ |
263 | err = request_percpu_irq(arch_timer_ppi, arch_timer_handler, |
264 | "arch_timer", arch_timer_evt); | |
265 | if (err) { | |
266 | pr_err("arch_timer: can't register interrupt %d (%d)\n", | |
267 | arch_timer_ppi, err); | |
268 | goto out_free; | |
269 | } | |
270 | ||
0075242b | 271 | if (arch_timer_ppi2) { |
022c03a2 MZ |
272 | err = request_percpu_irq(arch_timer_ppi2, arch_timer_handler, |
273 | "arch_timer", arch_timer_evt); | |
274 | if (err) { | |
275 | pr_err("arch_timer: can't register interrupt %d (%d)\n", | |
276 | arch_timer_ppi2, err); | |
277 | arch_timer_ppi2 = 0; | |
278 | goto out_free_irq; | |
279 | } | |
280 | } | |
281 | ||
282 | err = local_timer_register(&arch_timer_ops); | |
283 | if (err) | |
284 | goto out_free_irq; | |
285 | ||
286 | return 0; | |
287 | ||
288 | out_free_irq: | |
289 | free_percpu_irq(arch_timer_ppi, arch_timer_evt); | |
290 | if (arch_timer_ppi2) | |
291 | free_percpu_irq(arch_timer_ppi2, arch_timer_evt); | |
292 | ||
293 | out_free: | |
294 | free_percpu(arch_timer_evt); | |
295 | ||
296 | return err; | |
297 | } | |
3f61c80e | 298 | |
0075242b MZ |
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 | ||
3f61c80e MZ |
342 | int __init arch_timer_sched_clock_init(void) |
343 | { | |
344 | int err; | |
345 | ||
346 | err = arch_timer_available(); | |
347 | if (err) | |
348 | return err; | |
349 | ||
350 | setup_sched_clock(arch_counter_get_cntvct32, 32, arch_timer_rate); | |
351 | return 0; | |
352 | } |