linux/arch/arm/mach-mv78xx0/pcie.c
<<
>>
Prefs
   1/*
   2 * arch/arm/mach-mv78xx0/pcie.c
   3 *
   4 * PCIe functions for Marvell MV78xx0 SoCs
   5 *
   6 * This file is licensed under the terms of the GNU General Public
   7 * License version 2.  This program is licensed "as is" without any
   8 * warranty of any kind, whether express or implied.
   9 */
  10
  11#include <linux/kernel.h>
  12#include <linux/pci.h>
  13#include <linux/mbus.h>
  14#include <asm/irq.h>
  15#include <asm/mach/pci.h>
  16#include <plat/pcie.h>
  17#include "common.h"
  18
  19struct pcie_port {
  20        u8                      maj;
  21        u8                      min;
  22        u8                      root_bus_nr;
  23        void __iomem            *base;
  24        spinlock_t              conf_lock;
  25        char                    io_space_name[16];
  26        char                    mem_space_name[16];
  27        struct resource         res[2];
  28};
  29
  30static struct pcie_port pcie_port[8];
  31static int num_pcie_ports;
  32static struct resource pcie_io_space;
  33static struct resource pcie_mem_space;
  34
  35
  36void __init mv78xx0_pcie_id(u32 *dev, u32 *rev)
  37{
  38        *dev = orion_pcie_dev_id((void __iomem *)PCIE00_VIRT_BASE);
  39        *rev = orion_pcie_rev((void __iomem *)PCIE00_VIRT_BASE);
  40}
  41
  42static void __init mv78xx0_pcie_preinit(void)
  43{
  44        int i;
  45        u32 size_each;
  46        u32 start;
  47        int win;
  48
  49        pcie_io_space.name = "PCIe I/O Space";
  50        pcie_io_space.start = MV78XX0_PCIE_IO_PHYS_BASE(0);
  51        pcie_io_space.end =
  52                MV78XX0_PCIE_IO_PHYS_BASE(0) + MV78XX0_PCIE_IO_SIZE * 8 - 1;
  53        pcie_io_space.flags = IORESOURCE_IO;
  54        if (request_resource(&iomem_resource, &pcie_io_space))
  55                panic("can't allocate PCIe I/O space");
  56
  57        pcie_mem_space.name = "PCIe MEM Space";
  58        pcie_mem_space.start = MV78XX0_PCIE_MEM_PHYS_BASE;
  59        pcie_mem_space.end =
  60                MV78XX0_PCIE_MEM_PHYS_BASE + MV78XX0_PCIE_MEM_SIZE - 1;
  61        pcie_mem_space.flags = IORESOURCE_MEM;
  62        if (request_resource(&iomem_resource, &pcie_mem_space))
  63                panic("can't allocate PCIe MEM space");
  64
  65        for (i = 0; i < num_pcie_ports; i++) {
  66                struct pcie_port *pp = pcie_port + i;
  67
  68                snprintf(pp->io_space_name, sizeof(pp->io_space_name),
  69                        "PCIe %d.%d I/O", pp->maj, pp->min);
  70                pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
  71                pp->res[0].name = pp->io_space_name;
  72                pp->res[0].start = MV78XX0_PCIE_IO_PHYS_BASE(i);
  73                pp->res[0].end = pp->res[0].start + MV78XX0_PCIE_IO_SIZE - 1;
  74                pp->res[0].flags = IORESOURCE_IO;
  75
  76                snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
  77                        "PCIe %d.%d MEM", pp->maj, pp->min);
  78                pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
  79                pp->res[1].name = pp->mem_space_name;
  80                pp->res[1].flags = IORESOURCE_MEM;
  81        }
  82
  83        switch (num_pcie_ports) {
  84        case 0:
  85                size_each = 0;
  86                break;
  87
  88        case 1:
  89                size_each = 0x30000000;
  90                break;
  91
  92        case 2 ... 3:
  93                size_each = 0x10000000;
  94                break;
  95
  96        case 4 ... 6:
  97                size_each = 0x08000000;
  98                break;
  99
 100        case 7:
 101                size_each = 0x04000000;
 102                break;
 103
 104        default:
 105                panic("invalid number of PCIe ports");
 106        }
 107
 108        start = MV78XX0_PCIE_MEM_PHYS_BASE;
 109        for (i = 0; i < num_pcie_ports; i++) {
 110                struct pcie_port *pp = pcie_port + i;
 111
 112                pp->res[1].start = start;
 113                pp->res[1].end = start + size_each - 1;
 114                start += size_each;
 115        }
 116
 117        for (i = 0; i < num_pcie_ports; i++) {
 118                struct pcie_port *pp = pcie_port + i;
 119
 120                if (request_resource(&pcie_io_space, &pp->res[0]))
 121                        panic("can't allocate PCIe I/O sub-space");
 122
 123                if (request_resource(&pcie_mem_space, &pp->res[1]))
 124                        panic("can't allocate PCIe MEM sub-space");
 125        }
 126
 127        win = 0;
 128        for (i = 0; i < num_pcie_ports; i++) {
 129                struct pcie_port *pp = pcie_port + i;
 130
 131                mv78xx0_setup_pcie_io_win(win++, pp->res[0].start,
 132                        pp->res[0].end - pp->res[0].start + 1,
 133                        pp->maj, pp->min);
 134
 135                mv78xx0_setup_pcie_mem_win(win++, pp->res[1].start,
 136                        pp->res[1].end - pp->res[1].start + 1,
 137                        pp->maj, pp->min);
 138        }
 139}
 140
 141static int __init mv78xx0_pcie_setup(int nr, struct pci_sys_data *sys)
 142{
 143        struct pcie_port *pp;
 144
 145        if (nr >= num_pcie_ports)
 146                return 0;
 147
 148        pp = &pcie_port[nr];
 149        pp->root_bus_nr = sys->busnr;
 150
 151        /*
 152         * Generic PCIe unit setup.
 153         */
 154        orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
 155        orion_pcie_setup(pp->base, &mv78xx0_mbus_dram_info);
 156
 157        sys->resource[0] = &pp->res[0];
 158        sys->resource[1] = &pp->res[1];
 159        sys->resource[2] = NULL;
 160
 161        return 1;
 162}
 163
 164static struct pcie_port *bus_to_port(int bus)
 165{
 166        int i;
 167
 168        for (i = num_pcie_ports - 1; i >= 0; i--) {
 169                int rbus = pcie_port[i].root_bus_nr;
 170                if (rbus != -1 && rbus <= bus)
 171                        break;
 172        }
 173
 174        return i >= 0 ? pcie_port + i : NULL;
 175}
 176
 177static int pcie_valid_config(struct pcie_port *pp, int bus, int dev)
 178{
 179        /*
 180         * Don't go out when trying to access nonexisting devices
 181         * on the local bus.
 182         */
 183        if (bus == pp->root_bus_nr && dev > 1)
 184                return 0;
 185
 186        return 1;
 187}
 188
 189static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
 190                        int size, u32 *val)
 191{
 192        struct pcie_port *pp = bus_to_port(bus->number);
 193        unsigned long flags;
 194        int ret;
 195
 196        if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) {
 197                *val = 0xffffffff;
 198                return PCIBIOS_DEVICE_NOT_FOUND;
 199        }
 200
 201        spin_lock_irqsave(&pp->conf_lock, flags);
 202        ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val);
 203        spin_unlock_irqrestore(&pp->conf_lock, flags);
 204
 205        return ret;
 206}
 207
 208static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
 209                        int where, int size, u32 val)
 210{
 211        struct pcie_port *pp = bus_to_port(bus->number);
 212        unsigned long flags;
 213        int ret;
 214
 215        if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0)
 216                return PCIBIOS_DEVICE_NOT_FOUND;
 217
 218        spin_lock_irqsave(&pp->conf_lock, flags);
 219        ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val);
 220        spin_unlock_irqrestore(&pp->conf_lock, flags);
 221
 222        return ret;
 223}
 224
 225static struct pci_ops pcie_ops = {
 226        .read = pcie_rd_conf,
 227        .write = pcie_wr_conf,
 228};
 229
 230static void __devinit rc_pci_fixup(struct pci_dev *dev)
 231{
 232        /*
 233         * Prevent enumeration of root complex.
 234         */
 235        if (dev->bus->parent == NULL && dev->devfn == 0) {
 236                int i;
 237
 238                for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
 239                        dev->resource[i].start = 0;
 240                        dev->resource[i].end   = 0;
 241                        dev->resource[i].flags = 0;
 242                }
 243        }
 244}
 245DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup);
 246
 247static struct pci_bus __init *
 248mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 249{
 250        struct pci_bus *bus;
 251
 252        if (nr < num_pcie_ports) {
 253                bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
 254        } else {
 255                bus = NULL;
 256                BUG();
 257        }
 258
 259        return bus;
 260}
 261
 262static int __init mv78xx0_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 263{
 264        struct pcie_port *pp = bus_to_port(dev->bus->number);
 265
 266        return IRQ_MV78XX0_PCIE_00 + (pp->maj << 2) + pp->min;
 267}
 268
 269static struct hw_pci mv78xx0_pci __initdata = {
 270        .nr_controllers = 8,
 271        .preinit        = mv78xx0_pcie_preinit,
 272        .swizzle        = pci_std_swizzle,
 273        .setup          = mv78xx0_pcie_setup,
 274        .scan           = mv78xx0_pcie_scan_bus,
 275        .map_irq        = mv78xx0_pcie_map_irq,
 276};
 277
 278static void __init add_pcie_port(int maj, int min, unsigned long base)
 279{
 280        printk(KERN_INFO "MV78xx0 PCIe port %d.%d: ", maj, min);
 281
 282        if (orion_pcie_link_up((void __iomem *)base)) {
 283                struct pcie_port *pp = &pcie_port[num_pcie_ports++];
 284
 285                printk("link up\n");
 286
 287                pp->maj = maj;
 288                pp->min = min;
 289                pp->root_bus_nr = -1;
 290                pp->base = (void __iomem *)base;
 291                spin_lock_init(&pp->conf_lock);
 292                memset(pp->res, 0, sizeof(pp->res));
 293        } else {
 294                printk("link down, ignoring\n");
 295        }
 296}
 297
 298void __init mv78xx0_pcie_init(int init_port0, int init_port1)
 299{
 300        if (init_port0) {
 301                add_pcie_port(0, 0, PCIE00_VIRT_BASE);
 302                if (!orion_pcie_x4_mode((void __iomem *)PCIE00_VIRT_BASE)) {
 303                        add_pcie_port(0, 1, PCIE01_VIRT_BASE);
 304                        add_pcie_port(0, 2, PCIE02_VIRT_BASE);
 305                        add_pcie_port(0, 3, PCIE03_VIRT_BASE);
 306                }
 307        }
 308
 309        if (init_port1) {
 310                add_pcie_port(1, 0, PCIE10_VIRT_BASE);
 311                if (!orion_pcie_x4_mode((void __iomem *)PCIE10_VIRT_BASE)) {
 312                        add_pcie_port(1, 1, PCIE11_VIRT_BASE);
 313                        add_pcie_port(1, 2, PCIE12_VIRT_BASE);
 314                        add_pcie_port(1, 3, PCIE13_VIRT_BASE);
 315                }
 316        }
 317
 318        pci_common_init(&mv78xx0_pci);
 319}
 320