]> git.proxmox.com Git - mirror_qemu.git/blame - hw/timer/bcm2835_systmr.c
target/arm: Add support for MTE to HCR_EL2 and SCR_EL3
[mirror_qemu.git] / hw / timer / bcm2835_systmr.c
CommitLineData
d05be883
PMD
1/*
2 * BCM2835 SYS timer emulation
3 *
4 * Copyright (C) 2019 Philippe Mathieu-Daudé <f4bug@amsat.org>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 *
8 * Datasheet: BCM2835 ARM Peripherals (C6357-M-1398)
9 * https://www.raspberrypi.org/app/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
10 *
11 * Only the free running 64-bit counter is implemented.
12 * The 4 COMPARE registers and the interruption are not implemented.
13 */
14
15#include "qemu/osdep.h"
16#include "qemu/log.h"
17#include "qemu/timer.h"
18#include "hw/timer/bcm2835_systmr.h"
19#include "hw/registerfields.h"
20#include "migration/vmstate.h"
21#include "trace.h"
22
23REG32(CTRL_STATUS, 0x00)
24REG32(COUNTER_LOW, 0x04)
25REG32(COUNTER_HIGH, 0x08)
26REG32(COMPARE0, 0x0c)
27REG32(COMPARE1, 0x10)
28REG32(COMPARE2, 0x14)
29REG32(COMPARE3, 0x18)
30
31static void bcm2835_systmr_update_irq(BCM2835SystemTimerState *s)
32{
33 bool enable = !!s->reg.status;
34
35 trace_bcm2835_systmr_irq(enable);
36 qemu_set_irq(s->irq, enable);
37}
38
39static void bcm2835_systmr_update_compare(BCM2835SystemTimerState *s,
40 unsigned timer_index)
41{
42 /* TODO fow now, since neither Linux nor U-boot use these timers. */
43 qemu_log_mask(LOG_UNIMP, "COMPARE register %u not implemented\n",
44 timer_index);
45}
46
47static uint64_t bcm2835_systmr_read(void *opaque, hwaddr offset,
48 unsigned size)
49{
50 BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
51 uint64_t r = 0;
52
53 switch (offset) {
54 case A_CTRL_STATUS:
55 r = s->reg.status;
56 break;
57 case A_COMPARE0 ... A_COMPARE3:
58 r = s->reg.compare[(offset - A_COMPARE0) >> 2];
59 break;
60 case A_COUNTER_LOW:
61 case A_COUNTER_HIGH:
62 /* Free running counter at 1MHz */
63 r = qemu_clock_get_us(QEMU_CLOCK_VIRTUAL);
64 r >>= 8 * (offset - A_COUNTER_LOW);
65 r &= UINT32_MAX;
66 break;
67 default:
68 qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
69 __func__, offset);
70 break;
71 }
72 trace_bcm2835_systmr_read(offset, r);
73
74 return r;
75}
76
77static void bcm2835_systmr_write(void *opaque, hwaddr offset,
78 uint64_t value, unsigned size)
79{
80 BCM2835SystemTimerState *s = BCM2835_SYSTIMER(opaque);
81
82 trace_bcm2835_systmr_write(offset, value);
83 switch (offset) {
84 case A_CTRL_STATUS:
85 s->reg.status &= ~value; /* Ack */
86 bcm2835_systmr_update_irq(s);
87 break;
88 case A_COMPARE0 ... A_COMPARE3:
89 s->reg.compare[(offset - A_COMPARE0) >> 2] = value;
90 bcm2835_systmr_update_compare(s, (offset - A_COMPARE0) >> 2);
91 break;
92 case A_COUNTER_LOW:
93 case A_COUNTER_HIGH:
94 qemu_log_mask(LOG_GUEST_ERROR, "%s: read-only ofs 0x%" HWADDR_PRIx "\n",
95 __func__, offset);
96 break;
97 default:
98 qemu_log_mask(LOG_GUEST_ERROR, "%s: bad offset 0x%" HWADDR_PRIx "\n",
99 __func__, offset);
100 break;
101 }
102}
103
104static const MemoryRegionOps bcm2835_systmr_ops = {
105 .read = bcm2835_systmr_read,
106 .write = bcm2835_systmr_write,
107 .endianness = DEVICE_LITTLE_ENDIAN,
108 .impl = {
109 .min_access_size = 4,
110 .max_access_size = 4,
111 },
112};
113
114static void bcm2835_systmr_reset(DeviceState *dev)
115{
116 BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
117
118 memset(&s->reg, 0, sizeof(s->reg));
119}
120
121static void bcm2835_systmr_realize(DeviceState *dev, Error **errp)
122{
123 BCM2835SystemTimerState *s = BCM2835_SYSTIMER(dev);
124
125 memory_region_init_io(&s->iomem, OBJECT(dev), &bcm2835_systmr_ops,
126 s, "bcm2835-sys-timer", 0x20);
127 sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
128 sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
129}
130
131static const VMStateDescription bcm2835_systmr_vmstate = {
132 .name = "bcm2835_sys_timer",
133 .version_id = 1,
134 .minimum_version_id = 1,
135 .fields = (VMStateField[]) {
136 VMSTATE_UINT32(reg.status, BCM2835SystemTimerState),
137 VMSTATE_UINT32_ARRAY(reg.compare, BCM2835SystemTimerState, 4),
138 VMSTATE_END_OF_LIST()
139 }
140};
141
142static void bcm2835_systmr_class_init(ObjectClass *klass, void *data)
143{
144 DeviceClass *dc = DEVICE_CLASS(klass);
145
146 dc->realize = bcm2835_systmr_realize;
147 dc->reset = bcm2835_systmr_reset;
148 dc->vmsd = &bcm2835_systmr_vmstate;
149}
150
151static const TypeInfo bcm2835_systmr_info = {
152 .name = TYPE_BCM2835_SYSTIMER,
153 .parent = TYPE_SYS_BUS_DEVICE,
154 .instance_size = sizeof(BCM2835SystemTimerState),
155 .class_init = bcm2835_systmr_class_init,
156};
157
158static void bcm2835_systmr_register_types(void)
159{
160 type_register_static(&bcm2835_systmr_info);
161}
162
163type_init(bcm2835_systmr_register_types);