aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-nomadik
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2010-12-15 16:53:02 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2010-12-22 17:44:48 -0500
commitec05aa139939d9c7b790041a379f0e752b2f1a4d (patch)
treed1af6271a2e832e44a1a8c42550484f1ec55c50c /arch/arm/plat-nomadik
parent08f26b1ef25a2f7b52afcb805d260fd5a000a7f6 (diff)
ARM: nomadik: convert sched_clock() to use new infrastructure
Convert nomadik platforms to use the new sched_clock() infrastructure for extending 32bit counters to full 64-bit nanoseconds. Acked-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/plat-nomadik')
-rw-r--r--arch/arm/plat-nomadik/Kconfig1
-rw-r--r--arch/arm/plat-nomadik/timer.c76
2 files changed, 10 insertions, 67 deletions
diff --git a/arch/arm/plat-nomadik/Kconfig b/arch/arm/plat-nomadik/Kconfig
index 5da3f97c537b..187f4e84bb22 100644
--- a/arch/arm/plat-nomadik/Kconfig
+++ b/arch/arm/plat-nomadik/Kconfig
@@ -14,6 +14,7 @@ if PLAT_NOMADIK
14 14
15config HAS_MTU 15config HAS_MTU
16 bool 16 bool
17 select HAVE_SCHED_CLOCK
17 help 18 help
18 Support for Multi Timer Unit. MTU provides access 19 Support for Multi Timer Unit. MTU provides access
19 to multiple interrupt generating programmable 20 to multiple interrupt generating programmable
diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c
index c3b8a2246b99..41723402006b 100644
--- a/arch/arm/plat-nomadik/timer.c
+++ b/arch/arm/plat-nomadik/timer.c
@@ -17,10 +17,9 @@
17#include <linux/clk.h> 17#include <linux/clk.h>
18#include <linux/jiffies.h> 18#include <linux/jiffies.h>
19#include <linux/err.h> 19#include <linux/err.h>
20#include <linux/cnt32_to_63.h>
21#include <linux/timer.h>
22#include <linux/sched.h> 20#include <linux/sched.h>
23#include <asm/mach/time.h> 21#include <asm/mach/time.h>
22#include <asm/sched_clock.h>
24 23
25#include <plat/mtu.h> 24#include <plat/mtu.h>
26 25
@@ -53,81 +52,24 @@ static struct clocksource nmdk_clksrc = {
53 * Override the global weak sched_clock symbol with this 52 * Override the global weak sched_clock symbol with this
54 * local implementation which uses the clocksource to get some 53 * local implementation which uses the clocksource to get some
55 * better resolution when scheduling the kernel. 54 * better resolution when scheduling the kernel.
56 *
57 * Because the hardware timer period may be quite short
58 * (32.3 secs on the 133 MHz MTU timer selection on ux500)
59 * and because cnt32_to_63() needs to be called at least once per
60 * half period to work properly, a kernel keepwarm() timer is set up
61 * to ensure this requirement is always met.
62 *
63 * Also the sched_clock timer will wrap around at some point,
64 * here we set it to run continously for a year.
65 */ 55 */
66#define SCHED_CLOCK_MIN_WRAP 3600*24*365 56static DEFINE_CLOCK_DATA(cd);
67static struct timer_list cnt32_to_63_keepwarm_timer;
68static u32 sched_mult;
69static u32 sched_shift;
70 57
71unsigned long long notrace sched_clock(void) 58unsigned long long notrace sched_clock(void)
72{ 59{
73 u64 cycles; 60 u32 cyc;
74 61
75 if (unlikely(!mtu_base)) 62 if (unlikely(!mtu_base))
76 return 0; 63 return 0;
77 64
78 cycles = cnt32_to_63(-readl(mtu_base + MTU_VAL(0))); 65 cyc = -readl(mtu_base + MTU_VAL(0));
79 /* 66 return cyc_to_sched_clock(&cd, cyc, (u32)~0);
80 * sched_mult is guaranteed to be even so will
81 * shift out bit 63
82 */
83 return (cycles * sched_mult) >> sched_shift;
84} 67}
85 68
86/* Just kick sched_clock every so often */ 69static void notrace nomadik_update_sched_clock(void)
87static void cnt32_to_63_keepwarm(unsigned long data)
88{ 70{
89 mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data)); 71 u32 cyc = -readl(mtu_base + MTU_VAL(0));
90 (void) sched_clock(); 72 update_sched_clock(&cd, cyc, (u32)~0);
91}
92
93/*
94 * Set up a timer to keep sched_clock():s 32_to_63 algorithm warm
95 * once in half a 32bit timer wrap interval.
96 */
97static void __init nmdk_sched_clock_init(unsigned long rate)
98{
99 u32 v;
100 unsigned long delta;
101 u64 days;
102
103 /* Find the apropriate mult and shift factors */
104 clocks_calc_mult_shift(&sched_mult, &sched_shift,
105 rate, NSEC_PER_SEC, SCHED_CLOCK_MIN_WRAP);
106 /* We need to multiply by an even number to get rid of bit 63 */
107 if (sched_mult & 1)
108 sched_mult++;
109
110 /* Let's see what we get, take max counter and scale it */
111 days = (0xFFFFFFFFFFFFFFFFLLU * sched_mult) >> sched_shift;
112 do_div(days, NSEC_PER_SEC);
113 do_div(days, (3600*24));
114
115 pr_info("sched_clock: using %d bits @ %lu Hz wrap in %lu days\n",
116 (64 - sched_shift), rate, (unsigned long) days);
117
118 /*
119 * Program a timer to kick us at half 32bit wraparound
120 * Formula: seconds per wrap = (2^32) / f
121 */
122 v = 0xFFFFFFFFUL / rate;
123 /* We want half of the wrap time to keep cnt32_to_63 warm */
124 v /= 2;
125 pr_debug("sched_clock: prescaled timer rate: %lu Hz, "
126 "initialize keepwarm timer every %d seconds\n", rate, v);
127 /* Convert seconds to jiffies */
128 delta = msecs_to_jiffies(v*1000);
129 setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, delta);
130 mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + delta));
131} 73}
132 74
133/* Clockevent device: use one-shot mode */ 75/* Clockevent device: use one-shot mode */
@@ -237,7 +179,7 @@ void __init nmdk_timer_init(void)
237 pr_err("timer: failed to initialize clock source %s\n", 179 pr_err("timer: failed to initialize clock source %s\n",
238 nmdk_clksrc.name); 180 nmdk_clksrc.name);
239 181
240 nmdk_sched_clock_init(rate); 182 init_sched_clock(&cd, nomadik_update_sched_clock, 32, rate);
241 183
242 /* Timer 1 is used for events */ 184 /* Timer 1 is used for events */
243 185