1/* arch/arm/mach-lh7a40x/arch-lpd7a40x.c
2 *
3 *  Copyright (C) 2004 Logic Product Development
4 *
5 *  This program is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU General Public License
7 *  version 2 as published by the Free Software Foundation.
8 *
9 */
10
11#include <linux/tty.h>
12#include <linux/init.h>
13#include <linux/platform_device.h>
14#include <linux/interrupt.h>
15#include <linux/irq.h>
16
17#include <asm/hardware.h>
18#include <asm/setup.h>
19#include <asm/mach-types.h>
20#include <asm/mach/arch.h>
21#include <asm/irq.h>
22#include <asm/mach/irq.h>
23#include <asm/mach/map.h>
24
25#include "common.h"
26
27#define CPLD_INT_NETHERNET	(1<<0)
28#define CPLD_INTMASK_ETHERNET	(1<<2)
29#if defined(CONFIG_MACH_LPD7A400)
30# define CPLD_INT_NTOUCH		(1<<1)
31# define CPLD_INTMASK_TOUCH	(1<<3)
32# define CPLD_INT_PEN		(1<<4)
33# define CPLD_INTMASK_PEN	(1<<4)
34# define CPLD_INT_PIRQ		(1<<4)
35#endif
36#define CPLD_INTMASK_CPLD	(1<<7)
37#define CPLD_INT_CPLD		(1<<6)
38
39#define CPLD_CONTROL_SWINT		(1<<7) /* Disable all CPLD IRQs */
40#define CPLD_CONTROL_OCMSK		(1<<6) /* Mask USB1 connect IRQ */
41#define CPLD_CONTROL_PDRV		(1<<5) /* PCC_nDRV high */
42#define CPLD_CONTROL_USB1C		(1<<4) /* USB1 connect IRQ active */
43#define CPLD_CONTROL_USB1P		(1<<3) /* USB1 power disable */
44#define CPLD_CONTROL_AWKP		(1<<2) /* Auto-wakeup disabled  */
45#define CPLD_CONTROL_LCD_ENABLE		(1<<1) /* LCD Vee enable */
46#define CPLD_CONTROL_WRLAN_NENABLE	(1<<0) /* SMC91x power disable */
47
48
49static struct resource smc91x_resources[] = {
50	[0] = {
51		.start	= CPLD00_PHYS,
52		.end	= CPLD00_PHYS + CPLD00_SIZE - 1, /* Only needs 16B */
53		.flags	= IORESOURCE_MEM,
54	},
55
56	[1] = {
57		.start	= IRQ_LPD7A40X_ETH_INT,
58		.end	= IRQ_LPD7A40X_ETH_INT,
59		.flags	= IORESOURCE_IRQ,
60	},
61
62};
63
64static struct platform_device smc91x_device = {
65	.name		= "smc91x",
66	.id		= 0,
67	.num_resources	= ARRAY_SIZE(smc91x_resources),
68	.resource	= smc91x_resources,
69};
70
71static struct resource lh7a40x_usbclient_resources[] = {
72	[0] = {
73		.start	= USB_PHYS,
74		.end	= (USB_PHYS + PAGE_SIZE),
75		.flags	= IORESOURCE_MEM,
76	},
77	[1] = {
78		.start	= IRQ_USB,
79		.end	= IRQ_USB,
80		.flags	= IORESOURCE_IRQ,
81	},
82};
83
84static u64 lh7a40x_usbclient_dma_mask = 0xffffffffUL;
85
86static struct platform_device lh7a40x_usbclient_device = {
87//	.name		= "lh7a40x_udc",
88	.name		= "lh7-udc",
89	.id		= 0,
90	.dev		= {
91		.dma_mask = &lh7a40x_usbclient_dma_mask,
92		.coherent_dma_mask = 0xffffffffUL,
93	},
94	.num_resources	= ARRAY_SIZE (lh7a40x_usbclient_resources),
95	.resource	= lh7a40x_usbclient_resources,
96};
97
98#if defined(CONFIG_ARCH_LH7A404)
99
100static struct resource lh7a404_usbhost_resources [] = {
101	[0] = {
102		.start	= USBH_PHYS,
103		.end	= (USBH_PHYS + 0xFF),
104		.flags	= IORESOURCE_MEM,
105	},
106	[1] = {
107		.start	= IRQ_USHINTR,
108		.end	= IRQ_USHINTR,
109		.flags	= IORESOURCE_IRQ,
110	},
111};
112
113static u64 lh7a404_usbhost_dma_mask = 0xffffffffUL;
114
115static struct platform_device lh7a404_usbhost_device = {
116	.name		= "lh7a404-ohci",
117	.id		= 0,
118	.dev		= {
119		.dma_mask = &lh7a404_usbhost_dma_mask,
120		.coherent_dma_mask = 0xffffffffUL,
121	},
122	.num_resources	= ARRAY_SIZE (lh7a404_usbhost_resources),
123	.resource	= lh7a404_usbhost_resources,
124};
125
126#endif
127
128static struct platform_device* lpd7a40x_devs[] __initdata = {
129	&smc91x_device,
130	&lh7a40x_usbclient_device,
131#if defined(CONFIG_ARCH_LH7A404)
132	&lh7a404_usbhost_device,
133#endif
134};
135
136extern void lpd7a400_map_io (void);
137
138static void __init lpd7a40x_init (void)
139{
140#if defined(CONFIG_MACH_LPD7A400)
141	CPLD_CONTROL |= 0
142		| CPLD_CONTROL_SWINT /* Disable software interrupt */
143		| CPLD_CONTROL_OCMSK; /* Mask USB1 connection IRQ */
144	CPLD_CONTROL &= ~(0
145			  | CPLD_CONTROL_LCD_ENABLE	/* Disable LCD */
146			  | CPLD_CONTROL_WRLAN_NENABLE	/* Enable SMC91x */
147		);
148#endif
149
150#if defined(CONFIG_MACH_LPD7A404)
151	CPLD_CONTROL &= ~(0
152			  | CPLD_CONTROL_WRLAN_NENABLE	/* Enable SMC91x */
153		);
154#endif
155
156	platform_add_devices (lpd7a40x_devs, ARRAY_SIZE (lpd7a40x_devs));
157#if defined(CONFIG_FB_ARMCLCD)
158        lh7a40x_clcd_init ();
159#endif
160}
161
162static void lh7a40x_ack_cpld_irq (u32 irq)
163{
164	/* CPLD doesn't have ack capability, but some devices may */
165
166#if defined(CPLD_INTMASK_TOUCH)
167	/* The touch control *must* mask the interrupt because the
168	 * interrupt bit is read by the driver to determine if the pen
169	 * is still down. */
170	if (irq == IRQ_TOUCH)
171		CPLD_INTERRUPTS |= CPLD_INTMASK_TOUCH;
172#endif
173}
174
175static void lh7a40x_mask_cpld_irq (u32 irq)
176{
177	switch (irq) {
178	case IRQ_LPD7A40X_ETH_INT:
179		CPLD_INTERRUPTS |= CPLD_INTMASK_ETHERNET;
180		break;
181#if defined(IRQ_TOUCH)
182	case IRQ_TOUCH:
183		CPLD_INTERRUPTS |= CPLD_INTMASK_TOUCH;
184		break;
185#endif
186	}
187}
188
189static void lh7a40x_unmask_cpld_irq (u32 irq)
190{
191	switch (irq) {
192	case IRQ_LPD7A40X_ETH_INT:
193		CPLD_INTERRUPTS &= ~CPLD_INTMASK_ETHERNET;
194		break;
195#if defined(IRQ_TOUCH)
196	case IRQ_TOUCH:
197		CPLD_INTERRUPTS &= ~CPLD_INTMASK_TOUCH;
198		break;
199#endif
200	}
201}
202
203static struct irq_chip lpd7a40x_cpld_chip = {
204	.name	= "CPLD",
205	.ack	= lh7a40x_ack_cpld_irq,
206	.mask	= lh7a40x_mask_cpld_irq,
207	.unmask	= lh7a40x_unmask_cpld_irq,
208};
209
210static void lpd7a40x_cpld_handler (unsigned int irq, struct irq_desc *desc)
211{
212	unsigned int mask = CPLD_INTERRUPTS;
213
214	desc->chip->ack (irq);
215
216	if ((mask & (1<<0)) == 0)	/* WLAN */
217		IRQ_DISPATCH (IRQ_LPD7A40X_ETH_INT);
218
219#if defined(IRQ_TOUCH)
220	if ((mask & (1<<1)) == 0)	/* Touch */
221		IRQ_DISPATCH (IRQ_TOUCH);
222#endif
223
224	desc->chip->unmask (irq); /* Level-triggered need this */
225}
226
227
228void __init lh7a40x_init_board_irq (void)
229{
230	int irq;
231
232		/* Rev A (v2.8): PF0, PF1, PF2, and PF3 are available IRQs.
233		                 PF7 supports the CPLD.
234		   Rev B (v3.4): PF0, PF1, and PF2 are available IRQs.
235		                 PF3 supports the CPLD.
236		   (Some) LPD7A404 prerelease boards report a version
237		   number of 0x16, but we force an override since the
238		   hardware is of the newer variety.
239		*/
240
241	unsigned char cpld_version = CPLD_REVISION;
242	int pinCPLD = (cpld_version == 0x28) ? 7 : 3;
243
244#if defined CONFIG_MACH_LPD7A404
245	cpld_version = 0x34;	/* Coerce LPD7A404 to RevB */
246#endif
247
248		/* First, configure user controlled GPIOF interrupts  */
249
250	GPIO_PFDD	&= ~0x0f; /* PF0-3 are inputs */
251	GPIO_INTTYPE1	&= ~0x0f; /* PF0-3 are level triggered */
252	GPIO_INTTYPE2	&= ~0x0f; /* PF0-3 are active low */
253	barrier ();
254	GPIO_GPIOFINTEN |=  0x0f; /* Enable PF0, PF1, PF2, and PF3 IRQs */
255
256		/* Then, configure CPLD interrupt */
257
258			/* Disable all CPLD interrupts */
259#if defined(CONFIG_MACH_LPD7A400)
260	CPLD_INTERRUPTS	= CPLD_INTMASK_TOUCH | CPLD_INTMASK_PEN
261		| CPLD_INTMASK_ETHERNET;
262	// (1<<7)|(1<<4)|(1<<3)|(1<<2);
263#endif
264#if defined(CONFIG_MACH_LPD7A404)
265	CPLD_INTERRUPTS	= CPLD_INTMASK_ETHERNET;
266	// (1<<6)|(1<<5)|(1<<3);
267#endif
268	GPIO_PFDD	&= ~(1 << pinCPLD); /* Make input */
269	GPIO_INTTYPE1	&= ~(1 << pinCPLD); /* Level triggered */
270	GPIO_INTTYPE2	&= ~(1 << pinCPLD); /* Active low */
271	barrier ();
272	GPIO_GPIOFINTEN |=  (1 << pinCPLD); /* Enable */
273
274		/* Cascade CPLD interrupts */
275
276	for (irq = IRQ_BOARD_START;
277	     irq < IRQ_BOARD_START + NR_IRQ_BOARD; ++irq) {
278		set_irq_chip (irq, &lpd7a40x_cpld_chip);
279		set_irq_handler (irq, handle_level_irq);
280		set_irq_flags (irq, IRQF_VALID);
281	}
282
283	set_irq_chained_handler ((cpld_version == 0x28)
284				 ? IRQ_CPLD_V28
285				 : IRQ_CPLD_V34,
286				 lpd7a40x_cpld_handler);
287}
288
289static struct map_desc lpd7a40x_io_desc[] __initdata = {
290	{
291		.virtual	= IO_VIRT,
292		.pfn		= __phys_to_pfn(IO_PHYS),
293		.length		= IO_SIZE,
294		.type		= MT_DEVICE
295	},
296	{
297		.virtual	= IOBARRIER_VIRT,
298		.pfn		= __phys_to_pfn(IOBARRIER_PHYS),
299		.length		= IOBARRIER_SIZE,
300		.type		= MT_DEVICE
301	},
302	{
303		.virtual	= CF_VIRT,
304		.pfn		= __phys_to_pfn(CF_PHYS),
305		.length		= CF_SIZE,
306		.type		= MT_DEVICE
307	},
308	{
309		.virtual	= CPLD02_VIRT,
310		.pfn		= __phys_to_pfn(CPLD02_PHYS),
311		.length		= CPLD02_SIZE,
312		.type		= MT_DEVICE
313	},
314	{
315		.virtual	= CPLD06_VIRT,
316		.pfn		= __phys_to_pfn(CPLD06_PHYS),
317		.length		= CPLD06_SIZE,
318		.type		= MT_DEVICE
319	},
320	{
321		.virtual	= CPLD08_VIRT,
322		.pfn		= __phys_to_pfn(CPLD08_PHYS),
323		.length		= CPLD08_SIZE,
324		.type		= MT_DEVICE
325	},
326	{
327		.virtual	= CPLD08_VIRT,
328		.pfn		= __phys_to_pfn(CPLD08_PHYS),
329		.length		= CPLD08_SIZE,
330		.type		= MT_DEVICE
331	},
332	{
333		.virtual	= CPLD0A_VIRT,
334		.pfn		= __phys_to_pfn(CPLD0A_PHYS),
335		.length		= CPLD0A_SIZE,
336		.type		= MT_DEVICE
337	},
338	{
339		.virtual	= CPLD0C_VIRT,
340		.pfn		= __phys_to_pfn(CPLD0C_PHYS),
341		.length		= CPLD0C_SIZE,
342		.type		= MT_DEVICE
343	},
344	{
345		.virtual	= CPLD0E_VIRT,
346		.pfn		= __phys_to_pfn(CPLD0E_PHYS),
347		.length		= CPLD0E_SIZE,
348		.type		= MT_DEVICE
349	},
350	{
351		.virtual	= CPLD10_VIRT,
352		.pfn		= __phys_to_pfn(CPLD10_PHYS),
353		.length		= CPLD10_SIZE,
354		.type		= MT_DEVICE
355	},
356	{
357		.virtual	= CPLD12_VIRT,
358		.pfn		= __phys_to_pfn(CPLD12_PHYS),
359		.length		= CPLD12_SIZE,
360		.type		= MT_DEVICE
361	},
362	{
363		.virtual	= CPLD14_VIRT,
364		.pfn		= __phys_to_pfn(CPLD14_PHYS),
365		.length		= CPLD14_SIZE,
366		.type		= MT_DEVICE
367	},
368	{
369		.virtual	= CPLD16_VIRT,
370		.pfn		= __phys_to_pfn(CPLD16_PHYS),
371		.length		= CPLD16_SIZE,
372		.type		= MT_DEVICE
373	},
374	{
375		.virtual	= CPLD18_VIRT,
376		.pfn		= __phys_to_pfn(CPLD18_PHYS),
377		.length		= CPLD18_SIZE,
378		.type		= MT_DEVICE
379	},
380	{
381		.virtual	= CPLD1A_VIRT,
382		.pfn		= __phys_to_pfn(CPLD1A_PHYS),
383		.length		= CPLD1A_SIZE,
384		.type		= MT_DEVICE
385	},
386};
387
388void __init
389lpd7a40x_map_io(void)
390{
391	iotable_init (lpd7a40x_io_desc, ARRAY_SIZE (lpd7a40x_io_desc));
392}
393
394#ifdef CONFIG_MACH_LPD7A400
395
396MACHINE_START (LPD7A400, "Logic Product Development LPD7A400-10")
397	/* Maintainer: Marc Singer */
398	.phys_io	= 0x80000000,
399	.io_pg_offst	= ((io_p2v (0x80000000))>>18) & 0xfffc,
400	.boot_params	= 0xc0000100,
401	.map_io		= lpd7a40x_map_io,
402	.init_irq	= lh7a400_init_irq,
403	.timer		= &lh7a40x_timer,
404	.init_machine	= lpd7a40x_init,
405MACHINE_END
406
407#endif
408
409#ifdef CONFIG_MACH_LPD7A404
410
411MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10")
412	/* Maintainer: Marc Singer */
413	.phys_io	= 0x80000000,
414	.io_pg_offst	= ((io_p2v (0x80000000))>>18) & 0xfffc,
415	.boot_params	= 0xc0000100,
416	.map_io		= lpd7a40x_map_io,
417	.init_irq	= lh7a404_init_irq,
418	.timer		= &lh7a40x_timer,
419	.init_machine	= lpd7a40x_init,
420MACHINE_END
421
422#endif
423