[coreboot-gerrit] Patch set updated for coreboot: nb/amd/mct_ddr3: Fix RDIMM training on certain DIMMs

Timothy Pearson (tpearson@raptorengineeringinc.com) gerrit at coreboot.org
Thu Apr 21 17:14:21 CEST 2016


Timothy Pearson (tpearson at raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14441

-gerrit

commit d86ffeb5f5bc0f7ef0d52d09158984af00a12ec1
Author: Timothy Pearson <tpearson at raptorengineeringinc.com>
Date:   Wed Apr 20 14:00:39 2016 -0500

    nb/amd/mct_ddr3: Fix RDIMM training on certain DIMMs
    
    Certain RDIMMs have inherently large write levelling delays,
    in some cases exceeding 1.5 MEMCLK.  When these DIMMs are
    utilized, the phase recovery system requires special handling
    due to the resultant offset exceeding the phase recovery reporting
    capabilities.
    
    Fix an old error where delays > 1.5 MEMCLK were not being programmed
    (gross delay high bit was not in set range), and restore special
    delay handling for delays greater than 1.5 MEMCLK.
    
    Also enhance debugging for x4 DIMMs around the affected code.
    
    Tested-On: ASUS KGPE-D16
    Config-CPU: 1x Opteron 6262HE
    Config-RAM: 4x Crucial 36KSF1G72PZ-1G6M1
    Change-Id: I0fb5454c4d5a9f308cc735597607f095fe9188db
    Signed-off-by: Timothy Pearson <tpearson at raptorengineeringinc.com>
---
 src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c | 83 +++++++++++++--------------
 1 file changed, 39 insertions(+), 44 deletions(-)

diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
index f246d88..9702126 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
@@ -1366,27 +1366,20 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
 		EccValue = 0;
 		while (ByteLane < lane_count)
 		{
-			if (is_fam15h()) {
-				grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
-			} else {
-				/* This subtract 0xC workaround might be temporary. */
-				if ((pDCTData->WLPass==2) && (pDCTData->RegMan1Present & (1<<(dimm*2+dct))))
-				{
-					tempW = (pDCTData->WLGrossDelay[index+ByteLane] << 5) | pDCTData->WLFineDelay[index+ByteLane];
-					tempW -= 0xC;
-					pDCTData->WLGrossDelay[index+ByteLane] = (u8)(tempW >> 5);
-					pDCTData->WLFineDelay[index+ByteLane] = (u8)(tempW & 0x1F);
-				}
-				grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
-				/* Adjust seed gross delay overflow (greater than 3):
-				 *      - Program seed gross delay as 2 (gross is 4 or 6) or 1 (gross is 5).
-				 *      - Keep original seed gross delay for later reference.
-				 */
-				if(grossDelayValue >= 3)
-				{
-					grossDelayValue = (grossDelayValue&1)? 1 : 2;
-				}
+			/* This subtract 0xC workaround might be temporary. */
+			if ((pDCTData->WLPass==2) && (pDCTData->RegMan1Present & (1<<(dimm*2+dct)))) {
+				tempW = (pDCTData->WLGrossDelay[index+ByteLane] << 5) | pDCTData->WLFineDelay[index+ByteLane];
+				tempW -= 0xC;
+				pDCTData->WLGrossDelay[index+ByteLane] = (u8)(tempW >> 5);
+				pDCTData->WLFineDelay[index+ByteLane] = (u8)(tempW & 0x1F);
 			}
+			grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
+			/* Adjust seed gross delay overflow (greater than 3):
+			 *      - Program seed gross delay as 2 (gross is 4 or 6) or 1 (gross is 5).
+			 *      - Keep original seed gross delay for later reference.
+			 */
+			if(grossDelayValue >= 3)
+				grossDelayValue = (grossDelayValue&1)? 1 : 2;
 			fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
 			if (ByteLane < 4)
 				ValueLow |= ((grossDelayValue << 5) | fineDelayValue) << 8*ByteLane;
@@ -1405,7 +1398,9 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
 	}
 	else
 	{
-		/* Fam10h BKDG Rev. 3.62 2.8.9.9.1 (6) */
+		/* Fam10h BKDG: Rev. 3.62 2.8.9.9.1 (6)
+		 * Fam15h BKDG: Rev. 3.14 2.10.5.8.1
+		 */
 		index = (u8)(lane_count * dimm);
 		grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
 		fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
@@ -1433,7 +1428,7 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
 		fineStartLoc = (u8)(tempB % 32);
 		fineEndLoc = (u8)(fineStartLoc + 4);
 		grossStartLoc = (u8)(fineEndLoc + 1);
-		grossEndLoc = (u8)(grossStartLoc + 1);
+		grossEndLoc = (u8)(grossStartLoc + 2);
 
 		set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
 				(u16)addr, fineStartLoc, fineEndLoc,(u32)fineDelayValue);
@@ -1498,29 +1493,30 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
 	gross = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
 				FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
 
-	printk(BIOS_SPEW, "\tLane %02x raw readback: %04x\n", ByteLane, ((gross & 0x1f) << 5) | (fine & 0x1f));
+	printk(BIOS_SPEW, "\tLane %02x nibble %01x raw readback: %04x\n", ByteLane, nibble, ((gross & 0x1f) << 5) | (fine & 0x1f));
 
-	if (!is_fam15h()) {
-		/* Adjust seed gross delay overflow (greater than 3):
-		 * - Adjust the trained gross delay to the original seed gross delay.
+	/* Adjust seed gross delay overflow (greater than 3):
+	 * - Adjust the trained gross delay to the original seed gross delay.
+	 */
+	if (pDCTData->WLGrossDelay[index+ByteLane] >= 3)
+	{
+		gross += pDCTData->WLGrossDelay[index+ByteLane];
+		if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
+			gross -= 1;
+		else
+			gross -= 2;
+	}
+	else if ((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 3))
+	{
+		/* If seed gross delay is 0 but PRE result gross delay is 3, it is negative.
+		 * We will then round the negative number to 0.
 		 */
-		if(pDCTData->WLGrossDelay[index+ByteLane] >= 3)
-		{
-			gross += pDCTData->WLGrossDelay[index+ByteLane];
-			if(pDCTData->WLGrossDelay[index+ByteLane] & 1)
-				gross -= 1;
-			else
-				gross -= 2;
-		}
-		else if((pDCTData->WLGrossDelay[index+ByteLane] == 0) && (gross == 3))
-		{
-			/* If seed gross delay is 0 but PRE result gross delay is 3, it is negative.
-			 * We will then round the negative number to 0.
-			 */
-			gross = 0;
-			fine = 0;
-		}
+		gross = 0;
+		fine = 0;
 	}
+	printk(BIOS_SPEW, "\tLane %02x nibble %01x adjusted value (pre nibble): %04x\n", ByteLane, nibble, ((gross & 0x1f) << 5) | (fine & 0x1f));
+
+	/* Nibble adjustments */
 	if (nibble == 0) {
 		pDCTData->WLFineDelay[index+ByteLane] = (uint8_t)fine;
 		pDCTData->WLGrossDelay[index+ByteLane] = (uint8_t)gross;
@@ -1531,6 +1527,5 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
 		pDCTData->WLFineDelay[index+ByteLane] = (uint8_t)(WLTotalDelay & 0x1f);
 		pDCTData->WLGrossDelay[index+ByteLane] = (uint8_t)((WLTotalDelay >> 5) & 0x1f);
 	}
-
-	printk(BIOS_SPEW, "\tLane %02x adjusted value: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[index+ByteLane] & 0x1f));
+	printk(BIOS_SPEW, "\tLane %02x nibble %01x adjusted value (post nibble): %04x\n", ByteLane, nibble, ((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[index+ByteLane] & 0x1f));
 }



More information about the coreboot-gerrit mailing list