Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / arch / arm / mach-integrator / core.c
1 /*
2  *  linux/arch/arm/mach-integrator/core.c
3  *
4  *  Copyright (C) 2000-2003 Deep Blue Solutions Ltd
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2, as
8  * published by the Free Software Foundation.
9  */
10 #include <linux/types.h>
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/device.h>
14 #include <linux/spinlock.h>
15 #include <linux/interrupt.h>
16 #include <linux/sched.h>
17 #include <linux/smp.h>
18
19 #include <asm/hardware.h>
20 #include <asm/irq.h>
21 #include <asm/io.h>
22 #include <asm/hardware/amba.h>
23 #include <asm/arch/cm.h>
24 #include <asm/system.h>
25 #include <asm/leds.h>
26 #include <asm/mach/time.h>
27
28 #include "common.h"
29
30 static struct amba_device rtc_device = {
31         .dev            = {
32                 .bus_id = "mb:15",
33         },
34         .res            = {
35                 .start  = INTEGRATOR_RTC_BASE,
36                 .end    = INTEGRATOR_RTC_BASE + SZ_4K - 1,
37                 .flags  = IORESOURCE_MEM,
38         },
39         .irq            = { IRQ_RTCINT, NO_IRQ },
40         .periphid       = 0x00041030,
41 };
42
43 static struct amba_device uart0_device = {
44         .dev            = {
45                 .bus_id = "mb:16",
46         },
47         .res            = {
48                 .start  = INTEGRATOR_UART0_BASE,
49                 .end    = INTEGRATOR_UART0_BASE + SZ_4K - 1,
50                 .flags  = IORESOURCE_MEM,
51         },
52         .irq            = { IRQ_UARTINT0, NO_IRQ },
53         .periphid       = 0x0041010,
54 };
55
56 static struct amba_device uart1_device = {
57         .dev            = {
58                 .bus_id = "mb:17",
59         },
60         .res            = {
61                 .start  = INTEGRATOR_UART1_BASE,
62                 .end    = INTEGRATOR_UART1_BASE + SZ_4K - 1,
63                 .flags  = IORESOURCE_MEM,
64         },
65         .irq            = { IRQ_UARTINT1, NO_IRQ },
66         .periphid       = 0x0041010,
67 };
68
69 static struct amba_device kmi0_device = {
70         .dev            = {
71                 .bus_id = "mb:18",
72         },
73         .res            = {
74                 .start  = KMI0_BASE,
75                 .end    = KMI0_BASE + SZ_4K - 1,
76                 .flags  = IORESOURCE_MEM,
77         },
78         .irq            = { IRQ_KMIINT0, NO_IRQ },
79         .periphid       = 0x00041050,
80 };
81
82 static struct amba_device kmi1_device = {
83         .dev            = {
84                 .bus_id = "mb:19",
85         },
86         .res            = {
87                 .start  = KMI1_BASE,
88                 .end    = KMI1_BASE + SZ_4K - 1,
89                 .flags  = IORESOURCE_MEM,
90         },
91         .irq            = { IRQ_KMIINT1, NO_IRQ },
92         .periphid       = 0x00041050,
93 };
94
95 static struct amba_device *amba_devs[] __initdata = {
96         &rtc_device,
97         &uart0_device,
98         &uart1_device,
99         &kmi0_device,
100         &kmi1_device,
101 };
102
103 static int __init integrator_init(void)
104 {
105         int i;
106
107         for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
108                 struct amba_device *d = amba_devs[i];
109                 amba_device_register(d, &iomem_resource);
110         }
111
112         return 0;
113 }
114
115 arch_initcall(integrator_init);
116
117 #define CM_CTRL IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_CTRL_OFFSET
118
119 static DEFINE_SPINLOCK(cm_lock);
120
121 /**
122  * cm_control - update the CM_CTRL register.
123  * @mask: bits to change
124  * @set: bits to set
125  */
126 void cm_control(u32 mask, u32 set)
127 {
128         unsigned long flags;
129         u32 val;
130
131         spin_lock_irqsave(&cm_lock, flags);
132         val = readl(CM_CTRL) & ~mask;
133         writel(val | set, CM_CTRL);
134         spin_unlock_irqrestore(&cm_lock, flags);
135 }
136
137 EXPORT_SYMBOL(cm_control);
138
139 /*
140  * Where is the timer (VA)?
141  */
142 #define TIMER0_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000000)
143 #define TIMER1_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000100)
144 #define TIMER2_VA_BASE (IO_ADDRESS(INTEGRATOR_CT_BASE)+0x00000200)
145 #define VA_IC_BASE     IO_ADDRESS(INTEGRATOR_IC_BASE) 
146
147 /*
148  * How long is the timer interval?
149  */
150 #define TIMER_INTERVAL  (TICKS_PER_uSEC * mSEC_10)
151 #if TIMER_INTERVAL >= 0x100000
152 #define TICKS2USECS(x)  (256 * (x) / TICKS_PER_uSEC)
153 #elif TIMER_INTERVAL >= 0x10000
154 #define TICKS2USECS(x)  (16 * (x) / TICKS_PER_uSEC)
155 #else
156 #define TICKS2USECS(x)  ((x) / TICKS_PER_uSEC)
157 #endif
158
159 /*
160  * What does it look like?
161  */
162 typedef struct TimerStruct {
163         unsigned long TimerLoad;
164         unsigned long TimerValue;
165         unsigned long TimerControl;
166         unsigned long TimerClear;
167 } TimerStruct_t;
168
169 static unsigned long timer_reload;
170
171 /*
172  * Returns number of ms since last clock interrupt.  Note that interrupts
173  * will have been disabled by do_gettimeoffset()
174  */
175 unsigned long integrator_gettimeoffset(void)
176 {
177         volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE;
178         unsigned long ticks1, ticks2, status;
179
180         /*
181          * Get the current number of ticks.  Note that there is a race
182          * condition between us reading the timer and checking for
183          * an interrupt.  We get around this by ensuring that the
184          * counter has not reloaded between our two reads.
185          */
186         ticks2 = timer1->TimerValue & 0xffff;
187         do {
188                 ticks1 = ticks2;
189                 status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
190                 ticks2 = timer1->TimerValue & 0xffff;
191         } while (ticks2 > ticks1);
192
193         /*
194          * Number of ticks since last interrupt.
195          */
196         ticks1 = timer_reload - ticks2;
197
198         /*
199          * Interrupt pending?  If so, we've reloaded once already.
200          */
201         if (status & (1 << IRQ_TIMERINT1))
202                 ticks1 += timer_reload;
203
204         /*
205          * Convert the ticks to usecs
206          */
207         return TICKS2USECS(ticks1);
208 }
209
210 /*
211  * IRQ handler for the timer
212  */
213 static irqreturn_t
214 integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
215 {
216         volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
217
218         write_seqlock(&xtime_lock);
219
220         /*
221          * clear the interrupt
222          */
223         timer1->TimerClear = 1;
224
225         /*
226          * the clock tick routines are only processed on the
227          * primary CPU
228          */
229         if (hard_smp_processor_id() == 0) {
230                 timer_tick(regs);
231 #ifdef CONFIG_SMP
232                 smp_send_timer();
233 #endif
234         }
235
236 #ifdef CONFIG_SMP
237         /*
238          * this is the ARM equivalent of the APIC timer interrupt
239          */
240         update_process_times(user_mode(regs));
241 #endif /* CONFIG_SMP */
242
243         write_sequnlock(&xtime_lock);
244
245         return IRQ_HANDLED;
246 }
247
248 static struct irqaction integrator_timer_irq = {
249         .name           = "Integrator Timer Tick",
250         .flags          = SA_INTERRUPT,
251         .handler        = integrator_timer_interrupt
252 };
253
254 /*
255  * Set up timer interrupt, and return the current time in seconds.
256  */
257 void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
258 {
259         volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
260         volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
261         volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
262         unsigned int timer_ctrl = 0x80 | 0x40;  /* periodic */
263
264         timer_reload = reload;
265         timer_ctrl |= ctrl;
266
267         if (timer_reload > 0x100000) {
268                 timer_reload >>= 8;
269                 timer_ctrl |= 0x08; /* /256 */
270         } else if (timer_reload > 0x010000) {
271                 timer_reload >>= 4;
272                 timer_ctrl |= 0x04; /* /16 */
273         }
274
275         /*
276          * Initialise to a known state (all timers off)
277          */
278         timer0->TimerControl = 0;
279         timer1->TimerControl = 0;
280         timer2->TimerControl = 0;
281
282         timer1->TimerLoad    = timer_reload;
283         timer1->TimerValue   = timer_reload;
284         timer1->TimerControl = timer_ctrl;
285
286         /*
287          * Make irqs happen for the system timer
288          */
289         setup_irq(IRQ_TIMERINT1, &integrator_timer_irq);
290 }