Patrick Georgi has submitted this change. ( https://review.coreboot.org/c/coreboot/+/18498 )
Change subject: libpayload: Improve rtc functions ......................................................................
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 --- M payloads/libpayload/drivers/nvram.c M payloads/libpayload/include/libpayload.h 2 files changed, 41 insertions(+), 9 deletions(-)
Approvals: build bot (Jenkins): Verified Nico Huber: Looks good to me, approved
diff --git a/payloads/libpayload/drivers/nvram.c b/payloads/libpayload/drivers/nvram.c index a116d1b..34ee033 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 @@ */ void rtc_read_clock(struct tm *time) { + u16 timeout = 10000; + u8 statusB; + u8 reg8; + memset(time, 0, sizeof(*time));
- while(nvram_updating()); + while (nvram_updating()) + if (!timeout--) + return;
- 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)); + 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; } diff --git a/payloads/libpayload/include/libpayload.h b/payloads/libpayload/include/libpayload.h index 4b6a250..7496972 100644 --- a/payloads/libpayload/include/libpayload.h +++ b/payloads/libpayload/include/libpayload.h @@ -130,6 +130,9 @@ #define NVRAM_RTC_YEAR 9 /**< RTC Year offset in CMOS */ #define NVRAM_RTC_FREQ_SELECT 10 /**< RTC Update Status Register */ #define NVRAM_RTC_UIP 0x80 +#define NVRAM_RTC_STATUSB 11 /**< RTC Status Register B */ +#define NVRAM_RTC_FORMAT_24HOUR 0x02 +#define NVRAM_RTC_FORMAT_BINARY 0x04
/** Broken down time structure */ struct tm {