xref: /rk3399_ARM-atf/drivers/st/ddr/phy/phyinit/src/ddrphy_phyinit_i_loadpieimage.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 <arch_helpers.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 #if STM32MP_LPDDR4_TYPE
18 /*
19  * Program DfiWrRdDataCsConfig
20  * - Fields:
21  *   - dfiwrdatacspolarity
22  *   - dfirddatacspolarity
23  */
dfiwrrddatacsconfig_program(void)24 static void dfiwrrddatacsconfig_program(void)
25 {
26 	uint16_t dfiwrdatacspolarity;
27 	uint16_t dfirddatacspolarity;
28 
29 	/*
30 	 * DfiWrRdDataCsConfig : dfiwrdatacspolarity=0x1 and dfirddatacspolarity=0x1.
31 	 * Set DataCsPolarity bits to enable active high
32 	 */
33 	dfiwrdatacspolarity = 0x1U;
34 	dfirddatacspolarity = 0x1U;
35 
36 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | C0 |
37 							CSR_DFIWRRDDATACSCONFIG_ADDR))),
38 		      (dfiwrdatacspolarity << CSR_DFIWRDATACSPOLARITY_LSB) |
39 		      (dfirddatacspolarity << CSR_DFIRDDATACSPOLARITY_LSB));
40 }
41 #endif /* STM32MP_LPDDR4_TYPE */
42 
43 /*
44  * Registers: Seq0BDLY0, Seq0BDLY1, Seq0BDLY2, Seq0BDLY3
45  * - Program PIE instruction delays
46  * - Dependencies:
47  *   - user_input_basic.frequency
48  */
seq0bdly_program(struct stm32mp_ddr_config * config)49 static void seq0bdly_program(struct stm32mp_ddr_config *config)
50 {
51 	uint16_t lowfreqopt __unused;
52 	uint16_t dfifrq_x10;
53 	uint16_t pscount_ref;
54 	uint16_t pscount[4]; /* Need delays for 0.5us, 1us, 10us, and 25us */
55 
56 	/*
57 	 * Calculate the counts to obtain the correct delay for each frequency
58 	 * Need to divide by 4 since the delay value are specified in units of
59 	 * 4 clocks.
60 	 */
61 	dfifrq_x10 = (10U * (uint16_t)config->uib.frequency) / 2U;
62 	pscount_ref = dfifrq_x10 / 4U;
63 	pscount[0] = pscount_ref / (2U * 10U);
64 
65 #if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
66 	if (config->uib.frequency < 400U) {
67 		lowfreqopt = 3U;
68 	} else if (config->uib.frequency < 533U) {
69 		lowfreqopt = 11U;
70 	} else {
71 		lowfreqopt = 0U;
72 	}
73 
74 	pscount[1] = (pscount_ref / 10U) - lowfreqopt;
75 #else /* STM32MP_LPDDR4_TYPE */
76 	pscount[1] = pscount_ref / 10U;
77 #endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
78 	pscount[2] = pscount_ref;
79 
80 	if (dfifrq_x10 > 2665U) {
81 		pscount[3] = 44U;
82 	} else if ((dfifrq_x10 <= 2665U) && (dfifrq_x10 > 2000U)) {
83 		pscount[3] = 33U;
84 	} else {
85 		pscount[3] = 16U;
86 	}
87 
88 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TMASTER | CSR_SEQ0BDLY0_ADDR))),
89 		      pscount[0]);
90 
91 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TMASTER | CSR_SEQ0BDLY1_ADDR))),
92 		      pscount[1]);
93 
94 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TMASTER | CSR_SEQ0BDLY2_ADDR))),
95 		      pscount[2]);
96 
97 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TMASTER | CSR_SEQ0BDLY3_ADDR))),
98 		      pscount[3]);
99 }
100 
101 /*
102  * Registers: Seq0BDisableFlag0..7
103  * - Program PIE Instruction Disable Flags
104  * - Dependencies:
105  *   - user_input_advanced.DisableRetraining (LPDDR4)
106  *   - skip_training (LPDDR4)
107  *   - user_input_basic.frequency (LPDDR4)
108  */
seq0bdisableflag_program(struct stm32mp_ddr_config * config,bool skip_training)109 static void seq0bdisableflag_program(struct stm32mp_ddr_config *config, bool skip_training)
110 {
111 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG0_ADDR))),
112 		      0x0000U);
113 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG1_ADDR))),
114 		      0x0173U);
115 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG2_ADDR))),
116 		      0x0060U);
117 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG3_ADDR))),
118 		      0x6110U);
119 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG4_ADDR))),
120 		      0x2152U);
121 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG5_ADDR))),
122 		      0xDFBDU);
123 
124 #if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
125 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG6_ADDR))),
126 		      0xFFFFU);
127 #else /* STM32MP_LPDDR4_TYPE */
128 	if (skip_training || (config->uia.disableretraining != 0U) ||
129 	    (config->uib.frequency < 333U)) {
130 		/* Disabling DRAM drift compensation */
131 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG |
132 								CSR_SEQ0BDISABLEFLAG6_ADDR))),
133 			      0xFFFFU);
134 	} else {
135 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG |
136 								CSR_SEQ0BDISABLEFLAG6_ADDR))),
137 			      0x2060U);
138 	}
139 #endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
140 
141 	/*
142 	 * - Register: Seq0BGPR7
143 	 *   - Program active CSx for MRS7 during D4 RDIMM frequency change
144 	 */
145 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BDISABLEFLAG7_ADDR))),
146 		      0x6152U);
147 }
148 
149 #if STM32MP_LPDDR4_TYPE
150 /*
151  * Registers: ppttrainsetup and ppttrainsetup2
152  * - Related to DFI PHY Master Interface (PMI).
153  * - Enable DFI PMI if training firmware was run
154  * - Fields:
155  *   - PhyMstrTrainInterval
156  *   - PhyMstrMaxReqToAck
157  *   - PhyMstrFreqOverride
158  * - Dependencies:
159  *   - user_input_basic.frequency
160  *   - user_input_advanced.PhyMstrTrainInterval
161  *   - user_input_advanced.PhyMstrMaxReqToAck
162  */
ppttrainsetup_program(struct stm32mp_ddr_config * config)163 static void ppttrainsetup_program(struct stm32mp_ddr_config *config)
164 {
165 	uint16_t ppttrainsetup;
166 
167 	/* Enabling Phy Master Interface for DRAM drift compensation */
168 	if (config->uib.frequency >= 333U) {
169 		ppttrainsetup =	(uint16_t)((config->uia.phymstrtraininterval <<
170 					    CSR_PHYMSTRTRAININTERVAL_LSB) |
171 					   (config->uia.phymstrmaxreqtoack <<
172 					    CSR_PHYMSTRMAXREQTOACK_LSB));
173 
174 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_PPTTRAINSETUP_ADDR))),
175 			      ppttrainsetup);
176 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER |
177 								CSR_PPTTRAINSETUP2_ADDR))),
178 			      0x0003U);
179 	}
180 }
181 
182 /*
183  * Registers AcsmPlayback*x*
184  * - Program Address/Command Sequence Engine (ACSM) registers with
185  *   required instructions for retraining algorithm.
186  */
acsmplayback_program(void)187 static void acsmplayback_program(void)
188 {
189 	uint32_t vec;
190 
191 	for (vec = 0U; vec < 3U; vec++) {
192 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TACSM | (CSR_ACSMPLAYBACK0X0_ADDR +
193 									 (vec * 2U))))),
194 			      0xE0U);
195 
196 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TACSM | (CSR_ACSMPLAYBACK1X0_ADDR +
197 									 (vec * 2U))))),
198 			      0x12U);
199 	}
200 }
201 
202 /*
203  * Program Training Hardware Registers for mission mode retraining
204  * and DRAM drift compensation algorithm.
205  */
traininghwreg_program(struct stm32mp_ddr_config * config)206 static void traininghwreg_program(struct stm32mp_ddr_config *config)
207 {
208 	uint32_t byte;
209 
210 	/* Programing Training Hardware Registers for mission mode retraining */
211 
212 	/*
213 	 * - Register: AcsmCtrl13
214 	 *   - Fields: AcsmCkeEnb
215 	 */
216 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TACSM | CSR_ACSMCTRL13_ADDR))),
217 		      0xFU << CSR_ACSMCKEENB_LSB);
218 
219 	/*
220 	 * - Register: AcsmCtrl1
221 	 *   - Fields: AcsmRepCnt
222 	 *             Need 19 iterations @ 0.25ui increments to cover 4.5UI
223 	 */
224 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TACSM | CSR_ACSMCTRL1_ADDR))),
225 		      0xEU << CSR_ACSMREPCNT_LSB);
226 
227 	/*
228 	 * - Register: TsmByte1, TsmByte2
229 	 *   - Dependencies: config->uib.numdbyte
230 	 */
231 
232 	for (byte = 0U; byte < config->uib.numdbyte; byte++) {
233 		uint32_t c_addr;
234 		uint32_t i_addr;
235 		uint16_t regdata;
236 		uint32_t vec;
237 
238 		c_addr = byte * C1;
239 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
240 								CSR_TSMBYTE1_ADDR))),
241 			      0x1U);   /* [15:8] gstep; [7:0]bstep; */
242 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
243 								CSR_TSMBYTE2_ADDR))),
244 			      0x1U);   /* [15:0] good_bar; */
245 
246 		regdata = (CSR_DTSMSTATICCMPR_MASK | CSR_DTSMSTATICCMPRVAL_MASK);
247 
248 		/*
249 		 * - Register: TsmByte3, TsmByte5
250 		 *   - Fields:
251 		 *     - DtsmStaticCmpr
252 		 *     - DtsmStaticCmprVal
253 		 */
254 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
255 								CSR_TSMBYTE3_ADDR))),
256 			      regdata);
257 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
258 								CSR_TSMBYTE5_ADDR))),
259 			      0x1U); /* [15:0] bad_bar; */
260 
261 		/*
262 		 * - Register: TrainingParam
263 		 *   - Fields:
264 		 *     - EnDynRateReduction
265 		 *     - RollIntoCoarse
266 		 *     - IncDecRate
267 		 *     - TrainEnRxEn
268 		 *   - Dependencies:
269 		 *     - user_input_advanced.DisableRetraining
270 		 */
271 		regdata = (CSR_ENDYNRATEREDUCTION_MASK | CSR_ROLLINTOCOARSE_MASK |
272 			   (0x3U << CSR_INCDECRATE_LSB));
273 		regdata = config->uia.disableretraining ?
274 			  regdata : (regdata | CSR_TRAINENRXEN_MASK);
275 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
276 								CSR_TRAININGPARAM_ADDR))),
277 			      regdata);
278 
279 		/*
280 		 * - Register: Tsm0
281 		 *   - Fields:
282 		 *     - DtsmEnb
283 		 */
284 		regdata = (0x1U << CSR_DTSMENB_LSB);
285 		mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | I0 | TDBYTE |
286 								CSR_TSM0_ADDR))),
287 			      regdata);
288 
289 		/*
290 		 * - Register: Tsm2
291 		 *   - Fields:
292 		 *     - DtsmDisErrChk
293 		 */
294 		regdata = (0x1U << CSR_DTSMDISERRCHK_LSB);
295 		for (vec = 1U; vec <= I_MAX; vec++) {
296 			i_addr = vec * I1;
297 			mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | i_addr | TDBYTE |
298 									CSR_TSM2_ADDR))),
299 				      regdata);
300 		}
301 	}
302 }
303 #endif /* STM32MP_LPDDR4_TYPE */
304 
305 /*
306  * - Register: calrate
307  *   - Fields:
308  *     - calOnce
309  *     - calinterval
310  *   - Dependencies
311  *     - user_input_advanced.calinterval
312  *     - user_input_advanced.calonce
313  */
calrate_program(struct stm32mp_ddr_config * config)314 static void calrate_program(struct stm32mp_ddr_config *config)
315 {
316 	uint32_t calinterval;
317 	uint32_t calonce;
318 	uint16_t calrate;
319 
320 	calinterval = config->uia.calinterval;
321 	calonce = config->uia.calonce;
322 
323 	calrate = (uint16_t)((0x1U << CSR_CALRUN_LSB) | (calonce << CSR_CALONCE_LSB) |
324 			     (calinterval << CSR_CALINTERVAL_LSB));
325 
326 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_CALRATE_ADDR))), calrate);
327 }
328 
329 /*
330  * Loads registers after training
331  *
332  * This function programs the PHY Initialization Engine (PIE) instructions and
333  * the associated registers.
334  * Training hardware registers are also programmed to for mission mode
335  * retraining. (LPDDR4)
336  *
337  * \return void
338  */
ddrphy_phyinit_i_loadpieimage(struct stm32mp_ddr_config * config,bool skip_training)339 void ddrphy_phyinit_i_loadpieimage(struct stm32mp_ddr_config *config, bool skip_training)
340 {
341 	/*
342 	 * Enable access to the internal CSRs by setting the MicroContMuxSel CSR to 0.
343 	 * This allows the memory controller unrestricted access to the configuration CSRs.
344 	 */
345 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
346 		      0x0U);
347 
348 	ddrphy_phyinit_loadpieprodcode();
349 
350 #if STM32MP_LPDDR4_TYPE
351 	/*
352 	 * No user specified EnableDfiCsPolarityFix, running with new PUB with DFI CS polarity fix
353 	 * so program the data polarity CSR.
354 	 */
355 	dfiwrrddatacsconfig_program();
356 #endif /* STM32MP_LPDDR4_TYPE */
357 
358 	seq0bdly_program(config);
359 
360 	seq0bdisableflag_program(config, skip_training);
361 
362 #if STM32MP_LPDDR4_TYPE
363 	if (!skip_training) {
364 		ppttrainsetup_program(config);
365 	}
366 
367 	acsmplayback_program();
368 
369 	traininghwreg_program(config);
370 #endif /* STM32MP_LPDDR4_TYPE */
371 
372 	/*
373 	 * - Register: CalZap
374 	 *   - Prepare the calibration controller for mission mode.
375 	 *     Turn on calibration and hold idle until dfi_init_start is asserted sequence is
376 	 *     triggered.
377 	 */
378 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_CALZAP_ADDR))), 0x1U);
379 
380 	calrate_program(config);
381 
382 	/*
383 	 * At the end of this function, PHY Clk gating register UcclkHclkEnables is
384 	 * set for mission mode.  Additionally APB access is Isolated by setting
385 	 * MicroContMuxSel.
386 	 */
387 	/* Disabling Ucclk (PMU) and Hclk (training hardware) */
388 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDRTUB | CSR_UCCLKHCLKENABLES_ADDR))),
389 		      0x0U);
390 
391 	/* Isolate the APB access from the internal CSRs by setting the MicroContMuxSel CSR to 1 */
392 	mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TAPBONLY | CSR_MICROCONTMUXSEL_ADDR))),
393 		      0x1U);
394 }
395