drivers/intel/fsp2_0: add option to incorporate platform memory version

On Chrome OS systems a memory setting change is needed to be deployed
without updating the FSP blob proper. Under such conditions one needs
to trigger retrain of the memory. For ease of use provide an option,
FSP_PLATFORM_MEMORY_SETTINGS_VERSIONS, which incorproates the SoC
and mainboard memory setting version number into the FSP version
passed to the platform. The lower 8 bits of the FSP version are the
build number which in practice is normally 0. Use those 8 bits to
include the SoC and mainboard memory settings version. When FSP,
SoC, or mainboard memory setting number is bumped a retrain will be
triggered.

BUG=b:37687843

Change-Id: I6a269dcf654be7a409045cedeea3f82eb641f1d6
Signed-off-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: https://review.coreboot.org/19452
Reviewed-by: Furquan Shaikh <furquan@google.com>
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
Reviewed-by: Duncan Laurie <dlaurie@chromium.org>
diff --git a/src/drivers/intel/fsp2_0/memory_init.c b/src/drivers/intel/fsp2_0/memory_init.c
index 559d83e..424a325 100644
--- a/src/drivers/intel/fsp2_0/memory_init.c
+++ b/src/drivers/intel/fsp2_0/memory_init.c
@@ -281,6 +281,41 @@
 	return CB_SUCCESS;
 }
 
+__attribute__ ((weak))
+uint8_t fsp_memory_mainboard_version(void)
+{
+	return 0;
+}
+
+__attribute__ ((weak))
+uint8_t fsp_memory_soc_version(void)
+{
+	return 0;
+}
+
+/*
+ * Allow SoC and/or mainboard to bump the revision of the FSP setting
+ * number. The FSP spec uses the low 8 bits as the build number. Take over
+ * bits 3:0 for the SoC setting and bits 7:4 for the mainboard. That way
+ * a tweak in the settings will bump the version used to track the cached
+ * setting which triggers retraining when the FSP version hasn't changed, but
+ * the SoC or mainboard settings have.
+ */
+static uint32_t fsp_memory_settings_version(const struct fsp_header *hdr)
+{
+	/* Use the full FSP version by default. */
+	uint32_t ver = hdr->fsp_revision;
+
+	if (!IS_ENABLED(CONFIG_FSP_PLATFORM_MEMORY_SETTINGS_VERSIONS))
+		return ver;
+
+	ver &= ~0xff;
+	ver |= (0xf & fsp_memory_mainboard_version()) << 4;
+	ver |= (0xf & fsp_memory_soc_version()) << 0;
+
+	return ver;
+}
+
 static void do_fsp_memory_init(struct fsp_header *hdr, bool s3wake,
 					const struct memranges *memmap)
 {
@@ -288,9 +323,12 @@
 	fsp_memory_init_fn fsp_raminit;
 	FSPM_UPD fspm_upd, *upd;
 	FSPM_ARCH_UPD *arch_upd;
+	uint32_t fsp_version;
 
 	post_code(0x34);
 
+	fsp_version = fsp_memory_settings_version(hdr);
+
 	upd = (FSPM_UPD *)(hdr->cfg_region_offset + hdr->image_base);
 
 	if (upd->FspUpdHeader.Signature != FSPM_UPD_SIGNATURE)
@@ -305,12 +343,12 @@
 	arch_upd->BootLoaderTolumSize = cbmem_overhead_size();
 
 	/* Fill common settings on behalf of chipset. */
-	if (fsp_fill_common_arch_params(arch_upd, s3wake, hdr->fsp_revision,
+	if (fsp_fill_common_arch_params(arch_upd, s3wake, fsp_version,
 					memmap) != CB_SUCCESS)
 		die("FSPM_ARCH_UPD not found!\n");
 
 	/* Give SoC and mainboard a chance to update the UPD */
-	platform_fsp_memory_init_params_cb(&fspm_upd, hdr->fsp_revision);
+	platform_fsp_memory_init_params_cb(&fspm_upd, fsp_version);
 
 	if (IS_ENABLED(CONFIG_MMA))
 		setup_mma(&fspm_upd.FspmConfig);
@@ -334,7 +372,7 @@
 		die("FspMemoryInit returned an error!\n");
 	}
 
-	do_fsp_post_memory_init(s3wake, hdr->fsp_revision);
+	do_fsp_post_memory_init(s3wake, fsp_version);
 }
 
 /* Load the binary into the memory specified by the info header. */