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