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 #include <ddrphy_wrapper.h>
13
14 #include <lib/mmio.h>
15
16 #include <platform_def.h>
17
18 struct phyinit_timings {
19 int tstaoff;
20 int tpdm;
21 int tcasl_add;
22 };
23
24 static struct phyinit_timings timings;
25
26 /*
27 * Program dfimrl according to this formula:
28 *
29 * dfimrl = ceiling( (ARdPtrinitval*UI + phy_tx_insertion_dly +
30 * phy_rx_insertion_dly + PHY_Rx_Fifo_dly + tDQSCK + tstaoff) /
31 * dficlk_period)
32 *
33 * All terms in above equation specified in ps
34 * tDQSCK - determine from memory model
35 * tstaoff - determine from memory model
36 * phy_tx_insertion_dly = 200ps
37 * phy_rx_insertion_dly = 200ps
38 * phy_rx_fifo_dly = 200ps + 4UI
39 */
dfimrl_program(struct stm32mp_ddr_config * config,struct pmu_smb_ddr_1d * mb_ddr_1d,int ardptrinitval)40 static void dfimrl_program(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d,
41 int ardptrinitval)
42 {
43 uint32_t byte;
44 int dfimrl_in_dficlk;
45 int phy_rx_fifo_dly;
46 int phy_rx_insertion_dly = 200;
47 int phy_tx_insertion_dly = 200;
48 long long dficlk_period_x1000;
49 long long dfimrl_in_fs;
50 long long uifs;
51 uint16_t dfimrl;
52
53 uifs = (1000 * 1000000) / ((int)config->uib.frequency * 2);
54 dficlk_period_x1000 = 4 * uifs;
55
56 phy_rx_fifo_dly = (int)(((200 * 1000) + (4 * uifs)) / 1000);
57
58 dfimrl_in_fs = (ardptrinitval * uifs) +
59 ((phy_tx_insertion_dly + phy_rx_insertion_dly + phy_rx_fifo_dly +
60 timings.tstaoff + timings.tcasl_add + timings.tpdm) * 1000);
61
62 dfimrl_in_dficlk = (int)(dfimrl_in_fs / dficlk_period_x1000);
63 if ((dfimrl_in_fs % dficlk_period_x1000) != 0) {
64 dfimrl_in_dficlk++;
65 }
66 dfimrl = (uint16_t)(dfimrl_in_dficlk + mb_ddr_1d->dfimrlmargin);
67
68 /*
69 * mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDBYTE | CBRD | CSR_DFIMRL_ADDR))),
70 * dfimrl);
71 */
72 for (byte = 0U; byte < config->uib.numdbyte; byte++) {
73 uint32_t c_addr;
74
75 c_addr = byte << 12;
76 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TDBYTE | c_addr |
77 CSR_DFIMRL_ADDR))),
78 dfimrl);
79 }
80
81 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTMRL_ADDR))), dfimrl);
82 }
83
84 /*
85 * Program txdqsdlytg0/1[9:0]:
86 *
87 * txdqsdlytg*[9:6] = floor( (4*UI + tstaoff) / UI)
88 * txdqsdlytg*[5:0] = ceiling( (tstaoff%UI / UI) * 32)
89 *
90 * tstaoff and UI expressed in ps
91 *
92 * For HMD and LPDDR4X and MEMCLK <= 533 mhz:
93 * txdqsdlytg*[9:6] = 0x5
94 *
95 * For other dimm types, leave TDqsDlyTg*[9:0] at default 0x100
96 *
97 * ppp_0001_cccc_uuuu_1101_0000
98 *
99 * if DDR3 or DDR4
100 * num_timingroup = numrank_dfi0;
101 * else
102 * num_timingroup = numrank_dfi0 + numrank_dfi1 * dfi1exists;
103 */
txdqsdlytg_program(struct stm32mp_ddr_config * config,struct pmu_smb_ddr_1d * mb_ddr_1d,uint16_t * txdqsdly)104 static void txdqsdlytg_program(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d,
105 uint16_t *txdqsdly)
106 {
107 uint32_t byte;
108 int txdqsdlytg_5to0; /* Fine delay - 1/32UI per increment */
109 int txdqsdlytg_9to6; /* Coarse delay - 1UI per increment */
110 int txdqsdlytg_fine_default = 0;
111 int txdqsdlytg_coarse_default = 4;
112 long long tmp_value;
113 long long uifs;
114
115 uifs = (1000 * 1000000) / ((int)config->uib.frequency * 2);
116
117 txdqsdlytg_9to6 = (int)(((int)((txdqsdlytg_coarse_default * uifs) / 1000) +
118 timings.tstaoff + timings.tcasl_add
119 - timings.tpdm) / (int)(uifs / 1000));
120
121 tmp_value = fmodll(((txdqsdlytg_fine_default * uifs / 32) +
122 ((timings.tstaoff + timings.tcasl_add) * 1000) -
123 (timings.tpdm * 1000)),
124 uifs);
125 txdqsdlytg_5to0 = (int)(tmp_value / uifs * 32);
126 if ((tmp_value % uifs) != 0) {
127 txdqsdlytg_5to0++;
128 }
129
130 /* Bit-5 of LCDL is no longer used, so bumping bit-5 of fine_dly up to coarse_dly */
131 if (txdqsdlytg_5to0 >= 32) {
132 txdqsdlytg_9to6 = txdqsdlytg_9to6 + 1;
133 txdqsdlytg_5to0 = txdqsdlytg_5to0 - 32;
134 }
135
136 *txdqsdly = (uint16_t)((txdqsdlytg_9to6 << 6) | txdqsdlytg_5to0);
137
138 for (byte = 0U; byte < config->uib.numdbyte; byte++) {
139 uint32_t c_addr;
140 uint32_t nibble;
141
142 c_addr = byte << 12;
143 for (nibble = 0U; nibble < 2U; nibble++) {
144 uint32_t u_addr;
145
146 if (ddrphy_phyinit_isdbytedisabled(config, mb_ddr_1d, byte) != 0) {
147 continue;
148 }
149
150 u_addr = nibble << 8;
151
152 #if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
153 if ((mb_ddr_1d->cspresent & 0x1U) != 0U) {
154 #else /* STM32MP_LPDDR4_TYPE */
155 if (((mb_ddr_1d->cspresentcha & 0x1U) |
156 (mb_ddr_1d->cspresentchb & 0x1U)) != 0U) {
157 #endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
158 mmio_write_16((uintptr_t)
159 (DDRPHYC_BASE + (4U * (TDBYTE | c_addr | u_addr |
160 CSR_TXDQSDLYTG0_ADDR))),
161 *txdqsdly);
162 }
163
164 #if STM32MP_LPDDR4_TYPE
165 if ((((mb_ddr_1d->cspresentcha & 0x2U) >> 1) |
166 ((mb_ddr_1d->cspresentchb & 0x2U) >> 1)) != 0U) {
167 mmio_write_16((uintptr_t)
168 (DDRPHYC_BASE + (4U * (TDBYTE | c_addr | u_addr |
169 CSR_TXDQSDLYTG1_ADDR))),
170 *txdqsdly);
171 }
172 #endif /* STM32MP_LPDDR4_TYPE */
173 }
174 }
175 }
176
177 /*
178 * ##############################################################
179 *
180 * Program txdqdlyTg0/1[8:0]:
181 *
182 * txdqdlyTg*[8:6] = floor( (txdqsdlytg*[5:0]*UI/32 + tDQS2DQ + 0.5UI) / UI)
183 * txdqdlyTg*[5:0] = ceil( ((txdqsdlytg*[5:0]*UI/32 + tDQS2DQ + 0.5UI)%UI / UI) * 32)
184 *
185 * ##############################################################
186 */
187 static void txdqdlytg_program(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d,
188 uint16_t txdqsdly)
189 {
190 uint32_t byte;
191 int txdqdly_5to0; /* Fine delay - 1/32UI per increment */
192 int txdqdly_8to6; /* Coarse delay - 1UI per increment */
193 int txdqsdlytg_5to0; /* Fine delay - 1/32UI per increment */
194 long long tmp_value;
195 long long uifs;
196 uint16_t txdqdly;
197
198 uifs = (1000 * 1000000) / ((int)config->uib.frequency * 2);
199
200 txdqsdlytg_5to0 = (int)txdqsdly & 0x3F;
201
202 txdqdly_8to6 = (int)(((txdqsdlytg_5to0 * uifs / 32) + (uifs / 2)) / uifs);
203 tmp_value = fmodll(((txdqsdlytg_5to0 * uifs / 32) + (uifs / 2)), uifs);
204 txdqdly_5to0 = (int)(((tmp_value * 32) / uifs));
205 if ((tmp_value % uifs) != 0) {
206 txdqdly_5to0++;
207 }
208
209 /* Bit-5 of LCDL is no longer used, so bumping bit-5 of fine_dly up to coarse_dly */
210 if (txdqdly_5to0 >= 32) {
211 txdqdly_8to6 = txdqdly_8to6 + 1;
212 txdqdly_5to0 = txdqdly_5to0 - 32;
213 }
214
215 txdqdly = (uint16_t)((txdqdly_8to6 << 6) | txdqdly_5to0);
216
217 for (byte = 0U; byte < config->uib.numdbyte; byte++) {
218 uint32_t c_addr;
219 uint32_t lane;
220
221 c_addr = byte << 12;
222 for (lane = 0U; lane < 9U; lane++) {
223 uint32_t r_addr;
224
225 if (ddrphy_phyinit_isdbytedisabled(config, mb_ddr_1d, byte) != 0) {
226 continue;
227 }
228
229 r_addr = lane << 8;
230
231 #if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
232 if ((mb_ddr_1d->cspresent & 0x1U) != 0U) {
233 #else /* STM32MP_LPDDR4_TYPE */
234 if (((mb_ddr_1d->cspresentcha & 0x1U) |
235 (mb_ddr_1d->cspresentchb & 0x1U)) != 0U) {
236 #endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
237 mmio_write_16((uintptr_t)
238 (DDRPHYC_BASE + (4U * (TDBYTE | c_addr | r_addr |
239 CSR_TXDQDLYTG0_ADDR))),
240 txdqdly);
241 }
242
243 #if STM32MP_LPDDR4_TYPE
244 if ((((mb_ddr_1d->cspresentcha & 0x2U) >> 1) |
245 ((mb_ddr_1d->cspresentchb & 0x2U) >> 1)) != 0U) {
246 mmio_write_16((uintptr_t)
247 (DDRPHYC_BASE + (4U * (TDBYTE | c_addr | r_addr |
248 CSR_TXDQDLYTG1_ADDR))),
249 txdqdly);
250 }
251 #endif /* STM32MP_LPDDR4_TYPE */
252 }
253 }
254 }
255
256 /*
257 * Program rxendly0/1[10:0]:
258 *
259 * rxendly[10:6] = floor( (4*UI + tDQSCK + tstaoff) / UI)
260 * rxendly[5:0] = ceil( ((tDQSCK + tstaoff) % UI) * 32)
261 *
262 * tDQSCK, tstaoff and UI expressed in ps
263 */
264 static void rxendly_program(struct stm32mp_ddr_config *config, struct pmu_smb_ddr_1d *mb_ddr_1d)
265 {
266 int rxendly_coarse_default = 4;
267 int rxendly_fine_default = 0;
268
269 int backoff_x1000 __maybe_unused;
270 int zerobackoff_x1000 __maybe_unused;
271 uint32_t byte;
272 int rxendly_10to6; /* Coarse delay - 1UI per increment */
273 int rxendly_5to0; /* Fine delay - 1/32UI per increment */
274 int totfinestep;
275 long long finestepfs; /* Fine steps in fs */
276 long long rxendly_offset_x1000000 = 0; /* 0 Offset is 1UI before the first DQS. */
277 long long totfs;
278 long long uifs;
279 uint16_t rxendly;
280
281 uifs = (1000 * 1000000) / ((int)config->uib.frequency * 2);
282
283 #if STM32MP_LPDDR4_TYPE
284 /* Compensate for pptenrxenbackoff */
285 zerobackoff_x1000 = (1000 * 24) / 32;
286 if (config->uia.lp4rxpreamblemode == 1U) {
287 backoff_x1000 = 1000 - ((1000 * 2) / 32);
288 } else {
289 backoff_x1000 = (1000 * (int)config->uia.rxenbackoff) - ((1000 * 2) / 32);
290 }
291
292 if (config->uia.disableretraining == 0U) {
293 rxendly_offset_x1000000 = config->uib.frequency < 333U ?
294 backoff_x1000 * uifs : zerobackoff_x1000 * uifs;
295 } else {
296 rxendly_offset_x1000000 = zerobackoff_x1000 * uifs;
297 }
298 #endif /* STM32MP_LPDDR4_TYPE */
299
300 finestepfs = uifs / 32;
301 totfs = ((32 * rxendly_coarse_default * finestepfs) +
302 (rxendly_fine_default * finestepfs) +
303 ((timings.tstaoff + timings.tcasl_add +
304 timings.tpdm) * 1000) + (rxendly_offset_x1000000 / 1000));
305 totfinestep = totfs / finestepfs;
306
307 rxendly_10to6 = totfinestep / 32;
308 rxendly_5to0 = fmodi(totfinestep, 32);
309
310 /* Bit-5 of LCDL is no longer used, so bumping bit-5 of fine_dly up to coarse_dly */
311 if (rxendly_5to0 >= 32) {
312 rxendly_10to6 = rxendly_10to6 + 1;
313 rxendly_5to0 = rxendly_5to0 - 32;
314 }
315
316 rxendly = (uint16_t)((rxendly_10to6 << 6) | rxendly_5to0);
317
318 for (byte = 0U; byte < config->uib.numdbyte; byte++) {
319 uint32_t c_addr;
320 uint32_t nibble;
321
322 c_addr = byte << 12;
323 for (nibble = 0U; nibble < 2U; nibble++) {
324 uint32_t u_addr;
325
326 if (ddrphy_phyinit_isdbytedisabled(config, mb_ddr_1d, byte) != 0) {
327 continue;
328 }
329
330 u_addr = nibble << 8;
331
332 #if STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE
333 if ((mb_ddr_1d->cspresent & 0x1U) != 0) {
334 #else /* STM32MP_LPDDR4_TYPE */
335 if (((mb_ddr_1d->cspresentcha & 0x1U) |
336 (mb_ddr_1d->cspresentchb & 0x1U)) != 0U) {
337 #endif /* STM32MP_DDR3_TYPE || STM32MP_DDR4_TYPE */
338 mmio_write_16((uintptr_t)
339 (DDRPHYC_BASE + (4U * (TDBYTE | c_addr | u_addr |
340 CSR_RXENDLYTG0_ADDR))),
341 rxendly);
342 }
343
344 #if STM32MP_LPDDR4_TYPE
345 if ((((mb_ddr_1d->cspresentcha & 0x2U) >> 1) |
346 ((mb_ddr_1d->cspresentchb & 0x2U) >> 1)) != 0U) {
347 mmio_write_16((uintptr_t)
348 (DDRPHYC_BASE + (4U * (TDBYTE | c_addr | u_addr |
349 CSR_RXENDLYTG1_ADDR))),
350 rxendly);
351 }
352 #endif /* STM32MP_LPDDR4_TYPE */
353 }
354 }
355 }
356
357 #if STM32MP_LPDDR4_TYPE
358 /*
359 * Programming Seq0BGPR1/2/3 for LPDDR4
360 */
361 static void seq0bgpr_program(struct stm32mp_ddr_config *config)
362 {
363 uint32_t extradly = 3U;
364 uint32_t rl = 0U; /* Computed read latency */
365 uint32_t wl = 0U; /* Computed write latency */
366 uint16_t mr_dbi_rd; /* Extracted field from MR */
367 uint16_t mr_rl;
368 uint16_t mr_wl;
369 uint16_t mr_wls;
370 uint16_t regdata;
371
372 mr_rl = (uint16_t)config->uia.lp4rl; /* RL[2:0] */
373 mr_wl = (uint16_t)config->uia.lp4wl; /* WL[5:3] */
374 mr_wls = (uint16_t)config->uia.lp4wls; /* WLS */
375 mr_dbi_rd = (uint16_t)config->uia.lp4dbird; /* DBI-RD */
376
377 switch ((mr_dbi_rd << 3) | mr_rl) {
378 /* DBI-RD Disabled */
379 case 0U:
380 rl = 6U;
381 break;
382 case 1U:
383 rl = 10U;
384 break;
385 case 2U:
386 rl = 14U;
387 break;
388 case 3U:
389 rl = 20U;
390 break;
391 case 4U:
392 rl = 24U;
393 break;
394 case 5U:
395 rl = 28U;
396 break;
397 case 6U:
398 rl = 32U;
399 break;
400 case 7U:
401 rl = 36U;
402 break;
403 /* DBI-RD Enabled */
404 case 8U:
405 rl = 6U;
406 break;
407 case 9U:
408 rl = 12U;
409 break;
410 case 10U:
411 rl = 16U;
412 break;
413 case 11U:
414 rl = 22U;
415 break;
416 case 12U:
417 rl = 28U;
418 break;
419 case 13U:
420 rl = 32U;
421 break;
422 case 14U:
423 rl = 36U;
424 break;
425 case 15U:
426 rl = 40U;
427 break;
428 default:
429 rl = 6U;
430 break;
431 }
432
433 switch ((mr_wls << 3) | mr_wl) {
434 /* DBI-RD Disabled */
435 case 0U:
436 wl = 4U;
437 break;
438 case 1U:
439 wl = 6U;
440 break;
441 case 2U:
442 wl = 8U;
443 break;
444 case 3U:
445 wl = 10U;
446 break;
447 case 4U:
448 wl = 12U;
449 break;
450 case 5U:
451 wl = 14U;
452 break;
453 case 6U:
454 wl = 16U;
455 break;
456 case 7U:
457 wl = 18U;
458 break;
459 /* DBI-RD Enabled */
460 case 8U:
461 wl = 4U;
462 break;
463 case 9U:
464 wl = 8U;
465 break;
466 case 10U:
467 wl = 12U;
468 break;
469 case 11U:
470 wl = 18U;
471 break;
472 case 12U:
473 wl = 22U;
474 break;
475 case 13U:
476 wl = 26U;
477 break;
478 case 14U:
479 wl = 30U;
480 break;
481 case 15U:
482 wl = 34U;
483 break;
484 default:
485 wl = 4U;
486 break;
487 }
488
489 /* Program Seq0b_GPRx */
490 regdata = (uint16_t)((rl - 5U + extradly) << CSR_ACSMRCASLAT_LSB);
491 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (P0 | C0 | TINITENG | R2 |
492 CSR_SEQ0BGPR1_ADDR))),
493 regdata);
494
495 regdata = (uint16_t)((wl - 5U + extradly) << CSR_ACSMWCASLAT_LSB);
496 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (P0 | C0 | TINITENG | R2 |
497 CSR_SEQ0BGPR2_ADDR))),
498 regdata);
499
500 regdata = (uint16_t)((rl - 5U + extradly + 4U + 8U) << CSR_ACSMRCASLAT_LSB);
501 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (P0 | C0 | TINITENG | R2 |
502 CSR_SEQ0BGPR3_ADDR))),
503 regdata);
504 }
505
506 /*
507 * Program hwtlpcsena and hwtlpcsenb based on number of ranks per channel
508 * Applicable only for LPDDR4. These CSRs have no effect for DDR3/4.
509 *
510 * CSRs to program:
511 * hwtlpcsena
512 * hwtlpcsenb
513 *
514 * User input dependencies:
515 * config->uib.numrank_dfi0
516 * config->uib.numrank_dfi1
517 * config->uib.dfi1exists
518 * config->uib.numactivedbytedfi1
519 */
520 static void hwtlpcsen_program(struct stm32mp_ddr_config *config)
521 {
522 uint16_t hwtlpcsena;
523 uint16_t hwtlpcsenb;
524
525 /* Channel A - 1'b01 if signal-rank, 2'b11 if dual-rank */
526 hwtlpcsena = (uint16_t)config->uib.numrank_dfi0 | 0x1U;
527 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTLPCSENA_ADDR))),
528 hwtlpcsena);
529
530 /*
531 * Channel B - 1'b01 if signal-rank, 2'b11 if dual-rank
532 * If DFI1 exists but disabled, numrank_dfi0 is used to program CsEnB
533 */
534 if ((config->uib.dfi1exists != 0U) && (config->uib.numactivedbytedfi1 == 0U)) {
535 hwtlpcsenb = (uint16_t)config->uib.numrank_dfi0 | 0x1U;
536 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTLPCSENB_ADDR))),
537 hwtlpcsenb);
538 } else if ((config->uib.dfi1exists != 0U) && (config->uib.numactivedbytedfi1 > 0U)) {
539 hwtlpcsenb = (uint16_t)config->uib.numrank_dfi1 | 0x1U;
540 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTLPCSENB_ADDR))),
541 hwtlpcsenb);
542 } else {
543 /* Disable Channel B */
544 hwtlpcsenb = 0x0U;
545 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTLPCSENB_ADDR))),
546 hwtlpcsenb);
547 }
548 }
549
550 /*
551 * Program pptdqscntinvtrntg0 and pptdqscntinvtrntg1
552 * Calculated based on tDQS2DQ and Frequencey
553 * Applicable to LPDDR4 only
554 *
555 * 65536*(tdqs2dq_value_rank<rank>_chan<chan>*2)/(2*2048*UI(ps)_int)
556 *
557 * CSRs to program:
558 * pptdqscntinvtrntg0
559 * pptdqscntinvtrntg1
560 *
561 * User input dependencies:
562 * config->uib.numrank_dfi0
563 * config->uib.numrank_dfi1
564 * config->uib.dfi1exists
565 * config->uib.numdbyte
566 */
567 static void pptdqscntinvtrntg_program(struct stm32mp_ddr_config *config)
568 {
569 uint32_t numrank_total = config->uib.numrank_dfi0;
570 uint32_t rank;
571
572 /* Calculate total number of timing groups (ranks) */
573 if (config->uib.dfi1exists != 0U) {
574 numrank_total += config->uib.numrank_dfi1;
575 }
576
577 /* Set per timing group */
578 for (rank = 0U; rank < numrank_total; rank++) {
579 uint32_t byte;
580
581 for (byte = 0U; byte < config->uib.numdbyte; byte++) {
582 uint32_t c_addr;
583
584 c_addr = byte << 12;
585 if (rank == 0U) {
586 mmio_write_16((uintptr_t)
587 (DDRPHYC_BASE + (4U * (TDBYTE | c_addr |
588 CSR_PPTDQSCNTINVTRNTG0_ADDR))),
589 0U);
590 } else if (rank == 1U) {
591 mmio_write_16((uintptr_t)
592 (DDRPHYC_BASE + (4U * (TDBYTE | c_addr |
593 CSR_PPTDQSCNTINVTRNTG1_ADDR))),
594 0U);
595 }
596 }
597 }
598 }
599
600 /*
601 * CSRs to program:
602 * PptCtlStatic:: DOCByteSelTg0/1
603 * :: pptenrxenbackoff
604 *
605 * User input dependencies::
606 * config->uib.numdbyte
607 * config->uib.numrank_dfi0
608 * config->uib.numrank_dfi1
609 * config->uia.lp4rxpreamblemode
610 * config->uia.rxenbackoff
611 * config->uia.drambyteswap
612 */
613 static void pptctlstatic_program(struct stm32mp_ddr_config *config)
614 {
615 uint32_t byte;
616 uint32_t pptenrxenbackoff;
617
618 /*
619 * The customer will setup some fields in this csr so the fw needs to do a
620 * read-modify-write here.
621 */
622
623 if (config->uia.lp4rxpreamblemode == 1U) {
624 /* Rx-preamble mode for PS0 */
625 /* Programming PptCtlStatic detected toggling preamble */
626 pptenrxenbackoff = 0x1U; /* Toggling RD_PRE */
627 } else {
628 pptenrxenbackoff = config->uia.rxenbackoff; /* Static RD_PRE */
629 }
630
631 for (byte = 0U; byte < config->uib.numdbyte; byte++) {
632 uint32_t c_addr;
633 uint16_t regdata;
634 uint8_t pptentg1;
635 uint32_t docbytetg0;
636 uint32_t docbytetg1;
637
638 /* Each Dbyte could have a different configuration */
639 c_addr = byte * C1;
640 if ((byte % 2) == 0) {
641 docbytetg0 = 0x1U & (config->uia.drambyteswap >> byte);
642 docbytetg1 = 0x1U & (config->uia.drambyteswap >> byte);
643 } else {
644 docbytetg0 = 0x1U & (~(config->uia.drambyteswap >> byte));
645 docbytetg1 = 0x1U & (~(config->uia.drambyteswap >> byte));
646 }
647
648 pptentg1 = ((config->uib.numrank_dfi0 == 2U) || (config->uib.numrank_dfi1 == 2U)) ?
649 0x1U : 0x0U;
650 regdata = (uint16_t)((0x1U << CSR_PPTENDQS2DQTG0_LSB) |
651 (pptentg1 << CSR_PPTENDQS2DQTG1_LSB) |
652 (0x1U << CSR_PPTENRXENDLYTG0_LSB) |
653 (pptentg1 << CSR_PPTENRXENDLYTG1_LSB) |
654 (pptenrxenbackoff << CSR_PPTENRXENBACKOFF_LSB) |
655 (docbytetg0 << CSR_DOCBYTESELTG0_LSB) |
656 (docbytetg1 << CSR_DOCBYTESELTG1_LSB));
657
658 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (c_addr | TDBYTE |
659 CSR_PPTCTLSTATIC_ADDR))),
660 regdata);
661 }
662 }
663 #endif /* STM32MP_LPDDR4_TYPE */
664
665 /*
666 * Program hwtcamode based on dram type
667 *
668 * CSRs to program:
669 * hwtcamode::hwtlp3camode
670 * ::hwtd4camode
671 * ::hwtlp4camode
672 * ::hwtd4altcamode
673 * ::hwtcsinvert
674 * ::hwtdbiinvert
675 */
676 static void hwtcamode_program(void)
677 {
678 uint32_t hwtlp3camode = 0U;
679 uint32_t hwtd4camode = 0U;
680 uint32_t hwtlp4camode = 0U;
681 uint32_t hwtd4altcamode = 0U;
682 uint32_t hwtcsinvert = 0U;
683 uint32_t hwtdbiinvert = 0U;
684 uint16_t hwtcamode;
685
686 #if STM32MP_DDR4_TYPE
687 hwtd4camode = 1U;
688 #elif STM32MP_LPDDR4_TYPE
689 hwtlp4camode = 1U;
690 hwtcsinvert = 1U;
691 hwtdbiinvert = 1U;
692 #else /* STM32MP_DDR3_TYPE */
693 /* Nothing to declare */
694 #endif /* STM32MP_DDR4_TYPE */
695
696 hwtcamode = (uint16_t)((hwtdbiinvert << CSR_HWTDBIINVERT_LSB) |
697 (hwtcsinvert << CSR_HWTCSINVERT_LSB) |
698 (hwtd4altcamode << CSR_HWTD4ALTCAMODE_LSB) |
699 (hwtlp4camode << CSR_HWTLP4CAMODE_LSB) |
700 (hwtd4camode << CSR_HWTD4CAMODE_LSB) |
701 (hwtlp3camode << CSR_HWTLP3CAMODE_LSB));
702
703 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_HWTCAMODE_ADDR))), hwtcamode);
704 }
705
706 /*
707 * Program DllGainCtl and DllLockParam based on frequency
708 */
709 static void dllgainctl_dlllockparam_program(struct stm32mp_ddr_config *config)
710 {
711 uint32_t dllgainiv;
712 uint32_t dllgaintv;
713 uint32_t lcdlseed;
714 uint32_t memck_freq;
715 uint32_t stepsize_x10 = 47U; /*
716 * Nominal stepsize, in units of tenths of a ps,
717 * if nominal=4.7ps use 47
718 */
719 uint16_t wddllgainctl;
720 uint16_t wddlllockparam;
721
722 memck_freq = config->uib.frequency;
723
724 /*
725 * lcdlseed = ((1000000/memck_freq)/2)/lcdl_stepsize ...
726 * where default lcdl_stepsize=4.7 in simulation.
727 */
728 if (memck_freq >= 1200U) {
729 dllgainiv = 0x04U;
730 dllgaintv = 0x05U;
731 } else if (memck_freq >= 800U) {
732 dllgainiv = 0x03U;
733 dllgaintv = 0x05U;
734 } else if (memck_freq >= 532U) {
735 dllgainiv = 0x02U;
736 dllgaintv = 0x04U;
737 } else if (memck_freq >= 332U) {
738 dllgainiv = 0x01U;
739 dllgaintv = 0x03U;
740 } else {
741 dllgainiv = 0x00U;
742 dllgaintv = 0x02U;
743 }
744
745 /*
746 * lcdlseed= (1000000/(2*memck_freq)) * (100/(120*(stepsize_nominal)));
747 * *100/105 is to bias the seed low.
748 */
749 lcdlseed = (1000000U * 10U * 100U) / (2U * memck_freq * stepsize_x10 * 105U);
750
751 if (lcdlseed > (511U - 32U)) {
752 lcdlseed = 511U - 32U;
753 }
754
755 if (lcdlseed < 32U) {
756 lcdlseed = 32U;
757 }
758
759 wddllgainctl = (uint16_t)((CSR_DLLGAINTV_MASK & (dllgaintv << CSR_DLLGAINTV_LSB)) |
760 (CSR_DLLGAINIV_MASK & (dllgainiv << CSR_DLLGAINIV_LSB)));
761
762 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_DLLGAINCTL_ADDR))),
763 wddllgainctl);
764
765 wddlllockparam = (uint16_t)((CSR_LCDLSEED0_MASK & (lcdlseed << CSR_LCDLSEED0_LSB)) |
766 (CSR_DISDLLGAINIVSEED_MASK & 0xFFFFU));
767
768 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_DLLLOCKPARAM_ADDR))),
769 wddlllockparam);
770 }
771
772 /*
773 * Program AcsmCtrl23 for Fw and Ppt.
774 *
775 * CSRs to program:
776 * AcsmCtrl23::AcsmCsMask
777 * AcsmCsMode
778 */
779 static void acsmctrl23_program(void)
780 {
781 uint16_t regdata;
782
783 regdata = (0x0FU << CSR_ACSMCSMASK_LSB) | (0x1U << CSR_ACSMCSMODE_LSB);
784 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (C0 | TACSM | CSR_ACSMCTRL23_ADDR))),
785 regdata);
786 }
787
788 /*
789 * Set PllForceCal to 1 and PllDacValIn to some arbitrary value
790 */
791 static void pllforcecal_plldacvalin_program(void)
792 {
793 uint32_t dacval_in = 0x10U;
794 uint32_t force_cal = 0x1U;
795 uint32_t pllencal = 0x1U;
796 uint32_t maxrange = 0x1FU;
797 uint16_t pllctrl3_gpr;
798 uint16_t pllctrl3_startup;
799
800 pllctrl3_startup = (uint16_t)((dacval_in << CSR_PLLDACVALIN_LSB) |
801 (maxrange << CSR_PLLMAXRANGE_LSB));
802 pllctrl3_gpr = pllctrl3_startup | (uint16_t)((force_cal << CSR_PLLFORCECAL_LSB) |
803 (pllencal << CSR_PLLENCAL_LSB));
804
805 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TMASTER | CSR_PLLCTRL3_ADDR))),
806 pllctrl3_startup);
807 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_SEQ0BGPR6_ADDR))),
808 pllctrl3_gpr);
809 }
810
811 /*
812 * This function programs registers that are normally set by training
813 * firmware.
814 *
815 * This function is used in place of running 1D or 1D training steps. PhyInit
816 * calls this function when skip_train = true. In that case, PhyInit does not
817 * execute training firmware and this function is called instead to program
818 * PHY registers according to DRAM timing parameters specified in userInput
819 * data structure. See documentation of ddrphy_phyinit_struct.h file
820 * details of timing parameters available in skip training.
821 *
822 * \warning ddrphy_phyinit_progcsrskiptrain() only supports zero board
823 * delay model. If system board delays are set or randomized, full 1D or 1D
824 * initialization flow must be executed.
825 *
826 * This function replaces these steps in the PHY Initialization sequence:
827 * - (E) Set the PHY input clocks to the desired frequency
828 * - (F) Write the Message Block parameters for the training firmware
829 * - (G) Execute the Training Firmware
830 * - (H) Read the Message Block results
831 *
832 * \returns \c void
833 */
834 void ddrphy_phyinit_progcsrskiptrain(struct stm32mp_ddr_config *config,
835 struct pmu_smb_ddr_1d *mb_ddr_1d, uint32_t ardptrinitval)
836 {
837 uint16_t txdqsdly;
838
839 /*
840 * Program ATxDlY
841 * For DDR4, DDR3 and LPDDR4, leave AtxDly[6:0] at default (0x0)
842 */
843
844 dfimrl_program(config, mb_ddr_1d, ardptrinitval);
845
846 txdqsdlytg_program(config, mb_ddr_1d, &txdqsdly);
847
848 txdqdlytg_program(config, mb_ddr_1d, txdqsdly);
849
850 rxendly_program(config, mb_ddr_1d);
851
852 #if STM32MP_LPDDR4_TYPE
853 seq0bgpr_program(config);
854
855 hwtlpcsen_program(config);
856
857 pptdqscntinvtrntg_program(config);
858
859 pptctlstatic_program(config);
860 #endif /* STM32MP_LPDDR4_TYPE */
861
862 hwtcamode_program();
863
864 dllgainctl_dlllockparam_program(config);
865
866 acsmctrl23_program();
867
868 pllforcecal_plldacvalin_program();
869
870 /*
871 * ##############################################################
872 *
873 * Setting PhyInLP3 to 0 to cause PIE to execute LP2 sequence instead of INIT on first
874 * dfi_init_start.
875 * This prevents any DRAM commands before DRAM is initialized, which is the case for
876 * skip_train.
877 *
878 * Moved to here from dddrphy_phyinit_I_loadPIEImage()
879 * These should not be needed on S3-exit
880 *
881 * Note this executes for SkipTrain only, *not* DevInit+SkipTrain
882 * DevInit+SkipTrain already initializes DRAM and thus don't need to avoid DRAM commands
883 *
884 * ##############################################################
885 */
886
887 /*
888 * Special skipTraining configuration to Prevent DRAM Commands on the first dfi
889 * status interface handshake. In order to see this behavior, the first dfi_freq
890 * should be in the range of 0x0f < dfi_freq_sel[4:0] < 0x14.
891 */
892 mmio_write_16((uintptr_t)(DDRPHYC_BASE + (4U * (TINITENG | CSR_PHYINLP3_ADDR))), 0x0U);
893 }
894