2 * Arm SSE Subsystem System Timer
4 * Copyright (c) 2020 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 "System timer" which is documented in
14 * the Arm SSE-123 Example Subsystem Technical Reference Manual:
15 * https://developer.arm.com/documentation/101370/latest/
17 * The timer is based around a simple 64-bit incrementing counter
18 * (readable from CNTPCT_HI/LO). The timer fires when
19 * Counter - CompareValue >= 0.
20 * The CompareValue is guest-writable, via CNTP_CVAL_HI/LO.
21 * CNTP_TVAL is an alternative view of the CompareValue defined by
22 * TimerValue = CompareValue[31:0] - Counter[31:0]
23 * which can be both read and written.
24 * This part is similar to the generic timer in an Arm A-class CPU.
26 * The timer also has a separate auto-increment timer. When this
27 * timer is enabled, then the AutoIncrValue is set to:
28 * AutoIncrValue = Reload + Counter
29 * and this timer fires when
30 * Counter - AutoIncrValue >= 0
31 * at which point, an interrupt is generated and the new AutoIncrValue
33 * When the auto-increment timer is enabled, interrupt generation
34 * via the compare/timervalue registers is disabled.
36 #include "qemu/osdep.h"
38 #include "qemu/timer.h"
39 #include "qapi/error.h"
41 #include "hw/timer/sse-timer.h"
42 #include "hw/timer/sse-counter.h"
43 #include "hw/sysbus.h"
45 #include "hw/registerfields.h"
47 #include "hw/qdev-clock.h"
48 #include "hw/qdev-properties.h"
49 #include "migration/vmstate.h"
54 REG32(CNTP_CVAL_LO
, 0x20)
55 REG32(CNTP_CVAL_HI
, 0x24)
56 REG32(CNTP_TVAL
, 0x28)
58 FIELD(CNTP_CTL
, ENABLE
, 0, 1)
59 FIELD(CNTP_CTL
, IMASK
, 1, 1)
60 FIELD(CNTP_CTL
, ISTATUS
, 2, 1)
61 REG32(CNTP_AIVAL_LO
, 0x40)
62 REG32(CNTP_AIVAL_HI
, 0x44)
63 REG32(CNTP_AIVAL_RELOAD
, 0x48)
64 REG32(CNTP_AIVAL_CTL
, 0x4c)
65 FIELD(CNTP_AIVAL_CTL
, EN
, 0, 1)
66 FIELD(CNTP_AIVAL_CTL
, CLR
, 1, 1)
68 FIELD(CNTP_CFG
, AIVAL
, 0, 4)
69 #define R_CNTP_CFG_AIVAL_IMPLEMENTED 1
84 static const int timer_id
[] = {
85 0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
86 0xb7, 0xb0, 0x0b, 0x00, /* PID0..PID3 */
87 0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
90 static bool sse_is_autoinc(SSETimer
*s
)
92 return (s
->cntp_aival_ctl
& R_CNTP_AIVAL_CTL_EN_MASK
) != 0;
95 static bool sse_enabled(SSETimer
*s
)
97 return (s
->cntp_ctl
& R_CNTP_CTL_ENABLE_MASK
) != 0;
100 static uint64_t sse_cntpct(SSETimer
*s
)
102 /* Return the CNTPCT value for the current time */
103 return sse_counter_for_timestamp(s
->counter
,
104 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
));
107 static bool sse_timer_status(SSETimer
*s
)
110 * Return true if timer condition is met. This is used for both
111 * the CNTP_CTL.ISTATUS bit and for whether (unless masked) we
113 * The documentation is unclear about the behaviour of ISTATUS when
114 * in autoincrement mode; we assume that it follows CNTP_AIVAL_CTL.CLR
115 * (ie whether the autoincrement timer is asserting the interrupt).
117 if (!sse_enabled(s
)) {
121 if (sse_is_autoinc(s
)) {
122 return s
->cntp_aival_ctl
& R_CNTP_AIVAL_CTL_CLR_MASK
;
124 return sse_cntpct(s
) >= s
->cntp_cval
;
128 static void sse_update_irq(SSETimer
*s
)
130 bool irqstate
= (!(s
->cntp_ctl
& R_CNTP_CTL_IMASK_MASK
) &&
131 sse_timer_status(s
));
133 qemu_set_irq(s
->irq
, irqstate
);
136 static void sse_set_timer(SSETimer
*s
, uint64_t nexttick
)
138 /* Set the timer to expire at nexttick */
139 uint64_t expiry
= sse_counter_tick_to_time(s
->counter
, nexttick
);
141 if (expiry
<= INT64_MAX
) {
142 timer_mod_ns(&s
->timer
, expiry
);
145 * nexttick is so far in the future that it would overflow the
146 * signed 64-bit range of a QEMUTimer. Since timer_mod_ns()
147 * expiry times are absolute, not relative, we are never going
148 * to be able to set the timer to this value, so we must just
149 * assume that guest execution can never run so long that it
150 * reaches the theoretical point when the timer fires.
151 * This is also the code path for "counter is not running",
152 * which is signalled by expiry == UINT64_MAX.
154 timer_del(&s
->timer
);
158 static void sse_recalc_timer(SSETimer
*s
)
160 /* Recalculate the normal timer */
161 uint64_t count
, nexttick
;
163 if (sse_is_autoinc(s
)) {
167 if (!sse_enabled(s
)) {
168 timer_del(&s
->timer
);
172 count
= sse_cntpct(s
);
174 if (count
>= s
->cntp_cval
) {
176 * Timer condition already met. In theory we have a transition when
177 * the count rolls back over to 0, but that is so far in the future
178 * that it is not representable as a timer_mod() expiry, so in
179 * fact sse_set_timer() will always just delete the timer.
181 nexttick
= UINT64_MAX
;
183 /* Next transition is when count hits cval */
184 nexttick
= s
->cntp_cval
;
186 sse_set_timer(s
, nexttick
);
190 static void sse_autoinc(SSETimer
*s
)
192 /* Auto-increment the AIVAL, and set the timer accordingly */
193 s
->cntp_aival
= sse_cntpct(s
) + s
->cntp_aival_reload
;
194 sse_set_timer(s
, s
->cntp_aival
);
197 static void sse_timer_cb(void *opaque
)
199 SSETimer
*s
= SSE_TIMER(opaque
);
201 if (sse_is_autoinc(s
)) {
202 uint64_t count
= sse_cntpct(s
);
204 if (count
>= s
->cntp_aival
) {
205 /* Timer condition met, set CLR and do another autoinc */
206 s
->cntp_aival_ctl
|= R_CNTP_AIVAL_CTL_CLR_MASK
;
207 s
->cntp_aival
= count
+ s
->cntp_aival_reload
;
209 sse_set_timer(s
, s
->cntp_aival
);
216 static uint64_t sse_timer_read(void *opaque
, hwaddr offset
, unsigned size
)
218 SSETimer
*s
= SSE_TIMER(opaque
);
223 r
= extract64(sse_cntpct(s
), 0, 32);
226 r
= extract64(sse_cntpct(s
), 32, 32);
232 r
= extract64(s
->cntp_cval
, 0, 32);
235 r
= extract64(s
->cntp_cval
, 32, 32);
238 r
= extract64(s
->cntp_cval
- sse_cntpct(s
), 0, 32);
242 if (sse_timer_status(s
)) {
243 r
|= R_CNTP_CTL_ISTATUS_MASK
;
246 case A_CNTP_AIVAL_LO
:
247 r
= extract64(s
->cntp_aival
, 0, 32);
249 case A_CNTP_AIVAL_HI
:
250 r
= extract64(s
->cntp_aival
, 32, 32);
252 case A_CNTP_AIVAL_RELOAD
:
253 r
= s
->cntp_aival_reload
;
255 case A_CNTP_AIVAL_CTL
:
257 * All the bits of AIVAL_CTL are documented as WO, but this is probably
258 * a documentation error. We implement them as readable.
260 r
= s
->cntp_aival_ctl
;
263 r
= R_CNTP_CFG_AIVAL_IMPLEMENTED
<< R_CNTP_CFG_AIVAL_SHIFT
;
265 case A_PID4
... A_CID3
:
266 r
= timer_id
[(offset
- A_PID4
) / 4];
269 qemu_log_mask(LOG_GUEST_ERROR
,
270 "SSE System Timer read: bad offset 0x%x",
276 trace_sse_timer_read(offset
, r
, size
);
280 static void sse_timer_write(void *opaque
, hwaddr offset
, uint64_t value
,
283 SSETimer
*s
= SSE_TIMER(opaque
);
285 trace_sse_timer_write(offset
, value
, size
);
292 s
->cntp_cval
= deposit64(s
->cntp_cval
, 0, 32, value
);
296 s
->cntp_cval
= deposit64(s
->cntp_cval
, 32, 32, value
);
300 s
->cntp_cval
= sse_cntpct(s
) + sextract64(value
, 0, 32);
305 uint32_t old_ctl
= s
->cntp_ctl
;
306 value
&= R_CNTP_CTL_ENABLE_MASK
| R_CNTP_CTL_IMASK_MASK
;
308 if ((old_ctl
^ s
->cntp_ctl
) & R_CNTP_CTL_ENABLE_MASK
) {
309 if (sse_enabled(s
)) {
310 if (sse_is_autoinc(s
)) {
320 case A_CNTP_AIVAL_RELOAD
:
321 s
->cntp_aival_reload
= value
;
323 case A_CNTP_AIVAL_CTL
:
325 uint32_t old_ctl
= s
->cntp_aival_ctl
;
327 /* EN bit is writable; CLR bit is write-0-to-clear, write-1-ignored */
328 s
->cntp_aival_ctl
&= ~R_CNTP_AIVAL_CTL_EN_MASK
;
329 s
->cntp_aival_ctl
|= value
& R_CNTP_AIVAL_CTL_EN_MASK
;
330 if (!(value
& R_CNTP_AIVAL_CTL_CLR_MASK
)) {
331 s
->cntp_aival_ctl
&= ~R_CNTP_AIVAL_CTL_CLR_MASK
;
333 if ((old_ctl
^ s
->cntp_aival_ctl
) & R_CNTP_AIVAL_CTL_EN_MASK
) {
334 /* Auto-increment toggled on/off */
335 if (sse_enabled(s
)) {
336 if (sse_is_autoinc(s
)) {
349 case A_CNTP_AIVAL_LO
:
350 case A_CNTP_AIVAL_HI
:
351 case A_PID4
... A_CID3
:
352 qemu_log_mask(LOG_GUEST_ERROR
,
353 "SSE System Timer write: write to RO offset 0x%x\n",
357 qemu_log_mask(LOG_GUEST_ERROR
,
358 "SSE System Timer write: bad offset 0x%x\n",
364 static const MemoryRegionOps sse_timer_ops
= {
365 .read
= sse_timer_read
,
366 .write
= sse_timer_write
,
367 .endianness
= DEVICE_LITTLE_ENDIAN
,
368 .valid
.min_access_size
= 4,
369 .valid
.max_access_size
= 4,
372 static void sse_timer_reset(DeviceState
*dev
)
374 SSETimer
*s
= SSE_TIMER(dev
);
376 trace_sse_timer_reset();
378 timer_del(&s
->timer
);
383 s
->cntp_aival_ctl
= 0;
384 s
->cntp_aival_reload
= 0;
387 static void sse_timer_counter_callback(Notifier
*notifier
, void *data
)
389 SSETimer
*s
= container_of(notifier
, SSETimer
, counter_notifier
);
391 /* System counter told us we need to recalculate */
392 if (sse_enabled(s
)) {
393 if (sse_is_autoinc(s
)) {
394 sse_set_timer(s
, s
->cntp_aival
);
401 static void sse_timer_init(Object
*obj
)
403 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
404 SSETimer
*s
= SSE_TIMER(obj
);
406 memory_region_init_io(&s
->iomem
, obj
, &sse_timer_ops
,
407 s
, "sse-timer", 0x1000);
408 sysbus_init_mmio(sbd
, &s
->iomem
);
409 sysbus_init_irq(sbd
, &s
->irq
);
412 static void sse_timer_realize(DeviceState
*dev
, Error
**errp
)
414 SSETimer
*s
= SSE_TIMER(dev
);
417 error_setg(errp
, "counter property was not set");
421 s
->counter_notifier
.notify
= sse_timer_counter_callback
;
422 sse_counter_register_consumer(s
->counter
, &s
->counter_notifier
);
424 timer_init_ns(&s
->timer
, QEMU_CLOCK_VIRTUAL
, sse_timer_cb
, s
);
427 static const VMStateDescription sse_timer_vmstate
= {
430 .minimum_version_id
= 1,
431 .fields
= (VMStateField
[]) {
432 VMSTATE_TIMER(timer
, SSETimer
),
433 VMSTATE_UINT32(cntfrq
, SSETimer
),
434 VMSTATE_UINT32(cntp_ctl
, SSETimer
),
435 VMSTATE_UINT64(cntp_cval
, SSETimer
),
436 VMSTATE_UINT64(cntp_aival
, SSETimer
),
437 VMSTATE_UINT32(cntp_aival_ctl
, SSETimer
),
438 VMSTATE_UINT32(cntp_aival_reload
, SSETimer
),
439 VMSTATE_END_OF_LIST()
443 static Property sse_timer_properties
[] = {
444 DEFINE_PROP_LINK("counter", SSETimer
, counter
, TYPE_SSE_COUNTER
, SSECounter
*),
445 DEFINE_PROP_END_OF_LIST(),
448 static void sse_timer_class_init(ObjectClass
*klass
, void *data
)
450 DeviceClass
*dc
= DEVICE_CLASS(klass
);
452 dc
->realize
= sse_timer_realize
;
453 dc
->vmsd
= &sse_timer_vmstate
;
454 dc
->reset
= sse_timer_reset
;
455 device_class_set_props(dc
, sse_timer_properties
);
458 static const TypeInfo sse_timer_info
= {
459 .name
= TYPE_SSE_TIMER
,
460 .parent
= TYPE_SYS_BUS_DEVICE
,
461 .instance_size
= sizeof(SSETimer
),
462 .instance_init
= sse_timer_init
,
463 .class_init
= sse_timer_class_init
,
466 static void sse_timer_register_types(void)
468 type_register_static(&sse_timer_info
);
471 type_init(sse_timer_register_types
);