linux/drivers/pci/cadence/pcie-cadence-host.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (c) 2017 Cadence
   3// Cadence PCIe host controller driver.
   4// Author: Cyrille Pitchen <cyrille.pitchen@free-electrons.com>
   5
   6#include <linux/kernel.h>
   7#include <linux/of_address.h>
   8#include <linux/of_pci.h>
   9#include <linux/platform_device.h>
  10#include <linux/pm_runtime.h>
  11
  12#include "pcie-cadence.h"
  13
  14/**
  15 * struct cdns_pcie_rc - private data for this PCIe Root Complex driver
  16 * @pcie: Cadence PCIe controller
  17 * @dev: pointer to PCIe device
  18 * @cfg_res: start/end offsets in the physical system memory to map PCI
  19 *           configuration space accesses
  20 * @bus_range: first/last buses behind the PCIe host controller
  21 * @cfg_base: IO mapped window to access the PCI configuration space of a
  22 *            single function at a time
  23 * @max_regions: maximum number of regions supported by the hardware
  24 * @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address
  25 *                translation (nbits sets into the "no BAR match" register)
  26 * @vendor_id: PCI vendor ID
  27 * @device_id: PCI device ID
  28 */
  29struct cdns_pcie_rc {
  30        struct cdns_pcie        pcie;
  31        struct device           *dev;
  32        struct resource         *cfg_res;
  33        struct resource         *bus_range;
  34        void __iomem            *cfg_base;
  35        u32                     max_regions;
  36        u32                     no_bar_nbits;
  37        u16                     vendor_id;
  38        u16                     device_id;
  39};
  40
  41static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
  42                                      int where)
  43{
  44        struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
  45        struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
  46        struct cdns_pcie *pcie = &rc->pcie;
  47        unsigned int busn = bus->number;
  48        u32 addr0, desc0;
  49
  50        if (busn == rc->bus_range->start) {
  51                /*
  52                 * Only the root port (devfn == 0) is connected to this bus.
  53                 * All other PCI devices are behind some bridge hence on another
  54                 * bus.
  55                 */
  56                if (devfn)
  57                        return NULL;
  58
  59                return pcie->reg_base + (where & 0xfff);
  60        }
  61
  62        /* Update Output registers for AXI region 0. */
  63        addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
  64                CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
  65                CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn);
  66        cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0);
  67
  68        /* Configuration Type 0 or Type 1 access. */
  69        desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
  70                CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
  71        /*
  72         * The bus number was already set once for all in desc1 by
  73         * cdns_pcie_host_init_address_translation().
  74         */
  75        if (busn == rc->bus_range->start + 1)
  76                desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
  77        else
  78                desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
  79        cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0);
  80
  81        return rc->cfg_base + (where & 0xfff);
  82}
  83
  84static struct pci_ops cdns_pcie_host_ops = {
  85        .map_bus        = cdns_pci_map_bus,
  86        .read           = pci_generic_config_read,
  87        .write          = pci_generic_config_write,
  88};
  89
  90static const struct of_device_id cdns_pcie_host_of_match[] = {
  91        { .compatible = "cdns,cdns-pcie-host" },
  92
  93        { },
  94};
  95
  96static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
  97{
  98        struct cdns_pcie *pcie = &rc->pcie;
  99        u32 value, ctrl;
 100
 101        /*
 102         * Set the root complex BAR configuration register:
 103         * - disable both BAR0 and BAR1.
 104         * - enable Prefetchable Memory Base and Limit registers in type 1
 105         *   config space (64 bits).
 106         * - enable IO Base and Limit registers in type 1 config
 107         *   space (32 bits).
 108         */
 109        ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
 110        value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
 111                CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
 112                CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
 113                CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
 114                CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE |
 115                CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS;
 116        cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
 117
 118        /* Set root port configuration space */
 119        if (rc->vendor_id != 0xffff)
 120                cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id);
 121        if (rc->device_id != 0xffff)
 122                cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
 123
 124        cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
 125        cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
 126        cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
 127
 128        return 0;
 129}
 130
 131static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
 132{
 133        struct cdns_pcie *pcie = &rc->pcie;
 134        struct resource *cfg_res = rc->cfg_res;
 135        struct resource *mem_res = pcie->mem_res;
 136        struct resource *bus_range = rc->bus_range;
 137        struct device *dev = rc->dev;
 138        struct device_node *np = dev->of_node;
 139        struct of_pci_range_parser parser;
 140        struct of_pci_range range;
 141        u32 addr0, addr1, desc1;
 142        u64 cpu_addr;
 143        int r, err;
 144
 145        /*
 146         * Reserve region 0 for PCI configure space accesses:
 147         * OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
 148         * cdns_pci_map_bus(), other region registers are set here once for all.
 149         */
 150        addr1 = 0; /* Should be programmed to zero. */
 151        desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start);
 152        cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1);
 153        cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1);
 154
 155        cpu_addr = cfg_res->start - mem_res->start;
 156        addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
 157                (lower_32_bits(cpu_addr) & GENMASK(31, 8));
 158        addr1 = upper_32_bits(cpu_addr);
 159        cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0);
 160        cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1);
 161
 162        err = of_pci_range_parser_init(&parser, np);
 163        if (err)
 164                return err;
 165
 166        r = 1;
 167        for_each_of_pci_range(&parser, &range) {
 168                bool is_io;
 169
 170                if (r >= rc->max_regions)
 171                        break;
 172
 173                if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
 174                        is_io = false;
 175                else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
 176                        is_io = true;
 177                else
 178                        continue;
 179
 180                cdns_pcie_set_outbound_region(pcie, 0, r, is_io,
 181                                              range.cpu_addr,
 182                                              range.pci_addr,
 183                                              range.size);
 184                r++;
 185        }
 186
 187        /*
 188         * Set Root Port no BAR match Inbound Translation registers:
 189         * needed for MSI and DMA.
 190         * Root Port BAR0 and BAR1 are disabled, hence no need to set their
 191         * inbound translation registers.
 192         */
 193        addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits);
 194        addr1 = 0;
 195        cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0);
 196        cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1);
 197
 198        return 0;
 199}
 200
 201static int cdns_pcie_host_init(struct device *dev,
 202                               struct list_head *resources,
 203                               struct cdns_pcie_rc *rc)
 204{
 205        struct resource *bus_range = NULL;
 206        int err;
 207
 208        /* Parse our PCI ranges and request their resources */
 209        err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
 210        if (err)
 211                return err;
 212
 213        rc->bus_range = bus_range;
 214        rc->pcie.bus = bus_range->start;
 215
 216        err = cdns_pcie_host_init_root_port(rc);
 217        if (err)
 218                goto err_out;
 219
 220        err = cdns_pcie_host_init_address_translation(rc);
 221        if (err)
 222                goto err_out;
 223
 224        return 0;
 225
 226 err_out:
 227        pci_free_resource_list(resources);
 228        return err;
 229}
 230
 231static int cdns_pcie_host_probe(struct platform_device *pdev)
 232{
 233        const char *type;
 234        struct device *dev = &pdev->dev;
 235        struct device_node *np = dev->of_node;
 236        struct pci_host_bridge *bridge;
 237        struct list_head resources;
 238        struct cdns_pcie_rc *rc;
 239        struct cdns_pcie *pcie;
 240        struct resource *res;
 241        int ret;
 242
 243        bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
 244        if (!bridge)
 245                return -ENOMEM;
 246
 247        rc = pci_host_bridge_priv(bridge);
 248        rc->dev = dev;
 249
 250        pcie = &rc->pcie;
 251        pcie->is_rc = true;
 252
 253        rc->max_regions = 32;
 254        of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions);
 255
 256        rc->no_bar_nbits = 32;
 257        of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits);
 258
 259        rc->vendor_id = 0xffff;
 260        of_property_read_u16(np, "vendor-id", &rc->vendor_id);
 261
 262        rc->device_id = 0xffff;
 263        of_property_read_u16(np, "device-id", &rc->device_id);
 264
 265        type = of_get_property(np, "device_type", NULL);
 266        if (!type || strcmp(type, "pci")) {
 267                dev_err(dev, "invalid \"device_type\" %s\n", type);
 268                return -EINVAL;
 269        }
 270
 271        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
 272        pcie->reg_base = devm_ioremap_resource(dev, res);
 273        if (IS_ERR(pcie->reg_base)) {
 274                dev_err(dev, "missing \"reg\"\n");
 275                return PTR_ERR(pcie->reg_base);
 276        }
 277
 278        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
 279        rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
 280        if (IS_ERR(rc->cfg_base)) {
 281                dev_err(dev, "missing \"cfg\"\n");
 282                return PTR_ERR(rc->cfg_base);
 283        }
 284        rc->cfg_res = res;
 285
 286        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
 287        if (!res) {
 288                dev_err(dev, "missing \"mem\"\n");
 289                return -EINVAL;
 290        }
 291        pcie->mem_res = res;
 292
 293        pm_runtime_enable(dev);
 294        ret = pm_runtime_get_sync(dev);
 295        if (ret < 0) {
 296                dev_err(dev, "pm_runtime_get_sync() failed\n");
 297                goto err_get_sync;
 298        }
 299
 300        ret = cdns_pcie_host_init(dev, &resources, rc);
 301        if (ret)
 302                goto err_init;
 303
 304        list_splice_init(&resources, &bridge->windows);
 305        bridge->dev.parent = dev;
 306        bridge->busnr = pcie->bus;
 307        bridge->ops = &cdns_pcie_host_ops;
 308        bridge->map_irq = of_irq_parse_and_map_pci;
 309        bridge->swizzle_irq = pci_common_swizzle;
 310
 311        ret = pci_host_probe(bridge);
 312        if (ret < 0)
 313                goto err_host_probe;
 314
 315        return 0;
 316
 317 err_host_probe:
 318        pci_free_resource_list(&resources);
 319
 320 err_init:
 321        pm_runtime_put_sync(dev);
 322
 323 err_get_sync:
 324        pm_runtime_disable(dev);
 325
 326        return ret;
 327}
 328
 329static struct platform_driver cdns_pcie_host_driver = {
 330        .driver = {
 331                .name = "cdns-pcie-host",
 332                .of_match_table = cdns_pcie_host_of_match,
 333        },
 334        .probe = cdns_pcie_host_probe,
 335};
 336builtin_platform_driver(cdns_pcie_host_driver);
 337