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,
364ba324b3fSRichard 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
391*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, 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