generic-poky/meta/packages/linux/linux-omap2-git/beagleboard/02-gptimer_use_match_for_tick

98 lines
3.4 KiB
Plaintext

OMAP2/3 system tick GPTIMER: use match interrupts rather than overflow interrupts
From: Paul Walmsley <paul@pwsan.com>
On some OMAP3 chips, GPTIMER1 will occasionally decline to interrupt
the MPU when a timer overflow event occurs. The timer stops running;
and TOCR is sometimes incremented; but the MPU apparently never receives
the interrupt. This patch was an experiment in using the GPTIMER
match interrupt to determine if it resolves the problem.
Unfortunately, it does not; the same problem occurs with match
interrupts; but this patch is preserved as the base for a
match+overflow interrupt workaround used in a following patch.
---
arch/arm/mach-omap2/timer-gp.c | 32 ++++++++++----------------------
1 files changed, 10 insertions(+), 22 deletions(-)
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 557603f..51996ba 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -36,6 +36,8 @@
#include <asm/mach/time.h>
#include <asm/arch/dmtimer.h>
+#define GPTIMER_MATCH_VAL 0xffff0000
+
static struct omap_dm_timer *gptimer;
static struct clock_event_device clockevent_gpt;
@@ -44,7 +46,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
struct omap_dm_timer *gpt = (struct omap_dm_timer *)dev_id;
struct clock_event_device *evt = &clockevent_gpt;
- omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_OVERFLOW);
+ omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_MATCH);
evt->event_handler(evt);
return IRQ_HANDLED;
@@ -59,7 +61,7 @@ static struct irqaction omap2_gp_timer_irq = {
static int omap2_gp_timer_set_next_event(unsigned long cycles,
struct clock_event_device *evt)
{
- omap_dm_timer_set_load_start(gptimer, 0, 0xffffffff - cycles);
+ omap_dm_timer_set_load_start(gptimer, 0, GPTIMER_MATCH_VAL - cycles);
return 0;
}
@@ -67,29 +69,12 @@ static int omap2_gp_timer_set_next_event(unsigned long cycles,
static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
- u32 period;
-
omap_dm_timer_stop(gptimer);
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ;
- period -= 1;
-
- omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period);
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_RESUME:
- break;
- }
}
static struct clock_event_device clockevent_gpt = {
.name = "gp timer",
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .features = CLOCK_EVT_FEAT_ONESHOT,
.shift = 32,
.set_next_event = omap2_gp_timer_set_next_event,
.set_mode = omap2_gp_timer_set_mode,
@@ -111,12 +96,15 @@ static void __init omap2_gp_clockevent_init(void)
omap2_gp_timer_irq.dev_id = (void *)gptimer;
setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq);
- omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
+ omap_dm_timer_stop(gptimer);
+ /* omap_dm_timer_set_load(gptimer, 0, 0);*/
+ omap_dm_timer_set_match(gptimer, 1, GPTIMER_MATCH_VAL);
+ omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_MATCH);
clockevent_gpt.mult = div_sc(tick_rate, NSEC_PER_SEC,
clockevent_gpt.shift);
clockevent_gpt.max_delta_ns =
- clockevent_delta2ns(0xffffffff, &clockevent_gpt);
+ clockevent_delta2ns(GPTIMER_MATCH_VAL, &clockevent_gpt);
clockevent_gpt.min_delta_ns =
clockevent_delta2ns(1, &clockevent_gpt);