From d9d10881a0841481d8df2e357adb870ce52f9387 Mon Sep 17 00:00:00 2001
From: Timothy Pearson <tpearson@raptorengineeringinc.com>
Date: Thu, 27 Aug 2015 23:37:38 -0500
Subject: [PATCH 129/143] northbridge/amd/amdmct/mct_ddr3: Fix broken support
 for multiple DIMMs on single channel

Change-Id: I0278656e98461882d0a64519dfde54a6cf28ab0f
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
---
 src/northbridge/amd/amdmct/mct_ddr3/mct_d.c    |  336 +++++++++++++++++++-----
 src/northbridge/amd/amdmct/mct_ddr3/mct_d.h    |    8 +-
 src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c |    2 +-
 src/northbridge/amd/amdmct/mct_ddr3/mctrci.c   |   26 +-
 src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c   |    4 +
 src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c  |    8 +-
 6 files changed, 310 insertions(+), 74 deletions(-)

diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
index a11b227..5bc80f4 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
@@ -1360,6 +1360,224 @@ static uint8_t fam15h_slow_access_mode(struct DCTStatStruc *pDCTstat, uint8_t dc
 	return slow_access;
 }
 
+static uint8_t fam15h_odt_tristate_enable_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
+{
+	uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+
+	uint8_t package_type;
+	uint8_t odt_tristate_code = 0;
+
+	package_type = mctGet_NVbits(NV_PACK_TYPE);
+
+	/* Obtain number of DIMMs on channel */
+	uint8_t dimm_count = pDCTstat->MAdimms[dct];
+	uint8_t rank_count_dimm0;
+	uint8_t rank_count_dimm1;
+
+	if (package_type == PT_GR) {
+		/* Socket G34 */
+		if (pDCTstat->Status & (1 << SB_Registered)) {
+			/* RDIMM */
+			/* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 104 */
+			if (MaxDimmsInstallable == 1) {
+				rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+				if (rank_count_dimm0 == 1)
+					odt_tristate_code = 0xe;
+				else
+					odt_tristate_code = 0xa;
+			} else if (MaxDimmsInstallable == 2) {
+				if (dimm_count == 1) {
+					/* 1 DIMM detected */
+					rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+					if (rank_count_dimm1 == 1)
+						odt_tristate_code = 0xd;
+					else
+						odt_tristate_code = 0x5;
+				} else if (dimm_count == 2) {
+					/* 2 DIMMs detected */
+					rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct];
+					rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+					if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1))
+						odt_tristate_code = 0xc;
+					else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 >= 2))
+						odt_tristate_code = 0x4;
+					else if ((rank_count_dimm0 >= 2) && (rank_count_dimm1 == 1))
+						odt_tristate_code = 0x8;
+					else
+						odt_tristate_code = 0x0;
+				}
+			} else if (MaxDimmsInstallable == 3) {
+				/* TODO
+				 * 3 DIMM/channel support unimplemented
+				 */
+			}
+		} else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+			/* LRDIMM */
+
+			/* TODO
+			 * Implement LRDIMM support
+			 * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 105
+			 */
+		} else {
+			/* UDIMM */
+			/* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 103 */
+			if (MaxDimmsInstallable == 1) {
+				rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+				if (rank_count_dimm0 == 1)
+					odt_tristate_code = 0xe;
+				else
+					odt_tristate_code = 0xa;
+			} else if (MaxDimmsInstallable == 2) {
+				if (dimm_count == 1) {
+					/* 1 DIMM detected */
+					rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+					if (rank_count_dimm0 == 1)
+						odt_tristate_code = 0xd;
+					else
+						odt_tristate_code = 0x5;
+				} else if (dimm_count == 2) {
+					/* 2 DIMMs detected */
+					rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct];
+					rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+					if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1))
+						odt_tristate_code = 0xc;
+					else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 2))
+						odt_tristate_code = 0x4;
+					else if ((rank_count_dimm0 == 2) && (rank_count_dimm1 == 1))
+						odt_tristate_code = 0x8;
+					else
+						odt_tristate_code = 0x0;
+				}
+			} else if (MaxDimmsInstallable == 3) {
+				/* TODO
+				 * 3 DIMM/channel support unimplemented
+				 */
+			}
+		}
+	} else {
+		/* TODO
+		 * Other socket support unimplemented
+		 */
+	}
+
+	return odt_tristate_code;
+}
+
+static uint8_t fam15h_cs_tristate_enable_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
+{
+	uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
+
+	uint8_t package_type;
+	uint8_t cs_tristate_code = 0;
+
+	package_type = mctGet_NVbits(NV_PACK_TYPE);
+
+	/* Obtain number of DIMMs on channel */
+	uint8_t dimm_count = pDCTstat->MAdimms[dct];
+	uint8_t rank_count_dimm0;
+	uint8_t rank_count_dimm1;
+
+	if (package_type == PT_GR) {
+		/* Socket G34 */
+		if (pDCTstat->Status & (1 << SB_Registered)) {
+			/* RDIMM */
+			/* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 104 */
+			if (MaxDimmsInstallable == 1) {
+				rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+				if (rank_count_dimm0 < 4)
+					cs_tristate_code = 0xfc;
+				else
+					cs_tristate_code = 0xcc;
+			} else if (MaxDimmsInstallable == 2) {
+				if (dimm_count == 1) {
+					/* 1 DIMM detected */
+					rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+					if (rank_count_dimm1 < 4)
+						cs_tristate_code = 0xf3;
+					else
+						cs_tristate_code = 0x33;
+				} else if (dimm_count == 2) {
+					/* 2 DIMMs detected */
+					rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct];
+					rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+					if ((rank_count_dimm0 < 4) && (rank_count_dimm1 < 4))
+						cs_tristate_code = 0xf0;
+					else if ((rank_count_dimm0 < 4) && (rank_count_dimm1 == 4))
+						cs_tristate_code = 0x30;
+					else if ((rank_count_dimm0 == 4) && (rank_count_dimm1 < 4))
+						cs_tristate_code = 0xc0;
+					else
+						cs_tristate_code = 0x0;
+				}
+			} else if (MaxDimmsInstallable == 3) {
+				/* TODO
+				 * 3 DIMM/channel support unimplemented
+				 */
+			}
+		} else if (pDCTstat->Status & (1 << SB_LoadReduced)) {
+			/* LRDIMM */
+
+			/* TODO
+			 * Implement LRDIMM support
+			 * See Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 105
+			 */
+		} else {
+			/* UDIMM */
+			/* Fam15h BKDG Rev. 3.14 section 2.10.5.10.1 Table 103 */
+			if (MaxDimmsInstallable == 1) {
+				rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+				if (rank_count_dimm0 == 1)
+					cs_tristate_code = 0xfe;
+				else
+					cs_tristate_code = 0xfc;
+			} else if (MaxDimmsInstallable == 2) {
+				if (dimm_count == 1) {
+					/* 1 DIMM detected */
+					rank_count_dimm0 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+					if (rank_count_dimm0 == 1)
+						cs_tristate_code = 0xfb;
+					else
+						cs_tristate_code = 0xf3;
+				} else if (dimm_count == 2) {
+					/* 2 DIMMs detected */
+					rank_count_dimm0 = pDCTstat->DimmRanks[(0 * 2) + dct];
+					rank_count_dimm1 = pDCTstat->DimmRanks[(1 * 2) + dct];
+
+					if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 1))
+						cs_tristate_code = 0xfa;
+					else if ((rank_count_dimm0 == 1) && (rank_count_dimm1 == 2))
+						cs_tristate_code = 0xf2;
+					else if ((rank_count_dimm0 == 2) && (rank_count_dimm1 == 1))
+						cs_tristate_code = 0xf8;
+					else
+						cs_tristate_code = 0xf0;
+				}
+			} else if (MaxDimmsInstallable == 3) {
+				/* TODO
+				 * 3 DIMM/channel support unimplemented
+				 */
+			}
+		}
+	} else {
+		/* TODO
+		 * Other socket support unimplemented
+		 */
+	}
+
+	return cs_tristate_code;
+}
+
 static void set_2t_configuration(struct MCTStatStruc *pMCTstat,
 				struct DCTStatStruc *pDCTstat, u8 dct)
 {
@@ -2299,20 +2517,16 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat,
 		if (memclk_index <= 0x6) {
 			delay = 0x5;
 			delay2 = 0x3;
-		}
-		else if (memclk_index == 0xa) {
+		} else if (memclk_index == 0xa) {
 			delay = 0x6;
 			delay2 = 0x3;
-		}
-		else if (memclk_index == 0xe) {
+		} else if (memclk_index == 0xe) {
 			delay = 0x7;
 			delay2 = 0x4;
-		}
-		else if (memclk_index == 0x12) {
+		} else if (memclk_index == 0x12) {
 			delay = 0x8;
 			delay2 = 0x4;
-		}
-		else if (memclk_index == 0x16) {
+		} else if (memclk_index == 0x16) {
 			delay = 0xa;
 			delay2 = 0x5;
 		}
@@ -3329,8 +3543,7 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
 			tCK16x = 40;
 		else
 			tCK16x = 48;
-	}
-	else {
+	} else {
 		if (byte == 7)
 			tCK16x = 20;
 		else if (byte == 6)
@@ -4657,13 +4870,13 @@ static u8 DIMMPresence_D(struct MCTStatStruc *pMCTstat,
 					else
 						pDCTstat->RegMan1Present |= 1 << i;
 				}
-				/* Get Control word values for RC3. We dont need it. */
+				/* Get control word value for RC3 */
 				byte = pDCTstat->spd_data.spd_bytes[i][70];
-				pDCTstat->CtrlWrd3 |= (byte >> 4) << (i << 2); /* C3 = SPD byte 70 [7:4] */
-				/* Get Control word values for RC4, and RC5 */
+				pDCTstat->CtrlWrd3 |= ((byte >> 4) & 0xf) << (i << 2);	/* RC3 = SPD byte 70 [7:4] */
+				/* Get control word values for RC4 and RC5 */
 				byte = pDCTstat->spd_data.spd_bytes[i][71];
-				pDCTstat->CtrlWrd4 |= (byte & 0xFF) << (i << 2); /* RC4 = SPD byte 71 [3:0] */
-				pDCTstat->CtrlWrd5 |= (byte >> 4) << (i << 2); /* RC5 = SPD byte 71 [7:4] */
+				pDCTstat->CtrlWrd4 |= (byte & 0xf) << (i << 2);		/* RC4 = SPD byte 71 [3:0] */
+				pDCTstat->CtrlWrd5 |= ((byte >> 4) & 0xf) << (i << 2);	/* RC5 = SPD byte 71 [7:4] */
 			}
 		}
 	}
@@ -5849,23 +6062,27 @@ static void SetCSTriState(struct MCTStatStruc *pMCTstat,
 	u32 val;
 	u32 dev = pDCTstat->dev_dct;
 	u32 index_reg = 0x98;
-	u32 index;
 	u16 word;
 
-	/* Tri-state unused chipselects when motherboard
-	   termination is available */
+	if (is_fam15h()) {
+		word = fam15h_cs_tristate_enable_code(pDCTstat, dct);
+	} else {
+		/* Tri-state unused chipselects when motherboard
+		termination is available */
 
-	/* FIXME: skip for Ax */
+		/* FIXME: skip for Ax */
 
-	word = pDCTstat->CSPresent;
-	if (pDCTstat->Status & (1 << SB_Registered)) {
-		word |= (word & 0x55) << 1;
+		word = pDCTstat->CSPresent;
+		if (pDCTstat->Status & (1 << SB_Registered)) {
+			word |= (word & 0x55) << 1;
+		}
+		word = (~word) & 0xff;
 	}
-	word = (~word) & 0xFF;
-	index  = 0x0c;
-	val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+
+	val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
+	val &= ~0xff;
 	val |= word;
-	Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
+	Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
 }
 
 static void SetCKETriState(struct MCTStatStruc *pMCTstat,
@@ -5874,7 +6091,6 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
 	u32 val;
 	u32 dev;
 	u32 index_reg = 0x98;
-	u32 index;
 	u16 word;
 
 	/* Tri-state unused CKEs when motherboard termination is available */
@@ -5884,15 +6100,13 @@ static void SetCKETriState(struct MCTStatStruc *pMCTstat,
 	dev = pDCTstat->dev_dct;
 	word = pDCTstat->CSPresent;
 
-	index  = 0x0c;
-	val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
+	val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
+	val &= ~(0x3 << 12);
 	if ((word & 0x55) == 0)
 		val |= 1 << 12;
-
-	if ((word & 0xAA) == 0)
+	if ((word & 0xaa) == 0)
 		val |= 1 << 13;
-
-	Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
+	Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
 }
 
 static void SetODTTriState(struct MCTStatStruc *pMCTstat,
@@ -5902,42 +6116,44 @@ static void SetODTTriState(struct MCTStatStruc *pMCTstat,
 	u32 dev;
 	u32 index_reg = 0x98;
 	u8 cs;
-	u32 index;
 	u8 odt;
 	u8 max_dimms;
 
-	/* FIXME: skip for Ax */
-
 	dev = pDCTstat->dev_dct;
 
-	/* Tri-state unused ODTs when motherboard termination is available */
-	max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS);
-	odt = 0x0F;	/* ODT tri-state setting */
-
-	if (pDCTstat->Status & (1 <<SB_Registered)) {
-		for (cs = 0; cs < 8; cs += 2) {
-			if (pDCTstat->CSPresent & (1 << cs)) {
-				odt &= ~(1 << (cs / 2));
-				if (mctGet_NVbits(NV_4RANKType) != 0) { /* quad-rank capable platform */
-					if (pDCTstat->CSPresent & (1 << (cs + 1)))
-						odt &= ~(4 << (cs / 2));
+	if (is_fam15h()) {
+		odt = fam15h_odt_tristate_enable_code(pDCTstat, dct);
+	} else {
+		/* FIXME: skip for Ax */
+
+		/* Tri-state unused ODTs when motherboard termination is available */
+		max_dimms = (u8) mctGet_NVbits(NV_MAX_DIMMS);
+		odt = 0x0f;	/* ODT tri-state setting */
+
+		if (pDCTstat->Status & (1 <<SB_Registered)) {
+			for (cs = 0; cs < 8; cs += 2) {
+				if (pDCTstat->CSPresent & (1 << cs)) {
+					odt &= ~(1 << (cs / 2));
+					if (mctGet_NVbits(NV_4RANKType) != 0) { /* quad-rank capable platform */
+						if (pDCTstat->CSPresent & (1 << (cs + 1)))
+							odt &= ~(4 << (cs / 2));
+					}
 				}
 			}
+		} else {		/* AM3 package */
+			val = ~(pDCTstat->CSPresent);
+			odt = val & 9;	/* swap bits 1 and 2 */
+			if (val & (1 << 1))
+				odt |= 1 << 2;
+			if (val & (1 << 2))
+				odt |= 1 << 1;
 		}
-	} else {		/* AM3 package */
-		val = ~(pDCTstat->CSPresent);
-		odt = val & 9;	/* swap bits 1 and 2 */
-		if (val & (1 << 1))
-			odt |= 1 << 2;
-		if (val & (1 << 2))
-			odt |= 1 << 1;
 	}
 
-	index  = 0x0C;
-	val = Get_NB32_index_wait_DCT(dev, dct, index_reg, index);
-	val |= ((odt & 0xFF) << 8);	/* set bits 11:8 ODTTriState[3:0] */
-	Set_NB32_index_wait_DCT(dev, dct, index_reg, index, val);
-
+	val = Get_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c);
+	val &= ~(0xf << 8);		/* ODTTri = odt */
+	val |= (odt & 0xf) << 8;
+	Set_NB32_index_wait_DCT(dev, dct, index_reg, 0x0000000c, val);
 }
 
 /* Family 15h */
@@ -6507,7 +6723,7 @@ static void mct_ProgramODT_D(struct MCTStatStruc *pMCTstat,
 		dword |= (read_odt_delay & 0xf);
 		Set_NB32_DCT(dev, dct, 0x240, dword);
 
-		printk(BIOS_SPEW, "Programmed ODT pattern %08x %08x %08x %08x\n", odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
+		printk(BIOS_SPEW, "Programmed DCT %d ODT pattern %08x %08x %08x %08x\n", dct, odt_pattern_0, odt_pattern_1, odt_pattern_2, odt_pattern_3);
 	} else if (pDCTstat->LogicalCPUID & AMD_DR_Dx) {
 		if (pDCTstat->Speed == 3)
 			dword = 0x00000800;
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
index ec5658e..8bc4ec2 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
@@ -582,7 +582,7 @@ struct DCTStatStruc {		/* A per Node structure*/
 	uint8_t NbPstateThreshold;
 	uint8_t NbPstateHi;
 
-/* New for LB Support */
+	/* New for LB Support */
 	u8 NodePresent;
 	u32 dev_host;
 	u32 dev_map;
@@ -592,9 +592,9 @@ struct DCTStatStruc {		/* A per Node structure*/
 	u32 dev_nbctl;
 	u8 TargetFreq;
 	u8 TargetCASL;
-	u8 CtrlWrd3;
-	u8 CtrlWrd4;
-	u8 CtrlWrd5;
+	uint32_t CtrlWrd3;
+	uint32_t CtrlWrd4;
+	uint32_t CtrlWrd5;
 	u8 DqsRdWrPos_Saved;
 	u8 DqsRcvEnGrossMax;
 	u8 DqsRcvEnGrossMin;
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
index d870f17..553a54a 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c
@@ -1021,7 +1021,7 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
 		pDCTstat->CH_MaxRdLat[dct] = n - 1;
 
 #if DQS_TRAIN_DEBUG > 0
-	printk(BIOS_DEBUG, "%s: CH_MaxRdLat[%d]: %03x\n", __func__, dct, pDCTstat->CH_MaxRdLat[dct]);
+		printk(BIOS_DEBUG, "%s: CH_MaxRdLat[%d]: %03x\n", __func__, dct, pDCTstat->CH_MaxRdLat[dct]);
 #endif
 	}
 
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
index 8fd2523..dec2bf8 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctrci.c
@@ -18,7 +18,7 @@
  * Foundation, Inc.
  */
 
-static uint8_t fam15h_rdimm_rc2_control_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
+static uint8_t fam15h_rdimm_rc2_ibt_code(struct DCTStatStruc *pDCTstat, uint8_t dct)
 {
 	uint8_t MaxDimmsInstallable = mctGet_NVbits(NV_MAX_DIMMS_PER_CH);
 
@@ -161,7 +161,7 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
 			val = 0xc; /* if single rank, set DBA1 and DBA0 */
 	} else if (CtrlWordNum == 2) {
 		if (is_fam15h()) {
-			val = fam15h_rdimm_rc2_control_code(pDCTstat, dct);
+			val = (fam15h_rdimm_rc2_ibt_code(pDCTstat, dct) & 0x1) << 2;
 		} else {
 			if (package_type == PT_GR) {
 				/* Socket G34 */
@@ -178,10 +178,14 @@ static u32 mct_ControlRC(struct MCTStatStruc *pMCTstat,
 	} else if (CtrlWordNum == 5) {
 		val = (pDCTstat->CtrlWrd5 >> (DimmNum << 2)) & 0xff;
 	} else if (CtrlWordNum == 8) {
-		if (package_type == PT_GR) {
-			/* Socket G34 */
-			if (MaxDimmsInstallable == 2) {
-				val = 0x0;
+		if (is_fam15h()) {
+			val = (fam15h_rdimm_rc2_ibt_code(pDCTstat, dct) & 0xe) >> 1;
+		} else {
+			if (package_type == PT_GR) {
+				/* Socket G34 */
+				if (MaxDimmsInstallable == 2) {
+					val = 0x0;
+				}
 			}
 		}
 	} else if (CtrlWordNum == 9) {
@@ -233,7 +237,11 @@ void mct_DramControlReg_Init_D(struct MCTStatStruc *pMCTstat,
 
 	mct_Wait(1200);
 
-	for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel ++, MrsChipSel ++) {
+	pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
+	if (pDCTstat->GangedMode & 1)
+		pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
+
+	for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel += 2) {
 		if (pDCTstat->CSPresent & (1 << MrsChipSel)) {
 			val = Get_NB32_DCT(dev, dct, 0xa8);
 			val &= ~(0xff << 8);
@@ -276,6 +284,10 @@ void FreqChgCtrlWrd(struct MCTStatStruc *pMCTstat,
 	u32 val;
 	uint16_t mem_freq;
 
+	pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
+	if (pDCTstat->GangedMode & 1)
+		pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
+
 	pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
 	mem_freq = memclk_to_freq(pDCTstat->TargetFreq);
 	for (MrsChipSel=0; MrsChipSel < 8; MrsChipSel++, MrsChipSel++) {
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
index 7804a38..5019faa 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctsdi.c
@@ -845,6 +845,10 @@ void mct_DramInit_Sw_D(struct MCTStatStruc *pMCTstat,
 			 */
 	}
 
+	pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[dct];
+	if (pDCTstat->GangedMode & 1)
+		pDCTstat->CSPresent = pDCTstat->CSPresent_DCT[0];
+
 	/* The following steps are performed once for unbuffered DIMMs and once for each
 	 * chip select on registered DIMMs: */
 	for (MrsChipSel = 0; MrsChipSel < 8; MrsChipSel++) {
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
index 73b231e..5cbadc3 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
@@ -925,7 +925,7 @@ void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat,
  *       OUT
  * ----------------------------------------------------------------------------
  */
-void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, u8 dimm)
+void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm)
 {
 	sMCTStruct *pMCTData = pDCTstat->C_MCTPtr;
 	sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct];
@@ -933,6 +933,10 @@ void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
 	u8 WrLvOdt1=0;
 
 	if (is_fam15h()) {
+		/* On Family15h processors, the value for the specific CS being targetted
+		 * is taken from F2x238 / F2x23C as appropriate, then loaded into F2x9C_x0000_0008
+		 */
+
 		/* Convert DIMM number to CS */
 		uint32_t dword;
 		uint8_t cs;
@@ -967,7 +971,7 @@ void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui
 	set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
 			DRAM_ADD_DCT_PHY_CONTROL_REG, 8, 11, (u32)WrLvOdt1);
 
-	printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern %08x\n", dct, WrLvOdt1);
+	printk(BIOS_SPEW, "Programmed DCT %d write levelling ODT pattern %08x from DIMM %d data\n", dct, WrLvOdt1, dimm);
 
 }
 
-- 
1.7.9.5

