aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/lib
diff options
context:
space:
mode:
authorJonathan Austin <Jonathan.Austin@arm.com>2012-09-21 13:51:44 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-09-26 17:57:52 -0400
commit56942fec06efa0e17df0f4c3b438332c923b9014 (patch)
tree89b604c987b7f6a0eaaa16af7a9d8f45711349a7 /arch/arm/lib
parenta1b2dde70419ae947fd7c9c8fcad7da005dc600e (diff)
ARM: 7538/1: delay: add registration mechanism for delay timer sources
The current timer-based delay loop relies on the architected timer to initiate the switch away from the polling-based implementation. This is unfortunate for platforms without the architected timers but with a suitable delay source (that is, constant frequency, always powered-up and ticking as long as the CPUs are online). This patch introduces a registration mechanism for the delay timer (which provides an unconditional read_current_timer implementation) and updates the architected timer code to use the new interface. Reviewed-by: Stephen Boyd <sboyd@codeaurora.org> Signed-off-by: Jonathan Austin <jonathan.austin@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/lib')
-rw-r--r--arch/arm/lib/delay.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/arch/arm/lib/delay.c b/arch/arm/lib/delay.c
index d6dacc69254e..9d0a30032d7f 100644
--- a/arch/arm/lib/delay.c
+++ b/arch/arm/lib/delay.c
@@ -34,7 +34,18 @@ struct arm_delay_ops arm_delay_ops = {
34 .udelay = __loop_udelay, 34 .udelay = __loop_udelay,
35}; 35};
36 36
37#ifdef ARCH_HAS_READ_CURRENT_TIMER 37static const struct delay_timer *delay_timer;
38static bool delay_calibrated;
39
40int read_current_timer(unsigned long *timer_val)
41{
42 if (!delay_timer)
43 return -ENXIO;
44
45 *timer_val = delay_timer->read_current_timer();
46 return 0;
47}
48
38static void __timer_delay(unsigned long cycles) 49static void __timer_delay(unsigned long cycles)
39{ 50{
40 cycles_t start = get_cycles(); 51 cycles_t start = get_cycles();
@@ -55,17 +66,24 @@ static void __timer_udelay(unsigned long usecs)
55 __timer_const_udelay(usecs * UDELAY_MULT); 66 __timer_const_udelay(usecs * UDELAY_MULT);
56} 67}
57 68
58void __init init_current_timer_delay(unsigned long freq) 69void __init register_current_timer_delay(const struct delay_timer *timer)
59{ 70{
60 pr_info("Switching to timer-based delay loop\n"); 71 if (!delay_calibrated) {
61 lpj_fine = freq / HZ; 72 pr_info("Switching to timer-based delay loop\n");
62 arm_delay_ops.delay = __timer_delay; 73 delay_timer = timer;
63 arm_delay_ops.const_udelay = __timer_const_udelay; 74 lpj_fine = timer->freq / HZ;
64 arm_delay_ops.udelay = __timer_udelay; 75 loops_per_jiffy = lpj_fine;
76 arm_delay_ops.delay = __timer_delay;
77 arm_delay_ops.const_udelay = __timer_const_udelay;
78 arm_delay_ops.udelay = __timer_udelay;
79 delay_calibrated = true;
80 } else {
81 pr_info("Ignoring duplicate/late registration of read_current_timer delay\n");
82 }
65} 83}
66 84
67unsigned long __cpuinit calibrate_delay_is_known(void) 85unsigned long __cpuinit calibrate_delay_is_known(void)
68{ 86{
87 delay_calibrated = true;
69 return lpj_fine; 88 return lpj_fine;
70} 89}
71#endif