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