1 /* 2 * linux/arch/arm/kernel/dec21285.c: PCI functions for DC21285 3 * 4 * Copyright (C) 1998-2001 Russell King 5 * Copyright (C) 1998-2000 Phil Blundell 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 #include <linux/kernel.h> 12 #include <linux/pci.h> 13 #include <linux/interrupt.h> 14 #include <linux/mm.h> 15 #include <linux/slab.h> 16 #include <linux/init.h> 17 #include <linux/ioport.h> 18 #include <linux/irq.h> 19 #include <linux/io.h> 20 #include <linux/spinlock.h> 21 #include <video/vga.h> 22 23 #include <asm/irq.h> 24 #include <asm/system.h> 25 #include <asm/mach/pci.h> 26 #include <asm/hardware/dec21285.h> 27 28 #define MAX_SLOTS 21 29 30 #define PCICMD_ABORT ((PCI_STATUS_REC_MASTER_ABORT| \ 31 PCI_STATUS_REC_TARGET_ABORT)<<16) 32 33 #define PCICMD_ERROR_BITS ((PCI_STATUS_DETECTED_PARITY | \ 34 PCI_STATUS_REC_MASTER_ABORT | \ 35 PCI_STATUS_REC_TARGET_ABORT | \ 36 PCI_STATUS_PARITY) << 16) 37 38 extern int setup_arm_irq(int, struct irqaction *); 39 extern void pcibios_report_status(u_int status_mask, int warn); 40 41 static unsigned long 42 dc21285_base_address(struct pci_bus *bus, unsigned int devfn) 43 { 44 unsigned long addr = 0; 45 46 if (bus->number == 0) { 47 if (PCI_SLOT(devfn) == 0) 48 /* 49 * For devfn 0, point at the 21285 50 */ 51 addr = ARMCSR_BASE; 52 else { 53 devfn -= 1 << 3; 54 55 if (devfn < PCI_DEVFN(MAX_SLOTS, 0)) 56 addr = PCICFG0_BASE | 0xc00000 | (devfn << 8); 57 } 58 } else 59 addr = PCICFG1_BASE | (bus->number << 16) | (devfn << 8); 60 61 return addr; 62 } 63 64 static int 65 dc21285_read_config(struct pci_bus *bus, unsigned int devfn, int where, 66 int size, u32 *value) 67 { 68 unsigned long addr = dc21285_base_address(bus, devfn); 69 u32 v = 0xffffffff; 70 71 if (addr) 72 switch (size) { 73 case 1: 74 asm("ldrb %0, [%1, %2]" 75 : "=r" (v) : "r" (addr), "r" (where) : "cc"); 76 break; 77 case 2: 78 asm("ldrh %0, [%1, %2]" 79 : "=r" (v) : "r" (addr), "r" (where) : "cc"); 80 break; 81 case 4: 82 asm("ldr %0, [%1, %2]" 83 : "=r" (v) : "r" (addr), "r" (where) : "cc"); 84 break; 85 } 86 87 *value = v; 88 89 v = *CSR_PCICMD; 90 if (v & PCICMD_ABORT) { 91 *CSR_PCICMD = v & (0xffff|PCICMD_ABORT); 92 return -1; 93 } 94 95 return PCIBIOS_SUCCESSFUL; 96 } 97 98 static int 99 dc21285_write_config(struct pci_bus *bus, unsigned int devfn, int where, 100 int size, u32 value) 101 { 102 unsigned long addr = dc21285_base_address(bus, devfn); 103 u32 v; 104 105 if (addr) 106 switch (size) { 107 case 1: 108 asm("strb %0, [%1, %2]" 109 : : "r" (value), "r" (addr), "r" (where) 110 : "cc"); 111 break; 112 case 2: 113 asm("strh %0, [%1, %2]" 114 : : "r" (value), "r" (addr), "r" (where) 115 : "cc"); 116 break; 117 case 4: 118 asm("str %0, [%1, %2]" 119 : : "r" (value), "r" (addr), "r" (where) 120 : "cc"); 121 break; 122 } 123 124 v = *CSR_PCICMD; 125 if (v & PCICMD_ABORT) { 126 *CSR_PCICMD = v & (0xffff|PCICMD_ABORT); 127 return -1; 128 } 129 130 return PCIBIOS_SUCCESSFUL; 131 } 132 133 static struct pci_ops dc21285_ops = { 134 .read = dc21285_read_config, 135 .write = dc21285_write_config, 136 }; 137 138 static struct timer_list serr_timer; 139 static struct timer_list perr_timer; 140 141 static void dc21285_enable_error(unsigned long __data) 142 { 143 switch (__data) { 144 case IRQ_PCI_SERR: 145 del_timer(&serr_timer); 146 break; 147 148 case IRQ_PCI_PERR: 149 del_timer(&perr_timer); 150 break; 151 } 152 153 enable_irq(__data); 154 } 155 156 /* 157 * Warn on PCI errors. 158 */ 159 static irqreturn_t dc21285_abort_irq(int irq, void *dev_id) 160 { 161 unsigned int cmd; 162 unsigned int status; 163 164 cmd = *CSR_PCICMD; 165 status = cmd >> 16; 166 cmd = cmd & 0xffff; 167 168 if (status & PCI_STATUS_REC_MASTER_ABORT) { 169 printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n", 170 instruction_pointer(get_irq_regs())); 171 cmd |= PCI_STATUS_REC_MASTER_ABORT << 16; 172 } 173 174 if (status & PCI_STATUS_REC_TARGET_ABORT) { 175 printk(KERN_DEBUG "PCI: target abort: "); 176 pcibios_report_status(PCI_STATUS_REC_MASTER_ABORT | 177 PCI_STATUS_SIG_TARGET_ABORT | 178 PCI_STATUS_REC_TARGET_ABORT, 1); 179 printk("\n"); 180 181 cmd |= PCI_STATUS_REC_TARGET_ABORT << 16; 182 } 183 184 *CSR_PCICMD = cmd; 185 186 return IRQ_HANDLED; 187 } 188 189 static irqreturn_t dc21285_serr_irq(int irq, void *dev_id) 190 { 191 struct timer_list *timer = dev_id; 192 unsigned int cntl; 193 194 printk(KERN_DEBUG "PCI: system error received: "); 195 pcibios_report_status(PCI_STATUS_SIG_SYSTEM_ERROR, 1); 196 printk("\n"); 197 198 cntl = *CSR_SA110_CNTL & 0xffffdf07; 199 *CSR_SA110_CNTL = cntl | SA110_CNTL_RXSERR; 200 201 /* 202 * back off this interrupt 203 */ 204 disable_irq(irq); 205 timer->expires = jiffies + HZ; 206 add_timer(timer); 207 208 return IRQ_HANDLED; 209 } 210 211 static irqreturn_t dc21285_discard_irq(int irq, void *dev_id) 212 { 213 printk(KERN_DEBUG "PCI: discard timer expired\n"); 214 *CSR_SA110_CNTL &= 0xffffde07; 215 216 return IRQ_HANDLED; 217 } 218 219 static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id) 220 { 221 unsigned int cmd; 222 223 printk(KERN_DEBUG "PCI: data parity error detected: "); 224 pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); 225 printk("\n"); 226 227 cmd = *CSR_PCICMD & 0xffff; 228 *CSR_PCICMD = cmd | 1 << 24; 229 230 return IRQ_HANDLED; 231 } 232 233 static irqreturn_t dc21285_parity_irq(int irq, void *dev_id) 234 { 235 struct timer_list *timer = dev_id; 236 unsigned int cmd; 237 238 printk(KERN_DEBUG "PCI: parity error detected: "); 239 pcibios_report_status(PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY, 1); 240 printk("\n"); 241 242 cmd = *CSR_PCICMD & 0xffff; 243 *CSR_PCICMD = cmd | 1 << 31; 244 245 /* 246 * back off this interrupt 247 */ 248 disable_irq(irq); 249 timer->expires = jiffies + HZ; 250 add_timer(timer); 251 252 return IRQ_HANDLED; 253 } 254 255 int __init dc21285_setup(int nr, struct pci_sys_data *sys) 256 { 257 struct resource *res; 258 259 if (nr || !footbridge_cfn_mode()) 260 return 0; 261 262 res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL); 263 if (!res) { 264 printk("out of memory for root bus resources"); 265 return 0; 266 } 267 268 res[0].flags = IORESOURCE_MEM; 269 res[0].name = "Footbridge non-prefetch"; 270 res[1].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; 271 res[1].name = "Footbridge prefetch"; 272 273 allocate_resource(&iomem_resource, &res[1], 0x20000000, 274 0xa0000000, 0xffffffff, 0x20000000, NULL, NULL); 275 allocate_resource(&iomem_resource, &res[0], 0x40000000, 276 0x80000000, 0xffffffff, 0x40000000, NULL, NULL); 277 278 sys->resource[0] = &ioport_resource; 279 sys->resource[1] = &res[0]; 280 sys->resource[2] = &res[1]; 281 sys->mem_offset = DC21285_PCI_MEM; 282 283 return 1; 284 } 285 286 struct pci_bus * __init dc21285_scan_bus(int nr, struct pci_sys_data *sys) 287 { 288 return pci_scan_bus(0, &dc21285_ops, sys); 289 } 290 291 #define dc21285_request_irq(_a, _b, _c, _d, _e) \ 292 WARN_ON(request_irq(_a, _b, _c, _d, _e) < 0) 293 294 void __init dc21285_preinit(void) 295 { 296 unsigned int mem_size, mem_mask; 297 int cfn_mode; 298 299 pcibios_min_mem = 0x81000000; 300 vga_base = PCIMEM_BASE; 301 302 mem_size = (unsigned int)high_memory - PAGE_OFFSET; 303 for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1) 304 if (mem_mask >= mem_size) 305 break; 306 307 /* 308 * These registers need to be set up whether we're the 309 * central function or not. 310 */ 311 *CSR_SDRAMBASEMASK = (mem_mask - 1) & 0x0ffc0000; 312 *CSR_SDRAMBASEOFFSET = 0; 313 *CSR_ROMBASEMASK = 0x80000000; 314 *CSR_CSRBASEMASK = 0; 315 *CSR_CSRBASEOFFSET = 0; 316 *CSR_PCIADDR_EXTN = 0; 317 318 cfn_mode = __footbridge_cfn_mode(); 319 320 printk(KERN_INFO "PCI: DC21285 footbridge, revision %02lX, in " 321 "%s mode\n", *CSR_CLASSREV & 0xff, cfn_mode ? 322 "central function" : "addin"); 323 324 if (footbridge_cfn_mode()) { 325 /* 326 * Clear any existing errors - we aren't 327 * interested in historical data... 328 */ 329 *CSR_SA110_CNTL = (*CSR_SA110_CNTL & 0xffffde07) | 330 SA110_CNTL_RXSERR; 331 *CSR_PCICMD = (*CSR_PCICMD & 0xffff) | PCICMD_ERROR_BITS; 332 } 333 334 init_timer(&serr_timer); 335 init_timer(&perr_timer); 336 337 serr_timer.data = IRQ_PCI_SERR; 338 serr_timer.function = dc21285_enable_error; 339 perr_timer.data = IRQ_PCI_PERR; 340 perr_timer.function = dc21285_enable_error; 341 342 /* 343 * We don't care if these fail. 344 */ 345 dc21285_request_irq(IRQ_PCI_SERR, dc21285_serr_irq, IRQF_DISABLED, 346 "PCI system error", &serr_timer); 347 dc21285_request_irq(IRQ_PCI_PERR, dc21285_parity_irq, IRQF_DISABLED, 348 "PCI parity error", &perr_timer); 349 dc21285_request_irq(IRQ_PCI_ABORT, dc21285_abort_irq, IRQF_DISABLED, 350 "PCI abort", NULL); 351 dc21285_request_irq(IRQ_DISCARD_TIMER, dc21285_discard_irq, IRQF_DISABLED, 352 "Discard timer", NULL); 353 dc21285_request_irq(IRQ_PCI_DPERR, dc21285_dparity_irq, IRQF_DISABLED, 354 "PCI data parity", NULL); 355 356 if (cfn_mode) { 357 static struct resource csrio; 358 359 csrio.flags = IORESOURCE_IO; 360 csrio.name = "Footbridge"; 361 362 allocate_resource(&ioport_resource, &csrio, 128, 363 0xff00, 0xffff, 128, NULL, NULL); 364 365 /* 366 * Map our SDRAM at a known address in PCI space, just in case 367 * the firmware had other ideas. Using a nonzero base is 368 * necessary, since some VGA cards forcefully use PCI addresses 369 * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards). 370 */ 371 *CSR_PCICSRBASE = 0xf4000000; 372 *CSR_PCICSRIOBASE = csrio.start; 373 *CSR_PCISDRAMBASE = __virt_to_bus(PAGE_OFFSET); 374 *CSR_PCIROMBASE = 0; 375 *CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | 376 PCI_COMMAND_INVALIDATE | PCICMD_ERROR_BITS; 377 } else if (footbridge_cfn_mode() != 0) { 378 /* 379 * If we are not compiled to accept "add-in" mode, then 380 * we are using a constant virt_to_bus translation which 381 * can not hope to cater for the way the host BIOS has 382 * set up the machine. 383 */ 384 panic("PCI: this kernel is compiled for central " 385 "function mode only"); 386 } 387 } 388 389 void __init dc21285_postinit(void) 390 { 391 register_isa_ports(DC21285_PCI_MEM, DC21285_PCI_IO, 0); 392 } 393