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/spinlock.h> 41 #include <linux/clk.h> 42 #include <linux/err.h> 43 #include <linux/clocksource.h> 44 #include <linux/clockchips.h> 45 #include <linux/io.h> 46 47 #include <asm/system.h> 48 #include <asm/leds.h> 49 #include <asm/irq.h> 50 #include <asm/sched_clock.h> 51 52 #include <mach/hardware.h> 53 #include <asm/mach/irq.h> 54 #include <asm/mach/time.h> 55 56 #include "iomap.h" 57 #include "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 ((omap_mpu_timer_regs_t __iomem *)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 omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr); 77 return readl(&timer->read_tim); 78 } 79 80 static inline void omap_mpu_set_autoreset(int nr) 81 { 82 omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr); 83 84 writel(readl(&timer->cntl) | MPU_TIMER_AR, &timer->cntl); 85 } 86 87 static inline void omap_mpu_remove_autoreset(int nr) 88 { 89 omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr); 90 91 writel(readl(&timer->cntl) & ~MPU_TIMER_AR, &timer->cntl); 92 } 93 94 static inline void omap_mpu_timer_start(int nr, unsigned long load_val, 95 int autoreset) 96 { 97 omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr); 98 unsigned int timerflags = MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST; 99 100 if (autoreset) 101 timerflags |= MPU_TIMER_AR; 102 103 writel(MPU_TIMER_CLOCK_ENABLE, &timer->cntl); 104 udelay(1); 105 writel(load_val, &timer->load_tim); 106 udelay(1); 107 writel(timerflags, &timer->cntl); 108 } 109 110 static inline void omap_mpu_timer_stop(int nr) 111 { 112 omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr); 113 114 writel(readl(&timer->cntl) & ~MPU_TIMER_ST, &timer->cntl); 115 } 116 117 /* 118 * --------------------------------------------------------------------------- 119 * MPU timer 1 ... count down to zero, interrupt, reload 120 * --------------------------------------------------------------------------- 121 */ 122 static int omap_mpu_set_next_event(unsigned long cycles, 123 struct clock_event_device *evt) 124 { 125 omap_mpu_timer_start(0, cycles, 0); 126 return 0; 127 } 128 129 static void omap_mpu_set_mode(enum clock_event_mode mode, 130 struct clock_event_device *evt) 131 { 132 switch (mode) { 133 case CLOCK_EVT_MODE_PERIODIC: 134 omap_mpu_set_autoreset(0); 135 break; 136 case CLOCK_EVT_MODE_ONESHOT: 137 omap_mpu_timer_stop(0); 138 omap_mpu_remove_autoreset(0); 139 break; 140 case CLOCK_EVT_MODE_UNUSED: 141 case CLOCK_EVT_MODE_SHUTDOWN: 142 case CLOCK_EVT_MODE_RESUME: 143 break; 144 } 145 } 146 147 static struct clock_event_device clockevent_mpu_timer1 = { 148 .name = "mpu_timer1", 149 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, 150 .shift = 32, 151 .set_next_event = omap_mpu_set_next_event, 152 .set_mode = omap_mpu_set_mode, 153 }; 154 155 static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id) 156 { 157 struct clock_event_device *evt = &clockevent_mpu_timer1; 158 159 evt->event_handler(evt); 160 161 return IRQ_HANDLED; 162 } 163 164 static struct irqaction omap_mpu_timer1_irq = { 165 .name = "mpu_timer1", 166 .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, 167 .handler = omap_mpu_timer1_interrupt, 168 }; 169 170 static __init void omap_init_mpu_timer(unsigned long rate) 171 { 172 setup_irq(INT_TIMER1, &omap_mpu_timer1_irq); 173 omap_mpu_timer_start(0, (rate / HZ) - 1, 1); 174 175 clockevent_mpu_timer1.mult = div_sc(rate, NSEC_PER_SEC, 176 clockevent_mpu_timer1.shift); 177 clockevent_mpu_timer1.max_delta_ns = 178 clockevent_delta2ns(-1, &clockevent_mpu_timer1); 179 clockevent_mpu_timer1.min_delta_ns = 180 clockevent_delta2ns(1, &clockevent_mpu_timer1); 181 182 clockevent_mpu_timer1.cpumask = cpumask_of(0); 183 clockevents_register_device(&clockevent_mpu_timer1); 184 } 185 186 187 /* 188 * --------------------------------------------------------------------------- 189 * MPU timer 2 ... free running 32-bit clock source and scheduler clock 190 * --------------------------------------------------------------------------- 191 */ 192 193 static u32 notrace omap_mpu_read_sched_clock(void) 194 { 195 return ~omap_mpu_timer_read(1); 196 } 197 198 static void __init omap_init_clocksource(unsigned long rate) 199 { 200 omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(1); 201 static char err[] __initdata = KERN_ERR 202 "%s: can't register clocksource!\n"; 203 204 omap_mpu_timer_start(1, ~0, 1); 205 setup_sched_clock(omap_mpu_read_sched_clock, 32, rate); 206 207 if (clocksource_mmio_init(&timer->read_tim, "mpu_timer2", rate, 208 300, 32, clocksource_mmio_readl_down)) 209 printk(err, "mpu_timer2"); 210 } 211 212 static void __init omap_mpu_timer_init(void) 213 { 214 struct clk *ck_ref = clk_get(NULL, "ck_ref"); 215 unsigned long rate; 216 217 BUG_ON(IS_ERR(ck_ref)); 218 219 rate = clk_get_rate(ck_ref); 220 clk_put(ck_ref); 221 222 /* PTV = 0 */ 223 rate /= 2; 224 225 omap_init_mpu_timer(rate); 226 omap_init_clocksource(rate); 227 } 228 229 #else 230 static inline void omap_mpu_timer_init(void) 231 { 232 pr_err("Bogus timer, should not happen\n"); 233 } 234 #endif /* CONFIG_OMAP_MPU_TIMER */ 235 236 static inline int omap_32k_timer_usable(void) 237 { 238 int res = false; 239 240 if (cpu_is_omap730() || cpu_is_omap15xx()) 241 return res; 242 243 #ifdef CONFIG_OMAP_32K_TIMER 244 res = omap_32k_timer_init(); 245 #endif 246 247 return res; 248 } 249 250 /* 251 * --------------------------------------------------------------------------- 252 * Timer initialization 253 * --------------------------------------------------------------------------- 254 */ 255 static void __init omap1_timer_init(void) 256 { 257 if (!omap_32k_timer_usable()) 258 omap_mpu_timer_init(); 259 } 260 261 struct sys_timer omap1_timer = { 262 .init = omap1_timer_init, 263 }; 264