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 const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
  37};
  38
  39static int dw_plat_pcie_establish_link(struct dw_pcie *pci)
  40{
  41        return 0;
  42}
  43
  44static const struct dw_pcie_ops dw_pcie_ops = {
  45        .start_link = dw_plat_pcie_establish_link,
  46};
  47
  48static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
  49{
  50        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
  51        enum pci_barno bar;
  52
  53        for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
  54                dw_pcie_ep_reset_bar(pci, bar);
  55}
  56
  57static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
  58                                     enum pci_epc_irq_type type,
  59                                     u16 interrupt_num)
  60{
  61        struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
  62
  63        switch (type) {
  64        case PCI_EPC_IRQ_LEGACY:
  65                return dw_pcie_ep_raise_legacy_irq(ep, func_no);
  66        case PCI_EPC_IRQ_MSI:
  67                return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
  68        case PCI_EPC_IRQ_MSIX:
  69                return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
  70        default:
  71                dev_err(pci->dev, "UNKNOWN IRQ type\n");
  72        }
  73
  74        return 0;
  75}
  76
  77static const struct pci_epc_features dw_plat_pcie_epc_features = {
  78        .linkup_notifier = false,
  79        .msi_capable = true,
  80        .msix_capable = true,
  81};
  82
  83static const struct pci_epc_features*
  84dw_plat_pcie_get_features(struct dw_pcie_ep *ep)
  85{
  86        return &dw_plat_pcie_epc_features;
  87}
  88
  89static const struct dw_pcie_ep_ops pcie_ep_ops = {
  90        .ep_init = dw_plat_pcie_ep_init,
  91        .raise_irq = dw_plat_pcie_ep_raise_irq,
  92        .get_features = dw_plat_pcie_get_features,
  93};
  94
  95static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
  96                                 struct platform_device *pdev)
  97{
  98        struct dw_pcie *pci = dw_plat_pcie->pci;
  99        struct pcie_port *pp = &pci->pp;
 100        struct device *dev = &pdev->dev;
 101        int ret;
 102
 103        pp->irq = platform_get_irq(pdev, 1);
 104        if (pp->irq < 0)
 105                return pp->irq;
 106
 107        pp->num_vectors = MAX_MSI_IRQS;
 108        pp->ops = &dw_plat_pcie_host_ops;
 109
 110        ret = dw_pcie_host_init(pp);
 111        if (ret) {
 112                dev_err(dev, "Failed to initialize host\n");
 113                return ret;
 114        }
 115
 116        return 0;
 117}
 118
 119static int dw_plat_pcie_probe(struct platform_device *pdev)
 120{
 121        struct device *dev = &pdev->dev;
 122        struct dw_plat_pcie *dw_plat_pcie;
 123        struct dw_pcie *pci;
 124        int ret;
 125        const struct of_device_id *match;
 126        const struct dw_plat_pcie_of_data *data;
 127        enum dw_pcie_device_mode mode;
 128
 129        match = of_match_device(dw_plat_pcie_of_match, dev);
 130        if (!match)
 131                return -EINVAL;
 132
 133        data = (struct dw_plat_pcie_of_data *)match->data;
 134        mode = (enum dw_pcie_device_mode)data->mode;
 135
 136        dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL);
 137        if (!dw_plat_pcie)
 138                return -ENOMEM;
 139
 140        pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
 141        if (!pci)
 142                return -ENOMEM;
 143
 144        pci->dev = dev;
 145        pci->ops = &dw_pcie_ops;
 146
 147        dw_plat_pcie->pci = pci;
 148        dw_plat_pcie->mode = mode;
 149
 150        platform_set_drvdata(pdev, dw_plat_pcie);
 151
 152        switch (dw_plat_pcie->mode) {
 153        case DW_PCIE_RC_TYPE:
 154                if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST))
 155                        return -ENODEV;
 156
 157                ret = dw_plat_add_pcie_port(dw_plat_pcie, pdev);
 158                if (ret < 0)
 159                        return ret;
 160                break;
 161        case DW_PCIE_EP_TYPE:
 162                if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP))
 163                        return -ENODEV;
 164
 165                pci->ep.ops = &pcie_ep_ops;
 166                return dw_pcie_ep_init(&pci->ep);
 167        default:
 168                dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode);
 169        }
 170
 171        return 0;
 172}
 173
 174static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = {
 175        .mode = DW_PCIE_RC_TYPE,
 176};
 177
 178static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = {
 179        .mode = DW_PCIE_EP_TYPE,
 180};
 181
 182static const struct of_device_id dw_plat_pcie_of_match[] = {
 183        {
 184                .compatible = "snps,dw-pcie",
 185                .data = &dw_plat_pcie_rc_of_data,
 186        },
 187        {
 188                .compatible = "snps,dw-pcie-ep",
 189                .data = &dw_plat_pcie_ep_of_data,
 190        },
 191        {},
 192};
 193
 194static struct platform_driver dw_plat_pcie_driver = {
 195        .driver = {
 196                .name   = "dw-pcie",
 197                .of_match_table = dw_plat_pcie_of_match,
 198                .suppress_bind_attrs = true,
 199        },
 200        .probe = dw_plat_pcie_probe,
 201};
 202builtin_platform_driver(dw_plat_pcie_driver);
 203