qemu/hw/rtc/goldfish_rtc.c
<<
>>
Prefs
   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
  46static void goldfish_rtc_update(GoldfishRTCState *s)
  47{
  48    qemu_set_irq(s->irq, (s->irq_pending & s->irq_enabled) ? 1 : 0);
  49}
  50
  51static 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
  60static uint64_t goldfish_rtc_get_count(GoldfishRTCState *s)
  61{
  62    return s->tick_offset + (uint64_t)qemu_clock_get_ns(rtc_clock);
  63}
  64
  65static void goldfish_rtc_clear_alarm(GoldfishRTCState *s)
  66{
  67    timer_del(s->timer);
  68    s->alarm_running = 0;
  69}
  70
  71static 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
  91static 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
 137static 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
 181static 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
 201static 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    goldfish_rtc_set_alarm(s);
 215
 216    return 0;
 217}
 218
 219static const MemoryRegionOps goldfish_rtc_ops = {
 220    .read = goldfish_rtc_read,
 221    .write = goldfish_rtc_write,
 222    .endianness = DEVICE_NATIVE_ENDIAN,
 223    .valid = {
 224        .min_access_size = 4,
 225        .max_access_size = 4
 226    }
 227};
 228
 229static const VMStateDescription goldfish_rtc_vmstate = {
 230    .name = TYPE_GOLDFISH_RTC,
 231    .version_id = 2,
 232    .pre_save = goldfish_rtc_pre_save,
 233    .post_load = goldfish_rtc_post_load,
 234    .fields = (VMStateField[]) {
 235        VMSTATE_UINT64(tick_offset_vmstate, GoldfishRTCState),
 236        VMSTATE_UINT64(alarm_next, GoldfishRTCState),
 237        VMSTATE_UINT32(alarm_running, GoldfishRTCState),
 238        VMSTATE_UINT32(irq_pending, GoldfishRTCState),
 239        VMSTATE_UINT32(irq_enabled, GoldfishRTCState),
 240        VMSTATE_UINT32(time_high, GoldfishRTCState),
 241        VMSTATE_END_OF_LIST()
 242    }
 243};
 244
 245static void goldfish_rtc_reset(DeviceState *dev)
 246{
 247    GoldfishRTCState *s = GOLDFISH_RTC(dev);
 248    struct tm tm;
 249
 250    timer_del(s->timer);
 251
 252    qemu_get_timedate(&tm, 0);
 253    s->tick_offset = mktimegm(&tm);
 254    s->tick_offset *= NANOSECONDS_PER_SECOND;
 255    s->tick_offset -= qemu_clock_get_ns(rtc_clock);
 256    s->tick_offset_vmstate = 0;
 257    s->alarm_next = 0;
 258    s->alarm_running = 0;
 259    s->irq_pending = 0;
 260    s->irq_enabled = 0;
 261}
 262
 263static void goldfish_rtc_realize(DeviceState *d, Error **errp)
 264{
 265    SysBusDevice *dev = SYS_BUS_DEVICE(d);
 266    GoldfishRTCState *s = GOLDFISH_RTC(d);
 267
 268    memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_rtc_ops, s,
 269                          "goldfish_rtc", 0x24);
 270    sysbus_init_mmio(dev, &s->iomem);
 271
 272    sysbus_init_irq(dev, &s->irq);
 273
 274    s->timer = timer_new_ns(rtc_clock, goldfish_rtc_interrupt, s);
 275}
 276
 277static void goldfish_rtc_class_init(ObjectClass *klass, void *data)
 278{
 279    DeviceClass *dc = DEVICE_CLASS(klass);
 280
 281    dc->realize = goldfish_rtc_realize;
 282    dc->reset = goldfish_rtc_reset;
 283    dc->vmsd = &goldfish_rtc_vmstate;
 284}
 285
 286static const TypeInfo goldfish_rtc_info = {
 287    .name          = TYPE_GOLDFISH_RTC,
 288    .parent        = TYPE_SYS_BUS_DEVICE,
 289    .instance_size = sizeof(GoldfishRTCState),
 290    .class_init    = goldfish_rtc_class_init,
 291};
 292
 293static void goldfish_rtc_register_types(void)
 294{
 295    type_register_static(&goldfish_rtc_info);
 296}
 297
 298type_init(goldfish_rtc_register_types)
 299