summaryrefslogtreecommitdiff
path: root/payloads/libpayload/drivers/nvram.c
diff options
context:
space:
mode:
authorPatrick Rudolph <siro@das-labor.org>2017-02-25 09:56:53 +0100
committerPatrick Georgi <pgeorgi@google.com>2020-03-09 08:14:04 +0000
commit9f3e734e5c3760ff30906862a3f9ca724ea5fffb (patch)
treec3db88f9bdaa03ee1783976f4c46cca699643c90 /payloads/libpayload/drivers/nvram.c
parentef613b97cf03d764f2894e314c65282589af55b3 (diff)
downloadcoreboot-9f3e734e5c3760ff30906862a3f9ca724ea5fffb.tar.xz
libpayload: Improve rtc functions
On Lenovo T500 the RTC readings where wrong, as RTC has different encodings, depending on the statusB register. Support BCD vs binary RTC format and AM/PM vs 24h RTC format. Fixes wrong date and time on Lenovo 500. Change-Id: Id773c33e228973e190a7e14c3d11979678b1a619 Signed-off-by: Patrick Rudolph <siro@das-labor.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/18498 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Nico Huber <nico.h@gmx.de>
Diffstat (limited to 'payloads/libpayload/drivers/nvram.c')
-rw-r--r--payloads/libpayload/drivers/nvram.c49
1 files changed, 39 insertions, 10 deletions
diff --git a/payloads/libpayload/drivers/nvram.c b/payloads/libpayload/drivers/nvram.c
index a116d1b65f..34ee0331e1 100644
--- a/payloads/libpayload/drivers/nvram.c
+++ b/payloads/libpayload/drivers/nvram.c
@@ -2,6 +2,7 @@
* This file is part of the libpayload project.
*
* Copyright (C) 2008 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2017 Patrick Rudolph <siro@das-labor.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -111,23 +112,51 @@ int nvram_updating(void)
*/
void rtc_read_clock(struct tm *time)
{
- memset(time, 0, sizeof(*time));
+ u16 timeout = 10000;
+ u8 statusB;
+ u8 reg8;
- while(nvram_updating());
+ memset(time, 0, sizeof(*time));
- time->tm_mon = bcd2dec(nvram_read(NVRAM_RTC_MONTH)) - 1;
- time->tm_sec = bcd2dec(nvram_read(NVRAM_RTC_SECONDS));
- time->tm_min = bcd2dec(nvram_read(NVRAM_RTC_MINUTES));
- time->tm_mday = bcd2dec(nvram_read(NVRAM_RTC_DAY));
- time->tm_hour = bcd2dec(nvram_read(NVRAM_RTC_HOURS));
+ while (nvram_updating())
+ if (!timeout--)
+ return;
+
+ statusB = nvram_read(NVRAM_RTC_STATUSB);
+
+ if (!(statusB & NVRAM_RTC_FORMAT_BINARY)) {
+ time->tm_mon = bcd2dec(nvram_read(NVRAM_RTC_MONTH)) - 1;
+ time->tm_sec = bcd2dec(nvram_read(NVRAM_RTC_SECONDS));
+ time->tm_min = bcd2dec(nvram_read(NVRAM_RTC_MINUTES));
+ time->tm_mday = bcd2dec(nvram_read(NVRAM_RTC_DAY));
+
+ if (!(statusB & NVRAM_RTC_FORMAT_24HOUR)) {
+ reg8 = nvram_read(NVRAM_RTC_HOURS);
+ time->tm_hour = bcd2dec(reg8 & 0x7f);
+ time->tm_hour += (reg8 & 0x80) ? 12 : 0;
+ time->tm_hour %= 24;
+ } else
+ time->tm_hour = bcd2dec(nvram_read(NVRAM_RTC_HOURS));
+ time->tm_year = bcd2dec(nvram_read(NVRAM_RTC_YEAR));
+ } else {
+ time->tm_mon = nvram_read(NVRAM_RTC_MONTH) - 1;
+ time->tm_sec = nvram_read(NVRAM_RTC_SECONDS);
+ time->tm_min = nvram_read(NVRAM_RTC_MINUTES);
+ time->tm_mday = nvram_read(NVRAM_RTC_DAY);
+ if (!(statusB & NVRAM_RTC_FORMAT_24HOUR)) {
+ reg8 = nvram_read(NVRAM_RTC_HOURS);
+ time->tm_hour = reg8 & 0x7f;
+ time->tm_hour += (reg8 & 0x80) ? 12 : 0;
+ time->tm_hour %= 24;
+ } else
+ time->tm_hour = nvram_read(NVRAM_RTC_HOURS);
+ time->tm_year = nvram_read(NVRAM_RTC_YEAR);
+ }
/* Instead of finding the century register,
we just make an assumption that if the year value is
less then 80, then it is 2000+
*/
-
- time->tm_year = bcd2dec(nvram_read(NVRAM_RTC_YEAR));
-
if (time->tm_year < 80)
time->tm_year += 100;
}