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