linux/arch/mips/pci/pci-xlp.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2003-2012 Broadcom Corporation
   3 * All Rights Reserved
   4 *
   5 * This software is available to you under a choice of one of two
   6 * licenses.  You may choose to be licensed under the terms of the GNU
   7 * General Public License (GPL) Version 2, available from the file
   8 * COPYING in the main directory of this source tree, or the Broadcom
   9 * license below:
  10 *
  11 * Redistribution and use in source and binary forms, with or without
  12 * modification, are permitted provided that the following conditions
  13 * are met:
  14 *
  15 * 1. Redistributions of source code must retain the above copyright
  16 *    notice, this list of conditions and the following disclaimer.
  17 * 2. Redistributions in binary form must reproduce the above copyright
  18 *    notice, this list of conditions and the following disclaimer in
  19 *    the documentation and/or other materials provided with the
  20 *    distribution.
  21 *
  22 * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
  23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25 * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
  26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  29 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  30 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  31 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
  32 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33 */
  34
  35#include <linux/types.h>
  36#include <linux/pci.h>
  37#include <linux/kernel.h>
  38#include <linux/init.h>
  39#include <linux/msi.h>
  40#include <linux/mm.h>
  41#include <linux/irq.h>
  42#include <linux/irqdesc.h>
  43#include <linux/console.h>
  44
  45#include <asm/io.h>
  46
  47#include <asm/netlogic/interrupt.h>
  48#include <asm/netlogic/haldefs.h>
  49#include <asm/netlogic/common.h>
  50
  51#include <asm/netlogic/xlp-hal/iomap.h>
  52#include <asm/netlogic/xlp-hal/pic.h>
  53#include <asm/netlogic/xlp-hal/xlp.h>
  54#include <asm/netlogic/xlp-hal/pcibus.h>
  55#include <asm/netlogic/xlp-hal/bridge.h>
  56
  57static void *pci_config_base;
  58
  59#define pci_cfg_addr(bus, devfn, off) (((bus) << 20) | ((devfn) << 12) | (off))
  60
  61/* PCI ops */
  62static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,
  63        int where)
  64{
  65        u32 data;
  66        u32 *cfgaddr;
  67
  68        where &= ~3;
  69        if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954)
  70                return 0xffffffff;
  71
  72        cfgaddr = (u32 *)(pci_config_base +
  73                        pci_cfg_addr(bus->number, devfn, where));
  74        data = *cfgaddr;
  75        return data;
  76}
  77
  78static inline void pci_cfg_write_32bit(struct pci_bus *bus, unsigned int devfn,
  79        int where, u32 data)
  80{
  81        u32 *cfgaddr;
  82
  83        cfgaddr = (u32 *)(pci_config_base +
  84                        pci_cfg_addr(bus->number, devfn, where & ~3));
  85        *cfgaddr = data;
  86}
  87
  88static int nlm_pcibios_read(struct pci_bus *bus, unsigned int devfn,
  89        int where, int size, u32 *val)
  90{
  91        u32 data;
  92
  93        if ((size == 2) && (where & 1))
  94                return PCIBIOS_BAD_REGISTER_NUMBER;
  95        else if ((size == 4) && (where & 3))
  96                return PCIBIOS_BAD_REGISTER_NUMBER;
  97
  98        data = pci_cfg_read_32bit(bus, devfn, where);
  99
 100        if (size == 1)
 101                *val = (data >> ((where & 3) << 3)) & 0xff;
 102        else if (size == 2)
 103                *val = (data >> ((where & 3) << 3)) & 0xffff;
 104        else
 105                *val = data;
 106
 107        return PCIBIOS_SUCCESSFUL;
 108}
 109
 110
 111static int nlm_pcibios_write(struct pci_bus *bus, unsigned int devfn,
 112                int where, int size, u32 val)
 113{
 114        u32 data;
 115
 116        if ((size == 2) && (where & 1))
 117                return PCIBIOS_BAD_REGISTER_NUMBER;
 118        else if ((size == 4) && (where & 3))
 119                return PCIBIOS_BAD_REGISTER_NUMBER;
 120
 121        data = pci_cfg_read_32bit(bus, devfn, where);
 122
 123        if (size == 1)
 124                data = (data & ~(0xff << ((where & 3) << 3))) |
 125                        (val << ((where & 3) << 3));
 126        else if (size == 2)
 127                data = (data & ~(0xffff << ((where & 3) << 3))) |
 128                        (val << ((where & 3) << 3));
 129        else
 130                data = val;
 131
 132        pci_cfg_write_32bit(bus, devfn, where, data);
 133
 134        return PCIBIOS_SUCCESSFUL;
 135}
 136
 137struct pci_ops nlm_pci_ops = {
 138        .read  = nlm_pcibios_read,
 139        .write = nlm_pcibios_write
 140};
 141
 142static struct resource nlm_pci_mem_resource = {
 143        .name           = "XLP PCI MEM",
 144        .start          = 0xd0000000UL, /* 256MB PCI mem @ 0xd000_0000 */
 145        .end            = 0xdfffffffUL,
 146        .flags          = IORESOURCE_MEM,
 147};
 148
 149static struct resource nlm_pci_io_resource = {
 150        .name           = "XLP IO MEM",
 151        .start          = 0x14000000UL, /* 64MB PCI IO @ 0x1000_0000 */
 152        .end            = 0x17ffffffUL,
 153        .flags          = IORESOURCE_IO,
 154};
 155
 156struct pci_controller nlm_pci_controller = {
 157        .index          = 0,
 158        .pci_ops        = &nlm_pci_ops,
 159        .mem_resource   = &nlm_pci_mem_resource,
 160        .mem_offset     = 0x00000000UL,
 161        .io_resource    = &nlm_pci_io_resource,
 162        .io_offset      = 0x00000000UL,
 163};
 164
 165static struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev)
 166{
 167        struct pci_bus *bus, *p;
 168
 169        /* Find the bridge on bus 0 */
 170        bus = dev->bus;
 171        for (p = bus->parent; p && p->number != 0; p = p->parent)
 172                bus = p;
 173
 174        return p ? bus->self : NULL;
 175}
 176
 177static inline int nlm_pci_link_to_irq(int link)
 178{
 179        return PIC_PCIE_LINK_0_IRQ + link;
 180}
 181
 182int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 183{
 184        struct pci_dev *lnkdev;
 185        int lnkslot, lnkfunc;
 186
 187        /*
 188         * For XLP PCIe, there is an IRQ per Link, find out which
 189         * link the device is on to assign interrupts
 190        */
 191        lnkdev = xlp_get_pcie_link(dev);
 192        if (lnkdev == NULL)
 193                return 0;
 194        lnkfunc = PCI_FUNC(lnkdev->devfn);
 195        lnkslot = PCI_SLOT(lnkdev->devfn);
 196        return nlm_irq_to_xirq(lnkslot / 8, nlm_pci_link_to_irq(lnkfunc));
 197}
 198
 199/* Do platform specific device initialization at pci_enable_device() time */
 200int pcibios_plat_dev_init(struct pci_dev *dev)
 201{
 202        return 0;
 203}
 204
 205/*
 206 * If big-endian, enable hardware byteswap on the PCIe bridges.
 207 * This will make both the SoC and PCIe devices behave consistently with
 208 * readl/writel.
 209 */
 210#ifdef __BIG_ENDIAN
 211static void xlp_config_pci_bswap(int node, int link)
 212{
 213        uint64_t nbubase, lnkbase;
 214        u32 reg;
 215
 216        nbubase = nlm_get_bridge_regbase(node);
 217        lnkbase = nlm_get_pcie_base(node, link);
 218
 219        /*
 220         *  Enable byte swap in hardware. Program each link's PCIe SWAP regions
 221         * from the link's address ranges.
 222         */
 223        reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link);
 224        nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg);
 225
 226        reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_LIMIT0 + link);
 227        nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff);
 228
 229        reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link);
 230        nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg);
 231
 232        reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link);
 233        nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);
 234}
 235#else
 236/* Swap configuration not needed in little-endian mode */
 237static inline void xlp_config_pci_bswap(int node, int link) {}
 238#endif /* __BIG_ENDIAN */
 239
 240static int __init pcibios_init(void)
 241{
 242        struct nlm_soc_info *nodep;
 243        uint64_t pciebase;
 244        int link, n;
 245        u32 reg;
 246
 247        /* Firmware assigns PCI resources */
 248        pci_set_flags(PCI_PROBE_ONLY);
 249        pci_config_base = ioremap(XLP_DEFAULT_PCI_ECFG_BASE, 64 << 20);
 250
 251        /* Extend IO port for memory mapped io */
 252        ioport_resource.start =  0;
 253        ioport_resource.end   = ~0;
 254
 255        for (n = 0; n < NLM_NR_NODES; n++) {
 256                nodep = nlm_get_node(n);
 257                if (!nodep->coremask)
 258                        continue;       /* node does not exist */
 259
 260                for (link = 0; link < 4; link++) {
 261                        pciebase = nlm_get_pcie_base(n, link);
 262                        if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff)
 263                                continue;
 264                        xlp_config_pci_bswap(n, link);
 265
 266                        /* put in intpin and irq - u-boot does not */
 267                        reg = nlm_read_pci_reg(pciebase, 0xf);
 268                        reg &= ~0x1fu;
 269                        reg |= (1 << 8) | nlm_pci_link_to_irq(link);
 270                        nlm_write_pci_reg(pciebase, 0xf, reg);
 271                        pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link);
 272                }
 273        }
 274
 275        set_io_port_base(CKSEG1);
 276        nlm_pci_controller.io_map_base = CKSEG1;
 277
 278        register_pci_controller(&nlm_pci_controller);
 279        pr_info("XLP PCIe Controller %pR%pR.\n", &nlm_pci_io_resource,
 280                &nlm_pci_mem_resource);
 281
 282        return 0;
 283}
 284arch_initcall(pcibios_init);
 285