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 22 struct hisi_pcie { 23 void __iomem *reg_base; 24 }; 25 26 static 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 44 static 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 62 static 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 76 static 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 111 const 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 124 static 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 149 static 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 158 static 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 170 static 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 }; 178 builtin_platform_driver(hisi_pcie_almost_ecam_driver); 179 180 #endif 181 #endif 182