1 /* SPDX-License-Identifier: GPL-2.0-only */
5 #include <commonlib/bsd/bcd.h>
6 #include <console/console.h>
8 #include <pc80/mc146818rtc.h>
10 #include <security/vboot/vbnv.h>
11 #include <security/vboot/vbnv_layout.h>
15 static void cmos_reset_date(void)
17 /* Now setup a default date equals to the build date */
18 struct rtc_time time
= {
22 .mday
= bcd2bin(coreboot_build_date
.day
),
23 .mon
= bcd2bin(coreboot_build_date
.month
),
24 .year
= (bcd2bin(coreboot_build_date
.century
) * 100) +
25 bcd2bin(coreboot_build_date
.year
),
26 .wday
= bcd2bin(coreboot_build_date
.weekday
)
31 int cmos_checksum_valid(int range_start
, int range_end
, int cks_loc
)
36 if (CONFIG(STATIC_OPTION_TABLE
))
40 for (i
= range_start
; i
<= range_end
; i
++)
42 old_sum
= ((cmos_read(cks_loc
) << 8) | cmos_read(cks_loc
+ 1)) &
44 return sum
== old_sum
;
47 void cmos_set_checksum(int range_start
, int range_end
, int cks_loc
)
53 for (i
= range_start
; i
<= range_end
; i
++)
55 cmos_write(((sum
>> 8) & 0x0ff), cks_loc
);
56 cmos_write(((sum
>> 0) & 0x0ff), cks_loc
+ 1);
59 /* See if the CMOS error condition has been flagged */
62 return (cmos_read(RTC_VALID
) & RTC_VRT
) == 0;
65 #define RTC_CONTROL_DEFAULT (RTC_24H)
66 #define RTC_FREQ_SELECT_DEFAULT (RTC_REF_CLCK_32KHZ | RTC_RATE_1024HZ)
68 _Static_assert(!CONFIG(SOC_AMD_COMMON
) || !(RTC_FREQ_SELECT_DEFAULT
& RTC_AMD_BANK_SELECT
),
69 "Bank 1 should not be selected for AMD");
71 static bool __cmos_init(bool invalid
)
74 bool checksum_invalid
= false;
75 bool cleared_cmos
= false;
79 * Avoid clearing pending interrupts and resetting the RTC control
80 * register in the resume path because the Linux kernel relies on
81 * this to know if it should restart the RTC timer queue if the wake
82 * was due to the RTC alarm.
84 if (ENV_RAMSTAGE
&& acpi_is_wakeup_s3())
87 printk(BIOS_DEBUG
, "RTC Init\n");
89 /* See if there has been a CMOS power problem. */
90 cmos_invalid
= cmos_error();
92 if (CONFIG(USE_OPTION_TABLE
)) {
93 /* See if there is a CMOS checksum error */
94 checksum_invalid
= !cmos_checksum_valid(PC_CKS_RANGE_START
,
95 PC_CKS_RANGE_END
, PC_CKS_LOC
);
98 if (cmos_invalid
|| invalid
)
101 if (invalid
|| cmos_invalid
|| checksum_invalid
) {
102 if (!CONFIG(USE_OPTION_TABLE
)) {
103 cmos_write(0, RTC_CLK_SECOND_ALARM
);
104 cmos_write(0, RTC_CLK_MINUTE_ALARM
);
105 cmos_write(0, RTC_CLK_HOUR_ALARM
);
106 for (i
= 10; i
< 128; i
++)
111 if (cmos_invalid
|| invalid
)
114 printk(BIOS_WARNING
, "RTC:%s%s%s%s\n",
115 invalid
? " Clear requested":"",
116 cmos_invalid
? " Power Problem":"",
117 checksum_invalid
? " Checksum invalid":"",
118 cleared_cmos
? " zeroing cmos":"");
121 /* Setup the real time clock */
122 cmos_write(RTC_CONTROL_DEFAULT
, RTC_CONTROL
);
123 /* Setup the frequency it operates at */
124 cmos_write(RTC_FREQ_SELECT_DEFAULT
, RTC_FREQ_SELECT
);
125 /* Ensure all reserved bits are 0 in register D */
126 cmos_write(RTC_VRT
, RTC_VALID
);
128 if (CONFIG(USE_OPTION_TABLE
)) {
129 /* See if there is a LB CMOS checksum error */
130 checksum_invalid
= !cmos_lb_cks_valid();
131 if (checksum_invalid
)
132 printk(BIOS_DEBUG
, "RTC: coreboot checksum invalid\n");
134 /* Make certain we have a valid checksum */
135 cmos_set_checksum(PC_CKS_RANGE_START
, PC_CKS_RANGE_END
, PC_CKS_LOC
);
138 /* Clear any pending interrupts */
139 cmos_read(RTC_INTR_FLAGS
);
144 static void cmos_init_vbnv(bool invalid
)
146 uint8_t vbnv
[VBOOT_VBNV_BLOCK_SIZE
];
148 /* __cmos_init() will clear vbnv contents when a known rtc failure
149 occurred with !CONFIG(USE_OPTION_TABLE). However, __cmos_init() may
150 clear vbnv data for other internal reasons. For that, always back up
151 the vbnv contents and conditionally save them when __cmos_init()
152 indicates CMOS was cleared. */
153 read_vbnv_cmos(vbnv
);
155 if (__cmos_init(invalid
))
156 save_vbnv_cmos(vbnv
);
159 void cmos_init(bool invalid
)
164 if (CONFIG(VBOOT_VBNV_CMOS
))
165 cmos_init_vbnv(invalid
);
167 __cmos_init(invalid
);
171 * Upon return the caller is guaranteed 244 microseconds to complete any
172 * RTC operations. wait_uip may be called a single time prior to multiple
173 * accesses, but sequences requiring more time should call wait_uip again.
175 static void wait_uip(void)
177 while (cmos_read(RTC_REG_A
) & RTC_UIP
)
181 /* Perform a sanity check of current date and time. */
182 static int cmos_date_invalid(void)
187 return rtc_invalid(&now
);
191 * If the CMOS is cleared, the rtc_reg has the invalid date. That
192 * hurts some OSes. Even if we don't set USE_OPTION_TABLE, we need
193 * to make sure the date is valid.
195 void cmos_check_update_date(void)
197 u8 year
, century
= 0;
200 if (CONFIG(USE_PC_CMOS_ALTCENTURY
))
201 century
= cmos_read(RTC_CLK_ALTCENTURY
);
202 year
= cmos_read(RTC_CLK_YEAR
);
205 * If century is 0xFF, 100% that the CMOS is cleared.
206 * In addition, check the sanity of all values and reset the date in case of
209 if (century
> 0x99 || year
> 0x99 || cmos_date_invalid()) /* Invalid date */
213 int rtc_set(const struct rtc_time
*time
)
215 cmos_write(bin2bcd(time
->sec
), RTC_CLK_SECOND
);
216 cmos_write(bin2bcd(time
->min
), RTC_CLK_MINUTE
);
217 cmos_write(bin2bcd(time
->hour
), RTC_CLK_HOUR
);
218 cmos_write(bin2bcd(time
->mday
), RTC_CLK_DAYOFMONTH
);
219 cmos_write(bin2bcd(time
->mon
), RTC_CLK_MONTH
);
220 cmos_write(bin2bcd(time
->year
% 100), RTC_CLK_YEAR
);
221 if (CONFIG(USE_PC_CMOS_ALTCENTURY
))
222 cmos_write(bin2bcd(time
->year
/ 100), RTC_CLK_ALTCENTURY
);
223 cmos_write(bin2bcd(time
->wday
+ 1), RTC_CLK_DAYOFWEEK
);
227 int rtc_get(struct rtc_time
*time
)
230 time
->sec
= bcd2bin(cmos_read(RTC_CLK_SECOND
));
231 time
->min
= bcd2bin(cmos_read(RTC_CLK_MINUTE
));
232 time
->hour
= bcd2bin(cmos_read(RTC_CLK_HOUR
));
233 time
->mday
= bcd2bin(cmos_read(RTC_CLK_DAYOFMONTH
));
234 time
->mon
= bcd2bin(cmos_read(RTC_CLK_MONTH
));
235 time
->year
= bcd2bin(cmos_read(RTC_CLK_YEAR
));
236 if (CONFIG(USE_PC_CMOS_ALTCENTURY
)) {
237 time
->year
+= bcd2bin(cmos_read(RTC_CLK_ALTCENTURY
)) * 100;
240 if (time
->year
< 1970)
243 time
->wday
= bcd2bin(cmos_read(RTC_CLK_DAYOFWEEK
)) - 1;
248 * Signal coreboot proper completed -- just before running payload
249 * or jumping to ACPI S3 wakeup vector.
251 void set_boot_successful(void)
255 index
= inb(RTC_PORT_BANK0(0)) & 0x80;
256 index
|= RTC_BOOT_BYTE
;
257 outb(index
, RTC_PORT_BANK0(0));
259 byte
= inb(RTC_PORT_BANK0(1));
261 if (CONFIG(SKIP_MAX_REBOOT_CNT_CLEAR
)) {
263 * Set the fallback boot bit to allow for recovery if
264 * the payload fails to boot.
265 * It is the responsibility of the payload to reset
266 * the normal boot bit to 1 if desired
268 byte
&= ~RTC_BOOT_NORMAL
;
270 /* If we are in normal mode set the boot count to 0 */
271 if (byte
& RTC_BOOT_NORMAL
)
275 outb(byte
, RTC_PORT_BANK0(1));