From f943901777990554e3f5fb27b63613f6cd95c958 Mon Sep 17 00:00:00 2001 From: Patrick Georgi Date: Thu, 15 Nov 2012 14:54:05 +0100 Subject: [PATCH] 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 Reviewed-on: http://review.coreboot.org/1868 Tested-by: build bot (Jenkins) Reviewed-by: Stefan Reinauer --- src/include/pc80/mc146818rtc.h | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) 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;