Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-mmc
[sfrench/cifs-2.6.git] / arch / v850 / kernel / rte_me2_cb.c
1 /*
2  * arch/v850/kernel/rte_me2_cb.c -- Midas labs RTE-V850E/ME2-CB board
3  *
4  *  Copyright (C) 2001,02,03  NEC Electronics Corporation
5  *  Copyright (C) 2001,02,03  Miles Bader <miles@gnu.org>
6  *
7  * This file is subject to the terms and conditions of the GNU General
8  * Public License.  See the file COPYING in the main directory of this
9  * archive for more details.
10  *
11  * Written by Miles Bader <miles@gnu.org>
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/init.h>
16 #include <linux/bootmem.h>
17 #include <linux/irq.h>
18 #include <linux/fs.h>
19 #include <linux/major.h>
20 #include <linux/sched.h>
21 #include <linux/delay.h>
22
23 #include <asm/atomic.h>
24 #include <asm/page.h>
25 #include <asm/me2.h>
26 #include <asm/rte_me2_cb.h>
27 #include <asm/machdep.h>
28 #include <asm/v850e_intc.h>
29 #include <asm/v850e_cache.h>
30 #include <asm/irq.h>
31
32 #include "mach.h"
33
34 extern unsigned long *_intv_start;
35 extern unsigned long *_intv_end;
36
37 /* LED access routines.  */
38 extern unsigned read_leds (int pos, char *buf, int len);
39 extern unsigned write_leds (int pos, const char *buf, int len);
40
41
42 /* SDRAM are almost contiguous (with a small hole in between;
43    see mach_reserve_bootmem for details), so just use both as one big area.  */
44 #define RAM_START       SDRAM_ADDR
45 #define RAM_END         (SDRAM_ADDR + SDRAM_SIZE)
46
47
48 void __init mach_get_physical_ram (unsigned long *ram_start,
49                                    unsigned long *ram_len)
50 {
51         *ram_start = RAM_START;
52         *ram_len = RAM_END - RAM_START;
53 }
54
55 void mach_gettimeofday (struct timespec *tv)
56 {
57         tv->tv_sec = 0;
58         tv->tv_nsec = 0;
59 }
60
61 /* Called before configuring an on-chip UART.  */
62 void rte_me2_cb_uart_pre_configure (unsigned chan,
63                                     unsigned cflags, unsigned baud)
64 {
65         /* The RTE-V850E/ME2-CB connects some general-purpose I/O
66            pins on the CPU to the RTS/CTS lines of UARTB channel 0's
67            serial connection.
68            I/O pins P21 and P22 are RTS and CTS respectively.  */
69         if (chan == 0) {
70                 /* Put P21 & P22 in I/O port mode.  */
71                 ME2_PORT2_PMC &= ~0x6;
72                 /* Make P21 and output, and P22 an input.  */
73                 ME2_PORT2_PM = (ME2_PORT2_PM & ~0xC) | 0x4;
74         }
75
76         me2_uart_pre_configure (chan, cflags, baud);
77 }
78
79 void __init mach_init_irqs (void)
80 {
81         /* Initialize interrupts.  */
82         me2_init_irqs ();
83         rte_me2_cb_init_irqs ();
84 }
85
86 #ifdef CONFIG_ROM_KERNEL
87 /* Initialization for kernel in ROM.  */
88 static inline rom_kernel_init (void)
89 {
90         /* If the kernel is in ROM, we have to copy any initialized data
91            from ROM into RAM.  */
92         extern unsigned long _data_load_start, _sdata, _edata;
93         register unsigned long *src = &_data_load_start;
94         register unsigned long *dst = &_sdata, *end = &_edata;
95
96         while (dst != end)
97                 *dst++ = *src++;
98 }
99 #endif /* CONFIG_ROM_KERNEL */
100
101 static void install_interrupt_vectors (void)
102 {
103         unsigned long *p1, *p2;
104
105         ME2_IRAMM = 0x03; /* V850E/ME2 iRAM write mode */
106
107         /* vector copy to iRAM */
108         p1 = (unsigned long *)0; /* v85x vector start */
109         p2 = (unsigned long *)&_intv_start;
110         while (p2 < (unsigned long *)&_intv_end)
111                 *p1++ = *p2++;
112
113         ME2_IRAMM = 0x00; /* V850E/ME2 iRAM read mode */
114 }
115 \f
116 /* CompactFlash */
117
118 static void cf_power_on (void)
119 {
120         /* CF card detected? */
121         if (CB_CF_STS0 & 0x0030)
122                 return;
123
124         CB_CF_REG0 = 0x0002; /* reest on */
125         mdelay (10);
126         CB_CF_REG0 = 0x0003; /* power on */
127         mdelay (10);
128         CB_CF_REG0 = 0x0001; /* reset off */
129         mdelay (10);
130 }
131
132 static void cf_power_off (void)
133 {
134         CB_CF_REG0 = 0x0003; /* power on */
135         mdelay (10);
136         CB_CF_REG0 = 0x0002; /* reest on */
137         mdelay (10);
138 }
139
140 void __init mach_early_init (void)
141 {
142         install_interrupt_vectors ();
143
144         /* CS1 SDRAM instruction cache enable */
145         v850e_cache_enable (0x04, 0x03, 0);
146
147         rte_cb_early_init ();
148
149         /* CompactFlash power on */
150         cf_power_on ();
151
152 #if defined (CONFIG_ROM_KERNEL)
153         rom_kernel_init ();
154 #endif
155 }
156
157 \f
158 /* RTE-V850E/ME2-CB Programmable Interrupt Controller.  */
159
160 static struct cb_pic_irq_init cb_pic_irq_inits[] = {
161         { "CB_EXTTM0",       IRQ_CB_EXTTM0,       1, 1, 6 },
162         { "CB_EXTSIO",       IRQ_CB_EXTSIO,       1, 1, 6 },
163         { "CB_TOVER",        IRQ_CB_TOVER,        1, 1, 6 },
164         { "CB_GINT0",        IRQ_CB_GINT0,        1, 1, 6 },
165         { "CB_USB",          IRQ_CB_USB,          1, 1, 6 },
166         { "CB_LANC",         IRQ_CB_LANC,         1, 1, 6 },
167         { "CB_USB_VBUS_ON",  IRQ_CB_USB_VBUS_ON,  1, 1, 6 },
168         { "CB_USB_VBUS_OFF", IRQ_CB_USB_VBUS_OFF, 1, 1, 6 },
169         { "CB_EXTTM1",       IRQ_CB_EXTTM1,       1, 1, 6 },
170         { "CB_EXTTM2",       IRQ_CB_EXTTM2,       1, 1, 6 },
171         { 0 }
172 };
173 #define NUM_CB_PIC_IRQ_INITS  \
174    ((sizeof cb_pic_irq_inits / sizeof cb_pic_irq_inits[0]) - 1)
175
176 static struct hw_interrupt_type cb_pic_hw_itypes[NUM_CB_PIC_IRQ_INITS];
177 static unsigned char cb_pic_active_irqs = 0;
178
179 void __init rte_me2_cb_init_irqs (void)
180 {
181         cb_pic_init_irq_types (cb_pic_irq_inits, cb_pic_hw_itypes);
182
183         /* Initalize on board PIC1 (not PIC0) enable */
184         CB_PIC_INT0M  = 0x0000;
185         CB_PIC_INT1M  = 0x0000;
186         CB_PIC_INTR   = 0x0000;
187         CB_PIC_INTEN |= CB_PIC_INT1EN;
188
189         ME2_PORT2_PMC    |= 0x08;       /* INTP23/SCK1 mode */
190         ME2_PORT2_PFC    &= ~0x08;      /* INTP23 mode */
191         ME2_INTR(2)      &= ~0x08;      /* INTP23 falling-edge detect */
192         ME2_INTF(2)      &= ~0x08;      /*   " */
193
194         rte_cb_init_irqs ();    /* gbus &c */
195 }
196
197
198 /* Enable interrupt handling for interrupt IRQ.  */
199 void cb_pic_enable_irq (unsigned irq)
200 {
201         CB_PIC_INT1M |= 1 << (irq - CB_PIC_BASE_IRQ);
202 }
203
204 void cb_pic_disable_irq (unsigned irq)
205 {
206         CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
207 }
208
209 void cb_pic_shutdown_irq (unsigned irq)
210 {
211         cb_pic_disable_irq (irq);
212
213         if (--cb_pic_active_irqs == 0)
214                 free_irq (IRQ_CB_PIC, 0);
215
216         CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
217 }
218
219 static irqreturn_t cb_pic_handle_irq (int irq, void *dev_id,
220                                       struct pt_regs *regs)
221 {
222         irqreturn_t rval = IRQ_NONE;
223         unsigned status = CB_PIC_INTR;
224         unsigned enable = CB_PIC_INT1M;
225
226         /* Only pay attention to enabled interrupts.  */
227         status &= enable;
228
229         CB_PIC_INTEN &= ~CB_PIC_INT1EN;
230
231         if (status) {
232                 unsigned mask = 1;
233
234                 irq = CB_PIC_BASE_IRQ;
235                 do {
236                         /* There's an active interrupt, find out which one,
237                            and call its handler.  */
238                         while (! (status & mask)) {
239                                 irq++;
240                                 mask <<= 1;
241                         }
242                         status &= ~mask;
243
244                         CB_PIC_INTR = mask;
245
246                         /* Recursively call handle_irq to handle it. */
247                         handle_irq (irq, regs);
248                         rval = IRQ_HANDLED;
249                 } while (status);
250         }
251
252         CB_PIC_INTEN |= CB_PIC_INT1EN;
253
254         return rval;
255 }
256
257 \f
258 static void irq_nop (unsigned irq) { }
259
260 static unsigned cb_pic_startup_irq (unsigned irq)
261 {
262         int rval;
263
264         if (cb_pic_active_irqs == 0) {
265                 rval = request_irq (IRQ_CB_PIC, cb_pic_handle_irq,
266                                     IRQF_DISABLED, "cb_pic_handler", 0);
267                 if (rval != 0)
268                         return rval;
269         }
270
271         cb_pic_active_irqs++;
272
273         cb_pic_enable_irq (irq);
274
275         return 0;
276 }
277
278 /* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
279    INITS (which is terminated by an entry with the name field == 0).  */
280 void __init cb_pic_init_irq_types (struct cb_pic_irq_init *inits,
281                                    struct hw_interrupt_type *hw_irq_types)
282 {
283         struct cb_pic_irq_init *init;
284         for (init = inits; init->name; init++) {
285                 struct hw_interrupt_type *hwit = hw_irq_types++;
286
287                 hwit->typename = init->name;
288
289                 hwit->startup  = cb_pic_startup_irq;
290                 hwit->shutdown = cb_pic_shutdown_irq;
291                 hwit->enable   = cb_pic_enable_irq;
292                 hwit->disable  = cb_pic_disable_irq;
293                 hwit->ack      = irq_nop;
294                 hwit->end      = irq_nop;
295
296                 /* Initialize kernel IRQ infrastructure for this interrupt.  */
297                 init_irq_handlers(init->base, init->num, init->interval, hwit);
298         }
299 }