aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineeringinc.com>2015-06-24 19:15:09 -0500
committerStefan Reinauer <stefan.reinauer@coreboot.org>2015-11-15 02:43:22 +0100
commiteb2f6fff3265b5be87e2dfc9e69ad465c742ec8c (patch)
treee4416a4bad6419eea3e8415b35c82a16fc304cbf /src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c
parent876bdd4ab3591079d3ffa5b9b0fb6080098ea769 (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.c39
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 */