2 * ARM CMSDK APB dual-timer emulation
4 * Copyright (c) 2018 Linaro Limited
5 * Written by Peter Maydell
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.
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
19 #include "qemu/osdep.h"
22 #include "qapi/error.h"
23 #include "qemu/main-loop.h"
24 #include "qemu/module.h"
25 #include "hw/sysbus.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"
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)
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 */
83 static bool cmsdk_dualtimermod_intstatus(CMSDKAPBDualTimerModule
*m
)
85 /* Return masked interrupt status for the timer module */
86 return m
->intstatus
&& (m
->control
& R_CONTROL_INTEN_MASK
);
89 static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer
*s
)
91 bool timint1
, timint2
, timintc
;
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
;
98 timint1
= cmsdk_dualtimermod_intstatus(&s
->timermod
[0]);
99 timint2
= cmsdk_dualtimermod_intstatus(&s
->timermod
[1]);
102 timintc
= timint1
|| timint2
;
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
);
109 static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule
*m
,
112 /* Handle a write to the CONTROL register */
115 newctrl
&= R_CONTROL_VALID_MASK
;
117 changed
= m
->control
^ newctrl
;
119 if (changed
& ~newctrl
& R_CONTROL_ENABLE_MASK
) {
120 /* ENABLE cleared, stop timer before any further changes */
121 ptimer_stop(m
->timer
);
124 if (changed
& R_CONTROL_PRESCALE_MASK
) {
127 switch (FIELD_EX32(newctrl
, CONTROL
, PRESCALE
)) {
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");
145 g_assert_not_reached();
147 ptimer_set_freq(m
->timer
, m
->parent
->pclk_frq
/ divisor
);
150 if (changed
& R_CONTROL_MODE_MASK
) {
152 if (newctrl
& R_CONTROL_MODE_MASK
) {
153 /* Periodic: the limit is the LOAD register value */
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
);
164 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
167 ptimer_set_limit(m
->timer
, load
, 0);
170 if (changed
& R_CONTROL_SIZE_MASK
) {
171 /* Timer switched between 16 and 32 bit count */
172 uint32_t value
, load
;
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
);
180 /* 32 -> 16: save top half to struct field and truncate */
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
);
194 /* Free-running, timer limit is set to give wraparound */
195 if (newctrl
& R_CONTROL_SIZE_MASK
) {
201 ptimer_set_count(m
->timer
, value
);
202 ptimer_set_limit(m
->timer
, load
, 0);
205 if (newctrl
& R_CONTROL_ENABLE_MASK
) {
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.
212 ptimer_run(m
->timer
, !!(newctrl
& R_CONTROL_ONESHOT_MASK
));
215 m
->control
= newctrl
;
218 static uint64_t cmsdk_apb_dualtimer_read(void *opaque
, hwaddr offset
,
221 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(opaque
);
224 if (offset
>= A_TIMERITCR
) {
229 case A_PID4
... A_CID3
:
230 r
= timer_id
[(offset
- A_PID4
) / 4];
234 qemu_log_mask(LOG_GUEST_ERROR
,
235 "CMSDK APB dual-timer read: bad offset %x\n",
241 int timer
= offset
>> 5;
242 CMSDKAPBDualTimerModule
*m
;
244 if (timer
>= ARRAY_SIZE(s
->timermod
)) {
248 m
= &s
->timermod
[timer
];
250 switch (offset
& 0x1F) {
253 if (m
->control
& R_CONTROL_MODE_MASK
) {
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)
258 r
= ptimer_get_limit(m
->timer
);
259 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
260 r
= deposit32(m
->load
, 0, 16, r
);
263 /* Free-running: LOAD register value is just in m->load */
268 r
= ptimer_get_count(m
->timer
);
269 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
270 r
= deposit32(m
->value
, 0, 16, r
);
273 case A_TIMER1CONTROL
:
280 r
= cmsdk_dualtimermod_intstatus(m
);
287 trace_cmsdk_apb_dualtimer_read(offset
, r
, size
);
291 static void cmsdk_apb_dualtimer_write(void *opaque
, hwaddr offset
,
292 uint64_t value
, unsigned size
)
294 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(opaque
);
296 trace_cmsdk_apb_dualtimer_write(offset
, value
, size
);
298 if (offset
>= A_TIMERITCR
) {
301 s
->timeritcr
= value
& R_TIMERITCR_VALID_MASK
;
302 cmsdk_apb_dualtimer_update(s
);
305 s
->timeritop
= value
& R_TIMERITOP_VALID_MASK
;
306 cmsdk_apb_dualtimer_update(s
);
310 qemu_log_mask(LOG_GUEST_ERROR
,
311 "CMSDK APB dual-timer write: bad offset %x\n",
316 int timer
= offset
>> 5;
317 CMSDKAPBDualTimerModule
*m
;
319 if (timer
>= ARRAY_SIZE(s
->timermod
)) {
323 m
= &s
->timermod
[timer
];
325 switch (offset
& 0x1F) {
327 /* Set the limit, and immediately reload the count from it */
330 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
333 if (!(m
->control
& R_CONTROL_MODE_MASK
)) {
335 * In free-running mode this won't set the limit but will
336 * still change the current count value.
338 ptimer_set_count(m
->timer
, value
);
341 ptimer_stop(m
->timer
);
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);
351 /* Set the limit, but not the current count */
353 if (!(m
->control
& R_CONTROL_MODE_MASK
)) {
354 /* In free-running mode there is no limit */
357 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
360 ptimer_set_limit(m
->timer
, value
, 0);
362 case A_TIMER1CONTROL
:
363 cmsdk_dualtimermod_write_control(m
, value
);
364 cmsdk_apb_dualtimer_update(s
);
368 cmsdk_apb_dualtimer_update(s
);
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,
387 static void cmsdk_dualtimermod_tick(void *opaque
)
389 CMSDKAPBDualTimerModule
*m
= opaque
;
392 cmsdk_apb_dualtimer_update(m
->parent
);
395 static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule
*m
)
397 m
->control
= R_CONTROL_INTEN_MASK
;
400 m
->value
= 0xffffffff;
401 ptimer_stop(m
->timer
);
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.
407 ptimer_set_limit(m
->timer
, 0xffff, 1);
408 ptimer_set_freq(m
->timer
, m
->parent
->pclk_frq
);
411 static void cmsdk_apb_dualtimer_reset(DeviceState
*dev
)
413 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(dev
);
416 trace_cmsdk_apb_dualtimer_reset();
418 for (i
= 0; i
< ARRAY_SIZE(s
->timermod
); i
++) {
419 cmsdk_dualtimermod_reset(&s
->timermod
[i
]);
425 static void cmsdk_apb_dualtimer_init(Object
*obj
)
427 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
428 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(obj
);
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
);
436 for (i
= 0; i
< ARRAY_SIZE(s
->timermod
); i
++) {
437 sysbus_init_irq(sbd
, &s
->timermod
[i
].timerint
);
441 static void cmsdk_apb_dualtimer_realize(DeviceState
*dev
, Error
**errp
)
443 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(dev
);
446 if (s
->pclk_frq
== 0) {
447 error_setg(errp
, "CMSDK APB timer: pclk-frq property must be set");
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
);
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
);
464 static const VMStateDescription cmsdk_dualtimermod_vmstate
= {
465 .name
= "cmsdk-apb-dualtimer-module",
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()
478 static const VMStateDescription cmsdk_apb_dualtimer_vmstate
= {
479 .name
= "cmsdk-apb-dualtimer",
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()
493 static Property cmsdk_apb_dualtimer_properties
[] = {
494 DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBDualTimer
, pclk_frq
, 0),
495 DEFINE_PROP_END_OF_LIST(),
498 static void cmsdk_apb_dualtimer_class_init(ObjectClass
*klass
, void *data
)
500 DeviceClass
*dc
= DEVICE_CLASS(klass
);
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
;
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
,
516 static void cmsdk_apb_dualtimer_register_types(void)
518 type_register_static(&cmsdk_apb_dualtimer_info
);
521 type_init(cmsdk_apb_dualtimer_register_types
);