Damien Zammit (damien@zamaudio.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/13725
-gerrit
commit 1bebf9b1b339be5f1763f439cd75866ccdcb90f6 Author: Damien Zammit damien@zamaudio.com Date: Wed Feb 17 14:14:47 2016 +1100
nb/amd/amdmct: Select max_lanes based on ECC presence or absence
Change-Id: Ic5482dc13ab7b53ec4df408bbe32d20888ae2e12 Signed-off-by: Damien Zammit damien@zamaudio.com --- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 15 +++--- src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c | 29 ++++++++--- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c | 72 +++++++++++++++++++------- 3 files changed, 84 insertions(+), 32 deletions(-)
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c index 48f5a1e..e803431 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c @@ -2628,6 +2628,7 @@ static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat, uint8_t allow_config_restore;
uint8_t s3resume = acpi_is_wakeup_s3(); + u8 ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs);
restartinit: mctInitMemGPIOs_A_D(); /* Set any required GPIOs*/ @@ -2827,12 +2828,14 @@ restartinit: InterleaveNodes_D(pMCTstat, pDCTstatA); InterleaveChannels_D(pMCTstat, pDCTstatA);
- printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n"); - if (!ECCInit_D(pMCTstat, pDCTstatA)) { /* Setup ECC control and ECC check-bits*/ - /* Memory was not cleared during ECC setup */ - /* mctDoWarmResetMemClr_D(); */ - printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n"); - MCTMemClr_D(pMCTstat,pDCTstatA); + if (ecc_enabled) { + printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n"); + if (!ECCInit_D(pMCTstat, pDCTstatA)) { /* Setup ECC control and ECC check-bits*/ + /* Memory was not cleared during ECC setup */ + /* mctDoWarmResetMemClr_D(); */ + printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n"); + MCTMemClr_D(pMCTstat,pDCTstatA); + } }
if (is_fam15h()) { diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c index 22e9836..e02eaa5 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctdqs_d.c @@ -942,6 +942,13 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat, printk(BIOS_DEBUG, "%s: Start\n", __func__); #endif
+ u8 max_lane; + u8 ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs); + if (ecc_enabled) + max_lane = 9; + else + max_lane = 8; + mem_clk = Get_NB32_DCT(dev, dct, 0x94) & 0x1f; if (fam15h_freq_tab[mem_clk] == 0) { pDCTstat->CH_MaxRdLat[dct] = 0x55; @@ -983,7 +990,7 @@ static void Calc_SetMaxRdLatency_D_Fam15(struct MCTStatStruc *pMCTstat,
read_dqs_receiver_enable_control_registers(current_phy_phase_delay, dev, dct, dimm, index_reg); read_read_dqs_timing_control_registers(current_read_dqs_delay, dev, dct, dimm, index_reg); - for (lane = 0; lane < MAX_BYTE_LANES; lane++) + for (lane = 0; lane < max_lane; lane++) if ((current_phy_phase_delay[lane] + current_read_dqs_delay[lane]) > max_delay) max_delay = (current_phy_phase_delay[lane] + current_read_dqs_delay[lane]); } @@ -1672,6 +1679,13 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat, uint32_t index_reg = 0x98; uint32_t dev = pDCTstat->dev_dct;
+ u8 max_lane; + u8 ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs); + if (ecc_enabled) + max_lane = 9; + else + max_lane = 8; + print_debug_dqs("\nTrainDQSReceiverEnCyc: Node_ID ", pDCTstat->Node_ID, 0); cr4 = read_cr4(); if (cr4 & (1<<9)) { @@ -1689,7 +1703,8 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat, _WRMSR(addr, lo, hi); /* allow 64-bit memory references in real mode */
/* Disable ECC correction of reads on the dram bus. */ - _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat); + if (ecc_enabled) + _DisableDramECC = mct_DisableDimmEccEn_D(pMCTstat, pDCTstat);
Errors = 0;
@@ -1722,7 +1737,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat, /* 2.10.5.8.3 (2) */ read_dqs_receiver_enable_control_registers(initial_phy_phase_delay, dev, dct, dimm, index_reg);
- for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { /* Initialize variables */ memset(dqs_results_array, 0, sizeof(dqs_results_array));
@@ -1789,7 +1804,7 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat,
#if DQS_TRAIN_DEBUG > 0 printk(BIOS_DEBUG, "TrainDQSReceiverEnCyc_D_Fam15 DQS receiver enable timing: "); - for (lane = 0; lane < MAX_BYTE_LANES; lane++) { + for (lane = 0; lane < max_lane; lane++) { printk(BIOS_DEBUG, " %03x", current_phy_phase_delay[lane]); } printk(BIOS_DEBUG, "\n"); @@ -1829,8 +1844,10 @@ static void TrainDQSReceiverEnCyc_D_Fam15(struct MCTStatStruc *pMCTstat,
} #endif - if (_DisableDramECC) { - mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC); + if (ecc_enabled) { + if (_DisableDramECC) { + mct_EnableDimmEccEn_D(pMCTstat, pDCTstat, _DisableDramECC); + } } if (!_Wrap32Dis) { addr = HWCR; diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c index 2b8a997..2676c7e 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c @@ -32,7 +32,7 @@ void prepareDimms(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, u8 dct, u8 dimm, BOOL wl); void programODT(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, u8 dimm); void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, uint8_t dct, uint8_t dimm, uint8_t pass, uint8_t nibble); -void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass); +void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass, u8 max_lane); void getWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, uint8_t pass, uint8_t nibble);
static int32_t abs(int32_t val) { @@ -77,6 +77,14 @@ uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT u16 Addl_Data_Offset, Addl_Data_Port; sMCTStruct *pMCTData = pDCTstat->C_MCTPtr; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; + uint8_t ecc_enabled; + uint8_t max_lane; + + ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs); + if (ecc_enabled) + max_lane = 9; + else + max_lane = 8;
pDCTData->WLPass = pass; /* 1. Specify the target DIMM that is to be trained by programming @@ -176,7 +184,7 @@ uint8_t AgesaHwWlPhase1(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT /* Read from registers F2x[1, 0]9C_x[51:50] and F2x[1, 0]9C_x52 * to get the gross and fine delay settings * for the target DIMM and save these values. */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { getWLByteDelay(pDCTstat, dct, ByteLane, dimm, pass, nibble); }
@@ -192,6 +200,14 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT u8 ByteLane; uint8_t status = 0; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; + uint8_t ecc_enabled; + uint8_t max_lane; + + ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs); + if (ecc_enabled) + max_lane = 9; + else + max_lane = 8;
if (is_fam15h()) { int32_t gross_diff[MAX_BYTE_LANES]; @@ -205,7 +221,7 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT */
/* Calculate the Critical Gross Delay */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { /* Calculate the gross delay differential for this lane */ gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane]; gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane]; @@ -231,7 +247,7 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT * Figure out why this is and fix it, then remove the bypass code below... */ if (pass == FirstPass) { - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { pDCTData->WLGrossDelay[index+ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane]; pDCTData->WLFineDelay[index+ByteLane] = pDCTData->WLSeedFineDelay[index+ByteLane]; } @@ -240,7 +256,7 @@ uint8_t AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT }
/* Compensate for occasional noise/instability causing sporadic training failure */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { uint8_t faulty_value_detected = 0; uint16_t total_delay_seed = ((pDCTData->WLSeedGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLSeedFineDelay[index+ByteLane] & 0x1f); uint16_t total_delay_phy = ((pDCTData->WLGrossDelay[index+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[index+ByteLane] & 0x1f); @@ -278,6 +294,14 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT u8 ByteLane; sMCTStruct *pMCTData = pDCTstat->C_MCTPtr; sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; + uint8_t ecc_enabled; + u8 max_lane; + + ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs); + if (ecc_enabled) + max_lane = 9; + else + max_lane = 8;
if (is_fam15h()) { uint32_t dword; @@ -292,7 +316,7 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT dword |= ((abs(cgd) & 0x3) << 24); Set_NB32_DCT(pDCTstat->dev_dct, dct, 0xa8, dword);
- for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { /* Calculate the gross delay differential for this lane */ gross_diff[ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane] + pDCTData->WLGrossDelay[index+ByteLane]; gross_diff[ByteLane] -= pDCTData->WLSeedPreGrossDelay[index+ByteLane]; @@ -313,8 +337,8 @@ uint8_t AgesaHwWlPhase3(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCT
/* Write the adjusted gross and fine delay settings * to the target DIMM. */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { - setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 1, pass); + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { + setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 1, pass, max_lane); }
/* 6. Configure DRAM Phy Control Register so that the phy stops driving @@ -1006,6 +1030,14 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; uint16_t fam10h_freq_tab[] = {0, 0, 0, 400, 533, 667, 800}; uint16_t fam15h_freq_tab[] = {0, 0, 0, 0, 333, 0, 400, 0, 0, 0, 533, 0, 0, 0, 667, 0, 0, 0, 800, 0, 0, 0, 933}; + uint8_t ecc_enabled; + uint8_t max_lane; + + ecc_enabled = !!(pMCTstat->GStatus & 1 << GSB_ECCDIMMs); + if (ecc_enabled) + max_lane = 9; + else + max_lane = 8;
if (is_fam15h()) { /* MemClkFreq: 0x4: 333MHz; 0x6: 400MHz; 0xa: 533MHz; 0xe: 667MHz; 0x12: 800MHz; 0x16: 933MHz */ @@ -1113,7 +1145,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui Seed_Fine = Seed_Total & 0x1f;
/* Save seed values for later use */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Gross; pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = Seed_Fine;
@@ -1150,7 +1182,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui } } } - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { /* Program an initialization value to registers F2x[1, 0]9C_x[51:50] and * F2x[1, 0]9C_x52 to set the gross and fine delay for all the byte lane fields @@ -1194,7 +1226,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui WrDqDqsEarly = 0;
/* Generate new seed values */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { /* Calculate adjusted seed values */ SeedTotal[ByteLane] = (pDCTData->WLFineDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) | ((pDCTData->WLGrossDelayPrevPass[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5); @@ -1204,7 +1236,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui }
/* Generate register values from seeds */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { printk(BIOS_SPEW, "\tLane %02x scaled delay: %04x\n", ByteLane, SeedTotal[ByteLane]);
if (SeedTotal[ByteLane] >= 0) { @@ -1243,7 +1275,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui uint32_t SeedTotalPreScaling; uint32_t SeedTotal; uint8_t AddrCmdPrelaunch = 0; /* TODO: Fetch the correct value from RC2[0] */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { if (pDCTData->Status[DCT_STATUS_REGISTERED]) { if (AddrCmdPrelaunch == 0) @@ -1285,7 +1317,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui }
/* Save initial seeds for upper nibble pass */ - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane]; @@ -1293,7 +1325,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui } else { /* Restore seed values from lower nibble pass */ if (is_fam15h()) { - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { pDCTData->WLSeedGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLSeedFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLSeedPreGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedPreGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; @@ -1304,7 +1336,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui printk(BIOS_SPEW, "\tLane %02x new seed: %04x\n", ByteLane, ((pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f) << 5) | (pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] & 0x1f)); } } else { - for (ByteLane = 0; ByteLane < MAX_BYTE_LANES; ByteLane++) { + for (ByteLane = 0; ByteLane < max_lane; ByteLane++) { pDCTData->WLGrossDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedGrossPrevNibble[MAX_BYTE_LANES*dimm+ByteLane]; pDCTData->WLFineDelay[MAX_BYTE_LANES*dimm+ByteLane] = pDCTData->WLSeedFinePrevNibble[MAX_BYTE_LANES*dimm+ByteLane];
@@ -1315,11 +1347,11 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui }
pDCTData->WLPrevMemclkFreq = MemClkFreq; - setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 0, pass); + setWLByteDelay(pDCTstat, dct, ByteLane, dimm, 0, pass, max_lane); }
/*----------------------------------------------------------------------------- - * void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm){ + * void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 Dimm, u8 max_lane){ * * Description: * This function writes the write levelization byte delay for the Phase @@ -1339,7 +1371,7 @@ void procConfig(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat, ui * *----------------------------------------------------------------------------- */ -void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass) +void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 dimm, u8 targetAddr, uint8_t pass, u8 max_lane) { sDCTStruct *pDCTData = pDCTstat->C_DCTPtr[dct]; u8 fineStartLoc, fineEndLoc, grossStartLoc, grossEndLoc, tempB, index, offsetAddr; @@ -1352,7 +1384,7 @@ void setWLByteDelay(struct DCTStatStruc *pDCTstat, uint8_t dct, u8 ByteLane, u8 ValueHigh = 0; ByteLane = 0; EccValue = 0; - while (ByteLane < MAX_BYTE_LANES) + while (ByteLane < max_lane) { if (is_fam15h()) { grossDelayValue = pDCTData->WLGrossDelay[index+ByteLane];