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 <video/vga.h>
  14#include <asm/irq.h>
  15#include <asm/mach/pci.h>
  16#include <plat/pcie.h>
  17#include <plat/addr-map.h>
  18#include <mach/mv78xx0.h>
  19#include "common.h"
  20
  21struct pcie_port {
  22        u8                      maj;
  23        u8                      min;
  24        u8                      root_bus_nr;
  25        void __iomem            *base;
  26        spinlock_t              conf_lock;
  27        char                    mem_space_name[16];
  28        struct resource         res;
  29};
  30
  31static struct pcie_port pcie_port[8];
  32static int num_pcie_ports;
  33static struct resource pcie_io_space;
  34
  35void __init mv78xx0_pcie_id(u32 *dev, u32 *rev)
  36{
  37        *dev = orion_pcie_dev_id(PCIE00_VIRT_BASE);
  38        *rev = orion_pcie_rev(PCIE00_VIRT_BASE);
  39}
  40
  41u32 pcie_port_size[8] = {
  42        0,
  43        0x30000000,
  44        0x10000000,
  45        0x10000000,
  46        0x08000000,
  47        0x08000000,
  48        0x08000000,
  49        0x04000000,
  50};
  51
  52static void __init mv78xx0_pcie_preinit(void)
  53{
  54        int i;
  55        u32 size_each;
  56        u32 start;
  57        int win = 0;
  58
  59        pcie_io_space.name = "PCIe I/O Space";
  60        pcie_io_space.start = MV78XX0_PCIE_IO_PHYS_BASE(0);
  61        pcie_io_space.end =
  62                MV78XX0_PCIE_IO_PHYS_BASE(0) + MV78XX0_PCIE_IO_SIZE * 8 - 1;
  63        pcie_io_space.flags = IORESOURCE_MEM;
  64        if (request_resource(&iomem_resource, &pcie_io_space))
  65                panic("can't allocate PCIe I/O space");
  66
  67        if (num_pcie_ports > 7)
  68                panic("invalid number of PCIe ports");
  69
  70        size_each = pcie_port_size[num_pcie_ports];
  71
  72        start = MV78XX0_PCIE_MEM_PHYS_BASE;
  73        for (i = 0; i < num_pcie_ports; i++) {
  74                struct pcie_port *pp = pcie_port + i;
  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.name = pp->mem_space_name;
  80                pp->res.flags = IORESOURCE_MEM;
  81                pp->res.start = start;
  82                pp->res.end = start + size_each - 1;
  83                start += size_each;
  84
  85                if (request_resource(&iomem_resource, &pp->res))
  86                        panic("can't allocate PCIe MEM sub-space");
  87
  88                mv78xx0_setup_pcie_mem_win(win + i + 8, pp->res.start,
  89                                           resource_size(&pp->res),
  90                                           pp->maj, pp->min);
  91
  92                mv78xx0_setup_pcie_io_win(win + i, i * SZ_64K, SZ_64K,
  93                                          pp->maj, pp->min);
  94        }
  95}
  96
  97static int __init mv78xx0_pcie_setup(int nr, struct pci_sys_data *sys)
  98{
  99        struct pcie_port *pp;
 100
 101        if (nr >= num_pcie_ports)
 102                return 0;
 103
 104        pp = &pcie_port[nr];
 105        sys->private_data = pp;
 106        pp->root_bus_nr = sys->busnr;
 107
 108        /*
 109         * Generic PCIe unit setup.
 110         */
 111        orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
 112        orion_pcie_setup(pp->base);
 113
 114        pci_ioremap_io(nr * SZ_64K, MV78XX0_PCIE_IO_PHYS_BASE(nr));
 115
 116        pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
 117
 118        return 1;
 119}
 120
 121static int pcie_valid_config(struct pcie_port *pp, int bus, int dev)
 122{
 123        /*
 124         * Don't go out when trying to access nonexisting devices
 125         * on the local bus.
 126         */
 127        if (bus == pp->root_bus_nr && dev > 1)
 128                return 0;
 129
 130        return 1;
 131}
 132
 133static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
 134                        int size, u32 *val)
 135{
 136        struct pci_sys_data *sys = bus->sysdata;
 137        struct pcie_port *pp = sys->private_data;
 138        unsigned long flags;
 139        int ret;
 140
 141        if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0) {
 142                *val = 0xffffffff;
 143                return PCIBIOS_DEVICE_NOT_FOUND;
 144        }
 145
 146        spin_lock_irqsave(&pp->conf_lock, flags);
 147        ret = orion_pcie_rd_conf(pp->base, bus, devfn, where, size, val);
 148        spin_unlock_irqrestore(&pp->conf_lock, flags);
 149
 150        return ret;
 151}
 152
 153static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
 154                        int where, int size, u32 val)
 155{
 156        struct pci_sys_data *sys = bus->sysdata;
 157        struct pcie_port *pp = sys->private_data;
 158        unsigned long flags;
 159        int ret;
 160
 161        if (pcie_valid_config(pp, bus->number, PCI_SLOT(devfn)) == 0)
 162                return PCIBIOS_DEVICE_NOT_FOUND;
 163
 164        spin_lock_irqsave(&pp->conf_lock, flags);
 165        ret = orion_pcie_wr_conf(pp->base, bus, devfn, where, size, val);
 166        spin_unlock_irqrestore(&pp->conf_lock, flags);
 167
 168        return ret;
 169}
 170
 171static struct pci_ops pcie_ops = {
 172        .read = pcie_rd_conf,
 173        .write = pcie_wr_conf,
 174};
 175
 176static void __devinit rc_pci_fixup(struct pci_dev *dev)
 177{
 178        /*
 179         * Prevent enumeration of root complex.
 180         */
 181        if (dev->bus->parent == NULL && dev->devfn == 0) {
 182                int i;
 183
 184                for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
 185                        dev->resource[i].start = 0;
 186                        dev->resource[i].end   = 0;
 187                        dev->resource[i].flags = 0;
 188                }
 189        }
 190}
 191DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup);
 192
 193static struct pci_bus __init *
 194mv78xx0_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 195{
 196        struct pci_bus *bus;
 197
 198        if (nr < num_pcie_ports) {
 199                bus = pci_scan_root_bus(NULL, sys->busnr, &pcie_ops, sys,
 200                                        &sys->resources);
 201        } else {
 202                bus = NULL;
 203                BUG();
 204        }
 205
 206        return bus;
 207}
 208
 209static int __init mv78xx0_pcie_map_irq(const struct pci_dev *dev, u8 slot,
 210        u8 pin)
 211{
 212        struct pci_sys_data *sys = dev->bus->sysdata;
 213        struct pcie_port *pp = sys->private_data;
 214
 215        return IRQ_MV78XX0_PCIE_00 + (pp->maj << 2) + pp->min;
 216}
 217
 218static struct hw_pci mv78xx0_pci __initdata = {
 219        .nr_controllers = 8,
 220        .preinit        = mv78xx0_pcie_preinit,
 221        .setup          = mv78xx0_pcie_setup,
 222        .scan           = mv78xx0_pcie_scan_bus,
 223        .map_irq        = mv78xx0_pcie_map_irq,
 224};
 225
 226static void __init add_pcie_port(int maj, int min, void __iomem *base)
 227{
 228        printk(KERN_INFO "MV78xx0 PCIe port %d.%d: ", maj, min);
 229
 230        if (orion_pcie_link_up(base)) {
 231                struct pcie_port *pp = &pcie_port[num_pcie_ports++];
 232
 233                printk("link up\n");
 234
 235                pp->maj = maj;
 236                pp->min = min;
 237                pp->root_bus_nr = -1;
 238                pp->base = base;
 239                spin_lock_init(&pp->conf_lock);
 240                memset(&pp->res, 0, sizeof(pp->res));
 241        } else {
 242                printk("link down, ignoring\n");
 243        }
 244}
 245
 246void __init mv78xx0_pcie_init(int init_port0, int init_port1)
 247{
 248        vga_base = MV78XX0_PCIE_MEM_PHYS_BASE;
 249
 250        if (init_port0) {
 251                add_pcie_port(0, 0, PCIE00_VIRT_BASE);
 252                if (!orion_pcie_x4_mode(PCIE00_VIRT_BASE)) {
 253                        add_pcie_port(0, 1, PCIE01_VIRT_BASE);
 254                        add_pcie_port(0, 2, PCIE02_VIRT_BASE);
 255                        add_pcie_port(0, 3, PCIE03_VIRT_BASE);
 256                }
 257        }
 258
 259        if (init_port1) {
 260                add_pcie_port(1, 0, PCIE10_VIRT_BASE);
 261                if (!orion_pcie_x4_mode((void __iomem *)PCIE10_VIRT_BASE)) {
 262                        add_pcie_port(1, 1, PCIE11_VIRT_BASE);
 263                        add_pcie_port(1, 2, PCIE12_VIRT_BASE);
 264                        add_pcie_port(1, 3, PCIE13_VIRT_BASE);
 265                }
 266        }
 267
 268        pci_common_init(&mv78xx0_pci);
 269}
 270