diff options
Diffstat (limited to 'arch/arm/plat-nomadik/timer.c')
-rw-r--r-- | arch/arm/plat-nomadik/timer.c | 80 |
1 files changed, 11 insertions, 69 deletions
diff --git a/arch/arm/plat-nomadik/timer.c b/arch/arm/plat-nomadik/timer.c index 63cdc6025bd7..41723402006b 100644 --- a/arch/arm/plat-nomadik/timer.c +++ b/arch/arm/plat-nomadik/timer.c | |||
@@ -17,9 +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> | 20 | #include <linux/sched.h> |
21 | #include <linux/timer.h> | ||
22 | #include <asm/mach/time.h> | 21 | #include <asm/mach/time.h> |
22 | #include <asm/sched_clock.h> | ||
23 | 23 | ||
24 | #include <plat/mtu.h> | 24 | #include <plat/mtu.h> |
25 | 25 | ||
@@ -52,81 +52,24 @@ static struct clocksource nmdk_clksrc = { | |||
52 | * Override the global weak sched_clock symbol with this | 52 | * Override the global weak sched_clock symbol with this |
53 | * local implementation which uses the clocksource to get some | 53 | * local implementation which uses the clocksource to get some |
54 | * better resolution when scheduling the kernel. | 54 | * better resolution when scheduling the kernel. |
55 | * | ||
56 | * Because the hardware timer period may be quite short | ||
57 | * (32.3 secs on the 133 MHz MTU timer selection on ux500) | ||
58 | * and because cnt32_to_63() needs to be called at least once per | ||
59 | * half period to work properly, a kernel keepwarm() timer is set up | ||
60 | * to ensure this requirement is always met. | ||
61 | * | ||
62 | * Also the sched_clock timer will wrap around at some point, | ||
63 | * here we set it to run continously for a year. | ||
64 | */ | 55 | */ |
65 | #define SCHED_CLOCK_MIN_WRAP 3600*24*365 | 56 | static DEFINE_CLOCK_DATA(cd); |
66 | static struct timer_list cnt32_to_63_keepwarm_timer; | ||
67 | static u32 sched_mult; | ||
68 | static u32 sched_shift; | ||
69 | 57 | ||
70 | unsigned long long notrace sched_clock(void) | 58 | unsigned long long notrace sched_clock(void) |
71 | { | 59 | { |
72 | u64 cycles; | 60 | u32 cyc; |
73 | 61 | ||
74 | if (unlikely(!mtu_base)) | 62 | if (unlikely(!mtu_base)) |
75 | return 0; | 63 | return 0; |
76 | 64 | ||
77 | cycles = cnt32_to_63(-readl(mtu_base + MTU_VAL(0))); | 65 | cyc = -readl(mtu_base + MTU_VAL(0)); |
78 | /* | 66 | return cyc_to_sched_clock(&cd, cyc, (u32)~0); |
79 | * sched_mult is guaranteed to be even so will | ||
80 | * shift out bit 63 | ||
81 | */ | ||
82 | return (cycles * sched_mult) >> sched_shift; | ||
83 | } | 67 | } |
84 | 68 | ||
85 | /* Just kick sched_clock every so often */ | 69 | static void notrace nomadik_update_sched_clock(void) |
86 | static void cnt32_to_63_keepwarm(unsigned long data) | ||
87 | { | 70 | { |
88 | mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + data)); | 71 | u32 cyc = -readl(mtu_base + MTU_VAL(0)); |
89 | (void) sched_clock(); | 72 | update_sched_clock(&cd, cyc, (u32)~0); |
90 | } | ||
91 | |||
92 | /* | ||
93 | * Set up a timer to keep sched_clock():s 32_to_63 algorithm warm | ||
94 | * once in half a 32bit timer wrap interval. | ||
95 | */ | ||
96 | static void __init nmdk_sched_clock_init(unsigned long rate) | ||
97 | { | ||
98 | u32 v; | ||
99 | unsigned long delta; | ||
100 | u64 days; | ||
101 | |||
102 | /* Find the apropriate mult and shift factors */ | ||
103 | clocks_calc_mult_shift(&sched_mult, &sched_shift, | ||
104 | rate, NSEC_PER_SEC, SCHED_CLOCK_MIN_WRAP); | ||
105 | /* We need to multiply by an even number to get rid of bit 63 */ | ||
106 | if (sched_mult & 1) | ||
107 | sched_mult++; | ||
108 | |||
109 | /* Let's see what we get, take max counter and scale it */ | ||
110 | days = (0xFFFFFFFFFFFFFFFFLLU * sched_mult) >> sched_shift; | ||
111 | do_div(days, NSEC_PER_SEC); | ||
112 | do_div(days, (3600*24)); | ||
113 | |||
114 | pr_info("sched_clock: using %d bits @ %lu Hz wrap in %lu days\n", | ||
115 | (64 - sched_shift), rate, (unsigned long) days); | ||
116 | |||
117 | /* | ||
118 | * Program a timer to kick us at half 32bit wraparound | ||
119 | * Formula: seconds per wrap = (2^32) / f | ||
120 | */ | ||
121 | v = 0xFFFFFFFFUL / rate; | ||
122 | /* We want half of the wrap time to keep cnt32_to_63 warm */ | ||
123 | v /= 2; | ||
124 | pr_debug("sched_clock: prescaled timer rate: %lu Hz, " | ||
125 | "initialize keepwarm timer every %d seconds\n", rate, v); | ||
126 | /* Convert seconds to jiffies */ | ||
127 | delta = msecs_to_jiffies(v*1000); | ||
128 | setup_timer(&cnt32_to_63_keepwarm_timer, cnt32_to_63_keepwarm, delta); | ||
129 | mod_timer(&cnt32_to_63_keepwarm_timer, round_jiffies(jiffies + delta)); | ||
130 | } | 73 | } |
131 | 74 | ||
132 | /* Clockevent device: use one-shot mode */ | 75 | /* Clockevent device: use one-shot mode */ |
@@ -222,7 +165,6 @@ void __init nmdk_timer_init(void) | |||
222 | } else { | 165 | } else { |
223 | cr |= MTU_CRn_PRESCALE_1; | 166 | cr |= MTU_CRn_PRESCALE_1; |
224 | } | 167 | } |
225 | clocksource_calc_mult_shift(&nmdk_clksrc, rate, MTU_MIN_RANGE); | ||
226 | 168 | ||
227 | /* Timer 0 is the free running clocksource */ | 169 | /* Timer 0 is the free running clocksource */ |
228 | writel(cr, mtu_base + MTU_CR(0)); | 170 | writel(cr, mtu_base + MTU_CR(0)); |
@@ -233,11 +175,11 @@ void __init nmdk_timer_init(void) | |||
233 | /* Now the clock source is ready */ | 175 | /* Now the clock source is ready */ |
234 | nmdk_clksrc.read = nmdk_read_timer; | 176 | nmdk_clksrc.read = nmdk_read_timer; |
235 | 177 | ||
236 | if (clocksource_register(&nmdk_clksrc)) | 178 | if (clocksource_register_hz(&nmdk_clksrc, rate)) |
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 | ||