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 /* 98 * From the documentation linked at the top of the file: 99 * 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 103 * full value. 104 */ 105 switch (offset) { 106 case RTC_TIME_LOW: 107 r = goldfish_rtc_get_count(s); 108 s->time_high = r >> 32; 109 r &= 0xffffffff; 110 break; 111 case RTC_TIME_HIGH: 112 r = s->time_high; 113 break; 114 case RTC_ALARM_LOW: 115 r = s->alarm_next & 0xffffffff; 116 break; 117 case RTC_ALARM_HIGH: 118 r = s->alarm_next >> 32; 119 break; 120 case RTC_IRQ_ENABLED: 121 r = s->irq_enabled; 122 break; 123 case RTC_ALARM_STATUS: 124 r = s->alarm_running; 125 break; 126 default: 127 qemu_log_mask(LOG_GUEST_ERROR, 128 "%s: offset 0x%x is UNIMP.\n", __func__, (uint32_t)offset); 129 break; 130 } 131 132 trace_goldfish_rtc_read(offset, r); 133 134 return r; 135 } 136 137 static void goldfish_rtc_write(void *opaque, hwaddr offset, 138 uint64_t value, unsigned size) 139 { 140 GoldfishRTCState *s = opaque; 141 uint64_t current_tick, new_tick; 142 143 switch (offset) { 144 case RTC_TIME_LOW: 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; 148 break; 149 case RTC_TIME_HIGH: 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; 153 break; 154 case RTC_ALARM_LOW: 155 s->alarm_next = deposit64(s->alarm_next, 0, 32, value); 156 goldfish_rtc_set_alarm(s); 157 break; 158 case RTC_ALARM_HIGH: 159 s->alarm_next = deposit64(s->alarm_next, 32, 32, value); 160 break; 161 case RTC_IRQ_ENABLED: 162 s->irq_enabled = (uint32_t)(value & 0x1); 163 goldfish_rtc_update(s); 164 break; 165 case RTC_CLEAR_ALARM: 166 goldfish_rtc_clear_alarm(s); 167 break; 168 case RTC_CLEAR_INTERRUPT: 169 s->irq_pending = 0; 170 goldfish_rtc_update(s); 171 break; 172 default: 173 qemu_log_mask(LOG_GUEST_ERROR, 174 "%s: offset 0x%x is UNIMP.\n", __func__, (uint32_t)offset); 175 break; 176 } 177 178 trace_goldfish_rtc_write(offset, value); 179 } 180 181 static int goldfish_rtc_pre_save(void *opaque) 182 { 183 uint64_t delta; 184 GoldfishRTCState *s = opaque; 185 186 /* 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. 190 * 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. 193 */ 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; 197 198 return 0; 199 } 200 201 static int goldfish_rtc_post_load(void *opaque, int version_id) 202 { 203 uint64_t delta; 204 GoldfishRTCState *s = opaque; 205 206 /* 207 * We extract tick_offset from tick_offset_vmstate by doing 208 * reverse math compared to pre_save() function. 209 */ 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; 213 214 return 0; 215 } 216 217 static const MemoryRegionOps goldfish_rtc_ops = { 218 .read = goldfish_rtc_read, 219 .write = goldfish_rtc_write, 220 .endianness = DEVICE_LITTLE_ENDIAN, 221 .valid = { 222 .min_access_size = 4, 223 .max_access_size = 4 224 } 225 }; 226 227 static const VMStateDescription goldfish_rtc_vmstate = { 228 .name = TYPE_GOLDFISH_RTC, 229 .version_id = 2, 230 .pre_save = goldfish_rtc_pre_save, 231 .post_load = goldfish_rtc_post_load, 232 .fields = (VMStateField[]) { 233 VMSTATE_UINT64(tick_offset_vmstate, GoldfishRTCState), 234 VMSTATE_UINT64(alarm_next, GoldfishRTCState), 235 VMSTATE_UINT32(alarm_running, GoldfishRTCState), 236 VMSTATE_UINT32(irq_pending, GoldfishRTCState), 237 VMSTATE_UINT32(irq_enabled, GoldfishRTCState), 238 VMSTATE_UINT32(time_high, GoldfishRTCState), 239 VMSTATE_END_OF_LIST() 240 } 241 }; 242 243 static void goldfish_rtc_reset(DeviceState *dev) 244 { 245 GoldfishRTCState *s = GOLDFISH_RTC(dev); 246 struct tm tm; 247 248 timer_del(s->timer); 249 250 qemu_get_timedate(&tm, 0); 251 s->tick_offset = mktimegm(&tm); 252 s->tick_offset *= NANOSECONDS_PER_SECOND; 253 s->tick_offset -= qemu_clock_get_ns(rtc_clock); 254 s->tick_offset_vmstate = 0; 255 s->alarm_next = 0; 256 s->alarm_running = 0; 257 s->irq_pending = 0; 258 s->irq_enabled = 0; 259 } 260 261 static void goldfish_rtc_realize(DeviceState *d, Error **errp) 262 { 263 SysBusDevice *dev = SYS_BUS_DEVICE(d); 264 GoldfishRTCState *s = GOLDFISH_RTC(d); 265 266 memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_rtc_ops, s, 267 "goldfish_rtc", 0x24); 268 sysbus_init_mmio(dev, &s->iomem); 269 270 sysbus_init_irq(dev, &s->irq); 271 272 s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s); 273 } 274 275 static void goldfish_rtc_class_init(ObjectClass *klass, void *data) 276 { 277 DeviceClass *dc = DEVICE_CLASS(klass); 278 279 dc->realize = goldfish_rtc_realize; 280 dc->reset = goldfish_rtc_reset; 281 dc->vmsd = &goldfish_rtc_vmstate; 282 } 283 284 static const TypeInfo goldfish_rtc_info = { 285 .name = TYPE_GOLDFISH_RTC, 286 .parent = TYPE_SYS_BUS_DEVICE, 287 .instance_size = sizeof(GoldfishRTCState), 288 .class_init = goldfish_rtc_class_init, 289 }; 290 291 static void goldfish_rtc_register_types(void) 292 { 293 type_register_static(&goldfish_rtc_info); 294 } 295 296 type_init(goldfish_rtc_register_types) 297