plat: imx8mm: enable power domain support

Enable the power domain support on imx8mm.

Signed-off-by: Bai Ping <ping.bai@nxp.com>
(cherry picked from commit 1541d8a9e3c7704b6ca0aa66f6dacf6e10b70bb6)
diff --git a/plat/imx/imx8mm/gpc.c b/plat/imx/imx8mm/gpc.c
index cd1d45c..a2eabbb 100644
--- a/plat/imx/imx8mm/gpc.c
+++ b/plat/imx/imx8mm/gpc.c
@@ -17,6 +17,7 @@
 #include <psci.h>
 #include <imx_sip.h>
 #include <soc.h>
+#include <delay_timer.h>
 
 #define GPC_PGC_ACK_SEL_A53	0x24
 #define GPC_IMR1_CORE0_A53	0x30
@@ -87,23 +88,11 @@
 #define PLAT_PGC_PCR		0x900
 #define NOC_PGC_PCR		0xa40
 
-#define MIPI_PGC               0xc00
-#define PCIE_PGC               0xc40
-#define OTG1_PGC               0xc80
-#define OTG2_PGC               0xcc0
-#define GPU2D_PGC              0xd80
-#define GPUMIX_PGC             0xdc0
-#define VPUMIX_PGC             0xe00
-#define GPU3D_PGC              0xe40
-#define DISPMIX_PGC            0xe80
-#define VPU_G1_PGC             0xec0
-#define VPU_G2_PGC             0xf00
-#define VPU_H1_PGC             0xf40
-
 #define MIPI_PWR_REQ		(1 << 0)
 #define PCIE_PWR_REQ		(1 << 1)
 #define OTG1_PWR_REQ		(1 << 2)
 #define OTG2_PWR_REQ		(1 << 3)
+#define HSIOMIX_PWR_REQ		(1 << 4)
 #define GPU2D_PWR_REQ		(1 << 6)
 #define GPUMIX_PWR_REQ		(1 << 7)
 #define VPUMIX_PWR_REQ		(1 << 8)
@@ -113,11 +102,13 @@
 #define VPU_G2_PWR_REQ		(1 << 12)
 #define VPU_H1_PWR_REQ		(1 << 13)
 
+#define HSIOMIX_ADB400_SYNC	(0x3 << 5)
 #define DISPMIX_ADB400_SYNC	(1 << 7)
 #define VPUMIX_ADB400_SYNC	(1 << 8)
 #define GPU3D_ADB400_SYNC	(1 << 9)
 #define GPU2D_ADB400_SYNC	(1 << 10)
 #define GPUMIX_ADB400_SYNC	(1 << 11)
+#define HSIOMIX_ADB400_ACK	(0x3 << 23)
 #define DISPMIX_ADB400_ACK	(1 << 25)
 #define VPUMIX_ADB400_ACK	(1 << 26)
 #define GPU3D_ADB400_ACK	(1 << 27)
@@ -128,6 +119,7 @@
 #define PCIE_PGC		0xc40
 #define OTG1_PGC		0xc80
 #define OTG2_PGC		0xcc0
+#define HSIOMIX_PGC	        0xd00
 #define GPU2D_PGC		0xd80
 #define GPUMIX_PGC		0xdc0
 #define VPUMIX_PGC		0xe00
@@ -173,19 +165,39 @@
 	bool init_on;
 };
 
+enum pu_domain_id {
+	HSIOMIX,
+	PCIE,
+	OTG1,
+	OTG2,
+	GPUMIX,
+	VPUMIX,
+	VPU_G1,
+	VPU_G2,
+	VPU_H1,
+	DISPMIX,
+	MIPI,
+	/* below two domain only for ATF internal use */
+	GPU2D,
+	GPU3D,
+};
+
 /* PU domain */
 static struct imx_pwr_domain pu_domains[] = {
-	IMX_PD_DOMAIN(MIPI),
+	IMX_MIX_DOMAIN(HSIOMIX),
 	IMX_PD_DOMAIN(PCIE),
 	IMX_PD_DOMAIN(OTG1),
 	IMX_PD_DOMAIN(OTG2),
-	IMX_MIX_DOMAIN(GPU2D),
 	IMX_MIX_DOMAIN(GPUMIX),
 	IMX_MIX_DOMAIN(VPUMIX),
-	IMX_MIX_DOMAIN(GPU3D),
-	IMX_MIX_DOMAIN(DISPMIX),
 	IMX_PD_DOMAIN(VPU_G1),
 	IMX_PD_DOMAIN(VPU_G2),
+	IMX_PD_DOMAIN(VPU_H1),
+	IMX_MIX_DOMAIN(DISPMIX),
+	IMX_PD_DOMAIN(MIPI),
+	/* below two domain only for ATF internal use */
+	IMX_MIX_DOMAIN(GPU2D),
+	IMX_MIX_DOMAIN(GPU3D),
 };
 
 static uint32_t gpc_wake_irqs[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, };
@@ -193,6 +205,8 @@
 /* save gic dist&redist context when NOC wrapper is power down */
 static struct plat_gic_ctx imx_gicv3_ctx;
 
+static unsigned int pu_domain_status;
+
 void imx_set_cpu_secure_entry(int core_id, uintptr_t sec_entrypoint)
 {
 	uint64_t temp_base;
@@ -532,10 +546,10 @@
 	val |= (0x3 << 1);
 	mmio_write_32(IMX_GPC_BASE + MST_CPU_MAPPING, val);
 
-	/* FIXME enable NOC power down on real silicon */
-#if 0
-	imx_noc_slot_config(true);
-#endif
+	/* noc can only be power down when all the pu domain is off */
+//	if (!pu_domain_status)
+//		/* enable noc power down */
+//		imx_noc_slot_config(true);
 	/*
 	 * gic redistributor context save must be called when
 	 * the GIC CPU interface is disabled and before distributor save.
@@ -557,10 +571,11 @@
 	val &= ~(0x3 << 1);
 	mmio_write_32(IMX_GPC_BASE + MST_CPU_MAPPING, val);
 
-	/* FIXME enable NOC power down on real silicon */
-#if 0
-	imx_noc_slot_config(false);
-#endif
+	/* noc can only be power down when all the pu domain is off */
+//	if (!pu_domain_status)
+//		/* disable noc power down */
+//		imx_noc_slot_config(false);
+
 	/* restore gic context */
 	plat_gic_restore(proc_num, &imx_gicv3_ctx);
 }
@@ -605,25 +620,86 @@
 				 gpc_wake_irqs[idx] | mask;
 }
 
+
 static void imx_gpc_pm_domain_enable(uint32_t domain_id, uint32_t on)
 {
 	uint32_t val;
 
 	struct imx_pwr_domain *pwr_domain = &pu_domains[domain_id];
 
-	/* FIXME, will remove after runtime PM is ok */
-	return;
-
 	if (on) {
-		/* clear the PGC bit */
-		val = mmio_read_32(IMX_GPC_BASE + pwr_domain->pgc_offset);
-		val &= ~(1 << 0);
-		mmio_write_32(IMX_GPC_BASE + pwr_domain->pgc_offset, val);
+		pu_domain_status |= (1 << domain_id);
 
-		/* power up the domain */
-		val = mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG);
-		val |= pwr_domain->pwr_req;
-		mmio_write_32(IMX_GPC_BASE + PU_PGC_UP_TRG, val);
+		/* HSIOMIX has no PU bit, so skip for it */
+		if (domain_id != HSIOMIX) {
+			/* clear the PGC bit */
+			val = mmio_read_32(IMX_GPC_BASE + pwr_domain->pgc_offset);
+			val &= ~(1 << 0);
+			mmio_write_32(IMX_GPC_BASE + pwr_domain->pgc_offset, val);
+
+			/* power up the domain */
+			val = mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG);
+			val |= pwr_domain->pwr_req;
+			mmio_write_32(IMX_GPC_BASE + PU_PGC_UP_TRG, val);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & pwr_domain->pwr_req);
+		}
+
+		if (domain_id == GPUMIX) {
+			/* power up GPU2D */
+			val = mmio_read_32(IMX_GPC_BASE + GPU2D_PGC);
+			val &= ~(1 << 0);
+			mmio_write_32(IMX_GPC_BASE + GPU2D_PGC, val);
+
+			val = mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG);
+			val |= GPU2D_PWR_REQ;
+			mmio_write_32(IMX_GPC_BASE + PU_PGC_UP_TRG, val);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & GPU2D_PWR_REQ);
+
+			udelay(1);
+
+			/* power up GPU3D */
+			val = mmio_read_32(IMX_GPC_BASE + GPU3D_PGC);
+			val &= ~(1 << 0);
+			mmio_write_32(IMX_GPC_BASE + GPU3D_PGC, val);
+
+			val = mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG);
+			val |= GPU3D_PWR_REQ;
+			mmio_write_32(IMX_GPC_BASE + PU_PGC_UP_TRG, val);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & GPU3D_PWR_REQ);
+
+			udelay(1);
+
+			/* assert reset */
+			mmio_write_32(0x30390040, 0x1);
+			udelay(10);
+			mmio_write_32(0x30390040, 0x0);
+			udelay(10);
+		}
+
+		/* vpu sft clock enable */
+		if (domain_id == VPUMIX) {
+			mmio_write_32(0x30390044, 0x1);
+			udelay(5);
+			mmio_write_32(0x30390044, 0x0);
+			udelay(5);
+
+			/* enable all clock */
+			mmio_write_32(0x38330004, 0x7);
+		}
+
+		if (domain_id == DISPMIX) {
+			/* special setting for DISPMIX */
+			mmio_write_32(0x303845d0, 0x3);
+			mmio_write_32(0x32e28004, 0x1fff);
+			mmio_write_32(0x32e28000, 0x7f);
+			mmio_write_32(0x32e28008, 0x30000);
+		}
 
 		/* handle the ADB400 sync */
 		if (!pwr_domain->init_on && pwr_domain->need_sync) {
@@ -635,25 +711,55 @@
 			/* wait for adb power request ack */
 			while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack))
 				;
-		}
 
-		/* special fixup for dispmix */
-		if (pwr_domain->pwr_req == DISPMIX_PWR_REQ) {
-			mmio_write_32(0x303845d0, 0x3);
-			mmio_write_32(0x32e28000, 0x7f);
-			mmio_write_32(0x32e28004, 0x1fff);
-			mmio_write_32(0x32e28008, 0x30000);
+			if (domain_id == GPUMIX) {
+				/* power up GPU2D ADB */
+				val = mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK);
+				val |= GPU2D_ADB400_SYNC;
+				mmio_write_32(IMX_GPC_BASE + GPC_PU_PWRHSK, val);
+
+				/* wait for adb power request ack */
+				while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU2D_ADB400_ACK))
+					;
+
+				/* power up GPU3D ADB */
+				val = mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK);
+				val |= GPU3D_ADB400_SYNC;
+				mmio_write_32(IMX_GPC_BASE + GPC_PU_PWRHSK, val);
+
+				/* wait for adb power request ack */
+				while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU3D_ADB400_ACK))
+					;
+			}
 		}
 	} else {
-		/* TODO  for bringup purpose */
-		return;
-		/* set the PGC bit */
-		val = mmio_read_32(IMX_GPC_BASE + pwr_domain->pgc_offset);
-		val |= (1 << 0);
-		mmio_write_32(IMX_GPC_BASE + pwr_domain->pgc_offset, val);
+		pu_domain_status &= ~(1 << domain_id);
+
+		if (domain_id == OTG1 || domain_id == OTG2)
+			return;
 
 		/* handle the ADB400 sync */
 		if (!pwr_domain->init_on && pwr_domain->need_sync) {
+
+			/* GPU2D & GPU3D ADB power down */
+			if (domain_id == GPUMIX) {
+				val = mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK);
+				val &= ~GPU2D_ADB400_SYNC;
+				mmio_write_32(IMX_GPC_BASE + GPC_PU_PWRHSK, val);
+
+				/* wait for adb power request ack */
+				while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU2D_ADB400_ACK))
+					;
+
+				val = mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK);
+				val &= ~GPU3D_ADB400_SYNC;
+				mmio_write_32(IMX_GPC_BASE + GPC_PU_PWRHSK, val);
+
+				/* wait for adb power request ack */
+				while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU3D_ADB400_ACK))
+					;
+			}
+
 			/* set adb power down request */
 			val = mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK);
 			val &= ~(pwr_domain->adb400_sync);
@@ -664,10 +770,50 @@
 				;
 		}
 
-		/* power down the domain */
-		val = mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG);
-		val |= pwr_domain->pwr_req;
-		mmio_write_32(IMX_GPC_BASE + PU_PGC_DN_TRG, val);
+		if (domain_id == GPUMIX) {
+			/* power down GPU2D */
+			val = mmio_read_32(IMX_GPC_BASE + GPU2D_PGC);
+			val |= (1 << 0);
+			mmio_write_32(IMX_GPC_BASE + GPU2D_PGC, val);
+
+			val = mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG);
+			val |= GPU2D_PWR_REQ;
+			mmio_write_32(IMX_GPC_BASE + PU_PGC_DN_TRG, val);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & GPU2D_PWR_REQ);
+
+			/* power down GPU3D */
+			val = mmio_read_32(IMX_GPC_BASE + GPU3D_PGC);
+			val |= (1 << 0);
+			mmio_write_32(IMX_GPC_BASE + GPU3D_PGC, val);
+
+			val = mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG);
+			val |= GPU3D_PWR_REQ;
+			mmio_write_32(IMX_GPC_BASE + PU_PGC_DN_TRG, val);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & GPU3D_PWR_REQ);
+		}
+
+		/* HSIOMIX has no PU bit, so skip for it */
+		if (domain_id != HSIOMIX) {
+			if (domain_id == GPUMIX || domain_id == VPUMIX)
+				return;
+
+			/* set the PGC bit */
+			val = mmio_read_32(IMX_GPC_BASE + pwr_domain->pgc_offset);
+			val |= (1 << 0);
+			mmio_write_32(IMX_GPC_BASE + pwr_domain->pgc_offset, val);
+
+			/* power down the domain */
+			val = mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG);
+			val |= pwr_domain->pwr_req;
+			mmio_write_32(IMX_GPC_BASE + PU_PGC_DN_TRG, val);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & pwr_domain->pwr_req);
+		}
 	}
 
 	pwr_domain->init_on = false;
@@ -707,23 +853,6 @@
 	/*set all mix/PU in A53 domain */
 	mmio_write_32(IMX_GPC_BASE + GPC_PGC_CPU_0_1_MAPPING, 0xffff);
 
-	/* TODO release dispmix sft reset */
-	/* enable all the PU for bringup up purpose */
-	mmio_write_32(0x30384450, 0x3);
-	mmio_write_32(0x303844d0, 0x3);
-	mmio_write_32(0x303844f0, 0x3);
-	mmio_write_32(0x30384560, 0x3);
-	mmio_write_32(0x30384570, 0x3);
-	mmio_write_32(0x30384590, 0x3);
-	mmio_write_32(0x303845a0, 0x3);
-	mmio_write_32(0x303845d0, 0x3);
-	mmio_write_32(0x30384630, 0x3);
-	mmio_write_32(0x30384660, 0x3);
-	mmio_write_32(IMX_GPC_BASE + 0xf8, 0x3fcf);
-	mmio_write_32(0x32e28000, 0x7f);
-	mmio_write_32(0x32e28004, 0x1fff);
-	mmio_write_32(0x32e28008, 0x30000);
-
 	/* set SCU timming */
 	mmio_write_32(IMX_GPC_BASE + GPC_PGC_SCU_TIMMING,
 		      (0x59 << 10) | 0x5B | (0x2 << 20));
diff --git a/plat/imx/imx8mm/imx8mm_bl31_setup.c b/plat/imx/imx8mm/imx8mm_bl31_setup.c
index d3d64d0..1820c4b 100644
--- a/plat/imx/imx8mm/imx8mm_bl31_setup.c
+++ b/plat/imx/imx8mm/imx8mm_bl31_setup.c
@@ -13,6 +13,7 @@
 #include <debug.h>
 #include <stdbool.h>
 #include <dram.h>
+#include <generic_delay_timer.h>
 #include <mmio.h>
 #include <platform.h>
 #include <platform_def.h>
@@ -259,6 +260,8 @@
 
 	mmap_add_region(0x180000, 0x180000, 0x8000, MT_MEMORY | MT_RW);
 
+	mmap_add_region(0x38330000, 0x38330000, 0x100000, MT_DEVICE | MT_RW);
+
 #if USE_COHERENT_MEM
 	mmap_add_region(BL31_COHERENT_RAM_BASE, BL31_COHERENT_RAM_BASE,
 		BL31_COHERENT_RAM_LIMIT - BL31_COHERENT_RAM_BASE,
@@ -273,6 +276,8 @@
 
 void bl31_platform_setup(void)
 {
+	generic_delay_timer_init();
+
 	/* select the CKIL source to 32K OSC */
 	mmio_write_32(0x30360124, 0x1);
 
diff --git a/plat/imx/imx8mm/platform.mk b/plat/imx/imx8mm/platform.mk
index 2ec0986..a4dd64b 100644
--- a/plat/imx/imx8mm/platform.mk
+++ b/plat/imx/imx8mm/platform.mk
@@ -32,8 +32,10 @@
 				lib/xlat_tables/xlat_tables_common.c	\
 				lib/cpus/aarch64/cortex_a53.S		\
 				drivers/console/aarch64/console.S	\
-				${PLAT_GIC_SOURCES}			\
-				${PLAT_DRAM_SOURCES}			\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				${PLAT_GIC_SOURCES}				\
+				${PLAT_DRAM_SOURCES}				\
 				drivers/arm/tzc/tzc380.c
 
 ENABLE_PLAT_COMPAT	:=	0