2 * linux/include/asm-arm/arch-versatile/time.h
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.
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.
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
18 #include <asm/system.h>
22 * Where is the timer (VA)?
24 #define TIMER0_VA_BASE IO_ADDRESS(VERSATILE_TIMER0_1_BASE)
25 #define TIMER1_VA_BASE (IO_ADDRESS(VERSATILE_TIMER0_1_BASE) + 0x20)
26 #define TIMER2_VA_BASE IO_ADDRESS(VERSATILE_TIMER2_3_BASE)
27 #define TIMER3_VA_BASE (IO_ADDRESS(VERSATILE_TIMER2_3_BASE) + 0x20)
28 #define VA_IC_BASE IO_ADDRESS(VERSATILE_VIC_BASE)
31 * How long is the timer interval?
33 #define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
34 #if TIMER_INTERVAL >= 0x100000
35 #define TIMER_RELOAD (TIMER_INTERVAL >> 8) /* Divide by 256 */
36 #define TIMER_CTRL 0x88 /* Enable, Clock / 256 */
37 #define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
38 #elif TIMER_INTERVAL >= 0x10000
39 #define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */
40 #define TIMER_CTRL 0x84 /* Enable, Clock / 16 */
41 #define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
43 #define TIMER_RELOAD (TIMER_INTERVAL)
44 #define TIMER_CTRL 0x80 /* Enable */
45 #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
48 #define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */
51 * What does it look like?
53 typedef struct TimerStruct {
54 unsigned long TimerLoad;
55 unsigned long TimerValue;
56 unsigned long TimerControl;
57 unsigned long TimerClear;
60 extern unsigned long (*gettimeoffset)(void);
63 * Returns number of ms since last clock interrupt. Note that interrupts
64 * will have been disabled by do_gettimeoffset()
66 static unsigned long versatile_gettimeoffset(void)
68 volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE;
69 unsigned long ticks1, ticks2, status;
72 * Get the current number of ticks. Note that there is a race
73 * condition between us reading the timer and checking for
74 * an interrupt. We get around this by ensuring that the
75 * counter has not reloaded between our two reads.
77 ticks2 = timer0->TimerValue & 0xffff;
80 status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS);
81 ticks2 = timer0->TimerValue & 0xffff;
82 } while (ticks2 > ticks1);
85 * Number of ticks since last interrupt.
87 ticks1 = TIMER_RELOAD - ticks2;
90 * Interrupt pending? If so, we've reloaded once already.
92 * FIXME: Need to check this is effectively timer 0 that expires
94 if (status & IRQMASK_TIMERINT0_1)
95 ticks1 += TIMER_RELOAD;
98 * Convert the ticks to usecs
100 return TICKS2USECS(ticks1);
104 * IRQ handler for the timer
106 static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
108 volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
110 // ...clear the interrupt
111 timer0->TimerClear = 1;
121 * Set up timer interrupt, and return the current time in seconds.
123 void __init time_init(void)
125 volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
126 volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
127 volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
128 volatile TimerStruct_t *timer3 = (volatile TimerStruct_t *)TIMER3_VA_BASE;
131 * set clock frequency:
132 * VERSATILE_REFCLK is 32KHz
133 * VERSATILE_TIMCLK is 1MHz
135 *(volatile unsigned int *)IO_ADDRESS(VERSATILE_SCTL_BASE) |=
136 ((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
137 (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel));
139 timer_irq.handler = versatile_timer_interrupt;
142 * Initialise to a known state (all timers off)
144 timer0->TimerControl = 0;
145 timer1->TimerControl = 0;
146 timer2->TimerControl = 0;
147 timer3->TimerControl = 0;
149 timer0->TimerLoad = TIMER_RELOAD;
150 timer0->TimerValue = TIMER_RELOAD;
151 timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE; /* periodic + IE */
154 * Make irqs happen for the system timer
156 setup_irq(IRQ_TIMERINT0_1, &timer_irq);
157 gettimeoffset = versatile_gettimeoffset;