brintos

brintos / linux-shallow public Read only

0
0
Text · 4.0 KiB · 0456845 Raw
181 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Cadence PCIe platform  driver.4 *5 * Copyright (c) 2019, Cadence Design Systems6 * Author: Tom Joseph <tjoseph@cadence.com>7 */8#include <linux/kernel.h>9#include <linux/of.h>10#include <linux/of_pci.h>11#include <linux/platform_device.h>12#include <linux/pm_runtime.h>13#include "pcie-cadence.h"14 15#define CDNS_PLAT_CPU_TO_BUS_ADDR	0x0FFFFFFF16 17/**18 * struct cdns_plat_pcie - private data for this PCIe platform driver19 * @pcie: Cadence PCIe controller20 */21struct cdns_plat_pcie {22	struct cdns_pcie        *pcie;23};24 25struct cdns_plat_pcie_of_data {26	bool is_rc;27};28 29static const struct of_device_id cdns_plat_pcie_of_match[];30 31static u64 cdns_plat_cpu_addr_fixup(struct cdns_pcie *pcie, u64 cpu_addr)32{33	return cpu_addr & CDNS_PLAT_CPU_TO_BUS_ADDR;34}35 36static const struct cdns_pcie_ops cdns_plat_ops = {37	.cpu_addr_fixup = cdns_plat_cpu_addr_fixup,38};39 40static int cdns_plat_pcie_probe(struct platform_device *pdev)41{42	const struct cdns_plat_pcie_of_data *data;43	struct cdns_plat_pcie *cdns_plat_pcie;44	struct device *dev = &pdev->dev;45	struct pci_host_bridge *bridge;46	struct cdns_pcie_ep *ep;47	struct cdns_pcie_rc *rc;48	int phy_count;49	bool is_rc;50	int ret;51 52	data = of_device_get_match_data(dev);53	if (!data)54		return -EINVAL;55 56	is_rc = data->is_rc;57 58	pr_debug(" Started %s with is_rc: %d\n", __func__, is_rc);59	cdns_plat_pcie = devm_kzalloc(dev, sizeof(*cdns_plat_pcie), GFP_KERNEL);60	if (!cdns_plat_pcie)61		return -ENOMEM;62 63	platform_set_drvdata(pdev, cdns_plat_pcie);64	if (is_rc) {65		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_PLAT_HOST))66			return -ENODEV;67 68		bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));69		if (!bridge)70			return -ENOMEM;71 72		rc = pci_host_bridge_priv(bridge);73		rc->pcie.dev = dev;74		rc->pcie.ops = &cdns_plat_ops;75		cdns_plat_pcie->pcie = &rc->pcie;76 77		ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);78		if (ret) {79			dev_err(dev, "failed to init phy\n");80			return ret;81		}82		pm_runtime_enable(dev);83		ret = pm_runtime_get_sync(dev);84		if (ret < 0) {85			dev_err(dev, "pm_runtime_get_sync() failed\n");86			goto err_get_sync;87		}88 89		ret = cdns_pcie_host_setup(rc);90		if (ret)91			goto err_init;92	} else {93		if (!IS_ENABLED(CONFIG_PCIE_CADENCE_PLAT_EP))94			return -ENODEV;95 96		ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);97		if (!ep)98			return -ENOMEM;99 100		ep->pcie.dev = dev;101		ep->pcie.ops = &cdns_plat_ops;102		cdns_plat_pcie->pcie = &ep->pcie;103 104		ret = cdns_pcie_init_phy(dev, cdns_plat_pcie->pcie);105		if (ret) {106			dev_err(dev, "failed to init phy\n");107			return ret;108		}109 110		pm_runtime_enable(dev);111		ret = pm_runtime_get_sync(dev);112		if (ret < 0) {113			dev_err(dev, "pm_runtime_get_sync() failed\n");114			goto err_get_sync;115		}116 117		ret = cdns_pcie_ep_setup(ep);118		if (ret)119			goto err_init;120	}121 122	return 0;123 124 err_init:125 err_get_sync:126	pm_runtime_put_sync(dev);127	pm_runtime_disable(dev);128	cdns_pcie_disable_phy(cdns_plat_pcie->pcie);129	phy_count = cdns_plat_pcie->pcie->phy_count;130	while (phy_count--)131		device_link_del(cdns_plat_pcie->pcie->link[phy_count]);132 133	return 0;134}135 136static void cdns_plat_pcie_shutdown(struct platform_device *pdev)137{138	struct device *dev = &pdev->dev;139	struct cdns_pcie *pcie = dev_get_drvdata(dev);140	int ret;141 142	ret = pm_runtime_put_sync(dev);143	if (ret < 0)144		dev_dbg(dev, "pm_runtime_put_sync failed\n");145 146	pm_runtime_disable(dev);147 148	cdns_pcie_disable_phy(pcie);149}150 151static const struct cdns_plat_pcie_of_data cdns_plat_pcie_host_of_data = {152	.is_rc = true,153};154 155static const struct cdns_plat_pcie_of_data cdns_plat_pcie_ep_of_data = {156	.is_rc = false,157};158 159static const struct of_device_id cdns_plat_pcie_of_match[] = {160	{161		.compatible = "cdns,cdns-pcie-host",162		.data = &cdns_plat_pcie_host_of_data,163	},164	{165		.compatible = "cdns,cdns-pcie-ep",166		.data = &cdns_plat_pcie_ep_of_data,167	},168	{},169};170 171static struct platform_driver cdns_plat_pcie_driver = {172	.driver = {173		.name = "cdns-pcie",174		.of_match_table = cdns_plat_pcie_of_match,175		.pm	= &cdns_pcie_pm_ops,176	},177	.probe = cdns_plat_pcie_probe,178	.shutdown = cdns_plat_pcie_shutdown,179};180builtin_platform_driver(cdns_plat_pcie_driver);181