diff options
author | Marshall Dawson <marshalldawson3rd@gmail.com> | 2016-11-05 18:31:33 -0600 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2016-11-17 23:08:43 +0100 |
commit | 5a043fe08d84490356888d236ee7d190aa195217 (patch) | |
tree | 80b062db6bc068d06917afbbe0d3410b191b15d2 | |
parent | 05abe4351b1d76148a8cc69f817e659fa372a5dd (diff) |
rtc: Check update-in-progress bit
While the real-time clock updates its count, values may not be correctly
read or written. On reads, ensure the UIP bit is clear which guarantees
a minimum of 244 microseconds exists before the update begins. Writes
already avoid the problem by disabling the RTC count via the SET bit.
Change-Id: I39e34493113015d32582f1c280fafa9e97f43a40
Signed-off-by: Marshall Dawson <marshalldawson3rd@gmail.com>
Reviewed-on: https://review.coreboot.org/17369
Tested-by: build bot (Jenkins)
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-by: Paul Menzel <paulepanter@users.sourceforge.net>
-rw-r--r-- | src/drivers/pc80/rtc/mc146818rtc.c | 2 | ||||
-rw-r--r-- | src/include/pc80/mc146818rtc.h | 10 |
2 files changed, 12 insertions, 0 deletions
diff --git a/src/drivers/pc80/rtc/mc146818rtc.c b/src/drivers/pc80/rtc/mc146818rtc.c index 5fb9cf695b..c3026a4dbc 100644 --- a/src/drivers/pc80/rtc/mc146818rtc.c +++ b/src/drivers/pc80/rtc/mc146818rtc.c @@ -360,6 +360,7 @@ void cmos_check_update_date(void) u8 year, century; /* Assume hardware always supports RTC_CLK_ALTCENTURY. */ + wait_uip(); century = cmos_read(RTC_CLK_ALTCENTURY); year = cmos_read(RTC_CLK_YEAR); @@ -388,6 +389,7 @@ int rtc_set(const struct rtc_time *time) int rtc_get(struct rtc_time *time) { + wait_uip(); time->sec = bcd2bin(cmos_read(RTC_CLK_SECOND)); time->min = bcd2bin(cmos_read(RTC_CLK_MINUTE)); time->hour = bcd2bin(cmos_read(RTC_CLK_HOUR)); diff --git a/src/include/pc80/mc146818rtc.h b/src/include/pc80/mc146818rtc.h index effc03d2ae..66d5edb4b9 100644 --- a/src/include/pc80/mc146818rtc.h +++ b/src/include/pc80/mc146818rtc.h @@ -112,6 +112,16 @@ static inline unsigned char cmos_read(unsigned char addr) return inb(RTC_BASE_PORT + offs + 1); } +/* Upon return the caller is guaranteed 244 microseconds to complete any + * RTC operations. wait_uip may be called a single time prior to multiple + * accesses, but sequences requiring more time should call wait_uip again. + */ +static inline void wait_uip(void) +{ + while (cmos_read(RTC_REG_A) & RTC_UIP) + ; +} + static inline void cmos_write_inner(unsigned char val, unsigned char addr) { int offs = 0; |