diff options
author | Patrick Rudolph <siro@das-labor.org> | 2017-02-25 09:56:53 +0100 |
---|---|---|
committer | Patrick Georgi <pgeorgi@google.com> | 2020-03-09 08:14:04 +0000 |
commit | 9f3e734e5c3760ff30906862a3f9ca724ea5fffb (patch) | |
tree | c3db88f9bdaa03ee1783976f4c46cca699643c90 /payloads/libpayload/drivers | |
parent | ef613b97cf03d764f2894e314c65282589af55b3 (diff) |
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')
-rw-r--r-- | payloads/libpayload/drivers/nvram.c | 49 |
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; } |