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.c145
1 files changed, 119 insertions, 26 deletions
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
index 0718477872..ad0e6e807b 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
@@ -35,7 +35,8 @@
static u8 ReconfigureDIMMspare_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstatA);
static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstatA);
+ struct DCTStatStruc *pDCTstatA,
+ uint8_t allow_config_restore);
static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstatA);
static void HTMemMapInit_D(struct MCTStatStruc *pMCTstat,
@@ -1169,6 +1170,30 @@ static void read_spd_bytes(struct MCTStatStruc *pMCTstat,
}
}
+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
+static void calculate_and_store_spd_hashes(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ uint8_t dimm;
+
+ for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
+ calculate_spd_hash(pDCTstat->spd_data.spd_bytes[dimm], &pDCTstat->spd_data.spd_hash[dimm]);
+ }
+}
+
+static void compare_nvram_spd_hashes(struct MCTStatStruc *pMCTstat,
+ struct DCTStatStruc *pDCTstat)
+{
+ uint8_t dimm;
+
+ pDCTstat->spd_data.nvram_spd_match = 1;
+ for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++) {
+ if (pDCTstat->spd_data.spd_hash[dimm] != pDCTstat->spd_data.nvram_spd_hash[dimm])
+ pDCTstat->spd_data.nvram_spd_match = 0;
+ }
+}
+#endif
+
static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstatA)
{
@@ -1217,6 +1242,8 @@ static void mctAutoInitMCT_D(struct MCTStatStruc *pMCTstat,
*/
u8 Node, NodesWmem;
u32 node_sys_base;
+ uint8_t nvram;
+ uint8_t allow_config_restore;
uint8_t s3resume = acpi_is_wakeup_s3();
@@ -1233,7 +1260,8 @@ restartinit:
#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DCT configuration from NVRAM\n");
- restore_mct_information_from_nvram();
+ if (restore_mct_information_from_nvram(0) != 0)
+ printk(BIOS_CRIT, "%s: ERROR: Unable to restore DCT configuration from NVRAM\n", __func__);
#endif
printk(BIOS_DEBUG, "mctAutoInitMCT_D: mct_ForceNBPState0_Dis_Fam15\n");
@@ -1283,11 +1311,26 @@ restartinit:
node_sys_base += (pDCTstat->NodeSysLimit + 2) & ~0x0F;
}
+ /* If the boot fails make sure training is attempted after reset */
+ nvram = 0;
+ set_option("allow_spd_nvram_cache_restore", &nvram);
+
#if IS_ENABLED(DIMM_VOLTAGE_SET_SUPPORT)
printk(BIOS_DEBUG, "%s: DIMMSetVoltage\n", __func__);
DIMMSetVoltages(pMCTstat, pDCTstatA); /* Set the DIMM voltages (mainboard specific) */
#endif
+ /* If DIMM configuration has not changed since last boot restore training values */
+ allow_config_restore = 1;
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+
+ if (pDCTstat->NodePresent)
+ if (!pDCTstat->spd_data.nvram_spd_match)
+ allow_config_restore = 0;
+ }
+
for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
struct DCTStatStruc *pDCTstat;
pDCTstat = pDCTstatA + Node;
@@ -1321,14 +1364,33 @@ restartinit:
CPUMemTyping_D(pMCTstat, pDCTstatA); /* Map dram into WB/UC CPU cacheability */
mctHookAfterCPU(); /* Setup external northbridge(s) */
+ /* FIXME
+ * Previous training values should only be used if the current desired
+ * speed is the same as the speed used in the previous boot.
+ * How to get the desired speed at this point in the code?
+ */
+#if 0
+ for (Node = 0; Node < MAX_NODES_SUPPORTED; Node++) {
+ struct DCTStatStruc *pDCTstat;
+ pDCTstat = pDCTstatA + Node;
+
+ if (pDCTstat->NodePresent) {
+ if (pDCTstat->spd_data.nvram_memclk[0] != pDCTstat->DIMMAutoSpeed)
+ allow_config_restore = 0;
+ }
+ }
+#endif
+
printk(BIOS_DEBUG, "mctAutoInitMCT_D: DQSTiming_D\n");
- DQSTiming_D(pMCTstat, pDCTstatA); /* Get Receiver Enable and DQS signal timing*/
+ DQSTiming_D(pMCTstat, pDCTstatA, allow_config_restore); /* Get Receiver Enable and DQS signal timing*/
printk(BIOS_DEBUG, "mctAutoInitMCT_D: UMAMemTyping_D\n");
UMAMemTyping_D(pMCTstat, pDCTstatA); /* Fix up for UMA sizing */
- printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
- mct_OtherTiming(pMCTstat, pDCTstatA);
+ if (!allow_config_restore) {
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: :OtherTiming\n");
+ mct_OtherTiming(pMCTstat, pDCTstatA);
+ }
if (ReconfigureDIMMspare_D(pMCTstat, pDCTstatA)) { /* RESET# if 1st pass of DIMM spare enabled*/
goto restartinit;
@@ -1810,7 +1872,7 @@ static void exit_training_mode_fam15(struct MCTStatStruc *pMCTstat,
}
static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
- struct DCTStatStruc *pDCTstatA)
+ struct DCTStatStruc *pDCTstatA, uint8_t allow_config_restore)
{
u8 nv_DQSTrainCTL;
@@ -1818,9 +1880,8 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
return;
}
- nv_DQSTrainCTL = mctGet_NVbits(NV_DQSTrainCTL);
- /* FIXME: BOZO- DQS training every time*/
- nv_DQSTrainCTL = 1;
+ // nv_DQSTrainCTL = mctGet_NVbits(NV_DQSTrainCTL);
+ nv_DQSTrainCTL = !allow_config_restore;
mct_BeforeDQSTrain_D(pMCTstat, pDCTstatA);
phyAssistedMemFnceTraining(pMCTstat, pDCTstatA);
@@ -1839,15 +1900,16 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
}
}
+ mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
+ if (!is_fam15h()) {
+ /* TODO: should be in mctHookBeforeAnyTraining */
+ _WRMSR(0x26C, 0x04040404, 0x04040404);
+ _WRMSR(0x26D, 0x04040404, 0x04040404);
+ _WRMSR(0x26E, 0x04040404, 0x04040404);
+ _WRMSR(0x26F, 0x04040404, 0x04040404);
+ }
+
if (nv_DQSTrainCTL) {
- mctHookBeforeAnyTraining(pMCTstat, pDCTstatA);
- if (!is_fam15h()) {
- /* TODO: should be in mctHookBeforeAnyTraining */
- _WRMSR(0x26C, 0x04040404, 0x04040404);
- _WRMSR(0x26D, 0x04040404, 0x04040404);
- _WRMSR(0x26E, 0x04040404, 0x04040404);
- _WRMSR(0x26F, 0x04040404, 0x04040404);
- }
mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass);
if (is_fam15h()) {
@@ -1877,18 +1939,26 @@ static void DQSTiming_D(struct MCTStatStruc *pMCTstat,
exit_training_mode_fam15(pMCTstat, pDCTstatA);
else
mctSetEccDQSRcvrEn_D(pMCTstat, pDCTstatA);
+ } else {
+ mct_WriteLevelization_HW(pMCTstat, pDCTstatA, FirstPass);
- /* FIXME - currently uses calculated value TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
- mctHookAfterAnyTraining();
- mctSaveDQSSigTmg_D();
+ mct_WriteLevelization_HW(pMCTstat, pDCTstatA, SecondPass);
- MCTMemClr_D(pMCTstat, pDCTstatA);
- } else {
- mctGetDQSSigTmg_D(); /* get values into data structure */
- LoadDQSSigTmgRegs_D(pMCTstat, pDCTstatA); /* load values into registers.*/
- /* mctDoWarmResetMemClr_D(); */
- MCTMemClr_D(pMCTstat, pDCTstatA);
+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
+ printk(BIOS_DEBUG, "mctAutoInitMCT_D: Restoring DIMM training configuration from NVRAM\n");
+ if (restore_mct_information_from_nvram(1) != 0)
+ printk(BIOS_CRIT, "%s: ERROR: Unable to restore DCT configuration from NVRAM\n", __func__);
+#endif
+
+ if (is_fam15h())
+ exit_training_mode_fam15(pMCTstat, pDCTstatA);
}
+
+ /* FIXME - currently uses calculated value TrainMaxReadLatency_D(pMCTstat, pDCTstatA); */
+ mctHookAfterAnyTraining();
+
+ /* mctDoWarmResetMemClr_D(); */
+ MCTMemClr_D(pMCTstat, pDCTstatA);
}
static void LoadDQSSigTmgRegs_D(struct MCTStatStruc *pMCTstat,
@@ -3898,6 +3968,8 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
struct DCTStatStruc *pDCTstat)
{
u8 err_code;
+ uint8_t nvram;
+ uint8_t allow_config_restore;
/* Preconfigure DCT0 */
DCTPreInit_D(pMCTstat, pDCTstat, 0);
@@ -3912,6 +3984,27 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
pDCTstat->ErrCode = err_code; /* Using DCT0 Error code to update pDCTstat.ErrCode */
}
}
+
+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
+ calculate_and_store_spd_hashes(pMCTstat, pDCTstat);
+
+ if (load_spd_hashes_from_nvram(pDCTstat) < 0) {
+ pDCTstat->spd_data.nvram_spd_match = 0;
+ }
+ else {
+ compare_nvram_spd_hashes(pMCTstat, pDCTstat);
+ }
+#else
+ pDCTstat->spd_data.nvram_spd_match = 0;
+#endif
+
+ /* Check to see if restoration of SPD data from NVRAM is allowed */
+ allow_config_restore = 0;
+ if (get_option(&nvram, "allow_spd_nvram_cache_restore") == CB_SUCCESS)
+ allow_config_restore = !!nvram;
+
+ if (!allow_config_restore)
+ pDCTstat->spd_data.nvram_spd_match = 0;
}
static void mct_initDCT(struct MCTStatStruc *pMCTstat,