19a5b40b8SAnup Patel /* 29a5b40b8SAnup Patel * Goldfish virtual platform RTC 39a5b40b8SAnup Patel * 49a5b40b8SAnup Patel * Copyright (C) 2019 Western Digital Corporation or its affiliates. 59a5b40b8SAnup Patel * 69a5b40b8SAnup Patel * For more details on Google Goldfish virtual platform refer: 79a5b40b8SAnup Patel * https://android.googlesource.com/platform/external/qemu/+/refs/heads/emu-2.0-release/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT 89a5b40b8SAnup Patel * 99a5b40b8SAnup Patel * This program is free software; you can redistribute it and/or modify it 109a5b40b8SAnup Patel * under the terms and conditions of the GNU General Public License, 119a5b40b8SAnup Patel * version 2 or later, as published by the Free Software Foundation. 129a5b40b8SAnup Patel * 139a5b40b8SAnup Patel * This program is distributed in the hope it will be useful, but WITHOUT 149a5b40b8SAnup Patel * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 159a5b40b8SAnup Patel * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 169a5b40b8SAnup Patel * more details. 179a5b40b8SAnup Patel * 189a5b40b8SAnup Patel * You should have received a copy of the GNU General Public License along with 199a5b40b8SAnup Patel * this program. If not, see <http://www.gnu.org/licenses/>. 209a5b40b8SAnup Patel */ 219a5b40b8SAnup Patel 229a5b40b8SAnup Patel #include "qemu/osdep.h" 239a5b40b8SAnup Patel #include "hw/rtc/goldfish_rtc.h" 249a5b40b8SAnup Patel #include "migration/vmstate.h" 259a5b40b8SAnup Patel #include "hw/irq.h" 269a5b40b8SAnup Patel #include "hw/qdev-properties.h" 279a5b40b8SAnup Patel #include "hw/sysbus.h" 289a5b40b8SAnup Patel #include "qemu/bitops.h" 299a5b40b8SAnup Patel #include "qemu/timer.h" 309a5b40b8SAnup Patel #include "sysemu/sysemu.h" 31*2f93d8b0SPeter Maydell #include "sysemu/rtc.h" 329a5b40b8SAnup Patel #include "qemu/cutils.h" 339a5b40b8SAnup Patel #include "qemu/log.h" 349a5b40b8SAnup Patel 359a5b40b8SAnup Patel #include "trace.h" 369a5b40b8SAnup Patel 379a5b40b8SAnup Patel #define RTC_TIME_LOW 0x00 389a5b40b8SAnup Patel #define RTC_TIME_HIGH 0x04 399a5b40b8SAnup Patel #define RTC_ALARM_LOW 0x08 409a5b40b8SAnup Patel #define RTC_ALARM_HIGH 0x0c 419a5b40b8SAnup Patel #define RTC_IRQ_ENABLED 0x10 429a5b40b8SAnup Patel #define RTC_CLEAR_ALARM 0x14 439a5b40b8SAnup Patel #define RTC_ALARM_STATUS 0x18 449a5b40b8SAnup Patel #define RTC_CLEAR_INTERRUPT 0x1c 459a5b40b8SAnup Patel 469a5b40b8SAnup Patel static void goldfish_rtc_update(GoldfishRTCState *s) 479a5b40b8SAnup Patel { 489a5b40b8SAnup Patel qemu_set_irq(s->irq, (s->irq_pending & s->irq_enabled) ? 1 : 0); 499a5b40b8SAnup Patel } 509a5b40b8SAnup Patel 519a5b40b8SAnup Patel static void goldfish_rtc_interrupt(void *opaque) 529a5b40b8SAnup Patel { 539a5b40b8SAnup Patel GoldfishRTCState *s = (GoldfishRTCState *)opaque; 549a5b40b8SAnup Patel 559a5b40b8SAnup Patel s->alarm_running = 0; 569a5b40b8SAnup Patel s->irq_pending = 1; 579a5b40b8SAnup Patel goldfish_rtc_update(s); 589a5b40b8SAnup Patel } 599a5b40b8SAnup Patel 609a5b40b8SAnup Patel static uint64_t goldfish_rtc_get_count(GoldfishRTCState *s) 619a5b40b8SAnup Patel { 629a5b40b8SAnup Patel return s->tick_offset + (uint64_t)qemu_clock_get_ns(rtc_clock); 639a5b40b8SAnup Patel } 649a5b40b8SAnup Patel 659a5b40b8SAnup Patel static void goldfish_rtc_clear_alarm(GoldfishRTCState *s) 669a5b40b8SAnup Patel { 679a5b40b8SAnup Patel timer_del(s->timer); 689a5b40b8SAnup Patel s->alarm_running = 0; 699a5b40b8SAnup Patel } 709a5b40b8SAnup Patel 719a5b40b8SAnup Patel static void goldfish_rtc_set_alarm(GoldfishRTCState *s) 729a5b40b8SAnup Patel { 739a5b40b8SAnup Patel uint64_t ticks = goldfish_rtc_get_count(s); 749a5b40b8SAnup Patel uint64_t event = s->alarm_next; 759a5b40b8SAnup Patel 769a5b40b8SAnup Patel if (event <= ticks) { 779a5b40b8SAnup Patel goldfish_rtc_clear_alarm(s); 789a5b40b8SAnup Patel goldfish_rtc_interrupt(s); 799a5b40b8SAnup Patel } else { 809a5b40b8SAnup Patel /* 819a5b40b8SAnup Patel * We should be setting timer expiry to: 829a5b40b8SAnup Patel * qemu_clock_get_ns(rtc_clock) + (event - ticks) 839a5b40b8SAnup Patel * but this is equivalent to: 849a5b40b8SAnup Patel * event - s->tick_offset 859a5b40b8SAnup Patel */ 869a5b40b8SAnup Patel timer_mod(s->timer, event - s->tick_offset); 879a5b40b8SAnup Patel s->alarm_running = 1; 889a5b40b8SAnup Patel } 899a5b40b8SAnup Patel } 909a5b40b8SAnup Patel 919a5b40b8SAnup Patel static uint64_t goldfish_rtc_read(void *opaque, hwaddr offset, 929a5b40b8SAnup Patel unsigned size) 939a5b40b8SAnup Patel { 949a5b40b8SAnup Patel GoldfishRTCState *s = opaque; 959a5b40b8SAnup Patel uint64_t r = 0; 969a5b40b8SAnup Patel 978380b3a4SJessica Clarke /* 988380b3a4SJessica Clarke * From the documentation linked at the top of the file: 998380b3a4SJessica Clarke * 1008380b3a4SJessica Clarke * To read the value, the kernel must perform an IO_READ(TIME_LOW), which 1018380b3a4SJessica Clarke * returns an unsigned 32-bit value, before an IO_READ(TIME_HIGH), which 1028380b3a4SJessica Clarke * returns a signed 32-bit value, corresponding to the higher half of the 1038380b3a4SJessica Clarke * full value. 1048380b3a4SJessica Clarke */ 1059a5b40b8SAnup Patel switch (offset) { 1069a5b40b8SAnup Patel case RTC_TIME_LOW: 1078380b3a4SJessica Clarke r = goldfish_rtc_get_count(s); 1088380b3a4SJessica Clarke s->time_high = r >> 32; 1098380b3a4SJessica Clarke r &= 0xffffffff; 1109a5b40b8SAnup Patel break; 1119a5b40b8SAnup Patel case RTC_TIME_HIGH: 1128380b3a4SJessica Clarke r = s->time_high; 1139a5b40b8SAnup Patel break; 1149a5b40b8SAnup Patel case RTC_ALARM_LOW: 1159a5b40b8SAnup Patel r = s->alarm_next & 0xffffffff; 1169a5b40b8SAnup Patel break; 1179a5b40b8SAnup Patel case RTC_ALARM_HIGH: 1189a5b40b8SAnup Patel r = s->alarm_next >> 32; 1199a5b40b8SAnup Patel break; 1209a5b40b8SAnup Patel case RTC_IRQ_ENABLED: 1219a5b40b8SAnup Patel r = s->irq_enabled; 1229a5b40b8SAnup Patel break; 1239a5b40b8SAnup Patel case RTC_ALARM_STATUS: 1249a5b40b8SAnup Patel r = s->alarm_running; 1259a5b40b8SAnup Patel break; 1269a5b40b8SAnup Patel default: 1279a5b40b8SAnup Patel qemu_log_mask(LOG_GUEST_ERROR, 1289a5b40b8SAnup Patel "%s: offset 0x%x is UNIMP.\n", __func__, (uint32_t)offset); 1299a5b40b8SAnup Patel break; 1309a5b40b8SAnup Patel } 1319a5b40b8SAnup Patel 1329a5b40b8SAnup Patel trace_goldfish_rtc_read(offset, r); 1339a5b40b8SAnup Patel 1349a5b40b8SAnup Patel return r; 1359a5b40b8SAnup Patel } 1369a5b40b8SAnup Patel 1379a5b40b8SAnup Patel static void goldfish_rtc_write(void *opaque, hwaddr offset, 1389a5b40b8SAnup Patel uint64_t value, unsigned size) 1399a5b40b8SAnup Patel { 1409a5b40b8SAnup Patel GoldfishRTCState *s = opaque; 1419a5b40b8SAnup Patel uint64_t current_tick, new_tick; 1429a5b40b8SAnup Patel 1439a5b40b8SAnup Patel switch (offset) { 1449a5b40b8SAnup Patel case RTC_TIME_LOW: 1459a5b40b8SAnup Patel current_tick = goldfish_rtc_get_count(s); 1469a5b40b8SAnup Patel new_tick = deposit64(current_tick, 0, 32, value); 1479a5b40b8SAnup Patel s->tick_offset += new_tick - current_tick; 1489a5b40b8SAnup Patel break; 1499a5b40b8SAnup Patel case RTC_TIME_HIGH: 1509a5b40b8SAnup Patel current_tick = goldfish_rtc_get_count(s); 1519a5b40b8SAnup Patel new_tick = deposit64(current_tick, 32, 32, value); 1529a5b40b8SAnup Patel s->tick_offset += new_tick - current_tick; 1539a5b40b8SAnup Patel break; 1549a5b40b8SAnup Patel case RTC_ALARM_LOW: 1559a5b40b8SAnup Patel s->alarm_next = deposit64(s->alarm_next, 0, 32, value); 1569a5b40b8SAnup Patel goldfish_rtc_set_alarm(s); 1579a5b40b8SAnup Patel break; 1589a5b40b8SAnup Patel case RTC_ALARM_HIGH: 1599a5b40b8SAnup Patel s->alarm_next = deposit64(s->alarm_next, 32, 32, value); 1609a5b40b8SAnup Patel break; 1619a5b40b8SAnup Patel case RTC_IRQ_ENABLED: 1629a5b40b8SAnup Patel s->irq_enabled = (uint32_t)(value & 0x1); 1639a5b40b8SAnup Patel goldfish_rtc_update(s); 1649a5b40b8SAnup Patel break; 1659a5b40b8SAnup Patel case RTC_CLEAR_ALARM: 1669a5b40b8SAnup Patel goldfish_rtc_clear_alarm(s); 1679a5b40b8SAnup Patel break; 1689a5b40b8SAnup Patel case RTC_CLEAR_INTERRUPT: 1699a5b40b8SAnup Patel s->irq_pending = 0; 1709a5b40b8SAnup Patel goldfish_rtc_update(s); 1719a5b40b8SAnup Patel break; 1729a5b40b8SAnup Patel default: 1739a5b40b8SAnup Patel qemu_log_mask(LOG_GUEST_ERROR, 1749a5b40b8SAnup Patel "%s: offset 0x%x is UNIMP.\n", __func__, (uint32_t)offset); 1759a5b40b8SAnup Patel break; 1769a5b40b8SAnup Patel } 1779a5b40b8SAnup Patel 1789a5b40b8SAnup Patel trace_goldfish_rtc_write(offset, value); 1799a5b40b8SAnup Patel } 1809a5b40b8SAnup Patel 1819a5b40b8SAnup Patel static int goldfish_rtc_pre_save(void *opaque) 1829a5b40b8SAnup Patel { 1839a5b40b8SAnup Patel uint64_t delta; 1849a5b40b8SAnup Patel GoldfishRTCState *s = opaque; 1859a5b40b8SAnup Patel 1869a5b40b8SAnup Patel /* 1879a5b40b8SAnup Patel * We want to migrate this offset, which sounds straightforward. 1889a5b40b8SAnup Patel * Unfortunately, we cannot directly pass tick_offset because 1899a5b40b8SAnup Patel * rtc_clock on destination Host might not be same source Host. 1909a5b40b8SAnup Patel * 1919a5b40b8SAnup Patel * To tackle, this we pass tick_offset relative to vm_clock from 1929a5b40b8SAnup Patel * source Host and make it relative to rtc_clock at destination Host. 1939a5b40b8SAnup Patel */ 1949a5b40b8SAnup Patel delta = qemu_clock_get_ns(rtc_clock) - 1959a5b40b8SAnup Patel qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 1969a5b40b8SAnup Patel s->tick_offset_vmstate = s->tick_offset + delta; 1979a5b40b8SAnup Patel 1989a5b40b8SAnup Patel return 0; 1999a5b40b8SAnup Patel } 2009a5b40b8SAnup Patel 2019a5b40b8SAnup Patel static int goldfish_rtc_post_load(void *opaque, int version_id) 2029a5b40b8SAnup Patel { 2039a5b40b8SAnup Patel uint64_t delta; 2049a5b40b8SAnup Patel GoldfishRTCState *s = opaque; 2059a5b40b8SAnup Patel 2069a5b40b8SAnup Patel /* 2079a5b40b8SAnup Patel * We extract tick_offset from tick_offset_vmstate by doing 2089a5b40b8SAnup Patel * reverse math compared to pre_save() function. 2099a5b40b8SAnup Patel */ 2109a5b40b8SAnup Patel delta = qemu_clock_get_ns(rtc_clock) - 2119a5b40b8SAnup Patel qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 2129a5b40b8SAnup Patel s->tick_offset = s->tick_offset_vmstate - delta; 2139a5b40b8SAnup Patel 2146b9409baSLaurent Vivier goldfish_rtc_set_alarm(s); 2156b9409baSLaurent Vivier 2169a5b40b8SAnup Patel return 0; 2179a5b40b8SAnup Patel } 2189a5b40b8SAnup Patel 2199a5b40b8SAnup Patel static const MemoryRegionOps goldfish_rtc_ops = { 2209a5b40b8SAnup Patel .read = goldfish_rtc_read, 2219a5b40b8SAnup Patel .write = goldfish_rtc_write, 22216b66c56SLaurent Vivier .endianness = DEVICE_NATIVE_ENDIAN, 2239a5b40b8SAnup Patel .valid = { 2249a5b40b8SAnup Patel .min_access_size = 4, 2259a5b40b8SAnup Patel .max_access_size = 4 2269a5b40b8SAnup Patel } 2279a5b40b8SAnup Patel }; 2289a5b40b8SAnup Patel 2299a5b40b8SAnup Patel static const VMStateDescription goldfish_rtc_vmstate = { 2309a5b40b8SAnup Patel .name = TYPE_GOLDFISH_RTC, 2318380b3a4SJessica Clarke .version_id = 2, 2329a5b40b8SAnup Patel .pre_save = goldfish_rtc_pre_save, 2339a5b40b8SAnup Patel .post_load = goldfish_rtc_post_load, 2349a5b40b8SAnup Patel .fields = (VMStateField[]) { 2359a5b40b8SAnup Patel VMSTATE_UINT64(tick_offset_vmstate, GoldfishRTCState), 2369a5b40b8SAnup Patel VMSTATE_UINT64(alarm_next, GoldfishRTCState), 2379a5b40b8SAnup Patel VMSTATE_UINT32(alarm_running, GoldfishRTCState), 2389a5b40b8SAnup Patel VMSTATE_UINT32(irq_pending, GoldfishRTCState), 2399a5b40b8SAnup Patel VMSTATE_UINT32(irq_enabled, GoldfishRTCState), 2408380b3a4SJessica Clarke VMSTATE_UINT32(time_high, GoldfishRTCState), 2419a5b40b8SAnup Patel VMSTATE_END_OF_LIST() 2429a5b40b8SAnup Patel } 2439a5b40b8SAnup Patel }; 2449a5b40b8SAnup Patel 2459a5b40b8SAnup Patel static void goldfish_rtc_reset(DeviceState *dev) 2469a5b40b8SAnup Patel { 2479a5b40b8SAnup Patel GoldfishRTCState *s = GOLDFISH_RTC(dev); 2489a5b40b8SAnup Patel struct tm tm; 2499a5b40b8SAnup Patel 2509a5b40b8SAnup Patel timer_del(s->timer); 2519a5b40b8SAnup Patel 2529a5b40b8SAnup Patel qemu_get_timedate(&tm, 0); 2539a5b40b8SAnup Patel s->tick_offset = mktimegm(&tm); 2549a5b40b8SAnup Patel s->tick_offset *= NANOSECONDS_PER_SECOND; 2559a5b40b8SAnup Patel s->tick_offset -= qemu_clock_get_ns(rtc_clock); 2569a5b40b8SAnup Patel s->tick_offset_vmstate = 0; 2579a5b40b8SAnup Patel s->alarm_next = 0; 2589a5b40b8SAnup Patel s->alarm_running = 0; 2599a5b40b8SAnup Patel s->irq_pending = 0; 2609a5b40b8SAnup Patel s->irq_enabled = 0; 2619a5b40b8SAnup Patel } 2629a5b40b8SAnup Patel 2639a5b40b8SAnup Patel static void goldfish_rtc_realize(DeviceState *d, Error **errp) 2649a5b40b8SAnup Patel { 2659a5b40b8SAnup Patel SysBusDevice *dev = SYS_BUS_DEVICE(d); 2669a5b40b8SAnup Patel GoldfishRTCState *s = GOLDFISH_RTC(d); 2679a5b40b8SAnup Patel 2689a5b40b8SAnup Patel memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_rtc_ops, s, 2699a5b40b8SAnup Patel "goldfish_rtc", 0x24); 2709a5b40b8SAnup Patel sysbus_init_mmio(dev, &s->iomem); 2719a5b40b8SAnup Patel 2729a5b40b8SAnup Patel sysbus_init_irq(dev, &s->irq); 2739a5b40b8SAnup Patel 2749a5b40b8SAnup Patel s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s); 2759a5b40b8SAnup Patel } 2769a5b40b8SAnup Patel 2779a5b40b8SAnup Patel static void goldfish_rtc_class_init(ObjectClass *klass, void *data) 2789a5b40b8SAnup Patel { 2799a5b40b8SAnup Patel DeviceClass *dc = DEVICE_CLASS(klass); 2809a5b40b8SAnup Patel 2819a5b40b8SAnup Patel dc->realize = goldfish_rtc_realize; 2829a5b40b8SAnup Patel dc->reset = goldfish_rtc_reset; 2839a5b40b8SAnup Patel dc->vmsd = &goldfish_rtc_vmstate; 2849a5b40b8SAnup Patel } 2859a5b40b8SAnup Patel 2869a5b40b8SAnup Patel static const TypeInfo goldfish_rtc_info = { 2879a5b40b8SAnup Patel .name = TYPE_GOLDFISH_RTC, 2889a5b40b8SAnup Patel .parent = TYPE_SYS_BUS_DEVICE, 2899a5b40b8SAnup Patel .instance_size = sizeof(GoldfishRTCState), 2909a5b40b8SAnup Patel .class_init = goldfish_rtc_class_init, 2919a5b40b8SAnup Patel }; 2929a5b40b8SAnup Patel 2939a5b40b8SAnup Patel static void goldfish_rtc_register_types(void) 2949a5b40b8SAnup Patel { 2959a5b40b8SAnup Patel type_register_static(&goldfish_rtc_info); 2969a5b40b8SAnup Patel } 2979a5b40b8SAnup Patel 2989a5b40b8SAnup Patel type_init(goldfish_rtc_register_types) 299