diff options
Diffstat (limited to 'drivers/clocksource')
-rw-r--r-- | drivers/clocksource/Kconfig | 12 | ||||
-rw-r--r-- | drivers/clocksource/Makefile | 5 | ||||
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 391 | ||||
-rw-r--r-- | drivers/clocksource/arm_generic.c | 232 | ||||
-rw-r--r-- | drivers/clocksource/bcm2835_timer.c | 9 | ||||
-rw-r--r-- | drivers/clocksource/clksrc-of.c | 35 | ||||
-rw-r--r-- | drivers/clocksource/cs5535-clockevt.c | 11 | ||||
-rw-r--r-- | drivers/clocksource/dw_apb_timer_of.c | 6 | ||||
-rw-r--r-- | drivers/clocksource/nomadik-mtu.c | 45 | ||||
-rw-r--r-- | drivers/clocksource/sunxi_timer.c | 21 | ||||
-rw-r--r-- | drivers/clocksource/tcb_clksrc.c | 7 | ||||
-rw-r--r-- | drivers/clocksource/tegra20_timer.c | 281 | ||||
-rw-r--r-- | drivers/clocksource/time-armada-370-xp.c | 150 | ||||
-rw-r--r-- | drivers/clocksource/vt8500_timer.c | 180 |
14 files changed, 1055 insertions, 330 deletions
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 75bc7520ace5..e507ab7df60b 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -1,3 +1,6 @@ | |||
1 | config CLKSRC_OF | ||
2 | bool | ||
3 | |||
1 | config CLKSRC_I8253 | 4 | config CLKSRC_I8253 |
2 | bool | 5 | bool |
3 | 6 | ||
@@ -25,6 +28,9 @@ config ARMADA_370_XP_TIMER | |||
25 | config SUNXI_TIMER | 28 | config SUNXI_TIMER |
26 | bool | 29 | bool |
27 | 30 | ||
31 | config VT8500_TIMER | ||
32 | bool | ||
33 | |||
28 | config CLKSRC_NOMADIK_MTU | 34 | config CLKSRC_NOMADIK_MTU |
29 | bool | 35 | bool |
30 | depends on (ARCH_NOMADIK || ARCH_U8500) | 36 | depends on (ARCH_NOMADIK || ARCH_U8500) |
@@ -54,10 +60,8 @@ config CLKSRC_DBX500_PRCMU_SCHED_CLOCK | |||
54 | help | 60 | help |
55 | Use the always on PRCMU Timer as sched_clock | 61 | Use the always on PRCMU Timer as sched_clock |
56 | 62 | ||
57 | config CLKSRC_ARM_GENERIC | 63 | config ARM_ARCH_TIMER |
58 | def_bool y if ARM64 | 64 | bool |
59 | help | ||
60 | This option enables support for the ARM generic timer. | ||
61 | 65 | ||
62 | config CLKSRC_METAG_GENERIC | 66 | config CLKSRC_METAG_GENERIC |
63 | def_bool y if METAG | 67 | def_bool y if METAG |
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 09dcd49b7e31..4d8283aec5b5 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-$(CONFIG_CLKSRC_OF) += clksrc-of.o | ||
1 | obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o | 2 | obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o |
2 | obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o | 3 | obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o |
3 | obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o | 4 | obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o |
@@ -16,6 +17,8 @@ obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o | |||
16 | obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o | 17 | obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o |
17 | obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o | 18 | obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o |
18 | obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o | 19 | obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o |
20 | obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o | ||
21 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o | ||
19 | 22 | ||
20 | obj-$(CONFIG_CLKSRC_ARM_GENERIC) += arm_generic.o | 23 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o |
21 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o | 24 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o |
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c new file mode 100644 index 000000000000..d7ad425ab9b3 --- /dev/null +++ b/drivers/clocksource/arm_arch_timer.c | |||
@@ -0,0 +1,391 @@ | |||
1 | /* | ||
2 | * linux/drivers/clocksource/arm_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/device.h> | ||
14 | #include <linux/smp.h> | ||
15 | #include <linux/cpu.h> | ||
16 | #include <linux/clockchips.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/of_irq.h> | ||
19 | #include <linux/io.h> | ||
20 | |||
21 | #include <asm/arch_timer.h> | ||
22 | #include <asm/virt.h> | ||
23 | |||
24 | #include <clocksource/arm_arch_timer.h> | ||
25 | |||
26 | static u32 arch_timer_rate; | ||
27 | |||
28 | enum ppi_nr { | ||
29 | PHYS_SECURE_PPI, | ||
30 | PHYS_NONSECURE_PPI, | ||
31 | VIRT_PPI, | ||
32 | HYP_PPI, | ||
33 | MAX_TIMER_PPI | ||
34 | }; | ||
35 | |||
36 | static int arch_timer_ppi[MAX_TIMER_PPI]; | ||
37 | |||
38 | static struct clock_event_device __percpu *arch_timer_evt; | ||
39 | |||
40 | static bool arch_timer_use_virtual = true; | ||
41 | |||
42 | /* | ||
43 | * Architected system timer support. | ||
44 | */ | ||
45 | |||
46 | static inline irqreturn_t timer_handler(const int access, | ||
47 | struct clock_event_device *evt) | ||
48 | { | ||
49 | unsigned long ctrl; | ||
50 | ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL); | ||
51 | if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { | ||
52 | ctrl |= ARCH_TIMER_CTRL_IT_MASK; | ||
53 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl); | ||
54 | evt->event_handler(evt); | ||
55 | return IRQ_HANDLED; | ||
56 | } | ||
57 | |||
58 | return IRQ_NONE; | ||
59 | } | ||
60 | |||
61 | static irqreturn_t arch_timer_handler_virt(int irq, void *dev_id) | ||
62 | { | ||
63 | struct clock_event_device *evt = dev_id; | ||
64 | |||
65 | return timer_handler(ARCH_TIMER_VIRT_ACCESS, evt); | ||
66 | } | ||
67 | |||
68 | static irqreturn_t arch_timer_handler_phys(int irq, void *dev_id) | ||
69 | { | ||
70 | struct clock_event_device *evt = dev_id; | ||
71 | |||
72 | return timer_handler(ARCH_TIMER_PHYS_ACCESS, evt); | ||
73 | } | ||
74 | |||
75 | static inline void timer_set_mode(const int access, int mode) | ||
76 | { | ||
77 | unsigned long ctrl; | ||
78 | switch (mode) { | ||
79 | case CLOCK_EVT_MODE_UNUSED: | ||
80 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
81 | ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL); | ||
82 | ctrl &= ~ARCH_TIMER_CTRL_ENABLE; | ||
83 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl); | ||
84 | break; | ||
85 | default: | ||
86 | break; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | static void arch_timer_set_mode_virt(enum clock_event_mode mode, | ||
91 | struct clock_event_device *clk) | ||
92 | { | ||
93 | timer_set_mode(ARCH_TIMER_VIRT_ACCESS, mode); | ||
94 | } | ||
95 | |||
96 | static void arch_timer_set_mode_phys(enum clock_event_mode mode, | ||
97 | struct clock_event_device *clk) | ||
98 | { | ||
99 | timer_set_mode(ARCH_TIMER_PHYS_ACCESS, mode); | ||
100 | } | ||
101 | |||
102 | static inline void set_next_event(const int access, unsigned long evt) | ||
103 | { | ||
104 | unsigned long ctrl; | ||
105 | ctrl = arch_timer_reg_read(access, ARCH_TIMER_REG_CTRL); | ||
106 | ctrl |= ARCH_TIMER_CTRL_ENABLE; | ||
107 | ctrl &= ~ARCH_TIMER_CTRL_IT_MASK; | ||
108 | arch_timer_reg_write(access, ARCH_TIMER_REG_TVAL, evt); | ||
109 | arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl); | ||
110 | } | ||
111 | |||
112 | static int arch_timer_set_next_event_virt(unsigned long evt, | ||
113 | struct clock_event_device *unused) | ||
114 | { | ||
115 | set_next_event(ARCH_TIMER_VIRT_ACCESS, evt); | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int arch_timer_set_next_event_phys(unsigned long evt, | ||
120 | struct clock_event_device *unused) | ||
121 | { | ||
122 | set_next_event(ARCH_TIMER_PHYS_ACCESS, evt); | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int __cpuinit arch_timer_setup(struct clock_event_device *clk) | ||
127 | { | ||
128 | clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP; | ||
129 | clk->name = "arch_sys_timer"; | ||
130 | clk->rating = 450; | ||
131 | if (arch_timer_use_virtual) { | ||
132 | clk->irq = arch_timer_ppi[VIRT_PPI]; | ||
133 | clk->set_mode = arch_timer_set_mode_virt; | ||
134 | clk->set_next_event = arch_timer_set_next_event_virt; | ||
135 | } else { | ||
136 | clk->irq = arch_timer_ppi[PHYS_SECURE_PPI]; | ||
137 | clk->set_mode = arch_timer_set_mode_phys; | ||
138 | clk->set_next_event = arch_timer_set_next_event_phys; | ||
139 | } | ||
140 | |||
141 | clk->cpumask = cpumask_of(smp_processor_id()); | ||
142 | |||
143 | clk->set_mode(CLOCK_EVT_MODE_SHUTDOWN, NULL); | ||
144 | |||
145 | clockevents_config_and_register(clk, arch_timer_rate, | ||
146 | 0xf, 0x7fffffff); | ||
147 | |||
148 | if (arch_timer_use_virtual) | ||
149 | enable_percpu_irq(arch_timer_ppi[VIRT_PPI], 0); | ||
150 | else { | ||
151 | enable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], 0); | ||
152 | if (arch_timer_ppi[PHYS_NONSECURE_PPI]) | ||
153 | enable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], 0); | ||
154 | } | ||
155 | |||
156 | arch_counter_set_user_access(); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int arch_timer_available(void) | ||
162 | { | ||
163 | u32 freq; | ||
164 | |||
165 | if (arch_timer_rate == 0) { | ||
166 | freq = arch_timer_get_cntfrq(); | ||
167 | |||
168 | /* Check the timer frequency. */ | ||
169 | if (freq == 0) { | ||
170 | pr_warn("Architected timer frequency not available\n"); | ||
171 | return -EINVAL; | ||
172 | } | ||
173 | |||
174 | arch_timer_rate = freq; | ||
175 | } | ||
176 | |||
177 | pr_info_once("Architected local timer running at %lu.%02luMHz (%s).\n", | ||
178 | (unsigned long)arch_timer_rate / 1000000, | ||
179 | (unsigned long)(arch_timer_rate / 10000) % 100, | ||
180 | arch_timer_use_virtual ? "virt" : "phys"); | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | u32 arch_timer_get_rate(void) | ||
185 | { | ||
186 | return arch_timer_rate; | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * Some external users of arch_timer_read_counter (e.g. sched_clock) may try to | ||
191 | * call it before it has been initialised. Rather than incur a performance | ||
192 | * penalty checking for initialisation, provide a default implementation that | ||
193 | * won't lead to time appearing to jump backwards. | ||
194 | */ | ||
195 | static u64 arch_timer_read_zero(void) | ||
196 | { | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | u64 (*arch_timer_read_counter)(void) = arch_timer_read_zero; | ||
201 | |||
202 | static cycle_t arch_counter_read(struct clocksource *cs) | ||
203 | { | ||
204 | return arch_timer_read_counter(); | ||
205 | } | ||
206 | |||
207 | static cycle_t arch_counter_read_cc(const struct cyclecounter *cc) | ||
208 | { | ||
209 | return arch_timer_read_counter(); | ||
210 | } | ||
211 | |||
212 | static struct clocksource clocksource_counter = { | ||
213 | .name = "arch_sys_counter", | ||
214 | .rating = 400, | ||
215 | .read = arch_counter_read, | ||
216 | .mask = CLOCKSOURCE_MASK(56), | ||
217 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
218 | }; | ||
219 | |||
220 | static struct cyclecounter cyclecounter = { | ||
221 | .read = arch_counter_read_cc, | ||
222 | .mask = CLOCKSOURCE_MASK(56), | ||
223 | }; | ||
224 | |||
225 | static struct timecounter timecounter; | ||
226 | |||
227 | struct timecounter *arch_timer_get_timecounter(void) | ||
228 | { | ||
229 | return &timecounter; | ||
230 | } | ||
231 | |||
232 | static void __cpuinit arch_timer_stop(struct clock_event_device *clk) | ||
233 | { | ||
234 | pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n", | ||
235 | clk->irq, smp_processor_id()); | ||
236 | |||
237 | if (arch_timer_use_virtual) | ||
238 | disable_percpu_irq(arch_timer_ppi[VIRT_PPI]); | ||
239 | else { | ||
240 | disable_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI]); | ||
241 | if (arch_timer_ppi[PHYS_NONSECURE_PPI]) | ||
242 | disable_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI]); | ||
243 | } | ||
244 | |||
245 | clk->set_mode(CLOCK_EVT_MODE_UNUSED, clk); | ||
246 | } | ||
247 | |||
248 | static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, | ||
249 | unsigned long action, void *hcpu) | ||
250 | { | ||
251 | struct clock_event_device *evt = this_cpu_ptr(arch_timer_evt); | ||
252 | |||
253 | switch (action & ~CPU_TASKS_FROZEN) { | ||
254 | case CPU_STARTING: | ||
255 | arch_timer_setup(evt); | ||
256 | break; | ||
257 | case CPU_DYING: | ||
258 | arch_timer_stop(evt); | ||
259 | break; | ||
260 | } | ||
261 | |||
262 | return NOTIFY_OK; | ||
263 | } | ||
264 | |||
265 | static struct notifier_block arch_timer_cpu_nb __cpuinitdata = { | ||
266 | .notifier_call = arch_timer_cpu_notify, | ||
267 | }; | ||
268 | |||
269 | static int __init arch_timer_register(void) | ||
270 | { | ||
271 | int err; | ||
272 | int ppi; | ||
273 | |||
274 | err = arch_timer_available(); | ||
275 | if (err) | ||
276 | goto out; | ||
277 | |||
278 | arch_timer_evt = alloc_percpu(struct clock_event_device); | ||
279 | if (!arch_timer_evt) { | ||
280 | err = -ENOMEM; | ||
281 | goto out; | ||
282 | } | ||
283 | |||
284 | clocksource_register_hz(&clocksource_counter, arch_timer_rate); | ||
285 | cyclecounter.mult = clocksource_counter.mult; | ||
286 | cyclecounter.shift = clocksource_counter.shift; | ||
287 | timecounter_init(&timecounter, &cyclecounter, | ||
288 | arch_counter_get_cntpct()); | ||
289 | |||
290 | if (arch_timer_use_virtual) { | ||
291 | ppi = arch_timer_ppi[VIRT_PPI]; | ||
292 | err = request_percpu_irq(ppi, arch_timer_handler_virt, | ||
293 | "arch_timer", arch_timer_evt); | ||
294 | } else { | ||
295 | ppi = arch_timer_ppi[PHYS_SECURE_PPI]; | ||
296 | err = request_percpu_irq(ppi, arch_timer_handler_phys, | ||
297 | "arch_timer", arch_timer_evt); | ||
298 | if (!err && arch_timer_ppi[PHYS_NONSECURE_PPI]) { | ||
299 | ppi = arch_timer_ppi[PHYS_NONSECURE_PPI]; | ||
300 | err = request_percpu_irq(ppi, arch_timer_handler_phys, | ||
301 | "arch_timer", arch_timer_evt); | ||
302 | if (err) | ||
303 | free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], | ||
304 | arch_timer_evt); | ||
305 | } | ||
306 | } | ||
307 | |||
308 | if (err) { | ||
309 | pr_err("arch_timer: can't register interrupt %d (%d)\n", | ||
310 | ppi, err); | ||
311 | goto out_free; | ||
312 | } | ||
313 | |||
314 | err = register_cpu_notifier(&arch_timer_cpu_nb); | ||
315 | if (err) | ||
316 | goto out_free_irq; | ||
317 | |||
318 | /* Immediately configure the timer on the boot CPU */ | ||
319 | arch_timer_setup(this_cpu_ptr(arch_timer_evt)); | ||
320 | |||
321 | return 0; | ||
322 | |||
323 | out_free_irq: | ||
324 | if (arch_timer_use_virtual) | ||
325 | free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt); | ||
326 | else { | ||
327 | free_percpu_irq(arch_timer_ppi[PHYS_SECURE_PPI], | ||
328 | arch_timer_evt); | ||
329 | if (arch_timer_ppi[PHYS_NONSECURE_PPI]) | ||
330 | free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI], | ||
331 | arch_timer_evt); | ||
332 | } | ||
333 | |||
334 | out_free: | ||
335 | free_percpu(arch_timer_evt); | ||
336 | out: | ||
337 | return err; | ||
338 | } | ||
339 | |||
340 | static const struct of_device_id arch_timer_of_match[] __initconst = { | ||
341 | { .compatible = "arm,armv7-timer", }, | ||
342 | { .compatible = "arm,armv8-timer", }, | ||
343 | {}, | ||
344 | }; | ||
345 | |||
346 | int __init arch_timer_init(void) | ||
347 | { | ||
348 | struct device_node *np; | ||
349 | u32 freq; | ||
350 | int i; | ||
351 | |||
352 | np = of_find_matching_node(NULL, arch_timer_of_match); | ||
353 | if (!np) { | ||
354 | pr_err("arch_timer: can't find DT node\n"); | ||
355 | return -ENODEV; | ||
356 | } | ||
357 | |||
358 | /* Try to determine the frequency from the device tree or CNTFRQ */ | ||
359 | if (!of_property_read_u32(np, "clock-frequency", &freq)) | ||
360 | arch_timer_rate = freq; | ||
361 | |||
362 | for (i = PHYS_SECURE_PPI; i < MAX_TIMER_PPI; i++) | ||
363 | arch_timer_ppi[i] = irq_of_parse_and_map(np, i); | ||
364 | |||
365 | of_node_put(np); | ||
366 | |||
367 | /* | ||
368 | * If HYP mode is available, we know that the physical timer | ||
369 | * has been configured to be accessible from PL1. Use it, so | ||
370 | * that a guest can use the virtual timer instead. | ||
371 | * | ||
372 | * If no interrupt provided for virtual timer, we'll have to | ||
373 | * stick to the physical timer. It'd better be accessible... | ||
374 | */ | ||
375 | if (is_hyp_mode_available() || !arch_timer_ppi[VIRT_PPI]) { | ||
376 | arch_timer_use_virtual = false; | ||
377 | |||
378 | if (!arch_timer_ppi[PHYS_SECURE_PPI] || | ||
379 | !arch_timer_ppi[PHYS_NONSECURE_PPI]) { | ||
380 | pr_warn("arch_timer: No interrupt available, giving up\n"); | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | if (arch_timer_use_virtual) | ||
386 | arch_timer_read_counter = arch_counter_get_cntvct; | ||
387 | else | ||
388 | arch_timer_read_counter = arch_counter_get_cntpct; | ||
389 | |||
390 | return arch_timer_register(); | ||
391 | } | ||
diff --git a/drivers/clocksource/arm_generic.c b/drivers/clocksource/arm_generic.c deleted file mode 100644 index 8ae1a61523ff..000000000000 --- a/drivers/clocksource/arm_generic.c +++ /dev/null | |||
@@ -1,232 +0,0 @@ | |||
1 | /* | ||
2 | * Generic timers support | ||
3 | * | ||
4 | * Copyright (C) 2012 ARM Ltd. | ||
5 | * Author: Marc Zyngier <marc.zyngier@arm.com> | ||
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 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/init.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/device.h> | ||
24 | #include <linux/smp.h> | ||
25 | #include <linux/cpu.h> | ||
26 | #include <linux/jiffies.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/clockchips.h> | ||
29 | #include <linux/of_irq.h> | ||
30 | #include <linux/io.h> | ||
31 | |||
32 | #include <clocksource/arm_generic.h> | ||
33 | |||
34 | #include <asm/arm_generic.h> | ||
35 | |||
36 | static u32 arch_timer_rate; | ||
37 | static u64 sched_clock_mult __read_mostly; | ||
38 | static DEFINE_PER_CPU(struct clock_event_device, arch_timer_evt); | ||
39 | static int arch_timer_ppi; | ||
40 | |||
41 | static irqreturn_t arch_timer_handle_irq(int irq, void *dev_id) | ||
42 | { | ||
43 | struct clock_event_device *evt = dev_id; | ||
44 | unsigned long ctrl; | ||
45 | |||
46 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | ||
47 | if (ctrl & ARCH_TIMER_CTRL_ISTATUS) { | ||
48 | ctrl |= ARCH_TIMER_CTRL_IMASK; | ||
49 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | ||
50 | evt->event_handler(evt); | ||
51 | return IRQ_HANDLED; | ||
52 | } | ||
53 | |||
54 | return IRQ_NONE; | ||
55 | } | ||
56 | |||
57 | static void arch_timer_stop(void) | ||
58 | { | ||
59 | unsigned long ctrl; | ||
60 | |||
61 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | ||
62 | ctrl &= ~ARCH_TIMER_CTRL_ENABLE; | ||
63 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | ||
64 | } | ||
65 | |||
66 | static void arch_timer_set_mode(enum clock_event_mode mode, | ||
67 | struct clock_event_device *clk) | ||
68 | { | ||
69 | switch (mode) { | ||
70 | case CLOCK_EVT_MODE_UNUSED: | ||
71 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
72 | arch_timer_stop(); | ||
73 | break; | ||
74 | default: | ||
75 | break; | ||
76 | } | ||
77 | } | ||
78 | |||
79 | static int arch_timer_set_next_event(unsigned long evt, | ||
80 | struct clock_event_device *unused) | ||
81 | { | ||
82 | unsigned long ctrl; | ||
83 | |||
84 | ctrl = arch_timer_reg_read(ARCH_TIMER_REG_CTRL); | ||
85 | ctrl |= ARCH_TIMER_CTRL_ENABLE; | ||
86 | ctrl &= ~ARCH_TIMER_CTRL_IMASK; | ||
87 | |||
88 | arch_timer_reg_write(ARCH_TIMER_REG_TVAL, evt); | ||
89 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, ctrl); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static void __cpuinit arch_timer_setup(struct clock_event_device *clk) | ||
95 | { | ||
96 | /* Let's make sure the timer is off before doing anything else */ | ||
97 | arch_timer_stop(); | ||
98 | |||
99 | clk->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_C3STOP; | ||
100 | clk->name = "arch_sys_timer"; | ||
101 | clk->rating = 400; | ||
102 | clk->set_mode = arch_timer_set_mode; | ||
103 | clk->set_next_event = arch_timer_set_next_event; | ||
104 | clk->irq = arch_timer_ppi; | ||
105 | clk->cpumask = cpumask_of(smp_processor_id()); | ||
106 | |||
107 | clockevents_config_and_register(clk, arch_timer_rate, | ||
108 | 0xf, 0x7fffffff); | ||
109 | |||
110 | enable_percpu_irq(clk->irq, 0); | ||
111 | |||
112 | /* Ensure the virtual counter is visible to userspace for the vDSO. */ | ||
113 | arch_counter_enable_user_access(); | ||
114 | } | ||
115 | |||
116 | static void __init arch_timer_calibrate(void) | ||
117 | { | ||
118 | if (arch_timer_rate == 0) { | ||
119 | arch_timer_reg_write(ARCH_TIMER_REG_CTRL, 0); | ||
120 | arch_timer_rate = arch_timer_reg_read(ARCH_TIMER_REG_FREQ); | ||
121 | |||
122 | /* Check the timer frequency. */ | ||
123 | if (arch_timer_rate == 0) | ||
124 | panic("Architected timer frequency is set to zero.\n" | ||
125 | "You must set this in your .dts file\n"); | ||
126 | } | ||
127 | |||
128 | /* Cache the sched_clock multiplier to save a divide in the hot path. */ | ||
129 | |||
130 | sched_clock_mult = DIV_ROUND_CLOSEST(NSEC_PER_SEC, arch_timer_rate); | ||
131 | |||
132 | pr_info("Architected local timer running at %u.%02uMHz.\n", | ||
133 | arch_timer_rate / 1000000, (arch_timer_rate / 10000) % 100); | ||
134 | } | ||
135 | |||
136 | static cycle_t arch_counter_read(struct clocksource *cs) | ||
137 | { | ||
138 | return arch_counter_get_cntpct(); | ||
139 | } | ||
140 | |||
141 | static struct clocksource clocksource_counter = { | ||
142 | .name = "arch_sys_counter", | ||
143 | .rating = 400, | ||
144 | .read = arch_counter_read, | ||
145 | .mask = CLOCKSOURCE_MASK(56), | ||
146 | .flags = (CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_VALID_FOR_HRES), | ||
147 | }; | ||
148 | |||
149 | int read_current_timer(unsigned long *timer_value) | ||
150 | { | ||
151 | *timer_value = arch_counter_get_cntpct(); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | unsigned long long notrace sched_clock(void) | ||
156 | { | ||
157 | return arch_counter_get_cntvct() * sched_clock_mult; | ||
158 | } | ||
159 | |||
160 | static int __cpuinit arch_timer_cpu_notify(struct notifier_block *self, | ||
161 | unsigned long action, void *hcpu) | ||
162 | { | ||
163 | int cpu = (long)hcpu; | ||
164 | struct clock_event_device *clk = per_cpu_ptr(&arch_timer_evt, cpu); | ||
165 | |||
166 | switch(action) { | ||
167 | case CPU_STARTING: | ||
168 | case CPU_STARTING_FROZEN: | ||
169 | arch_timer_setup(clk); | ||
170 | break; | ||
171 | |||
172 | case CPU_DYING: | ||
173 | case CPU_DYING_FROZEN: | ||
174 | pr_debug("arch_timer_teardown disable IRQ%d cpu #%d\n", | ||
175 | clk->irq, cpu); | ||
176 | disable_percpu_irq(clk->irq); | ||
177 | arch_timer_set_mode(CLOCK_EVT_MODE_UNUSED, clk); | ||
178 | break; | ||
179 | } | ||
180 | |||
181 | return NOTIFY_OK; | ||
182 | } | ||
183 | |||
184 | static struct notifier_block __cpuinitdata arch_timer_cpu_nb = { | ||
185 | .notifier_call = arch_timer_cpu_notify, | ||
186 | }; | ||
187 | |||
188 | static const struct of_device_id arch_timer_of_match[] __initconst = { | ||
189 | { .compatible = "arm,armv8-timer" }, | ||
190 | {}, | ||
191 | }; | ||
192 | |||
193 | int __init arm_generic_timer_init(void) | ||
194 | { | ||
195 | struct device_node *np; | ||
196 | int err; | ||
197 | u32 freq; | ||
198 | |||
199 | np = of_find_matching_node(NULL, arch_timer_of_match); | ||
200 | if (!np) { | ||
201 | pr_err("arch_timer: can't find DT node\n"); | ||
202 | return -ENODEV; | ||
203 | } | ||
204 | |||
205 | /* Try to determine the frequency from the device tree or CNTFRQ */ | ||
206 | if (!of_property_read_u32(np, "clock-frequency", &freq)) | ||
207 | arch_timer_rate = freq; | ||
208 | arch_timer_calibrate(); | ||
209 | |||
210 | arch_timer_ppi = irq_of_parse_and_map(np, 0); | ||
211 | pr_info("arch_timer: found %s irq %d\n", np->name, arch_timer_ppi); | ||
212 | |||
213 | err = request_percpu_irq(arch_timer_ppi, arch_timer_handle_irq, | ||
214 | np->name, &arch_timer_evt); | ||
215 | if (err) { | ||
216 | pr_err("arch_timer: can't register interrupt %d (%d)\n", | ||
217 | arch_timer_ppi, err); | ||
218 | return err; | ||
219 | } | ||
220 | |||
221 | clocksource_register_hz(&clocksource_counter, arch_timer_rate); | ||
222 | |||
223 | /* Calibrate the delay loop directly */ | ||
224 | lpj_fine = DIV_ROUND_CLOSEST(arch_timer_rate, HZ); | ||
225 | |||
226 | /* Immediately configure the timer on the boot CPU */ | ||
227 | arch_timer_setup(this_cpu_ptr(&arch_timer_evt)); | ||
228 | |||
229 | register_cpu_notifier(&arch_timer_cpu_nb); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
diff --git a/drivers/clocksource/bcm2835_timer.c b/drivers/clocksource/bcm2835_timer.c index bc19f12c20ce..50c68fef944b 100644 --- a/drivers/clocksource/bcm2835_timer.c +++ b/drivers/clocksource/bcm2835_timer.c | |||
@@ -16,7 +16,6 @@ | |||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/bcm2835_timer.h> | ||
20 | #include <linux/bitops.h> | 19 | #include <linux/bitops.h> |
21 | #include <linux/clockchips.h> | 20 | #include <linux/clockchips.h> |
22 | #include <linux/clocksource.h> | 21 | #include <linux/clocksource.h> |
@@ -101,7 +100,7 @@ static struct of_device_id bcm2835_time_match[] __initconst = { | |||
101 | {} | 100 | {} |
102 | }; | 101 | }; |
103 | 102 | ||
104 | static void __init bcm2835_time_init(void) | 103 | static void __init bcm2835_timer_init(void) |
105 | { | 104 | { |
106 | struct device_node *node; | 105 | struct device_node *node; |
107 | void __iomem *base; | 106 | void __iomem *base; |
@@ -155,7 +154,5 @@ static void __init bcm2835_time_init(void) | |||
155 | 154 | ||
156 | pr_info("bcm2835: system timer (irq = %d)\n", irq); | 155 | pr_info("bcm2835: system timer (irq = %d)\n", irq); |
157 | } | 156 | } |
158 | 157 | CLOCKSOURCE_OF_DECLARE(bcm2835, "brcm,bcm2835-system-timer", | |
159 | struct sys_timer bcm2835_timer = { | 158 | bcm2835_timer_init); |
160 | .init = bcm2835_time_init, | ||
161 | }; | ||
diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c new file mode 100644 index 000000000000..bdabdaa8d00f --- /dev/null +++ b/drivers/clocksource/clksrc-of.c | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/of.h> | ||
19 | |||
20 | extern struct of_device_id __clksrc_of_table[]; | ||
21 | |||
22 | static const struct of_device_id __clksrc_of_table_sentinel | ||
23 | __used __section(__clksrc_of_table_end); | ||
24 | |||
25 | void __init clocksource_of_init(void) | ||
26 | { | ||
27 | struct device_node *np; | ||
28 | const struct of_device_id *match; | ||
29 | void (*init_func)(void); | ||
30 | |||
31 | for_each_matching_node_and_match(np, __clksrc_of_table, &match) { | ||
32 | init_func = match->data; | ||
33 | init_func(); | ||
34 | } | ||
35 | } | ||
diff --git a/drivers/clocksource/cs5535-clockevt.c b/drivers/clocksource/cs5535-clockevt.c index d9279385304d..ea210482dd20 100644 --- a/drivers/clocksource/cs5535-clockevt.c +++ b/drivers/clocksource/cs5535-clockevt.c | |||
@@ -100,7 +100,6 @@ static struct clock_event_device cs5535_clockevent = { | |||
100 | .set_mode = mfgpt_set_mode, | 100 | .set_mode = mfgpt_set_mode, |
101 | .set_next_event = mfgpt_next_event, | 101 | .set_next_event = mfgpt_next_event, |
102 | .rating = 250, | 102 | .rating = 250, |
103 | .shift = 32 | ||
104 | }; | 103 | }; |
105 | 104 | ||
106 | static irqreturn_t mfgpt_tick(int irq, void *dev_id) | 105 | static irqreturn_t mfgpt_tick(int irq, void *dev_id) |
@@ -169,17 +168,11 @@ static int __init cs5535_mfgpt_init(void) | |||
169 | cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, val); | 168 | cs5535_mfgpt_write(cs5535_event_clock, MFGPT_REG_SETUP, val); |
170 | 169 | ||
171 | /* Set up the clock event */ | 170 | /* Set up the clock event */ |
172 | cs5535_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC, | ||
173 | cs5535_clockevent.shift); | ||
174 | cs5535_clockevent.min_delta_ns = clockevent_delta2ns(0xF, | ||
175 | &cs5535_clockevent); | ||
176 | cs5535_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE, | ||
177 | &cs5535_clockevent); | ||
178 | |||
179 | printk(KERN_INFO DRV_NAME | 171 | printk(KERN_INFO DRV_NAME |
180 | ": Registering MFGPT timer as a clock event, using IRQ %d\n", | 172 | ": Registering MFGPT timer as a clock event, using IRQ %d\n", |
181 | timer_irq); | 173 | timer_irq); |
182 | clockevents_register_device(&cs5535_clockevent); | 174 | clockevents_config_and_register(&cs5535_clockevent, MFGPT_HZ, |
175 | 0xF, 0xFFFE); | ||
183 | 176 | ||
184 | return 0; | 177 | return 0; |
185 | 178 | ||
diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c index f7dba5b79b44..ab09ed3742ee 100644 --- a/drivers/clocksource/dw_apb_timer_of.c +++ b/drivers/clocksource/dw_apb_timer_of.c | |||
@@ -107,7 +107,7 @@ static const struct of_device_id osctimer_ids[] __initconst = { | |||
107 | {}, | 107 | {}, |
108 | }; | 108 | }; |
109 | 109 | ||
110 | static void __init timer_init(void) | 110 | void __init dw_apb_timer_init(void) |
111 | { | 111 | { |
112 | struct device_node *event_timer, *source_timer; | 112 | struct device_node *event_timer, *source_timer; |
113 | 113 | ||
@@ -125,7 +125,3 @@ static void __init timer_init(void) | |||
125 | 125 | ||
126 | init_sched_clock(); | 126 | init_sched_clock(); |
127 | } | 127 | } |
128 | |||
129 | struct sys_timer dw_apb_timer = { | ||
130 | .init = timer_init, | ||
131 | }; | ||
diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index 8914c3c1c88b..071f6eadfea2 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/clocksource.h> | 15 | #include <linux/clocksource.h> |
16 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
17 | #include <linux/jiffies.h> | 17 | #include <linux/jiffies.h> |
18 | #include <linux/delay.h> | ||
18 | #include <linux/err.h> | 19 | #include <linux/err.h> |
19 | #include <linux/platform_data/clocksource-nomadik-mtu.h> | 20 | #include <linux/platform_data/clocksource-nomadik-mtu.h> |
20 | #include <asm/mach/time.h> | 21 | #include <asm/mach/time.h> |
@@ -64,6 +65,7 @@ static void __iomem *mtu_base; | |||
64 | static bool clkevt_periodic; | 65 | static bool clkevt_periodic; |
65 | static u32 clk_prescale; | 66 | static u32 clk_prescale; |
66 | static u32 nmdk_cycle; /* write-once */ | 67 | static u32 nmdk_cycle; /* write-once */ |
68 | static struct delay_timer mtu_delay_timer; | ||
67 | 69 | ||
68 | #ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK | 70 | #ifdef CONFIG_NOMADIK_MTU_SCHED_CLOCK |
69 | /* | 71 | /* |
@@ -80,6 +82,11 @@ static u32 notrace nomadik_read_sched_clock(void) | |||
80 | } | 82 | } |
81 | #endif | 83 | #endif |
82 | 84 | ||
85 | static unsigned long nmdk_timer_read_current_timer(void) | ||
86 | { | ||
87 | return ~readl_relaxed(mtu_base + MTU_VAL(0)); | ||
88 | } | ||
89 | |||
83 | /* Clockevent device: use one-shot mode */ | 90 | /* Clockevent device: use one-shot mode */ |
84 | static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev) | 91 | static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev) |
85 | { | 92 | { |
@@ -134,12 +141,32 @@ static void nmdk_clkevt_mode(enum clock_event_mode mode, | |||
134 | } | 141 | } |
135 | } | 142 | } |
136 | 143 | ||
144 | void nmdk_clksrc_reset(void) | ||
145 | { | ||
146 | /* Disable */ | ||
147 | writel(0, mtu_base + MTU_CR(0)); | ||
148 | |||
149 | /* ClockSource: configure load and background-load, and fire it up */ | ||
150 | writel(nmdk_cycle, mtu_base + MTU_LR(0)); | ||
151 | writel(nmdk_cycle, mtu_base + MTU_BGLR(0)); | ||
152 | |||
153 | writel(clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA, | ||
154 | mtu_base + MTU_CR(0)); | ||
155 | } | ||
156 | |||
157 | static void nmdk_clkevt_resume(struct clock_event_device *cedev) | ||
158 | { | ||
159 | nmdk_clkevt_reset(); | ||
160 | nmdk_clksrc_reset(); | ||
161 | } | ||
162 | |||
137 | static struct clock_event_device nmdk_clkevt = { | 163 | static struct clock_event_device nmdk_clkevt = { |
138 | .name = "mtu_1", | 164 | .name = "mtu_1", |
139 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, | 165 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, |
140 | .rating = 200, | 166 | .rating = 200, |
141 | .set_mode = nmdk_clkevt_mode, | 167 | .set_mode = nmdk_clkevt_mode, |
142 | .set_next_event = nmdk_clkevt_next, | 168 | .set_next_event = nmdk_clkevt_next, |
169 | .resume = nmdk_clkevt_resume, | ||
143 | }; | 170 | }; |
144 | 171 | ||
145 | /* | 172 | /* |
@@ -161,19 +188,6 @@ static struct irqaction nmdk_timer_irq = { | |||
161 | .dev_id = &nmdk_clkevt, | 188 | .dev_id = &nmdk_clkevt, |
162 | }; | 189 | }; |
163 | 190 | ||
164 | void nmdk_clksrc_reset(void) | ||
165 | { | ||
166 | /* Disable */ | ||
167 | writel(0, mtu_base + MTU_CR(0)); | ||
168 | |||
169 | /* ClockSource: configure load and background-load, and fire it up */ | ||
170 | writel(nmdk_cycle, mtu_base + MTU_LR(0)); | ||
171 | writel(nmdk_cycle, mtu_base + MTU_BGLR(0)); | ||
172 | |||
173 | writel(clk_prescale | MTU_CRn_32BITS | MTU_CRn_ENA, | ||
174 | mtu_base + MTU_CR(0)); | ||
175 | } | ||
176 | |||
177 | void __init nmdk_timer_init(void __iomem *base, int irq) | 191 | void __init nmdk_timer_init(void __iomem *base, int irq) |
178 | { | 192 | { |
179 | unsigned long rate; | 193 | unsigned long rate; |
@@ -226,5 +240,10 @@ void __init nmdk_timer_init(void __iomem *base, int irq) | |||
226 | /* Timer 1 is used for events, register irq and clockevents */ | 240 | /* Timer 1 is used for events, register irq and clockevents */ |
227 | setup_irq(irq, &nmdk_timer_irq); | 241 | setup_irq(irq, &nmdk_timer_irq); |
228 | nmdk_clkevt.cpumask = cpumask_of(0); | 242 | nmdk_clkevt.cpumask = cpumask_of(0); |
243 | nmdk_clkevt.irq = irq; | ||
229 | clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU); | 244 | clockevents_config_and_register(&nmdk_clkevt, rate, 2, 0xffffffffU); |
245 | |||
246 | mtu_delay_timer.read_current_timer = &nmdk_timer_read_current_timer; | ||
247 | mtu_delay_timer.freq = rate; | ||
248 | register_current_timer_delay(&mtu_delay_timer); | ||
230 | } | 249 | } |
diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sunxi_timer.c index 3cd1bd3d7aee..4086b9167159 100644 --- a/drivers/clocksource/sunxi_timer.c +++ b/drivers/clocksource/sunxi_timer.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include <linux/of_address.h> | 23 | #include <linux/of_address.h> |
24 | #include <linux/of_irq.h> | 24 | #include <linux/of_irq.h> |
25 | #include <linux/sunxi_timer.h> | 25 | #include <linux/sunxi_timer.h> |
26 | #include <linux/clk/sunxi.h> | 26 | #include <linux/clk-provider.h> |
27 | 27 | ||
28 | #define TIMER_CTL_REG 0x00 | 28 | #define TIMER_CTL_REG 0x00 |
29 | #define TIMER_CTL_ENABLE (1 << 0) | 29 | #define TIMER_CTL_ENABLE (1 << 0) |
@@ -74,7 +74,6 @@ static int sunxi_clkevt_next_event(unsigned long evt, | |||
74 | 74 | ||
75 | static struct clock_event_device sunxi_clockevent = { | 75 | static struct clock_event_device sunxi_clockevent = { |
76 | .name = "sunxi_tick", | 76 | .name = "sunxi_tick", |
77 | .shift = 32, | ||
78 | .rating = 300, | 77 | .rating = 300, |
79 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 78 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
80 | .set_mode = sunxi_clkevt_mode, | 79 | .set_mode = sunxi_clkevt_mode, |
@@ -104,7 +103,7 @@ static struct of_device_id sunxi_timer_dt_ids[] = { | |||
104 | { } | 103 | { } |
105 | }; | 104 | }; |
106 | 105 | ||
107 | static void __init sunxi_timer_init(void) | 106 | void __init sunxi_timer_init(void) |
108 | { | 107 | { |
109 | struct device_node *node; | 108 | struct device_node *node; |
110 | unsigned long rate = 0; | 109 | unsigned long rate = 0; |
@@ -124,7 +123,7 @@ static void __init sunxi_timer_init(void) | |||
124 | if (irq <= 0) | 123 | if (irq <= 0) |
125 | panic("Can't parse IRQ"); | 124 | panic("Can't parse IRQ"); |
126 | 125 | ||
127 | sunxi_init_clocks(); | 126 | of_clk_init(NULL); |
128 | 127 | ||
129 | clk = of_clk_get(node, 0); | 128 | clk = of_clk_get(node, 0); |
130 | if (IS_ERR(clk)) | 129 | if (IS_ERR(clk)) |
@@ -154,18 +153,8 @@ static void __init sunxi_timer_init(void) | |||
154 | val = readl(timer_base + TIMER_CTL_REG); | 153 | val = readl(timer_base + TIMER_CTL_REG); |
155 | writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG); | 154 | writel(val | TIMER_CTL_ENABLE, timer_base + TIMER_CTL_REG); |
156 | 155 | ||
157 | sunxi_clockevent.mult = div_sc(rate / TIMER_SCAL, | ||
158 | NSEC_PER_SEC, | ||
159 | sunxi_clockevent.shift); | ||
160 | sunxi_clockevent.max_delta_ns = clockevent_delta2ns(0xff, | ||
161 | &sunxi_clockevent); | ||
162 | sunxi_clockevent.min_delta_ns = clockevent_delta2ns(0x1, | ||
163 | &sunxi_clockevent); | ||
164 | sunxi_clockevent.cpumask = cpumask_of(0); | 156 | sunxi_clockevent.cpumask = cpumask_of(0); |
165 | 157 | ||
166 | clockevents_register_device(&sunxi_clockevent); | 158 | clockevents_config_and_register(&sunxi_clockevent, rate / TIMER_SCAL, |
159 | 0x1, 0xff); | ||
167 | } | 160 | } |
168 | |||
169 | struct sys_timer sunxi_timer = { | ||
170 | .init = sunxi_timer_init, | ||
171 | }; | ||
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index 32cb929b8eb6..8a6187225dd0 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c | |||
@@ -157,7 +157,6 @@ static struct tc_clkevt_device clkevt = { | |||
157 | .name = "tc_clkevt", | 157 | .name = "tc_clkevt", |
158 | .features = CLOCK_EVT_FEAT_PERIODIC | 158 | .features = CLOCK_EVT_FEAT_PERIODIC |
159 | | CLOCK_EVT_FEAT_ONESHOT, | 159 | | CLOCK_EVT_FEAT_ONESHOT, |
160 | .shift = 32, | ||
161 | /* Should be lower than at91rm9200's system timer */ | 160 | /* Should be lower than at91rm9200's system timer */ |
162 | .rating = 125, | 161 | .rating = 125, |
163 | .set_next_event = tc_next_event, | 162 | .set_next_event = tc_next_event, |
@@ -196,13 +195,9 @@ static void __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx) | |||
196 | 195 | ||
197 | timer_clock = clk32k_divisor_idx; | 196 | timer_clock = clk32k_divisor_idx; |
198 | 197 | ||
199 | clkevt.clkevt.mult = div_sc(32768, NSEC_PER_SEC, clkevt.clkevt.shift); | ||
200 | clkevt.clkevt.max_delta_ns | ||
201 | = clockevent_delta2ns(0xffff, &clkevt.clkevt); | ||
202 | clkevt.clkevt.min_delta_ns = clockevent_delta2ns(1, &clkevt.clkevt) + 1; | ||
203 | clkevt.clkevt.cpumask = cpumask_of(0); | 198 | clkevt.clkevt.cpumask = cpumask_of(0); |
204 | 199 | ||
205 | clockevents_register_device(&clkevt.clkevt); | 200 | clockevents_config_and_register(&clkevt.clkevt, 32768, 1, 0xffff); |
206 | 201 | ||
207 | setup_irq(irq, &tc_irqaction); | 202 | setup_irq(irq, &tc_irqaction); |
208 | } | 203 | } |
diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c new file mode 100644 index 000000000000..0bde03feb095 --- /dev/null +++ b/drivers/clocksource/tegra20_timer.c | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 Google, Inc. | ||
3 | * | ||
4 | * Author: | ||
5 | * Colin Cross <ccross@google.com> | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/init.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/time.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/clockchips.h> | ||
24 | #include <linux/clocksource.h> | ||
25 | #include <linux/clk.h> | ||
26 | #include <linux/io.h> | ||
27 | #include <linux/of_address.h> | ||
28 | #include <linux/of_irq.h> | ||
29 | |||
30 | #include <asm/mach/time.h> | ||
31 | #include <asm/smp_twd.h> | ||
32 | #include <asm/sched_clock.h> | ||
33 | |||
34 | #define RTC_SECONDS 0x08 | ||
35 | #define RTC_SHADOW_SECONDS 0x0c | ||
36 | #define RTC_MILLISECONDS 0x10 | ||
37 | |||
38 | #define TIMERUS_CNTR_1US 0x10 | ||
39 | #define TIMERUS_USEC_CFG 0x14 | ||
40 | #define TIMERUS_CNTR_FREEZE 0x4c | ||
41 | |||
42 | #define TIMER1_BASE 0x0 | ||
43 | #define TIMER2_BASE 0x8 | ||
44 | #define TIMER3_BASE 0x50 | ||
45 | #define TIMER4_BASE 0x58 | ||
46 | |||
47 | #define TIMER_PTV 0x0 | ||
48 | #define TIMER_PCR 0x4 | ||
49 | |||
50 | static void __iomem *timer_reg_base; | ||
51 | static void __iomem *rtc_base; | ||
52 | |||
53 | static struct timespec persistent_ts; | ||
54 | static u64 persistent_ms, last_persistent_ms; | ||
55 | |||
56 | #define timer_writel(value, reg) \ | ||
57 | __raw_writel(value, timer_reg_base + (reg)) | ||
58 | #define timer_readl(reg) \ | ||
59 | __raw_readl(timer_reg_base + (reg)) | ||
60 | |||
61 | static int tegra_timer_set_next_event(unsigned long cycles, | ||
62 | struct clock_event_device *evt) | ||
63 | { | ||
64 | u32 reg; | ||
65 | |||
66 | reg = 0x80000000 | ((cycles > 1) ? (cycles-1) : 0); | ||
67 | timer_writel(reg, TIMER3_BASE + TIMER_PTV); | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static void tegra_timer_set_mode(enum clock_event_mode mode, | ||
73 | struct clock_event_device *evt) | ||
74 | { | ||
75 | u32 reg; | ||
76 | |||
77 | timer_writel(0, TIMER3_BASE + TIMER_PTV); | ||
78 | |||
79 | switch (mode) { | ||
80 | case CLOCK_EVT_MODE_PERIODIC: | ||
81 | reg = 0xC0000000 | ((1000000/HZ)-1); | ||
82 | timer_writel(reg, TIMER3_BASE + TIMER_PTV); | ||
83 | break; | ||
84 | case CLOCK_EVT_MODE_ONESHOT: | ||
85 | break; | ||
86 | case CLOCK_EVT_MODE_UNUSED: | ||
87 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
88 | case CLOCK_EVT_MODE_RESUME: | ||
89 | break; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | static struct clock_event_device tegra_clockevent = { | ||
94 | .name = "timer0", | ||
95 | .rating = 300, | ||
96 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, | ||
97 | .set_next_event = tegra_timer_set_next_event, | ||
98 | .set_mode = tegra_timer_set_mode, | ||
99 | }; | ||
100 | |||
101 | static u32 notrace tegra_read_sched_clock(void) | ||
102 | { | ||
103 | return timer_readl(TIMERUS_CNTR_1US); | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * tegra_rtc_read - Reads the Tegra RTC registers | ||
108 | * Care must be taken that this funciton is not called while the | ||
109 | * tegra_rtc driver could be executing to avoid race conditions | ||
110 | * on the RTC shadow register | ||
111 | */ | ||
112 | static u64 tegra_rtc_read_ms(void) | ||
113 | { | ||
114 | u32 ms = readl(rtc_base + RTC_MILLISECONDS); | ||
115 | u32 s = readl(rtc_base + RTC_SHADOW_SECONDS); | ||
116 | return (u64)s * MSEC_PER_SEC + ms; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * tegra_read_persistent_clock - Return time from a persistent clock. | ||
121 | * | ||
122 | * Reads the time from a source which isn't disabled during PM, the | ||
123 | * 32k sync timer. Convert the cycles elapsed since last read into | ||
124 | * nsecs and adds to a monotonically increasing timespec. | ||
125 | * Care must be taken that this funciton is not called while the | ||
126 | * tegra_rtc driver could be executing to avoid race conditions | ||
127 | * on the RTC shadow register | ||
128 | */ | ||
129 | static void tegra_read_persistent_clock(struct timespec *ts) | ||
130 | { | ||
131 | u64 delta; | ||
132 | struct timespec *tsp = &persistent_ts; | ||
133 | |||
134 | last_persistent_ms = persistent_ms; | ||
135 | persistent_ms = tegra_rtc_read_ms(); | ||
136 | delta = persistent_ms - last_persistent_ms; | ||
137 | |||
138 | timespec_add_ns(tsp, delta * NSEC_PER_MSEC); | ||
139 | *ts = *tsp; | ||
140 | } | ||
141 | |||
142 | static irqreturn_t tegra_timer_interrupt(int irq, void *dev_id) | ||
143 | { | ||
144 | struct clock_event_device *evt = (struct clock_event_device *)dev_id; | ||
145 | timer_writel(1<<30, TIMER3_BASE + TIMER_PCR); | ||
146 | evt->event_handler(evt); | ||
147 | return IRQ_HANDLED; | ||
148 | } | ||
149 | |||
150 | static struct irqaction tegra_timer_irq = { | ||
151 | .name = "timer0", | ||
152 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_TRIGGER_HIGH, | ||
153 | .handler = tegra_timer_interrupt, | ||
154 | .dev_id = &tegra_clockevent, | ||
155 | }; | ||
156 | |||
157 | static const struct of_device_id timer_match[] __initconst = { | ||
158 | { .compatible = "nvidia,tegra20-timer" }, | ||
159 | {} | ||
160 | }; | ||
161 | |||
162 | static const struct of_device_id rtc_match[] __initconst = { | ||
163 | { .compatible = "nvidia,tegra20-rtc" }, | ||
164 | {} | ||
165 | }; | ||
166 | |||
167 | static void __init tegra20_init_timer(void) | ||
168 | { | ||
169 | struct device_node *np; | ||
170 | struct clk *clk; | ||
171 | unsigned long rate; | ||
172 | int ret; | ||
173 | |||
174 | np = of_find_matching_node(NULL, timer_match); | ||
175 | if (!np) { | ||
176 | pr_err("Failed to find timer DT node\n"); | ||
177 | BUG(); | ||
178 | } | ||
179 | |||
180 | timer_reg_base = of_iomap(np, 0); | ||
181 | if (!timer_reg_base) { | ||
182 | pr_err("Can't map timer registers\n"); | ||
183 | BUG(); | ||
184 | } | ||
185 | |||
186 | tegra_timer_irq.irq = irq_of_parse_and_map(np, 2); | ||
187 | if (tegra_timer_irq.irq <= 0) { | ||
188 | pr_err("Failed to map timer IRQ\n"); | ||
189 | BUG(); | ||
190 | } | ||
191 | |||
192 | clk = clk_get_sys("timer", NULL); | ||
193 | if (IS_ERR(clk)) { | ||
194 | pr_warn("Unable to get timer clock. Assuming 12Mhz input clock.\n"); | ||
195 | rate = 12000000; | ||
196 | } else { | ||
197 | clk_prepare_enable(clk); | ||
198 | rate = clk_get_rate(clk); | ||
199 | } | ||
200 | |||
201 | of_node_put(np); | ||
202 | |||
203 | np = of_find_matching_node(NULL, rtc_match); | ||
204 | if (!np) { | ||
205 | pr_err("Failed to find RTC DT node\n"); | ||
206 | BUG(); | ||
207 | } | ||
208 | |||
209 | rtc_base = of_iomap(np, 0); | ||
210 | if (!rtc_base) { | ||
211 | pr_err("Can't map RTC registers"); | ||
212 | BUG(); | ||
213 | } | ||
214 | |||
215 | /* | ||
216 | * rtc registers are used by read_persistent_clock, keep the rtc clock | ||
217 | * enabled | ||
218 | */ | ||
219 | clk = clk_get_sys("rtc-tegra", NULL); | ||
220 | if (IS_ERR(clk)) | ||
221 | pr_warn("Unable to get rtc-tegra clock\n"); | ||
222 | else | ||
223 | clk_prepare_enable(clk); | ||
224 | |||
225 | of_node_put(np); | ||
226 | |||
227 | switch (rate) { | ||
228 | case 12000000: | ||
229 | timer_writel(0x000b, TIMERUS_USEC_CFG); | ||
230 | break; | ||
231 | case 13000000: | ||
232 | timer_writel(0x000c, TIMERUS_USEC_CFG); | ||
233 | break; | ||
234 | case 19200000: | ||
235 | timer_writel(0x045f, TIMERUS_USEC_CFG); | ||
236 | break; | ||
237 | case 26000000: | ||
238 | timer_writel(0x0019, TIMERUS_USEC_CFG); | ||
239 | break; | ||
240 | default: | ||
241 | WARN(1, "Unknown clock rate"); | ||
242 | } | ||
243 | |||
244 | setup_sched_clock(tegra_read_sched_clock, 32, 1000000); | ||
245 | |||
246 | if (clocksource_mmio_init(timer_reg_base + TIMERUS_CNTR_1US, | ||
247 | "timer_us", 1000000, 300, 32, clocksource_mmio_readl_up)) { | ||
248 | pr_err("Failed to register clocksource\n"); | ||
249 | BUG(); | ||
250 | } | ||
251 | |||
252 | ret = setup_irq(tegra_timer_irq.irq, &tegra_timer_irq); | ||
253 | if (ret) { | ||
254 | pr_err("Failed to register timer IRQ: %d\n", ret); | ||
255 | BUG(); | ||
256 | } | ||
257 | |||
258 | tegra_clockevent.cpumask = cpu_all_mask; | ||
259 | tegra_clockevent.irq = tegra_timer_irq.irq; | ||
260 | clockevents_config_and_register(&tegra_clockevent, 1000000, | ||
261 | 0x1, 0x1fffffff); | ||
262 | #ifdef CONFIG_HAVE_ARM_TWD | ||
263 | twd_local_timer_of_register(); | ||
264 | #endif | ||
265 | register_persistent_clock(NULL, tegra_read_persistent_clock); | ||
266 | } | ||
267 | CLOCKSOURCE_OF_DECLARE(tegra20, "nvidia,tegra20-timer", tegra20_init_timer); | ||
268 | |||
269 | #ifdef CONFIG_PM | ||
270 | static u32 usec_config; | ||
271 | |||
272 | void tegra_timer_suspend(void) | ||
273 | { | ||
274 | usec_config = timer_readl(TIMERUS_USEC_CFG); | ||
275 | } | ||
276 | |||
277 | void tegra_timer_resume(void) | ||
278 | { | ||
279 | timer_writel(usec_config, TIMERUS_USEC_CFG); | ||
280 | } | ||
281 | #endif | ||
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index a4605fd7e303..47a673070d70 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c | |||
@@ -27,8 +27,10 @@ | |||
27 | #include <linux/of_address.h> | 27 | #include <linux/of_address.h> |
28 | #include <linux/irq.h> | 28 | #include <linux/irq.h> |
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <asm/sched_clock.h> | ||
31 | 30 | ||
31 | #include <asm/sched_clock.h> | ||
32 | #include <asm/localtimer.h> | ||
33 | #include <linux/percpu.h> | ||
32 | /* | 34 | /* |
33 | * Timer block registers. | 35 | * Timer block registers. |
34 | */ | 36 | */ |
@@ -49,6 +51,7 @@ | |||
49 | #define TIMER1_RELOAD_OFF 0x0018 | 51 | #define TIMER1_RELOAD_OFF 0x0018 |
50 | #define TIMER1_VAL_OFF 0x001c | 52 | #define TIMER1_VAL_OFF 0x001c |
51 | 53 | ||
54 | #define LCL_TIMER_EVENTS_STATUS 0x0028 | ||
52 | /* Global timers are connected to the coherency fabric clock, and the | 55 | /* Global timers are connected to the coherency fabric clock, and the |
53 | below divider reduces their incrementing frequency. */ | 56 | below divider reduces their incrementing frequency. */ |
54 | #define TIMER_DIVIDER_SHIFT 5 | 57 | #define TIMER_DIVIDER_SHIFT 5 |
@@ -57,14 +60,17 @@ | |||
57 | /* | 60 | /* |
58 | * SoC-specific data. | 61 | * SoC-specific data. |
59 | */ | 62 | */ |
60 | static void __iomem *timer_base; | 63 | static void __iomem *timer_base, *local_base; |
61 | static int timer_irq; | 64 | static unsigned int timer_clk; |
65 | static bool timer25Mhz = true; | ||
62 | 66 | ||
63 | /* | 67 | /* |
64 | * Number of timer ticks per jiffy. | 68 | * Number of timer ticks per jiffy. |
65 | */ | 69 | */ |
66 | static u32 ticks_per_jiffy; | 70 | static u32 ticks_per_jiffy; |
67 | 71 | ||
72 | static struct clock_event_device __percpu **percpu_armada_370_xp_evt; | ||
73 | |||
68 | static u32 notrace armada_370_xp_read_sched_clock(void) | 74 | static u32 notrace armada_370_xp_read_sched_clock(void) |
69 | { | 75 | { |
70 | return ~readl(timer_base + TIMER0_VAL_OFF); | 76 | return ~readl(timer_base + TIMER0_VAL_OFF); |
@@ -78,24 +84,23 @@ armada_370_xp_clkevt_next_event(unsigned long delta, | |||
78 | struct clock_event_device *dev) | 84 | struct clock_event_device *dev) |
79 | { | 85 | { |
80 | u32 u; | 86 | u32 u; |
81 | |||
82 | /* | 87 | /* |
83 | * Clear clockevent timer interrupt. | 88 | * Clear clockevent timer interrupt. |
84 | */ | 89 | */ |
85 | writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS); | 90 | writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); |
86 | 91 | ||
87 | /* | 92 | /* |
88 | * Setup new clockevent timer value. | 93 | * Setup new clockevent timer value. |
89 | */ | 94 | */ |
90 | writel(delta, timer_base + TIMER1_VAL_OFF); | 95 | writel(delta, local_base + TIMER0_VAL_OFF); |
91 | 96 | ||
92 | /* | 97 | /* |
93 | * Enable the timer. | 98 | * Enable the timer. |
94 | */ | 99 | */ |
95 | u = readl(timer_base + TIMER_CTRL_OFF); | 100 | u = readl(local_base + TIMER_CTRL_OFF); |
96 | u = ((u & ~TIMER1_RELOAD_EN) | TIMER1_EN | | 101 | u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN | |
97 | TIMER1_DIV(TIMER_DIVIDER_SHIFT)); | 102 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)); |
98 | writel(u, timer_base + TIMER_CTRL_OFF); | 103 | writel(u, local_base + TIMER_CTRL_OFF); |
99 | 104 | ||
100 | return 0; | 105 | return 0; |
101 | } | 106 | } |
@@ -107,37 +112,38 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode, | |||
107 | u32 u; | 112 | u32 u; |
108 | 113 | ||
109 | if (mode == CLOCK_EVT_MODE_PERIODIC) { | 114 | if (mode == CLOCK_EVT_MODE_PERIODIC) { |
115 | |||
110 | /* | 116 | /* |
111 | * Setup timer to fire at 1/HZ intervals. | 117 | * Setup timer to fire at 1/HZ intervals. |
112 | */ | 118 | */ |
113 | writel(ticks_per_jiffy - 1, timer_base + TIMER1_RELOAD_OFF); | 119 | writel(ticks_per_jiffy - 1, local_base + TIMER0_RELOAD_OFF); |
114 | writel(ticks_per_jiffy - 1, timer_base + TIMER1_VAL_OFF); | 120 | writel(ticks_per_jiffy - 1, local_base + TIMER0_VAL_OFF); |
115 | 121 | ||
116 | /* | 122 | /* |
117 | * Enable timer. | 123 | * Enable timer. |
118 | */ | 124 | */ |
119 | u = readl(timer_base + TIMER_CTRL_OFF); | ||
120 | 125 | ||
121 | writel((u | TIMER1_EN | TIMER1_RELOAD_EN | | 126 | u = readl(local_base + TIMER_CTRL_OFF); |
122 | TIMER1_DIV(TIMER_DIVIDER_SHIFT)), | 127 | |
123 | timer_base + TIMER_CTRL_OFF); | 128 | writel((u | TIMER0_EN | TIMER0_RELOAD_EN | |
129 | TIMER0_DIV(TIMER_DIVIDER_SHIFT)), | ||
130 | local_base + TIMER_CTRL_OFF); | ||
124 | } else { | 131 | } else { |
125 | /* | 132 | /* |
126 | * Disable timer. | 133 | * Disable timer. |
127 | */ | 134 | */ |
128 | u = readl(timer_base + TIMER_CTRL_OFF); | 135 | u = readl(local_base + TIMER_CTRL_OFF); |
129 | writel(u & ~TIMER1_EN, timer_base + TIMER_CTRL_OFF); | 136 | writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF); |
130 | 137 | ||
131 | /* | 138 | /* |
132 | * ACK pending timer interrupt. | 139 | * ACK pending timer interrupt. |
133 | */ | 140 | */ |
134 | writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS); | 141 | writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); |
135 | |||
136 | } | 142 | } |
137 | } | 143 | } |
138 | 144 | ||
139 | static struct clock_event_device armada_370_xp_clkevt = { | 145 | static struct clock_event_device armada_370_xp_clkevt = { |
140 | .name = "armada_370_xp_tick", | 146 | .name = "armada_370_xp_per_cpu_tick", |
141 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, | 147 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, |
142 | .shift = 32, | 148 | .shift = 32, |
143 | .rating = 300, | 149 | .rating = 300, |
@@ -150,32 +156,78 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) | |||
150 | /* | 156 | /* |
151 | * ACK timer interrupt and call event handler. | 157 | * ACK timer interrupt and call event handler. |
152 | */ | 158 | */ |
159 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; | ||
153 | 160 | ||
154 | writel(TIMER1_CLR_MASK, timer_base + TIMER_EVENTS_STATUS); | 161 | writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); |
155 | armada_370_xp_clkevt.event_handler(&armada_370_xp_clkevt); | 162 | evt->event_handler(evt); |
156 | 163 | ||
157 | return IRQ_HANDLED; | 164 | return IRQ_HANDLED; |
158 | } | 165 | } |
159 | 166 | ||
160 | static struct irqaction armada_370_xp_timer_irq = { | 167 | /* |
161 | .name = "armada_370_xp_tick", | 168 | * Setup the local clock events for a CPU. |
162 | .flags = IRQF_DISABLED | IRQF_TIMER, | 169 | */ |
163 | .handler = armada_370_xp_timer_interrupt | 170 | static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt) |
171 | { | ||
172 | u32 u; | ||
173 | int cpu = smp_processor_id(); | ||
174 | |||
175 | /* Use existing clock_event for cpu 0 */ | ||
176 | if (!smp_processor_id()) | ||
177 | return 0; | ||
178 | |||
179 | u = readl(local_base + TIMER_CTRL_OFF); | ||
180 | if (timer25Mhz) | ||
181 | writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | ||
182 | else | ||
183 | writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | ||
184 | |||
185 | evt->name = armada_370_xp_clkevt.name; | ||
186 | evt->irq = armada_370_xp_clkevt.irq; | ||
187 | evt->features = armada_370_xp_clkevt.features; | ||
188 | evt->shift = armada_370_xp_clkevt.shift; | ||
189 | evt->rating = armada_370_xp_clkevt.rating, | ||
190 | evt->set_next_event = armada_370_xp_clkevt_next_event, | ||
191 | evt->set_mode = armada_370_xp_clkevt_mode, | ||
192 | evt->cpumask = cpumask_of(cpu); | ||
193 | |||
194 | *__this_cpu_ptr(percpu_armada_370_xp_evt) = evt; | ||
195 | |||
196 | clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe); | ||
197 | enable_percpu_irq(evt->irq, 0); | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static void armada_370_xp_timer_stop(struct clock_event_device *evt) | ||
203 | { | ||
204 | evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); | ||
205 | disable_percpu_irq(evt->irq); | ||
206 | } | ||
207 | |||
208 | static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = { | ||
209 | .setup = armada_370_xp_timer_setup, | ||
210 | .stop = armada_370_xp_timer_stop, | ||
164 | }; | 211 | }; |
165 | 212 | ||
166 | void __init armada_370_xp_timer_init(void) | 213 | void __init armada_370_xp_timer_init(void) |
167 | { | 214 | { |
168 | u32 u; | 215 | u32 u; |
169 | struct device_node *np; | 216 | struct device_node *np; |
170 | unsigned int timer_clk; | 217 | int res; |
218 | |||
171 | np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer"); | 219 | np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer"); |
172 | timer_base = of_iomap(np, 0); | 220 | timer_base = of_iomap(np, 0); |
173 | WARN_ON(!timer_base); | 221 | WARN_ON(!timer_base); |
222 | local_base = of_iomap(np, 1); | ||
174 | 223 | ||
175 | if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { | 224 | if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { |
176 | /* The fixed 25MHz timer is available so let's use it */ | 225 | /* The fixed 25MHz timer is available so let's use it */ |
226 | u = readl(local_base + TIMER_CTRL_OFF); | ||
227 | writel(u | TIMER0_25MHZ, | ||
228 | local_base + TIMER_CTRL_OFF); | ||
177 | u = readl(timer_base + TIMER_CTRL_OFF); | 229 | u = readl(timer_base + TIMER_CTRL_OFF); |
178 | writel(u | TIMER0_25MHZ | TIMER1_25MHZ, | 230 | writel(u | TIMER0_25MHZ, |
179 | timer_base + TIMER_CTRL_OFF); | 231 | timer_base + TIMER_CTRL_OFF); |
180 | timer_clk = 25000000; | 232 | timer_clk = 25000000; |
181 | } else { | 233 | } else { |
@@ -183,15 +235,23 @@ void __init armada_370_xp_timer_init(void) | |||
183 | struct clk *clk = of_clk_get(np, 0); | 235 | struct clk *clk = of_clk_get(np, 0); |
184 | WARN_ON(IS_ERR(clk)); | 236 | WARN_ON(IS_ERR(clk)); |
185 | rate = clk_get_rate(clk); | 237 | rate = clk_get_rate(clk); |
238 | u = readl(local_base + TIMER_CTRL_OFF); | ||
239 | writel(u & ~(TIMER0_25MHZ), | ||
240 | local_base + TIMER_CTRL_OFF); | ||
241 | |||
186 | u = readl(timer_base + TIMER_CTRL_OFF); | 242 | u = readl(timer_base + TIMER_CTRL_OFF); |
187 | writel(u & ~(TIMER0_25MHZ | TIMER1_25MHZ), | 243 | writel(u & ~(TIMER0_25MHZ), |
188 | timer_base + TIMER_CTRL_OFF); | 244 | timer_base + TIMER_CTRL_OFF); |
245 | |||
189 | timer_clk = rate / TIMER_DIVIDER; | 246 | timer_clk = rate / TIMER_DIVIDER; |
247 | timer25Mhz = false; | ||
190 | } | 248 | } |
191 | 249 | ||
192 | /* We use timer 0 as clocksource, and timer 1 for | 250 | /* |
193 | clockevents */ | 251 | * We use timer 0 as clocksource, and private(local) timer 0 |
194 | timer_irq = irq_of_parse_and_map(np, 1); | 252 | * for clockevents |
253 | */ | ||
254 | armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4); | ||
195 | 255 | ||
196 | ticks_per_jiffy = (timer_clk + HZ / 2) / HZ; | 256 | ticks_per_jiffy = (timer_clk + HZ / 2) / HZ; |
197 | 257 | ||
@@ -216,12 +276,26 @@ void __init armada_370_xp_timer_init(void) | |||
216 | "armada_370_xp_clocksource", | 276 | "armada_370_xp_clocksource", |
217 | timer_clk, 300, 32, clocksource_mmio_readl_down); | 277 | timer_clk, 300, 32, clocksource_mmio_readl_down); |
218 | 278 | ||
219 | /* | 279 | /* Register the clockevent on the private timer of CPU 0 */ |
220 | * Setup clockevent timer (interrupt-driven). | ||
221 | */ | ||
222 | setup_irq(timer_irq, &armada_370_xp_timer_irq); | ||
223 | armada_370_xp_clkevt.cpumask = cpumask_of(0); | 280 | armada_370_xp_clkevt.cpumask = cpumask_of(0); |
224 | clockevents_config_and_register(&armada_370_xp_clkevt, | 281 | clockevents_config_and_register(&armada_370_xp_clkevt, |
225 | timer_clk, 1, 0xfffffffe); | 282 | timer_clk, 1, 0xfffffffe); |
226 | } | ||
227 | 283 | ||
284 | percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *); | ||
285 | |||
286 | |||
287 | /* | ||
288 | * Setup clockevent timer (interrupt-driven). | ||
289 | */ | ||
290 | *__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt; | ||
291 | res = request_percpu_irq(armada_370_xp_clkevt.irq, | ||
292 | armada_370_xp_timer_interrupt, | ||
293 | armada_370_xp_clkevt.name, | ||
294 | percpu_armada_370_xp_evt); | ||
295 | if (!res) { | ||
296 | enable_percpu_irq(armada_370_xp_clkevt.irq, 0); | ||
297 | #ifdef CONFIG_LOCAL_TIMERS | ||
298 | local_timer_register(&armada_370_xp_local_timer_ops); | ||
299 | #endif | ||
300 | } | ||
301 | } | ||
diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c new file mode 100644 index 000000000000..8efc86b5b5dd --- /dev/null +++ b/drivers/clocksource/vt8500_timer.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-vt8500/timer.c | ||
3 | * | ||
4 | * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> | ||
5 | * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com> | ||
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 as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | /* | ||
23 | * This file is copied and modified from the original timer.c provided by | ||
24 | * Alexey Charkov. Minor changes have been made for Device Tree Support. | ||
25 | */ | ||
26 | |||
27 | #include <linux/io.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/clocksource.h> | ||
31 | #include <linux/clockchips.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <asm/mach/time.h> | ||
34 | |||
35 | #include <linux/of.h> | ||
36 | #include <linux/of_address.h> | ||
37 | #include <linux/of_irq.h> | ||
38 | |||
39 | #define VT8500_TIMER_OFFSET 0x0100 | ||
40 | #define VT8500_TIMER_HZ 3000000 | ||
41 | #define TIMER_MATCH_VAL 0x0000 | ||
42 | #define TIMER_COUNT_VAL 0x0010 | ||
43 | #define TIMER_STATUS_VAL 0x0014 | ||
44 | #define TIMER_IER_VAL 0x001c /* interrupt enable */ | ||
45 | #define TIMER_CTRL_VAL 0x0020 | ||
46 | #define TIMER_AS_VAL 0x0024 /* access status */ | ||
47 | #define TIMER_COUNT_R_ACTIVE (1 << 5) /* not ready for read */ | ||
48 | #define TIMER_COUNT_W_ACTIVE (1 << 4) /* not ready for write */ | ||
49 | #define TIMER_MATCH_W_ACTIVE (1 << 0) /* not ready for write */ | ||
50 | |||
51 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) | ||
52 | |||
53 | static void __iomem *regbase; | ||
54 | |||
55 | static cycle_t vt8500_timer_read(struct clocksource *cs) | ||
56 | { | ||
57 | int loops = msecs_to_loops(10); | ||
58 | writel(3, regbase + TIMER_CTRL_VAL); | ||
59 | while ((readl((regbase + TIMER_AS_VAL)) & TIMER_COUNT_R_ACTIVE) | ||
60 | && --loops) | ||
61 | cpu_relax(); | ||
62 | return readl(regbase + TIMER_COUNT_VAL); | ||
63 | } | ||
64 | |||
65 | static struct clocksource clocksource = { | ||
66 | .name = "vt8500_timer", | ||
67 | .rating = 200, | ||
68 | .read = vt8500_timer_read, | ||
69 | .mask = CLOCKSOURCE_MASK(32), | ||
70 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
71 | }; | ||
72 | |||
73 | static int vt8500_timer_set_next_event(unsigned long cycles, | ||
74 | struct clock_event_device *evt) | ||
75 | { | ||
76 | int loops = msecs_to_loops(10); | ||
77 | cycle_t alarm = clocksource.read(&clocksource) + cycles; | ||
78 | while ((readl(regbase + TIMER_AS_VAL) & TIMER_MATCH_W_ACTIVE) | ||
79 | && --loops) | ||
80 | cpu_relax(); | ||
81 | writel((unsigned long)alarm, regbase + TIMER_MATCH_VAL); | ||
82 | |||
83 | if ((signed)(alarm - clocksource.read(&clocksource)) <= 16) | ||
84 | return -ETIME; | ||
85 | |||
86 | writel(1, regbase + TIMER_IER_VAL); | ||
87 | |||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static void vt8500_timer_set_mode(enum clock_event_mode mode, | ||
92 | struct clock_event_device *evt) | ||
93 | { | ||
94 | switch (mode) { | ||
95 | case CLOCK_EVT_MODE_RESUME: | ||
96 | case CLOCK_EVT_MODE_PERIODIC: | ||
97 | break; | ||
98 | case CLOCK_EVT_MODE_ONESHOT: | ||
99 | case CLOCK_EVT_MODE_UNUSED: | ||
100 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
101 | writel(readl(regbase + TIMER_CTRL_VAL) | 1, | ||
102 | regbase + TIMER_CTRL_VAL); | ||
103 | writel(0, regbase + TIMER_IER_VAL); | ||
104 | break; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | static struct clock_event_device clockevent = { | ||
109 | .name = "vt8500_timer", | ||
110 | .features = CLOCK_EVT_FEAT_ONESHOT, | ||
111 | .rating = 200, | ||
112 | .set_next_event = vt8500_timer_set_next_event, | ||
113 | .set_mode = vt8500_timer_set_mode, | ||
114 | }; | ||
115 | |||
116 | static irqreturn_t vt8500_timer_interrupt(int irq, void *dev_id) | ||
117 | { | ||
118 | struct clock_event_device *evt = dev_id; | ||
119 | writel(0xf, regbase + TIMER_STATUS_VAL); | ||
120 | evt->event_handler(evt); | ||
121 | |||
122 | return IRQ_HANDLED; | ||
123 | } | ||
124 | |||
125 | static struct irqaction irq = { | ||
126 | .name = "vt8500_timer", | ||
127 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | ||
128 | .handler = vt8500_timer_interrupt, | ||
129 | .dev_id = &clockevent, | ||
130 | }; | ||
131 | |||
132 | static struct of_device_id vt8500_timer_ids[] = { | ||
133 | { .compatible = "via,vt8500-timer" }, | ||
134 | { } | ||
135 | }; | ||
136 | |||
137 | static void __init vt8500_timer_init(void) | ||
138 | { | ||
139 | struct device_node *np; | ||
140 | int timer_irq; | ||
141 | |||
142 | np = of_find_matching_node(NULL, vt8500_timer_ids); | ||
143 | if (!np) { | ||
144 | pr_err("%s: Timer description missing from Device Tree\n", | ||
145 | __func__); | ||
146 | return; | ||
147 | } | ||
148 | regbase = of_iomap(np, 0); | ||
149 | if (!regbase) { | ||
150 | pr_err("%s: Missing iobase description in Device Tree\n", | ||
151 | __func__); | ||
152 | of_node_put(np); | ||
153 | return; | ||
154 | } | ||
155 | timer_irq = irq_of_parse_and_map(np, 0); | ||
156 | if (!timer_irq) { | ||
157 | pr_err("%s: Missing irq description in Device Tree\n", | ||
158 | __func__); | ||
159 | of_node_put(np); | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | writel(1, regbase + TIMER_CTRL_VAL); | ||
164 | writel(0xf, regbase + TIMER_STATUS_VAL); | ||
165 | writel(~0, regbase + TIMER_MATCH_VAL); | ||
166 | |||
167 | if (clocksource_register_hz(&clocksource, VT8500_TIMER_HZ)) | ||
168 | pr_err("%s: vt8500_timer_init: clocksource_register failed for %s\n", | ||
169 | __func__, clocksource.name); | ||
170 | |||
171 | clockevent.cpumask = cpumask_of(0); | ||
172 | |||
173 | if (setup_irq(timer_irq, &irq)) | ||
174 | pr_err("%s: setup_irq failed for %s\n", __func__, | ||
175 | clockevent.name); | ||
176 | clockevents_config_and_register(&clockevent, VT8500_TIMER_HZ, | ||
177 | 4, 0xf0000000); | ||
178 | } | ||
179 | |||
180 | CLOCKSOURCE_OF_DECLARE(vt8500, "via,vt8500-timer", vt8500_timer_init) | ||