linux/arch/arm/mach-versatile/pci.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/mach-versatile/pci.c
   3 *
   4 * (C) Copyright Koninklijke Philips Electronics NV 2004. All rights reserved.
   5 * You can redistribute and/or modify this software under the terms of version 2
   6 * of the GNU General Public License as published by the Free Software Foundation.
   7 * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED
   8 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   9 * General Public License for more details.
  10 * Koninklijke Philips Electronics nor its subsidiaries is obligated to provide any support for this software.
  11 *
  12 * ARM Versatile PCI driver.
  13 *
  14 * 14/04/2005 Initial version, colin.king@philips.com
  15 *
  16 */
  17#include <linux/kernel.h>
  18#include <linux/pci.h>
  19#include <linux/slab.h>
  20#include <linux/ioport.h>
  21#include <linux/interrupt.h>
  22#include <linux/spinlock.h>
  23#include <linux/init.h>
  24
  25#include <asm/hardware.h>
  26#include <asm/io.h>
  27#include <asm/irq.h>
  28#include <asm/system.h>
  29#include <asm/mach/pci.h>
  30
  31/*
  32 * these spaces are mapped using the following base registers:
  33 *
  34 * Usage Local Bus Memory         Base/Map registers used
  35 *
  36 * Mem   50000000 - 5FFFFFFF      LB_BASE0/LB_MAP0,  non prefetch
  37 * Mem   60000000 - 6FFFFFFF      LB_BASE1/LB_MAP1,  prefetch
  38 * IO    44000000 - 4FFFFFFF      LB_BASE2/LB_MAP2,  IO
  39 * Cfg   42000000 - 42FFFFFF      PCI config
  40 *
  41 */
  42#define __IO_ADDRESS(n) ((void __iomem *)(unsigned long)IO_ADDRESS(n))
  43#define SYS_PCICTL              __IO_ADDRESS(VERSATILE_SYS_PCICTL)
  44#define PCI_IMAP0               __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0)
  45#define PCI_IMAP1               __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4)
  46#define PCI_IMAP2               __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8)
  47#define PCI_SMAP0               __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10)
  48#define PCI_SMAP1               __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14)
  49#define PCI_SMAP2               __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18)
  50#define PCI_SELFID              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc)
  51
  52#define DEVICE_ID_OFFSET                0x00
  53#define CSR_OFFSET                      0x04
  54#define CLASS_ID_OFFSET                 0x08
  55
  56#define VP_PCI_DEVICE_ID                0x030010ee
  57#define VP_PCI_CLASS_ID                 0x0b400000
  58
  59static unsigned long pci_slot_ignore = 0;
  60
  61static int __init versatile_pci_slot_ignore(char *str)
  62{
  63        int retval;
  64        int slot;
  65
  66        while ((retval = get_option(&str,&slot))) {
  67                if ((slot < 0) || (slot > 31)) {
  68                        printk("Illegal slot value: %d\n",slot);
  69                } else {
  70                        pci_slot_ignore |= (1 << slot);
  71                }
  72        }
  73        return 1;
  74}
  75
  76__setup("pci_slot_ignore=", versatile_pci_slot_ignore);
  77
  78
  79static void __iomem *__pci_addr(struct pci_bus *bus,
  80                                unsigned int devfn, int offset)
  81{
  82        unsigned int busnr = bus->number;
  83
  84        /*
  85         * Trap out illegal values
  86         */
  87        if (offset > 255)
  88                BUG();
  89        if (busnr > 255)
  90                BUG();
  91        if (devfn > 255)
  92                BUG();
  93
  94        return VERSATILE_PCI_CFG_VIRT_BASE + ((busnr << 16) |
  95                (PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | offset);
  96}
  97
  98static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int where,
  99                                 int size, u32 *val)
 100{
 101        void __iomem *addr = __pci_addr(bus, devfn, where & ~3);
 102        u32 v;
 103        int slot = PCI_SLOT(devfn);
 104
 105        if (pci_slot_ignore & (1 << slot)) {
 106                /* Ignore this slot */
 107                switch (size) {
 108                case 1:
 109                        v = 0xff;
 110                        break;
 111                case 2:
 112                        v = 0xffff;
 113                        break;
 114                default:
 115                        v = 0xffffffff;
 116                }
 117        } else {
 118                switch (size) {
 119                case 1:
 120                        v = __raw_readl(addr);
 121                        if (where & 2) v >>= 16;
 122                        if (where & 1) v >>= 8;
 123                        v &= 0xff;
 124                        break;
 125
 126                case 2:
 127                        v = __raw_readl(addr);
 128                        if (where & 2) v >>= 16;
 129                        v &= 0xffff;
 130                        break;
 131
 132                default:
 133                        v = __raw_readl(addr);
 134                        break;
 135                }
 136        }
 137
 138        *val = v;
 139        return PCIBIOS_SUCCESSFUL;
 140}
 141
 142static int versatile_write_config(struct pci_bus *bus, unsigned int devfn, int where,
 143                                  int size, u32 val)
 144{
 145        void __iomem *addr = __pci_addr(bus, devfn, where);
 146        int slot = PCI_SLOT(devfn);
 147
 148        if (pci_slot_ignore & (1 << slot)) {
 149                return PCIBIOS_SUCCESSFUL;
 150        }
 151
 152        switch (size) {
 153        case 1:
 154                __raw_writeb((u8)val, addr);
 155                break;
 156
 157        case 2:
 158                __raw_writew((u16)val, addr);
 159                break;
 160
 161        case 4:
 162                __raw_writel(val, addr);
 163                break;
 164        }
 165
 166        return PCIBIOS_SUCCESSFUL;
 167}
 168
 169static struct pci_ops pci_versatile_ops = {
 170        .read   = versatile_read_config,
 171        .write  = versatile_write_config,
 172};
 173
 174static struct resource io_mem = {
 175        .name   = "PCI I/O space",
 176        .start  = VERSATILE_PCI_MEM_BASE0,
 177        .end    = VERSATILE_PCI_MEM_BASE0+VERSATILE_PCI_MEM_BASE0_SIZE-1,
 178        .flags  = IORESOURCE_IO,
 179};
 180
 181static struct resource non_mem = {
 182        .name   = "PCI non-prefetchable",
 183        .start  = VERSATILE_PCI_MEM_BASE1,
 184        .end    = VERSATILE_PCI_MEM_BASE1+VERSATILE_PCI_MEM_BASE1_SIZE-1,
 185        .flags  = IORESOURCE_MEM,
 186};
 187
 188static struct resource pre_mem = {
 189        .name   = "PCI prefetchable",
 190        .start  = VERSATILE_PCI_MEM_BASE2,
 191        .end    = VERSATILE_PCI_MEM_BASE2+VERSATILE_PCI_MEM_BASE2_SIZE-1,
 192        .flags  = IORESOURCE_MEM | IORESOURCE_PREFETCH,
 193};
 194
 195static int __init pci_versatile_setup_resources(struct resource **resource)
 196{
 197        int ret = 0;
 198
 199        ret = request_resource(&iomem_resource, &io_mem);
 200        if (ret) {
 201                printk(KERN_ERR "PCI: unable to allocate I/O "
 202                       "memory region (%d)\n", ret);
 203                goto out;
 204        }
 205        ret = request_resource(&iomem_resource, &non_mem);
 206        if (ret) {
 207                printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
 208                       "memory region (%d)\n", ret);
 209                goto release_io_mem;
 210        }
 211        ret = request_resource(&iomem_resource, &pre_mem);
 212        if (ret) {
 213                printk(KERN_ERR "PCI: unable to allocate prefetchable "
 214                       "memory region (%d)\n", ret);
 215                goto release_non_mem;
 216        }
 217
 218        /*
 219         * bus->resource[0] is the IO resource for this bus
 220         * bus->resource[1] is the mem resource for this bus
 221         * bus->resource[2] is the prefetch mem resource for this bus
 222         */
 223        resource[0] = &io_mem;
 224        resource[1] = &non_mem;
 225        resource[2] = &pre_mem;
 226
 227        goto out;
 228
 229 release_non_mem:
 230        release_resource(&non_mem);
 231 release_io_mem:
 232        release_resource(&io_mem);
 233 out:
 234        return ret;
 235}
 236
 237int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
 238{
 239        int ret = 0;
 240        int i;
 241        int myslot = -1;
 242        unsigned long val;
 243        void __iomem *local_pci_cfg_base;
 244
 245        val = __raw_readl(SYS_PCICTL);
 246        if (!(val & 1)) {
 247                printk("Not plugged into PCI backplane!\n");
 248                ret = -EIO;
 249                goto out;
 250        }
 251
 252        if (nr == 0) {
 253                sys->mem_offset = 0;
 254                ret = pci_versatile_setup_resources(sys->resource);
 255                if (ret < 0) {
 256                        printk("pci_versatile_setup: resources... oops?\n");
 257                        goto out;
 258                }
 259        } else {
 260                printk("pci_versatile_setup: resources... nr == 0??\n");
 261                goto out;
 262        }
 263
 264        /*
 265         *  We need to discover the PCI core first to configure itself
 266         *  before the main PCI probing is performed
 267         */
 268        for (i=0; i<32; i++)
 269                if ((__raw_readl(VERSATILE_PCI_VIRT_BASE+(i<<11)+DEVICE_ID_OFFSET) == VP_PCI_DEVICE_ID) &&
 270                    (__raw_readl(VERSATILE_PCI_VIRT_BASE+(i<<11)+CLASS_ID_OFFSET) == VP_PCI_CLASS_ID)) {
 271                        myslot = i;
 272                        break;
 273                }
 274
 275        if (myslot == -1) {
 276                printk("Cannot find PCI core!\n");
 277                ret = -EIO;
 278                goto out;
 279        }
 280
 281        printk("PCI core found (slot %d)\n",myslot);
 282
 283        __raw_writel(myslot, PCI_SELFID);
 284        local_pci_cfg_base = VERSATILE_PCI_CFG_VIRT_BASE + (myslot << 11);
 285
 286        val = __raw_readl(local_pci_cfg_base + CSR_OFFSET);
 287        val |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
 288        __raw_writel(val, local_pci_cfg_base + CSR_OFFSET);
 289
 290        /*
 291         * Configure the PCI inbound memory windows to be 1:1 mapped to SDRAM
 292         */
 293        __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_0);
 294        __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_1);
 295        __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_2);
 296
 297        /*
 298         * Do not to map Versatile FPGA PCI device into memory space
 299         */
 300        pci_slot_ignore |= (1 << myslot);
 301        ret = 1;
 302
 303 out:
 304        return ret;
 305}
 306
 307
 308struct pci_bus *pci_versatile_scan_bus(int nr, struct pci_sys_data *sys)
 309{
 310        return pci_scan_bus(sys->busnr, &pci_versatile_ops, sys);
 311}
 312
 313void __init pci_versatile_preinit(void)
 314{
 315        __raw_writel(VERSATILE_PCI_MEM_BASE0 >> 28, PCI_IMAP0);
 316        __raw_writel(VERSATILE_PCI_MEM_BASE1 >> 28, PCI_IMAP1);
 317        __raw_writel(VERSATILE_PCI_MEM_BASE2 >> 28, PCI_IMAP2);
 318
 319        __raw_writel(PHYS_OFFSET >> 28, PCI_SMAP0);
 320        __raw_writel(PHYS_OFFSET >> 28, PCI_SMAP1);
 321        __raw_writel(PHYS_OFFSET >> 28, PCI_SMAP2);
 322
 323        __raw_writel(1, SYS_PCICTL);
 324}
 325
 326/*
 327 * map the specified device/slot/pin to an IRQ.   Different backplanes may need to modify this.
 328 */
 329static int __init versatile_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 330{
 331        int irq;
 332        int devslot = PCI_SLOT(dev->devfn);
 333
 334        /* slot,  pin,  irq
 335         *  24     1     27
 336         *  25     1     28
 337         *  26     1     29
 338         *  27     1     30
 339         */
 340        irq = 27 + ((slot + pin - 1) & 3);
 341
 342        printk("PCI map irq: slot %d, pin %d, devslot %d, irq: %d\n",slot,pin,devslot,irq);
 343
 344        return irq;
 345}
 346
 347static struct hw_pci versatile_pci __initdata = {
 348        .swizzle                = NULL,
 349        .map_irq                = versatile_map_irq,
 350        .nr_controllers         = 1,
 351        .setup                  = pci_versatile_setup,
 352        .scan                   = pci_versatile_scan_bus,
 353        .preinit                = pci_versatile_preinit,
 354};
 355
 356static int __init versatile_pci_init(void)
 357{
 358        pci_common_init(&versatile_pci);
 359        return 0;
 360}
 361
 362subsys_initcall(versatile_pci_init);
 363