summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Georgi <patrick.georgi@secunet.com>2012-11-15 14:54:05 +0100
committerPatrick Georgi <patrick@georgi-clan.de>2012-11-19 22:06:48 +0100
commitf943901777990554e3f5fb27b63613f6cd95c958 (patch)
tree899988d8bf1d8f5e0ad1cbf431fe2e467b9ef9d5
parent4b62ebe961846b5b07aa57dacc24878a30ea9cc9 (diff)
downloadcoreboot-f943901777990554e3f5fb27b63613f6cd95c958.tar.xz
mc146818rtc: disable RTC before writing to nvram
In principle this isn't necessary. However there's a byte (or several) outside the first 14 bytes that are part of the RTC, and require locking (century/altCentury). Since their location is mostly unknown, guard writes properly. Change-Id: I847cd4efa92722e8504d29feaf7dbfa5c5244b4e Signed-off-by: Patrick Georgi <patrick.georgi@secunet.com> Reviewed-on: http://review.coreboot.org/1868 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
-rw-r--r--src/include/pc80/mc146818rtc.h31
1 files changed, 30 insertions, 1 deletions
diff --git a/src/include/pc80/mc146818rtc.h b/src/include/pc80/mc146818rtc.h
index 31322ea528..ee1473b71a 100644
--- a/src/include/pc80/mc146818rtc.h
+++ b/src/include/pc80/mc146818rtc.h
@@ -110,7 +110,7 @@ static inline unsigned char cmos_read(unsigned char addr)
return inb(RTC_BASE_PORT + offs + 1);
}
-static inline void cmos_write(unsigned char val, unsigned char addr)
+static inline void cmos_write_inner(unsigned char val, unsigned char addr)
{
int offs = 0;
if (addr >= 128) {
@@ -121,6 +121,35 @@ static inline void cmos_write(unsigned char val, unsigned char addr)
outb(val, RTC_BASE_PORT + offs + 1);
}
+static inline void cmos_write(unsigned char val, unsigned char addr)
+{
+ u8 control_state = cmos_read(RTC_CONTROL);
+ /* There are various places where RTC bits might be hiding,
+ * eg. the Century / AltCentury byte. So to be safe, disable
+ * RTC before changing any value.
+ */
+ if ((addr != RTC_CONTROL) && !(control_state & RTC_SET)) {
+ cmos_write_inner(control_state | RTC_SET, RTC_CONTROL);
+ }
+ cmos_write_inner(val, addr);
+ /* reset to prior configuration */
+ if ((addr != RTC_CONTROL) && !(control_state & RTC_SET)) {
+ cmos_write_inner(control_state, RTC_CONTROL);
+ }
+}
+
+static inline void cmos_disable_rtc(void)
+{
+ u8 control_state = cmos_read(RTC_CONTROL);
+ cmos_write(control_state | RTC_SET, RTC_CONTROL);
+}
+
+static inline void cmos_enable_rtc(void)
+{
+ u8 control_state = cmos_read(RTC_CONTROL);
+ cmos_write(control_state & ~RTC_SET, RTC_CONTROL);
+}
+
static inline u32 cmos_read32(u8 offset)
{
u32 value = 0;