From 3d8553f0a3eea4a0b9b2f6b3ce247fee9c4232f2 Mon Sep 17 00:00:00 2001
From: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
Date: Fri, 3 Mar 2017 12:35:09 +0800
Subject: [PATCH] pci: layerscape: add LS2088A series SoC pcie support

The LS2088A series SoCs has different physical memory map address and
CCSR registers address against LS2080A series SoCs.

Signed-off-by: Hou Zhiqiang <Zhiqiang.Hou@nxp.com>
Reviewed-by: York Sun <york.sun@nxp.com>
---
 arch/arm/cpu/armv8/fsl-layerscape/cpu.c | 46 +++++++++++++++++++++++++
 drivers/pci/pcie_layerscape.c           | 35 +++++++++++++++++++
 drivers/pci/pcie_layerscape.h           |  8 +++++
 3 files changed, 89 insertions(+)

diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
index 78e250c1cc..cebbb0fec5 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
@@ -89,6 +89,49 @@ static inline void early_mmu_setup(void)
 	set_sctlr(get_sctlr() | CR_M);
 }
 
+static void fix_pcie_mmu_map(void)
+{
+#ifdef CONFIG_LS2080A
+	unsigned int i;
+	u32 svr, ver;
+	struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+
+	svr = gur_in32(&gur->svr);
+	ver = SVR_SOC_VER(svr);
+
+	/* Fix PCIE base and size for LS2088A */
+	if ((ver == SVR_LS2088A) || (ver == SVR_LS2084A) ||
+	    (ver == SVR_LS2048A) || (ver == SVR_LS2044A)) {
+		for (i = 0; i < ARRAY_SIZE(final_map); i++) {
+			switch (final_map[i].phys) {
+			case CONFIG_SYS_PCIE1_PHYS_ADDR:
+				final_map[i].phys = 0x2000000000ULL;
+				final_map[i].virt = 0x2000000000ULL;
+				final_map[i].size = 0x800000000ULL;
+				break;
+			case CONFIG_SYS_PCIE2_PHYS_ADDR:
+				final_map[i].phys = 0x2800000000ULL;
+				final_map[i].virt = 0x2800000000ULL;
+				final_map[i].size = 0x800000000ULL;
+				break;
+			case CONFIG_SYS_PCIE3_PHYS_ADDR:
+				final_map[i].phys = 0x3000000000ULL;
+				final_map[i].virt = 0x3000000000ULL;
+				final_map[i].size = 0x800000000ULL;
+				break;
+			case CONFIG_SYS_PCIE4_PHYS_ADDR:
+				final_map[i].phys = 0x3800000000ULL;
+				final_map[i].virt = 0x3800000000ULL;
+				final_map[i].size = 0x800000000ULL;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+#endif
+}
+
 /*
  * The final tables look similar to early tables, but different in detail.
  * These tables are in DRAM. Sub tables are added to enable cache for
@@ -103,6 +146,9 @@ static inline void final_mmu_setup(void)
 	unsigned int el = current_el();
 	int index;
 
+	/* fix the final_map before filling in the block entries */
+	fix_pcie_mmu_map();
+
 	mem_map = final_map;
 
 	/* Update mapping for DDR to actual size */
diff --git a/drivers/pci/pcie_layerscape.c b/drivers/pci/pcie_layerscape.c
index 47dd806ad2..1c5a33ac28 100644
--- a/drivers/pci/pcie_layerscape.c
+++ b/drivers/pci/pcie_layerscape.c
@@ -167,6 +167,27 @@ static void ls_pcie_setup_atu(struct ls_pcie *pcie)
 	pci_get_regions(pcie->bus, &io, &mem, &pref);
 	idx = PCIE_ATU_REGION_INDEX1 + 1;
 
+	/* Fix the pcie memory map for LS2088A series SoCs */
+	svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
+	if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
+	    svr == SVR_LS2048A || svr == SVR_LS2044A) {
+		if (io)
+			io->phys_start = (io->phys_start &
+					 (PCIE_PHYS_SIZE - 1)) +
+					 LS2088A_PCIE1_PHYS_ADDR +
+					 LS2088A_PCIE_PHYS_SIZE * pcie->idx;
+		if (mem)
+			mem->phys_start = (mem->phys_start &
+					 (PCIE_PHYS_SIZE - 1)) +
+					 LS2088A_PCIE1_PHYS_ADDR +
+					 LS2088A_PCIE_PHYS_SIZE * pcie->idx;
+		if (pref)
+			pref->phys_start = (pref->phys_start &
+					 (PCIE_PHYS_SIZE - 1)) +
+					 LS2088A_PCIE1_PHYS_ADDR +
+					 LS2088A_PCIE_PHYS_SIZE * pcie->idx;
+	}
+
 	if (io)
 		/* ATU : OUTBOUND : IO */
 		ls_pcie_atu_outbound_set(pcie, idx++,
@@ -449,6 +470,7 @@ static int ls_pcie_probe(struct udevice *dev)
 	u8 header_type;
 	u16 link_sta;
 	bool ep_mode;
+	uint svr;
 	int ret;
 
 	pcie->bus = dev;
@@ -502,6 +524,19 @@ static int ls_pcie_probe(struct udevice *dev)
 		return ret;
 	}
 
+	/*
+	 * Fix the pcie memory map address and PF control registers address
+	 * for LS2088A series SoCs
+	 */
+	svr = get_svr();
+	svr = (svr >> SVR_VAR_PER_SHIFT) & 0xFFFFFE;
+	if (svr == SVR_LS2088A || svr == SVR_LS2084A ||
+	    svr == SVR_LS2048A || svr == SVR_LS2044A) {
+		pcie->cfg_res.start = LS2088A_PCIE1_PHYS_ADDR +
+					LS2088A_PCIE_PHYS_SIZE * pcie->idx;
+		pcie->ctrl = pcie->lut + 0x40000;
+	}
+
 	pcie->cfg0 = map_physmem(pcie->cfg_res.start,
 				 fdt_resource_size(&pcie->cfg_res),
 				 MAP_NOCACHE);
diff --git a/drivers/pci/pcie_layerscape.h b/drivers/pci/pcie_layerscape.h
index 0f9d2fe6d3..e3324a5e52 100644
--- a/drivers/pci/pcie_layerscape.h
+++ b/drivers/pci/pcie_layerscape.h
@@ -26,6 +26,10 @@
 #define CONFIG_SYS_PCI_EP_MEMORY_BASE CONFIG_SYS_LOAD_ADDR
 #endif
 
+#define PCIE_PHYS_SIZE			0x200000000
+#define LS2088A_PCIE_PHYS_SIZE		0x800000000
+#define LS2088A_PCIE1_PHYS_ADDR		0x2000000000
+
 /* iATU registers */
 #define PCIE_ATU_VIEWPORT		0x900
 #define PCIE_ATU_REGION_INBOUND		(0x1 << 31)
@@ -109,6 +113,10 @@
 #define SVR_LS102XA		0
 #define SVR_VAR_PER_SHIFT	8
 #define SVR_LS102XA_MASK	0x700
+#define SVR_LS2088A		0x870900
+#define SVR_LS2084A		0x870910
+#define SVR_LS2048A		0x870920
+#define SVR_LS2044A		0x870930
 
 /* LS1021a PCIE space */
 #define LS1021_PCIE_SPACE_OFFSET	0x4000000000ULL
-- 
2.39.5