File Index
Files and directories
Sign in
FILE

pcie-hisi.c

File preview with syntax highlighting.

linux-6.19.14/drivers/pci/controller/dwc/pcie-hisi.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * PCIe host controller driver for HiSilicon SoCs
  4 *
  5 * Copyright (C) 2015 HiSilicon Co., Ltd. http://www.hisilicon.com
  6 *
  7 * Authors: Zhou Wang <wangzhou1@hisilicon.com>
  8 *          Dacai Zhu <zhudacai@hisilicon.com>
  9 *          Gabriele Paoloni <gabriele.paoloni@huawei.com>
 10 */
 11#include <linux/interrupt.h>
 12#include <linux/init.h>
 13#include <linux/platform_device.h>
 14#include <linux/pci.h>
 15#include <linux/pci-acpi.h>
 16#include <linux/pci-ecam.h>
 17#include "../../pci.h"
 18#include "../pci-host-common.h"
 19
 20#if defined(CONFIG_PCI_HISI) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS))
 21
 22struct hisi_pcie {
 23	void __iomem	*reg_base;
 24};
 25
 26static int hisi_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
 27			     int size, u32 *val)
 28{
 29	struct pci_config_window *cfg = bus->sysdata;
 30	int dev = PCI_SLOT(devfn);
 31
 32	if (bus->number == cfg->busr.start) {
 33		/* access only one slot on each root port */
 34		if (dev > 0)
 35			return PCIBIOS_DEVICE_NOT_FOUND;
 36		else
 37			return pci_generic_config_read32(bus, devfn, where,
 38							 size, val);
 39	}
 40
 41	return pci_generic_config_read(bus, devfn, where, size, val);
 42}
 43
 44static int hisi_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
 45			     int where, int size, u32 val)
 46{
 47	struct pci_config_window *cfg = bus->sysdata;
 48	int dev = PCI_SLOT(devfn);
 49
 50	if (bus->number == cfg->busr.start) {
 51		/* access only one slot on each root port */
 52		if (dev > 0)
 53			return PCIBIOS_DEVICE_NOT_FOUND;
 54		else
 55			return pci_generic_config_write32(bus, devfn, where,
 56							  size, val);
 57	}
 58
 59	return pci_generic_config_write(bus, devfn, where, size, val);
 60}
 61
 62static void __iomem *hisi_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
 63				       int where)
 64{
 65	struct pci_config_window *cfg = bus->sysdata;
 66	struct hisi_pcie *pcie = cfg->priv;
 67
 68	if (bus->number == cfg->busr.start)
 69		return pcie->reg_base + where;
 70	else
 71		return pci_ecam_map_bus(bus, devfn, where);
 72}
 73
 74#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
 75
 76static int hisi_pcie_init(struct pci_config_window *cfg)
 77{
 78	struct device *dev = cfg->parent;
 79	struct hisi_pcie *pcie;
 80	struct acpi_device *adev = to_acpi_device(dev);
 81	struct acpi_pci_root *root = acpi_driver_data(adev);
 82	struct resource *res;
 83	int ret;
 84
 85	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
 86	if (!pcie)
 87		return -ENOMEM;
 88
 89	/*
 90	 * Retrieve RC base and size from a HISI0081 device with _UID
 91	 * matching our segment.
 92	 */
 93	res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
 94	if (!res)
 95		return -ENOMEM;
 96
 97	ret = acpi_get_rc_resources(dev, "HISI0081", root->segment, res);
 98	if (ret) {
 99		dev_err(dev, "can't get rc base address\n");
100		return -ENOMEM;
101	}
102
103	pcie->reg_base = devm_pci_remap_cfgspace(dev, res->start, resource_size(res));
104	if (!pcie->reg_base)
105		return -ENOMEM;
106
107	cfg->priv = pcie;
108	return 0;
109}
110
111const struct pci_ecam_ops hisi_pcie_ops = {
112	.init         =  hisi_pcie_init,
113	.pci_ops      = {
114		.map_bus    = hisi_pcie_map_bus,
115		.read       = hisi_pcie_rd_conf,
116		.write      = hisi_pcie_wr_conf,
117	}
118};
119
120#endif
121
122#ifdef CONFIG_PCI_HISI
123
124static int hisi_pcie_platform_init(struct pci_config_window *cfg)
125{
126	struct device *dev = cfg->parent;
127	struct hisi_pcie *pcie;
128	struct platform_device *pdev = to_platform_device(dev);
129	struct resource *res;
130
131	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
132	if (!pcie)
133		return -ENOMEM;
134
135	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
136	if (!res) {
137		dev_err(dev, "missing \"reg[1]\"property\n");
138		return -EINVAL;
139	}
140
141	pcie->reg_base = devm_pci_remap_cfgspace(dev, res->start, resource_size(res));
142	if (!pcie->reg_base)
143		return -ENOMEM;
144
145	cfg->priv = pcie;
146	return 0;
147}
148
149static const struct pci_ecam_ops hisi_pcie_platform_ops = {
150	.init         =  hisi_pcie_platform_init,
151	.pci_ops      = {
152		.map_bus    = hisi_pcie_map_bus,
153		.read       = hisi_pcie_rd_conf,
154		.write      = hisi_pcie_wr_conf,
155	}
156};
157
158static const struct of_device_id hisi_pcie_almost_ecam_of_match[] = {
159	{
160		.compatible =  "hisilicon,hip06-pcie-ecam",
161		.data	    =  &hisi_pcie_platform_ops,
162	},
163	{
164		.compatible =  "hisilicon,hip07-pcie-ecam",
165		.data       =  &hisi_pcie_platform_ops,
166	},
167	{},
168};
169
170static struct platform_driver hisi_pcie_almost_ecam_driver = {
171	.probe  = pci_host_common_probe,
172	.driver = {
173		   .name = "hisi-pcie-almost-ecam",
174		   .of_match_table = hisi_pcie_almost_ecam_of_match,
175		   .suppress_bind_attrs = true,
176	},
177};
178builtin_platform_driver(hisi_pcie_almost_ecam_driver);
179
180#endif
181#endif
~/ Read-only file preview.