1/*
2 *  linux/arch/arm/mach-clps7500/core.c
3 *
4 *  Copyright (C) 1998 Russell King
5 *  Copyright (C) 1999 Nexus Electronics Ltd
6 *
7 * Extra MM routines for CL7500 architecture
8 */
9#include <linux/kernel.h>
10#include <linux/types.h>
11#include <linux/interrupt.h>
12#include <linux/irq.h>
13#include <linux/list.h>
14#include <linux/sched.h>
15#include <linux/init.h>
16#include <linux/device.h>
17#include <linux/serial_8250.h>
18
19#include <asm/mach/arch.h>
20#include <asm/mach/map.h>
21#include <asm/mach/irq.h>
22#include <asm/mach/time.h>
23
24#include <asm/hardware.h>
25#include <asm/hardware/iomd.h>
26#include <asm/io.h>
27#include <asm/irq.h>
28#include <asm/mach-types.h>
29
30unsigned int vram_size;
31
32static void cl7500_ack_irq_a(unsigned int irq)
33{
34	unsigned int val, mask;
35
36	mask = 1 << irq;
37	val = iomd_readb(IOMD_IRQMASKA);
38	iomd_writeb(val & ~mask, IOMD_IRQMASKA);
39	iomd_writeb(mask, IOMD_IRQCLRA);
40}
41
42static void cl7500_mask_irq_a(unsigned int irq)
43{
44	unsigned int val, mask;
45
46	mask = 1 << irq;
47	val = iomd_readb(IOMD_IRQMASKA);
48	iomd_writeb(val & ~mask, IOMD_IRQMASKA);
49}
50
51static void cl7500_unmask_irq_a(unsigned int irq)
52{
53	unsigned int val, mask;
54
55	mask = 1 << irq;
56	val = iomd_readb(IOMD_IRQMASKA);
57	iomd_writeb(val | mask, IOMD_IRQMASKA);
58}
59
60static struct irq_chip clps7500_a_chip = {
61	.ack	= cl7500_ack_irq_a,
62	.mask	= cl7500_mask_irq_a,
63	.unmask	= cl7500_unmask_irq_a,
64};
65
66static void cl7500_mask_irq_b(unsigned int irq)
67{
68	unsigned int val, mask;
69
70	mask = 1 << (irq & 7);
71	val = iomd_readb(IOMD_IRQMASKB);
72	iomd_writeb(val & ~mask, IOMD_IRQMASKB);
73}
74
75static void cl7500_unmask_irq_b(unsigned int irq)
76{
77	unsigned int val, mask;
78
79	mask = 1 << (irq & 7);
80	val = iomd_readb(IOMD_IRQMASKB);
81	iomd_writeb(val | mask, IOMD_IRQMASKB);
82}
83
84static struct irq_chip clps7500_b_chip = {
85	.ack	= cl7500_mask_irq_b,
86	.mask	= cl7500_mask_irq_b,
87	.unmask	= cl7500_unmask_irq_b,
88};
89
90static void cl7500_mask_irq_c(unsigned int irq)
91{
92	unsigned int val, mask;
93
94	mask = 1 << (irq & 7);
95	val = iomd_readb(IOMD_IRQMASKC);
96	iomd_writeb(val & ~mask, IOMD_IRQMASKC);
97}
98
99static void cl7500_unmask_irq_c(unsigned int irq)
100{
101	unsigned int val, mask;
102
103	mask = 1 << (irq & 7);
104	val = iomd_readb(IOMD_IRQMASKC);
105	iomd_writeb(val | mask, IOMD_IRQMASKC);
106}
107
108static struct irq_chip clps7500_c_chip = {
109	.ack	= cl7500_mask_irq_c,
110	.mask	= cl7500_mask_irq_c,
111	.unmask	= cl7500_unmask_irq_c,
112};
113
114static void cl7500_mask_irq_d(unsigned int irq)
115{
116	unsigned int val, mask;
117
118	mask = 1 << (irq & 7);
119	val = iomd_readb(IOMD_IRQMASKD);
120	iomd_writeb(val & ~mask, IOMD_IRQMASKD);
121}
122
123static void cl7500_unmask_irq_d(unsigned int irq)
124{
125	unsigned int val, mask;
126
127	mask = 1 << (irq & 7);
128	val = iomd_readb(IOMD_IRQMASKD);
129	iomd_writeb(val | mask, IOMD_IRQMASKD);
130}
131
132static struct irq_chip clps7500_d_chip = {
133	.ack	= cl7500_mask_irq_d,
134	.mask	= cl7500_mask_irq_d,
135	.unmask	= cl7500_unmask_irq_d,
136};
137
138static void cl7500_mask_irq_dma(unsigned int irq)
139{
140	unsigned int val, mask;
141
142	mask = 1 << (irq & 7);
143	val = iomd_readb(IOMD_DMAMASK);
144	iomd_writeb(val & ~mask, IOMD_DMAMASK);
145}
146
147static void cl7500_unmask_irq_dma(unsigned int irq)
148{
149	unsigned int val, mask;
150
151	mask = 1 << (irq & 7);
152	val = iomd_readb(IOMD_DMAMASK);
153	iomd_writeb(val | mask, IOMD_DMAMASK);
154}
155
156static struct irq_chip clps7500_dma_chip = {
157	.ack	= cl7500_mask_irq_dma,
158	.mask	= cl7500_mask_irq_dma,
159	.unmask	= cl7500_unmask_irq_dma,
160};
161
162static void cl7500_mask_irq_fiq(unsigned int irq)
163{
164	unsigned int val, mask;
165
166	mask = 1 << (irq & 7);
167	val = iomd_readb(IOMD_FIQMASK);
168	iomd_writeb(val & ~mask, IOMD_FIQMASK);
169}
170
171static void cl7500_unmask_irq_fiq(unsigned int irq)
172{
173	unsigned int val, mask;
174
175	mask = 1 << (irq & 7);
176	val = iomd_readb(IOMD_FIQMASK);
177	iomd_writeb(val | mask, IOMD_FIQMASK);
178}
179
180static struct irq_chip clps7500_fiq_chip = {
181	.ack	= cl7500_mask_irq_fiq,
182	.mask	= cl7500_mask_irq_fiq,
183	.unmask	= cl7500_unmask_irq_fiq,
184};
185
186static void cl7500_no_action(unsigned int irq)
187{
188}
189
190static struct irq_chip clps7500_no_chip = {
191	.ack	= cl7500_no_action,
192	.mask	= cl7500_no_action,
193	.unmask	= cl7500_no_action,
194};
195
196static struct irqaction irq_isa = { no_action, 0, CPU_MASK_NONE, "isa", NULL, NULL };
197
198static void __init clps7500_init_irq(void)
199{
200	unsigned int irq, flags;
201
202	iomd_writeb(0, IOMD_IRQMASKA);
203	iomd_writeb(0, IOMD_IRQMASKB);
204	iomd_writeb(0, IOMD_FIQMASK);
205	iomd_writeb(0, IOMD_DMAMASK);
206
207	for (irq = 0; irq < NR_IRQS; irq++) {
208		flags = IRQF_VALID;
209
210		if (irq <= 6 || (irq >= 9 && irq <= 15) ||
211		    (irq >= 48 && irq <= 55))
212			flags |= IRQF_PROBE;
213
214		switch (irq) {
215		case 0 ... 7:
216			set_irq_chip(irq, &clps7500_a_chip);
217			set_irq_handler(irq, handle_level_irq);
218			set_irq_flags(irq, flags);
219			break;
220
221		case 8 ... 15:
222			set_irq_chip(irq, &clps7500_b_chip);
223			set_irq_handler(irq, handle_level_irq);
224			set_irq_flags(irq, flags);
225			break;
226
227		case 16 ... 22:
228			set_irq_chip(irq, &clps7500_dma_chip);
229			set_irq_handler(irq, handle_level_irq);
230			set_irq_flags(irq, flags);
231			break;
232
233		case 24 ... 31:
234			set_irq_chip(irq, &clps7500_c_chip);
235			set_irq_handler(irq, handle_level_irq);
236			set_irq_flags(irq, flags);
237			break;
238
239		case 40 ... 47:
240			set_irq_chip(irq, &clps7500_d_chip);
241			set_irq_handler(irq, handle_level_irq);
242			set_irq_flags(irq, flags);
243			break;
244
245		case 48 ... 55:
246			set_irq_chip(irq, &clps7500_no_chip);
247			set_irq_handler(irq, handle_level_irq);
248			set_irq_flags(irq, flags);
249			break;
250
251		case 64 ... 72:
252			set_irq_chip(irq, &clps7500_fiq_chip);
253			set_irq_handler(irq, handle_level_irq);
254			set_irq_flags(irq, flags);
255			break;
256		}
257	}
258
259	setup_irq(IRQ_ISA, &irq_isa);
260}
261
262static struct map_desc cl7500_io_desc[] __initdata = {
263	{ 	/* IO space	*/
264		.virtual	= (unsigned long)IO_BASE,
265		.pfn		= __phys_to_pfn(IO_START),
266		.length		= IO_SIZE,
267		.type		= MT_DEVICE
268	}, {	/* ISA space	*/
269		.virtual	= ISA_BASE,
270		.pfn		= __phys_to_pfn(ISA_START),
271		.length		= ISA_SIZE,
272		.type		= MT_DEVICE
273	}, {	/* Flash	*/
274		.virtual	= FLASH_BASE,
275		.pfn		= __phys_to_pfn(FLASH_START),
276		.length		= FLASH_SIZE,
277		.type		= MT_DEVICE
278	}, {	/* LED		*/
279		.virtual	= LED_BASE,
280		.pfn		= __phys_to_pfn(LED_START),
281		.length		= LED_SIZE,
282		.type		= MT_DEVICE
283	}
284};
285
286static void __init clps7500_map_io(void)
287{
288	iotable_init(cl7500_io_desc, ARRAY_SIZE(cl7500_io_desc));
289}
290
291extern void ioctime_init(void);
292extern unsigned long ioc_timer_gettimeoffset(void);
293
294static irqreturn_t
295clps7500_timer_interrupt(int irq, void *dev_id)
296{
297	write_seqlock(&xtime_lock);
298
299	timer_tick();
300
301	/* Why not using do_leds interface?? */
302	{
303		/* Twinkle the lights. */
304		static int count, state = 0xff00;
305		if (count-- == 0) {
306			state ^= 0x100;
307			count = 25;
308			*((volatile unsigned int *)LED_ADDRESS) = state;
309		}
310	}
311
312	write_sequnlock(&xtime_lock);
313
314	return IRQ_HANDLED;
315}
316
317static struct irqaction clps7500_timer_irq = {
318	.name		= "CLPS7500 Timer Tick",
319	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
320	.handler	= clps7500_timer_interrupt,
321};
322
323/*
324 * Set up timer interrupt.
325 */
326static void __init clps7500_timer_init(void)
327{
328	ioctime_init();
329	setup_irq(IRQ_TIMER, &clps7500_timer_irq);
330}
331
332static struct sys_timer clps7500_timer = {
333	.init		= clps7500_timer_init,
334	.offset		= ioc_timer_gettimeoffset,
335};
336
337static struct plat_serial8250_port serial_platform_data[] = {
338	{
339		.mapbase	= 0x03010fe0,
340		.irq		= 10,
341		.uartclk	= 1843200,
342		.regshift	= 2,
343		.iotype		= UPIO_MEM,
344		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,
345	},
346	{
347		.mapbase	= 0x03010be0,
348		.irq		= 0,
349		.uartclk	= 1843200,
350		.regshift	= 2,
351		.iotype		= UPIO_MEM,
352		.flags		= UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_SKIP_TEST,
353	},
354	{
355		.iobase		= ISASLOT_IO + 0x2e8,
356		.irq		= 41,
357		.uartclk	= 1843200,
358		.regshift	= 0,
359		.iotype		= UPIO_PORT,
360		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
361	},
362	{
363		.iobase		= ISASLOT_IO + 0x3e8,
364		.irq		= 40,
365		.uartclk	= 1843200,
366		.regshift	= 0,
367		.iotype		= UPIO_PORT,
368		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
369	},
370	{ },
371};
372
373static struct platform_device serial_device = {
374	.name			= "serial8250",
375	.id			= PLAT8250_DEV_PLATFORM,
376	.dev			= {
377		.platform_data	= serial_platform_data,
378	},
379};
380
381static void __init clps7500_init(void)
382{
383	platform_device_register(&serial_device);
384}
385
386MACHINE_START(CLPS7500, "CL-PS7500")
387	/* Maintainer: Philip Blundell */
388	.phys_io	= 0x03000000,
389	.io_pg_offst	= ((0xe0000000) >> 18) & 0xfffc,
390	.map_io		= clps7500_map_io,
391	.init_irq	= clps7500_init_irq,
392	.init_machine	= clps7500_init,
393	.timer		= &clps7500_timer,
394MACHINE_END
395