1From b59e0d6c6035db80fc9044df0333f96ede53ad7a Mon Sep 17 00:00:00 2001
2From: Sayanta Pattanayak <sayanta.pattanayak@arm.com>
3Date: Wed, 9 Feb 2022 20:37:43 +0530
4Subject: [PATCH] n1sdp: pcie: add quirk support enabling remote chip PCIe
5
6Base address mapping for remote chip Root PCIe ECAM space.
7
8When two N1SDP boards are coupled via the CCIX connection, the PCI host
9complex of the remote board appears as PCIe segment 2 on the primary board.
10The resources of the secondary board, including the host complex, are
11mapped at offset 0x40000000000 into the address space of the primary
12board, so take that into account when accessing the remote PCIe segment.
13
14Change-Id: I0e8d1eb119aef6444b9df854a39b24441c12195a
15Signed-off-by: Sayanta Pattanayak <sayanta.pattanayak@arm.com>
16Signed-off-by: Khasim Syed Mohammed <khasim.mohammed@arm.com>
17Signed-off-by: Andre Przywara <andre.przywara@arm.com>
18Signed-off-by: sahil <sahil@arm.com>
19
20Upstream-Status: Inappropriate [will not be submitted as its an hack required to fix the hardware issue]
21Signed-off-by: Sayanta Pattanayak <sayanta.pattanayak@arm.com>
22Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
23Signed-off-by: Adam Johnston <adam.johnston@arm.com>
24---
25 drivers/acpi/pci_mcfg.c             |  1 +
26 drivers/pci/controller/pcie-n1sdp.c | 32 +++++++++++++++++++++++++----
27 include/linux/pci-ecam.h            |  1 +
28 3 files changed, 30 insertions(+), 4 deletions(-)
29
30diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c
31index 2d4c1c699ffe..27f1e9a45c17 100644
32--- a/drivers/acpi/pci_mcfg.c
33+++ b/drivers/acpi/pci_mcfg.c
34@@ -178,6 +178,7 @@ static struct mcfg_fixup mcfg_quirks[] = {
35 	/* N1SDP SoC with v1 PCIe controller */
36 	N1SDP_ECAM_MCFG(0x20181101, 0, &pci_n1sdp_pcie_ecam_ops),
37 	N1SDP_ECAM_MCFG(0x20181101, 1, &pci_n1sdp_ccix_ecam_ops),
38+	N1SDP_ECAM_MCFG(0x20181101, 2, &pci_n1sdp_remote_pcie_ecam_ops),
39 #endif /* ARM64 */
40
41 #ifdef CONFIG_LOONGARCH
42diff --git a/drivers/pci/controller/pcie-n1sdp.c b/drivers/pci/controller/pcie-n1sdp.c
43index 408699b9dcb1..b3b02417fd7d 100644
44--- a/drivers/pci/controller/pcie-n1sdp.c
45+++ b/drivers/pci/controller/pcie-n1sdp.c
46@@ -30,8 +30,10 @@
47
48 /* Platform specific values as hardcoded in the firmware. */
49 #define AP_NS_SHARED_MEM_BASE	0x06000000
50-#define MAX_SEGMENTS		2		/* Two PCIe root complexes. */
51+/* Two PCIe root complexes in One Chip + One PCIe RC in Remote Chip */
52+#define MAX_SEGMENTS		3
53 #define BDF_TABLE_SIZE		SZ_16K
54+#define REMOTE_CHIP_ADDR_OFFSET	0x40000000000
55
56 /*
57  * Shared memory layout as written by the SCP upon boot time:
58@@ -97,12 +99,17 @@ static int pci_n1sdp_init(struct pci_config_window *cfg, unsigned int segment)
59 	phys_addr_t table_base;
60 	struct device *dev = cfg->parent;
61 	struct pcie_discovery_data *shared_data;
62-	size_t bdfs_size;
63+	size_t bdfs_size, rc_base_addr = 0;
64
65 	if (segment >= MAX_SEGMENTS)
66 		return -ENODEV;
67
68-	table_base = AP_NS_SHARED_MEM_BASE + segment * BDF_TABLE_SIZE;
69+	if (segment > 1) {
70+		rc_base_addr = REMOTE_CHIP_ADDR_OFFSET;
71+		table_base = AP_NS_SHARED_MEM_BASE + REMOTE_CHIP_ADDR_OFFSET;
72+	} else {
73+		table_base = AP_NS_SHARED_MEM_BASE + segment * BDF_TABLE_SIZE;
74+	}
75
76 	if (!request_mem_region(table_base, BDF_TABLE_SIZE,
77 				"PCIe valid BDFs")) {
78@@ -114,6 +121,7 @@ static int pci_n1sdp_init(struct pci_config_window *cfg, unsigned int segment)
79 				   table_base, BDF_TABLE_SIZE);
80 	if (!shared_data)
81 		return -ENOMEM;
82+	rc_base_addr += shared_data->rc_base_addr;
83
84 	/* Copy the valid BDFs structure to allocated normal memory. */
85 	bdfs_size = sizeof(struct pcie_discovery_data) +
86@@ -125,7 +133,7 @@ static int pci_n1sdp_init(struct pci_config_window *cfg, unsigned int segment)
87 	memcpy_fromio(pcie_discovery_data[segment], shared_data, bdfs_size);
88
89 	rc_remapped_addr[segment] = devm_ioremap(dev,
90-						 shared_data->rc_base_addr,
91+						 rc_base_addr,
92 						 PCI_CFG_SPACE_EXP_SIZE);
93 	if (!rc_remapped_addr[segment]) {
94 		dev_err(dev, "Cannot remap root port base\n");
95@@ -161,6 +169,12 @@ static int pci_n1sdp_ccix_init(struct pci_config_window *cfg)
96 	return pci_n1sdp_init(cfg, 1);
97 }
98
99+/* Called for ACPI segment 2. */
100+static int pci_n1sdp_remote_pcie_init(struct pci_config_window *cfg)
101+{
102+	return pci_n1sdp_init(cfg, 2);
103+}
104+
105 const struct pci_ecam_ops pci_n1sdp_pcie_ecam_ops = {
106 	.bus_shift	= 20,
107 	.init		= pci_n1sdp_pcie_init,
108@@ -181,6 +195,16 @@ const struct pci_ecam_ops pci_n1sdp_ccix_ecam_ops = {
109 	}
110 };
111
112+const struct pci_ecam_ops pci_n1sdp_remote_pcie_ecam_ops = {
113+	.bus_shift	= 20,
114+	.init		= pci_n1sdp_remote_pcie_init,
115+	.pci_ops	= {
116+		.map_bus        = pci_n1sdp_map_bus,
117+		.read           = pci_generic_config_read32,
118+		.write          = pci_generic_config_write32,
119+	}
120+};
121+
122 static const struct of_device_id n1sdp_pcie_of_match[] = {
123 	{ .compatible = "arm,n1sdp-pcie", .data = &pci_n1sdp_pcie_ecam_ops },
124 	{ },
125diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h
126index b3cf3adeab28..d4316795c00d 100644
127--- a/include/linux/pci-ecam.h
128+++ b/include/linux/pci-ecam.h
129@@ -90,6 +90,7 @@ extern const struct pci_ecam_ops tegra194_pcie_ops; /* Tegra194 PCIe */
130 extern const struct pci_ecam_ops loongson_pci_ecam_ops; /* Loongson PCIe */
131 extern const struct pci_ecam_ops pci_n1sdp_pcie_ecam_ops; /* Arm N1SDP PCIe */
132 extern const struct pci_ecam_ops pci_n1sdp_ccix_ecam_ops; /* Arm N1SDP PCIe */
133+extern const struct pci_ecam_ops pci_n1sdp_remote_pcie_ecam_ops; /* Arm N1SDP PCIe */
134 #endif
135
136 #if IS_ENABLED(CONFIG_PCI_HOST_COMMON)
137