[ARM] 4507/1: pxa2xx clock_event_device

Reimplements arch/arm/mach-pxa/time.c using a clock_event_device based
on OSMR0. Tested on PXA270, linux-2.6.22+arm:pxa patches.

Signed-off-by: Bill Gatliff <bgat@billgatliff.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by Bill Gatliff and committed by Russell King 7bbb18c9 3d50527b

+127 -129
+127 -129
arch/arm/mach-pxa/time.c
··· 1 /* 2 * arch/arm/mach-pxa/time.c 3 * 4 - * Author: Nicolas Pitre 5 - * Created: Jun 15, 2001 6 - * Copyright: MontaVista Software Inc. 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as ··· 14 15 #include <linux/kernel.h> 16 #include <linux/init.h> 17 - #include <linux/delay.h> 18 #include <linux/interrupt.h> 19 - #include <linux/time.h> 20 - #include <linux/signal.h> 21 - #include <linux/errno.h> 22 - #include <linux/sched.h> 23 - #include <linux/clocksource.h> 24 25 - #include <asm/system.h> 26 - #include <asm/hardware.h> 27 - #include <asm/io.h> 28 - #include <asm/leds.h> 29 - #include <asm/irq.h> 30 #include <asm/mach/irq.h> 31 #include <asm/mach/time.h> 32 #include <asm/arch/pxa-regs.h> 33 34 - 35 - static int pxa_set_rtc(void) 36 - { 37 - unsigned long current_time = xtime.tv_sec; 38 - 39 - if (RTSR & RTSR_ALE) { 40 - /* make sure not to forward the clock over an alarm */ 41 - unsigned long alarm = RTAR; 42 - if (current_time >= alarm && alarm >= RCNR) 43 - return -ERESTARTSYS; 44 - } 45 - RCNR = current_time; 46 - return 0; 47 - } 48 - 49 - #ifdef CONFIG_NO_IDLE_HZ 50 - static unsigned long initial_match; 51 - static int match_posponed; 52 - #endif 53 - 54 static irqreturn_t 55 - pxa_timer_interrupt(int irq, void *dev_id) 56 { 57 int next_match; 58 59 - write_seqlock(&xtime_lock); 60 - 61 - #ifdef CONFIG_NO_IDLE_HZ 62 - if (match_posponed) { 63 - match_posponed = 0; 64 - OSMR0 = initial_match; 65 - } 66 - #endif 67 - 68 - /* Loop until we get ahead of the free running timer. 69 - * This ensures an exact clock tick count and time accuracy. 70 - * Since IRQs are disabled at this point, coherence between 71 - * lost_ticks(updated in do_timer()) and the match reg value is 72 - * ensured, hence we can use do_gettimeofday() from interrupt 73 - * handlers. 74 - * 75 - * HACK ALERT: it seems that the PXA timer regs aren't updated right 76 - * away in all cases when a write occurs. We therefore compare with 77 - * 8 instead of 0 in the while() condition below to avoid missing a 78 - * match if OSCR has already reached the next OSMR value. 79 - * Experience has shown that up to 6 ticks are needed to work around 80 - * this problem, but let's use 8 to be conservative. Note that this 81 - * affect things only when the timer IRQ has been delayed by nearly 82 - * exactly one tick period which should be a pretty rare event. 83 */ 84 do { 85 - timer_tick(); 86 - OSSR = OSSR_M0; /* Clear match on timer 0 */ 87 next_match = (OSMR0 += LATCH); 88 - } while( (signed long)(next_match - OSCR) <= 8 ); 89 - 90 - write_sequnlock(&xtime_lock); 91 92 return IRQ_HANDLED; 93 } 94 95 - static struct irqaction pxa_timer_irq = { 96 - .name = "PXA Timer Tick", 97 - .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 98 - .handler = pxa_timer_interrupt, 99 }; 100 101 - static cycle_t pxa_get_cycles(void) 102 { 103 return OSCR; 104 } 105 106 - static struct clocksource clocksource_pxa = { 107 - .name = "pxa_timer", 108 .rating = 200, 109 - .read = pxa_get_cycles, 110 .mask = CLOCKSOURCE_MASK(32), 111 .shift = 20, 112 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 113 }; 114 115 static void __init pxa_timer_init(void) 116 { 117 - struct timespec tv; 118 - unsigned long flags; 119 120 - set_rtc = pxa_set_rtc; 121 122 - OIER = 0; /* disable any timer interrupts */ 123 - OSSR = 0xf; /* clear status on all timers */ 124 - setup_irq(IRQ_OST0, &pxa_timer_irq); 125 - local_irq_save(flags); 126 - OIER = OIER_E0; /* enable match on timer 0 to cause interrupts */ 127 - OSMR0 = OSCR + LATCH; /* set initial match */ 128 - local_irq_restore(flags); 129 130 - /* 131 - * OSCR runs continuously on PXA and is not written to, 132 - * so we can use it as clock source directly. 133 - */ 134 - clocksource_pxa.mult = 135 - clocksource_hz2mult(CLOCK_TICK_RATE, clocksource_pxa.shift); 136 - clocksource_register(&clocksource_pxa); 137 } 138 - 139 - #ifdef CONFIG_NO_IDLE_HZ 140 - static int pxa_dyn_tick_enable_disable(void) 141 - { 142 - /* nothing to do */ 143 - return 0; 144 - } 145 - 146 - static void pxa_dyn_tick_reprogram(unsigned long ticks) 147 - { 148 - if (ticks > 1) { 149 - initial_match = OSMR0; 150 - OSMR0 = initial_match + ticks * LATCH; 151 - match_posponed = 1; 152 - } 153 - } 154 - 155 - static irqreturn_t 156 - pxa_dyn_tick_handler(int irq, void *dev_id) 157 - { 158 - if (match_posponed) { 159 - match_posponed = 0; 160 - OSMR0 = initial_match; 161 - if ( (signed long)(initial_match - OSCR) <= 8 ) 162 - return pxa_timer_interrupt(irq, dev_id); 163 - } 164 - return IRQ_NONE; 165 - } 166 - 167 - static struct dyn_tick_timer pxa_dyn_tick = { 168 - .enable = pxa_dyn_tick_enable_disable, 169 - .disable = pxa_dyn_tick_enable_disable, 170 - .reprogram = pxa_dyn_tick_reprogram, 171 - .handler = pxa_dyn_tick_handler, 172 - }; 173 - #endif 174 175 #ifdef CONFIG_PM 176 static unsigned long osmr[4], oier; ··· 189 OIER = oier; 190 191 /* 192 - * OSMR0 is the system timer: make sure OSCR is sufficiently behind 193 */ 194 OSCR = OSMR0 - LATCH; 195 } ··· 205 .init = pxa_timer_init, 206 .suspend = pxa_timer_suspend, 207 .resume = pxa_timer_resume, 208 - #ifdef CONFIG_NO_IDLE_HZ 209 - .dyn_tick = &pxa_dyn_tick, 210 - #endif 211 };
··· 1 /* 2 * arch/arm/mach-pxa/time.c 3 * 4 + * PXA clocksource, clockevents, and OST interrupt handlers. 5 + * Copyright (c) 2007 by Bill Gatliff <bgat@billgatliff.com>. 6 + * 7 + * Derived from Nicolas Pitre's PXA timer handler Copyright (c) 2001 8 + * by MontaVista Software, Inc. (Nico, your code rocks!) 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as ··· 12 13 #include <linux/kernel.h> 14 #include <linux/init.h> 15 #include <linux/interrupt.h> 16 + #include <linux/clockchips.h> 17 18 #include <asm/mach/irq.h> 19 #include <asm/mach/time.h> 20 #include <asm/arch/pxa-regs.h> 21 22 static irqreturn_t 23 + pxa_ost0_interrupt(int irq, void *dev_id) 24 { 25 int next_match; 26 + struct clock_event_device *c = dev_id; 27 28 + if (c->mode == CLOCK_EVT_MODE_ONESHOT) { 29 + /* Disarm the compare/match, signal the event. */ 30 + OIER &= ~OIER_E0; 31 + c->event_handler(c); 32 + } else if (c->mode == CLOCK_EVT_MODE_PERIODIC) { 33 + /* Call the event handler as many times as necessary 34 + * to recover missed events, if any (if we update 35 + * OSMR0 and OSCR0 is still ahead of us, we've missed 36 + * the event). As we're dealing with that, re-arm the 37 + * compare/match for the next event. 38 + * 39 + * HACK ALERT: 40 + * 41 + * There's a latency between the instruction that 42 + * writes to OSMR0 and the actual commit to the 43 + * physical hardware, because the CPU doesn't (have 44 + * to) run at bus speed, there's a write buffer 45 + * between the CPU and the bus, etc. etc. So if the 46 + * target OSCR0 is "very close", to the OSMR0 load 47 + * value, the update to OSMR0 might not get to the 48 + * hardware in time and we'll miss that interrupt. 49 + * 50 + * To be safe, if the new OSMR0 is "very close" to the 51 + * target OSCR0 value, we call the event_handler as 52 + * though the event actually happened. According to 53 + * Nico's comment in the previous version of this 54 + * code, experience has shown that 6 OSCR ticks is 55 + * "very close" but he went with 8. We will use 16, 56 + * based on the results of testing on PXA270. 57 + * 58 + * To be doubly sure, we also tell clkevt via 59 + * clockevents_register_device() not to ask for 60 + * anything that might put us "very close". 61 */ 62 + #define MIN_OSCR_DELTA 16 63 do { 64 + OSSR = OSSR_M0; 65 next_match = (OSMR0 += LATCH); 66 + c->event_handler(c); 67 + } while (((signed long)(next_match - OSCR) <= MIN_OSCR_DELTA) 68 + && (c->mode == CLOCK_EVT_MODE_PERIODIC)); 69 + } 70 71 return IRQ_HANDLED; 72 } 73 74 + static int 75 + pxa_osmr0_set_next_event(unsigned long delta, struct clock_event_device *dev) 76 + { 77 + unsigned long irqflags; 78 + 79 + raw_local_irq_save(irqflags); 80 + OSMR0 = OSCR + delta; 81 + OSSR = OSSR_M0; 82 + OIER |= OIER_E0; 83 + raw_local_irq_restore(irqflags); 84 + return 0; 85 + } 86 + 87 + static void 88 + pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev) 89 + { 90 + unsigned long irqflags; 91 + 92 + switch (mode) { 93 + case CLOCK_EVT_MODE_PERIODIC: 94 + raw_local_irq_save(irqflags); 95 + OSMR0 = OSCR + LATCH; 96 + OSSR = OSSR_M0; 97 + OIER |= OIER_E0; 98 + raw_local_irq_restore(irqflags); 99 + break; 100 + 101 + case CLOCK_EVT_MODE_ONESHOT: 102 + raw_local_irq_save(irqflags); 103 + OIER &= ~OIER_E0; 104 + raw_local_irq_restore(irqflags); 105 + break; 106 + 107 + case CLOCK_EVT_MODE_UNUSED: 108 + case CLOCK_EVT_MODE_SHUTDOWN: 109 + /* initializing, released, or preparing for suspend */ 110 + raw_local_irq_save(irqflags); 111 + OIER &= ~OIER_E0; 112 + raw_local_irq_restore(irqflags); 113 + break; 114 + } 115 + } 116 + 117 + static struct clock_event_device ckevt_pxa_osmr0 = { 118 + .name = "osmr0", 119 + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 120 + .shift = 32, 121 + .rating = 200, 122 + .cpumask = CPU_MASK_CPU0, 123 + .set_next_event = pxa_osmr0_set_next_event, 124 + .set_mode = pxa_osmr0_set_mode, 125 }; 126 127 + static cycle_t pxa_read_oscr(void) 128 { 129 return OSCR; 130 } 131 132 + static struct clocksource cksrc_pxa_oscr0 = { 133 + .name = "oscr0", 134 .rating = 200, 135 + .read = pxa_read_oscr, 136 .mask = CLOCKSOURCE_MASK(32), 137 .shift = 20, 138 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 139 }; 140 141 + static struct irqaction pxa_ost0_irq = { 142 + .name = "ost0", 143 + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 144 + .handler = pxa_ost0_interrupt, 145 + .dev_id = &ckevt_pxa_osmr0, 146 + }; 147 + 148 static void __init pxa_timer_init(void) 149 { 150 + OIER = 0; 151 + OSSR = OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3; 152 153 + ckevt_pxa_osmr0.mult = 154 + div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC, ckevt_pxa_osmr0.shift); 155 + ckevt_pxa_osmr0.max_delta_ns = 156 + clockevent_delta2ns(0x7fffffff, &ckevt_pxa_osmr0); 157 + ckevt_pxa_osmr0.min_delta_ns = 158 + clockevent_delta2ns(MIN_OSCR_DELTA, &ckevt_pxa_osmr0) + 1; 159 160 + cksrc_pxa_oscr0.mult = 161 + clocksource_hz2mult(CLOCK_TICK_RATE, cksrc_pxa_oscr0.shift); 162 163 + setup_irq(IRQ_OST0, &pxa_ost0_irq); 164 + 165 + clocksource_register(&cksrc_pxa_oscr0); 166 + clockevents_register_device(&ckevt_pxa_osmr0); 167 } 168 169 #ifdef CONFIG_PM 170 static unsigned long osmr[4], oier; ··· 191 OIER = oier; 192 193 /* 194 + * OSCR0 is the system timer, which has to increase 195 + * monotonically until it rolls over in hardware. The value 196 + * (OSMR0 - LATCH) is OSCR0 at the most recent system tick, 197 + * which is a handy value to restore to OSCR0. 198 */ 199 OSCR = OSMR0 - LATCH; 200 } ··· 204 .init = pxa_timer_init, 205 .suspend = pxa_timer_suspend, 206 .resume = pxa_timer_resume, 207 };