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/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 typedef struct { 60 u32 cntl; /* CNTL_TIMER, R/W */ 61 u32 load_tim; /* LOAD_TIM, W */ 62 u32 read_tim; /* READ_TIM, R */ 63 } omap_mpu_timer_regs_t; 64 65 #define omap_mpu_timer_base(n) \ 66 ((volatile omap_mpu_timer_regs_t*)IO_ADDRESS(OMAP_MPU_TIMER_BASE + \ 67 (n)*OMAP_MPU_TIMER_OFFSET)) 68 69 static inline unsigned long omap_mpu_timer_read(int nr) 70 { 71 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 72 return timer->read_tim; 73 } 74 75 static inline void omap_mpu_set_autoreset(int nr) 76 { 77 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 78 79 timer->cntl = timer->cntl | MPU_TIMER_AR; 80 } 81 82 static inline void omap_mpu_remove_autoreset(int nr) 83 { 84 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 85 86 timer->cntl = timer->cntl & ~MPU_TIMER_AR; 87 } 88 89 static inline void omap_mpu_timer_start(int nr, unsigned long load_val, 90 int autoreset) 91 { 92 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 93 unsigned int timerflags = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST); 94 95 if (autoreset) timerflags |= MPU_TIMER_AR; 96 97 timer->cntl = MPU_TIMER_CLOCK_ENABLE; 98 udelay(1); 99 timer->load_tim = load_val; 100 udelay(1); 101 timer->cntl = timerflags; 102 } 103 104 static inline void omap_mpu_timer_stop(int nr) 105 { 106 volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); 107 108 timer->cntl &= ~MPU_TIMER_ST; 109 } 110 111 /* 112 * --------------------------------------------------------------------------- 113 * MPU timer 1 ... count down to zero, interrupt, reload 114 * --------------------------------------------------------------------------- 115 */ 116 static int omap_mpu_set_next_event(unsigned long cycles, 117 struct clock_event_device *evt) 118 { 119 omap_mpu_timer_start(0, cycles, 0); 120 return 0; 121 } 122 123 static void omap_mpu_set_mode(enum clock_event_mode mode, 124 struct clock_event_device *evt) 125 { 126 switch (mode) { 127 case CLOCK_EVT_MODE_PERIODIC: 128 omap_mpu_set_autoreset(0); 129 break; 130 case CLOCK_EVT_MODE_ONESHOT: 131 omap_mpu_timer_stop(0); 132 omap_mpu_remove_autoreset(0); 133 break; 134 case CLOCK_EVT_MODE_UNUSED: 135 case CLOCK_EVT_MODE_SHUTDOWN: 136 case CLOCK_EVT_MODE_RESUME: 137 break; 138 } 139 } 140 141 static struct clock_event_device clockevent_mpu_timer1 = { 142 .name = "mpu_timer1", 143 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 144 .shift = 32, 145 .set_next_event = omap_mpu_set_next_event, 146 .set_mode = omap_mpu_set_mode, 147 }; 148 149 static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id) 150 { 151 struct clock_event_device *evt = &clockevent_mpu_timer1; 152 153 evt->event_handler(evt); 154 155 return IRQ_HANDLED; 156 } 157 158 static struct irqaction omap_mpu_timer1_irq = { 159 .name = "mpu_timer1", 160 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 161 .handler = omap_mpu_timer1_interrupt, 162 }; 163 164 static __init void omap_init_mpu_timer(unsigned long rate) 165 { 166 setup_irq(INT_TIMER1, &omap_mpu_timer1_irq); 167 omap_mpu_timer_start(0, (rate / HZ) - 1, 1); 168 169 clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC, 170 clockevent_mpu_timer1.shift); 171 clockevent_mpu_timer1.max_delta_ns = 172 clockevent_delta2ns(-1, &clockevent_mpu_timer1); 173 clockevent_mpu_timer1.min_delta_ns = 174 clockevent_delta2ns(1, &clockevent_mpu_timer1); 175 176 clockevent_mpu_timer1.cpumask = cpumask_of(0); 177 clockevents_register_device(&clockevent_mpu_timer1); 178 } 179 180 181 /* 182 * --------------------------------------------------------------------------- 183 * MPU timer 2 ... free running 32-bit clock source and scheduler clock 184 * --------------------------------------------------------------------------- 185 */ 186 187 static unsigned long omap_mpu_timer2_overflows; 188 189 static irqreturn_t omap_mpu_timer2_interrupt(int irq, void *dev_id) 190 { 191 omap_mpu_timer2_overflows++; 192 return IRQ_HANDLED; 193 } 194 195 static struct irqaction omap_mpu_timer2_irq = { 196 .name = "mpu_timer2", 197 .flags = IRQF_DISABLED, 198 .handler = omap_mpu_timer2_interrupt, 199 }; 200 201 static cycle_t mpu_read(void) 202 { 203 return ~omap_mpu_timer_read(1); 204 } 205 206 static struct clocksource clocksource_mpu = { 207 .name = "mpu_timer2", 208 .rating = 300, 209 .read = mpu_read, 210 .mask = CLOCKSOURCE_MASK(32), 211 .shift = 24, 212 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 213 }; 214 215 static void __init omap_init_clocksource(unsigned long rate) 216 { 217 static char err[] __initdata = KERN_ERR 218 "%s: can't register clocksource!\n"; 219 220 clocksource_mpu.mult 221 = clocksource_khz2mult(rate/1000, clocksource_mpu.shift); 222 223 setup_irq(INT_TIMER2, &omap_mpu_timer2_irq); 224 omap_mpu_timer_start(1, ~0, 1); 225 226 if (clocksource_register(&clocksource_mpu)) 227 printk(err, clocksource_mpu.name); 228 } 229 230 /* 231 * --------------------------------------------------------------------------- 232 * Timer initialization 233 * --------------------------------------------------------------------------- 234 */ 235 static void __init omap_timer_init(void) 236 { 237 struct clk *ck_ref = clk_get(NULL, "ck_ref"); 238 unsigned long rate; 239 240 BUG_ON(IS_ERR(ck_ref)); 241 242 rate = clk_get_rate(ck_ref); 243 clk_put(ck_ref); 244 245 /* PTV = 0 */ 246 rate /= 2; 247 248 omap_init_mpu_timer(rate); 249 omap_init_clocksource(rate); 250 } 251 252 struct sys_timer omap_timer = { 253 .init = omap_timer_init, 254 }; 255