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"
26 #include "hw/registerfields.h"
27 #include "hw/timer/cmsdk-apb-dualtimer.h"
29 REG32(TIMER1LOAD
, 0x0)
30 REG32(TIMER1VALUE
, 0x4)
31 REG32(TIMER1CONTROL
, 0x8)
32 FIELD(CONTROL
, ONESHOT
, 0, 1)
33 FIELD(CONTROL
, SIZE
, 1, 1)
34 FIELD(CONTROL
, PRESCALE
, 2, 2)
35 FIELD(CONTROL
, INTEN
, 5, 1)
36 FIELD(CONTROL
, MODE
, 6, 1)
37 FIELD(CONTROL
, ENABLE
, 7, 1)
38 #define R_CONTROL_VALID_MASK (R_CONTROL_ONESHOT_MASK | R_CONTROL_SIZE_MASK | \
39 R_CONTROL_PRESCALE_MASK | R_CONTROL_INTEN_MASK | \
40 R_CONTROL_MODE_MASK | R_CONTROL_ENABLE_MASK)
41 REG32(TIMER1INTCLR
, 0xc)
42 REG32(TIMER1RIS
, 0x10)
43 REG32(TIMER1MIS
, 0x14)
44 REG32(TIMER1BGLOAD
, 0x18)
45 REG32(TIMER2LOAD
, 0x20)
46 REG32(TIMER2VALUE
, 0x24)
47 REG32(TIMER2CONTROL
, 0x28)
48 REG32(TIMER2INTCLR
, 0x2c)
49 REG32(TIMER2RIS
, 0x30)
50 REG32(TIMER2MIS
, 0x34)
51 REG32(TIMER2BGLOAD
, 0x38)
52 REG32(TIMERITCR
, 0xf00)
53 FIELD(TIMERITCR
, ENABLE
, 0, 1)
54 #define R_TIMERITCR_VALID_MASK R_TIMERITCR_ENABLE_MASK
55 REG32(TIMERITOP
, 0xf04)
56 FIELD(TIMERITOP
, TIMINT1
, 0, 1)
57 FIELD(TIMERITOP
, TIMINT2
, 1, 1)
58 #define R_TIMERITOP_VALID_MASK (R_TIMERITOP_TIMINT1_MASK | \
59 R_TIMERITOP_TIMINT2_MASK)
74 static const int timer_id
[] = {
75 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
76 0x23, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
77 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
80 static bool cmsdk_dualtimermod_intstatus(CMSDKAPBDualTimerModule
*m
)
82 /* Return masked interrupt status for the timer module */
83 return m
->intstatus
&& (m
->control
& R_CONTROL_INTEN_MASK
);
86 static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer
*s
)
88 bool timint1
, timint2
, timintc
;
91 /* Integration test mode: outputs driven directly from TIMERITOP bits */
92 timint1
= s
->timeritop
& R_TIMERITOP_TIMINT1_MASK
;
93 timint2
= s
->timeritop
& R_TIMERITOP_TIMINT2_MASK
;
95 timint1
= cmsdk_dualtimermod_intstatus(&s
->timermod
[0]);
96 timint2
= cmsdk_dualtimermod_intstatus(&s
->timermod
[1]);
99 timintc
= timint1
|| timint2
;
101 qemu_set_irq(s
->timermod
[0].timerint
, timint1
);
102 qemu_set_irq(s
->timermod
[1].timerint
, timint2
);
103 qemu_set_irq(s
->timerintc
, timintc
);
106 static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule
*m
,
109 /* Handle a write to the CONTROL register */
112 newctrl
&= R_CONTROL_VALID_MASK
;
114 changed
= m
->control
^ newctrl
;
116 if (changed
& ~newctrl
& R_CONTROL_ENABLE_MASK
) {
117 /* ENABLE cleared, stop timer before any further changes */
118 ptimer_stop(m
->timer
);
121 if (changed
& R_CONTROL_PRESCALE_MASK
) {
124 switch (FIELD_EX32(newctrl
, CONTROL
, PRESCALE
)) {
135 /* UNDEFINED; complain, and arbitrarily treat like 2 */
136 qemu_log_mask(LOG_GUEST_ERROR
,
137 "CMSDK APB dual-timer: CONTROL.PRESCALE==0b11"
138 " is undefined behaviour\n");
142 g_assert_not_reached();
144 ptimer_set_freq(m
->timer
, m
->parent
->pclk_frq
/ divisor
);
147 if (changed
& R_CONTROL_MODE_MASK
) {
149 if (newctrl
& R_CONTROL_MODE_MASK
) {
150 /* Periodic: the limit is the LOAD register value */
153 /* Free-running: counter wraps around */
154 load
= ptimer_get_limit(m
->timer
);
155 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
156 load
= deposit32(m
->load
, 0, 16, load
);
161 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
164 ptimer_set_limit(m
->timer
, load
, 0);
167 if (changed
& R_CONTROL_SIZE_MASK
) {
168 /* Timer switched between 16 and 32 bit count */
169 uint32_t value
, load
;
171 value
= ptimer_get_count(m
->timer
);
172 load
= ptimer_get_limit(m
->timer
);
173 if (newctrl
& R_CONTROL_SIZE_MASK
) {
174 /* 16 -> 32, top half of VALUE is in struct field */
175 value
= deposit32(m
->value
, 0, 16, value
);
177 /* 32 -> 16: save top half to struct field and truncate */
182 if (newctrl
& R_CONTROL_MODE_MASK
) {
183 /* Periodic, timer limit has LOAD value */
184 if (newctrl
& R_CONTROL_SIZE_MASK
) {
185 load
= deposit32(m
->load
, 0, 16, load
);
191 /* Free-running, timer limit is set to give wraparound */
192 if (newctrl
& R_CONTROL_SIZE_MASK
) {
198 ptimer_set_count(m
->timer
, value
);
199 ptimer_set_limit(m
->timer
, load
, 0);
202 if (newctrl
& R_CONTROL_ENABLE_MASK
) {
204 * ENABLE is set; start the timer after all other changes.
205 * We start it even if the ENABLE bit didn't actually change,
206 * in case the timer was an expired one-shot timer that has
207 * now been changed into a free-running or periodic timer.
209 ptimer_run(m
->timer
, !!(newctrl
& R_CONTROL_ONESHOT_MASK
));
212 m
->control
= newctrl
;
215 static uint64_t cmsdk_apb_dualtimer_read(void *opaque
, hwaddr offset
,
218 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(opaque
);
221 if (offset
>= A_TIMERITCR
) {
226 case A_PID4
... A_CID3
:
227 r
= timer_id
[(offset
- A_PID4
) / 4];
231 qemu_log_mask(LOG_GUEST_ERROR
,
232 "CMSDK APB dual-timer read: bad offset %x\n",
238 int timer
= offset
>> 5;
239 CMSDKAPBDualTimerModule
*m
;
241 if (timer
>= ARRAY_SIZE(s
->timermod
)) {
245 m
= &s
->timermod
[timer
];
247 switch (offset
& 0x1F) {
250 if (m
->control
& R_CONTROL_MODE_MASK
) {
252 * Periodic: the ptimer limit is the LOAD register value, (or
253 * just the low 16 bits of it if the timer is in 16-bit mode)
255 r
= ptimer_get_limit(m
->timer
);
256 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
257 r
= deposit32(m
->load
, 0, 16, r
);
260 /* Free-running: LOAD register value is just in m->load */
265 r
= ptimer_get_count(m
->timer
);
266 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
267 r
= deposit32(m
->value
, 0, 16, r
);
270 case A_TIMER1CONTROL
:
277 r
= cmsdk_dualtimermod_intstatus(m
);
284 trace_cmsdk_apb_dualtimer_read(offset
, r
, size
);
288 static void cmsdk_apb_dualtimer_write(void *opaque
, hwaddr offset
,
289 uint64_t value
, unsigned size
)
291 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(opaque
);
293 trace_cmsdk_apb_dualtimer_write(offset
, value
, size
);
295 if (offset
>= A_TIMERITCR
) {
298 s
->timeritcr
= value
& R_TIMERITCR_VALID_MASK
;
299 cmsdk_apb_dualtimer_update(s
);
302 s
->timeritop
= value
& R_TIMERITOP_VALID_MASK
;
303 cmsdk_apb_dualtimer_update(s
);
307 qemu_log_mask(LOG_GUEST_ERROR
,
308 "CMSDK APB dual-timer write: bad offset %x\n",
313 int timer
= offset
>> 5;
314 CMSDKAPBDualTimerModule
*m
;
316 if (timer
>= ARRAY_SIZE(s
->timermod
)) {
320 m
= &s
->timermod
[timer
];
322 switch (offset
& 0x1F) {
324 /* Set the limit, and immediately reload the count from it */
327 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
330 if (!(m
->control
& R_CONTROL_MODE_MASK
)) {
332 * In free-running mode this won't set the limit but will
333 * still change the current count value.
335 ptimer_set_count(m
->timer
, value
);
338 ptimer_stop(m
->timer
);
340 ptimer_set_limit(m
->timer
, value
, 1);
341 if (value
&& (m
->control
& R_CONTROL_ENABLE_MASK
)) {
342 /* Force possibly-expired oneshot timer to restart */
343 ptimer_run(m
->timer
, 1);
348 /* Set the limit, but not the current count */
350 if (!(m
->control
& R_CONTROL_MODE_MASK
)) {
351 /* In free-running mode there is no limit */
354 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
357 ptimer_set_limit(m
->timer
, value
, 0);
359 case A_TIMER1CONTROL
:
360 cmsdk_dualtimermod_write_control(m
, value
);
361 cmsdk_apb_dualtimer_update(s
);
365 cmsdk_apb_dualtimer_update(s
);
373 static const MemoryRegionOps cmsdk_apb_dualtimer_ops
= {
374 .read
= cmsdk_apb_dualtimer_read
,
375 .write
= cmsdk_apb_dualtimer_write
,
376 .endianness
= DEVICE_LITTLE_ENDIAN
,
377 /* byte/halfword accesses are just zero-padded on reads and writes */
378 .impl
.min_access_size
= 4,
379 .impl
.max_access_size
= 4,
380 .valid
.min_access_size
= 1,
381 .valid
.max_access_size
= 4,
384 static void cmsdk_dualtimermod_tick(void *opaque
)
386 CMSDKAPBDualTimerModule
*m
= opaque
;
389 cmsdk_apb_dualtimer_update(m
->parent
);
392 static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule
*m
)
394 m
->control
= R_CONTROL_INTEN_MASK
;
397 m
->value
= 0xffffffff;
398 ptimer_stop(m
->timer
);
400 * We start in free-running mode, with VALUE at 0xffffffff, and
401 * in 16-bit counter mode. This means that the ptimer count and
402 * limit must both be set to 0xffff, so we wrap at 16 bits.
404 ptimer_set_limit(m
->timer
, 0xffff, 1);
405 ptimer_set_freq(m
->timer
, m
->parent
->pclk_frq
);
408 static void cmsdk_apb_dualtimer_reset(DeviceState
*dev
)
410 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(dev
);
413 trace_cmsdk_apb_dualtimer_reset();
415 for (i
= 0; i
< ARRAY_SIZE(s
->timermod
); i
++) {
416 cmsdk_dualtimermod_reset(&s
->timermod
[i
]);
422 static void cmsdk_apb_dualtimer_init(Object
*obj
)
424 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
425 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(obj
);
428 memory_region_init_io(&s
->iomem
, obj
, &cmsdk_apb_dualtimer_ops
,
429 s
, "cmsdk-apb-dualtimer", 0x1000);
430 sysbus_init_mmio(sbd
, &s
->iomem
);
431 sysbus_init_irq(sbd
, &s
->timerintc
);
433 for (i
= 0; i
< ARRAY_SIZE(s
->timermod
); i
++) {
434 sysbus_init_irq(sbd
, &s
->timermod
[i
].timerint
);
438 static void cmsdk_apb_dualtimer_realize(DeviceState
*dev
, Error
**errp
)
440 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(dev
);
443 if (s
->pclk_frq
== 0) {
444 error_setg(errp
, "CMSDK APB timer: pclk-frq property must be set");
448 for (i
= 0; i
< ARRAY_SIZE(s
->timermod
); i
++) {
449 CMSDKAPBDualTimerModule
*m
= &s
->timermod
[i
];
450 QEMUBH
*bh
= qemu_bh_new(cmsdk_dualtimermod_tick
, m
);
453 m
->timer
= ptimer_init(bh
,
454 PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD
|
455 PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT
|
456 PTIMER_POLICY_NO_IMMEDIATE_RELOAD
|
457 PTIMER_POLICY_NO_COUNTER_ROUND_DOWN
);
461 static const VMStateDescription cmsdk_dualtimermod_vmstate
= {
462 .name
= "cmsdk-apb-dualtimer-module",
464 .minimum_version_id
= 1,
465 .fields
= (VMStateField
[]) {
466 VMSTATE_PTIMER(timer
, CMSDKAPBDualTimerModule
),
467 VMSTATE_UINT32(load
, CMSDKAPBDualTimerModule
),
468 VMSTATE_UINT32(value
, CMSDKAPBDualTimerModule
),
469 VMSTATE_UINT32(control
, CMSDKAPBDualTimerModule
),
470 VMSTATE_UINT32(intstatus
, CMSDKAPBDualTimerModule
),
471 VMSTATE_END_OF_LIST()
475 static const VMStateDescription cmsdk_apb_dualtimer_vmstate
= {
476 .name
= "cmsdk-apb-dualtimer",
478 .minimum_version_id
= 1,
479 .fields
= (VMStateField
[]) {
480 VMSTATE_STRUCT_ARRAY(timermod
, CMSDKAPBDualTimer
,
481 CMSDK_APB_DUALTIMER_NUM_MODULES
,
482 1, cmsdk_dualtimermod_vmstate
,
483 CMSDKAPBDualTimerModule
),
484 VMSTATE_UINT32(timeritcr
, CMSDKAPBDualTimer
),
485 VMSTATE_UINT32(timeritop
, CMSDKAPBDualTimer
),
486 VMSTATE_END_OF_LIST()
490 static Property cmsdk_apb_dualtimer_properties
[] = {
491 DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBDualTimer
, pclk_frq
, 0),
492 DEFINE_PROP_END_OF_LIST(),
495 static void cmsdk_apb_dualtimer_class_init(ObjectClass
*klass
, void *data
)
497 DeviceClass
*dc
= DEVICE_CLASS(klass
);
499 dc
->realize
= cmsdk_apb_dualtimer_realize
;
500 dc
->vmsd
= &cmsdk_apb_dualtimer_vmstate
;
501 dc
->reset
= cmsdk_apb_dualtimer_reset
;
502 dc
->props
= cmsdk_apb_dualtimer_properties
;
505 static const TypeInfo cmsdk_apb_dualtimer_info
= {
506 .name
= TYPE_CMSDK_APB_DUALTIMER
,
507 .parent
= TYPE_SYS_BUS_DEVICE
,
508 .instance_size
= sizeof(CMSDKAPBDualTimer
),
509 .instance_init
= cmsdk_apb_dualtimer_init
,
510 .class_init
= cmsdk_apb_dualtimer_class_init
,
513 static void cmsdk_apb_dualtimer_register_types(void)
515 type_register_static(&cmsdk_apb_dualtimer_info
);
518 type_init(cmsdk_apb_dualtimer_register_types
);