From 98fb5ffd6b934edd5be7c9ac753d2763dfbafba9 Mon Sep 17 00:00:00 2001 From: Krishna Prasad Bhat Date: Tue, 18 Jul 2023 21:49:17 +0530 Subject: 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 Signed-off-by: Rizwan Qureshi Reviewed-on: https://review.coreboot.org/c/coreboot/+/77069 Tested-by: build bot (Jenkins) Reviewed-by: Kapil Porwal Reviewed-by: Subrata Banik --- src/soc/intel/common/block/cse/cse_lite_cmos.c | 69 ++++++++++++++++++++++ src/soc/intel/common/block/cse/cse_lite_cmos.h | 10 ++++ .../intel/common/block/include/intelblocks/cse.h | 12 ++++ 3 files changed, 91 insertions(+) (limited to 'src/soc/intel/common/block') 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 5fc3fb0e42..02d0232376 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 @@ void cmos_write_fw_partition_info(const struct cse_specific_info *info) 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 a6dd6ce7f2..c8cd6e3d42 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 @@ void cmos_read_fw_partition_info(struct cse_specific_info *info); /* 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 0f7356854d..ebf20ed857 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 @@ struct cse_specific_info { 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 { /* -- cgit v1.2.3