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/module.h"
24 #include "hw/sysbus.h"
26 #include "hw/qdev-properties.h"
27 #include "hw/registerfields.h"
28 #include "hw/timer/cmsdk-apb-dualtimer.h"
29 #include "migration/vmstate.h"
31 REG32(TIMER1LOAD
, 0x0)
32 REG32(TIMER1VALUE
, 0x4)
33 REG32(TIMER1CONTROL
, 0x8)
34 FIELD(CONTROL
, ONESHOT
, 0, 1)
35 FIELD(CONTROL
, SIZE
, 1, 1)
36 FIELD(CONTROL
, PRESCALE
, 2, 2)
37 FIELD(CONTROL
, INTEN
, 5, 1)
38 FIELD(CONTROL
, MODE
, 6, 1)
39 FIELD(CONTROL
, ENABLE
, 7, 1)
40 #define R_CONTROL_VALID_MASK (R_CONTROL_ONESHOT_MASK | R_CONTROL_SIZE_MASK | \
41 R_CONTROL_PRESCALE_MASK | R_CONTROL_INTEN_MASK | \
42 R_CONTROL_MODE_MASK | R_CONTROL_ENABLE_MASK)
43 REG32(TIMER1INTCLR
, 0xc)
44 REG32(TIMER1RIS
, 0x10)
45 REG32(TIMER1MIS
, 0x14)
46 REG32(TIMER1BGLOAD
, 0x18)
47 REG32(TIMER2LOAD
, 0x20)
48 REG32(TIMER2VALUE
, 0x24)
49 REG32(TIMER2CONTROL
, 0x28)
50 REG32(TIMER2INTCLR
, 0x2c)
51 REG32(TIMER2RIS
, 0x30)
52 REG32(TIMER2MIS
, 0x34)
53 REG32(TIMER2BGLOAD
, 0x38)
54 REG32(TIMERITCR
, 0xf00)
55 FIELD(TIMERITCR
, ENABLE
, 0, 1)
56 #define R_TIMERITCR_VALID_MASK R_TIMERITCR_ENABLE_MASK
57 REG32(TIMERITOP
, 0xf04)
58 FIELD(TIMERITOP
, TIMINT1
, 0, 1)
59 FIELD(TIMERITOP
, TIMINT2
, 1, 1)
60 #define R_TIMERITOP_VALID_MASK (R_TIMERITOP_TIMINT1_MASK | \
61 R_TIMERITOP_TIMINT2_MASK)
76 static const int timer_id
[] = {
77 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
78 0x23, 0xb8, 0x1b, 0x00, /* PID0..PID3 */
79 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
82 static bool cmsdk_dualtimermod_intstatus(CMSDKAPBDualTimerModule
*m
)
84 /* Return masked interrupt status for the timer module */
85 return m
->intstatus
&& (m
->control
& R_CONTROL_INTEN_MASK
);
88 static void cmsdk_apb_dualtimer_update(CMSDKAPBDualTimer
*s
)
90 bool timint1
, timint2
, timintc
;
93 /* Integration test mode: outputs driven directly from TIMERITOP bits */
94 timint1
= s
->timeritop
& R_TIMERITOP_TIMINT1_MASK
;
95 timint2
= s
->timeritop
& R_TIMERITOP_TIMINT2_MASK
;
97 timint1
= cmsdk_dualtimermod_intstatus(&s
->timermod
[0]);
98 timint2
= cmsdk_dualtimermod_intstatus(&s
->timermod
[1]);
101 timintc
= timint1
|| timint2
;
103 qemu_set_irq(s
->timermod
[0].timerint
, timint1
);
104 qemu_set_irq(s
->timermod
[1].timerint
, timint2
);
105 qemu_set_irq(s
->timerintc
, timintc
);
108 static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule
*m
,
111 /* Handle a write to the CONTROL register */
114 ptimer_transaction_begin(m
->timer
);
116 newctrl
&= R_CONTROL_VALID_MASK
;
118 changed
= m
->control
^ newctrl
;
120 if (changed
& ~newctrl
& R_CONTROL_ENABLE_MASK
) {
121 /* ENABLE cleared, stop timer before any further changes */
122 ptimer_stop(m
->timer
);
125 if (changed
& R_CONTROL_PRESCALE_MASK
) {
128 switch (FIELD_EX32(newctrl
, CONTROL
, PRESCALE
)) {
139 /* UNDEFINED; complain, and arbitrarily treat like 2 */
140 qemu_log_mask(LOG_GUEST_ERROR
,
141 "CMSDK APB dual-timer: CONTROL.PRESCALE==0b11"
142 " is undefined behaviour\n");
146 g_assert_not_reached();
148 ptimer_set_freq(m
->timer
, m
->parent
->pclk_frq
/ divisor
);
151 if (changed
& R_CONTROL_MODE_MASK
) {
153 if (newctrl
& R_CONTROL_MODE_MASK
) {
154 /* Periodic: the limit is the LOAD register value */
157 /* Free-running: counter wraps around */
158 load
= ptimer_get_limit(m
->timer
);
159 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
160 load
= deposit32(m
->load
, 0, 16, load
);
165 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
168 ptimer_set_limit(m
->timer
, load
, 0);
171 if (changed
& R_CONTROL_SIZE_MASK
) {
172 /* Timer switched between 16 and 32 bit count */
173 uint32_t value
, load
;
175 value
= ptimer_get_count(m
->timer
);
176 load
= ptimer_get_limit(m
->timer
);
177 if (newctrl
& R_CONTROL_SIZE_MASK
) {
178 /* 16 -> 32, top half of VALUE is in struct field */
179 value
= deposit32(m
->value
, 0, 16, value
);
181 /* 32 -> 16: save top half to struct field and truncate */
186 if (newctrl
& R_CONTROL_MODE_MASK
) {
187 /* Periodic, timer limit has LOAD value */
188 if (newctrl
& R_CONTROL_SIZE_MASK
) {
189 load
= deposit32(m
->load
, 0, 16, load
);
195 /* Free-running, timer limit is set to give wraparound */
196 if (newctrl
& R_CONTROL_SIZE_MASK
) {
202 ptimer_set_count(m
->timer
, value
);
203 ptimer_set_limit(m
->timer
, load
, 0);
206 if (newctrl
& R_CONTROL_ENABLE_MASK
) {
208 * ENABLE is set; start the timer after all other changes.
209 * We start it even if the ENABLE bit didn't actually change,
210 * in case the timer was an expired one-shot timer that has
211 * now been changed into a free-running or periodic timer.
213 ptimer_run(m
->timer
, !!(newctrl
& R_CONTROL_ONESHOT_MASK
));
216 m
->control
= newctrl
;
218 ptimer_transaction_commit(m
->timer
);
221 static uint64_t cmsdk_apb_dualtimer_read(void *opaque
, hwaddr offset
,
224 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(opaque
);
227 if (offset
>= A_TIMERITCR
) {
232 case A_PID4
... A_CID3
:
233 r
= timer_id
[(offset
- A_PID4
) / 4];
237 qemu_log_mask(LOG_GUEST_ERROR
,
238 "CMSDK APB dual-timer read: bad offset %x\n",
244 int timer
= offset
>> 5;
245 CMSDKAPBDualTimerModule
*m
;
247 if (timer
>= ARRAY_SIZE(s
->timermod
)) {
251 m
= &s
->timermod
[timer
];
253 switch (offset
& 0x1F) {
256 if (m
->control
& R_CONTROL_MODE_MASK
) {
258 * Periodic: the ptimer limit is the LOAD register value, (or
259 * just the low 16 bits of it if the timer is in 16-bit mode)
261 r
= ptimer_get_limit(m
->timer
);
262 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
263 r
= deposit32(m
->load
, 0, 16, r
);
266 /* Free-running: LOAD register value is just in m->load */
271 r
= ptimer_get_count(m
->timer
);
272 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
273 r
= deposit32(m
->value
, 0, 16, r
);
276 case A_TIMER1CONTROL
:
283 r
= cmsdk_dualtimermod_intstatus(m
);
290 trace_cmsdk_apb_dualtimer_read(offset
, r
, size
);
294 static void cmsdk_apb_dualtimer_write(void *opaque
, hwaddr offset
,
295 uint64_t value
, unsigned size
)
297 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(opaque
);
299 trace_cmsdk_apb_dualtimer_write(offset
, value
, size
);
301 if (offset
>= A_TIMERITCR
) {
304 s
->timeritcr
= value
& R_TIMERITCR_VALID_MASK
;
305 cmsdk_apb_dualtimer_update(s
);
308 s
->timeritop
= value
& R_TIMERITOP_VALID_MASK
;
309 cmsdk_apb_dualtimer_update(s
);
313 qemu_log_mask(LOG_GUEST_ERROR
,
314 "CMSDK APB dual-timer write: bad offset %x\n",
319 int timer
= offset
>> 5;
320 CMSDKAPBDualTimerModule
*m
;
322 if (timer
>= ARRAY_SIZE(s
->timermod
)) {
326 m
= &s
->timermod
[timer
];
328 switch (offset
& 0x1F) {
330 /* Set the limit, and immediately reload the count from it */
333 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
336 ptimer_transaction_begin(m
->timer
);
337 if (!(m
->control
& R_CONTROL_MODE_MASK
)) {
339 * In free-running mode this won't set the limit but will
340 * still change the current count value.
342 ptimer_set_count(m
->timer
, value
);
345 ptimer_stop(m
->timer
);
347 ptimer_set_limit(m
->timer
, value
, 1);
348 if (value
&& (m
->control
& R_CONTROL_ENABLE_MASK
)) {
349 /* Force possibly-expired oneshot timer to restart */
350 ptimer_run(m
->timer
, 1);
353 ptimer_transaction_commit(m
->timer
);
356 /* Set the limit, but not the current count */
358 if (!(m
->control
& R_CONTROL_MODE_MASK
)) {
359 /* In free-running mode there is no limit */
362 if (!(m
->control
& R_CONTROL_SIZE_MASK
)) {
365 ptimer_transaction_begin(m
->timer
);
366 ptimer_set_limit(m
->timer
, value
, 0);
367 ptimer_transaction_commit(m
->timer
);
369 case A_TIMER1CONTROL
:
370 cmsdk_dualtimermod_write_control(m
, value
);
371 cmsdk_apb_dualtimer_update(s
);
375 cmsdk_apb_dualtimer_update(s
);
383 static const MemoryRegionOps cmsdk_apb_dualtimer_ops
= {
384 .read
= cmsdk_apb_dualtimer_read
,
385 .write
= cmsdk_apb_dualtimer_write
,
386 .endianness
= DEVICE_LITTLE_ENDIAN
,
387 /* byte/halfword accesses are just zero-padded on reads and writes */
388 .impl
.min_access_size
= 4,
389 .impl
.max_access_size
= 4,
390 .valid
.min_access_size
= 1,
391 .valid
.max_access_size
= 4,
394 static void cmsdk_dualtimermod_tick(void *opaque
)
396 CMSDKAPBDualTimerModule
*m
= opaque
;
399 cmsdk_apb_dualtimer_update(m
->parent
);
402 static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule
*m
)
404 m
->control
= R_CONTROL_INTEN_MASK
;
407 m
->value
= 0xffffffff;
408 ptimer_transaction_begin(m
->timer
);
409 ptimer_stop(m
->timer
);
411 * We start in free-running mode, with VALUE at 0xffffffff, and
412 * in 16-bit counter mode. This means that the ptimer count and
413 * limit must both be set to 0xffff, so we wrap at 16 bits.
415 ptimer_set_limit(m
->timer
, 0xffff, 1);
416 ptimer_set_freq(m
->timer
, m
->parent
->pclk_frq
);
417 ptimer_transaction_commit(m
->timer
);
420 static void cmsdk_apb_dualtimer_reset(DeviceState
*dev
)
422 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(dev
);
425 trace_cmsdk_apb_dualtimer_reset();
427 for (i
= 0; i
< ARRAY_SIZE(s
->timermod
); i
++) {
428 cmsdk_dualtimermod_reset(&s
->timermod
[i
]);
434 static void cmsdk_apb_dualtimer_init(Object
*obj
)
436 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
437 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(obj
);
440 memory_region_init_io(&s
->iomem
, obj
, &cmsdk_apb_dualtimer_ops
,
441 s
, "cmsdk-apb-dualtimer", 0x1000);
442 sysbus_init_mmio(sbd
, &s
->iomem
);
443 sysbus_init_irq(sbd
, &s
->timerintc
);
445 for (i
= 0; i
< ARRAY_SIZE(s
->timermod
); i
++) {
446 sysbus_init_irq(sbd
, &s
->timermod
[i
].timerint
);
450 static void cmsdk_apb_dualtimer_realize(DeviceState
*dev
, Error
**errp
)
452 CMSDKAPBDualTimer
*s
= CMSDK_APB_DUALTIMER(dev
);
455 if (s
->pclk_frq
== 0) {
456 error_setg(errp
, "CMSDK APB timer: pclk-frq property must be set");
460 for (i
= 0; i
< ARRAY_SIZE(s
->timermod
); i
++) {
461 CMSDKAPBDualTimerModule
*m
= &s
->timermod
[i
];
464 m
->timer
= ptimer_init(cmsdk_dualtimermod_tick
, m
,
465 PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD
|
466 PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT
|
467 PTIMER_POLICY_NO_IMMEDIATE_RELOAD
|
468 PTIMER_POLICY_NO_COUNTER_ROUND_DOWN
);
472 static const VMStateDescription cmsdk_dualtimermod_vmstate
= {
473 .name
= "cmsdk-apb-dualtimer-module",
475 .minimum_version_id
= 1,
476 .fields
= (VMStateField
[]) {
477 VMSTATE_PTIMER(timer
, CMSDKAPBDualTimerModule
),
478 VMSTATE_UINT32(load
, CMSDKAPBDualTimerModule
),
479 VMSTATE_UINT32(value
, CMSDKAPBDualTimerModule
),
480 VMSTATE_UINT32(control
, CMSDKAPBDualTimerModule
),
481 VMSTATE_UINT32(intstatus
, CMSDKAPBDualTimerModule
),
482 VMSTATE_END_OF_LIST()
486 static const VMStateDescription cmsdk_apb_dualtimer_vmstate
= {
487 .name
= "cmsdk-apb-dualtimer",
489 .minimum_version_id
= 1,
490 .fields
= (VMStateField
[]) {
491 VMSTATE_STRUCT_ARRAY(timermod
, CMSDKAPBDualTimer
,
492 CMSDK_APB_DUALTIMER_NUM_MODULES
,
493 1, cmsdk_dualtimermod_vmstate
,
494 CMSDKAPBDualTimerModule
),
495 VMSTATE_UINT32(timeritcr
, CMSDKAPBDualTimer
),
496 VMSTATE_UINT32(timeritop
, CMSDKAPBDualTimer
),
497 VMSTATE_END_OF_LIST()
501 static Property cmsdk_apb_dualtimer_properties
[] = {
502 DEFINE_PROP_UINT32("pclk-frq", CMSDKAPBDualTimer
, pclk_frq
, 0),
503 DEFINE_PROP_END_OF_LIST(),
506 static void cmsdk_apb_dualtimer_class_init(ObjectClass
*klass
, void *data
)
508 DeviceClass
*dc
= DEVICE_CLASS(klass
);
510 dc
->realize
= cmsdk_apb_dualtimer_realize
;
511 dc
->vmsd
= &cmsdk_apb_dualtimer_vmstate
;
512 dc
->reset
= cmsdk_apb_dualtimer_reset
;
513 device_class_set_props(dc
, cmsdk_apb_dualtimer_properties
);
516 static const TypeInfo cmsdk_apb_dualtimer_info
= {
517 .name
= TYPE_CMSDK_APB_DUALTIMER
,
518 .parent
= TYPE_SYS_BUS_DEVICE
,
519 .instance_size
= sizeof(CMSDKAPBDualTimer
),
520 .instance_init
= cmsdk_apb_dualtimer_init
,
521 .class_init
= cmsdk_apb_dualtimer_class_init
,
524 static void cmsdk_apb_dualtimer_register_types(void)
526 type_register_static(&cmsdk_apb_dualtimer_info
);
529 type_init(cmsdk_apb_dualtimer_register_types
);