summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mct_d.c144
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctecc_d.c39
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mctproc.c22
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c3
4 files changed, 147 insertions, 61 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
index 1312b34bce..24d6c6c8a2 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
@@ -1517,11 +1517,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++) {
@@ -1714,7 +1715,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;
@@ -1752,9 +1752,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;
@@ -1946,21 +1943,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.
@@ -2002,11 +1988,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 */
}
}
@@ -2111,6 +2103,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();
}
@@ -2357,6 +2362,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)){
@@ -2377,6 +2383,18 @@ static void MCTMemClr_D(struct MCTStatStruc *pMCTstat,
}
}
}
+
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ pDCTstat = pDCTstatA + 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,
@@ -2384,48 +2402,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)
@@ -3366,8 +3395,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 */
@@ -3422,9 +3451,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()) */
@@ -4132,8 +4167,7 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
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
@@ -4331,8 +4365,8 @@ static u8 mct_PlatformSpec(struct MCTStatStruc *pMCTstat,
}
for (i=i_start; i<i_end; i++) {
index_reg = 0x98;
- Set_NB32_index_wait_DCT(dev, i, index_reg, 0x00, pDCTstat->CH_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;
@@ -6130,11 +6164,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 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 */
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
index a86c319a88..77acaec3a4 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mctproc.c
@@ -19,7 +19,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 f3915a2438..48b72caf36 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mhwlc_d.c
@@ -205,7 +205,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];
}