aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mainboard/asus/kgpe-d16/cmos.layout1
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mct_d.c145
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/mct_d.h6
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/s3utils.c175
-rw-r--r--src/northbridge/amd/amdmct/mct_ddr3/s3utils.h10
-rw-r--r--src/northbridge/amd/amdmct/wrappers/mcti_d.c4
6 files changed, 289 insertions, 52 deletions
diff --git a/src/mainboard/asus/kgpe-d16/cmos.layout b/src/mainboard/asus/kgpe-d16/cmos.layout
index 264c893a76..b64a85b2a7 100644
--- a/src/mainboard/asus/kgpe-d16/cmos.layout
+++ b/src/mainboard/asus/kgpe-d16/cmos.layout
@@ -38,6 +38,7 @@ entries
458 4 e 11 hypertransport_speed_limit
462 2 e 12 minimum_memory_voltage
464 1 e 2 compute_unit_siblings
+465 1 r 0 allow_spd_nvram_cache_restore
477 1 e 1 ieee1394_controller
728 256 h 0 user_data
984 16 h 0 check_sum
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,
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
index e6b427ed7b..1ac7bbfe62 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
@@ -321,6 +321,10 @@ struct MCTStatStruc {
struct amd_spd_node_data {
uint8_t spd_bytes[MAX_DIMMS_SUPPORTED][256]; /* [DIMM][byte] */
uint8_t spd_address[MAX_DIMMS_SUPPORTED]; /* [DIMM] */
+ uint64_t spd_hash[MAX_DIMMS_SUPPORTED]; /* [DIMM] */
+ uint64_t nvram_spd_hash[MAX_DIMMS_SUPPORTED]; /* [DIMM] */
+ uint8_t nvram_spd_match;
+ uint8_t nvram_memclk[2]; /* [channel] */
} __attribute__((packed));
struct DCTStatStruc { /* A per Node structure*/
@@ -780,6 +784,8 @@ struct amd_s3_persistent_mct_channel_data {
struct amd_s3_persistent_node_data {
uint32_t node_present;
+ uint64_t spd_hash[MAX_DIMMS_SUPPORTED];
+ uint8_t memclk[2];
struct amd_s3_persistent_mct_channel_data channel[2];
} __attribute__((packed));
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
index 3c2043be54..c4410443e0 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
@@ -22,8 +22,10 @@
#include <device/pci_ops.h>
#include <console/console.h>
#include <cbfs.h>
+#include <cbmem.h>
#include <spi-generic.h>
#include <spi_flash.h>
+#include <pc80/mc146818rtc.h>
#include "s3utils.h"
@@ -120,6 +122,68 @@ static uint32_t read_amd_dct_index_register_dct(device_t dev, uint8_t node, uint
return read_amd_dct_index_register(dev, index_ctl_reg, index);
}
+/* Non-cryptographic 64-bit hash function taken from Stack Overflow:
+ * http://stackoverflow.com/a/13326345
+ * Any 64-bit hash with sufficiently low collision potential
+ * could be used instead.
+ */
+void calculate_spd_hash(uint8_t *spd_data, uint64_t *spd_hash)
+{
+ const unsigned long long prime = 2654435789ULL;
+ uint16_t byte;
+ *spd_hash = 104395301;
+
+ for (byte = 0; byte < 256; byte++)
+ *spd_hash += (spd_data[byte] * prime) ^ (*spd_hash >> 23);
+
+ *spd_hash = *spd_hash ^ (*spd_hash << 37);
+}
+
+static struct amd_s3_persistent_data * map_s3nv_in_nvram(void)
+{
+ ssize_t s3nv_offset;
+ ssize_t s3nv_file_offset;
+ void * s3nv_cbfs_file_ptr;
+ struct amd_s3_persistent_data *persistent_data;
+
+ /* Obtain CBFS file offset */
+ s3nv_offset = get_s3nv_file_offset();
+ if (s3nv_offset == -1)
+ return NULL;
+
+ /* Align flash pointer to nearest boundary */
+ s3nv_file_offset = s3nv_offset;
+ s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
+ s3nv_offset += CONFIG_S3_DATA_SIZE;
+ s3nv_file_offset = s3nv_offset - s3nv_file_offset;
+
+ /* Map data structure in CBFS and restore settings */
+ s3nv_cbfs_file_ptr = cbfs_boot_map_with_leak(S3NV_FILE_NAME, CBFS_TYPE_RAW, NULL);
+ if (!s3nv_cbfs_file_ptr) {
+ printk(BIOS_DEBUG, "S3 state file could not be mapped: %s\n", S3NV_FILE_NAME);
+ return NULL;
+ }
+ persistent_data = (s3nv_cbfs_file_ptr + s3nv_file_offset);
+
+ return persistent_data;
+}
+
+#ifdef __PRE_RAM__
+int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat)
+{
+ struct amd_s3_persistent_data *persistent_data;
+
+ persistent_data = map_s3nv_in_nvram();
+ if (!persistent_data)
+ return -1;
+
+ memcpy(pDCTstat->spd_data.nvram_spd_hash, persistent_data->node[pDCTstat->Node_ID].spd_hash, sizeof(pDCTstat->spd_data.nvram_spd_hash));
+ memcpy(pDCTstat->spd_data.nvram_memclk, persistent_data->node[pDCTstat->Node_ID].memclk, sizeof(pDCTstat->spd_data.nvram_memclk));
+
+ return 0;
+}
+#endif
+
#ifdef __RAMSTAGE__
static uint64_t rdmsr_uint64_t(unsigned long index) {
msr_t msr = rdmsr(index);
@@ -145,6 +209,31 @@ static uint32_t read_config32_dct_nbpstate(device_t dev, uint8_t node, uint8_t d
return pci_read_config32(dev, reg);
}
+static void copy_cbmem_spd_data_to_save_variable(struct amd_s3_persistent_data* persistent_data)
+{
+ uint8_t node;
+ uint8_t dimm;
+ uint8_t channel;
+ struct amdmct_memory_info *mem_info;
+ mem_info = cbmem_find(CBMEM_ID_AMDMCT_MEMINFO);
+ if (mem_info == NULL) {
+ /* can't find amdmct information in cbmem */
+ for (node = 0; node < MAX_NODES_SUPPORTED; node++)
+ for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++)
+ persistent_data->node[node].spd_hash[dimm] = 0xffffffffffffffffULL;
+
+ return;
+ }
+
+ for (node = 0; node < MAX_NODES_SUPPORTED; node++)
+ for (dimm = 0; dimm < MAX_DIMMS_SUPPORTED; dimm++)
+ calculate_spd_hash(mem_info->dct_stat[node].spd_data.spd_bytes[dimm], &persistent_data->node[node].spd_hash[dimm]);
+
+ for (node = 0; node < MAX_NODES_SUPPORTED; node++)
+ for (channel = 0; channel < 2; channel++)
+ persistent_data->node[node].memclk[channel] = mem_info->dct_stat[node].Speed;
+}
+
void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_data)
{
uint8_t i;
@@ -437,7 +526,7 @@ static void wrmsr_uint64_t(unsigned long index, uint64_t value) {
wrmsr(index, msr);
}
-void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persistent_data)
+void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persistent_data, uint8_t training_only)
{
uint8_t i;
uint8_t j;
@@ -447,6 +536,51 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
uint8_t dct_enabled;
uint32_t dword;
+ if (training_only) {
+ /* Only restore the Receiver Enable and DQS training registers */
+ for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
+ for (channel = 0; channel < 2; channel++) {
+ struct amd_s3_persistent_mct_channel_data* data = &persistent_data->node[node].channel[channel];
+ if (!persistent_data->node[node].node_present)
+ continue;
+
+ /* Restore training parameters */
+ for (i=0; i<4; i++)
+ for (j=0; j<3; j++)
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, (0x01 + i) + (0x100 * j), data->f2x9cx3_0_0_3_1[i][j]);
+ for (i=0; i<4; i++)
+ for (j=0; j<3; j++)
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, (0x05 + i) + (0x100 * j), data->f2x9cx3_0_0_7_5[i][j]);
+
+ for (i=0; i<12; i++)
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x10 + i, data->f2x9cx10[i]);
+ for (i=0; i<12; i++)
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x20 + i, data->f2x9cx20[i]);
+
+ if (IS_ENABLED(CONFIG_DIMM_DDR3)) {
+ for (i=0; i<12; i++)
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x30 + i, data->f2x9cx30[i]);
+ for (i=0; i<12; i++)
+ write_amd_dct_index_register_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x98, 0x40 + i, data->f2x9cx40[i]);
+ }
+
+ /* Restore MaxRdLatency */
+ if (is_fam15h()) {
+ for (i=0; i<4; i++)
+ write_config32_dct_nbpstate(PCI_DEV(0, 0x18 + node, 2), node, channel, i, 0x210, data->f2x210[i]);
+ }
+ else {
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x78, data->f2x78);
+ }
+
+ /* Other timing control registers */
+ write_config32_dct(PCI_DEV(0, 0x18 + node, 2), node, channel, 0x8c, data->f2x8c);
+ }
+ }
+
+ return;
+ }
+
/* Load data from data structure into DCTs */
/* Stage 1 */
for (node = 0; node < MAX_NODES_SUPPORTED; node++) {
@@ -497,7 +631,8 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
wrmsr_uint64_t(0x00000250, data->msr00000250);
wrmsr_uint64_t(0x00000258, data->msr00000258);
/* FIXME
- * Restoring these MSRs causes a hang on resume
+ * Restoring these MSRs causes a hang on resume due to
+ * destroying CAR while still executing from CAR!
* For now, skip restoration...
*/
// for (i=0; i<8; i++)
@@ -886,6 +1021,8 @@ void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persiste
#ifdef __RAMSTAGE__
int8_t save_mct_information_to_nvram(void)
{
+ uint8_t nvram;
+
if (acpi_is_wakeup_s3())
return 0;
@@ -905,6 +1042,9 @@ int8_t save_mct_information_to_nvram(void)
/* Obtain MCT configuration data */
copy_mct_data_to_save_variable(persistent_data);
+ /* Save RAM SPD data at the same time */
+ copy_cbmem_spd_data_to_save_variable(persistent_data);
+
/* Obtain CBFS file offset */
s3nv_offset = get_s3nv_file_offset();
if (s3nv_offset == -1)
@@ -945,36 +1085,23 @@ int8_t save_mct_information_to_nvram(void)
/* Restore SPI MMIO address */
pci_write_config32(lpc_dev, 0xa0, spi_mmio_prev);
+ /* Allow training bypass if DIMM configuration is unchanged on next boot */
+ nvram = 1;
+ set_option("allow_spd_nvram_cache_restore", &nvram);
+
return 0;
}
#endif
-int8_t restore_mct_information_from_nvram(void)
+int8_t restore_mct_information_from_nvram(uint8_t training_only)
{
- ssize_t s3nv_offset;
- ssize_t s3nv_file_offset;
- void * s3nv_cbfs_file_ptr;
struct amd_s3_persistent_data *persistent_data;
- /* Obtain CBFS file offset */
- s3nv_offset = get_s3nv_file_offset();
- if (s3nv_offset == -1)
+ persistent_data = map_s3nv_in_nvram();
+ if (!persistent_data)
return -1;
- /* Align flash pointer to nearest boundary */
- s3nv_file_offset = s3nv_offset;
- s3nv_offset &= ~(CONFIG_S3_DATA_SIZE-1);
- s3nv_offset += CONFIG_S3_DATA_SIZE;
- s3nv_file_offset = s3nv_offset - s3nv_file_offset;
-
- /* Map data structure in CBFS and restore settings */
- s3nv_cbfs_file_ptr = cbfs_boot_map_with_leak(S3NV_FILE_NAME, CBFS_TYPE_RAW, NULL);
- if (!s3nv_cbfs_file_ptr) {
- printk(BIOS_DEBUG, "S3 state file could not be mapped: %s\n", S3NV_FILE_NAME);
- return -1;
- }
- persistent_data = (s3nv_cbfs_file_ptr + s3nv_file_offset);
- restore_mct_data_from_save_variable(persistent_data);
+ restore_mct_data_from_save_variable(persistent_data, training_only);
return 0;
-} \ No newline at end of file
+}
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
index 5370496615..56e627e413 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
@@ -16,9 +16,15 @@
#include "../wrappers/mcti.h"
#include "mct_d.h"
+void calculate_spd_hash(uint8_t *spd_data, uint64_t *spd_hash);
+
+#ifdef __PRE_RAM__
+int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat);
+#endif
+
#ifdef __RAMSTAGE__
int8_t save_mct_information_to_nvram(void);
#endif
-int8_t restore_mct_information_from_nvram(void);
+int8_t restore_mct_information_from_nvram(uint8_t training_only);
void copy_mct_data_to_save_variable(struct amd_s3_persistent_data* persistent_data);
-void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persistent_data); \ No newline at end of file
+void restore_mct_data_from_save_variable(struct amd_s3_persistent_data* persistent_data, uint8_t training_only);
diff --git a/src/northbridge/amd/amdmct/wrappers/mcti_d.c b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
index 48ab8007ab..a030f71e95 100644
--- a/src/northbridge/amd/amdmct/wrappers/mcti_d.c
+++ b/src/northbridge/amd/amdmct/wrappers/mcti_d.c
@@ -396,14 +396,18 @@ static void mctHookAfterCPU(void)
}
+#if IS_ENABLED(CONFIG_DIMM_DDR2)
static void mctSaveDQSSigTmg_D(void)
{
}
+#endif
+#if IS_ENABLED(CONFIG_DIMM_DDR2)
static void mctGetDQSSigTmg_D(void)
{
}
+#endif
static void mctHookBeforeECC(void)