xref: /openbmc/qemu/hw/timer/nrf51_timer.c (revision ba324b3f)
1c5a4829cSSteffen Görtz /*
2c5a4829cSSteffen Görtz  * nRF51 System-on-Chip Timer peripheral
3c5a4829cSSteffen Görtz  *
4c5a4829cSSteffen Görtz  * Reference Manual: http://infocenter.nordicsemi.com/pdf/nRF51_RM_v3.0.pdf
5c5a4829cSSteffen Görtz  * Product Spec: http://infocenter.nordicsemi.com/pdf/nRF51822_PS_v3.1.pdf
6c5a4829cSSteffen Görtz  *
7c5a4829cSSteffen Görtz  * Copyright 2018 Steffen Görtz <contrib@steffen-goertz.de>
8c5a4829cSSteffen Görtz  * Copyright (c) 2019 Red Hat, Inc.
9c5a4829cSSteffen Görtz  *
10c5a4829cSSteffen Görtz  * This code is licensed under the GPL version 2 or later.  See
11c5a4829cSSteffen Görtz  * the COPYING file in the top-level directory.
12c5a4829cSSteffen Görtz  */
13c5a4829cSSteffen Görtz 
14c5a4829cSSteffen Görtz #include "qemu/osdep.h"
15c5a4829cSSteffen Görtz #include "qemu/log.h"
160b8fa32fSMarkus Armbruster #include "qemu/module.h"
17c5a4829cSSteffen Görtz #include "hw/arm/nrf51.h"
1864552b6bSMarkus Armbruster #include "hw/irq.h"
19c5a4829cSSteffen Görtz #include "hw/timer/nrf51_timer.h"
2027d6dea3SPhilippe Mathieu-Daudé #include "hw/qdev-properties.h"
21d6454270SMarkus Armbruster #include "migration/vmstate.h"
22c5a4829cSSteffen Görtz #include "trace.h"
23c5a4829cSSteffen Görtz 
24c5a4829cSSteffen Görtz #define TIMER_CLK_FREQ 16000000UL
25c5a4829cSSteffen Görtz 
26c5a4829cSSteffen Görtz static uint32_t const bitwidths[] = {16, 8, 24, 32};
27c5a4829cSSteffen Görtz 
ns_to_ticks(NRF51TimerState * s,int64_t ns)28c5a4829cSSteffen Görtz static uint32_t ns_to_ticks(NRF51TimerState *s, int64_t ns)
29c5a4829cSSteffen Görtz {
30c5a4829cSSteffen Görtz     uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
31c5a4829cSSteffen Görtz 
32c5a4829cSSteffen Görtz     return muldiv64(ns, freq, NANOSECONDS_PER_SECOND);
33c5a4829cSSteffen Görtz }
34c5a4829cSSteffen Görtz 
ticks_to_ns(NRF51TimerState * s,uint32_t ticks)35c5a4829cSSteffen Görtz static int64_t ticks_to_ns(NRF51TimerState *s, uint32_t ticks)
36c5a4829cSSteffen Görtz {
37c5a4829cSSteffen Görtz     uint32_t freq = TIMER_CLK_FREQ >> s->prescaler;
38c5a4829cSSteffen Görtz 
39c5a4829cSSteffen Görtz     return muldiv64(ticks, NANOSECONDS_PER_SECOND, freq);
40c5a4829cSSteffen Görtz }
41c5a4829cSSteffen Görtz 
42c5a4829cSSteffen Görtz /* Returns number of ticks since last call */
update_counter(NRF51TimerState * s,int64_t now)43c5a4829cSSteffen Görtz static uint32_t update_counter(NRF51TimerState *s, int64_t now)
44c5a4829cSSteffen Görtz {
45c5a4829cSSteffen Görtz     uint32_t ticks = ns_to_ticks(s, now - s->update_counter_ns);
46c5a4829cSSteffen Görtz 
47c5a4829cSSteffen Görtz     s->counter = (s->counter + ticks) % BIT(bitwidths[s->bitmode]);
48d2f9a79aSPeter Maydell     /*
49d2f9a79aSPeter Maydell      * Only advance the sync time to the timestamp of the last tick,
50d2f9a79aSPeter Maydell      * not all the way to 'now', so we don't lose time if we do
51d2f9a79aSPeter Maydell      * multiple resyncs in a single tick.
52d2f9a79aSPeter Maydell      */
53d2f9a79aSPeter Maydell     s->update_counter_ns += ticks_to_ns(s, ticks);
54c5a4829cSSteffen Görtz     return ticks;
55c5a4829cSSteffen Görtz }
56c5a4829cSSteffen Görtz 
57c5a4829cSSteffen Görtz /* Assumes s->counter is up-to-date */
rearm_timer(NRF51TimerState * s,int64_t now)58c5a4829cSSteffen Görtz static void rearm_timer(NRF51TimerState *s, int64_t now)
59c5a4829cSSteffen Görtz {
60c5a4829cSSteffen Görtz     int64_t min_ns = INT64_MAX;
61c5a4829cSSteffen Görtz     size_t i;
62c5a4829cSSteffen Görtz 
63c5a4829cSSteffen Görtz     for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
64c5a4829cSSteffen Görtz         int64_t delta_ns;
65c5a4829cSSteffen Görtz 
66c5a4829cSSteffen Görtz         if (s->events_compare[i]) {
67c5a4829cSSteffen Görtz             continue; /* already expired, ignore it for now */
68c5a4829cSSteffen Görtz         }
69c5a4829cSSteffen Görtz 
70c5a4829cSSteffen Görtz         if (s->cc[i] <= s->counter) {
71c5a4829cSSteffen Görtz             delta_ns = ticks_to_ns(s, BIT(bitwidths[s->bitmode]) -
72c5a4829cSSteffen Görtz                                       s->counter + s->cc[i]);
73c5a4829cSSteffen Görtz         } else {
74c5a4829cSSteffen Görtz             delta_ns = ticks_to_ns(s, s->cc[i] - s->counter);
75c5a4829cSSteffen Görtz         }
76c5a4829cSSteffen Görtz 
77c5a4829cSSteffen Görtz         if (delta_ns < min_ns) {
78c5a4829cSSteffen Görtz             min_ns = delta_ns;
79c5a4829cSSteffen Görtz         }
80c5a4829cSSteffen Görtz     }
81c5a4829cSSteffen Görtz 
82c5a4829cSSteffen Görtz     if (min_ns != INT64_MAX) {
83c5a4829cSSteffen Görtz         timer_mod_ns(&s->timer, now + min_ns);
84c5a4829cSSteffen Görtz     }
85c5a4829cSSteffen Görtz }
86c5a4829cSSteffen Görtz 
update_irq(NRF51TimerState * s)87c5a4829cSSteffen Görtz static void update_irq(NRF51TimerState *s)
88c5a4829cSSteffen Görtz {
89c5a4829cSSteffen Görtz     bool flag = false;
90c5a4829cSSteffen Görtz     size_t i;
91c5a4829cSSteffen Görtz 
92c5a4829cSSteffen Görtz     for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
93c5a4829cSSteffen Görtz         flag |= s->events_compare[i] && extract32(s->inten, 16 + i, 1);
94c5a4829cSSteffen Görtz     }
95c5a4829cSSteffen Görtz     qemu_set_irq(s->irq, flag);
96c5a4829cSSteffen Görtz }
97c5a4829cSSteffen Görtz 
timer_expire(void * opaque)98c5a4829cSSteffen Görtz static void timer_expire(void *opaque)
99c5a4829cSSteffen Görtz {
100c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(opaque);
101c5a4829cSSteffen Görtz     int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
102c5a4829cSSteffen Görtz     uint32_t cc_remaining[NRF51_TIMER_REG_COUNT];
103c5a4829cSSteffen Görtz     bool should_stop = false;
104c5a4829cSSteffen Görtz     uint32_t ticks;
105c5a4829cSSteffen Görtz     size_t i;
106c5a4829cSSteffen Görtz 
107c5a4829cSSteffen Görtz     for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
108c5a4829cSSteffen Görtz         if (s->cc[i] > s->counter) {
109c5a4829cSSteffen Görtz             cc_remaining[i] = s->cc[i] - s->counter;
110c5a4829cSSteffen Görtz         } else {
111c5a4829cSSteffen Görtz             cc_remaining[i] = BIT(bitwidths[s->bitmode]) -
112c5a4829cSSteffen Görtz                               s->counter + s->cc[i];
113c5a4829cSSteffen Görtz         }
114c5a4829cSSteffen Görtz     }
115c5a4829cSSteffen Görtz 
116c5a4829cSSteffen Görtz     ticks = update_counter(s, now);
117c5a4829cSSteffen Görtz 
118c5a4829cSSteffen Görtz     for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
119c5a4829cSSteffen Görtz         if (cc_remaining[i] <= ticks) {
120c5a4829cSSteffen Görtz             s->events_compare[i] = 1;
121c5a4829cSSteffen Görtz 
122c5a4829cSSteffen Görtz             if (s->shorts & BIT(i)) {
123c5a4829cSSteffen Görtz                 s->timer_start_ns = now;
124c5a4829cSSteffen Görtz                 s->update_counter_ns = s->timer_start_ns;
125c5a4829cSSteffen Görtz                 s->counter = 0;
126c5a4829cSSteffen Görtz             }
127c5a4829cSSteffen Görtz 
128c5a4829cSSteffen Görtz             should_stop |= s->shorts & BIT(i + 8);
129c5a4829cSSteffen Görtz         }
130c5a4829cSSteffen Görtz     }
131c5a4829cSSteffen Görtz 
132c5a4829cSSteffen Görtz     update_irq(s);
133c5a4829cSSteffen Görtz 
134c5a4829cSSteffen Görtz     if (should_stop) {
135c5a4829cSSteffen Görtz         s->running = false;
136c5a4829cSSteffen Görtz         timer_del(&s->timer);
137c5a4829cSSteffen Görtz     } else {
138c5a4829cSSteffen Görtz         rearm_timer(s, now);
139c5a4829cSSteffen Görtz     }
140c5a4829cSSteffen Görtz }
141c5a4829cSSteffen Görtz 
counter_compare(NRF51TimerState * s)142c5a4829cSSteffen Görtz static void counter_compare(NRF51TimerState *s)
143c5a4829cSSteffen Görtz {
144c5a4829cSSteffen Görtz     uint32_t counter = s->counter;
145c5a4829cSSteffen Görtz     size_t i;
146c5a4829cSSteffen Görtz 
147c5a4829cSSteffen Görtz     for (i = 0; i < NRF51_TIMER_REG_COUNT; i++) {
148c5a4829cSSteffen Görtz         if (counter == s->cc[i]) {
149c5a4829cSSteffen Görtz             s->events_compare[i] = 1;
150c5a4829cSSteffen Görtz 
151c5a4829cSSteffen Görtz             if (s->shorts & BIT(i)) {
152c5a4829cSSteffen Görtz                 s->counter = 0;
153c5a4829cSSteffen Görtz             }
154c5a4829cSSteffen Görtz         }
155c5a4829cSSteffen Görtz     }
156c5a4829cSSteffen Görtz }
157c5a4829cSSteffen Görtz 
nrf51_timer_read(void * opaque,hwaddr offset,unsigned int size)158c5a4829cSSteffen Görtz static uint64_t nrf51_timer_read(void *opaque, hwaddr offset, unsigned int size)
159c5a4829cSSteffen Görtz {
160c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(opaque);
161c5a4829cSSteffen Görtz     uint64_t r = 0;
162c5a4829cSSteffen Görtz 
163c5a4829cSSteffen Görtz     switch (offset) {
164c5a4829cSSteffen Görtz     case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
165c5a4829cSSteffen Görtz         r = s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4];
166c5a4829cSSteffen Görtz         break;
167c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_SHORTS:
168c5a4829cSSteffen Görtz         r = s->shorts;
169c5a4829cSSteffen Görtz         break;
170c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_INTENSET:
171c5a4829cSSteffen Görtz         r = s->inten;
172c5a4829cSSteffen Görtz         break;
173c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_INTENCLR:
174c5a4829cSSteffen Görtz         r = s->inten;
175c5a4829cSSteffen Görtz         break;
176c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_MODE:
177c5a4829cSSteffen Görtz         r = s->mode;
178c5a4829cSSteffen Görtz         break;
179c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_BITMODE:
180c5a4829cSSteffen Görtz         r = s->bitmode;
181c5a4829cSSteffen Görtz         break;
182c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_PRESCALER:
183c5a4829cSSteffen Görtz         r = s->prescaler;
184c5a4829cSSteffen Görtz         break;
185c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
186c5a4829cSSteffen Görtz         r = s->cc[(offset - NRF51_TIMER_REG_CC0) / 4];
187c5a4829cSSteffen Görtz         break;
188c5a4829cSSteffen Görtz     default:
189c5a4829cSSteffen Görtz         qemu_log_mask(LOG_GUEST_ERROR,
190c5a4829cSSteffen Görtz                 "%s: bad read offset 0x%" HWADDR_PRIx "\n",
191c5a4829cSSteffen Görtz                       __func__, offset);
192c5a4829cSSteffen Görtz     }
193c5a4829cSSteffen Görtz 
19427d6dea3SPhilippe Mathieu-Daudé     trace_nrf51_timer_read(s->id, offset, r, size);
195c5a4829cSSteffen Görtz 
196c5a4829cSSteffen Görtz     return r;
197c5a4829cSSteffen Görtz }
198c5a4829cSSteffen Görtz 
nrf51_timer_write(void * opaque,hwaddr offset,uint64_t value,unsigned int size)199c5a4829cSSteffen Görtz static void nrf51_timer_write(void *opaque, hwaddr offset,
200c5a4829cSSteffen Görtz                        uint64_t value, unsigned int size)
201c5a4829cSSteffen Görtz {
202c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(opaque);
203c5a4829cSSteffen Görtz     uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
204c5a4829cSSteffen Görtz     size_t idx;
205c5a4829cSSteffen Görtz 
20627d6dea3SPhilippe Mathieu-Daudé     trace_nrf51_timer_write(s->id, offset, value, size);
207c5a4829cSSteffen Görtz 
208c5a4829cSSteffen Görtz     switch (offset) {
209c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_START:
210c5a4829cSSteffen Görtz         if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_TIMER) {
211c5a4829cSSteffen Görtz             s->running = true;
212c5a4829cSSteffen Görtz             s->timer_start_ns = now - ticks_to_ns(s, s->counter);
213c5a4829cSSteffen Görtz             s->update_counter_ns = s->timer_start_ns;
214c5a4829cSSteffen Görtz             rearm_timer(s, now);
215c5a4829cSSteffen Görtz         }
216c5a4829cSSteffen Görtz         break;
217c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_STOP:
218c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_SHUTDOWN:
219c5a4829cSSteffen Görtz         if (value == NRF51_TRIGGER_TASK) {
220c5a4829cSSteffen Görtz             s->running = false;
221c5a4829cSSteffen Görtz             timer_del(&s->timer);
222c5a4829cSSteffen Görtz         }
223c5a4829cSSteffen Görtz         break;
224c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_COUNT:
225c5a4829cSSteffen Görtz         if (value == NRF51_TRIGGER_TASK && s->mode == NRF51_TIMER_COUNTER) {
226c5a4829cSSteffen Görtz             s->counter = (s->counter + 1) % BIT(bitwidths[s->bitmode]);
227c5a4829cSSteffen Görtz             counter_compare(s);
228c5a4829cSSteffen Görtz         }
229c5a4829cSSteffen Görtz         break;
230c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_CLEAR:
231c5a4829cSSteffen Görtz         if (value == NRF51_TRIGGER_TASK) {
232c5a4829cSSteffen Görtz             s->timer_start_ns = now;
233c5a4829cSSteffen Görtz             s->update_counter_ns = s->timer_start_ns;
234c5a4829cSSteffen Görtz             s->counter = 0;
235c5a4829cSSteffen Görtz             if (s->running) {
236c5a4829cSSteffen Görtz                 rearm_timer(s, now);
237c5a4829cSSteffen Görtz             }
238c5a4829cSSteffen Görtz         }
239c5a4829cSSteffen Görtz         break;
240c5a4829cSSteffen Görtz     case NRF51_TIMER_TASK_CAPTURE_0 ... NRF51_TIMER_TASK_CAPTURE_3:
241c5a4829cSSteffen Görtz         if (value == NRF51_TRIGGER_TASK) {
242c5a4829cSSteffen Görtz             if (s->running) {
243c5a4829cSSteffen Görtz                 timer_expire(s); /* update counter and all state */
244c5a4829cSSteffen Görtz             }
245c5a4829cSSteffen Görtz 
246c5a4829cSSteffen Görtz             idx = (offset - NRF51_TIMER_TASK_CAPTURE_0) / 4;
247c5a4829cSSteffen Görtz             s->cc[idx] = s->counter;
248602ab789SPhilippe Mathieu-Daudé             trace_nrf51_timer_set_count(s->id, idx, s->counter);
249c5a4829cSSteffen Görtz         }
250c5a4829cSSteffen Görtz         break;
251c5a4829cSSteffen Görtz     case NRF51_TIMER_EVENT_COMPARE_0 ... NRF51_TIMER_EVENT_COMPARE_3:
252c5a4829cSSteffen Görtz         if (value == NRF51_EVENT_CLEAR) {
253c5a4829cSSteffen Görtz             s->events_compare[(offset - NRF51_TIMER_EVENT_COMPARE_0) / 4] = 0;
254c5a4829cSSteffen Görtz 
255c5a4829cSSteffen Görtz             if (s->running) {
256c5a4829cSSteffen Görtz                 timer_expire(s); /* update counter and all state */
257c5a4829cSSteffen Görtz             }
258c5a4829cSSteffen Görtz         }
259c5a4829cSSteffen Görtz         break;
260c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_SHORTS:
261c5a4829cSSteffen Görtz         s->shorts = value & NRF51_TIMER_REG_SHORTS_MASK;
262c5a4829cSSteffen Görtz         break;
263c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_INTENSET:
264c5a4829cSSteffen Görtz         s->inten |= value & NRF51_TIMER_REG_INTEN_MASK;
265c5a4829cSSteffen Görtz         break;
266c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_INTENCLR:
267c5a4829cSSteffen Görtz         s->inten &= ~(value & NRF51_TIMER_REG_INTEN_MASK);
268c5a4829cSSteffen Görtz         break;
269c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_MODE:
270c5a4829cSSteffen Görtz         s->mode = value;
271c5a4829cSSteffen Görtz         break;
272c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_BITMODE:
273c5a4829cSSteffen Görtz         if (s->mode == NRF51_TIMER_TIMER && s->running) {
274c5a4829cSSteffen Görtz             qemu_log_mask(LOG_GUEST_ERROR,
275c5a4829cSSteffen Görtz                     "%s: erroneous change of BITMODE while timer is running\n",
276c5a4829cSSteffen Görtz                     __func__);
277c5a4829cSSteffen Görtz         }
278c5a4829cSSteffen Görtz         s->bitmode = value & NRF51_TIMER_REG_BITMODE_MASK;
279c5a4829cSSteffen Görtz         break;
280c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_PRESCALER:
281c5a4829cSSteffen Görtz         if (s->mode == NRF51_TIMER_TIMER && s->running) {
282c5a4829cSSteffen Görtz             qemu_log_mask(LOG_GUEST_ERROR,
283c5a4829cSSteffen Görtz                 "%s: erroneous change of PRESCALER while timer is running\n",
284c5a4829cSSteffen Görtz                 __func__);
285c5a4829cSSteffen Görtz         }
286c5a4829cSSteffen Görtz         s->prescaler = value & NRF51_TIMER_REG_PRESCALER_MASK;
287c5a4829cSSteffen Görtz         break;
288c5a4829cSSteffen Görtz     case NRF51_TIMER_REG_CC0 ... NRF51_TIMER_REG_CC3:
289c5a4829cSSteffen Görtz         if (s->running) {
290c5a4829cSSteffen Görtz             timer_expire(s); /* update counter */
291c5a4829cSSteffen Görtz         }
292c5a4829cSSteffen Görtz 
293c5a4829cSSteffen Görtz         idx = (offset - NRF51_TIMER_REG_CC0) / 4;
294c5a4829cSSteffen Görtz         s->cc[idx] = value % BIT(bitwidths[s->bitmode]);
295c5a4829cSSteffen Görtz 
296c5a4829cSSteffen Görtz         if (s->running) {
297c5a4829cSSteffen Görtz             rearm_timer(s, now);
298c5a4829cSSteffen Görtz         }
299c5a4829cSSteffen Görtz         break;
300c5a4829cSSteffen Görtz     default:
301c5a4829cSSteffen Görtz         qemu_log_mask(LOG_GUEST_ERROR,
302c5a4829cSSteffen Görtz                       "%s: bad write offset 0x%" HWADDR_PRIx "\n",
303c5a4829cSSteffen Görtz                       __func__, offset);
304c5a4829cSSteffen Görtz     }
305c5a4829cSSteffen Görtz 
306c5a4829cSSteffen Görtz     update_irq(s);
307c5a4829cSSteffen Görtz }
308c5a4829cSSteffen Görtz 
309c5a4829cSSteffen Görtz static const MemoryRegionOps rng_ops = {
310c5a4829cSSteffen Görtz     .read =  nrf51_timer_read,
311c5a4829cSSteffen Görtz     .write = nrf51_timer_write,
312c5a4829cSSteffen Görtz     .endianness = DEVICE_LITTLE_ENDIAN,
313c5a4829cSSteffen Görtz     .impl.min_access_size = 4,
314c5a4829cSSteffen Görtz     .impl.max_access_size = 4,
315c5a4829cSSteffen Görtz };
316c5a4829cSSteffen Görtz 
nrf51_timer_init(Object * obj)317c5a4829cSSteffen Görtz static void nrf51_timer_init(Object *obj)
318c5a4829cSSteffen Görtz {
319c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(obj);
320c5a4829cSSteffen Görtz     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
321c5a4829cSSteffen Görtz 
322c5a4829cSSteffen Görtz     memory_region_init_io(&s->iomem, obj, &rng_ops, s,
32354595a57SPhilippe Mathieu-Daudé                           TYPE_NRF51_TIMER, NRF51_PERIPHERAL_SIZE);
324c5a4829cSSteffen Görtz     sysbus_init_mmio(sbd, &s->iomem);
325c5a4829cSSteffen Görtz     sysbus_init_irq(sbd, &s->irq);
326c5a4829cSSteffen Görtz 
327c5a4829cSSteffen Görtz     timer_init_ns(&s->timer, QEMU_CLOCK_VIRTUAL, timer_expire, s);
328c5a4829cSSteffen Görtz }
329c5a4829cSSteffen Görtz 
nrf51_timer_reset(DeviceState * dev)330c5a4829cSSteffen Görtz static void nrf51_timer_reset(DeviceState *dev)
331c5a4829cSSteffen Görtz {
332c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(dev);
333c5a4829cSSteffen Görtz 
334c5a4829cSSteffen Görtz     timer_del(&s->timer);
335c5a4829cSSteffen Görtz     s->timer_start_ns = 0x00;
336c5a4829cSSteffen Görtz     s->update_counter_ns = 0x00;
337c5a4829cSSteffen Görtz     s->counter = 0x00;
338c5a4829cSSteffen Görtz     s->running = false;
339c5a4829cSSteffen Görtz 
340c5a4829cSSteffen Görtz     memset(s->events_compare, 0x00, sizeof(s->events_compare));
341c5a4829cSSteffen Görtz     memset(s->cc, 0x00, sizeof(s->cc));
342c5a4829cSSteffen Görtz 
343c5a4829cSSteffen Görtz     s->shorts = 0x00;
344c5a4829cSSteffen Görtz     s->inten = 0x00;
345c5a4829cSSteffen Görtz     s->mode = 0x00;
346c5a4829cSSteffen Görtz     s->bitmode = 0x00;
347c5a4829cSSteffen Görtz     s->prescaler = 0x00;
348c5a4829cSSteffen Görtz }
349c5a4829cSSteffen Görtz 
nrf51_timer_post_load(void * opaque,int version_id)350c5a4829cSSteffen Görtz static int nrf51_timer_post_load(void *opaque, int version_id)
351c5a4829cSSteffen Görtz {
352c5a4829cSSteffen Görtz     NRF51TimerState *s = NRF51_TIMER(opaque);
353c5a4829cSSteffen Görtz 
354c5a4829cSSteffen Görtz     if (s->running && s->mode == NRF51_TIMER_TIMER) {
355c5a4829cSSteffen Görtz         timer_expire(s);
356c5a4829cSSteffen Görtz     }
357c5a4829cSSteffen Görtz     return 0;
358c5a4829cSSteffen Görtz }
359c5a4829cSSteffen Görtz 
360c5a4829cSSteffen Görtz static const VMStateDescription vmstate_nrf51_timer = {
361c5a4829cSSteffen Görtz     .name = TYPE_NRF51_TIMER,
362c5a4829cSSteffen Görtz     .version_id = 1,
363c5a4829cSSteffen Görtz     .post_load = nrf51_timer_post_load,
364*ba324b3fSRichard Henderson     .fields = (const VMStateField[]) {
365c5a4829cSSteffen Görtz         VMSTATE_TIMER(timer, NRF51TimerState),
366c5a4829cSSteffen Görtz         VMSTATE_INT64(timer_start_ns, NRF51TimerState),
367c5a4829cSSteffen Görtz         VMSTATE_INT64(update_counter_ns, NRF51TimerState),
368c5a4829cSSteffen Görtz         VMSTATE_UINT32(counter, NRF51TimerState),
369c5a4829cSSteffen Görtz         VMSTATE_BOOL(running, NRF51TimerState),
370c5a4829cSSteffen Görtz         VMSTATE_UINT8_ARRAY(events_compare, NRF51TimerState,
371c5a4829cSSteffen Görtz                             NRF51_TIMER_REG_COUNT),
372c5a4829cSSteffen Görtz         VMSTATE_UINT32_ARRAY(cc, NRF51TimerState, NRF51_TIMER_REG_COUNT),
373c5a4829cSSteffen Görtz         VMSTATE_UINT32(shorts, NRF51TimerState),
374c5a4829cSSteffen Görtz         VMSTATE_UINT32(inten, NRF51TimerState),
375c5a4829cSSteffen Görtz         VMSTATE_UINT32(mode, NRF51TimerState),
376c5a4829cSSteffen Görtz         VMSTATE_UINT32(bitmode, NRF51TimerState),
377c5a4829cSSteffen Görtz         VMSTATE_UINT32(prescaler, NRF51TimerState),
378c5a4829cSSteffen Görtz         VMSTATE_END_OF_LIST()
379c5a4829cSSteffen Görtz     }
380c5a4829cSSteffen Görtz };
381c5a4829cSSteffen Görtz 
38227d6dea3SPhilippe Mathieu-Daudé static Property nrf51_timer_properties[] = {
38327d6dea3SPhilippe Mathieu-Daudé     DEFINE_PROP_UINT8("id", NRF51TimerState, id, 0),
38427d6dea3SPhilippe Mathieu-Daudé     DEFINE_PROP_END_OF_LIST(),
38527d6dea3SPhilippe Mathieu-Daudé };
38627d6dea3SPhilippe Mathieu-Daudé 
nrf51_timer_class_init(ObjectClass * klass,void * data)387c5a4829cSSteffen Görtz static void nrf51_timer_class_init(ObjectClass *klass, void *data)
388c5a4829cSSteffen Görtz {
389c5a4829cSSteffen Görtz     DeviceClass *dc = DEVICE_CLASS(klass);
390c5a4829cSSteffen Görtz 
391c5a4829cSSteffen Görtz     dc->reset = nrf51_timer_reset;
392c5a4829cSSteffen Görtz     dc->vmsd = &vmstate_nrf51_timer;
39327d6dea3SPhilippe Mathieu-Daudé     device_class_set_props(dc, nrf51_timer_properties);
394c5a4829cSSteffen Görtz }
395c5a4829cSSteffen Görtz 
396c5a4829cSSteffen Görtz static const TypeInfo nrf51_timer_info = {
397c5a4829cSSteffen Görtz     .name = TYPE_NRF51_TIMER,
398c5a4829cSSteffen Görtz     .parent = TYPE_SYS_BUS_DEVICE,
399c5a4829cSSteffen Görtz     .instance_size = sizeof(NRF51TimerState),
400c5a4829cSSteffen Görtz     .instance_init = nrf51_timer_init,
401c5a4829cSSteffen Görtz     .class_init = nrf51_timer_class_init
402c5a4829cSSteffen Görtz };
403c5a4829cSSteffen Görtz 
nrf51_timer_register_types(void)404c5a4829cSSteffen Görtz static void nrf51_timer_register_types(void)
405c5a4829cSSteffen Görtz {
406c5a4829cSSteffen Görtz     type_register_static(&nrf51_timer_info);
407c5a4829cSSteffen Görtz }
408c5a4829cSSteffen Görtz 
409c5a4829cSSteffen Görtz type_init(nrf51_timer_register_types)
410