X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Farm%2Fmach-omap%2Ftime.c;h=f673eeedd1d96be35e7019ba129056c568185821;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=cb3c5d6f7be60f8836ef78d725bc9835678d01c7;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/arch/arm/mach-omap/time.c b/arch/arm/mach-omap/time.c index cb3c5d6f7..f673eeedd 100644 --- a/arch/arm/mach-omap/time.c +++ b/arch/arm/mach-omap/time.c @@ -1,8 +1,14 @@ /* - * arch/arm/mach-omap/time.c + * linux/arch/arm/mach-omap/time.c * - * OMAP Timer Tick + * OMAP Timers * + * Copyright (C) 2004 Nokia Corporation + * Partial timer rewrite and additional VST timer support by + * Tony Lindgen and + * Tuukka Tikkanen + * + * MPU timer code based on the older MPU timer code for OMAP * Copyright (C) 2000 RidgeRun, Inc. * Author: Greg Lonnon * @@ -33,6 +39,7 @@ #include #include #include +#include #include #include @@ -41,177 +48,135 @@ #include #include #include -#include - -#ifndef __instrument -#define __instrument -#define __noinstrument __attribute__ ((no_instrument_function)) -#endif -typedef struct { - u32 cntl; /* CNTL_TIMER, R/W */ - u32 load_tim; /* LOAD_TIM, W */ - u32 read_tim; /* READ_TIM, R */ -} mputimer_regs_t; - -#define mputimer_base(n) \ - ((volatile mputimer_regs_t*)IO_ADDRESS(OMAP_MPUTIMER_BASE + \ - (n)*OMAP_MPUTIMER_OFFSET)) - -static inline unsigned long timer32k_read(int reg) { - unsigned long val; - val = omap_readw(reg + OMAP_32kHz_TIMER_BASE); - return val; -} -static inline void timer32k_write(int reg,int val) { - omap_writew(val, reg + OMAP_32kHz_TIMER_BASE); -} +struct sys_timer omap_timer; /* - * How long is the timer interval? 100 HZ, right... - * IRQ rate = (TVR + 1) / 32768 seconds - * TVR = 32768 * IRQ_RATE -1 - * IRQ_RATE = 1/100 - * TVR = 326 + * --------------------------------------------------------------------------- + * MPU timer + * --------------------------------------------------------------------------- */ -#define TIMER32k_PERIOD 326 -//#define TIMER32k_PERIOD 0x7ff +#define OMAP_MPU_TIMER1_BASE (0xfffec500) +#define OMAP_MPU_TIMER2_BASE (0xfffec600) +#define OMAP_MPU_TIMER3_BASE (0xfffec700) +#define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE +#define OMAP_MPU_TIMER_OFFSET 0x100 -static inline void start_timer32k(void) { - timer32k_write(TIMER32k_CR, - TIMER32k_TSS | TIMER32k_TRB | - TIMER32k_INT | TIMER32k_ARL); -} +#define MPU_TIMER_FREE (1 << 6) +#define MPU_TIMER_CLOCK_ENABLE (1 << 5) +#define MPU_TIMER_AR (1 << 1) +#define MPU_TIMER_ST (1 << 0) -#ifdef CONFIG_MACH_OMAP_PERSEUS2 /* - * After programming PTV with 0 and setting the MPUTIM_CLOCK_ENABLE - * (external clock enable) bit, the timer count rate is 6.5 MHz (13 - * MHZ input/2). !! The divider by 2 is undocumented !! + * MPU_TICKS_PER_SEC must be an even number, otherwise machinecycles_to_usecs + * will break. On P2, the timer count rate is 6.5 MHz after programming PTV + * with 0. This divides the 13MHz input by 2, and is undocumented. */ -#define MPUTICKS_PER_SEC (13000000/2) -#else -/* - * After programming PTV with 0, the timer count rate is 6 MHz. - * WARNING! this must be an even number, or machinecycles_to_usecs - * below will break. +#ifdef CONFIG_MACH_OMAP_PERSEUS2 +/* REVISIT: This ifdef construct should be replaced by a query to clock + * framework to see if timer base frequency is 12.0, 13.0 or 19.2 MHz. */ -#define MPUTICKS_PER_SEC (12000000/2) +#define MPU_TICKS_PER_SEC (13000000 / 2) +#else +#define MPU_TICKS_PER_SEC (12000000 / 2) #endif -static int mputimer_started[3] = {0,0,0}; +#define MPU_TIMER_TICK_PERIOD ((MPU_TICKS_PER_SEC / HZ) - 1) -static inline void __noinstrument start_mputimer(int n, - unsigned long load_val) -{ - volatile mputimer_regs_t* timer = mputimer_base(n); - - mputimer_started[n] = 0; - timer->cntl = MPUTIM_CLOCK_ENABLE; - udelay(1); - - timer->load_tim = load_val; - udelay(1); - timer->cntl = (MPUTIM_CLOCK_ENABLE | MPUTIM_AR | MPUTIM_ST); - mputimer_started[n] = 1; -} +typedef struct { + u32 cntl; /* CNTL_TIMER, R/W */ + u32 load_tim; /* LOAD_TIM, W */ + u32 read_tim; /* READ_TIM, R */ +} omap_mpu_timer_regs_t; -static inline unsigned long __noinstrument -read_mputimer(int n) -{ - volatile mputimer_regs_t* timer = mputimer_base(n); - return (mputimer_started[n] ? timer->read_tim : 0); -} +#define omap_mpu_timer_base(n) \ +((volatile omap_mpu_timer_regs_t*)IO_ADDRESS(OMAP_MPU_TIMER_BASE + \ + (n)*OMAP_MPU_TIMER_OFFSET)) -void __noinstrument start_mputimer1(unsigned long load_val) -{ - start_mputimer(0, load_val); -} -void __noinstrument start_mputimer2(unsigned long load_val) +static inline unsigned long omap_mpu_timer_read(int nr) { - start_mputimer(1, load_val); -} -void __noinstrument start_mputimer3(unsigned long load_val) -{ - start_mputimer(2, load_val); + volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); + return timer->read_tim; } -unsigned long __noinstrument read_mputimer1(void) -{ - return read_mputimer(0); -} -unsigned long __noinstrument read_mputimer2(void) -{ - return read_mputimer(1); -} -unsigned long __noinstrument read_mputimer3(void) +static inline void omap_mpu_timer_start(int nr, unsigned long load_val) { - return read_mputimer(2); -} + volatile omap_mpu_timer_regs_t* timer = omap_mpu_timer_base(nr); -unsigned long __noinstrument do_getmachinecycles(void) -{ - return 0 - read_mputimer(0); + timer->cntl = MPU_TIMER_CLOCK_ENABLE; + udelay(1); + timer->load_tim = load_val; + udelay(1); + timer->cntl = (MPU_TIMER_CLOCK_ENABLE | MPU_TIMER_AR | MPU_TIMER_ST); } -unsigned long __noinstrument machinecycles_to_usecs(unsigned long mputicks) +unsigned long omap_mpu_timer_ticks_to_usecs(unsigned long nr_ticks) { /* Round up to nearest usec */ - return ((mputicks * 1000) / (MPUTICKS_PER_SEC / 2 / 1000) + 1) >> 1; + return ((nr_ticks * 1000) / (MPU_TICKS_PER_SEC / 2 / 1000) + 1) >> 1; } /* - * This marks the time of the last system timer interrupt - * that was *processed by the ISR* (timer 2). + * Last processed system timer interrupt */ -static unsigned long systimer_mark; +static unsigned long omap_mpu_timer_last = 0; -static unsigned long omap_gettimeoffset(void) +/* + * Returns elapsed usecs since last system timer interrupt + */ +static unsigned long omap_mpu_timer_gettimeoffset(void) { - /* Return elapsed usecs since last system timer ISR */ - return machinecycles_to_usecs(do_getmachinecycles() - systimer_mark); + unsigned long now = 0 - omap_mpu_timer_read(0); + unsigned long elapsed = now - omap_mpu_timer_last; + + return omap_mpu_timer_ticks_to_usecs(elapsed); } -static irqreturn_t -omap_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +/* + * Elapsed time between interrupts is calculated using timer0. + * Latency during the interrupt is calculated using timer1. + * Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz). + */ +static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { - unsigned long now, ilatency; - - /* - * Mark the time at which the timer interrupt ocurred using - * timer1. We need to remove interrupt latency, which we can - * retrieve from the current system timer2 counter. Both the - * offset timer1 and the system timer2 are counting at 6MHz, - * so we're ok. - */ - now = 0 - read_mputimer1(); - ilatency = MPUTICKS_PER_SEC / 100 - read_mputimer2(); - systimer_mark = now - ilatency; + unsigned long now, latency; + write_seqlock(&xtime_lock); + now = 0 - omap_mpu_timer_read(0); + latency = MPU_TICKS_PER_SEC / HZ - omap_mpu_timer_read(1); + omap_mpu_timer_last = now - latency; timer_tick(regs); + write_sequnlock(&xtime_lock); return IRQ_HANDLED; } -static struct irqaction omap_timer_irq = { - .name = "OMAP Timer Tick", +static struct irqaction omap_mpu_timer_irq = { + .name = "mpu timer", .flags = SA_INTERRUPT, - .handler = omap_timer_interrupt + .handler = omap_mpu_timer_interrupt }; -void __init omap_init_time(void) +static __init void omap_init_mpu_timer(void) { - /* Since we don't call request_irq, we must init the structure */ - gettimeoffset = omap_gettimeoffset; - -#ifdef OMAP1510_USE_32KHZ_TIMER - timer32k_write(TIMER32k_CR, 0x0); - timer32k_write(TIMER32k_TVR,TIMER32k_PERIOD); - setup_irq(INT_OS_32kHz_TIMER, &omap_timer_irq); - start_timer32k(); -#else - setup_irq(INT_TIMER2, &omap_timer_irq); - start_mputimer2(MPUTICKS_PER_SEC / 100 - 1); -#endif + omap_timer.offset = omap_mpu_timer_gettimeoffset; + setup_irq(INT_TIMER2, &omap_mpu_timer_irq); + omap_mpu_timer_start(0, 0xffffffff); + omap_mpu_timer_start(1, MPU_TIMER_TICK_PERIOD); } +/* + * --------------------------------------------------------------------------- + * Timer initialization + * --------------------------------------------------------------------------- + */ +void __init omap_timer_init(void) +{ + omap_init_mpu_timer(); +} + +struct sys_timer omap_timer = { + .init = omap_timer_init, + .offset = NULL, /* Initialized later */ +};