From 4818de5c4895e3de9bca7d7f3566492e8e529e21 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Wed, 24 Jun 2015 19:15:09 -0500 Subject: [PATCH 071/146] northbridge/amd/amdmct/mct_ddr3: Fix lockups and wasted time during ECC init --- src/northbridge/amd/amdmct/mct_ddr3/mct_d.c | 146 +++++++++++++++--------- src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c | 39 ++++++- src/northbridge/amd/amdmct/mct_ddr3/mctproc.c | 22 +++- src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c | 3 +- 4 files changed, 147 insertions(+), 63 deletions(-) diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c index e39ce17..b66b328 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c @@ -983,7 +983,7 @@ static uint32_t fam15h_address_timing_compensation_code(struct DCTStatStruc *pDC /* 2 DIMMs detected */ rank_count_dimm0 = pDCTstat->C_DCTPtr[dct]->DimmRanks[0]; rank_count_dimm1 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1]; - + if (MemClkFreq == 0x4) { /* DDR3-667 */ calibration_code = 0x00390039; @@ -1072,7 +1072,7 @@ static uint8_t fam15h_slow_access_mode(struct DCTStatStruc *pDCTstat, uint8_t dc /* 2 DIMMs detected */ rank_count_dimm0 = pDCTstat->C_DCTPtr[dct]->DimmRanks[0]; rank_count_dimm1 = pDCTstat->C_DCTPtr[dct]->DimmRanks[1]; - + if ((MemClkFreq == 0x4) || (MemClkFreq == 0x6) || (MemClkFreq == 0xa)) { /* DDR3-667 - DDR3-1066 */ @@ -1492,11 +1492,12 @@ restartinit: InterleaveChannels_D(pMCTstat, pDCTstatA); printk(BIOS_DEBUG, "mctAutoInitMCT_D: ECCInit_D\n"); - ECCInit_D(pMCTstat, pDCTstatA); /* Setup ECC control and ECC check-bits*/ - - /* mctDoWarmResetMemClr_D(); */ - printk(BIOS_DEBUG, "mctAutoInitMCT_D: MCTMemClr_D\n"); - MCTMemClr_D(pMCTstat,pDCTstatA); + 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); + } printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_Dis_Fam15\n"); for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { @@ -1689,7 +1690,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, uint8_t x8_present = 0; uint8_t memclk_index; uint8_t interleave_channels = 0; - uint8_t redirect_ecc_scrub = 0; uint16_t trdrdsddc; uint16_t trdrddd; uint16_t cdd_trdrddd; @@ -1727,9 +1727,6 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, if (pDCTstat->DIMMValidDCT[0] && pDCTstat->DIMMValidDCT[1] && mctGet_NVbits(NV_Unganged)) interleave_channels = 1; - if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && mctGet_NVbits(NV_ECCRedir)) - redirect_ecc_scrub = 1; - dword = (Get_NB32_DCT(dev, dct, 0x240) >> 4) & 0xf; if (dword > 6) read_odt_delay = dword - 6; @@ -1922,21 +1919,10 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, dword |= (interleave_channels & 0x1) << 2; Set_NB32_DCT(dev, dct, 0x110, dword); /* DRAM Controller Select Low */ - dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58); /* Scrub Rate Control */ - dword &= ~(0x1f << 24); /* L3Scrub = NV_L3BKScrub */ - dword |= (mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24; - dword &= ~(0x1f); /* DramScrub = NV_DramBKScrub */ - dword |= mctGet_NVbits(NV_DramBKScrub) & 0x1f; - Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword); /* Scrub Rate Control */ - - dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c); /* DRAM Scrub Address Low */ - dword &= ~(0x1); /* ScrubReDirEn = redirect_ecc_scrub */ - dword |= redirect_ecc_scrub & 0x1; - Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword); /* DRAM Scrub Address Low */ - - dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 Control 1 */ - dword &= ~(0x1 << 4); /* L3ScrbRedirDis = 0 */ - Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword); /* L3 Control 1 */ + /* NOTE + * ECC-related setup is performed as part of ECCInit_D and must not be located here, + * otherwise semi-random lockups will occur due to misconfigured scrubbing hardware! + */ /* FIXME * The BKDG-recommended settings cause memory corruption on the ASUS KGPE-D16. @@ -1978,11 +1964,17 @@ static void fam15EnableTrainingMode(struct MCTStatStruc *pMCTstat, dword |= ((((dword >> 8) & 0x1f) + 1) << 16); Set_NB32_DCT(dev, dct, 0x21c, dword); /* DRAM Timing 6 */ + /* Configure partial power down delay */ + dword = Get_NB32(dev, 0x244); /* DRAM Controller Miscellaneous 3 */ + dword &= ~0xf; /* PrtlChPDDynDly = 0x2 */ + dword |= 0x2; + Set_NB32(dev, 0x244, dword); /* DRAM Controller Miscellaneous 3 */ + /* Enable prefetchers */ - dword = Get_NB32_DCT(dev, dct, 0x110); /* Memory Controller Configuration High */ + dword = Get_NB32(dev, 0x11c); /* Memory Controller Configuration High */ dword &= ~(0x1 << 13); /* PrefIoDis = 0 */ dword &= ~(0x1 << 12); /* PrefCpuDis = 0 */ - Set_NB32_DCT(dev, dct, 0x110, dword); /* Memory Controller Configuration High */ + Set_NB32(dev, 0x11c, dword); /* Memory Controller Configuration High */ } } @@ -2084,6 +2076,19 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat, pMCTstat->GStatus |= 1 << GSB_ConfigRestored; } + if (is_fam15h()) { + uint8_t Node; + struct DCTStatStruc *pDCTstat; + + /* Switch DCT control register to DCT 0 per Erratum 505 */ + for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { + pDCTstat = pDCTstatA + Node; + if (pDCTstat->NodePresent) { + fam15h_switch_dct(pDCTstat->dev_map, 0); + } + } + } + /* FIXME - currently uses calculated value TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */ mctHookAfterAnyTraining(); } @@ -2330,6 +2335,7 @@ static void MCTMemClr_D(struct MCTStatStruc *pMCTstat, * status are checked to ensure that memclr has completed. */ u8 Node; + uint32_t dword; struct DCTStatStruc *pDCTstat; if (!mctGet_NVbits(NV_DQSTrainCTL)){ @@ -2350,6 +2356,16 @@ static void MCTMemClr_D(struct MCTStatStruc *pMCTstat, } } } + + for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) { + /* Configure and enable prefetchers */ + if (is_fam15h()) + dword = 0x0ce00f41; /* BKDG recommended */ + else + dword = 0x0fe40fc0; /* BKDG recommended */ + dword |= MCCH_FlushWrOnStpGnt; /* Set for S3 */ + Set_NB32(pDCTstat->dev_dct, 0x11c, dword); + } } static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat, @@ -2357,48 +2373,59 @@ static void DCTMemClr_Init_D(struct MCTStatStruc *pMCTstat, { u32 val; u32 dev; - u32 reg; + uint32_t dword; /* Initiates a memory clear operation on one node */ if (pDCTstat->DCTSysLimit) { dev = pDCTstat->dev_dct; - reg = 0x110; + + /* Disable prefetchers */ + dword = Get_NB32(dev, 0x11c); /* Memory Controller Configuration High */ + dword |= 0x1 << 13; /* PrefIoDis = 1 */ + dword |= 0x1 << 12; /* PrefCpuDis = 1 */ + Set_NB32(dev, 0x11c, dword); /* Memory Controller Configuration High */ do { - val = Get_NB32(dev, reg); + val = Get_NB32(dev, 0x110); } while (val & (1 << MemClrBusy)); val |= (1 << MemClrInit); - Set_NB32(dev, reg, val); + Set_NB32(dev, 0x110, val); } } static void DCTMemClr_Sync_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat) { - u32 val; - u32 dev = pDCTstat->dev_dct; - u32 reg; + uint32_t dword; + uint32_t dev = pDCTstat->dev_dct; + + printk(BIOS_DEBUG, "%s: Start\n", __func__); /* Ensure that a memory clear operation has completed on one node */ if (pDCTstat->DCTSysLimit){ - reg = 0x110; - + printk(BIOS_DEBUG, "%s: Waiting for memory clear to complete", __func__); do { - val = Get_NB32(dev, reg); - } while (val & (1 << MemClrBusy)); + dword = Get_NB32(dev, 0x110); + + printk(BIOS_DEBUG, "."); + } while (dword & (1 << MemClrBusy)); + printk(BIOS_DEBUG, "\n"); do { - val = Get_NB32(dev, reg); - } while (!(val & (1 << Dr_MemClrStatus))); + printk(BIOS_DEBUG, "."); + dword = Get_NB32(dev, 0x110); + } while (!(dword & (1 << Dr_MemClrStatus))); + printk(BIOS_DEBUG, "\n"); } - if (is_fam15h()) - val = 0x0ce00f41; /* BKDG recommended */ - else - val = 0x0fe40fc0; /* BKDG recommended */ - val |= MCCH_FlushWrOnStpGnt; /* Set for S3 */ - Set_NB32(dev, 0x11c, val); + /* Enable prefetchers */ + dword = Get_NB32(dev, 0x11c); /* Memory Controller Configuration High */ + dword &= ~(0x1 << 13); /* PrefIoDis = 0 */ + dword &= ~(0x1 << 12); /* PrefCpuDis = 0 */ + Set_NB32(dev, 0x11c, dword); /* Memory Controller Configuration High */ + + printk(BIOS_DEBUG, "%s: Done\n", __func__); } static u8 NodePresent_D(u8 Node) @@ -3339,8 +3366,8 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat, dev = pDCTstat->dev_dct; /* Build Dram Control Register Value */ - DramConfigMisc2 = Get_NB32_DCT(dev, dct, 0xA8); /* Dram Control*/ - DramControl = Get_NB32_DCT(dev, dct, 0x78); /* Dram Control*/ + DramConfigMisc2 = Get_NB32_DCT(dev, dct, 0xa8); /* Dram Miscellaneous 2 */ + DramControl = Get_NB32_DCT(dev, dct, 0x78); /* Dram Control */ /* FIXME: Skip mct_checkForDxSupport */ /* REV_CALL mct_DoRdPtrInit if not Dx */ @@ -3395,9 +3422,15 @@ static u8 AutoConfig_D(struct MCTStatStruc *pMCTstat, /* set only if x8 Registered DIMMs in System*/ DramConfigHi |= 1 << RDqsEn; - if (mctGet_NVbits(NV_CKE_CTL)) - /*Chip Select control of CKE*/ - DramConfigHi |= 1 << 16; + if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) { + DramConfigLo |= 1 << 25; /* PendRefPaybackS3En = 1 */ + DramConfigLo |= 1 << 24; /* StagRefEn = 1 */ + DramConfigHi |= 1 << 16; /* PowerDownMode = 1 */ + } else { + if (mctGet_NVbits(NV_CKE_CTL)) + /*Chip Select control of CKE*/ + DramConfigHi |= 1 << 16; + } /* Control Bank Swizzle */ if (0) /* call back not needed mctBankSwizzleControl_D()) */ @@ -4105,8 +4138,7 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat, #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME) if (load_spd_hashes_from_nvram(pMCTstat, pDCTstat) < 0) { pDCTstat->spd_data.nvram_spd_match = 0; - } - else { + } else { compare_nvram_spd_hashes(pMCTstat, pDCTstat); } #else @@ -4300,8 +4332,8 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat, } for (i=i_start; iCH_ODC_CTL[i]); /* Channel A Output Driver Compensation Control */ - Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, pDCTstat->CH_ADDR_TMG[i]); /* Channel A Output Driver Compensation Control */ + Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, pDCTstat->CH_ODC_CTL[i]); /* Channel A/B Output Driver Compensation Control */ + Set_NB32_index_wait_DCT(dev, i, index_reg, 0x04, pDCTstat->CH_ADDR_TMG[i]); /* Channel A/B Output Driver Compensation Control */ } return pDCTstat->ErrCode; @@ -6091,11 +6123,11 @@ void ProgDramMRSReg_D(struct MCTStatStruc *pMCTstat, DramMRS |= 1 << 1; dword = Get_NB32_DCT(pDCTstat->dev_dct, dct, 0x84); + dword |= DramMRS; if (is_fam15h()) dword &= ~0x00800003; else dword &= ~0x00fc2f8f; - dword |= DramMRS; Set_NB32_DCT(pDCTstat->dev_dct, dct, 0x84, dword); } diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c index 99cccb8..e352886 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c @@ -92,8 +92,13 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA) uint8_t sync_flood_on_dram_err[MAX_NODES_SUPPORTED]; uint8_t sync_flood_on_any_uc_err[MAX_NODES_SUPPORTED]; + uint8_t redirect_ecc_scrub = 0; + mctHookBeforeECC(); + if ((pMCTstat->GStatus & 1 << GSB_ECCDIMMs) && mctGet_NVbits(NV_ECCRedir)) + redirect_ecc_scrub = 1; + /* Construct these booleans, based on setup options, for easy handling later in this procedure */ OB_NBECC = mctGet_NVbits(NV_NBECC); /* MCA ECC (MCE) enable bit */ @@ -230,12 +235,12 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA) } dev = pDCTstat->dev_nbmisc; val = curBase << 8; - if(OB_ECCRedir) { - val |= (1<<0); /* enable redirection */ + if (OB_ECCRedir) { + val |= (1<<0); /* enable redirection */ } - Set_NB32(dev, 0x5C, val); /* Dram Scrub Addr Low */ + Set_NB32(dev, 0x5c, val); /* Dram Scrub Addr Low */ val = curBase>>24; - Set_NB32(dev, 0x60, val); /* Dram Scrub Addr High */ + Set_NB32(dev, 0x60, val); /* Dram Scrub Addr High */ Set_NB32(dev, 0x58, OF_ScrubCTL); /*Scrub Control */ if (!is_fam15h()) { @@ -252,6 +257,32 @@ u8 ECCInit_D(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstatA) } } } + + if (is_fam15h()) { + uint8_t dct; + + /* Disable training mode + * See fam15EnableTrainingMode for the non-ECC training mode tear-down code + */ + for (dct = 0; dct < 2; dct++) { + /* NOTE: Reads use DCT 0 and writes use the current DCT per Erratum 505 */ + dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, 0, 0x58); /* Scrub Rate Control */ + dword &= ~(0x1f << 24); /* L3Scrub = NV_L3BKScrub */ + dword |= (mctGet_NVbits(NV_L3BKScrub) & 0x1f) << 24; + dword &= ~(0x1f); /* DramScrub = NV_DramBKScrub */ + dword |= mctGet_NVbits(NV_DramBKScrub) & 0x1f; + Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x58, dword); /* Scrub Rate Control */ + + dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c); /* DRAM Scrub Address Low */ + dword &= ~(0x1); /* ScrubReDirEn = redirect_ecc_scrub */ + dword |= redirect_ecc_scrub & 0x1; + Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x5c, dword); /* DRAM Scrub Address Low */ + + dword = Get_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8); /* L3 Control 1 */ + dword &= ~(0x1 << 4); /* L3ScrbRedirDis = 0 */ + Set_NB32_DCT(pDCTstat->dev_nbmisc, dct, 0x1b8, dword); /* L3 Control 1 */ + } + } } /* this node has ECC enabled dram */ } /*Node has Dram */ } /*if Node present */ diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c index 5ef4a2c..32b447f 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c @@ -23,7 +23,27 @@ u32 mct_SetDramConfigMisc2(struct DCTStatStruc *pDCTstat, u8 dct, u32 misc2) { u32 val; - if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx)) { + /* FIXME + * Mainboards need to be able to specify the maximum number of DIMMs installable per channel + * For now assume a maximum of 2 DIMMs per channel can be installed + */ + uint8_t MaxDimmsInstallable = 2; + + if (pDCTstat->LogicalCPUID & AMD_FAM15_ALL) { + uint8_t cs_mux_45; + uint8_t cs_mux_67; + + /* BKDG v3.14 Table 200 / Table 201 */ + if (MaxDimmsInstallable < 3) { + cs_mux_45 = 1; + cs_mux_67 = 1; + } else { + cs_mux_45 = 0; + cs_mux_67 = 0; + } + misc2 |= (cs_mux_45 & 0x1) << 26; + misc2 |= (cs_mux_67 & 0x1) << 27; + } else if (pDCTstat->LogicalCPUID & (AMD_DR_Dx | AMD_DR_Cx)) { if (pDCTstat->Status & (1 << SB_Registered)) { misc2 |= 1 << SubMemclkRegDly; if (mctGet_NVbits(NV_MAX_DIMMS) == 8) diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c index cbb34dc..3995a70 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c @@ -209,7 +209,8 @@ void AgesaHwWlPhase2(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTsta 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); if (abs(total_delay_phy - total_delay_seed) > 0x20) { - printk(BIOS_DEBUG, "%s: overriding faulty phy value\n", __func__); + printk(BIOS_DEBUG, "%s: overriding faulty phy value (seed: %04x phy: %04x step: %04x)\n", __func__, + total_delay_seed, total_delay_phy, abs(total_delay_phy - total_delay_seed)); pDCTData->WLGrossDelay[index+ByteLane] = pDCTData->WLSeedGrossDelay[index+ByteLane]; pDCTData->WLFineDelay[index+ByteLane] = pDCTData->WLSeedFineDelay[index+ByteLane]; } -- 1.7.9.5