aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/mach-pxa/time.c51
2 files changed, 53 insertions, 2 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4bf0e8737e1f..dc0fafc7f9bd 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -365,8 +365,8 @@ config NO_IDLE_HZ
365 365
366 Please note that dynamic tick may affect the accuracy of 366 Please note that dynamic tick may affect the accuracy of
367 timekeeping on some platforms depending on the implementation. 367 timekeeping on some platforms depending on the implementation.
368 Currently at least OMAP platform is known to have accurate 368 Currently at least OMAP and PXA2xx platforms are known to have
369 timekeeping with dynamic tick. 369 accurate timekeeping with dynamic tick.
370 370
371config ARCH_DISCONTIGMEM_ENABLE 371config ARCH_DISCONTIGMEM_ENABLE
372 bool 372 bool
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 6e5202154f91..72b15e9a373a 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -70,6 +70,11 @@ static unsigned long pxa_gettimeoffset (void)
70 return usec; 70 return usec;
71} 71}
72 72
73#ifdef CONFIG_NO_IDLE_HZ
74static unsigned long initial_match;
75static int match_posponed;
76#endif
77
73static irqreturn_t 78static irqreturn_t
74pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 79pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
75{ 80{
@@ -77,6 +82,13 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
77 82
78 write_seqlock(&xtime_lock); 83 write_seqlock(&xtime_lock);
79 84
85#ifdef CONFIG_NO_IDLE_HZ
86 if (match_posponed) {
87 match_posponed = 0;
88 OSMR0 = initial_match;
89 }
90#endif
91
80 /* Loop until we get ahead of the free running timer. 92 /* Loop until we get ahead of the free running timer.
81 * This ensures an exact clock tick count and time accuracy. 93 * This ensures an exact clock tick count and time accuracy.
82 * IRQs are disabled inside the loop to ensure coherence between 94 * IRQs are disabled inside the loop to ensure coherence between
@@ -126,6 +138,42 @@ static void __init pxa_timer_init(void)
126 OSCR = 0; /* initialize free-running timer, force first match */ 138 OSCR = 0; /* initialize free-running timer, force first match */
127} 139}
128 140
141#ifdef CONFIG_NO_IDLE_HZ
142static int pxa_dyn_tick_enable_disable(void)
143{
144 /* nothing to do */
145 return 0;
146}
147
148static void pxa_dyn_tick_reprogram(unsigned long ticks)
149{
150 if (ticks > 1) {
151 initial_match = OSMR0;
152 OSMR0 = initial_match + ticks * LATCH;
153 match_posponed = 1;
154 }
155}
156
157static irqreturn_t
158pxa_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
159{
160 if (match_posponed) {
161 match_posponed = 0;
162 OSMR0 = initial_match;
163 if ( (signed long)(initial_match - OSCR) <= 8 )
164 return pxa_timer_interrupt(irq, dev_id, regs);
165 }
166 return IRQ_NONE;
167}
168
169static struct dyn_tick_timer pxa_dyn_tick = {
170 .enable = pxa_dyn_tick_enable_disable,
171 .disable = pxa_dyn_tick_enable_disable,
172 .reprogram = pxa_dyn_tick_reprogram,
173 .handler = pxa_dyn_tick_handler,
174};
175#endif
176
129#ifdef CONFIG_PM 177#ifdef CONFIG_PM
130static unsigned long osmr[4], oier; 178static unsigned long osmr[4], oier;
131 179
@@ -161,4 +209,7 @@ struct sys_timer pxa_timer = {
161 .suspend = pxa_timer_suspend, 209 .suspend = pxa_timer_suspend,
162 .resume = pxa_timer_resume, 210 .resume = pxa_timer_resume,
163 .offset = pxa_gettimeoffset, 211 .offset = pxa_gettimeoffset,
212#ifdef CONFIG_NO_IDLE_HZ
213 .dyn_tick = &pxa_dyn_tick,
214#endif
164}; 215};