diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-10-25 14:17:08 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-10-25 14:17:08 +0100 |
commit | bad76ac319556dab2497429d473b49a237672e1c (patch) | |
tree | b97e8459af7e56c945ae0e033d9e36547e13004c /hw/rtc/aspeed_rtc.c | |
parent | 7bc8f9734213b76e76631a483be13d6737c2adbc (diff) | |
parent | fabb862f76f093cdd1610571de9ba714d3333c1c (diff) |
Merge remote-tracking branch 'remotes/vivier2/tags/trivial-branch-pull-request' into staging
Fix typos and docs, trivial changes and RTC devices split
# gpg: Signature made Fri 25 Oct 2019 09:35:02 BST
# gpg: using RSA key CD2F75DDC8E3A4DC2E4F5173F30C38BD3F2FBE3C
# gpg: issuer "laurent@vivier.eu"
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>" [full]
# gpg: aka "Laurent Vivier <laurent@vivier.eu>" [full]
# gpg: aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>" [full]
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F 5173 F30C 38BD 3F2F BE3C
* remotes/vivier2/tags/trivial-branch-pull-request:
hw/rtc/aspeed_rtc: Remove unused includes
hw/rtc/xlnx-zynqmp-rtc: Remove unused "ptimer.h" include
hw/rtc/mc146818: Include mc146818rtc_regs.h a bit less
hw: Move Aspeed RTC from hw/timer/ to hw/rtc/ subdirectory
hw: Move Exynos4210 RTC from hw/timer/ to hw/rtc/ subdirectory
hw: Move Xilinx ZynqMP RTC from hw/timer/ to hw/rtc/ subdirectory
hw: Move DS1338 device from hw/timer/ to hw/rtc/ subdirectory
hw: Move TWL92230 device from hw/timer/ to hw/rtc/ subdirectory
hw: Move sun4v hypervisor RTC from hw/timer/ to hw/rtc/ subdirectory
hw: Move M41T80 device from hw/timer/ to hw/rtc/ subdirectory
hw: Move M48T59 device from hw/timer/ to hw/rtc/ subdirectory
hw: Move MC146818 device from hw/timer/ to hw/rtc/ subdirectory
hw: Move PL031 device from hw/timer/ to hw/rtc/ subdirectory
hw/timer: Compile devices not target-dependent as common object
qemu-timer: reuse MIN macro in qemu_timeout_ns_to_ms
event_notifier: avoid dandling file descriptor in event_notifier_cleanup
util/async: avoid useless cast
pci_bridge: fix a typo in comment
qemu-options.hx: Update for reboot-timeout parameter
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
# Conflicts:
# hw/timer/trace-events
Diffstat (limited to 'hw/rtc/aspeed_rtc.c')
-rw-r--r-- | hw/rtc/aspeed_rtc.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/hw/rtc/aspeed_rtc.c b/hw/rtc/aspeed_rtc.c new file mode 100644 index 0000000000..3ca1183558 --- /dev/null +++ b/hw/rtc/aspeed_rtc.c @@ -0,0 +1,181 @@ +/* + * ASPEED Real Time Clock + * Joel Stanley <joel@jms.id.au> + * + * Copyright 2019 IBM Corp + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "hw/rtc/aspeed_rtc.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/timer.h" + +#include "trace.h" + +#define COUNTER1 (0x00 / 4) +#define COUNTER2 (0x04 / 4) +#define ALARM (0x08 / 4) +#define CONTROL (0x10 / 4) +#define ALARM_STATUS (0x14 / 4) + +#define RTC_UNLOCKED BIT(1) +#define RTC_ENABLED BIT(0) + +static void aspeed_rtc_calc_offset(AspeedRtcState *rtc) +{ + struct tm tm; + uint32_t year, cent; + uint32_t reg1 = rtc->reg[COUNTER1]; + uint32_t reg2 = rtc->reg[COUNTER2]; + + tm.tm_mday = (reg1 >> 24) & 0x1f; + tm.tm_hour = (reg1 >> 16) & 0x1f; + tm.tm_min = (reg1 >> 8) & 0x3f; + tm.tm_sec = (reg1 >> 0) & 0x3f; + + cent = (reg2 >> 16) & 0x1f; + year = (reg2 >> 8) & 0x7f; + tm.tm_mon = ((reg2 >> 0) & 0x0f) - 1; + tm.tm_year = year + (cent * 100) - 1900; + + rtc->offset = qemu_timedate_diff(&tm); +} + +static uint32_t aspeed_rtc_get_counter(AspeedRtcState *rtc, int r) +{ + uint32_t year, cent; + struct tm now; + + qemu_get_timedate(&now, rtc->offset); + + switch (r) { + case COUNTER1: + return (now.tm_mday << 24) | (now.tm_hour << 16) | + (now.tm_min << 8) | now.tm_sec; + case COUNTER2: + cent = (now.tm_year + 1900) / 100; + year = now.tm_year % 100; + return ((cent & 0x1f) << 16) | ((year & 0x7f) << 8) | + ((now.tm_mon + 1) & 0xf); + default: + g_assert_not_reached(); + } +} + +static uint64_t aspeed_rtc_read(void *opaque, hwaddr addr, + unsigned size) +{ + AspeedRtcState *rtc = opaque; + uint64_t val; + uint32_t r = addr >> 2; + + switch (r) { + case COUNTER1: + case COUNTER2: + if (rtc->reg[CONTROL] & RTC_ENABLED) { + rtc->reg[r] = aspeed_rtc_get_counter(rtc, r); + } + /* fall through */ + case CONTROL: + val = rtc->reg[r]; + break; + case ALARM: + case ALARM_STATUS: + default: + qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr); + return 0; + } + + trace_aspeed_rtc_read(addr, val); + + return val; +} + +static void aspeed_rtc_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + AspeedRtcState *rtc = opaque; + uint32_t r = addr >> 2; + + switch (r) { + case COUNTER1: + case COUNTER2: + if (!(rtc->reg[CONTROL] & RTC_UNLOCKED)) { + break; + } + /* fall through */ + case CONTROL: + rtc->reg[r] = val; + aspeed_rtc_calc_offset(rtc); + break; + case ALARM: + case ALARM_STATUS: + default: + qemu_log_mask(LOG_UNIMP, "%s: 0x%" HWADDR_PRIx "\n", __func__, addr); + break; + } + trace_aspeed_rtc_write(addr, val); +} + +static void aspeed_rtc_reset(DeviceState *d) +{ + AspeedRtcState *rtc = ASPEED_RTC(d); + + rtc->offset = 0; + memset(rtc->reg, 0, sizeof(rtc->reg)); +} + +static const MemoryRegionOps aspeed_rtc_ops = { + .read = aspeed_rtc_read, + .write = aspeed_rtc_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + +static const VMStateDescription vmstate_aspeed_rtc = { + .name = TYPE_ASPEED_RTC, + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(reg, AspeedRtcState, 0x18), + VMSTATE_INT32(offset, AspeedRtcState), + VMSTATE_INT32(offset, AspeedRtcState), + VMSTATE_END_OF_LIST() + } +}; + +static void aspeed_rtc_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + AspeedRtcState *s = ASPEED_RTC(dev); + + sysbus_init_irq(sbd, &s->irq); + + memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_rtc_ops, s, + "aspeed-rtc", 0x18ULL); + sysbus_init_mmio(sbd, &s->iomem); +} + +static void aspeed_rtc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = aspeed_rtc_realize; + dc->vmsd = &vmstate_aspeed_rtc; + dc->reset = aspeed_rtc_reset; +} + +static const TypeInfo aspeed_rtc_info = { + .name = TYPE_ASPEED_RTC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(AspeedRtcState), + .class_init = aspeed_rtc_class_init, +}; + +static void aspeed_rtc_register_types(void) +{ + type_register_static(&aspeed_rtc_info); +} + +type_init(aspeed_rtc_register_types) |