1/* 2 * linux/include/asm-arm/arch-integrator/time.h 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18#include <asm/system.h> 19#include <asm/leds.h> 20 21/* 22 * Where is the timer (VA)? 23 */ 24#define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000) 25#define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100) 26#define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200) 27#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) 28 29/* 30 * How long is the timer interval? 31 */ 32#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) 33#if TIMER_INTERVAL >= 0x100000 34#define TIMER_RELOAD (TIMER_INTERVAL >> 8) /* Divide by 256 */ 35#define TIMER_CTRL 0x88 /* Enable, Clock / 256 */ 36#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) 37#elif TIMER_INTERVAL >= 0x10000 38#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ 39#define TIMER_CTRL 0x84 /* Enable, Clock / 16 */ 40#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) 41#else 42#define TIMER_RELOAD (TIMER_INTERVAL) 43#define TIMER_CTRL 0x80 /* Enable */ 44#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) 45#endif 46 47/* 48 * What does it look like? 49 */ 50typedef struct TimerStruct { 51 unsigned long TimerLoad; 52 unsigned long TimerValue; 53 unsigned long TimerControl; 54 unsigned long TimerClear; 55} TimerStruct_t; 56 57extern unsigned long (*gettimeoffset)(void); 58 59/* 60 * Returns number of ms since last clock interrupt. Note that interrupts 61 * will have been disabled by do_gettimeoffset() 62 */ 63static unsigned long integrator_gettimeoffset(void) 64{ 65 volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE; 66 unsigned long ticks1, ticks2, status; 67 68 /* 69 * Get the current number of ticks. Note that there is a race 70 * condition between us reading the timer and checking for 71 * an interrupt. We get around this by ensuring that the 72 * counter has not reloaded between our two reads. 73 */ 74 ticks2 = timer1->TimerValue & 0xffff; 75 do { 76 ticks1 = ticks2; 77 status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS); 78 ticks2 = timer1->TimerValue & 0xffff; 79 } while (ticks2 > ticks1); 80 81 /* 82 * Number of ticks since last interrupt. 83 */ 84 ticks1 = TIMER_RELOAD - ticks2; 85 86 /* 87 * Interrupt pending? If so, we've reloaded once already. 88 */ 89 if (status & IRQMASK_TIMERINT1) 90 ticks1 += TIMER_RELOAD; 91 92 /* 93 * Convert the ticks to usecs 94 */ 95 return TICKS2USECS(ticks1); 96} 97 98/* 99 * IRQ handler for the timer 100 */ 101static void integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 102{ 103 volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; 104 105 // ...clear the interrupt 106 timer1->TimerClear = 1; 107 108 do_leds(); 109 do_timer(regs); 110 do_profile(regs); 111} 112 113/* 114 * Set up timer interrupt, and return the current time in seconds. 115 */ 116static inline void setup_timer(void) 117{ 118 volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE; 119 volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE; 120 volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE; 121 122 timer_irq.handler = integrator_timer_interrupt; 123 124 /* 125 * Initialise to a known state (all timers off) 126 */ 127 timer0->TimerControl = 0; 128 timer1->TimerControl = 0; 129 timer2->TimerControl = 0; 130 131 timer1->TimerLoad = TIMER_RELOAD; 132 timer1->TimerValue = TIMER_RELOAD; 133 timer1->TimerControl = TIMER_CTRL | 0x40; /* periodic */ 134 135 /* 136 * Make irqs happen for the system timer 137 */ 138 setup_arm_irq(IRQ_TIMERINT1, &timer_irq); 139 gettimeoffset = integrator_gettimeoffset; 140} 141