plat: imx8mq: refact the dram low power code

refact the dram low power related code to make it more
friendly for different dram config or different board.

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

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 b47f7f0..a47f85a 100644
--- a/plat/imx/common/imx8_sip_svc.c
+++ b/plat/imx/common/imx8_sip_svc.c
@@ -34,17 +34,10 @@
 			      u_register_t flags)
 {
 	switch (smc_fid) {
-#ifdef PLAT_IMX8M
-	case FSL_SIP_DDR_DVFS:
-		SMC_RET1(handle, lpddr4_dvfs_handler(smc_fid, x1, x2, x3));
-		break;
-#endif
-#if defined(PLAT_IMX8MM)
+#if defined(PLAT_IMX8M) || defined(PLAT_IMX8MM)
 	case FSL_SIP_DDR_DVFS:
 		SMC_RET1(handle, dram_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;
diff --git a/plat/imx/common/imx8m/clock.c b/plat/imx/common/imx8m/clock.c
index fee6821..86ebd9a 100644
--- a/plat/imx/common/imx8m/clock.c
+++ b/plat/imx/common/imx8m/clock.c
@@ -61,3 +61,30 @@
 		ddr_pll_bypass_dis();
 	}
 }
+
+#if defined(PLAT_IMX8M)
+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, 0x00ece580);
+		break;
+	case 1600:
+		mmio_write_32(HW_DRAM_PLL_CFG2, 0x00ec6984);
+		break;
+	case 667:
+		mmio_write_32(HW_DRAM_PLL_CFG2, 0x00f5a406);
+		break;
+	default:
+		break;
+	}
+
+	/* bypass the PLL */
+	mmio_clrbits_32(HW_DRAM_PLL_CFG0, 0x30);
+	while(!(mmio_read_32(HW_DRAM_PLL_CFG0) &(1 << 31)))
+		;
+}
+#endif
diff --git a/plat/imx/common/imx8m/dram.c b/plat/imx/common/imx8m/dram.c
index df34c4b..abb607a 100644
--- a/plat/imx/common/imx8m/dram.c
+++ b/plat/imx/common/imx8m/dram.c
@@ -15,11 +15,81 @@
 /* lock used for DDR DVFS */
 spinlock_t dfs_lock;
 /* IRQ used for DDR DVFS */
+#if defined(PLAT_IMX8M)
+static uint32_t irqs_used [] = {102, 109, 110, 111};
+/* ocram used to dram timing */
+static uint8_t dram_timing_saved[13 * 1024] __aligned(8);
+#else
 static uint32_t irqs_used[] = {74, 75, 76, 77};
+#endif
 static volatile uint32_t wfe_done;
 static volatile bool wait_ddrc_hwffc_done = true;
 
 static unsigned int dev_fsp = 0x1;
+bool bypass_mode_supported = true;
+
+#if defined (PLAT_IMX8M)
+/* copy the dram timing info from DRAM to OCRAM */
+void imx8mq_dram_timing_copy(struct dram_timing_info *from,
+	 struct dram_timing_info *to)
+{
+	struct dram_cfg_param *cfg1, *cfg2;
+	unsigned int num;
+
+	/* copy the dram_timing info header */
+	cfg1 = (struct dram_cfg_param *) ((unsigned long) to + sizeof(struct dram_timing_info));
+	cfg2 = from->ddrc_cfg;
+
+	/* copy the ddrc init config */
+	to->ddrc_cfg_num = from->ddrc_cfg_num;
+	to->ddrphy_cfg_num = from->ddrphy_cfg_num;
+	to->ddrphy_trained_csr_num = from->ddrphy_trained_csr_num;
+	to->ddrphy_pie_num = from->ddrphy_pie_num;
+
+	/* copy the fsp table */
+	for (int i = 0; i < 4; i++)
+		to->fsp_table[i] = from->fsp_table[i];
+
+	/* copy the ddrc config */
+	to->ddrc_cfg = cfg1;
+	num = from->ddrc_cfg_num;
+	for (int i = 0; i < num; i++) {
+		cfg1->reg = cfg2->reg;
+		cfg1->val = cfg2->val;
+		cfg1++;
+		cfg2++;
+	}
+
+	/* copy the ddrphy init config */
+	to->ddrphy_cfg = cfg1;
+	num = from->ddrphy_cfg_num;
+	for (int i = 0; i < num; i++) {
+		cfg1->reg = cfg2->reg;
+		cfg1->val = cfg2->val;
+		cfg1++;
+		cfg2++;
+	}
+
+	/* copy the ddrphy csr */
+	to->ddrphy_trained_csr = cfg1;
+	num = from->ddrphy_trained_csr_num;
+	for (int i = 0; i < num; i++) {
+		cfg1->reg = cfg2->reg;
+		cfg1->val = cfg2->val;
+		cfg1++;
+		cfg2++;
+	}
+	/* copy the PIE image */
+	to->ddrphy_pie = cfg1;
+	num = from->ddrphy_pie_num;
+	for (int i = 0; i < num; i++) {
+		cfg1->reg = cfg2->reg;
+		cfg1->val = cfg2->val;
+		cfg1++;
+		cfg2++;
+	}
+}
+#endif
 
 /* restore the ddrc config */
 void dram_umctl2_init(void)
@@ -67,6 +137,19 @@
 	}
 }
 
+#define BYPASS_MODE_DRATE		666
+static bool is_bypass_mode_enabled(struct dram_timing_info *info)
+{
+	/*
+	 * if there is a fsp drate is lower than 666, we assume
+	 * that the bypass mode is enanbled.
+	 */
+	if(info->fsp_table[1] > BYPASS_MODE_DRATE ||
+		 info->fsp_table[2] > BYPASS_MODE_DRATE)
+		return false;
+	else
+		return true;
+}
 
 void dram_info_init(unsigned long dram_timing_base)
 {
@@ -85,6 +168,13 @@
 	dram_info.boot_fsp = current_fsp;
 	dram_info.current_fsp = current_fsp;
 
+#if defined(PLAT_IMX8M)
+	imx8mq_dram_timing_copy((struct dram_timing_info *)dram_timing_base,
+		(struct dram_timing_info *)dram_timing_saved);
+
+	dram_timing_base = (unsigned long) dram_timing_saved;
+#endif
+	bypass_mode_supported = is_bypass_mode_enabled((struct dram_timing_info *)dram_timing_base);
 	/*
 	 * No need to do save for ddrc and phy config register,
 	 * we have done it in SPL stage and save in memory
@@ -95,7 +185,7 @@
 	if(ddr_type == DDRC_LPDDR4 && current_fsp != 0x0) {
 		/* flush the L1/L2 cache */
 		dcsw_op_all(DCCSW);
-		lpddr4_swffc(dev_fsp, 0x0);
+		lpddr4_swffc(&dram_info, dev_fsp, 0x0, bypass_mode_supported);
 		dev_fsp = (~dev_fsp) & 0x1;
 	} else if (ddr_type == DDRC_DDR4 && current_fsp != 0x0) {
 		/* flush the L1/L2 cache */
@@ -156,15 +246,21 @@
 		/* make sure all the core in WFE */
 		online_cores &= ~(0x1 << (cpu_id * 8));
 		while (1) {
+#if defined(PLAT_IMX8M)
+			mmio_write_32(0x30340004, mmio_read_32(0x30340004) | (1 << 12));
+#endif
 			if (online_cores == wfe_done)
 				break;
 		}
+#if defined(PLAT_IMX8M)
+		mmio_write_32(0x30340004, mmio_read_32(0x30340004) & ~(1 << 12));
+#endif
 
 		/* flush the L1/L2 cache */
 		dcsw_op_all(DCCSW);
 
 		if (dram_info.dram_type == DDRC_LPDDR4) {
-			lpddr4_swffc(dev_fsp, target_freq);
+			lpddr4_swffc(&dram_info, dev_fsp, target_freq, bypass_mode_supported);
 			dev_fsp = (~dev_fsp) & 0x1;
 		} else if (dram_info.dram_type == DDRC_DDR4) {
 			ddr4_swffc(&dram_info, target_freq);
diff --git a/plat/imx/common/imx8m/lpddr4_dvfs.c b/plat/imx/common/imx8m/lpddr4_dvfs.c
index 4cdbd52..b3ea27b 100644
--- a/plat/imx/common/imx8m/lpddr4_dvfs.c
+++ b/plat/imx/common/imx8m/lpddr4_dvfs.c
@@ -13,7 +13,8 @@
 
 extern void dram_clock_switch(unsigned target_freq);
 
-void lpddr4_swffc(unsigned int init_fsp, unsigned int tgt_freq)
+void lpddr4_swffc(struct dram_info *info, unsigned int init_fsp,
+	 unsigned int tgt_freq, bool bypass_mode)
 
 {
 	unsigned int mr, emr, emr2, emr3;
@@ -60,6 +61,9 @@
 	tmp &= ~0xf; 
 	mmio_write_32(DDRC_PWRCTL(0), tmp);
 
+	/* more safe */
+	mmio_write_32(DDRC_DFIPHYMSTR(0), 0x00000000);
+
 	lpddr4_mr_write(3, 13, emr3);
 	lpddr4_mr_write(3, 1, mr);
 	lpddr4_mr_write(3, 2, emr);
@@ -84,7 +88,6 @@
 	/* 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 */
-	mmio_write_32(DDRC_DFIPHYMSTR(0),0x00000000);
 
 #ifdef DFILP_SPT 
 	/* 8. disable DFI LP */
@@ -214,7 +217,14 @@
 	} while ((tmp & 0x1) == 0x1);
 
 	/* change the clock frequency */
+#if defined(PLAT_IMX8M)
+	if (bypass_mode)
+		dram_clock_switch(tgt_freq);
+	else
+		dram_pll_init(info->timing_info->fsp_table[tgt_freq]);
+#else
 	dram_clock_switch(tgt_freq);
+#endif
 
 	/* dfi_init_start de-assert */
 	tmp= mmio_read_32(DDRC_DFIMISC(0));
@@ -269,7 +279,6 @@
 		tmp= mmio_read_32(DDRC_DBGSTAT(0));
 	} while ((tmp & 0x10 ) != 0x0);
 
-#if 1
 	/* 33. Reset ZQCTL0.dis_srx_zqcl=0 */
 	if (tgt_freq == 1) {
 		tmp = mmio_read_32(DDRC_FREQ1_ZQCTL0(0));
@@ -346,5 +355,4 @@
 	mmio_write_32(DDRC_PCTRL_0(0), 0x1);
 
 	/* 42. enable SBRCTL.scrub_en, skip if never enable it */
-#endif
 }
diff --git a/plat/imx/common/imx8m/lpddr4_retention.c b/plat/imx/common/imx8m/lpddr4_retention.c
index c44dd29..205dbbf 100644
--- a/plat/imx/common/imx8m/lpddr4_retention.c
+++ b/plat/imx/common/imx8m/lpddr4_retention.c
@@ -92,7 +92,7 @@
 	for (i=0; i<20; i++){
  	}
 
-#ifdef M850D
+#if defined(PLAT_IMX8M)
 	/* pwrdnreqn_async adbm/adbs of ddr */
 	mmio_clrbits_32(GPC_PU_PWRHSK, (1 << 1));
 	do {
@@ -140,7 +140,7 @@
 	}
 
 	/*assert all reset */
-#ifdef M850D
+#if defined(PLAT_IMX8M)
 	mmio_write_32(SRC_DDRC_RCR_ADDR+0x4, 0x8F000003); // assert [0]src_system_rst_b!
 	mmio_write_32(SRC_DDRC_RCR_ADDR, 0x8F00000F); // assert [0]ddr1_preset_n, [1]ddr1_core_reset_n, [2]ddr1_phy_reset, [3]ddr1_phy_pwrokin_n,
 	mmio_write_32(SRC_DDRC_RCR_ADDR+0x4, 0x8F000000); // deassert  [4]src_system_rst_b!
diff --git a/plat/imx/common/include/dram.h b/plat/imx/common/include/dram.h
index f3d72dd..bf0b384 100644
--- a/plat/imx/common/include/dram.h
+++ b/plat/imx/common/include/dram.h
@@ -56,6 +56,8 @@
 	/* 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 {
@@ -79,7 +81,8 @@
 void ddr4_enter_retention(void);
 void ddr4_exit_retention(void);
 /* lpddr4 swffc for dvfs */
-void lpddr4_swffc(unsigned int dev_fsp, unsigned int tgt_freq);
+void lpddr4_swffc(struct dram_info *dram_info, unsigned int dev_fsp,
+	 unsigned int tgt_freq, bool bypass_mode_supported);
 /* ddr4 swffw for dvfs */
 void ddr4_swffc(struct dram_info *dram_info, unsigned int target_fsp);
 
@@ -88,5 +91,6 @@
 void dram_exit_retention(void);
 
 void dram_clock_switch(unsigned int target_freq);
+void dram_pll_init(unsigned int drate);
 
 #endif /* __DRAM_H__ */
diff --git a/plat/imx/imx8mq/ddr/lpddr4_dvfs.c b/plat/imx/imx8mq/ddr/lpddr4_dvfs.c
index 7adbf92..c770229 100644
--- a/plat/imx/imx8mq/ddr/lpddr4_dvfs.c
+++ b/plat/imx/imx8mq/ddr/lpddr4_dvfs.c
@@ -109,6 +109,3 @@
 
 	return 0;
 }
-
-
-
diff --git a/plat/imx/imx8mq/gpc.c b/plat/imx/imx8mq/gpc.c
index 832de0f..5b25228 100644
--- a/plat/imx/imx8mq/gpc.c
+++ b/plat/imx/imx8mq/gpc.c
@@ -14,6 +14,7 @@
 
 #include <debug.h>
 #include <delay_timer.h>
+#include <dram.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <stdbool.h>
@@ -398,10 +399,10 @@
 			 SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN);
 
 		/* DDR enter retention */
-		ddrc_enter_retention();
+		dram_enter_retention();
 	} else {
 		/* DDR exit retention */
-		ddrc_exit_retention();
+		dram_exit_retention();
 	}
 
 	mmio_write_32(IMX_GPC_BASE + 0x14, val);
diff --git a/plat/imx/imx8mq/imx8mq_bl31_setup.c b/plat/imx/imx8mq/imx8mq_bl31_setup.c
index 8be2ce2..4a6423b 100644
--- a/plat/imx/imx8mq/imx8mq_bl31_setup.c
+++ b/plat/imx/imx8mq/imx8mq_bl31_setup.c
@@ -36,6 +36,7 @@
 #include <context.h>
 #include <context_mgmt.h>
 #include <debug.h>
+#include <dram.h>
 #include <generic_delay_timer.h>
 #include <stdbool.h>
 #include <mmio.h>
@@ -44,6 +45,7 @@
 #include <plat_imx8.h>
 #include <xlat_tables.h>
 #include <soc.h>
+#include <string.h>
 #include <tzc380.h>
 #include <imx_csu.h>
 #include <imx_rdc.h>
@@ -83,6 +85,7 @@
 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)
 {
@@ -315,8 +318,7 @@
 	/* gpc init */
 	imx_gpc_init();
 
-	/* switch DDR frequency to 3200 mts */
-	lpddr4_switch_to_3200();
+	dram_info_init(SAVED_DRAM_TIMING_BASE);
 }
 
 entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type)
diff --git a/plat/imx/imx8mq/include/ddrc.h b/plat/imx/imx8mq/include/ddrc.h
index 8eb42fd..ed6ebfa 100644
--- a/plat/imx/imx8mq/include/ddrc.h
+++ b/plat/imx/imx8mq/include/ddrc.h
@@ -297,6 +297,33 @@
 #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 IP2APB_DDRPHY_IPS_BASE_ADDR(X) (0x3c000000 + (X * 0x2000000))
 #define dwc_ddrphy_apb_rd(addr) mmio_read_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * (addr))
 #define dwc_ddrphy_apb_wr(addr, val) mmio_write_32(IP2APB_DDRPHY_IPS_BASE_ADDR(0) + 4 * (addr), val)
diff --git a/plat/imx/imx8mq/include/platform_def.h b/plat/imx/imx8mq/include/platform_def.h
index 5aef41b..822d95a 100644
--- a/plat/imx/imx8mq/include/platform_def.h
+++ b/plat/imx/imx8mq/include/platform_def.h
@@ -70,6 +70,12 @@
 #define IMX_DDR_IPS_BASE		0x3d000000
 #define IMX_ROM_BASE			0x0
 
+#define SAVED_DRAM_TIMING_BASE		0x40000000
+
+#define HW_DRAM_PLL_CFG0		(IMX_ANAMIX_BASE + 0x60)
+#define HW_DRAM_PLL_CFG1		(IMX_ANAMIX_BASE + 0x64)
+#define HW_DRAM_PLL_CFG2		(IMX_ANAMIX_BASE + 0x68)
+
 #define OCRAM_S_BASE			0x00180000
 #define OCRAM_S_SIZE			0x8000
 #define OCRAM_S_LIMIT			(OCRAM_S_BASE + OCRAM_S_SIZE)
diff --git a/plat/imx/imx8mq/platform.mk b/plat/imx/imx8mq/platform.mk
index c613863..f27f640 100644
--- a/plat/imx/imx8mq/platform.mk
+++ b/plat/imx/imx8mq/platform.mk
@@ -7,11 +7,13 @@
 				plat/common/plat_gicv3.c		\
 				plat/imx/common/plat_imx8_gic.c
 
-PLAT_DDR_SOURCES	:=	plat/imx/imx8mq/ddr/lpddr4_ddrc_cfg.c	\
-				plat/imx/imx8mq/ddr/lpddr4_phy_cfg.c	\
-				plat/imx/imx8mq/ddr/lpddr4_dvfs.c	\
-				plat/imx/imx8mq/ddr/lpddr4_swffc.c	\
-				plat/imx/imx8mq/ddr/lpddr4_retention.c
+PLAT_DRAM_SOURCES	:=	plat/imx/common/imx8m/dram.c		\
+				plat/imx/common/imx8m/clock.c		\
+				plat/imx/common/imx8m/lpddr4_retention.c \
+				plat/imx/common/imx8m/ddr4_retention.c \
+				plat/imx/common/imx8m/lpddr4_helper.c	\
+				plat/imx/common/imx8m/lpddr4_dvfs.c	\
+				plat/imx/common/imx8m/ddr4_dvfs.c
 
 BL31_SOURCES		+=	plat/imx/common/imx8_helpers.S		\
 				plat/imx/common/mxcuart_console.S	\
@@ -33,7 +35,7 @@
 				drivers/delay_timer/delay_timer.c		\
 				drivers/delay_timer/generic_delay_timer.c	\
 				${PLAT_GIC_SOURCES}			\
-				${PLAT_DDR_SOURCES}			\
+				${PLAT_DRAM_SOURCES}				\
 				drivers/arm/tzc/tzc380.c
 
 ENABLE_PLAT_COMPAT	:=	0