From 8d05bdd3b68cdde4eb7f710f4cad9b5deb290d7c Mon Sep 17 00:00:00 2001 From: Peter Robinson Date: Wed, 5 Aug 2020 23:38:07 +0100 Subject: Upstream 5.9 tegra DT patch, tegra ACPI quirks patch --- ...MCFG-quirks-for-Tegra194-host-controllers.patch | 236 +++++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 0001-PCI-Add-MCFG-quirks-for-Tegra194-host-controllers.patch (limited to '0001-PCI-Add-MCFG-quirks-for-Tegra194-host-controllers.patch') diff --git a/0001-PCI-Add-MCFG-quirks-for-Tegra194-host-controllers.patch b/0001-PCI-Add-MCFG-quirks-for-Tegra194-host-controllers.patch new file mode 100644 index 000000000..6f785a0fe --- /dev/null +++ b/0001-PCI-Add-MCFG-quirks-for-Tegra194-host-controllers.patch @@ -0,0 +1,236 @@ +From a74b75072e094e40a8d1c5fb0370b6c9fc4f7f26 Mon Sep 17 00:00:00 2001 +From: Vidya Sagar +Date: Sat, 11 Jan 2020 00:45:00 +0530 +Subject: [PATCH 1/2] PCI: Add MCFG quirks for Tegra194 host controllers + +The PCIe controller in Tegra194 SoC is not completely ECAM-compliant. +With the current hardware design limitations in place, ECAM can be enabled +only for one controller (C5 controller to be precise) with bus numbers +starting from 160 instead of 0. A different approach is taken to avoid this +abnormal way of enabling ECAM for just one controller but to enable +configuration space access for all the other controllers. In this approach, +ops are added through MCFG quirk mechanism which access the configuration +spaces by dynamically programming iATU (internal AddressTranslation Unit) +to generate respective configuration accesses just like the way it is +done in DesignWare core sub-system. + +Signed-off-by: Vidya Sagar +Reported-by: kbuild test robot +Acked-by: Thierry Reding +[ Updated by jonathanh@nvidia.com only permit building the Tegra194 + PCIe driver into the kernel and not as a module ] +Signed-off-by: Jon Hunter +--- + drivers/acpi/pci_mcfg.c | 7 ++ + drivers/pci/controller/dwc/Kconfig | 9 +- + drivers/pci/controller/dwc/Makefile | 2 +- + drivers/pci/controller/dwc/pcie-tegra194.c | 102 +++++++++++++++++++++ + include/linux/pci-ecam.h | 1 + + 5 files changed, 116 insertions(+), 5 deletions(-) + +diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c +index 54b36b7ad47d9..6573d495d9c1f 100644 +--- a/drivers/acpi/pci_mcfg.c ++++ b/drivers/acpi/pci_mcfg.c +@@ -116,6 +116,13 @@ static struct mcfg_fixup mcfg_quirks[] = { + THUNDER_ECAM_QUIRK(2, 12), + THUNDER_ECAM_QUIRK(2, 13), + ++ { "NVIDIA", "TEGRA194", 1, 0, MCFG_BUS_ANY, &tegra194_pcie_ops}, ++ { "NVIDIA", "TEGRA194", 1, 1, MCFG_BUS_ANY, &tegra194_pcie_ops}, ++ { "NVIDIA", "TEGRA194", 1, 2, MCFG_BUS_ANY, &tegra194_pcie_ops}, ++ { "NVIDIA", "TEGRA194", 1, 3, MCFG_BUS_ANY, &tegra194_pcie_ops}, ++ { "NVIDIA", "TEGRA194", 1, 4, MCFG_BUS_ANY, &tegra194_pcie_ops}, ++ { "NVIDIA", "TEGRA194", 1, 5, MCFG_BUS_ANY, &tegra194_pcie_ops}, ++ + #define XGENE_V1_ECAM_MCFG(rev, seg) \ + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \ + &xgene_v1_pcie_ecam_ops } +diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig +index 044a3761c44f2..7745d26420a72 100644 +--- a/drivers/pci/controller/dwc/Kconfig ++++ b/drivers/pci/controller/dwc/Kconfig +@@ -247,10 +247,10 @@ config PCI_MESON + implement the driver. + + config PCIE_TEGRA194 +- tristate ++ bool + + config PCIE_TEGRA194_HOST +- tristate "NVIDIA Tegra194 (and later) PCIe controller - Host Mode" ++ bool "NVIDIA Tegra194 (and later) PCIe controller - Host Mode" + depends on ARCH_TEGRA_194_SOC || COMPILE_TEST + depends on PCI_MSI_IRQ_DOMAIN + select PCIE_DW_HOST +@@ -262,10 +262,11 @@ config PCIE_TEGRA194_HOST + Tegra194. This controller can work either as EP or RC. In order to + enable host-specific features PCIE_TEGRA194_HOST must be selected and + in order to enable device-specific features PCIE_TEGRA194_EP must be +- selected. This uses the DesignWare core. ++ selected. This uses the DesignWare core. ACPI platforms with Tegra194 ++ don't need to enable this. + + config PCIE_TEGRA194_EP +- tristate "NVIDIA Tegra194 (and later) PCIe controller - Endpoint Mode" ++ bool "NVIDIA Tegra194 (and later) PCIe controller - Endpoint Mode" + depends on ARCH_TEGRA_194_SOC || COMPILE_TEST + depends on PCI_ENDPOINT + select PCIE_DW_EP +diff --git a/drivers/pci/controller/dwc/Makefile b/drivers/pci/controller/dwc/Makefile +index a751553fa0dbd..dbb9818765566 100644 +--- a/drivers/pci/controller/dwc/Makefile ++++ b/drivers/pci/controller/dwc/Makefile +@@ -17,7 +17,6 @@ obj-$(CONFIG_PCIE_INTEL_GW) += pcie-intel-gw.o + obj-$(CONFIG_PCIE_KIRIN) += pcie-kirin.o + obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o + obj-$(CONFIG_PCI_MESON) += pci-meson.o +-obj-$(CONFIG_PCIE_TEGRA194) += pcie-tegra194.o + obj-$(CONFIG_PCIE_UNIPHIER) += pcie-uniphier.o + obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o + +@@ -34,4 +33,5 @@ obj-$(CONFIG_PCIE_UNIPHIER_EP) += pcie-uniphier-ep.o + ifdef CONFIG_PCI + obj-$(CONFIG_ARM64) += pcie-al.o + obj-$(CONFIG_ARM64) += pcie-hisi.o ++obj-$(CONFIG_ARM64) += pcie-tegra194.o + endif +diff --git a/drivers/pci/controller/dwc/pcie-tegra194.c b/drivers/pci/controller/dwc/pcie-tegra194.c +index 92b77f7d83546..cc18814c5bece 100644 +--- a/drivers/pci/controller/dwc/pcie-tegra194.c ++++ b/drivers/pci/controller/dwc/pcie-tegra194.c +@@ -22,6 +22,8 @@ + #include + #include + #include ++#include ++#include + #include + #include + #include +@@ -324,6 +326,103 @@ struct tegra_pcie_dw_of_data { + enum dw_pcie_device_mode mode; + }; + ++#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) ++struct tegra194_pcie_acpi { ++ void __iomem *config_base; ++ void __iomem *iatu_base; ++ void __iomem *dbi_base; ++}; ++ ++static int tegra194_acpi_init(struct pci_config_window *cfg) ++{ ++ struct device *dev = cfg->parent; ++ struct tegra194_pcie_acpi *pcie; ++ ++ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); ++ if (!pcie) ++ return -ENOMEM; ++ ++ pcie->config_base = cfg->win; ++ pcie->iatu_base = cfg->win + SZ_256K; ++ pcie->dbi_base = cfg->win + SZ_512K; ++ cfg->priv = pcie; ++ ++ return 0; ++} ++ ++static inline void atu_reg_write(struct tegra194_pcie_acpi *pcie, int index, ++ u32 val, u32 reg) ++{ ++ u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index); ++ ++ writel(val, pcie->iatu_base + offset + reg); ++} ++ ++static void program_outbound_atu(struct tegra194_pcie_acpi *pcie, int index, ++ int type, u64 cpu_addr, u64 pci_addr, u64 size) ++{ ++ atu_reg_write(pcie, index, lower_32_bits(cpu_addr), ++ PCIE_ATU_LOWER_BASE); ++ atu_reg_write(pcie, index, upper_32_bits(cpu_addr), ++ PCIE_ATU_UPPER_BASE); ++ atu_reg_write(pcie, index, lower_32_bits(pci_addr), ++ PCIE_ATU_LOWER_TARGET); ++ atu_reg_write(pcie, index, lower_32_bits(cpu_addr + size - 1), ++ PCIE_ATU_LIMIT); ++ atu_reg_write(pcie, index, upper_32_bits(pci_addr), ++ PCIE_ATU_UPPER_TARGET); ++ atu_reg_write(pcie, index, type, PCIE_ATU_CR1); ++ atu_reg_write(pcie, index, PCIE_ATU_ENABLE, PCIE_ATU_CR2); ++} ++ ++static void __iomem *tegra194_map_bus(struct pci_bus *bus, ++ unsigned int devfn, int where) ++{ ++ struct pci_config_window *cfg = bus->sysdata; ++ struct tegra194_pcie_acpi *pcie = cfg->priv; ++ u32 busdev; ++ int type; ++ ++ if (bus->number < cfg->busr.start || bus->number > cfg->busr.end) ++ return NULL; ++ ++ if (bus->number == cfg->busr.start) { ++ if (PCI_SLOT(devfn) == 0) ++ return pcie->dbi_base + where; ++ else ++ return NULL; ++ } ++ ++ busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) | ++ PCIE_ATU_FUNC(PCI_FUNC(devfn)); ++ ++ if (bus->parent->number == cfg->busr.start) { ++ if (PCI_SLOT(devfn) == 0) ++ type = PCIE_ATU_TYPE_CFG0; ++ else ++ return NULL; ++ } else { ++ type = PCIE_ATU_TYPE_CFG1; ++ } ++ ++ program_outbound_atu(pcie, PCIE_ATU_REGION_INDEX0, type, ++ cfg->res.start, busdev, SZ_256K); ++ return (void __iomem *)(pcie->config_base + where); ++} ++ ++struct pci_ecam_ops tegra194_pcie_ops = { ++ .bus_shift = 20, ++ .init = tegra194_acpi_init, ++ .pci_ops = { ++ .map_bus = tegra194_map_bus, ++ .read = pci_generic_config_read, ++ .write = pci_generic_config_write, ++ } ++}; ++#endif /* defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) */ ++ ++#ifdef CONFIG_PCIE_TEGRA194 ++ + static inline struct tegra_pcie_dw *to_tegra_pcie(struct dw_pcie *pci) + { + return container_of(pci, struct tegra_pcie_dw, pci); +@@ -2405,3 +2504,6 @@ MODULE_DEVICE_TABLE(of, tegra_pcie_dw_of_match); + MODULE_AUTHOR("Vidya Sagar "); + MODULE_DESCRIPTION("NVIDIA PCIe host controller driver"); + MODULE_LICENSE("GPL v2"); ++ ++#endif /* CONFIG_PCIE_TEGRA194 */ ++ +diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h +index 1af5cb02ef7f9..3fb16ada505a0 100644 +--- a/include/linux/pci-ecam.h ++++ b/include/linux/pci-ecam.h +@@ -57,6 +57,7 @@ extern const struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */ + extern const struct pci_ecam_ops xgene_v1_pcie_ecam_ops; /* APM X-Gene PCIe v1 */ + extern const struct pci_ecam_ops xgene_v2_pcie_ecam_ops; /* APM X-Gene PCIe v2.x */ + extern const struct pci_ecam_ops al_pcie_ops; /* Amazon Annapurna Labs PCIe */ ++extern const struct pci_ecam_ops tegra194_pcie_ops; /* Tegra194 PCIe */ + #endif + + #if IS_ENABLED(CONFIG_PCI_HOST_COMMON) +-- +2.26.2 + -- cgit