ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / asm-arm / arch-versatile / time.h
1 /*
2  *  linux/include/asm-arm/arch-versatile/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(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) 
29
30 /*
31  * How long is the timer interval?
32  */
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)
42 #else
43 #define TIMER_RELOAD    (TIMER_INTERVAL)
44 #define TIMER_CTRL      0x80                            /* Enable */
45 #define TICKS2USECS(x)  ((x) / TICKS_PER_uSEC)
46 #endif
47
48 #define TIMER_CTRL_IE   (1 << 5)        /* Interrupt Enable */
49
50 /*
51  * What does it look like?
52  */
53 typedef struct TimerStruct {
54         unsigned long TimerLoad;
55         unsigned long TimerValue;
56         unsigned long TimerControl;
57         unsigned long TimerClear;
58 } TimerStruct_t;
59
60 extern unsigned long (*gettimeoffset)(void);
61
62 /*
63  * Returns number of ms since last clock interrupt.  Note that interrupts
64  * will have been disabled by do_gettimeoffset()
65  */
66 static unsigned long versatile_gettimeoffset(void)
67 {
68         volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE;
69         unsigned long ticks1, ticks2, status;
70
71         /*
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.
76          */
77         ticks2 = timer0->TimerValue & 0xffff;
78         do {
79                 ticks1 = ticks2;
80                 status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS);
81                 ticks2 = timer0->TimerValue & 0xffff;
82         } while (ticks2 > ticks1);
83
84         /*
85          * Number of ticks since last interrupt.
86          */
87         ticks1 = TIMER_RELOAD - ticks2;
88
89         /*
90          * Interrupt pending?  If so, we've reloaded once already.
91          *
92          * FIXME: Need to check this is effectively timer 0 that expires
93          */
94         if (status & IRQMASK_TIMERINT0_1)
95                 ticks1 += TIMER_RELOAD;
96
97         /*
98          * Convert the ticks to usecs
99          */
100         return TICKS2USECS(ticks1);
101 }
102
103 /*
104  * IRQ handler for the timer
105  */
106 static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
107 {
108         volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
109
110         // ...clear the interrupt
111         timer0->TimerClear = 1;
112
113         do_leds();
114         do_timer(regs);
115         do_profile(regs);
116
117         return IRQ_HANDLED;
118 }
119
120 /*
121  * Set up timer interrupt, and return the current time in seconds.
122  */
123 void __init time_init(void)
124 {
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;
129
130         /* 
131          * set clock frequency: 
132          *      VERSATILE_REFCLK is 32KHz
133          *      VERSATILE_TIMCLK is 1MHz
134          */
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));
138
139         timer_irq.handler = versatile_timer_interrupt;
140
141         /*
142          * Initialise to a known state (all timers off)
143          */
144         timer0->TimerControl = 0;
145         timer1->TimerControl = 0;
146         timer2->TimerControl = 0;
147         timer3->TimerControl = 0;
148
149         timer0->TimerLoad    = TIMER_RELOAD;
150         timer0->TimerValue   = TIMER_RELOAD;
151         timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE;  /* periodic + IE */
152
153         /* 
154          * Make irqs happen for the system timer
155          */
156         setup_irq(IRQ_TIMERINT0_1, &timer_irq);
157         gettimeoffset = versatile_gettimeoffset;
158 }