1 /* 2 * linux/arch/arm/mach-omap1/time.c 3 * 4 * OMAP Timers 5 * 6 * Copyright (C) 2004 Nokia Corporation 7 * Partial timer rewrite and additional dynamic tick timer support by 8 * Tony Lindgen <tony@atomide.com> and 9 * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> 10 * 11 * MPU timer code based on the older MPU timer code for OMAP 12 * Copyright (C) 2000 RidgeRun, Inc. 13 * Author: Greg Lonnon <glonnon@ridgerun.com> 14 * 15 * This program is free software; you can redistribute it and/or modify it 16 * under the terms of the GNU General Public License as published by the 17 * Free Software Foundation; either version 2 of the License, or (at your 18 * option) any later version. 19 * 20 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 21 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 23 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * You should have received a copy of the GNU General Public License along 32 * with this program; if not, write to the Free Software Foundation, Inc., 33 * 675 Mass Ave, Cambridge, MA 02139, USA. 34 */ 35 36 #include <linux/kernel.h> 37 #include <linux/init.h> 38 #include <linux/delay.h> 39 #include <linux/interrupt.h> 40 #include <linux/sched.h> 41 #include <linux/spinlock.h> 42 #include <linux/clk.h> 43 #include <linux/err.h> 44 #include <linux/clocksource.h> 45 #include <linux/clockchips.h> 46 47 #include <asm/system.h> 48 #include <asm/hardware.h> 49 #include <asm/io.h> 50 #include <asm/leds.h> 51 #include <asm/irq.h> 52 #include <asm/mach/irq.h> 53 #include <asm/mach/time.h> 54 55 56 #define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE 57 #define OMAP_MPU_TIMER_OFFSET 0x100 58 59 /* cycles to nsec conversions taken from arch/i386/kernel/timers/timer_tsc.c, 60 * converted to use kHz by Kevin Hilman */ 61 /* convert from cycles(64bits) => nanoseconds (64bits) 62 * basic equation: 63 * ns = cycles / (freq / ns_per_sec) 64 * ns = cycles * (ns_per_sec / freq) 65 * ns = cycles * (10^9 / (cpu_khz * 10^3)) 66 * ns = cycles * (10^6 / cpu_khz) 67 * 68 * Then we use scaling math (suggested by george at mvista.com) to get: 69 * ns = cycles * (10^6 * SC / cpu_khz / SC 70 * ns = cycles * cyc2ns_scale / SC 71 * 72 * And since SC is a constant power of two, we can convert the div 73 * into a shift. 74 * -johnstul at us.ibm.com "math is hard, lets go shopping!" 75 */ 76 static unsigned long cyc2ns_scale; 77 #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ 78 79 static inline void set_cyc2ns_scale(unsigned long cpu_khz) 80 { 81 cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz; 82 } 83 84 static inline unsigned long long cycles_2_ns(unsigned long long cyc) 85 { 86 return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR; 87 } 88 89 90 typedef struct { 91 u32 cntl; /* CNTL_TIMER, R/W */ 92 u32 load_tim; /* LOAD_TIM, W */ 93 u32 read_tim; /* READ_TIM, R */ 94 } omap_mpu_timer_regs_t; 95 96 #define omap_mpu_timer_base(n) \ 97 ((volatile omap_mpu_timer_regs_t*)IO_ADDRESS(OMAP_MPU_TIMER_BASE + \ 98 (n)*OMAP_MPU_TIMER_OFFSET)) 99 100 static inline unsigned long omap_mpu_timer_read(int nr) 101 { 102 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 103 return timer->read_tim; 104 } 105 106 static inline void omap_mpu_set_autoreset(int nr) 107 { 108 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 109 110 timer->cntl = timer->cntl | MPU_TIMER_AR; 111 } 112 113 static inline void omap_mpu_remove_autoreset(int nr) 114 { 115 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 116 117 timer->cntl = timer->cntl & ~MPU_TIMER_AR; 118 } 119 120 static inline void omap_mpu_timer_start(int nr, unsigned long load_val, 121 int autoreset) 122 { 123 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 124 unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST); 125 126 if (autoreset) timerflags |= MPU_TIMER_AR; 127 128 timer->cntl = MPU_TIMER_CLOCK_ENABLE; 129 udelay(1); 130 timer->load_tim = load_val; 131 udelay(1); 132 timer->cntl = timerflags; 133 } 134 135 static inline void omap_mpu_timer_stop(int nr) 136 { 137 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 138 139 timer->cntl &= ~MPU_TIMER_ST; 140 } 141 142 /* 143 * --------------------------------------------------------------------------- 144 * MPU timer 1 ... count down to zero, interrupt, reload 145 * --------------------------------------------------------------------------- 146 */ 147 static int omap_mpu_set_next_event(unsigned long cycles, 148 struct clock_event_device *evt) 149 { 150 omap_mpu_timer_start(0, cycles, 0); 151 return 0; 152 } 153 154 static void omap_mpu_set_mode(enum clock_event_mode mode, 155 struct clock_event_device *evt) 156 { 157 switch (mode) { 158 case CLOCK_EVT_MODE_PERIODIC: 159 omap_mpu_set_autoreset(0); 160 break; 161 case CLOCK_EVT_MODE_ONESHOT: 162 omap_mpu_timer_stop(0); 163 omap_mpu_remove_autoreset(0); 164 break; 165 case CLOCK_EVT_MODE_UNUSED: 166 case CLOCK_EVT_MODE_SHUTDOWN: 167 case CLOCK_EVT_MODE_RESUME: 168 break; 169 } 170 } 171 172 static struct clock_event_device clockevent_mpu_timer1 = { 173 .name = "mpu_timer1", 174 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 175 .shift = 32, 176 .set_next_event = omap_mpu_set_next_event, 177 .set_mode = omap_mpu_set_mode, 178 }; 179 180 static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id) 181 { 182 struct clock_event_device *evt = &clockevent_mpu_timer1; 183 184 evt->event_handler(evt); 185 186 return IRQ_HANDLED; 187 } 188 189 static struct irqaction omap_mpu_timer1_irq = { 190 .name = "mpu_timer1", 191 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 192 .handler = omap_mpu_timer1_interrupt, 193 }; 194 195 static __init void omap_init_mpu_timer(unsigned long rate) 196 { 197 set_cyc2ns_scale(rate / 1000); 198 199 setup_irq(INT_TIMER1, &omap_mpu_timer1_irq); 200 omap_mpu_timer_start(0, (rate / HZ) - 1, 1); 201 202 clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC, 203 clockevent_mpu_timer1.shift); 204 clockevent_mpu_timer1.max_delta_ns = 205 clockevent_delta2ns(-1, &clockevent_mpu_timer1); 206 clockevent_mpu_timer1.min_delta_ns = 207 clockevent_delta2ns(1, &clockevent_mpu_timer1); 208 209 clockevent_mpu_timer1.cpumask = cpumask_of_cpu(0); 210 clockevents_register_device(&clockevent_mpu_timer1); 211 } 212 213 214 /* 215 * --------------------------------------------------------------------------- 216 * MPU timer 2 ... free running 32-bit clock source and scheduler clock 217 * --------------------------------------------------------------------------- 218 */ 219 220 static unsigned long omap_mpu_timer2_overflows; 221 222 static irqreturn_t omap_mpu_timer2_interrupt(int irq, void *dev_id) 223 { 224 omap_mpu_timer2_overflows++; 225 return IRQ_HANDLED; 226 } 227 228 static struct irqaction omap_mpu_timer2_irq = { 229 .name = "mpu_timer2", 230 .flags = IRQF_DISABLED, 231 .handler = omap_mpu_timer2_interrupt, 232 }; 233 234 static cycle_t mpu_read(void) 235 { 236 return ~omap_mpu_timer_read(1); 237 } 238 239 static struct clocksource clocksource_mpu = { 240 .name = "mpu_timer2", 241 .rating = 300, 242 .read = mpu_read, 243 .mask = CLOCKSOURCE_MASK(32), 244 .shift = 24, 245 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 246 }; 247 248 static void __init omap_init_clocksource(unsigned long rate) 249 { 250 static char err[] __initdata = KERN_ERR 251 "%s: can't register clocksource!\n"; 252 253 clocksource_mpu.mult 254 = clocksource_khz2mult(rate/1000, clocksource_mpu.shift); 255 256 setup_irq(INT_TIMER2, &omap_mpu_timer2_irq); 257 omap_mpu_timer_start(1, ~0, 1); 258 259 if (clocksource_register(&clocksource_mpu)) 260 printk(err, clocksource_mpu.name); 261 } 262 263 264 /* 265 * Scheduler clock - returns current time in nanosec units. 266 */ 267 unsigned long long sched_clock(void) 268 { 269 unsigned long ticks = 0 - omap_mpu_timer_read(1); 270 unsigned long long ticks64; 271 272 ticks64 = omap_mpu_timer2_overflows; 273 ticks64 <<= 32; 274 ticks64 |= ticks; 275 276 return cycles_2_ns(ticks64); 277 } 278 279 /* 280 * --------------------------------------------------------------------------- 281 * Timer initialization 282 * --------------------------------------------------------------------------- 283 */ 284 static void __init omap_timer_init(void) 285 { 286 struct clk *ck_ref = clk_get(NULL, "ck_ref"); 287 unsigned long rate; 288 289 BUG_ON(IS_ERR(ck_ref)); 290 291 rate = clk_get_rate(ck_ref); 292 clk_put(ck_ref); 293 294 /* PTV = 0 */ 295 rate /= 2; 296 297 omap_init_mpu_timer(rate); 298 omap_init_clocksource(rate); 299 } 300 301 struct sys_timer omap_timer = { 302 .init = omap_timer_init, 303 }; 304