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 #include <linux/io.h> 47 48 #include <asm/system.h> 49 #include <mach/hardware.h> 50 #include <asm/leds.h> 51 #include <asm/irq.h> 52 #include <asm/sched_clock.h> 53 54 #include <asm/mach/irq.h> 55 #include <asm/mach/time.h> 56 57 #include <plat/common.h> 58 59 #ifdef CONFIG_OMAP_MPU_TIMER 60 61 #define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE 62 #define OMAP_MPU_TIMER_OFFSET 0x100 63 64 typedef struct { 65 u32 cntl; /* CNTL_TIMER, R/W */ 66 u32 load_tim; /* LOAD_TIM, W */ 67 u32 read_tim; /* READ_TIM, R */ 68 } omap_mpu_timer_regs_t; 69 70 #define omap_mpu_timer_base(n) \ 71 ((volatile omap_mpu_timer_regs_t*)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE + \ 72 (n)*OMAP_MPU_TIMER_OFFSET)) 73 74 static inline unsigned long notrace omap_mpu_timer_read(int nr) 75 { 76 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 77 return timer->read_tim; 78 } 79 80 static inline void omap_mpu_set_autoreset(int nr) 81 { 82 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 83 84 timer->cntl = timer->cntl | MPU_TIMER_AR; 85 } 86 87 static inline void omap_mpu_remove_autoreset(int nr) 88 { 89 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 90 91 timer->cntl = timer->cntl & ~MPU_TIMER_AR; 92 } 93 94 static inline void omap_mpu_timer_start(int nr, unsigned long load_val, 95 int autoreset) 96 { 97 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 98 unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST); 99 100 if (autoreset) timerflags |= MPU_TIMER_AR; 101 102 timer->cntl = MPU_TIMER_CLOCK_ENABLE; 103 udelay(1); 104 timer->load_tim = load_val; 105 udelay(1); 106 timer->cntl = timerflags; 107 } 108 109 static inline void omap_mpu_timer_stop(int nr) 110 { 111 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 112 113 timer->cntl &= ~MPU_TIMER_ST; 114 } 115 116 /* 117 * --------------------------------------------------------------------------- 118 * MPU timer 1 ... count down to zero, interrupt, reload 119 * --------------------------------------------------------------------------- 120 */ 121 static int omap_mpu_set_next_event(unsigned long cycles, 122 struct clock_event_device *evt) 123 { 124 omap_mpu_timer_start(0, cycles, 0); 125 return 0; 126 } 127 128 static void omap_mpu_set_mode(enum clock_event_mode mode, 129 struct clock_event_device *evt) 130 { 131 switch (mode) { 132 case CLOCK_EVT_MODE_PERIODIC: 133 omap_mpu_set_autoreset(0); 134 break; 135 case CLOCK_EVT_MODE_ONESHOT: 136 omap_mpu_timer_stop(0); 137 omap_mpu_remove_autoreset(0); 138 break; 139 case CLOCK_EVT_MODE_UNUSED: 140 case CLOCK_EVT_MODE_SHUTDOWN: 141 case CLOCK_EVT_MODE_RESUME: 142 break; 143 } 144 } 145 146 static struct clock_event_device clockevent_mpu_timer1 = { 147 .name = "mpu_timer1", 148 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 149 .shift = 32, 150 .set_next_event = omap_mpu_set_next_event, 151 .set_mode = omap_mpu_set_mode, 152 }; 153 154 static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id) 155 { 156 struct clock_event_device *evt = &clockevent_mpu_timer1; 157 158 evt->event_handler(evt); 159 160 return IRQ_HANDLED; 161 } 162 163 static struct irqaction omap_mpu_timer1_irq = { 164 .name = "mpu_timer1", 165 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 166 .handler = omap_mpu_timer1_interrupt, 167 }; 168 169 static __init void omap_init_mpu_timer(unsigned long rate) 170 { 171 setup_irq(INT_TIMER1, &omap_mpu_timer1_irq); 172 omap_mpu_timer_start(0, (rate / HZ) - 1, 1); 173 174 clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC, 175 clockevent_mpu_timer1.shift); 176 clockevent_mpu_timer1.max_delta_ns = 177 clockevent_delta2ns(-1, &clockevent_mpu_timer1); 178 clockevent_mpu_timer1.min_delta_ns = 179 clockevent_delta2ns(1, &clockevent_mpu_timer1); 180 181 clockevent_mpu_timer1.cpumask = cpumask_of(0); 182 clockevents_register_device(&clockevent_mpu_timer1); 183 } 184 185 186 /* 187 * --------------------------------------------------------------------------- 188 * MPU timer 2 ... free running 32-bit clock source and scheduler clock 189 * --------------------------------------------------------------------------- 190 */ 191 192 static unsigned long omap_mpu_timer2_overflows; 193 194 static irqreturn_t omap_mpu_timer2_interrupt(int irq, void *dev_id) 195 { 196 omap_mpu_timer2_overflows++; 197 return IRQ_HANDLED; 198 } 199 200 static struct irqaction omap_mpu_timer2_irq = { 201 .name = "mpu_timer2", 202 .flags = IRQF_DISABLED, 203 .handler = omap_mpu_timer2_interrupt, 204 }; 205 206 static cycle_t mpu_read(struct clocksource *cs) 207 { 208 return ~omap_mpu_timer_read(1); 209 } 210 211 static struct clocksource clocksource_mpu = { 212 .name = "mpu_timer2", 213 .rating = 300, 214 .read = mpu_read, 215 .mask = CLOCKSOURCE_MASK(32), 216 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 217 }; 218 219 static DEFINE_CLOCK_DATA(cd); 220 221 static inline unsigned long long notrace _omap_mpu_sched_clock(void) 222 { 223 u32 cyc = mpu_read(&clocksource_mpu); 224 return cyc_to_sched_clock(&cd, cyc, (u32)~0); 225 } 226 227 #ifndef CONFIG_OMAP_32K_TIMER 228 unsigned long long notrace sched_clock(void) 229 { 230 return _omap_mpu_sched_clock(); 231 } 232 #else 233 static unsigned long long notrace omap_mpu_sched_clock(void) 234 { 235 return _omap_mpu_sched_clock(); 236 } 237 #endif 238 239 static void notrace mpu_update_sched_clock(void) 240 { 241 u32 cyc = mpu_read(&clocksource_mpu); 242 update_sched_clock(&cd, cyc, (u32)~0); 243 } 244 245 static void __init omap_init_clocksource(unsigned long rate) 246 { 247 static char err[] __initdata = KERN_ERR 248 "%s: can't register clocksource!\n"; 249 250 setup_irq(INT_TIMER2, &omap_mpu_timer2_irq); 251 omap_mpu_timer_start(1, ~0, 1); 252 init_sched_clock(&cd, mpu_update_sched_clock, 32, rate); 253 254 if (clocksource_register_hz(&clocksource_mpu, rate)) 255 printk(err, clocksource_mpu.name); 256 } 257 258 static void __init omap_mpu_timer_init(void) 259 { 260 struct clk *ck_ref = clk_get(NULL, "ck_ref"); 261 unsigned long rate; 262 263 BUG_ON(IS_ERR(ck_ref)); 264 265 rate = clk_get_rate(ck_ref); 266 clk_put(ck_ref); 267 268 /* PTV = 0 */ 269 rate /= 2; 270 271 omap_init_mpu_timer(rate); 272 omap_init_clocksource(rate); 273 } 274 275 #else 276 static inline void omap_mpu_timer_init(void) 277 { 278 pr_err("Bogus timer, should not happen\n"); 279 } 280 #endif /* CONFIG_OMAP_MPU_TIMER */ 281 282 #if defined(CONFIG_OMAP_MPU_TIMER) && defined(CONFIG_OMAP_32K_TIMER) 283 static unsigned long long (*preferred_sched_clock)(void); 284 285 unsigned long long notrace sched_clock(void) 286 { 287 if (!preferred_sched_clock) 288 return 0; 289 290 return preferred_sched_clock(); 291 } 292 293 static inline void preferred_sched_clock_init(bool use_32k_sched_clock) 294 { 295 if (use_32k_sched_clock) 296 preferred_sched_clock = omap_32k_sched_clock; 297 else 298 preferred_sched_clock = omap_mpu_sched_clock; 299 } 300 #else 301 static inline void preferred_sched_clock_init(bool use_32k_sched_clcok) 302 { 303 } 304 #endif 305 306 static inline int omap_32k_timer_usable(void) 307 { 308 int res = false; 309 310 if (cpu_is_omap730() || cpu_is_omap15xx()) 311 return res; 312 313 #ifdef CONFIG_OMAP_32K_TIMER 314 res = omap_32k_timer_init(); 315 #endif 316 317 return res; 318 } 319 320 /* 321 * --------------------------------------------------------------------------- 322 * Timer initialization 323 * --------------------------------------------------------------------------- 324 */ 325 static void __init omap_timer_init(void) 326 { 327 if (omap_32k_timer_usable()) { 328 preferred_sched_clock_init(1); 329 } else { 330 omap_mpu_timer_init(); 331 preferred_sched_clock_init(0); 332 } 333 } 334 335 struct sys_timer omap_timer = { 336 .init = omap_timer_init, 337 }; 338