From fdb1ff9b466c0fb32c019ceeeeefb23e857cf00e Mon Sep 17 00:00:00 2001
From: Timothy Pearson <tpearson@raptorengineeringinc.com>
Date: Wed, 10 Jun 2015 10:46:17 -0500
Subject: [PATCH 054/143] northbridge/amd/amdmct: Verify MCT NVRAM options
 before skipping training

Change-Id: If26e5d148a906d63bd1407b8ffa58f08ae6b4275
Signed-off-by: Timothy Pearson <tpearson@raptorengineeringinc.com>
---
 src/northbridge/amd/amdmct/mct_ddr3/mct_d.c   |    9 ++++++-
 src/northbridge/amd/amdmct/mct_ddr3/mct_d.h   |    2 ++
 src/northbridge/amd/amdmct/mct_ddr3/s3utils.c |   36 ++++++++++++++++++++++++-
 src/northbridge/amd/amdmct/mct_ddr3/s3utils.h |    3 ++-
 4 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
index 3edce9e..4d7e5aa 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.c
@@ -4126,7 +4126,7 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
 #if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
 	calculate_and_store_spd_hashes(pMCTstat, pDCTstat);
 
-	if (load_spd_hashes_from_nvram(pDCTstat) < 0) {
+	if (load_spd_hashes_from_nvram(pMCTstat, pDCTstat) < 0) {
 		pDCTstat->spd_data.nvram_spd_match = 0;
 	}
 	else {
@@ -4141,6 +4141,13 @@ static void mct_preInitDCT(struct MCTStatStruc *pMCTstat,
 	if (get_option(&nvram, "allow_spd_nvram_cache_restore") == CB_SUCCESS)
 		allow_config_restore = !!nvram;
 
+#if IS_ENABLED(CONFIG_HAVE_ACPI_RESUME)
+	if (pMCTstat->nvram_checksum != calculate_nvram_mct_hash())
+		allow_config_restore = 0;
+#else
+	allow_config_restore = 0;
+#endif
+
 	if (!allow_config_restore)
 		pDCTstat->spd_data.nvram_spd_match = 0;
 }
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
index adf89b2..11555ae 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
+++ b/src/northbridge/amd/amdmct/mct_ddr3/mct_d.h
@@ -301,6 +301,7 @@ struct MCTStatStruc {
 	u32 Sub4GCacheTop;	/* If not zero, the 32-bit top of cacheable memory.*/
 	u32 SysLimit;		/* LIMIT[39:8] (system address)*/
 	uint32_t TSCFreq;
+	uint16_t nvram_checksum;
 } __attribute__((packed));
 
 /*=============================================================================
@@ -796,6 +797,7 @@ struct amd_s3_persistent_node_data {
 
 struct amd_s3_persistent_data {
 	struct amd_s3_persistent_node_data node[MAX_NODES_SUPPORTED];
+	uint16_t nvram_checksum;
 } __attribute__((packed));
 
 /*===============================================================================
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
index 1e5c1a0..fe89af1 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.c
@@ -143,6 +143,36 @@ void calculate_spd_hash(uint8_t *spd_data, uint64_t *spd_hash)
 	*spd_hash = *spd_hash ^ (*spd_hash << 37);
 }
 
+uint16_t calculate_nvram_mct_hash(void)
+{
+	uint32_t nvram;
+	uint16_t ret;
+
+	ret = 0;
+	if (get_option(&nvram, "max_mem_clock") == CB_SUCCESS)
+		ret |= nvram & 0xf;
+	if (get_option(&nvram, "minimum_memory_voltage") == CB_SUCCESS)
+		ret |= (nvram & 0x3) << 4;
+	if (get_option(&nvram, "ECC_memory") == CB_SUCCESS)
+		ret |= (nvram & 0x1) << 6;
+	if (get_option(&nvram, "ECC_redirection") == CB_SUCCESS)
+		ret |= (nvram & 0x1) << 7;
+	if (get_option(&nvram, "ecc_scrub_rate") == CB_SUCCESS)
+		ret |= (nvram & 0x1) << 8;
+	if (get_option(&nvram, "interleave_chip_selects") == CB_SUCCESS)
+		ret |= (nvram & 0x1) << 9;
+	if (get_option(&nvram, "interleave_nodes") == CB_SUCCESS)
+		ret |= (nvram & 0x1) << 10;
+	if (get_option(&nvram, "interleave_memory_channels") == CB_SUCCESS)
+		ret |= (nvram & 0x1) << 11;
+	if (get_option(&nvram, "cpu_c_states") == CB_SUCCESS)
+		ret |= (nvram & 0x1) << 12;
+	if (get_option(&nvram, "cpu_cc6_state") == CB_SUCCESS)
+		ret |= (nvram & 0x1) << 13;
+
+	return ret;
+}
+
 static struct amd_s3_persistent_data * map_s3nv_in_nvram(void)
 {
 	ssize_t s3nv_offset;
@@ -173,7 +203,7 @@ static struct amd_s3_persistent_data * map_s3nv_in_nvram(void)
 }
 
 #ifdef __PRE_RAM__
-int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat)
+int8_t load_spd_hashes_from_nvram(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat)
 {
 	struct amd_s3_persistent_data *persistent_data;
 
@@ -184,6 +214,8 @@ int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat)
 	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));
 
+	pMCTstat->nvram_checksum = persistent_data->nvram_checksum;
+
 	return 0;
 }
 #endif
@@ -237,6 +269,8 @@ static void copy_cbmem_spd_data_to_save_variable(struct amd_s3_persistent_data*
 		for (channel = 0; channel < 2; channel++)
 			persistent_data->node[node].memclk[channel] = mem_info->dct_stat[node].Speed;
 
+	persistent_data->nvram_checksum = calculate_nvram_mct_hash();
+
 	if (restored) {
 		if (mem_info->mct_stat.GStatus & (1 << GSB_ConfigRestored))
 			*restored = 1;
diff --git a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
index 82f73a7..74922c4 100644
--- a/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
+++ b/src/northbridge/amd/amdmct/mct_ddr3/s3utils.h
@@ -21,9 +21,10 @@
 #include "mct_d.h"
 
 void calculate_spd_hash(uint8_t *spd_data, uint64_t *spd_hash);
+uint16_t calculate_nvram_mct_hash(void);
 
 #ifdef __PRE_RAM__
-int8_t load_spd_hashes_from_nvram(struct DCTStatStruc *pDCTstat);
+int8_t load_spd_hashes_from_nvram(struct MCTStatStruc *pMCTstat, struct DCTStatStruc *pDCTstat);
 #endif
 
 #ifdef __RAMSTAGE__
-- 
1.7.9.5

