]> git.proxmox.com Git - mirror_qemu.git/blob - hw/timer/armv7m_systick.c
Merge remote-tracking branch 'remotes/vivier2/tags/trivial-branch-pull-request' into...
[mirror_qemu.git] / hw / timer / armv7m_systick.c
1 /*
2 * ARMv7M SysTick timer
3 *
4 * Copyright (c) 2006-2007 CodeSourcery.
5 * Written by Paul Brook
6 * Copyright (c) 2017 Linaro Ltd
7 * Written by Peter Maydell
8 *
9 * This code is licensed under the GPL (version 2 or later).
10 */
11
12 #include "qemu/osdep.h"
13 #include "hw/timer/armv7m_systick.h"
14 #include "hw/sysbus.h"
15 #include "qemu/timer.h"
16 #include "qemu/log.h"
17 #include "qemu/module.h"
18 #include "trace.h"
19
20 /* qemu timers run at 1GHz. We want something closer to 1MHz. */
21 #define SYSTICK_SCALE 1000ULL
22
23 #define SYSTICK_ENABLE (1 << 0)
24 #define SYSTICK_TICKINT (1 << 1)
25 #define SYSTICK_CLKSOURCE (1 << 2)
26 #define SYSTICK_COUNTFLAG (1 << 16)
27
28 int system_clock_scale;
29
30 /* Conversion factor from qemu timer to SysTick frequencies. */
31 static inline int64_t systick_scale(SysTickState *s)
32 {
33 if (s->control & SYSTICK_CLKSOURCE) {
34 return system_clock_scale;
35 } else {
36 return 1000;
37 }
38 }
39
40 static void systick_reload(SysTickState *s, int reset)
41 {
42 /* The Cortex-M3 Devices Generic User Guide says that "When the
43 * ENABLE bit is set to 1, the counter loads the RELOAD value from the
44 * SYST RVR register and then counts down". So, we need to check the
45 * ENABLE bit before reloading the value.
46 */
47 trace_systick_reload();
48
49 if ((s->control & SYSTICK_ENABLE) == 0) {
50 return;
51 }
52
53 if (reset) {
54 s->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
55 }
56 s->tick += (s->reload + 1) * systick_scale(s);
57 timer_mod(s->timer, s->tick);
58 }
59
60 static void systick_timer_tick(void *opaque)
61 {
62 SysTickState *s = (SysTickState *)opaque;
63
64 trace_systick_timer_tick();
65
66 s->control |= SYSTICK_COUNTFLAG;
67 if (s->control & SYSTICK_TICKINT) {
68 /* Tell the NVIC to pend the SysTick exception */
69 qemu_irq_pulse(s->irq);
70 }
71 if (s->reload == 0) {
72 s->control &= ~SYSTICK_ENABLE;
73 } else {
74 systick_reload(s, 0);
75 }
76 }
77
78 static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data,
79 unsigned size, MemTxAttrs attrs)
80 {
81 SysTickState *s = opaque;
82 uint32_t val;
83
84 if (attrs.user) {
85 /* Generate BusFault for unprivileged accesses */
86 return MEMTX_ERROR;
87 }
88
89 switch (addr) {
90 case 0x0: /* SysTick Control and Status. */
91 val = s->control;
92 s->control &= ~SYSTICK_COUNTFLAG;
93 break;
94 case 0x4: /* SysTick Reload Value. */
95 val = s->reload;
96 break;
97 case 0x8: /* SysTick Current Value. */
98 {
99 int64_t t;
100
101 if ((s->control & SYSTICK_ENABLE) == 0) {
102 val = 0;
103 break;
104 }
105 t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
106 if (t >= s->tick) {
107 val = 0;
108 break;
109 }
110 val = ((s->tick - (t + 1)) / systick_scale(s)) + 1;
111 /* The interrupt in triggered when the timer reaches zero.
112 However the counter is not reloaded until the next clock
113 tick. This is a hack to return zero during the first tick. */
114 if (val > s->reload) {
115 val = 0;
116 }
117 break;
118 }
119 case 0xc: /* SysTick Calibration Value. */
120 val = 10000;
121 break;
122 default:
123 val = 0;
124 qemu_log_mask(LOG_GUEST_ERROR,
125 "SysTick: Bad read offset 0x%" HWADDR_PRIx "\n", addr);
126 break;
127 }
128
129 trace_systick_read(addr, val, size);
130 *data = val;
131 return MEMTX_OK;
132 }
133
134 static MemTxResult systick_write(void *opaque, hwaddr addr,
135 uint64_t value, unsigned size,
136 MemTxAttrs attrs)
137 {
138 SysTickState *s = opaque;
139
140 if (attrs.user) {
141 /* Generate BusFault for unprivileged accesses */
142 return MEMTX_ERROR;
143 }
144
145 trace_systick_write(addr, value, size);
146
147 switch (addr) {
148 case 0x0: /* SysTick Control and Status. */
149 {
150 uint32_t oldval = s->control;
151
152 s->control &= 0xfffffff8;
153 s->control |= value & 7;
154 if ((oldval ^ value) & SYSTICK_ENABLE) {
155 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
156 if (value & SYSTICK_ENABLE) {
157 if (s->tick) {
158 s->tick += now;
159 timer_mod(s->timer, s->tick);
160 } else {
161 systick_reload(s, 1);
162 }
163 } else {
164 timer_del(s->timer);
165 s->tick -= now;
166 if (s->tick < 0) {
167 s->tick = 0;
168 }
169 }
170 } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
171 /* This is a hack. Force the timer to be reloaded
172 when the reference clock is changed. */
173 systick_reload(s, 1);
174 }
175 break;
176 }
177 case 0x4: /* SysTick Reload Value. */
178 s->reload = value;
179 break;
180 case 0x8: /* SysTick Current Value. Writes reload the timer. */
181 systick_reload(s, 1);
182 s->control &= ~SYSTICK_COUNTFLAG;
183 break;
184 default:
185 qemu_log_mask(LOG_GUEST_ERROR,
186 "SysTick: Bad write offset 0x%" HWADDR_PRIx "\n", addr);
187 }
188 return MEMTX_OK;
189 }
190
191 static const MemoryRegionOps systick_ops = {
192 .read_with_attrs = systick_read,
193 .write_with_attrs = systick_write,
194 .endianness = DEVICE_NATIVE_ENDIAN,
195 .valid.min_access_size = 4,
196 .valid.max_access_size = 4,
197 };
198
199 static void systick_reset(DeviceState *dev)
200 {
201 SysTickState *s = SYSTICK(dev);
202
203 s->control = 0;
204 s->reload = 0;
205 s->tick = 0;
206 timer_del(s->timer);
207 }
208
209 static void systick_instance_init(Object *obj)
210 {
211 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
212 SysTickState *s = SYSTICK(obj);
213
214 memory_region_init_io(&s->iomem, obj, &systick_ops, s, "systick", 0xe0);
215 sysbus_init_mmio(sbd, &s->iomem);
216 sysbus_init_irq(sbd, &s->irq);
217 s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s);
218 }
219
220 static const VMStateDescription vmstate_systick = {
221 .name = "armv7m_systick",
222 .version_id = 1,
223 .minimum_version_id = 1,
224 .fields = (VMStateField[]) {
225 VMSTATE_UINT32(control, SysTickState),
226 VMSTATE_UINT32(reload, SysTickState),
227 VMSTATE_INT64(tick, SysTickState),
228 VMSTATE_TIMER_PTR(timer, SysTickState),
229 VMSTATE_END_OF_LIST()
230 }
231 };
232
233 static void systick_class_init(ObjectClass *klass, void *data)
234 {
235 DeviceClass *dc = DEVICE_CLASS(klass);
236
237 dc->vmsd = &vmstate_systick;
238 dc->reset = systick_reset;
239 }
240
241 static const TypeInfo armv7m_systick_info = {
242 .name = TYPE_SYSTICK,
243 .parent = TYPE_SYS_BUS_DEVICE,
244 .instance_init = systick_instance_init,
245 .instance_size = sizeof(SysTickState),
246 .class_init = systick_class_init,
247 };
248
249 static void armv7m_systick_register_types(void)
250 {
251 type_register_static(&armv7m_systick_info);
252 }
253
254 type_init(armv7m_systick_register_types)