arch-lpd7a40x.c 10.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12
/* arch/arm/mach-lh7a40x/arch-lpd7a40x.c
 *
 *  Copyright (C) 2004 Logic Product Development
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License
 *  version 2 as published by the Free Software Foundation.
 *
 */

#include <linux/tty.h>
#include <linux/init.h>
13
#include <linux/platform_device.h>
L
Linus Torvalds 已提交
14
#include <linux/interrupt.h>
15
#include <linux/irq.h>
L
Linus Torvalds 已提交
16

17
#include <mach/hardware.h>
L
Linus Torvalds 已提交
18 19 20 21 22 23 24 25 26
#include <asm/setup.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/mach/map.h>

#include "common.h"

27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
#define CPLD_INT_NETHERNET	(1<<0)
#define CPLD_INTMASK_ETHERNET	(1<<2)
#if defined (CONFIG_MACH_LPD7A400)
# define CPLD_INT_NTOUCH		(1<<1)
# define CPLD_INTMASK_TOUCH	(1<<3)
# define CPLD_INT_PEN		(1<<4)
# define CPLD_INTMASK_PEN	(1<<4)
# define CPLD_INT_PIRQ		(1<<4)
#endif
#define CPLD_INTMASK_CPLD	(1<<7)
#define CPLD_INT_CPLD		(1<<6)

#define CPLD_CONTROL_SWINT		(1<<7) /* Disable all CPLD IRQs */
#define CPLD_CONTROL_OCMSK		(1<<6) /* Mask USB1 connect IRQ */
#define CPLD_CONTROL_PDRV		(1<<5) /* PCC_nDRV high */
#define CPLD_CONTROL_USB1C		(1<<4) /* USB1 connect IRQ active */
#define CPLD_CONTROL_USB1P		(1<<3) /* USB1 power disable */
#define CPLD_CONTROL_AWKP		(1<<2) /* Auto-wakeup disabled  */
#define CPLD_CONTROL_LCD_ENABLE		(1<<1) /* LCD Vee enable */
#define CPLD_CONTROL_WRLAN_NENABLE	(1<<0) /* SMC91x power disable */


L
Linus Torvalds 已提交
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
static struct resource smc91x_resources[] = {
	[0] = {
		.start	= CPLD00_PHYS,
		.end	= CPLD00_PHYS + CPLD00_SIZE - 1, /* Only needs 16B */
		.flags	= IORESOURCE_MEM,
	},

	[1] = {
		.start	= IRQ_LPD7A40X_ETH_INT,
		.end	= IRQ_LPD7A40X_ETH_INT,
		.flags	= IORESOURCE_IRQ,
	},

};

static struct platform_device smc91x_device = {
	.name		= "smc91x",
	.id		= 0,
	.num_resources	= ARRAY_SIZE(smc91x_resources),
	.resource	= smc91x_resources,
};

static struct resource lh7a40x_usbclient_resources[] = {
	[0] = {
		.start	= USB_PHYS,
74
		.end	= (USB_PHYS + PAGE_SIZE),
L
Linus Torvalds 已提交
75 76 77
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
78 79
		.start	= IRQ_USB,
		.end	= IRQ_USB,
L
Linus Torvalds 已提交
80 81 82 83 84 85 86
		.flags	= IORESOURCE_IRQ,
	},
};

static u64 lh7a40x_usbclient_dma_mask = 0xffffffffUL;

static struct platform_device lh7a40x_usbclient_device = {
87 88
//	.name		= "lh7a40x_udc",
	.name		= "lh7-udc",
L
Linus Torvalds 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127
	.id		= 0,
	.dev		= {
		.dma_mask = &lh7a40x_usbclient_dma_mask,
		.coherent_dma_mask = 0xffffffffUL,
	},
	.num_resources	= ARRAY_SIZE (lh7a40x_usbclient_resources),
	.resource	= lh7a40x_usbclient_resources,
};

#if defined (CONFIG_ARCH_LH7A404)

static struct resource lh7a404_usbhost_resources [] = {
	[0] = {
		.start	= USBH_PHYS,
		.end	= (USBH_PHYS + 0xFF),
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= IRQ_USHINTR,
		.end	= IRQ_USHINTR,
		.flags	= IORESOURCE_IRQ,
	},
};

static u64 lh7a404_usbhost_dma_mask = 0xffffffffUL;

static struct platform_device lh7a404_usbhost_device = {
	.name		= "lh7a404-ohci",
	.id		= 0,
	.dev		= {
		.dma_mask = &lh7a404_usbhost_dma_mask,
		.coherent_dma_mask = 0xffffffffUL,
	},
	.num_resources	= ARRAY_SIZE (lh7a404_usbhost_resources),
	.resource	= lh7a404_usbhost_resources,
};

#endif

128
static struct platform_device* lpd7a40x_devs[] __initdata = {
L
Linus Torvalds 已提交
129 130 131 132 133 134 135 136 137 138 139
	&smc91x_device,
	&lh7a40x_usbclient_device,
#if defined (CONFIG_ARCH_LH7A404)
	&lh7a404_usbhost_device,
#endif
};

extern void lpd7a400_map_io (void);

static void __init lpd7a40x_init (void)
{
140 141 142 143
#if defined (CONFIG_MACH_LPD7A400)
	CPLD_CONTROL |= 0
		| CPLD_CONTROL_SWINT /* Disable software interrupt */
		| CPLD_CONTROL_OCMSK; /* Mask USB1 connection IRQ */
L
Linus Torvalds 已提交
144
	CPLD_CONTROL &= ~(0
145 146
			  | CPLD_CONTROL_LCD_ENABLE	/* Disable LCD */
			  | CPLD_CONTROL_WRLAN_NENABLE	/* Enable SMC91x */
L
Linus Torvalds 已提交
147
		);
148 149 150 151 152 153 154
#endif

#if defined (CONFIG_MACH_LPD7A404)
	CPLD_CONTROL &= ~(0
			  | CPLD_CONTROL_WRLAN_NENABLE	/* Enable SMC91x */
		);
#endif
L
Linus Torvalds 已提交
155 156

	platform_add_devices (lpd7a40x_devs, ARRAY_SIZE (lpd7a40x_devs));
157 158 159
#if defined (CONFIG_FB_ARMCLCD)
        lh7a40x_clcd_init ();
#endif
L
Linus Torvalds 已提交
160 161 162 163
}

static void lh7a40x_ack_cpld_irq (u32 irq)
{
164 165 166
	/* CPLD doesn't have ack capability, but some devices may */

#if defined (CPLD_INTMASK_TOUCH)
M
Matt LaPlante 已提交
167
	/* The touch control *must* mask the interrupt because the
168 169 170 171 172
	 * interrupt bit is read by the driver to determine if the pen
	 * is still down. */
	if (irq == IRQ_TOUCH)
		CPLD_INTERRUPTS |= CPLD_INTMASK_TOUCH;
#endif
L
Linus Torvalds 已提交
173 174 175 176 177 178
}

static void lh7a40x_mask_cpld_irq (u32 irq)
{
	switch (irq) {
	case IRQ_LPD7A40X_ETH_INT:
179
		CPLD_INTERRUPTS |= CPLD_INTMASK_ETHERNET;
L
Linus Torvalds 已提交
180
		break;
181 182 183
#if defined (IRQ_TOUCH)
	case IRQ_TOUCH:
		CPLD_INTERRUPTS |= CPLD_INTMASK_TOUCH;
L
Linus Torvalds 已提交
184
		break;
185
#endif
L
Linus Torvalds 已提交
186 187 188 189 190 191 192
	}
}

static void lh7a40x_unmask_cpld_irq (u32 irq)
{
	switch (irq) {
	case IRQ_LPD7A40X_ETH_INT:
193
		CPLD_INTERRUPTS &= ~CPLD_INTMASK_ETHERNET;
L
Linus Torvalds 已提交
194
		break;
195 196 197
#if defined (IRQ_TOUCH)
	case IRQ_TOUCH:
		CPLD_INTERRUPTS &= ~CPLD_INTMASK_TOUCH;
L
Linus Torvalds 已提交
198
		break;
199
#endif
L
Linus Torvalds 已提交
200 201 202
	}
}

203 204
static struct irq_chip lpd7a40x_cpld_chip = {
	.name	= "CPLD",
L
Linus Torvalds 已提交
205 206 207 208 209
	.ack	= lh7a40x_ack_cpld_irq,
	.mask	= lh7a40x_mask_cpld_irq,
	.unmask	= lh7a40x_unmask_cpld_irq,
};

210
static void lpd7a40x_cpld_handler (unsigned int irq, struct irq_desc *desc)
L
Linus Torvalds 已提交
211 212 213 214 215
{
	unsigned int mask = CPLD_INTERRUPTS;

	desc->chip->ack (irq);

216
	if ((mask & (1<<0)) == 0)	/* WLAN */
217
		generic_handle_irq(IRQ_LPD7A40X_ETH_INT);
L
Linus Torvalds 已提交
218

219 220
#if defined (IRQ_TOUCH)
	if ((mask & (1<<1)) == 0)	/* Touch */
221
		generic_handle_irq(IRQ_TOUCH);
222
#endif
L
Linus Torvalds 已提交
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257

	desc->chip->unmask (irq); /* Level-triggered need this */
}


void __init lh7a40x_init_board_irq (void)
{
	int irq;

		/* Rev A (v2.8): PF0, PF1, PF2, and PF3 are available IRQs.
		                 PF7 supports the CPLD.
		   Rev B (v3.4): PF0, PF1, and PF2 are available IRQs.
		                 PF3 supports the CPLD.
		   (Some) LPD7A404 prerelease boards report a version
		   number of 0x16, but we force an override since the
		   hardware is of the newer variety.
		*/

	unsigned char cpld_version = CPLD_REVISION;
	int pinCPLD = (cpld_version == 0x28) ? 7 : 3;

#if defined CONFIG_MACH_LPD7A404
	cpld_version = 0x34;	/* Coerce LPD7A404 to RevB */
#endif

		/* First, configure user controlled GPIOF interrupts  */

	GPIO_PFDD	&= ~0x0f; /* PF0-3 are inputs */
	GPIO_INTTYPE1	&= ~0x0f; /* PF0-3 are level triggered */
	GPIO_INTTYPE2	&= ~0x0f; /* PF0-3 are active low */
	barrier ();
	GPIO_GPIOFINTEN |=  0x0f; /* Enable PF0, PF1, PF2, and PF3 IRQs */

		/* Then, configure CPLD interrupt */

258 259 260 261 262 263 264 265 266 267 268 269 270
			/* Disable all CPLD interrupts */
#if defined (CONFIG_MACH_LPD7A400)
	CPLD_INTERRUPTS	= CPLD_INTMASK_TOUCH | CPLD_INTMASK_PEN
		| CPLD_INTMASK_ETHERNET;
	/* *** FIXME: don't know why we need 7 and 4. 7 is way wrong
               and 4 is uncefined. */
	// (1<<7)|(1<<4)|(1<<3)|(1<<2);
#endif
#if defined (CONFIG_MACH_LPD7A404)
	CPLD_INTERRUPTS	= CPLD_INTMASK_ETHERNET;
	/* *** FIXME: don't know why we need 6 and 5, neither is defined. */
	// (1<<6)|(1<<5)|(1<<3);
#endif
L
Linus Torvalds 已提交
271
	GPIO_PFDD	&= ~(1 << pinCPLD); /* Make input */
272
	GPIO_INTTYPE1	&= ~(1 << pinCPLD); /* Level triggered */
L
Linus Torvalds 已提交
273 274 275 276 277 278 279 280 281
	GPIO_INTTYPE2	&= ~(1 << pinCPLD); /* Active low */
	barrier ();
	GPIO_GPIOFINTEN |=  (1 << pinCPLD); /* Enable */

		/* Cascade CPLD interrupts */

	for (irq = IRQ_BOARD_START;
	     irq < IRQ_BOARD_START + NR_IRQ_BOARD; ++irq) {
		set_irq_chip (irq, &lpd7a40x_cpld_chip);
282
		set_irq_handler (irq, handle_level_irq);
L
Linus Torvalds 已提交
283 284 285 286 287 288 289 290 291
		set_irq_flags (irq, IRQF_VALID);
	}

	set_irq_chained_handler ((cpld_version == 0x28)
				 ? IRQ_CPLD_V28
				 : IRQ_CPLD_V34,
				 lpd7a40x_cpld_handler);
}

292
static struct map_desc lpd7a40x_io_desc[] __initdata = {
293
	{
294
		.virtual	= IO_VIRT,
295
		.pfn		= __phys_to_pfn(IO_PHYS),
296
		.length		= IO_SIZE,
297
		.type		= MT_DEVICE
298 299
	},
	{	/* Mapping added to work around chip select problems */
300 301 302 303
		.virtual	= IOBARRIER_VIRT,
		.pfn		= __phys_to_pfn(IOBARRIER_PHYS),
		.length		= IOBARRIER_SIZE,
		.type		= MT_DEVICE
304 305
	},
	{
306 307
		.virtual	= CF_VIRT,
		.pfn		= __phys_to_pfn(CF_PHYS),
308
		.length		= CF_SIZE,
309
		.type		= MT_DEVICE
310 311
	},
	{
312 313
		.virtual	= CPLD02_VIRT,
		.pfn		= __phys_to_pfn(CPLD02_PHYS),
314
		.length		= CPLD02_SIZE,
315
		.type		= MT_DEVICE
316 317
	},
	{
318 319
		.virtual	= CPLD06_VIRT,
		.pfn		= __phys_to_pfn(CPLD06_PHYS),
320 321 322 323 324 325 326
		.length		= CPLD06_SIZE,
		.type		= MT_DEVICE
	},
	{
		.virtual	= CPLD08_VIRT,
		.pfn		= __phys_to_pfn(CPLD08_PHYS),
		.length		= CPLD08_SIZE,
327
		.type		= MT_DEVICE
328 329
	},
	{
330 331
		.virtual	= CPLD08_VIRT,
		.pfn		= __phys_to_pfn(CPLD08_PHYS),
332
		.length		= CPLD08_SIZE,
333
		.type		= MT_DEVICE
334 335 336 337 338 339 340 341
	},
	{
		.virtual	= CPLD0A_VIRT,
		.pfn		= __phys_to_pfn(CPLD0A_PHYS),
		.length		= CPLD0A_SIZE,
		.type		= MT_DEVICE
	},
	{
342 343
		.virtual	= CPLD0C_VIRT,
		.pfn		= __phys_to_pfn(CPLD0C_PHYS),
344
		.length		= CPLD0C_SIZE,
345
		.type		= MT_DEVICE
346 347
	},
	{
348 349
		.virtual	= CPLD0E_VIRT,
		.pfn		= __phys_to_pfn(CPLD0E_PHYS),
350
		.length		= CPLD0E_SIZE,
351
		.type		= MT_DEVICE
352 353
	},
	{
354 355
		.virtual	= CPLD10_VIRT,
		.pfn		= __phys_to_pfn(CPLD10_PHYS),
356
		.length		= CPLD10_SIZE,
357
		.type		= MT_DEVICE
358 359
	},
	{
360 361
		.virtual	= CPLD12_VIRT,
		.pfn		= __phys_to_pfn(CPLD12_PHYS),
362
		.length		= CPLD12_SIZE,
363
		.type		= MT_DEVICE
364 365
	},
	{
366 367
		.virtual	= CPLD14_VIRT,
		.pfn		= __phys_to_pfn(CPLD14_PHYS),
368
		.length		= CPLD14_SIZE,
369
		.type		= MT_DEVICE
370 371
	},
	{
372 373
		.virtual	= CPLD16_VIRT,
		.pfn		= __phys_to_pfn(CPLD16_PHYS),
374
		.length		= CPLD16_SIZE,
375
		.type		= MT_DEVICE
376 377
	},
	{
378 379
		.virtual	= CPLD18_VIRT,
		.pfn		= __phys_to_pfn(CPLD18_PHYS),
380
		.length		= CPLD18_SIZE,
381
		.type		= MT_DEVICE
382 383
	},
	{
384 385
		.virtual	= CPLD1A_VIRT,
		.pfn		= __phys_to_pfn(CPLD1A_PHYS),
386
		.length		= CPLD1A_SIZE,
387 388
		.type		= MT_DEVICE
	},
L
Linus Torvalds 已提交
389 390 391
};

void __init
392
lpd7a40x_map_io(void)
L
Linus Torvalds 已提交
393
{
394
	iotable_init (lpd7a40x_io_desc, ARRAY_SIZE (lpd7a40x_io_desc));
L
Linus Torvalds 已提交
395 396 397 398 399
}

#ifdef CONFIG_MACH_LPD7A400

MACHINE_START (LPD7A400, "Logic Product Development LPD7A400-10")
400 401 402 403
	/* Maintainer: Marc Singer */
	.phys_io	= 0x80000000,
	.io_pg_offst	= ((io_p2v (0x80000000))>>18) & 0xfffc,
	.boot_params	= 0xc0000100,
404
	.map_io		= lpd7a40x_map_io,
405
	.init_irq	= lh7a400_init_irq,
L
Linus Torvalds 已提交
406
	.timer		= &lh7a40x_timer,
407
	.init_machine	= lpd7a40x_init,
L
Linus Torvalds 已提交
408 409 410 411 412 413 414
MACHINE_END

#endif

#ifdef CONFIG_MACH_LPD7A404

MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10")
415 416 417 418
	/* Maintainer: Marc Singer */
	.phys_io	= 0x80000000,
	.io_pg_offst	= ((io_p2v (0x80000000))>>18) & 0xfffc,
	.boot_params	= 0xc0000100,
419
	.map_io		= lpd7a40x_map_io,
420
	.init_irq	= lh7a404_init_irq,
L
Linus Torvalds 已提交
421
	.timer		= &lh7a40x_timer,
422
	.init_machine	= lpd7a40x_init,
L
Linus Torvalds 已提交
423 424 425
MACHINE_END

#endif