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