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