xref: /rk3399_ARM-atf/plat/imx/imx8ulp/dram.c (revision 416c4433f0047a86165e450e60f93020c561151b)
1478af8d3SJacky Bai /*
2478af8d3SJacky Bai  * Copyright 2021-2024 NXP
3478af8d3SJacky Bai  *
4478af8d3SJacky Bai  * SPDX-License-Identifier: BSD-3-Clause
5478af8d3SJacky Bai  */
6478af8d3SJacky Bai 
7478af8d3SJacky Bai #include <assert.h>
8478af8d3SJacky Bai #include <stdbool.h>
9478af8d3SJacky Bai 
10caee2733SJacky Bai #include <arch_helpers.h>
11caee2733SJacky Bai #include <bl31/interrupt_mgmt.h>
12caee2733SJacky Bai #include <common/runtime_svc.h>
13478af8d3SJacky Bai #include <lib/mmio.h>
14caee2733SJacky Bai #include <lib/spinlock.h>
15caee2733SJacky Bai #include <plat/common/platform.h>
16caee2733SJacky Bai 
17478af8d3SJacky Bai #include <platform_def.h>
18478af8d3SJacky Bai 
19caee2733SJacky Bai #include <dram.h>
20478af8d3SJacky Bai #include <upower_api.h>
21478af8d3SJacky Bai 
22478af8d3SJacky Bai #define PHY_FREQ_SEL_INDEX(x)		((x) << 16)
23478af8d3SJacky Bai #define PHY_FREQ_MULTICAST_EN(x)	((x) << 8)
24478af8d3SJacky Bai #define DENALI_PHY_1537			U(0x5804)
25478af8d3SJacky Bai 
26478af8d3SJacky Bai #define IMX_DDRC_BASE			U(0x2E060000)
27478af8d3SJacky Bai #define SAVED_DRAM_DATA_BASE		U(0x20055000)
28478af8d3SJacky Bai #define DENALI_CTL_144			0x240
29478af8d3SJacky Bai #define LPI_WAKEUP_EN_SHIFT		U(8)
30478af8d3SJacky Bai #define IMX_LPAV_SIM_BASE		0x2DA50000
31478af8d3SJacky Bai #define LPDDR_CTRL			0x14
32478af8d3SJacky Bai #define LPDDR_AUTO_LP_MODE_DISABLE	BIT(24)
33478af8d3SJacky Bai #define SOC_LP_CMD_SHIFT		U(15)
34478af8d3SJacky Bai #define LPDDR_CTRL2			0x18
35478af8d3SJacky Bai 
36478af8d3SJacky Bai #define DENALI_CTL_00			U(0x0)
37478af8d3SJacky Bai #define DENALI_CTL_23			U(0x5c)
38478af8d3SJacky Bai #define DFIBUS_FREQ_INIT_SHIFT		U(24)
39478af8d3SJacky Bai #define TSREF2PHYMSTR_SHIFT		U(8)
40478af8d3SJacky Bai #define TSREF2PHYMSTR_MASK		GENMASK(13, 8)
41478af8d3SJacky Bai 
42478af8d3SJacky Bai #define DENALI_CTL_24			U(0x60)
43478af8d3SJacky Bai #define DENALI_CTL_25			U(0x64)
44478af8d3SJacky Bai 
45478af8d3SJacky Bai #define DENALI_CTL_93			U(0x174)
46478af8d3SJacky Bai #define PWRUP_SREFRESH_EXIT		BIT(0)
47478af8d3SJacky Bai 
48478af8d3SJacky Bai #define DENALI_CTL_127				U(0x1fc)
49478af8d3SJacky Bai #define PHYMSTR_TRAIN_AFTER_INIT_COMPLETE	BIT(16)
50478af8d3SJacky Bai 
51478af8d3SJacky Bai #define DENALI_CTL_147			U(0x24c)
52478af8d3SJacky Bai #define DENALI_CTL_153			U(0x264)
53478af8d3SJacky Bai #define PCPCS_PD_EN			BIT(8)
54478af8d3SJacky Bai 
55478af8d3SJacky Bai #define DENALI_CTL_249			U(0x3E4)
56478af8d3SJacky Bai #define DENALI_CTL_266			U(0x428)
57478af8d3SJacky Bai 
58478af8d3SJacky Bai #define DENALI_PHY_1547			U(0x582c)
59478af8d3SJacky Bai #define PHY_LP4_BOOT_DISABLE		BIT(8)
60478af8d3SJacky Bai 
61478af8d3SJacky Bai #define DENALI_PHY_1559			U(0x585c)
62478af8d3SJacky Bai #define DENALI_PHY_1590			U(0x58D8)
63478af8d3SJacky Bai 
64478af8d3SJacky Bai #define DENALI_PI_00			U(0x2000)
65478af8d3SJacky Bai #define DENALI_PI_04			U(0x2010)
66478af8d3SJacky Bai #define DENALI_PI_52			U(0x20D0)
67478af8d3SJacky Bai #define DENALI_PI_26			U(0x2068)
68478af8d3SJacky Bai #define DENALI_PI_33			U(0x2084)
69478af8d3SJacky Bai #define DENALI_PI_65			U(0x2104)
70478af8d3SJacky Bai #define DENALI_PI_77			U(0x2134)
71478af8d3SJacky Bai #define DENALI_PI_134			U(0x2218)
72478af8d3SJacky Bai #define DENALI_PI_131			U(0x220C)
73478af8d3SJacky Bai #define DENALI_PI_132			U(0x2210)
74478af8d3SJacky Bai #define DENALI_PI_134			U(0x2218)
75478af8d3SJacky Bai #define DENALI_PI_137			U(0x2224)
76478af8d3SJacky Bai #define DENALI_PI_174			U(0x22B8)
77478af8d3SJacky Bai #define DENALI_PI_175			U(0x22BC)
78478af8d3SJacky Bai #define DENALI_PI_181			U(0x22D4)
79478af8d3SJacky Bai #define DENALI_PI_182			U(0x22D8)
80478af8d3SJacky Bai #define DENALI_PI_191			U(0x22FC)
81478af8d3SJacky Bai #define DENALI_PI_192			U(0x2300)
82478af8d3SJacky Bai #define DENALI_PI_212			U(0x2350)
83478af8d3SJacky Bai #define DENALI_PI_214			U(0x2358)
84478af8d3SJacky Bai #define DENALI_PI_217			U(0x2364)
85478af8d3SJacky Bai 
86478af8d3SJacky Bai #define LPDDR3_TYPE	U(0x7)
87478af8d3SJacky Bai #define LPDDR4_TYPE	U(0xB)
88478af8d3SJacky Bai 
89478af8d3SJacky Bai extern void upower_wait_resp(void);
90478af8d3SJacky Bai 
91478af8d3SJacky Bai struct dram_cfg_param {
92478af8d3SJacky Bai 	uint32_t reg;
93478af8d3SJacky Bai 	uint32_t val;
94478af8d3SJacky Bai };
95478af8d3SJacky Bai 
96478af8d3SJacky Bai struct dram_timing_info {
97478af8d3SJacky Bai 	/* ddr controller config */
98478af8d3SJacky Bai 	struct dram_cfg_param *ctl_cfg;
99478af8d3SJacky Bai 	unsigned int ctl_cfg_num;
100478af8d3SJacky Bai 	/* pi config */
101478af8d3SJacky Bai 	struct dram_cfg_param *pi_cfg;
102478af8d3SJacky Bai 	unsigned int pi_cfg_num;
103478af8d3SJacky Bai 	/* phy freq1 config */
104478af8d3SJacky Bai 	struct dram_cfg_param *phy_f1_cfg;
105478af8d3SJacky Bai 	unsigned int phy_f1_cfg_num;
106478af8d3SJacky Bai 	/* phy freq2 config */
107478af8d3SJacky Bai 	struct dram_cfg_param *phy_f2_cfg;
108478af8d3SJacky Bai 	unsigned int phy_f2_cfg_num;
109478af8d3SJacky Bai 	/* initialized drate table */
110478af8d3SJacky Bai 	unsigned int fsp_table[3];
111478af8d3SJacky Bai };
112478af8d3SJacky Bai 
113478af8d3SJacky Bai #define CTL_NUM		U(680)
114478af8d3SJacky Bai #define PI_NUM		U(298)
115478af8d3SJacky Bai #define PHY_NUM		U(1654)
116478af8d3SJacky Bai #define PHY_DIFF_NUM	U(49)
117478af8d3SJacky Bai struct dram_cfg {
118478af8d3SJacky Bai 	uint32_t ctl_cfg[CTL_NUM];
119478af8d3SJacky Bai 	uint32_t pi_cfg[PI_NUM];
120478af8d3SJacky Bai 	uint32_t phy_full[PHY_NUM];
121478af8d3SJacky Bai 	uint32_t phy_diff[PHY_DIFF_NUM];
122478af8d3SJacky Bai };
123478af8d3SJacky Bai 
124478af8d3SJacky Bai struct dram_timing_info *info;
125478af8d3SJacky Bai struct dram_cfg *dram_timing_cfg;
126478af8d3SJacky Bai 
127478af8d3SJacky Bai /* mark if dram cfg is already saved */
128478af8d3SJacky Bai static bool dram_cfg_saved;
129478af8d3SJacky Bai static uint32_t dram_class;
130478af8d3SJacky Bai 
131478af8d3SJacky Bai /* PHY register index for frequency diff */
132478af8d3SJacky Bai uint32_t freq_specific_reg_array[PHY_DIFF_NUM] = {
133478af8d3SJacky Bai 90, 92, 93, 96, 97, 100, 101, 102, 103, 104, 114,
134478af8d3SJacky Bai 346, 348, 349, 352, 353, 356, 357, 358, 359, 360,
135478af8d3SJacky Bai 370, 602, 604, 605, 608, 609, 612, 613, 614, 615,
136478af8d3SJacky Bai 616, 626, 858, 860, 861, 864, 865, 868, 869, 870,
137478af8d3SJacky Bai 871, 872, 882, 1063, 1319, 1566, 1624, 1625
138478af8d3SJacky Bai };
139478af8d3SJacky Bai 
140caee2733SJacky Bai /* lock used for DDR DVFS */
141caee2733SJacky Bai spinlock_t dfs_lock;
142caee2733SJacky Bai static volatile uint32_t core_count;
143caee2733SJacky Bai static volatile bool in_progress;
144*416c4433SJacky Bai static volatile bool sys_dvfs;
145caee2733SJacky Bai static int num_fsp;
146caee2733SJacky Bai 
147478af8d3SJacky Bai static void ddr_init(void)
148478af8d3SJacky Bai {
149478af8d3SJacky Bai 	unsigned int i;
150478af8d3SJacky Bai 
151478af8d3SJacky Bai 	/* restore the ddr ctl config */
152478af8d3SJacky Bai 	for (i = 0U; i < CTL_NUM; i++) {
153478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + i * 4, dram_timing_cfg->ctl_cfg[i]);
154478af8d3SJacky Bai 	}
155478af8d3SJacky Bai 
156478af8d3SJacky Bai 	/* load the PI registers */
157478af8d3SJacky Bai 	for (i = 0U; i < PI_NUM; i++) {
158478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + 0x2000 + i * 4, dram_timing_cfg->pi_cfg[i]);
159478af8d3SJacky Bai 	}
160478af8d3SJacky Bai 
161478af8d3SJacky Bai 
162478af8d3SJacky Bai 	 /* restore all PHY registers for all the fsp. */
163478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x100);
164478af8d3SJacky Bai 	/* restore all the phy configs */
165478af8d3SJacky Bai 	for (i = 0U; i < PHY_NUM; i++) {
166478af8d3SJacky Bai 		/* skip the reserved registers space */
167478af8d3SJacky Bai 		if (i >= 121U && i <= 255U) {
168478af8d3SJacky Bai 			continue;
169478af8d3SJacky Bai 		}
170478af8d3SJacky Bai 		if (i >= 377U && i <= 511U) {
171478af8d3SJacky Bai 			continue;
172478af8d3SJacky Bai 		}
173478af8d3SJacky Bai 		if (i >= 633U && i <= 767U) {
174478af8d3SJacky Bai 			continue;
175478af8d3SJacky Bai 		}
176478af8d3SJacky Bai 		if (i >= 889U && i <= 1023U) {
177478af8d3SJacky Bai 			continue;
178478af8d3SJacky Bai 		}
179478af8d3SJacky Bai 		if (i >= 1065U && i <= 1279U) {
180478af8d3SJacky Bai 			continue;
181478af8d3SJacky Bai 		}
182478af8d3SJacky Bai 		if (i >= 1321U && i <= 1535U) {
183478af8d3SJacky Bai 			continue;
184478af8d3SJacky Bai 		}
185478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + 0x4000 + i * 4, dram_timing_cfg->phy_full[i]);
186478af8d3SJacky Bai 	}
187478af8d3SJacky Bai 
188478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
189478af8d3SJacky Bai 		/* restore only the diff. */
190478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
191478af8d3SJacky Bai 		for (i = 0U; i < PHY_DIFF_NUM; i++) {
192478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + 0x4000 + freq_specific_reg_array[i] * 4,
193478af8d3SJacky Bai 				      dram_timing_cfg->phy_diff[i]);
194478af8d3SJacky Bai 		}
195478af8d3SJacky Bai 	}
196478af8d3SJacky Bai 
197478af8d3SJacky Bai 	/* Re-enable MULTICAST mode */
198478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, PHY_FREQ_MULTICAST_EN(1));
199478af8d3SJacky Bai }
200478af8d3SJacky Bai 
201478af8d3SJacky Bai void dram_enter_retention(void)
202478af8d3SJacky Bai {
203478af8d3SJacky Bai 	unsigned int i;
204478af8d3SJacky Bai 
205478af8d3SJacky Bai 	/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
206478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
207478af8d3SJacky Bai 
208478af8d3SJacky Bai 	/*
209478af8d3SJacky Bai 	 * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
210478af8d3SJacky Bai 	 * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
211478af8d3SJacky Bai 	 * long with mem and ctlr clk gating or self-refresh  power-down
212478af8d3SJacky Bai 	 * long with mem and ctlr clk gating'
213478af8d3SJacky Bai 	 */
214478af8d3SJacky Bai 	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
215478af8d3SJacky Bai 
216478af8d3SJacky Bai 	/*
217478af8d3SJacky Bai 	 * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
218478af8d3SJacky Bai 	 * the logic to automatic handles low power entry/exit. This is the recommended
219478af8d3SJacky Bai 	 * option over handling through software.
220478af8d3SJacky Bai 	 * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
221478af8d3SJacky Bai 	 * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
222478af8d3SJacky Bai 	 * since LPPDR logic will be power gated).
223478af8d3SJacky Bai 	 */
224478af8d3SJacky Bai 	mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
225478af8d3SJacky Bai 	mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
226478af8d3SJacky Bai 			   0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
227478af8d3SJacky Bai 
228478af8d3SJacky Bai 	/* Save DDR Controller & PHY config.
229478af8d3SJacky Bai 	 * Set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=1. Read and store all
230478af8d3SJacky Bai 	 * the PHY registers for F2 into phy_f1_cfg, then read/store the diff between
231478af8d3SJacky Bai 	 * F1 & F2 into phy_f2_cfg.
232478af8d3SJacky Bai 	 */
233478af8d3SJacky Bai 	if (!dram_cfg_saved) {
234478af8d3SJacky Bai 		info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
235478af8d3SJacky Bai 		dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
236478af8d3SJacky Bai 					sizeof(struct dram_timing_info));
237478af8d3SJacky Bai 
238478af8d3SJacky Bai 		/* get the dram type */
239478af8d3SJacky Bai 		dram_class = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_00);
240478af8d3SJacky Bai 		dram_class = (dram_class >> 8) & 0xf;
241478af8d3SJacky Bai 
242478af8d3SJacky Bai 		/* save the ctl registers */
243478af8d3SJacky Bai 		for (i = 0U; i < CTL_NUM; i++) {
244478af8d3SJacky Bai 			dram_timing_cfg->ctl_cfg[i] = mmio_read_32(IMX_DDRC_BASE + i * 4);
245478af8d3SJacky Bai 		}
246478af8d3SJacky Bai 		dram_timing_cfg->ctl_cfg[0] = dram_timing_cfg->ctl_cfg[0] & 0xFFFFFFFE;
247478af8d3SJacky Bai 
248478af8d3SJacky Bai 		/* save the PI registers */
249478af8d3SJacky Bai 		for (i = 0U; i < PI_NUM; i++) {
250478af8d3SJacky Bai 			dram_timing_cfg->pi_cfg[i] = mmio_read_32(IMX_DDRC_BASE + 0x2000 + i * 4);
251478af8d3SJacky Bai 		}
252478af8d3SJacky Bai 		dram_timing_cfg->pi_cfg[0] = dram_timing_cfg->pi_cfg[0] & 0xFFFFFFFE;
253478af8d3SJacky Bai 
254478af8d3SJacky Bai 		/*
255478af8d3SJacky Bai 		 * Read and store all PHY registers. full array is a full
256478af8d3SJacky Bai 		 * copy for all the setpoint
257478af8d3SJacky Bai 		 */
258478af8d3SJacky Bai 		if (dram_class == LPDDR4_TYPE) {
259478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x10000);
260478af8d3SJacky Bai 			for (i = 0U; i < PHY_NUM; i++) {
261478af8d3SJacky Bai 				/* Make sure MULTICASE is enabled */
262478af8d3SJacky Bai 				if (i == 1537U) {
263478af8d3SJacky Bai 					dram_timing_cfg->phy_full[i] = 0x100;
264478af8d3SJacky Bai 				} else {
265478af8d3SJacky Bai 					dram_timing_cfg->phy_full[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + i * 4);
266478af8d3SJacky Bai 				}
267478af8d3SJacky Bai 			}
268478af8d3SJacky Bai 
269478af8d3SJacky Bai 			/*
270478af8d3SJacky Bai 			 * set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=0.
271478af8d3SJacky Bai 			 * Read and store only the diff.
272478af8d3SJacky Bai 			 */
273478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
274478af8d3SJacky Bai 			/* save only the frequency based diff config to save memory */
275478af8d3SJacky Bai 			for (i = 0U; i < PHY_DIFF_NUM; i++) {
276478af8d3SJacky Bai 				dram_timing_cfg->phy_diff[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 +
277478af8d3SJacky Bai 									    freq_specific_reg_array[i] * 4);
278478af8d3SJacky Bai 			}
279478af8d3SJacky Bai 		} else {
280478af8d3SJacky Bai 			/* LPDDR3, only f1 need to save */
281478af8d3SJacky Bai 			for (i = 0U; i < info->phy_f1_cfg_num; i++) {
282478af8d3SJacky Bai 				info->phy_f1_cfg[i].val = mmio_read_32(info->phy_f1_cfg[i].reg);
283478af8d3SJacky Bai 			}
284478af8d3SJacky Bai 		}
285478af8d3SJacky Bai 
286478af8d3SJacky Bai 		dram_cfg_saved = true;
287478af8d3SJacky Bai 	}
288478af8d3SJacky Bai }
289478af8d3SJacky Bai 
290478af8d3SJacky Bai void dram_exit_retention(void)
291478af8d3SJacky Bai {
292478af8d3SJacky Bai 	uint32_t val;
293478af8d3SJacky Bai 
294478af8d3SJacky Bai 	/* 1. Config the LPAV PLL4 and DDR clock for the desired LPDDR operating frequency. */
295478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
296478af8d3SJacky Bai 
297478af8d3SJacky Bai 	/* 2. Write PCC5.PCC_LPDDR4[SWRST] to 1b'1 to release LPDDR from reset. */
298478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(28));
299478af8d3SJacky Bai 
300478af8d3SJacky Bai 	/* 3. Reload the LPDDR CTL/PI/PHY register */
301478af8d3SJacky Bai 	ddr_init();
302478af8d3SJacky Bai 
303478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
304478af8d3SJacky Bai 		/* 4a. FIXME Set PHY_SET_DFI_INPUT_N parameters to 4'h1. LPDDR4 only */
305478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1559, 0x01010101);
306478af8d3SJacky Bai 
307478af8d3SJacky Bai 		/*
308478af8d3SJacky Bai 		 * 4b. CTL PWRUP_SREFRESH_EXIT=1'b0 for disabling self refresh exit
309478af8d3SJacky Bai 		 * from controller.
310478af8d3SJacky Bai 		 */
311478af8d3SJacky Bai 		/*
312478af8d3SJacky Bai 		 * 4c. PI_PWRUP_SELF_REF_EXIT=1, PI_MC_PWRUP_SELF_REF_EXIT=0 for enabling
313478af8d3SJacky Bai 		 * self refresh exit from PI
314478af8d3SJacky Bai 		 */
315478af8d3SJacky Bai 		/* 4c. PI_INT_LVL_EN=0 to skip Initialization trainings. */
316478af8d3SJacky Bai 		/*
317478af8d3SJacky Bai 		 * 4d. PI_WRLVL_EN_F0/1/2= PI_CALVL_EN_F0/1/2= PI_RDLVL_EN_F0/1/2=
318478af8d3SJacky Bai 		 * PI_RDLVL_GATE_EN_F0/1/2= PI_WDQLVL_EN_F0/1/2=0x2.
319478af8d3SJacky Bai 		 * Enable non initialization trainings.
320478af8d3SJacky Bai 		 */
321478af8d3SJacky Bai 		/* 4e. PI_PWRUP_SREFRESH_EXIT_CS=0xF */
322478af8d3SJacky Bai 		/* 4f. PI_DLL_RESET=0x1 */
323478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
324478af8d3SJacky Bai 		/* PI_PWRUP_SELF_REF_EXIT = 1 */
325478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
326478af8d3SJacky Bai 		/* PI_MC_PWRUP_SELF_REF_EXIT = 0 */
327478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
328478af8d3SJacky Bai 		/* PI_INT_LVL_EN = 0 */
329478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
330478af8d3SJacky Bai 		/* PI_WRLVL_EN_F0 = 3, PI_WRLVL_EN_F1 = 3 */
331478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x03030000);
332478af8d3SJacky Bai 		/* PI_WRLVL_EN_F2 = 3 */
333478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_175, 0x03);
334478af8d3SJacky Bai 		/* PI_CALVL_EN_F0 = 3, PI_CALVL_EN_F1 = 3 */
335478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x03030000);
336478af8d3SJacky Bai 		/* PI_CALVL_EN_F2 = 3 */
337478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_192, 0x03);
338478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F0 = 3 */
339478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_212, 0x300);
340478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F1 = 3 */
341478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_214, 0x03000000);
342478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F2 = 3 */
343478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_217, 0x300);
344478af8d3SJacky Bai 		/* PI_EDLVL_EN_F0 = 3, PI_EDLVL_GATE_EN_F0 = 3 */
345478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
346478af8d3SJacky Bai 		/*
347478af8d3SJacky Bai 		 * PI_RDLVL_EN_F1 = 3, PI_RDLVL_GATE_EN_F1 = 3,
348478af8d3SJacky Bai 		 * PI_RDLVL_EN_F2 = 3, PI_RDLVL_GATE_EN_F2 = 3
349478af8d3SJacky Bai 		 */
350478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_182, 0x03030303);
351478af8d3SJacky Bai 		/* PI_PWRUP_SREFRESH_EXIT_CS = 0xF */
352478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
353478af8d3SJacky Bai 	} else {
354478af8d3SJacky Bai 		/* PI_DLL_RESET=1 */
355478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
356478af8d3SJacky Bai 		/* PI_PWRUP_SELF_REF_EXIT=1 */
357478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
358478af8d3SJacky Bai 		/* PI_MC_PWRUP_SELF_REF_EXIT=0 */
359478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
360478af8d3SJacky Bai 		/* PI_INT_LVL_EN=0 */
361478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
362478af8d3SJacky Bai 		/* PI_WRLVL_EN_F0=3 */
363478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x00030000);
364478af8d3SJacky Bai 		/* PI_CALVL_EN_F0=3 */
365478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x00030000);
366478af8d3SJacky Bai 		/* PI_RDLVL_EN_F0=3,PI_RDLVL_GATE_EN_F0=3 */
367478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
368478af8d3SJacky Bai 		/* PI_PWRUP_SREFRESH_EXIT_CS=0xF */
369478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
370478af8d3SJacky Bai 	}
371478af8d3SJacky Bai 
372478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x00002D00);
373478af8d3SJacky Bai 
374478af8d3SJacky Bai 	/* Force in-order AXI read data */
375478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x1);
376478af8d3SJacky Bai 
377478af8d3SJacky Bai 	/*
378478af8d3SJacky Bai 	 * Disable special R/W group switches so that R/W group placement
379478af8d3SJacky Bai 	 * is always at END of R/W group.
380478af8d3SJacky Bai 	 */
381478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_249, 0x0);
382478af8d3SJacky Bai 
383478af8d3SJacky Bai 	/* Reduce time for IO pad calibration */
384478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1590, 0x01000000);
385478af8d3SJacky Bai 
386478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_25, 0x00020100);
387478af8d3SJacky Bai 
388478af8d3SJacky Bai 	/* PD disable */
389478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_153, 0x04040000);
390478af8d3SJacky Bai 	/*
391478af8d3SJacky Bai 	 * 5. Disable automatic LP entry and PCPCS modes LP_AUTO_ENTRY_EN
392478af8d3SJacky Bai 	 * to 1b'0, PCPCS_PD_EN to 1b'0
393478af8d3SJacky Bai 	 */
394478af8d3SJacky Bai 
395478af8d3SJacky Bai 	upwr_xcp_set_ddr_retention(APD_DOMAIN, 0, NULL);
396478af8d3SJacky Bai 	upower_wait_resp();
397478af8d3SJacky Bai 
398478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
399478af8d3SJacky Bai 		/* 7. Write PI START parameter to 1'b1 */
400478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000b01);
401478af8d3SJacky Bai 
402478af8d3SJacky Bai 		/* 8. Write CTL START parameter to 1'b1 */
403478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000b01);
404478af8d3SJacky Bai 	} else {
405478af8d3SJacky Bai 		/* 7. Write PI START parameter to 1'b1 */
406478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000701);
407478af8d3SJacky Bai 
408478af8d3SJacky Bai 		/* 8. Write CTL START parameter to 1'b1 */
409478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000701);
410478af8d3SJacky Bai 	}
411478af8d3SJacky Bai 
412478af8d3SJacky Bai 	/* 9. DENALI_CTL_266:  Wait for INT_STATUS_INIT=0x2 */
413478af8d3SJacky Bai 	do {
414478af8d3SJacky Bai 		val = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_266) >> 8) & 0xFF;
415478af8d3SJacky Bai 	} while (val != 0x2);
416478af8d3SJacky Bai 
417478af8d3SJacky Bai 	/*
418478af8d3SJacky Bai 	 * 10. Run SW trainings by setting PI_CALVL_REQ,PI_WRLVL_REQ,PI_RDLVL_GATE_REQ,
419478af8d3SJacky Bai 	 * PI_RDLVL_REQ,PI_WDQLVL_REQ(NA for LPDDR3) in same order.
420478af8d3SJacky Bai 	 */
421478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
422478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
423478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
424478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
425478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
426478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_65, 0x10000); /* WDQLVL */
427478af8d3SJacky Bai 
428478af8d3SJacky Bai 		/* 11. Wait for trainings to get complete by polling PI_INT_STATUS */
429478af8d3SJacky Bai 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x07E00000) != 0x07E00000) {
430478af8d3SJacky Bai 			;
431478af8d3SJacky Bai 		}
432478af8d3SJacky Bai 	} else {
433478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
434478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
435478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
436478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
437478af8d3SJacky Bai 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x05E00000) != 0x05E00000) {
438478af8d3SJacky Bai 			;
439478af8d3SJacky Bai 		}
440478af8d3SJacky Bai 	}
441478af8d3SJacky Bai }
442caee2733SJacky Bai 
443caee2733SJacky Bai #define LPDDR_DONE       (0x1<<4)
444caee2733SJacky Bai #define SOC_FREQ_CHG_ACK (0x1<<6)
445caee2733SJacky Bai #define SOC_FREQ_CHG_REQ (0x1<<7)
446caee2733SJacky Bai #define LPI_WAKEUP_EN    (0x4<<8)
447caee2733SJacky Bai #define SOC_FREQ_REQ     (0x1<<11)
448caee2733SJacky Bai 
449caee2733SJacky Bai #define LPDDR_EN_CLKGATE (0x1<<17)
450caee2733SJacky Bai 
451caee2733SJacky Bai static void set_cgc2_ddrclk(uint8_t src, uint8_t div)
452caee2733SJacky Bai {
453caee2733SJacky Bai 
454caee2733SJacky Bai 	/* Wait until the reg is unlocked for writing */
455caee2733SJacky Bai 	while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31))
456caee2733SJacky Bai 		;
457caee2733SJacky Bai 
458caee2733SJacky Bai 	mmio_write_32(IMX_CGC2_BASE + 0x40, (src << 28) | (div << 21));
459caee2733SJacky Bai 	/* Wait for the clock switching done */
460caee2733SJacky Bai 	while (!(mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(27)))
461caee2733SJacky Bai 		;
462caee2733SJacky Bai }
463caee2733SJacky Bai static void set_ddr_clk(uint32_t ddr_freq)
464caee2733SJacky Bai {
465caee2733SJacky Bai 	/* Disable DDR clock */
466caee2733SJacky Bai 	mmio_clrbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
467caee2733SJacky Bai 	switch (ddr_freq) {
468caee2733SJacky Bai 	/* boot frequency ? */
469caee2733SJacky Bai 	case 48:
470caee2733SJacky Bai 		set_cgc2_ddrclk(2, 0);
471caee2733SJacky Bai 		break;
472caee2733SJacky Bai 	/* default bypass frequency for fsp 1 */
473caee2733SJacky Bai 	case 192:
474caee2733SJacky Bai 		set_cgc2_ddrclk(0, 1);
475caee2733SJacky Bai 		break;
476caee2733SJacky Bai 	case 384:
477caee2733SJacky Bai 		set_cgc2_ddrclk(0, 0);
478caee2733SJacky Bai 		break;
479caee2733SJacky Bai 	case 264:
480caee2733SJacky Bai 		set_cgc2_ddrclk(4, 3);
481caee2733SJacky Bai 		break;
482caee2733SJacky Bai 	case 528:
483caee2733SJacky Bai 		set_cgc2_ddrclk(4, 1);
484caee2733SJacky Bai 		break;
485caee2733SJacky Bai 	default:
486caee2733SJacky Bai 		break;
487caee2733SJacky Bai 	}
488caee2733SJacky Bai 	/* Enable DDR clock */
489caee2733SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
490caee2733SJacky Bai 
491caee2733SJacky Bai 	/* Wait until the reg is unlocked for writing */
492caee2733SJacky Bai 	while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31)) {
493caee2733SJacky Bai 		;
494caee2733SJacky Bai 	}
495caee2733SJacky Bai }
496caee2733SJacky Bai 
497caee2733SJacky Bai #define AVD_SIM_LPDDR_CTRL	(IMX_LPAV_SIM_BASE + 0x14)
498caee2733SJacky Bai #define AVD_SIM_LPDDR_CTRL2	(IMX_LPAV_SIM_BASE + 0x18)
499caee2733SJacky Bai #define MAX_FSP_NUM	U(3)
500caee2733SJacky Bai #define DDR_DFS_GET_FSP_COUNT	0x10
501caee2733SJacky Bai #define DDR_BYPASS_DRATE	U(400)
502caee2733SJacky Bai 
503*416c4433SJacky Bai extern int upower_pmic_i2c_write(uint32_t reg_addr, uint32_t reg_val);
504*416c4433SJacky Bai 
505caee2733SJacky Bai /* Normally, we only switch frequency between 1(bypass) and 2(highest) */
506caee2733SJacky Bai int lpddr4_dfs(uint32_t freq_index)
507caee2733SJacky Bai {
508caee2733SJacky Bai 	uint32_t lpddr_ctrl, lpddr_ctrl2;
509caee2733SJacky Bai 	uint32_t ddr_ctl_144;
510caee2733SJacky Bai 
511caee2733SJacky Bai 	/*
512caee2733SJacky Bai 	 * Valid index: 0 to 2
513caee2733SJacky Bai 	 * index 0: boot frequency
514caee2733SJacky Bai 	 * index 1: bypass frequency
515caee2733SJacky Bai 	 * index 2: highest frequency
516caee2733SJacky Bai 	 */
517caee2733SJacky Bai 	if (freq_index > 2U) {
518caee2733SJacky Bai 		return -1;
519caee2733SJacky Bai 	}
520caee2733SJacky Bai 
521*416c4433SJacky Bai 	/*
522*416c4433SJacky Bai 	 * increase the voltage to 1.1V firstly before increase frequency
523*416c4433SJacky Bai 	 * and APD enter OD mode
524*416c4433SJacky Bai 	 */
525*416c4433SJacky Bai 	if (freq_index == 2U && sys_dvfs) {
526*416c4433SJacky Bai 		upower_pmic_i2c_write(0x22, 0x28);
527*416c4433SJacky Bai 	}
528*416c4433SJacky Bai 
529caee2733SJacky Bai 	/* Enable LPI_WAKEUP_EN */
530caee2733SJacky Bai 	ddr_ctl_144 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144);
531caee2733SJacky Bai 	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, LPI_WAKEUP_EN);
532caee2733SJacky Bai 
533caee2733SJacky Bai 	/* put DRAM into long self-refresh & clock gating */
534caee2733SJacky Bai 	lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL);
535caee2733SJacky Bai 	lpddr_ctrl = (lpddr_ctrl & ~((0x3f << 15) | (0x3 << 9))) | (0x28 << 15) | (freq_index << 9);
536caee2733SJacky Bai 	mmio_write_32(AVD_SIM_LPDDR_CTRL, lpddr_ctrl);
537caee2733SJacky Bai 
538caee2733SJacky Bai 	/* Gating the clock */
539caee2733SJacky Bai 	lpddr_ctrl2 = mmio_read_32(AVD_SIM_LPDDR_CTRL2);
540caee2733SJacky Bai 	mmio_setbits_32(AVD_SIM_LPDDR_CTRL2, LPDDR_EN_CLKGATE);
541caee2733SJacky Bai 
542caee2733SJacky Bai 	/* Request frequency change */
543caee2733SJacky Bai 	mmio_setbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_REQ);
544caee2733SJacky Bai 
545caee2733SJacky Bai 	do {
546caee2733SJacky Bai 		lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL);
547caee2733SJacky Bai 		if (lpddr_ctrl & SOC_FREQ_CHG_REQ) {
548caee2733SJacky Bai 			/* Bypass mode */
549caee2733SJacky Bai 			if (info->fsp_table[freq_index] < DDR_BYPASS_DRATE) {
550caee2733SJacky Bai 				/* Change to PLL bypass mode */
551caee2733SJacky Bai 				mmio_write_32(IMX_LPAV_SIM_BASE, 0x1);
552caee2733SJacky Bai 				/* change the ddr clock source & frequency */
553caee2733SJacky Bai 				set_ddr_clk(info->fsp_table[freq_index]);
554caee2733SJacky Bai 			} else {
555caee2733SJacky Bai 				/* Change to PLL unbypass mode */
556caee2733SJacky Bai 				mmio_write_32(IMX_LPAV_SIM_BASE, 0x0);
557caee2733SJacky Bai 				/* change the ddr clock source & frequency */
558caee2733SJacky Bai 				set_ddr_clk(info->fsp_table[freq_index] >> 1);
559caee2733SJacky Bai 			}
560caee2733SJacky Bai 
561caee2733SJacky Bai 			mmio_clrsetbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_CHG_REQ, SOC_FREQ_CHG_ACK);
562caee2733SJacky Bai 			continue;
563caee2733SJacky Bai 		}
564caee2733SJacky Bai 	} while ((lpddr_ctrl & LPDDR_DONE) != 0); /* several try? */
565caee2733SJacky Bai 
566caee2733SJacky Bai 	/* restore the original setting */
567caee2733SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, ddr_ctl_144);
568caee2733SJacky Bai 	mmio_write_32(AVD_SIM_LPDDR_CTRL2, lpddr_ctrl2);
569caee2733SJacky Bai 
570caee2733SJacky Bai 	/* Check the DFS result */
571caee2733SJacky Bai 	lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL) & 0xF;
572caee2733SJacky Bai 	if (lpddr_ctrl != 0U) {
573caee2733SJacky Bai 		/* Must be something wrong, return failure */
574caee2733SJacky Bai 		return -1;
575caee2733SJacky Bai 	}
576caee2733SJacky Bai 
577*416c4433SJacky Bai 	/* decrease the BUCK3 voltage after frequency changed to lower
578*416c4433SJacky Bai 	 * and APD in ND_MODE
579*416c4433SJacky Bai 	 */
580*416c4433SJacky Bai 	if (freq_index == 1U && sys_dvfs) {
581*416c4433SJacky Bai 		upower_pmic_i2c_write(0x22, 0x20);
582*416c4433SJacky Bai 	}
583*416c4433SJacky Bai 
584caee2733SJacky Bai 	/* DFS done successfully */
585caee2733SJacky Bai 	return 0;
586caee2733SJacky Bai }
587caee2733SJacky Bai 
588caee2733SJacky Bai /* for the non-primary core, waiting for DFS done */
589caee2733SJacky Bai static uint64_t waiting_dvfs(uint32_t id, uint32_t flags,
590caee2733SJacky Bai 		void *handle, void *cookie)
591caee2733SJacky Bai {
592caee2733SJacky Bai 	uint32_t irq;
593caee2733SJacky Bai 
594caee2733SJacky Bai 	irq = plat_ic_acknowledge_interrupt();
595caee2733SJacky Bai 	if (irq < 1022U) {
596caee2733SJacky Bai 		plat_ic_end_of_interrupt(irq);
597caee2733SJacky Bai 	}
598caee2733SJacky Bai 
599caee2733SJacky Bai 	/* set the WFE done status */
600caee2733SJacky Bai 	spin_lock(&dfs_lock);
601caee2733SJacky Bai 	core_count++;
602caee2733SJacky Bai 	dsb();
603caee2733SJacky Bai 	spin_unlock(&dfs_lock);
604caee2733SJacky Bai 
605caee2733SJacky Bai 	while (in_progress) {
606caee2733SJacky Bai 		wfe();
607caee2733SJacky Bai 	}
608caee2733SJacky Bai 
609caee2733SJacky Bai 	return 0;
610caee2733SJacky Bai }
611caee2733SJacky Bai 
612caee2733SJacky Bai int dram_dvfs_handler(uint32_t smc_fid, void *handle,
613caee2733SJacky Bai 		u_register_t x1, u_register_t x2, u_register_t x3)
614caee2733SJacky Bai {
615caee2733SJacky Bai 	unsigned int fsp_index = x1;
616caee2733SJacky Bai 	uint32_t online_cpus = x2 - 1;
617caee2733SJacky Bai 	uint64_t mpidr = read_mpidr_el1();
618caee2733SJacky Bai 	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
619caee2733SJacky Bai 
620caee2733SJacky Bai 	/* Get the number of FSPs */
621caee2733SJacky Bai 	if (x1 == DDR_DFS_GET_FSP_COUNT) {
622caee2733SJacky Bai 		SMC_RET2(handle, num_fsp, info->fsp_table[1]);
623caee2733SJacky Bai 	}
624caee2733SJacky Bai 
625caee2733SJacky Bai 	/* start lpddr frequency scaling */
626caee2733SJacky Bai 	in_progress = true;
627*416c4433SJacky Bai 	sys_dvfs = x3 ? true : false;
628caee2733SJacky Bai 	dsb();
629caee2733SJacky Bai 
630caee2733SJacky Bai 	/* notify other core wait for scaling done */
631caee2733SJacky Bai 	for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++)
632caee2733SJacky Bai 		/* Skip raise SGI for current CPU */
633caee2733SJacky Bai 		if (i != cpu_id) {
634caee2733SJacky Bai 			plat_ic_raise_el3_sgi(0x8, i);
635caee2733SJacky Bai 		}
636caee2733SJacky Bai 
637caee2733SJacky Bai 	/* Make sure all the cpu in WFE */
638caee2733SJacky Bai 	while (online_cpus != core_count) {
639caee2733SJacky Bai 		;
640caee2733SJacky Bai 	}
641caee2733SJacky Bai 
642caee2733SJacky Bai 	/* Flush the L1/L2 cache */
643caee2733SJacky Bai 	dcsw_op_all(DCCSW);
644caee2733SJacky Bai 
645caee2733SJacky Bai 	lpddr4_dfs(fsp_index);
646caee2733SJacky Bai 
647caee2733SJacky Bai 	in_progress = false;
648caee2733SJacky Bai 	core_count = 0;
649caee2733SJacky Bai 	dsb();
650caee2733SJacky Bai 	sev();
651caee2733SJacky Bai 	isb();
652caee2733SJacky Bai 
653caee2733SJacky Bai 	SMC_RET1(handle, 0);
654caee2733SJacky Bai }
655caee2733SJacky Bai 
656caee2733SJacky Bai void dram_init(void)
657caee2733SJacky Bai {
658caee2733SJacky Bai 	uint32_t flags = 0;
659caee2733SJacky Bai 	uint32_t rc;
660caee2733SJacky Bai 	unsigned int i;
661caee2733SJacky Bai 
662caee2733SJacky Bai 	/* Register the EL3 handler for DDR DVFS */
663caee2733SJacky Bai 	set_interrupt_rm_flag(flags, NON_SECURE);
664caee2733SJacky Bai 	rc = register_interrupt_type_handler(INTR_TYPE_EL3, waiting_dvfs, flags);
665caee2733SJacky Bai 	if (rc) {
666caee2733SJacky Bai 		panic();
667caee2733SJacky Bai 	}
668caee2733SJacky Bai 
669caee2733SJacky Bai 	info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
670caee2733SJacky Bai 
671caee2733SJacky Bai 	/* Get the num of the supported Fsp */
672caee2733SJacky Bai 	for (i = 0; i < MAX_FSP_NUM; i++) {
673caee2733SJacky Bai 		if (!info->fsp_table[i]) {
674caee2733SJacky Bai 			break;
675caee2733SJacky Bai 		}
676caee2733SJacky Bai 	}
677caee2733SJacky Bai 
678caee2733SJacky Bai 	num_fsp = (i > MAX_FSP_NUM) ? MAX_FSP_NUM : i;
679caee2733SJacky Bai }
680