nb/intel/sandybridge: Introduce `ddr3_mirror_mrreg` helper

Write training needs to update mode register 1, but `write_mrreg` will
clobber the IOSAV sequence. Reference code uses one four-subsequence to
unset Qoff in MR1, run the test, and finally set Qoff again. This will
be implemented in future changes, and will use the newly-added helper.

Change-Id: I06a06a7bdd43dbde34af4ea2f90e00873eefe599
Signed-off-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/47613
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
diff --git a/src/northbridge/intel/sandybridge/raminit_common.c b/src/northbridge/intel/sandybridge/raminit_common.c
index 971d692..b58328b 100644
--- a/src/northbridge/intel/sandybridge/raminit_common.c
+++ b/src/northbridge/intel/sandybridge/raminit_common.c
@@ -598,17 +598,22 @@
 	}
 }
 
+/*
+ * DDR3 Rank1 Address mirror swap the following pins:
+ * A3<->A4, A5<->A6, A7<->A8, BA0<->BA1
+ */
+static void ddr3_mirror_mrreg(int *bank, u32 *addr)
+{
+	*bank = ((*bank >> 1) & 1) | ((*bank << 1) & 2);
+	*addr = (*addr & ~0x1f8) | ((*addr >> 1) & 0xa8) | ((*addr & 0xa8) << 1);
+}
+
 static void write_mrreg(ramctr_timing *ctrl, int channel, int slotrank, int reg, u32 val)
 {
 	wait_for_iosav(channel);
 
-	if (ctrl->rank_mirror[channel][slotrank]) {
-		/* DDR3 Rank1 Address mirror
-		   swap the following pins:
-		   A3<->A4, A5<->A6, A7<->A8, BA0<->BA1 */
-		reg = ((reg >> 1) & 1) | ((reg << 1) & 2);
-		val = (val & ~0x1f8) | ((val >> 1) & 0xa8) | ((val & 0xa8) << 1);
-	}
+	if (ctrl->rank_mirror[channel][slotrank])
+		ddr3_mirror_mrreg(&reg, &val);
 
 	const struct iosav_ssq sequence[] = {
 		/* DRAM command MRS */