diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2013-03-14 23:31:39 -0400 |
---|---|---|
committer | David Brown <davidb@codeaurora.org> | 2013-03-22 13:46:16 -0400 |
commit | e25e3d1fef2c57e49aef64535341c15fe2b29b4a (patch) | |
tree | b5ae984efc823a9eb256e10c98f5b339f10e0712 /arch/arm/mach-msm | |
parent | eebdb0c1e1d63532399f7cbb65ade5969d63df06 (diff) |
ARM: msm: Wait for timer clear to complete
Without looping on the status bit, there is no way to guarantee
that a clear of the timer has actually completed. This can cause
us to enable the timer before the count has cleared and miss a
timer interrupt. To simplify this patch, remove the timer
register setup done during timer init, since it's duplicate work
that is eventually done in the set_next_event() callback.
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: David Brown <davidb@codeaurora.org>
Diffstat (limited to 'arch/arm/mach-msm')
-rw-r--r-- | arch/arm/mach-msm/timer.c | 41 |
1 files changed, 23 insertions, 18 deletions
diff --git a/arch/arm/mach-msm/timer.c b/arch/arm/mach-msm/timer.c index 165e33b9b1ee..b4b0d79476a8 100644 --- a/arch/arm/mach-msm/timer.c +++ b/arch/arm/mach-msm/timer.c | |||
@@ -30,20 +30,22 @@ | |||
30 | 30 | ||
31 | #include "common.h" | 31 | #include "common.h" |
32 | 32 | ||
33 | #define TIMER_MATCH_VAL 0x0000 | 33 | #define TIMER_MATCH_VAL 0x0000 |
34 | #define TIMER_COUNT_VAL 0x0004 | 34 | #define TIMER_COUNT_VAL 0x0004 |
35 | #define TIMER_ENABLE 0x0008 | 35 | #define TIMER_ENABLE 0x0008 |
36 | #define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1) | 36 | #define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1) |
37 | #define TIMER_ENABLE_EN BIT(0) | 37 | #define TIMER_ENABLE_EN BIT(0) |
38 | #define TIMER_CLEAR 0x000C | 38 | #define TIMER_CLEAR 0x000C |
39 | #define DGT_CLK_CTL 0x10 | 39 | #define DGT_CLK_CTL 0x10 |
40 | #define DGT_CLK_CTL_DIV_4 0x3 | 40 | #define DGT_CLK_CTL_DIV_4 0x3 |
41 | #define TIMER_STS_GPT0_CLR_PEND BIT(10) | ||
41 | 42 | ||
42 | #define GPT_HZ 32768 | 43 | #define GPT_HZ 32768 |
43 | 44 | ||
44 | #define MSM_DGT_SHIFT 5 | 45 | #define MSM_DGT_SHIFT 5 |
45 | 46 | ||
46 | static void __iomem *event_base; | 47 | static void __iomem *event_base; |
48 | static void __iomem *sts_base; | ||
47 | 49 | ||
48 | static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) | 50 | static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) |
49 | { | 51 | { |
@@ -65,6 +67,11 @@ static int msm_timer_set_next_event(unsigned long cycles, | |||
65 | 67 | ||
66 | writel_relaxed(0, event_base + TIMER_CLEAR); | 68 | writel_relaxed(0, event_base + TIMER_CLEAR); |
67 | writel_relaxed(cycles, event_base + TIMER_MATCH_VAL); | 69 | writel_relaxed(cycles, event_base + TIMER_MATCH_VAL); |
70 | |||
71 | if (sts_base) | ||
72 | while (readl_relaxed(sts_base) & TIMER_STS_GPT0_CLR_PEND) | ||
73 | cpu_relax(); | ||
74 | |||
68 | writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE); | 75 | writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE); |
69 | return 0; | 76 | return 0; |
70 | } | 77 | } |
@@ -135,9 +142,6 @@ static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt) | |||
135 | if (!smp_processor_id()) | 142 | if (!smp_processor_id()) |
136 | return 0; | 143 | return 0; |
137 | 144 | ||
138 | writel_relaxed(0, event_base + TIMER_ENABLE); | ||
139 | writel_relaxed(0, event_base + TIMER_CLEAR); | ||
140 | writel_relaxed(~0, event_base + TIMER_MATCH_VAL); | ||
141 | evt->irq = msm_clockevent.irq; | 145 | evt->irq = msm_clockevent.irq; |
142 | evt->name = "local_timer"; | 146 | evt->name = "local_timer"; |
143 | evt->features = msm_clockevent.features; | 147 | evt->features = msm_clockevent.features; |
@@ -175,9 +179,6 @@ static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, | |||
175 | struct clocksource *cs = &msm_clocksource; | 179 | struct clocksource *cs = &msm_clocksource; |
176 | int res; | 180 | int res; |
177 | 181 | ||
178 | writel_relaxed(0, event_base + TIMER_ENABLE); | ||
179 | writel_relaxed(0, event_base + TIMER_CLEAR); | ||
180 | writel_relaxed(~0, event_base + TIMER_MATCH_VAL); | ||
181 | ce->cpumask = cpumask_of(0); | 182 | ce->cpumask = cpumask_of(0); |
182 | ce->irq = irq; | 183 | ce->irq = irq; |
183 | 184 | ||
@@ -272,6 +273,7 @@ void __init msm_dt_timer_init(void) | |||
272 | of_node_put(np); | 273 | of_node_put(np); |
273 | 274 | ||
274 | event_base = base + 0x4; | 275 | event_base = base + 0x4; |
276 | sts_base = base + 0x88; | ||
275 | source_base = cpu0_base + 0x24; | 277 | source_base = cpu0_base + 0x24; |
276 | freq /= 4; | 278 | freq /= 4; |
277 | writel_relaxed(DGT_CLK_CTL_DIV_4, source_base + DGT_CLK_CTL); | 279 | writel_relaxed(DGT_CLK_CTL_DIV_4, source_base + DGT_CLK_CTL); |
@@ -280,7 +282,8 @@ void __init msm_dt_timer_init(void) | |||
280 | } | 282 | } |
281 | #endif | 283 | #endif |
282 | 284 | ||
283 | static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source) | 285 | static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source, |
286 | u32 sts) | ||
284 | { | 287 | { |
285 | void __iomem *base; | 288 | void __iomem *base; |
286 | 289 | ||
@@ -291,6 +294,8 @@ static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source) | |||
291 | } | 294 | } |
292 | event_base = base + event; | 295 | event_base = base + event; |
293 | source_base = base + source; | 296 | source_base = base + source; |
297 | if (sts) | ||
298 | sts_base = base + sts; | ||
294 | 299 | ||
295 | return 0; | 300 | return 0; |
296 | } | 301 | } |
@@ -299,7 +304,7 @@ void __init msm7x01_timer_init(void) | |||
299 | { | 304 | { |
300 | struct clocksource *cs = &msm_clocksource; | 305 | struct clocksource *cs = &msm_clocksource; |
301 | 306 | ||
302 | if (msm_timer_map(0xc0100000, 0x0, 0x10)) | 307 | if (msm_timer_map(0xc0100000, 0x0, 0x10, 0x0)) |
303 | return; | 308 | return; |
304 | cs->read = msm_read_timer_count_shift; | 309 | cs->read = msm_read_timer_count_shift; |
305 | cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)); | 310 | cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)); |
@@ -310,14 +315,14 @@ void __init msm7x01_timer_init(void) | |||
310 | 315 | ||
311 | void __init msm7x30_timer_init(void) | 316 | void __init msm7x30_timer_init(void) |
312 | { | 317 | { |
313 | if (msm_timer_map(0xc0100000, 0x4, 0x24)) | 318 | if (msm_timer_map(0xc0100000, 0x4, 0x24, 0x80)) |
314 | return; | 319 | return; |
315 | msm_timer_init(24576000 / 4, 32, 1, false); | 320 | msm_timer_init(24576000 / 4, 32, 1, false); |
316 | } | 321 | } |
317 | 322 | ||
318 | void __init qsd8x50_timer_init(void) | 323 | void __init qsd8x50_timer_init(void) |
319 | { | 324 | { |
320 | if (msm_timer_map(0xAC100000, 0x0, 0x10)) | 325 | if (msm_timer_map(0xAC100000, 0x0, 0x10, 0x34)) |
321 | return; | 326 | return; |
322 | msm_timer_init(19200000 / 4, 32, 7, false); | 327 | msm_timer_init(19200000 / 4, 32, 7, false); |
323 | } | 328 | } |