0001
0002
0003
0004
0005
0006
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
0020
0021
0022
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);