File Index
Files and directories
Sign in
FILE

pcie-sg2042.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pci/controller/cadence/pcie-sg2042.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * pcie-sg2042 - PCIe controller driver for Sophgo SG2042 SoC
  4 *
  5 * Copyright (C) 2025 Sophgo Technology Inc.
  6 * Copyright (C) 2025 Chen Wang <unicorn_wang@outlook.com>
  7 */
  8
  9#include <linux/mod_devicetable.h>
 10#include <linux/pci.h>
 11#include <linux/platform_device.h>
 12#include <linux/pm_runtime.h>
 13
 14#include "pcie-cadence.h"
 15
 16/*
 17 * SG2042 only supports 4-byte aligned access, so for the rootbus (i.e. to
 18 * read/write the Root Port itself, read32/write32 is required. For
 19 * non-rootbus (i.e. to read/write the PCIe peripheral registers, supports
 20 * 1/2/4 byte aligned access, so directly using read/write should be fine.
 21 */
 22
 23static struct pci_ops sg2042_pcie_root_ops = {
 24	.map_bus	= cdns_pci_map_bus,
 25	.read		= pci_generic_config_read32,
 26	.write		= pci_generic_config_write32,
 27};
 28
 29static struct pci_ops sg2042_pcie_child_ops = {
 30	.map_bus	= cdns_pci_map_bus,
 31	.read		= pci_generic_config_read,
 32	.write		= pci_generic_config_write,
 33};
 34
 35static int sg2042_pcie_probe(struct platform_device *pdev)
 36{
 37	struct device *dev = &pdev->dev;
 38	struct pci_host_bridge *bridge;
 39	struct cdns_pcie *pcie;
 40	struct cdns_pcie_rc *rc;
 41	int ret;
 42
 43	bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
 44	if (!bridge)
 45		return dev_err_probe(dev, -ENOMEM, "Failed to alloc host bridge!\n");
 46
 47	bridge->ops = &sg2042_pcie_root_ops;
 48	bridge->child_ops = &sg2042_pcie_child_ops;
 49
 50	rc = pci_host_bridge_priv(bridge);
 51	pcie = &rc->pcie;
 52	pcie->dev = dev;
 53
 54	platform_set_drvdata(pdev, pcie);
 55
 56	pm_runtime_set_active(dev);
 57	pm_runtime_no_callbacks(dev);
 58	devm_pm_runtime_enable(dev);
 59
 60	ret = cdns_pcie_init_phy(dev, pcie);
 61	if (ret)
 62		return dev_err_probe(dev, ret, "Failed to init phy!\n");
 63
 64	ret = cdns_pcie_host_setup(rc);
 65	if (ret) {
 66		dev_err_probe(dev, ret, "Failed to setup host!\n");
 67		cdns_pcie_disable_phy(pcie);
 68		return ret;
 69	}
 70
 71	return 0;
 72}
 73
 74static void sg2042_pcie_remove(struct platform_device *pdev)
 75{
 76	struct cdns_pcie *pcie = platform_get_drvdata(pdev);
 77	struct cdns_pcie_rc *rc;
 78
 79	rc = container_of(pcie, struct cdns_pcie_rc, pcie);
 80	cdns_pcie_host_disable(rc);
 81
 82	cdns_pcie_disable_phy(pcie);
 83}
 84
 85static int sg2042_pcie_suspend_noirq(struct device *dev)
 86{
 87	struct cdns_pcie *pcie = dev_get_drvdata(dev);
 88
 89	cdns_pcie_disable_phy(pcie);
 90
 91	return 0;
 92}
 93
 94static int sg2042_pcie_resume_noirq(struct device *dev)
 95{
 96	struct cdns_pcie *pcie = dev_get_drvdata(dev);
 97	int ret;
 98
 99	ret = cdns_pcie_enable_phy(pcie);
100	if (ret) {
101		dev_err(dev, "failed to enable PHY\n");
102		return ret;
103	}
104
105	return 0;
106}
107
108static DEFINE_NOIRQ_DEV_PM_OPS(sg2042_pcie_pm_ops,
109			       sg2042_pcie_suspend_noirq,
110			       sg2042_pcie_resume_noirq);
111
112static const struct of_device_id sg2042_pcie_of_match[] = {
113	{ .compatible = "sophgo,sg2042-pcie-host" },
114	{},
115};
116MODULE_DEVICE_TABLE(of, sg2042_pcie_of_match);
117
118static struct platform_driver sg2042_pcie_driver = {
119	.driver = {
120		.name		= "sg2042-pcie",
121		.of_match_table	= sg2042_pcie_of_match,
122		.pm		= pm_sleep_ptr(&sg2042_pcie_pm_ops),
123	},
124	.probe		= sg2042_pcie_probe,
125	.remove		= sg2042_pcie_remove,
126};
127module_platform_driver(sg2042_pcie_driver);
128
129MODULE_LICENSE("GPL");
130MODULE_DESCRIPTION("PCIe controller driver for SG2042 SoCs");
131MODULE_AUTHOR("Chen Wang <unicorn_wang@outlook.com>");
~/ Read-only file preview.