Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * PCIe RC driver for Synopsys DesignWare Core
0004  *
0005  * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
0006  *
0007  * Authors: Joao Pinto <Joao.Pinto@synopsys.com>
0008  */
0009 #include <linux/clk.h>
0010 #include <linux/delay.h>
0011 #include <linux/gpio.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/kernel.h>
0014 #include <linux/init.h>
0015 #include <linux/of_device.h>
0016 #include <linux/pci.h>
0017 #include <linux/platform_device.h>
0018 #include <linux/resource.h>
0019 #include <linux/types.h>
0020 
0021 #include "pcie-designware.h"
0022 
0023 struct dw_plat_pcie {
0024     struct dw_pcie          *pci;
0025     enum dw_pcie_device_mode    mode;
0026 };
0027 
0028 struct dw_plat_pcie_of_data {
0029     enum dw_pcie_device_mode    mode;
0030 };
0031 
0032 static const struct dw_pcie_host_ops dw_plat_pcie_host_ops = {
0033 };
0034 
0035 static void dw_plat_pcie_ep_init(struct dw_pcie_ep *ep)
0036 {
0037     struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
0038     enum pci_barno bar;
0039 
0040     for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
0041         dw_pcie_ep_reset_bar(pci, bar);
0042 }
0043 
0044 static int dw_plat_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
0045                      enum pci_epc_irq_type type,
0046                      u16 interrupt_num)
0047 {
0048     struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
0049 
0050     switch (type) {
0051     case PCI_EPC_IRQ_LEGACY:
0052         return dw_pcie_ep_raise_legacy_irq(ep, func_no);
0053     case PCI_EPC_IRQ_MSI:
0054         return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
0055     case PCI_EPC_IRQ_MSIX:
0056         return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
0057     default:
0058         dev_err(pci->dev, "UNKNOWN IRQ type\n");
0059     }
0060 
0061     return 0;
0062 }
0063 
0064 static const struct pci_epc_features dw_plat_pcie_epc_features = {
0065     .linkup_notifier = false,
0066     .msi_capable = true,
0067     .msix_capable = true,
0068 };
0069 
0070 static const struct pci_epc_features*
0071 dw_plat_pcie_get_features(struct dw_pcie_ep *ep)
0072 {
0073     return &dw_plat_pcie_epc_features;
0074 }
0075 
0076 static const struct dw_pcie_ep_ops pcie_ep_ops = {
0077     .ep_init = dw_plat_pcie_ep_init,
0078     .raise_irq = dw_plat_pcie_ep_raise_irq,
0079     .get_features = dw_plat_pcie_get_features,
0080 };
0081 
0082 static int dw_plat_add_pcie_port(struct dw_plat_pcie *dw_plat_pcie,
0083                  struct platform_device *pdev)
0084 {
0085     struct dw_pcie *pci = dw_plat_pcie->pci;
0086     struct dw_pcie_rp *pp = &pci->pp;
0087     struct device *dev = &pdev->dev;
0088     int ret;
0089 
0090     pp->irq = platform_get_irq(pdev, 1);
0091     if (pp->irq < 0)
0092         return pp->irq;
0093 
0094     pp->num_vectors = MAX_MSI_IRQS;
0095     pp->ops = &dw_plat_pcie_host_ops;
0096 
0097     ret = dw_pcie_host_init(pp);
0098     if (ret) {
0099         dev_err(dev, "Failed to initialize host\n");
0100         return ret;
0101     }
0102 
0103     return 0;
0104 }
0105 
0106 static int dw_plat_pcie_probe(struct platform_device *pdev)
0107 {
0108     struct device *dev = &pdev->dev;
0109     struct dw_plat_pcie *dw_plat_pcie;
0110     struct dw_pcie *pci;
0111     int ret;
0112     const struct dw_plat_pcie_of_data *data;
0113     enum dw_pcie_device_mode mode;
0114 
0115     data = of_device_get_match_data(dev);
0116     if (!data)
0117         return -EINVAL;
0118 
0119     mode = (enum dw_pcie_device_mode)data->mode;
0120 
0121     dw_plat_pcie = devm_kzalloc(dev, sizeof(*dw_plat_pcie), GFP_KERNEL);
0122     if (!dw_plat_pcie)
0123         return -ENOMEM;
0124 
0125     pci = devm_kzalloc(dev, sizeof(*pci), GFP_KERNEL);
0126     if (!pci)
0127         return -ENOMEM;
0128 
0129     pci->dev = dev;
0130 
0131     dw_plat_pcie->pci = pci;
0132     dw_plat_pcie->mode = mode;
0133 
0134     platform_set_drvdata(pdev, dw_plat_pcie);
0135 
0136     switch (dw_plat_pcie->mode) {
0137     case DW_PCIE_RC_TYPE:
0138         if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_HOST))
0139             return -ENODEV;
0140 
0141         ret = dw_plat_add_pcie_port(dw_plat_pcie, pdev);
0142         break;
0143     case DW_PCIE_EP_TYPE:
0144         if (!IS_ENABLED(CONFIG_PCIE_DW_PLAT_EP))
0145             return -ENODEV;
0146 
0147         pci->ep.ops = &pcie_ep_ops;
0148         ret = dw_pcie_ep_init(&pci->ep);
0149         break;
0150     default:
0151         dev_err(dev, "INVALID device type %d\n", dw_plat_pcie->mode);
0152         ret = -EINVAL;
0153         break;
0154     }
0155 
0156     return ret;
0157 }
0158 
0159 static const struct dw_plat_pcie_of_data dw_plat_pcie_rc_of_data = {
0160     .mode = DW_PCIE_RC_TYPE,
0161 };
0162 
0163 static const struct dw_plat_pcie_of_data dw_plat_pcie_ep_of_data = {
0164     .mode = DW_PCIE_EP_TYPE,
0165 };
0166 
0167 static const struct of_device_id dw_plat_pcie_of_match[] = {
0168     {
0169         .compatible = "snps,dw-pcie",
0170         .data = &dw_plat_pcie_rc_of_data,
0171     },
0172     {
0173         .compatible = "snps,dw-pcie-ep",
0174         .data = &dw_plat_pcie_ep_of_data,
0175     },
0176     {},
0177 };
0178 
0179 static struct platform_driver dw_plat_pcie_driver = {
0180     .driver = {
0181         .name   = "dw-pcie",
0182         .of_match_table = dw_plat_pcie_of_match,
0183         .suppress_bind_attrs = true,
0184     },
0185     .probe = dw_plat_pcie_probe,
0186 };
0187 builtin_platform_driver(dw_plat_pcie_driver);