aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSudipto Paul <sudipto.paul@arm.com>2018-11-21 18:53:12 +0000
committersudipto paul <sudipto.paul@arm.com>2019-07-22 14:00:38 +0100
commit8fa835eb141b6a0a052ab65233eaf7db869cabca (patch)
tree0188065650a410afd2dc4844efd9bfbbaa4c9619
parent75cf1a23a7be4d1525e7be9caff74fff02253325 (diff)
N1SDP PCIe Enablement: Quirks for N1SDP PCie controller
-PCIe Host Controller with MCFG quirk for Bus Map -PCIe Slave Error Mitigation Change-Id: I88ab886799a16fcf35f3a4162ac4387036c567f5 Signed-off-by: Sudipto Paul <sudipto.paul@arm.com> extend the quirk for the ccix root port Signed-off-by: Deepak Pandey <Deepak.Pandey@arm.com>
-rw-r--r--arch/arm64/configs/defconfig2
-rw-r--r--drivers/acpi/pci_mcfg.c6
-rw-r--r--drivers/pci/controller/Kconfig8
-rw-r--r--drivers/pci/controller/Makefile1
-rw-r--r--drivers/pci/controller/pcie-n1sdp.c167
-rw-r--r--include/linux/pci-ecam.h1
6 files changed, 185 insertions, 0 deletions
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index b1c796b6abc7..7f951157a683 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -70,6 +70,7 @@ CONFIG_ARCH_ZX=y
CONFIG_ARCH_ZYNQMP=y
CONFIG_PCI=y
CONFIG_PCIEPORTBUS=y
+CONFIG_PCI_QUIRKS=y
CONFIG_PCI_IOV=y
CONFIG_HOTPLUG_PCI=y
CONFIG_HOTPLUG_PCI_ACPI=y
@@ -87,6 +88,7 @@ CONFIG_PCIE_QCOM=y
CONFIG_PCIE_ARMADA_8K=y
CONFIG_PCIE_KIRIN=y
CONFIG_PCIE_HISI_STB=y
+CONFIG_PCIE_HOST_N1SDP_ECAM=y
CONFIG_ARM64_VA_BITS_48=y
CONFIG_SCHED_MC=y
CONFIG_NUMA=y
diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
index a4e8432fc2fb..50d3d765f7c4 100644
--- a/drivers/acpi/pci_mcfg.c
+++ b/drivers/acpi/pci_mcfg.c
@@ -141,6 +141,12 @@ static struct mcfg_fixup mcfg_quirks[] = {
XGENE_V2_ECAM_MCFG(4, 0),
XGENE_V2_ECAM_MCFG(4, 1),
XGENE_V2_ECAM_MCFG(4, 2),
+
+#define N1SDP_ECAM_MCFG(rev, seg, ops) \
+ {"ARMLTD", "ARMN1SDP", rev, seg, MCFG_BUS_ANY, ops }
+ /* N1SDP SoC with v1 PCIe controller */
+ N1SDP_ECAM_MCFG(0x20181101, 0, &pci_n1sdp_ecam_ops),
+ N1SDP_ECAM_MCFG(0x20181101, 1, &pci_n1sdp_ecam_ops),
};
static char mcfg_oem_id[ACPI_OEM_ID_SIZE];
diff --git a/drivers/pci/controller/Kconfig b/drivers/pci/controller/Kconfig
index 6012f3059acd..900e920c3f04 100644
--- a/drivers/pci/controller/Kconfig
+++ b/drivers/pci/controller/Kconfig
@@ -65,6 +65,14 @@ config PCI_FTPCI100
depends on OF
default ARCH_GEMINI
+config PCIE_HOST_N1SDP_ECAM
+ bool "ARM N1SDP PCIe Controller"
+ depends on ARM64
+ depends on OF || (ACPI && PCI_QUIRKS)
+ select PCI_HOST_COMMON
+ help
+ Say Y here if you want PCIe support for N1SDP platform.
+
config PCI_TEGRA
bool "NVIDIA Tegra PCIe controller"
depends on ARCH_TEGRA || COMPILE_TEST
diff --git a/drivers/pci/controller/Makefile b/drivers/pci/controller/Makefile
index d56a507495c5..1531d9085386 100644
--- a/drivers/pci/controller/Makefile
+++ b/drivers/pci/controller/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_PCIE_MEDIATEK) += pcie-mediatek.o
obj-$(CONFIG_PCIE_MOBIVEIL) += pcie-mobiveil.o
obj-$(CONFIG_PCIE_TANGO_SMP8759) += pcie-tango.o
obj-$(CONFIG_VMD) += vmd.o
+obj-$(CONFIG_PCIE_HOST_N1SDP_ECAM) += pcie-n1sdp.o
# pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
obj-y += dwc/
diff --git a/drivers/pci/controller/pcie-n1sdp.c b/drivers/pci/controller/pcie-n1sdp.c
new file mode 100644
index 000000000000..ea98580f1fb7
--- /dev/null
+++ b/drivers/pci/controller/pcie-n1sdp.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 ARM Ltd
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/of_pci.h>
+#include <linux/of.h>
+#include <linux/pci-ecam.h>
+#include <linux/platform_device.h>
+
+#if defined(CONFIG_PCIE_HOST_N1SDP_ECAM) || (defined(CONFIG_ACPI) \
+&& defined(CONFIG_PCI_QUIRKS))
+
+#define MAX_SEGMENT 0x2
+#define SEGMENT_PCI 0
+#define SEGMENT_CCIX 1
+#define AP_NS_SHARED_MEM_BASE 0x06000000
+#define AP_PCIE_BDF_BASE AP_NS_SHARED_MEM_BASE
+#define AP_CCIX_BDF_BASE (AP_NS_SHARED_MEM_BASE + (16*1024))
+#define AP_NS_SHARED_MEM_SZ 0x0008000
+#define DATA_WIDTH 4
+#define CONFIG_SPACE (DATA_WIDTH * 1024)
+
+typedef struct {
+u32 RC_addr;
+u32 bdf_entry_count;
+} Discover_data_header;
+
+Discover_data_header *DiscoveryData_header[MAX_SEGMENT];
+unsigned int *DiscoveryData[MAX_SEGMENT];
+void *DiscoverySharedMemoryBase[MAX_SEGMENT];
+void __iomem *rc_remapped_addr[MAX_SEGMENT];
+
+/*
+ * This quirk is created to mask the following issues:
+ * PCIE SLVERR issue and MCFG BDF mapping
+ * The low level F/W creates a discovery table with the Root Complex
+ * base address and BDF values
+ * Linux responds only to the EP listed in this table and for rest returns NULL
+ *
+ * Shared Memory layout
+ * ----
+ * Dicover data header --> RC base address
+ * |
+ * --> BDF Count
+ * Discover data --> BDF 0...n
+ * ----
+ *
+ * When the Config Read/Write is called it will call the bus map to get the
+ * address of the Config register
+ *
+ * For the first time map the PCIe Shared Memory
+ * (Non-Secure RAM Location 0x0600_0000)
+ * Read the list of BDFs supported and create a remap for each of these
+ * devices for later processing
+ */
+
+static void __iomem *pci_n1sdp_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int where)
+{
+ struct pci_config_window *cfg = bus->sysdata;
+ unsigned int devfn_shift = cfg->ops->bus_shift - 8;
+ unsigned int busn = bus->number;
+ unsigned int bdf_addr;
+ unsigned int index;
+ void __iomem *remapped_addr;
+ unsigned int * discovery_data;
+ unsigned int segment = bus->domain_nr;
+
+ unsigned int table_count = DiscoveryData_header[segment]->bdf_entry_count;
+
+ if ( busn < cfg->busr.start || busn > cfg->busr.end )
+ return NULL;
+
+ if ((busn == 0) && (devfn == 0)) {
+ return (rc_remapped_addr[segment] + where);
+ }
+ else {
+ discovery_data = DiscoveryData[segment];
+ bdf_addr = ((busn << cfg->ops->bus_shift)
+ |(devfn << devfn_shift));
+ for (index = 0; index < table_count; index++) {
+ if (bdf_addr == discovery_data[index])
+ break;
+ }
+ remapped_addr = (index == table_count)
+ ? NULL : cfg->win + bdf_addr + where;
+ return remapped_addr;
+ }
+}
+static int pci_n1sdp_init(struct pci_config_window *cfg)
+{
+ static unsigned int segment = 0;
+ phys_addr_t TableBase;
+ if (segment == SEGMENT_PCI)
+ {
+ TableBase = (phys_addr_t)AP_PCIE_BDF_BASE;
+ }
+ else if (segment == SEGMENT_CCIX)
+ {
+ TableBase = (phys_addr_t)AP_CCIX_BDF_BASE;
+ }
+ else
+ {
+ printk(KERN_ERR "Invalid Call \n");
+ return -ENOMEM;
+ }
+ if(!request_mem_region(TableBase, AP_NS_SHARED_MEM_SZ/2,
+ "NonSecureMemory")) {
+ printk(KERN_ERR "Region request failed \n");
+ return -ENOMEM;
+ }
+ DiscoverySharedMemoryBase[segment] = (void *)ioremap_nocache(TableBase,
+ AP_NS_SHARED_MEM_SZ/2);
+ if(DiscoverySharedMemoryBase[segment] == NULL) return -ENOMEM;
+
+ /* Allocate memory to hold the discover data header from the
+ shared memory */
+ DiscoveryData_header[segment] = (Discover_data_header *)
+ kmalloc(sizeof(Discover_data_header),
+ GFP_KERNEL);
+ if(DiscoveryData_header[segment] == NULL) {
+ printk(KERN_ERR "Failed to allocate the Discovery \
+ data header struct \n");
+ return -ENOMEM;
+ }
+ memcpy_fromio((void *)DiscoveryData_header[segment],
+ (void *)DiscoverySharedMemoryBase[segment],
+ sizeof(Discover_data_header));
+
+ /* Allocate memory to hold the bdf entry and populate from the
+ shared memory */
+ DiscoveryData[segment] = (unsigned int *)
+ kmalloc(DiscoveryData_header[segment]->bdf_entry_count
+ *sizeof(u32), GFP_KERNEL);
+ if(DiscoveryData[segment] == NULL) {
+ printk(KERN_ERR "Failed to allocate the BDF table memory \n");
+ return -ENOMEM;
+ }
+ memcpy_fromio((void *)DiscoveryData[segment], (void *)DiscoverySharedMemoryBase[segment] +
+ sizeof(Discover_data_header),
+ DiscoveryData_header[segment]->bdf_entry_count*sizeof(u32));
+
+ rc_remapped_addr[segment] = ioremap_nocache(DiscoveryData_header[segment]->RC_addr,
+ CONFIG_SPACE);
+ if (rc_remapped_addr[segment] == NULL) {
+ printk(KERN_ERR "Cannot remap root \
+ port base\n");
+ return -ENOMEM;
+ }
+ segment++;
+ return 0;
+}
+
+struct pci_ecam_ops pci_n1sdp_ecam_ops = {
+ .bus_shift = 20,
+ .init = pci_n1sdp_init,
+ .pci_ops = {
+ .map_bus = pci_n1sdp_map_bus,
+ .read = pci_generic_config_read32,
+ .write = pci_generic_config_write32,
+ }
+};
+#endif
diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
index 29efa09d686b..be89f5ebe620 100644
--- a/include/linux/pci-ecam.h
+++ b/include/linux/pci-ecam.h
@@ -56,6 +56,7 @@ extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 1.x & 2.x */
extern struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */
extern struct pci_ecam_ops xgene_v1_pcie_ecam_ops; /* APM X-Gene PCIe v1 */
extern struct pci_ecam_ops xgene_v2_pcie_ecam_ops; /* APM X-Gene PCIe v2.x */
+extern struct pci_ecam_ops pci_n1sdp_ecam_ops; /* APM N1SDP PCIe */
#endif
#ifdef CONFIG_PCI_HOST_COMMON