xref: /aosp_15_r20/external/coreboot/src/northbridge/intel/sandybridge/raminit_iosav.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <commonlib/helpers.h>
4 #include <types.h>
5 
6 #include "raminit_common.h"
7 #include "raminit_tables.h"
8 #include "sandybridge.h"
9 
10 /* FIXME: no support for 3-channel chipsets */
11 
12 /* Number of programmed IOSAV subsequences. */
13 static unsigned int ssq_count = 0;
14 
iosav_write_sequence(const int ch,const struct iosav_ssq * seq,const unsigned int length)15 void iosav_write_sequence(const int ch, const struct iosav_ssq *seq, const unsigned int length)
16 {
17 	for (unsigned int i = 0; i < length; i++) {
18 		mchbar_write32(IOSAV_n_SP_CMD_CTRL_ch(ch, i), seq[i].sp_cmd_ctrl.raw);
19 		mchbar_write32(IOSAV_n_SUBSEQ_CTRL_ch(ch, i), seq[i].subseq_ctrl.raw);
20 		mchbar_write32(IOSAV_n_SP_CMD_ADDR_ch(ch, i), seq[i].sp_cmd_addr.raw);
21 		mchbar_write32(IOSAV_n_ADDR_UPDATE_ch(ch, i), seq[i].addr_update.raw);
22 	}
23 
24 	ssq_count = length;
25 }
26 
iosav_run_queue(const int ch,const u8 loops,const u8 as_timer)27 void iosav_run_queue(const int ch, const u8 loops, const u8 as_timer)
28 {
29 	/* Should never happen */
30 	if (ssq_count == 0)
31 		return;
32 
33 	mchbar_write32(IOSAV_SEQ_CTL_ch(ch), loops | (ssq_count - 1) << 18 | as_timer << 22);
34 }
35 
wait_for_iosav(int channel)36 void wait_for_iosav(int channel)
37 {
38 	while (1) {
39 		if (mchbar_read32(IOSAV_STATUS_ch(channel)) & 0x50)
40 			return;
41 	}
42 }
43 
iosav_run_once_and_wait(const int ch)44 void iosav_run_once_and_wait(const int ch)
45 {
46 	iosav_run_queue(ch, 1, 0);
47 	wait_for_iosav(ch);
48 }
49 
iosav_write_zqcs_sequence(int channel,int slotrank,u32 gap,u32 post,u32 wrap)50 void iosav_write_zqcs_sequence(int channel, int slotrank, u32 gap, u32 post, u32 wrap)
51 {
52 	const struct iosav_ssq sequence[] = {
53 		/* DRAM command ZQCS */
54 		[0] = {
55 			.sp_cmd_ctrl = {
56 				.command = IOSAV_ZQCS,
57 			},
58 			.subseq_ctrl = {
59 				.cmd_executions = 1,
60 				.cmd_delay_gap  = gap,
61 				.post_ssq_wait  = post,
62 				.data_direction = SSQ_NA,
63 			},
64 			.sp_cmd_addr = {
65 				.address = 0,
66 				.rowbits = 6,
67 				.bank    = 0,
68 				.rank    = slotrank,
69 			},
70 			.addr_update = {
71 				.addr_wrap = wrap,
72 			},
73 		},
74 	};
75 	iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
76 }
77 
iosav_write_prea_sequence(int channel,int slotrank,u32 post,u32 wrap)78 void iosav_write_prea_sequence(int channel, int slotrank, u32 post, u32 wrap)
79 {
80 	const struct iosav_ssq sequence[] = {
81 		/* DRAM command PREA */
82 		[0] = {
83 			.sp_cmd_ctrl = {
84 				.command = IOSAV_PRE,
85 				.ranksel_ap = 1,
86 			},
87 			.subseq_ctrl = {
88 				.cmd_executions = 1,
89 				.cmd_delay_gap  = 3,
90 				.post_ssq_wait  = post,
91 				.data_direction = SSQ_NA,
92 			},
93 			.sp_cmd_addr = {
94 				.address = 1 << 10,
95 				.rowbits = 6,
96 				.bank    = 0,
97 				.rank    = slotrank,
98 			},
99 			.addr_update = {
100 				.addr_wrap = wrap,
101 			},
102 		},
103 	};
104 	iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
105 }
106 
iosav_write_read_mpr_sequence(int channel,int slotrank,u32 tMOD,u32 loops,u32 gap,u32 loops2,u32 post2)107 void iosav_write_read_mpr_sequence(
108 	int channel, int slotrank, u32 tMOD, u32 loops, u32 gap, u32 loops2, u32 post2)
109 {
110 	const struct iosav_ssq sequence[] = {
111 		/*
112 		 * DRAM command MRS
113 		 *
114 		 * Write MR3 MPR enable. In this mode only RD and RDA
115 		 * are allowed, and all reads return a predefined pattern.
116 		 */
117 		[0] = {
118 			.sp_cmd_ctrl = {
119 				.command    = IOSAV_MRS,
120 				.ranksel_ap = 1,
121 			},
122 			.subseq_ctrl = {
123 				.cmd_executions = 1,
124 				.cmd_delay_gap  = 3,
125 				.post_ssq_wait  = tMOD,
126 				.data_direction = SSQ_NA,
127 			},
128 			.sp_cmd_addr = {
129 				.address = 4,
130 				.rowbits = 6,
131 				.bank    = 3,
132 				.rank    = slotrank,
133 			},
134 		},
135 		/* DRAM command RD */
136 		[1] = {
137 			.sp_cmd_ctrl = {
138 				.command    = IOSAV_RD,
139 				.ranksel_ap = 1,
140 			},
141 			.subseq_ctrl = {
142 				.cmd_executions = loops,
143 				.cmd_delay_gap  = gap,
144 				.post_ssq_wait  = 4,
145 				.data_direction = SSQ_RD,
146 			},
147 			.sp_cmd_addr = {
148 				.address = 0,
149 				.rowbits = 0,
150 				.bank    = 0,
151 				.rank    = slotrank,
152 			},
153 		},
154 		/* DRAM command RD */
155 		[2] = {
156 			.sp_cmd_ctrl = {
157 				.command    = IOSAV_RD,
158 				.ranksel_ap = 1,
159 			},
160 			.subseq_ctrl = {
161 				.cmd_executions = loops2,
162 				.cmd_delay_gap  = 4,
163 				.post_ssq_wait  = post2,
164 				.data_direction = SSQ_NA,
165 			},
166 			.sp_cmd_addr = {
167 				.address = 0,
168 				.rowbits = 6,
169 				.bank    = 0,
170 				.rank    = slotrank,
171 			},
172 		},
173 		/*
174 		 * DRAM command MRS
175 		 *
176 		 * Write MR3 MPR disable.
177 		 */
178 		[3] = {
179 			.sp_cmd_ctrl = {
180 				.command    = IOSAV_MRS,
181 				.ranksel_ap = 1,
182 			},
183 			.subseq_ctrl = {
184 				.cmd_executions = 1,
185 				.cmd_delay_gap  = 3,
186 				.post_ssq_wait  = tMOD,
187 				.data_direction = SSQ_NA,
188 			},
189 			.sp_cmd_addr = {
190 				.address = 0,
191 				.rowbits = 6,
192 				.bank    = 3,
193 				.rank    = slotrank,
194 			},
195 		},
196 	};
197 	iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
198 }
199 
iosav_write_prea_act_read_sequence(ramctr_timing * ctrl,int channel,int slotrank)200 void iosav_write_prea_act_read_sequence(ramctr_timing *ctrl, int channel, int slotrank)
201 {
202 	const struct iosav_ssq sequence[] = {
203 		/* DRAM command PREA */
204 		[0] = {
205 			.sp_cmd_ctrl = {
206 				.command    = IOSAV_PRE,
207 				.ranksel_ap = 1,
208 			},
209 			.subseq_ctrl = {
210 				.cmd_executions = 1,
211 				.cmd_delay_gap  = 3,
212 				.post_ssq_wait  = ctrl->tRP,
213 				.data_direction = SSQ_NA,
214 			},
215 			.sp_cmd_addr = {
216 				.address = 1 << 10,
217 				.rowbits = 6,
218 				.bank    = 0,
219 				.rank    = slotrank,
220 			},
221 			.addr_update = {
222 				.addr_wrap = 18,
223 			},
224 		},
225 		/* DRAM command ACT */
226 		[1] = {
227 			.sp_cmd_ctrl = {
228 				.command    = IOSAV_ACT,
229 				.ranksel_ap = 1,
230 			},
231 			.subseq_ctrl = {
232 				.cmd_executions = 8,
233 				.cmd_delay_gap  = MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1),
234 				.post_ssq_wait  = ctrl->CAS,
235 				.data_direction = SSQ_NA,
236 			},
237 			.sp_cmd_addr = {
238 				.address = 0,
239 				.rowbits = 6,
240 				.bank    = 0,
241 				.rank    = slotrank,
242 			},
243 			.addr_update = {
244 				.inc_bank  = 1,
245 				.addr_wrap = 18,
246 			},
247 		},
248 		/* DRAM command RD */
249 		[2] = {
250 			.sp_cmd_ctrl = {
251 				.command    = IOSAV_RD,
252 				.ranksel_ap = 1,
253 			},
254 			.subseq_ctrl = {
255 				.cmd_executions = 500,
256 				.cmd_delay_gap  = 4,
257 				.post_ssq_wait  = MAX(ctrl->tRTP, 8),
258 				.data_direction = SSQ_RD,
259 			},
260 			.sp_cmd_addr = {
261 				.address = 0,
262 				.rowbits = 0,
263 				.bank    = 0,
264 				.rank    = slotrank,
265 			},
266 			.addr_update = {
267 				.inc_addr_8 = 1,
268 				.addr_wrap  = 18,
269 			},
270 		},
271 		/* DRAM command PREA */
272 		[3] = {
273 			.sp_cmd_ctrl = {
274 				.command    = IOSAV_PRE,
275 				.ranksel_ap = 1,
276 			},
277 			.subseq_ctrl = {
278 				.cmd_executions = 1,
279 				.cmd_delay_gap  = 3,
280 				.post_ssq_wait  = ctrl->tRP,
281 				.data_direction = SSQ_NA,
282 			},
283 			.sp_cmd_addr = {
284 				.address = 1 << 10,
285 				.rowbits = 6,
286 				.bank    = 0,
287 				.rank    = slotrank,
288 			},
289 			.addr_update = {
290 				.addr_wrap = 18,
291 			},
292 		},
293 	};
294 	iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
295 }
296 
iosav_write_jedec_write_leveling_sequence(ramctr_timing * ctrl,int channel,int slotrank,int bank,u32 mr1reg)297 void iosav_write_jedec_write_leveling_sequence(
298 	ramctr_timing *ctrl, int channel, int slotrank, int bank, u32 mr1reg)
299 {
300 	/* First DQS/DQS# rising edge after write leveling mode is programmed */
301 	const u32 tWLMRD = 40;
302 
303 	const struct iosav_ssq sequence[] = {
304 		/* DRAM command MRS: enable DQs on this slotrank */
305 		[0] = {
306 			.sp_cmd_ctrl = {
307 				.command    = IOSAV_MRS,
308 				.ranksel_ap = 1,
309 			},
310 			.subseq_ctrl = {
311 				.cmd_executions = 1,
312 				.cmd_delay_gap  = 3,
313 				.post_ssq_wait  = tWLMRD,
314 				.data_direction = SSQ_NA,
315 			},
316 			.sp_cmd_addr = {
317 				.address = mr1reg,
318 				.rowbits = 6,
319 				.bank    = bank,
320 				.rank    = slotrank,
321 			},
322 		},
323 		/* DRAM command NOP */
324 		[1] = {
325 			.sp_cmd_ctrl = {
326 				.command    = IOSAV_NOP,
327 				.ranksel_ap = 1,
328 			},
329 			.subseq_ctrl = {
330 				.cmd_executions = 1,
331 				.cmd_delay_gap  = 3,
332 				.post_ssq_wait  = ctrl->CWL + ctrl->tWLO,
333 				.data_direction = SSQ_WR,
334 			},
335 			.sp_cmd_addr = {
336 				.address = 8,
337 				.rowbits = 0,
338 				.bank    = 0,
339 				.rank    = slotrank,
340 			},
341 		},
342 		/* DRAM command NOP */
343 		[2] = {
344 			.sp_cmd_ctrl = {
345 				.command    = IOSAV_NOP_ALT,
346 				.ranksel_ap = 1,
347 			},
348 			.subseq_ctrl = {
349 				.cmd_executions = 1,
350 				.cmd_delay_gap  = 3,
351 				.post_ssq_wait  = ctrl->CAS + 38,
352 				.data_direction = SSQ_RD,
353 			},
354 			.sp_cmd_addr = {
355 				.address = 4,
356 				.rowbits = 0,
357 				.bank    = 0,
358 				.rank    = slotrank,
359 			},
360 		},
361 		/* DRAM command MRS: disable DQs on this slotrank */
362 		[3] = {
363 			.sp_cmd_ctrl = {
364 				.command    = IOSAV_MRS,
365 				.ranksel_ap = 1,
366 			},
367 			.subseq_ctrl = {
368 				.cmd_executions = 1,
369 				.cmd_delay_gap  = 3,
370 				.post_ssq_wait  = ctrl->tMOD,
371 				.data_direction = SSQ_NA,
372 			},
373 			.sp_cmd_addr = {
374 				.address = mr1reg | 1 << 12,
375 				.rowbits = 6,
376 				.bank    = bank,
377 				.rank    = slotrank,
378 			},
379 		},
380 	};
381 	iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
382 }
383 
iosav_write_misc_write_sequence(ramctr_timing * ctrl,int channel,int slotrank,u32 gap0,u32 loops0,u32 gap1,u32 loops2,u32 wrap2)384 void iosav_write_misc_write_sequence(ramctr_timing *ctrl, int channel, int slotrank,
385 				     u32 gap0, u32 loops0, u32 gap1, u32 loops2, u32 wrap2)
386 {
387 	const struct iosav_ssq sequence[] = {
388 		/* DRAM command ACT */
389 		[0] = {
390 			.sp_cmd_ctrl = {
391 				.command    = IOSAV_ACT,
392 				.ranksel_ap = 1,
393 			},
394 			.subseq_ctrl = {
395 				.cmd_executions = loops0,
396 				.cmd_delay_gap  = gap0,
397 				.post_ssq_wait  = ctrl->tRCD,
398 				.data_direction = SSQ_NA,
399 			},
400 			.sp_cmd_addr = {
401 				.address = 0,
402 				.rowbits = 6,
403 				.bank    = 0,
404 				.rank    = slotrank,
405 			},
406 			.addr_update = {
407 				.inc_bank  = loops0 == 1 ? 0 : 1,
408 				.addr_wrap = loops0 == 1 ? 0 : 18,
409 			},
410 		},
411 		/* DRAM command NOP */
412 		[1] = {
413 			.sp_cmd_ctrl = {
414 				.command    = IOSAV_NOP,
415 				.ranksel_ap = 1,
416 			},
417 			.subseq_ctrl = {
418 				.cmd_executions = 1,
419 				.cmd_delay_gap  = gap1,
420 				.post_ssq_wait  = 4,
421 				.data_direction = SSQ_WR,
422 			},
423 			.sp_cmd_addr = {
424 				.address = 8,
425 				.rowbits = 0,
426 				.bank    = 0,
427 				.rank    = slotrank,
428 			},
429 			.addr_update = {
430 				.addr_wrap = 31,
431 			},
432 		},
433 		/* DRAM command WR */
434 		[2] = {
435 			.sp_cmd_ctrl = {
436 				.command    = IOSAV_WR,
437 				.ranksel_ap = 1,
438 			},
439 			.subseq_ctrl = {
440 				.cmd_executions = loops2,
441 				.cmd_delay_gap  = 4,
442 				.post_ssq_wait  = 4,
443 				.data_direction = SSQ_WR,
444 			},
445 			.sp_cmd_addr = {
446 				.address = 0,
447 				.rowbits = 0,
448 				.bank    = 0,
449 				.rank    = slotrank,
450 			},
451 			.addr_update = {
452 				.inc_addr_8 = 1,
453 				.addr_wrap  = wrap2,
454 			},
455 		},
456 		/* DRAM command NOP */
457 		[3] = {
458 			.sp_cmd_ctrl = {
459 				.command    = IOSAV_NOP,
460 				.ranksel_ap = 1,
461 			},
462 			.subseq_ctrl = {
463 				.cmd_executions = 1,
464 				.cmd_delay_gap  = 3,
465 				.post_ssq_wait  = ctrl->CWL + ctrl->tWTR + 5,
466 				.data_direction = SSQ_WR,
467 			},
468 			.sp_cmd_addr = {
469 				.address = 8,
470 				.rowbits = 0,
471 				.bank    = 0,
472 				.rank    = slotrank,
473 			},
474 			.addr_update = {
475 				.addr_wrap = 31,
476 			},
477 		},
478 	};
479 	iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
480 }
481 
iosav_write_command_training_sequence(ramctr_timing * ctrl,int channel,int slotrank,unsigned int address)482 void iosav_write_command_training_sequence(
483 	ramctr_timing *ctrl, int channel, int slotrank, unsigned int address)
484 {
485 	const struct iosav_ssq sequence[] = {
486 		/* DRAM command ACT */
487 		[0] = {
488 			.sp_cmd_ctrl = {
489 				.command    = IOSAV_ACT,
490 				.ranksel_ap = 1,
491 			},
492 			.subseq_ctrl = {
493 				.cmd_executions = 8,
494 				.cmd_delay_gap  = MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1),
495 				.post_ssq_wait  = ctrl->tRCD,
496 				.data_direction = SSQ_NA,
497 			},
498 			.sp_cmd_addr = {
499 				.address = address,
500 				.rowbits = 6,
501 				.bank    = 0,
502 				.rank    = slotrank,
503 			},
504 			.addr_update = {
505 				.inc_bank  = 1,
506 				.addr_wrap = 18,
507 			},
508 		},
509 		/* DRAM command WR */
510 		[1] = {
511 			.sp_cmd_ctrl = {
512 				.command    = IOSAV_WR,
513 				.ranksel_ap = 1,
514 			},
515 			.subseq_ctrl = {
516 				.cmd_executions = 32,
517 				.cmd_delay_gap  = 4,
518 				.post_ssq_wait  = ctrl->CWL + ctrl->tWTR + 8,
519 				.data_direction = SSQ_WR,
520 			},
521 			.sp_cmd_addr = {
522 				.address = 0,
523 				.rowbits = 0,
524 				.bank    = 0,
525 				.rank    = slotrank,
526 			},
527 			.addr_update = {
528 				.inc_addr_8 = 1,
529 				.addr_wrap  = 18,
530 				.lfsr_upd   = 3,
531 				.lfsr_xors  = 2,
532 			},
533 		},
534 		/* DRAM command RD */
535 		[2] = {
536 			.sp_cmd_ctrl = {
537 				.command    = IOSAV_RD,
538 				.ranksel_ap = 1,
539 			},
540 			.subseq_ctrl = {
541 				.cmd_executions = 32,
542 				.cmd_delay_gap  = 4,
543 				.post_ssq_wait  = MAX(ctrl->tRTP, 8),
544 				.data_direction = SSQ_RD,
545 			},
546 			.sp_cmd_addr = {
547 				.address = 0,
548 				.rowbits = 0,
549 				.bank    = 0,
550 				.rank    = slotrank,
551 			},
552 			.addr_update = {
553 				.inc_addr_8 = 1,
554 				.addr_wrap  = 18,
555 				.lfsr_upd   = 3,
556 				.lfsr_xors  = 2,
557 			},
558 		},
559 		/* DRAM command PRE */
560 		[3] = {
561 			.sp_cmd_ctrl = {
562 				.command    = IOSAV_PRE,
563 				.ranksel_ap = 1,
564 			},
565 			.subseq_ctrl = {
566 				.cmd_executions = 1,
567 				.cmd_delay_gap  = 4,
568 				.post_ssq_wait  = 15,
569 				.data_direction = SSQ_NA,
570 			},
571 			.sp_cmd_addr = {
572 				.address = 1 << 10,
573 				.rowbits = 6,
574 				.bank    = 0,
575 				.rank    = slotrank,
576 			},
577 			.addr_update = {
578 				.addr_wrap = 18,
579 			},
580 		},
581 	};
582 	iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
583 }
584 
iosav_write_data_write_sequence(ramctr_timing * ctrl,int channel,int slotrank)585 void iosav_write_data_write_sequence(ramctr_timing *ctrl, int channel, int slotrank)
586 {
587 	const struct iosav_ssq sequence[] = {
588 		/* DRAM command ACT */
589 		[0] = {
590 			.sp_cmd_ctrl = {
591 				.command    = IOSAV_ACT,
592 				.ranksel_ap = 1,
593 			},
594 			.subseq_ctrl = {
595 				.cmd_executions = 4,
596 				.cmd_delay_gap = MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1),
597 				.post_ssq_wait  = ctrl->tRCD,
598 				.data_direction = SSQ_NA,
599 			},
600 			.sp_cmd_addr = {
601 				.address = 0,
602 				.rowbits = 6,
603 				.bank    = 0,
604 				.rank    = slotrank,
605 			},
606 			.addr_update = {
607 				.inc_bank  = 0,
608 				.addr_wrap = 18,
609 			},
610 		},
611 		/* DRAM command WR */
612 		[1] = {
613 			.sp_cmd_ctrl = {
614 				.command    = IOSAV_WR,
615 				.ranksel_ap = 1,
616 			},
617 			.subseq_ctrl = {
618 				.cmd_executions = 32,
619 				.cmd_delay_gap  = 20,
620 				.post_ssq_wait  = ctrl->CWL + ctrl->tWTR + 8,
621 				.data_direction = SSQ_WR,
622 			},
623 			.sp_cmd_addr = {
624 				.address = 0,
625 				.rowbits = 0,
626 				.bank    = 0,
627 				.rank    = slotrank,
628 			},
629 			.addr_update = {
630 				.inc_addr_8 = 1,
631 				.addr_wrap  = 18,
632 			},
633 		},
634 		/* DRAM command RD */
635 		[2] = {
636 			.sp_cmd_ctrl = {
637 				.command    = IOSAV_RD,
638 				.ranksel_ap = 1,
639 			},
640 			.subseq_ctrl = {
641 				.cmd_executions = 32,
642 				.cmd_delay_gap  = 20,
643 				.post_ssq_wait  = MAX(ctrl->tRTP, 8),
644 				.data_direction = SSQ_RD,
645 			},
646 			.sp_cmd_addr = {
647 				.address = 0,
648 				.rowbits = 0,
649 				.bank    = 0,
650 				.rank    = slotrank,
651 			},
652 			.addr_update = {
653 				.inc_addr_8 = 1,
654 				.addr_wrap  = 18,
655 			},
656 		},
657 		/* DRAM command PRE */
658 		[3] = {
659 			.sp_cmd_ctrl = {
660 				.command    = IOSAV_PRE,
661 				.ranksel_ap = 1,
662 			},
663 			.subseq_ctrl = {
664 				.cmd_executions = 1,
665 				.cmd_delay_gap  = 3,
666 				.post_ssq_wait  = ctrl->tRP,
667 				.data_direction = SSQ_NA,
668 			},
669 			.sp_cmd_addr = {
670 				.address = 1 << 10,
671 				.rowbits = 6,
672 				.bank    = 0,
673 				.rank    = slotrank,
674 			},
675 		},
676 	};
677 	iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
678 }
679 
iosav_write_aggressive_write_read_sequence(ramctr_timing * ctrl,int channel,int slotrank)680 void iosav_write_aggressive_write_read_sequence(ramctr_timing *ctrl, int channel, int slotrank)
681 {
682 	const struct iosav_ssq sequence[] = {
683 		/* DRAM command ACT */
684 		[0] = {
685 			.sp_cmd_ctrl = {
686 				.command    = IOSAV_ACT,
687 				.ranksel_ap = 1,
688 			},
689 			.subseq_ctrl = {
690 				.cmd_executions = 4,
691 				.cmd_delay_gap  = MAX((ctrl->tFAW >> 2) + 1, ctrl->tRRD),
692 				.post_ssq_wait  = ctrl->tRCD,
693 				.data_direction = SSQ_NA,
694 			},
695 			.sp_cmd_addr = {
696 				.address = 0,
697 				.rowbits = 6,
698 				.bank    = 0,
699 				.rank    = slotrank,
700 			},
701 			.addr_update = {
702 				.inc_bank  = 1,
703 				.addr_wrap = 18,
704 			},
705 		},
706 		/* DRAM command WR */
707 		[1] = {
708 			.sp_cmd_ctrl = {
709 				.command    = IOSAV_WR,
710 				.ranksel_ap = 1,
711 			},
712 			.subseq_ctrl = {
713 				.cmd_executions = 480,
714 				.cmd_delay_gap  = 4,
715 				.post_ssq_wait  = ctrl->tWTR + ctrl->CWL + 8,
716 				.data_direction = SSQ_WR,
717 			},
718 			.sp_cmd_addr = {
719 				.address = 0,
720 				.rowbits = 0,
721 				.bank    = 0,
722 				.rank    = slotrank,
723 			},
724 			.addr_update = {
725 				.inc_addr_8 = 1,
726 				.addr_wrap  = 18,
727 			},
728 		},
729 		/* DRAM command RD */
730 		[2] = {
731 			.sp_cmd_ctrl = {
732 				.command    = IOSAV_RD,
733 				.ranksel_ap = 1,
734 			},
735 			.subseq_ctrl = {
736 				.cmd_executions = 480,
737 				.cmd_delay_gap  = 4,
738 				.post_ssq_wait  = MAX(ctrl->tRTP, 8),
739 				.data_direction = SSQ_RD,
740 			},
741 			.sp_cmd_addr = {
742 				.address = 0,
743 				.rowbits = 0,
744 				.bank    = 0,
745 				.rank    = slotrank,
746 			},
747 			.addr_update = {
748 				.inc_addr_8 = 1,
749 				.addr_wrap  = 18,
750 			},
751 		},
752 		/* DRAM command PRE */
753 		[3] = {
754 			.sp_cmd_ctrl = {
755 				.command    = IOSAV_PRE,
756 				.ranksel_ap = 1,
757 			},
758 			.subseq_ctrl = {
759 				.cmd_executions = 1,
760 				.cmd_delay_gap  = 4,
761 				.post_ssq_wait  = ctrl->tRP,
762 				.data_direction = SSQ_NA,
763 			},
764 			.sp_cmd_addr = {
765 				.address = 1 << 10,
766 				.rowbits = 6,
767 				.bank    = 0,
768 				.rank    = slotrank,
769 			},
770 		},
771 	};
772 	iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
773 }
774 
iosav_write_memory_test_sequence(ramctr_timing * ctrl,int channel,int slotrank)775 void iosav_write_memory_test_sequence(ramctr_timing *ctrl, int channel, int slotrank)
776 {
777 	const struct iosav_ssq sequence[] = {
778 		/* DRAM command ACT */
779 		[0] = {
780 			.sp_cmd_ctrl = {
781 				.command    = IOSAV_ACT,
782 				.ranksel_ap = 1,
783 			},
784 			.subseq_ctrl = {
785 				.cmd_executions = 4,
786 				.cmd_delay_gap  = 8,
787 				.post_ssq_wait  = 40,
788 				.data_direction = SSQ_NA,
789 			},
790 			.sp_cmd_addr = {
791 				.address = 0,
792 				.rowbits = 6,
793 				.bank    = 0,
794 				.rank    = slotrank,
795 			},
796 			.addr_update = {
797 				.inc_bank  = 1,
798 				.addr_wrap = 18,
799 			},
800 		},
801 		/* DRAM command WR */
802 		[1] = {
803 			.sp_cmd_ctrl = {
804 				.command    = IOSAV_WR,
805 				.ranksel_ap = 1,
806 			},
807 			.subseq_ctrl = {
808 				.cmd_executions = 100,
809 				.cmd_delay_gap  = 4,
810 				.post_ssq_wait  = 40,
811 				.data_direction = SSQ_WR,
812 			},
813 			.sp_cmd_addr = {
814 				.address = 0,
815 				.rowbits = 0,
816 				.bank    = 0,
817 				.rank    = slotrank,
818 			},
819 			.addr_update = {
820 				.inc_addr_8 = 1,
821 				.addr_wrap  = 18,
822 			},
823 		},
824 		/* DRAM command RD */
825 		[2] = {
826 			.sp_cmd_ctrl = {
827 				.command    = IOSAV_RD,
828 				.ranksel_ap = 1,
829 			},
830 			.subseq_ctrl = {
831 				.cmd_executions = 100,
832 				.cmd_delay_gap  = 4,
833 				.post_ssq_wait  = 40,
834 				.data_direction = SSQ_RD,
835 			},
836 			.sp_cmd_addr = {
837 				.address = 0,
838 				.rowbits = 0,
839 				.bank    = 0,
840 				.rank    = slotrank,
841 			},
842 			.addr_update = {
843 				.inc_addr_8 = 1,
844 				.addr_wrap  = 18,
845 			},
846 		},
847 		/* DRAM command PRE */
848 		[3] = {
849 			.sp_cmd_ctrl = {
850 				.command    = IOSAV_PRE,
851 				.ranksel_ap = 1,
852 			},
853 			.subseq_ctrl = {
854 				.cmd_executions = 1,
855 				.cmd_delay_gap  = 3,
856 				.post_ssq_wait  = 40,
857 				.data_direction = SSQ_NA,
858 			},
859 			.sp_cmd_addr = {
860 				.address = 1 << 10,
861 				.rowbits = 6,
862 				.bank    = 0,
863 				.rank    = slotrank,
864 			},
865 			.addr_update = {
866 				.addr_wrap = 18,
867 			},
868 		},
869 	};
870 	iosav_write_sequence(channel, sequence, ARRAY_SIZE(sequence));
871 }
872