Commit 5f00f1a0 authored by Dongdong Liu's avatar Dongdong Liu Committed by Bjorn Helgaas

PCI: Add MCFG quirks for HiSilicon Hip05/06/07 host controllers

The PCIe controller in Hip05/Hip06/Hip07 SoCs is not completely
ECAM-compliant.  It is non-ECAM only for the RC bus config space; for any
other bus underneath the root bus it does support ECAM access.

Add specific quirks for PCI config space accessors.  This involves:
1. New initialization call hisi_pcie_init() to obtain RC base
addresses from PNP0C02 at the root of the ACPI namespace (under \_SB).
2. New entry in common quirk array.

[bhelgaas: move to pcie-hisi.c and change Makefile/ifdefs so quirk doesn't
depend on CONFIG_PCI_HISI]
Signed-off-by: default avatarDongdong Liu <liudongdong3@huawei.com>
Signed-off-by: default avatarGabriele Paoloni <gabriele.paoloni@huawei.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
parent 2ca5b8dd
...@@ -62,6 +62,18 @@ static struct mcfg_fixup mcfg_quirks[] = { ...@@ -62,6 +62,18 @@ static struct mcfg_fixup mcfg_quirks[] = {
QCOM_ECAM32(5), QCOM_ECAM32(5),
QCOM_ECAM32(6), QCOM_ECAM32(6),
QCOM_ECAM32(7), QCOM_ECAM32(7),
#define HISI_QUAD_DOM(table_id, seg, ops) \
{ "HISI ", table_id, 0, (seg) + 0, MCFG_BUS_ANY, ops }, \
{ "HISI ", table_id, 0, (seg) + 1, MCFG_BUS_ANY, ops }, \
{ "HISI ", table_id, 0, (seg) + 2, MCFG_BUS_ANY, ops }, \
{ "HISI ", table_id, 0, (seg) + 3, MCFG_BUS_ANY, ops }
HISI_QUAD_DOM("HIP05 ", 0, &hisi_pcie_ops),
HISI_QUAD_DOM("HIP06 ", 0, &hisi_pcie_ops),
HISI_QUAD_DOM("HIP07 ", 0, &hisi_pcie_ops),
HISI_QUAD_DOM("HIP07 ", 4, &hisi_pcie_ops),
HISI_QUAD_DOM("HIP07 ", 8, &hisi_pcie_ops),
HISI_QUAD_DOM("HIP07 ", 12, &hisi_pcie_ops),
}; };
static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
......
...@@ -25,7 +25,7 @@ obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o ...@@ -25,7 +25,7 @@ obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o
obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o
obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o
obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o
obj-$(CONFIG_PCI_HISI) += pcie-hisi.o obj-$(CONFIG_ARM64) += pcie-hisi.o
obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
......
...@@ -18,7 +18,106 @@ ...@@ -18,7 +18,106 @@
#include <linux/of_pci.h> #include <linux/of_pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/pci.h>
#include <linux/pci-acpi.h>
#include <linux/pci-ecam.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include "../pci.h"
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
static int hisi_pcie_acpi_rd_conf(struct pci_bus *bus, u32 devfn, int where,
int size, u32 *val)
{
struct pci_config_window *cfg = bus->sysdata;
int dev = PCI_SLOT(devfn);
if (bus->number == cfg->busr.start) {
/* access only one slot on each root port */
if (dev > 0)
return PCIBIOS_DEVICE_NOT_FOUND;
else
return pci_generic_config_read32(bus, devfn, where,
size, val);
}
return pci_generic_config_read(bus, devfn, where, size, val);
}
static int hisi_pcie_acpi_wr_conf(struct pci_bus *bus, u32 devfn,
int where, int size, u32 val)
{
struct pci_config_window *cfg = bus->sysdata;
int dev = PCI_SLOT(devfn);
if (bus->number == cfg->busr.start) {
/* access only one slot on each root port */
if (dev > 0)
return PCIBIOS_DEVICE_NOT_FOUND;
else
return pci_generic_config_write32(bus, devfn, where,
size, val);
}
return pci_generic_config_write(bus, devfn, where, size, val);
}
static void __iomem *hisi_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
int where)
{
struct pci_config_window *cfg = bus->sysdata;
void __iomem *reg_base = cfg->priv;
if (bus->number == cfg->busr.start)
return reg_base + where;
else
return pci_ecam_map_bus(bus, devfn, where);
}
static int hisi_pcie_init(struct pci_config_window *cfg)
{
struct device *dev = cfg->parent;
struct acpi_device *adev = to_acpi_device(dev);
struct acpi_pci_root *root = acpi_driver_data(adev);
struct resource *res;
void __iomem *reg_base;
int ret;
/*
* Retrieve RC base and size from a HISI0081 device with _UID
* matching our segment.
*/
res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
if (!res)
return -ENOMEM;
ret = acpi_get_rc_resources(dev, "HISI0081", root->segment, res);
if (ret) {
dev_err(dev, "can't get rc base address\n");
return -ENOMEM;
}
reg_base = devm_ioremap(dev, res->start, resource_size(res));
if (!reg_base)
return -ENOMEM;
cfg->priv = reg_base;
return 0;
}
struct pci_ecam_ops hisi_pcie_ops = {
.bus_shift = 20,
.init = hisi_pcie_init,
.pci_ops = {
.map_bus = hisi_pcie_map_bus,
.read = hisi_pcie_acpi_rd_conf,
.write = hisi_pcie_acpi_wr_conf,
}
};
#endif
#ifdef CONFIG_PCI_HISI
#include "pcie-designware.h" #include "pcie-designware.h"
...@@ -227,3 +326,5 @@ static struct platform_driver hisi_pcie_driver = { ...@@ -227,3 +326,5 @@ static struct platform_driver hisi_pcie_driver = {
}, },
}; };
builtin_platform_driver(hisi_pcie_driver); builtin_platform_driver(hisi_pcie_driver);
#endif
...@@ -61,6 +61,7 @@ extern struct pci_ecam_ops pci_generic_ecam_ops; ...@@ -61,6 +61,7 @@ extern struct pci_ecam_ops pci_generic_ecam_ops;
#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
extern struct pci_ecam_ops pci_32b_ops; /* 32-bit accesses only */ extern struct pci_ecam_ops pci_32b_ops; /* 32-bit accesses only */
extern struct pci_ecam_ops hisi_pcie_ops; /* HiSilicon */
#endif #endif
#ifdef CONFIG_PCI_HOST_GENERIC #ifdef CONFIG_PCI_HOST_GENERIC
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment