diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap2-git/beagleboard/02-gptimer_use_match_for_tick')
-rw-r--r-- | meta/recipes-kernel/linux/linux-omap2-git/beagleboard/02-gptimer_use_match_for_tick | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap2-git/beagleboard/02-gptimer_use_match_for_tick b/meta/recipes-kernel/linux/linux-omap2-git/beagleboard/02-gptimer_use_match_for_tick new file mode 100644 index 0000000000..6eb6c9b477 --- /dev/null +++ b/meta/recipes-kernel/linux/linux-omap2-git/beagleboard/02-gptimer_use_match_for_tick | |||
@@ -0,0 +1,97 @@ | |||
1 | OMAP2/3 system tick GPTIMER: use match interrupts rather than overflow interrupts | ||
2 | |||
3 | From: Paul Walmsley <paul@pwsan.com> | ||
4 | |||
5 | On some OMAP3 chips, GPTIMER1 will occasionally decline to interrupt | ||
6 | the MPU when a timer overflow event occurs. The timer stops running; | ||
7 | and TOCR is sometimes incremented; but the MPU apparently never receives | ||
8 | the interrupt. This patch was an experiment in using the GPTIMER | ||
9 | match interrupt to determine if it resolves the problem. | ||
10 | Unfortunately, it does not; the same problem occurs with match | ||
11 | interrupts; but this patch is preserved as the base for a | ||
12 | match+overflow interrupt workaround used in a following patch. | ||
13 | --- | ||
14 | |||
15 | arch/arm/mach-omap2/timer-gp.c | 32 ++++++++++---------------------- | ||
16 | 1 files changed, 10 insertions(+), 22 deletions(-) | ||
17 | |||
18 | diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c | ||
19 | index 557603f..51996ba 100644 | ||
20 | --- a/arch/arm/mach-omap2/timer-gp.c | ||
21 | +++ b/arch/arm/mach-omap2/timer-gp.c | ||
22 | @@ -36,6 +36,8 @@ | ||
23 | #include <asm/mach/time.h> | ||
24 | #include <asm/arch/dmtimer.h> | ||
25 | |||
26 | +#define GPTIMER_MATCH_VAL 0xffff0000 | ||
27 | + | ||
28 | static struct omap_dm_timer *gptimer; | ||
29 | static struct clock_event_device clockevent_gpt; | ||
30 | |||
31 | @@ -44,7 +46,7 @@ static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) | ||
32 | struct omap_dm_timer *gpt = (struct omap_dm_timer *)dev_id; | ||
33 | struct clock_event_device *evt = &clockevent_gpt; | ||
34 | |||
35 | - omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_OVERFLOW); | ||
36 | + omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_MATCH); | ||
37 | |||
38 | evt->event_handler(evt); | ||
39 | return IRQ_HANDLED; | ||
40 | @@ -59,7 +61,7 @@ static struct irqaction omap2_gp_timer_irq = { | ||
41 | static int omap2_gp_timer_set_next_event(unsigned long cycles, | ||
42 | struct clock_event_device *evt) | ||
43 | { | ||
44 | - omap_dm_timer_set_load_start(gptimer, 0, 0xffffffff - cycles); | ||
45 | + omap_dm_timer_set_load_start(gptimer, 0, GPTIMER_MATCH_VAL - cycles); | ||
46 | |||
47 | return 0; | ||
48 | } | ||
49 | @@ -67,29 +69,12 @@ static int omap2_gp_timer_set_next_event(unsigned long cycles, | ||
50 | static void omap2_gp_timer_set_mode(enum clock_event_mode mode, | ||
51 | struct clock_event_device *evt) | ||
52 | { | ||
53 | - u32 period; | ||
54 | - | ||
55 | omap_dm_timer_stop(gptimer); | ||
56 | - | ||
57 | - switch (mode) { | ||
58 | - case CLOCK_EVT_MODE_PERIODIC: | ||
59 | - period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ; | ||
60 | - period -= 1; | ||
61 | - | ||
62 | - omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period); | ||
63 | - break; | ||
64 | - case CLOCK_EVT_MODE_ONESHOT: | ||
65 | - break; | ||
66 | - case CLOCK_EVT_MODE_UNUSED: | ||
67 | - case CLOCK_EVT_MODE_SHUTDOWN: | ||
68 | - case CLOCK_EVT_MODE_RESUME: | ||
69 | - break; | ||
70 | - } | ||
71 | } | ||
72 | |||
73 | static struct clock_event_device clockevent_gpt = { | ||
74 | .name = "gp timer", | ||
75 | - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
76 | + .features = CLOCK_EVT_FEAT_ONESHOT, | ||
77 | .shift = 32, | ||
78 | .set_next_event = omap2_gp_timer_set_next_event, | ||
79 | .set_mode = omap2_gp_timer_set_mode, | ||
80 | @@ -111,12 +96,15 @@ static void __init omap2_gp_clockevent_init(void) | ||
81 | |||
82 | omap2_gp_timer_irq.dev_id = (void *)gptimer; | ||
83 | setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq); | ||
84 | - omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW); | ||
85 | + omap_dm_timer_stop(gptimer); | ||
86 | + /* omap_dm_timer_set_load(gptimer, 0, 0);*/ | ||
87 | + omap_dm_timer_set_match(gptimer, 1, GPTIMER_MATCH_VAL); | ||
88 | + omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_MATCH); | ||
89 | |||
90 | clockevent_gpt.mult = div_sc(tick_rate, NSEC_PER_SEC, | ||
91 | clockevent_gpt.shift); | ||
92 | clockevent_gpt.max_delta_ns = | ||
93 | - clockevent_delta2ns(0xffffffff, &clockevent_gpt); | ||
94 | + clockevent_delta2ns(GPTIMER_MATCH_VAL, &clockevent_gpt); | ||
95 | clockevent_gpt.min_delta_ns = | ||
96 | clockevent_delta2ns(1, &clockevent_gpt); | ||
97 | |||