xref: /openbmc/qemu/hw/timer/cmsdk-apb-dualtimer.c (revision 2038f8c8)
1 /*
2  * ARM CMSDK APB dual-timer emulation
3  *
4  * Copyright (c) 2018 Linaro Limited
5  * Written by Peter Maydell
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 or
9  *  (at your option) any later version.
10  */
11 
12 /*
13  * This is a model of the "APB dual-input timer" which is part of the Cortex-M
14  * System Design Kit (CMSDK) and documented in the Cortex-M System
15  * Design Kit Technical Reference Manual (ARM DDI0479C):
16  * https://developer.arm.com/products/system-design/system-design-kits/cortex-m-system-design-kit
17  */
18 
19 #include "qemu/osdep.h"
20 #include "qemu/log.h"
21 #include "trace.h"
22 #include "qapi/error.h"
23 #include "qemu/main-loop.h"
24 #include "qemu/module.h"
25 #include "hw/sysbus.h"
26 #include "hw/irq.h"
27 #include "hw/qdev-properties.h"
28 #include "hw/registerfields.h"
29 #include "hw/timer/cmsdk-apb-dualtimer.h"
30 #include "migration/vmstate.h"
31 
32 REG32(TIMER1LOAD, 0x0)
33 REG32(TIMER1VALUE, 0x4)
34 REG32(TIMER1CONTROL, 0x8)
35     FIELD(CONTROL, ONESHOT, 0, 1)
36     FIELD(CONTROL, SIZE, 1, 1)
37     FIELD(CONTROL, PRESCALE, 2, 2)
38     FIELD(CONTROL, INTEN, 5, 1)
39     FIELD(CONTROL, MODE, 6, 1)
40     FIELD(CONTROL, ENABLE, 7, 1)
41 #define R_CONTROL_VALID_MASK (R_CONTROL_ONESHOT_MASK | R_CONTROL_SIZE_MASK | \
42                               R_CONTROL_PRESCALE_MASK | R_CONTROL_INTEN_MASK | \
43                               R_CONTROL_MODE_MASK | R_CONTROL_ENABLE_MASK)
44 REG32(TIMER1INTCLR, 0xc)
45 REG32(TIMER1RIS, 0x10)
46 REG32(TIMER1MIS, 0x14)
47 REG32(TIMER1BGLOAD, 0x18)
48 REG32(TIMER2LOAD, 0x20)
49 REG32(TIMER2VALUE, 0x24)
50 REG32(TIMER2CONTROL, 0x28)
51 REG32(TIMER2INTCLR, 0x2c)
52 REG32(TIMER2RIS, 0x30)
53 REG32(TIMER2MIS, 0x34)
54 REG32(TIMER2BGLOAD, 0x38)
55 REG32(TIMERITCR, 0xf00)
56     FIELD(TIMERITCR, ENABLE, 0, 1)
57 #define R_TIMERITCR_VALID_MASK R_TIMERITCR_ENABLE_MASK
58 REG32(TIMERITOP, 0xf04)
59     FIELD(TIMERITOP, TIMINT1, 0, 1)
60     FIELD(TIMERITOP, TIMINT2, 1, 1)
61 #define R_TIMERITOP_VALID_MASK (R_TIMERITOP_TIMINT1_MASK | \
62                                 R_TIMERITOP_TIMINT2_MASK)
63 REG32(PID4, 0xfd0)
64 REG32(PID5, 0xfd4)
65 REG32(PID6, 0xfd8)
66 REG32(PID7, 0xfdc)
67 REG32(PID0, 0xfe0)
68 REG32(PID1, 0xfe4)
69 REG32(PID2, 0xfe8)
70 REG32(PID3, 0xfec)
71 REG32(CID0, 0xff0)
72 REG32(CID1, 0xff4)
73 REG32(CID2, 0xff8)
74 REG32(CID3, 0xffc)
75 
76 /* PID/CID values */
77 static const int timer_id[] = {
78     0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
79     0x23, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
80     0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
81 };
82 
83 static bool cmsdk_dualtimermod_intstatus(CMSDKAPBDualTimerModule *m)
84 {
85     /* Return masked interrupt status for the timer module */
86     return m->intstatus && (m->control & R_CONTROL_INTEN_MASK);
87 }
88 
89 static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer *s)
90 {
91     bool timint1, timint2, timintc;
92 
93     if (s->timeritcr) {
94         /* Integration test mode: outputs driven directly from TIMERITOP bits */
95         timint1 = s->timeritop & R_TIMERITOP_TIMINT1_MASK;
96         timint2 = s->timeritop & R_TIMERITOP_TIMINT2_MASK;
97     } else {
98         timint1 = cmsdk_dualtimermod_intstatus(&s->timermod[0]);
99         timint2 = cmsdk_dualtimermod_intstatus(&s->timermod[1]);
100     }
101 
102     timintc = timint1 || timint2;
103 
104     qemu_set_irq(s->timermod[0].timerint, timint1);
105     qemu_set_irq(s->timermod[1].timerint, timint2);
106     qemu_set_irq(s->timerintc, timintc);
107 }
108 
109 static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m,
110                                              uint32_t newctrl)
111 {
112     /* Handle a write to the CONTROL register */
113     uint32_t changed;
114 
115     newctrl &= R_CONTROL_VALID_MASK;
116 
117     changed = m->control ^ newctrl;
118 
119     if (changed & ~newctrl & R_CONTROL_ENABLE_MASK) {
120         /* ENABLE cleared, stop timer before any further changes */
121         ptimer_stop(m->timer);
122     }
123 
124     if (changed & R_CONTROL_PRESCALE_MASK) {
125         int divisor;
126 
127         switch (FIELD_EX32(newctrl, CONTROL, PRESCALE)) {
128         case 0:
129             divisor = 1;
130             break;
131         case 1:
132             divisor = 16;
133             break;
134         case 2:
135             divisor = 256;
136             break;
137         case 3:
138             /* UNDEFINED; complain, and arbitrarily treat like 2 */
139             qemu_log_mask(LOG_GUEST_ERROR,
140                           "CMSDK APB dual-timer: CONTROL.PRESCALE==0b11"
141                           " is undefined behaviour\n");
142             divisor = 256;
143             break;
144         default:
145             g_assert_not_reached();
146         }
147         ptimer_set_freq(m->timer, m->parent->pclk_frq / divisor);
148     }
149 
150     if (changed & R_CONTROL_MODE_MASK) {
151         uint32_t load;
152         if (newctrl & R_CONTROL_MODE_MASK) {
153             /* Periodic: the limit is the LOAD register value */
154             load = m->load;
155         } else {
156             /* Free-running: counter wraps around */
157             load = ptimer_get_limit(m->timer);
158             if (!(m->control & R_CONTROL_SIZE_MASK)) {
159                 load = deposit32(m->load, 0, 16, load);
160             }
161             m->load = load;
162             load = 0xffffffff;
163         }
164         if (!(m->control & R_CONTROL_SIZE_MASK)) {
165             load &= 0xffff;
166         }
167         ptimer_set_limit(m->timer, load, 0);
168     }
169 
170     if (changed & R_CONTROL_SIZE_MASK) {
171         /* Timer switched between 16 and 32 bit count */
172         uint32_t value, load;
173 
174         value = ptimer_get_count(m->timer);
175         load = ptimer_get_limit(m->timer);
176         if (newctrl & R_CONTROL_SIZE_MASK) {
177             /* 16 -> 32, top half of VALUE is in struct field */
178             value = deposit32(m->value, 0, 16, value);
179         } else {
180             /* 32 -> 16: save top half to struct field and truncate */
181             m->value = value;
182             value &= 0xffff;
183         }
184 
185         if (newctrl & R_CONTROL_MODE_MASK) {
186             /* Periodic, timer limit has LOAD value */
187             if (newctrl & R_CONTROL_SIZE_MASK) {
188                 load = deposit32(m->load, 0, 16, load);
189             } else {
190                 m->load = load;
191                 load &= 0xffff;
192             }
193         } else {
194             /* Free-running, timer limit is set to give wraparound */
195             if (newctrl & R_CONTROL_SIZE_MASK) {
196                 load = 0xffffffff;
197             } else {
198                 load = 0xffff;
199             }
200         }
201         ptimer_set_count(m->timer, value);
202         ptimer_set_limit(m->timer, load, 0);
203     }
204 
205     if (newctrl & R_CONTROL_ENABLE_MASK) {
206         /*
207          * ENABLE is set; start the timer after all other changes.
208          * We start it even if the ENABLE bit didn't actually change,
209          * in case the timer was an expired one-shot timer that has
210          * now been changed into a free-running or periodic timer.
211          */
212         ptimer_run(m->timer, !!(newctrl & R_CONTROL_ONESHOT_MASK));
213     }
214 
215     m->control = newctrl;
216 }
217 
218 static uint64_t cmsdk_apb_dualtimer_read(void *opaque, hwaddr offset,
219                                           unsigned size)
220 {
221     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
222     uint64_t r;
223 
224     if (offset >= A_TIMERITCR) {
225         switch (offset) {
226         case A_TIMERITCR:
227             r = s->timeritcr;
228             break;
229         case A_PID4 ... A_CID3:
230             r = timer_id[(offset - A_PID4) / 4];
231             break;
232         default:
233         bad_offset:
234             qemu_log_mask(LOG_GUEST_ERROR,
235                           "CMSDK APB dual-timer read: bad offset %x\n",
236                           (int) offset);
237             r = 0;
238             break;
239         }
240     } else {
241         int timer = offset >> 5;
242         CMSDKAPBDualTimerModule *m;
243 
244         if (timer >= ARRAY_SIZE(s->timermod)) {
245             goto bad_offset;
246         }
247 
248         m = &s->timermod[timer];
249 
250         switch (offset & 0x1F) {
251         case A_TIMER1LOAD:
252         case A_TIMER1BGLOAD:
253             if (m->control & R_CONTROL_MODE_MASK) {
254                 /*
255                  * Periodic: the ptimer limit is the LOAD register value, (or
256                  * just the low 16 bits of it if the timer is in 16-bit mode)
257                  */
258                 r = ptimer_get_limit(m->timer);
259                 if (!(m->control & R_CONTROL_SIZE_MASK)) {
260                     r = deposit32(m->load, 0, 16, r);
261                 }
262             } else {
263                 /* Free-running: LOAD register value is just in m->load */
264                 r = m->load;
265             }
266             break;
267         case A_TIMER1VALUE:
268             r = ptimer_get_count(m->timer);
269             if (!(m->control & R_CONTROL_SIZE_MASK)) {
270                 r = deposit32(m->value, 0, 16, r);
271             }
272             break;
273         case A_TIMER1CONTROL:
274             r = m->control;
275             break;
276         case A_TIMER1RIS:
277             r = m->intstatus;
278             break;
279         case A_TIMER1MIS:
280             r = cmsdk_dualtimermod_intstatus(m);
281             break;
282         default:
283             goto bad_offset;
284         }
285     }
286 
287     trace_cmsdk_apb_dualtimer_read(offset, r, size);
288     return r;
289 }
290 
291 static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset,
292                                        uint64_t value, unsigned size)
293 {
294     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(opaque);
295 
296     trace_cmsdk_apb_dualtimer_write(offset, value, size);
297 
298     if (offset >= A_TIMERITCR) {
299         switch (offset) {
300         case A_TIMERITCR:
301             s->timeritcr = value & R_TIMERITCR_VALID_MASK;
302             cmsdk_apb_dualtimer_update(s);
303             break;
304         case A_TIMERITOP:
305             s->timeritop = value & R_TIMERITOP_VALID_MASK;
306             cmsdk_apb_dualtimer_update(s);
307             break;
308         default:
309         bad_offset:
310             qemu_log_mask(LOG_GUEST_ERROR,
311                           "CMSDK APB dual-timer write: bad offset %x\n",
312                           (int) offset);
313             break;
314         }
315     } else {
316         int timer = offset >> 5;
317         CMSDKAPBDualTimerModule *m;
318 
319         if (timer >= ARRAY_SIZE(s->timermod)) {
320             goto bad_offset;
321         }
322 
323         m = &s->timermod[timer];
324 
325         switch (offset & 0x1F) {
326         case A_TIMER1LOAD:
327             /* Set the limit, and immediately reload the count from it */
328             m->load = value;
329             m->value = value;
330             if (!(m->control & R_CONTROL_SIZE_MASK)) {
331                 value &= 0xffff;
332             }
333             if (!(m->control & R_CONTROL_MODE_MASK)) {
334                 /*
335                  * In free-running mode this won't set the limit but will
336                  * still change the current count value.
337                  */
338                 ptimer_set_count(m->timer, value);
339             } else {
340                 if (!value) {
341                     ptimer_stop(m->timer);
342                 }
343                 ptimer_set_limit(m->timer, value, 1);
344                 if (value && (m->control & R_CONTROL_ENABLE_MASK)) {
345                     /* Force possibly-expired oneshot timer to restart */
346                     ptimer_run(m->timer, 1);
347                 }
348             }
349             break;
350         case A_TIMER1BGLOAD:
351             /* Set the limit, but not the current count */
352             m->load = value;
353             if (!(m->control & R_CONTROL_MODE_MASK)) {
354                 /* In free-running mode there is no limit */
355                 break;
356             }
357             if (!(m->control & R_CONTROL_SIZE_MASK)) {
358                 value &= 0xffff;
359             }
360             ptimer_set_limit(m->timer, value, 0);
361             break;
362         case A_TIMER1CONTROL:
363             cmsdk_dualtimermod_write_control(m, value);
364             cmsdk_apb_dualtimer_update(s);
365             break;
366         case A_TIMER1INTCLR:
367             m->intstatus = 0;
368             cmsdk_apb_dualtimer_update(s);
369             break;
370         default:
371             goto bad_offset;
372         }
373     }
374 }
375 
376 static const MemoryRegionOps cmsdk_apb_dualtimer_ops = {
377     .read = cmsdk_apb_dualtimer_read,
378     .write = cmsdk_apb_dualtimer_write,
379     .endianness = DEVICE_LITTLE_ENDIAN,
380     /* byte/halfword accesses are just zero-padded on reads and writes */
381     .impl.min_access_size = 4,
382     .impl.max_access_size = 4,
383     .valid.min_access_size = 1,
384     .valid.max_access_size = 4,
385 };
386 
387 static void cmsdk_dualtimermod_tick(void *opaque)
388 {
389     CMSDKAPBDualTimerModule *m = opaque;
390 
391     m->intstatus = 1;
392     cmsdk_apb_dualtimer_update(m->parent);
393 }
394 
395 static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m)
396 {
397     m->control = R_CONTROL_INTEN_MASK;
398     m->intstatus = 0;
399     m->load = 0;
400     m->value = 0xffffffff;
401     ptimer_stop(m->timer);
402     /*
403      * We start in free-running mode, with VALUE at 0xffffffff, and
404      * in 16-bit counter mode. This means that the ptimer count and
405      * limit must both be set to 0xffff, so we wrap at 16 bits.
406      */
407     ptimer_set_limit(m->timer, 0xffff, 1);
408     ptimer_set_freq(m->timer, m->parent->pclk_frq);
409 }
410 
411 static void cmsdk_apb_dualtimer_reset(DeviceState *dev)
412 {
413     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
414     int i;
415 
416     trace_cmsdk_apb_dualtimer_reset();
417 
418     for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
419         cmsdk_dualtimermod_reset(&s->timermod[i]);
420     }
421     s->timeritcr = 0;
422     s->timeritop = 0;
423 }
424 
425 static void cmsdk_apb_dualtimer_init(Object *obj)
426 {
427     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
428     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(obj);
429     int i;
430 
431     memory_region_init_io(&s->iomem, obj, &cmsdk_apb_dualtimer_ops,
432                           s, "cmsdk-apb-dualtimer", 0x1000);
433     sysbus_init_mmio(sbd, &s->iomem);
434     sysbus_init_irq(sbd, &s->timerintc);
435 
436     for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
437         sysbus_init_irq(sbd, &s->timermod[i].timerint);
438     }
439 }
440 
441 static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp)
442 {
443     CMSDKAPBDualTimer *s = CMSDK_APB_DUALTIMER(dev);
444     int i;
445 
446     if (s->pclk_frq == 0) {
447         error_setg(errp, "CMSDK APB timer: pclk-frq property must be set");
448         return;
449     }
450 
451     for (i = 0; i < ARRAY_SIZE(s->timermod); i++) {
452         CMSDKAPBDualTimerModule *m = &s->timermod[i];
453         QEMUBH *bh = qemu_bh_new(cmsdk_dualtimermod_tick, m);
454 
455         m->parent = s;
456         m->timer = ptimer_init(bh,
457                                PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
458                                PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT |
459                                PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
460                                PTIMER_POLICY_NO_COUNTER_ROUND_DOWN);
461     }
462 }
463 
464 static const VMStateDescription cmsdk_dualtimermod_vmstate = {
465     .name = "cmsdk-apb-dualtimer-module",
466     .version_id = 1,
467     .minimum_version_id = 1,
468     .fields = (VMStateField[]) {
469         VMSTATE_PTIMER(timer, CMSDKAPBDualTimerModule),
470         VMSTATE_UINT32(load, CMSDKAPBDualTimerModule),
471         VMSTATE_UINT32(value, CMSDKAPBDualTimerModule),
472         VMSTATE_UINT32(control, CMSDKAPBDualTimerModule),
473         VMSTATE_UINT32(intstatus, CMSDKAPBDualTimerModule),
474         VMSTATE_END_OF_LIST()
475     }
476 };
477 
478 static const VMStateDescription cmsdk_apb_dualtimer_vmstate = {
479     .name = "cmsdk-apb-dualtimer",
480     .version_id = 1,
481     .minimum_version_id = 1,
482     .fields = (VMStateField[]) {
483         VMSTATE_STRUCT_ARRAY(timermod, CMSDKAPBDualTimer,
484                              CMSDK_APB_DUALTIMER_NUM_MODULES,
485                              1, cmsdk_dualtimermod_vmstate,
486                              CMSDKAPBDualTimerModule),
487         VMSTATE_UINT32(timeritcr, CMSDKAPBDualTimer),
488         VMSTATE_UINT32(timeritop, CMSDKAPBDualTimer),
489         VMSTATE_END_OF_LIST()
490     }
491 };
492 
493 static Property cmsdk_apb_dualtimer_properties[] = {
494     DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBDualTimer, pclk_frq, 0),
495     DEFINE_PROP_END_OF_LIST(),
496 };
497 
498 static void cmsdk_apb_dualtimer_class_init(ObjectClass *klass, void *data)
499 {
500     DeviceClass *dc = DEVICE_CLASS(klass);
501 
502     dc->realize = cmsdk_apb_dualtimer_realize;
503     dc->vmsd = &cmsdk_apb_dualtimer_vmstate;
504     dc->reset = cmsdk_apb_dualtimer_reset;
505     dc->props = cmsdk_apb_dualtimer_properties;
506 }
507 
508 static const TypeInfo cmsdk_apb_dualtimer_info = {
509     .name = TYPE_CMSDK_APB_DUALTIMER,
510     .parent = TYPE_SYS_BUS_DEVICE,
511     .instance_size = sizeof(CMSDKAPBDualTimer),
512     .instance_init = cmsdk_apb_dualtimer_init,
513     .class_init = cmsdk_apb_dualtimer_class_init,
514 };
515 
516 static void cmsdk_apb_dualtimer_register_types(void)
517 {
518     type_register_static(&cmsdk_apb_dualtimer_info);
519 }
520 
521 type_init(cmsdk_apb_dualtimer_register_types);
522