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