xref: /rk3399_ARM-atf/drivers/st/ddr/phy/phyinit/usercustom/ddrphy_phyinit_usercustom_saveretregs.c (revision eaaf26e3e6ac347cbfda00b6ba7d327e715d68f0)
1 /*
2  * Copyright (C) 2021-2024, STMicroelectronics - All Rights Reserved
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdlib.h>
8 
9 #include <common/debug.h>
10 
11 #include <ddrphy_phyinit.h>
12 
13 #include <lib/mmio.h>
14 
15 #include <platform_def.h>
16 
17 /*
18  * This function can be used to implement saving of PHY registers to be
19  * restored on retention exit.
20  *
21  * The requirement of this function is to issue register reads and store the
22  * value to be recovered on retention exit. The following is an example
23  * implementation and the user may implement alternate methods that suit their
24  * specific SoC system needs.
25  *
26  * In this implementation PhyInit saves register values in an internal C array.
27  * During retention exit it restores register values from the array. The exact
28  * list of registers to save and later restore can be seen in the output txt
29  * file with an associated calls to mmio_read_16().
30  *
31  * PhyInit provides a register interface and a tracking mechanism to minimize
32  * the number registers needing restore. Refer to source code for
33  * ddrphy_phyinit_reginterface() for detailed implementation of tracking
34  * mechanism. Tracking is disabled from step D to Step H as these involve
35  * loading, executing and checking the state of training firmware execution
36  * which are not required to implement the retention exit sequence. The registers
37  * specified representing training results are also saved in addition to registers
38  * written by PhyInit during PHY initialization.
39  *
40  * \return 0 on success.
41  */
ddrphy_phyinit_usercustom_saveretregs(struct stm32mp_ddr_config * config)42 int ddrphy_phyinit_usercustom_saveretregs(struct stm32mp_ddr_config *config)
43 {
44 	uint32_t anib;
45 	uint32_t byte;
46 	uint32_t nibble;
47 	uint32_t lane;
48 	uint32_t c_addr;
49 	uint32_t u_addr;
50 	uint32_t b_addr;
51 	uint32_t r_addr;
52 	int ret;
53 
54 	/*
55 	 * --------------------------------------------------------------------------
56 	 * 1. Enable tracking of training firmware result registers
57 	 *
58 	 *    \note  The tagged registers in this step are in
59 	 *    addition to what is automatically tagged during Steps C to I.
60 	 *
61 	 * --------------------------------------------------------------------------
62 	 */
63 
64 	ret = ddrphy_phyinit_trackreg(TMASTER | CSR_PLLCTRL3_ADDR);
65 	if (ret != 0) {
66 		return ret;
67 	}
68 
69 	/* Non-PState Dbyte Registers */
70 	for (byte = 0U; byte < config->uib.numdbyte; byte++) {
71 		c_addr = byte << 12;
72 
73 		for (lane = 0U; lane <= R_MAX; lane++) {
74 			r_addr = lane << 8;
75 
76 			ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr |
77 						      CSR_RXPBDLYTG0_ADDR);
78 			if (ret != 0) {
79 				return ret;
80 			}
81 #if STM32MP_LPDDR4_TYPE
82 			ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr |
83 						      CSR_RXPBDLYTG1_ADDR);
84 			if (ret != 0) {
85 				return ret;
86 			}
87 #endif /* STM32MP_LPDDR4_TYPE */
88 		}
89 
90 #if STM32MP_LPDDR4_TYPE
91 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_PPTCTLSTATIC_ADDR);
92 		if (ret != 0) {
93 			return ret;
94 		}
95 
96 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_TRAININGINCDECDTSMEN_ADDR);
97 		if (ret != 0) {
98 			return ret;
99 		}
100 
101 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_TSMBYTE0_ADDR);
102 		if (ret != 0) {
103 			return ret;
104 		}
105 
106 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ0LNSEL_ADDR);
107 		if (ret != 0) {
108 			return ret;
109 		}
110 
111 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ1LNSEL_ADDR);
112 		if (ret != 0) {
113 			return ret;
114 		}
115 
116 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ2LNSEL_ADDR);
117 		if (ret != 0) {
118 			return ret;
119 		}
120 
121 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ3LNSEL_ADDR);
122 		if (ret != 0) {
123 			return ret;
124 		}
125 
126 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ4LNSEL_ADDR);
127 		if (ret != 0) {
128 			return ret;
129 		}
130 
131 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ5LNSEL_ADDR);
132 		if (ret != 0) {
133 			return ret;
134 		}
135 
136 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ6LNSEL_ADDR);
137 		if (ret != 0) {
138 			return ret;
139 		}
140 
141 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DQ7LNSEL_ADDR);
142 		if (ret != 0) {
143 			return ret;
144 		}
145 #endif /* STM32MP_LPDDR4_TYPE */
146 	}
147 
148 	ret = ddrphy_phyinit_trackreg(TMASTER | CSR_VREFINGLOBAL_ADDR);
149 	if (ret != 0) {
150 		return ret;
151 	}
152 
153 	/* Anib Registers */
154 	for (anib = 0U; anib < config->uib.numanib; anib++) {
155 		c_addr = anib << 12;
156 
157 		ret = ddrphy_phyinit_trackreg(TANIB | c_addr | CSR_ATXDLY_ADDR);
158 		if (ret != 0) {
159 			return ret;
160 		}
161 	}
162 
163 	/* Dbyte Registers */
164 	for (byte = 0U; byte < config->uib.numdbyte; byte++) {
165 		c_addr = byte << 12;
166 
167 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_DFIMRL_ADDR);
168 		if (ret != 0) {
169 			return ret;
170 		}
171 
172 		for (nibble = 0U; nibble <= B_MAX; nibble++) {
173 			b_addr = nibble << 8;
174 
175 			ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | b_addr |
176 						      CSR_DQDQSRCVCNTRL_ADDR);
177 			if (ret != 0) {
178 				return ret;
179 			}
180 		}
181 
182 		for (nibble = 0U; nibble < 2U; nibble++) {
183 			u_addr = nibble << 8;
184 
185 			ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
186 						      CSR_RXENDLYTG0_ADDR);
187 			if (ret != 0) {
188 				return ret;
189 			}
190 #if STM32MP_LPDDR4_TYPE
191 			ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
192 						      CSR_RXENDLYTG1_ADDR);
193 			if (ret != 0) {
194 				return ret;
195 			}
196 #endif /* STM32MP_LPDDR4_TYPE */
197 			ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
198 						      CSR_TXDQSDLYTG0_ADDR);
199 			if (ret != 0) {
200 				return ret;
201 			}
202 #if STM32MP_LPDDR4_TYPE
203 			ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
204 						      CSR_TXDQSDLYTG1_ADDR);
205 			if (ret != 0) {
206 				return ret;
207 			}
208 #endif /* STM32MP_LPDDR4_TYPE */
209 			ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
210 						      CSR_RXCLKDLYTG0_ADDR);
211 			if (ret != 0) {
212 				return ret;
213 			}
214 #if STM32MP_LPDDR4_TYPE
215 			ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | u_addr |
216 						      CSR_RXCLKDLYTG1_ADDR);
217 			if (ret != 0) {
218 				return ret;
219 			}
220 #endif /* STM32MP_LPDDR4_TYPE */
221 		}
222 
223 		for (lane = R_MIN; lane <= R_MAX; lane++) {
224 			r_addr = lane << 8;
225 
226 			ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr |
227 						      CSR_TXDQDLYTG0_ADDR);
228 			if (ret != 0) {
229 				return ret;
230 			}
231 #if STM32MP_LPDDR4_TYPE
232 			ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | r_addr |
233 						      CSR_TXDQDLYTG1_ADDR);
234 			if (ret != 0) {
235 				return ret;
236 			}
237 #endif /* STM32MP_LPDDR4_TYPE */
238 		}
239 
240 #if STM32MP_LPDDR4_TYPE
241 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_PPTDQSCNTINVTRNTG0_ADDR);
242 		if (ret != 0) {
243 			return ret;
244 		}
245 		ret = ddrphy_phyinit_trackreg(TDBYTE | c_addr | CSR_PPTDQSCNTINVTRNTG1_ADDR);
246 		if (ret != 0) {
247 			return ret;
248 		}
249 #endif /* STM32MP_LPDDR4_TYPE */
250 	}
251 
252 	/* PIE Registers */
253 	ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR1_ADDR);
254 	if (ret != 0) {
255 		return ret;
256 	}
257 
258 	ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR2_ADDR);
259 	if (ret != 0) {
260 		return ret;
261 	}
262 
263 	ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR3_ADDR);
264 	if (ret != 0) {
265 		return ret;
266 	}
267 
268 	ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR4_ADDR);
269 	if (ret != 0) {
270 		return ret;
271 	}
272 
273 	ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR5_ADDR);
274 	if (ret != 0) {
275 		return ret;
276 	}
277 
278 	ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR6_ADDR);
279 	if (ret != 0) {
280 		return ret;
281 	}
282 
283 	ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR7_ADDR);
284 	if (ret != 0) {
285 		return ret;
286 	}
287 
288 	ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BGPR8_ADDR);
289 	if (ret != 0) {
290 		return ret;
291 	}
292 
293 	/* Master Registers */
294 	ret = ddrphy_phyinit_trackreg(TMASTER | CSR_DLLGAINCTL_ADDR);
295 	if (ret != 0) {
296 		return ret;
297 	}
298 
299 	ret = ddrphy_phyinit_trackreg(TMASTER | CSR_DLLLOCKPARAM_ADDR);
300 	if (ret != 0) {
301 		return ret;
302 	}
303 #if STM32MP_LPDDR4_TYPE
304 	ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTMRL_ADDR);
305 	if (ret != 0) {
306 		return ret;
307 	}
308 
309 	/* INITENG Registers */
310 	ret = ddrphy_phyinit_trackreg(TINITENG | CSR_SEQ0BDISABLEFLAG6_ADDR);
311 	if (ret != 0) {
312 		return ret;
313 	}
314 #endif /* STM32MP_LPDDR4_TYPE */
315 
316 	ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTCAMODE_ADDR);
317 	if (ret != 0) {
318 		return ret;
319 	}
320 
321 #if STM32MP_LPDDR4_TYPE
322 	ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTLPCSENA_ADDR);
323 	if (ret != 0) {
324 		return ret;
325 	}
326 
327 	ret = ddrphy_phyinit_trackreg(TMASTER | CSR_HWTLPCSENB_ADDR);
328 	if (ret != 0) {
329 		return ret;
330 	}
331 
332 	/* ACSM registers */
333 	ret = ddrphy_phyinit_trackreg(TACSM | CSR_ACSMCTRL13_ADDR);
334 	if (ret != 0) {
335 		return ret;
336 	}
337 
338 	ret = ddrphy_phyinit_trackreg(TACSM | CSR_ACSMCTRL23_ADDR);
339 	if (ret != 0) {
340 		return ret;
341 	}
342 #endif /* STM32MP_LPDDR4_TYPE */
343 
344 	/*
345 	 * --------------------------------------------------------------------------
346 	 * 2. Track any additional registers
347 	 *    Register writes made using the any of the PhyInit functions are
348 	 *    automatically tracked using the call to ddrphy_phyinit_trackreg() in
349 	 *    mmio_write_16(). Use this section to track additional registers.
350 	 * --------------------------------------------------------------------------
351 	 */
352 
353 	/*
354 	 * Example:
355 	 * ddrphy_phyinit_trackreg(<addr>);
356 	 */
357 
358 	/*
359 	 * --------------------------------------------------------------------------
360 	 * 3. Prepare for register reads
361 	 *    - Write the MicroContMuxSel CSR to 0x0 to allow access to the internal CSRs
362 	 *    - Write the UcclkHclkEnables CSR to 0x3 to enable all the clocks so the reads
363 	 *      can complete.
364 	 * --------------------------------------------------------------------------
365 	 */
366 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
367 		      0x0U);
368 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDRTUB | CSR_UCCLKHCLKENABLES_ADDR))),
369 		      0x3U);
370 
371 	/*
372 	 * --------------------------------------------------------------------------
373 	 * / 4. Read and save all the registers
374 	 * /    - The list of registers differ depending on protocol and 1D training.
375 	 * --------------------------------------------------------------------------
376 	 */
377 
378 	ret = ddrphy_phyinit_reginterface(SAVEREGS, 0U, 0U);
379 	if (ret != 0) {
380 		return ret;
381 	}
382 
383 	/*
384 	 * --------------------------------------------------------------------------
385 	 * 5. Prepare for mission mode
386 	 *  - Write the UcclkHclkEnables CSR to disable the appropriate clocks after all reads done.
387 	 *  - Write the MicroContMuxSel CSR to 0x1 to isolate the internal CSRs during mission mode.
388 	 * --------------------------------------------------------------------------
389 	 */
390 
391 	/* Disabling Ucclk (PMU) and Hclk (training hardware) */
392 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDRTUB | CSR_UCCLKHCLKENABLES_ADDR))),
393 		      0x0U);
394 
395 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
396 		      0x1U);
397 
398 	return 0;
399 }
400