[coreboot-gerrit] Patch set updated for coreboot: libpayload: Fix and improve rtc functions

Patrick Rudolph (siro@das-labor.org) gerrit at coreboot.org
Sun Feb 26 14:46:53 CET 2017


Patrick Rudolph (siro at das-labor.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/18498

-gerrit

commit 8008c8e93c47e5688a1b719b7114fa58bea3feb1
Author: Patrick Rudolph <siro at das-labor.org>
Date:   Sat Feb 25 09:56:53 2017 +0100

    libpayload: Fix and 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 T500.
    
    Add a function to write RTC.
    Writing the RTC allows payloads to easily change the RTC.
    
    Change-Id: Id773c33e228973e190a7e14c3d11979678b1a619
    Signed-off-by: Patrick Rudolph <siro at das-labor.org>
---
 payloads/libpayload/drivers/nvram.c      | 100 +++++++++++++++++++++++++++----
 payloads/libpayload/include/libpayload.h |   2 +
 2 files changed, 92 insertions(+), 10 deletions(-)

diff --git a/payloads/libpayload/drivers/nvram.c b/payloads/libpayload/drivers/nvram.c
index c825331..6e2ebdc 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 at hermann-uwe.de>
+ * Copyright (C) 2017 Patrick Rudolph <siro at 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,102 @@ 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 & 0x04)) {
+		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 & 0x02)) {
+			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 & 0x02)) {
+			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;
 }
+
+/**
+ * Write the current time and date to the RTC
+ *
+ * @param time A pointer to a broken-down time structure
+ */
+void rtc_write_clock(struct tm *time)
+{
+	u16 timeout = 10000;
+	u8 statusB;
+	u8 reg8;
+
+	while (nvram_updating())
+		if (!timeout--)
+			return;
+
+	statusB = nvram_read(NVRAM_RTC_STATUSB);
+
+	if (time->tm_year > 100)
+		time->tm_year -= 100;
+
+	if (!(statusB & 0x04)) {
+		nvram_write(dec2bcd(time->tm_mon + 1), NVRAM_RTC_MONTH);
+		nvram_write(dec2bcd(time->tm_sec), NVRAM_RTC_SECONDS);
+		nvram_write(dec2bcd(time->tm_min), NVRAM_RTC_MINUTES);
+		nvram_write(dec2bcd(time->tm_mday), NVRAM_RTC_DAY);
+		if (!(statusB & 0x02)) {
+			if (time->tm_hour > 12)
+				reg8 = dec2bcd(time->tm_hour - 12) | 0x80;
+			else
+				reg8 = dec2bcd(time->tm_hour);
+		} else
+			reg8 = dec2bcd(time->tm_hour);
+		nvram_write(reg8, NVRAM_RTC_HOURS);
+		nvram_write(dec2bcd(time->tm_year), NVRAM_RTC_YEAR);
+	} else {
+		nvram_write(time->tm_mon + 1, NVRAM_RTC_MONTH);
+		nvram_write(time->tm_sec, NVRAM_RTC_SECONDS);
+		nvram_write(time->tm_min, NVRAM_RTC_MINUTES);
+		nvram_write(time->tm_mday, NVRAM_RTC_DAY);
+		if (!(statusB & 0x02)) {
+			if (time->tm_hour > 12)
+				reg8 = (time->tm_hour - 12) | 0x80;
+			else
+				reg8 = time->tm_hour;
+		} else
+			reg8 = time->tm_hour;
+		nvram_write(reg8, NVRAM_RTC_HOURS);
+		nvram_write(time->tm_year, NVRAM_RTC_YEAR);
+	}
+}
diff --git a/payloads/libpayload/include/libpayload.h b/payloads/libpayload/include/libpayload.h
index 97d5944..53c96cd 100644
--- a/payloads/libpayload/include/libpayload.h
+++ b/payloads/libpayload/include/libpayload.h
@@ -104,6 +104,7 @@ static const char _pstruct(key)[]                                        \
 #define NVRAM_RTC_MONTH          8      /**< RTC Month offset in CMOS */
 #define NVRAM_RTC_YEAR           9      /**< RTC Year offset in CMOS */
 #define NVRAM_RTC_FREQ_SELECT    10     /**< RTC Update Status Register */
+#define NVRAM_RTC_STATUSB        11     /**< RTC Status Register B */
 #define  NVRAM_RTC_UIP           0x80
 
 /** Broken down time structure */
@@ -123,6 +124,7 @@ u8 nvram_read(u8 addr);
 void nvram_write(u8 val, u8 addr);
 int nvram_updating(void);
 void rtc_read_clock(struct tm *tm);
+void rtc_write_clock(struct tm *time);
 /** @} */
 
 /**



More information about the coreboot-gerrit mailing list