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