diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2013-03-15 04:31:39 +0100 |
---|---|---|
committer | David Brown <davidb@codeaurora.org> | 2013-03-22 18:46:16 +0100 |
commit | e25e3d1fef2c57e49aef64535341c15fe2b29b4a (patch) | |
tree | b5ae984efc823a9eb256e10c98f5b339f10e0712 | |
parent | ARM: msm: Rework timer binding to be more general (diff) | |
download | linux-e25e3d1fef2c57e49aef64535341c15fe2b29b4a.tar.xz linux-e25e3d1fef2c57e49aef64535341c15fe2b29b4a.zip |
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>
-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 @@ #include "common.h" -#define TIMER_MATCH_VAL 0x0000 -#define TIMER_COUNT_VAL 0x0004 -#define TIMER_ENABLE 0x0008 -#define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1) -#define TIMER_ENABLE_EN BIT(0) -#define TIMER_CLEAR 0x000C -#define DGT_CLK_CTL 0x10 -#define DGT_CLK_CTL_DIV_4 0x3 +#define TIMER_MATCH_VAL 0x0000 +#define TIMER_COUNT_VAL 0x0004 +#define TIMER_ENABLE 0x0008 +#define TIMER_ENABLE_CLR_ON_MATCH_EN BIT(1) +#define TIMER_ENABLE_EN BIT(0) +#define TIMER_CLEAR 0x000C +#define DGT_CLK_CTL 0x10 +#define DGT_CLK_CTL_DIV_4 0x3 +#define TIMER_STS_GPT0_CLR_PEND BIT(10) #define GPT_HZ 32768 #define MSM_DGT_SHIFT 5 static void __iomem *event_base; +static void __iomem *sts_base; static irqreturn_t msm_timer_interrupt(int irq, void *dev_id) { @@ -65,6 +67,11 @@ static int msm_timer_set_next_event(unsigned long cycles, writel_relaxed(0, event_base + TIMER_CLEAR); writel_relaxed(cycles, event_base + TIMER_MATCH_VAL); + + if (sts_base) + while (readl_relaxed(sts_base) & TIMER_STS_GPT0_CLR_PEND) + cpu_relax(); + writel_relaxed(ctrl | TIMER_ENABLE_EN, event_base + TIMER_ENABLE); return 0; } @@ -135,9 +142,6 @@ static int __cpuinit msm_local_timer_setup(struct clock_event_device *evt) if (!smp_processor_id()) return 0; - writel_relaxed(0, event_base + TIMER_ENABLE); - writel_relaxed(0, event_base + TIMER_CLEAR); - writel_relaxed(~0, event_base + TIMER_MATCH_VAL); evt->irq = msm_clockevent.irq; evt->name = "local_timer"; evt->features = msm_clockevent.features; @@ -175,9 +179,6 @@ static void __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq, struct clocksource *cs = &msm_clocksource; int res; - writel_relaxed(0, event_base + TIMER_ENABLE); - writel_relaxed(0, event_base + TIMER_CLEAR); - writel_relaxed(~0, event_base + TIMER_MATCH_VAL); ce->cpumask = cpumask_of(0); ce->irq = irq; @@ -272,6 +273,7 @@ void __init msm_dt_timer_init(void) of_node_put(np); event_base = base + 0x4; + sts_base = base + 0x88; source_base = cpu0_base + 0x24; freq /= 4; writel_relaxed(DGT_CLK_CTL_DIV_4, source_base + DGT_CLK_CTL); @@ -280,7 +282,8 @@ void __init msm_dt_timer_init(void) } #endif -static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source) +static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source, + u32 sts) { void __iomem *base; @@ -291,6 +294,8 @@ static int __init msm_timer_map(phys_addr_t addr, u32 event, u32 source) } event_base = base + event; source_base = base + source; + if (sts) + sts_base = base + sts; return 0; } @@ -299,7 +304,7 @@ void __init msm7x01_timer_init(void) { struct clocksource *cs = &msm_clocksource; - if (msm_timer_map(0xc0100000, 0x0, 0x10)) + if (msm_timer_map(0xc0100000, 0x0, 0x10, 0x0)) return; cs->read = msm_read_timer_count_shift; cs->mask = CLOCKSOURCE_MASK((32 - MSM_DGT_SHIFT)); @@ -310,14 +315,14 @@ void __init msm7x01_timer_init(void) void __init msm7x30_timer_init(void) { - if (msm_timer_map(0xc0100000, 0x4, 0x24)) + if (msm_timer_map(0xc0100000, 0x4, 0x24, 0x80)) return; msm_timer_init(24576000 / 4, 32, 1, false); } void __init qsd8x50_timer_init(void) { - if (msm_timer_map(0xAC100000, 0x0, 0x10)) + if (msm_timer_map(0xAC100000, 0x0, 0x10, 0x34)) return; msm_timer_init(19200000 / 4, 32, 7, false); } |