1/* 2 * arch/arm/plat-iop/pci.c 3 * 4 * PCI support for the Intel IOP32X and IOP33X processors 5 * 6 * Author: Rory Bolt <rorybolt@pacbell.net> 7 * Copyright (C) 2002 Rory Bolt 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 14#include <linux/kernel.h> 15#include <linux/pci.h> 16#include <linux/slab.h> 17#include <linux/mm.h> 18#include <linux/init.h> 19#include <linux/ioport.h> 20#include <linux/io.h> 21#include <asm/irq.h> 22#include <asm/signal.h> 23#include <asm/system.h> 24#include <mach/hardware.h> 25#include <asm/mach/pci.h> 26#include <asm/hardware/iop3xx.h> 27 28// #define DEBUG 29 30#ifdef DEBUG 31#define DBG(x...) printk(x) 32#else 33#define DBG(x...) do { } while (0) 34#endif 35 36/* 37 * This routine builds either a type0 or type1 configuration command. If the 38 * bus is on the 803xx then a type0 made, else a type1 is created. 39 */ 40static u32 iop3xx_cfg_address(struct pci_bus *bus, int devfn, int where) 41{ 42 struct pci_sys_data *sys = bus->sysdata; 43 u32 addr; 44 45 if (sys->busnr == bus->number) 46 addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11); 47 else 48 addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1; 49 50 addr |= PCI_FUNC(devfn) << 8 | (where & ~3); 51 52 return addr; 53} 54 55/* 56 * This routine checks the status of the last configuration cycle. If an error 57 * was detected it returns a 1, else it returns a 0. The errors being checked 58 * are parity, master abort, target abort (master and target). These types of 59 * errors occur during a config cycle where there is no device, like during 60 * the discovery stage. 61 */ 62static int iop3xx_pci_status(void) 63{ 64 unsigned int status; 65 int ret = 0; 66 67 /* 68 * Check the status registers. 69 */ 70 status = *IOP3XX_ATUSR; 71 if (status & 0xf900) { 72 DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status); 73 *IOP3XX_ATUSR = status & 0xf900; 74 ret = 1; 75 } 76 77 status = *IOP3XX_ATUISR; 78 if (status & 0x679f) { 79 DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status); 80 *IOP3XX_ATUISR = status & 0x679f; 81 ret = 1; 82 } 83 84 return ret; 85} 86 87/* 88 * Simply write the address register and read the configuration 89 * data. Note that the 4 nops ensure that we are able to handle 90 * a delayed abort (in theory.) 91 */ 92static u32 iop3xx_read(unsigned long addr) 93{ 94 u32 val; 95 96 __asm__ __volatile__( 97 "str %1, [%2]\n\t" 98 "ldr %0, [%3]\n\t" 99 "nop\n\t" 100 "nop\n\t" 101 "nop\n\t" 102 "nop\n\t" 103 : "=r" (val) 104 : "r" (addr), "r" (IOP3XX_OCCAR), "r" (IOP3XX_OCCDR)); 105 106 return val; 107} 108 109/* 110 * The read routines must check the error status of the last configuration 111 * cycle. If there was an error, the routine returns all hex f's. 112 */ 113static int 114iop3xx_read_config(struct pci_bus *bus, unsigned int devfn, int where, 115 int size, u32 *value) 116{ 117 unsigned long addr = iop3xx_cfg_address(bus, devfn, where); 118 u32 val = iop3xx_read(addr) >> ((where & 3) * 8); 119 120 if (iop3xx_pci_status()) 121 val = 0xffffffff; 122 123 *value = val; 124 125 return PCIBIOS_SUCCESSFUL; 126} 127 128static int 129iop3xx_write_config(struct pci_bus *bus, unsigned int devfn, int where, 130 int size, u32 value) 131{ 132 unsigned long addr = iop3xx_cfg_address(bus, devfn, where); 133 u32 val; 134 135 if (size != 4) { 136 val = iop3xx_read(addr); 137 if (iop3xx_pci_status()) 138 return PCIBIOS_SUCCESSFUL; 139 140 where = (where & 3) * 8; 141 142 if (size == 1) 143 val &= ~(0xff << where); 144 else 145 val &= ~(0xffff << where); 146 147 *IOP3XX_OCCDR = val | value << where; 148 } else { 149 asm volatile( 150 "str %1, [%2]\n\t" 151 "str %0, [%3]\n\t" 152 "nop\n\t" 153 "nop\n\t" 154 "nop\n\t" 155 "nop\n\t" 156 : 157 : "r" (value), "r" (addr), 158 "r" (IOP3XX_OCCAR), "r" (IOP3XX_OCCDR)); 159 } 160 161 return PCIBIOS_SUCCESSFUL; 162} 163 164static struct pci_ops iop3xx_ops = { 165 .read = iop3xx_read_config, 166 .write = iop3xx_write_config, 167}; 168 169/* 170 * When a PCI device does not exist during config cycles, the 80200 gets a 171 * bus error instead of returning 0xffffffff. This handler simply returns. 172 */ 173static int 174iop3xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs) 175{ 176 DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n", 177 addr, fsr, regs->ARM_pc, regs->ARM_lr); 178 179 /* 180 * If it was an imprecise abort, then we need to correct the 181 * return address to be _after_ the instruction. 182 */ 183 if (fsr & (1 << 10)) 184 regs->ARM_pc += 4; 185 186 return 0; 187} 188 189int iop3xx_pci_setup(int nr, struct pci_sys_data *sys) 190{ 191 struct resource *res; 192 193 if (nr != 0) 194 return 0; 195 196 res = kzalloc(2 * sizeof(struct resource), GFP_KERNEL); 197 if (!res) 198 panic("PCI: unable to alloc resources"); 199 200 res[0].start = IOP3XX_PCI_LOWER_IO_PA; 201 res[0].end = IOP3XX_PCI_LOWER_IO_PA + IOP3XX_PCI_IO_WINDOW_SIZE - 1; 202 res[0].name = "IOP3XX PCI I/O Space"; 203 res[0].flags = IORESOURCE_IO; 204 request_resource(&ioport_resource, &res[0]); 205 206 res[1].start = IOP3XX_PCI_LOWER_MEM_PA; 207 res[1].end = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE - 1; 208 res[1].name = "IOP3XX PCI Memory Space"; 209 res[1].flags = IORESOURCE_MEM; 210 request_resource(&iomem_resource, &res[1]); 211 212 /* 213 * Use whatever translation is already setup. 214 */ 215 sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - *IOP3XX_OMWTVR0; 216 sys->io_offset = IOP3XX_PCI_LOWER_IO_PA - *IOP3XX_OIOWTVR; 217 218 sys->resource[0] = &res[0]; 219 sys->resource[1] = &res[1]; 220 sys->resource[2] = NULL; 221 222 return 1; 223} 224 225struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *sys) 226{ 227 return pci_scan_bus(sys->busnr, &iop3xx_ops, sys); 228} 229 230void __init iop3xx_atu_setup(void) 231{ 232 /* BAR 0 ( Disabled ) */ 233 *IOP3XX_IAUBAR0 = 0x0; 234 *IOP3XX_IABAR0 = 0x0; 235 *IOP3XX_IATVR0 = 0x0; 236 *IOP3XX_IALR0 = 0x0; 237 238 /* BAR 1 ( Disabled ) */ 239 *IOP3XX_IAUBAR1 = 0x0; 240 *IOP3XX_IABAR1 = 0x0; 241 *IOP3XX_IALR1 = 0x0; 242 243 /* BAR 2 (1:1 mapping with Physical RAM) */ 244 /* Set limit and enable */ 245 *IOP3XX_IALR2 = ~((u32)IOP3XX_MAX_RAM_SIZE - 1) & ~0x1; 246 *IOP3XX_IAUBAR2 = 0x0; 247 248 /* Align the inbound bar with the base of memory */ 249 *IOP3XX_IABAR2 = PHYS_OFFSET | 250 PCI_BASE_ADDRESS_MEM_TYPE_64 | 251 PCI_BASE_ADDRESS_MEM_PREFETCH; 252 253 *IOP3XX_IATVR2 = PHYS_OFFSET; 254 255 /* Outbound window 0 */ 256 *IOP3XX_OMWTVR0 = IOP3XX_PCI_LOWER_MEM_BA; 257 *IOP3XX_OUMWTVR0 = 0; 258 259 /* Outbound window 1 */ 260 *IOP3XX_OMWTVR1 = IOP3XX_PCI_LOWER_MEM_BA + 261 IOP3XX_PCI_MEM_WINDOW_SIZE / 2; 262 *IOP3XX_OUMWTVR1 = 0; 263 264 /* BAR 3 ( Disabled ) */ 265 *IOP3XX_IAUBAR3 = 0x0; 266 *IOP3XX_IABAR3 = 0x0; 267 *IOP3XX_IATVR3 = 0x0; 268 *IOP3XX_IALR3 = 0x0; 269 270 /* Setup the I/O Bar 271 */ 272 *IOP3XX_OIOWTVR = IOP3XX_PCI_LOWER_IO_BA; 273 274 /* Enable inbound and outbound cycles 275 */ 276 *IOP3XX_ATUCMD |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | 277 PCI_COMMAND_PARITY | PCI_COMMAND_SERR; 278 *IOP3XX_ATUCR |= IOP3XX_ATUCR_OUT_EN; 279} 280 281void __init iop3xx_atu_disable(void) 282{ 283 *IOP3XX_ATUCMD = 0; 284 *IOP3XX_ATUCR = 0; 285 286 /* wait for cycles to quiesce */ 287 while (*IOP3XX_PCSR & (IOP3XX_PCSR_OUT_Q_BUSY | 288 IOP3XX_PCSR_IN_Q_BUSY)) 289 cpu_relax(); 290 291 /* BAR 0 ( Disabled ) */ 292 *IOP3XX_IAUBAR0 = 0x0; 293 *IOP3XX_IABAR0 = 0x0; 294 *IOP3XX_IATVR0 = 0x0; 295 *IOP3XX_IALR0 = 0x0; 296 297 /* BAR 1 ( Disabled ) */ 298 *IOP3XX_IAUBAR1 = 0x0; 299 *IOP3XX_IABAR1 = 0x0; 300 *IOP3XX_IALR1 = 0x0; 301 302 /* BAR 2 ( Disabled ) */ 303 *IOP3XX_IAUBAR2 = 0x0; 304 *IOP3XX_IABAR2 = 0x0; 305 *IOP3XX_IATVR2 = 0x0; 306 *IOP3XX_IALR2 = 0x0; 307 308 /* BAR 3 ( Disabled ) */ 309 *IOP3XX_IAUBAR3 = 0x0; 310 *IOP3XX_IABAR3 = 0x0; 311 *IOP3XX_IATVR3 = 0x0; 312 *IOP3XX_IALR3 = 0x0; 313 314 /* Clear the outbound windows */ 315 *IOP3XX_OIOWTVR = 0; 316 317 /* Outbound window 0 */ 318 *IOP3XX_OMWTVR0 = 0; 319 *IOP3XX_OUMWTVR0 = 0; 320 321 /* Outbound window 1 */ 322 *IOP3XX_OMWTVR1 = 0; 323 *IOP3XX_OUMWTVR1 = 0; 324} 325 326/* Flag to determine whether the ATU is initialized and the PCI bus scanned */ 327int init_atu; 328 329int iop3xx_get_init_atu(void) { 330 /* check if default has been overridden */ 331 if (init_atu != IOP3XX_INIT_ATU_DEFAULT) 332 return init_atu; 333 else 334 return IOP3XX_INIT_ATU_DISABLE; 335} 336 337static void __init iop3xx_atu_debug(void) 338{ 339 DBG("PCI: Intel IOP3xx PCI init.\n"); 340 DBG("PCI: Outbound memory window 0: PCI 0x%08x%08x\n", 341 *IOP3XX_OUMWTVR0, *IOP3XX_OMWTVR0); 342 DBG("PCI: Outbound memory window 1: PCI 0x%08x%08x\n", 343 *IOP3XX_OUMWTVR1, *IOP3XX_OMWTVR1); 344 DBG("PCI: Outbound IO window: PCI 0x%08x\n", 345 *IOP3XX_OIOWTVR); 346 347 DBG("PCI: Inbound memory window 0: PCI 0x%08x%08x 0x%08x -> 0x%08x\n", 348 *IOP3XX_IAUBAR0, *IOP3XX_IABAR0, *IOP3XX_IALR0, *IOP3XX_IATVR0); 349 DBG("PCI: Inbound memory window 1: PCI 0x%08x%08x 0x%08x\n", 350 *IOP3XX_IAUBAR1, *IOP3XX_IABAR1, *IOP3XX_IALR1); 351 DBG("PCI: Inbound memory window 2: PCI 0x%08x%08x 0x%08x -> 0x%08x\n", 352 *IOP3XX_IAUBAR2, *IOP3XX_IABAR2, *IOP3XX_IALR2, *IOP3XX_IATVR2); 353 DBG("PCI: Inbound memory window 3: PCI 0x%08x%08x 0x%08x -> 0x%08x\n", 354 *IOP3XX_IAUBAR3, *IOP3XX_IABAR3, *IOP3XX_IALR3, *IOP3XX_IATVR3); 355 356 DBG("PCI: Expansion ROM window: PCI 0x%08x%08x 0x%08x -> 0x%08x\n", 357 0, *IOP3XX_ERBAR, *IOP3XX_ERLR, *IOP3XX_ERTVR); 358 359 DBG("ATU: IOP3XX_ATUCMD=0x%04x\n", *IOP3XX_ATUCMD); 360 DBG("ATU: IOP3XX_ATUCR=0x%08x\n", *IOP3XX_ATUCR); 361 362 hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, 0, "imprecise external abort"); 363} 364 365/* for platforms that might be host-bus-adapters */ 366void __init iop3xx_pci_preinit_cond(void) 367{ 368 if (iop3xx_get_init_atu() == IOP3XX_INIT_ATU_ENABLE) { 369 iop3xx_atu_disable(); 370 iop3xx_atu_setup(); 371 iop3xx_atu_debug(); 372 } 373} 374 375void __init iop3xx_pci_preinit(void) 376{ 377 iop3xx_atu_disable(); 378 iop3xx_atu_setup(); 379 iop3xx_atu_debug(); 380} 381 382/* allow init_atu to be user overridden */ 383static int __init iop3xx_init_atu_setup(char *str) 384{ 385 init_atu = IOP3XX_INIT_ATU_DEFAULT; 386 if (str) { 387 while (*str != '\0') { 388 switch (*str) { 389 case 'y': 390 case 'Y': 391 init_atu = IOP3XX_INIT_ATU_ENABLE; 392 break; 393 case 'n': 394 case 'N': 395 init_atu = IOP3XX_INIT_ATU_DISABLE; 396 break; 397 case ',': 398 case '=': 399 break; 400 default: 401 printk(KERN_DEBUG "\"%s\" malformed at " 402 "character: \'%c\'", 403 __func__, 404 *str); 405 *(str + 1) = '\0'; 406 } 407 str++; 408 } 409 } 410 411 return 1; 412} 413 414__setup("iop3xx_init_atu", iop3xx_init_atu_setup); 415