Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Cadence PCIe platform  driver.
0004  *
0005  * Copyright (c) 2019, Cadence Design Systems
0006  * Author: Tom Joseph <tjoseph@cadence.com>
0007  */
0008 #include <linux/kernel.h>
0009 #include <linux/of_address.h>
0010 #include <linux/of_pci.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/pm_runtime.h>
0013 #include <linux/of_device.h>
0014 #include "pcie-cadence.h"
0015 
0016 #define CDNS_PLAT_CPU_TO_BUS_ADDR   0x0FFFFFFF
0017 
0018 /**
0019  * struct cdns_plat_pcie - private data for this PCIe platform driver
0020  * @pcie: Cadence PCIe controller
0021  * @is_rc: Set to 1 indicates the PCIe controller mode is Root Complex,
0022  *         if 0 it is in Endpoint mode.
0023  */
0024 struct cdns_plat_pcie {
0025     struct cdns_pcie        *pcie;
0026     bool is_rc;
0027 };
0028 
0029 struct cdns_plat_pcie_of_data {
0030     bool is_rc;
0031 };
0032 
0033 static const struct of_device_id cdns_plat_pcie_of_match[];
0034 
0035 static u64 cdns_plat_cpu_addr_fixup(struct cdns_pcie *pcie, u64 cpu_addr)
0036 {
0037     return cpu_addr & CDNS_PLAT_CPU_TO_BUS_ADDR;
0038 }
0039 
0040 static const struct cdns_pcie_ops cdns_plat_ops = {
0041     .cpu_addr_fixup = cdns_plat_cpu_addr_fixup,
0042 };
0043 
0044 static int cdns_plat_pcie_probe(struct platform_device *pdev)
0045 {
0046     const struct cdns_plat_pcie_of_data *data;
0047     struct cdns_plat_pcie *cdns_plat_pcie;
0048     struct device *dev = &pdev->dev;
0049     struct pci_host_bridge *bridge;
0050     struct cdns_pcie_ep *ep;
0051     struct cdns_pcie_rc *rc;
0052     int phy_count;
0053     bool is_rc;
0054     int ret;
0055 
0056     data = of_device_get_match_data(dev);
0057     if (!data)
0058         return -EINVAL;
0059 
0060     is_rc = data->is_rc;
0061 
0062     pr_debug(" Started %s with is_rc: %d\n", __func__, is_rc);
0063     cdns_plat_pcie = devm_kzalloc(dev, sizeof(*cdns_plat_pcie), GFP_KERNEL);
0064     if (!cdns_plat_pcie)
0065         return -ENOMEM;
0066 
0067     platform_set_drvdata(pdev, cdns_plat_pcie);
0068     if (is_rc) {
0069         if (!IS_ENABLED(CONFIG_PCIE_CADENCE_PLAT_HOST))
0070             return -ENODEV;
0071 
0072         bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
0073         if (!bridge)
0074             return -ENOMEM;
0075 
0076         rc = pci_host_bridge_priv(bridge);
0077         rc->pcie.dev = dev;
0078         rc->pcie.ops = &cdns_plat_ops;
0079         cdns_plat_pcie->pcie = &rc->pcie;
0080         cdns_plat_pcie->is_rc = is_rc;
0081 
0082         ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);
0083         if (ret) {
0084             dev_err(dev, "failed to init phy\n");
0085             return ret;
0086         }
0087         pm_runtime_enable(dev);
0088         ret = pm_runtime_get_sync(dev);
0089         if (ret < 0) {
0090             dev_err(dev, "pm_runtime_get_sync() failed\n");
0091             goto err_get_sync;
0092         }
0093 
0094         ret = cdns_pcie_host_setup(rc);
0095         if (ret)
0096             goto err_init;
0097     } else {
0098         if (!IS_ENABLED(CONFIG_PCIE_CADENCE_PLAT_EP))
0099             return -ENODEV;
0100 
0101         ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
0102         if (!ep)
0103             return -ENOMEM;
0104 
0105         ep->pcie.dev = dev;
0106         ep->pcie.ops = &cdns_plat_ops;
0107         cdns_plat_pcie->pcie = &ep->pcie;
0108         cdns_plat_pcie->is_rc = is_rc;
0109 
0110         ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);
0111         if (ret) {
0112             dev_err(dev, "failed to init phy\n");
0113             return ret;
0114         }
0115 
0116         pm_runtime_enable(dev);
0117         ret = pm_runtime_get_sync(dev);
0118         if (ret < 0) {
0119             dev_err(dev, "pm_runtime_get_sync() failed\n");
0120             goto err_get_sync;
0121         }
0122 
0123         ret = cdns_pcie_ep_setup(ep);
0124         if (ret)
0125             goto err_init;
0126     }
0127 
0128     return 0;
0129 
0130  err_init:
0131  err_get_sync:
0132     pm_runtime_put_sync(dev);
0133     pm_runtime_disable(dev);
0134     cdns_pcie_disable_phy(cdns_plat_pcie->pcie);
0135     phy_count = cdns_plat_pcie->pcie->phy_count;
0136     while (phy_count--)
0137         device_link_del(cdns_plat_pcie->pcie->link[phy_count]);
0138 
0139     return 0;
0140 }
0141 
0142 static void cdns_plat_pcie_shutdown(struct platform_device *pdev)
0143 {
0144     struct device *dev = &pdev->dev;
0145     struct cdns_pcie *pcie = dev_get_drvdata(dev);
0146     int ret;
0147 
0148     ret = pm_runtime_put_sync(dev);
0149     if (ret < 0)
0150         dev_dbg(dev, "pm_runtime_put_sync failed\n");
0151 
0152     pm_runtime_disable(dev);
0153 
0154     cdns_pcie_disable_phy(pcie);
0155 }
0156 
0157 static const struct cdns_plat_pcie_of_data cdns_plat_pcie_host_of_data = {
0158     .is_rc = true,
0159 };
0160 
0161 static const struct cdns_plat_pcie_of_data cdns_plat_pcie_ep_of_data = {
0162     .is_rc = false,
0163 };
0164 
0165 static const struct of_device_id cdns_plat_pcie_of_match[] = {
0166     {
0167         .compatible = "cdns,cdns-pcie-host",
0168         .data = &cdns_plat_pcie_host_of_data,
0169     },
0170     {
0171         .compatible = "cdns,cdns-pcie-ep",
0172         .data = &cdns_plat_pcie_ep_of_data,
0173     },
0174     {},
0175 };
0176 
0177 static struct platform_driver cdns_plat_pcie_driver = {
0178     .driver = {
0179         .name = "cdns-pcie",
0180         .of_match_table = cdns_plat_pcie_of_match,
0181         .pm = &cdns_pcie_pm_ops,
0182     },
0183     .probe = cdns_plat_pcie_probe,
0184     .shutdown = cdns_plat_pcie_shutdown,
0185 };
0186 builtin_platform_driver(cdns_plat_pcie_driver);