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