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
34extern unsigned long *_intv_start;
35extern unsigned long *_intv_end;
36
37/* LED access routines.  */
38extern unsigned read_leds (int pos, char *buf, int len);
39extern 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
48void __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
55void 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.  */
62void 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
79void __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.  */
88static 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
101static 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
116/* CompactFlash */
117
118static 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
132static 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
140void __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
158/* RTE-V850E/ME2-CB Programmable Interrupt Controller.  */
159
160static 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 (ARRAY_SIZE(cb_pic_irq_inits) - 1)
174
175static struct hw_interrupt_type cb_pic_hw_itypes[NUM_CB_PIC_IRQ_INITS];
176static unsigned char cb_pic_active_irqs = 0;
177
178void __init rte_me2_cb_init_irqs (void)
179{
180	cb_pic_init_irq_types (cb_pic_irq_inits, cb_pic_hw_itypes);
181
182	/* Initalize on board PIC1 (not PIC0) enable */
183	CB_PIC_INT0M  = 0x0000;
184	CB_PIC_INT1M  = 0x0000;
185	CB_PIC_INTR   = 0x0000;
186	CB_PIC_INTEN |= CB_PIC_INT1EN;
187
188	ME2_PORT2_PMC 	 |= 0x08;	/* INTP23/SCK1 mode */
189	ME2_PORT2_PFC 	 &= ~0x08;	/* INTP23 mode */
190	ME2_INTR(2) 	 &= ~0x08;	/* INTP23 falling-edge detect */
191	ME2_INTF(2) 	 &= ~0x08;	/*   " */
192
193	rte_cb_init_irqs ();	/* gbus &c */
194}
195
196
197/* Enable interrupt handling for interrupt IRQ.  */
198void cb_pic_enable_irq (unsigned irq)
199{
200	CB_PIC_INT1M |= 1 << (irq - CB_PIC_BASE_IRQ);
201}
202
203void cb_pic_disable_irq (unsigned irq)
204{
205	CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
206}
207
208void cb_pic_shutdown_irq (unsigned irq)
209{
210	cb_pic_disable_irq (irq);
211
212	if (--cb_pic_active_irqs == 0)
213		free_irq (IRQ_CB_PIC, 0);
214
215	CB_PIC_INT1M &= ~(1 << (irq - CB_PIC_BASE_IRQ));
216}
217
218static irqreturn_t cb_pic_handle_irq (int irq, void *dev_id,
219				      struct pt_regs *regs)
220{
221	irqreturn_t rval = IRQ_NONE;
222	unsigned status = CB_PIC_INTR;
223	unsigned enable = CB_PIC_INT1M;
224
225	/* Only pay attention to enabled interrupts.  */
226	status &= enable;
227
228	CB_PIC_INTEN &= ~CB_PIC_INT1EN;
229
230	if (status) {
231		unsigned mask = 1;
232
233		irq = CB_PIC_BASE_IRQ;
234		do {
235			/* There's an active interrupt, find out which one,
236			   and call its handler.  */
237			while (! (status & mask)) {
238				irq++;
239				mask <<= 1;
240			}
241			status &= ~mask;
242
243			CB_PIC_INTR = mask;
244
245			/* Recursively call handle_irq to handle it. */
246			handle_irq (irq, regs);
247			rval = IRQ_HANDLED;
248		} while (status);
249	}
250
251	CB_PIC_INTEN |= CB_PIC_INT1EN;
252
253	return rval;
254}
255
256
257static void irq_nop (unsigned irq) { }
258
259static unsigned cb_pic_startup_irq (unsigned irq)
260{
261	int rval;
262
263	if (cb_pic_active_irqs == 0) {
264		rval = request_irq (IRQ_CB_PIC, cb_pic_handle_irq,
265				    IRQF_DISABLED, "cb_pic_handler", 0);
266		if (rval != 0)
267			return rval;
268	}
269
270	cb_pic_active_irqs++;
271
272	cb_pic_enable_irq (irq);
273
274	return 0;
275}
276
277/* Initialize HW_IRQ_TYPES for INTC-controlled irqs described in array
278   INITS (which is terminated by an entry with the name field == 0).  */
279void __init cb_pic_init_irq_types (struct cb_pic_irq_init *inits,
280				   struct hw_interrupt_type *hw_irq_types)
281{
282	struct cb_pic_irq_init *init;
283	for (init = inits; init->name; init++) {
284		struct hw_interrupt_type *hwit = hw_irq_types++;
285
286		hwit->typename = init->name;
287
288		hwit->startup  = cb_pic_startup_irq;
289		hwit->shutdown = cb_pic_shutdown_irq;
290		hwit->enable   = cb_pic_enable_irq;
291		hwit->disable  = cb_pic_disable_irq;
292		hwit->ack      = irq_nop;
293		hwit->end      = irq_nop;
294
295		/* Initialize kernel IRQ infrastructure for this interrupt.  */
296		init_irq_handlers(init->base, init->num, init->interval, hwit);
297	}
298}
299