xref: /rk3399_ARM-atf/plat/imx/imx8ulp/dram.c (revision ff5e1793b95ed4297deae72cdb665178e6e72e44)
1 /*
2  * Copyright 2021-2024 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <assert.h>
8 #include <stdbool.h>
9 
10 #include <lib/mmio.h>
11 #include <platform_def.h>
12 
13 #include <upower_api.h>
14 
15 #define PHY_FREQ_SEL_INDEX(x)		((x) << 16)
16 #define PHY_FREQ_MULTICAST_EN(x)	((x) << 8)
17 #define DENALI_PHY_1537			U(0x5804)
18 
19 #define IMX_DDRC_BASE			U(0x2E060000)
20 #define SAVED_DRAM_DATA_BASE		U(0x20055000)
21 #define DENALI_CTL_144			0x240
22 #define LPI_WAKEUP_EN_SHIFT		U(8)
23 #define IMX_LPAV_SIM_BASE		0x2DA50000
24 #define LPDDR_CTRL			0x14
25 #define LPDDR_AUTO_LP_MODE_DISABLE	BIT(24)
26 #define SOC_LP_CMD_SHIFT		U(15)
27 #define LPDDR_CTRL2			0x18
28 
29 #define DENALI_CTL_00			U(0x0)
30 #define DENALI_CTL_23			U(0x5c)
31 #define DFIBUS_FREQ_INIT_SHIFT		U(24)
32 #define TSREF2PHYMSTR_SHIFT		U(8)
33 #define TSREF2PHYMSTR_MASK		GENMASK(13, 8)
34 
35 #define DENALI_CTL_24			U(0x60)
36 #define DENALI_CTL_25			U(0x64)
37 
38 #define DENALI_CTL_93			U(0x174)
39 #define PWRUP_SREFRESH_EXIT		BIT(0)
40 
41 #define DENALI_CTL_127				U(0x1fc)
42 #define PHYMSTR_TRAIN_AFTER_INIT_COMPLETE	BIT(16)
43 
44 #define DENALI_CTL_147			U(0x24c)
45 #define DENALI_CTL_153			U(0x264)
46 #define PCPCS_PD_EN			BIT(8)
47 
48 #define DENALI_CTL_249			U(0x3E4)
49 #define DENALI_CTL_266			U(0x428)
50 
51 #define DENALI_PHY_1547			U(0x582c)
52 #define PHY_LP4_BOOT_DISABLE		BIT(8)
53 
54 #define DENALI_PHY_1559			U(0x585c)
55 #define DENALI_PHY_1590			U(0x58D8)
56 
57 #define DENALI_PI_00			U(0x2000)
58 #define DENALI_PI_04			U(0x2010)
59 #define DENALI_PI_52			U(0x20D0)
60 #define DENALI_PI_26			U(0x2068)
61 #define DENALI_PI_33			U(0x2084)
62 #define DENALI_PI_65			U(0x2104)
63 #define DENALI_PI_77			U(0x2134)
64 #define DENALI_PI_134			U(0x2218)
65 #define DENALI_PI_131			U(0x220C)
66 #define DENALI_PI_132			U(0x2210)
67 #define DENALI_PI_134			U(0x2218)
68 #define DENALI_PI_137			U(0x2224)
69 #define DENALI_PI_174			U(0x22B8)
70 #define DENALI_PI_175			U(0x22BC)
71 #define DENALI_PI_181			U(0x22D4)
72 #define DENALI_PI_182			U(0x22D8)
73 #define DENALI_PI_191			U(0x22FC)
74 #define DENALI_PI_192			U(0x2300)
75 #define DENALI_PI_212			U(0x2350)
76 #define DENALI_PI_214			U(0x2358)
77 #define DENALI_PI_217			U(0x2364)
78 
79 #define LPDDR3_TYPE	U(0x7)
80 #define LPDDR4_TYPE	U(0xB)
81 
82 extern void upower_wait_resp(void);
83 
84 struct dram_cfg_param {
85 	uint32_t reg;
86 	uint32_t val;
87 };
88 
89 struct dram_timing_info {
90 	/* ddr controller config */
91 	struct dram_cfg_param *ctl_cfg;
92 	unsigned int ctl_cfg_num;
93 	/* pi config */
94 	struct dram_cfg_param *pi_cfg;
95 	unsigned int pi_cfg_num;
96 	/* phy freq1 config */
97 	struct dram_cfg_param *phy_f1_cfg;
98 	unsigned int phy_f1_cfg_num;
99 	/* phy freq2 config */
100 	struct dram_cfg_param *phy_f2_cfg;
101 	unsigned int phy_f2_cfg_num;
102 	/* initialized drate table */
103 	unsigned int fsp_table[3];
104 };
105 
106 #define CTL_NUM		U(680)
107 #define PI_NUM		U(298)
108 #define PHY_NUM		U(1654)
109 #define PHY_DIFF_NUM	U(49)
110 struct dram_cfg {
111 	uint32_t ctl_cfg[CTL_NUM];
112 	uint32_t pi_cfg[PI_NUM];
113 	uint32_t phy_full[PHY_NUM];
114 	uint32_t phy_diff[PHY_DIFF_NUM];
115 };
116 
117 struct dram_timing_info *info;
118 struct dram_cfg *dram_timing_cfg;
119 
120 /* mark if dram cfg is already saved */
121 static bool dram_cfg_saved;
122 static uint32_t dram_class;
123 
124 /* PHY register index for frequency diff */
125 uint32_t freq_specific_reg_array[PHY_DIFF_NUM] = {
126 90, 92, 93, 96, 97, 100, 101, 102, 103, 104, 114,
127 346, 348, 349, 352, 353, 356, 357, 358, 359, 360,
128 370, 602, 604, 605, 608, 609, 612, 613, 614, 615,
129 616, 626, 858, 860, 861, 864, 865, 868, 869, 870,
130 871, 872, 882, 1063, 1319, 1566, 1624, 1625
131 };
132 
133 static void ddr_init(void)
134 {
135 	unsigned int i;
136 
137 	/* restore the ddr ctl config */
138 	for (i = 0U; i < CTL_NUM; i++) {
139 		mmio_write_32(IMX_DDRC_BASE + i * 4, dram_timing_cfg->ctl_cfg[i]);
140 	}
141 
142 	/* load the PI registers */
143 	for (i = 0U; i < PI_NUM; i++) {
144 		mmio_write_32(IMX_DDRC_BASE + 0x2000 + i * 4, dram_timing_cfg->pi_cfg[i]);
145 	}
146 
147 
148 	 /* restore all PHY registers for all the fsp. */
149 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x100);
150 	/* restore all the phy configs */
151 	for (i = 0U; i < PHY_NUM; i++) {
152 		/* skip the reserved registers space */
153 		if (i >= 121U && i <= 255U) {
154 			continue;
155 		}
156 		if (i >= 377U && i <= 511U) {
157 			continue;
158 		}
159 		if (i >= 633U && i <= 767U) {
160 			continue;
161 		}
162 		if (i >= 889U && i <= 1023U) {
163 			continue;
164 		}
165 		if (i >= 1065U && i <= 1279U) {
166 			continue;
167 		}
168 		if (i >= 1321U && i <= 1535U) {
169 			continue;
170 		}
171 		mmio_write_32(IMX_DDRC_BASE + 0x4000 + i * 4, dram_timing_cfg->phy_full[i]);
172 	}
173 
174 	if (dram_class == LPDDR4_TYPE) {
175 		/* restore only the diff. */
176 		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
177 		for (i = 0U; i < PHY_DIFF_NUM; i++) {
178 			mmio_write_32(IMX_DDRC_BASE + 0x4000 + freq_specific_reg_array[i] * 4,
179 				      dram_timing_cfg->phy_diff[i]);
180 		}
181 	}
182 
183 	/* Re-enable MULTICAST mode */
184 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, PHY_FREQ_MULTICAST_EN(1));
185 }
186 
187 void dram_enter_retention(void)
188 {
189 	unsigned int i;
190 
191 	/* 1. config the PCC_LPDDR4[SSADO] to 2b'11 for ACK domain 0/1's STOP */
192 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, 0x2 << 22);
193 
194 	/*
195 	 * 2. Make sure the DENALI_CTL_144[LPI_WAKEUP_EN[5:0]] has the bit
196 	 * LPI_WAKEUP_EN[3] = 1b'1. This enables the option 'self-refresh
197 	 * long with mem and ctlr clk gating or self-refresh  power-down
198 	 * long with mem and ctlr clk gating'
199 	 */
200 	mmio_setbits_32(IMX_DDRC_BASE + DENALI_CTL_144, BIT(3) << LPI_WAKEUP_EN_SHIFT);
201 
202 	/*
203 	 * 3a. Config SIM_LPAV LPDDR_CTRL[LPDDR_AUTO_LP_MODE_DISABLE] to 1b'0(enable
204 	 * the logic to automatic handles low power entry/exit. This is the recommended
205 	 * option over handling through software.
206 	 * 3b. Config the SIM_LPAV LPDDR_CTRL[SOC_LP_CMD] to 6b'101001(encoding for
207 	 * self_refresh with both DDR controller and DRAM clock gate. THis is mandatory
208 	 * since LPPDR logic will be power gated).
209 	 */
210 	mmio_clrbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL, LPDDR_AUTO_LP_MODE_DISABLE);
211 	mmio_clrsetbits_32(IMX_LPAV_SIM_BASE + LPDDR_CTRL,
212 			   0x3f << SOC_LP_CMD_SHIFT, 0x29 << SOC_LP_CMD_SHIFT);
213 
214 	/* Save DDR Controller & PHY config.
215 	 * Set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=1. Read and store all
216 	 * the PHY registers for F2 into phy_f1_cfg, then read/store the diff between
217 	 * F1 & F2 into phy_f2_cfg.
218 	 */
219 	if (!dram_cfg_saved) {
220 		info = (struct dram_timing_info *)SAVED_DRAM_DATA_BASE;
221 		dram_timing_cfg = (struct dram_cfg *)(SAVED_DRAM_DATA_BASE +
222 					sizeof(struct dram_timing_info));
223 
224 		/* get the dram type */
225 		dram_class = mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_00);
226 		dram_class = (dram_class >> 8) & 0xf;
227 
228 		/* save the ctl registers */
229 		for (i = 0U; i < CTL_NUM; i++) {
230 			dram_timing_cfg->ctl_cfg[i] = mmio_read_32(IMX_DDRC_BASE + i * 4);
231 		}
232 		dram_timing_cfg->ctl_cfg[0] = dram_timing_cfg->ctl_cfg[0] & 0xFFFFFFFE;
233 
234 		/* save the PI registers */
235 		for (i = 0U; i < PI_NUM; i++) {
236 			dram_timing_cfg->pi_cfg[i] = mmio_read_32(IMX_DDRC_BASE + 0x2000 + i * 4);
237 		}
238 		dram_timing_cfg->pi_cfg[0] = dram_timing_cfg->pi_cfg[0] & 0xFFFFFFFE;
239 
240 		/*
241 		 * Read and store all PHY registers. full array is a full
242 		 * copy for all the setpoint
243 		 */
244 		if (dram_class == LPDDR4_TYPE) {
245 			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x10000);
246 			for (i = 0U; i < PHY_NUM; i++) {
247 				/* Make sure MULTICASE is enabled */
248 				if (i == 1537U) {
249 					dram_timing_cfg->phy_full[i] = 0x100;
250 				} else {
251 					dram_timing_cfg->phy_full[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 + i * 4);
252 				}
253 			}
254 
255 			/*
256 			 * set PHY_FREQ_SEL_MULTICAST_EN=0 & PHY_FREQ_SEL_INDEX=0.
257 			 * Read and store only the diff.
258 			 */
259 			mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1537, 0x0);
260 			/* save only the frequency based diff config to save memory */
261 			for (i = 0U; i < PHY_DIFF_NUM; i++) {
262 				dram_timing_cfg->phy_diff[i] = mmio_read_32(IMX_DDRC_BASE + 0x4000 +
263 									    freq_specific_reg_array[i] * 4);
264 			}
265 		} else {
266 			/* LPDDR3, only f1 need to save */
267 			for (i = 0U; i < info->phy_f1_cfg_num; i++) {
268 				info->phy_f1_cfg[i].val = mmio_read_32(info->phy_f1_cfg[i].reg);
269 			}
270 		}
271 
272 		dram_cfg_saved = true;
273 	}
274 }
275 
276 void dram_exit_retention(void)
277 {
278 	uint32_t val;
279 
280 	/* 1. Config the LPAV PLL4 and DDR clock for the desired LPDDR operating frequency. */
281 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(30));
282 
283 	/* 2. Write PCC5.PCC_LPDDR4[SWRST] to 1b'1 to release LPDDR from reset. */
284 	mmio_setbits_32(IMX_PCC5_BASE + 0x108, BIT(28));
285 
286 	/* 3. Reload the LPDDR CTL/PI/PHY register */
287 	ddr_init();
288 
289 	if (dram_class == LPDDR4_TYPE) {
290 		/* 4a. FIXME Set PHY_SET_DFI_INPUT_N parameters to 4'h1. LPDDR4 only */
291 		mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1559, 0x01010101);
292 
293 		/*
294 		 * 4b. CTL PWRUP_SREFRESH_EXIT=1'b0 for disabling self refresh exit
295 		 * from controller.
296 		 */
297 		/*
298 		 * 4c. PI_PWRUP_SELF_REF_EXIT=1, PI_MC_PWRUP_SELF_REF_EXIT=0 for enabling
299 		 * self refresh exit from PI
300 		 */
301 		/* 4c. PI_INT_LVL_EN=0 to skip Initialization trainings. */
302 		/*
303 		 * 4d. PI_WRLVL_EN_F0/1/2= PI_CALVL_EN_F0/1/2= PI_RDLVL_EN_F0/1/2=
304 		 * PI_RDLVL_GATE_EN_F0/1/2= PI_WDQLVL_EN_F0/1/2=0x2.
305 		 * Enable non initialization trainings.
306 		 */
307 		/* 4e. PI_PWRUP_SREFRESH_EXIT_CS=0xF */
308 		/* 4f. PI_DLL_RESET=0x1 */
309 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
310 		/* PI_PWRUP_SELF_REF_EXIT = 1 */
311 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
312 		/* PI_MC_PWRUP_SELF_REF_EXIT = 0 */
313 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
314 		/* PI_INT_LVL_EN = 0 */
315 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
316 		/* PI_WRLVL_EN_F0 = 3, PI_WRLVL_EN_F1 = 3 */
317 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x03030000);
318 		/* PI_WRLVL_EN_F2 = 3 */
319 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_175, 0x03);
320 		/* PI_CALVL_EN_F0 = 3, PI_CALVL_EN_F1 = 3 */
321 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x03030000);
322 		/* PI_CALVL_EN_F2 = 3 */
323 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_192, 0x03);
324 		/* PI_WDQLVL_EN_F0 = 3 */
325 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_212, 0x300);
326 		/* PI_WDQLVL_EN_F1 = 3 */
327 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_214, 0x03000000);
328 		/* PI_WDQLVL_EN_F2 = 3 */
329 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_217, 0x300);
330 		/* PI_EDLVL_EN_F0 = 3, PI_EDLVL_GATE_EN_F0 = 3 */
331 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
332 		/*
333 		 * PI_RDLVL_EN_F1 = 3, PI_RDLVL_GATE_EN_F1 = 3,
334 		 * PI_RDLVL_EN_F2 = 3, PI_RDLVL_GATE_EN_F2 = 3
335 		 */
336 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_182, 0x03030303);
337 		/* PI_PWRUP_SREFRESH_EXIT_CS = 0xF */
338 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
339 	} else {
340 		/* PI_DLL_RESET=1 */
341 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_137, 0x1);
342 		/* PI_PWRUP_SELF_REF_EXIT=1 */
343 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_132, 0x01000000);
344 		/* PI_MC_PWRUP_SELF_REF_EXIT=0 */
345 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_132, BIT(16));
346 		/* PI_INT_LVL_EN=0 */
347 		mmio_clrbits_32(IMX_DDRC_BASE + DENALI_PI_04, BIT(0));
348 		/* PI_WRLVL_EN_F0=3 */
349 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_174, 0x00030000);
350 		/* PI_CALVL_EN_F0=3 */
351 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_191, 0x00030000);
352 		/* PI_RDLVL_EN_F0=3,PI_RDLVL_GATE_EN_F0=3 */
353 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_181, 0x03030000);
354 		/* PI_PWRUP_SREFRESH_EXIT_CS=0xF */
355 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_134, 0x000F0000);
356 	}
357 
358 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x00002D00);
359 
360 	/* Force in-order AXI read data */
361 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_144, 0x1);
362 
363 	/*
364 	 * Disable special R/W group switches so that R/W group placement
365 	 * is always at END of R/W group.
366 	 */
367 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_249, 0x0);
368 
369 	/* Reduce time for IO pad calibration */
370 	mmio_write_32(IMX_DDRC_BASE + DENALI_PHY_1590, 0x01000000);
371 
372 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_25, 0x00020100);
373 
374 	/* PD disable */
375 	mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_153, 0x04040000);
376 	/*
377 	 * 5. Disable automatic LP entry and PCPCS modes LP_AUTO_ENTRY_EN
378 	 * to 1b'0, PCPCS_PD_EN to 1b'0
379 	 */
380 
381 	upwr_xcp_set_ddr_retention(APD_DOMAIN, 0, NULL);
382 	upower_wait_resp();
383 
384 	if (dram_class == LPDDR4_TYPE) {
385 		/* 7. Write PI START parameter to 1'b1 */
386 		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000b01);
387 
388 		/* 8. Write CTL START parameter to 1'b1 */
389 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000b01);
390 	} else {
391 		/* 7. Write PI START parameter to 1'b1 */
392 		mmio_write_32(IMX_DDRC_BASE + DENALI_PI_00, 0x00000701);
393 
394 		/* 8. Write CTL START parameter to 1'b1 */
395 		mmio_write_32(IMX_DDRC_BASE + DENALI_CTL_00, 0x00000701);
396 	}
397 
398 	/* 9. DENALI_CTL_266:  Wait for INT_STATUS_INIT=0x2 */
399 	do {
400 		val = (mmio_read_32(IMX_DDRC_BASE + DENALI_CTL_266) >> 8) & 0xFF;
401 	} while (val != 0x2);
402 
403 	/*
404 	 * 10. Run SW trainings by setting PI_CALVL_REQ,PI_WRLVL_REQ,PI_RDLVL_GATE_REQ,
405 	 * PI_RDLVL_REQ,PI_WDQLVL_REQ(NA for LPDDR3) in same order.
406 	 */
407 	if (dram_class == LPDDR4_TYPE) {
408 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
409 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
410 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
411 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
412 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_65, 0x10000); /* WDQLVL */
413 
414 		/* 11. Wait for trainings to get complete by polling PI_INT_STATUS */
415 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x07E00000) != 0x07E00000) {
416 			;
417 		}
418 	} else {
419 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_52, 0x10000); /* CALVL */
420 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_26, 0x100); /* WRLVL */
421 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x10000); /* RDGATE */
422 		mmio_setbits_32(IMX_DDRC_BASE + DENALI_PI_33, 0x100); /* RDQLVL */
423 		while ((mmio_read_32(IMX_DDRC_BASE + DENALI_PI_77) & 0x05E00000) != 0x05E00000) {
424 			;
425 		}
426 	}
427 }
428