linux/drivers/pci/controller/dwc/pcie-designware-plat.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * PCIe RC driver for Synopsys DesignWare Core
   4 *
   5 * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
   6 *
   7 * Authors: Joao Pinto <Joao.Pinto@synopsys.com>
   8 */
   9#include <linux/clk.h>
  10#include <linux/delay.h>
  11#include <linux/gpio.h>
  12#include <linux/interrupt.h>
  13#include <linux/kernel.h>
  14#include <linux/init.h>
  15#include <linux/of_device.h>
  16#include <linux/pci.h>
  17#include <linux/platform_device.h>
  18#include <linux/resource.h>
  19#include <linux/types.h>
  20#include <linux/regmap.h>
  21
  22#include "pcie-designware.h"
  23
  24struct dw_plat_pcie {
  25        struct dw_pcie                  *pci;
  26        struct regmap                   *regmap;
  27        enum dw_pcie_device_mode        mode;
  28};
  29
  30struct dw_plat_pcie_of_data {
  31        enum dw_pcie_device_mode        mode;
  32};
  33
  34static const struct of_device_id dw_plat_pcie_of_match[];
  35
  36static int dw_plat_pcie_host_init(struct pcie_port *pp)
  37{
  38        struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
  39
  40        dw_pcie_setup_rc(pp);
  41        dw_pcie_wait_for_link(pci);
  42
  43        if (IS_ENABLED(CONFIG_PCI_MSI))
  44                dw_pcie_msi_init(pp);
  45
  46        return 0;
  47}
  48
  49static void dw_plat_set_num_vectors(struct pcie_port *pp)
  50{
  51        pp->num_vectors = MAX_MSI_IRQS;
  52}
  53
  54static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
  55        .host_init = dw_plat_pcie_host_init,
  56        .set_num_vectors = dw_plat_set_num_vectors,
  57};
  58
  59static int dw_plat_pcie_establish_link(struct dw_pcie *pci)
  60{
  61        return 0;
  62}
  63
  64static const struct dw_pcie_ops dw_pcie_ops = {
  65        .start_link = dw_plat_pcie_establish_link,
  66};
  67
  68static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
  69{
  70        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
  71        enum pci_barno bar;
  72
  73        for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
  74                dw_pcie_ep_reset_bar(pci, bar);
  75}
  76
  77static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
  78                                     enum pci_epc_irq_type type,
  79                                     u16 interrupt_num)
  80{
  81        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
  82
  83        switch (type) {
  84        case PCI_EPC_IRQ_LEGACY:
  85                return dw_pcie_ep_raise_legacy_irq(ep, func_no);
  86        case PCI_EPC_IRQ_MSI:
  87                return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
  88        case PCI_EPC_IRQ_MSIX:
  89                return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
  90        default:
  91                dev_err(pci->dev, "UNKNOWN IRQ type\n");
  92        }
  93
  94        return 0;
  95}
  96
  97static const struct pci_epc_features dw_plat_pcie_epc_features = {
  98        .linkup_notifier = false,
  99        .msi_capable = true,
 100        .msix_capable = true,
 101};
 102
 103static const struct pci_epc_features*
 104dw_plat_pcie_get_features(struct dw_pcie_ep *ep)
 105{
 106        return &dw_plat_pcie_epc_features;
 107}
 108
 109static const struct dw_pcie_ep_ops pcie_ep_ops = {
 110        .ep_init = dw_plat_pcie_ep_init,
 111        .raise_irq = dw_plat_pcie_ep_raise_irq,
 112        .get_features = dw_plat_pcie_get_features,
 113};
 114
 115static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
 116                                 struct platform_device *pdev)
 117{
 118        struct dw_pcie *pci = dw_plat_pcie->pci;
 119        struct pcie_port *pp = &pci->pp;
 120        struct device *dev = &pdev->dev;
 121        int ret;
 122
 123        pp->irq = platform_get_irq(pdev, 1);
 124        if (pp->irq < 0)
 125                return pp->irq;
 126
 127        if (IS_ENABLED(CONFIG_PCI_MSI)) {
 128                pp->msi_irq = platform_get_irq(pdev, 0);
 129                if (pp->msi_irq < 0)
 130                        return pp->msi_irq;
 131        }
 132
 133        pp->ops = &dw_plat_pcie_host_ops;
 134
 135        ret = dw_pcie_host_init(pp);
 136        if (ret) {
 137                dev_err(dev, "Failed to initialize host\n");
 138                return ret;
 139        }
 140
 141        return 0;
 142}
 143
 144static int dw_plat_add_pcie_ep(struct dw_plat_pcie *dw_plat_pcie,
 145                               struct platform_device *pdev)
 146{
 147        int ret;
 148        struct dw_pcie_ep *ep;
 149        struct resource *res;
 150        struct device *dev = &pdev->dev;
 151        struct dw_pcie *pci = dw_plat_pcie->pci;
 152
 153        ep = &pci->ep;
 154        ep->ops = &pcie_ep_ops;
 155
 156        pci->dbi_base2 = devm_platform_ioremap_resource_byname(pdev, "dbi2");
 157        if (IS_ERR(pci->dbi_base2))
 158                return PTR_ERR(pci->dbi_base2);
 159
 160        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
 161        if (!res)
 162                return -EINVAL;
 163
 164        ep->phys_base = res->start;
 165        ep->addr_size = resource_size(res);
 166
 167        ret = dw_pcie_ep_init(ep);
 168        if (ret) {
 169                dev_err(dev, "Failed to initialize endpoint\n");
 170                return ret;
 171        }
 172        return 0;
 173}
 174
 175static int dw_plat_pcie_probe(struct platform_device *pdev)
 176{
 177        struct device *dev = &pdev->dev;
 178        struct dw_plat_pcie *dw_plat_pcie;
 179        struct dw_pcie *pci;
 180        struct resource *res;  /* Resource from DT */
 181        int ret;
 182        const struct of_device_id *match;
 183        const struct dw_plat_pcie_of_data *data;
 184        enum dw_pcie_device_mode mode;
 185
 186        match = of_match_device(dw_plat_pcie_of_match, dev);
 187        if (!match)
 188                return -EINVAL;
 189
 190        data = (struct dw_plat_pcie_of_data *)match->data;
 191        mode = (enum dw_pcie_device_mode)data->mode;
 192
 193        dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL);
 194        if (!dw_plat_pcie)
 195                return -ENOMEM;
 196
 197        pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
 198        if (!pci)
 199                return -ENOMEM;
 200
 201        pci->dev = dev;
 202        pci->ops = &dw_pcie_ops;
 203
 204        dw_plat_pcie->pci = pci;
 205        dw_plat_pcie->mode = mode;
 206
 207        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
 208        if (!res)
 209                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 210
 211        pci->dbi_base = devm_ioremap_resource(dev, res);
 212        if (IS_ERR(pci->dbi_base))
 213                return PTR_ERR(pci->dbi_base);
 214
 215        platform_set_drvdata(pdev, dw_plat_pcie);
 216
 217        switch (dw_plat_pcie->mode) {
 218        case DW_PCIE_RC_TYPE:
 219                if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST))
 220                        return -ENODEV;
 221
 222                ret = dw_plat_add_pcie_port(dw_plat_pcie, pdev);
 223                if (ret < 0)
 224                        return ret;
 225                break;
 226        case DW_PCIE_EP_TYPE:
 227                if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP))
 228                        return -ENODEV;
 229
 230                ret = dw_plat_add_pcie_ep(dw_plat_pcie, pdev);
 231                if (ret < 0)
 232                        return ret;
 233                break;
 234        default:
 235                dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode);
 236        }
 237
 238        return 0;
 239}
 240
 241static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = {
 242        .mode = DW_PCIE_RC_TYPE,
 243};
 244
 245static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = {
 246        .mode = DW_PCIE_EP_TYPE,
 247};
 248
 249static const struct of_device_id dw_plat_pcie_of_match[] = {
 250        {
 251                .compatible = "snps,dw-pcie",
 252                .data = &dw_plat_pcie_rc_of_data,
 253        },
 254        {
 255                .compatible = "snps,dw-pcie-ep",
 256                .data = &dw_plat_pcie_ep_of_data,
 257        },
 258        {},
 259};
 260
 261static struct platform_driver dw_plat_pcie_driver = {
 262        .driver = {
 263                .name   = "dw-pcie",
 264                .of_match_table = dw_plat_pcie_of_match,
 265                .suppress_bind_attrs = true,
 266        },
 267        .probe = dw_plat_pcie_probe,
 268};
 269builtin_platform_driver(dw_plat_pcie_driver);
 270