xref: /aosp_15_r20/external/coreboot/src/soc/intel/common/block/cse/cse_lite_cmos.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <commonlib/bsd/ipchksum.h>
4 #include <console/console.h>
5 #include <pc80/mc146818rtc.h>
6 
7 #include "cse_lite_cmos.h"
8 
9 /*
10  * We need a region in CMOS to store the firmware versions.
11  *
12  * This can either be declared as part of the option
13  * table or statically defined in the board config.
14  */
15 #if CONFIG(USE_OPTION_TABLE)
16 # include "option_table.h"
17 
18 #ifndef CMOS_VSTART_partition_fw
19 #error "The `CSE partition firmware` CMOS entry is missing, please add it to your cmos.layout."
20 #endif
21 
22 #if CMOS_VSTART_partition_fw % 8 != 0
23 #error "The `CSE partition firmware` CMOS entry needs to be byte aligned, check your cmos.layout."
24 #endif	// CMOS_VSTART_partition_fw % 8 != 0
25 
26 #if CMOS_VLEN_partition_fw != (32 * 8)
27 #error "The partition firmware entry needs to be 32 bytes long, check your cmos.layout."
28 #endif
29 
30 # define PARTITION_FW_CMOS_OFFSET (CMOS_VSTART_partition_fw >> 3)
31 
32 #else
33 # if (CONFIG_SOC_INTEL_CSE_FW_PARTITION_CMOS_OFFSET != 0)
34 #  define PARTITION_FW_CMOS_OFFSET CONFIG_SOC_INTEL_CSE_FW_PARTITION_CMOS_OFFSET
35 # else
36 #  error "Must configure CONFIG_SOC_INTEL_CSE_FW_PARTITION_CMOS_OFFSET"
37 # endif
38 #endif
39 
40 #define PSR_BACKUP_STATUS_SIGNATURE 0x42525350	/* 'PSRB' */
41 
42 /* Helper function to read CSE fpt information from cmos memory. */
cmos_read_fw_partition_info(struct cse_specific_info * info)43 void cmos_read_fw_partition_info(struct cse_specific_info *info)
44 {
45 	for (uint8_t *p = (uint8_t *)info, i = 0; i < sizeof(*info); i++, p++)
46 		*p = cmos_read(PARTITION_FW_CMOS_OFFSET + i);
47 }
48 
49 /* Helper function to write CSE fpt information to cmos memory. */
cmos_write_fw_partition_info(const struct cse_specific_info * info)50 void cmos_write_fw_partition_info(const struct cse_specific_info *info)
51 {
52 	for (uint8_t *p = (uint8_t *)info, i = 0; i < sizeof(*info); i++, p++)
53 		cmos_write(*p, PARTITION_FW_CMOS_OFFSET + i);
54 }
55 
56 /* Read and validate `psr_backup_status` structure from CMOS */
psr_backup_status_cmos_read(struct psr_backup_status * psr)57 static int psr_backup_status_cmos_read(struct psr_backup_status *psr)
58 {
59 	for (uint8_t *p = (uint8_t *)psr, i = 0; i < sizeof(*psr); i++, p++)
60 		*p = cmos_read(PARTITION_FW_CMOS_OFFSET + sizeof(struct cse_specific_info) + i);
61 
62 	/* Verify signature */
63 	if (psr->signature != PSR_BACKUP_STATUS_SIGNATURE) {
64 		printk(BIOS_ERR, "PSR backup status invalid signature\n");
65 		return -1;
66 	}
67 
68 	/* Verify checksum over signature and backup_status only */
69 	uint16_t csum = ipchksum(psr, offsetof(struct psr_backup_status, checksum));
70 
71 	if (csum != psr->checksum) {
72 		printk(BIOS_ERR, "PSR backup status checksum mismatch\n");
73 		return -1;
74 	}
75 
76 	return 0;
77 }
78 
79 /* Write `psr_backup_status structure` to CMOS */
psr_backup_status_cmos_write(struct psr_backup_status * psr)80 static void psr_backup_status_cmos_write(struct psr_backup_status *psr)
81 {
82 	/* Checksum over signature and backup_status only */
83 	psr->checksum = ipchksum(psr, offsetof(struct psr_backup_status, checksum));
84 
85 	for (uint8_t *p = (uint8_t *)psr, i = 0; i < sizeof(*psr); i++, p++)
86 		cmos_write(*p, PARTITION_FW_CMOS_OFFSET + sizeof(struct cse_specific_info) + i);
87 }
88 
89 /* Helper function to update the `psr_backup_status` in CMOS memory */
update_psr_backup_status(int8_t status)90 void update_psr_backup_status(int8_t status)
91 {
92 	struct psr_backup_status psr;
93 
94 	/* Read and update psr_backup_status */
95 	if (psr_backup_status_cmos_read(&psr) < 0)
96 		/* Structure invalid, re-initialize */
97 		psr.signature = PSR_BACKUP_STATUS_SIGNATURE;
98 
99 	psr.value = status;
100 
101 	/* Write the new status to CMOS */
102 	psr_backup_status_cmos_write(&psr);
103 
104 	printk(BIOS_INFO, "PSR backup status updated\n");
105 }
106 
107 /*
108  * Helper function to retrieve the current `psr_backup_status` in CMOS memory
109  * Returns current status on success, the status can be PSR_BACKUP_DONE or PSR_BACKUP_PENDING.
110  * Returns -1 in case of signature mismatch or checksum failure.
111  */
get_psr_backup_status(void)112 int8_t get_psr_backup_status(void)
113 {
114 	struct psr_backup_status psr;
115 
116 	if (psr_backup_status_cmos_read(&psr) < 0)
117 		return -1;
118 
119 	return psr.value;
120 }
121