Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * PCIe host controller driver for HiSilicon SoCs
0004  *
0005  * Copyright (C) 2015 HiSilicon Co., Ltd. http://www.hisilicon.com
0006  *
0007  * Authors: Zhou Wang <wangzhou1@hisilicon.com>
0008  *          Dacai Zhu <zhudacai@hisilicon.com>
0009  *          Gabriele Paoloni <gabriele.paoloni@huawei.com>
0010  */
0011 #include <linux/interrupt.h>
0012 #include <linux/init.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/pci.h>
0015 #include <linux/pci-acpi.h>
0016 #include <linux/pci-ecam.h>
0017 #include "../../pci.h"
0018 
0019 #if defined(CONFIG_PCI_HISI) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS))
0020 
0021 struct hisi_pcie {
0022     void __iomem    *reg_base;
0023 };
0024 
0025 static int hisi_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
0026                  int size, u32 *val)
0027 {
0028     struct pci_config_window *cfg = bus->sysdata;
0029     int dev = PCI_SLOT(devfn);
0030 
0031     if (bus->number == cfg->busr.start) {
0032         /* access only one slot on each root port */
0033         if (dev > 0)
0034             return PCIBIOS_DEVICE_NOT_FOUND;
0035         else
0036             return pci_generic_config_read32(bus, devfn, where,
0037                              size, val);
0038     }
0039 
0040     return pci_generic_config_read(bus, devfn, where, size, val);
0041 }
0042 
0043 static int hisi_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
0044                  int where, int size, u32 val)
0045 {
0046     struct pci_config_window *cfg = bus->sysdata;
0047     int dev = PCI_SLOT(devfn);
0048 
0049     if (bus->number == cfg->busr.start) {
0050         /* access only one slot on each root port */
0051         if (dev > 0)
0052             return PCIBIOS_DEVICE_NOT_FOUND;
0053         else
0054             return pci_generic_config_write32(bus, devfn, where,
0055                               size, val);
0056     }
0057 
0058     return pci_generic_config_write(bus, devfn, where, size, val);
0059 }
0060 
0061 static void __iomem *hisi_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
0062                        int where)
0063 {
0064     struct pci_config_window *cfg = bus->sysdata;
0065     struct hisi_pcie *pcie = cfg->priv;
0066 
0067     if (bus->number == cfg->busr.start)
0068         return pcie->reg_base + where;
0069     else
0070         return pci_ecam_map_bus(bus, devfn, where);
0071 }
0072 
0073 #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
0074 
0075 static int hisi_pcie_init(struct pci_config_window *cfg)
0076 {
0077     struct device *dev = cfg->parent;
0078     struct hisi_pcie *pcie;
0079     struct acpi_device *adev = to_acpi_device(dev);
0080     struct acpi_pci_root *root = acpi_driver_data(adev);
0081     struct resource *res;
0082     int ret;
0083 
0084     pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
0085     if (!pcie)
0086         return -ENOMEM;
0087 
0088     /*
0089      * Retrieve RC base and size from a HISI0081 device with _UID
0090      * matching our segment.
0091      */
0092     res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
0093     if (!res)
0094         return -ENOMEM;
0095 
0096     ret = acpi_get_rc_resources(dev, "HISI0081", root->segment, res);
0097     if (ret) {
0098         dev_err(dev, "can't get rc base address\n");
0099         return -ENOMEM;
0100     }
0101 
0102     pcie->reg_base = devm_pci_remap_cfgspace(dev, res->start, resource_size(res));
0103     if (!pcie->reg_base)
0104         return -ENOMEM;
0105 
0106     cfg->priv = pcie;
0107     return 0;
0108 }
0109 
0110 const struct pci_ecam_ops hisi_pcie_ops = {
0111     .init         =  hisi_pcie_init,
0112     .pci_ops      = {
0113         .map_bus    = hisi_pcie_map_bus,
0114         .read       = hisi_pcie_rd_conf,
0115         .write      = hisi_pcie_wr_conf,
0116     }
0117 };
0118 
0119 #endif
0120 
0121 #ifdef CONFIG_PCI_HISI
0122 
0123 static int hisi_pcie_platform_init(struct pci_config_window *cfg)
0124 {
0125     struct device *dev = cfg->parent;
0126     struct hisi_pcie *pcie;
0127     struct platform_device *pdev = to_platform_device(dev);
0128     struct resource *res;
0129 
0130     pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
0131     if (!pcie)
0132         return -ENOMEM;
0133 
0134     res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0135     if (!res) {
0136         dev_err(dev, "missing \"reg[1]\"property\n");
0137         return -EINVAL;
0138     }
0139 
0140     pcie->reg_base = devm_pci_remap_cfgspace(dev, res->start, resource_size(res));
0141     if (!pcie->reg_base)
0142         return -ENOMEM;
0143 
0144     cfg->priv = pcie;
0145     return 0;
0146 }
0147 
0148 static const struct pci_ecam_ops hisi_pcie_platform_ops = {
0149     .init         =  hisi_pcie_platform_init,
0150     .pci_ops      = {
0151         .map_bus    = hisi_pcie_map_bus,
0152         .read       = hisi_pcie_rd_conf,
0153         .write      = hisi_pcie_wr_conf,
0154     }
0155 };
0156 
0157 static const struct of_device_id hisi_pcie_almost_ecam_of_match[] = {
0158     {
0159         .compatible =  "hisilicon,hip06-pcie-ecam",
0160         .data       =  &hisi_pcie_platform_ops,
0161     },
0162     {
0163         .compatible =  "hisilicon,hip07-pcie-ecam",
0164         .data       =  &hisi_pcie_platform_ops,
0165     },
0166     {},
0167 };
0168 
0169 static struct platform_driver hisi_pcie_almost_ecam_driver = {
0170     .probe  = pci_host_common_probe,
0171     .driver = {
0172            .name = "hisi-pcie-almost-ecam",
0173            .of_match_table = hisi_pcie_almost_ecam_of_match,
0174            .suppress_bind_attrs = true,
0175     },
0176 };
0177 builtin_platform_driver(hisi_pcie_almost_ecam_driver);
0178 
0179 #endif
0180 #endif