From 1ada01f13068766a44cb05d0868beab3a5d2d575 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Sun, 3 Aug 2008 13:16:29 +0000 Subject: linux-omap2: More beagleboard updates from OE.dev git-svn-id: https://svn.o-hand.com/repos/poky/trunk@5010 311d38ba-8fff-0310-9ca6-ca027cbcb966 --- .../beagleboard/03-gptimer_match_plus_ovf | 94 ++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 meta/packages/linux/linux-omap2-git/beagleboard/03-gptimer_match_plus_ovf (limited to 'meta/packages/linux/linux-omap2-git/beagleboard/03-gptimer_match_plus_ovf') diff --git a/meta/packages/linux/linux-omap2-git/beagleboard/03-gptimer_match_plus_ovf b/meta/packages/linux/linux-omap2-git/beagleboard/03-gptimer_match_plus_ovf new file mode 100644 index 000000000..3de6e0504 --- /dev/null +++ b/meta/packages/linux/linux-omap2-git/beagleboard/03-gptimer_match_plus_ovf @@ -0,0 +1,94 @@ +OMAP2/3 system tick GPTIMER: use overflow interrupts to detect missing match interrupts + +From: Paul Walmsley + +GPTIMER1 on some OMAP3 chips occasionally misses match conditions +between the timer counter and the target register value, and does not +interrupt to the MPU. This patch adds another line of defense by +setting the timer to generate an overflow interrupt 0.5 seconds after the +timer passes the original comparison value. + +If interrupts are masked for a long period of time, one would expect +both a match and an overflow interrupt to be logged. This is considered +a normal condition. However, if only an overflow interrupt is logged, +this is considered evidence of a hardware bug and the kernel will issue +a warning. + +This workaround is unlikely to be 100% effective, since GPTIMER1 has +also been observed to lose overflow interrupts occasionally. It is +hoped that the probability of losing both will be significantly lower +than the probability of losing either one. +--- + + arch/arm/mach-omap2/timer-gp.c | 36 ++++++++++++++++++++++++++++++++---- + 1 files changed, 32 insertions(+), 4 deletions(-) + +diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c +index 51996ba..ce5c2b4 100644 +--- a/arch/arm/mach-omap2/timer-gp.c ++++ b/arch/arm/mach-omap2/timer-gp.c +@@ -36,17 +36,43 @@ + #include + #include + +-#define GPTIMER_MATCH_VAL 0xffff0000 ++/* ++ * The number of timer ticks to delay will be subtracted from ++ * GPTIMER_MATCH_VAL before loading into the timer. So GPTIMER_MATCH_VAL ++ * constrains the longest delay that can be generated with the timer. ++ * Since the current code uses overflow interrupts as protection against ++ * missed comparison interrupts, this value should also be sufficiently ++ * large such that there is not an excessively long delay between ticks ++ * if the comparison interrupt fails to arrive. The 0xfffff800 value ++ * below results in a half-second delay in such a case when using ++ * the 32kHz timer as source. ++ */ ++#define GPTIMER_MATCH_VAL (0xffffffff - (32768/2)) + + static struct omap_dm_timer *gptimer; + static struct clock_event_device clockevent_gpt; + ++static u32 last_load; ++ + 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_MATCH); ++ u32 v; ++ ++ v = omap_dm_timer_read_status(gpt); ++ if ((v & OMAP_TIMER_INT_OVERFLOW) && !(v & OMAP_TIMER_INT_MATCH)) { ++ /* ++ * Should never happen. Current belief is that this is ++ * due to a hardware bug in the GPTIMER block on some ++ * OMAP3 revisions. ++ */ ++ pr_err("*** GPTIMER missed match interrupt! last load: %08x\n", ++ last_load); ++ WARN_ON(1); ++ } ++ ++ omap_dm_timer_write_status(gpt, v); + + evt->event_handler(evt); + return IRQ_HANDLED; +@@ -61,6 +87,7 @@ static struct irqaction omap2_gp_timer_irq = { + static int omap2_gp_timer_set_next_event(unsigned long cycles, + struct clock_event_device *evt) + { ++ last_load = GPTIMER_MATCH_VAL - cycles; + omap_dm_timer_set_load_start(gptimer, 0, GPTIMER_MATCH_VAL - cycles); + + return 0; +@@ -99,7 +126,8 @@ static void __init omap2_gp_clockevent_init(void) + 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); ++ omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_MATCH | ++ OMAP_TIMER_INT_OVERFLOW); + + clockevent_gpt.mult = div_sc(tick_rate, NSEC_PER_SEC, + clockevent_gpt.shift); -- cgit v1.2.3