aboutsummaryrefslogtreecommitdiff
path: root/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/northbridge/amd/amdmct/mct_ddr3/mct_d.c')
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mct_d.c70
1 files changed, 68 insertions, 2 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
index e1c0d4f563..cbe75b60d4 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
@@ -3332,12 +3332,24 @@ static void exit_training_mode_fam15(struct MCTStatStruc *pMCTstat,
static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstatA, uint8_t allow_config_restore)
{
+ uint8_t Node;
u8 nv_DQSTrainCTL;
+ uint8_t retry_requested;
if (pMCTstat->GStatus & (1 << GSB_EnDIMMSpareNW)) {
return;
}
+ /* Set initial TCWL offset to zero */
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ uint8_t dct;
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+ for (dct = 0; dct < 2; dct++)
+ pDCTstat->tcwl_delay[dct] = 0;
+ }
+
+retry_dqs_training_and_levelization:
// nv_DQSTrainCTL = mctGet_NVbits(NV_DQSTrainCTL);
nv_DQSTrainCTL = !allow_config_restore;
@@ -3345,7 +3357,6 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
phyAssistedMemFnceTraining(pMCTstat, pDCTstatA, -1);
if (is_fam15h()) {
- uint8_t Node;
struct DCTStatStruc *pDCTstat;
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
pDCTstat = pDCTstatA + Node;
@@ -3393,6 +3404,59 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
mct_TrainDQSPos_D(pMCTstat, pDCTstatA);
+ /* Determine if DQS training requested a retrain attempt */
+ retry_requested = 0;
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+
+ if (pDCTstat->NodePresent) {
+ if (pDCTstat->TrainErrors & (1 << SB_FatalError)) {
+ die("DIMM training FAILED! Halting system.");
+ }
+ if (pDCTstat->TrainErrors & (1 << SB_RetryConfigTrain)) {
+ retry_requested = 1;
+
+ /* Clear previous errors */
+ pDCTstat->TrainErrors &= ~(1 << SB_RetryConfigTrain);
+ pDCTstat->TrainErrors &= ~(1 << SB_NODQSPOS);
+ pDCTstat->ErrStatus &= ~(1 << SB_RetryConfigTrain);
+ pDCTstat->ErrStatus &= ~(1 << SB_NODQSPOS);
+ }
+ }
+ }
+
+ /* Retry training and levelization if requested */
+ if (retry_requested) {
+ printk(BIOS_DEBUG, "%s: Restarting training on algorithm request\n", __func__);
+ /* Reset frequency to minimum */
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+ if (pDCTstat->NodePresent) {
+ uint8_t original_target_freq = pDCTstat->TargetFreq;
+ uint8_t original_auto_speed = pDCTstat->DIMMAutoSpeed;
+ pDCTstat->TargetFreq = mhz_to_memclk_config(mctGet_NVbits(NV_MIN_MEMCLK));
+ pDCTstat->Speed = pDCTstat->DIMMAutoSpeed = pDCTstat->TargetFreq;
+ SetTargetFreq(pMCTstat, pDCTstatA, Node);
+ pDCTstat->TargetFreq = original_target_freq;
+ pDCTstat->DIMMAutoSpeed = original_auto_speed;
+ }
+ }
+ /* Apply any DIMM timing changes */
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+ if (pDCTstat->NodePresent) {
+ AutoCycTiming_D(pMCTstat, pDCTstat, 0);
+ if (!pDCTstat->GangedMode)
+ if (pDCTstat->DIMMValidDCT[1] > 0)
+ AutoCycTiming_D(pMCTstat, pDCTstat, 1);
+ }
+ }
+ goto retry_dqs_training_and_levelization;
+ }
+
TrainMaxRdLatency_En_D(pMCTstat, pDCTstatA);
if (is_fam15h())
@@ -3417,7 +3481,6 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
}
if (is_fam15h()) {
- uint8_t Node;
struct DCTStatStruc *pDCTstat;
/* Switch DCT control register to DCT 0 per Erratum 505 */
@@ -4268,6 +4331,9 @@ static void SPD2ndTiming(struct MCTStatStruc *pMCTstat,
Tcwl = 0x9;
else
Tcwl = 0x5; /* Power-on default */
+
+ /* Apply offset */
+ Tcwl += pDCTstat->tcwl_delay[dct];
}
/* Program DRAM Timing values */