1/* 2 * arch/arm/mach-ixp23xx/ixdp2351.c 3 * 4 * IXDP2351 board-specific routines 5 * 6 * Author: Deepak Saxena <dsaxena@plexity.net> 7 * 8 * Copyright 2005 (c) MontaVista Software, Inc. 9 * 10 * Based on 2.4 code Copyright 2004 (c) Intel Corporation 11 * 12 * This file is licensed under the terms of the GNU General Public 13 * License version 2. This program is licensed "as is" without any 14 * warranty of any kind, whether express or implied. 15 */ 16 17#include <linux/kernel.h> 18#include <linux/init.h> 19#include <linux/spinlock.h> 20#include <linux/sched.h> 21#include <linux/interrupt.h> 22#include <linux/irq.h> 23#include <linux/serial.h> 24#include <linux/tty.h> 25#include <linux/bitops.h> 26#include <linux/ioport.h> 27#include <linux/serial.h> 28#include <linux/serial_8250.h> 29#include <linux/serial_core.h> 30#include <linux/device.h> 31#include <linux/mm.h> 32#include <linux/pci.h> 33#include <linux/mtd/physmap.h> 34 35#include <asm/types.h> 36#include <asm/setup.h> 37#include <asm/memory.h> 38#include <asm/hardware.h> 39#include <asm/mach-types.h> 40#include <asm/system.h> 41#include <asm/tlbflush.h> 42#include <asm/pgtable.h> 43 44#include <asm/mach/map.h> 45#include <asm/mach/irq.h> 46#include <asm/mach/arch.h> 47#include <asm/mach/irq.h> 48#include <asm/mach/pci.h> 49 50/* 51 * IXDP2351 Interrupt Handling 52 */ 53static void ixdp2351_inta_mask(unsigned int irq) 54{ 55 *IXDP2351_CPLD_INTA_MASK_SET_REG = IXDP2351_INTA_IRQ_MASK(irq); 56} 57 58static void ixdp2351_inta_unmask(unsigned int irq) 59{ 60 *IXDP2351_CPLD_INTA_MASK_CLR_REG = IXDP2351_INTA_IRQ_MASK(irq); 61} 62 63static void ixdp2351_inta_handler(unsigned int irq, struct irq_desc *desc) 64{ 65 u16 ex_interrupt = 66 *IXDP2351_CPLD_INTA_STAT_REG & IXDP2351_INTA_IRQ_VALID; 67 int i; 68 69 desc->chip->mask(irq); 70 71 for (i = 0; i < IXDP2351_INTA_IRQ_NUM; i++) { 72 if (ex_interrupt & (1 << i)) { 73 struct irq_desc *cpld_desc; 74 int cpld_irq = 75 IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + i); 76 cpld_desc = irq_desc + cpld_irq; 77 desc_handle_irq(cpld_irq, cpld_desc); 78 } 79 } 80 81 desc->chip->unmask(irq); 82} 83 84static struct irq_chip ixdp2351_inta_chip = { 85 .ack = ixdp2351_inta_mask, 86 .mask = ixdp2351_inta_mask, 87 .unmask = ixdp2351_inta_unmask 88}; 89 90static void ixdp2351_intb_mask(unsigned int irq) 91{ 92 *IXDP2351_CPLD_INTB_MASK_SET_REG = IXDP2351_INTB_IRQ_MASK(irq); 93} 94 95static void ixdp2351_intb_unmask(unsigned int irq) 96{ 97 *IXDP2351_CPLD_INTB_MASK_CLR_REG = IXDP2351_INTB_IRQ_MASK(irq); 98} 99 100static void ixdp2351_intb_handler(unsigned int irq, struct irq_desc *desc) 101{ 102 u16 ex_interrupt = 103 *IXDP2351_CPLD_INTB_STAT_REG & IXDP2351_INTB_IRQ_VALID; 104 int i; 105 106 desc->chip->ack(irq); 107 108 for (i = 0; i < IXDP2351_INTB_IRQ_NUM; i++) { 109 if (ex_interrupt & (1 << i)) { 110 struct irq_desc *cpld_desc; 111 int cpld_irq = 112 IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + i); 113 cpld_desc = irq_desc + cpld_irq; 114 desc_handle_irq(cpld_irq, cpld_desc); 115 } 116 } 117 118 desc->chip->unmask(irq); 119} 120 121static struct irq_chip ixdp2351_intb_chip = { 122 .ack = ixdp2351_intb_mask, 123 .mask = ixdp2351_intb_mask, 124 .unmask = ixdp2351_intb_unmask 125}; 126 127void __init ixdp2351_init_irq(void) 128{ 129 int irq; 130 131 /* Mask all interrupts from CPLD, disable simulation */ 132 *IXDP2351_CPLD_INTA_MASK_SET_REG = (u16) -1; 133 *IXDP2351_CPLD_INTB_MASK_SET_REG = (u16) -1; 134 *IXDP2351_CPLD_INTA_SIM_REG = 0; 135 *IXDP2351_CPLD_INTB_SIM_REG = 0; 136 137 ixp23xx_init_irq(); 138 139 for (irq = IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE); 140 irq < 141 IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + IXDP2351_INTA_IRQ_NUM); 142 irq++) { 143 if (IXDP2351_INTA_IRQ_MASK(irq) & IXDP2351_INTA_IRQ_VALID) { 144 set_irq_flags(irq, IRQF_VALID); 145 set_irq_handler(irq, handle_level_irq); 146 set_irq_chip(irq, &ixdp2351_inta_chip); 147 } 148 } 149 150 for (irq = IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE); 151 irq < 152 IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + IXDP2351_INTB_IRQ_NUM); 153 irq++) { 154 if (IXDP2351_INTB_IRQ_MASK(irq) & IXDP2351_INTB_IRQ_VALID) { 155 set_irq_flags(irq, IRQF_VALID); 156 set_irq_handler(irq, handle_level_irq); 157 set_irq_chip(irq, &ixdp2351_intb_chip); 158 } 159 } 160 161 set_irq_chained_handler(IRQ_IXP23XX_INTA, ixdp2351_inta_handler); 162 set_irq_chained_handler(IRQ_IXP23XX_INTB, ixdp2351_intb_handler); 163} 164 165/* 166 * IXDP2351 PCI 167 */ 168 169/* 170 * This board does not do normal PCI IRQ routing, or any 171 * sort of swizzling, so we just need to check where on the 172 * bus the device is and figure out what CPLD pin it is 173 * being routed to. 174 */ 175#define DEVPIN(dev, pin) ((pin) | ((dev) << 3)) 176 177static int __init ixdp2351_map_irq(struct pci_dev *dev, u8 slot, u8 pin) 178{ 179 u8 bus = dev->bus->number; 180 u32 devpin = DEVPIN(PCI_SLOT(dev->devfn), pin); 181 struct pci_bus *tmp_bus = dev->bus; 182 183 /* Primary bus, no interrupts here */ 184 if (!bus) 185 return -1; 186 187 /* Lookup first leaf in bus tree */ 188 while ((tmp_bus->parent != NULL) && (tmp_bus->parent->parent != NULL)) 189 tmp_bus = tmp_bus->parent; 190 191 /* Select between known bridges */ 192 switch (tmp_bus->self->devfn | (tmp_bus->self->bus->number << 8)) { 193 /* Device is located after first bridge */ 194 case 0x0008: 195 if (tmp_bus == dev->bus) { 196 /* Device is located directy after first bridge */ 197 switch (devpin) { 198 /* Onboard 82546 */ 199 case DEVPIN(1, 1): /* Onboard 82546 ch 0 */ 200 return IRQ_IXDP2351_INTA_82546; 201 case DEVPIN(1, 2): /* Onboard 82546 ch 1 */ 202 return IRQ_IXDP2351_INTB_82546; 203 /* PMC SLOT */ 204 case DEVPIN(0, 1): /* PMCP INTA# */ 205 case DEVPIN(2, 4): /* PMCS INTD# */ 206 return IRQ_IXDP2351_SPCI_PMC_INTA; 207 case DEVPIN(0, 2): /* PMCP INTB# */ 208 case DEVPIN(2, 1): /* PMCS INTA# */ 209 return IRQ_IXDP2351_SPCI_PMC_INTB; 210 case DEVPIN(0, 3): /* PMCP INTC# */ 211 case DEVPIN(2, 2): /* PMCS INTB# */ 212 return IRQ_IXDP2351_SPCI_PMC_INTC; 213 case DEVPIN(0, 4): /* PMCP INTD# */ 214 case DEVPIN(2, 3): /* PMCS INTC# */ 215 return IRQ_IXDP2351_SPCI_PMC_INTD; 216 } 217 } else { 218 /* Device is located indirectly after first bridge */ 219 /* Not supported now */ 220 return -1; 221 } 222 break; 223 case 0x0010: 224 if (tmp_bus == dev->bus) { 225 /* Device is located directy after second bridge */ 226 /* Secondary bus of second bridge */ 227 switch (devpin) { 228 case DEVPIN(0, 1): /* DB#0 */ 229 case DEVPIN(0, 2): 230 case DEVPIN(0, 3): 231 case DEVPIN(0, 4): 232 return IRQ_IXDP2351_SPCI_DB_0; 233 case DEVPIN(1, 1): /* DB#1 */ 234 case DEVPIN(1, 2): 235 case DEVPIN(1, 3): 236 case DEVPIN(1, 4): 237 return IRQ_IXDP2351_SPCI_DB_1; 238 case DEVPIN(2, 1): /* FIC1 */ 239 case DEVPIN(2, 2): 240 case DEVPIN(2, 3): 241 case DEVPIN(2, 4): 242 case DEVPIN(3, 1): /* FIC2 */ 243 case DEVPIN(3, 2): 244 case DEVPIN(3, 3): 245 case DEVPIN(3, 4): 246 return IRQ_IXDP2351_SPCI_FIC; 247 } 248 } else { 249 /* Device is located indirectly after second bridge */ 250 /* Not supported now */ 251 return -1; 252 } 253 break; 254 } 255 256 return -1; 257} 258 259struct hw_pci ixdp2351_pci __initdata = { 260 .nr_controllers = 1, 261 .preinit = ixp23xx_pci_preinit, 262 .setup = ixp23xx_pci_setup, 263 .scan = ixp23xx_pci_scan_bus, 264 .map_irq = ixdp2351_map_irq, 265}; 266 267int __init ixdp2351_pci_init(void) 268{ 269 if (machine_is_ixdp2351()) 270 pci_common_init(&ixdp2351_pci); 271 272 return 0; 273} 274 275subsys_initcall(ixdp2351_pci_init); 276 277/* 278 * IXDP2351 Static Mapped I/O 279 */ 280static struct map_desc ixdp2351_io_desc[] __initdata = { 281 { 282 .virtual = IXDP2351_NP_VIRT_BASE, 283 .pfn = __phys_to_pfn((u64)IXDP2351_NP_PHYS_BASE), 284 .length = IXDP2351_NP_PHYS_SIZE, 285 .type = MT_DEVICE 286 }, { 287 .virtual = IXDP2351_BB_BASE_VIRT, 288 .pfn = __phys_to_pfn((u64)IXDP2351_BB_BASE_PHYS), 289 .length = IXDP2351_BB_SIZE, 290 .type = MT_DEVICE 291 } 292}; 293 294static void __init ixdp2351_map_io(void) 295{ 296 ixp23xx_map_io(); 297 iotable_init(ixdp2351_io_desc, ARRAY_SIZE(ixdp2351_io_desc)); 298} 299 300static struct physmap_flash_data ixdp2351_flash_data = { 301 .width = 1, 302}; 303 304static struct resource ixdp2351_flash_resource = { 305 .start = 0x90000000, 306 .end = 0x93ffffff, 307 .flags = IORESOURCE_MEM, 308}; 309 310static struct platform_device ixdp2351_flash = { 311 .name = "physmap-flash", 312 .id = 0, 313 .dev = { 314 .platform_data = &ixdp2351_flash_data, 315 }, 316 .num_resources = 1, 317 .resource = &ixdp2351_flash_resource, 318}; 319 320static void __init ixdp2351_init(void) 321{ 322 platform_device_register(&ixdp2351_flash); 323 324 /* 325 * Mark flash as writeable 326 */ 327 IXP23XX_EXP_CS0[0] |= IXP23XX_FLASH_WRITABLE; 328 IXP23XX_EXP_CS0[1] |= IXP23XX_FLASH_WRITABLE; 329 IXP23XX_EXP_CS0[2] |= IXP23XX_FLASH_WRITABLE; 330 IXP23XX_EXP_CS0[3] |= IXP23XX_FLASH_WRITABLE; 331 332 ixp23xx_sys_init(); 333} 334 335MACHINE_START(IXDP2351, "Intel IXDP2351 Development Platform") 336 /* Maintainer: MontaVista Software, Inc. */ 337 .phys_io = IXP23XX_PERIPHERAL_PHYS, 338 .io_pg_offst = ((IXP23XX_PERIPHERAL_VIRT >> 18)) & 0xfffc, 339 .map_io = ixdp2351_map_io, 340 .init_irq = ixdp2351_init_irq, 341 .timer = &ixp23xx_timer, 342 .boot_params = 0x00000100, 343 .init_machine = ixdp2351_init, 344MACHINE_END 345