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 = BAR_0; bar <= BAR_5; 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        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2");
 157        pci->dbi_base2 = devm_ioremap_resource(dev, res);
 158        if (IS_ERR(pci->dbi_base2))
 159                return PTR_ERR(pci->dbi_base2);
 160
 161        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
 162        if (!res)
 163                return -EINVAL;
 164
 165        ep->phys_base = res->start;
 166        ep->addr_size = resource_size(res);
 167
 168        ret = dw_pcie_ep_init(ep);
 169        if (ret) {
 170                dev_err(dev, "Failed to initialize endpoint\n");
 171                return ret;
 172        }
 173        return 0;
 174}
 175
 176static int dw_plat_pcie_probe(struct platform_device *pdev)
 177{
 178        struct device *dev = &pdev->dev;
 179        struct dw_plat_pcie *dw_plat_pcie;
 180        struct dw_pcie *pci;
 181        struct resource *res;  /* Resource from DT */
 182        int ret;
 183        const struct of_device_id *match;
 184        const struct dw_plat_pcie_of_data *data;
 185        enum dw_pcie_device_mode mode;
 186
 187        match = of_match_device(dw_plat_pcie_of_match, dev);
 188        if (!match)
 189                return -EINVAL;
 190
 191        data = (struct dw_plat_pcie_of_data *)match->data;
 192        mode = (enum dw_pcie_device_mode)data->mode;
 193
 194        dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL);
 195        if (!dw_plat_pcie)
 196                return -ENOMEM;
 197
 198        pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
 199        if (!pci)
 200                return -ENOMEM;
 201
 202        pci->dev = dev;
 203        pci->ops = &dw_pcie_ops;
 204
 205        dw_plat_pcie->pci = pci;
 206        dw_plat_pcie->mode = mode;
 207
 208        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
 209        if (!res)
 210                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 211
 212        pci->dbi_base = devm_ioremap_resource(dev, res);
 213        if (IS_ERR(pci->dbi_base))
 214                return PTR_ERR(pci->dbi_base);
 215
 216        platform_set_drvdata(pdev, dw_plat_pcie);
 217
 218        switch (dw_plat_pcie->mode) {
 219        case DW_PCIE_RC_TYPE:
 220                if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST))
 221                        return -ENODEV;
 222
 223                ret = dw_plat_add_pcie_port(dw_plat_pcie, pdev);
 224                if (ret < 0)
 225                        return ret;
 226                break;
 227        case DW_PCIE_EP_TYPE:
 228                if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP))
 229                        return -ENODEV;
 230
 231                ret = dw_plat_add_pcie_ep(dw_plat_pcie, pdev);
 232                if (ret < 0)
 233                        return ret;
 234                break;
 235        default:
 236                dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode);
 237        }
 238
 239        return 0;
 240}
 241
 242static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = {
 243        .mode = DW_PCIE_RC_TYPE,
 244};
 245
 246static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = {
 247        .mode = DW_PCIE_EP_TYPE,
 248};
 249
 250static const struct of_device_id dw_plat_pcie_of_match[] = {
 251        {
 252                .compatible = "snps,dw-pcie",
 253                .data = &dw_plat_pcie_rc_of_data,
 254        },
 255        {
 256                .compatible = "snps,dw-pcie-ep",
 257                .data = &dw_plat_pcie_ep_of_data,
 258        },
 259        {},
 260};
 261
 262static struct platform_driver dw_plat_pcie_driver = {
 263        .driver = {
 264                .name   = "dw-pcie",
 265                .of_match_table = dw_plat_pcie_of_match,
 266                .suppress_bind_attrs = true,
 267        },
 268        .probe = dw_plat_pcie_probe,
 269};
 270builtin_platform_driver(dw_plat_pcie_driver);
 271