linux/arch/arm/mach-cns3xxx/pcie.c
<<
>>
Prefs
   1/*
   2 * PCI-E support for CNS3xxx
   3 *
   4 * Copyright 2008 Cavium Networks
   5 *                Richard Liu <richard.liu@caviumnetworks.com>
   6 * Copyright 2010 MontaVista Software, LLC.
   7 *                Anton Vorontsov <avorontsov@mvista.com>
   8 *
   9 * This file is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License, Version 2, as
  11 * published by the Free Software Foundation.
  12 */
  13
  14#include <linux/init.h>
  15#include <linux/kernel.h>
  16#include <linux/bug.h>
  17#include <linux/pci.h>
  18#include <linux/io.h>
  19#include <linux/ioport.h>
  20#include <linux/interrupt.h>
  21#include <linux/ptrace.h>
  22#include <asm/mach/map.h>
  23#include "cns3xxx.h"
  24#include "core.h"
  25
  26struct cns3xxx_pcie {
  27        void __iomem *host_regs; /* PCI config registers for host bridge */
  28        void __iomem *cfg0_regs; /* PCI Type 0 config registers */
  29        void __iomem *cfg1_regs; /* PCI Type 1 config registers */
  30        unsigned int irqs[2];
  31        struct resource res_io;
  32        struct resource res_mem;
  33        int port;
  34        bool linked;
  35};
  36
  37static struct cns3xxx_pcie *sysdata_to_cnspci(void *sysdata)
  38{
  39        struct pci_sys_data *root = sysdata;
  40
  41        return root->private_data;
  42}
  43
  44static struct cns3xxx_pcie *pdev_to_cnspci(const struct pci_dev *dev)
  45{
  46        return sysdata_to_cnspci(dev->sysdata);
  47}
  48
  49static struct cns3xxx_pcie *pbus_to_cnspci(struct pci_bus *bus)
  50{
  51        return sysdata_to_cnspci(bus->sysdata);
  52}
  53
  54static void __iomem *cns3xxx_pci_map_bus(struct pci_bus *bus,
  55                                         unsigned int devfn, int where)
  56{
  57        struct cns3xxx_pcie *cnspci = pbus_to_cnspci(bus);
  58        int busno = bus->number;
  59        int slot = PCI_SLOT(devfn);
  60        void __iomem *base;
  61
  62        /* If there is no link, just show the CNS PCI bridge. */
  63        if (!cnspci->linked && busno > 0)
  64                return NULL;
  65
  66        /*
  67         * The CNS PCI bridge doesn't fit into the PCI hierarchy, though
  68         * we still want to access it.
  69         * We place the host bridge on bus 0, and the directly connected
  70         * device on bus 1, slot 0.
  71         */
  72        if (busno == 0) { /* internal PCIe bus, host bridge device */
  73                if (devfn == 0) /* device# and function# are ignored by hw */
  74                        base = cnspci->host_regs;
  75                else
  76                        return NULL; /* no such device */
  77
  78        } else if (busno == 1) { /* directly connected PCIe device */
  79                if (slot == 0) /* device# is ignored by hw */
  80                        base = cnspci->cfg0_regs;
  81                else
  82                        return NULL; /* no such device */
  83        } else /* remote PCI bus */
  84                base = cnspci->cfg1_regs + ((busno & 0xf) << 20);
  85
  86        return base + (where & 0xffc) + (devfn << 12);
  87}
  88
  89static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
  90                                   int where, int size, u32 *val)
  91{
  92        int ret;
  93        u32 mask = (0x1ull << (size * 8)) - 1;
  94        int shift = (where % 4) * 8;
  95
  96        ret = pci_generic_config_read32(bus, devfn, where, size, val);
  97
  98        if (ret == PCIBIOS_SUCCESSFUL && !bus->number && !devfn &&
  99            (where & 0xffc) == PCI_CLASS_REVISION)
 100                /*
 101                 * RC's class is 0xb, but Linux PCI driver needs 0x604
 102                 * for a PCIe bridge. So we must fixup the class code
 103                 * to 0x604 here.
 104                 */
 105                *val = ((((*val << shift) & 0xff) | (0x604 << 16)) >> shift) & mask;
 106
 107        return ret;
 108}
 109
 110static int cns3xxx_pci_setup(int nr, struct pci_sys_data *sys)
 111{
 112        struct cns3xxx_pcie *cnspci = sysdata_to_cnspci(sys);
 113        struct resource *res_io = &cnspci->res_io;
 114        struct resource *res_mem = &cnspci->res_mem;
 115
 116        BUG_ON(request_resource(&iomem_resource, res_io) ||
 117               request_resource(&iomem_resource, res_mem));
 118
 119        pci_add_resource_offset(&sys->resources, res_io, sys->io_offset);
 120        pci_add_resource_offset(&sys->resources, res_mem, sys->mem_offset);
 121
 122        return 1;
 123}
 124
 125static struct pci_ops cns3xxx_pcie_ops = {
 126        .map_bus = cns3xxx_pci_map_bus,
 127        .read = cns3xxx_pci_read_config,
 128        .write = pci_generic_config_write,
 129};
 130
 131static int cns3xxx_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 132{
 133        struct cns3xxx_pcie *cnspci = pdev_to_cnspci(dev);
 134        int irq = cnspci->irqs[!!dev->bus->number];
 135
 136        pr_info("PCIe map irq: %04d:%02x:%02x.%02x slot %d, pin %d, irq: %d\n",
 137                pci_domain_nr(dev->bus), dev->bus->number, PCI_SLOT(dev->devfn),
 138                PCI_FUNC(dev->devfn), slot, pin, irq);
 139
 140        return irq;
 141}
 142
 143static struct cns3xxx_pcie cns3xxx_pcie[] = {
 144        [0] = {
 145                .host_regs = (void __iomem *)CNS3XXX_PCIE0_HOST_BASE_VIRT,
 146                .cfg0_regs = (void __iomem *)CNS3XXX_PCIE0_CFG0_BASE_VIRT,
 147                .cfg1_regs = (void __iomem *)CNS3XXX_PCIE0_CFG1_BASE_VIRT,
 148                .res_io = {
 149                        .name = "PCIe0 I/O space",
 150                        .start = CNS3XXX_PCIE0_IO_BASE,
 151                        .end = CNS3XXX_PCIE0_CFG0_BASE - 1, /* 16 MiB */
 152                        .flags = IORESOURCE_IO,
 153                },
 154                .res_mem = {
 155                        .name = "PCIe0 non-prefetchable",
 156                        .start = CNS3XXX_PCIE0_MEM_BASE,
 157                        .end = CNS3XXX_PCIE0_HOST_BASE - 1, /* 176 MiB */
 158                        .flags = IORESOURCE_MEM,
 159                },
 160                .irqs = { IRQ_CNS3XXX_PCIE0_RC, IRQ_CNS3XXX_PCIE0_DEVICE, },
 161                .port = 0,
 162        },
 163        [1] = {
 164                .host_regs = (void __iomem *)CNS3XXX_PCIE1_HOST_BASE_VIRT,
 165                .cfg0_regs = (void __iomem *)CNS3XXX_PCIE1_CFG0_BASE_VIRT,
 166                .cfg1_regs = (void __iomem *)CNS3XXX_PCIE1_CFG1_BASE_VIRT,
 167                .res_io = {
 168                        .name = "PCIe1 I/O space",
 169                        .start = CNS3XXX_PCIE1_IO_BASE,
 170                        .end = CNS3XXX_PCIE1_CFG0_BASE - 1, /* 16 MiB */
 171                        .flags = IORESOURCE_IO,
 172                },
 173                .res_mem = {
 174                        .name = "PCIe1 non-prefetchable",
 175                        .start = CNS3XXX_PCIE1_MEM_BASE,
 176                        .end = CNS3XXX_PCIE1_HOST_BASE - 1, /* 176 MiB */
 177                        .flags = IORESOURCE_MEM,
 178                },
 179                .irqs = { IRQ_CNS3XXX_PCIE1_RC, IRQ_CNS3XXX_PCIE1_DEVICE, },
 180                .port = 1,
 181        },
 182};
 183
 184static void __init cns3xxx_pcie_check_link(struct cns3xxx_pcie *cnspci)
 185{
 186        int port = cnspci->port;
 187        u32 reg;
 188        unsigned long time;
 189
 190        reg = __raw_readl(MISC_PCIE_CTRL(port));
 191        /*
 192         * Enable Application Request to 1, it will exit L1 automatically,
 193         * but when chip back, it will use another clock, still can use 0x1.
 194         */
 195        reg |= 0x3;
 196        __raw_writel(reg, MISC_PCIE_CTRL(port));
 197
 198        pr_info("PCIe: Port[%d] Enable PCIe LTSSM\n", port);
 199        pr_info("PCIe: Port[%d] Check data link layer...", port);
 200
 201        time = jiffies;
 202        while (1) {
 203                reg = __raw_readl(MISC_PCIE_PM_DEBUG(port));
 204                if (reg & 0x1) {
 205                        pr_info("Link up.\n");
 206                        cnspci->linked = 1;
 207                        break;
 208                } else if (time_after(jiffies, time + 50)) {
 209                        pr_info("Device not found.\n");
 210                        break;
 211                }
 212        }
 213}
 214
 215static void cns3xxx_write_config(struct cns3xxx_pcie *cnspci,
 216                                         int where, int size, u32 val)
 217{
 218        void __iomem *base = cnspci->host_regs + (where & 0xffc);
 219        u32 v;
 220        u32 mask = (0x1ull << (size * 8)) - 1;
 221        int shift = (where % 4) * 8;
 222
 223        v = readl_relaxed(base);
 224
 225        v &= ~(mask << shift);
 226        v |= (val & mask) << shift;
 227
 228        writel_relaxed(v, base);
 229        readl_relaxed(base);
 230}
 231
 232static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
 233{
 234        u16 mem_base  = cnspci->res_mem.start >> 16;
 235        u16 mem_limit = cnspci->res_mem.end   >> 16;
 236        u16 io_base   = cnspci->res_io.start  >> 16;
 237        u16 io_limit  = cnspci->res_io.end    >> 16;
 238
 239        cns3xxx_write_config(cnspci, PCI_PRIMARY_BUS, 1, 0);
 240        cns3xxx_write_config(cnspci, PCI_SECONDARY_BUS, 1, 1);
 241        cns3xxx_write_config(cnspci, PCI_SUBORDINATE_BUS, 1, 1);
 242        cns3xxx_write_config(cnspci, PCI_MEMORY_BASE, 2, mem_base);
 243        cns3xxx_write_config(cnspci, PCI_MEMORY_LIMIT, 2, mem_limit);
 244        cns3xxx_write_config(cnspci, PCI_IO_BASE_UPPER16, 2, io_base);
 245        cns3xxx_write_config(cnspci, PCI_IO_LIMIT_UPPER16, 2, io_limit);
 246
 247        if (!cnspci->linked)
 248                return;
 249
 250        /* Set Device Max_Read_Request_Size to 128 byte */
 251        pcie_bus_config = PCIE_BUS_PEER2PEER;
 252
 253        /* Disable PCIe0 Interrupt Mask INTA to INTD */
 254        __raw_writel(~0x3FFF, MISC_PCIE_INT_MASK(cnspci->port));
 255}
 256
 257static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr,
 258                                      struct pt_regs *regs)
 259{
 260        if (fsr & (1 << 10))
 261                regs->ARM_pc += 4;
 262        return 0;
 263}
 264
 265void __init cns3xxx_pcie_init_late(void)
 266{
 267        int i;
 268        void *private_data;
 269        struct hw_pci hw_pci = {
 270               .nr_controllers = 1,
 271               .ops = &cns3xxx_pcie_ops,
 272               .setup = cns3xxx_pci_setup,
 273               .map_irq = cns3xxx_pcie_map_irq,
 274               .private_data = &private_data,
 275        };
 276
 277        pcibios_min_io = 0;
 278        pcibios_min_mem = 0;
 279
 280        hook_fault_code(16 + 6, cns3xxx_pcie_abort_handler, SIGBUS, 0,
 281                        "imprecise external abort");
 282
 283        for (i = 0; i < ARRAY_SIZE(cns3xxx_pcie); i++) {
 284                cns3xxx_pwr_clk_en(0x1 << PM_CLK_GATE_REG_OFFSET_PCIE(i));
 285                cns3xxx_pwr_soft_rst(0x1 << PM_SOFT_RST_REG_OFFST_PCIE(i));
 286                cns3xxx_pcie_check_link(&cns3xxx_pcie[i]);
 287                cns3xxx_pcie_hw_init(&cns3xxx_pcie[i]);
 288                private_data = &cns3xxx_pcie[i];
 289                pci_common_init(&hw_pci);
 290        }
 291
 292        pci_assign_unassigned_resources();
 293}
 294