blob: 11b2acb252ed0b8b63d5c7cbfad2445afffbb03a [file] [log] [blame]
Angel Pons1c505f82020-11-11 20:55:35 +01001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <commonlib/helpers.h>
4#include <console/console.h>
5#include <delay.h>
6#include <types.h>
7
8#include "raminit_native.h"
9#include "raminit_common.h"
10#include "raminit_tables.h"
11#include "sandybridge.h"
12
13/* FIXME: no support for 3-channel chipsets */
14
15/* Number of programmed IOSAV subsequences. */
16static unsigned int ssq_count = 0;
17
Angel Pons8f0757e2020-11-11 23:03:36 +010018void iosav_write_sequence(const int ch, const struct iosav_ssq *seq, const unsigned int length)
Angel Pons1c505f82020-11-11 20:55:35 +010019{
Angel Pons8f0757e2020-11-11 23:03:36 +010020 for (unsigned int i = 0; i < length; i++) {
21 MCHBAR32(IOSAV_n_SP_CMD_CTRL_ch(ch, i)) = seq[i].sp_cmd_ctrl.raw;
22 MCHBAR32(IOSAV_n_SUBSEQ_CTRL_ch(ch, i)) = seq[i].subseq_ctrl.raw;
23 MCHBAR32(IOSAV_n_SP_CMD_ADDR_ch(ch, i)) = seq[i].sp_cmd_addr.raw;
24 MCHBAR32(IOSAV_n_ADDR_UPDATE_ch(ch, i)) = seq[i].addr_update.raw;
25 }
Angel Pons1c505f82020-11-11 20:55:35 +010026
Angel Pons8f0757e2020-11-11 23:03:36 +010027 ssq_count = length;
Angel Pons1c505f82020-11-11 20:55:35 +010028}
29
30void iosav_run_queue(const int ch, const u8 loops, const u8 as_timer)
31{
Angel Pons8f0757e2020-11-11 23:03:36 +010032 /* Should never happen */
33 if (ssq_count == 0)
34 return;
Angel Pons1c505f82020-11-11 20:55:35 +010035
Angel Pons8f0757e2020-11-11 23:03:36 +010036 MCHBAR32(IOSAV_SEQ_CTL_ch(ch)) = loops | ((ssq_count - 1) << 18) | (as_timer << 22);
Angel Pons1c505f82020-11-11 20:55:35 +010037}
38
39void iosav_run_once(const int ch)
40{
41 iosav_run_queue(ch, 1, 0);
42}
43
44void wait_for_iosav(int channel)
45{
46 while (1) {
47 if (MCHBAR32(IOSAV_STATUS_ch(channel)) & 0x50)
48 return;
49 }
50}
Angel Ponsffd50152020-11-12 11:03:10 +010051
52void iosav_write_zqcs_sequence(int channel, int slotrank, u32 gap, u32 post, u32 wrap)
53{
Angel Pons9f58bb22020-11-12 11:56:07 +010054 const struct iosav_ssq sequence[] = {
55 /* DRAM command ZQCS */
56 [0] = {
57 .sp_cmd_ctrl = {
58 .command = IOSAV_ZQCS,
59 },
60 .subseq_ctrl = {
61 .cmd_executions = 1,
62 .cmd_delay_gap = gap,
63 .post_ssq_wait = post,
64 .data_direction = SSQ_NA,
65 },
66 .sp_cmd_addr = {
67 .address = 0,
68 .rowbits = 6,
69 .bank = 0,
70 .rank = slotrank,
71 },
72 .addr_update = {
73 .addr_wrap = wrap,
74 },
75 },
76 };
Angel Ponsffd50152020-11-12 11:03:10 +010077 iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
78}
79
80void iosav_write_prea_sequence(int channel, int slotrank, u32 post, u32 wrap)
81{
Angel Pons9f58bb22020-11-12 11:56:07 +010082 const struct iosav_ssq sequence[] = {
83 /* DRAM command PREA */
84 [0] = {
85 .sp_cmd_ctrl = {
86 .command = IOSAV_PRE,
87 .ranksel_ap = 1,
88 },
89 .subseq_ctrl = {
90 .cmd_executions = 1,
91 .cmd_delay_gap = 3,
92 .post_ssq_wait = post,
93 .data_direction = SSQ_NA,
94 },
95 .sp_cmd_addr = {
96 .address = 1024,
97 .rowbits = 6,
98 .bank = 0,
99 .rank = slotrank,
100 },
101 .addr_update = {
102 .addr_wrap = wrap,
103 },
104 },
105 };
Angel Ponsffd50152020-11-12 11:03:10 +0100106 iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
107}
108
109void iosav_write_read_mpr_sequence(
110 int channel, int slotrank, u32 tMOD, u32 loops, u32 gap, u32 loops2, u32 post2)
111{
Angel Pons9f58bb22020-11-12 11:56:07 +0100112 const struct iosav_ssq sequence[] = {
113 /*
114 * DRAM command MRS
115 *
116 * Write MR3 MPR enable. In this mode only RD and RDA
117 * are allowed, and all reads return a predefined pattern.
118 */
119 [0] = {
120 .sp_cmd_ctrl = {
121 .command = IOSAV_MRS,
122 .ranksel_ap = 1,
123 },
124 .subseq_ctrl = {
125 .cmd_executions = 1,
126 .cmd_delay_gap = 3,
127 .post_ssq_wait = tMOD,
128 .data_direction = SSQ_NA,
129 },
130 .sp_cmd_addr = {
131 .address = 4,
132 .rowbits = 6,
133 .bank = 3,
134 .rank = slotrank,
135 },
136 },
137 /* DRAM command RD */
138 [1] = {
139 .sp_cmd_ctrl = {
140 .command = IOSAV_RD,
141 .ranksel_ap = 1,
142 },
143 .subseq_ctrl = {
144 .cmd_executions = loops,
145 .cmd_delay_gap = gap,
146 .post_ssq_wait = 4,
147 .data_direction = SSQ_RD,
148 },
149 .sp_cmd_addr = {
150 .address = 0,
151 .rowbits = 0,
152 .bank = 0,
153 .rank = slotrank,
154 },
155 },
156 /* DRAM command RD */
157 [2] = {
158 .sp_cmd_ctrl = {
159 .command = IOSAV_RD,
160 .ranksel_ap = 1,
161 },
162 .subseq_ctrl = {
163 .cmd_executions = loops2,
164 .cmd_delay_gap = 4,
165 .post_ssq_wait = post2,
166 .data_direction = SSQ_NA,
167 },
168 .sp_cmd_addr = {
169 .address = 0,
170 .rowbits = 6,
171 .bank = 0,
172 .rank = slotrank,
173 },
174 },
175 /*
176 * DRAM command MRS
177 *
178 * Write MR3 MPR disable.
179 */
180 [3] = {
181 .sp_cmd_ctrl = {
182 .command = IOSAV_MRS,
183 .ranksel_ap = 1,
184 },
185 .subseq_ctrl = {
186 .cmd_executions = 1,
187 .cmd_delay_gap = 3,
188 .post_ssq_wait = tMOD,
189 .data_direction = SSQ_NA,
190 },
191 .sp_cmd_addr = {
192 .address = 0,
193 .rowbits = 6,
194 .bank = 3,
195 .rank = slotrank,
196 },
197 },
198 };
Angel Ponsffd50152020-11-12 11:03:10 +0100199 iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
200}
201
202void iosav_write_misc_write_sequence(ramctr_timing *ctrl, int channel, int slotrank,
203 u32 gap0, u32 loops0, u32 gap1, u32 loops2, u32 wrap2)
204{
Angel Pons9f58bb22020-11-12 11:56:07 +0100205 const struct iosav_ssq sequence[] = {
206 /* DRAM command ACT */
207 [0] = {
208 .sp_cmd_ctrl = {
209 .command = IOSAV_ACT,
210 .ranksel_ap = 1,
211 },
212 .subseq_ctrl = {
213 .cmd_executions = loops0,
214 .cmd_delay_gap = gap0,
215 .post_ssq_wait = ctrl->tRCD,
216 .data_direction = SSQ_NA,
217 },
218 .sp_cmd_addr = {
219 .address = 0,
220 .rowbits = 6,
221 .bank = 0,
222 .rank = slotrank,
223 },
224 .addr_update = {
225 .inc_bank = loops0 == 1 ? 0 : 1,
226 .addr_wrap = loops0 == 1 ? 0 : 18,
227 },
228 },
229 /* DRAM command NOP */
230 [1] = {
231 .sp_cmd_ctrl = {
232 .command = IOSAV_NOP,
233 .ranksel_ap = 1,
234 },
235 .subseq_ctrl = {
236 .cmd_executions = 1,
237 .cmd_delay_gap = gap1,
238 .post_ssq_wait = 4,
239 .data_direction = SSQ_WR,
240 },
241 .sp_cmd_addr = {
242 .address = 8,
243 .rowbits = 0,
244 .bank = 0,
245 .rank = slotrank,
246 },
247 .addr_update = {
248 .addr_wrap = 31,
249 },
250 },
251 /* DRAM command WR */
252 [2] = {
253 .sp_cmd_ctrl = {
254 .command = IOSAV_WR,
255 .ranksel_ap = 1,
256 },
257 .subseq_ctrl = {
258 .cmd_executions = loops2,
259 .cmd_delay_gap = 4,
260 .post_ssq_wait = 4,
261 .data_direction = SSQ_WR,
262 },
263 .sp_cmd_addr = {
264 .address = 0,
265 .rowbits = 0,
266 .bank = 0,
267 .rank = slotrank,
268 },
269 .addr_update = {
270 .inc_addr_8 = 1,
271 .addr_wrap = wrap2,
272 },
273 },
274 /* DRAM command NOP */
275 [3] = {
276 .sp_cmd_ctrl = {
277 .command = IOSAV_NOP,
278 .ranksel_ap = 1,
279 },
280 .subseq_ctrl = {
281 .cmd_executions = 1,
282 .cmd_delay_gap = 3,
283 .post_ssq_wait = ctrl->CWL + ctrl->tWTR + 5,
284 .data_direction = SSQ_WR,
285 },
286 .sp_cmd_addr = {
287 .address = 8,
288 .rowbits = 0,
289 .bank = 0,
290 .rank = slotrank,
291 },
292 .addr_update = {
293 .addr_wrap = 31,
294 },
295 },
296 };
Angel Ponsffd50152020-11-12 11:03:10 +0100297 iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
298}
299
300void iosav_write_command_training_sequence(
301 ramctr_timing *ctrl, int channel, int slotrank, unsigned int address)
302{
Angel Pons9f58bb22020-11-12 11:56:07 +0100303 const struct iosav_ssq sequence[] = {
304 /* DRAM command ACT */
305 [0] = {
306 .sp_cmd_ctrl = {
307 .command = IOSAV_ACT,
308 .ranksel_ap = 1,
309 },
310 .subseq_ctrl = {
311 .cmd_executions = 8,
312 .cmd_delay_gap = MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1),
313 .post_ssq_wait = ctrl->tRCD,
314 .data_direction = SSQ_NA,
315 },
316 .sp_cmd_addr = {
317 .address = address,
318 .rowbits = 6,
319 .bank = 0,
320 .rank = slotrank,
321 },
322 .addr_update = {
323 .inc_bank = 1,
324 .addr_wrap = 18,
325 },
326 },
327 /* DRAM command WR */
328 [1] = {
329 .sp_cmd_ctrl = {
330 .command = IOSAV_WR,
331 .ranksel_ap = 1,
332 },
333 .subseq_ctrl = {
334 .cmd_executions = 32,
335 .cmd_delay_gap = 4,
336 .post_ssq_wait = ctrl->CWL + ctrl->tWTR + 8,
337 .data_direction = SSQ_WR,
338 },
339 .sp_cmd_addr = {
340 .address = 0,
341 .rowbits = 0,
342 .bank = 0,
343 .rank = slotrank,
344 },
345 .addr_update = {
346 .inc_addr_8 = 1,
347 .addr_wrap = 18,
348 .lfsr_upd = 3,
349 .lfsr_xors = 2,
350 },
351 },
352 /* DRAM command RD */
353 [2] = {
354 .sp_cmd_ctrl = {
355 .command = IOSAV_RD,
356 .ranksel_ap = 1,
357 },
358 .subseq_ctrl = {
359 .cmd_executions = 32,
360 .cmd_delay_gap = 4,
361 .post_ssq_wait = MAX(ctrl->tRTP, 8),
362 .data_direction = SSQ_RD,
363 },
364 .sp_cmd_addr = {
365 .address = 0,
366 .rowbits = 0,
367 .bank = 0,
368 .rank = slotrank,
369 },
370 .addr_update = {
371 .inc_addr_8 = 1,
372 .addr_wrap = 18,
373 .lfsr_upd = 3,
374 .lfsr_xors = 2,
375 },
376 },
377 /* DRAM command PRE */
378 [3] = {
379 .sp_cmd_ctrl = {
380 .command = IOSAV_PRE,
381 .ranksel_ap = 1,
382 },
383 .subseq_ctrl = {
384 .cmd_executions = 1,
385 .cmd_delay_gap = 4,
386 .post_ssq_wait = 15,
387 .data_direction = SSQ_NA,
388 },
389 .sp_cmd_addr = {
390 .address = 1024,
391 .rowbits = 6,
392 .bank = 0,
393 .rank = slotrank,
394 },
395 .addr_update = {
396 .addr_wrap = 18,
397 },
398 },
399 };
Angel Ponsffd50152020-11-12 11:03:10 +0100400 iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
401}
402
403void iosav_write_data_write_sequence(ramctr_timing *ctrl, int channel, int slotrank)
404{
Angel Pons9f58bb22020-11-12 11:56:07 +0100405 const struct iosav_ssq sequence[] = {
406 /* DRAM command ACT */
407 [0] = {
408 .sp_cmd_ctrl = {
409 .command = IOSAV_ACT,
410 .ranksel_ap = 1,
411 },
412 .subseq_ctrl = {
413 .cmd_executions = 4,
414 .cmd_delay_gap = MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1),
415 .post_ssq_wait = ctrl->tRCD,
416 .data_direction = SSQ_NA,
417 },
418 .sp_cmd_addr = {
419 .address = 0,
420 .rowbits = 6,
421 .bank = 0,
422 .rank = slotrank,
423 },
424 .addr_update = {
425 .inc_bank = 0,
426 .addr_wrap = 18,
427 },
428 },
429 /* DRAM command WR */
430 [1] = {
431 .sp_cmd_ctrl = {
432 .command = IOSAV_WR,
433 .ranksel_ap = 1,
434 },
435 .subseq_ctrl = {
436 .cmd_executions = 32,
437 .cmd_delay_gap = 20,
438 .post_ssq_wait = ctrl->CWL + ctrl->tWTR + 8,
439 .data_direction = SSQ_WR,
440 },
441 .sp_cmd_addr = {
442 .address = 0,
443 .rowbits = 0,
444 .bank = 0,
445 .rank = slotrank,
446 },
447 .addr_update = {
448 .inc_addr_8 = 1,
449 .addr_wrap = 18,
450 },
451 },
452 /* DRAM command RD */
453 [2] = {
454 .sp_cmd_ctrl = {
455 .command = IOSAV_RD,
456 .ranksel_ap = 1,
457 },
458 .subseq_ctrl = {
459 .cmd_executions = 32,
460 .cmd_delay_gap = 20,
461 .post_ssq_wait = MAX(ctrl->tRTP, 8),
462 .data_direction = SSQ_RD,
463 },
464 .sp_cmd_addr = {
465 .address = 0,
466 .rowbits = 0,
467 .bank = 0,
468 .rank = slotrank,
469 },
470 .addr_update = {
471 .inc_addr_8 = 1,
472 .addr_wrap = 18,
473 },
474 },
475 /* DRAM command PRE */
476 [3] = {
477 .sp_cmd_ctrl = {
478 .command = IOSAV_PRE,
479 .ranksel_ap = 1,
480 },
481 .subseq_ctrl = {
482 .cmd_executions = 1,
483 .cmd_delay_gap = 3,
484 .post_ssq_wait = ctrl->tRP,
485 .data_direction = SSQ_NA,
486 },
487 .sp_cmd_addr = {
488 .address = 1024,
489 .rowbits = 6,
490 .bank = 0,
491 .rank = slotrank,
492 },
493 },
494 };
Angel Ponsffd50152020-11-12 11:03:10 +0100495 iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
496}
497
498void iosav_write_aggressive_write_read_sequence(ramctr_timing *ctrl, int channel, int slotrank)
499{
Angel Pons9f58bb22020-11-12 11:56:07 +0100500 const struct iosav_ssq sequence[] = {
501 /* DRAM command ACT */
502 [0] = {
503 .sp_cmd_ctrl = {
504 .command = IOSAV_ACT,
505 .ranksel_ap = 1,
506 },
507 .subseq_ctrl = {
508 .cmd_executions = 4,
509 .cmd_delay_gap = MAX((ctrl->tFAW >> 2) + 1, ctrl->tRRD),
510 .post_ssq_wait = ctrl->tRCD,
511 .data_direction = SSQ_NA,
512 },
513 .sp_cmd_addr = {
514 .address = 0,
515 .rowbits = 6,
516 .bank = 0,
517 .rank = slotrank,
518 },
519 .addr_update = {
520 .inc_bank = 1,
521 .addr_wrap = 18,
522 },
523 },
524 /* DRAM command WR */
525 [1] = {
526 .sp_cmd_ctrl = {
527 .command = IOSAV_WR,
528 .ranksel_ap = 1,
529 },
530 .subseq_ctrl = {
531 .cmd_executions = 480,
532 .cmd_delay_gap = 4,
533 .post_ssq_wait = ctrl->tWTR + ctrl->CWL + 8,
534 .data_direction = SSQ_WR,
535 },
536 .sp_cmd_addr = {
537 .address = 0,
538 .rowbits = 0,
539 .bank = 0,
540 .rank = slotrank,
541 },
542 .addr_update = {
543 .inc_addr_8 = 1,
544 .addr_wrap = 18,
545 },
546 },
547 /* DRAM command RD */
548 [2] = {
549 .sp_cmd_ctrl = {
550 .command = IOSAV_RD,
551 .ranksel_ap = 1,
552 },
553 .subseq_ctrl = {
554 .cmd_executions = 480,
555 .cmd_delay_gap = 4,
556 .post_ssq_wait = MAX(ctrl->tRTP, 8),
557 .data_direction = SSQ_RD,
558 },
559 .sp_cmd_addr = {
560 .address = 0,
561 .rowbits = 0,
562 .bank = 0,
563 .rank = slotrank,
564 },
565 .addr_update = {
566 .inc_addr_8 = 1,
567 .addr_wrap = 18,
568 },
569 },
570 /* DRAM command PRE */
571 [3] = {
572 .sp_cmd_ctrl = {
573 .command = IOSAV_PRE,
574 .ranksel_ap = 1,
575 },
576 .subseq_ctrl = {
577 .cmd_executions = 1,
578 .cmd_delay_gap = 4,
579 .post_ssq_wait = ctrl->tRP,
580 .data_direction = SSQ_NA,
581 },
582 .sp_cmd_addr = {
583 .address = 1024,
584 .rowbits = 6,
585 .bank = 0,
586 .rank = slotrank,
587 },
588 },
589 };
Angel Ponsffd50152020-11-12 11:03:10 +0100590 iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
591}
592
593void iosav_write_memory_test_sequence(ramctr_timing *ctrl, int channel, int slotrank)
594{
Angel Pons9f58bb22020-11-12 11:56:07 +0100595 const struct iosav_ssq sequence[] = {
596 /* DRAM command ACT */
597 [0] = {
598 .sp_cmd_ctrl = {
599 .command = IOSAV_ACT,
600 .ranksel_ap = 1,
601 },
602 .subseq_ctrl = {
603 .cmd_executions = 4,
604 .cmd_delay_gap = 8,
605 .post_ssq_wait = 40,
606 .data_direction = SSQ_NA,
607 },
608 .sp_cmd_addr = {
609 .address = 0,
610 .rowbits = 6,
611 .bank = 0,
612 .rank = slotrank,
613 },
614 .addr_update = {
615 .inc_bank = 1,
616 .addr_wrap = 18,
617 },
618 },
619 /* DRAM command WR */
620 [1] = {
621 .sp_cmd_ctrl = {
622 .command = IOSAV_WR,
623 .ranksel_ap = 1,
624 },
625 .subseq_ctrl = {
626 .cmd_executions = 100,
627 .cmd_delay_gap = 4,
628 .post_ssq_wait = 40,
629 .data_direction = SSQ_WR,
630 },
631 .sp_cmd_addr = {
632 .address = 0,
633 .rowbits = 0,
634 .bank = 0,
635 .rank = slotrank,
636 },
637 .addr_update = {
638 .inc_addr_8 = 1,
639 .addr_wrap = 18,
640 },
641 },
642 /* DRAM command RD */
643 [2] = {
644 .sp_cmd_ctrl = {
645 .command = IOSAV_RD,
646 .ranksel_ap = 1,
647 },
648 .subseq_ctrl = {
649 .cmd_executions = 100,
650 .cmd_delay_gap = 4,
651 .post_ssq_wait = 40,
652 .data_direction = SSQ_RD,
653 },
654 .sp_cmd_addr = {
655 .address = 0,
656 .rowbits = 0,
657 .bank = 0,
658 .rank = slotrank,
659 },
660 .addr_update = {
661 .inc_addr_8 = 1,
662 .addr_wrap = 18,
663 },
664 },
665 /* DRAM command PRE */
666 [3] = {
667 .sp_cmd_ctrl = {
668 .command = IOSAV_PRE,
669 .ranksel_ap = 1,
670 },
671 .subseq_ctrl = {
672 .cmd_executions = 1,
673 .cmd_delay_gap = 3,
674 .post_ssq_wait = 40,
675 .data_direction = SSQ_NA,
676 },
677 .sp_cmd_addr = {
678 .address = 1024,
679 .rowbits = 6,
680 .bank = 0,
681 .rank = slotrank,
682 },
683 .addr_update = {
684 .addr_wrap = 18,
685 },
686 },
687 };
Angel Ponsffd50152020-11-12 11:03:10 +0100688 iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
689}