diff options
author | Sudipto Paul <sudipto.paul@arm.com> | 2018-11-21 18:53:12 +0000 |
---|---|---|
committer | sudipto paul <sudipto.paul@arm.com> | 2019-07-22 14:00:38 +0100 |
commit | 8fa835eb141b6a0a052ab65233eaf7db869cabca (patch) | |
tree | 0188065650a410afd2dc4844efd9bfbbaa4c9619 | |
parent | 75cf1a23a7be4d1525e7be9caff74fff02253325 (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/defconfig | 2 | ||||
-rw-r--r-- | drivers/acpi/pci_mcfg.c | 6 | ||||
-rw-r--r-- | drivers/pci/controller/Kconfig | 8 | ||||
-rw-r--r-- | drivers/pci/controller/Makefile | 1 | ||||
-rw-r--r-- | drivers/pci/controller/pcie-n1sdp.c | 167 | ||||
-rw-r--r-- | include/linux/pci-ecam.h | 1 |
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 |