1c21c3b53SPeter Crosthwaite /*
2c21c3b53SPeter Crosthwaite * Global peripheral timer block for ARM A9MP
3c21c3b53SPeter Crosthwaite *
4c21c3b53SPeter Crosthwaite * (C) 2013 Xilinx Inc.
5c21c3b53SPeter Crosthwaite *
6c21c3b53SPeter Crosthwaite * Written by François LEGAL
7c21c3b53SPeter Crosthwaite * Written by Peter Crosthwaite <peter.crosthwaite@xilinx.com>
8c21c3b53SPeter Crosthwaite *
9c21c3b53SPeter Crosthwaite * This program is free software; you can redistribute it and/or
10c21c3b53SPeter Crosthwaite * modify it under the terms of the GNU General Public License
11c21c3b53SPeter Crosthwaite * as published by the Free Software Foundation; either version
12c21c3b53SPeter Crosthwaite * 2 of the License, or (at your option) any later version.
13c21c3b53SPeter Crosthwaite *
14c21c3b53SPeter Crosthwaite * This program is distributed in the hope that it will be useful,
15c21c3b53SPeter Crosthwaite * but WITHOUT ANY WARRANTY; without even the implied warranty of
16c21c3b53SPeter Crosthwaite * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17c21c3b53SPeter Crosthwaite * GNU General Public License for more details.
18c21c3b53SPeter Crosthwaite *
19c21c3b53SPeter Crosthwaite * You should have received a copy of the GNU General Public License along
20c21c3b53SPeter Crosthwaite * with this program; if not, see <http://www.gnu.org/licenses/>.
21c21c3b53SPeter Crosthwaite */
22c21c3b53SPeter Crosthwaite
238ef94f0bSPeter Maydell #include "qemu/osdep.h"
24650d103dSMarkus Armbruster #include "hw/hw.h"
2564552b6bSMarkus Armbruster #include "hw/irq.h"
26a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
27c21c3b53SPeter Crosthwaite #include "hw/timer/a9gtimer.h"
28d6454270SMarkus Armbruster #include "migration/vmstate.h"
29da34e65cSMarkus Armbruster #include "qapi/error.h"
30c21c3b53SPeter Crosthwaite #include "qemu/timer.h"
31c21c3b53SPeter Crosthwaite #include "qemu/bitops.h"
32c21c3b53SPeter Crosthwaite #include "qemu/log.h"
330b8fa32fSMarkus Armbruster #include "qemu/module.h"
342e5b09fdSMarkus Armbruster #include "hw/core/cpu.h"
35ff8aff01SZheyu Ma #include "sysemu/qtest.h"
36c21c3b53SPeter Crosthwaite
37c21c3b53SPeter Crosthwaite #ifndef A9_GTIMER_ERR_DEBUG
38c21c3b53SPeter Crosthwaite #define A9_GTIMER_ERR_DEBUG 0
39c21c3b53SPeter Crosthwaite #endif
40c21c3b53SPeter Crosthwaite
41c21c3b53SPeter Crosthwaite #define DB_PRINT_L(level, ...) do { \
42c21c3b53SPeter Crosthwaite if (A9_GTIMER_ERR_DEBUG > (level)) { \
43c21c3b53SPeter Crosthwaite fprintf(stderr, ": %s: ", __func__); \
44c21c3b53SPeter Crosthwaite fprintf(stderr, ## __VA_ARGS__); \
45c21c3b53SPeter Crosthwaite } \
462562755eSEric Blake } while (0)
47c21c3b53SPeter Crosthwaite
48c21c3b53SPeter Crosthwaite #define DB_PRINT(...) DB_PRINT_L(0, ## __VA_ARGS__)
49c21c3b53SPeter Crosthwaite
a9_gtimer_get_current_cpu(A9GTimerState * s)50c21c3b53SPeter Crosthwaite static inline int a9_gtimer_get_current_cpu(A9GTimerState *s)
51c21c3b53SPeter Crosthwaite {
52ff8aff01SZheyu Ma if (qtest_enabled()) {
53ff8aff01SZheyu Ma return 0;
54ff8aff01SZheyu Ma }
55ff8aff01SZheyu Ma
56c21c3b53SPeter Crosthwaite if (current_cpu->cpu_index >= s->num_cpu) {
57c21c3b53SPeter Crosthwaite hw_error("a9gtimer: num-cpu %d but this cpu is %d!\n",
58c21c3b53SPeter Crosthwaite s->num_cpu, current_cpu->cpu_index);
59c21c3b53SPeter Crosthwaite }
60c21c3b53SPeter Crosthwaite return current_cpu->cpu_index;
61c21c3b53SPeter Crosthwaite }
62c21c3b53SPeter Crosthwaite
a9_gtimer_get_conv(A9GTimerState * s)63c21c3b53SPeter Crosthwaite static inline uint64_t a9_gtimer_get_conv(A9GTimerState *s)
64c21c3b53SPeter Crosthwaite {
65c21c3b53SPeter Crosthwaite uint64_t prescale = extract32(s->control, R_CONTROL_PRESCALER_SHIFT,
66c21c3b53SPeter Crosthwaite R_CONTROL_PRESCALER_LEN);
67c21c3b53SPeter Crosthwaite
68c21c3b53SPeter Crosthwaite return (prescale + 1) * 10;
69c21c3b53SPeter Crosthwaite }
70c21c3b53SPeter Crosthwaite
a9_gtimer_get_update(A9GTimerState * s)71c21c3b53SPeter Crosthwaite static A9GTimerUpdate a9_gtimer_get_update(A9GTimerState *s)
72c21c3b53SPeter Crosthwaite {
73c21c3b53SPeter Crosthwaite A9GTimerUpdate ret;
74c21c3b53SPeter Crosthwaite
75c21c3b53SPeter Crosthwaite ret.now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
76c21c3b53SPeter Crosthwaite ret.new = s->ref_counter +
77c21c3b53SPeter Crosthwaite (ret.now - s->cpu_ref_time) / a9_gtimer_get_conv(s);
78c21c3b53SPeter Crosthwaite return ret;
79c21c3b53SPeter Crosthwaite }
80c21c3b53SPeter Crosthwaite
a9_gtimer_update(A9GTimerState * s,bool sync)81c21c3b53SPeter Crosthwaite static void a9_gtimer_update(A9GTimerState *s, bool sync)
82c21c3b53SPeter Crosthwaite {
83c21c3b53SPeter Crosthwaite
84c21c3b53SPeter Crosthwaite A9GTimerUpdate update = a9_gtimer_get_update(s);
85c21c3b53SPeter Crosthwaite int i;
86c21c3b53SPeter Crosthwaite int64_t next_cdiff = 0;
87c21c3b53SPeter Crosthwaite
88c21c3b53SPeter Crosthwaite for (i = 0; i < s->num_cpu; ++i) {
89c21c3b53SPeter Crosthwaite A9GTimerPerCPU *gtb = &s->per_cpu[i];
90c21c3b53SPeter Crosthwaite int64_t cdiff = 0;
91c21c3b53SPeter Crosthwaite
92c21c3b53SPeter Crosthwaite if ((s->control & R_CONTROL_TIMER_ENABLE) &&
93c21c3b53SPeter Crosthwaite (gtb->control & R_CONTROL_COMP_ENABLE)) {
94c21c3b53SPeter Crosthwaite /* R2p0+, where the compare function is >= */
956be8f5e2SPrasad J Pandit if (gtb->compare < update.new) {
96c21c3b53SPeter Crosthwaite DB_PRINT("Compare event happened for CPU %d\n", i);
97c21c3b53SPeter Crosthwaite gtb->status = 1;
986be8f5e2SPrasad J Pandit if (gtb->control & R_CONTROL_AUTO_INCREMENT && gtb->inc) {
996be8f5e2SPrasad J Pandit uint64_t inc =
1006be8f5e2SPrasad J Pandit QEMU_ALIGN_UP(update.new - gtb->compare, gtb->inc);
1016be8f5e2SPrasad J Pandit DB_PRINT("Auto incrementing timer compare by %"
1026be8f5e2SPrasad J Pandit PRId64 "\n", inc);
1036be8f5e2SPrasad J Pandit gtb->compare += inc;
104c21c3b53SPeter Crosthwaite }
105c21c3b53SPeter Crosthwaite }
106c21c3b53SPeter Crosthwaite cdiff = (int64_t)gtb->compare - (int64_t)update.new + 1;
107c21c3b53SPeter Crosthwaite if (cdiff > 0 && (cdiff < next_cdiff || !next_cdiff)) {
108c21c3b53SPeter Crosthwaite next_cdiff = cdiff;
109c21c3b53SPeter Crosthwaite }
110c21c3b53SPeter Crosthwaite }
111c21c3b53SPeter Crosthwaite
112c21c3b53SPeter Crosthwaite qemu_set_irq(gtb->irq,
113c21c3b53SPeter Crosthwaite gtb->status && (gtb->control & R_CONTROL_IRQ_ENABLE));
114c21c3b53SPeter Crosthwaite }
115c21c3b53SPeter Crosthwaite
116c21c3b53SPeter Crosthwaite timer_del(s->timer);
117c21c3b53SPeter Crosthwaite if (next_cdiff) {
118c21c3b53SPeter Crosthwaite DB_PRINT("scheduling qemu_timer to fire again in %"
119c21c3b53SPeter Crosthwaite PRIx64 " cycles\n", next_cdiff);
120c21c3b53SPeter Crosthwaite timer_mod(s->timer, update.now + next_cdiff * a9_gtimer_get_conv(s));
121c21c3b53SPeter Crosthwaite }
122c21c3b53SPeter Crosthwaite
123c21c3b53SPeter Crosthwaite if (s->control & R_CONTROL_TIMER_ENABLE) {
124c21c3b53SPeter Crosthwaite s->counter = update.new;
125c21c3b53SPeter Crosthwaite }
126c21c3b53SPeter Crosthwaite
127c21c3b53SPeter Crosthwaite if (sync) {
128c21c3b53SPeter Crosthwaite s->cpu_ref_time = update.now;
129c21c3b53SPeter Crosthwaite s->ref_counter = s->counter;
130c21c3b53SPeter Crosthwaite }
131c21c3b53SPeter Crosthwaite }
132c21c3b53SPeter Crosthwaite
a9_gtimer_update_no_sync(void * opaque)133c21c3b53SPeter Crosthwaite static void a9_gtimer_update_no_sync(void *opaque)
134c21c3b53SPeter Crosthwaite {
135c21c3b53SPeter Crosthwaite A9GTimerState *s = A9_GTIMER(opaque);
136c21c3b53SPeter Crosthwaite
137e7ae771fSStefan Weil a9_gtimer_update(s, false);
138c21c3b53SPeter Crosthwaite }
139c21c3b53SPeter Crosthwaite
a9_gtimer_read(void * opaque,hwaddr addr,unsigned size)140c21c3b53SPeter Crosthwaite static uint64_t a9_gtimer_read(void *opaque, hwaddr addr, unsigned size)
141c21c3b53SPeter Crosthwaite {
142c21c3b53SPeter Crosthwaite A9GTimerPerCPU *gtb = (A9GTimerPerCPU *)opaque;
143c21c3b53SPeter Crosthwaite A9GTimerState *s = gtb->parent;
144c21c3b53SPeter Crosthwaite A9GTimerUpdate update;
145c21c3b53SPeter Crosthwaite uint64_t ret = 0;
146c21c3b53SPeter Crosthwaite int shift = 0;
147c21c3b53SPeter Crosthwaite
148c21c3b53SPeter Crosthwaite switch (addr) {
149c21c3b53SPeter Crosthwaite case R_COUNTER_HI:
150c21c3b53SPeter Crosthwaite shift = 32;
151c21c3b53SPeter Crosthwaite /* fallthrough */
152c21c3b53SPeter Crosthwaite case R_COUNTER_LO:
153c21c3b53SPeter Crosthwaite update = a9_gtimer_get_update(s);
154c21c3b53SPeter Crosthwaite ret = extract64(update.new, shift, 32);
155c21c3b53SPeter Crosthwaite break;
156c21c3b53SPeter Crosthwaite case R_CONTROL:
157c21c3b53SPeter Crosthwaite ret = s->control | gtb->control;
158c21c3b53SPeter Crosthwaite break;
159c21c3b53SPeter Crosthwaite case R_INTERRUPT_STATUS:
160c21c3b53SPeter Crosthwaite ret = gtb->status;
161c21c3b53SPeter Crosthwaite break;
162c21c3b53SPeter Crosthwaite case R_COMPARATOR_HI:
163c21c3b53SPeter Crosthwaite shift = 32;
164c21c3b53SPeter Crosthwaite /* fallthrough */
165c21c3b53SPeter Crosthwaite case R_COMPARATOR_LO:
166c21c3b53SPeter Crosthwaite ret = extract64(gtb->compare, shift, 32);
167c21c3b53SPeter Crosthwaite break;
168c21c3b53SPeter Crosthwaite case R_AUTO_INCREMENT:
169c21c3b53SPeter Crosthwaite ret = gtb->inc;
170c21c3b53SPeter Crosthwaite break;
171c21c3b53SPeter Crosthwaite default:
172c21c3b53SPeter Crosthwaite qemu_log_mask(LOG_GUEST_ERROR, "bad a9gtimer register: %x\n",
173c21c3b53SPeter Crosthwaite (unsigned)addr);
174c21c3b53SPeter Crosthwaite return 0;
175c21c3b53SPeter Crosthwaite }
176c21c3b53SPeter Crosthwaite
177c21c3b53SPeter Crosthwaite DB_PRINT("addr:%#x data:%#08" PRIx64 "\n", (unsigned)addr, ret);
178c21c3b53SPeter Crosthwaite return ret;
179c21c3b53SPeter Crosthwaite }
180c21c3b53SPeter Crosthwaite
a9_gtimer_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)181c21c3b53SPeter Crosthwaite static void a9_gtimer_write(void *opaque, hwaddr addr, uint64_t value,
182c21c3b53SPeter Crosthwaite unsigned size)
183c21c3b53SPeter Crosthwaite {
184c21c3b53SPeter Crosthwaite A9GTimerPerCPU *gtb = (A9GTimerPerCPU *)opaque;
185c21c3b53SPeter Crosthwaite A9GTimerState *s = gtb->parent;
186c21c3b53SPeter Crosthwaite int shift = 0;
187c21c3b53SPeter Crosthwaite
188c21c3b53SPeter Crosthwaite DB_PRINT("addr:%#x data:%#08" PRIx64 "\n", (unsigned)addr, value);
189c21c3b53SPeter Crosthwaite
190c21c3b53SPeter Crosthwaite switch (addr) {
191c21c3b53SPeter Crosthwaite case R_COUNTER_HI:
192c21c3b53SPeter Crosthwaite shift = 32;
193c21c3b53SPeter Crosthwaite /* fallthrough */
194c21c3b53SPeter Crosthwaite case R_COUNTER_LO:
195c21c3b53SPeter Crosthwaite /*
196c21c3b53SPeter Crosthwaite * Keep it simple - ARM docco explicitly says to disable timer before
197cb8d4c8fSStefan Weil * modding it, so don't bother trying to do all the difficult on the fly
198c21c3b53SPeter Crosthwaite * timer modifications - (if they even work in real hardware??).
199c21c3b53SPeter Crosthwaite */
200c21c3b53SPeter Crosthwaite if (s->control & R_CONTROL_TIMER_ENABLE) {
201c21c3b53SPeter Crosthwaite qemu_log_mask(LOG_GUEST_ERROR, "Cannot mod running ARM gtimer\n");
202c21c3b53SPeter Crosthwaite return;
203c21c3b53SPeter Crosthwaite }
204c21c3b53SPeter Crosthwaite s->counter = deposit64(s->counter, shift, 32, value);
205c21c3b53SPeter Crosthwaite return;
206c21c3b53SPeter Crosthwaite case R_CONTROL:
207c21c3b53SPeter Crosthwaite a9_gtimer_update(s, (value ^ s->control) & R_CONTROL_NEEDS_SYNC);
208c21c3b53SPeter Crosthwaite gtb->control = value & R_CONTROL_BANKED;
209c21c3b53SPeter Crosthwaite s->control = value & ~R_CONTROL_BANKED;
210c21c3b53SPeter Crosthwaite break;
211c21c3b53SPeter Crosthwaite case R_INTERRUPT_STATUS:
212c21c3b53SPeter Crosthwaite a9_gtimer_update(s, false);
213c21c3b53SPeter Crosthwaite gtb->status &= ~value;
214c21c3b53SPeter Crosthwaite break;
215c21c3b53SPeter Crosthwaite case R_COMPARATOR_HI:
216c21c3b53SPeter Crosthwaite shift = 32;
217c21c3b53SPeter Crosthwaite /* fallthrough */
218c21c3b53SPeter Crosthwaite case R_COMPARATOR_LO:
219c21c3b53SPeter Crosthwaite a9_gtimer_update(s, false);
220c21c3b53SPeter Crosthwaite gtb->compare = deposit64(gtb->compare, shift, 32, value);
221c21c3b53SPeter Crosthwaite break;
222c21c3b53SPeter Crosthwaite case R_AUTO_INCREMENT:
223c21c3b53SPeter Crosthwaite gtb->inc = value;
224c21c3b53SPeter Crosthwaite return;
225c21c3b53SPeter Crosthwaite default:
226c21c3b53SPeter Crosthwaite return;
227c21c3b53SPeter Crosthwaite }
228c21c3b53SPeter Crosthwaite
229c21c3b53SPeter Crosthwaite a9_gtimer_update(s, false);
230c21c3b53SPeter Crosthwaite }
231c21c3b53SPeter Crosthwaite
232c21c3b53SPeter Crosthwaite /* Wrapper functions to implement the "read global timer for
233c21c3b53SPeter Crosthwaite * the current CPU" memory regions.
234c21c3b53SPeter Crosthwaite */
a9_gtimer_this_read(void * opaque,hwaddr addr,unsigned size)235c21c3b53SPeter Crosthwaite static uint64_t a9_gtimer_this_read(void *opaque, hwaddr addr,
236c21c3b53SPeter Crosthwaite unsigned size)
237c21c3b53SPeter Crosthwaite {
238c21c3b53SPeter Crosthwaite A9GTimerState *s = A9_GTIMER(opaque);
239c21c3b53SPeter Crosthwaite int id = a9_gtimer_get_current_cpu(s);
240c21c3b53SPeter Crosthwaite
241c21c3b53SPeter Crosthwaite /* no \n so concatenates with message from read fn */
242c21c3b53SPeter Crosthwaite DB_PRINT("CPU:%d:", id);
243c21c3b53SPeter Crosthwaite
244c21c3b53SPeter Crosthwaite return a9_gtimer_read(&s->per_cpu[id], addr, size);
245c21c3b53SPeter Crosthwaite }
246c21c3b53SPeter Crosthwaite
a9_gtimer_this_write(void * opaque,hwaddr addr,uint64_t value,unsigned size)247c21c3b53SPeter Crosthwaite static void a9_gtimer_this_write(void *opaque, hwaddr addr,
248c21c3b53SPeter Crosthwaite uint64_t value, unsigned size)
249c21c3b53SPeter Crosthwaite {
250c21c3b53SPeter Crosthwaite A9GTimerState *s = A9_GTIMER(opaque);
251c21c3b53SPeter Crosthwaite int id = a9_gtimer_get_current_cpu(s);
252c21c3b53SPeter Crosthwaite
253c21c3b53SPeter Crosthwaite /* no \n so concatenates with message from write fn */
254c21c3b53SPeter Crosthwaite DB_PRINT("CPU:%d:", id);
255c21c3b53SPeter Crosthwaite
256c21c3b53SPeter Crosthwaite a9_gtimer_write(&s->per_cpu[id], addr, value, size);
257c21c3b53SPeter Crosthwaite }
258c21c3b53SPeter Crosthwaite
259c21c3b53SPeter Crosthwaite static const MemoryRegionOps a9_gtimer_this_ops = {
260c21c3b53SPeter Crosthwaite .read = a9_gtimer_this_read,
261c21c3b53SPeter Crosthwaite .write = a9_gtimer_this_write,
262c21c3b53SPeter Crosthwaite .valid = {
263c21c3b53SPeter Crosthwaite .min_access_size = 4,
264c21c3b53SPeter Crosthwaite .max_access_size = 4,
265c21c3b53SPeter Crosthwaite },
266c21c3b53SPeter Crosthwaite .endianness = DEVICE_NATIVE_ENDIAN,
267c21c3b53SPeter Crosthwaite };
268c21c3b53SPeter Crosthwaite
269c21c3b53SPeter Crosthwaite static const MemoryRegionOps a9_gtimer_ops = {
270c21c3b53SPeter Crosthwaite .read = a9_gtimer_read,
271c21c3b53SPeter Crosthwaite .write = a9_gtimer_write,
272c21c3b53SPeter Crosthwaite .valid = {
273c21c3b53SPeter Crosthwaite .min_access_size = 4,
274c21c3b53SPeter Crosthwaite .max_access_size = 4,
275c21c3b53SPeter Crosthwaite },
276c21c3b53SPeter Crosthwaite .endianness = DEVICE_NATIVE_ENDIAN,
277c21c3b53SPeter Crosthwaite };
278c21c3b53SPeter Crosthwaite
a9_gtimer_reset(DeviceState * dev)279c21c3b53SPeter Crosthwaite static void a9_gtimer_reset(DeviceState *dev)
280c21c3b53SPeter Crosthwaite {
281c21c3b53SPeter Crosthwaite A9GTimerState *s = A9_GTIMER(dev);
282c21c3b53SPeter Crosthwaite int i;
283c21c3b53SPeter Crosthwaite
284c21c3b53SPeter Crosthwaite s->counter = 0;
285c21c3b53SPeter Crosthwaite s->control = 0;
286c21c3b53SPeter Crosthwaite
287c21c3b53SPeter Crosthwaite for (i = 0; i < s->num_cpu; i++) {
288c21c3b53SPeter Crosthwaite A9GTimerPerCPU *gtb = &s->per_cpu[i];
289c21c3b53SPeter Crosthwaite
290c21c3b53SPeter Crosthwaite gtb->control = 0;
291c21c3b53SPeter Crosthwaite gtb->status = 0;
292c21c3b53SPeter Crosthwaite gtb->compare = 0;
293c21c3b53SPeter Crosthwaite gtb->inc = 0;
294c21c3b53SPeter Crosthwaite }
295c21c3b53SPeter Crosthwaite a9_gtimer_update(s, false);
296c21c3b53SPeter Crosthwaite }
297c21c3b53SPeter Crosthwaite
a9_gtimer_realize(DeviceState * dev,Error ** errp)298c21c3b53SPeter Crosthwaite static void a9_gtimer_realize(DeviceState *dev, Error **errp)
299c21c3b53SPeter Crosthwaite {
300c21c3b53SPeter Crosthwaite A9GTimerState *s = A9_GTIMER(dev);
301c21c3b53SPeter Crosthwaite SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
302c21c3b53SPeter Crosthwaite int i;
303c21c3b53SPeter Crosthwaite
304c21c3b53SPeter Crosthwaite if (s->num_cpu < 1 || s->num_cpu > A9_GTIMER_MAX_CPUS) {
30515e10b34SGonglei error_setg(errp, "%s: num-cpu must be between 1 and %d",
306c21c3b53SPeter Crosthwaite __func__, A9_GTIMER_MAX_CPUS);
307c21c3b53SPeter Crosthwaite return;
308c21c3b53SPeter Crosthwaite }
309c21c3b53SPeter Crosthwaite
310c21c3b53SPeter Crosthwaite memory_region_init_io(&s->iomem, OBJECT(dev), &a9_gtimer_this_ops, s,
311c21c3b53SPeter Crosthwaite "a9gtimer shared", 0x20);
312c21c3b53SPeter Crosthwaite sysbus_init_mmio(sbd, &s->iomem);
313c21c3b53SPeter Crosthwaite s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, a9_gtimer_update_no_sync, s);
314c21c3b53SPeter Crosthwaite
315c21c3b53SPeter Crosthwaite for (i = 0; i < s->num_cpu; i++) {
316c21c3b53SPeter Crosthwaite A9GTimerPerCPU *gtb = &s->per_cpu[i];
317c21c3b53SPeter Crosthwaite
318c21c3b53SPeter Crosthwaite gtb->parent = s;
319c21c3b53SPeter Crosthwaite sysbus_init_irq(sbd, >b->irq);
320c21c3b53SPeter Crosthwaite memory_region_init_io(>b->iomem, OBJECT(dev), &a9_gtimer_ops, gtb,
321c21c3b53SPeter Crosthwaite "a9gtimer per cpu", 0x20);
322c21c3b53SPeter Crosthwaite sysbus_init_mmio(sbd, >b->iomem);
323c21c3b53SPeter Crosthwaite }
324c21c3b53SPeter Crosthwaite }
325c21c3b53SPeter Crosthwaite
vmstate_a9_gtimer_control_needed(void * opaque)326432732b5SPavel Dovgalyuk static bool vmstate_a9_gtimer_control_needed(void *opaque)
327432732b5SPavel Dovgalyuk {
328432732b5SPavel Dovgalyuk A9GTimerState *s = opaque;
329432732b5SPavel Dovgalyuk return s->control != 0;
330432732b5SPavel Dovgalyuk }
331432732b5SPavel Dovgalyuk
332c21c3b53SPeter Crosthwaite static const VMStateDescription vmstate_a9_gtimer_per_cpu = {
333c21c3b53SPeter Crosthwaite .name = "arm.cortex-a9-global-timer.percpu",
334c21c3b53SPeter Crosthwaite .version_id = 1,
335c21c3b53SPeter Crosthwaite .minimum_version_id = 1,
336ba324b3fSRichard Henderson .fields = (const VMStateField[]) {
337c21c3b53SPeter Crosthwaite VMSTATE_UINT32(control, A9GTimerPerCPU),
338c21c3b53SPeter Crosthwaite VMSTATE_UINT64(compare, A9GTimerPerCPU),
339c21c3b53SPeter Crosthwaite VMSTATE_UINT32(status, A9GTimerPerCPU),
340c21c3b53SPeter Crosthwaite VMSTATE_UINT32(inc, A9GTimerPerCPU),
341c21c3b53SPeter Crosthwaite VMSTATE_END_OF_LIST()
342c21c3b53SPeter Crosthwaite }
343c21c3b53SPeter Crosthwaite };
344c21c3b53SPeter Crosthwaite
345432732b5SPavel Dovgalyuk static const VMStateDescription vmstate_a9_gtimer_control = {
346432732b5SPavel Dovgalyuk .name = "arm.cortex-a9-global-timer.control",
347432732b5SPavel Dovgalyuk .version_id = 1,
348432732b5SPavel Dovgalyuk .minimum_version_id = 1,
349432732b5SPavel Dovgalyuk .needed = vmstate_a9_gtimer_control_needed,
350ba324b3fSRichard Henderson .fields = (const VMStateField[]) {
351432732b5SPavel Dovgalyuk VMSTATE_UINT32(control, A9GTimerState),
352432732b5SPavel Dovgalyuk VMSTATE_END_OF_LIST()
353432732b5SPavel Dovgalyuk }
354432732b5SPavel Dovgalyuk };
355432732b5SPavel Dovgalyuk
356c21c3b53SPeter Crosthwaite static const VMStateDescription vmstate_a9_gtimer = {
357c21c3b53SPeter Crosthwaite .name = "arm.cortex-a9-global-timer",
358c21c3b53SPeter Crosthwaite .version_id = 1,
359c21c3b53SPeter Crosthwaite .minimum_version_id = 1,
360ba324b3fSRichard Henderson .fields = (const VMStateField[]) {
361e720677eSPaolo Bonzini VMSTATE_TIMER_PTR(timer, A9GTimerState),
362c21c3b53SPeter Crosthwaite VMSTATE_UINT64(counter, A9GTimerState),
363c21c3b53SPeter Crosthwaite VMSTATE_UINT64(ref_counter, A9GTimerState),
364c21c3b53SPeter Crosthwaite VMSTATE_UINT64(cpu_ref_time, A9GTimerState),
365c21c3b53SPeter Crosthwaite VMSTATE_STRUCT_VARRAY_UINT32(per_cpu, A9GTimerState, num_cpu,
366c21c3b53SPeter Crosthwaite 1, vmstate_a9_gtimer_per_cpu,
367c21c3b53SPeter Crosthwaite A9GTimerPerCPU),
368c21c3b53SPeter Crosthwaite VMSTATE_END_OF_LIST()
369432732b5SPavel Dovgalyuk },
370ba324b3fSRichard Henderson .subsections = (const VMStateDescription * const []) {
371432732b5SPavel Dovgalyuk &vmstate_a9_gtimer_control,
372432732b5SPavel Dovgalyuk NULL
373c21c3b53SPeter Crosthwaite }
374c21c3b53SPeter Crosthwaite };
375c21c3b53SPeter Crosthwaite
376c21c3b53SPeter Crosthwaite static Property a9_gtimer_properties[] = {
377c21c3b53SPeter Crosthwaite DEFINE_PROP_UINT32("num-cpu", A9GTimerState, num_cpu, 0),
378c21c3b53SPeter Crosthwaite DEFINE_PROP_END_OF_LIST()
379c21c3b53SPeter Crosthwaite };
380c21c3b53SPeter Crosthwaite
a9_gtimer_class_init(ObjectClass * klass,void * data)381c21c3b53SPeter Crosthwaite static void a9_gtimer_class_init(ObjectClass *klass, void *data)
382c21c3b53SPeter Crosthwaite {
383c21c3b53SPeter Crosthwaite DeviceClass *dc = DEVICE_CLASS(klass);
384c21c3b53SPeter Crosthwaite
385c21c3b53SPeter Crosthwaite dc->realize = a9_gtimer_realize;
386c21c3b53SPeter Crosthwaite dc->vmsd = &vmstate_a9_gtimer;
387*e3d08143SPeter Maydell device_class_set_legacy_reset(dc, a9_gtimer_reset);
3884f67d30bSMarc-André Lureau device_class_set_props(dc, a9_gtimer_properties);
389c21c3b53SPeter Crosthwaite }
390c21c3b53SPeter Crosthwaite
391c21c3b53SPeter Crosthwaite static const TypeInfo a9_gtimer_info = {
392c21c3b53SPeter Crosthwaite .name = TYPE_A9_GTIMER,
393c21c3b53SPeter Crosthwaite .parent = TYPE_SYS_BUS_DEVICE,
394c21c3b53SPeter Crosthwaite .instance_size = sizeof(A9GTimerState),
395c21c3b53SPeter Crosthwaite .class_init = a9_gtimer_class_init,
396c21c3b53SPeter Crosthwaite };
397c21c3b53SPeter Crosthwaite
a9_gtimer_register_types(void)398c21c3b53SPeter Crosthwaite static void a9_gtimer_register_types(void)
399c21c3b53SPeter Crosthwaite {
400c21c3b53SPeter Crosthwaite type_register_static(&a9_gtimer_info);
401c21c3b53SPeter Crosthwaite }
402c21c3b53SPeter Crosthwaite
403c21c3b53SPeter Crosthwaite type_init(a9_gtimer_register_types)
404