nb/intel/sandybridge: Use bitfields for I/O data timings

Refactor in preparation to split up `program_timings`.

Tested on Asus P8Z77-V LX2, still boots.

Change-Id: I68410165f397d8b4f662e40e88fb6a58ab1c5cff
Signed-off-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/47772
Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/northbridge/intel/sandybridge/raminit_common.c b/src/northbridge/intel/sandybridge/raminit_common.c
index 8418ccd..d2049c1 100644
--- a/src/northbridge/intel/sandybridge/raminit_common.c
+++ b/src/northbridge/intel/sandybridge/raminit_common.c
@@ -1029,23 +1029,26 @@
 		    ctrl->timings[channel][slotrank].roundtrip_latency << (8 * slotrank);
 
 		FOR_ALL_LANES {
-			MCHBAR32(lane_base[lane] + GDCRRX(channel, slotrank)) =
-			    ((ctrl->timings[channel][slotrank].lanes[lane].timA & 0x3f)
-			     |
-			     (ctrl->timings[channel][slotrank].lanes[lane].rising << 8)
-			     |
-			     ((ctrl->timings[channel][slotrank].lanes[lane].timA & 0x1c0) << 10)
-			     |
-			     (ctrl->timings[channel][slotrank].lanes[lane].falling << 20));
+			const u16 timA = ctrl->timings[channel][slotrank].lanes[lane].timA;
+			const u8 dqs_p = ctrl->timings[channel][slotrank].lanes[lane].rising;
+			const u8 dqs_n = ctrl->timings[channel][slotrank].lanes[lane].falling;
+			const union gdcr_rx_reg gdcr_rx = {
+				.rcven_pi_code     = timA % 64,
+				.rx_dqs_p_pi_code  = dqs_p,
+				.rcven_logic_delay = timA / 64,
+				.rx_dqs_n_pi_code  = dqs_n,
+			};
+			MCHBAR32(lane_base[lane] + GDCRRX(channel, slotrank)) = gdcr_rx.raw;
 
-			MCHBAR32(lane_base[lane] + GDCRTX(channel, slotrank)) =
-			    ((ctrl->timings[channel][slotrank].lanes[lane].timC & 0x3f)
-			     |
-			     ((ctrl->timings[channel][slotrank].lanes[lane].timB & 0x3f) << 8)
-			     |
-			     ((ctrl->timings[channel][slotrank].lanes[lane].timB & 0x1c0) << 9)
-			     |
-			    ((ctrl->timings[channel][slotrank].lanes[lane].timC & 0x40) << 13));
+			const u16 timB = ctrl->timings[channel][slotrank].lanes[lane].timB;
+			const int timC = ctrl->timings[channel][slotrank].lanes[lane].timC;
+			const union gdcr_tx_reg gdcr_tx = {
+				.tx_dq_pi_code      = timC % 64,
+				.tx_dqs_pi_code     = timB % 64,
+				.tx_dqs_logic_delay = timB / 64,
+				.tx_dq_logic_delay  = timC / 64,
+			};
+			MCHBAR32(lane_base[lane] + GDCRTX(channel, slotrank)) = gdcr_tx.raw;
 		}
 	}
 	MCHBAR32(SC_ROUNDT_LAT_ch(channel)) = reg_roundtrip_latency;
diff --git a/src/northbridge/intel/sandybridge/raminit_common.h b/src/northbridge/intel/sandybridge/raminit_common.h
index debfaa2..8c92c17 100644
--- a/src/northbridge/intel/sandybridge/raminit_common.h
+++ b/src/northbridge/intel/sandybridge/raminit_common.h
@@ -98,6 +98,34 @@
 	} addr_update;
 };
 
+union gdcr_rx_reg {
+	struct {
+		u32 rcven_pi_code     : 6; /* [ 5.. 0] */
+		u32                   : 2;
+		u32 rx_dqs_p_pi_code  : 7; /* [14.. 8] */
+		u32                   : 1;
+		u32 rcven_logic_delay : 3; /* [18..16] */
+		u32                   : 1;
+		u32 rx_dqs_n_pi_code  : 7; /* [26..20] */
+		u32                   : 5;
+	};
+	u32 raw;
+};
+
+union gdcr_tx_reg {
+	struct {
+		u32 tx_dq_pi_code      :  6; /* [ 5.. 0] */
+		u32                    :  2;
+		u32 tx_dqs_pi_code     :  6; /* [13.. 8] */
+		u32                    :  1;
+		u32 tx_dqs_logic_delay :  3; /* [17..15] */
+		u32                    :  1;
+		u32 tx_dq_logic_delay  :  1; /* [19..19] */
+		u32                    : 12;
+	};
+	u32 raw;
+};
+
 union gdcr_cmd_pi_coding_reg {
 	struct {
 		u32 cmd_pi_code         : 6; /* [ 5.. 0] */