| /* SPDX-License-Identifier: GPL-2.0-only */ |
| |
| #include <console/console.h> |
| #include <ip_checksum.h> |
| #include <pc80/mc146818rtc.h> |
| |
| #include "cse_lite_cmos.h" |
| |
| /* |
| * We need a region in CMOS to store the firmware versions. |
| * |
| * This can either be declared as part of the option |
| * table or statically defined in the board config. |
| */ |
| #if CONFIG(USE_OPTION_TABLE) |
| # include "option_table.h" |
| |
| #ifndef CMOS_VSTART_partition_fw |
| #error "The `ramtop` CMOS entry is missing, please add it to your cmos.layout." |
| #endif |
| |
| #if CMOS_VSTART_partition_fw % 8 != 0 |
| #error "The `partition firmware` CMOS entry needs to be byte aligned, check your cmos.layout." |
| #endif // CMOS_VSTART_partition_fw % 8 != 0 |
| |
| #if CMOS_VLEN_partition_fw != (32 * 8) |
| #error "The partition firmware entry needs to be 32 bytes long, check your cmos.layout." |
| #endif |
| |
| # define PARTITION_FW_CMOS_OFFSET (CMOS_VSTART_partition_fw >> 3) |
| |
| #else |
| # if (CONFIG_SOC_INTEL_CSE_FW_PARTITION_CMOS_OFFSET != 0) |
| # define PARTITION_FW_CMOS_OFFSET CONFIG_SOC_INTEL_CSE_FW_PARTITION_CMOS_OFFSET |
| # else |
| # error "Must configure CONFIG_SOC_INTEL_CSE_FW_PARTITION_CMOS_OFFSET" |
| # 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) |
| { |
| for (uint8_t *p = (uint8_t *)info, i = 0; i < sizeof(*info); i++, p++) |
| *p = cmos_read(PARTITION_FW_CMOS_OFFSET + i); |
| } |
| |
| /* Helper function to write CSE fpt information to cmos memory. */ |
| 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; |
| } |