linux/arch/arm/mach-kirkwood/pcie.c
<<
>>
Prefs
   1/*
   2 * arch/arm/mach-kirkwood/pcie.c
   3 *
   4 * PCIe functions for Marvell Kirkwood 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 <mach/bridge-regs.h>
  18#include "common.h"
  19
  20
  21#define PCIE_BASE       ((void __iomem *)PCIE_VIRT_BASE)
  22
  23void __init kirkwood_pcie_id(u32 *dev, u32 *rev)
  24{
  25        *dev = orion_pcie_dev_id(PCIE_BASE);
  26        *rev = orion_pcie_rev(PCIE_BASE);
  27}
  28
  29static int pcie_valid_config(int bus, int dev)
  30{
  31        /*
  32         * Don't go out when trying to access --
  33         * 1. nonexisting device on local bus
  34         * 2. where there's no device connected (no link)
  35         */
  36        if (bus == 0 && dev == 0)
  37                return 1;
  38
  39        if (!orion_pcie_link_up(PCIE_BASE))
  40                return 0;
  41
  42        if (bus == 0 && dev != 1)
  43                return 0;
  44
  45        return 1;
  46}
  47
  48
  49/*
  50 * PCIe config cycles are done by programming the PCIE_CONF_ADDR register
  51 * and then reading the PCIE_CONF_DATA register. Need to make sure these
  52 * transactions are atomic.
  53 */
  54static DEFINE_SPINLOCK(kirkwood_pcie_lock);
  55
  56static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
  57                        int size, u32 *val)
  58{
  59        unsigned long flags;
  60        int ret;
  61
  62        if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0) {
  63                *val = 0xffffffff;
  64                return PCIBIOS_DEVICE_NOT_FOUND;
  65        }
  66
  67        spin_lock_irqsave(&kirkwood_pcie_lock, flags);
  68        ret = orion_pcie_rd_conf(PCIE_BASE, bus, devfn, where, size, val);
  69        spin_unlock_irqrestore(&kirkwood_pcie_lock, flags);
  70
  71        return ret;
  72}
  73
  74static int pcie_wr_conf(struct pci_bus *bus, u32 devfn,
  75                        int where, int size, u32 val)
  76{
  77        unsigned long flags;
  78        int ret;
  79
  80        if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0)
  81                return PCIBIOS_DEVICE_NOT_FOUND;
  82
  83        spin_lock_irqsave(&kirkwood_pcie_lock, flags);
  84        ret = orion_pcie_wr_conf(PCIE_BASE, bus, devfn, where, size, val);
  85        spin_unlock_irqrestore(&kirkwood_pcie_lock, flags);
  86
  87        return ret;
  88}
  89
  90static struct pci_ops pcie_ops = {
  91        .read = pcie_rd_conf,
  92        .write = pcie_wr_conf,
  93};
  94
  95
  96static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
  97{
  98        struct resource *res;
  99        extern unsigned int kirkwood_clk_ctrl;
 100
 101        /*
 102         * Generic PCIe unit setup.
 103         */
 104        orion_pcie_setup(PCIE_BASE, &kirkwood_mbus_dram_info);
 105
 106        /*
 107         * Request resources.
 108         */
 109        res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
 110        if (!res)
 111                panic("pcie_setup unable to alloc resources");
 112
 113        /*
 114         * IORESOURCE_IO
 115         */
 116        res[0].name = "PCIe I/O Space";
 117        res[0].flags = IORESOURCE_IO;
 118        res[0].start = KIRKWOOD_PCIE_IO_BUS_BASE;
 119        res[0].end = res[0].start + KIRKWOOD_PCIE_IO_SIZE - 1;
 120        if (request_resource(&ioport_resource, &res[0]))
 121                panic("Request PCIe IO resource failed\n");
 122        sys->resource[0] = &res[0];
 123
 124        /*
 125         * IORESOURCE_MEM
 126         */
 127        res[1].name = "PCIe Memory Space";
 128        res[1].flags = IORESOURCE_MEM;
 129        res[1].start = KIRKWOOD_PCIE_MEM_BUS_BASE;
 130        res[1].end = res[1].start + KIRKWOOD_PCIE_MEM_SIZE - 1;
 131        if (request_resource(&iomem_resource, &res[1]))
 132                panic("Request PCIe Memory resource failed\n");
 133        sys->resource[1] = &res[1];
 134
 135        sys->resource[2] = NULL;
 136        sys->io_offset = 0;
 137
 138        kirkwood_clk_ctrl |= CGC_PEX0;
 139
 140        return 1;
 141}
 142
 143static void __devinit rc_pci_fixup(struct pci_dev *dev)
 144{
 145        /*
 146         * Prevent enumeration of root complex.
 147         */
 148        if (dev->bus->parent == NULL && dev->devfn == 0) {
 149                int i;
 150
 151                for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
 152                        dev->resource[i].start = 0;
 153                        dev->resource[i].end   = 0;
 154                        dev->resource[i].flags = 0;
 155                }
 156        }
 157}
 158DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup);
 159
 160static struct pci_bus __init *
 161kirkwood_pcie_scan_bus(int nr, struct pci_sys_data *sys)
 162{
 163        struct pci_bus *bus;
 164
 165        if (nr == 0) {
 166                bus = pci_scan_bus(sys->busnr, &pcie_ops, sys);
 167        } else {
 168                bus = NULL;
 169                BUG();
 170        }
 171
 172        return bus;
 173}
 174
 175static int __init kirkwood_pcie_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
 176{
 177        return IRQ_KIRKWOOD_PCIE;
 178}
 179
 180static struct hw_pci kirkwood_pci __initdata = {
 181        .nr_controllers = 1,
 182        .swizzle        = pci_std_swizzle,
 183        .setup          = kirkwood_pcie_setup,
 184        .scan           = kirkwood_pcie_scan_bus,
 185        .map_irq        = kirkwood_pcie_map_irq,
 186};
 187
 188void __init kirkwood_pcie_init(void)
 189{
 190        pci_common_init(&kirkwood_pci);
 191}
 192
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.