xref: /rk3399_ARM-atf/plat/imx/imx8ulp/dram.c (revision caee2733ba4e7a09ea656b0be85f150a275cc57c)
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 
10*caee2733SJacky Bai #include <arch_helpers.h>
11*caee2733SJacky Bai #include <bl31/interrupt_mgmt.h>
12*caee2733SJacky Bai #include <common/runtime_svc.h>
13478af8d3SJacky Bai #include <lib/mmio.h>
14*caee2733SJacky Bai #include <lib/spinlock.h>
15*caee2733SJacky Bai #include <plat/common/platform.h>
16*caee2733SJacky Bai 
17478af8d3SJacky Bai #include <platform_def.h>
18478af8d3SJacky Bai 
19*caee2733SJacky 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 
140*caee2733SJacky Bai /* lock used for DDR DVFS */
141*caee2733SJacky Bai spinlock_t dfs_lock;
142*caee2733SJacky Bai static volatile uint32_t core_count;
143*caee2733SJacky Bai static volatile bool in_progress;
144*caee2733SJacky Bai static int num_fsp;
145*caee2733SJacky Bai 
146478af8d3SJacky Bai static void ddr_init(void)
147478af8d3SJacky Bai {
148478af8d3SJacky Bai 	unsigned int i;
149478af8d3SJacky Bai 
150478af8d3SJacky Bai 	/* restore the ddr ctl config */
151478af8d3SJacky Bai 	for (i = 0U; i < CTL_NUM; i++) {
152478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + i * 4, dram_timing_cfg->ctl_cfg[i]);
153478af8d3SJacky Bai 	}
154478af8d3SJacky Bai 
155478af8d3SJacky Bai 	/* load the PI registers */
156478af8d3SJacky Bai 	for (i = 0U; i < PI_NUM; i++) {
157478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + 0x2000 + i * 4, dram_timing_cfg->pi_cfg[i]);
158478af8d3SJacky Bai 	}
159478af8d3SJacky Bai 
160478af8d3SJacky Bai 
161478af8d3SJacky Bai 	 /* restore all PHY registers for all the fsp. */
162478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x100);
163478af8d3SJacky Bai 	/* restore all the phy configs */
164478af8d3SJacky Bai 	for (i = 0U; i < PHY_NUM; i++) {
165478af8d3SJacky Bai 		/* skip the reserved registers space */
166478af8d3SJacky Bai 		if (i >= 121U && i <= 255U) {
167478af8d3SJacky Bai 			continue;
168478af8d3SJacky Bai 		}
169478af8d3SJacky Bai 		if (i >= 377U && i <= 511U) {
170478af8d3SJacky Bai 			continue;
171478af8d3SJacky Bai 		}
172478af8d3SJacky Bai 		if (i >= 633U && i <= 767U) {
173478af8d3SJacky Bai 			continue;
174478af8d3SJacky Bai 		}
175478af8d3SJacky Bai 		if (i >= 889U && i <= 1023U) {
176478af8d3SJacky Bai 			continue;
177478af8d3SJacky Bai 		}
178478af8d3SJacky Bai 		if (i >= 1065U && i <= 1279U) {
179478af8d3SJacky Bai 			continue;
180478af8d3SJacky Bai 		}
181478af8d3SJacky Bai 		if (i >= 1321U && i <= 1535U) {
182478af8d3SJacky Bai 			continue;
183478af8d3SJacky Bai 		}
184478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + 0x4000 + i * 4, dram_timing_cfg->phy_full[i]);
185478af8d3SJacky Bai 	}
186478af8d3SJacky Bai 
187478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
188478af8d3SJacky Bai 		/* restore only the diff. */
189478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
190478af8d3SJacky Bai 		for (i = 0U; i < PHY_DIFF_NUM; i++) {
191478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + 0x4000 + freq_specific_reg_array[i] * 4,
192478af8d3SJacky Bai 				      dram_timing_cfg->phy_diff[i]);
193478af8d3SJacky Bai 		}
194478af8d3SJacky Bai 	}
195478af8d3SJacky Bai 
196478af8d3SJacky Bai 	/* Re-enable MULTICAST mode */
197478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, PHY_FREQ_MULTICAST_EN(1));
198478af8d3SJacky Bai }
199478af8d3SJacky Bai 
200478af8d3SJacky Bai void dram_enter_retention(void)
201478af8d3SJacky Bai {
202478af8d3SJacky Bai 	unsigned int i;
203478af8d3SJacky Bai 
204478af8d3SJacky Bai 	/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
205478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
206478af8d3SJacky Bai 
207478af8d3SJacky Bai 	/*
208478af8d3SJacky Bai 	 * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
209478af8d3SJacky Bai 	 * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
210478af8d3SJacky Bai 	 * long with mem and ctlr clk gating or self-refresh  power-down
211478af8d3SJacky Bai 	 * long with mem and ctlr clk gating'
212478af8d3SJacky Bai 	 */
213478af8d3SJacky Bai 	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
214478af8d3SJacky Bai 
215478af8d3SJacky Bai 	/*
216478af8d3SJacky Bai 	 * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
217478af8d3SJacky Bai 	 * the logic to automatic handles low power entry/exit. This is the recommended
218478af8d3SJacky Bai 	 * option over handling through software.
219478af8d3SJacky Bai 	 * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
220478af8d3SJacky Bai 	 * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
221478af8d3SJacky Bai 	 * since LPPDR logic will be power gated).
222478af8d3SJacky Bai 	 */
223478af8d3SJacky Bai 	mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
224478af8d3SJacky Bai 	mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
225478af8d3SJacky Bai 			   0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
226478af8d3SJacky Bai 
227478af8d3SJacky Bai 	/* Save DDR Controller & PHY config.
228478af8d3SJacky Bai 	 * Set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=1. Read and store all
229478af8d3SJacky Bai 	 * the PHY registers for F2 into phy_f1_cfg, then read/store the diff between
230478af8d3SJacky Bai 	 * F1 & F2 into phy_f2_cfg.
231478af8d3SJacky Bai 	 */
232478af8d3SJacky Bai 	if (!dram_cfg_saved) {
233478af8d3SJacky Bai 		info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
234478af8d3SJacky Bai 		dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
235478af8d3SJacky Bai 					sizeof(struct dram_timing_info));
236478af8d3SJacky Bai 
237478af8d3SJacky Bai 		/* get the dram type */
238478af8d3SJacky Bai 		dram_class = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_00);
239478af8d3SJacky Bai 		dram_class = (dram_class >> 8) & 0xf;
240478af8d3SJacky Bai 
241478af8d3SJacky Bai 		/* save the ctl registers */
242478af8d3SJacky Bai 		for (i = 0U; i < CTL_NUM; i++) {
243478af8d3SJacky Bai 			dram_timing_cfg->ctl_cfg[i] = mmio_read_32(IMX_DDRC_BASE + i * 4);
244478af8d3SJacky Bai 		}
245478af8d3SJacky Bai 		dram_timing_cfg->ctl_cfg[0] = dram_timing_cfg->ctl_cfg[0] & 0xFFFFFFFE;
246478af8d3SJacky Bai 
247478af8d3SJacky Bai 		/* save the PI registers */
248478af8d3SJacky Bai 		for (i = 0U; i < PI_NUM; i++) {
249478af8d3SJacky Bai 			dram_timing_cfg->pi_cfg[i] = mmio_read_32(IMX_DDRC_BASE + 0x2000 + i * 4);
250478af8d3SJacky Bai 		}
251478af8d3SJacky Bai 		dram_timing_cfg->pi_cfg[0] = dram_timing_cfg->pi_cfg[0] & 0xFFFFFFFE;
252478af8d3SJacky Bai 
253478af8d3SJacky Bai 		/*
254478af8d3SJacky Bai 		 * Read and store all PHY registers. full array is a full
255478af8d3SJacky Bai 		 * copy for all the setpoint
256478af8d3SJacky Bai 		 */
257478af8d3SJacky Bai 		if (dram_class == LPDDR4_TYPE) {
258478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x10000);
259478af8d3SJacky Bai 			for (i = 0U; i < PHY_NUM; i++) {
260478af8d3SJacky Bai 				/* Make sure MULTICASE is enabled */
261478af8d3SJacky Bai 				if (i == 1537U) {
262478af8d3SJacky Bai 					dram_timing_cfg->phy_full[i] = 0x100;
263478af8d3SJacky Bai 				} else {
264478af8d3SJacky Bai 					dram_timing_cfg->phy_full[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + i * 4);
265478af8d3SJacky Bai 				}
266478af8d3SJacky Bai 			}
267478af8d3SJacky Bai 
268478af8d3SJacky Bai 			/*
269478af8d3SJacky Bai 			 * set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=0.
270478af8d3SJacky Bai 			 * Read and store only the diff.
271478af8d3SJacky Bai 			 */
272478af8d3SJacky Bai 			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
273478af8d3SJacky Bai 			/* save only the frequency based diff config to save memory */
274478af8d3SJacky Bai 			for (i = 0U; i < PHY_DIFF_NUM; i++) {
275478af8d3SJacky Bai 				dram_timing_cfg->phy_diff[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 +
276478af8d3SJacky Bai 									    freq_specific_reg_array[i] * 4);
277478af8d3SJacky Bai 			}
278478af8d3SJacky Bai 		} else {
279478af8d3SJacky Bai 			/* LPDDR3, only f1 need to save */
280478af8d3SJacky Bai 			for (i = 0U; i < info->phy_f1_cfg_num; i++) {
281478af8d3SJacky Bai 				info->phy_f1_cfg[i].val = mmio_read_32(info->phy_f1_cfg[i].reg);
282478af8d3SJacky Bai 			}
283478af8d3SJacky Bai 		}
284478af8d3SJacky Bai 
285478af8d3SJacky Bai 		dram_cfg_saved = true;
286478af8d3SJacky Bai 	}
287478af8d3SJacky Bai }
288478af8d3SJacky Bai 
289478af8d3SJacky Bai void dram_exit_retention(void)
290478af8d3SJacky Bai {
291478af8d3SJacky Bai 	uint32_t val;
292478af8d3SJacky Bai 
293478af8d3SJacky Bai 	/* 1. Config the LPAV PLL4 and DDR clock for the desired LPDDR operating frequency. */
294478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
295478af8d3SJacky Bai 
296478af8d3SJacky Bai 	/* 2. Write PCC5.PCC_LPDDR4[SWRST] to 1b'1 to release LPDDR from reset. */
297478af8d3SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(28));
298478af8d3SJacky Bai 
299478af8d3SJacky Bai 	/* 3. Reload the LPDDR CTL/PI/PHY register */
300478af8d3SJacky Bai 	ddr_init();
301478af8d3SJacky Bai 
302478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
303478af8d3SJacky Bai 		/* 4a. FIXME Set PHY_SET_DFI_INPUT_N parameters to 4'h1. LPDDR4 only */
304478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1559, 0x01010101);
305478af8d3SJacky Bai 
306478af8d3SJacky Bai 		/*
307478af8d3SJacky Bai 		 * 4b. CTL PWRUP_SREFRESH_EXIT=1'b0 for disabling self refresh exit
308478af8d3SJacky Bai 		 * from controller.
309478af8d3SJacky Bai 		 */
310478af8d3SJacky Bai 		/*
311478af8d3SJacky Bai 		 * 4c. PI_PWRUP_SELF_REF_EXIT=1, PI_MC_PWRUP_SELF_REF_EXIT=0 for enabling
312478af8d3SJacky Bai 		 * self refresh exit from PI
313478af8d3SJacky Bai 		 */
314478af8d3SJacky Bai 		/* 4c. PI_INT_LVL_EN=0 to skip Initialization trainings. */
315478af8d3SJacky Bai 		/*
316478af8d3SJacky Bai 		 * 4d. PI_WRLVL_EN_F0/1/2= PI_CALVL_EN_F0/1/2= PI_RDLVL_EN_F0/1/2=
317478af8d3SJacky Bai 		 * PI_RDLVL_GATE_EN_F0/1/2= PI_WDQLVL_EN_F0/1/2=0x2.
318478af8d3SJacky Bai 		 * Enable non initialization trainings.
319478af8d3SJacky Bai 		 */
320478af8d3SJacky Bai 		/* 4e. PI_PWRUP_SREFRESH_EXIT_CS=0xF */
321478af8d3SJacky Bai 		/* 4f. PI_DLL_RESET=0x1 */
322478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
323478af8d3SJacky Bai 		/* PI_PWRUP_SELF_REF_EXIT = 1 */
324478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
325478af8d3SJacky Bai 		/* PI_MC_PWRUP_SELF_REF_EXIT = 0 */
326478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
327478af8d3SJacky Bai 		/* PI_INT_LVL_EN = 0 */
328478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
329478af8d3SJacky Bai 		/* PI_WRLVL_EN_F0 = 3, PI_WRLVL_EN_F1 = 3 */
330478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x03030000);
331478af8d3SJacky Bai 		/* PI_WRLVL_EN_F2 = 3 */
332478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_175, 0x03);
333478af8d3SJacky Bai 		/* PI_CALVL_EN_F0 = 3, PI_CALVL_EN_F1 = 3 */
334478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x03030000);
335478af8d3SJacky Bai 		/* PI_CALVL_EN_F2 = 3 */
336478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_192, 0x03);
337478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F0 = 3 */
338478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_212, 0x300);
339478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F1 = 3 */
340478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_214, 0x03000000);
341478af8d3SJacky Bai 		/* PI_WDQLVL_EN_F2 = 3 */
342478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_217, 0x300);
343478af8d3SJacky Bai 		/* PI_EDLVL_EN_F0 = 3, PI_EDLVL_GATE_EN_F0 = 3 */
344478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
345478af8d3SJacky Bai 		/*
346478af8d3SJacky Bai 		 * PI_RDLVL_EN_F1 = 3, PI_RDLVL_GATE_EN_F1 = 3,
347478af8d3SJacky Bai 		 * PI_RDLVL_EN_F2 = 3, PI_RDLVL_GATE_EN_F2 = 3
348478af8d3SJacky Bai 		 */
349478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_182, 0x03030303);
350478af8d3SJacky Bai 		/* PI_PWRUP_SREFRESH_EXIT_CS = 0xF */
351478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
352478af8d3SJacky Bai 	} else {
353478af8d3SJacky Bai 		/* PI_DLL_RESET=1 */
354478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
355478af8d3SJacky Bai 		/* PI_PWRUP_SELF_REF_EXIT=1 */
356478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
357478af8d3SJacky Bai 		/* PI_MC_PWRUP_SELF_REF_EXIT=0 */
358478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
359478af8d3SJacky Bai 		/* PI_INT_LVL_EN=0 */
360478af8d3SJacky Bai 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
361478af8d3SJacky Bai 		/* PI_WRLVL_EN_F0=3 */
362478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x00030000);
363478af8d3SJacky Bai 		/* PI_CALVL_EN_F0=3 */
364478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x00030000);
365478af8d3SJacky Bai 		/* PI_RDLVL_EN_F0=3,PI_RDLVL_GATE_EN_F0=3 */
366478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
367478af8d3SJacky Bai 		/* PI_PWRUP_SREFRESH_EXIT_CS=0xF */
368478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
369478af8d3SJacky Bai 	}
370478af8d3SJacky Bai 
371478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x00002D00);
372478af8d3SJacky Bai 
373478af8d3SJacky Bai 	/* Force in-order AXI read data */
374478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x1);
375478af8d3SJacky Bai 
376478af8d3SJacky Bai 	/*
377478af8d3SJacky Bai 	 * Disable special R/W group switches so that R/W group placement
378478af8d3SJacky Bai 	 * is always at END of R/W group.
379478af8d3SJacky Bai 	 */
380478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_249, 0x0);
381478af8d3SJacky Bai 
382478af8d3SJacky Bai 	/* Reduce time for IO pad calibration */
383478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1590, 0x01000000);
384478af8d3SJacky Bai 
385478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_25, 0x00020100);
386478af8d3SJacky Bai 
387478af8d3SJacky Bai 	/* PD disable */
388478af8d3SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_153, 0x04040000);
389478af8d3SJacky Bai 	/*
390478af8d3SJacky Bai 	 * 5. Disable automatic LP entry and PCPCS modes LP_AUTO_ENTRY_EN
391478af8d3SJacky Bai 	 * to 1b'0, PCPCS_PD_EN to 1b'0
392478af8d3SJacky Bai 	 */
393478af8d3SJacky Bai 
394478af8d3SJacky Bai 	upwr_xcp_set_ddr_retention(APD_DOMAIN, 0, NULL);
395478af8d3SJacky Bai 	upower_wait_resp();
396478af8d3SJacky Bai 
397478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
398478af8d3SJacky Bai 		/* 7. Write PI START parameter to 1'b1 */
399478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000b01);
400478af8d3SJacky Bai 
401478af8d3SJacky Bai 		/* 8. Write CTL START parameter to 1'b1 */
402478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000b01);
403478af8d3SJacky Bai 	} else {
404478af8d3SJacky Bai 		/* 7. Write PI START parameter to 1'b1 */
405478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000701);
406478af8d3SJacky Bai 
407478af8d3SJacky Bai 		/* 8. Write CTL START parameter to 1'b1 */
408478af8d3SJacky Bai 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000701);
409478af8d3SJacky Bai 	}
410478af8d3SJacky Bai 
411478af8d3SJacky Bai 	/* 9. DENALI_CTL_266:  Wait for INT_STATUS_INIT=0x2 */
412478af8d3SJacky Bai 	do {
413478af8d3SJacky Bai 		val = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_266) >> 8) & 0xFF;
414478af8d3SJacky Bai 	} while (val != 0x2);
415478af8d3SJacky Bai 
416478af8d3SJacky Bai 	/*
417478af8d3SJacky Bai 	 * 10. Run SW trainings by setting PI_CALVL_REQ,PI_WRLVL_REQ,PI_RDLVL_GATE_REQ,
418478af8d3SJacky Bai 	 * PI_RDLVL_REQ,PI_WDQLVL_REQ(NA for LPDDR3) in same order.
419478af8d3SJacky Bai 	 */
420478af8d3SJacky Bai 	if (dram_class == LPDDR4_TYPE) {
421478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
422478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
423478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
424478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
425478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_65, 0x10000); /* WDQLVL */
426478af8d3SJacky Bai 
427478af8d3SJacky Bai 		/* 11. Wait for trainings to get complete by polling PI_INT_STATUS */
428478af8d3SJacky Bai 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x07E00000) != 0x07E00000) {
429478af8d3SJacky Bai 			;
430478af8d3SJacky Bai 		}
431478af8d3SJacky Bai 	} else {
432478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
433478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
434478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
435478af8d3SJacky Bai 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
436478af8d3SJacky Bai 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x05E00000) != 0x05E00000) {
437478af8d3SJacky Bai 			;
438478af8d3SJacky Bai 		}
439478af8d3SJacky Bai 	}
440478af8d3SJacky Bai }
441*caee2733SJacky Bai 
442*caee2733SJacky Bai #define LPDDR_DONE       (0x1<<4)
443*caee2733SJacky Bai #define SOC_FREQ_CHG_ACK (0x1<<6)
444*caee2733SJacky Bai #define SOC_FREQ_CHG_REQ (0x1<<7)
445*caee2733SJacky Bai #define LPI_WAKEUP_EN    (0x4<<8)
446*caee2733SJacky Bai #define SOC_FREQ_REQ     (0x1<<11)
447*caee2733SJacky Bai 
448*caee2733SJacky Bai #define LPDDR_EN_CLKGATE (0x1<<17)
449*caee2733SJacky Bai 
450*caee2733SJacky Bai static void set_cgc2_ddrclk(uint8_t src, uint8_t div)
451*caee2733SJacky Bai {
452*caee2733SJacky Bai 
453*caee2733SJacky Bai 	/* Wait until the reg is unlocked for writing */
454*caee2733SJacky Bai 	while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31))
455*caee2733SJacky Bai 		;
456*caee2733SJacky Bai 
457*caee2733SJacky Bai 	mmio_write_32(IMX_CGC2_BASE + 0x40, (src << 28) | (div << 21));
458*caee2733SJacky Bai 	/* Wait for the clock switching done */
459*caee2733SJacky Bai 	while (!(mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(27)))
460*caee2733SJacky Bai 		;
461*caee2733SJacky Bai }
462*caee2733SJacky Bai static void set_ddr_clk(uint32_t ddr_freq)
463*caee2733SJacky Bai {
464*caee2733SJacky Bai 	/* Disable DDR clock */
465*caee2733SJacky Bai 	mmio_clrbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
466*caee2733SJacky Bai 	switch (ddr_freq) {
467*caee2733SJacky Bai 	/* boot frequency ? */
468*caee2733SJacky Bai 	case 48:
469*caee2733SJacky Bai 		set_cgc2_ddrclk(2, 0);
470*caee2733SJacky Bai 		break;
471*caee2733SJacky Bai 	/* default bypass frequency for fsp 1 */
472*caee2733SJacky Bai 	case 192:
473*caee2733SJacky Bai 		set_cgc2_ddrclk(0, 1);
474*caee2733SJacky Bai 		break;
475*caee2733SJacky Bai 	case 384:
476*caee2733SJacky Bai 		set_cgc2_ddrclk(0, 0);
477*caee2733SJacky Bai 		break;
478*caee2733SJacky Bai 	case 264:
479*caee2733SJacky Bai 		set_cgc2_ddrclk(4, 3);
480*caee2733SJacky Bai 		break;
481*caee2733SJacky Bai 	case 528:
482*caee2733SJacky Bai 		set_cgc2_ddrclk(4, 1);
483*caee2733SJacky Bai 		break;
484*caee2733SJacky Bai 	default:
485*caee2733SJacky Bai 		break;
486*caee2733SJacky Bai 	}
487*caee2733SJacky Bai 	/* Enable DDR clock */
488*caee2733SJacky Bai 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
489*caee2733SJacky Bai 
490*caee2733SJacky Bai 	/* Wait until the reg is unlocked for writing */
491*caee2733SJacky Bai 	while (mmio_read_32(IMX_CGC2_BASE + 0x40) & BIT(31)) {
492*caee2733SJacky Bai 		;
493*caee2733SJacky Bai 	}
494*caee2733SJacky Bai }
495*caee2733SJacky Bai 
496*caee2733SJacky Bai #define AVD_SIM_LPDDR_CTRL	(IMX_LPAV_SIM_BASE + 0x14)
497*caee2733SJacky Bai #define AVD_SIM_LPDDR_CTRL2	(IMX_LPAV_SIM_BASE + 0x18)
498*caee2733SJacky Bai #define MAX_FSP_NUM	U(3)
499*caee2733SJacky Bai #define DDR_DFS_GET_FSP_COUNT	0x10
500*caee2733SJacky Bai #define DDR_BYPASS_DRATE	U(400)
501*caee2733SJacky Bai 
502*caee2733SJacky Bai /* Normally, we only switch frequency between 1(bypass) and 2(highest) */
503*caee2733SJacky Bai int lpddr4_dfs(uint32_t freq_index)
504*caee2733SJacky Bai {
505*caee2733SJacky Bai 	uint32_t lpddr_ctrl, lpddr_ctrl2;
506*caee2733SJacky Bai 	uint32_t ddr_ctl_144;
507*caee2733SJacky Bai 
508*caee2733SJacky Bai 	/*
509*caee2733SJacky Bai 	 * Valid index: 0 to 2
510*caee2733SJacky Bai 	 * index 0: boot frequency
511*caee2733SJacky Bai 	 * index 1: bypass frequency
512*caee2733SJacky Bai 	 * index 2: highest frequency
513*caee2733SJacky Bai 	 */
514*caee2733SJacky Bai 	if (freq_index > 2U) {
515*caee2733SJacky Bai 		return -1;
516*caee2733SJacky Bai 	}
517*caee2733SJacky Bai 
518*caee2733SJacky Bai 	/* Enable LPI_WAKEUP_EN */
519*caee2733SJacky Bai 	ddr_ctl_144 = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_144);
520*caee2733SJacky Bai 	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, LPI_WAKEUP_EN);
521*caee2733SJacky Bai 
522*caee2733SJacky Bai 	/* put DRAM into long self-refresh & clock gating */
523*caee2733SJacky Bai 	lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL);
524*caee2733SJacky Bai 	lpddr_ctrl = (lpddr_ctrl & ~((0x3f << 15) | (0x3 << 9))) | (0x28 << 15) | (freq_index << 9);
525*caee2733SJacky Bai 	mmio_write_32(AVD_SIM_LPDDR_CTRL, lpddr_ctrl);
526*caee2733SJacky Bai 
527*caee2733SJacky Bai 	/* Gating the clock */
528*caee2733SJacky Bai 	lpddr_ctrl2 = mmio_read_32(AVD_SIM_LPDDR_CTRL2);
529*caee2733SJacky Bai 	mmio_setbits_32(AVD_SIM_LPDDR_CTRL2, LPDDR_EN_CLKGATE);
530*caee2733SJacky Bai 
531*caee2733SJacky Bai 	/* Request frequency change */
532*caee2733SJacky Bai 	mmio_setbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_REQ);
533*caee2733SJacky Bai 
534*caee2733SJacky Bai 	do {
535*caee2733SJacky Bai 		lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL);
536*caee2733SJacky Bai 		if (lpddr_ctrl & SOC_FREQ_CHG_REQ) {
537*caee2733SJacky Bai 			/* Bypass mode */
538*caee2733SJacky Bai 			if (info->fsp_table[freq_index] < DDR_BYPASS_DRATE) {
539*caee2733SJacky Bai 				/* Change to PLL bypass mode */
540*caee2733SJacky Bai 				mmio_write_32(IMX_LPAV_SIM_BASE, 0x1);
541*caee2733SJacky Bai 				/* change the ddr clock source & frequency */
542*caee2733SJacky Bai 				set_ddr_clk(info->fsp_table[freq_index]);
543*caee2733SJacky Bai 			} else {
544*caee2733SJacky Bai 				/* Change to PLL unbypass mode */
545*caee2733SJacky Bai 				mmio_write_32(IMX_LPAV_SIM_BASE, 0x0);
546*caee2733SJacky Bai 				/* change the ddr clock source & frequency */
547*caee2733SJacky Bai 				set_ddr_clk(info->fsp_table[freq_index] >> 1);
548*caee2733SJacky Bai 			}
549*caee2733SJacky Bai 
550*caee2733SJacky Bai 			mmio_clrsetbits_32(AVD_SIM_LPDDR_CTRL, SOC_FREQ_CHG_REQ, SOC_FREQ_CHG_ACK);
551*caee2733SJacky Bai 			continue;
552*caee2733SJacky Bai 		}
553*caee2733SJacky Bai 	} while ((lpddr_ctrl & LPDDR_DONE) != 0); /* several try? */
554*caee2733SJacky Bai 
555*caee2733SJacky Bai 	/* restore the original setting */
556*caee2733SJacky Bai 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, ddr_ctl_144);
557*caee2733SJacky Bai 	mmio_write_32(AVD_SIM_LPDDR_CTRL2, lpddr_ctrl2);
558*caee2733SJacky Bai 
559*caee2733SJacky Bai 	/* Check the DFS result */
560*caee2733SJacky Bai 	lpddr_ctrl = mmio_read_32(AVD_SIM_LPDDR_CTRL) & 0xF;
561*caee2733SJacky Bai 	if (lpddr_ctrl != 0U) {
562*caee2733SJacky Bai 		/* Must be something wrong, return failure */
563*caee2733SJacky Bai 		return -1;
564*caee2733SJacky Bai 	}
565*caee2733SJacky Bai 
566*caee2733SJacky Bai 	/* DFS done successfully */
567*caee2733SJacky Bai 	return 0;
568*caee2733SJacky Bai }
569*caee2733SJacky Bai 
570*caee2733SJacky Bai /* for the non-primary core, waiting for DFS done */
571*caee2733SJacky Bai static uint64_t waiting_dvfs(uint32_t id, uint32_t flags,
572*caee2733SJacky Bai 		void *handle, void *cookie)
573*caee2733SJacky Bai {
574*caee2733SJacky Bai 	uint32_t irq;
575*caee2733SJacky Bai 
576*caee2733SJacky Bai 	irq = plat_ic_acknowledge_interrupt();
577*caee2733SJacky Bai 	if (irq < 1022U) {
578*caee2733SJacky Bai 		plat_ic_end_of_interrupt(irq);
579*caee2733SJacky Bai 	}
580*caee2733SJacky Bai 
581*caee2733SJacky Bai 	/* set the WFE done status */
582*caee2733SJacky Bai 	spin_lock(&dfs_lock);
583*caee2733SJacky Bai 	core_count++;
584*caee2733SJacky Bai 	dsb();
585*caee2733SJacky Bai 	spin_unlock(&dfs_lock);
586*caee2733SJacky Bai 
587*caee2733SJacky Bai 	while (in_progress) {
588*caee2733SJacky Bai 		wfe();
589*caee2733SJacky Bai 	}
590*caee2733SJacky Bai 
591*caee2733SJacky Bai 	return 0;
592*caee2733SJacky Bai }
593*caee2733SJacky Bai 
594*caee2733SJacky Bai int dram_dvfs_handler(uint32_t smc_fid, void *handle,
595*caee2733SJacky Bai 		u_register_t x1, u_register_t x2, u_register_t x3)
596*caee2733SJacky Bai {
597*caee2733SJacky Bai 	unsigned int fsp_index = x1;
598*caee2733SJacky Bai 	uint32_t online_cpus = x2 - 1;
599*caee2733SJacky Bai 	uint64_t mpidr = read_mpidr_el1();
600*caee2733SJacky Bai 	unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
601*caee2733SJacky Bai 
602*caee2733SJacky Bai 	/* Get the number of FSPs */
603*caee2733SJacky Bai 	if (x1 == DDR_DFS_GET_FSP_COUNT) {
604*caee2733SJacky Bai 		SMC_RET2(handle, num_fsp, info->fsp_table[1]);
605*caee2733SJacky Bai 	}
606*caee2733SJacky Bai 
607*caee2733SJacky Bai 	/* start lpddr frequency scaling */
608*caee2733SJacky Bai 	in_progress = true;
609*caee2733SJacky Bai 	dsb();
610*caee2733SJacky Bai 
611*caee2733SJacky Bai 	/* notify other core wait for scaling done */
612*caee2733SJacky Bai 	for (unsigned int i = 0; i < PLATFORM_CORE_COUNT; i++)
613*caee2733SJacky Bai 		/* Skip raise SGI for current CPU */
614*caee2733SJacky Bai 		if (i != cpu_id) {
615*caee2733SJacky Bai 			plat_ic_raise_el3_sgi(0x8, i);
616*caee2733SJacky Bai 		}
617*caee2733SJacky Bai 
618*caee2733SJacky Bai 	/* Make sure all the cpu in WFE */
619*caee2733SJacky Bai 	while (online_cpus != core_count) {
620*caee2733SJacky Bai 		;
621*caee2733SJacky Bai 	}
622*caee2733SJacky Bai 
623*caee2733SJacky Bai 	/* Flush the L1/L2 cache */
624*caee2733SJacky Bai 	dcsw_op_all(DCCSW);
625*caee2733SJacky Bai 
626*caee2733SJacky Bai 	lpddr4_dfs(fsp_index);
627*caee2733SJacky Bai 
628*caee2733SJacky Bai 	in_progress = false;
629*caee2733SJacky Bai 	core_count = 0;
630*caee2733SJacky Bai 	dsb();
631*caee2733SJacky Bai 	sev();
632*caee2733SJacky Bai 	isb();
633*caee2733SJacky Bai 
634*caee2733SJacky Bai 	SMC_RET1(handle, 0);
635*caee2733SJacky Bai }
636*caee2733SJacky Bai 
637*caee2733SJacky Bai void dram_init(void)
638*caee2733SJacky Bai {
639*caee2733SJacky Bai 	uint32_t flags = 0;
640*caee2733SJacky Bai 	uint32_t rc;
641*caee2733SJacky Bai 	unsigned int i;
642*caee2733SJacky Bai 
643*caee2733SJacky Bai 	/* Register the EL3 handler for DDR DVFS */
644*caee2733SJacky Bai 	set_interrupt_rm_flag(flags, NON_SECURE);
645*caee2733SJacky Bai 	rc = register_interrupt_type_handler(INTR_TYPE_EL3, waiting_dvfs, flags);
646*caee2733SJacky Bai 	if (rc) {
647*caee2733SJacky Bai 		panic();
648*caee2733SJacky Bai 	}
649*caee2733SJacky Bai 
650*caee2733SJacky Bai 	info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
651*caee2733SJacky Bai 
652*caee2733SJacky Bai 	/* Get the num of the supported Fsp */
653*caee2733SJacky Bai 	for (i = 0; i < MAX_FSP_NUM; i++) {
654*caee2733SJacky Bai 		if (!info->fsp_table[i]) {
655*caee2733SJacky Bai 			break;
656*caee2733SJacky Bai 		}
657*caee2733SJacky Bai 	}
658*caee2733SJacky Bai 
659*caee2733SJacky Bai 	num_fsp = (i > MAX_FSP_NUM) ? MAX_FSP_NUM : i;
660*caee2733SJacky Bai }
661