2 * Goldfish virtual platform RTC
4 * Copyright (C) 2019 Western Digital Corporation or its affiliates.
6 * For more details on Google Goldfish virtual platform refer:
7 * https://android.googlesource.com/platform/external/qemu/+/refs/heads/emu-2.0-release/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms and conditions of the GNU General Public License,
11 * version 2 or later, as published by the Free Software Foundation.
13 * This program is distributed in the hope it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "qemu/osdep.h"
23 #include "hw/rtc/goldfish_rtc.h"
24 #include "migration/vmstate.h"
26 #include "hw/qdev-properties.h"
27 #include "hw/sysbus.h"
28 #include "qemu/bitops.h"
29 #include "qemu/timer.h"
30 #include "sysemu/sysemu.h"
31 #include "sysemu/rtc.h"
32 #include "qemu/cutils.h"
37 #define RTC_TIME_LOW 0x00
38 #define RTC_TIME_HIGH 0x04
39 #define RTC_ALARM_LOW 0x08
40 #define RTC_ALARM_HIGH 0x0c
41 #define RTC_IRQ_ENABLED 0x10
42 #define RTC_CLEAR_ALARM 0x14
43 #define RTC_ALARM_STATUS 0x18
44 #define RTC_CLEAR_INTERRUPT 0x1c
46 static void goldfish_rtc_update(GoldfishRTCState
*s
)
48 qemu_set_irq(s
->irq
, (s
->irq_pending
& s
->irq_enabled
) ? 1 : 0);
51 static void goldfish_rtc_interrupt(void *opaque
)
53 GoldfishRTCState
*s
= (GoldfishRTCState
*)opaque
;
57 goldfish_rtc_update(s
);
60 static uint64_t goldfish_rtc_get_count(GoldfishRTCState
*s
)
62 return s
->tick_offset
+ (uint64_t)qemu_clock_get_ns(rtc_clock
);
65 static void goldfish_rtc_clear_alarm(GoldfishRTCState
*s
)
71 static void goldfish_rtc_set_alarm(GoldfishRTCState
*s
)
73 uint64_t ticks
= goldfish_rtc_get_count(s
);
74 uint64_t event
= s
->alarm_next
;
77 goldfish_rtc_clear_alarm(s
);
78 goldfish_rtc_interrupt(s
);
81 * We should be setting timer expiry to:
82 * qemu_clock_get_ns(rtc_clock) + (event - ticks)
83 * but this is equivalent to:
84 * event - s->tick_offset
86 timer_mod(s
->timer
, event
- s
->tick_offset
);
91 static uint64_t goldfish_rtc_read(void *opaque
, hwaddr offset
,
94 GoldfishRTCState
*s
= opaque
;
98 * From the documentation linked at the top of the file:
100 * To read the value, the kernel must perform an IO_READ(TIME_LOW), which
101 * returns an unsigned 32-bit value, before an IO_READ(TIME_HIGH), which
102 * returns a signed 32-bit value, corresponding to the higher half of the
107 r
= goldfish_rtc_get_count(s
);
108 s
->time_high
= r
>> 32;
115 r
= s
->alarm_next
& 0xffffffff;
118 r
= s
->alarm_next
>> 32;
120 case RTC_IRQ_ENABLED
:
123 case RTC_ALARM_STATUS
:
124 r
= s
->alarm_running
;
127 qemu_log_mask(LOG_GUEST_ERROR
,
128 "%s: offset 0x%x is UNIMP.\n", __func__
, (uint32_t)offset
);
132 trace_goldfish_rtc_read(offset
, r
);
137 static void goldfish_rtc_write(void *opaque
, hwaddr offset
,
138 uint64_t value
, unsigned size
)
140 GoldfishRTCState
*s
= opaque
;
141 uint64_t current_tick
, new_tick
;
145 current_tick
= goldfish_rtc_get_count(s
);
146 new_tick
= deposit64(current_tick
, 0, 32, value
);
147 s
->tick_offset
+= new_tick
- current_tick
;
150 current_tick
= goldfish_rtc_get_count(s
);
151 new_tick
= deposit64(current_tick
, 32, 32, value
);
152 s
->tick_offset
+= new_tick
- current_tick
;
155 s
->alarm_next
= deposit64(s
->alarm_next
, 0, 32, value
);
156 goldfish_rtc_set_alarm(s
);
159 s
->alarm_next
= deposit64(s
->alarm_next
, 32, 32, value
);
161 case RTC_IRQ_ENABLED
:
162 s
->irq_enabled
= (uint32_t)(value
& 0x1);
163 goldfish_rtc_update(s
);
165 case RTC_CLEAR_ALARM
:
166 goldfish_rtc_clear_alarm(s
);
168 case RTC_CLEAR_INTERRUPT
:
170 goldfish_rtc_update(s
);
173 qemu_log_mask(LOG_GUEST_ERROR
,
174 "%s: offset 0x%x is UNIMP.\n", __func__
, (uint32_t)offset
);
178 trace_goldfish_rtc_write(offset
, value
);
181 static int goldfish_rtc_pre_save(void *opaque
)
184 GoldfishRTCState
*s
= opaque
;
187 * We want to migrate this offset, which sounds straightforward.
188 * Unfortunately, we cannot directly pass tick_offset because
189 * rtc_clock on destination Host might not be same source Host.
191 * To tackle, this we pass tick_offset relative to vm_clock from
192 * source Host and make it relative to rtc_clock at destination Host.
194 delta
= qemu_clock_get_ns(rtc_clock
) -
195 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
196 s
->tick_offset_vmstate
= s
->tick_offset
+ delta
;
201 static int goldfish_rtc_post_load(void *opaque
, int version_id
)
204 GoldfishRTCState
*s
= opaque
;
207 * We extract tick_offset from tick_offset_vmstate by doing
208 * reverse math compared to pre_save() function.
210 delta
= qemu_clock_get_ns(rtc_clock
) -
211 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
212 s
->tick_offset
= s
->tick_offset_vmstate
- delta
;
214 goldfish_rtc_set_alarm(s
);
219 static const MemoryRegionOps goldfish_rtc_ops
[2] = {
221 .read
= goldfish_rtc_read
,
222 .write
= goldfish_rtc_write
,
223 .endianness
= DEVICE_LITTLE_ENDIAN
,
225 .min_access_size
= 4,
230 .read
= goldfish_rtc_read
,
231 .write
= goldfish_rtc_write
,
232 .endianness
= DEVICE_BIG_ENDIAN
,
234 .min_access_size
= 4,
240 static const VMStateDescription goldfish_rtc_vmstate
= {
241 .name
= TYPE_GOLDFISH_RTC
,
243 .pre_save
= goldfish_rtc_pre_save
,
244 .post_load
= goldfish_rtc_post_load
,
245 .fields
= (const VMStateField
[]) {
246 VMSTATE_UINT64(tick_offset_vmstate
, GoldfishRTCState
),
247 VMSTATE_UINT64(alarm_next
, GoldfishRTCState
),
248 VMSTATE_UINT32(alarm_running
, GoldfishRTCState
),
249 VMSTATE_UINT32(irq_pending
, GoldfishRTCState
),
250 VMSTATE_UINT32(irq_enabled
, GoldfishRTCState
),
251 VMSTATE_UINT32(time_high
, GoldfishRTCState
),
252 VMSTATE_END_OF_LIST()
256 static void goldfish_rtc_reset(DeviceState
*dev
)
258 GoldfishRTCState
*s
= GOLDFISH_RTC(dev
);
263 qemu_get_timedate(&tm
, 0);
264 s
->tick_offset
= mktimegm(&tm
);
265 s
->tick_offset
*= NANOSECONDS_PER_SECOND
;
266 s
->tick_offset
-= qemu_clock_get_ns(rtc_clock
);
267 s
->tick_offset_vmstate
= 0;
269 s
->alarm_running
= 0;
274 static void goldfish_rtc_realize(DeviceState
*d
, Error
**errp
)
276 SysBusDevice
*dev
= SYS_BUS_DEVICE(d
);
277 GoldfishRTCState
*s
= GOLDFISH_RTC(d
);
279 memory_region_init_io(&s
->iomem
, OBJECT(s
),
280 &goldfish_rtc_ops
[s
->big_endian
], s
,
281 "goldfish_rtc", 0x24);
282 sysbus_init_mmio(dev
, &s
->iomem
);
284 sysbus_init_irq(dev
, &s
->irq
);
286 s
->timer
= timer_new_ns(rtc_clock
, goldfish_rtc_interrupt
, s
);
289 static Property goldfish_rtc_properties
[] = {
290 DEFINE_PROP_BOOL("big-endian", GoldfishRTCState
, big_endian
,
292 DEFINE_PROP_END_OF_LIST(),
295 static void goldfish_rtc_class_init(ObjectClass
*klass
, void *data
)
297 DeviceClass
*dc
= DEVICE_CLASS(klass
);
299 device_class_set_props(dc
, goldfish_rtc_properties
);
300 dc
->realize
= goldfish_rtc_realize
;
301 device_class_set_legacy_reset(dc
, goldfish_rtc_reset
);
302 dc
->vmsd
= &goldfish_rtc_vmstate
;
305 static const TypeInfo goldfish_rtc_info
= {
306 .name
= TYPE_GOLDFISH_RTC
,
307 .parent
= TYPE_SYS_BUS_DEVICE
,
308 .instance_size
= sizeof(GoldfishRTCState
),
309 .class_init
= goldfish_rtc_class_init
,
312 static void goldfish_rtc_register_types(void)
314 type_register_static(&goldfish_rtc_info
);
317 type_init(goldfish_rtc_register_types
)