From 569d2c34dcf259b07977835492aa8813d1168230 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 1 Sep 2005 12:48:48 +0100 Subject: [ARM] 2864/1: VST aka CONFIG_NO_IDLE_HZ support for SA11x0 Patch from Nicolas Pitre Signed-off-by: Nicolas Pitre Signed-off-by: Russell King --- arch/arm/Kconfig | 4 ++-- arch/arm/mach-sa1100/time.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index dc0fafc7f9bd..68dfdba71d74 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -365,8 +365,8 @@ config NO_IDLE_HZ Please note that dynamic tick may affect the accuracy of timekeeping on some platforms depending on the implementation. - Currently at least OMAP and PXA2xx platforms are known to have - accurate timekeeping with dynamic tick. + Currently at least OMAP, PXA2xx and SA11x0 platforms are known + to have accurate timekeeping with dynamic tick. config ARCH_DISCONTIGMEM_ENABLE bool diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index a084b38698cf..47e0420623fc 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c @@ -70,6 +70,11 @@ static unsigned long sa1100_gettimeoffset (void) return usec; } +#ifdef CONFIG_NO_IDLE_HZ +static unsigned long initial_match; +static int match_posponed; +#endif + static irqreturn_t sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { @@ -77,6 +82,13 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) write_seqlock(&xtime_lock); +#ifdef CONFIG_NO_IDLE_HZ + if (match_posponed) { + match_posponed = 0; + OSMR0 = initial_match; + } +#endif + /* * Loop until we get ahead of the free running timer. * This ensures an exact clock tick count and time accuracy. @@ -119,6 +131,42 @@ static void __init sa1100_timer_init(void) OSCR = 0; /* initialize free-running timer, force first match */ } +#ifdef CONFIG_NO_IDLE_HZ +static int sa1100_dyn_tick_enable_disable(void) +{ + /* nothing to do */ + return 0; +} + +static void sa1100_dyn_tick_reprogram(unsigned long ticks) +{ + if (ticks > 1) { + initial_match = OSMR0; + OSMR0 = initial_match + ticks * LATCH; + match_posponed = 1; + } +} + +static irqreturn_t +sa1100_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + if (match_posponed) { + match_posponed = 0; + OSMR0 = initial_match; + if ((signed long)(initial_match - OSCR) <= 0) + return sa1100_timer_interrupt(irq, dev_id, regs); + } + return IRQ_NONE; +} + +static struct dyn_tick_timer sa1100_dyn_tick = { + .enable = sa1100_dyn_tick_enable_disable, + .disable = sa1100_dyn_tick_enable_disable, + .reprogram = sa1100_dyn_tick_reprogram, + .handler = sa1100_dyn_tick_handler, +}; +#endif + #ifdef CONFIG_PM unsigned long osmr[4], oier; @@ -155,4 +203,7 @@ struct sys_timer sa1100_timer = { .suspend = sa1100_timer_suspend, .resume = sa1100_timer_resume, .offset = sa1100_gettimeoffset, +#ifdef CONFIG_NO_IDLE_HZ + .dyn_tick = &sa1100_dyn_tick, +#endif }; -- cgit v1.2.1