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 bool __cmos_init(bool invalid
)
71 bool checksum_invalid
= false;
72 bool cleared_cmos
= false;
76 * Avoid clearing pending interrupts and resetting the RTC control
77 * register in the resume path because the Linux kernel relies on
78 * this to know if it should restart the RTC timer queue if the wake
79 * was due to the RTC alarm.
81 if (ENV_RAMSTAGE
&& acpi_is_wakeup_s3())
84 printk(BIOS_DEBUG
, "RTC Init\n");
86 /* See if there has been a CMOS power problem. */
87 cmos_invalid
= cmos_error();
89 if (CONFIG(USE_OPTION_TABLE
)) {
90 /* See if there is a CMOS checksum error */
91 checksum_invalid
= !cmos_checksum_valid(PC_CKS_RANGE_START
,
92 PC_CKS_RANGE_END
, PC_CKS_LOC
);
95 if (cmos_invalid
|| invalid
)
98 if (invalid
|| cmos_invalid
|| checksum_invalid
) {
99 if (!CONFIG(USE_OPTION_TABLE
)) {
103 for (i
= 10; i
< 128; i
++)
108 if (cmos_invalid
|| invalid
)
111 printk(BIOS_WARNING
, "RTC:%s%s%s%s\n",
112 invalid
? " Clear requested":"",
113 cmos_invalid
? " Power Problem":"",
114 checksum_invalid
? " Checksum invalid":"",
115 cleared_cmos
? " zeroing cmos":"");
118 /* Setup the real time clock */
119 cmos_write(RTC_CONTROL_DEFAULT
, RTC_CONTROL
);
120 /* Setup the frequency it operates at */
121 cmos_write(RTC_FREQ_SELECT_DEFAULT
, RTC_FREQ_SELECT
);
122 /* Ensure all reserved bits are 0 in register D */
123 cmos_write(RTC_VRT
, RTC_VALID
);
125 if (CONFIG(USE_OPTION_TABLE
)) {
126 /* See if there is a LB CMOS checksum error */
127 checksum_invalid
= !cmos_lb_cks_valid();
128 if (checksum_invalid
)
129 printk(BIOS_DEBUG
, "RTC: coreboot checksum invalid\n");
131 /* Make certain we have a valid checksum */
132 cmos_set_checksum(PC_CKS_RANGE_START
, PC_CKS_RANGE_END
, PC_CKS_LOC
);
135 /* Clear any pending interrupts */
136 cmos_read(RTC_INTR_FLAGS
);
141 static void cmos_init_vbnv(bool invalid
)
143 uint8_t vbnv
[VBOOT_VBNV_BLOCK_SIZE
];
145 /* __cmos_init() will clear vbnv contents when a known rtc failure
146 occurred with !CONFIG(USE_OPTION_TABLE). However, __cmos_init() may
147 clear vbnv data for other internal reasons. For that, always back up
148 the vbnv contents and conditionally save them when __cmos_init()
149 indicates CMOS was cleared. */
150 read_vbnv_cmos(vbnv
);
152 if (__cmos_init(invalid
))
153 save_vbnv_cmos(vbnv
);
156 void cmos_init(bool invalid
)
161 if (CONFIG(VBOOT_VBNV_CMOS
))
162 cmos_init_vbnv(invalid
);
164 __cmos_init(invalid
);
168 * Upon return the caller is guaranteed 244 microseconds to complete any
169 * RTC operations. wait_uip may be called a single time prior to multiple
170 * accesses, but sequences requiring more time should call wait_uip again.
172 static void wait_uip(void)
174 while (cmos_read(RTC_REG_A
) & RTC_UIP
)
178 /* Perform a sanity check of current date and time. */
179 static int cmos_date_invalid(void)
184 return rtc_invalid(&now
);
188 * If the CMOS is cleared, the rtc_reg has the invalid date. That
189 * hurts some OSes. Even if we don't set USE_OPTION_TABLE, we need
190 * to make sure the date is valid.
192 void cmos_check_update_date(void)
194 u8 year
, century
= 0;
197 if (CONFIG(USE_PC_CMOS_ALTCENTURY
))
198 century
= cmos_read(RTC_CLK_ALTCENTURY
);
199 year
= cmos_read(RTC_CLK_YEAR
);
202 * If century is 0xFF, 100% that the CMOS is cleared.
203 * In addition, check the sanity of all values and reset the date in case of
206 if (century
> 0x99 || year
> 0x99 || cmos_date_invalid()) /* Invalid date */
210 int rtc_set(const struct rtc_time
*time
)
212 cmos_write(bin2bcd(time
->sec
), RTC_CLK_SECOND
);
213 cmos_write(bin2bcd(time
->min
), RTC_CLK_MINUTE
);
214 cmos_write(bin2bcd(time
->hour
), RTC_CLK_HOUR
);
215 cmos_write(bin2bcd(time
->mday
), RTC_CLK_DAYOFMONTH
);
216 cmos_write(bin2bcd(time
->mon
), RTC_CLK_MONTH
);
217 cmos_write(bin2bcd(time
->year
% 100), RTC_CLK_YEAR
);
218 if (CONFIG(USE_PC_CMOS_ALTCENTURY
))
219 cmos_write(bin2bcd(time
->year
/ 100), RTC_CLK_ALTCENTURY
);
220 cmos_write(bin2bcd(time
->wday
+ 1), RTC_CLK_DAYOFWEEK
);
224 int rtc_get(struct rtc_time
*time
)
227 time
->sec
= bcd2bin(cmos_read(RTC_CLK_SECOND
));
228 time
->min
= bcd2bin(cmos_read(RTC_CLK_MINUTE
));
229 time
->hour
= bcd2bin(cmos_read(RTC_CLK_HOUR
));
230 time
->mday
= bcd2bin(cmos_read(RTC_CLK_DAYOFMONTH
));
231 time
->mon
= bcd2bin(cmos_read(RTC_CLK_MONTH
));
232 time
->year
= bcd2bin(cmos_read(RTC_CLK_YEAR
));
233 if (CONFIG(USE_PC_CMOS_ALTCENTURY
)) {
234 time
->year
+= bcd2bin(cmos_read(RTC_CLK_ALTCENTURY
)) * 100;
237 if (time
->year
< 1970)
240 time
->wday
= bcd2bin(cmos_read(RTC_CLK_DAYOFWEEK
)) - 1;
245 * Signal coreboot proper completed -- just before running payload
246 * or jumping to ACPI S3 wakeup vector.
248 void set_boot_successful(void)
252 index
= inb(RTC_PORT(0)) & 0x80;
253 index
|= RTC_BOOT_BYTE
;
254 outb(index
, RTC_PORT(0));
256 byte
= inb(RTC_PORT(1));
258 if (CONFIG(SKIP_MAX_REBOOT_CNT_CLEAR
)) {
260 * Set the fallback boot bit to allow for recovery if
261 * the payload fails to boot.
262 * It is the responsibility of the payload to reset
263 * the normal boot bit to 1 if desired
265 byte
&= ~RTC_BOOT_NORMAL
;
267 /* If we are in normal mode set the boot count to 0 */
268 if (byte
& RTC_BOOT_NORMAL
)
272 outb(byte
, RTC_PORT(1));