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