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