Merge changes Ie650728a,Ie2736ef4 into integration

* changes:
  refactor(stm32mp1-fdts): add missing spaces for consistent codestyle
  refactor(stm32mp1-fdts): drop unused DDR calibration result on DHCOM
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
index 60313d5..07e7821 100644
--- a/docs/design/cpu-specific-build-macros.rst
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -498,6 +498,10 @@
 -  ``ERRATA_N2_2280757``: This applies errata 2280757 workaround to Neoverse-N2
    CPU. This needs to be enabled for revision r0p0 of the CPU and is still open.
 
+-  ``ERRATA_N2_2388450``: This applies errata 2388450 workaround to Neoverse-N2
+   CPU. This needs to be enabled for revision r0p0 of the CPU, it is fixed in
+   r0p1.
+
 For Cortex-X2, the following errata build flags are defined :
 
 -  ``ERRATA_X2_2002765``: This applies errata 2002765 workaround to Cortex-X2
diff --git a/docs/getting_started/prerequisites.rst b/docs/getting_started/prerequisites.rst
index 0b8a71c..179d17b 100644
--- a/docs/getting_started/prerequisites.rst
+++ b/docs/getting_started/prerequisites.rst
@@ -7,6 +7,7 @@
 It may possible to build |TF-A| with combinations of software packages that are
 different from those listed below, however only the software described in this
 document can be officially supported.
+
 Build Host
 ----------
 
diff --git a/include/lib/cpus/aarch64/a64fx.h b/include/lib/cpus/aarch64/a64fx.h
new file mode 100644
index 0000000..b7342b0
--- /dev/null
+++ b/include/lib/cpus/aarch64/a64fx.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, Fujitsu Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef A64FX_H
+#define A64FX_H
+
+#include <lib/utils_def.h>
+
+/* A64FX midr for revision 0 */
+#define A64FX_MIDR					U(0x461f0010)
+
+#endif /* A64FX_H */
diff --git a/include/lib/cpus/aarch64/neoverse_n2.h b/include/lib/cpus/aarch64/neoverse_n2.h
index 0452b39..5d41a13 100644
--- a/include/lib/cpus/aarch64/neoverse_n2.h
+++ b/include/lib/cpus/aarch64/neoverse_n2.h
@@ -38,6 +38,7 @@
  ******************************************************************************/
 #define NEOVERSE_N2_CPUACTLR2_EL1			S3_0_C15_C1_1
 #define NEOVERSE_N2_CPUACTLR2_EL1_BIT_2			(ULL(1) << 2)
+#define NEOVERSE_N2_CPUACTLR2_EL1_BIT_40		(ULL(1) << 40)
 
 /*******************************************************************************
  * CPU Auxiliary Control register 5 specific definitions.
diff --git a/lib/cpus/aarch64/a64fx.S b/lib/cpus/aarch64/a64fx.S
new file mode 100644
index 0000000..54c20c3
--- /dev/null
+++ b/lib/cpus/aarch64/a64fx.S
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2022, Fujitsu Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <a64fx.h>
+#include <cpu_macros.S>
+#include <plat_macros.S>
+
+func a64fx_core_pwr_dwn
+endfunc a64fx_core_pwr_dwn
+
+func a64fx_cluster_pwr_dwn
+endfunc a64fx_cluster_pwr_dwn
+
+#if REPORT_ERRATA
+/*
+ * Errata printing function for A64FX. Must follow AAPCS.
+ */
+func a64fx_errata_report
+        ret
+endfunc a64fx_errata_report
+#endif
+
+        /* ---------------------------------------------
+         * This function provides cpu specific
+         * register information for crash reporting.
+         * It needs to return with x6 pointing to
+         * a list of register names in ascii and
+         * x8 - x15 having values of registers to be
+         * reported.
+         * ---------------------------------------------
+         */
+.section .rodata.a64fx_regs, "aS"
+a64fx_regs:  /* The ascii list of register names to be reported */
+        .asciz  ""
+
+func a64fx_cpu_reg_dump
+        adr     x6, a64fx_regs
+        ret
+endfunc a64fx_cpu_reg_dump
+
+declare_cpu_ops a64fx, A64FX_MIDR, CPU_NO_RESET_FUNC \
+                a64fx_core_pwr_dwn, \
+                a64fx_cluster_pwr_dwn
+
diff --git a/lib/cpus/aarch64/neoverse_n2.S b/lib/cpus/aarch64/neoverse_n2.S
index 5b796dc..fae3be2 100644
--- a/lib/cpus/aarch64/neoverse_n2.S
+++ b/lib/cpus/aarch64/neoverse_n2.S
@@ -338,6 +338,36 @@
 	b	cpu_rev_var_ls
 endfunc check_errata_2280757
 
+/* --------------------------------------------------
+ * Errata Workaround for Neoverse N2 Erratum 2388450.
+ * This applies to revision r0p0 of Neoverse N2,
+ * fixed in r0p1.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x1, x17
+ * --------------------------------------------------
+ */
+func errata_n2_2388450_wa
+	/* Check revision. */
+	mov	x17, x30
+	bl	check_errata_2388450
+	cbz	x0, 1f
+
+	/*Set bit 40 in ACTLR2_EL1 */
+	mrs	x1, NEOVERSE_N2_CPUACTLR2_EL1
+	orr	x1, x1, #NEOVERSE_N2_CPUACTLR2_EL1_BIT_40
+	msr	NEOVERSE_N2_CPUACTLR2_EL1, x1
+	isb
+1:
+	ret	x17
+endfunc errata_n2_2388450_wa
+
+func check_errata_2388450
+	/* Applies to r0p0, fixed in r0p1 */
+	mov	x1, #0x00
+	b	cpu_rev_var_ls
+endfunc check_errata_2388450
+
 func check_errata_cve_2022_23960
 #if WORKAROUND_CVE_2022_23960
 	mov	x0, #ERRATA_APPLIES
@@ -417,6 +447,11 @@
 	bl	errata_n2_2280757_wa
 #endif
 
+#if ERRATA_N2_2388450
+	mov	x0, x18
+	bl	errata_n2_2388450_wa
+#endif
+
 #if ENABLE_AMU
 	/* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */
 	mrs	x0, cptr_el3
@@ -496,6 +531,7 @@
 	report_errata ERRATA_N2_2138958, neoverse_n2, 2138958
 	report_errata ERRATA_N2_2242400, neoverse_n2, 2242400
 	report_errata ERRATA_N2_2280757, neoverse_n2, 2280757
+	report_errata ERRATA_N2_2388450, neoverse_n2, 2388450
 	report_errata WORKAROUND_CVE_2022_23960, neoverse_n2, cve_2022_23960
 	report_errata ERRATA_DSU_2313941, neoverse_n2, dsu_2313941
 
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index 6d49dab..5eecdd6 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -556,6 +556,10 @@
 # to revision r0p0 of the Neoverse N2 cpu and is still open.
 ERRATA_N2_2280757	?=0
 
+# Flag to apply erratum 2388450 workaround during reset. This erratum applies
+# to revision r0p0 of the Neoverse N2 cpu, it is fixed in r0p1.
+ERRATA_N2_2388450	?=0
+
 # Flag to apply erratum 2002765 workaround during reset. This erratum applies
 # to revisions r0p0, r1p0, and r2p0 of the Cortex-X2 cpu and is still open.
 ERRATA_X2_2002765	?=0
@@ -1103,6 +1107,10 @@
 $(eval $(call assert_boolean,ERRATA_N2_2280757))
 $(eval $(call add_define,ERRATA_N2_2280757))
 
+# Process ERRATA_N2_2388450 flag
+$(eval $(call assert_boolean,ERRATA_N2_2388450))
+$(eval $(call add_define,ERRATA_N2_2388450))
+
 # Process ERRATA_X2_2002765 flag
 $(eval $(call assert_boolean,ERRATA_X2_2002765))
 $(eval $(call add_define,ERRATA_X2_2002765))
diff --git a/plat/imx/common/imx_sip_svc.c b/plat/imx/common/imx_sip_svc.c
index fd54820..fae9750 100644
--- a/plat/imx/common/imx_sip_svc.c
+++ b/plat/imx/common/imx_sip_svc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -34,6 +34,13 @@
 		SMC_RET1(handle, imx_soc_info_handler(smc_fid, x1, x2, x3));
 		break;
 #endif
+#if defined(PLAT_imx8mm) || defined(PLAT_imx8mn) || defined(PLAT_imx8mp)
+	case IMX_SIP_DDR_DVFS:
+		return dram_dvfs_handler(smc_fid, handle, x1, x2, x3);
+	case IMX_SIP_GPC:
+		SMC_RET1(handle, imx_gpc_handler(smc_fid, x1, x2, x3));
+		break;
+#endif
 #if (defined(PLAT_imx8qm) || defined(PLAT_imx8qx))
 	case  IMX_SIP_SRTC:
 		return imx_srtc_handler(smc_fid, handle, x1, x2, x3, x4);
diff --git a/plat/imx/common/include/imx_sip_svc.h b/plat/imx/common/include/imx_sip_svc.h
index 6c7a760..c6e9879 100644
--- a/plat/imx/common/include/imx_sip_svc.h
+++ b/plat/imx/common/include/imx_sip_svc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,6 +8,8 @@
 #define __IMX_SIP_SVC_H__
 
 /* SMC function IDs for SiP Service queries */
+#define IMX_SIP_GPC			0xC2000000
+
 #define IMX_SIP_CPUFREQ			0xC2000001
 #define IMX_SIP_SET_CPUFREQ		0x00
 
@@ -17,6 +19,8 @@
 #define IMX_SIP_BUILDINFO			0xC2000003
 #define IMX_SIP_BUILDINFO_GET_COMMITHASH	0x00
 
+#define IMX_SIP_DDR_DVFS		0xc2000004
+
 #define IMX_SIP_SRC			0xC2000005
 #define IMX_SIP_SRC_SET_SECONDARY_BOOT	0x10
 #define IMX_SIP_SRC_IS_SECONDARY_BOOT	0x11
@@ -41,6 +45,13 @@
 int imx_soc_info_handler(uint32_t smc_fid, u_register_t x1,
 			 u_register_t x2, u_register_t x3);
 #endif
+#if defined(PLAT_imx8mm) || defined(PLAT_imx8mn) || defined(PLAT_imx8mp)
+int dram_dvfs_handler(uint32_t smc_fid, void *handle,
+	u_register_t x1, u_register_t x2, u_register_t x3);
+
+int imx_gpc_handler(uint32_t smc_fid, u_register_t x1,
+		    u_register_t x2, u_register_t x3);
+#endif
 
 #if defined(PLAT_imx8mm) || defined(PLAT_imx8mq)
 int imx_src_handler(uint32_t smc_fid, u_register_t x1,
diff --git a/plat/imx/imx8m/ddr/clock.c b/plat/imx/imx8m/ddr/clock.c
new file mode 100644
index 0000000..7fb5730
--- /dev/null
+++ b/plat/imx/imx8m/ddr/clock.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define IMX_CCM_IP_BASE				(IMX_CCM_BASE + 0xa000)
+#define DRAM_SEL_CFG				(IMX_CCM_BASE + 0x9800)
+#define CCM_IP_CLK_ROOT_GEN_TAGET(i)		(IMX_CCM_IP_BASE + 0x80 * (i) + 0x00)
+#define CCM_IP_CLK_ROOT_GEN_TAGET_SET(i)	(IMX_CCM_IP_BASE + 0x80 * (i) + 0x04)
+#define CCM_IP_CLK_ROOT_GEN_TAGET_CLR(i)	(IMX_CCM_IP_BASE + 0x80 * (i) + 0x08)
+#define PLL_FREQ_800M	U(0x00ece580)
+#define PLL_FREQ_400M	U(0x00ec6984)
+#define PLL_FREQ_167M	U(0x00f5a406)
+
+void ddr_pll_bypass_100mts(void)
+{
+	/* change the clock source of dram_alt_clk_root to source 2 --100MHz */
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(0), (0x7 << 24) | (0x7 << 16));
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(0), (0x2 << 24));
+
+	/* change the clock source of dram_apb_clk_root to source 2 --40MHz/2 */
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(1), (0x7 << 24) | (0x7 << 16));
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(1), (0x2 << 24) | (0x1 << 16));
+
+	/* configure pll bypass mode */
+	mmio_write_32(DRAM_SEL_CFG + 0x4, BIT(24));
+}
+
+void ddr_pll_bypass_400mts(void)
+{
+	/* change the clock source of dram_alt_clk_root to source 1 --400MHz */
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(0), (0x7 << 24) | (0x7 << 16));
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(0), (0x1 << 24) | (0x1 << 16));
+
+	/* change the clock source of dram_apb_clk_root to source 3 --160MHz/2 */
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(1), (0x7 << 24) | (0x7 << 16));
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(1), (0x3 << 24) | (0x1 << 16));
+
+	/* configure pll bypass mode */
+	mmio_write_32(DRAM_SEL_CFG + 0x4, BIT(24));
+}
+
+void ddr_pll_unbypass(void)
+{
+	mmio_write_32(DRAM_SEL_CFG + 0x8, BIT(24));
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_CLR(1), (0x7 << 24) | (0x7 << 16));
+	/* to source 4 --800MHz/5 */
+	mmio_write_32(CCM_IP_CLK_ROOT_GEN_TAGET_SET(1), (0x4 << 24) | (0x4 << 16));
+}
+
+#if defined(PLAT_imx8mq)
+void dram_pll_init(unsigned int drate)
+{
+	/* bypass the PLL */
+	mmio_setbits_32(HW_DRAM_PLL_CFG0, 0x30);
+
+	switch (drate) {
+	case 3200:
+		mmio_write_32(HW_DRAM_PLL_CFG2, PLL_FREQ_800M);
+		break;
+	case 1600:
+		mmio_write_32(HW_DRAM_PLL_CFG2, PLL_FREQ_400M);
+		break;
+	case 667:
+		mmio_write_32(HW_DRAM_PLL_CFG2, PLL_FREQ_167M);
+		break;
+	default:
+		break;
+	}
+
+	/* unbypass the PLL */
+	mmio_clrbits_32(HW_DRAM_PLL_CFG0, 0x30);
+	while (!(mmio_read_32(HW_DRAM_PLL_CFG0) & (1 << 31))) {
+		;
+	}
+}
+#else
+void dram_pll_init(unsigned int drate)
+{
+	/* bypass the PLL */
+	mmio_setbits_32(DRAM_PLL_CTRL, (1 << 16));
+	mmio_clrbits_32(DRAM_PLL_CTRL, (1 << 9));
+
+	switch (drate) {
+	case 2400:
+		mmio_write_32(DRAM_PLL_CTRL + 0x4, (300 << 12) | (3 << 4) | 2);
+		break;
+	case 1600:
+		mmio_write_32(DRAM_PLL_CTRL + 0x4, (400 << 12) | (3 << 4) | 3);
+		break;
+	case 1066:
+		mmio_write_32(DRAM_PLL_CTRL + 0x4, (266 << 12) | (3 << 4) | 3);
+		break;
+	case 667:
+		mmio_write_32(DRAM_PLL_CTRL + 0x4, (334 << 12) | (3 << 4) | 4);
+		break;
+	default:
+		break;
+	}
+
+	mmio_setbits_32(DRAM_PLL_CTRL, BIT(9));
+	/* wait for PLL locked */
+	while (!(mmio_read_32(DRAM_PLL_CTRL) & BIT(31))) {
+		;
+	}
+
+	/* unbypass the PLL */
+	mmio_clrbits_32(DRAM_PLL_CTRL, BIT(16));
+}
+#endif
+
+/* change the dram clock frequency */
+void dram_clock_switch(unsigned int target_drate, bool bypass_mode)
+{
+	if (bypass_mode) {
+		switch (target_drate) {
+		case 400:
+			ddr_pll_bypass_400mts();
+			break;
+		case 100:
+			ddr_pll_bypass_100mts();
+			break;
+		default:
+			ddr_pll_unbypass();
+			break;
+		}
+	} else {
+		dram_pll_init(target_drate);
+	}
+}
diff --git a/plat/imx/imx8m/ddr/ddr4_dvfs.c b/plat/imx/imx8m/ddr/ddr4_dvfs.c
new file mode 100644
index 0000000..cdc7dc2
--- /dev/null
+++ b/plat/imx/imx8m/ddr/ddr4_dvfs.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <dram.h>
+
+void ddr4_mr_write(uint32_t mr, uint32_t data, uint32_t mr_type, uint32_t rank)
+{
+	uint32_t val, mr_mirror, data_mirror;
+
+	/*
+	 * 1. Poll MRSTAT.mr_wr_busy until it is 0 to make sure
+	 * that there is no outstanding MR transAction.
+	 */
+	while (mmio_read_32(DDRC_MRSTAT(0)) & 0x1) {
+		;
+	}
+
+	/*
+	 * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank
+	 * and (for MRWs) MRCTRL1.mr_data to define the MR transaction.
+	 */
+	val = mmio_read_32(DDRC_DIMMCTL(0));
+	if ((val & 0x2) && (rank == 0x2)) {
+		mr_mirror = (mr & 0x4) | ((mr & 0x1) << 1) | ((mr & 0x2) >> 1); /* BA0, BA1 swap */
+		data_mirror = (data & 0x1607) | ((data & 0x8) << 1) | ((data & 0x10) >> 1) |
+				((data & 0x20) << 1) | ((data & 0x40) >> 1) | ((data & 0x80) << 1) |
+				 ((data & 0x100) >> 1) | ((data & 0x800) << 2) | ((data & 0x2000) >> 2) ;
+	} else {
+		mr_mirror = mr;
+		data_mirror = data;
+	}
+
+	mmio_write_32(DDRC_MRCTRL0(0), mr_type | (mr_mirror << 12) | (rank << 4));
+	mmio_write_32(DDRC_MRCTRL1(0), data_mirror);
+
+	/*
+	 * 3. In a separate APB transaction, write the MRCTRL0.mr_wr to 1.
+	 * This bit is self-clearing, and triggers the MR transaction.
+	 * The uMCTL2 then asserts the MRSTAT.mr_wr_busy while it performs
+	 * the MR transaction to SDRAM, and no further accesses can be
+	 * initiated until it is deasserted.
+	 */
+	mmio_setbits_32(DDRC_MRCTRL0(0), BIT(31));
+
+	while (mmio_read_32(DDRC_MRSTAT(0))) {
+		;
+	}
+}
+
+void dram_cfg_all_mr(struct dram_info *info, uint32_t pstate)
+{
+	uint32_t num_rank = info->num_rank;
+	/*
+	 * 15. Perform MRS commands as required to re-program
+	 * timing registers in the SDRAM for the new frequency
+	 * (in particular, CL, CWL and WR may need to be changed).
+	 */
+
+	for (int i = 1; i <= num_rank; i++) {
+		for (int j = 0; j < 6; j++) {
+			ddr4_mr_write(j, info->mr_table[pstate][j], 0, i);
+		}
+		ddr4_mr_write(6, info->mr_table[pstate][7], 0, i);
+	}
+}
+
+void sw_pstate(uint32_t pstate, uint32_t drate)
+{
+	uint32_t val;
+
+	mmio_write_32(DDRC_SWCTL(0), 0x0);
+
+	/*
+	 * Update any registers which may be required to
+	 * change for the new frequency.
+	 */
+	mmio_write_32(DDRC_MSTR2(0), pstate);
+	mmio_setbits_32(DDRC_MSTR(0), (0x1 << 29));
+
+	/*
+	 * Toggle RFSHCTL3.refresh_update_level to allow the
+	 * new refresh-related register values to propagate
+	 * to the refresh logic.
+	 */
+	val = mmio_read_32(DDRC_RFSHCTL3(0));
+	if (val & 0x2) {
+		mmio_write_32(DDRC_RFSHCTL3(0), val & 0xFFFFFFFD);
+	} else {
+		mmio_write_32(DDRC_RFSHCTL3(0), val | 0x2);
+	}
+
+	/*
+	 * 19. If required, trigger the initialization in the PHY.
+	 * If using the gen2 multiPHY, PLL initialization should
+	 * be triggered at this point. See the PHY databook for
+	 * details about the frequency change procedure.
+	 */
+	mmio_write_32(DDRC_DFIMISC(0), 0x00000000 | (pstate << 8));
+	mmio_write_32(DDRC_DFIMISC(0), 0x00000020 | (pstate << 8));
+
+	/* wait DFISTAT.dfi_init_complete to 0 */
+	while (mmio_read_32(DDRC_DFISTAT(0)) & 0x1) {
+		;
+	}
+
+	/* change the clock to the target frequency */
+	dram_clock_switch(drate, false);
+
+	mmio_write_32(DDRC_DFIMISC(0), 0x00000000 | (pstate << 8));
+
+	/* wait DFISTAT.dfi_init_complete to 1 */
+	while (!(mmio_read_32(DDRC_DFISTAT(0)) & 0x1)) {
+		;
+	}
+
+	/*
+	 * When changing frequencies the controller may violate the JEDEC
+	 * requirement that no more than 16 refreshes should be issued within
+	 * 2*tREFI. These extra refreshes are not expected to cause a problem
+	 * in the SDRAM. This issue can be avoided by waiting for at least 2*tREFI
+	 * before exiting self-refresh in step 19.
+	 */
+	udelay(14);
+
+	/* 14. Exit the self-refresh state by setting PWRCTL.selfref_sw = 0. */
+	mmio_clrbits_32(DDRC_PWRCTL(0), (1 << 5));
+
+	while ((mmio_read_32(DDRC_STAT(0)) & 0x3f) == 0x23) {
+		;
+	}
+}
+
+void ddr4_swffc(struct dram_info *info, unsigned int pstate)
+{
+	uint32_t drate = info->timing_info->fsp_table[pstate];
+
+	/*
+	 * 1. set SWCTL.sw_done to disable quasi-dynamic register
+	 * programming outside reset.
+	 */
+	mmio_write_32(DDRC_SWCTL(0), 0x0);
+
+	/*
+	 * 2. Write 0 to PCTRL_n.port_en. This blocks AXI port(s)
+	 * from taking any transaction (blocks traffic on AXI ports).
+	 */
+	mmio_write_32(DDRC_PCTRL_0(0), 0x0);
+
+	/*
+	 * 3. Poll PSTAT.rd_port_busy_n=0 and PSTAT.wr_port_busy_n=0.
+	 * Wait until all AXI ports are idle (the uMCTL2 core has to
+	 * be idle).
+	 */
+	while (mmio_read_32(DDRC_PSTAT(0)) & 0x10001) {
+		;
+	}
+
+	/*
+	 * 4. Write 0 to SBRCTL.scrub_en. Disable SBR, required only if
+	 * SBR instantiated.
+	 * 5. Poll SBRSTAT.scrub_busy=0.
+	 * 6. Set DERATEEN.derate_enable = 0, if DERATEEN.derate_eanble = 1
+	 * and the read latency (RL) value needs to change after the frequency
+	 * change (LPDDR2/3/4 only).
+	 * 7. Set DBG1.dis_hif=1 so that no new commands will be accepted by the uMCTL2.
+	 */
+	mmio_setbits_32(DDRC_DBG1(0), (0x1 << 1));
+
+	/*
+	 * 8. Poll DBGCAM.dbg_wr_q_empty and DBGCAM.dbg_rd_q_empty to ensure
+	 * that write and read data buffers are empty.
+	 */
+	while ((mmio_read_32(DDRC_DBGCAM(0)) & 0x06000000) != 0x06000000) {
+		;
+	}
+
+	/*
+	 * 9. For DDR4, update MR6 with the new tDLLK value via the Mode
+	 * Register Write signals
+	 * 10. Set DFILPCFG0.dfi_lp_en_sr = 0, if DFILPCFG0.dfi_lp_en_sr = 1,
+	 * and wait until DFISTAT.dfi_lp_ack
+	 * 11. If DFI PHY Master interface is active in uMCTL2, then disable it
+	 * 12. Wait until STAT.operating_mode[1:0]!=11 indicating that the
+	 * controller is not in self-refresh mode.
+	 */
+	while ((mmio_read_32(DDRC_STAT(0)) & 0x3) == 0x3) {
+		;
+	}
+
+	/*
+	 * 13. Assert PWRCTL.selfref_sw for the DWC_ddr_umctl2 core to enter
+	 * the self-refresh mode.
+	 */
+	mmio_setbits_32(DDRC_PWRCTL(0), (1 << 5));
+
+	/*
+	 * 14. Wait until STAT.operating_mode[1:0]==11 indicating that the
+	 * controller core is in self-refresh mode.
+	 */
+	while ((mmio_read_32(DDRC_STAT(0)) & 0x3f) != 0x23) {
+		;
+	}
+
+	sw_pstate(pstate, drate);
+	dram_cfg_all_mr(info, pstate);
+
+	/* 23. Enable HIF commands by setting DBG1.dis_hif=0. */
+	mmio_clrbits_32(DDRC_DBG1(0), (0x1 << 1));
+
+	/*
+	 * 24. Reset DERATEEN.derate_enable = 1 if DERATEEN.derate_enable
+	 * has been set to 0 in step 6.
+	 * 25. If DFI PHY Master interface was active before step 11 then
+	 * enable it back by programming DFIPHYMSTR.phymstr_en = 1'b1.
+	 * 26. Write 1 to PCTRL_n.port_en. AXI port(s) are no longer blocked
+	 * from taking transactions (Re-enable traffic on AXI ports)
+	 */
+	mmio_write_32(DDRC_PCTRL_0(0), 0x1);
+
+	/*
+	 * 27. Write 1 to SBRCTL.scrub_en. Enable SBR if desired, only
+	 * required if SBR instantiated.
+	 */
+
+	/*
+	 * set SWCTL.sw_done to enable quasi-dynamic register programming
+	 * outside reset.
+	 */
+	mmio_write_32(DDRC_SWCTL(0), 0x1);
+
+	/* wait SWSTAT.sw_done_ack to 1 */
+	while (!(mmio_read_32(DDRC_SWSTAT(0)) & 0x1)) {
+		;
+	}
+}
diff --git a/plat/imx/imx8m/ddr/dram.c b/plat/imx/imx8m/ddr/dram.c
new file mode 100644
index 0000000..6ccd6fd
--- /dev/null
+++ b/plat/imx/imx8m/ddr/dram.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright 2019-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <bl31/interrupt_mgmt.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+
+#include <dram.h>
+
+#define IMX_SIP_DDR_DVFS_GET_FREQ_COUNT		0x10
+#define IMX_SIP_DDR_DVFS_GET_FREQ_INFO		0x11
+
+struct dram_info dram_info;
+
+/* lock used for DDR DVFS */
+spinlock_t dfs_lock;
+
+static volatile uint32_t wfe_done;
+static volatile bool wait_ddrc_hwffc_done = true;
+static unsigned int dev_fsp = 0x1;
+
+static uint32_t fsp_init_reg[3][4] = {
+	{ DDRC_INIT3(0), DDRC_INIT4(0), DDRC_INIT6(0), DDRC_INIT7(0) },
+	{ DDRC_FREQ1_INIT3(0), DDRC_FREQ1_INIT4(0), DDRC_FREQ1_INIT6(0), DDRC_FREQ1_INIT7(0) },
+	{ DDRC_FREQ2_INIT3(0), DDRC_FREQ2_INIT4(0), DDRC_FREQ2_INIT6(0), DDRC_FREQ2_INIT7(0) },
+};
+
+static void get_mr_values(uint32_t (*mr_value)[8])
+{
+	uint32_t init_val;
+	unsigned int i, fsp_index;
+
+	for (fsp_index = 0U; fsp_index < 3U; fsp_index++) {
+		for (i = 0U; i < 4U; i++) {
+			init_val = mmio_read_32(fsp_init_reg[fsp_index][i]);
+			mr_value[fsp_index][2*i] = init_val >> 16;
+			mr_value[fsp_index][2*i + 1] = init_val & 0xFFFF;
+		}
+	}
+}
+
+/* Restore the ddrc configs */
+void dram_umctl2_init(struct dram_timing_info *timing)
+{
+	struct dram_cfg_param *ddrc_cfg = timing->ddrc_cfg;
+	unsigned int i;
+
+	for (i = 0U; i < timing->ddrc_cfg_num; i++) {
+		mmio_write_32(ddrc_cfg->reg, ddrc_cfg->val);
+		ddrc_cfg++;
+	}
+
+	/* set the default fsp to P0 */
+	mmio_write_32(DDRC_MSTR2(0), 0x0);
+}
+
+/* Restore the dram PHY config */
+void dram_phy_init(struct dram_timing_info *timing)
+{
+	struct dram_cfg_param *cfg = timing->ddrphy_cfg;
+	unsigned int i;
+
+	/* Restore the PHY init config */
+	cfg = timing->ddrphy_cfg;
+	for (i = 0U; i < timing->ddrphy_cfg_num; i++) {
+		dwc_ddrphy_apb_wr(cfg->reg, cfg->val);
+		cfg++;
+	}
+
+	/* Restore the DDR PHY CSRs */
+	cfg = timing->ddrphy_trained_csr;
+	for (i = 0U; i < timing->ddrphy_trained_csr_num; i++) {
+		dwc_ddrphy_apb_wr(cfg->reg, cfg->val);
+		cfg++;
+	}
+
+	/* Load the PIE image */
+	cfg = timing->ddrphy_pie;
+	for (i = 0U; i < timing->ddrphy_pie_num; i++) {
+		dwc_ddrphy_apb_wr(cfg->reg, cfg->val);
+		cfg++;
+	}
+}
+
+/* EL3 SGI-8 IPI handler for DDR Dynamic frequency scaling */
+static uint64_t waiting_dvfs(uint32_t id, uint32_t flags,
+				void *handle, void *cookie)
+{
+	uint64_t mpidr = read_mpidr_el1();
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+	uint32_t irq;
+
+	irq = plat_ic_acknowledge_interrupt();
+	if (irq < 1022U) {
+		plat_ic_end_of_interrupt(irq);
+	}
+
+	/* set the WFE done status */
+	spin_lock(&dfs_lock);
+	wfe_done |= (1 << cpu_id * 8);
+	dsb();
+	spin_unlock(&dfs_lock);
+
+	while (1) {
+		/* ddr frequency change done */
+		if (!wait_ddrc_hwffc_done)
+			break;
+
+		wfe();
+	}
+
+	return 0;
+}
+
+void dram_info_init(unsigned long dram_timing_base)
+{
+	uint32_t ddrc_mstr, current_fsp;
+	uint32_t flags = 0;
+	uint32_t rc;
+	unsigned int i;
+
+	/* Get the dram type & rank */
+	ddrc_mstr = mmio_read_32(DDRC_MSTR(0));
+
+	dram_info.dram_type = ddrc_mstr & DDR_TYPE_MASK;
+	dram_info.num_rank = (ddrc_mstr >> 24) & ACTIVE_RANK_MASK;
+
+	/* Get current fsp info */
+	current_fsp = mmio_read_32(DDRC_DFIMISC(0)) & 0xf;
+	dram_info.boot_fsp = current_fsp;
+	dram_info.current_fsp = current_fsp;
+
+	get_mr_values(dram_info.mr_table);
+
+	dram_info.timing_info = (struct dram_timing_info *)dram_timing_base;
+
+	/* get the num of supported fsp */
+	for (i = 0U; i < 4U; ++i) {
+		if (!dram_info.timing_info->fsp_table[i]) {
+			break;
+		}
+	}
+	dram_info.num_fsp = i;
+
+	/* check if has bypass mode support */
+	if (dram_info.timing_info->fsp_table[i-1] < 666) {
+		dram_info.bypass_mode = true;
+	} else {
+		dram_info.bypass_mode = false;
+	}
+
+	/* Register the EL3 handler for DDR DVFS */
+	set_interrupt_rm_flag(flags, NON_SECURE);
+	rc = register_interrupt_type_handler(INTR_TYPE_EL3, waiting_dvfs, flags);
+	if (rc != 0) {
+		panic();
+	}
+}
+
+
+/*
+ * For each freq return the following info:
+ *
+ * r1: data rate
+ * r2: 1 + dram_core parent
+ * r3: 1 + dram_alt parent index
+ * r4: 1 + dram_apb parent index
+ *
+ * The parent indices can be used by an OS who manages source clocks to enabled
+ * them ahead of the switch.
+ *
+ * A parent value of "0" means "don't care".
+ *
+ * Current implementation of freq switch is hardcoded in
+ * plat/imx/common/imx8m/clock.c but in theory this can be enhanced to support
+ * a wide variety of rates.
+ */
+int dram_dvfs_get_freq_info(void *handle, u_register_t index)
+{
+	switch (index) {
+	case 0:
+		 SMC_RET4(handle, dram_info.timing_info->fsp_table[0],
+			1, 0, 5);
+	case 1:
+		if (!dram_info.bypass_mode) {
+			SMC_RET4(handle, dram_info.timing_info->fsp_table[1],
+				1, 0, 0);
+		}
+		SMC_RET4(handle, dram_info.timing_info->fsp_table[1],
+			2, 2, 4);
+	case 2:
+		if (!dram_info.bypass_mode) {
+			SMC_RET4(handle, dram_info.timing_info->fsp_table[2],
+				1, 0, 0);
+		}
+		SMC_RET4(handle, dram_info.timing_info->fsp_table[2],
+			2, 3, 3);
+	case 3:
+		 SMC_RET4(handle, dram_info.timing_info->fsp_table[3],
+			1, 0, 0);
+	default:
+		SMC_RET1(handle, -3);
+	}
+}
+
+int dram_dvfs_handler(uint32_t smc_fid, void *handle,
+	u_register_t x1, u_register_t x2, u_register_t x3)
+{
+	uint64_t mpidr = read_mpidr_el1();
+	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
+	unsigned int fsp_index = x1;
+	uint32_t online_cores = x2;
+
+	if (x1 == IMX_SIP_DDR_DVFS_GET_FREQ_COUNT) {
+		SMC_RET1(handle, dram_info.num_fsp);
+	} else if (x1 == IMX_SIP_DDR_DVFS_GET_FREQ_INFO) {
+		return dram_dvfs_get_freq_info(handle, x2);
+	} else if (x1 < 4) {
+		wait_ddrc_hwffc_done = true;
+		dsb();
+
+		/* trigger the SGI IPI to info other cores */
+		for (int i = 0; i < PLATFORM_CORE_COUNT; i++) {
+			if (cpu_id != i && (online_cores & (0x1 << (i * 8)))) {
+				plat_ic_raise_el3_sgi(0x8, i);
+			}
+		}
+
+		/* make sure all the core in WFE */
+		online_cores &= ~(0x1 << (cpu_id * 8));
+		while (1) {
+			if (online_cores == wfe_done) {
+				break;
+			}
+		}
+
+		/* flush the L1/L2 cache */
+		dcsw_op_all(DCCSW);
+
+		if (dram_info.dram_type == DDRC_LPDDR4) {
+			lpddr4_swffc(&dram_info, dev_fsp, fsp_index);
+			dev_fsp = (~dev_fsp) & 0x1;
+		} else if (dram_info.dram_type == DDRC_DDR4) {
+			ddr4_swffc(&dram_info, fsp_index);
+		}
+
+		dram_info.current_fsp = fsp_index;
+		wait_ddrc_hwffc_done = false;
+		wfe_done = 0;
+		dsb();
+		sev();
+		isb();
+	}
+
+	SMC_RET1(handle, 0);
+}
diff --git a/plat/imx/imx8m/ddr/dram_retention.c b/plat/imx/imx8m/ddr/dram_retention.c
new file mode 100644
index 0000000..7d4f823
--- /dev/null
+++ b/plat/imx/imx8m/ddr/dram_retention.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <lib/mmio.h>
+
+#include <dram.h>
+#include <platform_def.h>
+
+#define SRC_DDR1_RCR		(IMX_SRC_BASE + 0x1000)
+#define SRC_DDR2_RCR		(IMX_SRC_BASE + 0x1004)
+
+#define PU_PGC_UP_TRG		0xf8
+#define PU_PGC_DN_TRG		0x104
+#define GPC_PU_PWRHSK		(IMX_GPC_BASE + 0x01FC)
+#define CCM_SRC_CTRL_OFFSET     (IMX_CCM_BASE + 0x800)
+#define CCM_CCGR_OFFSET         (IMX_CCM_BASE + 0x4000)
+#define CCM_SRC_CTRL(n)		(CCM_SRC_CTRL_OFFSET + 0x10 * (n))
+#define CCM_CCGR(n)		(CCM_CCGR_OFFSET + 0x10 * (n))
+
+#define DRAM_PLL_CTRL		(IMX_ANAMIX_BASE + 0x50)
+
+#define DBGCAM_EMPTY		0x36000000
+
+void dram_enter_retention(void)
+{
+	/* Wait DBGCAM to be empty */
+	while (mmio_read_32(DDRC_DBGCAM(0)) != DBGCAM_EMPTY) {
+		;
+	}
+
+	/* Block AXI ports from taking anymore transactions */
+	mmio_write_32(DDRC_PCTRL_0(0), 0x0);
+	/* Wait until all AXI ports are idle */
+	while (mmio_read_32(DDRC_PSTAT(0)) & 0x10001) {
+		;
+	}
+
+	/* Enter self refresh */
+	mmio_write_32(DDRC_PWRCTL(0), 0xaa);
+
+	/* LPDDR4 & DDR4/DDR3L need to check different status */
+	if (dram_info.dram_type == DDRC_LPDDR4) {
+		while (0x223 != (mmio_read_32(DDRC_STAT(0)) & 0x33f)) {
+			;
+		}
+	} else {
+		while (0x23 != (mmio_read_32(DDRC_STAT(0)) & 0x3f)) {
+			;
+		}
+	}
+
+	mmio_write_32(DDRC_DFIMISC(0), 0x0);
+	mmio_write_32(DDRC_SWCTL(0), 0x0);
+	mmio_write_32(DDRC_DFIMISC(0), 0x1f00);
+	mmio_write_32(DDRC_DFIMISC(0), 0x1f20);
+
+	while (mmio_read_32(DDRC_DFISTAT(0)) & 0x1) {
+		;
+	}
+
+	mmio_write_32(DDRC_DFIMISC(0), 0x1f00);
+	/* wait DFISTAT.dfi_init_complete to 1 */
+	while (!(mmio_read_32(DDRC_DFISTAT(0)) & 0x1)) {
+		;
+	}
+
+	mmio_write_32(DDRC_SWCTL(0), 0x1);
+
+	/* should check PhyInLP3 pub reg */
+	dwc_ddrphy_apb_wr(0xd0000, 0x0);
+	if (!(dwc_ddrphy_apb_rd(0x90028) & 0x1)) {
+		INFO("PhyInLP3 = 1\n");
+	}
+	dwc_ddrphy_apb_wr(0xd0000, 0x1);
+
+#if defined(PLAT_imx8mq)
+	/* pwrdnreqn_async adbm/adbs of ddr */
+	mmio_clrbits_32(GPC_PU_PWRHSK, BIT(1));
+	while (mmio_read_32(GPC_PU_PWRHSK) & BIT(18)) {
+		;
+	}
+	mmio_setbits_32(GPC_PU_PWRHSK, BIT(1));
+#else
+	/* pwrdnreqn_async adbm/adbs of ddr */
+	mmio_clrbits_32(GPC_PU_PWRHSK, BIT(2));
+	while (mmio_read_32(GPC_PU_PWRHSK) & BIT(20)) {
+		;
+	}
+	mmio_setbits_32(GPC_PU_PWRHSK, BIT(2));
+#endif
+	/* remove PowerOk */
+	mmio_write_32(SRC_DDR1_RCR, 0x8F000008);
+
+	mmio_write_32(CCM_CCGR(5), 0);
+	mmio_write_32(CCM_SRC_CTRL(15), 2);
+
+	/* enable the phy iso */
+	mmio_setbits_32(IMX_GPC_BASE + 0xd40, 1);
+	mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, BIT(5));
+
+	VERBOSE("dram enter retention\n");
+}
+
+void dram_exit_retention(void)
+{
+	VERBOSE("dram exit retention\n");
+	/* assert all reset */
+#if defined(PLAT_imx8mq)
+	mmio_write_32(SRC_DDR2_RCR, 0x8F000003);
+	mmio_write_32(SRC_DDR1_RCR, 0x8F00000F);
+	mmio_write_32(SRC_DDR2_RCR, 0x8F000000);
+#else
+	mmio_write_32(SRC_DDR1_RCR, 0x8F00001F);
+	mmio_write_32(SRC_DDR1_RCR, 0x8F00000F);
+#endif
+	mmio_write_32(CCM_CCGR(5), 2);
+	mmio_write_32(CCM_SRC_CTRL(15), 2);
+
+	/* disable iso */
+	mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, BIT(5));
+	mmio_write_32(SRC_DDR1_RCR, 0x8F000006);
+
+	/* wait dram pll locked */
+	while (!(mmio_read_32(DRAM_PLL_CTRL) & BIT(31))) {
+		;
+	}
+
+	/* ddrc re-init */
+	dram_umctl2_init(dram_info.timing_info);
+
+	/*
+	 * Skips the DRAM init routine and starts up in selfrefresh mode
+	 * Program INIT0.skip_dram_init = 2'b11
+	 */
+	mmio_setbits_32(DDRC_INIT0(0), 0xc0000000);
+	/* Keeps the controller in self-refresh mode */
+	mmio_write_32(DDRC_PWRCTL(0), 0xaa);
+	mmio_write_32(DDRC_DBG1(0), 0x0);
+	mmio_write_32(SRC_DDR1_RCR, 0x8F000004);
+	mmio_write_32(SRC_DDR1_RCR, 0x8F000000);
+
+	/* before write Dynamic reg, sw_done should be 0 */
+	mmio_write_32(DDRC_SWCTL(0), 0x0);
+
+#if !PLAT_imx8mn
+	if (dram_info.dram_type == DDRC_LPDDR4) {
+		mmio_write_32(DDRC_DDR_SS_GPR0, 0x01); /*LPDDR4 mode */
+	}
+#endif /* !PLAT_imx8mn */
+
+	mmio_write_32(DDRC_DFIMISC(0), 0x0);
+
+	/* dram phy re-init */
+	dram_phy_init(dram_info.timing_info);
+
+	/* DWC_DDRPHYA_APBONLY0_MicroContMuxSel */
+	dwc_ddrphy_apb_wr(0xd0000, 0x0);
+	while (dwc_ddrphy_apb_rd(0x20097)) {
+		;
+	}
+	dwc_ddrphy_apb_wr(0xd0000, 0x1);
+
+	/* before write Dynamic reg, sw_done should be 0 */
+	mmio_write_32(DDRC_SWCTL(0), 0x0);
+	mmio_write_32(DDRC_DFIMISC(0), 0x20);
+	/* wait DFISTAT.dfi_init_complete to 1 */
+	while (!(mmio_read_32(DDRC_DFISTAT(0)) & 0x1)) {
+		;
+	}
+
+	/* clear DFIMISC.dfi_init_start */
+	mmio_write_32(DDRC_DFIMISC(0), 0x0);
+	/* set DFIMISC.dfi_init_complete_en */
+	mmio_write_32(DDRC_DFIMISC(0), 0x1);
+
+	/* set SWCTL.sw_done to enable quasi-dynamic register programming */
+	mmio_write_32(DDRC_SWCTL(0), 0x1);
+	/* wait SWSTAT.sw_done_ack to 1 */
+	while (!(mmio_read_32(DDRC_SWSTAT(0)) & 0x1)) {
+		;
+	}
+
+	mmio_write_32(DDRC_PWRCTL(0), 0x88);
+	/* wait STAT to normal state */
+	while (0x1 != (mmio_read_32(DDRC_STAT(0)) & 0x7)) {
+		;
+	}
+
+	mmio_write_32(DDRC_PCTRL_0(0), 0x1);
+	 /* dis_auto-refresh is set to 0 */
+	mmio_write_32(DDRC_RFSHCTL3(0), 0x0);
+
+	/* should check PhyInLP3 pub reg */
+	dwc_ddrphy_apb_wr(0xd0000, 0x0);
+	if (!(dwc_ddrphy_apb_rd(0x90028) & 0x1)) {
+		VERBOSE("PHYInLP3 = 0\n");
+	}
+	dwc_ddrphy_apb_wr(0xd0000, 0x1);
+}
diff --git a/plat/imx/imx8m/ddr/lpddr4_dvfs.c b/plat/imx/imx8m/ddr/lpddr4_dvfs.c
new file mode 100644
index 0000000..2b4f300
--- /dev/null
+++ b/plat/imx/imx8m/ddr/lpddr4_dvfs.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2018-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+
+#include <dram.h>
+
+static void lpddr4_mr_write(uint32_t mr_rank, uint32_t mr_addr, uint32_t mr_data)
+{
+	/*
+	 * 1. Poll MRSTAT.mr_wr_busy until it is 0. This checks that there
+	 * is no outstanding MR transaction. No
+	 * writes should be performed to MRCTRL0 and MRCTRL1 if MRSTAT.mr_wr_busy = 1.
+	 */
+	while (mmio_read_32(DDRC_MRSTAT(0)) & 0x1)
+		;
+
+	/*
+	 * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr,
+	 * MRCTRL0.mr_rank and (for MRWs)
+	 * MRCTRL1.mr_data to define the MR transaction.
+	 */
+	mmio_write_32(DDRC_MRCTRL0(0), (mr_rank << 4));
+	mmio_write_32(DDRC_MRCTRL1(0), (mr_addr << 8) | mr_data);
+	mmio_setbits_32(DDRC_MRCTRL0(0), BIT(31));
+}
+
+void lpddr4_swffc(struct dram_info *info, unsigned int init_fsp,
+	 unsigned int fsp_index)
+
+{
+	uint32_t mr, emr, emr2, emr3;
+	uint32_t mr11, mr12, mr22, mr14;
+	uint32_t val;
+	uint32_t derate_backup[3];
+	uint32_t (*mr_data)[8];
+
+	/* 1. program targetd UMCTL2_REGS_FREQ1/2/3,already done, skip it. */
+
+	/* 2. MR13.FSP-WR=1, MRW to update MR registers */
+	mr_data = info->mr_table;
+	mr = mr_data[fsp_index][0];
+	emr  = mr_data[fsp_index][1];
+	emr2 = mr_data[fsp_index][2];
+	emr3 = mr_data[fsp_index][3];
+	mr11 = mr_data[fsp_index][4];
+	mr12 = mr_data[fsp_index][5];
+	mr22 = mr_data[fsp_index][6];
+	mr14 = mr_data[fsp_index][7];
+
+	val = (init_fsp == 1) ? 0x2 << 6 : 0x1 << 6;
+	emr3 = (emr3 & 0x003f) | val | 0x0d00;
+
+	/* 12. set PWRCTL.selfref_en=0 */
+	mmio_clrbits_32(DDRC_PWRCTL(0), 0xf);
+
+	/* It is more safe to config it here */
+	mmio_clrbits_32(DDRC_DFIPHYMSTR(0), 0x1);
+
+	lpddr4_mr_write(3, 13, emr3);
+	lpddr4_mr_write(3, 1, mr);
+	lpddr4_mr_write(3, 2, emr);
+	lpddr4_mr_write(3, 3, emr2);
+	lpddr4_mr_write(3, 11, mr11);
+	lpddr4_mr_write(3, 12, mr12);
+	lpddr4_mr_write(3, 14, mr14);
+	lpddr4_mr_write(3, 22, mr22);
+
+	do {
+		val = mmio_read_32(DDRC_MRSTAT(0));
+	} while (val & 0x1);
+
+	/* 3. disable AXI ports */
+	mmio_write_32(DDRC_PCTRL_0(0), 0x0);
+
+	/* 4.Poll PSTAT.rd_port_busy_n=0 and PSTAT.wr_port_busy_n=0. */
+	do {
+		val = mmio_read_32(DDRC_PSTAT(0));
+	} while (val != 0);
+
+	/* 6.disable SBRCTL.scrub_en, skip if never enable it */
+	/* 7.poll SBRSTAT.scrub_busy  Q2: should skip phy master if never enable it */
+	/* Disable phy master */
+#ifdef DFILP_SPT
+	/* 8. disable DFI LP */
+	/* DFILPCFG0.dfi_lp_en_sr */
+	val = mmio_read_32(DDRC_DFILPCFG0(0));
+	if (val & 0x100) {
+		mmio_write_32(DDRC_DFILPCFG0(0), 0x0);
+		do {
+			val = mmio_read_32(DDRC_DFISTAT(0)); // dfi_lp_ack
+			val2 = mmio_read_32(DDRC_STAT(0)); // operating_mode
+		} while (((val & 0x2) == 0x2) && ((val2 & 0x7) == 3));
+	}
+#endif
+	/* 9. wait until in normal or power down states */
+	do {
+		/* operating_mode */
+		val = mmio_read_32(DDRC_STAT(0));
+	} while (((val & 0x7) != 1) && ((val & 0x7) != 2));
+
+	/* 10. Disable automatic derating: derate_enable */
+	val = mmio_read_32(DDRC_DERATEEN(0));
+	derate_backup[0] = val;
+	mmio_clrbits_32(DDRC_DERATEEN(0), 0x1);
+
+	val = mmio_read_32(DDRC_FREQ1_DERATEEN(0));
+	derate_backup[1] = val;
+	mmio_clrbits_32(DDRC_FREQ1_DERATEEN(0), 0x1);
+
+	val = mmio_read_32(DDRC_FREQ2_DERATEEN(0));
+	derate_backup[2] = val;
+	mmio_clrbits_32(DDRC_FREQ2_DERATEEN(0), 0x1);
+
+	/* 11. disable automatic ZQ calibration */
+	mmio_setbits_32(DDRC_ZQCTL0(0), BIT(31));
+	mmio_setbits_32(DDRC_FREQ1_ZQCTL0(0), BIT(31));
+	mmio_setbits_32(DDRC_FREQ2_ZQCTL0(0), BIT(31));
+
+	/* 12. set PWRCTL.selfref_en=0 */
+	mmio_clrbits_32(DDRC_PWRCTL(0), 0x1);
+
+	/* 13.Poll STAT.operating_mode is in "Normal" (001) or "Power-down" (010) */
+	do {
+		val = mmio_read_32(DDRC_STAT(0));
+	} while (((val & 0x7) != 1) && ((val & 0x7) != 2));
+
+	/* 14-15. trigger SW SR */
+	/* bit 5: selfref_sw, bit 6: stay_in_selfref */
+	mmio_setbits_32(DDRC_PWRCTL(0), 0x60);
+
+	/* 16. Poll STAT.selfref_state in "Self Refresh 1" */
+	do {
+		val = mmio_read_32(DDRC_STAT(0));
+	} while ((val & 0x300) != 0x100);
+
+	/* 17. disable dq */
+	mmio_setbits_32(DDRC_DBG1(0), 0x1);
+
+	/* 18. Poll DBGCAM.wr_data_pipeline_empty and DBGCAM.rd_data_pipeline_empty */
+	do {
+		val = mmio_read_32(DDRC_DBGCAM(0));
+		val &= 0x30000000;
+	} while (val != 0x30000000);
+
+	/* 19. change MR13.FSP-OP to new FSP and MR13.VRCG to high current */
+	emr3 = (((~init_fsp) & 0x1) << 7) | (0x1 << 3) | (emr3 & 0x0077) | 0x0d00;
+	lpddr4_mr_write(3, 13, emr3);
+
+	/* 20. enter SR Power Down */
+	mmio_clrsetbits_32(DDRC_PWRCTL(0), 0x60, 0x20);
+
+	/* 21. Poll STAT.selfref_state is in "SR Power down" */
+	do {
+		val = mmio_read_32(DDRC_STAT(0));
+	} while ((val & 0x300) != 0x200);
+
+	/* 22. set dfi_init_complete_en = 0 */
+
+	/* 23. switch clock */
+	/* set SWCTL.dw_done to 0 */
+	mmio_write_32(DDRC_SWCTL(0), 0x0000);
+
+	/* 24. program frequency mode=1(bit 29), target_frequency=target_freq (bit 29) */
+	mmio_write_32(DDRC_MSTR2(0), fsp_index);
+
+	/* 25. DBICTL for FSP-OP[1], skip it if never enable it */
+
+	/* 26.trigger initialization in the PHY */
+
+	/* Q3: if refresh level is updated, then should program */
+	/* as updating refresh, need to toggle refresh_update_level signal */
+	val = mmio_read_32(DDRC_RFSHCTL3(0));
+	val = val ^ 0x2;
+	mmio_write_32(DDRC_RFSHCTL3(0), val);
+
+	/* Q4: only for legacy PHY, so here can skipped */
+
+	/* dfi_frequency -> 0x1x */
+	val = mmio_read_32(DDRC_DFIMISC(0));
+	val &= 0xFE;
+	val |= (fsp_index << 8);
+	mmio_write_32(DDRC_DFIMISC(0), val);
+	/* dfi_init_start */
+	val |= 0x20;
+	mmio_write_32(DDRC_DFIMISC(0), val);
+
+	/* polling dfi_init_complete de-assert */
+	do {
+		val = mmio_read_32(DDRC_DFISTAT(0));
+	} while ((val & 0x1) == 0x1);
+
+	/* change the clock frequency */
+	dram_clock_switch(info->timing_info->fsp_table[fsp_index], info->bypass_mode);
+
+	/* dfi_init_start de-assert */
+	mmio_clrbits_32(DDRC_DFIMISC(0), 0x20);
+
+	/* polling dfi_init_complete re-assert */
+	do {
+		val = mmio_read_32(DDRC_DFISTAT(0));
+	} while ((val & 0x1) == 0x0);
+
+	/* 27. set ZQCTL0.dis_srx_zqcl = 1 */
+	if (fsp_index == 0) {
+		mmio_setbits_32(DDRC_ZQCTL0(0), BIT(30));
+	} else  if (fsp_index == 1) {
+		mmio_setbits_32(DDRC_FREQ1_ZQCTL0(0), BIT(30));
+	} else {
+		mmio_setbits_32(DDRC_FREQ2_ZQCTL0(0), BIT(30));
+	}
+
+	/* 28,29. exit "self refresh power down" to stay "self refresh 2" */
+	/* exit SR power down */
+	mmio_clrsetbits_32(DDRC_PWRCTL(0), 0x60, 0x40);
+	/* 30. Poll STAT.selfref_state in "Self refresh 2" */
+	do {
+		val = mmio_read_32(DDRC_STAT(0));
+	} while ((val & 0x300) != 0x300);
+
+	/* 31. change MR13.VRCG to normal */
+	emr3 = (emr3 & 0x00f7) | 0x0d00;
+	lpddr4_mr_write(3, 13, emr3);
+
+	/* enable PHY master */
+	mmio_write_32(DDRC_DFIPHYMSTR(0), 0x1);
+
+	/* 32. issue ZQ if required: zq_calib_short, bit 4 */
+	/* polling zq_calib_short_busy */
+	mmio_setbits_32(DDRC_DBGCMD(0), 0x10);
+
+	do {
+		val = mmio_read_32(DDRC_DBGSTAT(0));
+	} while ((val & 0x10) != 0x0);
+
+	/* 33. Reset ZQCTL0.dis_srx_zqcl=0 */
+	if (fsp_index == 1)
+		mmio_clrbits_32(DDRC_FREQ1_ZQCTL0(0), BIT(30));
+	else if (fsp_index == 2)
+		mmio_clrbits_32(DDRC_FREQ2_ZQCTL0(0), BIT(30));
+	else
+		mmio_clrbits_32(DDRC_ZQCTL0(0), BIT(30));
+
+	/* set SWCTL.dw_done to 1 and poll SWSTAT.sw_done_ack=1 */
+	mmio_write_32(DDRC_SWCTL(0), 0x1);
+
+	/* wait SWSTAT.sw_done_ack to 1 */
+	do {
+		val = mmio_read_32(DDRC_SWSTAT(0));
+	} while ((val & 0x1) == 0x0);
+
+	/* 34. set PWRCTL.stay_in_selfreh=0, exit SR */
+	mmio_clrbits_32(DDRC_PWRCTL(0), 0x40);
+	/* wait tXSR */
+
+	/* 35. Poll STAT.selfref_state in "Idle" */
+	do {
+		val = mmio_read_32(DDRC_STAT(0));
+	} while ((val & 0x300) != 0x0);
+
+#ifdef DFILP_SPT
+	/* 36. restore dfi_lp.dfi_lp_en_sr */
+	mmio_setbits_32(DDRC_DFILPCFG0(0), BIT(8));
+#endif
+
+	/* 37. re-enable CAM: dis_dq */
+	mmio_clrbits_32(DDRC_DBG1(0), 0x1);
+
+	/* 38. re-enable automatic SR: selfref_en */
+	mmio_setbits_32(DDRC_PWRCTL(0), 0x1);
+
+	/* 39. re-enable automatic ZQ: dis_auto_zq=0 */
+	/* disable automatic ZQ calibration */
+	if (fsp_index == 1)
+		mmio_clrbits_32(DDRC_FREQ1_ZQCTL0(0), BIT(31));
+	else if (fsp_index == 2)
+		mmio_clrbits_32(DDRC_FREQ2_ZQCTL0(0), BIT(31));
+	else
+		mmio_clrbits_32(DDRC_ZQCTL0(0), BIT(31));
+	/* 40. re-emable automatic derating: derate_enable */
+	mmio_write_32(DDRC_DERATEEN(0), derate_backup[0]);
+	mmio_write_32(DDRC_FREQ1_DERATEEN(0), derate_backup[1]);
+	mmio_write_32(DDRC_FREQ2_DERATEEN(0), derate_backup[2]);
+
+	/* 41. write 1 to PCTRL.port_en */
+	mmio_write_32(DDRC_PCTRL_0(0), 0x1);
+
+	/* 42. enable SBRCTL.scrub_en, skip if never enable it */
+}
diff --git a/plat/imx/imx8m/gpc_common.c b/plat/imx/imx8m/gpc_common.c
index 1e55f05..e674d7a 100644
--- a/plat/imx/imx8m/gpc_common.c
+++ b/plat/imx/imx8m/gpc_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,6 +9,7 @@
 #include <arch.h>
 #include <arch_helpers.h>
 #include <common/debug.h>
+#include <common/runtime_svc.h>
 #include <lib/mmio.h>
 #include <lib/psci/psci.h>
 
@@ -16,10 +17,14 @@
 #include <imx8m_psci.h>
 #include <plat_imx8.h>
 
+#define MAX_PLL_NUM	U(10)
+
 static uint32_t gpc_imr_offset[] = { IMR1_CORE0_A53, IMR1_CORE1_A53, IMR1_CORE2_A53, IMR1_CORE3_A53, };
 
 DEFINE_BAKERY_LOCK(gpc_lock);
 
+#define FSL_SIP_CONFIG_GPC_PM_DOMAIN		0x03
+
 #pragma weak imx_set_cpu_pwr_off
 #pragma weak imx_set_cpu_pwr_on
 #pragma weak imx_set_cpu_lpm
@@ -250,3 +255,54 @@
 	mmio_clrbits_32(IMX_GPC_BASE + SLPCR, SLPCR_RBC_EN |
 		(0x3f << SLPCR_RBC_COUNT_SHIFT));
 }
+
+struct pll_override {
+	uint32_t reg;
+	uint32_t override_mask;
+};
+
+struct pll_override pll[MAX_PLL_NUM] = {
+	{.reg = 0x0, .override_mask = (1 << 12) | (1 << 8), },
+	{.reg = 0x14, .override_mask = (1 << 12) | (1 << 8), },
+	{.reg = 0x28, .override_mask = (1 << 12) | (1 << 8), },
+	{.reg = 0x50, .override_mask = (1 << 12) | (1 << 8), },
+	{.reg = 0x64, .override_mask = (1 << 10) | (1 << 8), },
+	{.reg = 0x74, .override_mask = (1 << 10) | (1 << 8), },
+	{.reg = 0x84, .override_mask = (1 << 10) | (1 << 8), },
+	{.reg = 0x94, .override_mask = 0x5555500, },
+	{.reg = 0x104, .override_mask = 0x5555500, },
+	{.reg = 0x114, .override_mask = 0x500, },
+};
+
+#define PLL_BYPASS	BIT(4)
+void imx_anamix_override(bool enter)
+{
+	unsigned int i;
+
+	/*
+	 * bypass all the plls & enable the override bit before
+	 * entering DSM mode.
+	 */
+	for (i = 0U; i < MAX_PLL_NUM; i++) {
+		if (enter) {
+			mmio_setbits_32(IMX_ANAMIX_BASE + pll[i].reg, PLL_BYPASS);
+			mmio_setbits_32(IMX_ANAMIX_BASE + pll[i].reg, pll[i].override_mask);
+		} else {
+			mmio_clrbits_32(IMX_ANAMIX_BASE + pll[i].reg, PLL_BYPASS);
+			mmio_clrbits_32(IMX_ANAMIX_BASE + pll[i].reg, pll[i].override_mask);
+		}
+	}
+}
+
+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/imx8m/imx8m_psci_common.c b/plat/imx/imx8m/imx8m_psci_common.c
index 9dfd311..4df4f8e 100644
--- a/plat/imx/imx8m/imx8m_psci_common.c
+++ b/plat/imx/imx8m/imx8m_psci_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -13,6 +13,7 @@
 #include <lib/mmio.h>
 #include <lib/psci/psci.h>
 
+#include <dram.h>
 #include <gpc.h>
 #include <imx8m_psci.h>
 #include <plat_imx8.h>
@@ -118,8 +119,11 @@
 	if (!is_local_state_run(CLUSTER_PWR_STATE(target_state)))
 		imx_set_cluster_powerdown(core_id, CLUSTER_PWR_STATE(target_state));
 
-	if (is_local_state_off(SYSTEM_PWR_STATE(target_state)))
+	if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
 		imx_set_sys_lpm(core_id, true);
+		dram_enter_retention();
+		imx_anamix_override(true);
+	}
 }
 
 void imx_domain_suspend_finish(const psci_power_state_t *target_state)
@@ -127,8 +131,11 @@
 	uint64_t mpidr = read_mpidr_el1();
 	unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr);
 
-	if (is_local_state_off(SYSTEM_PWR_STATE(target_state)))
+	if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) {
+		imx_anamix_override(false);
+		dram_exit_retention();
 		imx_set_sys_lpm(core_id, false);
+	}
 
 	if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) {
 		imx_clear_rbc_count();
diff --git a/plat/imx/imx8m/imx8mm/gpc.c b/plat/imx/imx8m/imx8mm/gpc.c
index ab59292..cc1cb10 100644
--- a/plat/imx/imx8m/imx8mm/gpc.c
+++ b/plat/imx/imx8m/imx8mm/gpc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -19,6 +19,332 @@
 #include <gpc.h>
 #include <imx_sip_svc.h>
 
+#define MIPI_PWR_REQ		BIT(0)
+#define PCIE_PWR_REQ		BIT(1)
+#define OTG1_PWR_REQ		BIT(2)
+#define OTG2_PWR_REQ		BIT(3)
+#define HSIOMIX_PWR_REQ		BIT(4)
+#define GPU2D_PWR_REQ		BIT(6)
+#define GPUMIX_PWR_REQ		BIT(7)
+#define VPUMIX_PWR_REQ		BIT(8)
+#define GPU3D_PWR_REQ		BIT(9)
+#define DISPMIX_PWR_REQ		BIT(10)
+#define VPU_G1_PWR_REQ		BIT(11)
+#define VPU_G2_PWR_REQ		BIT(12)
+#define VPU_H1_PWR_REQ		BIT(13)
+
+#define HSIOMIX_ADB400_SYNC	(0x3 << 5)
+#define DISPMIX_ADB400_SYNC	BIT(7)
+#define VPUMIX_ADB400_SYNC	BIT(8)
+#define GPU3D_ADB400_SYNC	BIT(9)
+#define GPU2D_ADB400_SYNC	BIT(10)
+#define GPUMIX_ADB400_SYNC	BIT(11)
+#define HSIOMIX_ADB400_ACK	(0x3 << 23)
+#define DISPMIX_ADB400_ACK	BIT(25)
+#define VPUMIX_ADB400_ACK	BIT(26)
+#define GPU3D_ADB400_ACK	BIT(27)
+#define GPU2D_ADB400_ACK	BIT(28)
+#define GPUMIX_ADB400_ACK	BIT(29)
+
+#define MIPI_PGC		0xc00
+#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
+#define GPU3D_PGC		0xe40
+#define DISPMIX_PGC		0xe80
+#define VPU_G1_PGC		0xec0
+#define VPU_G2_PGC		0xf00
+#define VPU_H1_PGC		0xf40
+
+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,
+	MAX_DOMAINS,
+};
+
+/* PU domain */
+static struct imx_pwr_domain pu_domains[] = {
+	IMX_MIX_DOMAIN(HSIOMIX, false),
+	IMX_PD_DOMAIN(PCIE, false),
+	IMX_PD_DOMAIN(OTG1, true),
+	IMX_PD_DOMAIN(OTG2, true),
+	IMX_MIX_DOMAIN(GPUMIX, false),
+	IMX_MIX_DOMAIN(VPUMIX, false),
+	IMX_PD_DOMAIN(VPU_G1, false),
+	IMX_PD_DOMAIN(VPU_G2, false),
+	IMX_PD_DOMAIN(VPU_H1, false),
+	IMX_MIX_DOMAIN(DISPMIX, false),
+	IMX_PD_DOMAIN(MIPI, false),
+	/* below two domain only for ATF internal use */
+	IMX_MIX_DOMAIN(GPU2D, false),
+	IMX_MIX_DOMAIN(GPU3D, false),
+};
+
+static unsigned int pu_domain_status;
+
+#define GPU_RCR		0x40
+#define VPU_RCR		0x44
+
+#define VPU_CTL_BASE		0x38330000
+#define BLK_SFT_RSTN_CSR	0x0
+#define H1_SFT_RSTN		BIT(2)
+#define G1_SFT_RSTN		BIT(1)
+#define G2_SFT_RSTN		BIT(0)
+
+#define DISP_CTL_BASE		0x32e28000
+
+void vpu_sft_reset_assert(uint32_t domain_id)
+{
+	uint32_t val;
+
+	val = mmio_read_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR);
+
+	switch (domain_id) {
+	case VPU_G1:
+		val &= ~G1_SFT_RSTN;
+		mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+		break;
+	case VPU_G2:
+		val &= ~G2_SFT_RSTN;
+		mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+		break;
+	case VPU_H1:
+		val &= ~H1_SFT_RSTN;
+		mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+		break;
+	default:
+		break;
+	}
+}
+
+void vpu_sft_reset_deassert(uint32_t domain_id)
+{
+	uint32_t val;
+
+	val = mmio_read_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR);
+
+	switch (domain_id) {
+	case VPU_G1:
+		val |= G1_SFT_RSTN;
+		mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+		break;
+	case VPU_G2:
+		val |= G2_SFT_RSTN;
+		mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+		break;
+	case VPU_H1:
+		val |= H1_SFT_RSTN;
+		mmio_write_32(VPU_CTL_BASE + BLK_SFT_RSTN_CSR, val);
+		break;
+	default:
+		break;
+	}
+}
+
+void imx_gpc_pm_domain_enable(uint32_t domain_id, bool on)
+{
+	if (domain_id >= MAX_DOMAINS) {
+		return;
+	}
+
+	struct imx_pwr_domain *pwr_domain = &pu_domains[domain_id];
+
+	if (on) {
+		pu_domain_status |= (1 << domain_id);
+
+		if (domain_id == VPU_G1 || domain_id == VPU_G2 ||
+		    domain_id == VPU_H1) {
+			vpu_sft_reset_assert(domain_id);
+		}
+
+		/* HSIOMIX has no PU bit, so skip for it */
+		if (domain_id != HSIOMIX) {
+			/* clear the PGC bit */
+			mmio_clrbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
+
+			/* power up the domain */
+			mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, pwr_domain->pwr_req);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & pwr_domain->pwr_req) {
+				;
+			}
+		}
+
+		if (domain_id == VPU_G1 || domain_id == VPU_G2 ||
+		    domain_id == VPU_H1) {
+			vpu_sft_reset_deassert(domain_id);
+			/* dealy for a while to make sure reset done */
+			udelay(100);
+		}
+
+		if (domain_id == GPUMIX) {
+			/* assert reset */
+			mmio_write_32(IMX_SRC_BASE + GPU_RCR, 0x1);
+
+			/* power up GPU2D */
+			mmio_clrbits_32(IMX_GPC_BASE + GPU2D_PGC, 0x1);
+
+			mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, GPU2D_PWR_REQ);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & GPU2D_PWR_REQ) {
+				;
+			}
+
+			udelay(1);
+
+			/* power up GPU3D */
+			mmio_clrbits_32(IMX_GPC_BASE + GPU3D_PGC, 0x1);
+
+			mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, GPU3D_PWR_REQ);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & GPU3D_PWR_REQ) {
+				;
+			}
+
+			udelay(10);
+			/* release the gpumix reset */
+			mmio_write_32(IMX_SRC_BASE + GPU_RCR, 0x0);
+			udelay(10);
+		}
+
+		/* vpu sft clock enable */
+		if (domain_id == VPUMIX) {
+			mmio_write_32(IMX_SRC_BASE + VPU_RCR, 0x1);
+			udelay(5);
+			mmio_write_32(IMX_SRC_BASE + VPU_RCR, 0x0);
+			udelay(5);
+
+			/* enable all clock */
+			mmio_write_32(VPU_CTL_BASE + 0x4, 0x7);
+		}
+
+		if (domain_id == DISPMIX) {
+			/* special setting for DISPMIX */
+			mmio_write_32(DISP_CTL_BASE + 0x4, 0x1fff);
+			mmio_write_32(DISP_CTL_BASE, 0x7f);
+			mmio_write_32(DISP_CTL_BASE + 0x8, 0x30000);
+		}
+
+		/* handle the ADB400 sync */
+		if (pwr_domain->need_sync) {
+			/* clear adb power down request */
+			mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
+
+			/* wait for adb power request ack */
+			while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) {
+				;
+			}
+		}
+
+		if (domain_id == GPUMIX) {
+			/* power up GPU2D ADB */
+			mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, GPU2D_ADB400_SYNC);
+
+			/* wait for adb power request ack */
+			while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU2D_ADB400_ACK)) {
+				;
+			}
+
+			/* power up GPU3D ADB */
+			mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, GPU3D_ADB400_SYNC);
+
+			/* wait for adb power request ack */
+			while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU3D_ADB400_ACK)) {
+				;
+			}
+		}
+	} else {
+		pu_domain_status &= ~(1 << domain_id);
+
+		if (domain_id == OTG1 || domain_id == OTG2) {
+			return;
+		}
+
+		/* GPU2D & GPU3D ADB power down */
+		if (domain_id == GPUMIX) {
+			mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, GPU2D_ADB400_SYNC);
+
+			/* wait for adb power request ack */
+			while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU2D_ADB400_ACK)) {
+				;
+			}
+
+			mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, GPU3D_ADB400_SYNC);
+
+				/* wait for adb power request ack */
+			while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & GPU3D_ADB400_ACK)) {
+				;
+			}
+		}
+
+		/* handle the ADB400 sync */
+		if (pwr_domain->need_sync) {
+			/* set adb power down request */
+			mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
+
+			/* wait for adb power request ack */
+			while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) {
+				;
+			}
+		}
+
+		if (domain_id == GPUMIX) {
+			/* power down GPU2D */
+			mmio_setbits_32(IMX_GPC_BASE + GPU2D_PGC, 0x1);
+
+			mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, GPU2D_PWR_REQ);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & GPU2D_PWR_REQ) {
+				;
+			}
+
+			/* power down GPU3D */
+			mmio_setbits_32(IMX_GPC_BASE + GPU3D_PGC, 0x1);
+
+			mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, GPU3D_PWR_REQ);
+
+			/* 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) {
+			/* set the PGC bit */
+			mmio_setbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
+
+			/* power down the domain */
+			mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, pwr_domain->pwr_req);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & pwr_domain->pwr_req) {
+				;
+			}
+		}
+	}
+}
+
 void imx_gpc_init(void)
 {
 	unsigned int val;
@@ -85,7 +411,4 @@
 	 */
 	mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1);
 	mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1);
-
-	/* enable all the power domain by default */
-	mmio_write_32(IMX_GPC_BASE + PU_PGC_UP_TRG, 0x3fcf);
 }
diff --git a/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c b/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
index debede1..ba0db0c 100644
--- a/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
+++ b/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c
@@ -21,6 +21,7 @@
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <plat/common/platform.h>
 
+#include <dram.h>
 #include <gpc.h>
 #include <imx_aipstz.h>
 #include <imx_uart.h>
@@ -34,6 +35,9 @@
 static const mmap_region_t imx_mmap[] = {
 	MAP_REGION_FLAT(IMX_GIC_BASE, IMX_GIC_SIZE, MT_DEVICE | MT_RW),
 	MAP_REGION_FLAT(IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW), /* AIPS map */
+	MAP_REGION_FLAT(OCRAM_S_BASE, OCRAM_S_SIZE, MT_DEVICE | MT_RW), /* OCRAM_S */
+	MAP_REGION_FLAT(IMX_DDRPHY_BASE, IMX_DDR_IPS_SIZE, MT_DEVICE | MT_RW), /* DDRMIX */
+	MAP_REGION_FLAT(IMX_VPUMIX_BASE, IMX_VPUMIX_SIZE, MT_DEVICE | MT_RW), /* VPUMIX */
 	{0},
 };
 
@@ -198,6 +202,9 @@
 	/* select the CKIL source to 32K OSC */
 	mmio_write_32(IMX_ANAMIX_BASE + ANAMIX_MISC_CTL, 0x1);
 
+	/* Init the dram info */
+	dram_info_init(SAVED_DRAM_TIMING_BASE);
+
 	plat_gic_driver_init();
 	plat_gic_init();
 
diff --git a/plat/imx/imx8m/imx8mm/include/platform_def.h b/plat/imx/imx8m/imx8mm/include/platform_def.h
index ed693b9..84d86b9 100644
--- a/plat/imx/imx8m/imx8mm/include/platform_def.h
+++ b/plat/imx/imx8m/imx8mm/include/platform_def.h
@@ -6,6 +6,7 @@
 
 #include <arch.h>
 #include <common/tbbr/tbbr_img_def.h>
+#include <lib/utils_def.h>
 
 #define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
 #define PLATFORM_LINKER_ARCH		aarch64
@@ -85,7 +86,7 @@
 #define IMX_AIPSTZ4			U(0x32df0000)
 
 #define IMX_AIPS_BASE			U(0x30000000)
-#define IMX_AIPS_SIZE			U(0xC00000)
+#define IMX_AIPS_SIZE			U(0x3000000)
 #define IMX_GPV_BASE			U(0x32000000)
 #define IMX_GPV_SIZE			U(0x800000)
 #define IMX_AIPS1_BASE			U(0x30200000)
@@ -105,7 +106,10 @@
 #define IMX_DDRC_BASE			U(0x3d400000)
 #define IMX_DDRPHY_BASE			U(0x3c000000)
 #define IMX_DDR_IPS_BASE		U(0x3d000000)
+#define IMX_DDR_IPS_SIZE		U(0x1800000)
 #define IMX_ROM_BASE			U(0x0)
+#define IMX_VPUMIX_BASE                U(0x38330000)
+#define IMX_VPUMIX_SIZE                U(0x100000)
 
 #define GPV_BASE			U(0x32000000)
 #define GPV_SIZE			U(0x800000)
@@ -140,12 +144,14 @@
 #define GPR_TZASC_EN_LOCK		BIT(16)
 
 #define ANAMIX_MISC_CTL			U(0x124)
+#define DRAM_PLL_CTRL			(IMX_ANAMIX_BASE + 0x50)
 
 #define MAX_CSU_NUM			U(64)
 
 #define OCRAM_S_BASE			U(0x00180000)
 #define OCRAM_S_SIZE			U(0x8000)
 #define OCRAM_S_LIMIT			(OCRAM_S_BASE + OCRAM_S_SIZE)
+#define SAVED_DRAM_TIMING_BASE		OCRAM_S_BASE
 
 #define COUNTER_FREQUENCY		8000000 /* 8MHz */
 
diff --git a/plat/imx/imx8m/imx8mm/platform.mk b/plat/imx/imx8m/imx8mm/platform.mk
index 60fa325..1c6c9f8 100644
--- a/plat/imx/imx8m/imx8mm/platform.mk
+++ b/plat/imx/imx8m/imx8mm/platform.mk
@@ -19,6 +19,12 @@
 
 include lib/libfdt/libfdt.mk
 
+IMX_DRAM_SOURCES	:=	plat/imx/imx8m/ddr/dram.c		\
+				plat/imx/imx8m/ddr/clock.c		\
+				plat/imx/imx8m/ddr/dram_retention.c	\
+				plat/imx/imx8m/ddr/ddr4_dvfs.c		\
+				plat/imx/imx8m/ddr/lpddr4_dvfs.c
+
 IMX_GIC_SOURCES		:=	${GICV3_SOURCES}			\
 				plat/common/plat_gicv3.c		\
 				plat/common/plat_psci_common.c		\
@@ -43,6 +49,7 @@
 				drivers/delay_timer/delay_timer.c		\
 				drivers/delay_timer/generic_delay_timer.c	\
 				${XLAT_TABLES_LIB_SRCS}				\
+				${IMX_DRAM_SOURCES}				\
 				${IMX_GIC_SOURCES}
 
 ifeq (${NEED_BL2},yes)
diff --git a/plat/imx/imx8m/imx8mn/gpc.c b/plat/imx/imx8m/imx8mn/gpc.c
index 37d4226..4e05297 100644
--- a/plat/imx/imx8m/imx8mn/gpc.c
+++ b/plat/imx/imx8m/imx8mn/gpc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright 2019-2020 NXP
+ * Copyright 2019-2022 NXP
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -21,6 +21,124 @@
 
 #define CCGR(x)		(0x4000 + (x) * 0x10)
 
+#define MIPI_PWR_REQ		BIT(0)
+#define OTG1_PWR_REQ		BIT(2)
+#define HSIOMIX_PWR_REQ		BIT(4)
+#define GPUMIX_PWR_REQ		BIT(7)
+#define DISPMIX_PWR_REQ		BIT(10)
+
+#define HSIOMIX_ADB400_SYNC	BIT(5)
+#define DISPMIX_ADB400_SYNC	BIT(7)
+#define GPUMIX_ADB400_SYNC	(0x5 << 9)
+#define HSIOMIX_ADB400_ACK	BIT(23)
+#define DISPMIX_ADB400_ACK	BIT(25)
+#define GPUMIX_ADB400_ACK	(0x5 << 27)
+
+#define MIPI_PGC		0xc00
+#define OTG1_PGC		0xc80
+#define HSIOMIX_PGC	        0xd00
+#define GPUMIX_PGC		0xdc0
+#define DISPMIX_PGC		0xe80
+
+enum pu_domain_id {
+	HSIOMIX,
+	OTG1 = 2,
+	GPUMIX = 4,
+	DISPMIX = 9,
+	MIPI,
+};
+
+/* PU domain, add some hole to minimize the uboot change */
+static struct imx_pwr_domain pu_domains[11] = {
+	[HSIOMIX] = IMX_MIX_DOMAIN(HSIOMIX, false),
+	[OTG1] = IMX_PD_DOMAIN(OTG1, true),
+	[GPUMIX] = IMX_MIX_DOMAIN(GPUMIX, false),
+	[DISPMIX] = IMX_MIX_DOMAIN(DISPMIX, false),
+	[MIPI] = IMX_PD_DOMAIN(MIPI, true),
+};
+
+static unsigned int pu_domain_status;
+
+void imx_gpc_pm_domain_enable(uint32_t domain_id, bool on)
+{
+	if (domain_id > MIPI) {
+		return;
+	}
+
+	struct imx_pwr_domain *pwr_domain = &pu_domains[domain_id];
+
+	if (on) {
+		if (pwr_domain->need_sync) {
+			pu_domain_status |= (1 << domain_id);
+		}
+
+		/* HSIOMIX has no PU bit, so skip for it */
+		if (domain_id != HSIOMIX) {
+			/* clear the PGC bit */
+			mmio_clrbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
+
+			/* power up the domain */
+			mmio_setbits_32(IMX_GPC_BASE + PU_PGC_UP_TRG, pwr_domain->pwr_req);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_UP_TRG) & pwr_domain->pwr_req) {
+				;
+			}
+		}
+
+		if (domain_id == DISPMIX) {
+			/* de-reset bus_blk clk and
+			 * enable bus_blk clk
+			 */
+			mmio_write_32(0x32e28000, 0x100);
+			mmio_write_32(0x32e28004, 0x100);
+		}
+
+		/* handle the ADB400 sync */
+		if (pwr_domain->need_sync) {
+			/* clear adb power down request */
+			mmio_setbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
+
+			/* wait for adb power request ack */
+			while (!(mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) {
+				;
+			}
+		}
+	} else {
+		pu_domain_status &= ~(1 << domain_id);
+
+		if (domain_id == OTG1) {
+			return;
+		}
+
+		/* handle the ADB400 sync */
+		if (pwr_domain->need_sync) {
+
+			/* set adb power down request */
+			mmio_clrbits_32(IMX_GPC_BASE + GPC_PU_PWRHSK, pwr_domain->adb400_sync);
+
+			/* wait for adb power request ack */
+			while ((mmio_read_32(IMX_GPC_BASE + GPC_PU_PWRHSK) & pwr_domain->adb400_ack)) {
+				;
+			}
+		}
+
+		/* HSIOMIX has no PU bit, so skip for it */
+		if (domain_id != HSIOMIX) {
+			/* set the PGC bit */
+			mmio_setbits_32(IMX_GPC_BASE + pwr_domain->pgc_offset, 0x1);
+
+			/* power down the domain */
+			mmio_setbits_32(IMX_GPC_BASE + PU_PGC_DN_TRG, pwr_domain->pwr_req);
+
+			/* wait for power request done */
+			while (mmio_read_32(IMX_GPC_BASE + PU_PGC_DN_TRG) & pwr_domain->pwr_req) {
+				;
+			}
+		}
+	}
+}
+
 void imx_gpc_init(void)
 {
 	unsigned int val;
@@ -86,9 +204,4 @@
 	 * only need to do it once.
 	 */
 	mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1);
-
-	/* enable all the power domain by default */
-	for (i = 0; i < 103; i++)
-		mmio_write_32(IMX_CCM_BASE + CCGR(i), 0x3);
-	mmio_write_32(IMX_GPC_BASE + PU_PGC_UP_TRG, 0x485);
 }
diff --git a/plat/imx/imx8m/imx8mn/imx8mn_bl31_setup.c b/plat/imx/imx8m/imx8mn/imx8mn_bl31_setup.c
index 8147792..5d2a64e 100644
--- a/plat/imx/imx8m/imx8mn/imx8mn_bl31_setup.c
+++ b/plat/imx/imx8m/imx8mn/imx8mn_bl31_setup.c
@@ -19,6 +19,7 @@
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <plat/common/platform.h>
 
+#include <dram.h>
 #include <gpc.h>
 #include <imx_aipstz.h>
 #include <imx_uart.h>
@@ -207,6 +208,9 @@
 	/* select the CKIL source to 32K OSC */
 	mmio_write_32(IMX_ANAMIX_BASE + ANAMIX_MISC_CTL, 0x1);
 
+	/* Init the dram info */
+	dram_info_init(SAVED_DRAM_TIMING_BASE);
+
 	plat_gic_driver_init();
 	plat_gic_init();
 
diff --git a/plat/imx/imx8m/imx8mn/include/platform_def.h b/plat/imx/imx8m/imx8mn/include/platform_def.h
index 8d39ea6..dbb4416 100644
--- a/plat/imx/imx8m/imx8mn/include/platform_def.h
+++ b/plat/imx/imx8m/imx8mn/include/platform_def.h
@@ -9,6 +9,8 @@
 #include <lib/utils_def.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 
+#include <lib/utils_def.h>
+
 #define PLATFORM_LINKER_FORMAT		"elf64-littleaarch64"
 #define PLATFORM_LINKER_ARCH		aarch64
 
@@ -70,7 +72,7 @@
 #define IMX_AIPSTZ4			U(0x32df0000)
 
 #define IMX_AIPS_BASE			U(0x30000000)
-#define IMX_AIPS_SIZE			U(0xC00000)
+#define IMX_AIPS_SIZE			U(0x3000000)
 #define IMX_GPV_BASE			U(0x32000000)
 #define IMX_GPV_SIZE			U(0x800000)
 #define IMX_AIPS1_BASE			U(0x30200000)
diff --git a/plat/imx/imx8m/imx8mn/platform.mk b/plat/imx/imx8m/imx8mn/platform.mk
index 54be41b..0f3ad1a 100644
--- a/plat/imx/imx8m/imx8mn/platform.mk
+++ b/plat/imx/imx8m/imx8mn/platform.mk
@@ -13,6 +13,13 @@
 # Include GICv3 driver files
 include drivers/arm/gic/v3/gicv3.mk
 
+IMX_DRAM_SOURCES	:=	plat/imx/imx8m/ddr/dram.c		\
+				plat/imx/imx8m/ddr/clock.c		\
+				plat/imx/imx8m/ddr/dram_retention.c	\
+				plat/imx/imx8m/ddr/ddr4_dvfs.c		\
+				plat/imx/imx8m/ddr/lpddr4_dvfs.c
+
+
 IMX_GIC_SOURCES		:=	${GICV3_SOURCES}			\
 				plat/common/plat_gicv3.c		\
 				plat/common/plat_psci_common.c		\
@@ -36,6 +43,7 @@
 				drivers/arm/tzc/tzc380.c			\
 				drivers/delay_timer/delay_timer.c		\
 				drivers/delay_timer/generic_delay_timer.c	\
+				${IMX_DRAM_SOURCES}				\
 				${IMX_GIC_SOURCES}				\
 				${XLAT_TABLES_LIB_SRCS}
 
diff --git a/plat/imx/imx8m/imx8mp/gpc.c b/plat/imx/imx8m/imx8mp/gpc.c
index 3d68b94..452e788 100644
--- a/plat/imx/imx8m/imx8mp/gpc.c
+++ b/plat/imx/imx8m/imx8mp/gpc.c
@@ -170,7 +170,7 @@
 	}
 }
 
-static void imx_gpc_pm_domain_enable(uint32_t domain_id, bool on)
+void imx_gpc_pm_domain_enable(uint32_t domain_id, bool on)
 {
 	struct imx_pwr_domain *pwr_domain = &pu_domains[domain_id];
 	unsigned int i;
diff --git a/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c b/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c
index 57e5c51..d443c3d 100644
--- a/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c
+++ b/plat/imx/imx8m/imx8mp/imx8mp_bl31_setup.c
@@ -19,6 +19,7 @@
 #include <lib/xlat_tables/xlat_tables_v2.h>
 #include <plat/common/platform.h>
 
+#include <dram.h>
 #include <gpc.h>
 #include <imx_aipstz.h>
 #include <imx_uart.h>
@@ -203,6 +204,9 @@
 	/* select the CKIL source to 32K OSC */
 	mmio_write_32(IMX_ANAMIX_BASE + ANAMIX_MISC_CTL, 0x1);
 
+	/* Init the dram info */
+	dram_info_init(SAVED_DRAM_TIMING_BASE);
+
 	plat_gic_driver_init();
 	plat_gic_init();
 
diff --git a/plat/imx/imx8m/imx8mp/platform.mk b/plat/imx/imx8m/imx8mp/platform.mk
index 73fbd87..45f2972 100644
--- a/plat/imx/imx8m/imx8mp/platform.mk
+++ b/plat/imx/imx8m/imx8mp/platform.mk
@@ -15,6 +15,12 @@
 # Include GICv3 driver files
 include drivers/arm/gic/v3/gicv3.mk
 
+IMX_DRAM_SOURCES	:=	plat/imx/imx8m/ddr/dram.c		\
+				plat/imx/imx8m/ddr/clock.c		\
+				plat/imx/imx8m/ddr/dram_retention.c	\
+				plat/imx/imx8m/ddr/ddr4_dvfs.c		\
+				plat/imx/imx8m/ddr/lpddr4_dvfs.c
+
 IMX_GIC_SOURCES		:=	${GICV3_SOURCES}			\
 				plat/common/plat_gicv3.c		\
 				plat/common/plat_psci_common.c		\
@@ -38,6 +44,7 @@
 				drivers/arm/tzc/tzc380.c			\
 				drivers/delay_timer/delay_timer.c		\
 				drivers/delay_timer/generic_delay_timer.c	\
+				${IMX_DRAM_SOURCES}				\
 				${IMX_GIC_SOURCES}				\
 				${XLAT_TABLES_LIB_SRCS}
 
diff --git a/plat/imx/imx8m/include/ddrc.h b/plat/imx/imx8m/include/ddrc.h
new file mode 100644
index 0000000..55af3ff
--- /dev/null
+++ b/plat/imx/imx8m/include/ddrc.h
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2019-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef IMX_DDRC_H
+#define IMX_DDRC_H
+
+#define DDRC_IPS_BASE_ADDR(X)	(0x3d400000 + ((X) * 0x2000000))
+#define DDRC_DDR_SS_GPR0        0x3d000000
+
+/* DWC ddr umctl2 REGs offset*/
+/**********************/
+#define DDRC_MSTR(X)             (DDRC_IPS_BASE_ADDR(X) + 0x00)
+#define DDRC_STAT(X)             (DDRC_IPS_BASE_ADDR(X) + 0x04)
+#define DDRC_MSTR1(X)            (DDRC_IPS_BASE_ADDR(X) + 0x08)
+#define DDRC_MRCTRL0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x10)
+#define DDRC_MRCTRL1(X)          (DDRC_IPS_BASE_ADDR(X) + 0x14)
+#define DDRC_MRSTAT(X)           (DDRC_IPS_BASE_ADDR(X) + 0x18)
+#define DDRC_MRCTRL2(X)          (DDRC_IPS_BASE_ADDR(X) + 0x1c)
+#define DDRC_DERATEEN(X)         (DDRC_IPS_BASE_ADDR(X) + 0x20)
+#define DDRC_DERATEINT(X)        (DDRC_IPS_BASE_ADDR(X) + 0x24)
+#define DDRC_MSTR2(X)            (DDRC_IPS_BASE_ADDR(X) + 0x28)
+#define DDRC_PWRCTL(X)           (DDRC_IPS_BASE_ADDR(X) + 0x30)
+#define DDRC_PWRTMG(X)           (DDRC_IPS_BASE_ADDR(X) + 0x34)
+#define DDRC_HWLPCTL(X)          (DDRC_IPS_BASE_ADDR(X) + 0x38)
+#define DDRC_HWFFCCTL(X)         (DDRC_IPS_BASE_ADDR(X) + 0x3c)
+#define DDRC_HWFFCSTAT(X)        (DDRC_IPS_BASE_ADDR(X) + 0x40)
+#define DDRC_RFSHCTL0(X)         (DDRC_IPS_BASE_ADDR(X) + 0x50)
+#define DDRC_RFSHCTL1(X)         (DDRC_IPS_BASE_ADDR(X) + 0x54)
+#define DDRC_RFSHCTL2(X)         (DDRC_IPS_BASE_ADDR(X) + 0x58)
+#define DDRC_RFSHCTL3(X)         (DDRC_IPS_BASE_ADDR(X) + 0x60)
+#define DDRC_RFSHTMG(X)          (DDRC_IPS_BASE_ADDR(X) + 0x64)
+#define DDRC_ECCCFG0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x70)
+#define DDRC_ECCCFG1(X)          (DDRC_IPS_BASE_ADDR(X) + 0x74)
+#define DDRC_ECCSTAT(X)          (DDRC_IPS_BASE_ADDR(X) + 0x78)
+#define DDRC_ECCCLR(X)           (DDRC_IPS_BASE_ADDR(X) + 0x7c)
+#define DDRC_ECCERRCNT(X)        (DDRC_IPS_BASE_ADDR(X) + 0x80)
+#define DDRC_ECCCADDR0(X)        (DDRC_IPS_BASE_ADDR(X) + 0x84)
+#define DDRC_ECCCADDR1(X)        (DDRC_IPS_BASE_ADDR(X) + 0x88)
+#define DDRC_ECCCSYN0(X)         (DDRC_IPS_BASE_ADDR(X) + 0x8c)
+#define DDRC_ECCCSYN1(X)         (DDRC_IPS_BASE_ADDR(X) + 0x90)
+#define DDRC_ECCCSYN2(X)         (DDRC_IPS_BASE_ADDR(X) + 0x94)
+#define DDRC_ECCBITMASK0(X)      (DDRC_IPS_BASE_ADDR(X) + 0x98)
+#define DDRC_ECCBITMASK1(X)      (DDRC_IPS_BASE_ADDR(X) + 0x9c)
+#define DDRC_ECCBITMASK2(X)      (DDRC_IPS_BASE_ADDR(X) + 0xa0)
+#define DDRC_ECCUADDR0(X)        (DDRC_IPS_BASE_ADDR(X) + 0xa4)
+#define DDRC_ECCUADDR1(X)        (DDRC_IPS_BASE_ADDR(X) + 0xa8)
+#define DDRC_ECCUSYN0(X)         (DDRC_IPS_BASE_ADDR(X) + 0xac)
+#define DDRC_ECCUSYN1(X)         (DDRC_IPS_BASE_ADDR(X) + 0xb0)
+#define DDRC_ECCUSYN2(X)         (DDRC_IPS_BASE_ADDR(X) + 0xb4)
+#define DDRC_ECCPOISONADDR0(X)   (DDRC_IPS_BASE_ADDR(X) + 0xb8)
+#define DDRC_ECCPOISONADDR1(X)   (DDRC_IPS_BASE_ADDR(X) + 0xbc)
+#define DDRC_CRCPARCTL0(X)       (DDRC_IPS_BASE_ADDR(X) + 0xc0)
+#define DDRC_CRCPARCTL1(X)       (DDRC_IPS_BASE_ADDR(X) + 0xc4)
+#define DDRC_CRCPARCTL2(X)       (DDRC_IPS_BASE_ADDR(X) + 0xc8)
+#define DDRC_CRCPARSTAT(X)       (DDRC_IPS_BASE_ADDR(X) + 0xcc)
+#define DDRC_INIT0(X)            (DDRC_IPS_BASE_ADDR(X) + 0xd0)
+#define DDRC_INIT1(X)            (DDRC_IPS_BASE_ADDR(X) + 0xd4)
+#define DDRC_INIT2(X)            (DDRC_IPS_BASE_ADDR(X) + 0xd8)
+#define DDRC_INIT3(X)            (DDRC_IPS_BASE_ADDR(X) + 0xdc)
+#define DDRC_INIT4(X)            (DDRC_IPS_BASE_ADDR(X) + 0xe0)
+#define DDRC_INIT5(X)            (DDRC_IPS_BASE_ADDR(X) + 0xe4)
+#define DDRC_INIT6(X)            (DDRC_IPS_BASE_ADDR(X) + 0xe8)
+#define DDRC_INIT7(X)            (DDRC_IPS_BASE_ADDR(X) + 0xec)
+#define DDRC_DIMMCTL(X)          (DDRC_IPS_BASE_ADDR(X) + 0xf0)
+#define DDRC_RANKCTL(X)          (DDRC_IPS_BASE_ADDR(X) + 0xf4)
+#define DDRC_DRAMTMG0(X)         (DDRC_IPS_BASE_ADDR(X) + 0x100)
+#define DDRC_DRAMTMG1(X)         (DDRC_IPS_BASE_ADDR(X) + 0x104)
+#define DDRC_DRAMTMG2(X)         (DDRC_IPS_BASE_ADDR(X) + 0x108)
+#define DDRC_DRAMTMG3(X)         (DDRC_IPS_BASE_ADDR(X) + 0x10c)
+#define DDRC_DRAMTMG4(X)         (DDRC_IPS_BASE_ADDR(X) + 0x110)
+#define DDRC_DRAMTMG5(X)         (DDRC_IPS_BASE_ADDR(X) + 0x114)
+#define DDRC_DRAMTMG6(X)         (DDRC_IPS_BASE_ADDR(X) + 0x118)
+#define DDRC_DRAMTMG7(X)         (DDRC_IPS_BASE_ADDR(X) + 0x11c)
+#define DDRC_DRAMTMG8(X)         (DDRC_IPS_BASE_ADDR(X) + 0x120)
+#define DDRC_DRAMTMG9(X)         (DDRC_IPS_BASE_ADDR(X) + 0x124)
+#define DDRC_DRAMTMG10(X)        (DDRC_IPS_BASE_ADDR(X) + 0x128)
+#define DDRC_DRAMTMG11(X)        (DDRC_IPS_BASE_ADDR(X) + 0x12c)
+#define DDRC_DRAMTMG12(X)        (DDRC_IPS_BASE_ADDR(X) + 0x130)
+#define DDRC_DRAMTMG13(X)        (DDRC_IPS_BASE_ADDR(X) + 0x134)
+#define DDRC_DRAMTMG14(X)        (DDRC_IPS_BASE_ADDR(X) + 0x138)
+#define DDRC_DRAMTMG15(X)        (DDRC_IPS_BASE_ADDR(X) + 0x13C)
+#define DDRC_DRAMTMG16(X)        (DDRC_IPS_BASE_ADDR(X) + 0x140)
+#define DDRC_DRAMTMG17(X)        (DDRC_IPS_BASE_ADDR(X) + 0x144)
+
+#define DDRC_ZQCTL0(X)           (DDRC_IPS_BASE_ADDR(X) + 0x180)
+#define DDRC_ZQCTL1(X)           (DDRC_IPS_BASE_ADDR(X) + 0x184)
+#define DDRC_ZQCTL2(X)           (DDRC_IPS_BASE_ADDR(X) + 0x188)
+#define DDRC_ZQSTAT(X)           (DDRC_IPS_BASE_ADDR(X) + 0x18c)
+#define DDRC_DFITMG0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x190)
+#define DDRC_DFITMG1(X)          (DDRC_IPS_BASE_ADDR(X) + 0x194)
+#define DDRC_DFILPCFG0(X)        (DDRC_IPS_BASE_ADDR(X) + 0x198)
+#define DDRC_DFILPCFG1(X)        (DDRC_IPS_BASE_ADDR(X) + 0x19c)
+#define DDRC_DFIUPD0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x1a0)
+#define DDRC_DFIUPD1(X)          (DDRC_IPS_BASE_ADDR(X) + 0x1a4)
+#define DDRC_DFIUPD2(X)          (DDRC_IPS_BASE_ADDR(X) + 0x1a8)
+#define DDRC_DFIMISC(X)          (DDRC_IPS_BASE_ADDR(X) + 0x1b0)
+#define DDRC_DFITMG2(X)          (DDRC_IPS_BASE_ADDR(X) + 0x1b4)
+#define DDRC_DFITMG3(X)          (DDRC_IPS_BASE_ADDR(X) + 0x1b8)
+#define DDRC_DFISTAT(X)          (DDRC_IPS_BASE_ADDR(X) + 0x1bc)
+
+#define DDRC_DBICTL(X)           (DDRC_IPS_BASE_ADDR(X) + 0x1c0)
+#define DDRC_DFIPHYMSTR(X)       (DDRC_IPS_BASE_ADDR(X) + 0x1c4)
+#define DDRC_TRAINCTL0(X)        (DDRC_IPS_BASE_ADDR(X) + 0x1d0)
+#define DDRC_TRAINCTL1(X)        (DDRC_IPS_BASE_ADDR(X) + 0x1d4)
+#define DDRC_TRAINCTL2(X)        (DDRC_IPS_BASE_ADDR(X) + 0x1d8)
+#define DDRC_TRAINSTAT(X)        (DDRC_IPS_BASE_ADDR(X) + 0x1dc)
+#define DDRC_ADDRMAP0(X)         (DDRC_IPS_BASE_ADDR(X) + 0x200)
+#define DDRC_ADDRMAP1(X)         (DDRC_IPS_BASE_ADDR(X) + 0x204)
+#define DDRC_ADDRMAP2(X)         (DDRC_IPS_BASE_ADDR(X) + 0x208)
+#define DDRC_ADDRMAP3(X)         (DDRC_IPS_BASE_ADDR(X) + 0x20c)
+#define DDRC_ADDRMAP4(X)         (DDRC_IPS_BASE_ADDR(X) + 0x210)
+#define DDRC_ADDRMAP5(X)         (DDRC_IPS_BASE_ADDR(X) + 0x214)
+#define DDRC_ADDRMAP6(X)         (DDRC_IPS_BASE_ADDR(X) + 0x218)
+#define DDRC_ADDRMAP7(X)         (DDRC_IPS_BASE_ADDR(X) + 0x21c)
+#define DDRC_ADDRMAP8(X)         (DDRC_IPS_BASE_ADDR(X) + 0x220)
+#define DDRC_ADDRMAP9(X)         (DDRC_IPS_BASE_ADDR(X) + 0x224)
+#define DDRC_ADDRMAP10(X)        (DDRC_IPS_BASE_ADDR(X) + 0x228)
+#define DDRC_ADDRMAP11(X)        (DDRC_IPS_BASE_ADDR(X) + 0x22c)
+
+#define DDRC_ODTCFG(X)           (DDRC_IPS_BASE_ADDR(X) + 0x240)
+#define DDRC_ODTMAP(X)           (DDRC_IPS_BASE_ADDR(X) + 0x244)
+#define DDRC_SCHED(X)            (DDRC_IPS_BASE_ADDR(X) + 0x250)
+#define DDRC_SCHED1(X)           (DDRC_IPS_BASE_ADDR(X) + 0x254)
+#define DDRC_PERFHPR1(X)         (DDRC_IPS_BASE_ADDR(X) + 0x25c)
+#define DDRC_PERFLPR1(X)         (DDRC_IPS_BASE_ADDR(X) + 0x264)
+#define DDRC_PERFWR1(X)          (DDRC_IPS_BASE_ADDR(X) + 0x26c)
+#define DDRC_PERFVPR1(X)         (DDRC_IPS_BASE_ADDR(X) + 0x274)
+
+#define DDRC_PERFVPW1(X)         (DDRC_IPS_BASE_ADDR(X) + 0x278)
+
+#define DDRC_DQMAP0(X)           (DDRC_IPS_BASE_ADDR(X) + 0x280)
+#define DDRC_DQMAP1(X)           (DDRC_IPS_BASE_ADDR(X) + 0x284)
+#define DDRC_DQMAP2(X)           (DDRC_IPS_BASE_ADDR(X) + 0x288)
+#define DDRC_DQMAP3(X)           (DDRC_IPS_BASE_ADDR(X) + 0x28c)
+#define DDRC_DQMAP4(X)           (DDRC_IPS_BASE_ADDR(X) + 0x290)
+#define DDRC_DQMAP5(X)           (DDRC_IPS_BASE_ADDR(X) + 0x294)
+#define DDRC_DBG0(X)             (DDRC_IPS_BASE_ADDR(X) + 0x300)
+#define DDRC_DBG1(X)             (DDRC_IPS_BASE_ADDR(X) + 0x304)
+#define DDRC_DBGCAM(X)           (DDRC_IPS_BASE_ADDR(X) + 0x308)
+#define DDRC_DBGCMD(X)           (DDRC_IPS_BASE_ADDR(X) + 0x30c)
+#define DDRC_DBGSTAT(X)          (DDRC_IPS_BASE_ADDR(X) + 0x310)
+
+#define DDRC_SWCTL(X)            (DDRC_IPS_BASE_ADDR(X) + 0x320)
+#define DDRC_SWSTAT(X)           (DDRC_IPS_BASE_ADDR(X) + 0x324)
+#define DDRC_OCPARCFG0(X)        (DDRC_IPS_BASE_ADDR(X) + 0x330)
+#define DDRC_OCPARCFG1(X)        (DDRC_IPS_BASE_ADDR(X) + 0x334)
+#define DDRC_OCPARCFG2(X)        (DDRC_IPS_BASE_ADDR(X) + 0x338)
+#define DDRC_OCPARCFG3(X)        (DDRC_IPS_BASE_ADDR(X) + 0x33c)
+#define DDRC_OCPARSTAT0(X)       (DDRC_IPS_BASE_ADDR(X) + 0x340)
+#define DDRC_OCPARSTAT1(X)       (DDRC_IPS_BASE_ADDR(X) + 0x344)
+#define DDRC_OCPARWLOG0(X)       (DDRC_IPS_BASE_ADDR(X) + 0x348)
+#define DDRC_OCPARWLOG1(X)       (DDRC_IPS_BASE_ADDR(X) + 0x34c)
+#define DDRC_OCPARWLOG2(X)       (DDRC_IPS_BASE_ADDR(X) + 0x350)
+#define DDRC_OCPARAWLOG0(X)      (DDRC_IPS_BASE_ADDR(X) + 0x354)
+#define DDRC_OCPARAWLOG1(X)      (DDRC_IPS_BASE_ADDR(X) + 0x358)
+#define DDRC_OCPARRLOG0(X)       (DDRC_IPS_BASE_ADDR(X) + 0x35c)
+#define DDRC_OCPARRLOG1(X)       (DDRC_IPS_BASE_ADDR(X) + 0x360)
+#define DDRC_OCPARARLOG0(X)      (DDRC_IPS_BASE_ADDR(X) + 0x364)
+#define DDRC_OCPARARLOG1(X)      (DDRC_IPS_BASE_ADDR(X) + 0x368)
+#define DDRC_POISONCFG(X)        (DDRC_IPS_BASE_ADDR(X) + 0x36C)
+#define DDRC_POISONSTAT(X)       (DDRC_IPS_BASE_ADDR(X) + 0x370)
+#define DDRC_ADVECCINDEX(X)      (DDRC_IPS_BASE_ADDR(X) + 0x3)
+#define DDRC_ADVECCSTAT(X)       (DDRC_IPS_BASE_ADDR(X) + 0x3)
+#define DDRC_ECCPOISONPAT0(X)    (DDRC_IPS_BASE_ADDR(X) + 0x3)
+#define DDRC_ECCPOISONPAT1(X)    (DDRC_IPS_BASE_ADDR(X) + 0x3)
+#define DDRC_ECCPOISONPAT2(X)    (DDRC_IPS_BASE_ADDR(X) + 0x3)
+#define DDRC_HIFCTL(X)           (DDRC_IPS_BASE_ADDR(X) + 0x3)
+
+#define DDRC_PSTAT(X)            (DDRC_IPS_BASE_ADDR(X) + 0x3fc)
+#define DDRC_PCCFG(X)            (DDRC_IPS_BASE_ADDR(X) + 0x400)
+#define DDRC_PCFGR_0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x404)
+#define DDRC_PCFGR_1(X)          (DDRC_IPS_BASE_ADDR(X) + 1 * 0xb0 + 0x404)
+#define DDRC_PCFGR_2(X)          (DDRC_IPS_BASE_ADDR(X) + 2 * 0xb0 + 0x404)
+#define DDRC_PCFGR_3(X)          (DDRC_IPS_BASE_ADDR(X) + 3 * 0xb0 + 0x404)
+#define DDRC_PCFGW_0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x408)
+#define DDRC_PCFGW_1(X)          (DDRC_IPS_BASE_ADDR(X) + 1 * 0xb0 + 0x408)
+#define DDRC_PCFGW_2(X)          (DDRC_IPS_BASE_ADDR(X) + 2 * 0xb0 + 0x408)
+#define DDRC_PCFGW_3(X)          (DDRC_IPS_BASE_ADDR(X) + 3 * 0xb0 + 0x408)
+#define DDRC_PCFGC_0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x40c)
+#define DDRC_PCFGIDMASKCH(X)     (DDRC_IPS_BASE_ADDR(X) + 0x410)
+#define DDRC_PCFGIDVALUECH(X)    (DDRC_IPS_BASE_ADDR(X) + 0x414)
+#define DDRC_PCTRL_0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x490)
+#define DDRC_PCTRL_1(X)          (DDRC_IPS_BASE_ADDR(X) + 0x490 + 1 * 0xb0)
+#define DDRC_PCTRL_2(X)          (DDRC_IPS_BASE_ADDR(X) + 0x490 + 2 * 0xb0)
+#define DDRC_PCTRL_3(X)          (DDRC_IPS_BASE_ADDR(X) + 0x490 + 3 * 0xb0)
+#define DDRC_PCFGQOS0_0(X)       (DDRC_IPS_BASE_ADDR(X) + 0x494)
+#define DDRC_PCFGQOS1_0(X)       (DDRC_IPS_BASE_ADDR(X) + 0x498)
+#define DDRC_PCFGWQOS0_0(X)      (DDRC_IPS_BASE_ADDR(X) + 0x49c)
+#define DDRC_PCFGWQOS1_0(X)      (DDRC_IPS_BASE_ADDR(X) + 0x4a0)
+#define DDRC_SARBASE0(X)         (DDRC_IPS_BASE_ADDR(X) + 0xf04)
+#define DDRC_SARSIZE0(X)         (DDRC_IPS_BASE_ADDR(X) + 0xf08)
+#define DDRC_SBRCTL(X)           (DDRC_IPS_BASE_ADDR(X) + 0xf24)
+#define DDRC_SBRSTAT(X)          (DDRC_IPS_BASE_ADDR(X) + 0xf28)
+#define DDRC_SBRWDATA0(X)        (DDRC_IPS_BASE_ADDR(X) + 0xf2c)
+#define DDRC_SBRWDATA1(X)        (DDRC_IPS_BASE_ADDR(X) + 0xf30)
+#define DDRC_PDCH(X)             (DDRC_IPS_BASE_ADDR(X) + 0xf34)
+
+/* SHADOW registers */
+#define DDRC_FREQ1_DERATEEN(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2020)
+#define DDRC_FREQ1_DERATEINT(X)        (DDRC_IPS_BASE_ADDR(X) + 0x2024)
+#define DDRC_FREQ1_RFSHCTL0(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2050)
+#define DDRC_FREQ1_RFSHTMG(X)          (DDRC_IPS_BASE_ADDR(X) + 0x2064)
+#define DDRC_FREQ1_INIT3(X)            (DDRC_IPS_BASE_ADDR(X) + 0x20dc)
+#define DDRC_FREQ1_INIT4(X)            (DDRC_IPS_BASE_ADDR(X) + 0x20e0)
+#define DDRC_FREQ1_INIT6(X)            (DDRC_IPS_BASE_ADDR(X) + 0x20e8)
+#define DDRC_FREQ1_INIT7(X)            (DDRC_IPS_BASE_ADDR(X) + 0x20ec)
+#define DDRC_FREQ1_DRAMTMG0(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2100)
+#define DDRC_FREQ1_DRAMTMG1(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2104)
+#define DDRC_FREQ1_DRAMTMG2(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2108)
+#define DDRC_FREQ1_DRAMTMG3(X)         (DDRC_IPS_BASE_ADDR(X) + 0x210c)
+#define DDRC_FREQ1_DRAMTMG4(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2110)
+#define DDRC_FREQ1_DRAMTMG5(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2114)
+#define DDRC_FREQ1_DRAMTMG6(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2118)
+#define DDRC_FREQ1_DRAMTMG7(X)         (DDRC_IPS_BASE_ADDR(X) + 0x211c)
+#define DDRC_FREQ1_DRAMTMG8(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2120)
+#define DDRC_FREQ1_DRAMTMG9(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2124)
+#define DDRC_FREQ1_DRAMTMG10(X)        (DDRC_IPS_BASE_ADDR(X) + 0x2128)
+#define DDRC_FREQ1_DRAMTMG11(X)        (DDRC_IPS_BASE_ADDR(X) + 0x212c)
+#define DDRC_FREQ1_DRAMTMG12(X)        (DDRC_IPS_BASE_ADDR(X) + 0x2130)
+#define DDRC_FREQ1_DRAMTMG13(X)        (DDRC_IPS_BASE_ADDR(X) + 0x2134)
+#define DDRC_FREQ1_DRAMTMG14(X)        (DDRC_IPS_BASE_ADDR(X) + 0x2138)
+#define DDRC_FREQ1_DRAMTMG15(X)        (DDRC_IPS_BASE_ADDR(X) + 0x213C)
+#define DDRC_FREQ1_DRAMTMG16(X)        (DDRC_IPS_BASE_ADDR(X) + 0x2140)
+#define DDRC_FREQ1_DRAMTMG17(X)        (DDRC_IPS_BASE_ADDR(X) + 0x2144)
+#define DDRC_FREQ1_ZQCTL0(X)           (DDRC_IPS_BASE_ADDR(X) + 0x2180)
+#define DDRC_FREQ1_DFITMG0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x2190)
+#define DDRC_FREQ1_DFITMG1(X)          (DDRC_IPS_BASE_ADDR(X) + 0x2194)
+#define DDRC_FREQ1_DFITMG2(X)          (DDRC_IPS_BASE_ADDR(X) + 0x21b4)
+#define DDRC_FREQ1_DFITMG3(X)          (DDRC_IPS_BASE_ADDR(X) + 0x21b8)
+#define DDRC_FREQ1_ODTCFG(X)           (DDRC_IPS_BASE_ADDR(X) + 0x2240)
+
+#define DDRC_FREQ2_DERATEEN(X)         (DDRC_IPS_BASE_ADDR(X) + 0x3020)
+#define DDRC_FREQ2_DERATEINT(X)        (DDRC_IPS_BASE_ADDR(X) + 0x3024)
+#define DDRC_FREQ2_RFSHCTL0(X)         (DDRC_IPS_BASE_ADDR(X) + 0x3050)
+#define DDRC_FREQ2_RFSHTMG(X)          (DDRC_IPS_BASE_ADDR(X) + 0x3064)
+#define DDRC_FREQ2_INIT3(X)            (DDRC_IPS_BASE_ADDR(X) + 0x30dc)
+#define DDRC_FREQ2_INIT4(X)            (DDRC_IPS_BASE_ADDR(X) + 0x30e0)
+#define DDRC_FREQ2_INIT6(X)            (DDRC_IPS_BASE_ADDR(X) + 0x30e8)
+#define DDRC_FREQ2_INIT7(X)            (DDRC_IPS_BASE_ADDR(X) + 0x30ec)
+#define DDRC_FREQ2_DRAMTMG0(X)         (DDRC_IPS_BASE_ADDR(X) + 0x3100)
+#define DDRC_FREQ2_DRAMTMG1(X)         (DDRC_IPS_BASE_ADDR(X) + 0x3104)
+#define DDRC_FREQ2_DRAMTMG2(X)         (DDRC_IPS_BASE_ADDR(X) + 0x3108)
+#define DDRC_FREQ2_DRAMTMG3(X)         (DDRC_IPS_BASE_ADDR(X) + 0x310c)
+#define DDRC_FREQ2_DRAMTMG4(X)         (DDRC_IPS_BASE_ADDR(X) + 0x3110)
+#define DDRC_FREQ2_DRAMTMG5(X)         (DDRC_IPS_BASE_ADDR(X) + 0x3114)
+#define DDRC_FREQ2_DRAMTMG6(X)         (DDRC_IPS_BASE_ADDR(X) + 0x3118)
+#define DDRC_FREQ2_DRAMTMG7(X)         (DDRC_IPS_BASE_ADDR(X) + 0x311c)
+#define DDRC_FREQ2_DRAMTMG8(X)         (DDRC_IPS_BASE_ADDR(X) + 0x3120)
+#define DDRC_FREQ2_DRAMTMG9(X)         (DDRC_IPS_BASE_ADDR(X) + 0x3124)
+#define DDRC_FREQ2_DRAMTMG10(X)        (DDRC_IPS_BASE_ADDR(X) + 0x3128)
+#define DDRC_FREQ2_DRAMTMG11(X)        (DDRC_IPS_BASE_ADDR(X) + 0x312c)
+#define DDRC_FREQ2_DRAMTMG12(X)        (DDRC_IPS_BASE_ADDR(X) + 0x3130)
+#define DDRC_FREQ2_DRAMTMG13(X)        (DDRC_IPS_BASE_ADDR(X) + 0x3134)
+#define DDRC_FREQ2_DRAMTMG14(X)        (DDRC_IPS_BASE_ADDR(X) + 0x3138)
+#define DDRC_FREQ2_DRAMTMG15(X)        (DDRC_IPS_BASE_ADDR(X) + 0x313C)
+#define DDRC_FREQ2_DRAMTMG16(X)        (DDRC_IPS_BASE_ADDR(X) + 0x3140)
+#define DDRC_FREQ2_DRAMTMG17(X)        (DDRC_IPS_BASE_ADDR(X) + 0x3144)
+#define DDRC_FREQ2_ZQCTL0(X)           (DDRC_IPS_BASE_ADDR(X) + 0x3180)
+#define DDRC_FREQ2_DFITMG0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x3190)
+#define DDRC_FREQ2_DFITMG1(X)          (DDRC_IPS_BASE_ADDR(X) + 0x3194)
+#define DDRC_FREQ2_DFITMG2(X)          (DDRC_IPS_BASE_ADDR(X) + 0x31b4)
+#define DDRC_FREQ2_DFITMG3(X)          (DDRC_IPS_BASE_ADDR(X) + 0x31b8)
+#define DDRC_FREQ2_ODTCFG(X)           (DDRC_IPS_BASE_ADDR(X) + 0x3240)
+
+#define DDRC_FREQ3_DERATEEN(X)         (DDRC_IPS_BASE_ADDR(X) + 0x4020)
+#define DDRC_FREQ3_DERATEINT(X)        (DDRC_IPS_BASE_ADDR(X) + 0x4024)
+#define DDRC_FREQ3_RFSHCTL0(X)         (DDRC_IPS_BASE_ADDR(X) + 0x4050)
+#define DDRC_FREQ3_RFSHTMG(X)          (DDRC_IPS_BASE_ADDR(X) + 0x4064)
+#define DDRC_FREQ3_INIT3(X)            (DDRC_IPS_BASE_ADDR(X) + 0x40dc)
+#define DDRC_FREQ3_INIT4(X)            (DDRC_IPS_BASE_ADDR(X) + 0x40e0)
+#define DDRC_FREQ3_INIT6(X)            (DDRC_IPS_BASE_ADDR(X) + 0x40e8)
+#define DDRC_FREQ3_INIT7(X)            (DDRC_IPS_BASE_ADDR(X) + 0x40ec)
+#define DDRC_FREQ3_DRAMTMG0(X)         (DDRC_IPS_BASE_ADDR(X) + 0x4100)
+#define DDRC_FREQ3_DRAMTMG1(X)         (DDRC_IPS_BASE_ADDR(X) + 0x4104)
+#define DDRC_FREQ3_DRAMTMG2(X)         (DDRC_IPS_BASE_ADDR(X) + 0x4108)
+#define DDRC_FREQ3_DRAMTMG3(X)         (DDRC_IPS_BASE_ADDR(X) + 0x410c)
+#define DDRC_FREQ3_DRAMTMG4(X)         (DDRC_IPS_BASE_ADDR(X) + 0x4110)
+#define DDRC_FREQ3_DRAMTMG5(X)         (DDRC_IPS_BASE_ADDR(X) + 0x4114)
+#define DDRC_FREQ3_DRAMTMG6(X)         (DDRC_IPS_BASE_ADDR(X) + 0x4118)
+#define DDRC_FREQ3_DRAMTMG7(X)         (DDRC_IPS_BASE_ADDR(X) + 0x411c)
+#define DDRC_FREQ3_DRAMTMG8(X)         (DDRC_IPS_BASE_ADDR(X) + 0x4120)
+#define DDRC_FREQ3_DRAMTMG9(X)         (DDRC_IPS_BASE_ADDR(X) + 0x4124)
+#define DDRC_FREQ3_DRAMTMG10(X)        (DDRC_IPS_BASE_ADDR(X) + 0x4128)
+#define DDRC_FREQ3_DRAMTMG11(X)        (DDRC_IPS_BASE_ADDR(X) + 0x412c)
+#define DDRC_FREQ3_DRAMTMG12(X)        (DDRC_IPS_BASE_ADDR(X) + 0x4130)
+#define DDRC_FREQ3_DRAMTMG13(X)        (DDRC_IPS_BASE_ADDR(X) + 0x4134)
+#define DDRC_FREQ3_DRAMTMG14(X)        (DDRC_IPS_BASE_ADDR(X) + 0x4138)
+#define DDRC_FREQ3_DRAMTMG15(X)        (DDRC_IPS_BASE_ADDR(X) + 0x413C)
+#define DDRC_FREQ3_DRAMTMG16(X)        (DDRC_IPS_BASE_ADDR(X) + 0x4140)
+
+#define DDRC_FREQ3_ZQCTL0(X)           (DDRC_IPS_BASE_ADDR(X) + 0x4180)
+#define DDRC_FREQ3_DFITMG0(X)          (DDRC_IPS_BASE_ADDR(X) + 0x4190)
+#define DDRC_FREQ3_DFITMG1(X)          (DDRC_IPS_BASE_ADDR(X) + 0x4194)
+#define DDRC_FREQ3_DFITMG2(X)          (DDRC_IPS_BASE_ADDR(X) + 0x41b4)
+#define DDRC_FREQ3_DFITMG3(X)          (DDRC_IPS_BASE_ADDR(X) + 0x41b8)
+#define DDRC_FREQ3_ODTCFG(X)           (DDRC_IPS_BASE_ADDR(X) + 0x4240)
+#define DDRC_DFITMG0_SHADOW(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2190)
+#define DDRC_DFITMG1_SHADOW(X)         (DDRC_IPS_BASE_ADDR(X) + 0x2194)
+#define DDRC_DFITMG2_SHADOW(X)         (DDRC_IPS_BASE_ADDR(X) + 0x21b4)
+#define DDRC_DFITMG3_SHADOW(X)         (DDRC_IPS_BASE_ADDR(X) + 0x21b8)
+#define DDRC_ODTCFG_SHADOW(X)          (DDRC_IPS_BASE_ADDR(X) + 0x2240)
+
+#define DRC_PERF_MON_BASE_ADDR(X)	(0x3d800000 + ((X) * 0x2000000))
+#define DRC_PERF_MON_CNT0_CTL(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x0)
+#define DRC_PERF_MON_CNT1_CTL(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x4)
+#define DRC_PERF_MON_CNT2_CTL(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x8)
+#define DRC_PERF_MON_CNT3_CTL(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0xC)
+#define DRC_PERF_MON_CNT0_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x20)
+#define DRC_PERF_MON_CNT1_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x24)
+#define DRC_PERF_MON_CNT2_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x28)
+#define DRC_PERF_MON_CNT3_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x2C)
+#define DRC_PERF_MON_DPCR_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x30)
+#define DRC_PERF_MON_MRR0_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x40)
+#define DRC_PERF_MON_MRR1_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x44)
+#define DRC_PERF_MON_MRR2_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x48)
+#define DRC_PERF_MON_MRR3_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x4C)
+#define DRC_PERF_MON_MRR4_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x50)
+#define DRC_PERF_MON_MRR5_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x54)
+#define DRC_PERF_MON_MRR6_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x58)
+#define DRC_PERF_MON_MRR7_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x5C)
+#define DRC_PERF_MON_MRR8_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x60)
+#define DRC_PERF_MON_MRR9_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x64)
+#define DRC_PERF_MON_MRR10_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x68)
+#define DRC_PERF_MON_MRR11_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x6C)
+#define DRC_PERF_MON_MRR12_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x70)
+#define DRC_PERF_MON_MRR13_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x74)
+#define DRC_PERF_MON_MRR14_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x78)
+#define DRC_PERF_MON_MRR15_DAT(X)	(DRC_PERF_MON_BASE_ADDR(X) + 0x7C)
+
+#define dwc_ddrphy_apb_rd(addr)		mmio_read_32(IMX_DDRPHY_BASE + 4 * (addr))
+#define dwc_ddrphy_apb_wr(addr, val)	mmio_write_32(IMX_DDRPHY_BASE + 4 * (addr), val)
+
+#endif /*IMX_DDRC_H */
diff --git a/plat/imx/imx8m/include/dram.h b/plat/imx/imx8m/include/dram.h
new file mode 100644
index 0000000..ad11a27
--- /dev/null
+++ b/plat/imx/imx8m/include/dram.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019-2022 NXP
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DRAM_H
+#define DRAM_H
+
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <lib/utils_def.h>
+
+#include <ddrc.h>
+#include <platform_def.h>
+
+#define DDRC_LPDDR4		BIT(5)
+#define DDRC_DDR4		BIT(4)
+#define DDRC_DDR3L		BIT(0)
+#define DDR_TYPE_MASK		U(0x3f)
+#define ACTIVE_RANK_MASK	U(0x3)
+
+/* reg & config param */
+struct dram_cfg_param {
+	unsigned int reg;
+	unsigned int val;
+};
+
+struct dram_timing_info {
+	/* umctl2 config */
+	struct dram_cfg_param *ddrc_cfg;
+	unsigned int ddrc_cfg_num;
+	/* ddrphy config */
+	struct dram_cfg_param *ddrphy_cfg;
+	unsigned int ddrphy_cfg_num;
+	/* ddr fsp train info */
+	struct dram_fsp_msg *fsp_msg;
+	unsigned int fsp_msg_num;
+	/* ddr phy trained CSR */
+	struct dram_cfg_param *ddrphy_trained_csr;
+	unsigned int ddrphy_trained_csr_num;
+	/* ddr phy PIE */
+	struct dram_cfg_param *ddrphy_pie;
+	unsigned int ddrphy_pie_num;
+	/* initialized fsp table */
+	unsigned int fsp_table[4];
+};
+
+struct dram_info {
+	int dram_type;
+	unsigned int num_rank;
+	uint32_t num_fsp;
+	int current_fsp;
+	int boot_fsp;
+	bool bypass_mode;
+	struct dram_timing_info *timing_info;
+	/* mr, emr, emr2, emr3, mr11, mr12, mr22, mr14 */
+	uint32_t mr_table[3][8];
+};
+
+extern struct dram_info dram_info;
+
+void dram_info_init(unsigned long dram_timing_base);
+void dram_umctl2_init(struct dram_timing_info *timing);
+void dram_phy_init(struct dram_timing_info *timing);
+
+/* dram retention */
+void dram_enter_retention(void);
+void dram_exit_retention(void);
+
+void dram_clock_switch(unsigned int target_drate, bool bypass_mode);
+
+/* dram frequency change */
+void lpddr4_swffc(struct dram_info *info, unsigned int init_fsp, unsigned int fsp_index);
+void ddr4_swffc(struct dram_info *dram_info, unsigned int pstate);
+
+#endif /* DRAM_H */
diff --git a/plat/imx/imx8m/include/gpc.h b/plat/imx/imx8m/include/gpc.h
index 29b8ecf..a41030e 100644
--- a/plat/imx/imx8m/include/gpc.h
+++ b/plat/imx/imx8m/include/gpc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -69,5 +69,7 @@
 void imx_set_sys_lpm(unsigned last_core, bool retention);
 void imx_set_rbc_count(void);
 void imx_clear_rbc_count(void);
+void imx_anamix_override(bool enter);
+void imx_gpc_pm_domain_enable(uint32_t domain_id, bool on);
 
 #endif /*IMX8M_GPC_H */