aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2011-11-08 13:34:05 -0500
committerDavid Brown <davidb@codeaurora.org>2011-11-10 13:36:33 -0500
commitdd15ab814149df65187943c32ca09e4eeaac0047 (patch)
tree909789e3f7517e50882a42d5be7c1d99d3ad9856
parent4a1840755294b2a14236ee7b9c74ede261156b09 (diff)
msm: timer: Use GPT for clockevents and DGT for clocksource
The clocksource shouldn't stop ticking when the clockevent stops. This is exactly what happens today with MSM timers. The same hardware is used for both the clockevent and the clocksource because the ratings of the two are the same. Fix this by registering a clockevent based on the GPT and a clocksource based on the DGT. This removes any other possible configuration (e.g. a GPT clocksource and a DGT clockevent) but that shouldn't be a big issue since we want higher precision timing than high precision scheduling interrupts. Signed-off-by: Stephen Boyd <sboyd@codeaurora.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: David Brown <davidb@codeaurora.org>
-rw-r--r--arch/arm/mach-msm/timer.c121
1 files changed, 52 insertions, 69 deletions
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c
index ce389ca4950f..405e8a925202 100644
--- a/arch/arm/mach-msm/timer.c
+++ b/arch/arm/mach-msm/timer.c
@@ -1,6 +1,7 @@
1/* linux/arch/arm/mach-msm/timer.c 1/*
2 * 2 *
3 * Copyright (C) 2007 Google, Inc. 3 * Copyright (C) 2007 Google, Inc.
4 * Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
4 * 5 *
5 * This software is licensed under the terms of the GNU General Public 6 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and 7 * License version 2, as published by the Free Software Foundation, and
@@ -39,7 +40,7 @@
39 40
40#define GPT_HZ 32768 41#define GPT_HZ 32768
41 42
42#define MSM_GLOBAL_TIMER MSM_CLOCK_DGT 43#define MSM_GLOBAL_TIMER MSM_CLOCK_GPT
43 44
44/* TODO: Remove these ifdefs */ 45/* TODO: Remove these ifdefs */
45#if defined(CONFIG_ARCH_QSD8X50) 46#if defined(CONFIG_ARCH_QSD8X50)
@@ -153,25 +154,10 @@ static struct msm_clock msm_clocks[] = {
153 .set_next_event = msm_timer_set_next_event, 154 .set_next_event = msm_timer_set_next_event,
154 .set_mode = msm_timer_set_mode, 155 .set_mode = msm_timer_set_mode,
155 }, 156 },
156 .clocksource = {
157 .name = "gp_timer",
158 .rating = 200,
159 .read = msm_read_timer_count,
160 .mask = CLOCKSOURCE_MASK(32),
161 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
162 },
163 .irq = INT_GP_TIMER_EXP, 157 .irq = INT_GP_TIMER_EXP,
164 .freq = GPT_HZ, 158 .freq = GPT_HZ,
165 }, 159 },
166 [MSM_CLOCK_DGT] = { 160 [MSM_CLOCK_DGT] = {
167 .clockevent = {
168 .name = "dg_timer",
169 .features = CLOCK_EVT_FEAT_ONESHOT,
170 .shift = 32 + MSM_DGT_SHIFT,
171 .rating = 300,
172 .set_next_event = msm_timer_set_next_event,
173 .set_mode = msm_timer_set_mode,
174 },
175 .clocksource = { 161 .clocksource = {
176 .name = "dg_timer", 162 .name = "dg_timer",
177 .rating = 300, 163 .rating = 300,
@@ -179,7 +165,6 @@ static struct msm_clock msm_clocks[] = {
179 .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)), 165 .mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)),
180 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 166 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
181 }, 167 },
182 .irq = INT_DEBUG_TIMER_EXP,
183 .freq = DGT_HZ >> MSM_DGT_SHIFT, 168 .freq = DGT_HZ >> MSM_DGT_SHIFT,
184 .shift = MSM_DGT_SHIFT, 169 .shift = MSM_DGT_SHIFT,
185 } 170 }
@@ -187,10 +172,13 @@ static struct msm_clock msm_clocks[] = {
187 172
188static void __init msm_timer_init(void) 173static void __init msm_timer_init(void)
189{ 174{
190 int i; 175 struct msm_clock *clock;
176 struct clock_event_device *ce = &msm_clocks[MSM_CLOCK_GPT].clockevent;
177 struct clocksource *cs = &msm_clocks[MSM_CLOCK_DGT].clocksource;
191 int res; 178 int res;
192 int global_offset = 0; 179 int global_offset = 0;
193 180
181
194 if (cpu_is_msm7x01()) { 182 if (cpu_is_msm7x01()) {
195 msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE; 183 msm_clocks[MSM_CLOCK_GPT].regbase = MSM_CSR_BASE;
196 msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10; 184 msm_clocks[MSM_CLOCK_DGT].regbase = MSM_CSR_BASE + 0x10;
@@ -213,58 +201,55 @@ static void __init msm_timer_init(void)
213 writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL); 201 writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
214#endif 202#endif
215 203
216 for (i = 0; i < ARRAY_SIZE(msm_clocks); i++) { 204 clock = &msm_clocks[MSM_CLOCK_GPT];
217 struct msm_clock *clock = &msm_clocks[i]; 205 clock->local_counter = clock->regbase + TIMER_COUNT_VAL;
218 struct clock_event_device *ce = &clock->clockevent;
219 struct clocksource *cs = &clock->clocksource;
220
221 clock->local_counter = clock->regbase + TIMER_COUNT_VAL;
222 clock->global_counter = clock->local_counter + global_offset;
223
224 writel(0, clock->regbase + TIMER_ENABLE);
225 writel(0, clock->regbase + TIMER_CLEAR);
226 writel(~0, clock->regbase + TIMER_MATCH_VAL);
227 206
228 ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift); 207 writel_relaxed(0, clock->regbase + TIMER_ENABLE);
229 /* allow at least 10 seconds to notice that the timer wrapped */ 208 writel_relaxed(0, clock->regbase + TIMER_CLEAR);
230 ce->max_delta_ns = 209 writel_relaxed(~0, clock->regbase + TIMER_MATCH_VAL);
231 clockevent_delta2ns(0xf0000000 >> clock->shift, ce); 210 ce->mult = div_sc(clock->freq, NSEC_PER_SEC, ce->shift);
232 /* 4 gets rounded down to 3 */ 211 /*
233 ce->min_delta_ns = clockevent_delta2ns(4, ce); 212 * allow at least 10 seconds to notice that the timer
234 ce->cpumask = cpumask_of(0); 213 * wrapped
235 214 */
236 res = clocksource_register_hz(cs, clock->freq); 215 ce->max_delta_ns =
237 if (res) 216 clockevent_delta2ns(0xf0000000 >> clock->shift, ce);
238 printk(KERN_ERR "msm_timer_init: clocksource_register " 217 /* 4 gets rounded down to 3 */
239 "failed for %s\n", cs->name); 218 ce->min_delta_ns = clockevent_delta2ns(4, ce);
240 219 ce->cpumask = cpumask_of(0);
241 ce->irq = clock->irq; 220
242 if (cpu_is_msm8x60() || cpu_is_msm8960()) { 221 ce->irq = clock->irq;
243 clock->percpu_evt = alloc_percpu(struct clock_event_device *); 222 if (cpu_is_msm8x60() || cpu_is_msm8960()) {
244 if (!clock->percpu_evt) { 223 clock->percpu_evt = alloc_percpu(struct clock_event_device *);
245 pr_err("msm_timer_init: memory allocation " 224 if (!clock->percpu_evt) {
246 "failed for %s\n", ce->name); 225 pr_err("memory allocation failed for %s\n", ce->name);
247 continue; 226 goto err;
248 }
249
250 *__this_cpu_ptr(clock->percpu_evt) = ce;
251 res = request_percpu_irq(ce->irq, msm_timer_interrupt,
252 ce->name, clock->percpu_evt);
253 if (!res)
254 enable_percpu_irq(ce->irq, 0);
255 } else {
256 clock->evt = ce;
257 res = request_irq(ce->irq, msm_timer_interrupt,
258 IRQF_TIMER | IRQF_NOBALANCING | IRQF_TRIGGER_RISING,
259 ce->name, &clock->evt);
260 } 227 }
261 228
262 if (res) 229 *__this_cpu_ptr(clock->percpu_evt) = ce;
263 pr_err("msm_timer_init: request_irq failed for %s\n", 230 res = request_percpu_irq(ce->irq, msm_timer_interrupt,
264 ce->name); 231 ce->name, clock->percpu_evt);
265 232 if (!res)
266 clockevents_register_device(ce); 233 enable_percpu_irq(ce->irq, 0);
234 } else {
235 clock->evt = ce;
236 res = request_irq(ce->irq, msm_timer_interrupt,
237 IRQF_TIMER | IRQF_NOBALANCING |
238 IRQF_TRIGGER_RISING, ce->name, &clock->evt);
267 } 239 }
240
241 if (res)
242 pr_err("request_irq failed for %s\n", ce->name);
243
244 clockevents_register_device(ce);
245err:
246 clock = &msm_clocks[MSM_CLOCK_DGT];
247 clock->local_counter = clock->regbase + TIMER_COUNT_VAL;
248 clock->global_counter = clock->local_counter + global_offset;
249 writel_relaxed(TIMER_ENABLE_EN, clock->regbase + TIMER_ENABLE);
250 res = clocksource_register_hz(cs, clock->freq);
251 if (res)
252 pr_err("clocksource_register failed for %s\n", cs->name);
268} 253}
269 254
270#ifdef CONFIG_LOCAL_TIMERS 255#ifdef CONFIG_LOCAL_TIMERS
@@ -277,8 +262,6 @@ int __cpuinit local_timer_setup(struct clock_event_device *evt)
277 if (!smp_processor_id()) 262 if (!smp_processor_id())
278 return 0; 263 return 0;
279 264
280 writel(DGT_CLK_CTL_DIV_4, MSM_TMR_BASE + DGT_CLK_CTL);
281
282 if (!local_timer_inited) { 265 if (!local_timer_inited) {
283 writel(0, clock->regbase + TIMER_ENABLE); 266 writel(0, clock->regbase + TIMER_ENABLE);
284 writel(0, clock->regbase + TIMER_CLEAR); 267 writel(0, clock->regbase + TIMER_CLEAR);