plat: imx8mm: add basic imx8mm support

i.MX8MM is a new soc of the i.MX8M family, this patch
add the basic support for i.MX8MM. further code optimization
needed. WAIT mode support is currently disabled, will be enabled
later.

Signed-off-by: Bai Ping <ping.bai@nxp.com>
(cherry picked from commit 6aafe1fcd7296eded1163d919b6ce018487e8645)

Conflicts:
	plat/imx/imx8mq/sip_svc.c
diff --git a/plat/imx/common/imx8_sip_svc.c b/plat/imx/common/imx8_sip_svc.c
index 176d189..23fbf5a 100644
--- a/plat/imx/common/imx8_sip_svc.c
+++ b/plat/imx/common/imx8_sip_svc.c
@@ -34,13 +34,15 @@
 			      u_register_t flags)
 {
 	switch (smc_fid) {
-#if defined(PLAT_IMX8M)
-	case  FSL_SIP_GPC:
-		SMC_RET1(handle, imx_gpc_handler(smc_fid, x1, x2, x3));
-		break;
+#ifdef PLAT_IMX8M
 	case FSL_SIP_DDR_DVFS:
 		SMC_RET1(handle, lpddr4_dvfs_handler(smc_fid, x1, x2, x3));
 		break;
+#endif
+#if defined(PLAT_IMX8M) || defined(PLAT_IMX8MM)
+	case  FSL_SIP_GPC:
+		SMC_RET1(handle, imx_gpc_handler(smc_fid, x1, x2, x3));
+		break;
 	case FSL_SIP_SRC:
 		SMC_RET1(handle, imx_src_handler(smc_fid, x1, x2, x3));
 		break;
diff --git a/plat/imx/common/include/imx_sip.h b/plat/imx/common/include/imx_sip.h
index a119c54..aad5481 100644
--- a/plat/imx/common/include/imx_sip.h
+++ b/plat/imx/common/include/imx_sip.h
@@ -71,18 +71,18 @@
 				u_register_t x4);
 #endif
 
-#if defined(PLAT_IMX8M)
-extern int imx_gpc_handler(uint32_t  smc_fid, u_register_t x1,
-		u_register_t x2, u_register_t x3);
-extern int lpddr4_dvfs_handler(uint32_t  smc_fid, u_register_t x1,
-		u_register_t x2, u_register_t x3);
-extern int imx_src_handler(uint32_t  smc_fid, u_register_t x1,
-		u_register_t x2, u_register_t x3);
-extern int imx_soc_handler(uint32_t smc_fid, u_register_t x1,
-		u_register_t x2, u_register_t x3);
-extern int imx_hab_handler(uint32_t smc_fid, u_register_t x1,
-		u_register_t x2, u_register_t x3, u_register_t x4);
-extern int imx_noc_handler(uint32_t smc_fid, u_register_t x1,
+#if defined(PLAT_IMX8M) || defined(PLAT_IMX8MM)
+int imx_gpc_handler(uint32_t  smc_fid, u_register_t x1,
+	u_register_t x2, u_register_t x3);
+int lpddr4_dvfs_handler(uint32_t  smc_fid, u_register_t x1,
+	u_register_t x2, u_register_t x3);
+int imx_src_handler(uint32_t  smc_fid, u_register_t x1,
+	u_register_t x2, u_register_t x3);
+int imx_soc_handler(uint32_t smc_fid, u_register_t x1,
+	u_register_t x2, u_register_t x3);
+int imx_hab_handler(uint32_t smc_fid, u_register_t x1,
+	u_register_t x2, u_register_t x3, u_register_t x4);
+int imx_noc_handler(uint32_t smc_fid, u_register_t x1,
  		u_register_t x2, u_register_t x3);
 #endif
 
diff --git a/plat/imx/imx8mm/gpc.c b/plat/imx/imx8mm/gpc.c
new file mode 100644
index 0000000..4230e58
--- /dev/null
+++ b/plat/imx/imx8mm/gpc.c
@@ -0,0 +1,676 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <gicv3.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <runtime_svc.h>
+#include <std_svc.h>
+#include <mmio.h>
+#include <plat_imx8.h>
+#include <platform_def.h>
+#include <psci.h>
+#include <imx_sip.h>
+#include <soc.h>
+
+#define GPC_MST_CPU_MAPPING	0x18
+#define GPC_PGC_ACK_SEL_A53	0x24
+#define GPC_IMR1_CORE0_A53	0x30
+#define GPC_IMR1_CORE1_A53	0x40
+#define GPC_IMR1_CORE0_M4	0x50
+#define GPC_IMR1_CORE2_A53	0x1c0
+#define GPC_IMR1_CORE3_A53	0x1d0
+#define GPC_PGC_CPU_0_1_MAPPING	0xec
+#define GPC_PGC_SCU_TIMMING	0x910
+
+#define CPU_PGC_SW_PUP_TRG		0xf0
+#define CPU_PGC_SW_PDN_TRG		0xfc
+#define BM_CPU_PGC_SW_PDN_PUP_REQ 	0x1
+
+#define PGC_PCR			0
+
+#define LPCR_A53_BSC			0x0
+#define LPCR_A53_BSC2			0x108
+#define LPCR_M4				0x8
+#define SLPCR				0x14
+#define SLPCR_EN_DSM			(1 << 31)
+#define SLPCR_RBC_EN			(1 << 30)
+#define SLPCR_A53_FASTWUP_STOP		(1 << 17)
+#define SLPCR_A53_FASTWUP_WAIT		(1 << 16)
+#define SLPCR_VSTBY			(1 << 2)
+#define SLPCR_SBYOS			(1 << 1)
+#define SLPCR_BYPASS_PMIC_READY		0x1
+#define A53_LPM_WAIT			0x5
+#define A53_LPM_STOP			0xa
+#define A53_CLK_ON_LPM			(1 << 14)
+
+#define SRC_GPR1_OFFSET			0x74
+
+
+/* AD */
+#define LPCR_A53_AD			0x4 
+#define	L2PGE				(1 << 31)
+#define EN_L2_WFI_PDN			(1 << 5)
+#define EN_PLAT_PDN			(1 << 4)
+
+#define PU_PGC_UP_TRG			0xf8
+#define PU_PGC_DN_TRG			0x104
+#define GPC_PU_PWRHSK			0x1fc
+
+/* SLOT */
+#define PGC_ACK_SEL_A53			0x24
+#define SLT0_CFG			0xb0
+#define SLT1_CFG			0xb4
+#define SLT2_CFG			0xb8
+#define SLT3_CFG			0xbc
+
+/* ack for slot pup/pdn */
+#define A53_DUMMY_PGC_PUP_ACK	(1 << 31)
+#define NOC_PGC_PUP_ACK		(1 << 19)
+#define PLAT_PGC_PUP_ACK	(1 << 18)
+#define A53_DUMMY_PGC_PDN_ACK	(1 << 15)
+#define NOC_PGC_PDN_ACK		(1 << 3)
+#define PLAT_PGC_PDN_ACK	(1 << 2)
+
+/* pdn/pup bit define for slot control */
+#define NOC_PUP_SLT_CTRL	(1 << 11)
+#define NOC_PDN_SLT_CTRL	(1 << 10)
+#define PLAT_PUP_SLT_CTRL	(1 << 9)
+#define PLAT_PDN_SLT_CTRL	(1 << 8)
+
+#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 GPU2D_PWR_REQ		(1 << 6)
+#define GPUMIX_PWR_REQ		(1 << 7)
+#define VPUMIX_PWR_REQ		(1 << 8)
+#define GPU3D_PWR_REQ		(1 << 9)
+#define DISPMIX_PWR_REQ		(1 << 10)
+#define VPU_G1_PWR_REQ		(1 << 11)
+#define VPU_G2_PWR_REQ		(1 << 12)
+#define VPU_H1_PWR_REQ		(1 << 13)
+
+#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 DISPMIX_ADB400_ACK	(1 << 25)
+#define VPUMIX_ADB400_ACK	(1 << 26)
+#define GPU3D_ADB400_ACK	(1 << 27)
+#define GPU2D_ADB400_ACK	(1 << 28)
+#define GPUMIX_ADB400_ACK	(1 << 29)
+
+#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 IMX_PD_DOMAIN(name)				\
+	{						\
+		.pwr_req = name##_PWR_REQ,		\
+		.pgc_offset = name##_PGC,		\
+		.need_sync = false,			\
+		.init_on = true,			\
+	}
+
+#define IMX_MIX_DOMAIN(name)				\
+	{						\
+		.pwr_req = name##_PWR_REQ,		\
+		.pgc_offset = name##_PGC,		\
+		.adb400_sync = name##_ADB400_SYNC,	\
+		.adb400_ack = name##_ADB400_ACK,	\
+		.need_sync = true,			\
+		.init_on = true,			\
+	}
+
+#define COREx_PGC_PCR(core_id)	(0x800 + core_id * 0x40)
+#define COREx_WFI_PDN(core_id)	(1 << (core_id < 2 ? core_id * 2 : (core_id - 2) * 2 + 16))
+#define COREx_IRQ_WUP(core_id)	(core_id < 2 ? (1 << (core_id * 2 + 8)) : (1 << (core_id * 2 + 20)));
+#define LPM_MODE(local_state)	(local_state == PLAT_WAIT_OFF_STATE ? A53_LPM_WAIT : A53_LPM_STOP)
+#define A53_CORE_WUP_SRC(core_id) (1 << (core_id < 2 ? 28 + core_id : 22 + core_id - 2))
+
+#define IMR_MASK_ALL		0xffffffff
+#define IRQ_SRC_A53_WUP		30
+
+struct imx_pwr_domain {
+	uint32_t pwr_req;
+	uint32_t adb400_sync;
+	uint32_t adb400_ack;
+	uint32_t pgc_offset;
+	bool need_sync;
+	bool init_on;
+};
+
+/* PU domain */
+static struct imx_pwr_domain pu_domains[] = {
+	IMX_PD_DOMAIN(MIPI),
+	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),
+};
+
+static uint32_t gpc_imr_offset[] = { 0x30, 0x40, 0x1c0, 0x1d0, };
+/* save gic dist&redist context when NOC wrapper is power down */
+static struct plat_gic_ctx imx_gicv3_ctx;
+
+void imx_set_cpu_secure_entry(int core_id, uintptr_t sec_entrypoint)
+{
+	uint64_t temp_base;
+
+	temp_base = (uint64_t) sec_entrypoint;
+	temp_base >>= 2;
+
+	mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3),
+		((uint32_t)(temp_base >> 22) & 0xffff));
+	mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3) + 4,
+		((uint32_t)temp_base & 0x003fffff));
+}
+
+/* use wfi power down the core */
+void imx_set_cpu_pwr_off(int core_id)
+{
+	uint32_t val;
+
+	/* enable the wfi power down of the core */
+	val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
+	val |= COREx_WFI_PDN(core_id);
+	mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+
+	/* assert the pcg pcr bit of the core */
+	val = mmio_read_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id));
+	val |= (1 << 0);
+	mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), val);
+};
+
+/* use the sw method to power up the core */
+void imx_set_cpu_pwr_on(int core_id)
+{
+	uint32_t val;
+
+	/* clear the wfi power down bit of the core */
+	val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
+	val &= ~COREx_WFI_PDN(core_id);
+	mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+
+	/* assert the ncpuporeset */
+	val = mmio_read_32(IMX_SRC_BASE + 0x8);
+	val &= ~(1 << core_id);
+	mmio_write_32(IMX_SRC_BASE + 0x8, val);
+
+	/* assert the pcg pcr bit of the core */
+	val = mmio_read_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id));
+	val |= (1 << 0);
+	mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), val);
+
+	/* sw power up the core */
+	val = mmio_read_32(IMX_GPC_BASE + CPU_PGC_SW_PUP_TRG);
+	val |= (1 << core_id);
+	mmio_write_32(IMX_GPC_BASE + CPU_PGC_SW_PUP_TRG, val);
+
+	/* wait for the power up finished */
+	while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_SW_PUP_TRG) & (1 << core_id)) != 0)
+		;
+	/* deassert the pcg pcr bit of the core */
+	val = mmio_read_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id));
+	val &= ~(1 << 0);
+	mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), val);
+
+	/* deassert the ncpuporeset */
+	val = mmio_read_32(IMX_SRC_BASE + 0x8);
+	val |= (1 << core_id);
+	mmio_write_32(IMX_SRC_BASE + 0x8, val);
+}
+
+/* if out of lpm, we need to do reverse steps */
+void imx_set_cpu_lpm(int core_id, bool pdn)
+{
+	uint32_t val;
+
+	if (pdn) {
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
+		/* enable the core WFI power down */
+		val |= COREx_WFI_PDN(core_id);
+		/* enable the core IRQ wakeup */
+		val |= COREx_IRQ_WUP(core_id);
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+
+		/* assert the pcg pcr bit of the core */
+		val = mmio_read_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id));
+		val |= (1 << 0);
+		mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), val);
+	} else {
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
+		/* disable the core WFI power down */
+		val &= ~COREx_WFI_PDN(core_id);
+		/* disable the core IRQ wakeup */
+		val &= ~COREx_IRQ_WUP(core_id);
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+		/* deassert the pcg pcr bit of the core */
+		val = mmio_read_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id));
+		val &= ~(1 << 0);
+		mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), val);
+	}
+}
+
+/*
+ * SLOT 0 is used for A53 PLAT poewr down,
+ * SLOT 1 is used for A53 NOC power down,
+ * SLOT 2 is used for A53 NOC power up,
+ * SLOT 3 is used for A53 PLAT power up,
+ * when enter LPM power down, NOC's ACK is used,
+ * when out of LPM, SCU's ACK is used
+ */
+void imx_a53_plat_slot_config(bool pdn)
+{
+	uint32_t pgc_pcr, slot_ack, pdn_slot_cfg, pup_slot_cfg;
+
+	pdn_slot_cfg = mmio_read_32(IMX_GPC_BASE + SLT0_CFG);
+	pup_slot_cfg = mmio_read_32(IMX_GPC_BASE + SLT3_CFG);
+	pgc_pcr = mmio_read_32(IMX_GPC_BASE + PLAT_PGC_PCR);
+
+		/* enable PLAT PGC PCR */
+		pgc_pcr |= 0x1;
+		mmio_write_32(IMX_GPC_BASE + PLAT_PGC_PCR, pgc_pcr);
+
+
+	if (pdn) {
+		/* config a53 plat pdn/pup slot */
+		pdn_slot_cfg |= PLAT_PDN_SLT_CTRL;
+		pup_slot_cfg |= PLAT_PUP_SLT_CTRL;
+		/* config a53 plat pdn/pup ack */
+		slot_ack = PLAT_PGC_PDN_ACK | PLAT_PGC_PUP_ACK;
+		/* enable PLAT PGC PCR */
+		pgc_pcr |= 0x1;
+
+	} else {
+		/* clear slot/ack config */
+		pdn_slot_cfg &= ~PLAT_PDN_SLT_CTRL;
+		pup_slot_cfg &= ~PLAT_PUP_SLT_CTRL;
+		slot_ack = A53_DUMMY_PGC_PDN_ACK | A53_DUMMY_PGC_PUP_ACK;
+		/* enable PLAT PGC PCR */
+		pgc_pcr &= ~0x1;
+	}
+
+	mmio_write_32(IMX_GPC_BASE + SLT0_CFG, pdn_slot_cfg);
+	mmio_write_32(IMX_GPC_BASE + SLT3_CFG, pup_slot_cfg);
+	mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, slot_ack);
+	mmio_write_32(IMX_GPC_BASE + PLAT_PGC_PCR, pgc_pcr);
+}
+
+void imx_noc_slot_config(bool pdn)
+{
+	uint32_t pgc_pcr, slot_ack, pdn_slot_cfg, pup_slot_cfg;
+
+	pdn_slot_cfg = mmio_read_32(IMX_GPC_BASE + SLT1_CFG);
+	pup_slot_cfg = mmio_read_32(IMX_GPC_BASE + SLT2_CFG);
+	slot_ack = mmio_read_32(IMX_GPC_BASE + PGC_ACK_SEL_A53);
+	pgc_pcr = mmio_read_32(IMX_GPC_BASE + NOC_PGC_PCR);
+
+	if (pdn) {
+		pdn_slot_cfg |= NOC_PDN_SLT_CTRL;
+		pup_slot_cfg |= NOC_PUP_SLT_CTRL;
+
+		/* clear a53's PDN ack, use NOC's PDN ack */
+		slot_ack &= ~0xffff;
+		slot_ack |= NOC_PGC_PDN_ACK;
+		/* enable NOC PGC PCR */
+		pgc_pcr |= 0x1;
+	 } else {
+		pdn_slot_cfg &= ~NOC_PDN_SLT_CTRL;
+		pup_slot_cfg &= ~NOC_PUP_SLT_CTRL;
+		slot_ack = A53_DUMMY_PGC_PUP_ACK | A53_DUMMY_PGC_PDN_ACK;
+		/* disable NOC PGC PCR */
+		pgc_pcr&= ~0x1;
+	}
+
+	mmio_write_32(IMX_GPC_BASE + SLT1_CFG, pdn_slot_cfg);
+	mmio_write_32(IMX_GPC_BASE + SLT2_CFG, pup_slot_cfg);
+	mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, slot_ack);
+	mmio_write_32(IMX_GPC_BASE + NOC_PGC_PCR, pgc_pcr);
+}
+
+/* TODO for cpu clock gate off wait mode */
+void imx_set_cluster_standby(bool enter)
+{
+
+}
+
+/* set the BSC and BSC2 LPM bit, and other bit in AD */
+void imx_set_cluster_powerdown(int last_core, uint8_t power_state)
+{
+	uint32_t val;
+
+	if (is_local_state_off(power_state)) {
+
+		/* config A53 cluster LPM mode */
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+		val |= LPM_MODE(power_state); /* enable the C0~1 LPM */
+		val &= ~A53_CLK_ON_LPM;
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+
+		/* enable C2-3's LPM */
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC2);
+		val |= LPM_MODE(power_state);
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC2, val);
+
+		/* enable PLAT/SCU power down */
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
+		val &= ~EN_L2_WFI_PDN;
+		val |= (L2PGE | EN_PLAT_PDN);
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+
+		/* config SLOT for PLAT power up/down */
+		imx_a53_plat_slot_config(true);
+	} else {
+		/* clear the slot and ack for cluster power down */
+		imx_a53_plat_slot_config(false);
+
+		/* reverse the cluster level setting */
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+		val &= ~0xf; /* clear the C0~1 LPM */
+		val |= A53_CLK_ON_LPM;
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC2);
+		val &= ~0xf;
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC2, val);
+
+		/* clear PLAT/SCU power down */
+		val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD);
+		val |= EN_L2_WFI_PDN;
+		val &= ~(L2PGE | EN_PLAT_PDN);
+		mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val);
+	}
+}
+
+/* only handle the SLPCR and DDR retention */
+/* config the PLLs override setting */
+void imx_set_sys_lpm(bool retention)
+{
+	uint32_t val;
+
+	/* set system DSM mode SLPCR(0x14) */
+	val = mmio_read_32(IMX_GPC_BASE + SLPCR);
+	val &= ~(SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS |
+		 SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN);
+
+	if (retention) {
+		val |= (SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS |
+			SLPCR_BYPASS_PMIC_READY |
+			SLPCR_RBC_EN | SLPCR_A53_FASTWUP_STOP);
+		/* TODO DDR retention */
+	} else {
+		/* TODO DDR retention */
+	}
+	mmio_write_32(IMX_GPC_BASE + SLPCR, val);
+}
+
+void imx_set_rbc_count(void)
+{
+	uint32_t val;
+
+	val = mmio_read_32(IMX_GPC_BASE + SLPCR);
+	val |= (0x3f << 24);
+	mmio_write_32(IMX_GPC_BASE + SLPCR, val);
+}
+
+void imx_clear_rbc_count(void)
+{
+	uint32_t val;
+
+	val = mmio_read_32(IMX_GPC_BASE + SLPCR);
+	val &= ~(0x3f << 24);
+	mmio_write_32(IMX_GPC_BASE + SLPCR, val);
+
+}
+void imx_anamix_pre_suspend()
+{
+	/* TODO */
+}
+
+void imx_anamix_post_resume(void)
+{
+	/* TODO */
+}
+
+void noc_wrapper_pre_suspend(unsigned int proc_num)
+{
+	/* FIXME enable NOC power down on real silicon */
+#if 0
+	imx_noc_slot_config(true);
+#endif
+	/*
+	 * gic redistributor context save must be called when
+	 * the GIC CPU interface is disabled and before distributor save.
+	 */
+	plat_gic_save(proc_num, &imx_gicv3_ctx);
+}
+
+void noc_wrapper_post_resume(unsigned int proc_num)
+{
+	/* FIXME enable NOC power down on real silicon */
+#if 0
+	imx_noc_slot_config(false);
+#endif
+	/* restore gic context */
+	plat_gic_restore(proc_num, &imx_gicv3_ctx);
+}
+
+/* use external IRQ wakeup source for LPM if NOC power down */
+void imx_set_sys_wakeup(int last_core, bool pdn)
+{
+	uint32_t irq_mask, val;
+	gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx;
+
+	val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+	if (pdn) {
+		/* select the external IRQ as the LPM wakeup source */
+		val |= (1 << IRQ_SRC_A53_WUP);
+		/* select the external IRQ as last core's wakeup source */
+		val &= ~A53_CORE_WUP_SRC(last_core); 
+	} else {
+		val &= ~(1 << IRQ_SRC_A53_WUP);
+		val |= A53_CORE_WUP_SRC(last_core);
+	}
+	mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+	
+	/* clear last core's IMR based on GIC's mask setting */
+	for (int i = 0; i < 4; i++) {
+		if (pdn)
+			irq_mask = ~dist_ctx->gicd_isenabler[i];
+		else
+			irq_mask = IMR_MASK_ALL;
+
+		mmio_write_32(IMX_GPC_BASE + gpc_imr_offset[last_core] + i * 4,
+			      irq_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);
+
+		/* 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);
+
+		/* handle the ADB400 sync */
+		if (!pwr_domain->init_on && pwr_domain->need_sync) {
+			/* clear adb power down request */
+			val = mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK);
+			val |= pwr_domain->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) & 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);
+		}
+	} 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);
+
+		/* handle the ADB400 sync */
+		if (!pwr_domain->init_on && pwr_domain->need_sync) {
+			/* set adb power down request */
+			val = mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK);
+			val &= ~(pwr_domain->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) & pwr_domain->adb400_ack))
+				;
+		}
+
+		/* 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);
+	}
+
+	pwr_domain->init_on = false;
+}
+
+void imx_gpc_init(void)
+{
+	unsigned int val;
+	int i;
+
+	/* mask all the wakeup irq by default */
+	for (i = 0; i < 4; i++) {
+		mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE0_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE1_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE2_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE3_A53 + i * 4, ~0x0);
+		mmio_write_32(IMX_GPC_BASE + GPC_IMR1_CORE0_M4 + i * 4, ~0x0);
+	}
+
+	val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC);
+	/* use GIC wake_request to wakeup C0~C3 from LPM */
+	val |= 0x30c00000;
+	/* clear the MASTER0 LPM handshake */
+	val &= ~(1 << 6);
+	val &= ~(1 << 7);
+	val &= ~(1 << 8);
+	mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val);
+
+	/* mask M4 DSM trigger if M4 is NOT enabled */
+	val = mmio_read_32(IMX_GPC_BASE + LPCR_M4);
+	val |= 1 << 31;
+	mmio_write_32(IMX_GPC_BASE + LPCR_M4, val);
+
+	/*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(IMX_GPC_BASE + 0xf8, 0x3fcf);
+	mmio_write_32(0x303845d0, 0x3);
+	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));
+
+	/* set DUMMY PDN/PUP ACK by default for A53 domain */
+	mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53,
+		      A53_DUMMY_PGC_PUP_ACK | A53_DUMMY_PGC_PDN_ACK);
+	/* clear DSM by default */
+	val = mmio_read_32(IMX_GPC_BASE + SLPCR);
+	val &= ~SLPCR_EN_DSM;
+	/* enable the fast wakeup wait mode */
+	val |= SLPCR_A53_FASTWUP_WAIT;
+	/* TODO if M4 is not enabled, clear more SLPCR bits */
+	mmio_write_32(IMX_GPC_BASE + SLPCR, val);
+
+	/*
+	 * USB PHY power up needs to make sure RESET bit in SRC is clear,
+	 * otherwise, the PU power up bit in GPC will NOT self-cleared.
+	 * only need to do it once.
+	 */
+	val = mmio_read_32(0x30390020);
+	val &= ~0x1;
+	mmio_write_32(0x30390020, val);
+	val = mmio_read_32(0x30390024);
+	val &= ~0x1;
+	mmio_write_32(0x30390024, val);
+}
+
+int imx_gpc_handler(uint32_t smc_fid,
+		    u_register_t x1,
+		    u_register_t x2,
+		    u_register_t x3)
+{
+	switch(x1) {
+	case FSL_SIP_CONFIG_GPC_PM_DOMAIN:
+		imx_gpc_pm_domain_enable(x2, x3);
+		break;
+	default:
+		return SMC_UNK;
+	}
+
+	return 0;
+}
diff --git a/plat/imx/imx8mm/imx8mm_bl31_setup.c b/plat/imx/imx8mm/imx8mm_bl31_setup.c
new file mode 100644
index 0000000..8efb77c
--- /dev/null
+++ b/plat/imx/imx8mm/imx8mm_bl31_setup.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <console.h>
+#include <context.h>
+#include <context_mgmt.h>
+#include <debug.h>
+#include <stdbool.h>
+#include <mmio.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <plat_imx8.h>
+#include <xlat_tables.h>
+#include <soc.h>
+#include <tzc380.h>
+
+IMPORT_SYM(unsigned long, __COHERENT_RAM_START__, BL31_COHERENT_RAM_START);
+IMPORT_SYM(unsigned long, __COHERENT_RAM_END__, BL31_COHERENT_RAM_END);
+IMPORT_SYM(unsigned long, __RO_START__, BL31_RO_START);
+IMPORT_SYM(unsigned long, __RO_END__, BL31_RO_END);
+IMPORT_SYM(unsigned long, __RW_START__, BL31_RW_START);
+IMPORT_SYM(unsigned long, __RW_END__, BL31_RW_END);
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/* get SPSR for BL33 entry */
+static uint32_t get_spsr_for_bl33_entry(void)
+{
+	unsigned long el_status;
+	unsigned long mode;
+	uint32_t spsr;
+
+	/* figure out what mode we enter the non-secure world */
+	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
+	el_status &= ID_AA64PFR0_ELX_MASK;
+
+	mode = (el_status) ? MODE_EL2 : MODE_EL1;
+
+	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
+	return spsr;
+}
+
+#define SCTR_BASE_ADDR		0x306c0000
+#define CNTFID0_OFF		0x20
+#define CNTFID1_OFF		0x24
+
+#define SC_CNTCR_ENABLE         (1 << 0)
+#define SC_CNTCR_HDBG           (1 << 1)
+#define SC_CNTCR_FREQ0          (1 << 8)
+#define SC_CNTCR_FREQ1          (1 << 9)
+
+#define GPR_TZASC_EN		(1 << 0)
+#define GPR_TZASC_EN_LOCK	(1 << 16)
+
+#if 1
+void bl31_tzc380_setup(void)
+{
+	unsigned int val;
+
+	val = mmio_read_32(IMX_IOMUX_GPR_BASE + 0x28);
+	if ((val & GPR_TZASC_EN) != GPR_TZASC_EN)
+		return;
+
+	NOTICE("Configureing TZASC380\n");
+
+	tzc380_init(IMX_TZASC_BASE);
+
+	/*
+	 * Need to substact offset 0x40000000 from CPU address when
+	 * programming tzasc region for i.mx8mq.
+	 */
+
+	/* Enable 1G-5G S/NS RW */
+	tzc380_configure_region(0, 0x00000000, TZC_ATTR_REGION_SIZE(TZC_REGION_SIZE_4G) | TZC_ATTR_REGION_EN_MASK | TZC_ATTR_SP_ALL);
+
+	tzc380_dump_state();
+}
+
+static void imx8mm_aips_config(void)
+{
+	/* config the AIPSTZ1 */
+	mmio_write_32(0x301f0000, 0x77777777);
+	mmio_write_32(0x301f0004, 0x77777777);
+	mmio_write_32(0x301f0040, 0x0);
+	mmio_write_32(0x301f0044, 0x0);
+	mmio_write_32(0x301f0048, 0x0);
+	mmio_write_32(0x301f004c, 0x0);
+	mmio_write_32(0x301f0050, 0x0);
+
+	/* config the AIPSTZ2 */
+	mmio_write_32(0x305f0000, 0x77777777);
+	mmio_write_32(0x305f0004, 0x77777777);
+	mmio_write_32(0x305f0040, 0x0);
+	mmio_write_32(0x305f0044, 0x0);
+	mmio_write_32(0x305f0048, 0x0);
+	mmio_write_32(0x305f004c, 0x0);
+	mmio_write_32(0x305f0050, 0x0);
+
+	/* config the AIPSTZ3 */
+	mmio_write_32(0x309f0000, 0x77777777);
+	mmio_write_32(0x309f0004, 0x77777777);
+	mmio_write_32(0x309f0040, 0x0);
+	mmio_write_32(0x309f0044, 0x0);
+	mmio_write_32(0x309f0048, 0x0);
+	mmio_write_32(0x309f004c, 0x0);
+	mmio_write_32(0x309f0050, 0x0);
+
+	/* config the AIPSTZ4 */
+	mmio_write_32(0x32df0000, 0x77777777);
+	mmio_write_32(0x32df0004, 0x77777777);
+	mmio_write_32(0x32df0040, 0x0);
+	mmio_write_32(0x32df0044, 0x0);
+	mmio_write_32(0x32df0048, 0x0);
+	mmio_write_32(0x32df004c, 0x0);
+	mmio_write_32(0x32df0050, 0x0);
+}
+#endif
+
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+		u_register_t arg2, u_register_t arg3)
+{
+	int i;
+	/* enable CSU NS access permission */
+	for (i = 0; i < 64; i++) {
+		mmio_write_32(0x303e0000 + i * 4, 0xffffffff);
+	}
+
+	/* config the aips access permission */
+	imx8mm_aips_config();
+
+#if DEBUG_CONSOLE
+	console_init(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ,
+		     IMX_CONSOLE_BAUDRATE);
+#endif
+	/*
+	 * tell BL3-1 where the non-secure software image is located
+	 * and the entry state information.
+	 */
+	bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET;
+	bl33_image_ep_info.spsr = get_spsr_for_bl33_entry();
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+#ifdef TEE_IMX8
+	/* Populate entry point information for BL32 */
+	SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+	bl32_image_ep_info.pc = BL32_BASE;
+	bl32_image_ep_info.spsr = 0;
+	/* Pass TEE base and size to uboot */
+	bl33_image_ep_info.args.arg1 = 0xFE000000;
+	bl33_image_ep_info.args.arg2 = 0x2000000;
+#endif
+	bl31_tzc380_setup();
+}
+
+void bl31_plat_arch_setup(void)
+{
+	/* add the mmap */
+	mmap_add_region(BL31_BASE, BL31_BASE, 0x10000, MT_MEMORY | MT_RW);
+	mmap_add_region(BL31_BASE, BL31_BASE, BL31_RO_END - BL31_RO_START,
+			MT_MEMORY | MT_RO);
+	/* Map GPV */
+	mmap_add_region(IMX_GPV_BASE, IMX_GPV_BASE, IMX_GPV_SIZE, MT_DEVICE | MT_RW);
+	/* Map AIPS 1~3 */
+	mmap_add_region(IMX_AIPS_BASE, IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW);
+	/* map AIPS4 */
+	mmap_add_region(0x32c00000, 0x32c00000, 0x400000, MT_DEVICE | MT_RW);
+	/* map GIC */
+	mmap_add_region(PLAT_GIC_BASE, PLAT_GIC_BASE, 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,
+		MT_DEVICE | MT_RW);
+#endif
+	/* setup xlat table */
+	init_xlat_tables();
+
+	/* enable the MMU */
+	enable_mmu_el3(0);
+}
+
+void bl31_platform_setup(void)
+{
+	/* enable the GIC clock */
+	mmio_write_32(0x303845c0, 0x3);
+	/* init the GICv3 cpu and distributor interface */
+	plat_gic_driver_init();
+	plat_gic_init();
+
+	/* gpc init */
+	imx_gpc_init();
+}
+
+entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
+{
+	if (type == NON_SECURE)
+		return &bl33_image_ep_info;
+	if (type == SECURE)
+		return &bl32_image_ep_info;
+
+	return NULL;
+}
+
+unsigned int plat_get_syscnt_freq2(void)
+{
+	return COUNTER_FREQUENCY;
+}
+
+void bl31_plat_runtime_setup(void)
+{
+	return;
+}
diff --git a/plat/imx/imx8mm/imx8mm_misc.c b/plat/imx/imx8mm/imx8mm_misc.c
new file mode 100644
index 0000000..cec4b94
--- /dev/null
+++ b/plat/imx/imx8mm/imx8mm_misc.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <runtime_svc.h>
+#include <std_svc.h>
+#include <mmio.h>
+#include <platform_def.h>
+#include <imx_sip.h>
+#include <soc.h>
+
+#define M4RCR (0xC)
+#define SRC_SCR_M4_ENABLE_OFFSET		3
+#define SRC_SCR_M4_ENABLE_MASK			(1 << 3)
+#define SRC_SCR_M4C_NON_SCLR_RST_OFFSET		0
+#define SRC_SCR_M4C_NON_SCLR_RST_MASK		(1 << 0)
+
+#define DIGPROG		0x800
+
+int imx_src_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
+		    u_register_t x3)
+{
+	uint32_t val;
+
+	switch(x1) {
+	case FSL_SIP_SRC_M4_START:
+		val = mmio_read_32(IMX_SRC_BASE + M4RCR);
+		val &= ~SRC_SCR_M4C_NON_SCLR_RST_MASK;
+		val |= SRC_SCR_M4_ENABLE_MASK;
+		mmio_write_32(IMX_SRC_BASE + M4RCR, val);
+		break;
+	case FSL_SIP_SRC_M4_STARTED:
+		val = mmio_read_32(IMX_SRC_BASE + M4RCR);
+		return !(val & SRC_SCR_M4C_NON_SCLR_RST_MASK);
+	default:
+		return SMC_UNK;
+
+	};
+
+	return 0;
+}
+
+int imx_soc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
+		    u_register_t x3)
+{
+	return mmio_read_32(IMX_ANAMIX_BASE + DIGPROG);
+}
+
+int imx_noc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2,
+		    u_register_t x3)
+{
+	return 0;
+}
diff --git a/plat/imx/imx8mm/imx8mm_psci.c b/plat/imx/imx8mm/imx8mm_psci.c
new file mode 100644
index 0000000..b0074c2
--- /dev/null
+++ b/plat/imx/imx8mm/imx8mm_psci.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2018 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <debug.h>
+#include <stdbool.h>
+#include <plat_imx8.h>
+#include <psci.h>
+#include <mmio.h>
+#include <soc.h>
+
+#define SNVS_LPCR	0x38
+
+#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0])
+#define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1])
+#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL])
+
+int imx_pwr_domain_on(u_register_t mpidr)
+{
+	unsigned int core_id;
+	uint64_t base_addr = BL31_BASE;
+
+	core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	/* set the secure entrypoint */
+	imx_set_cpu_secure_entry(core_id, base_addr);
+	/* power up the core */
+	imx_set_cpu_pwr_on(core_id);
+
+	return PSCI_E_SUCCESS;
+}
+
+void imx_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	/* program the GIC per cpu dist and rdist interface */
+	plat_gic_pcpu_init();
+	/* enable the GICv3 cpu interface */
+	plat_gic_cpuif_enable();
+}
+
+void imx_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	uint64_t mpidr = read_mpidr_el1();
+	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	/* disable the GIC cpu interface first */
+	plat_gic_cpuif_disable();
+	/* config the core for power down */
+	imx_set_cpu_pwr_off(core_id);
+}
+
+int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
+{
+	/* The non-secure entrypoint should be in RAM space */
+	if (ns_entrypoint < 0x40000000)
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+int imx_validate_power_state(unsigned int power_state,
+			 psci_power_state_t *req_state)
+{
+	int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
+	int pwr_type = psci_get_pstate_type(power_state);
+	int state_id = psci_get_pstate_id(power_state);
+
+	if (pwr_lvl > PLAT_MAX_PWR_LVL)
+		return PSCI_E_INVALID_PARAMS;
+
+	if (pwr_type == PSTATE_TYPE_STANDBY) {
+		CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+		CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+	}
+
+	if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) {
+		CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE;
+	//	CLUSTER_PWR_STATE(req_state) = PLAT_WAIT_OFF_STATE;
+		CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE;
+	}
+
+	return PSCI_E_SUCCESS;
+}
+
+void imx_cpu_standby(plat_local_state_t cpu_state)
+{
+	dsb();
+	write_scr_el3(read_scr_el3() | 0x4);
+	isb();
+
+	wfi();
+
+	write_scr_el3(read_scr_el3() & (~0x4));
+	isb();
+}
+
+void imx_domain_suspend(const psci_power_state_t *target_state)
+{
+	uint64_t base_addr = BL31_BASE;
+	uint64_t mpidr = read_mpidr_el1();
+	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		/* disable the cpu interface */
+		plat_gic_cpuif_disable();
+		/* set the resume entry */
+		imx_set_cpu_secure_entry(core_id, base_addr);
+		imx_set_cpu_lpm(core_id, true);
+	} else {
+		/* TODO cluster level clock gate off ? */
+		dsb();
+		write_scr_el3(read_scr_el3() | 0x4);
+		isb();
+	}
+
+	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
+		imx_set_cluster_powerdown(core_id, CLUSTER_PWR_STATE(target_state));
+	} else
+		imx_set_cluster_standby(true);
+
+	/* do system level power mode setting */
+	if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
+		imx_set_sys_lpm(true);
+		imx_anamix_pre_suspend();
+		noc_wrapper_pre_suspend(core_id);
+		/* set the wakeup source based on GIC SPI config */
+		imx_set_sys_wakeup(core_id, true);
+	}
+}
+
+void imx_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+	uint64_t mpidr = read_mpidr_el1();
+	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
+
+	/* check the system level status */
+	if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
+		imx_set_sys_lpm(false);
+		/* clear the system wakeup setting */
+		imx_set_sys_wakeup(core_id, false);
+		imx_anamix_post_resume();
+		noc_wrapper_post_resume(core_id);
+		imx_clear_rbc_count();
+	}
+
+	/* check the cluster level power status */
+	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
+		imx_set_cluster_powerdown(core_id, PSCI_LOCAL_STATE_RUN);
+	} else
+		imx_set_cluster_standby(false);
+
+	/* check the core level power status */
+	if (is_local_state_off(CORE_PWR_STATE(target_state))) {
+		/* clear the core lpm setting */
+		imx_set_cpu_lpm(core_id, false);
+		/* enable the gic cpu interface */
+		plat_gic_cpuif_enable();
+	} else {
+		write_scr_el3(read_scr_el3() & (~0x4));
+		isb();
+	}
+}
+
+void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned int i;
+
+	for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++)
+		req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE;
+
+	req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE;
+}
+
+void __dead2 imx_system_reset(void)
+{
+	uintptr_t wdog_base = IMX_WDOG_BASE;
+	unsigned int val;
+
+	/* WDOG_B reset */
+	val = mmio_read_16(wdog_base);
+#ifdef IMX_WDOG_B_RESET
+	val = (val & 0x00FF) | (7 << 2) | (1 << 0);
+#else
+	val = (val & 0x00FF) | (4 << 2) | (1 << 0);
+#endif
+	mmio_write_16(wdog_base, val);
+
+	mmio_write_16(wdog_base + 0x2, 0x5555);
+	mmio_write_16(wdog_base + 0x2, 0xaaaa);
+	while (1)
+		;
+}
+
+void __dead2 imx_system_off(void)
+{
+	mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, 0x61);
+
+	INFO("Unable to poweroff system\n");
+
+	while (1)
+		;
+}
+
+void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state)
+{
+	if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
+		imx_set_rbc_count();
+
+		/* TODO need to workaround the PLL disable glitch */
+	}
+
+	while (1)
+		wfi();
+}
+
+static const plat_psci_ops_t imx_plat_psci_ops = {
+	.pwr_domain_on = imx_pwr_domain_on,
+	.pwr_domain_on_finish = imx_pwr_domain_on_finish,
+	.pwr_domain_off = imx_pwr_domain_off,
+	.validate_ns_entrypoint = imx_validate_ns_entrypoint,
+	.validate_power_state = imx_validate_power_state,
+	.cpu_standby = imx_cpu_standby,
+	.pwr_domain_suspend = imx_domain_suspend,
+	.pwr_domain_suspend_finish = imx_domain_suspend_finish,
+	.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
+	.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
+	.system_reset = imx_system_reset,
+	.system_off = imx_system_off,
+};
+
+/* export the platform specific psci ops */
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+			const plat_psci_ops_t **psci_ops)
+{
+	/* sec_entrypoint is used for warm reset */
+	imx_mailbox_init(sec_entrypoint);
+
+	*psci_ops = &imx_plat_psci_ops;
+
+	return 0;
+}
diff --git a/plat/imx/imx8mm/include/platform_def.h b/plat/imx/imx8mm/include/platform_def.h
new file mode 100644
index 0000000..001261a
--- /dev/null
+++ b/plat/imx/imx8mm/include/platform_def.h
@@ -0,0 +1,86 @@
+#define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
+#define PLATFORM_LINKER_ARCH		aarch64
+
+#define PLATFORM_STACK_SIZE		0x800
+#define CACHE_WRITEBACK_GRANULE		64
+
+#define PLAT_PRIMARY_CPU		0x0
+#define PLATFORM_MAX_CPU_PER_CLUSTER	4
+#define PLATFORM_CLUSTER_COUNT		1
+#define PLATFORM_CLUSTER0_CORE_COUNT	4
+#define PLATFORM_CLUSTER1_CORE_COUNT	0
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER0_CORE_COUNT)
+
+#define IMX_PWR_LVL0			MPIDR_AFFLVL0
+#define IMX_PWR_LVL1			MPIDR_AFFLVL1
+#define IMX_PWR_LVL2			MPIDR_AFFLVL2
+
+#define PWR_DOMAIN_AT_MAX_LVL		1
+#define PLAT_MAX_PWR_LVL		2
+#define PLAT_MAX_OFF_STATE		4
+#define PLAT_MAX_RET_STATE		1
+
+#define PLAT_WAIT_OFF_STATE		2
+#define PLAT_STOP_OFF_STATE		3
+
+#define BL31_BASE			0x920000
+#define BL31_LIMIT			0x940000
+#define BL32_BASE			0xfe000000
+
+/* non-secure uboot base */
+#define PLAT_NS_IMAGE_OFFSET		0x40200000
+
+/* GICv3 base address */
+#define PLAT_GIC_BASE			0x38800000
+#define PLAT_GICD_BASE			0x38800000
+#define PLAT_GICR_BASE			0x38880000
+
+#define PLAT_FSL_ADDR_SPACE_SIZE	(1ull << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ull << 32)
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ull << 32)
+
+#define MAX_XLAT_TABLES			4
+#define MAX_MMAP_REGIONS		12
+
+#define HAB_RVT_BASE			0x00000900 /* HAB_RVT for i.MX8MM */
+
+#define IMX_BOOT_UART_BASE		0x30890000
+#define IMX_BOOT_UART_CLK_IN_HZ		24000000 /* Select 24Mhz OSC */
+
+#define PLAT_CRASH_UART_BASE		IMX_BOOT_UART_BASE
+#define PLAT_CRASH_UART_CLK_IN_HZ	24000000
+#define IMX_CONSOLE_BAUDRATE		115200
+
+#define IMX_AIPSTZ1			0x301f0000
+#define IMX_AIPSTZ2			0x305f0000
+#define IMX_AIPSTZ3			0x309f0000
+#define IMX_AIPSTZ4			0x32df0000
+
+#define IMX_AIPS_BASE			0x30000000
+#define IMX_AIPS_SIZE			0xC00000
+#define IMX_GPV_BASE			0x32000000
+#define IMX_GPV_SIZE			0x800000
+#define IMX_AIPS1_BASE			0x30200000
+#define IMX_AIPS4_BASE			0x32c00000
+#define IMX_ANAMIX_BASE			0x30360000
+#define IMX_SRC_BASE			0x30390000
+#define IMX_GPC_BASE			0x303a0000
+#define IMX_WDOG_BASE			0x30280000
+#define IMX_SNVS_BASE			0x30370000
+#define IMX_NOC_BASE			0x32700000
+#define IMX_TZASC_BASE			0x32F80000
+#define IMX_IOMUX_GPR_BASE		0x30340000
+#define IMX_DDRC_BASE			0x3d400000
+#define IMX_DDRPHY_BASE			0x3c000000
+#define IMX_DDR_IPS_BASE		0x3d000000
+#define IMX_ROM_BASE			0x0
+
+#define OCRAM_S_BASE			0x00180000
+#define OCRAM_S_SIZE			0x8000
+#define OCRAM_S_LIMIT			(OCRAM_S_BASE + OCRAM_S_SIZE)
+
+#define COUNTER_FREQUENCY		8000000 /* 8MHz */
+
+#define DEBUG_CONSOLE			0
+#define IMX_WDOG_B_RESET
+#define PLAT_IMX8MM			1
diff --git a/plat/imx/imx8mm/include/soc.h b/plat/imx/imx8mm/include/soc.h
new file mode 100644
index 0000000..475b0bc
--- /dev/null
+++ b/plat/imx/imx8mm/include/soc.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __IMX_SOC_H
+#define __IMX_SOC_H
+
+void imx_gpc_set_m_core_pgc(unsigned int cpu, bool pdn);
+void imx_anamix_pre_suspend(void);
+void imx_anamix_post_resume(void);
+void imx_gpc_init(void);
+
+void imx_set_cpu_secure_entry(int cpu_id, uintptr_t sec_entrypoint);
+void imx_set_cpu_pwr_off(int cpu_id);
+void imx_set_cpu_pwr_on(int cpu_id);
+void imx_set_cpu_lpm(int cpu_id, bool pdn);
+void imx_set_lpm_wakeup(bool pdn);
+void imx_set_cluster_standby(bool pdn);
+void imx_set_cluster_powerdown(int last_core, uint8_t power_state);
+void imx_set_sys_lpm(bool retention);
+void imx_set_sys_wakeup(int last_core, bool pdn);
+void imx_set_rbc_count(void);
+void imx_clear_rbc_count(void);
+
+void noc_wrapper_pre_suspend(unsigned int proc_num);
+void noc_wrapper_post_resume(unsigned int proc_num);
+
+void ddrc_enter_retention(void);
+void ddrc_exit_retention(void);
+
+#endif /* __IMX_SOC_H */
diff --git a/plat/imx/imx8mm/platform.mk b/plat/imx/imx8mm/platform.mk
new file mode 100644
index 0000000..fa26fc4
--- /dev/null
+++ b/plat/imx/imx8mm/platform.mk
@@ -0,0 +1,42 @@
+PLAT_INCLUDES		:=	-Iplat/imx/imx8mm/include		\
+				-Iplat/imx/common/include		\
+
+PLAT_GIC_SOURCES	:=	drivers/arm/gic/v3/gicv3_helpers.c	\
+				drivers/arm/gic/v3/arm_gicv3_common.c   \
+				drivers/arm/gic/v3/gic500.c             \
+				drivers/arm/gic/v3/gicv3_main.c		\
+				drivers/arm/gic/common/gic_common.c	\
+				plat/common/plat_gicv3.c		\
+				plat/imx/common/plat_imx8_gic.c
+
+BL31_SOURCES		+=	plat/imx/common/imx8_helpers.S		\
+				plat/imx/common/mxcuart_console.S	\
+				plat/imx/common/imx8_sip_svc.c		\
+				plat/imx/common/misc.c			\
+				plat/imx/imx8mm/imx8mm_bl31_setup.c	\
+				plat/imx/imx8mm/gpc.c			\
+				plat/imx/imx8mm/imx8mm_misc.c			\
+				plat/imx/common/imx8m/hab.c		\
+				plat/imx/imx8mm/imx8mm_psci.c		\
+				plat/imx/common/imx8_topology.c		\
+				plat/common/plat_psci_common.c		\
+				lib/xlat_tables/aarch64/xlat_tables.c	\
+				lib/xlat_tables/xlat_tables_common.c	\
+				lib/cpus/aarch64/cortex_a53.S		\
+				drivers/console/aarch64/console.S	\
+				${PLAT_GIC_SOURCES}			\
+				${PLAT_DDR_SOURCES}			\
+				drivers/arm/tzc/tzc380.c
+
+ENABLE_PLAT_COMPAT	:=	0
+USE_COHERENT_MEM	:=	0
+MULTI_CONSOLE_API	:=	1
+RESET_TO_BL31		:=	1
+ERROR_DEPRECATED	:=	1
+#XLAT_TABLE_IN_OCRAM_S	:=	1
+#STACK_IN_OCRAM_S       :=      1
+ifneq (${SPD},none)
+$(eval $(call add_define,TEE_IMX8))
+endif
+#$(eval $(call add_define,XLAT_TABLE_IN_OCRAM_S))
+#$(eval $(call add_define,STACK_IN_OCRAM_S))