* Tony Lindgren <tony@xxxxxxxxxxx> [080320 13:58]: > * Woodruff, Richard <r-woodruff2@xxxxxx> [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 <tony@xxxxxxxxxxx> 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 <tony@xxxxxxxxxxx> 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);