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@raptorengineeringinc.com> Reviewed-on: https://review.coreboot.org/14441 Tested-by: Raptor Engineering Automated Test Stand <noreply@raptorengineeringinc.com> Tested-by: build bot (Jenkins) Reviewed-by: Martin Roth <martinroth@google.com>
This commit is contained in:
parent
b474afdd21
commit
490160140a
|
@ -1366,12 +1366,8 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
|
||||||
EccValue = 0;
|
EccValue = 0;
|
||||||
while (ByteLane < lane_count)
|
while (ByteLane < lane_count)
|
||||||
{
|
{
|
||||||
if (is_fam15h()) {
|
|
||||||
grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
|
|
||||||
} else {
|
|
||||||
/* This subtract 0xC workaround might be temporary. */
|
/* This subtract 0xC workaround might be temporary. */
|
||||||
if ((pDCTData->WLPass==2) && (pDCTData->RegMan1Present & (1<<(dimm*2+dct))))
|
if ((pDCTData->WLPass==2) && (pDCTData->RegMan1Present & (1<<(dimm*2+dct)))) {
|
||||||
{
|
|
||||||
tempW = (pDCTData->WLGrossDelay[index+ByteLane] << 5) | pDCTData->WLFineDelay[index+ByteLane];
|
tempW = (pDCTData->WLGrossDelay[index+ByteLane] << 5) | pDCTData->WLFineDelay[index+ByteLane];
|
||||||
tempW -= 0xC;
|
tempW -= 0xC;
|
||||||
pDCTData->WLGrossDelay[index+ByteLane] = (u8)(tempW >> 5);
|
pDCTData->WLGrossDelay[index+ByteLane] = (u8)(tempW >> 5);
|
||||||
|
@ -1383,10 +1379,7 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
|
||||||
* - Keep original seed gross delay for later reference.
|
* - Keep original seed gross delay for later reference.
|
||||||
*/
|
*/
|
||||||
if(grossDelayValue >= 3)
|
if(grossDelayValue >= 3)
|
||||||
{
|
|
||||||
grossDelayValue = (grossDelayValue&1)? 1 : 2;
|
grossDelayValue = (grossDelayValue&1)? 1 : 2;
|
||||||
}
|
|
||||||
}
|
|
||||||
fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
|
fineDelayValue = pDCTData->WLFineDelay[index+ByteLane];
|
||||||
if (ByteLane < 4)
|
if (ByteLane < 4)
|
||||||
ValueLow |= ((grossDelayValue << 5) | fineDelayValue) << 8*ByteLane;
|
ValueLow |= ((grossDelayValue << 5) | fineDelayValue) << 8*ByteLane;
|
||||||
|
@ -1405,7 +1398,9 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
|
||||||
}
|
}
|
||||||
else
|
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);
|
index = (u8)(lane_count * dimm);
|
||||||
grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
|
grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];
|
||||||
fineDelayValue = pDCTData->WLFineDelay[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);
|
fineStartLoc = (u8)(tempB % 32);
|
||||||
fineEndLoc = (u8)(fineStartLoc + 4);
|
fineEndLoc = (u8)(fineStartLoc + 4);
|
||||||
grossStartLoc = (u8)(fineEndLoc + 1);
|
grossStartLoc = (u8)(fineEndLoc + 1);
|
||||||
grossEndLoc = (u8)(grossStartLoc + 1);
|
grossEndLoc = (u8)(grossStartLoc + 2);
|
||||||
|
|
||||||
set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
|
set_DCT_ADDR_Bits(pDCTData, dct, pDCTData->NodeId, FUN_DCT,
|
||||||
(u16)addr, fineStartLoc, fineEndLoc,(u32)fineDelayValue);
|
(u16)addr, fineStartLoc, fineEndLoc,(u32)fineDelayValue);
|
||||||
|
@ -1498,9 +1493,8 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
|
||||||
gross = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
|
gross = get_ADD_DCT_Bits(pDCTData, dct, pDCTData->NodeId,
|
||||||
FUN_DCT, (u16)addr, grossStartLoc, grossEndLoc);
|
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 seed gross delay overflow (greater than 3):
|
||||||
* - Adjust the trained gross delay to the original seed gross delay.
|
* - Adjust the trained gross delay to the original seed gross delay.
|
||||||
*/
|
*/
|
||||||
|
@ -1520,7 +1514,9 @@ void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8
|
||||||
gross = 0;
|
gross = 0;
|
||||||
fine = 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) {
|
if (nibble == 0) {
|
||||||
pDCTData->WLFineDelay[index+ByteLane] = (uint8_t)fine;
|
pDCTData->WLFineDelay[index+ByteLane] = (uint8_t)fine;
|
||||||
pDCTData->WLGrossDelay[index+ByteLane] = (uint8_t)gross;
|
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->WLFineDelay[index+ByteLane] = (uint8_t)(WLTotalDelay & 0x1f);
|
||||||
pDCTData->WLGrossDelay[index+ByteLane] = (uint8_t)((WLTotalDelay >> 5) & 0x1f);
|
pDCTData->WLGrossDelay[index+ByteLane] = (uint8_t)((WLTotalDelay >> 5) & 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));
|
||||||
printk(BIOS_SPEW, "\tLane %02x adjusted value: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[index+ByteLane] & 0x1f));
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue