soc/intel/cmn/cse: Store ISH firmware version into CBMEM

The patch stores the ISH in the CBMEM table. It verifies CSE has been
updated by comparing previous and current CSE versions. If it has, the
patch updates the previous CSE version with the current CSE version. It
then updates the CBMEM table with the current ISH version.

BUG=b:273661726
TEST=The current and old CSE and ISH versions are verified on the
google/nissa during cold and warm reboots.

Additionally, version updates are verified by a debug patch that
purposely updated the stored cse version.

Signed-off-by: Dinesh Gehlot <digehlot@google.com>
Change-Id: Ie5c5faf926c75b05d189fb1118020fff024fc3e0
Reviewed-on: https://review.coreboot.org/c/coreboot/+/74208
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Kangheui Won <khwon@chromium.org>
diff --git a/src/soc/intel/common/block/cse/cse_lite.c b/src/soc/intel/common/block/cse/cse_lite.c
index f7ebed0..4cc4f51 100644
--- a/src/soc/intel/common/block/cse/cse_lite.c
+++ b/src/soc/intel/common/block/cse/cse_lite.c
@@ -1236,6 +1236,52 @@
 	return send_get_fpt_partition_info_cmd(id, resp);
 }
 
+/*
+ * Helper function to read ISH version from CSE FPT using HECI command.
+ *
+ * The HECI command only be executed after memory has been initialized.
+ * This is because the command relies on resources that are not available
+ * until DRAM initialization command has been sent.
+ */
+static void store_ish_version(void)
+{
+	if (!ENV_RAMSTAGE)
+		return;
+
+	if (vboot_recovery_mode_enabled())
+		return;
+
+	struct cse_fw_partition_info *version;
+	size_t size = sizeof(struct fw_version);
+	version = cbmem_find(CBMEM_ID_CSE_PARTITION_VERSION);
+	if (version == NULL)
+		return;
+
+	/*
+	 * Compare if stored cse version (from the previous boot) is same as current
+	 * running cse version.
+	 */
+	if (memcmp(&version->ish_partition_info.prev_cse_fw_version,
+		&version->cur_cse_fw_version, sizeof(struct fw_version))) {
+		/*
+		 * Current running CSE version is different than previous stored CSE version
+		 * which could be due to CSE update or rollback, hence, need to send ISHC
+		 * partition info cmd to know the currently running ISH version.
+		 */
+
+		struct fw_version_resp resp;
+		if (cse_get_fpt_partition_info(FPT_PARTITION_NAME_ISHC, &resp) == CB_SUCCESS) {
+			/* Update stored cse version with current version */
+			memcpy(&(version->ish_partition_info.prev_cse_fw_version),
+				&(version->cur_cse_fw_version), size);
+
+			/* Since cse version has been updated, ish version needs to be updated. */
+			memcpy(&(version->ish_partition_info.cur_ish_fw_version),
+				&(resp.manifest_data.version), size);
+		}
+	}
+}
+
 static void ramstage_cse_misc_ops(void *unused)
 {
 	if (acpi_get_sleep_type() == ACPI_S3)
@@ -1245,12 +1291,14 @@
 		cse_fw_sync();
 
 	/*
-	 * Store the CSE RW Firmware Version into CBMEM if ISH partition
+	 * Store the CSE/ISH RW Firmware Version into CBMEM if ISH partition
 	 * is available
 	 */
 	if (CONFIG(SOC_INTEL_STORE_CSE_FPT_PARTITION_VERSION) &&
-			 soc_is_ish_partition_enabled())
+			 soc_is_ish_partition_enabled()) {
 		store_cse_rw_fw_version();
+		store_ish_version();
+	}
 }
 
 BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_EXIT, ramstage_cse_misc_ops, NULL);