summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Sandberg <andreas@sandberg.pp.se>2013-06-03 12:28:52 +0200
committerAndreas Sandberg <andreas@sandberg.pp.se>2013-06-03 12:28:52 +0200
commit5e60f87aa3ec4ef9503e6bca54ebfd3c5a543aec (patch)
tree4187e32a5179b282b128dd8494aea8c7dc59cf1e
parent14b8a17f284ad398e39636da907f3055462f75cd (diff)
downloadgem5-5e60f87aa3ec4ef9503e6bca54ebfd3c5a543aec.tar.xz
dev: Add support for disabling ticking and the divider in MC146818
Some Linux versions disable updates (regB.set = 1) to prevent the chip from updating its internal state while the OS is updating it. Support for this was already there, this patch merely disables the check in writeReg that prevented it from being enabled. The patch also includes support for disabling the divider, which is used to control when clock updates should start after setting the internal RTC state. These changes are required to boot most vanilla Linux distributions that update the RTC settings at boot.
-rw-r--r--src/dev/mc146818.cc22
1 files changed, 16 insertions, 6 deletions
diff --git a/src/dev/mc146818.cc b/src/dev/mc146818.cc
index 276c98581..abacd8742 100644
--- a/src/dev/mc146818.cc
+++ b/src/dev/mc146818.cc
@@ -144,7 +144,8 @@ MC146818::writeData(const uint8_t addr, const uint8_t data)
// The "update in progress" bit is read only.
stat_regA.uip = old_rega;
- if (stat_regA.dv != RTCA_DV_32768HZ) {
+ if (!rega_dv_disabled(stat_regA) &&
+ stat_regA.dv != RTCA_DV_32768HZ) {
inform("RTC: Unimplemented divider configuration: %i\n",
stat_regA.dv);
panic_unsupported = true;
@@ -155,14 +156,21 @@ MC146818::writeData(const uint8_t addr, const uint8_t data)
stat_regA.rs);
panic_unsupported = true;
}
+
+ if (rega_dv_disabled(stat_regA)) {
+ // The divider is disabled, make sure that we don't
+ // schedule any ticks.
+ if (tickEvent.scheduled())
+ deschedule(tickEvent);
+ } else if (rega_dv_disabled(old_rega)) {
+ // If the divider chain goes from reset to active, we
+ // need to schedule a tick after precisely 0.5s.
+ assert(!tickEvent.scheduled());
+ schedule(tickEvent, curTick() + SimClock::Int::s / 2);
+ }
} break;
case RTC_STAT_REGB:
stat_regB = data;
- if (stat_regB.set) {
- inform("RTC: Updating stopping not implemented.\n");
- panic_unsupported = true;
- }
-
if (stat_regB.aie || stat_regB.uie) {
inform("RTC: Unimplemented interrupt configuration: %s %s\n",
stat_regB.aie ? "alarm" : "",
@@ -233,6 +241,8 @@ MC146818::readData(uint8_t addr)
void
MC146818::tickClock()
{
+ assert(!rega_dv_disabled(stat_regA));
+
if (stat_regB.set)
return;
time_t calTime = mkutctime(&curTime);