aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/arm_arch_timer.c
diff options
context:
space:
mode:
authorDaniel Lezcano <daniel.lezcano@linaro.org>2013-10-03 10:13:51 -0400
committerDaniel Lezcano <daniel.lezcano@linaro.org>2013-10-03 10:13:51 -0400
commit191124efb4d6e5e47fe073b4b97350873523e88c (patch)
tree8fb9dbbff739e19aa1750c58fe5ec12ee6547e49 /drivers/clocksource/arm_arch_timer.c
parent68e90740284c69292881cd38c7ece6f09a18a58f (diff)
parent346e7480f1d4740b3d798da60f83f087ea6488b4 (diff)
Merge branch 'timer_evtstrm' of git://linux-arm.org/linux-skn into clockevents/3.13
Adds support to configure the rate and enable the event stream for architected timer. The event streams can be used to impose a timeout on a wfe, to safeguard against any programming error in case an expected event is not generated or even to implement wfe-based timeouts for userspace locking implementations. This feature can be disabled(enabled by default). Since the timer control register is reset to zero on warm boot, CPU PM notifier is added to save and restore the value. Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r--drivers/clocksource/arm_arch_timer.c49
1 files changed, 49 insertions, 0 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index ce98d5e70927..b94b0d44c158 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -13,6 +13,7 @@
13#include <linux/device.h> 13#include <linux/device.h>
14#include <linux/smp.h> 14#include <linux/smp.h>
15#include <linux/cpu.h> 15#include <linux/cpu.h>
16#include <linux/cpu_pm.h>
16#include <linux/clockchips.h> 17#include <linux/clockchips.h>
17#include <linux/interrupt.h> 18#include <linux/interrupt.h>
18#include <linux/of_irq.h> 19#include <linux/of_irq.h>
@@ -294,6 +295,19 @@ static void __arch_timer_setup(unsigned type,
294 clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff); 295 clockevents_config_and_register(clk, arch_timer_rate, 0xf, 0x7fffffff);
295} 296}
296 297
298static void arch_timer_configure_evtstream(void)
299{
300 int evt_stream_div, pos;
301
302 /* Find the closest power of two to the divisor */
303 evt_stream_div = arch_timer_rate / ARCH_TIMER_EVT_STREAM_FREQ;
304 pos = fls(evt_stream_div);
305 if (pos > 1 && !(evt_stream_div & (1 << (pos - 2))))
306 pos--;
307 /* enable event stream */
308 arch_timer_evtstrm_enable(min(pos, 15));
309}
310
297static int arch_timer_setup(struct clock_event_device *clk) 311static int arch_timer_setup(struct clock_event_device *clk)
298{ 312{
299 __arch_timer_setup(ARCH_CP15_TIMER, clk); 313 __arch_timer_setup(ARCH_CP15_TIMER, clk);
@@ -307,6 +321,8 @@ static int arch_timer_setup(struct clock_event_device *clk)
307 } 321 }
308 322
309 arch_counter_set_user_access(); 323 arch_counter_set_user_access();
324 if (IS_ENABLED(CONFIG_ARM_ARCH_TIMER_EVTSTREAM))
325 arch_timer_configure_evtstream();
310 326
311 return 0; 327 return 0;
312} 328}
@@ -460,6 +476,33 @@ static struct notifier_block arch_timer_cpu_nb = {
460 .notifier_call = arch_timer_cpu_notify, 476 .notifier_call = arch_timer_cpu_notify,
461}; 477};
462 478
479#ifdef CONFIG_CPU_PM
480static unsigned int saved_cntkctl;
481static int arch_timer_cpu_pm_notify(struct notifier_block *self,
482 unsigned long action, void *hcpu)
483{
484 if (action == CPU_PM_ENTER)
485 saved_cntkctl = arch_timer_get_cntkctl();
486 else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT)
487 arch_timer_set_cntkctl(saved_cntkctl);
488 return NOTIFY_OK;
489}
490
491static struct notifier_block arch_timer_cpu_pm_notifier = {
492 .notifier_call = arch_timer_cpu_pm_notify,
493};
494
495static int __init arch_timer_cpu_pm_init(void)
496{
497 return cpu_pm_register_notifier(&arch_timer_cpu_pm_notifier);
498}
499#else
500static int __init arch_timer_cpu_pm_init(void)
501{
502 return 0;
503}
504#endif
505
463static int __init arch_timer_register(void) 506static int __init arch_timer_register(void)
464{ 507{
465 int err; 508 int err;
@@ -499,11 +542,17 @@ static int __init arch_timer_register(void)
499 if (err) 542 if (err)
500 goto out_free_irq; 543 goto out_free_irq;
501 544
545 err = arch_timer_cpu_pm_init();
546 if (err)
547 goto out_unreg_notify;
548
502 /* Immediately configure the timer on the boot CPU */ 549 /* Immediately configure the timer on the boot CPU */
503 arch_timer_setup(this_cpu_ptr(arch_timer_evt)); 550 arch_timer_setup(this_cpu_ptr(arch_timer_evt));
504 551
505 return 0; 552 return 0;
506 553
554out_unreg_notify:
555 unregister_cpu_notifier(&arch_timer_cpu_nb);
507out_free_irq: 556out_free_irq:
508 if (arch_timer_use_virtual) 557 if (arch_timer_use_virtual)
509 free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt); 558 free_percpu_irq(arch_timer_ppi[VIRT_PPI], arch_timer_evt);