diff options
author | Vaibhav Jain <vaibhav@linux.vnet.ibm.com> | 2015-09-29 10:31:48 +0530 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2015-10-07 18:26:00 +1100 |
commit | 6c1658f454e14d5984bef7a9b4d65dab7f32c133 (patch) | |
tree | df4d4b500a37c1c490f04e565df57a672a826b54 /hw/fake-rtc.c | |
parent | 3dfe3d50edede734d9d32bbbf64cff9ae65c28c0 (diff) | |
download | skiboot-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.c | 59 |
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); } |