diff options
author | Timothy Pearson <tpearson@raptorengineeringinc.com> | 2015-06-24 19:15:09 -0500 |
---|---|---|
committer | Stefan Reinauer <stefan.reinauer@coreboot.org> | 2015-11-15 02:43:22 +0100 |
commit | eb2f6fff3265b5be87e2dfc9e69ad465c742ec8c (patch) | |
tree | e4416a4bad6419eea3e8415b35c82a16fc304cbf /src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c | |
parent | 876bdd4ab3591079d3ffa5b9b0fb6080098ea769 (diff) |
northbridge/amd/amdmct/mct_ddr3: Fix lockups and wasted time during ECC init
The existing ECC initialization algorithm contained several bugs on both
Family 10h and Family 15h processors, including activation of ECC scrub
before DRAM setup was completed, in violation of both BKDG and errata
recommendations.
Change-Id: I09a8ea83024186b7ece7d78a4bef1201ab34ff8a
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
Reviewed-on: http://review.coreboot.org/12002
Tested-by: build bot (Jenkins)
Reviewed-by: Alexandru Gagniuc <mr.nuke.me@gmail.com>
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c')
-rw-r--r-- | src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c index 8701baebf7..1be46b1351 100644 --- a/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c +++ b/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c @@ -88,8 +88,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 */ @@ -226,12 +231,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()) { @@ -248,6 +253,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 */ |