aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-03-27 19:06:17 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-03-27 19:06:17 -0400
commit48d554418d3bfbba5e9dc1ebdf352f1b1f3ff4ee (patch)
tree696bdc0c1087e82c6493c852bca514bb0fcd7881 /arch/arm/kernel
parentd61b7a572b292e2be409e13b4b3adf475f18fb29 (diff)
parent2cbe23e3a432e3d09a849adb197c8fcc09e7391d (diff)
Merge tag 'timer' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull "ARM: timer cleanup work" from Arnd Bergmann: "These are split out from the generic soc and driver updates because there was a lot of conflicting work by multiple people. Marc Zyngier worked on simplifying the "localtimer" interfaces, and some of the platforms are touching the same code as they move to device tree based booting. Signed-off-by: Arnd Bergmann <arnd@arndb.de>" * tag 'timer' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (61 commits) ARM: tegra: select USB_ULPI if USB is selected arm/tegra: pcie: fix return value of function ARM: ux500: fix compilation after local timer rework ARM: shmobile: remove additional __io() macro use ARM: local timers: make the runtime registration interface mandatory ARM: local timers: convert MSM to runtime registration interface ARM: local timers: convert exynos to runtime registration interface ARM: smp_twd: remove old local timer interface ARM: imx6q: convert to twd_local_timer_register() interface ARM: highbank: convert to twd_local_timer_register() interface ARM: ux500: convert to twd_local_timer_register() interface ARM: shmobile: convert to twd_local_timer_register() interface ARM: tegra: convert to twd_local_timer_register() interface ARM: plat-versatile: convert to twd_local_timer_register() interface ARM: OMAP4: convert to twd_local_timer_register() interface ARM: smp_twd: add device tree support ARM: smp_twd: add runtime registration support ARM: local timers: introduce a new registration interface ARM: smp_twd: make local_timer_stop a symbol instead of a #define ARM: mach-shmobile: default to no earlytimer ...
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/smp.c22
-rw-r--r--arch/arm/kernel/smp_twd.c123
2 files changed, 119 insertions, 26 deletions
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index d616ed51e7a7..8f8cce2c46c4 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -246,6 +246,8 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
246 store_cpu_topology(cpuid); 246 store_cpu_topology(cpuid);
247} 247}
248 248
249static void percpu_timer_setup(void);
250
249/* 251/*
250 * This is the secondary CPU boot entry. We're using this CPUs 252 * This is the secondary CPU boot entry. We're using this CPUs
251 * idle thread stack, but a set of temporary page tables. 253 * idle thread stack, but a set of temporary page tables.
@@ -452,7 +454,20 @@ static void __cpuinit broadcast_timer_setup(struct clock_event_device *evt)
452 clockevents_register_device(evt); 454 clockevents_register_device(evt);
453} 455}
454 456
455void __cpuinit percpu_timer_setup(void) 457static struct local_timer_ops *lt_ops;
458
459#ifdef CONFIG_LOCAL_TIMERS
460int local_timer_register(struct local_timer_ops *ops)
461{
462 if (lt_ops)
463 return -EBUSY;
464
465 lt_ops = ops;
466 return 0;
467}
468#endif
469
470static void __cpuinit percpu_timer_setup(void)
456{ 471{
457 unsigned int cpu = smp_processor_id(); 472 unsigned int cpu = smp_processor_id();
458 struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); 473 struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
@@ -460,7 +475,7 @@ void __cpuinit percpu_timer_setup(void)
460 evt->cpumask = cpumask_of(cpu); 475 evt->cpumask = cpumask_of(cpu);
461 evt->broadcast = smp_timer_broadcast; 476 evt->broadcast = smp_timer_broadcast;
462 477
463 if (local_timer_setup(evt)) 478 if (!lt_ops || lt_ops->setup(evt))
464 broadcast_timer_setup(evt); 479 broadcast_timer_setup(evt);
465} 480}
466 481
@@ -475,7 +490,8 @@ static void percpu_timer_stop(void)
475 unsigned int cpu = smp_processor_id(); 490 unsigned int cpu = smp_processor_id();
476 struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu); 491 struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
477 492
478 local_timer_stop(evt); 493 if (lt_ops)
494 lt_ops->stop(evt);
479} 495}
480#endif 496#endif
481 497
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 7a79b24597b2..fef42b21cecb 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -18,20 +18,23 @@
18#include <linux/smp.h> 18#include <linux/smp.h>
19#include <linux/jiffies.h> 19#include <linux/jiffies.h>
20#include <linux/clockchips.h> 20#include <linux/clockchips.h>
21#include <linux/irq.h> 21#include <linux/interrupt.h>
22#include <linux/io.h> 22#include <linux/io.h>
23#include <linux/of_irq.h>
24#include <linux/of_address.h>
23 25
24#include <asm/smp_twd.h> 26#include <asm/smp_twd.h>
25#include <asm/localtimer.h> 27#include <asm/localtimer.h>
26#include <asm/hardware/gic.h> 28#include <asm/hardware/gic.h>
27 29
28/* set up by the platform code */ 30/* set up by the platform code */
29void __iomem *twd_base; 31static void __iomem *twd_base;
30 32
31static struct clk *twd_clk; 33static struct clk *twd_clk;
32static unsigned long twd_timer_rate; 34static unsigned long twd_timer_rate;
33 35
34static struct clock_event_device __percpu **twd_evt; 36static struct clock_event_device __percpu **twd_evt;
37static int twd_ppi;
35 38
36static void twd_set_mode(enum clock_event_mode mode, 39static void twd_set_mode(enum clock_event_mode mode,
37 struct clock_event_device *clk) 40 struct clock_event_device *clk)
@@ -77,7 +80,7 @@ static int twd_set_next_event(unsigned long evt,
77 * If a local timer interrupt has occurred, acknowledge and return 1. 80 * If a local timer interrupt has occurred, acknowledge and return 1.
78 * Otherwise, return 0. 81 * Otherwise, return 0.
79 */ 82 */
80int twd_timer_ack(void) 83static int twd_timer_ack(void)
81{ 84{
82 if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) { 85 if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
83 __raw_writel(1, twd_base + TWD_TIMER_INTSTAT); 86 __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
@@ -87,7 +90,7 @@ int twd_timer_ack(void)
87 return 0; 90 return 0;
88} 91}
89 92
90void twd_timer_stop(struct clock_event_device *clk) 93static void twd_timer_stop(struct clock_event_device *clk)
91{ 94{
92 twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk); 95 twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
93 disable_percpu_irq(clk->irq); 96 disable_percpu_irq(clk->irq);
@@ -222,28 +225,10 @@ static struct clk *twd_get_clock(void)
222/* 225/*
223 * Setup the local clock events for a CPU. 226 * Setup the local clock events for a CPU.
224 */ 227 */
225void __cpuinit twd_timer_setup(struct clock_event_device *clk) 228static int __cpuinit twd_timer_setup(struct clock_event_device *clk)
226{ 229{
227 struct clock_event_device **this_cpu_clk; 230 struct clock_event_device **this_cpu_clk;
228 231
229 if (!twd_evt) {
230 int err;
231
232 twd_evt = alloc_percpu(struct clock_event_device *);
233 if (!twd_evt) {
234 pr_err("twd: can't allocate memory\n");
235 return;
236 }
237
238 err = request_percpu_irq(clk->irq, twd_handler,
239 "twd", twd_evt);
240 if (err) {
241 pr_err("twd: can't register interrupt %d (%d)\n",
242 clk->irq, err);
243 return;
244 }
245 }
246
247 if (!twd_clk) 232 if (!twd_clk)
248 twd_clk = twd_get_clock(); 233 twd_clk = twd_get_clock();
249 234
@@ -260,6 +245,7 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
260 clk->rating = 350; 245 clk->rating = 350;
261 clk->set_mode = twd_set_mode; 246 clk->set_mode = twd_set_mode;
262 clk->set_next_event = twd_set_next_event; 247 clk->set_next_event = twd_set_next_event;
248 clk->irq = twd_ppi;
263 249
264 this_cpu_clk = __this_cpu_ptr(twd_evt); 250 this_cpu_clk = __this_cpu_ptr(twd_evt);
265 *this_cpu_clk = clk; 251 *this_cpu_clk = clk;
@@ -267,4 +253,95 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
267 clockevents_config_and_register(clk, twd_timer_rate, 253 clockevents_config_and_register(clk, twd_timer_rate,
268 0xf, 0xffffffff); 254 0xf, 0xffffffff);
269 enable_percpu_irq(clk->irq, 0); 255 enable_percpu_irq(clk->irq, 0);
256
257 return 0;
258}
259
260static struct local_timer_ops twd_lt_ops __cpuinitdata = {
261 .setup = twd_timer_setup,
262 .stop = twd_timer_stop,
263};
264
265static int __init twd_local_timer_common_register(void)
266{
267 int err;
268
269 twd_evt = alloc_percpu(struct clock_event_device *);
270 if (!twd_evt) {
271 err = -ENOMEM;
272 goto out_free;
273 }
274
275 err = request_percpu_irq(twd_ppi, twd_handler, "twd", twd_evt);
276 if (err) {
277 pr_err("twd: can't register interrupt %d (%d)\n", twd_ppi, err);
278 goto out_free;
279 }
280
281 err = local_timer_register(&twd_lt_ops);
282 if (err)
283 goto out_irq;
284
285 return 0;
286
287out_irq:
288 free_percpu_irq(twd_ppi, twd_evt);
289out_free:
290 iounmap(twd_base);
291 twd_base = NULL;
292 free_percpu(twd_evt);
293
294 return err;
270} 295}
296
297int __init twd_local_timer_register(struct twd_local_timer *tlt)
298{
299 if (twd_base || twd_evt)
300 return -EBUSY;
301
302 twd_ppi = tlt->res[1].start;
303
304 twd_base = ioremap(tlt->res[0].start, resource_size(&tlt->res[0]));
305 if (!twd_base)
306 return -ENOMEM;
307
308 return twd_local_timer_common_register();
309}
310
311#ifdef CONFIG_OF
312const static struct of_device_id twd_of_match[] __initconst = {
313 { .compatible = "arm,cortex-a9-twd-timer", },
314 { .compatible = "arm,cortex-a5-twd-timer", },
315 { .compatible = "arm,arm11mp-twd-timer", },
316 { },
317};
318
319void __init twd_local_timer_of_register(void)
320{
321 struct device_node *np;
322 int err;
323
324 np = of_find_matching_node(NULL, twd_of_match);
325 if (!np) {
326 err = -ENODEV;
327 goto out;
328 }
329
330 twd_ppi = irq_of_parse_and_map(np, 0);
331 if (!twd_ppi) {
332 err = -EINVAL;
333 goto out;
334 }
335
336 twd_base = of_iomap(np, 0);
337 if (!twd_base) {
338 err = -ENOMEM;
339 goto out;
340 }
341
342 err = twd_local_timer_common_register();
343
344out:
345 WARN(err, "twd_local_timer_of_register failed (%d)\n", err);
346}
347#endif