4 * Copyright (c) 2006-2007 CodeSourcery.
5 * Written by Paul Brook
6 * Copyright (c) 2017 Linaro Ltd
7 * Written by Peter Maydell
9 * This code is licensed under the GPL (version 2 or later).
12 #include "qemu/osdep.h"
13 #include "hw/timer/armv7m_systick.h"
14 #include "migration/vmstate.h"
16 #include "hw/sysbus.h"
17 #include "hw/qdev-clock.h"
18 #include "qemu/timer.h"
20 #include "qemu/module.h"
21 #include "qapi/error.h"
24 #define SYSTICK_ENABLE (1 << 0)
25 #define SYSTICK_TICKINT (1 << 1)
26 #define SYSTICK_CLKSOURCE (1 << 2)
27 #define SYSTICK_COUNTFLAG (1 << 16)
29 #define SYSCALIB_NOREF (1U << 31)
30 #define SYSCALIB_SKEW (1U << 30)
31 #define SYSCALIB_TENMS ((1U << 24) - 1)
33 static void systick_set_period_from_clock(SysTickState
*s
)
36 * Set the ptimer period from whichever clock is selected.
37 * Must be called from within a ptimer transaction block.
39 if (s
->control
& SYSTICK_CLKSOURCE
) {
40 ptimer_set_period_from_clock(s
->ptimer
, s
->cpuclk
, 1);
42 ptimer_set_period_from_clock(s
->ptimer
, s
->refclk
, 1);
46 static void systick_timer_tick(void *opaque
)
48 SysTickState
*s
= (SysTickState
*)opaque
;
50 trace_systick_timer_tick();
52 s
->control
|= SYSTICK_COUNTFLAG
;
53 if (s
->control
& SYSTICK_TICKINT
) {
54 /* Tell the NVIC to pend the SysTick exception */
55 qemu_irq_pulse(s
->irq
);
57 if (ptimer_get_limit(s
->ptimer
) == 0) {
59 * Timer expiry with SYST_RVR zero disables the timer
60 * (but doesn't clear SYST_CSR.ENABLE)
62 ptimer_stop(s
->ptimer
);
66 static MemTxResult
systick_read(void *opaque
, hwaddr addr
, uint64_t *data
,
67 unsigned size
, MemTxAttrs attrs
)
69 SysTickState
*s
= opaque
;
73 /* Generate BusFault for unprivileged accesses */
78 case 0x0: /* SysTick Control and Status. */
80 s
->control
&= ~SYSTICK_COUNTFLAG
;
82 case 0x4: /* SysTick Reload Value. */
83 val
= ptimer_get_limit(s
->ptimer
);
85 case 0x8: /* SysTick Current Value. */
86 val
= ptimer_get_count(s
->ptimer
);
88 case 0xc: /* SysTick Calibration Value. */
90 * In real hardware it is possible to make this register report
91 * a different value from what the reference clock is actually
92 * running at. We don't model that (which usually happens due
93 * to integration errors in the real hardware) and instead always
94 * report the theoretical correct value as described in the
95 * knowledgebase article at
96 * https://developer.arm.com/documentation/ka001325/latest
97 * If necessary, we could implement an extra QOM property on this
98 * device to force the STCALIB value to something different from
99 * the "correct" value.
101 if (!clock_has_source(s
->refclk
)) {
102 val
= SYSCALIB_NOREF
;
105 val
= clock_ns_to_ticks(s
->refclk
, 10 * SCALE_MS
) - 1;
106 val
&= SYSCALIB_TENMS
;
107 if (clock_ticks_to_ns(s
->refclk
, val
+ 1) != 10 * SCALE_MS
) {
108 /* report that tick count does not yield exactly 10ms */
109 val
|= SYSCALIB_SKEW
;
114 qemu_log_mask(LOG_GUEST_ERROR
,
115 "SysTick: Bad read offset 0x%" HWADDR_PRIx
"\n", addr
);
119 trace_systick_read(addr
, val
, size
);
124 static MemTxResult
systick_write(void *opaque
, hwaddr addr
,
125 uint64_t value
, unsigned size
,
128 SysTickState
*s
= opaque
;
131 /* Generate BusFault for unprivileged accesses */
135 trace_systick_write(addr
, value
, size
);
138 case 0x0: /* SysTick Control and Status. */
142 if (!clock_has_source(s
->refclk
)) {
143 /* This bit is always 1 if there is no external refclk */
144 value
|= SYSTICK_CLKSOURCE
;
147 ptimer_transaction_begin(s
->ptimer
);
149 s
->control
&= 0xfffffff8;
150 s
->control
|= value
& 7;
152 if ((oldval
^ value
) & SYSTICK_CLKSOURCE
) {
153 systick_set_period_from_clock(s
);
156 if ((oldval
^ value
) & SYSTICK_ENABLE
) {
157 if (value
& SYSTICK_ENABLE
) {
158 ptimer_run(s
->ptimer
, 0);
160 ptimer_stop(s
->ptimer
);
163 ptimer_transaction_commit(s
->ptimer
);
166 case 0x4: /* SysTick Reload Value. */
167 ptimer_transaction_begin(s
->ptimer
);
168 ptimer_set_limit(s
->ptimer
, value
& 0xffffff, 0);
169 ptimer_transaction_commit(s
->ptimer
);
171 case 0x8: /* SysTick Current Value. */
173 * Writing any value clears SYST_CVR to zero and clears
174 * SYST_CSR.COUNTFLAG. The counter will then reload from SYST_RVR
175 * on the next clock edge unless SYST_RVR is zero.
177 ptimer_transaction_begin(s
->ptimer
);
178 if (ptimer_get_limit(s
->ptimer
) == 0) {
179 ptimer_stop(s
->ptimer
);
181 ptimer_set_count(s
->ptimer
, 0);
182 s
->control
&= ~SYSTICK_COUNTFLAG
;
183 ptimer_transaction_commit(s
->ptimer
);
186 qemu_log_mask(LOG_GUEST_ERROR
,
187 "SysTick: Bad write offset 0x%" HWADDR_PRIx
"\n", addr
);
192 static const MemoryRegionOps systick_ops
= {
193 .read_with_attrs
= systick_read
,
194 .write_with_attrs
= systick_write
,
195 .endianness
= DEVICE_NATIVE_ENDIAN
,
196 .valid
.min_access_size
= 4,
197 .valid
.max_access_size
= 4,
200 static void systick_reset(DeviceState
*dev
)
202 SysTickState
*s
= SYSTICK(dev
);
204 ptimer_transaction_begin(s
->ptimer
);
206 if (!clock_has_source(s
->refclk
)) {
207 /* This bit is always 1 if there is no external refclk */
208 s
->control
|= SYSTICK_CLKSOURCE
;
210 ptimer_stop(s
->ptimer
);
211 ptimer_set_count(s
->ptimer
, 0);
212 ptimer_set_limit(s
->ptimer
, 0, 0);
213 systick_set_period_from_clock(s
);
214 ptimer_transaction_commit(s
->ptimer
);
217 static void systick_cpuclk_update(void *opaque
, ClockEvent event
)
219 SysTickState
*s
= SYSTICK(opaque
);
221 if (!(s
->control
& SYSTICK_CLKSOURCE
)) {
222 /* currently using refclk, we can ignore cpuclk changes */
225 ptimer_transaction_begin(s
->ptimer
);
226 ptimer_set_period_from_clock(s
->ptimer
, s
->cpuclk
, 1);
227 ptimer_transaction_commit(s
->ptimer
);
230 static void systick_refclk_update(void *opaque
, ClockEvent event
)
232 SysTickState
*s
= SYSTICK(opaque
);
234 if (s
->control
& SYSTICK_CLKSOURCE
) {
235 /* currently using cpuclk, we can ignore refclk changes */
238 ptimer_transaction_begin(s
->ptimer
);
239 ptimer_set_period_from_clock(s
->ptimer
, s
->refclk
, 1);
240 ptimer_transaction_commit(s
->ptimer
);
243 static void systick_instance_init(Object
*obj
)
245 SysBusDevice
*sbd
= SYS_BUS_DEVICE(obj
);
246 SysTickState
*s
= SYSTICK(obj
);
248 memory_region_init_io(&s
->iomem
, obj
, &systick_ops
, s
, "systick", 0xe0);
249 sysbus_init_mmio(sbd
, &s
->iomem
);
250 sysbus_init_irq(sbd
, &s
->irq
);
252 s
->refclk
= qdev_init_clock_in(DEVICE(obj
), "refclk",
253 systick_refclk_update
, s
, ClockUpdate
);
254 s
->cpuclk
= qdev_init_clock_in(DEVICE(obj
), "cpuclk",
255 systick_cpuclk_update
, s
, ClockUpdate
);
258 static void systick_realize(DeviceState
*dev
, Error
**errp
)
260 SysTickState
*s
= SYSTICK(dev
);
261 s
->ptimer
= ptimer_init(systick_timer_tick
, s
,
262 PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD
|
263 PTIMER_POLICY_NO_COUNTER_ROUND_DOWN
|
264 PTIMER_POLICY_NO_IMMEDIATE_RELOAD
|
265 PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT
);
267 if (!clock_has_source(s
->cpuclk
)) {
268 error_setg(errp
, "systick: cpuclk must be connected");
271 /* It's OK not to connect the refclk */
274 static const VMStateDescription vmstate_systick
= {
275 .name
= "armv7m_systick",
277 .minimum_version_id
= 3,
278 .fields
= (const VMStateField
[]) {
279 VMSTATE_CLOCK(refclk
, SysTickState
),
280 VMSTATE_CLOCK(cpuclk
, SysTickState
),
281 VMSTATE_UINT32(control
, SysTickState
),
282 VMSTATE_INT64(tick
, SysTickState
),
283 VMSTATE_PTIMER(ptimer
, SysTickState
),
284 VMSTATE_END_OF_LIST()
288 static void systick_class_init(ObjectClass
*klass
, void *data
)
290 DeviceClass
*dc
= DEVICE_CLASS(klass
);
292 dc
->vmsd
= &vmstate_systick
;
293 device_class_set_legacy_reset(dc
, systick_reset
);
294 dc
->realize
= systick_realize
;
297 static const TypeInfo armv7m_systick_info
= {
298 .name
= TYPE_SYSTICK
,
299 .parent
= TYPE_SYS_BUS_DEVICE
,
300 .instance_init
= systick_instance_init
,
301 .instance_size
= sizeof(SysTickState
),
302 .class_init
= systick_class_init
,
305 static void armv7m_systick_register_types(void)
307 type_register_static(&armv7m_systick_info
);
310 type_init(armv7m_systick_register_types
)