1 /* 2 * Goldfish virtual platform RTC 3 * 4 * Copyright (C) 2019 Western Digital Corporation or its affiliates. 5 * 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 8 * 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. 12 * 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 16 * more details. 17 * 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/>. 20 */ 21 22 #include "qemu/osdep.h" 23 #include "qemu-common.h" 24 #include "hw/rtc/goldfish_rtc.h" 25 #include "migration/vmstate.h" 26 #include "hw/irq.h" 27 #include "hw/qdev-properties.h" 28 #include "hw/sysbus.h" 29 #include "qemu/bitops.h" 30 #include "qemu/timer.h" 31 #include "sysemu/sysemu.h" 32 #include "qemu/cutils.h" 33 #include "qemu/log.h" 34 35 #include "trace.h" 36 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 45 46 static void goldfish_rtc_update(GoldfishRTCState *s) 47 { 48 qemu_set_irq(s->irq, (s->irq_pending & s->irq_enabled) ? 1 : 0); 49 } 50 51 static void goldfish_rtc_interrupt(void *opaque) 52 { 53 GoldfishRTCState *s = (GoldfishRTCState *)opaque; 54 55 s->alarm_running = 0; 56 s->irq_pending = 1; 57 goldfish_rtc_update(s); 58 } 59 60 static uint64_t goldfish_rtc_get_count(GoldfishRTCState *s) 61 { 62 return s->tick_offset + (uint64_t)qemu_clock_get_ns(rtc_clock); 63 } 64 65 static void goldfish_rtc_clear_alarm(GoldfishRTCState *s) 66 { 67 timer_del(s->timer); 68 s->alarm_running = 0; 69 } 70 71 static void goldfish_rtc_set_alarm(GoldfishRTCState *s) 72 { 73 uint64_t ticks = goldfish_rtc_get_count(s); 74 uint64_t event = s->alarm_next; 75 76 if (event <= ticks) { 77 goldfish_rtc_clear_alarm(s); 78 goldfish_rtc_interrupt(s); 79 } else { 80 /* 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 85 */ 86 timer_mod(s->timer, event - s->tick_offset); 87 s->alarm_running = 1; 88 } 89 } 90 91 static uint64_t goldfish_rtc_read(void *opaque, hwaddr offset, 92 unsigned size) 93 { 94 GoldfishRTCState *s = opaque; 95 uint64_t r = 0; 96 97 switch (offset) { 98 case RTC_TIME_LOW: 99 r = goldfish_rtc_get_count(s) & 0xffffffff; 100 break; 101 case RTC_TIME_HIGH: 102 r = goldfish_rtc_get_count(s) >> 32; 103 break; 104 case RTC_ALARM_LOW: 105 r = s->alarm_next & 0xffffffff; 106 break; 107 case RTC_ALARM_HIGH: 108 r = s->alarm_next >> 32; 109 break; 110 case RTC_IRQ_ENABLED: 111 r = s->irq_enabled; 112 break; 113 case RTC_ALARM_STATUS: 114 r = s->alarm_running; 115 break; 116 default: 117 qemu_log_mask(LOG_GUEST_ERROR, 118 "%s: offset 0x%x is UNIMP.\n", __func__, (uint32_t)offset); 119 break; 120 } 121 122 trace_goldfish_rtc_read(offset, r); 123 124 return r; 125 } 126 127 static void goldfish_rtc_write(void *opaque, hwaddr offset, 128 uint64_t value, unsigned size) 129 { 130 GoldfishRTCState *s = opaque; 131 uint64_t current_tick, new_tick; 132 133 switch (offset) { 134 case RTC_TIME_LOW: 135 current_tick = goldfish_rtc_get_count(s); 136 new_tick = deposit64(current_tick, 0, 32, value); 137 s->tick_offset += new_tick - current_tick; 138 break; 139 case RTC_TIME_HIGH: 140 current_tick = goldfish_rtc_get_count(s); 141 new_tick = deposit64(current_tick, 32, 32, value); 142 s->tick_offset += new_tick - current_tick; 143 break; 144 case RTC_ALARM_LOW: 145 s->alarm_next = deposit64(s->alarm_next, 0, 32, value); 146 goldfish_rtc_set_alarm(s); 147 break; 148 case RTC_ALARM_HIGH: 149 s->alarm_next = deposit64(s->alarm_next, 32, 32, value); 150 break; 151 case RTC_IRQ_ENABLED: 152 s->irq_enabled = (uint32_t)(value & 0x1); 153 goldfish_rtc_update(s); 154 break; 155 case RTC_CLEAR_ALARM: 156 goldfish_rtc_clear_alarm(s); 157 break; 158 case RTC_CLEAR_INTERRUPT: 159 s->irq_pending = 0; 160 goldfish_rtc_update(s); 161 break; 162 default: 163 qemu_log_mask(LOG_GUEST_ERROR, 164 "%s: offset 0x%x is UNIMP.\n", __func__, (uint32_t)offset); 165 break; 166 } 167 168 trace_goldfish_rtc_write(offset, value); 169 } 170 171 static int goldfish_rtc_pre_save(void *opaque) 172 { 173 uint64_t delta; 174 GoldfishRTCState *s = opaque; 175 176 /* 177 * We want to migrate this offset, which sounds straightforward. 178 * Unfortunately, we cannot directly pass tick_offset because 179 * rtc_clock on destination Host might not be same source Host. 180 * 181 * To tackle, this we pass tick_offset relative to vm_clock from 182 * source Host and make it relative to rtc_clock at destination Host. 183 */ 184 delta = qemu_clock_get_ns(rtc_clock) - 185 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 186 s->tick_offset_vmstate = s->tick_offset + delta; 187 188 return 0; 189 } 190 191 static int goldfish_rtc_post_load(void *opaque, int version_id) 192 { 193 uint64_t delta; 194 GoldfishRTCState *s = opaque; 195 196 /* 197 * We extract tick_offset from tick_offset_vmstate by doing 198 * reverse math compared to pre_save() function. 199 */ 200 delta = qemu_clock_get_ns(rtc_clock) - 201 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 202 s->tick_offset = s->tick_offset_vmstate - delta; 203 204 return 0; 205 } 206 207 static const MemoryRegionOps goldfish_rtc_ops = { 208 .read = goldfish_rtc_read, 209 .write = goldfish_rtc_write, 210 .endianness = DEVICE_LITTLE_ENDIAN, 211 .valid = { 212 .min_access_size = 4, 213 .max_access_size = 4 214 } 215 }; 216 217 static const VMStateDescription goldfish_rtc_vmstate = { 218 .name = TYPE_GOLDFISH_RTC, 219 .version_id = 1, 220 .pre_save = goldfish_rtc_pre_save, 221 .post_load = goldfish_rtc_post_load, 222 .fields = (VMStateField[]) { 223 VMSTATE_UINT64(tick_offset_vmstate, GoldfishRTCState), 224 VMSTATE_UINT64(alarm_next, GoldfishRTCState), 225 VMSTATE_UINT32(alarm_running, GoldfishRTCState), 226 VMSTATE_UINT32(irq_pending, GoldfishRTCState), 227 VMSTATE_UINT32(irq_enabled, GoldfishRTCState), 228 VMSTATE_END_OF_LIST() 229 } 230 }; 231 232 static void goldfish_rtc_reset(DeviceState *dev) 233 { 234 GoldfishRTCState *s = GOLDFISH_RTC(dev); 235 struct tm tm; 236 237 timer_del(s->timer); 238 239 qemu_get_timedate(&tm, 0); 240 s->tick_offset = mktimegm(&tm); 241 s->tick_offset *= NANOSECONDS_PER_SECOND; 242 s->tick_offset -= qemu_clock_get_ns(rtc_clock); 243 s->tick_offset_vmstate = 0; 244 s->alarm_next = 0; 245 s->alarm_running = 0; 246 s->irq_pending = 0; 247 s->irq_enabled = 0; 248 } 249 250 static void goldfish_rtc_realize(DeviceState *d, Error **errp) 251 { 252 SysBusDevice *dev = SYS_BUS_DEVICE(d); 253 GoldfishRTCState *s = GOLDFISH_RTC(d); 254 255 memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_rtc_ops, s, 256 "goldfish_rtc", 0x24); 257 sysbus_init_mmio(dev, &s->iomem); 258 259 sysbus_init_irq(dev, &s->irq); 260 261 s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s); 262 } 263 264 static void goldfish_rtc_class_init(ObjectClass *klass, void *data) 265 { 266 DeviceClass *dc = DEVICE_CLASS(klass); 267 268 dc->realize = goldfish_rtc_realize; 269 dc->reset = goldfish_rtc_reset; 270 dc->vmsd = &goldfish_rtc_vmstate; 271 } 272 273 static const TypeInfo goldfish_rtc_info = { 274 .name = TYPE_GOLDFISH_RTC, 275 .parent = TYPE_SYS_BUS_DEVICE, 276 .instance_size = sizeof(GoldfishRTCState), 277 .class_init = goldfish_rtc_class_init, 278 }; 279 280 static void goldfish_rtc_register_types(void) 281 { 282 type_register_static(&goldfish_rtc_info); 283 } 284 285 type_init(goldfish_rtc_register_types) 286