aboutsummaryrefslogtreecommitdiff
path: root/hw/fake-rtc.c
diff options
context:
space:
mode:
authorVaibhav Jain <vaibhav@linux.vnet.ibm.com>2015-09-29 10:31:48 +0530
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-10-07 18:26:00 +1100
commit6c1658f454e14d5984bef7a9b4d65dab7f32c133 (patch)
treedf4d4b500a37c1c490f04e565df57a672a826b54 /hw/fake-rtc.c
parent3dfe3d50edede734d9d32bbbf64cff9ae65c28c0 (diff)
downloadskiboot-6c1658f454e14d5984bef7a9b4d65dab7f32c133.zip
skiboot-6c1658f454e14d5984bef7a9b4d65dab7f32c133.tar.gz
skiboot-6c1658f454e14d5984bef7a9b4d65dab7f32c133.tar.bz2
hw/fake-rtc: Add support for emulated rtc clock
This patch adds support for an emulated rtc clock over existing fake rtc implementation for generic platform (e.g BML). Presently a fake rtc clock is initialized when reserved region named 'ibm,fake-rtc' is present in the boot device tree. This mem-region points to the initial value of bcd coded date-time values. However as this region is in system memory hence its not updated with time. This results in an error from hwclock tool which tries to detect a change in system clock and then complains "Timed out waiting for time change." The patch overcomes this issue by emulating an rtc clock whose date-time values are calculated from the difference of current timebase and its value when the initial epoch was assigned. The initial epoch is set from the values at "ibm,fake-rtc" memory region. Acked-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Vaibhav Jain <vaibhav@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw/fake-rtc.c')
-rw-r--r--hw/fake-rtc.c59
1 files changed, 50 insertions, 9 deletions
diff --git a/hw/fake-rtc.c b/hw/fake-rtc.c
index 1b7c473..eca3f1b 100644
--- a/hw/fake-rtc.c
+++ b/hw/fake-rtc.c
@@ -17,25 +17,53 @@
#include <skiboot.h>
#include <opal.h>
#include <mem_region.h>
+#include <device.h>
+#include <timebase.h>
+#include <time-utils.h>
+#include <lock.h>
-static uint32_t *fake_ymd;
-static uint64_t *fake_hmsm;
+/* timebase when tm_offset was assigned */
+static unsigned long tb_synctime;
+
+/*
+ * Absolute time that was last assigned.
+ * Current rtc value is calculated from this.
+*/
+static struct tm tm_offset;
+
+/* protects tm_offset & tb_synctime */
+static struct lock emulation_lock;
static int64_t fake_rtc_write(uint32_t ymd, uint64_t hmsm)
{
- *fake_ymd = ymd;
- *fake_hmsm = hmsm;
+
+ lock(&emulation_lock);
+
+ datetime_to_tm(ymd, hmsm, &tm_offset);
+ tb_synctime = mftb();
+
+ unlock(&emulation_lock);
return OPAL_SUCCESS;
}
static int64_t fake_rtc_read(uint32_t *ymd, uint64_t *hmsm)
{
+
+ time_t sec;
+ struct tm tm_calculated;
+
if (!ymd || !hmsm)
return OPAL_PARAMETER;
- *ymd = *fake_ymd;
- *hmsm = *fake_hmsm;
+ /* Compute the emulated clock value */
+ lock(&emulation_lock);
+
+ sec = tb_to_secs(mftb() - tb_synctime) + mktime(&tm_offset);
+ gmtime_r(&sec, &tm_calculated);
+ tm_to_datetime(&tm_calculated, ymd, hmsm);
+
+ unlock(&emulation_lock);
return OPAL_SUCCESS;
}
@@ -43,7 +71,9 @@ static int64_t fake_rtc_read(uint32_t *ymd, uint64_t *hmsm)
void fake_rtc_init(void)
{
struct mem_region *rtc_region = NULL;
- uint32_t *rtc = NULL;
+ uint32_t *rtc = NULL, *fake_ymd;
+ uint64_t *fake_hmsm;
+ struct dt_node *np;
/* Read initial values from reserved memory */
rtc_region = find_mem_region("ibm,fake-rtc");
@@ -54,14 +84,25 @@ void fake_rtc_init(void)
return;
}
+ init_lock(&emulation_lock);
+
+ /* Fetch the initial rtc values */
rtc = (uint32_t *) rtc_region->start;
fake_ymd = rtc;
fake_hmsm = ((uint64_t *) &rtc[1]);
- prlog(PR_TRACE, "Init fake RTC to 0x%x 0x%llx\n",
- *fake_ymd, *fake_hmsm);
+ fake_rtc_write(*fake_ymd, *fake_hmsm);
+ /* Register opal calls */
opal_register(OPAL_RTC_READ, fake_rtc_read, 2);
opal_register(OPAL_RTC_WRITE, fake_rtc_write, 2);
+
+ /* add the fake rtc dt node */
+ np = dt_new(opal_node, "rtc");
+ dt_add_property_strings(np, "compatible", "ibm,opal-rtc");
+
+ prlog(PR_TRACE, "Init fake RTC to Date:%d-%d-%d Time:%d-%d-%d\n",
+ tm_offset.tm_mon, tm_offset.tm_mday, tm_offset.tm_year,
+ tm_offset.tm_hour, tm_offset.tm_min, tm_offset.tm_sec);
}