blob: 2f192011eb045092a8962015ea9d820fb8dffdc4 [file] [log] [blame]
Peter Maydellff68dac2017-02-20 15:36:03 +00001/*
2 * ARMv7M SysTick timer
3 *
4 * Copyright (c) 2006-2007 CodeSourcery.
5 * Written by Paul Brook
6 * Copyright (c) 2017 Linaro Ltd
7 * Written by Peter Maydell
8 *
9 * This code is licensed under the GPL (version 2 or later).
10 */
11
12#include "qemu/osdep.h"
13#include "hw/timer/armv7m_systick.h"
Markus Armbrusterd6454272019-08-12 07:23:45 +020014#include "migration/vmstate.h"
Markus Armbruster64552b62019-08-12 07:23:42 +020015#include "hw/irq.h"
Peter Maydellff68dac2017-02-20 15:36:03 +000016#include "hw/sysbus.h"
17#include "qemu/timer.h"
18#include "qemu/log.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020019#include "qemu/module.h"
Peter Maydellff68dac2017-02-20 15:36:03 +000020#include "trace.h"
21
22/* qemu timers run at 1GHz. We want something closer to 1MHz. */
23#define SYSTICK_SCALE 1000ULL
24
25#define SYSTICK_ENABLE (1 << 0)
26#define SYSTICK_TICKINT (1 << 1)
27#define SYSTICK_CLKSOURCE (1 << 2)
28#define SYSTICK_COUNTFLAG (1 << 16)
29
30int system_clock_scale;
31
32/* Conversion factor from qemu timer to SysTick frequencies. */
33static inline int64_t systick_scale(SysTickState *s)
34{
35 if (s->control & SYSTICK_CLKSOURCE) {
36 return system_clock_scale;
37 } else {
38 return 1000;
39 }
40}
41
Peter Maydellff68dac2017-02-20 15:36:03 +000042static void systick_timer_tick(void *opaque)
43{
44 SysTickState *s = (SysTickState *)opaque;
45
46 trace_systick_timer_tick();
47
48 s->control |= SYSTICK_COUNTFLAG;
49 if (s->control & SYSTICK_TICKINT) {
50 /* Tell the NVIC to pend the SysTick exception */
51 qemu_irq_pulse(s->irq);
52 }
Peter Maydell32bd3222020-10-15 16:18:29 +010053 if (ptimer_get_limit(s->ptimer) == 0) {
54 /*
55 * Timer expiry with SYST_RVR zero disables the timer
56 * (but doesn't clear SYST_CSR.ENABLE)
57 */
58 ptimer_stop(s->ptimer);
Peter Maydellff68dac2017-02-20 15:36:03 +000059 }
60}
61
Peter Maydell9bed5212019-07-04 17:14:44 +010062static MemTxResult systick_read(void *opaque, hwaddr addr, uint64_t *data,
63 unsigned size, MemTxAttrs attrs)
Peter Maydellff68dac2017-02-20 15:36:03 +000064{
65 SysTickState *s = opaque;
66 uint32_t val;
67
Peter Maydell9bed5212019-07-04 17:14:44 +010068 if (attrs.user) {
69 /* Generate BusFault for unprivileged accesses */
70 return MEMTX_ERROR;
71 }
72
Peter Maydellff68dac2017-02-20 15:36:03 +000073 switch (addr) {
74 case 0x0: /* SysTick Control and Status. */
75 val = s->control;
76 s->control &= ~SYSTICK_COUNTFLAG;
77 break;
78 case 0x4: /* SysTick Reload Value. */
Peter Maydell32bd3222020-10-15 16:18:29 +010079 val = ptimer_get_limit(s->ptimer);
Peter Maydellff68dac2017-02-20 15:36:03 +000080 break;
81 case 0x8: /* SysTick Current Value. */
Peter Maydell32bd3222020-10-15 16:18:29 +010082 val = ptimer_get_count(s->ptimer);
Peter Maydellff68dac2017-02-20 15:36:03 +000083 break;
Peter Maydellff68dac2017-02-20 15:36:03 +000084 case 0xc: /* SysTick Calibration Value. */
85 val = 10000;
86 break;
87 default:
88 val = 0;
89 qemu_log_mask(LOG_GUEST_ERROR,
90 "SysTick: Bad read offset 0x%" HWADDR_PRIx "\n", addr);
91 break;
92 }
93
94 trace_systick_read(addr, val, size);
Peter Maydell9bed5212019-07-04 17:14:44 +010095 *data = val;
96 return MEMTX_OK;
Peter Maydellff68dac2017-02-20 15:36:03 +000097}
98
Peter Maydell9bed5212019-07-04 17:14:44 +010099static MemTxResult systick_write(void *opaque, hwaddr addr,
100 uint64_t value, unsigned size,
101 MemTxAttrs attrs)
Peter Maydellff68dac2017-02-20 15:36:03 +0000102{
103 SysTickState *s = opaque;
104
Peter Maydell9bed5212019-07-04 17:14:44 +0100105 if (attrs.user) {
106 /* Generate BusFault for unprivileged accesses */
107 return MEMTX_ERROR;
108 }
109
Peter Maydellff68dac2017-02-20 15:36:03 +0000110 trace_systick_write(addr, value, size);
111
112 switch (addr) {
113 case 0x0: /* SysTick Control and Status. */
114 {
Peter Maydell32bd3222020-10-15 16:18:29 +0100115 uint32_t oldval;
Peter Maydellff68dac2017-02-20 15:36:03 +0000116
Peter Maydell32bd3222020-10-15 16:18:29 +0100117 ptimer_transaction_begin(s->ptimer);
118 oldval = s->control;
Peter Maydellff68dac2017-02-20 15:36:03 +0000119 s->control &= 0xfffffff8;
120 s->control |= value & 7;
Peter Maydell32bd3222020-10-15 16:18:29 +0100121
Peter Maydellff68dac2017-02-20 15:36:03 +0000122 if ((oldval ^ value) & SYSTICK_ENABLE) {
Peter Maydellff68dac2017-02-20 15:36:03 +0000123 if (value & SYSTICK_ENABLE) {
Peter Maydell32bd3222020-10-15 16:18:29 +0100124 /*
125 * Always reload the period in case board code has
126 * changed system_clock_scale. If we ever replace that
127 * global with a more sensible API then we might be able
128 * to set the period only when it actually changes.
129 */
130 ptimer_set_period(s->ptimer, systick_scale(s));
131 ptimer_run(s->ptimer, 0);
Peter Maydellff68dac2017-02-20 15:36:03 +0000132 } else {
Peter Maydell32bd3222020-10-15 16:18:29 +0100133 ptimer_stop(s->ptimer);
Peter Maydellff68dac2017-02-20 15:36:03 +0000134 }
135 } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
Peter Maydell32bd3222020-10-15 16:18:29 +0100136 ptimer_set_period(s->ptimer, systick_scale(s));
Peter Maydellff68dac2017-02-20 15:36:03 +0000137 }
Peter Maydell32bd3222020-10-15 16:18:29 +0100138 ptimer_transaction_commit(s->ptimer);
Peter Maydellff68dac2017-02-20 15:36:03 +0000139 break;
140 }
141 case 0x4: /* SysTick Reload Value. */
Peter Maydell32bd3222020-10-15 16:18:29 +0100142 ptimer_transaction_begin(s->ptimer);
143 ptimer_set_limit(s->ptimer, value & 0xffffff, 0);
144 ptimer_transaction_commit(s->ptimer);
Peter Maydellff68dac2017-02-20 15:36:03 +0000145 break;
Peter Maydell32bd3222020-10-15 16:18:29 +0100146 case 0x8: /* SysTick Current Value. */
147 /*
148 * Writing any value clears SYST_CVR to zero and clears
149 * SYST_CSR.COUNTFLAG. The counter will then reload from SYST_RVR
150 * on the next clock edge unless SYST_RVR is zero.
151 */
152 ptimer_transaction_begin(s->ptimer);
153 if (ptimer_get_limit(s->ptimer) == 0) {
154 ptimer_stop(s->ptimer);
155 }
156 ptimer_set_count(s->ptimer, 0);
Peter Maydellff68dac2017-02-20 15:36:03 +0000157 s->control &= ~SYSTICK_COUNTFLAG;
Peter Maydell32bd3222020-10-15 16:18:29 +0100158 ptimer_transaction_commit(s->ptimer);
Peter Maydellff68dac2017-02-20 15:36:03 +0000159 break;
160 default:
161 qemu_log_mask(LOG_GUEST_ERROR,
162 "SysTick: Bad write offset 0x%" HWADDR_PRIx "\n", addr);
163 }
Peter Maydell9bed5212019-07-04 17:14:44 +0100164 return MEMTX_OK;
Peter Maydellff68dac2017-02-20 15:36:03 +0000165}
166
167static const MemoryRegionOps systick_ops = {
Peter Maydell9bed5212019-07-04 17:14:44 +0100168 .read_with_attrs = systick_read,
169 .write_with_attrs = systick_write,
Peter Maydellff68dac2017-02-20 15:36:03 +0000170 .endianness = DEVICE_NATIVE_ENDIAN,
171 .valid.min_access_size = 4,
172 .valid.max_access_size = 4,
173};
174
175static void systick_reset(DeviceState *dev)
176{
177 SysTickState *s = SYSTICK(dev);
178
Peter Maydellc9ebc8c2020-08-25 17:08:47 +0100179 /*
180 * Forgetting to set system_clock_scale is always a board code
181 * bug. We can't check this earlier because for some boards
182 * (like stellaris) it is not yet configured at the point where
183 * the systick device is realized.
184 */
185 assert(system_clock_scale != 0);
186
Peter Maydell32bd3222020-10-15 16:18:29 +0100187 ptimer_transaction_begin(s->ptimer);
Peter Maydellff68dac2017-02-20 15:36:03 +0000188 s->control = 0;
Peter Maydell32bd3222020-10-15 16:18:29 +0100189 ptimer_stop(s->ptimer);
190 ptimer_set_count(s->ptimer, 0);
191 ptimer_set_limit(s->ptimer, 0, 0);
192 ptimer_set_period(s->ptimer, systick_scale(s));
193 ptimer_transaction_commit(s->ptimer);
Peter Maydellff68dac2017-02-20 15:36:03 +0000194}
195
196static void systick_instance_init(Object *obj)
197{
198 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
199 SysTickState *s = SYSTICK(obj);
200
201 memory_region_init_io(&s->iomem, obj, &systick_ops, s, "systick", 0xe0);
202 sysbus_init_mmio(sbd, &s->iomem);
203 sysbus_init_irq(sbd, &s->irq);
Pan Nengyuanf3a508e2020-02-07 14:04:28 +0000204}
205
206static void systick_realize(DeviceState *dev, Error **errp)
207{
208 SysTickState *s = SYSTICK(dev);
Peter Maydell32bd3222020-10-15 16:18:29 +0100209 s->ptimer = ptimer_init(systick_timer_tick, s,
210 PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD |
211 PTIMER_POLICY_NO_COUNTER_ROUND_DOWN |
212 PTIMER_POLICY_NO_IMMEDIATE_RELOAD |
213 PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT);
Peter Maydellff68dac2017-02-20 15:36:03 +0000214}
215
216static const VMStateDescription vmstate_systick = {
217 .name = "armv7m_systick",
Peter Maydell32bd3222020-10-15 16:18:29 +0100218 .version_id = 2,
219 .minimum_version_id = 2,
Peter Maydellff68dac2017-02-20 15:36:03 +0000220 .fields = (VMStateField[]) {
221 VMSTATE_UINT32(control, SysTickState),
Peter Maydellff68dac2017-02-20 15:36:03 +0000222 VMSTATE_INT64(tick, SysTickState),
Peter Maydell32bd3222020-10-15 16:18:29 +0100223 VMSTATE_PTIMER(ptimer, SysTickState),
Peter Maydellff68dac2017-02-20 15:36:03 +0000224 VMSTATE_END_OF_LIST()
225 }
226};
227
228static void systick_class_init(ObjectClass *klass, void *data)
229{
230 DeviceClass *dc = DEVICE_CLASS(klass);
231
232 dc->vmsd = &vmstate_systick;
233 dc->reset = systick_reset;
Pan Nengyuanf3a508e2020-02-07 14:04:28 +0000234 dc->realize = systick_realize;
Peter Maydellff68dac2017-02-20 15:36:03 +0000235}
236
237static const TypeInfo armv7m_systick_info = {
238 .name = TYPE_SYSTICK,
239 .parent = TYPE_SYS_BUS_DEVICE,
240 .instance_init = systick_instance_init,
241 .instance_size = sizeof(SysTickState),
242 .class_init = systick_class_init,
243};
244
245static void armv7m_systick_register_types(void)
246{
247 type_register_static(&armv7m_systick_info);
248}
249
250type_init(armv7m_systick_register_types)