Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * linux/arch/arm/mach-omap1/time.c
0003  *
0004  * OMAP Timers
0005  *
0006  * Copyright (C) 2004 Nokia Corporation
0007  * Partial timer rewrite and additional dynamic tick timer support by
0008  * Tony Lindgen <tony@atomide.com> and
0009  * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
0010  *
0011  * MPU timer code based on the older MPU timer code for OMAP
0012  * Copyright (C) 2000 RidgeRun, Inc.
0013  * Author: Greg Lonnon <glonnon@ridgerun.com>
0014  *
0015  * This program is free software; you can redistribute it and/or modify it
0016  * under the terms of the GNU General Public License as published by the
0017  * Free Software Foundation; either version 2 of the License, or (at your
0018  * option) any later version.
0019  *
0020  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
0021  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
0022  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
0023  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
0024  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
0025  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0026  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
0027  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
0029  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0030  *
0031  * You should have received a copy of the  GNU General Public License along
0032  * with this program; if not, write  to the Free Software Foundation, Inc.,
0033  * 675 Mass Ave, Cambridge, MA 02139, USA.
0034  */
0035 
0036 #include <linux/kernel.h>
0037 #include <linux/init.h>
0038 #include <linux/delay.h>
0039 #include <linux/interrupt.h>
0040 #include <linux/spinlock.h>
0041 #include <linux/clk.h>
0042 #include <linux/err.h>
0043 #include <linux/clocksource.h>
0044 #include <linux/clockchips.h>
0045 #include <linux/io.h>
0046 #include <linux/sched_clock.h>
0047 
0048 #include <asm/irq.h>
0049 
0050 #include <asm/mach/irq.h>
0051 #include <asm/mach/time.h>
0052 
0053 #include "hardware.h"
0054 #include "mux.h"
0055 #include "iomap.h"
0056 #include "common.h"
0057 #include "clock.h"
0058 
0059 #ifdef CONFIG_OMAP_MPU_TIMER
0060 
0061 #define OMAP_MPU_TIMER_BASE     OMAP_MPU_TIMER1_BASE
0062 #define OMAP_MPU_TIMER_OFFSET       0x100
0063 
0064 typedef struct {
0065     u32 cntl;           /* CNTL_TIMER, R/W */
0066     u32 load_tim;           /* LOAD_TIM,   W */
0067     u32 read_tim;           /* READ_TIM,   R */
0068 } omap_mpu_timer_regs_t;
0069 
0070 #define omap_mpu_timer_base(n)                          \
0071 ((omap_mpu_timer_regs_t __iomem *)OMAP1_IO_ADDRESS(OMAP_MPU_TIMER_BASE +    \
0072                  (n)*OMAP_MPU_TIMER_OFFSET))
0073 
0074 static inline unsigned long notrace omap_mpu_timer_read(int nr)
0075 {
0076     omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
0077     return readl(&timer->read_tim);
0078 }
0079 
0080 static inline void omap_mpu_set_autoreset(int nr)
0081 {
0082     omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
0083 
0084     writel(readl(&timer->cntl) | MPU_TIMER_AR, &timer->cntl);
0085 }
0086 
0087 static inline void omap_mpu_remove_autoreset(int nr)
0088 {
0089     omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
0090 
0091     writel(readl(&timer->cntl) & ~MPU_TIMER_AR, &timer->cntl);
0092 }
0093 
0094 static inline void omap_mpu_timer_start(int nr, unsigned long load_val,
0095                     int autoreset)
0096 {
0097     omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
0098     unsigned int timerflags = MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_ST;
0099 
0100     if (autoreset)
0101         timerflags |= MPU_TIMER_AR;
0102 
0103     writel(MPU_TIMER_CLOCK_ENABLE, &timer->cntl);
0104     udelay(1);
0105     writel(load_val, &timer->load_tim);
0106         udelay(1);
0107     writel(timerflags, &timer->cntl);
0108 }
0109 
0110 static inline void omap_mpu_timer_stop(int nr)
0111 {
0112     omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(nr);
0113 
0114     writel(readl(&timer->cntl) & ~MPU_TIMER_ST, &timer->cntl);
0115 }
0116 
0117 /*
0118  * ---------------------------------------------------------------------------
0119  * MPU timer 1 ... count down to zero, interrupt, reload
0120  * ---------------------------------------------------------------------------
0121  */
0122 static int omap_mpu_set_next_event(unsigned long cycles,
0123                    struct clock_event_device *evt)
0124 {
0125     omap_mpu_timer_start(0, cycles, 0);
0126     return 0;
0127 }
0128 
0129 static int omap_mpu_set_oneshot(struct clock_event_device *evt)
0130 {
0131     omap_mpu_timer_stop(0);
0132     omap_mpu_remove_autoreset(0);
0133     return 0;
0134 }
0135 
0136 static int omap_mpu_set_periodic(struct clock_event_device *evt)
0137 {
0138     omap_mpu_set_autoreset(0);
0139     return 0;
0140 }
0141 
0142 static struct clock_event_device clockevent_mpu_timer1 = {
0143     .name           = "mpu_timer1",
0144     .features       = CLOCK_EVT_FEAT_PERIODIC |
0145                   CLOCK_EVT_FEAT_ONESHOT,
0146     .set_next_event     = omap_mpu_set_next_event,
0147     .set_state_periodic = omap_mpu_set_periodic,
0148     .set_state_oneshot  = omap_mpu_set_oneshot,
0149 };
0150 
0151 static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
0152 {
0153     struct clock_event_device *evt = &clockevent_mpu_timer1;
0154 
0155     evt->event_handler(evt);
0156 
0157     return IRQ_HANDLED;
0158 }
0159 
0160 static __init void omap_init_mpu_timer(unsigned long rate)
0161 {
0162     if (request_irq(INT_TIMER1, omap_mpu_timer1_interrupt,
0163             IRQF_TIMER | IRQF_IRQPOLL, "mpu_timer1", NULL))
0164         pr_err("Failed to request irq %d (mpu_timer1)\n", INT_TIMER1);
0165     omap_mpu_timer_start(0, (rate / HZ) - 1, 1);
0166 
0167     clockevent_mpu_timer1.cpumask = cpumask_of(0);
0168     clockevents_config_and_register(&clockevent_mpu_timer1, rate,
0169                     1, -1);
0170 }
0171 
0172 
0173 /*
0174  * ---------------------------------------------------------------------------
0175  * MPU timer 2 ... free running 32-bit clock source and scheduler clock
0176  * ---------------------------------------------------------------------------
0177  */
0178 
0179 static u64 notrace omap_mpu_read_sched_clock(void)
0180 {
0181     return ~omap_mpu_timer_read(1);
0182 }
0183 
0184 static void __init omap_init_clocksource(unsigned long rate)
0185 {
0186     omap_mpu_timer_regs_t __iomem *timer = omap_mpu_timer_base(1);
0187     static char err[] __initdata = KERN_ERR
0188             "%s: can't register clocksource!\n";
0189 
0190     omap_mpu_timer_start(1, ~0, 1);
0191     sched_clock_register(omap_mpu_read_sched_clock, 32, rate);
0192 
0193     if (clocksource_mmio_init(&timer->read_tim, "mpu_timer2", rate,
0194             300, 32, clocksource_mmio_readl_down))
0195         printk(err, "mpu_timer2");
0196 }
0197 
0198 static void __init omap_mpu_timer_init(void)
0199 {
0200     struct clk  *ck_ref = clk_get(NULL, "ck_ref");
0201     unsigned long   rate;
0202 
0203     BUG_ON(IS_ERR(ck_ref));
0204 
0205     rate = clk_get_rate(ck_ref);
0206     clk_put(ck_ref);
0207 
0208     /* PTV = 0 */
0209     rate /= 2;
0210 
0211     omap_init_mpu_timer(rate);
0212     omap_init_clocksource(rate);
0213 }
0214 
0215 #else
0216 static inline void omap_mpu_timer_init(void)
0217 {
0218     pr_err("Bogus timer, should not happen\n");
0219 }
0220 #endif  /* CONFIG_OMAP_MPU_TIMER */
0221 
0222 /*
0223  * ---------------------------------------------------------------------------
0224  * Timer initialization
0225  * ---------------------------------------------------------------------------
0226  */
0227 void __init omap1_timer_init(void)
0228 {
0229     omap1_clk_init();
0230     omap1_mux_init();
0231 
0232     if (omap_32k_timer_init() != 0)
0233         omap_mpu_timer_init();
0234 }