aboutsummaryrefslogtreecommitdiff
path: root/hw/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'hw/rtc')
-rw-r--r--hw/rtc/Kconfig5
-rw-r--r--hw/rtc/allwinner-rtc.c10
-rw-r--r--hw/rtc/aspeed_rtc.c2
-rw-r--r--hw/rtc/ds1338.c2
-rw-r--r--hw/rtc/exynos4210_rtc.c2
-rw-r--r--hw/rtc/goldfish_rtc.c58
-rw-r--r--hw/rtc/ls7a_rtc.c2
-rw-r--r--hw/rtc/m41t80.c2
-rw-r--r--hw/rtc/m48t59-isa.c8
-rw-r--r--hw/rtc/m48t59.c9
-rw-r--r--hw/rtc/mc146818rtc.c22
-rw-r--r--hw/rtc/meson.build1
-rw-r--r--hw/rtc/pl031.c2
-rw-r--r--hw/rtc/rs5c372.c236
-rw-r--r--hw/rtc/sun4v-rtc.c2
-rw-r--r--hw/rtc/trace-events4
-rw-r--r--hw/rtc/xlnx-zynqmp-rtc.c2
17 files changed, 298 insertions, 71 deletions
diff --git a/hw/rtc/Kconfig b/hw/rtc/Kconfig
index 2fe04ec..315b0e4 100644
--- a/hw/rtc/Kconfig
+++ b/hw/rtc/Kconfig
@@ -26,3 +26,8 @@ config GOLDFISH_RTC
config LS7A_RTC
bool
+
+config RS5C372_RTC
+ bool
+ depends on I2C
+ default y if I2C_DEVICES
diff --git a/hw/rtc/allwinner-rtc.c b/hw/rtc/allwinner-rtc.c
index a19e431..a747bff 100644
--- a/hw/rtc/allwinner-rtc.c
+++ b/hw/rtc/allwinner-rtc.c
@@ -259,7 +259,7 @@ static void allwinner_rtc_write(void *opaque, hwaddr offset,
static const MemoryRegionOps allwinner_rtc_ops = {
.read = allwinner_rtc_read,
.write = allwinner_rtc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
+ .endianness = DEVICE_LITTLE_ENDIAN,
.valid = {
.min_access_size = 4,
.max_access_size = 4,
@@ -315,7 +315,7 @@ static const Property allwinner_rtc_properties[] = {
DEFINE_PROP_INT32("base-year", AwRtcState, base_year, 0),
};
-static void allwinner_rtc_class_init(ObjectClass *klass, void *data)
+static void allwinner_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@@ -330,7 +330,7 @@ static void allwinner_rtc_sun4i_init(Object *obj)
s->base_year = 2010;
}
-static void allwinner_rtc_sun4i_class_init(ObjectClass *klass, void *data)
+static void allwinner_rtc_sun4i_class_init(ObjectClass *klass, const void *data)
{
AwRtcClass *arc = AW_RTC_CLASS(klass);
@@ -346,7 +346,7 @@ static void allwinner_rtc_sun6i_init(Object *obj)
s->base_year = 1970;
}
-static void allwinner_rtc_sun6i_class_init(ObjectClass *klass, void *data)
+static void allwinner_rtc_sun6i_class_init(ObjectClass *klass, const void *data)
{
AwRtcClass *arc = AW_RTC_CLASS(klass);
@@ -362,7 +362,7 @@ static void allwinner_rtc_sun7i_init(Object *obj)
s->base_year = 1970;
}
-static void allwinner_rtc_sun7i_class_init(ObjectClass *klass, void *data)
+static void allwinner_rtc_sun7i_class_init(ObjectClass *klass, const void *data)
{
AwRtcClass *arc = AW_RTC_CLASS(klass);
allwinner_rtc_sun4i_class_init(klass, arc);
diff --git a/hw/rtc/aspeed_rtc.c b/hw/rtc/aspeed_rtc.c
index fbdeb07..c4feea2 100644
--- a/hw/rtc/aspeed_rtc.c
+++ b/hw/rtc/aspeed_rtc.c
@@ -156,7 +156,7 @@ static void aspeed_rtc_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void aspeed_rtc_class_init(ObjectClass *klass, void *data)
+static void aspeed_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/rtc/ds1338.c b/hw/rtc/ds1338.c
index 8dd17fd..5f1ee2e 100644
--- a/hw/rtc/ds1338.c
+++ b/hw/rtc/ds1338.c
@@ -220,7 +220,7 @@ static void ds1338_reset(DeviceState *dev)
s->addr_byte = false;
}
-static void ds1338_class_init(ObjectClass *klass, void *data)
+static void ds1338_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
diff --git a/hw/rtc/exynos4210_rtc.c b/hw/rtc/exynos4210_rtc.c
index aa1b3cd..624b4f6 100644
--- a/hw/rtc/exynos4210_rtc.c
+++ b/hw/rtc/exynos4210_rtc.c
@@ -592,7 +592,7 @@ static void exynos4210_rtc_finalize(Object *obj)
ptimer_free(s->ptimer_1Hz);
}
-static void exynos4210_rtc_class_init(ObjectClass *klass, void *data)
+static void exynos4210_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c
index fa1d905..78df031 100644
--- a/hw/rtc/goldfish_rtc.c
+++ b/hw/rtc/goldfish_rtc.c
@@ -178,38 +178,21 @@ static void goldfish_rtc_write(void *opaque, hwaddr offset,
trace_goldfish_rtc_write(offset, value);
}
-static int goldfish_rtc_pre_save(void *opaque)
-{
- uint64_t delta;
- GoldfishRTCState *s = opaque;
-
- /*
- * We want to migrate this offset, which sounds straightforward.
- * Unfortunately, we cannot directly pass tick_offset because
- * rtc_clock on destination Host might not be same source Host.
- *
- * To tackle, this we pass tick_offset relative to vm_clock from
- * source Host and make it relative to rtc_clock at destination Host.
- */
- delta = qemu_clock_get_ns(rtc_clock) -
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->tick_offset_vmstate = s->tick_offset + delta;
-
- return 0;
-}
-
static int goldfish_rtc_post_load(void *opaque, int version_id)
{
- uint64_t delta;
GoldfishRTCState *s = opaque;
- /*
- * We extract tick_offset from tick_offset_vmstate by doing
- * reverse math compared to pre_save() function.
- */
- delta = qemu_clock_get_ns(rtc_clock) -
- qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- s->tick_offset = s->tick_offset_vmstate - delta;
+ if (version_id < 3) {
+ /*
+ * Previous versions didn't migrate tick_offset directly. Instead, they
+ * migrated tick_offset_vmstate, which is a recalculation based on
+ * QEMU_CLOCK_VIRTUAL. We use tick_offset_vmstate when migrating from
+ * older versions.
+ */
+ uint64_t delta = qemu_clock_get_ns(rtc_clock) -
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ s->tick_offset = s->tick_offset_vmstate - delta;
+ }
goldfish_rtc_set_alarm(s);
@@ -239,8 +222,7 @@ static const MemoryRegionOps goldfish_rtc_ops[2] = {
static const VMStateDescription goldfish_rtc_vmstate = {
.name = TYPE_GOLDFISH_RTC,
- .version_id = 2,
- .pre_save = goldfish_rtc_pre_save,
+ .version_id = 3,
.post_load = goldfish_rtc_post_load,
.fields = (const VMStateField[]) {
VMSTATE_UINT64(tick_offset_vmstate, GoldfishRTCState),
@@ -249,6 +231,7 @@ static const VMStateDescription goldfish_rtc_vmstate = {
VMSTATE_UINT32(irq_pending, GoldfishRTCState),
VMSTATE_UINT32(irq_enabled, GoldfishRTCState),
VMSTATE_UINT32(time_high, GoldfishRTCState),
+ VMSTATE_UINT64_V(tick_offset, GoldfishRTCState, 3),
VMSTATE_END_OF_LIST()
}
};
@@ -256,15 +239,8 @@ static const VMStateDescription goldfish_rtc_vmstate = {
static void goldfish_rtc_reset(DeviceState *dev)
{
GoldfishRTCState *s = GOLDFISH_RTC(dev);
- struct tm tm;
timer_del(s->timer);
-
- qemu_get_timedate(&tm, 0);
- s->tick_offset = mktimegm(&tm);
- s->tick_offset *= NANOSECONDS_PER_SECOND;
- s->tick_offset -= qemu_clock_get_ns(rtc_clock);
- s->tick_offset_vmstate = 0;
s->alarm_next = 0;
s->alarm_running = 0;
s->irq_pending = 0;
@@ -275,6 +251,7 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp)
{
SysBusDevice *dev = SYS_BUS_DEVICE(d);
GoldfishRTCState *s = GOLDFISH_RTC(d);
+ struct tm tm;
memory_region_init_io(&s->iomem, OBJECT(s),
&goldfish_rtc_ops[s->big_endian], s,
@@ -284,6 +261,11 @@ static void goldfish_rtc_realize(DeviceState *d, Error **errp)
sysbus_init_irq(dev, &s->irq);
s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s);
+
+ qemu_get_timedate(&tm, 0);
+ s->tick_offset = mktimegm(&tm);
+ s->tick_offset *= NANOSECONDS_PER_SECOND;
+ s->tick_offset -= qemu_clock_get_ns(rtc_clock);
}
static const Property goldfish_rtc_properties[] = {
@@ -291,7 +273,7 @@ static const Property goldfish_rtc_properties[] = {
false),
};
-static void goldfish_rtc_class_init(ObjectClass *klass, void *data)
+static void goldfish_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/rtc/ls7a_rtc.c b/hw/rtc/ls7a_rtc.c
index fce23a3..10097b2 100644
--- a/hw/rtc/ls7a_rtc.c
+++ b/hw/rtc/ls7a_rtc.c
@@ -464,7 +464,7 @@ static const VMStateDescription vmstate_ls7a_rtc = {
}
};
-static void ls7a_rtc_class_init(ObjectClass *klass, void *data)
+static void ls7a_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_ls7a_rtc;
diff --git a/hw/rtc/m41t80.c b/hw/rtc/m41t80.c
index 9600695..c631ec3 100644
--- a/hw/rtc/m41t80.c
+++ b/hw/rtc/m41t80.c
@@ -94,7 +94,7 @@ static int m41t80_event(I2CSlave *i2c, enum i2c_event event)
return 0;
}
-static void m41t80_class_init(ObjectClass *klass, void *data)
+static void m41t80_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
diff --git a/hw/rtc/m48t59-isa.c b/hw/rtc/m48t59-isa.c
index 38bc8dc..9e2f656 100644
--- a/hw/rtc/m48t59-isa.c
+++ b/hw/rtc/m48t59-isa.c
@@ -113,7 +113,7 @@ static void m48t59_isa_realize(DeviceState *dev, Error **errp)
}
}
-static void m48txx_isa_class_init(ObjectClass *klass, void *data)
+static void m48txx_isa_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
NvramClass *nc = NVRAM_CLASS(klass);
@@ -126,10 +126,10 @@ static void m48txx_isa_class_init(ObjectClass *klass, void *data)
nc->toggle_lock = m48txx_isa_toggle_lock;
}
-static void m48txx_isa_concrete_class_init(ObjectClass *klass, void *data)
+static void m48txx_isa_concrete_class_init(ObjectClass *klass, const void *data)
{
M48txxISADeviceClass *u = M48TXX_ISA_CLASS(klass);
- M48txxInfo *info = data;
+ const M48txxInfo *info = data;
u->info = *info;
}
@@ -140,7 +140,7 @@ static const TypeInfo m48txx_isa_type_info = {
.instance_size = sizeof(M48txxISAState),
.abstract = true,
.class_init = m48txx_isa_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_NVRAM },
{ }
}
diff --git a/hw/rtc/m48t59.c b/hw/rtc/m48t59.c
index c9bd6f8..68be2da 100644
--- a/hw/rtc/m48t59.c
+++ b/hw/rtc/m48t59.c
@@ -622,7 +622,7 @@ static const Property m48t59_sysbus_properties[] = {
DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0),
};
-static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
+static void m48txx_sysbus_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
NvramClass *nc = NVRAM_CLASS(klass);
@@ -636,10 +636,11 @@ static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
nc->toggle_lock = m48txx_sysbus_toggle_lock;
}
-static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data)
+static void m48txx_sysbus_concrete_class_init(ObjectClass *klass,
+ const void *data)
{
M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass);
- M48txxInfo *info = data;
+ const M48txxInfo *info = data;
u->info = *info;
}
@@ -657,7 +658,7 @@ static const TypeInfo m48txx_sysbus_type_info = {
.instance_init = m48t59_init1,
.abstract = true,
.class_init = m48txx_sysbus_class_init,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_NVRAM },
{ }
}
diff --git a/hw/rtc/mc146818rtc.c b/hw/rtc/mc146818rtc.c
index e322fc2..f9f5cf3 100644
--- a/hw/rtc/mc146818rtc.c
+++ b/hw/rtc/mc146818rtc.c
@@ -819,7 +819,7 @@ static const VMStateDescription vmstate_rtc_irq_reinject_on_ack_count = {
static const VMStateDescription vmstate_rtc = {
.name = "mc146818rtc",
.version_id = 3,
- .minimum_version_id = 1,
+ .minimum_version_id = 3,
.pre_save = rtc_pre_save,
.post_load = rtc_post_load,
.fields = (const VMStateField[]) {
@@ -829,13 +829,13 @@ static const VMStateDescription vmstate_rtc = {
VMSTATE_TIMER_PTR(periodic_timer, MC146818RtcState),
VMSTATE_INT64(next_periodic_time, MC146818RtcState),
VMSTATE_UNUSED(3*8),
- VMSTATE_UINT32_V(irq_coalesced, MC146818RtcState, 2),
- VMSTATE_UINT32_V(period, MC146818RtcState, 2),
- VMSTATE_UINT64_V(base_rtc, MC146818RtcState, 3),
- VMSTATE_UINT64_V(last_update, MC146818RtcState, 3),
- VMSTATE_INT64_V(offset, MC146818RtcState, 3),
- VMSTATE_TIMER_PTR_V(update_timer, MC146818RtcState, 3),
- VMSTATE_UINT64_V(next_alarm_time, MC146818RtcState, 3),
+ VMSTATE_UINT32(irq_coalesced, MC146818RtcState),
+ VMSTATE_UINT32(period, MC146818RtcState),
+ VMSTATE_UINT64(base_rtc, MC146818RtcState),
+ VMSTATE_UINT64(last_update, MC146818RtcState),
+ VMSTATE_INT64(offset, MC146818RtcState),
+ VMSTATE_TIMER_PTR(update_timer, MC146818RtcState),
+ VMSTATE_UINT64(next_alarm_time, MC146818RtcState),
VMSTATE_END_OF_LIST()
},
.subsections = (const VMStateDescription * const []) {
@@ -929,8 +929,6 @@ static void rtc_realizefn(DeviceState *dev, Error **errp)
memory_region_add_subregion(&s->io, 0, &s->coalesced_io);
memory_region_add_coalescing(&s->coalesced_io, 0, 1);
- qdev_set_legacy_instance_id(dev, s->io_base, 3);
-
object_property_add_tm(OBJECT(s), "date", rtc_get_date);
qdev_init_gpio_out(dev, &s->irq, 1);
@@ -1018,7 +1016,7 @@ static void rtc_build_aml(AcpiDevAmlIf *adev, Aml *scope)
aml_append(scope, dev);
}
-static void rtc_class_initfn(ObjectClass *klass, void *data)
+static void rtc_class_initfn(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
@@ -1038,7 +1036,7 @@ static const TypeInfo mc146818rtc_info = {
.parent = TYPE_ISA_DEVICE,
.instance_size = sizeof(MC146818RtcState),
.class_init = rtc_class_initfn,
- .interfaces = (InterfaceInfo[]) {
+ .interfaces = (const InterfaceInfo[]) {
{ TYPE_ACPI_DEV_AML_IF },
{ },
},
diff --git a/hw/rtc/meson.build b/hw/rtc/meson.build
index 8ecc2d7..6c87864 100644
--- a/hw/rtc/meson.build
+++ b/hw/rtc/meson.build
@@ -13,3 +13,4 @@ system_ss.add(when: 'CONFIG_GOLDFISH_RTC', if_true: files('goldfish_rtc.c'))
system_ss.add(when: 'CONFIG_LS7A_RTC', if_true: files('ls7a_rtc.c'))
system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-rtc.c'))
system_ss.add(when: 'CONFIG_MC146818RTC', if_true: files('mc146818rtc.c'))
+system_ss.add(when: 'CONFIG_RS5C372_RTC', if_true: files('rs5c372.c'))
diff --git a/hw/rtc/pl031.c b/hw/rtc/pl031.c
index ed439bd..e545b9d 100644
--- a/hw/rtc/pl031.c
+++ b/hw/rtc/pl031.c
@@ -332,7 +332,7 @@ static const Property pl031_properties[] = {
PL031State, migrate_tick_offset, true),
};
-static void pl031_class_init(ObjectClass *klass, void *data)
+static void pl031_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/rtc/rs5c372.c b/hw/rtc/rs5c372.c
new file mode 100644
index 0000000..bb92453
--- /dev/null
+++ b/hw/rtc/rs5c372.c
@@ -0,0 +1,236 @@
+/*
+ * Ricoh RS5C372, R222x I2C RTC
+ *
+ * Copyright (c) 2025 Bernhard Beschow <shentey@gmail.com>
+ *
+ * Based on hw/rtc/ds1338.c
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/i2c/i2c.h"
+#include "hw/qdev-properties.h"
+#include "hw/resettable.h"
+#include "migration/vmstate.h"
+#include "qemu/bcd.h"
+#include "qom/object.h"
+#include "system/rtc.h"
+#include "trace.h"
+
+#define NVRAM_SIZE 0x10
+
+/* Flags definitions */
+#define SECONDS_CH 0x80
+#define HOURS_PM 0x20
+#define CTRL2_24 0x20
+
+#define TYPE_RS5C372 "rs5c372"
+OBJECT_DECLARE_SIMPLE_TYPE(RS5C372State, RS5C372)
+
+struct RS5C372State {
+ I2CSlave parent_obj;
+
+ int64_t offset;
+ uint8_t wday_offset;
+ uint8_t nvram[NVRAM_SIZE];
+ uint8_t ptr;
+ uint8_t tx_format;
+ bool addr_byte;
+};
+
+static void capture_current_time(RS5C372State *s)
+{
+ /*
+ * Capture the current time into the secondary registers which will be
+ * actually read by the data transfer operation.
+ */
+ struct tm now;
+ qemu_get_timedate(&now, s->offset);
+ s->nvram[0] = to_bcd(now.tm_sec);
+ s->nvram[1] = to_bcd(now.tm_min);
+ if (s->nvram[0xf] & CTRL2_24) {
+ s->nvram[2] = to_bcd(now.tm_hour);
+ } else {
+ int tmp = now.tm_hour;
+ if (tmp % 12 == 0) {
+ tmp += 12;
+ }
+ if (tmp <= 12) {
+ s->nvram[2] = to_bcd(tmp);
+ } else {
+ s->nvram[2] = HOURS_PM | to_bcd(tmp - 12);
+ }
+ }
+ s->nvram[3] = (now.tm_wday + s->wday_offset) % 7 + 1;
+ s->nvram[4] = to_bcd(now.tm_mday);
+ s->nvram[5] = to_bcd(now.tm_mon + 1);
+ s->nvram[6] = to_bcd(now.tm_year - 100);
+}
+
+static void inc_regptr(RS5C372State *s)
+{
+ s->ptr = (s->ptr + 1) & (NVRAM_SIZE - 1);
+}
+
+static int rs5c372_event(I2CSlave *i2c, enum i2c_event event)
+{
+ RS5C372State *s = RS5C372(i2c);
+
+ switch (event) {
+ case I2C_START_RECV:
+ /*
+ * In h/w, capture happens on any START condition, not just a
+ * START_RECV, but there is no need to actually capture on
+ * START_SEND, because the guest can't get at that data
+ * without going through a START_RECV which would overwrite it.
+ */
+ capture_current_time(s);
+ s->ptr = 0xf;
+ break;
+ case I2C_START_SEND:
+ s->addr_byte = true;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static uint8_t rs5c372_recv(I2CSlave *i2c)
+{
+ RS5C372State *s = RS5C372(i2c);
+ uint8_t res;
+
+ res = s->nvram[s->ptr];
+
+ trace_rs5c372_recv(s->ptr, res);
+
+ inc_regptr(s);
+ return res;
+}
+
+static int rs5c372_send(I2CSlave *i2c, uint8_t data)
+{
+ RS5C372State *s = RS5C372(i2c);
+
+ if (s->addr_byte) {
+ s->ptr = data >> 4;
+ s->tx_format = data & 0xf;
+ s->addr_byte = false;
+ return 0;
+ }
+
+ trace_rs5c372_send(s->ptr, data);
+
+ if (s->ptr < 7) {
+ /* Time register. */
+ struct tm now;
+ qemu_get_timedate(&now, s->offset);
+ switch (s->ptr) {
+ case 0:
+ now.tm_sec = from_bcd(data & 0x7f);
+ break;
+ case 1:
+ now.tm_min = from_bcd(data & 0x7f);
+ break;
+ case 2:
+ if (s->nvram[0xf] & CTRL2_24) {
+ now.tm_hour = from_bcd(data & 0x3f);
+ } else {
+ int tmp = from_bcd(data & (HOURS_PM - 1));
+ if (data & HOURS_PM) {
+ tmp += 12;
+ }
+ if (tmp % 12 == 0) {
+ tmp -= 12;
+ }
+ now.tm_hour = tmp;
+ }
+ break;
+ case 3:
+ {
+ /*
+ * The day field is supposed to contain a value in the range
+ * 1-7. Otherwise behavior is undefined.
+ */
+ int user_wday = (data & 7) - 1;
+ s->wday_offset = (user_wday - now.tm_wday + 7) % 7;
+ }
+ break;
+ case 4:
+ now.tm_mday = from_bcd(data & 0x3f);
+ break;
+ case 5:
+ now.tm_mon = from_bcd(data & 0x1f) - 1;
+ break;
+ case 6:
+ now.tm_year = from_bcd(data) + 100;
+ break;
+ }
+ s->offset = qemu_timedate_diff(&now);
+ } else {
+ s->nvram[s->ptr] = data;
+ }
+ inc_regptr(s);
+ return 0;
+}
+
+static void rs5c372_reset_hold(Object *obj, ResetType type)
+{
+ RS5C372State *s = RS5C372(obj);
+
+ /* The clock is running and synchronized with the host */
+ s->offset = 0;
+ s->wday_offset = 0;
+ memset(s->nvram, 0, NVRAM_SIZE);
+ s->ptr = 0;
+ s->addr_byte = false;
+}
+
+static const VMStateDescription rs5c372_vmstate = {
+ .name = "rs5c372",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_I2C_SLAVE(parent_obj, RS5C372State),
+ VMSTATE_INT64(offset, RS5C372State),
+ VMSTATE_UINT8_V(wday_offset, RS5C372State, 2),
+ VMSTATE_UINT8_ARRAY(nvram, RS5C372State, NVRAM_SIZE),
+ VMSTATE_UINT8(ptr, RS5C372State),
+ VMSTATE_UINT8(tx_format, RS5C372State),
+ VMSTATE_BOOL(addr_byte, RS5C372State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static void rs5c372_init(Object *obj)
+{
+ qdev_prop_set_uint8(DEVICE(obj), "address", 0x32);
+}
+
+static void rs5c372_class_init(ObjectClass *klass, const void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ I2CSlaveClass *k = I2C_SLAVE_CLASS(klass);
+ ResettableClass *rc = RESETTABLE_CLASS(klass);
+
+ k->event = rs5c372_event;
+ k->recv = rs5c372_recv;
+ k->send = rs5c372_send;
+ dc->vmsd = &rs5c372_vmstate;
+ rc->phases.hold = rs5c372_reset_hold;
+}
+
+static const TypeInfo rs5c372_types[] = {
+ {
+ .name = TYPE_RS5C372,
+ .parent = TYPE_I2C_SLAVE,
+ .instance_size = sizeof(RS5C372State),
+ .instance_init = rs5c372_init,
+ .class_init = rs5c372_class_init,
+ },
+};
+
+DEFINE_TYPES(rs5c372_types)
diff --git a/hw/rtc/sun4v-rtc.c b/hw/rtc/sun4v-rtc.c
index ffcc0aa..29e24ef 100644
--- a/hw/rtc/sun4v-rtc.c
+++ b/hw/rtc/sun4v-rtc.c
@@ -75,7 +75,7 @@ static void sun4v_rtc_realize(DeviceState *dev, Error **errp)
sysbus_init_mmio(sbd, &s->iomem);
}
-static void sun4v_rtc_class_init(ObjectClass *klass, void *data)
+static void sun4v_rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
diff --git a/hw/rtc/trace-events b/hw/rtc/trace-events
index 8012afe..b9f2852 100644
--- a/hw/rtc/trace-events
+++ b/hw/rtc/trace-events
@@ -35,3 +35,7 @@ m48txx_nvram_mem_write(uint32_t addr, uint32_t value) "mem write addr:0x%04x val
# goldfish_rtc.c
goldfish_rtc_read(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
goldfish_rtc_write(uint64_t addr, uint64_t value) "addr 0x%02" PRIx64 " value 0x%08" PRIx64
+
+# rs5c372.c
+rs5c372_recv(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] -> 0x%02" PRIx8
+rs5c372_send(uint32_t addr, uint8_t value) "[0x%" PRIx32 "] <- 0x%02" PRIx8
diff --git a/hw/rtc/xlnx-zynqmp-rtc.c b/hw/rtc/xlnx-zynqmp-rtc.c
index b596b60..500982a 100644
--- a/hw/rtc/xlnx-zynqmp-rtc.c
+++ b/hw/rtc/xlnx-zynqmp-rtc.c
@@ -251,7 +251,7 @@ static const VMStateDescription vmstate_rtc = {
}
};
-static void rtc_class_init(ObjectClass *klass, void *data)
+static void rtc_class_init(ObjectClass *klass, const void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);