Justin Vreeland 794d92
From ec7b5bf1cc1444d9ad13bcef0f0f8d48ff9c0203 Mon Sep 17 00:00:00 2001
Justin Vreeland 794d92
From: Peter Robinson <pbrobinson@gmail.com>
Justin Vreeland 794d92
Date: Sat, 19 Dec 2020 14:10:40 +0000
Justin Vreeland 794d92
Subject: [PATCH] PCI: Add MCFG quirks for Tegra194 host controllers
Justin Vreeland 794d92
Justin Vreeland 794d92
The PCIe controller in Tegra194 SoC is not completely ECAM-compliant.
Justin Vreeland 794d92
With the current hardware design limitations in place, ECAM can be enabled
Justin Vreeland 794d92
only for one controller (C5 controller to be precise) with bus numbers
Justin Vreeland 794d92
starting from 160 instead of 0. A different approach is taken to avoid this
Justin Vreeland 794d92
abnormal way of enabling ECAM for just one controller but to enable
Justin Vreeland 794d92
configuration space access for all the other controllers. In this approach,
Justin Vreeland 794d92
ops are added through MCFG quirk mechanism which access the configuration
Justin Vreeland 794d92
spaces by dynamically programming iATU (internal AddressTranslation Unit)
Justin Vreeland 794d92
to generate respective configuration accesses just like the way it is
Justin Vreeland 794d92
done in DesignWare core sub-system.
Justin Vreeland 794d92
Justin Vreeland 794d92
Signed-off-by: Vidya Sagar <vidyas@nvidia.com>
Justin Vreeland 794d92
Acked-by: Thierry Reding <treding@nvidia.com>
Justin Vreeland 794d92
[ Updated by jonathanh@nvidia.com only permit building the Tegra194
Justin Vreeland 794d92
  PCIe driver into the kernel and not as a module ]
Justin Vreeland 794d92
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Justin Vreeland 794d92
Signed-off-by: Peter Robinson <pbrobinson@gmail.com>
Justin Vreeland 794d92
---
Justin Vreeland 794d92
 drivers/acpi/pci_mcfg.c                    |   7 ++
Justin Vreeland 794d92
 drivers/pci/controller/dwc/Kconfig         |  10 +-
Justin Vreeland 794d92
 drivers/pci/controller/dwc/Makefile        |   2 +-
Justin Vreeland 794d92
 drivers/pci/controller/dwc/pcie-tegra194.c | 102 +++++++++++++++++++++
Justin Vreeland 794d92
 include/linux/pci-ecam.h                   |   1 +
Justin Vreeland 794d92
 5 files changed, 117 insertions(+), 5 deletions(-)
Justin Vreeland 794d92
Justin Vreeland 794d92
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
Justin Vreeland 794d92
index 95f23acd5b80..53cab975f612 100644
Justin Vreeland 794d92
--- a/drivers/acpi/pci_mcfg.c
Justin Vreeland 794d92
+++ b/drivers/acpi/pci_mcfg.c
Justin Vreeland 794d92
@@ -116,6 +116,13 @@ static struct mcfg_fixup mcfg_quirks[] = {
Justin Vreeland 794d92
 	THUNDER_ECAM_QUIRK(2, 12),
Justin Vreeland 794d92
 	THUNDER_ECAM_QUIRK(2, 13),
Justin Vreeland 794d92
 
Justin Vreeland 794d92
+	{ "NVIDIA", "TEGRA194", 1, 0, MCFG_BUS_ANY, &tegra194_pcie_ops},
Justin Vreeland 794d92
+	{ "NVIDIA", "TEGRA194", 1, 1, MCFG_BUS_ANY, &tegra194_pcie_ops},
Justin Vreeland 794d92
+	{ "NVIDIA", "TEGRA194", 1, 2, MCFG_BUS_ANY, &tegra194_pcie_ops},
Justin Vreeland 794d92
+	{ "NVIDIA", "TEGRA194", 1, 3, MCFG_BUS_ANY, &tegra194_pcie_ops},
Justin Vreeland 794d92
+	{ "NVIDIA", "TEGRA194", 1, 4, MCFG_BUS_ANY, &tegra194_pcie_ops},
Justin Vreeland 794d92
+	{ "NVIDIA", "TEGRA194", 1, 5, MCFG_BUS_ANY, &tegra194_pcie_ops},
Justin Vreeland 794d92
+
Justin Vreeland 794d92
 #define XGENE_V1_ECAM_MCFG(rev, seg) \
Justin Vreeland 794d92
 	{"APM   ", "XGENE   ", rev, seg, MCFG_BUS_ANY, \
Justin Vreeland 794d92
 		&xgene_v1_pcie_ecam_ops }
Justin Vreeland 794d92
diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
Justin Vreeland 794d92
index bc049865f8e0..c5d40951a6ad 100644
Justin Vreeland 794d92
--- a/drivers/pci/controller/dwc/Kconfig
Justin Vreeland 794d92
+++ b/drivers/pci/controller/dwc/Kconfig
Justin Vreeland 794d92
@@ -248,25 +248,27 @@ config PCI_MESON
Justin Vreeland 794d92
 	  implement the driver.
Justin Vreeland 794d92
 
Justin Vreeland 794d92
 config PCIE_TEGRA194
Justin Vreeland 794d92
-	tristate
Justin Vreeland 794d92
+	bool
Justin Vreeland 794d92
 
Justin Vreeland 794d92
 config PCIE_TEGRA194_HOST
Justin Vreeland 794d92
-	tristate "NVIDIA Tegra194 (and later) PCIe controller - Host Mode"
Justin Vreeland 794d92
+	bool "NVIDIA Tegra194 (and later) PCIe controller - Host Mode"
Justin Vreeland 794d92
 	depends on ARCH_TEGRA_194_SOC || COMPILE_TEST
Justin Vreeland 794d92
 	depends on PCI_MSI_IRQ_DOMAIN
Justin Vreeland 794d92
 	select PCIE_DW_HOST
Justin Vreeland 794d92
 	select PHY_TEGRA194_P2U
Justin Vreeland 794d92
 	select PCIE_TEGRA194
Justin Vreeland 794d92
+	default y if ARCH_TEGRA_194_SOC
Justin Vreeland 794d92
 	help
Justin Vreeland 794d92
 	  Enables support for the PCIe controller in the NVIDIA Tegra194 SoC to
Justin Vreeland 794d92
 	  work in host mode. There are two instances of PCIe controllers in
Justin Vreeland 794d92
 	  Tegra194. This controller can work either as EP or RC. In order to
Justin Vreeland 794d92
 	  enable host-specific features PCIE_TEGRA194_HOST must be selected and
Justin Vreeland 794d92
 	  in order to enable device-specific features PCIE_TEGRA194_EP must be
Justin Vreeland 794d92
-	  selected. This uses the DesignWare core.
Justin Vreeland 794d92
+	  selected. This uses the DesignWare core. ACPI platforms with Tegra194
Justin Vreeland 794d92
+	  don't need to enable this.
Justin Vreeland 794d92
 
Justin Vreeland 794d92
 config PCIE_TEGRA194_EP
Justin Vreeland 794d92
-	tristate "NVIDIA Tegra194 (and later) PCIe controller - Endpoint Mode"
Justin Vreeland 794d92
+	bool "NVIDIA Tegra194 (and later) PCIe controller - Endpoint Mode"
Justin Vreeland 794d92
 	depends on ARCH_TEGRA_194_SOC || COMPILE_TEST
Justin Vreeland 794d92
 	depends on PCI_ENDPOINT
Justin Vreeland 794d92
 	select PCIE_DW_EP
Justin Vreeland 794d92
diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile
Justin Vreeland 794d92
index a751553fa0db..dbb981876556 100644
Justin Vreeland 794d92
--- a/drivers/pci/controller/dwc/Makefile
Justin Vreeland 794d92
+++ b/drivers/pci/controller/dwc/Makefile
Justin Vreeland 794d92
@@ -17,7 +17,6 @@ obj-$(CONFIG_PCIE_INTEL_GW) += pcie-intel-gw.o
Justin Vreeland 794d92
 obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o
Justin Vreeland 794d92
 obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
Justin Vreeland 794d92
 obj-$(CONFIG_PCI_MESON) += pci-meson.o
Justin Vreeland 794d92
-obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o
Justin Vreeland 794d92
 obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o
Justin Vreeland 794d92
 obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
Justin Vreeland 794d92
 
Justin Vreeland 794d92
@@ -34,4 +33,5 @@ obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o
Justin Vreeland 794d92
 ifdef CONFIG_PCI
Justin Vreeland 794d92
 obj-$(CONFIG_ARM64) += pcie-al.o
Justin Vreeland 794d92
 obj-$(CONFIG_ARM64) += pcie-hisi.o
Justin Vreeland 794d92
+obj-$(CONFIG_ARM64) += pcie-tegra194.o
Justin Vreeland 794d92
 endif
Justin Vreeland 794d92
diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c
Justin Vreeland 794d92
index f920e7efe118..87c7929db727 100644
Justin Vreeland 794d92
--- a/drivers/pci/controller/dwc/pcie-tegra194.c
Justin Vreeland 794d92
+++ b/drivers/pci/controller/dwc/pcie-tegra194.c
Justin Vreeland 794d92
@@ -22,6 +22,8 @@
Justin Vreeland 794d92
 #include <linux/of_irq.h>
Justin Vreeland 794d92
 #include <linux/of_pci.h>
Justin Vreeland 794d92
 #include <linux/pci.h>
Justin Vreeland 794d92
+#include <linux/pci-acpi.h>
Justin Vreeland 794d92
+#include <linux/pci-ecam.h>
Justin Vreeland 794d92
 #include <linux/phy/phy.h>
Justin Vreeland 794d92
 #include <linux/pinctrl/consumer.h>
Justin Vreeland 794d92
 #include <linux/platform_device.h>
Justin Vreeland 794d92
@@ -311,6 +313,103 @@ struct tegra_pcie_dw_of_data {
Justin Vreeland 794d92
 	enum dw_pcie_device_mode mode;
Justin Vreeland 794d92
 };
Justin Vreeland 794d92
 
Justin Vreeland 794d92
+#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)
Justin Vreeland 794d92
+struct tegra194_pcie_acpi  {
Justin Vreeland 794d92
+	void __iomem *config_base;
Justin Vreeland 794d92
+	void __iomem *iatu_base;
Justin Vreeland 794d92
+	void __iomem *dbi_base;
Justin Vreeland 794d92
+};
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+static int tegra194_acpi_init(struct pci_config_window *cfg)
Justin Vreeland 794d92
+{
Justin Vreeland 794d92
+	struct device *dev = cfg->parent;
Justin Vreeland 794d92
+	struct tegra194_pcie_acpi *pcie;
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+	pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
Justin Vreeland 794d92
+	if (!pcie)
Justin Vreeland 794d92
+		return -ENOMEM;
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+	pcie->config_base = cfg->win;
Justin Vreeland 794d92
+	pcie->iatu_base = cfg->win + SZ_256K;
Justin Vreeland 794d92
+	pcie->dbi_base = cfg->win + SZ_512K;
Justin Vreeland 794d92
+	cfg->priv = pcie;
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+	return 0;
Justin Vreeland 794d92
+}
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+static inline void atu_reg_write(struct tegra194_pcie_acpi *pcie, int index,
Justin Vreeland 794d92
+				 u32 val, u32 reg)
Justin Vreeland 794d92
+{
Justin Vreeland 794d92
+	u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+	writel(val, pcie->iatu_base + offset + reg);
Justin Vreeland 794d92
+}
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+static void program_outbound_atu(struct tegra194_pcie_acpi *pcie, int index,
Justin Vreeland 794d92
+				 int type, u64 cpu_addr, u64 pci_addr, u64 size)
Justin Vreeland 794d92
+{
Justin Vreeland 794d92
+	atu_reg_write(pcie, index, lower_32_bits(cpu_addr),
Justin Vreeland 794d92
+		      PCIE_ATU_LOWER_BASE);
Justin Vreeland 794d92
+	atu_reg_write(pcie, index, upper_32_bits(cpu_addr),
Justin Vreeland 794d92
+		      PCIE_ATU_UPPER_BASE);
Justin Vreeland 794d92
+	atu_reg_write(pcie, index, lower_32_bits(pci_addr),
Justin Vreeland 794d92
+		      PCIE_ATU_LOWER_TARGET);
Justin Vreeland 794d92
+	atu_reg_write(pcie, index, lower_32_bits(cpu_addr + size - 1),
Justin Vreeland 794d92
+		      PCIE_ATU_LIMIT);
Justin Vreeland 794d92
+	atu_reg_write(pcie, index, upper_32_bits(pci_addr),
Justin Vreeland 794d92
+		      PCIE_ATU_UPPER_TARGET);
Justin Vreeland 794d92
+	atu_reg_write(pcie, index, type, PCIE_ATU_CR1);
Justin Vreeland 794d92
+	atu_reg_write(pcie, index, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
Justin Vreeland 794d92
+}
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+static void __iomem *tegra194_map_bus(struct pci_bus *bus,
Justin Vreeland 794d92
+				      unsigned int devfn, int where)
Justin Vreeland 794d92
+{
Justin Vreeland 794d92
+	struct pci_config_window *cfg = bus->sysdata;
Justin Vreeland 794d92
+	struct tegra194_pcie_acpi *pcie = cfg->priv;
Justin Vreeland 794d92
+	u32 busdev;
Justin Vreeland 794d92
+	int type;
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+	if (bus->number < cfg->busr.start || bus->number > cfg->busr.end)
Justin Vreeland 794d92
+		return NULL;
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+	if (bus->number == cfg->busr.start) {
Justin Vreeland 794d92
+		if (PCI_SLOT(devfn) == 0)
Justin Vreeland 794d92
+			return pcie->dbi_base + where;
Justin Vreeland 794d92
+		else
Justin Vreeland 794d92
+			return NULL;
Justin Vreeland 794d92
+	}
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+	busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
Justin Vreeland 794d92
+		 PCIE_ATU_FUNC(PCI_FUNC(devfn));
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+	if (bus->parent->number == cfg->busr.start) {
Justin Vreeland 794d92
+		if (PCI_SLOT(devfn) == 0)
Justin Vreeland 794d92
+			type = PCIE_ATU_TYPE_CFG0;
Justin Vreeland 794d92
+		else
Justin Vreeland 794d92
+			return NULL;
Justin Vreeland 794d92
+	} else {
Justin Vreeland 794d92
+		type = PCIE_ATU_TYPE_CFG1;
Justin Vreeland 794d92
+	}
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+	program_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0, type,
Justin Vreeland 794d92
+			     cfg->res.start, busdev, SZ_256K);
Justin Vreeland 794d92
+	return (void __iomem *)(pcie->config_base + where);
Justin Vreeland 794d92
+}
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+const struct pci_ecam_ops tegra194_pcie_ops = {
Justin Vreeland 794d92
+	.bus_shift	= 20,
Justin Vreeland 794d92
+	.init		= tegra194_acpi_init,
Justin Vreeland 794d92
+	.pci_ops	= {
Justin Vreeland 794d92
+		.map_bus	= tegra194_map_bus,
Justin Vreeland 794d92
+		.read		= pci_generic_config_read,
Justin Vreeland 794d92
+		.write		= pci_generic_config_write,
Justin Vreeland 794d92
+	}
Justin Vreeland 794d92
+};
Justin Vreeland 794d92
+#endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+#ifdef CONFIG_PCIE_TEGRA194
Justin Vreeland 794d92
+
Justin Vreeland 794d92
 static inline struct tegra_pcie_dw *to_tegra_pcie(struct dw_pcie *pci)
Justin Vreeland 794d92
 {
Justin Vreeland 794d92
 	return container_of(pci, struct tegra_pcie_dw, pci);
Justin Vreeland 794d92
@@ -2339,3 +2438,6 @@ MODULE_DEVICE_TABLE(of, tegra_pcie_dw_of_match);
Justin Vreeland 794d92
 MODULE_AUTHOR("Vidya Sagar <vidyas@nvidia.com>");
Justin Vreeland 794d92
 MODULE_DESCRIPTION("NVIDIA PCIe host controller driver");
Justin Vreeland 794d92
 MODULE_LICENSE("GPL v2");
Justin Vreeland 794d92
+
Justin Vreeland 794d92
+#endif /* CONFIG_PCIE_TEGRA194 */
Justin Vreeland 794d92
+
Justin Vreeland 794d92
diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
Justin Vreeland 794d92
index 033ce74f02e8..ccbf3c38c6e6 100644
Justin Vreeland 794d92
--- a/include/linux/pci-ecam.h
Justin Vreeland 794d92
+++ b/include/linux/pci-ecam.h
Justin Vreeland 794d92
@@ -58,6 +58,7 @@ extern const struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */
Justin Vreeland 794d92
 extern const struct pci_ecam_ops xgene_v1_pcie_ecam_ops; /* APM X-Gene PCIe v1 */
Justin Vreeland 794d92
 extern const struct pci_ecam_ops xgene_v2_pcie_ecam_ops; /* APM X-Gene PCIe v2.x */
Justin Vreeland 794d92
 extern const struct pci_ecam_ops al_pcie_ops;	/* Amazon Annapurna Labs PCIe */
Justin Vreeland 794d92
+extern const struct pci_ecam_ops tegra194_pcie_ops; /* Tegra194 PCIe */
Justin Vreeland 794d92
 #endif
Justin Vreeland 794d92
 
Justin Vreeland 794d92
 #if IS_ENABLED(CONFIG_PCI_HOST_COMMON)
Justin Vreeland 794d92
-- 
Justin Vreeland 794d92
2.29.2
Justin Vreeland 794d92