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