* Tony Lindgren <[EMAIL PROTECTED]> [080320 13:58]:
> * Woodruff, Richard <[EMAIL PROTECTED]> [080320 00:14]:
> >
> > One note is some more optimization could happen later on with
> > reordering. The current usage in gptimer has dmtimer_set_load()
> > followed by a dm_timer_start(). This causes a read/write/read/write of
> > the CTRL register. Those writes could be collapsed into each other.
> > With a load_start(). Others maybe elsewhere.
>
> OK. We might also want to optimize the timer reload function. I'll post
> a separate patch on that to experiment with.
Here's an experimental patch that attempts to optimize the timer
reloading for gp_timer0. I don't know if this improves the latency
or performance, but might be worth testing.
I guess there's no way to update the timer without having to write
TCLR to (re)start it?
If the patch helps, then we can clean it up a bit more.
Tony
commit 25146a33220bb264f06dd61e407435d16c371288
Author: Tony Lindgren <[EMAIL PROTECTED]>
Date: Thu Mar 20 13:47:23 2008 +0200
ARM: OMAP: Optimize timer reload by bypassing omap_gp_timer_set_next_event()
This patch optimizes the timer reprogramming that happens during every
timer interrupt.
Signed-off-by: Tony Lindgren <[EMAIL PROTECTED]>
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index 78d05f2..7805fa2 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -65,6 +65,58 @@ static int omap2_gp_timer_set_next_event(unsigned long cycles,
return 0;
}
+#define OMAP2420_GP_TIMER0_BASE 0x48028000
+#define OMAP2430_GP_TIMER0_BASE 0x49018000
+#define OMAP34XX_GP_TIMER0_BASE 0x48318000
+#define GP_TIMER_TCLR 0x24
+#define GP_TIMER_TCRR 0x28
+#define GP_TIMER_TWPS 0x34
+#define TWPS_MASK 0x3 /* Check for TCLR and TCRR */
+
+/*
+ * Reloads gp_timer0 value. Assumes that gp_timer0 has be set into posted mode
+ * during init. Bypassess the gp_timer functions to optimize timer reloading
+ * during timer interrupts.
+ */
+#define GP_TIMER0_RELOAD(cycles, base) \
+{ \
+ while ((__raw_readl(IO_ADDRESS((base) + GP_TIMER_TWPS)) & TWPS_MASK)) \
+ cpu_relax(); \
+ __raw_writel(0xffffffff - (cycles), \
+ IO_ADDRESS((base) + GP_TIMER_TCRR)); \
+ __raw_writel(0x3, IO_ADDRESS((base) + GP_TIMER_TCLR)); \
+}
+
+#ifdef CONFIG_ARCH_OMAP24XX
+static int omap2420_gp_timer0_reload(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ GP_TIMER0_RELOAD(cycles, OMAP2420_GP_TIMER0_BASE);
+ return 0;
+}
+
+static int omap2430_gp_timer0_reload(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ GP_TIMER0_RELOAD(cycles, OMAP2430_GP_TIMER0_BASE);
+ return 0;
+}
+#else
+#define omap2420_gp_timer0_reload NULL
+#define omap2430_gp_timer0_reload NULL
+#endif
+
+#ifdef CONFIG_ARCH_OMAP34XX
+static int omap34xx_gp_timer0_reload(unsigned long cycles,
+ struct clock_event_device *evt)
+{
+ GP_TIMER0_RELOAD(cycles, OMAP34XX_GP_TIMER0_BASE);
+ return 0;
+}
+#else
+#define omap34xx_gp_timer0_reload NULL
+#endif
+
static void omap2_gp_timer_set_mode(enum clock_event_mode mode,
struct clock_event_device *evt)
{
@@ -93,7 +145,7 @@ static struct clock_event_device clockevent_gpt = {
.name = "gp timer",
.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
.shift = 32,
- .set_next_event = omap2_gp_timer_set_next_event,
+ .set_next_event = omap2_gp_timer_set_next_event, /* Init can rewrite */
.set_mode = omap2_gp_timer_set_mode,
};
@@ -111,6 +163,15 @@ static void __init omap2_gp_clockevent_init(void)
#endif
tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer));
+ if (cpu_is_omap2420())
+ clockevent_gpt.set_next_event = omap2420_gp_timer0_reload;
+ else if (cpu_is_omap2430())
+ clockevent_gpt.set_next_event = omap2430_gp_timer0_reload;
+ else if (cpu_is_omap34xx())
+ clockevent_gpt.set_next_event = omap34xx_gp_timer0_reload;
+ else
+ clockevent_gpt.set_next_event = omap2_gp_timer_set_next_event;
+
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);