xref: /openbmc/qemu/hw/timer/a9gtimer.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
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, &gtb->irq);
320c21c3b53SPeter Crosthwaite         memory_region_init_io(&gtb->iomem, OBJECT(dev), &a9_gtimer_ops, gtb,
321c21c3b53SPeter Crosthwaite                               "a9gtimer per cpu", 0x20);
322c21c3b53SPeter Crosthwaite         sysbus_init_mmio(sbd, &gtb->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