soc/intel/cse: Implement APIs to access PSR backup status in CMOS

PSR data is created and stored in CSE data partition. In platforms that
employ CSE Lite SKU firmware, a firmware downgrade involves clearing of
CSE data partition which results in PSR data being lost. The PSR data
needs to be preserved across the firmware downgrade flow. CSE Lite SKU
firmware supports command to backup PSR data. Since firmware downgrade
and PSR data backup flows involve global resets, there is a need to
track the PSR data backup status across resets. So adding a CMOS
variable for the same.

This patch implements API to access PSR backup status stored in CMOS.
The get API allows to retrieve the PSR backup status from CMOS memory.
The update API allows to update the PSR backup status in CMOS.

BRANCH=None
BUG=b:273207144
TEST=Able to retrieve PSR backup status across resets.

Change-Id: I270894e3e08dd50ca88e5402b59c211d7e693d14
Signed-off-by: Krishna Prasad Bhat <krishna.p.bhat.d@intel.com>
Signed-off-by: Rizwan Qureshi <rizwan.qureshi@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/77069
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Kapil Porwal <kapilporwal@google.com>
Reviewed-by: Subrata Banik <subratabanik@google.com>
diff --git a/src/soc/intel/common/block/cse/cse_lite_cmos.c b/src/soc/intel/common/block/cse/cse_lite_cmos.c
index 5fc3fb0..02d0232 100644
--- a/src/soc/intel/common/block/cse/cse_lite_cmos.c
+++ b/src/soc/intel/common/block/cse/cse_lite_cmos.c
@@ -37,6 +37,8 @@
 # endif
 #endif
 
+#define PSR_BACKUP_STATUS_SIGNATURE 0x42525350	/* 'PSRB' */
+
 /* Helper function to read CSE fpt information from cmos memory. */
 void cmos_read_fw_partition_info(struct cse_specific_info *info)
 {
@@ -50,3 +52,70 @@
 	for (uint8_t *p = (uint8_t *)info, i = 0; i < sizeof(*info); i++, p++)
 		cmos_write(*p, PARTITION_FW_CMOS_OFFSET + i);
 }
+
+/* Read and validate `psr_backup_status` structure from CMOS */
+static int psr_backup_status_cmos_read(struct psr_backup_status *psr)
+{
+	for (uint8_t *p = (uint8_t *)psr, i = 0; i < sizeof(*psr); i++, p++)
+		*p = cmos_read(PARTITION_FW_CMOS_OFFSET + sizeof(struct cse_specific_info) + i);
+
+	/* Verify signature */
+	if (psr->signature != PSR_BACKUP_STATUS_SIGNATURE) {
+		printk(BIOS_ERR, "PSR backup status invalid signature\n");
+		return -1;
+	}
+
+	/* Verify checksum over signature and backup_status only */
+	uint16_t csum = compute_ip_checksum(psr, offsetof(struct psr_backup_status, checksum));
+
+	if (csum != psr->checksum) {
+		printk(BIOS_ERR, "PSR backup status checksum mismatch\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/* Write `psr_backup_status structure` to CMOS */
+static void psr_backup_status_cmos_write(struct psr_backup_status *psr)
+{
+	/* Checksum over signature and backup_status only */
+	psr->checksum = compute_ip_checksum(
+		psr, offsetof(struct psr_backup_status, checksum));
+
+	for (uint8_t *p = (uint8_t *)psr, i = 0; i < sizeof(*psr); i++, p++)
+		cmos_write(*p, PARTITION_FW_CMOS_OFFSET + sizeof(struct cse_specific_info) + i);
+}
+
+/* Helper function to update the `psr_backup_status` in CMOS memory */
+void update_psr_backup_status(int8_t status)
+{
+	struct psr_backup_status psr;
+
+	/* Read and update psr_backup_status */
+	if (psr_backup_status_cmos_read(&psr) < 0)
+		/* Structure invalid, re-initialize */
+		psr.signature = PSR_BACKUP_STATUS_SIGNATURE;
+
+	psr.value = status;
+
+	/* Write the new status to CMOS */
+	psr_backup_status_cmos_write(&psr);
+
+	printk(BIOS_INFO, "PSR backup status updated\n");
+}
+
+/*
+ * Helper function to retrieve the current `psr_backup_status` in CMOS memory
+ * Returns current status on success, the status can be PSR_BACKUP_DONE or PSR_BACKUP_PENDING.
+ * Returns -1 in case of signature mismatch or checksum failure.
+ */
+int8_t get_psr_backup_status(void)
+{
+	struct psr_backup_status psr;
+
+	if (psr_backup_status_cmos_read(&psr) < 0)
+		return -1;
+
+	return psr.value;
+}
diff --git a/src/soc/intel/common/block/cse/cse_lite_cmos.h b/src/soc/intel/common/block/cse/cse_lite_cmos.h
index a6dd6ce7..c8cd6e3 100644
--- a/src/soc/intel/common/block/cse/cse_lite_cmos.h
+++ b/src/soc/intel/common/block/cse/cse_lite_cmos.h
@@ -11,4 +11,14 @@
 /* Helper function to write CSE fpt information to cmos memory. */
 void cmos_write_fw_partition_info(const struct cse_specific_info *info);
 
+/* Helper function to update the `psr_backup_status` in CMOS memory */
+void update_psr_backup_status(int8_t status);
+
+/*
+ * Helper function to retrieve the current `psr_backup_status` in CMOS memory
+ * Returns current status on success, the status can be PSR_BACKUP_DONE or PSR_BACKUP_PENDING.
+ * Returns -1 in case of signature mismatch or checksum failure.
+ */
+int8_t get_psr_backup_status(void);
+
 #endif /* SOC_INTEL_COMMON_BLOCK_CSE_LITE_CMOS_H */
diff --git a/src/soc/intel/common/block/include/intelblocks/cse.h b/src/soc/intel/common/block/include/intelblocks/cse.h
index 0f73568..ebf20ed 100644
--- a/src/soc/intel/common/block/include/intelblocks/cse.h
+++ b/src/soc/intel/common/block/include/intelblocks/cse.h
@@ -167,6 +167,18 @@
 	uint32_t crc;
 };
 
+/* PSR backup status */
+enum psr_backup_state {
+	PSR_BACKUP_DONE	= 0,
+	PSR_BACKUP_PENDING = 1,
+};
+
+struct psr_backup_status {
+	uint32_t signature;
+	int8_t value;
+	uint16_t checksum;
+};
+
 /* CSE RX and TX error status */
 enum cse_tx_rx_status {
 	/*