blob: 3937f414d20d959b3c011f682059be5e988bcf6b [file] [log] [blame]
Angel Pons6e5aabd2020-03-23 23:44:42 +01001/* SPDX-License-Identifier: GPL-2.0-only */
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +01002
3#ifndef RAMINIT_COMMON_H
4#define RAMINIT_COMMON_H
5
Felix Held380c6b22020-01-26 05:06:38 +01006#include <stdint.h>
7
Angel Pons7c49cb82020-03-16 23:17:32 +01008#define BASEFREQ 133
9#define tDLLK 512
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010010
Angel Pons7c49cb82020-03-16 23:17:32 +010011#define IS_SANDY_CPU(x) ((x & 0xffff0) == 0x206a0)
12#define IS_SANDY_CPU_C(x) ((x & 0xf) == 4)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010013#define IS_SANDY_CPU_D0(x) ((x & 0xf) == 5)
14#define IS_SANDY_CPU_D1(x) ((x & 0xf) == 6)
15#define IS_SANDY_CPU_D2(x) ((x & 0xf) == 7)
16
Angel Pons7c49cb82020-03-16 23:17:32 +010017#define IS_IVY_CPU(x) ((x & 0xffff0) == 0x306a0)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010018#define IS_IVY_CPU_C(x) ((x & 0xf) == 4)
19#define IS_IVY_CPU_K(x) ((x & 0xf) == 5)
20#define IS_IVY_CPU_D(x) ((x & 0xf) == 6)
21#define IS_IVY_CPU_E(x) ((x & 0xf) >= 8)
22
Angel Pons7c49cb82020-03-16 23:17:32 +010023#define NUM_CHANNELS 2
24#define NUM_SLOTRANKS 4
25#define NUM_SLOTS 2
Patrick Rudolphdd662872017-10-28 18:20:11 +020026#define NUM_LANES 9
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +010027
Angel Pons3abd2062020-05-03 00:25:02 +020028/* IOSAV_n_SP_CMD_CTRL DRAM commands */
Angel Pons6aa7cca2020-05-02 19:38:34 +020029#define IOSAV_MRS (0xf000)
30#define IOSAV_PRE (0xf002)
31#define IOSAV_ZQCS (0xf003)
32#define IOSAV_ACT (0xf006)
33#define IOSAV_RD (0xf105)
34#define IOSAV_NOP_ALT (0xf107)
35#define IOSAV_WR (0xf201)
36#define IOSAV_NOP (0xf207)
Angel Pons69e17142020-03-23 12:26:29 +010037
Angel Pons3abd2062020-05-03 00:25:02 +020038/* IOSAV_n_SUBSEQ_CTRL data direction */
39#define SSQ_NA 0 /* Non-data */
40#define SSQ_RD 1 /* Read */
41#define SSQ_WR 2 /* Write */
42#define SSQ_RW 3 /* Read and write */
43
Angel Ponsd5b780c2020-05-02 21:48:46 +020044struct iosav_ssq {
45 /* IOSAV_n_SP_CMD_CTRL */
46 union {
47 struct {
Angel Pons19c5cd22020-08-10 14:27:23 +020048 u32 command : 16; /* [15.. 0] */
49 u32 ranksel_ap : 2; /* [17..16] */
Angel Ponsd5b780c2020-05-02 21:48:46 +020050 u32 : 14;
51 };
52 u32 raw;
53 } sp_cmd_ctrl;
54
55 /* IOSAV_n_SUBSEQ_CTRL */
56 union {
57 struct {
Angel Pons19c5cd22020-08-10 14:27:23 +020058 u32 cmd_executions : 9; /* [ 8.. 0] */
Angel Ponsd5b780c2020-05-02 21:48:46 +020059 u32 : 1;
Angel Pons19c5cd22020-08-10 14:27:23 +020060 u32 cmd_delay_gap : 5; /* [14..10] */
Angel Ponsd5b780c2020-05-02 21:48:46 +020061 u32 : 1;
Angel Pons19c5cd22020-08-10 14:27:23 +020062 u32 post_ssq_wait : 9; /* [24..16] */
Angel Ponsd5b780c2020-05-02 21:48:46 +020063 u32 : 1;
Angel Pons19c5cd22020-08-10 14:27:23 +020064 u32 data_direction : 2; /* [27..26] */
Angel Ponsd5b780c2020-05-02 21:48:46 +020065 u32 : 4;
66 };
67 u32 raw;
68 } subseq_ctrl;
69
70 /* IOSAV_n_SP_CMD_ADDR */
71 union {
72 struct {
Angel Pons19c5cd22020-08-10 14:27:23 +020073 u32 address : 16; /* [15.. 0] */
74 u32 rowbits : 3; /* [18..16] */
Angel Ponsd5b780c2020-05-02 21:48:46 +020075 u32 : 1;
Angel Pons19c5cd22020-08-10 14:27:23 +020076 u32 bank : 3; /* [22..20] */
Angel Ponsd5b780c2020-05-02 21:48:46 +020077 u32 : 1;
Angel Pons19c5cd22020-08-10 14:27:23 +020078 u32 rank : 2; /* [25..24] */
Angel Ponsd5b780c2020-05-02 21:48:46 +020079 u32 : 6;
80 };
81 u32 raw;
82 } sp_cmd_addr;
83
84 /* IOSAV_n_ADDR_UPDATE */
85 union {
86 struct {
Angel Pons19c5cd22020-08-10 14:27:23 +020087 u32 inc_addr_1 : 1; /* [ 0.. 0] */
88 u32 inc_addr_8 : 1; /* [ 1.. 1] */
89 u32 inc_bank : 1; /* [ 2.. 2] */
90 u32 inc_rank : 2; /* [ 4.. 3] */
91 u32 addr_wrap : 5; /* [ 9.. 5] */
92 u32 lfsr_upd : 2; /* [11..10] */
93 u32 upd_rate : 4; /* [15..12] */
94 u32 lfsr_xors : 2; /* [17..16] */
Angel Ponsd5b780c2020-05-02 21:48:46 +020095 u32 : 14;
96 };
97 u32 raw;
98 } addr_update;
99};
100
Angel Pons6a8ddc72020-11-12 01:44:05 +0100101#define ZQCS_SEQUENCE(slotrank, gap, post, wrap) \
102 { \
103 /* DRAM command ZQCS */ \
104 [0] = { \
105 .sp_cmd_ctrl = { \
106 .command = IOSAV_ZQCS, \
107 }, \
108 .subseq_ctrl = { \
109 .cmd_executions = 1, \
110 .cmd_delay_gap = gap, \
111 .post_ssq_wait = post, \
112 .data_direction = SSQ_NA, \
113 }, \
114 .sp_cmd_addr = { \
115 .address = 0, \
116 .rowbits = 6, \
117 .bank = 0, \
118 .rank = slotrank, \
119 }, \
120 .addr_update = { \
121 .addr_wrap = wrap, \
122 }, \
123 }, \
124 }
125
126#define PREA_SEQUENCE(t_rp, wrap) \
127 { \
128 /* DRAM command PREA */ \
129 [0] = { \
130 .sp_cmd_ctrl = { \
131 .command = IOSAV_PRE, \
132 .ranksel_ap = 1, \
133 }, \
134 .subseq_ctrl = { \
135 .cmd_executions = 1, \
136 .cmd_delay_gap = 3, \
137 .post_ssq_wait = t_rp, \
138 .data_direction = SSQ_NA, \
139 }, \
140 .sp_cmd_addr = { \
141 .address = 1024, \
142 .rowbits = 6, \
143 .bank = 0, \
144 .rank = slotrank, \
145 }, \
146 .addr_update = { \
147 .addr_wrap = wrap, \
148 }, \
149 }, \
150 }
151
152#define READ_MPR_SEQUENCE(t_mod, loops, gap, loops2, post2) \
153 { \
154 /* \
155 * DRAM command MRS \
156 * \
157 * Write MR3 MPR enable. In this mode only RD and RDA \
158 * are allowed, and all reads return a predefined pattern. \
159 */ \
160 [0] = { \
161 .sp_cmd_ctrl = { \
162 .command = IOSAV_MRS, \
163 .ranksel_ap = 1, \
164 }, \
165 .subseq_ctrl = { \
166 .cmd_executions = 1, \
167 .cmd_delay_gap = 3, \
168 .post_ssq_wait = t_mod, \
169 .data_direction = SSQ_NA, \
170 }, \
171 .sp_cmd_addr = { \
172 .address = 4, \
173 .rowbits = 6, \
174 .bank = 3, \
175 .rank = slotrank, \
176 }, \
177 }, \
178 /* DRAM command RD */ \
179 [1] = { \
180 .sp_cmd_ctrl = { \
181 .command = IOSAV_RD, \
182 .ranksel_ap = 1, \
183 }, \
184 .subseq_ctrl = { \
185 .cmd_executions = loops, \
186 .cmd_delay_gap = gap, \
187 .post_ssq_wait = 4, \
188 .data_direction = SSQ_RD, \
189 }, \
190 .sp_cmd_addr = { \
191 .address = 0, \
192 .rowbits = 0, \
193 .bank = 0, \
194 .rank = slotrank, \
195 }, \
196 }, \
197 /* DRAM command RD */ \
198 [2] = { \
199 .sp_cmd_ctrl = { \
200 .command = IOSAV_RD, \
201 .ranksel_ap = 1, \
202 }, \
203 .subseq_ctrl = { \
204 .cmd_executions = loops2, \
205 .cmd_delay_gap = 4, \
206 .post_ssq_wait = post2, \
207 .data_direction = SSQ_NA, \
208 }, \
209 .sp_cmd_addr = { \
210 .address = 0, \
211 .rowbits = 6, \
212 .bank = 0, \
213 .rank = slotrank, \
214 }, \
215 }, \
216 /* \
217 * DRAM command MRS \
218 * \
219 * Write MR3 MPR disable. \
220 */ \
221 [3] = { \
222 .sp_cmd_ctrl = { \
223 .command = IOSAV_MRS, \
224 .ranksel_ap = 1, \
225 }, \
226 .subseq_ctrl = { \
227 .cmd_executions = 1, \
228 .cmd_delay_gap = 3, \
229 .post_ssq_wait = t_mod, \
230 .data_direction = SSQ_NA, \
231 }, \
232 .sp_cmd_addr = { \
233 .address = 0, \
234 .rowbits = 6, \
235 .bank = 3, \
236 .rank = slotrank, \
237 }, \
238 }, \
239 }
240
241#define MISC_WRITE_SEQUENCE(gap0, loops0, gap1, loops2, wrap2) \
242 { \
243 /* DRAM command ACT */ \
244 [0] = { \
245 .sp_cmd_ctrl = { \
246 .command = IOSAV_ACT, \
247 .ranksel_ap = 1, \
248 }, \
249 .subseq_ctrl = { \
250 .cmd_executions = loops0, \
251 .cmd_delay_gap = gap0, \
252 .post_ssq_wait = ctrl->tRCD, \
253 .data_direction = SSQ_NA, \
254 }, \
255 .sp_cmd_addr = { \
256 .address = 0, \
257 .rowbits = 6, \
258 .bank = 0, \
259 .rank = slotrank, \
260 }, \
261 .addr_update = { \
262 .inc_bank = loops0 == 1 ? 0 : 1, \
263 .addr_wrap = loops0 == 1 ? 0 : 18, \
264 }, \
265 }, \
266 /* DRAM command NOP */ \
267 [1] = { \
268 .sp_cmd_ctrl = { \
269 .command = IOSAV_NOP, \
270 .ranksel_ap = 1, \
271 }, \
272 .subseq_ctrl = { \
273 .cmd_executions = 1, \
274 .cmd_delay_gap = gap1, \
275 .post_ssq_wait = 4, \
276 .data_direction = SSQ_WR, \
277 }, \
278 .sp_cmd_addr = { \
279 .address = 8, \
280 .rowbits = 0, \
281 .bank = 0, \
282 .rank = slotrank, \
283 }, \
284 .addr_update = { \
285 .addr_wrap = 31, \
286 }, \
287 }, \
288 /* DRAM command WR */ \
289 [2] = { \
290 .sp_cmd_ctrl = { \
291 .command = IOSAV_WR, \
292 .ranksel_ap = 1, \
293 }, \
294 .subseq_ctrl = { \
295 .cmd_executions = loops2, \
296 .cmd_delay_gap = 4, \
297 .post_ssq_wait = 4, \
298 .data_direction = SSQ_WR, \
299 }, \
300 .sp_cmd_addr = { \
301 .address = 0, \
302 .rowbits = 0, \
303 .bank = 0, \
304 .rank = slotrank, \
305 }, \
306 .addr_update = { \
307 .inc_addr_8 = 1, \
308 .addr_wrap = wrap2, \
309 }, \
310 }, \
311 /* DRAM command NOP */ \
312 [3] = { \
313 .sp_cmd_ctrl = { \
314 .command = IOSAV_NOP, \
315 .ranksel_ap = 1, \
316 }, \
317 .subseq_ctrl = { \
318 .cmd_executions = 1, \
319 .cmd_delay_gap = 3, \
320 .post_ssq_wait = ctrl->CWL + ctrl->tWTR + 5, \
321 .data_direction = SSQ_WR, \
322 }, \
323 .sp_cmd_addr = { \
324 .address = 8, \
325 .rowbits = 0, \
326 .bank = 0, \
327 .rank = slotrank, \
328 }, \
329 .addr_update = { \
330 .addr_wrap = 31, \
331 }, \
332 }, \
333 }
334
335#define COMMAND_TRAINING_SEQUENCE(ctr) \
336 { \
337 /* DRAM command ACT */ \
338 [0] = { \
339 .sp_cmd_ctrl = { \
340 .command = IOSAV_ACT, \
341 .ranksel_ap = 1, \
342 }, \
343 .subseq_ctrl = { \
344 .cmd_executions = 8, \
345 .cmd_delay_gap = MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1), \
346 .post_ssq_wait = ctrl->tRCD, \
347 .data_direction = SSQ_NA, \
348 }, \
349 .sp_cmd_addr = { \
350 .address = ctr, \
351 .rowbits = 6, \
352 .bank = 0, \
353 .rank = slotrank, \
354 }, \
355 .addr_update = { \
356 .inc_bank = 1, \
357 .addr_wrap = 18, \
358 }, \
359 }, \
360 /* DRAM command WR */ \
361 [1] = { \
362 .sp_cmd_ctrl = { \
363 .command = IOSAV_WR, \
364 .ranksel_ap = 1, \
365 }, \
366 .subseq_ctrl = { \
367 .cmd_executions = 32, \
368 .cmd_delay_gap = 4, \
369 .post_ssq_wait = ctrl->CWL + ctrl->tWTR + 8, \
370 .data_direction = SSQ_WR, \
371 }, \
372 .sp_cmd_addr = { \
373 .address = 0, \
374 .rowbits = 0, \
375 .bank = 0, \
376 .rank = slotrank, \
377 }, \
378 .addr_update = { \
379 .inc_addr_8 = 1, \
380 .addr_wrap = 18, \
381 .lfsr_upd = 3, \
382 .lfsr_xors = 2, \
383 }, \
384 }, \
385 /* DRAM command RD */ \
386 [2] = { \
387 .sp_cmd_ctrl = { \
388 .command = IOSAV_RD, \
389 .ranksel_ap = 1, \
390 }, \
391 .subseq_ctrl = { \
392 .cmd_executions = 32, \
393 .cmd_delay_gap = 4, \
394 .post_ssq_wait = MAX(ctrl->tRTP, 8), \
395 .data_direction = SSQ_RD, \
396 }, \
397 .sp_cmd_addr = { \
398 .address = 0, \
399 .rowbits = 0, \
400 .bank = 0, \
401 .rank = slotrank, \
402 }, \
403 .addr_update = { \
404 .inc_addr_8 = 1, \
405 .addr_wrap = 18, \
406 .lfsr_upd = 3, \
407 .lfsr_xors = 2, \
408 }, \
409 }, \
410 /* DRAM command PRE */ \
411 [3] = { \
412 .sp_cmd_ctrl = { \
413 .command = IOSAV_PRE, \
414 .ranksel_ap = 1, \
415 }, \
416 .subseq_ctrl = { \
417 .cmd_executions = 1, \
418 .cmd_delay_gap = 4, \
419 .post_ssq_wait = 15, \
420 .data_direction = SSQ_NA, \
421 }, \
422 .sp_cmd_addr = { \
423 .address = 1024, \
424 .rowbits = 6, \
425 .bank = 0, \
426 .rank = slotrank, \
427 }, \
428 .addr_update = { \
429 .addr_wrap = 18, \
430 }, \
431 }, \
432 }
433
434#define WRITE_DATA_SEQUENCE \
435 { \
436 /* DRAM command ACT */ \
437 [0] = { \
438 .sp_cmd_ctrl = { \
439 .command = IOSAV_ACT, \
440 .ranksel_ap = 1, \
441 }, \
442 .subseq_ctrl = { \
443 .cmd_executions = 4, \
444 .cmd_delay_gap = MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1), \
445 .post_ssq_wait = ctrl->tRCD, \
446 .data_direction = SSQ_NA, \
447 }, \
448 .sp_cmd_addr = { \
449 .address = 0, \
450 .rowbits = 6, \
451 .bank = 0, \
452 .rank = slotrank, \
453 }, \
454 .addr_update = { \
455 .inc_bank = 0, \
456 .addr_wrap = 18, \
457 }, \
458 }, \
459 /* DRAM command WR */ \
460 [1] = { \
461 .sp_cmd_ctrl = { \
462 .command = IOSAV_WR, \
463 .ranksel_ap = 1, \
464 }, \
465 .subseq_ctrl = { \
466 .cmd_executions = 32, \
467 .cmd_delay_gap = 20, \
468 .post_ssq_wait = ctrl->CWL + ctrl->tWTR + 8, \
469 .data_direction = SSQ_WR, \
470 }, \
471 .sp_cmd_addr = { \
472 .address = 0, \
473 .rowbits = 0, \
474 .bank = 0, \
475 .rank = slotrank, \
476 }, \
477 .addr_update = { \
478 .inc_addr_8 = 1, \
479 .addr_wrap = 18, \
480 }, \
481 }, \
482 /* DRAM command RD */ \
483 [2] = { \
484 .sp_cmd_ctrl = { \
485 .command = IOSAV_RD, \
486 .ranksel_ap = 1, \
487 }, \
488 .subseq_ctrl = { \
489 .cmd_executions = 32, \
490 .cmd_delay_gap = 20, \
491 .post_ssq_wait = MAX(ctrl->tRTP, 8), \
492 .data_direction = SSQ_RD, \
493 }, \
494 .sp_cmd_addr = { \
495 .address = 0, \
496 .rowbits = 0, \
497 .bank = 0, \
498 .rank = slotrank, \
499 }, \
500 .addr_update = { \
501 .inc_addr_8 = 1, \
502 .addr_wrap = 18, \
503 }, \
504 }, \
505 /* DRAM command PRE */ \
506 [3] = { \
507 .sp_cmd_ctrl = { \
508 .command = IOSAV_PRE, \
509 .ranksel_ap = 1, \
510 }, \
511 .subseq_ctrl = { \
512 .cmd_executions = 1, \
513 .cmd_delay_gap = 3, \
514 .post_ssq_wait = ctrl->tRP, \
515 .data_direction = SSQ_NA, \
516 }, \
517 .sp_cmd_addr = { \
518 .address = 1024, \
519 .rowbits = 6, \
520 .bank = 0, \
521 .rank = slotrank, \
522 }, \
523 }, \
524 }
525
526#define AGGRESSIVE_WRITE_READ_SEQUENCE \
527 { \
528 /* DRAM command ACT */ \
529 [0] = { \
530 .sp_cmd_ctrl = { \
531 .command = IOSAV_ACT, \
532 .ranksel_ap = 1, \
533 }, \
534 .subseq_ctrl = { \
535 .cmd_executions = 4, \
536 .cmd_delay_gap = MAX((ctrl->tFAW >> 2) + 1, ctrl->tRRD), \
537 .post_ssq_wait = ctrl->tRCD, \
538 .data_direction = SSQ_NA, \
539 }, \
540 .sp_cmd_addr = { \
541 .address = 0, \
542 .rowbits = 6, \
543 .bank = 0, \
544 .rank = slotrank, \
545 }, \
546 .addr_update = { \
547 .inc_bank = 1, \
548 .addr_wrap = 18, \
549 }, \
550 }, \
551 /* DRAM command WR */ \
552 [1] = { \
553 .sp_cmd_ctrl = { \
554 .command = IOSAV_WR, \
555 .ranksel_ap = 1, \
556 }, \
557 .subseq_ctrl = { \
558 .cmd_executions = 480, \
559 .cmd_delay_gap = 4, \
560 .post_ssq_wait = ctrl->tWTR + ctrl->CWL + 8, \
561 .data_direction = SSQ_WR, \
562 }, \
563 .sp_cmd_addr = { \
564 .address = 0, \
565 .rowbits = 0, \
566 .bank = 0, \
567 .rank = slotrank, \
568 }, \
569 .addr_update = { \
570 .inc_addr_8 = 1, \
571 .addr_wrap = 18, \
572 }, \
573 }, \
574 /* DRAM command RD */ \
575 [2] = { \
576 .sp_cmd_ctrl = { \
577 .command = IOSAV_RD, \
578 .ranksel_ap = 1, \
579 }, \
580 .subseq_ctrl = { \
581 .cmd_executions = 480, \
582 .cmd_delay_gap = 4, \
583 .post_ssq_wait = MAX(ctrl->tRTP, 8), \
584 .data_direction = SSQ_RD, \
585 }, \
586 .sp_cmd_addr = { \
587 .address = 0, \
588 .rowbits = 0, \
589 .bank = 0, \
590 .rank = slotrank, \
591 }, \
592 .addr_update = { \
593 .inc_addr_8 = 1, \
594 .addr_wrap = 18, \
595 }, \
596 }, \
597 /* DRAM command PRE */ \
598 [3] = { \
599 .sp_cmd_ctrl = { \
600 .command = IOSAV_PRE, \
601 .ranksel_ap = 1, \
602 }, \
603 .subseq_ctrl = { \
604 .cmd_executions = 1, \
605 .cmd_delay_gap = 4, \
606 .post_ssq_wait = ctrl->tRP, \
607 .data_direction = SSQ_NA, \
608 }, \
609 .sp_cmd_addr = { \
610 .address = 1024, \
611 .rowbits = 6, \
612 .bank = 0, \
613 .rank = slotrank, \
614 }, \
615 }, \
616 }
617
618#define MEMORY_TEST_SEQUENCE \
619 { \
620 /* DRAM command ACT */ \
621 [0] = { \
622 .sp_cmd_ctrl = { \
623 .command = IOSAV_ACT, \
624 .ranksel_ap = 1, \
625 }, \
626 .subseq_ctrl = { \
627 .cmd_executions = 4, \
628 .cmd_delay_gap = 8, \
629 .post_ssq_wait = 40, \
630 .data_direction = SSQ_NA, \
631 }, \
632 .sp_cmd_addr = { \
633 .address = 0, \
634 .rowbits = 6, \
635 .bank = 0, \
636 .rank = slotrank, \
637 }, \
638 .addr_update = { \
639 .inc_bank = 1, \
640 .addr_wrap = 18, \
641 }, \
642 }, \
643 /* DRAM command WR */ \
644 [1] = { \
645 .sp_cmd_ctrl = { \
646 .command = IOSAV_WR, \
647 .ranksel_ap = 1, \
648 }, \
649 .subseq_ctrl = { \
650 .cmd_executions = 100, \
651 .cmd_delay_gap = 4, \
652 .post_ssq_wait = 40, \
653 .data_direction = SSQ_WR, \
654 }, \
655 .sp_cmd_addr = { \
656 .address = 0, \
657 .rowbits = 0, \
658 .bank = 0, \
659 .rank = slotrank, \
660 }, \
661 .addr_update = { \
662 .inc_addr_8 = 1, \
663 .addr_wrap = 18, \
664 }, \
665 }, \
666 /* DRAM command RD */ \
667 [2] = { \
668 .sp_cmd_ctrl = { \
669 .command = IOSAV_RD, \
670 .ranksel_ap = 1, \
671 }, \
672 .subseq_ctrl = { \
673 .cmd_executions = 100, \
674 .cmd_delay_gap = 4, \
675 .post_ssq_wait = 40, \
676 .data_direction = SSQ_RD, \
677 }, \
678 .sp_cmd_addr = { \
679 .address = 0, \
680 .rowbits = 0, \
681 .bank = 0, \
682 .rank = slotrank, \
683 }, \
684 .addr_update = { \
685 .inc_addr_8 = 1, \
686 .addr_wrap = 18, \
687 }, \
688 }, \
689 /* DRAM command PRE */ \
690 [3] = { \
691 .sp_cmd_ctrl = { \
692 .command = IOSAV_PRE, \
693 .ranksel_ap = 1, \
694 }, \
695 .subseq_ctrl = { \
696 .cmd_executions = 1, \
697 .cmd_delay_gap = 3, \
698 .post_ssq_wait = 40, \
699 .data_direction = SSQ_NA, \
700 }, \
701 .sp_cmd_addr = { \
702 .address = 1024, \
703 .rowbits = 6, \
704 .bank = 0, \
705 .rank = slotrank, \
706 }, \
707 .addr_update = { \
708 .addr_wrap = 18, \
709 }, \
710 }, \
711 }
712
Angel Pons8f0757e2020-11-11 23:03:36 +0100713void iosav_write_sequence(const int ch, const struct iosav_ssq *seq, const unsigned int length);
Angel Pons1c505f82020-11-11 20:55:35 +0100714void iosav_run_queue(const int ch, const u8 loops, const u8 as_timer);
715void iosav_run_once(const int ch);
716void wait_for_iosav(int channel);
717
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100718/* FIXME: Vendor BIOS uses 64 but our algorithms are less
719 performant and even 1 seems to be enough in practice. */
Angel Pons7c49cb82020-03-16 23:17:32 +0100720#define NUM_PATTERNS 4
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100721
Angel Pons5c1baf52020-03-22 12:23:35 +0100722/*
723 * WARNING: Do not forget to increase MRC_CACHE_VERSION when the saved data is changed!
724 */
Patrick Rudolphdd662872017-10-28 18:20:11 +0200725#define MRC_CACHE_VERSION 5
Angel Pons5c1baf52020-03-22 12:23:35 +0100726
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100727typedef struct odtmap_st {
728 u16 rttwr;
729 u16 rttnom;
730} odtmap;
731
Angel Pons5c1baf52020-03-22 12:23:35 +0100732/* WARNING: Do not forget to increase MRC_CACHE_VERSION when this struct is changed! */
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100733typedef struct dimm_info_st {
734 dimm_attr dimm[NUM_CHANNELS][NUM_SLOTS];
735} dimm_info;
736
Angel Pons5c1baf52020-03-22 12:23:35 +0100737/* WARNING: Do not forget to increase MRC_CACHE_VERSION when this struct is changed! */
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100738struct ram_rank_timings {
Angel Pons7c49cb82020-03-16 23:17:32 +0100739 /* ROUNDT_LAT register: One byte per slotrank */
Angel Pons88521882020-01-05 20:21:20 +0100740 u8 roundtrip_latency;
741
Angel Pons7c49cb82020-03-16 23:17:32 +0100742 /* IO_LATENCY register: One nibble per slotrank */
Felix Heldef4fe3e2019-12-31 14:15:05 +0100743 u8 io_latency;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100744
Angel Pons7c49cb82020-03-16 23:17:32 +0100745 /* Phase interpolator coding for command and control */
Angel Pons88521882020-01-05 20:21:20 +0100746 int pi_coding;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100747
748 struct ram_lane_timings {
Angel Pons7c49cb82020-03-16 23:17:32 +0100749 /* Lane register offset 0x10 */
750 u16 timA; /* bits 0 - 5, bits 16 - 18 */
751 u8 rising; /* bits 8 - 14 */
752 u8 falling; /* bits 20 - 26 */
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100753
Angel Pons7c49cb82020-03-16 23:17:32 +0100754 /* Lane register offset 0x20 */
755 int timC; /* bits 0 - 5, 19 */
756 u16 timB; /* bits 8 - 13, 15 - 17 */
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100757 } lanes[NUM_LANES];
758};
759
Angel Pons5c1baf52020-03-22 12:23:35 +0100760/* WARNING: Do not forget to increase MRC_CACHE_VERSION when this struct is changed! */
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100761typedef struct ramctr_timing_st {
762 u16 spd_crc[NUM_CHANNELS][NUM_SLOTS];
Angel Pons80037f72020-03-21 13:12:37 +0100763
764 /* CPUID value */
765 u32 cpu;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100766
Patrick Rudolph77eaba32016-11-11 18:55:54 +0100767 /* DDR base_freq = 100 Mhz / 133 Mhz */
768 u8 base_freq;
769
Angel Pons48409b82020-03-23 22:19:29 +0100770 /* Frequency index */
771 u32 FRQ;
772
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100773 u16 cas_supported;
Angel Pons7c49cb82020-03-16 23:17:32 +0100774 /* Latencies are in units of ns, scaled by x256 */
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100775 u32 tCK;
776 u32 tAA;
777 u32 tWR;
778 u32 tRCD;
779 u32 tRRD;
780 u32 tRP;
781 u32 tRAS;
782 u32 tRFC;
783 u32 tWTR;
784 u32 tRTP;
785 u32 tFAW;
Dan Elkoubydabebc32018-04-13 18:47:10 +0300786 u32 tCWL;
787 u32 tCMD;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100788 /* Latencies in terms of clock cycles
Angel Pons7c49cb82020-03-16 23:17:32 +0100789 They are saved separately as they are needed for DRAM MRS commands */
790 u8 CAS; /* CAS read latency */
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100791 u8 CWL; /* CAS write latency */
792
793 u32 tREFI;
794 u32 tMOD;
795 u32 tXSOffset;
796 u32 tWLO;
797 u32 tCKE;
798 u32 tXPDLL;
799 u32 tXP;
800 u32 tAONPD;
801
Angel Pons7c49cb82020-03-16 23:17:32 +0100802 /* Bits [0..11] of PM_DLL_CONFIG: Master DLL wakeup delay timer */
Angel Pons88521882020-01-05 20:21:20 +0100803 u16 mdll_wake_delay;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100804
805 u8 rankmap[NUM_CHANNELS];
806 int ref_card_offset[NUM_CHANNELS];
807 u32 mad_dimm[NUM_CHANNELS];
808 int channel_size_mb[NUM_CHANNELS];
809 u32 cmd_stretch[NUM_CHANNELS];
810
Angel Pons88521882020-01-05 20:21:20 +0100811 int pi_code_offset;
812 int pi_coding_threshold;
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100813
Patrick Rudolph05d4bf7e2017-10-28 16:36:09 +0200814 bool ecc_supported;
815 bool ecc_forced;
Patrick Rudolphdd662872017-10-28 18:20:11 +0200816 bool ecc_enabled;
817 int lanes; /* active lanes: 8 or 9 */
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100818 int edge_offset[3];
819 int timC_offset[3];
820
821 int extended_temperature_range;
822 int auto_self_refresh;
823
824 int rank_mirror[NUM_CHANNELS][NUM_SLOTRANKS];
825
826 struct ram_rank_timings timings[NUM_CHANNELS][NUM_SLOTRANKS];
827
828 dimm_info info;
829} ramctr_timing;
830
Felix Held87ddea22020-01-26 04:55:27 +0100831#define SOUTHBRIDGE PCI_DEV(0, 0x1f, 0)
832
Patrick Rudolphdd662872017-10-28 18:20:11 +0200833#define FOR_ALL_LANES for (lane = 0; lane < ctrl->lanes; lane++)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100834#define FOR_ALL_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++)
835#define FOR_ALL_POPULATED_RANKS for (slotrank = 0; slotrank < NUM_SLOTRANKS; slotrank++) if (ctrl->rankmap[channel] & (1 << slotrank))
836#define FOR_ALL_POPULATED_CHANNELS for (channel = 0; channel < NUM_CHANNELS; channel++) if (ctrl->rankmap[channel])
837#define MAX_EDGE_TIMING 71
838#define MAX_TIMC 127
839#define MAX_TIMB 511
840#define MAX_TIMA 127
841#define MAX_CAS 18
842#define MIN_CAS 4
843
Angel Pons7c49cb82020-03-16 23:17:32 +0100844#define MAKE_ERR ((channel << 16) | (slotrank << 8) | 1)
845#define GET_ERR_CHANNEL(x) (x >> 16)
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100846
Angel Pons88521882020-01-05 20:21:20 +0100847void dram_mrscommands(ramctr_timing *ctrl);
848void program_timings(ramctr_timing *ctrl, int channel);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100849void dram_find_common_params(ramctr_timing *ctrl);
Angel Pons88521882020-01-05 20:21:20 +0100850void dram_xover(ramctr_timing *ctrl);
851void dram_timing_regs(ramctr_timing *ctrl);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100852void dram_dimm_mapping(ramctr_timing *ctrl);
Patrick Rudolphdd662872017-10-28 18:20:11 +0200853void dram_dimm_set_mapping(ramctr_timing *ctrl, int training);
Angel Pons88521882020-01-05 20:21:20 +0100854void dram_zones(ramctr_timing *ctrl, int training);
Angel Pons88521882020-01-05 20:21:20 +0100855void dram_memorymap(ramctr_timing *ctrl, int me_uma_size);
856void dram_jedecreset(ramctr_timing *ctrl);
857int read_training(ramctr_timing *ctrl);
858int write_training(ramctr_timing *ctrl);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100859int command_training(ramctr_timing *ctrl);
860int discover_edges(ramctr_timing *ctrl);
861int discover_edges_write(ramctr_timing *ctrl);
862int discover_timC_write(ramctr_timing *ctrl);
Angel Pons88521882020-01-05 20:21:20 +0100863void normalize_training(ramctr_timing *ctrl);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100864int channel_test(ramctr_timing *ctrl);
Angel Pons88521882020-01-05 20:21:20 +0100865void set_scrambling_seed(ramctr_timing *ctrl);
Angel Pons89ae6b82020-03-21 13:23:32 +0100866void set_wmm_behavior(const u32 cpu);
Angel Pons88521882020-01-05 20:21:20 +0100867void prepare_training(ramctr_timing *ctrl);
Angel Pons7c49cb82020-03-16 23:17:32 +0100868void set_read_write_timings(ramctr_timing *ctrl);
Angel Pons88521882020-01-05 20:21:20 +0100869void set_normal_operation(ramctr_timing *ctrl);
870void final_registers(ramctr_timing *ctrl);
871void restore_timings(ramctr_timing *ctrl);
Angel Ponsefbed262020-03-23 23:18:03 +0100872int try_init_dram_ddr3(ramctr_timing *ctrl, int fast_boot, int s3resume, int me_uma_size);
Patrick Rudolphfd5fa2a2016-11-11 18:22:33 +0100873
Patrick Rudolphdd662872017-10-28 18:20:11 +0200874void channel_scrub(ramctr_timing *ctrl);
Patrick Rudolph05d4bf7e2017-10-28 16:36:09 +0200875bool get_host_ecc_cap(void);
876bool get_host_ecc_forced(void);
877
Patrick Rudolph305035c2016-11-11 18:38:50 +0100878#endif