nb/intel/sandybridge: Use the new IOSAV struct API

Now that we have created the IOSAV API, we can put it to good use.
Drop all the helper macros and replace them with struct constructs.

Tested with BUILD_TIMELESS=1, ASUS P8Z77-V LX2 remains unchanged.

Change-Id: Ib366e364df11c9bb240cdfbce418540ec715c634
Signed-off-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/41003
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/northbridge/intel/sandybridge/mchbar_regs.h b/src/northbridge/intel/sandybridge/mchbar_regs.h
index 742c499..849a892 100644
--- a/src/northbridge/intel/sandybridge/mchbar_regs.h
+++ b/src/northbridge/intel/sandybridge/mchbar_regs.h
@@ -188,64 +188,6 @@
  *   [6]        Cleared with a new sequence, and set when done and refresh counter is drained.
  */
 
-/* Temporary IOSAV register macros to verifiably split bitfields */
-#define SUBSEQ_CTRL(reps, gap, post, dir)	(((reps) <<  0) | \
-						 ((gap)  << 10) | \
-						 ((post) << 16) | \
-						 ((dir)  << 26))
-
-#define SSQ_NA		0 /* Non-data */
-#define SSQ_RD		1 /* Read */
-#define SSQ_WR		2 /* Write */
-#define SSQ_RW		3 /* Read and write */
-
-#define SP_CMD_ADDR(addr, rowbits, bank, rank)	(((addr)    <<  0) | \
-						 ((rowbits) << 16) | \
-						 ((bank)    << 20) | \
-						 ((rank)    << 24))
-
-#define ADDR_UPDATE(addr_1, addr_8, bank, rank, wrap, lfsr, rate, xors)	(((addr_1) <<  0) | \
-									 ((addr_8) <<  1) | \
-									 ((bank)   <<  2) | \
-									 ((rank)   <<  3) | \
-									 ((wrap)   <<  5) | \
-									 ((lfsr)   << 10) | \
-									 ((rate)   << 12) | \
-									 ((xors)   << 16))
-
-#define IOSAV_SUBSEQUENCE(ch, n, cmd, ranksel, reps, gap, post, dir, addr, row_bits, bank_addr, rank_addr, addr_1, addr_8, upd_bank, upd_rank, wrap, lfsr, rate, xors) \
-	do {						\
-		const struct iosav_ssq ssq = {		\
-			.sp_cmd_ctrl = {		\
-				.command    = cmd,	\
-				.ranksel_ap = ranksel,	\
-			},				\
-			.subseq_ctrl = {		\
-				.cmd_executions = reps,	\
-				.cmd_delay_gap  = gap,	\
-				.post_ssq_wait  = post,	\
-				.data_direction = dir,	\
-			},				\
-			.sp_cmd_addr = {		\
-				.address = addr,	\
-				.rowbits = row_bits,	\
-				.bank    = bank_addr,	\
-				.rank    = rank_addr,	\
-			},				\
-			.addr_update = {		\
-				.inc_addr_1 = addr_1,	\
-				.inc_addr_8 = addr_8,	\
-				.inc_bank   = upd_bank,	\
-				.inc_rank   = upd_rank,	\
-				.addr_wrap  = wrap,	\
-				.lfsr_upd   = lfsr,	\
-				.upd_rate   = rate,	\
-				.lfsr_xors  = xors,	\
-			},				\
-		};					\
-		iosav_write_ssq(ch, &ssq);		\
-	} while (0)
-
 /* Indexed register helper macros */
 #define Gz(r, z)	((r) + ((z) <<  8))
 #define Ly(r, y)	((r) + ((y) <<  2))
diff --git a/src/northbridge/intel/sandybridge/raminit_common.c b/src/northbridge/intel/sandybridge/raminit_common.c
index b5d337d..371527e 100644
--- a/src/northbridge/intel/sandybridge/raminit_common.c
+++ b/src/northbridge/intel/sandybridge/raminit_common.c
@@ -594,11 +594,26 @@
 	slotrank = (ctrl->rankmap[channel] & 1) ? 0 : 2;
 
 	/* DRAM command ZQCS */
-	IOSAV_SUBSEQUENCE(channel, 0,
-		IOSAV_ZQCS, 0,
-		1, 3, 8, SSQ_NA,
-		0, 6, 0, slotrank,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command = IOSAV_ZQCS,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 3,
+				.post_ssq_wait  = 8,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/*
 	 * Execute command queue - why is bit 22 set here?!
@@ -687,25 +702,71 @@
 	}
 
 	/* DRAM command MRS */
-	IOSAV_SUBSEQUENCE(channel, 0,
-		IOSAV_MRS, 0,
-		1, 4, 4, SSQ_NA,
-		val, 6, reg, slotrank,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command = IOSAV_MRS,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = 4,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = val,
+				.rowbits = 6,
+				.bank    = reg,
+				.rank    = slotrank,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command MRS */
-	IOSAV_SUBSEQUENCE(channel, 1,
-		IOSAV_MRS, 1,
-		1, 4, 4, SSQ_NA,
-		val, 6, reg, slotrank,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_MRS,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = 4,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = val,
+				.rowbits = 6,
+				.bank    = reg,
+				.rank    = slotrank,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command MRS */
-	IOSAV_SUBSEQUENCE(channel, 2,
-		IOSAV_MRS, 0,
-		1, 4, ctrl->tMOD, SSQ_NA,
-		val, 6, reg, slotrank,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_MRS,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = ctrl->tMOD,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = val,
+				.rowbits = 6,
+				.bank    = reg,
+				.rank    = slotrank,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* Execute command queue */
 	iosav_run_once(channel);
@@ -831,18 +892,53 @@
 	}
 
 	/* DRAM command NOP (without ODT nor chip selects) */
-	IOSAV_SUBSEQUENCE(BROADCAST_CH, 0,
-		IOSAV_NOP & ~(0xff << 8), 0,
-		1, 4, 15, SSQ_NA,
-		2, 6, 0, 0,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_NOP & ~(0xff << 8),
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = 15,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 2,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = 0,
+			},
+		};
+		iosav_write_ssq(BROADCAST_CH, &ssq);
+	}
 
 	/* DRAM command ZQCL */
-	IOSAV_SUBSEQUENCE(BROADCAST_CH, 1,
-		IOSAV_ZQCS, 1,
-		1, 4, 400, SSQ_NA,
-		1024, 6, 0, 0,
-		0, 0, 0, 1, 20, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_ZQCS,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = 400,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 1024,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = 0,
+			},
+			.addr_update = {
+				.inc_rank   = 1,
+				.addr_wrap  = 20,
+			},
+		};
+		iosav_write_ssq(BROADCAST_CH, &ssq);
+	}
 
 	/* Execute command queue on all channels. Do it four times. */
 	iosav_run_queue(BROADCAST_CH, 4, 0);
@@ -866,11 +962,29 @@
 		wait_for_iosav(channel);
 
 		/* DRAM command ZQCS */
-		IOSAV_SUBSEQUENCE(channel, 0,
-			IOSAV_ZQCS, 0,
-			1, 4, 101, SSQ_NA,
-			0, 6, 0, slotrank,
-			0, 0, 0, 0, 31, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_ZQCS,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = 101,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.addr_wrap  = 31,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* Execute command queue */
 		iosav_run_once(channel);
@@ -1030,37 +1144,106 @@
 {
 	wait_for_iosav(channel);
 
-	/* DRAM command MRS
-	   write MR3 MPR enable
-	   in this mode only RD and RDA are allowed
-	   all reads return a predefined pattern */
-	IOSAV_SUBSEQUENCE(channel, 0,
-		IOSAV_MRS, 1,
-		1, 3, ctrl->tMOD, SSQ_NA,
-		4, 6, 3, slotrank,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	/*
+	 * DRAM command MRS
+	 *
+	 * Write MR3 MPR enable.
+	 * In this mode only RD and RDA are allowed, and all reads return a predefined pattern.
+	 */
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_MRS,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 3,
+				.post_ssq_wait  = ctrl->tMOD,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 4,
+				.rowbits = 6,
+				.bank    = 3,
+				.rank    = slotrank,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command RD */
-	IOSAV_SUBSEQUENCE(channel, 1,
-		IOSAV_RD, 1,
-		1, 3, 4, SSQ_RD,
-		0, 0, 0, slotrank,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_RD,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 3,
+				.post_ssq_wait  = 4,
+				.data_direction = SSQ_RD,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 0,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command RD */
-	IOSAV_SUBSEQUENCE(channel, 2,
-		IOSAV_RD, 1,
-		15, 4, ctrl->CAS + 36, SSQ_NA,
-		0, 6, 0, slotrank,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_RD,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 15,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = ctrl->CAS + 36,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
-	/* DRAM command MRS
-	   write MR3 MPR disable */
-	IOSAV_SUBSEQUENCE(channel, 3,
-		IOSAV_MRS, 1,
-		1, 3, ctrl->tMOD, SSQ_NA,
-		0, 6, 3, slotrank,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	/*
+	 * DRAM command MRS
+	 *
+	 * Write MR3 MPR disable.
+	 */
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_MRS,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 3,
+				.post_ssq_wait  = ctrl->tMOD,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 6,
+				.bank    = 3,
+				.rank    = slotrank,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* Execute command queue */
 	iosav_run_once(channel);
@@ -1322,11 +1505,27 @@
 		wait_for_iosav(channel);
 
 		/* DRAM command PREA */
-		IOSAV_SUBSEQUENCE(channel, 0,
-			IOSAV_PRE, 1,
-			1, 3, ctrl->tRP, SSQ_NA,
-			1024, 6, 0, slotrank,
-			0, 0, 0, 0, 0, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_PRE,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 3,
+					.post_ssq_wait  = ctrl->tRP,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 1024,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* Execute command queue */
 		iosav_run_once(channel);
@@ -1423,32 +1622,110 @@
 	wait_for_iosav(channel);
 
 	/* DRAM command ACT */
-	IOSAV_SUBSEQUENCE(channel, 0,
-		IOSAV_ACT, 1,
-		4, MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1), ctrl->tRCD, SSQ_NA,
-		0, 6, 0, slotrank,
-		0, 0, 1, 0, 18, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_ACT,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 4,
+				.cmd_delay_gap  = MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1),
+				.post_ssq_wait  = ctrl->tRCD,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.inc_bank  = 1,
+				.addr_wrap = 18,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command NOP */
-	IOSAV_SUBSEQUENCE(channel, 1,
-		IOSAV_NOP, 1,
-		1, 4, 4, SSQ_WR,
-		8, 0, 0, slotrank,
-		0, 0, 0, 0, 31, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_NOP,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = 4,
+				.data_direction = SSQ_WR,
+			},
+			.sp_cmd_addr = {
+				.address = 8,
+				.rowbits = 0,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.addr_wrap = 31,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command WR */
-	IOSAV_SUBSEQUENCE(channel, 2,
-		IOSAV_WR, 1,
-		500, 4, 4, SSQ_WR,
-		0, 0, 0, slotrank,
-		0, 1, 0, 0, 18, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_WR,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 500,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = 4,
+				.data_direction = SSQ_WR,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 0,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.inc_addr_8 = 1,
+				.addr_wrap  = 18,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command NOP */
-	IOSAV_SUBSEQUENCE(channel, 3,
-		IOSAV_NOP, 1,
-		1, 3, ctrl->CWL + ctrl->tWTR + 5, SSQ_WR,
-		8, 0, 0, slotrank,
-		0, 0, 0, 0, 31, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_NOP,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 3,
+				.post_ssq_wait  = ctrl->CWL + ctrl->tWTR + 5,
+				.data_direction = SSQ_WR,
+			},
+			.sp_cmd_addr = {
+				.address = 8,
+				.rowbits = 0,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.addr_wrap = 31,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* Execute command queue */
 	iosav_run_once(channel);
@@ -1456,32 +1733,110 @@
 	wait_for_iosav(channel);
 
 	/* DRAM command PREA */
-	IOSAV_SUBSEQUENCE(channel, 0,
-		IOSAV_PRE, 1,
-		1, 3, ctrl->tRP, SSQ_NA,
-		1024, 6, 0, slotrank,
-		0, 0, 0, 0, 18, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_PRE,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 3,
+				.post_ssq_wait  = ctrl->tRP,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 1024,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.addr_wrap = 18,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command ACT */
-	IOSAV_SUBSEQUENCE(channel, 1,
-		IOSAV_ACT, 1,
-		8, MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1), ctrl->CAS, SSQ_NA,
-		0, 6, 0, slotrank,
-		0, 0, 1, 0, 18, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_ACT,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 8,
+				.cmd_delay_gap  = MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1),
+				.post_ssq_wait  = ctrl->CAS,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.inc_bank  = 1,
+				.addr_wrap = 18,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command RD */
-	IOSAV_SUBSEQUENCE(channel, 2,
-		IOSAV_RD, 1,
-		500, 4, MAX(ctrl->tRTP, 8), SSQ_RD,
-		0, 0, 0, slotrank,
-		0, 1, 0, 0, 18, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_RD,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 500,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = MAX(ctrl->tRTP, 8),
+				.data_direction = SSQ_RD,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 0,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.inc_addr_8 = 1,
+				.addr_wrap  = 18,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command PREA */
-	IOSAV_SUBSEQUENCE(channel, 3,
-		IOSAV_PRE, 1,
-		1, 3, ctrl->tRP, SSQ_NA,
-		1024, 6, 0, slotrank,
-		0, 0, 0, 0, 18, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_PRE,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 3,
+				.post_ssq_wait  = ctrl->tRP,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 1024,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.addr_wrap  = 18,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* Execute command queue */
 	iosav_run_once(channel);
@@ -1517,11 +1872,30 @@
 	wait_for_iosav(channel);
 
 	/* DRAM command PREA */
-	IOSAV_SUBSEQUENCE(channel, 0,
-		IOSAV_PRE, 1,
-		1, 3, ctrl->tRP, SSQ_NA,
-		1024, 6, 0, slotrank,
-		0, 0, 0, 0, 18, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_PRE,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 3,
+				.post_ssq_wait  = ctrl->tRP,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 1024,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.addr_wrap  = 18,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* Execute command queue */
 	iosav_run_once(channel);
@@ -1620,37 +1994,107 @@
 		FOR_ALL_POPULATED_RANKS {
 			wait_for_iosav(channel);
 
-			/* DRAM command MRS
-			   write MR3 MPR enable
-			   in this mode only RD and RDA are allowed
-			   all reads return a predefined pattern */
-			IOSAV_SUBSEQUENCE(channel, 0,
-				IOSAV_MRS, 1,
-				1, 3, ctrl->tMOD, SSQ_NA,
-				4, 6, 3, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			/*
+			 * DRAM command MRS
+			 *
+			 * Write MR3 MPR enable.
+			 * In this mode only RD and RDA are allowed,
+			 * and all reads return a predefined pattern.
+			 */
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_MRS,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 3,
+						.post_ssq_wait  = ctrl->tMOD,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 4,
+						.rowbits = 6,
+						.bank    = 3,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* DRAM command RD */
-			IOSAV_SUBSEQUENCE(channel, 1,
-				IOSAV_RD, 1,
-				3, 4, 4, SSQ_RD,
-				0, 0, 0, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_RD,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 3,
+						.cmd_delay_gap  = 4,
+						.post_ssq_wait  = 4,
+						.data_direction = SSQ_RD,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 0,
+						.bank    = 0,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* DRAM command RD */
-			IOSAV_SUBSEQUENCE(channel, 2,
-				IOSAV_RD, 1,
-				1, 4, ctrl->CAS + 8, SSQ_NA,
-				0, 6, 0, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_RD,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 4,
+						.post_ssq_wait  = ctrl->CAS + 8,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 6,
+						.bank    = 0,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
-			/* DRAM command MRS
-			 * write MR3 MPR disable */
-			IOSAV_SUBSEQUENCE(channel, 3,
-				IOSAV_MRS, 1,
-				1, 3, ctrl->tMOD, SSQ_NA,
-				0, 6, 3, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			/*
+			 * DRAM command MRS
+			 *
+			 * Write MR3 MPR disable.
+			 */
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_MRS,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 3,
+						.post_ssq_wait  = ctrl->tMOD,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 6,
+						.bank    = 3,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* Execute command queue */
 			iosav_run_once(channel);
@@ -1667,37 +2111,108 @@
 
 		FOR_ALL_POPULATED_RANKS {
 			wait_for_iosav(channel);
-			/* DRAM command MRS
-			 * write MR3 MPR enable
-			 * in this mode only RD and RDA are allowed
-			 * all reads return a predefined pattern */
-			IOSAV_SUBSEQUENCE(channel, 0,
-				IOSAV_MRS, 1,
-				1, 3, ctrl->tMOD, SSQ_NA,
-				4, 6, 3, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+
+			/*
+			 * DRAM command MRS
+			 *
+			 * Write MR3 MPR enable.
+			 * In this mode only RD and RDA are allowed,
+			 * and all reads return a predefined pattern.
+			 */
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_MRS,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 3,
+						.post_ssq_wait  = ctrl->tMOD,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 4,
+						.rowbits = 6,
+						.bank    = 3,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* DRAM command RD */
-			IOSAV_SUBSEQUENCE(channel, 1,
-				IOSAV_RD, 1,
-				3, 4, 4, SSQ_RD,
-				0, 0, 0, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_RD,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 3,
+						.cmd_delay_gap  = 4,
+						.post_ssq_wait  = 4,
+						.data_direction = SSQ_RD,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 0,
+						.bank    = 0,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* DRAM command RD */
-			IOSAV_SUBSEQUENCE(channel, 2,
-				IOSAV_RD, 1,
-				1, 4, ctrl->CAS + 8, SSQ_NA,
-				0, 6, 0, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_RD,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 4,
+						.post_ssq_wait  = ctrl->CAS + 8,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 6,
+						.bank    = 0,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
-			/* DRAM command MRS
-			 * write MR3 MPR disable */
-			IOSAV_SUBSEQUENCE(channel, 3,
-				IOSAV_MRS, 1,
-				1, 3, ctrl->tMOD, SSQ_NA,
-				0, 6, 3, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			/*
+			 * DRAM command MRS
+			 *
+			 * Write MR3 MPR disable.
+			 */
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_MRS,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 3,
+						.post_ssq_wait  = ctrl->tMOD,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 6,
+						.bank    = 3,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* Execute command queue */
 			iosav_run_once(channel);
@@ -1714,18 +2229,50 @@
 
 	wait_for_iosav(channel);
 	/* DRAM command NOP */
-	IOSAV_SUBSEQUENCE(channel, 0,
-		IOSAV_NOP, 1,
-		1, 3, ctrl->CWL + ctrl->tWLO, SSQ_WR,
-		8, 0, 0, slotrank,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_NOP,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 3,
+				.post_ssq_wait  = ctrl->CWL + ctrl->tWLO,
+				.data_direction = SSQ_WR,
+			},
+			.sp_cmd_addr = {
+				.address = 8,
+				.rowbits = 0,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command NOP */
-	IOSAV_SUBSEQUENCE(channel, 1,
-		IOSAV_NOP_ALT, 1,
-		1, 3, ctrl->CAS + 38, SSQ_RD,
-		4, 0, 0, slotrank,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_NOP_ALT,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 3,
+				.post_ssq_wait  = ctrl->CAS + 38,
+				.data_direction = SSQ_RD,
+			},
+			.sp_cmd_addr = {
+				.address = 4,
+				.rowbits = 0,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* Execute command queue */
 	iosav_run_once(channel);
@@ -1824,32 +2371,106 @@
 		wait_for_iosav(channel);
 
 		/* DRAM command ACT */
-		IOSAV_SUBSEQUENCE(channel, 0,
-			IOSAV_ACT, 1,
-			1, 3, ctrl->tRCD, SSQ_NA,
-			0, 6, 0, slotrank,
-			0, 0, 0, 0, 0, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_ACT,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 3,
+					.post_ssq_wait  = ctrl->tRCD,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* DRAM command NOP */
-		IOSAV_SUBSEQUENCE(channel, 1,
-			IOSAV_NOP, 1,
-			1, 3, 4, SSQ_WR,
-			8, 0, 0, slotrank,
-			0, 0, 0, 0, 31, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_NOP,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 3,
+					.post_ssq_wait  = 4,
+					.data_direction = SSQ_WR,
+				},
+				.sp_cmd_addr = {
+					.address = 8,
+					.rowbits = 0,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.addr_wrap = 31,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* DRAM command WR */
-		IOSAV_SUBSEQUENCE(channel, 2,
-			IOSAV_WR, 1,
-			3, 4, 4, SSQ_WR,
-			0, 0, 0, slotrank,
-			0, 1, 0, 0, 31, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_WR,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 3,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = 4,
+					.data_direction = SSQ_WR,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 0,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.inc_addr_8 = 1,
+					.addr_wrap  = 31,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* DRAM command NOP */
-		IOSAV_SUBSEQUENCE(channel, 3,
-			IOSAV_NOP, 1,
-			1, 3, ctrl->CWL + ctrl->tWTR + 5, SSQ_WR,
-			8, 0, 0, slotrank,
-			0, 0, 0, 0, 31, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_NOP,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 3,
+					.post_ssq_wait  = ctrl->CWL + ctrl->tWTR + 5,
+					.data_direction = SSQ_WR,
+				},
+				.sp_cmd_addr = {
+					.address = 8,
+					.rowbits = 0,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.addr_wrap = 31,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* Execute command queue */
 		iosav_run_once(channel);
@@ -1857,27 +2478,78 @@
 		wait_for_iosav(channel);
 
 		/* DRAM command PREA */
-		IOSAV_SUBSEQUENCE(channel, 0,
-			IOSAV_PRE, 1,
-			1, 3, ctrl->tRP, SSQ_NA,
-			1024, 6, 0, slotrank,
-			0, 0, 0, 0, 18, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_PRE,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 3,
+					.post_ssq_wait  = ctrl->tRP,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 1024,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.addr_wrap = 18,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* DRAM command ACT */
-		IOSAV_SUBSEQUENCE(channel, 1,
-			IOSAV_ACT, 1,
-			1, 3, ctrl->tRCD, SSQ_NA,
-			0, 6, 0, slotrank,
-			0, 0, 0, 0, 0, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_ACT,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 3,
+					.post_ssq_wait  = ctrl->tRCD,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* DRAM command RD */
-		IOSAV_SUBSEQUENCE(channel, 2,
-			IOSAV_RD, 3,
-			1, 3, ctrl->tRP +
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_RD,
+					.ranksel_ap = 3,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 3,
+					.post_ssq_wait  = ctrl->tRP +
 				ctrl->timings[channel][slotrank].roundtrip_latency +
-				ctrl->timings[channel][slotrank].io_latency, SSQ_RD,
-			8, 6, 0, slotrank,
-			0, 0, 0, 0, 0, 0, 0, 0);
+				ctrl->timings[channel][slotrank].io_latency,
+					.data_direction = SSQ_RD,
+				},
+				.sp_cmd_addr = {
+					.address = 8,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* Execute command queue */
 		iosav_run_once(channel);
@@ -1909,11 +2581,29 @@
 	slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
 
 	/* DRAM command ZQCS */
-	IOSAV_SUBSEQUENCE(channel, 0,
-		IOSAV_ZQCS, 0,
-		1, 4, 4, SSQ_NA,
-		0, 6, 0, slotrank,
-		0, 0, 0, 0, 31, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command = IOSAV_ZQCS,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = 4,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.addr_wrap = 31,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* Execute command queue */
 	iosav_run_once(channel);
@@ -1988,11 +2678,29 @@
 		wait_for_iosav(channel);
 
 		/* DRAM command ZQCS */
-		IOSAV_SUBSEQUENCE(channel, 0,
-			IOSAV_ZQCS, 0,
-			1, 4, 101, SSQ_NA,
-			0, 6, 0, 0,
-			0, 0, 0, 0, 31, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command = IOSAV_ZQCS,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = 101,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = 0,
+				},
+				.addr_update = {
+					.addr_wrap = 31,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* Execute command queue */
 		iosav_run_once(channel);
@@ -2058,36 +2766,120 @@
 
 		wait_for_iosav(channel);
 		/* DRAM command ACT */
-		IOSAV_SUBSEQUENCE(channel, 0,
-			IOSAV_ACT, 1,
-			8, MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1), ctrl->tRCD, SSQ_NA,
-			ctr, 6, 0, slotrank,
-			0, 0, 1, 0, 18, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_ACT,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 8,
+					.cmd_delay_gap = MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1),
+					.post_ssq_wait  = ctrl->tRCD,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = ctr,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.inc_bank  = 1,
+					.addr_wrap = 18,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* DRAM command WR */
-		IOSAV_SUBSEQUENCE(channel, 1,
-			IOSAV_WR, 1,
-			32, 4, ctrl->CWL + ctrl->tWTR + 8, SSQ_WR,
-			0, 0, 0, slotrank,
-			0, 1, 0, 0, 18, 3, 0, 2);
-
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_WR,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 32,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = ctrl->CWL + ctrl->tWTR + 8,
+					.data_direction = SSQ_WR,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 0,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.inc_addr_8 = 1,
+					.addr_wrap  = 18,
+					.lfsr_upd   = 3,
+					.lfsr_xors  = 2,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
+		/* FIXME: Hardcoded subsequence index */
 		MCHBAR32(IOSAV_n_ADDRESS_LFSR_ch(channel, 1)) = 0x389abcd;
 
 		/* DRAM command RD */
-		IOSAV_SUBSEQUENCE(channel, 2,
-			IOSAV_RD, 1,
-			32, 4, MAX(ctrl->tRTP, 8), SSQ_RD,
-			0, 0, 0, slotrank,
-			0, 1, 0, 0, 18, 3, 0, 2);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_RD,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 32,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = MAX(ctrl->tRTP, 8),
+					.data_direction = SSQ_RD,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 0,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.inc_addr_8 = 1,
+					.addr_wrap  = 18,
+					.lfsr_upd   = 3,
+					.lfsr_xors  = 2,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
+		/* FIXME: Hardcoded subsequence index */
 		MCHBAR32(IOSAV_n_ADDRESS_LFSR_ch(channel, 2)) = 0x389abcd;
 
 		/* DRAM command PRE */
-		IOSAV_SUBSEQUENCE(channel, 3,
-			IOSAV_PRE, 1,
-			1, 4, 15, SSQ_NA,
-			1024, 6, 0, slotrank,
-			0, 0, 0, 0, 18, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_PRE,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = 15,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 1024,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.addr_wrap  = 18,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* Execute command queue */
 		iosav_run_once(channel);
@@ -2150,11 +2942,29 @@
 		slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
 
 		/* DRAM command ZQCS */
-		IOSAV_SUBSEQUENCE(channel, 0,
-			IOSAV_ZQCS, 0,
-			1, 4, 4, SSQ_NA,
-			0, 6, 0, slotrank,
-			0, 0, 0, 0, 31, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command = IOSAV_ZQCS,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = 4,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.addr_wrap  = 31,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* Execute command queue */
 		iosav_run_once(channel);
@@ -2172,11 +2982,29 @@
 		slotrank = !(ctrl->rankmap[channel] & 1) ? 2 : 0;
 
 		/* DRAM command ZQCS */
-		IOSAV_SUBSEQUENCE(channel, 0,
-			IOSAV_ZQCS, 0,
-			1, 4, 4, SSQ_NA,
-			0, 6, 0, slotrank,
-			0, 0, 0, 0, 31, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command = IOSAV_ZQCS,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = 4,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.addr_wrap  = 31,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* Execute command queue */
 		iosav_run_once(channel);
@@ -2333,37 +3161,107 @@
 
 		wait_for_iosav(channel);
 
-		/* DRAM command MRS
-		   write MR3 MPR enable
-		   in this mode only RD and RDA are allowed
-		   all reads return a predefined pattern */
-		IOSAV_SUBSEQUENCE(channel, 0,
-			IOSAV_MRS, 1,
-			1, 3, ctrl->tMOD, SSQ_NA,
-			4, 6, 3, slotrank,
-			0, 0, 0, 0, 0, 0, 0, 0);
+		/*
+		 * DRAM command MRS
+		 *
+		 * Write MR3 MPR enable.
+		 * In this mode only RD and RDA are allowed,
+		 * and all reads return a predefined pattern.
+		 */
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_MRS,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 3,
+					.post_ssq_wait  = ctrl->tMOD,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 4,
+					.rowbits = 6,
+					.bank    = 3,
+					.rank    = slotrank,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* DRAM command RD */
-		IOSAV_SUBSEQUENCE(channel, 1,
-			IOSAV_RD, 1,
-			500, 4, 4, SSQ_RD,
-			0, 0, 0, slotrank,
-			0, 0, 0, 0, 0, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_RD,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 500,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = 4,
+					.data_direction = SSQ_RD,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 0,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* DRAM command RD */
-		IOSAV_SUBSEQUENCE(channel, 2,
-			IOSAV_RD, 1,
-			1, 4, ctrl->CAS + 8, SSQ_NA,
-			0, 6, 0, slotrank,
-			0, 0, 0, 0, 0, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_RD,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = ctrl->CAS + 8,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
-		/* DRAM command MRS
-		   MR3 disable MPR */
-		IOSAV_SUBSEQUENCE(channel, 3,
-			IOSAV_MRS, 1,
-			1, 3, ctrl->tMOD, SSQ_NA,
-			0, 6, 3, slotrank,
-			0, 0, 0, 0, 0, 0, 0, 0);
+		/*
+		 * DRAM command MRS
+		 *
+		 * Write MR3 MPR disable.
+		 */
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_MRS,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 3,
+					.post_ssq_wait  = ctrl->tMOD,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 6,
+					.bank    = 3,
+					.rank    = slotrank,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* Execute command queue */
 		iosav_run_once(channel);
@@ -2421,38 +3319,107 @@
 		FOR_ALL_POPULATED_RANKS {
 			wait_for_iosav(channel);
 
-			/* DRAM command MRS
-			   MR3 enable MPR
-			   write MR3 MPR enable
-			   in this mode only RD and RDA are allowed
-			   all reads return a predefined pattern */
-			IOSAV_SUBSEQUENCE(channel, 0,
-				IOSAV_MRS, 1,
-				1, 3, ctrl->tMOD, SSQ_NA,
-				4, 6, 3, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			/*
+			 * DRAM command MRS
+			 *
+			 * Write MR3 MPR enable.
+			 * In this mode only RD and RDA are allowed,
+			 * and all reads return a predefined pattern.
+			 */
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_MRS,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 3,
+						.post_ssq_wait  = ctrl->tMOD,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 4,
+						.rowbits = 6,
+						.bank    = 3,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* DRAM command RD */
-			IOSAV_SUBSEQUENCE(channel, 1,
-				IOSAV_RD, 1,
-				3, 4, 4, SSQ_RD,
-				0, 0, 0, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_RD,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 3,
+						.cmd_delay_gap  = 4,
+						.post_ssq_wait  = 4,
+						.data_direction = SSQ_RD,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 0,
+						.bank    = 0,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* DRAM command RD */
-			IOSAV_SUBSEQUENCE(channel, 2,
-				IOSAV_RD, 1,
-				1, 4, ctrl->CAS + 8, SSQ_NA,
-				0, 6, 0, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_RD,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 4,
+						.post_ssq_wait  = ctrl->CAS + 8,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 6,
+						.bank    = 0,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
-			/* DRAM command MRS
-			 * MR3 disable MPR */
-			IOSAV_SUBSEQUENCE(channel, 3,
-				IOSAV_MRS, 1,
-				1, 3, ctrl->tMOD, SSQ_NA,
-				0, 6, 3, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			/*
+			 * DRAM command MRS
+			 *
+			 * Write MR3 MPR disable.
+			 */
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_MRS,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 3,
+						.post_ssq_wait  = ctrl->tMOD,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 6,
+						.bank    = 3,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* Execute command queue */
 			iosav_run_once(channel);
@@ -2472,38 +3439,107 @@
 		FOR_ALL_POPULATED_RANKS {
 			wait_for_iosav(channel);
 
-			/* DRAM command MRS
-			   MR3 enable MPR
-			   write MR3 MPR enable
-			   in this mode only RD and RDA are allowed
-			   all reads return a predefined pattern */
-			IOSAV_SUBSEQUENCE(channel, 0,
-				IOSAV_MRS, 1,
-				1, 3, ctrl->tMOD, SSQ_NA,
-				4, 6, 3, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			/*
+			 * DRAM command MRS
+			 *
+			 * Write MR3 MPR enable.
+			 * In this mode only RD and RDA are allowed,
+			 * and all reads return a predefined pattern.
+			 */
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_MRS,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 3,
+						.post_ssq_wait  = ctrl->tMOD,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 4,
+						.rowbits = 6,
+						.bank    = 3,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* DRAM command RD */
-			IOSAV_SUBSEQUENCE(channel, 1,
-				IOSAV_RD, 1,
-				3, 4, 4, SSQ_RD,
-				0, 0, 0, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_RD,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 3,
+						.cmd_delay_gap  = 4,
+						.post_ssq_wait  = 4,
+						.data_direction = SSQ_RD,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 0,
+						.bank    = 0,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* DRAM command RD */
-			IOSAV_SUBSEQUENCE(channel, 2,
-				IOSAV_RD, 1,
-				1, 4, ctrl->CAS + 8, SSQ_NA,
-				0, 6, 0, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_RD,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 4,
+						.post_ssq_wait  = ctrl->CAS + 8,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 6,
+						.bank    = 0,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
-			/* DRAM command MRS
-			 * MR3 disable MPR */
-			IOSAV_SUBSEQUENCE(channel, 3,
-				IOSAV_MRS, 1,
-				1, 3, ctrl->tMOD, SSQ_NA,
-				0, 6, 3, slotrank,
-				0, 0, 0, 0, 0, 0, 0, 0);
+			/*
+			 * DRAM command MRS
+			 *
+			 * Write MR3 MPR disable.
+			 */
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_MRS,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 3,
+						.post_ssq_wait  = ctrl->tMOD,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 0,
+						.rowbits = 6,
+						.bank    = 3,
+						.rank    = slotrank,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* Execute command queue */
 			iosav_run_once(channel);
@@ -2606,32 +3642,109 @@
 				wait_for_iosav(channel);
 
 				/* DRAM command ACT */
-				IOSAV_SUBSEQUENCE(channel, 0,
-					IOSAV_ACT, 1,
-					4, MAX(ctrl->tRRD, (ctrl->tFAW >> 2) + 1), ctrl->tRCD, SSQ_NA,
-					0, 6, 0, slotrank,
-					0, 0, 0, 0, 18, 0, 0, 0);
+				{
+					const struct iosav_ssq ssq = {
+						.sp_cmd_ctrl = {
+							.command    = IOSAV_ACT,
+							.ranksel_ap = 1,
+						},
+						.subseq_ctrl = {
+							.cmd_executions = 4,
+							.cmd_delay_gap  = MAX(ctrl->tRRD,
+									(ctrl->tFAW >> 2) + 1),
+							.post_ssq_wait  = ctrl->tRCD,
+							.data_direction = SSQ_NA,
+						},
+						.sp_cmd_addr = {
+							.address = 0,
+							.rowbits = 6,
+							.bank    = 0,
+							.rank    = slotrank,
+						},
+						.addr_update = {
+							.addr_wrap = 18,
+						},
+					};
+					iosav_write_ssq(channel, &ssq);
+				}
 
 				/* DRAM command WR */
-				IOSAV_SUBSEQUENCE(channel, 1,
-					IOSAV_WR, 1,
-					32, 20, ctrl->tWTR + ctrl->CWL + 8, SSQ_WR,
-					0, 0, 0, slotrank,
-					0, 1, 0, 0, 18, 0, 0, 0);
+				{
+					const struct iosav_ssq ssq = {
+						.sp_cmd_ctrl = {
+							.command    = IOSAV_WR,
+							.ranksel_ap = 1,
+						},
+						.subseq_ctrl = {
+							.cmd_executions = 32,
+							.cmd_delay_gap  = 20,
+							.post_ssq_wait  = ctrl->tWTR +
+										ctrl->CWL + 8,
+							.data_direction = SSQ_WR,
+						},
+						.sp_cmd_addr = {
+							.address = 0,
+							.rowbits = 0,
+							.bank    = 0,
+							.rank    = slotrank,
+						},
+						.addr_update = {
+							.inc_addr_8 = 1,
+							.addr_wrap  = 18,
+						},
+					};
+					iosav_write_ssq(channel, &ssq);
+				}
 
 				/* DRAM command RD */
-				IOSAV_SUBSEQUENCE(channel, 2,
-					IOSAV_RD, 1,
-					32, 20, MAX(ctrl->tRTP, 8), SSQ_RD,
-					0, 0, 0, slotrank,
-					0, 1, 0, 0, 18, 0, 0, 0);
+				{
+					const struct iosav_ssq ssq = {
+						.sp_cmd_ctrl = {
+							.command    = IOSAV_RD,
+							.ranksel_ap = 1,
+						},
+						.subseq_ctrl = {
+							.cmd_executions = 32,
+							.cmd_delay_gap  = 20,
+							.post_ssq_wait  = MAX(ctrl->tRTP, 8),
+							.data_direction = SSQ_RD,
+						},
+						.sp_cmd_addr = {
+							.address = 0,
+							.rowbits = 0,
+							.bank    = 0,
+							.rank    = slotrank,
+						},
+						.addr_update = {
+							.inc_addr_8 = 1,
+							.addr_wrap  = 18,
+						},
+					};
+					iosav_write_ssq(channel, &ssq);
+				}
 
 				/* DRAM command PRE */
-				IOSAV_SUBSEQUENCE(channel, 3,
-					IOSAV_PRE, 1,
-					1, 3, ctrl->tRP, SSQ_NA,
-					1024, 6, 0, slotrank,
-					0, 0, 0, 0, 0, 0, 0, 0);
+				{
+					const struct iosav_ssq ssq = {
+						.sp_cmd_ctrl = {
+							.command    = IOSAV_PRE,
+							.ranksel_ap = 1,
+						},
+						.subseq_ctrl = {
+							.cmd_executions = 1,
+							.cmd_delay_gap  = 3,
+							.post_ssq_wait  = ctrl->tRP,
+							.data_direction = SSQ_NA,
+						},
+						.sp_cmd_addr = {
+							.address = 1024,
+							.rowbits = 6,
+							.bank    = 0,
+							.rank    = slotrank,
+						},
+					};
+					iosav_write_ssq(channel, &ssq);
+				}
 
 				/* Execute command queue */
 				iosav_run_once(channel);
@@ -2730,32 +3843,108 @@
 	wait_for_iosav(channel);
 
 	/* DRAM command ACT */
-	IOSAV_SUBSEQUENCE(channel, 0,
-		IOSAV_ACT, 1,
-		4, MAX((ctrl->tFAW >> 2) + 1, ctrl->tRRD), ctrl->tRCD, SSQ_NA,
-		0, 6, 0, slotrank,
-		0, 0, 1, 0, 18, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_ACT,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 4,
+				.cmd_delay_gap  = MAX((ctrl->tFAW >> 2) + 1, ctrl->tRRD),
+				.post_ssq_wait  = ctrl->tRCD,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.inc_bank  = 1,
+				.addr_wrap = 18,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command WR */
-	IOSAV_SUBSEQUENCE(channel, 1,
-		IOSAV_WR, 1,
-		480, 4, ctrl->tWTR + ctrl->CWL + 8, SSQ_WR,
-		0, 0, 0, slotrank,
-		0, 1, 0, 0, 18, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_WR,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 480,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = ctrl->tWTR + ctrl->CWL + 8,
+				.data_direction = SSQ_WR,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 0,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.inc_addr_8 = 1,
+				.addr_wrap  = 18,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command RD */
-	IOSAV_SUBSEQUENCE(channel, 2,
-		IOSAV_RD, 1,
-		480, 4, MAX(ctrl->tRTP, 8), SSQ_RD,
-		0, 0, 0, slotrank,
-		0, 1, 0, 0, 18, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_RD,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 480,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = MAX(ctrl->tRTP, 8),
+				.data_direction = SSQ_RD,
+			},
+			.sp_cmd_addr = {
+				.address = 0,
+				.rowbits = 0,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+			.addr_update = {
+				.inc_addr_8 = 1,
+				.addr_wrap  = 18,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* DRAM command PRE */
-	IOSAV_SUBSEQUENCE(channel, 3,
-		IOSAV_PRE, 1,
-		1, 4, ctrl->tRP, SSQ_NA,
-		1024, 6, 0, slotrank,
-		0, 0, 0, 0, 0, 0, 0, 0);
+	{
+		const struct iosav_ssq ssq = {
+			.sp_cmd_ctrl = {
+				.command    = IOSAV_PRE,
+				.ranksel_ap = 1,
+			},
+			.subseq_ctrl = {
+				.cmd_executions = 1,
+				.cmd_delay_gap  = 4,
+				.post_ssq_wait  = ctrl->tRP,
+				.data_direction = SSQ_NA,
+			},
+			.sp_cmd_addr = {
+				.address = 1024,
+				.rowbits = 6,
+				.bank    = 0,
+				.rank    = slotrank,
+			},
+		};
+		iosav_write_ssq(channel, &ssq);
+	}
 
 	/* Execute command queue */
 	iosav_run_once(channel);
@@ -2947,32 +4136,111 @@
 		wait_for_iosav(channel);
 
 		/* DRAM command ACT */
-		IOSAV_SUBSEQUENCE(channel, 0,
-			IOSAV_ACT, 1,
-			4, 8, 40, SSQ_NA,
-			0, 6, 0, slotrank,
-			0, 0, 1, 0, 18, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_ACT,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 4,
+					.cmd_delay_gap  = 8,
+					.post_ssq_wait  = 40,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.inc_bank  = 1,
+					.addr_wrap = 18,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* DRAM command WR */
-		IOSAV_SUBSEQUENCE(channel, 1,
-			IOSAV_WR, 1,
-			100, 4, 40, SSQ_WR,
-			0, 0, 0, slotrank,
-			0, 1, 0, 0, 18, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_WR,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 100,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = 40,
+					.data_direction = SSQ_WR,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 0,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.inc_addr_8 = 1,
+					.addr_wrap  = 18,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* DRAM command RD */
-		IOSAV_SUBSEQUENCE(channel, 2,
-			IOSAV_RD, 1,
-			100, 4, 40, SSQ_RD,
-			0, 0, 0, slotrank,
-			0, 1, 0, 0, 18, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_RD,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 100,
+					.cmd_delay_gap  = 4,
+					.post_ssq_wait  = 40,
+					.data_direction = SSQ_RD,
+				},
+				.sp_cmd_addr = {
+					.address = 0,
+					.rowbits = 0,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.inc_addr_8 = 1,
+					.addr_wrap  = 18,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* DRAM command PRE */
-		IOSAV_SUBSEQUENCE(channel, 3,
-			IOSAV_PRE, 1,
-			1, 3, 40, SSQ_NA,
-			1024, 6, 0, slotrank,
-			0, 0, 0, 0, 18, 0, 0, 0);
+		{
+			const struct iosav_ssq ssq = {
+				.sp_cmd_ctrl = {
+					.command    = IOSAV_PRE,
+					.ranksel_ap = 1,
+				},
+				.subseq_ctrl = {
+					.cmd_executions = 1,
+					.cmd_delay_gap  = 3,
+					.post_ssq_wait  = 40,
+					.data_direction = SSQ_NA,
+				},
+				.sp_cmd_addr = {
+					.address = 1024,
+					.rowbits = 6,
+					.bank    = 0,
+					.rank    = slotrank,
+				},
+				.addr_update = {
+					.addr_wrap  = 18,
+				},
+			};
+			iosav_write_ssq(channel, &ssq);
+		}
 
 		/* Execute command queue */
 		iosav_run_once(channel);
@@ -2999,25 +4267,85 @@
 			wait_for_iosav(channel);
 
 			/* DRAM command ACT */
-			IOSAV_SUBSEQUENCE(channel, 0,
-				IOSAV_ACT, 1,
-				1, MAX((ctrl->tFAW >> 2) + 1, ctrl->tRRD), ctrl->tRCD, SSQ_NA,
-				row, 6, 0, slotrank,
-				1, 0, 0, 0, 18, 0, 0, 0);
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_ACT,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = MAX((ctrl->tFAW >> 2) + 1,
+									ctrl->tRRD),
+						.post_ssq_wait  = ctrl->tRCD,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = row,
+						.rowbits = 6,
+						.bank    = 0,
+						.rank    = slotrank,
+					},
+					.addr_update = {
+						.inc_addr_1 = 1,
+						.addr_wrap  = 18,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* DRAM command WR */
-			IOSAV_SUBSEQUENCE(channel, 1,
-				IOSAV_WR, 1,
-				129, 4, 40, SSQ_WR,
-				row, 0, 0, slotrank,
-				0, 1, 0, 0, 18, 0, 0, 0);
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_WR,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 129,
+						.cmd_delay_gap  = 4,
+						.post_ssq_wait  = 40,
+						.data_direction = SSQ_WR,
+					},
+					.sp_cmd_addr = {
+						.address = row,
+						.rowbits = 0,
+						.bank    = 0,
+						.rank    = slotrank,
+					},
+					.addr_update = {
+						.inc_addr_8 = 1,
+						.addr_wrap  = 18,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* DRAM command PRE */
-			IOSAV_SUBSEQUENCE(channel, 2,
-				IOSAV_PRE, 1,
-				1, 3, 40, SSQ_NA,
-				1024, 6, 0, slotrank,
-				0, 0, 0, 0, 18, 0, 0, 0);
+			{
+				const struct iosav_ssq ssq = {
+					.sp_cmd_ctrl = {
+						.command    = IOSAV_PRE,
+						.ranksel_ap = 1,
+					},
+					.subseq_ctrl = {
+						.cmd_executions = 1,
+						.cmd_delay_gap  = 3,
+						.post_ssq_wait  = 40,
+						.data_direction = SSQ_NA,
+					},
+					.sp_cmd_addr = {
+						.address = 1024,
+						.rowbits = 6,
+						.bank    = 0,
+						.rank    = slotrank,
+					},
+					.addr_update = {
+						.addr_wrap  = 18,
+					},
+				};
+				iosav_write_ssq(channel, &ssq);
+			}
 
 			/* execute command queue */
 			iosav_run_once(channel);
diff --git a/src/northbridge/intel/sandybridge/raminit_common.h b/src/northbridge/intel/sandybridge/raminit_common.h
index 6e76cbc0..3f31950 100644
--- a/src/northbridge/intel/sandybridge/raminit_common.h
+++ b/src/northbridge/intel/sandybridge/raminit_common.h
@@ -25,6 +25,7 @@
 #define NUM_SLOTS	2
 #define NUM_LANES	9
 
+/* IOSAV_n_SP_CMD_CTRL DRAM commands */
 #define IOSAV_MRS		(0xf000)
 #define IOSAV_PRE		(0xf002)
 #define IOSAV_ZQCS		(0xf003)
@@ -34,6 +35,12 @@
 #define IOSAV_WR		(0xf201)
 #define IOSAV_NOP		(0xf207)
 
+/* IOSAV_n_SUBSEQ_CTRL data direction */
+#define SSQ_NA			0 /* Non-data */
+#define SSQ_RD			1 /* Read */
+#define SSQ_WR			2 /* Write */
+#define SSQ_RW			3 /* Read and write */
+
 struct iosav_ssq {
 	/* IOSAV_n_SP_CMD_CTRL */
 	union {