diff options
author | Jonathan Austin <Jonathan.Austin@arm.com> | 2012-09-21 13:51:44 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-09-26 17:57:52 -0400 |
commit | 56942fec06efa0e17df0f4c3b438332c923b9014 (patch) | |
tree | 89b604c987b7f6a0eaaa16af7a9d8f45711349a7 /arch/arm/lib | |
parent | a1b2dde70419ae947fd7c9c8fcad7da005dc600e (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.c | 34 |
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 | 37 | static const struct delay_timer *delay_timer; |
38 | static bool delay_calibrated; | ||
39 | |||
40 | int 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 | |||
38 | static void __timer_delay(unsigned long cycles) | 49 | static 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 | ||
58 | void __init init_current_timer_delay(unsigned long freq) | 69 | void __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 | ||
67 | unsigned long __cpuinit calibrate_delay_is_known(void) | 85 | unsigned 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 | ||