nb/intel/sandybridge: Redefine IOSAV_SUBSEQUENCE

Instead of directly writing values to the IOSAV registers, use a struct
and some helper functions to provide a cleaner interface for the IOSAV.
Having IOSAV_SUBSEQUENCE refer to a static function is weird, but we
will remove this macro in a follow-up that does not change the binary.

Tested on Asus P8Z77-V LX2, still boots.

Change-Id: I73f13c18a739c5586a7415966f9017c2335fdfd1
Signed-off-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/40980
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/src/northbridge/intel/sandybridge/mchbar_regs.h b/src/northbridge/intel/sandybridge/mchbar_regs.h
index 446861b..0edfd53 100644
--- a/src/northbridge/intel/sandybridge/mchbar_regs.h
+++ b/src/northbridge/intel/sandybridge/mchbar_regs.h
@@ -213,12 +213,37 @@
 									 ((rate)   << 12) | \
 									 ((xors)   << 16))
 
-#define IOSAV_SUBSEQUENCE(ch, n, cmd, ranksel, reps, gap, post, dir, addr, rowbits, bank, rank, addr_1, addr_8, upd_bank, upd_rank, wrap, lfsr, rate, xors) \
-	do { \
-		MCHBAR32(IOSAV_n_SP_CMD_CTRL_ch(ch, n)) = (cmd) | ((ranksel) << 16); \
-		MCHBAR32(IOSAV_n_SUBSEQ_CTRL_ch(ch, n)) = SUBSEQ_CTRL(reps, gap, post, dir); \
-		MCHBAR32(IOSAV_n_SP_CMD_ADDR_ch(ch, n)) = SP_CMD_ADDR(addr, rowbits, bank, rank); \
-		MCHBAR32(IOSAV_n_ADDR_UPDATE_ch(ch, n)) = ADDR_UPDATE(addr_1, addr_8, upd_bank, upd_rank, wrap, lfsr, rate, xors); \
+#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, n, &ssq);		\
 	} while (0)
 
 /* Indexed register helper macros */
diff --git a/src/northbridge/intel/sandybridge/raminit_common.c b/src/northbridge/intel/sandybridge/raminit_common.c
index d66a0f0e..c4bf5ff 100644
--- a/src/northbridge/intel/sandybridge/raminit_common.c
+++ b/src/northbridge/intel/sandybridge/raminit_common.c
@@ -17,10 +17,25 @@
 
 /* FIXME: no support for 3-channel chipsets */
 
+/* Number of programmed IOSAV subsequences. */
+static unsigned int ssq_count = 0;
+
+static void iosav_write_ssq(const int ch, const int n, const struct iosav_ssq *ssq)
+{
+	MCHBAR32(IOSAV_n_SP_CMD_CTRL_ch(ch, ssq_count)) = ssq->sp_cmd_ctrl.raw;
+	MCHBAR32(IOSAV_n_SUBSEQ_CTRL_ch(ch, ssq_count)) = ssq->subseq_ctrl.raw;
+	MCHBAR32(IOSAV_n_SP_CMD_ADDR_ch(ch, ssq_count)) = ssq->sp_cmd_addr.raw;
+	MCHBAR32(IOSAV_n_ADDR_UPDATE_ch(ch, ssq_count)) = ssq->addr_update.raw;
+
+	ssq_count++;
+}
+
 /* length:      [1..4] */
 static void iosav_run_queue(const int ch, const u8 loops, const u8 length, const u8 as_timer)
 {
-	MCHBAR32(IOSAV_SEQ_CTL_ch(ch)) = loops | ((length - 1) << 18) | (as_timer << 22);
+	MCHBAR32(IOSAV_SEQ_CTL_ch(ch)) = loops | ((ssq_count - 1) << 18) | (as_timer << 22);
+
+	ssq_count = 0;
 }
 
 static void iosav_run_once(const int ch, const u8 length)
diff --git a/src/northbridge/intel/sandybridge/raminit_common.h b/src/northbridge/intel/sandybridge/raminit_common.h
index c544cde..6e76cbc0 100644
--- a/src/northbridge/intel/sandybridge/raminit_common.h
+++ b/src/northbridge/intel/sandybridge/raminit_common.h
@@ -34,6 +34,63 @@
 #define IOSAV_WR		(0xf201)
 #define IOSAV_NOP		(0xf207)
 
+struct iosav_ssq {
+	/* IOSAV_n_SP_CMD_CTRL */
+	union {
+		struct {
+			u32 command    : 16;
+			u32 ranksel_ap :  2;
+			u32            : 14;
+		};
+		u32 raw;
+	} sp_cmd_ctrl;
+
+	/* IOSAV_n_SUBSEQ_CTRL */
+	union {
+		struct {
+			u32 cmd_executions : 9;
+			u32                : 1;
+			u32 cmd_delay_gap  : 5;
+			u32                : 1;
+			u32 post_ssq_wait  : 9;
+			u32                : 1;
+			u32 data_direction : 2;
+			u32                : 4;
+		};
+		u32 raw;
+	} subseq_ctrl;
+
+	/* IOSAV_n_SP_CMD_ADDR */
+	union {
+		struct {
+			u32 address : 16;
+			u32 rowbits :  3;
+			u32         :  1;
+			u32 bank    :  3;
+			u32         :  1;
+			u32 rank    :  2;
+			u32         :  6;
+		};
+		u32 raw;
+	} sp_cmd_addr;
+
+	/* IOSAV_n_ADDR_UPDATE */
+	union {
+		struct {
+			u32 inc_addr_1 :  1;
+			u32 inc_addr_8 :  1;
+			u32 inc_bank   :  1;
+			u32 inc_rank   :  2;
+			u32 addr_wrap  :  5;
+			u32 lfsr_upd   :  2;
+			u32 upd_rate   :  4;
+			u32 lfsr_xors  :  2;
+			u32            : 14;
+		};
+		u32 raw;
+	} addr_update;
+};
+
 /* FIXME: Vendor BIOS uses 64 but our algorithms are less
    performant and even 1 seems to be enough in practice.  */
 #define NUM_PATTERNS	4