qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

aspeed_rtc.c (4475B)


      1 /*
      2  * ASPEED Real Time Clock
      3  * Joel Stanley <joel@jms.id.au>
      4  *
      5  * Copyright 2019 IBM Corp
      6  * SPDX-License-Identifier: GPL-2.0-or-later
      7  */
      8 
      9 #include "qemu/osdep.h"
     10 #include "hw/rtc/aspeed_rtc.h"
     11 #include "migration/vmstate.h"
     12 #include "qemu/log.h"
     13 #include "qemu/timer.h"
     14 #include "sysemu/rtc.h"
     15 
     16 #include "trace.h"
     17 
     18 #define COUNTER1        (0x00 / 4)
     19 #define COUNTER2        (0x04 / 4)
     20 #define ALARM           (0x08 / 4)
     21 #define CONTROL         (0x10 / 4)
     22 #define ALARM_STATUS    (0x14 / 4)
     23 
     24 #define RTC_UNLOCKED    BIT(1)
     25 #define RTC_ENABLED     BIT(0)
     26 
     27 static void aspeed_rtc_calc_offset(AspeedRtcState *rtc)
     28 {
     29     struct tm tm;
     30     uint32_t year, cent;
     31     uint32_t reg1 = rtc->reg[COUNTER1];
     32     uint32_t reg2 = rtc->reg[COUNTER2];
     33 
     34     tm.tm_mday = (reg1 >> 24) & 0x1f;
     35     tm.tm_hour = (reg1 >> 16) & 0x1f;
     36     tm.tm_min = (reg1 >> 8) & 0x3f;
     37     tm.tm_sec = (reg1 >> 0) & 0x3f;
     38 
     39     cent = (reg2 >> 16) & 0x1f;
     40     year = (reg2 >> 8) & 0x7f;
     41     tm.tm_mon = ((reg2 >>  0) & 0x0f) - 1;
     42     tm.tm_year = year + (cent * 100) - 1900;
     43 
     44     rtc->offset = qemu_timedate_diff(&tm);
     45 }
     46 
     47 static uint32_t aspeed_rtc_get_counter(AspeedRtcState *rtc, int r)
     48 {
     49     uint32_t year, cent;
     50     struct tm now;
     51 
     52     qemu_get_timedate(&now, rtc->offset);
     53 
     54     switch (r) {
     55     case COUNTER1:
     56         return (now.tm_mday << 24) | (now.tm_hour << 16) |
     57             (now.tm_min << 8) | now.tm_sec;
     58     case COUNTER2:
     59         cent = (now.tm_year + 1900) / 100;
     60         year = now.tm_year % 100;
     61         return ((cent & 0x1f) << 16) | ((year & 0x7f) << 8) |
     62             ((now.tm_mon + 1) & 0xf);
     63     default:
     64         g_assert_not_reached();
     65     }
     66 }
     67 
     68 static uint64_t aspeed_rtc_read(void *opaque, hwaddr addr,
     69                                 unsigned size)
     70 {
     71     AspeedRtcState *rtc = opaque;
     72     uint64_t val;
     73     uint32_t r = addr >> 2;
     74 
     75     switch (r) {
     76     case COUNTER1:
     77     case COUNTER2:
     78         if (rtc->reg[CONTROL] & RTC_ENABLED) {
     79             rtc->reg[r] = aspeed_rtc_get_counter(rtc, r);
     80         }
     81         /* fall through */
     82     case CONTROL:
     83         val = rtc->reg[r];
     84         break;
     85     case ALARM:
     86     case ALARM_STATUS:
     87     default:
     88         qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr);
     89         return 0;
     90     }
     91 
     92     trace_aspeed_rtc_read(addr, val);
     93 
     94     return val;
     95 }
     96 
     97 static void aspeed_rtc_write(void *opaque, hwaddr addr,
     98                              uint64_t val, unsigned size)
     99 {
    100     AspeedRtcState *rtc = opaque;
    101     uint32_t r = addr >> 2;
    102 
    103     switch (r) {
    104     case COUNTER1:
    105     case COUNTER2:
    106         if (!(rtc->reg[CONTROL] & RTC_UNLOCKED)) {
    107             break;
    108         }
    109         /* fall through */
    110     case CONTROL:
    111         rtc->reg[r] = val;
    112         aspeed_rtc_calc_offset(rtc);
    113         break;
    114     case ALARM:
    115     case ALARM_STATUS:
    116     default:
    117         qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr);
    118         break;
    119     }
    120     trace_aspeed_rtc_write(addr, val);
    121 }
    122 
    123 static void aspeed_rtc_reset(DeviceState *d)
    124 {
    125     AspeedRtcState *rtc = ASPEED_RTC(d);
    126 
    127     rtc->offset = 0;
    128     memset(rtc->reg, 0, sizeof(rtc->reg));
    129 }
    130 
    131 static const MemoryRegionOps aspeed_rtc_ops = {
    132     .read = aspeed_rtc_read,
    133     .write = aspeed_rtc_write,
    134     .endianness = DEVICE_NATIVE_ENDIAN,
    135 };
    136 
    137 static const VMStateDescription vmstate_aspeed_rtc = {
    138     .name = TYPE_ASPEED_RTC,
    139     .version_id = 1,
    140     .fields = (VMStateField[]) {
    141         VMSTATE_UINT32_ARRAY(reg, AspeedRtcState, 0x18),
    142         VMSTATE_INT32(offset, AspeedRtcState),
    143         VMSTATE_INT32(offset, AspeedRtcState),
    144         VMSTATE_END_OF_LIST()
    145     }
    146 };
    147 
    148 static void aspeed_rtc_realize(DeviceState *dev, Error **errp)
    149 {
    150     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    151     AspeedRtcState *s = ASPEED_RTC(dev);
    152 
    153     sysbus_init_irq(sbd, &s->irq);
    154 
    155     memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_rtc_ops, s,
    156                           "aspeed-rtc", 0x18ULL);
    157     sysbus_init_mmio(sbd, &s->iomem);
    158 }
    159 
    160 static void aspeed_rtc_class_init(ObjectClass *klass, void *data)
    161 {
    162     DeviceClass *dc = DEVICE_CLASS(klass);
    163 
    164     dc->realize = aspeed_rtc_realize;
    165     dc->vmsd = &vmstate_aspeed_rtc;
    166     dc->reset = aspeed_rtc_reset;
    167 }
    168 
    169 static const TypeInfo aspeed_rtc_info = {
    170     .name          = TYPE_ASPEED_RTC,
    171     .parent        = TYPE_SYS_BUS_DEVICE,
    172     .instance_size = sizeof(AspeedRtcState),
    173     .class_init    = aspeed_rtc_class_init,
    174 };
    175 
    176 static void aspeed_rtc_register_types(void)
    177 {
    178     type_register_static(&aspeed_rtc_info);
    179 }
    180 
    181 type_init(aspeed_rtc_register_types)