nb/intel/gm45: Split DDR2 JEDEC init out

Split JEDEC init into common and DDR3 specific parts and add the DDR2
specific init code. This also replaces raw `mchbar_clrsetbits32` calls
with a dedicated `jedec_command` function.

TEST: DDR2 systems boot (with the rest of the patch train)
- Tested on a Dell Latitude E6400
- Tested on a Compal JHL90
TEST: Ensure DDR3 systems still boot
- Tested on a Thinkpad X200

Change-Id: I7a57549887c0323e5babbf18f691183412a99ba9
Signed-off-by: Nico Huber <nico.h@gmx.de>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/34827
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
diff --git a/src/northbridge/intel/gm45/gm45.h b/src/northbridge/intel/gm45/gm45.h
index c5c17a6..c8ec6dc 100644
--- a/src/northbridge/intel/gm45/gm45.h
+++ b/src/northbridge/intel/gm45/gm45.h
@@ -243,6 +243,7 @@
 #define DCC_CMD_SHIFT		16
 #define DCC_CMD_MASK		(7 << DCC_CMD_SHIFT)
 #define DCC_CMD_NOP		(1 << DCC_CMD_SHIFT)
+#define DCC_CMD_ABP		(2 << DCC_CMD_SHIFT)
 				/* For mode register mr0: */
 #define DCC_SET_MREG		(3 << DCC_CMD_SHIFT)
 				/* For extended mode registers mr1 to mr3: */
@@ -252,6 +253,7 @@
 #define DCC_SET_EREGx(x)	((DCC_SET_EREG |			     \
 					(((x) - 1) << DCC_SET_EREG_SHIFT)) & \
 				 DCC_SET_EREG_MASK)
+#define DCC_CMD_CBR		(6 << DCC_CMD_SHIFT)
 
 /* Per channel DRAM Row Attribute registers (32-bit) */
 #define CxDRA_MCHBAR(x)		(0x1208 + ((x) * 0x0100))
diff --git a/src/northbridge/intel/gm45/raminit.c b/src/northbridge/intel/gm45/raminit.c
index 62785d3..a57f201 100644
--- a/src/northbridge/intel/gm45/raminit.c
+++ b/src/northbridge/intel/gm45/raminit.c
@@ -1697,28 +1697,19 @@
 	ddr3_read_io_init(ddr3clock, dimms, sff);
 }
 
-static void jedec_init(const timings_t *const timings,
-		       const dimminfo_t *const dimms)
+static void jedec_command(const uintptr_t rankaddr, const u32 cmd, const u32 val)
+{
+	mchbar_clrsetbits32(DCC_MCHBAR, DCC_SET_EREG_MASK, cmd);
+	read32p(rankaddr | val);
+}
+
+static void jedec_init_ddr3(const timings_t *const timings,
+			    const dimminfo_t *const dimms)
 {
 	if ((timings->tWR < 5) || (timings->tWR > 12))
 		die("tWR value unsupported in Jedec initialization.\n");
 
-	/* Pre-jedec settings */
-	mchbar_setbits32(0x40, 1 << 1);
-	mchbar_setbits32(0x230, 3 << 1);
-	mchbar_setbits32(0x238, 3 << 24);
-	mchbar_setbits32(0x23c, 3 << 24);
 
-	/* Normal write pointer operation */
-	mchbar_setbits32(0x14f0, 1 << 9);
-	mchbar_setbits32(0x15f0, 1 << 9);
-
-	mchbar_clrsetbits32(DCC_MCHBAR, DCC_CMD_MASK, DCC_CMD_NOP);
-
-	pci_and_config8(PCI_DEV(0, 0, 0), 0xf0, ~(1 << 2));
-
-	pci_or_config8(PCI_DEV(0, 0, 0), 0xf0, 1 << 2);
-	udelay(2);
 
 				  /* 5  6  7  8  9 10 11 12 */
 	static const u8 wr_lut[] = { 1, 2, 3, 4, 5, 5, 6, 6 };
@@ -1736,18 +1727,82 @@
 		/* We won't do this in dual-interleaved mode,
 		   so don't care about the offset.
 		   Mirrored ranks aren't taken into account here. */
-		const u32 rankaddr = raminit_get_rank_addr(ch, r);
-		printk(BIOS_DEBUG, "JEDEC init @0x%08x\n", rankaddr);
-		mchbar_clrsetbits32(DCC_MCHBAR, DCC_SET_EREG_MASK, DCC_SET_EREGx(2));
-		read32p(rankaddr | WL);
-		mchbar_clrsetbits32(DCC_MCHBAR, DCC_SET_EREG_MASK, DCC_SET_EREGx(3));
-		read32p(rankaddr);
-		mchbar_clrsetbits32(DCC_MCHBAR, DCC_SET_EREG_MASK, DCC_SET_EREGx(1));
-		read32p(rankaddr | ODT_120OHMS | ODS_34OHMS);
-		mchbar_clrsetbits32(DCC_MCHBAR, DCC_CMD_MASK, DCC_SET_MREG);
-		read32p(rankaddr | WR | DLL1 | CAS | INTERLEAVED);
-		mchbar_clrsetbits32(DCC_MCHBAR, DCC_CMD_MASK, DCC_SET_MREG);
-		read32p(rankaddr | WR | CAS | INTERLEAVED);
+		const uintptr_t rankaddr = raminit_get_rank_addr(ch, r);
+		printk(BIOS_DEBUG, "JEDEC init @0x%08x\n", (u32)rankaddr);
+
+		jedec_command(rankaddr, DCC_SET_EREGx(2), WL);
+		jedec_command(rankaddr, DCC_SET_EREGx(3), 0);
+		jedec_command(rankaddr, DCC_SET_EREGx(1), ODT_120OHMS | ODS_34OHMS);
+		jedec_command(rankaddr, DCC_SET_MREG, WR | DLL1 | CAS | INTERLEAVED);
+		jedec_command(rankaddr, DCC_SET_MREG, WR | CAS | INTERLEAVED);
+	}
+}
+
+static void jedec_init_ddr2(const timings_t *const timings,
+			    const dimminfo_t *const dimms)
+{
+	/* All bit offsets are off by 3 (2^3 bytes bus width). */
+
+	/* Mode Register (MR) settings */
+	const int WR = ((timings->tWR - 1) & 7) << 12;
+	const int DLLreset = 1 << 11;
+	const int CAS = (timings->CAS & 7) << 7;
+	const int BTinterleaved = 1 << 6;
+	const int BL8 = 3 << 3;
+
+	/* Extended Mode Register 1 (EMR1) */
+	const int OCDdefault = 7 << 10;
+	const int ODT_150OHMS = 1 << 9 | 0 << 5;
+
+	int ch, r;
+	FOR_EACH_POPULATED_RANK(dimms, ch, r) {
+		/* We won't do this in dual-interleaved mode,
+		   so don't care about the offset.
+		   Mirrored ranks aren't taken into account here. */
+		const uintptr_t rankaddr = raminit_get_rank_addr(ch, r);
+		printk(BIOS_DEBUG, "JEDEC init @0x%08x\n", (u32)rankaddr);
+
+		jedec_command(rankaddr, DCC_CMD_ABP, 0);
+		jedec_command(rankaddr, DCC_SET_EREGx(2), 0);
+		jedec_command(rankaddr, DCC_SET_EREGx(3), 0);
+		jedec_command(rankaddr, DCC_SET_EREGx(1), ODT_150OHMS);
+		jedec_command(rankaddr, DCC_SET_MREG, WR | DLLreset | CAS | BTinterleaved | BL8);
+		jedec_command(rankaddr, DCC_CMD_ABP, 0);
+		jedec_command(rankaddr, DCC_CMD_CBR, 0);
+		udelay(1);
+		read32((void *)(rankaddr));
+
+		jedec_command(rankaddr, DCC_SET_MREG, WR | CAS | BTinterleaved | BL8);
+		jedec_command(rankaddr, DCC_SET_EREGx(1), OCDdefault | ODT_150OHMS);
+		jedec_command(rankaddr, DCC_SET_EREGx(1), ODT_150OHMS);
+	}
+}
+
+static void jedec_init(const int spd_type,
+		       const timings_t *const timings,
+		       const dimminfo_t *const dimms)
+{
+	/* Pre-jedec settings */
+	mchbar_setbits32(0x40, 1 << 1);
+	mchbar_setbits32(0x230, 3 << 1);
+	mchbar_setbits32(0x238, 3 << 24);
+	mchbar_setbits32(0x23c, 3 << 24);
+
+	/* Normal write pointer operation */
+	mchbar_setbits32(0x14f0, 1 << 9);
+	mchbar_setbits32(0x15f0, 1 << 9);
+
+	mchbar_clrsetbits32(DCC_MCHBAR, DCC_CMD_MASK, DCC_CMD_NOP);
+
+	pci_and_config8(PCI_DEV(0, 0, 0), 0xf0, ~(1 << 2));
+
+	pci_or_config8(PCI_DEV(0, 0, 0), 0xf0, 1 << 2);
+	udelay(2);
+
+	if (spd_type == DDR2) {
+		jedec_init_ddr2(timings, dimms);
+	} else if (spd_type == DDR3) {
+		jedec_init_ddr3(timings, dimms);
 	}
 }
 
@@ -1920,7 +1975,7 @@
 	prejedec_memory_map(dimms, timings->channel_mode);
 	if (!s3resume)
 		/* Perform JEDEC initialization of DIMMS. */
-		jedec_init(timings, dimms);
+		jedec_init(sysinfo->spd_type, timings, dimms);
 	/* Some programming steps after JEDEC initialization. */
 	post_jedec_sequence(sysinfo->cores);