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