blob: 69c886347222ddcf80806becfbe908e8393115f0 [file] [log] [blame]
ths5fafdf22007-09-16 21:08:06 +00001/*
pbrookcdbdb642006-04-09 01:32:52 +00002 * ARM PrimeCell Timer modules.
3 *
4 * Copyright (c) 2005-2006 CodeSourcery.
5 * Written by Paul Brook
6 *
Matthew Fernandez8e31bf32011-06-26 12:21:35 +10007 * This code is licensed under the GPL.
pbrookcdbdb642006-04-09 01:32:52 +00008 */
9
Peter Maydell8ef94f02016-01-26 18:17:05 +000010#include "qemu/osdep.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010011#include "hw/sysbus.h"
Markus Armbrusterd6454272019-08-12 07:23:45 +020012#include "migration/vmstate.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010013#include "qemu/timer.h"
Markus Armbruster64552b62019-08-12 07:23:42 +020014#include "hw/irq.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010015#include "hw/ptimer.h"
Markus Armbrustera27bd6c2019-08-12 07:23:51 +020016#include "hw/qdev-properties.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020017#include "qemu/module.h"
Paolo Bonzini03dd0242015-12-15 13:16:16 +010018#include "qemu/log.h"
Eduardo Habkostdb1015e2020-09-03 16:43:22 -040019#include "qom/object.h"
pbrookcdbdb642006-04-09 01:32:52 +000020
21/* Common timer implementation. */
22
23#define TIMER_CTRL_ONESHOT (1 << 0)
24#define TIMER_CTRL_32BIT (1 << 1)
25#define TIMER_CTRL_DIV1 (0 << 2)
26#define TIMER_CTRL_DIV16 (1 << 2)
27#define TIMER_CTRL_DIV256 (2 << 2)
28#define TIMER_CTRL_IE (1 << 5)
29#define TIMER_CTRL_PERIODIC (1 << 6)
30#define TIMER_CTRL_ENABLE (1 << 7)
31
32typedef struct {
pbrook423f0742007-05-23 00:06:54 +000033 ptimer_state *timer;
pbrookcdbdb642006-04-09 01:32:52 +000034 uint32_t control;
pbrookcdbdb642006-04-09 01:32:52 +000035 uint32_t limit;
pbrookcdbdb642006-04-09 01:32:52 +000036 int freq;
37 int int_level;
pbrookd537cf62007-04-07 18:14:41 +000038 qemu_irq irq;
pbrookcdbdb642006-04-09 01:32:52 +000039} arm_timer_state;
40
pbrookcdbdb642006-04-09 01:32:52 +000041/* Check all active timers, and schedule the next timer interrupt. */
42
pbrook423f0742007-05-23 00:06:54 +000043static void arm_timer_update(arm_timer_state *s)
pbrookcdbdb642006-04-09 01:32:52 +000044{
pbrookcdbdb642006-04-09 01:32:52 +000045 /* Update interrupts. */
46 if (s->int_level && (s->control & TIMER_CTRL_IE)) {
pbrookd537cf62007-04-07 18:14:41 +000047 qemu_irq_raise(s->irq);
pbrookcdbdb642006-04-09 01:32:52 +000048 } else {
pbrookd537cf62007-04-07 18:14:41 +000049 qemu_irq_lower(s->irq);
pbrookcdbdb642006-04-09 01:32:52 +000050 }
pbrookcdbdb642006-04-09 01:32:52 +000051}
52
Avi Kivitya8170e52012-10-23 12:30:10 +020053static uint32_t arm_timer_read(void *opaque, hwaddr offset)
pbrookcdbdb642006-04-09 01:32:52 +000054{
55 arm_timer_state *s = (arm_timer_state *)opaque;
56
57 switch (offset >> 2) {
58 case 0: /* TimerLoad */
59 case 6: /* TimerBGLoad */
60 return s->limit;
61 case 1: /* TimerValue */
pbrook423f0742007-05-23 00:06:54 +000062 return ptimer_get_count(s->timer);
pbrookcdbdb642006-04-09 01:32:52 +000063 case 2: /* TimerControl */
64 return s->control;
65 case 4: /* TimerRIS */
66 return s->int_level;
67 case 5: /* TimerMIS */
68 if ((s->control & TIMER_CTRL_IE) == 0)
69 return 0;
70 return s->int_level;
71 default:
Peter Maydelledb94a42012-10-30 07:45:10 +000072 qemu_log_mask(LOG_GUEST_ERROR,
73 "%s: Bad offset %x\n", __func__, (int)offset);
pbrookcdbdb642006-04-09 01:32:52 +000074 return 0;
75 }
76}
77
Peter Maydell5a65f7b2019-10-08 18:17:23 +010078/*
79 * Reset the timer limit after settings have changed.
80 * May only be called from inside a ptimer transaction block.
81 */
pbrook423f0742007-05-23 00:06:54 +000082static void arm_timer_recalibrate(arm_timer_state *s, int reload)
83{
84 uint32_t limit;
85
Rabin Vincenta9cf98d2010-05-02 15:20:52 +053086 if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
pbrook423f0742007-05-23 00:06:54 +000087 /* Free running. */
88 if (s->control & TIMER_CTRL_32BIT)
89 limit = 0xffffffff;
90 else
91 limit = 0xffff;
92 } else {
93 /* Periodic. */
94 limit = s->limit;
95 }
96 ptimer_set_limit(s->timer, limit, reload);
97}
98
Avi Kivitya8170e52012-10-23 12:30:10 +020099static void arm_timer_write(void *opaque, hwaddr offset,
pbrookcdbdb642006-04-09 01:32:52 +0000100 uint32_t value)
101{
102 arm_timer_state *s = (arm_timer_state *)opaque;
pbrook423f0742007-05-23 00:06:54 +0000103 int freq;
pbrookcdbdb642006-04-09 01:32:52 +0000104
pbrookcdbdb642006-04-09 01:32:52 +0000105 switch (offset >> 2) {
106 case 0: /* TimerLoad */
107 s->limit = value;
Peter Maydell5a65f7b2019-10-08 18:17:23 +0100108 ptimer_transaction_begin(s->timer);
pbrook423f0742007-05-23 00:06:54 +0000109 arm_timer_recalibrate(s, 1);
Peter Maydell5a65f7b2019-10-08 18:17:23 +0100110 ptimer_transaction_commit(s->timer);
pbrookcdbdb642006-04-09 01:32:52 +0000111 break;
112 case 1: /* TimerValue */
113 /* ??? Linux seems to want to write to this readonly register.
114 Ignore it. */
115 break;
116 case 2: /* TimerControl */
Peter Maydell5a65f7b2019-10-08 18:17:23 +0100117 ptimer_transaction_begin(s->timer);
pbrookcdbdb642006-04-09 01:32:52 +0000118 if (s->control & TIMER_CTRL_ENABLE) {
119 /* Pause the timer if it is running. This may cause some
120 inaccuracy dure to rounding, but avoids a whole lot of other
121 messyness. */
pbrook423f0742007-05-23 00:06:54 +0000122 ptimer_stop(s->timer);
pbrookcdbdb642006-04-09 01:32:52 +0000123 }
124 s->control = value;
pbrook423f0742007-05-23 00:06:54 +0000125 freq = s->freq;
pbrookcdbdb642006-04-09 01:32:52 +0000126 /* ??? Need to recalculate expiry time after changing divisor. */
127 switch ((value >> 2) & 3) {
pbrook423f0742007-05-23 00:06:54 +0000128 case 1: freq >>= 4; break;
129 case 2: freq >>= 8; break;
pbrookcdbdb642006-04-09 01:32:52 +0000130 }
Rabin Vincentd6759902010-05-02 15:20:51 +0530131 arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
pbrook423f0742007-05-23 00:06:54 +0000132 ptimer_set_freq(s->timer, freq);
pbrookcdbdb642006-04-09 01:32:52 +0000133 if (s->control & TIMER_CTRL_ENABLE) {
134 /* Restart the timer if still enabled. */
pbrook423f0742007-05-23 00:06:54 +0000135 ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
pbrookcdbdb642006-04-09 01:32:52 +0000136 }
Peter Maydell5a65f7b2019-10-08 18:17:23 +0100137 ptimer_transaction_commit(s->timer);
pbrookcdbdb642006-04-09 01:32:52 +0000138 break;
139 case 3: /* TimerIntClr */
140 s->int_level = 0;
141 break;
142 case 6: /* TimerBGLoad */
143 s->limit = value;
Peter Maydell5a65f7b2019-10-08 18:17:23 +0100144 ptimer_transaction_begin(s->timer);
pbrook423f0742007-05-23 00:06:54 +0000145 arm_timer_recalibrate(s, 0);
Peter Maydell5a65f7b2019-10-08 18:17:23 +0100146 ptimer_transaction_commit(s->timer);
pbrookcdbdb642006-04-09 01:32:52 +0000147 break;
148 default:
Peter Maydelledb94a42012-10-30 07:45:10 +0000149 qemu_log_mask(LOG_GUEST_ERROR,
150 "%s: Bad offset %x\n", __func__, (int)offset);
pbrookcdbdb642006-04-09 01:32:52 +0000151 }
pbrook423f0742007-05-23 00:06:54 +0000152 arm_timer_update(s);
pbrookcdbdb642006-04-09 01:32:52 +0000153}
154
155static void arm_timer_tick(void *opaque)
156{
pbrook423f0742007-05-23 00:06:54 +0000157 arm_timer_state *s = (arm_timer_state *)opaque;
158 s->int_level = 1;
159 arm_timer_update(s);
pbrookcdbdb642006-04-09 01:32:52 +0000160}
161
Juan Quintelaeecd33a2010-12-01 23:15:41 +0100162static const VMStateDescription vmstate_arm_timer = {
163 .name = "arm_timer",
164 .version_id = 1,
165 .minimum_version_id = 1,
Juan Quintela8f1e8842014-05-13 16:09:35 +0100166 .fields = (VMStateField[]) {
Juan Quintelaeecd33a2010-12-01 23:15:41 +0100167 VMSTATE_UINT32(control, arm_timer_state),
168 VMSTATE_UINT32(limit, arm_timer_state),
169 VMSTATE_INT32(int_level, arm_timer_state),
170 VMSTATE_PTIMER(timer, arm_timer_state),
171 VMSTATE_END_OF_LIST()
172 }
173};
pbrook23e39292008-07-02 16:48:32 +0000174
Paul Brook6a824ec2009-05-14 22:35:07 +0100175static arm_timer_state *arm_timer_init(uint32_t freq)
pbrookcdbdb642006-04-09 01:32:52 +0000176{
177 arm_timer_state *s;
178
Markus Armbrusterb21e2382022-03-15 15:41:56 +0100179 s = g_new0(arm_timer_state, 1);
pbrook423f0742007-05-23 00:06:54 +0000180 s->freq = freq;
pbrookcdbdb642006-04-09 01:32:52 +0000181 s->control = TIMER_CTRL_IE;
pbrookcdbdb642006-04-09 01:32:52 +0000182
Peter Maydell9598c1b2022-05-16 11:30:58 +0100183 s->timer = ptimer_init(arm_timer_tick, s, PTIMER_POLICY_LEGACY);
Peter Xu1df2c9a2019-10-16 10:29:30 +0800184 vmstate_register(NULL, VMSTATE_INSTANCE_ID_ANY, &vmstate_arm_timer, s);
pbrookcdbdb642006-04-09 01:32:52 +0000185 return s;
186}
187
Peter Maydell932a8d12021-02-05 17:14:56 +0000188/*
189 * ARM PrimeCell SP804 dual timer module.
Peter Chubb7b4252e2011-12-12 10:25:42 +0000190 * Docs at
Peter Maydell932a8d12021-02-05 17:14:56 +0000191 * https://developer.arm.com/documentation/ddi0271/latest/
192 */
pbrookcdbdb642006-04-09 01:32:52 +0000193
Andreas Färber0c88dea2013-07-27 14:17:41 +0200194#define TYPE_SP804 "sp804"
Eduardo Habkost80633962020-09-16 14:25:19 -0400195OBJECT_DECLARE_SIMPLE_TYPE(SP804State, SP804)
Andreas Färber0c88dea2013-07-27 14:17:41 +0200196
Eduardo Habkostdb1015e2020-09-03 16:43:22 -0400197struct SP804State {
Andreas Färber0c88dea2013-07-27 14:17:41 +0200198 SysBusDevice parent_obj;
199
Avi Kivitye219dea2011-08-15 17:17:19 +0300200 MemoryRegion iomem;
Paul Brook6a824ec2009-05-14 22:35:07 +0100201 arm_timer_state *timer[2];
Mark Langsdorf104a26a2011-12-29 06:19:51 +0000202 uint32_t freq0, freq1;
pbrookcdbdb642006-04-09 01:32:52 +0000203 int level[2];
pbrookd537cf62007-04-07 18:14:41 +0000204 qemu_irq irq;
Eduardo Habkostdb1015e2020-09-03 16:43:22 -0400205};
pbrookcdbdb642006-04-09 01:32:52 +0000206
Peter Chubb7b4252e2011-12-12 10:25:42 +0000207static const uint8_t sp804_ids[] = {
208 /* Timer ID */
209 0x04, 0x18, 0x14, 0,
210 /* PrimeCell ID */
211 0xd, 0xf0, 0x05, 0xb1
212};
213
pbrookd537cf62007-04-07 18:14:41 +0000214/* Merge the IRQs from the two component devices. */
pbrookcdbdb642006-04-09 01:32:52 +0000215static void sp804_set_irq(void *opaque, int irq, int level)
216{
Andreas Färber1024d7f2013-07-27 14:15:46 +0200217 SP804State *s = (SP804State *)opaque;
pbrookcdbdb642006-04-09 01:32:52 +0000218
219 s->level[irq] = level;
pbrookd537cf62007-04-07 18:14:41 +0000220 qemu_set_irq(s->irq, s->level[0] || s->level[1]);
pbrookcdbdb642006-04-09 01:32:52 +0000221}
222
Avi Kivitya8170e52012-10-23 12:30:10 +0200223static uint64_t sp804_read(void *opaque, hwaddr offset,
Avi Kivitye219dea2011-08-15 17:17:19 +0300224 unsigned size)
pbrookcdbdb642006-04-09 01:32:52 +0000225{
Andreas Färber1024d7f2013-07-27 14:15:46 +0200226 SP804State *s = (SP804State *)opaque;
pbrookcdbdb642006-04-09 01:32:52 +0000227
pbrookcdbdb642006-04-09 01:32:52 +0000228 if (offset < 0x20) {
229 return arm_timer_read(s->timer[0], offset);
Peter Chubb7b4252e2011-12-12 10:25:42 +0000230 }
231 if (offset < 0x40) {
pbrookcdbdb642006-04-09 01:32:52 +0000232 return arm_timer_read(s->timer[1], offset - 0x20);
233 }
Peter Chubb7b4252e2011-12-12 10:25:42 +0000234
235 /* TimerPeriphID */
236 if (offset >= 0xfe0 && offset <= 0xffc) {
237 return sp804_ids[(offset - 0xfe0) >> 2];
238 }
239
240 switch (offset) {
241 /* Integration Test control registers, which we won't support */
242 case 0xf00: /* TimerITCR */
243 case 0xf04: /* TimerITOP (strictly write only but..) */
Peter Maydelledb94a42012-10-30 07:45:10 +0000244 qemu_log_mask(LOG_UNIMP,
245 "%s: integration test registers unimplemented\n",
246 __func__);
Peter Chubb7b4252e2011-12-12 10:25:42 +0000247 return 0;
248 }
249
Peter Maydelledb94a42012-10-30 07:45:10 +0000250 qemu_log_mask(LOG_GUEST_ERROR,
251 "%s: Bad offset %x\n", __func__, (int)offset);
Peter Chubb7b4252e2011-12-12 10:25:42 +0000252 return 0;
pbrookcdbdb642006-04-09 01:32:52 +0000253}
254
Avi Kivitya8170e52012-10-23 12:30:10 +0200255static void sp804_write(void *opaque, hwaddr offset,
Avi Kivitye219dea2011-08-15 17:17:19 +0300256 uint64_t value, unsigned size)
pbrookcdbdb642006-04-09 01:32:52 +0000257{
Andreas Färber1024d7f2013-07-27 14:15:46 +0200258 SP804State *s = (SP804State *)opaque;
pbrookcdbdb642006-04-09 01:32:52 +0000259
pbrookcdbdb642006-04-09 01:32:52 +0000260 if (offset < 0x20) {
261 arm_timer_write(s->timer[0], offset, value);
Peter Chubb7b4252e2011-12-12 10:25:42 +0000262 return;
pbrookcdbdb642006-04-09 01:32:52 +0000263 }
Peter Chubb7b4252e2011-12-12 10:25:42 +0000264
265 if (offset < 0x40) {
266 arm_timer_write(s->timer[1], offset - 0x20, value);
267 return;
268 }
269
270 /* Technically we could be writing to the Test Registers, but not likely */
Peter Maydelledb94a42012-10-30 07:45:10 +0000271 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %x\n",
272 __func__, (int)offset);
pbrookcdbdb642006-04-09 01:32:52 +0000273}
274
Avi Kivitye219dea2011-08-15 17:17:19 +0300275static const MemoryRegionOps sp804_ops = {
276 .read = sp804_read,
277 .write = sp804_write,
278 .endianness = DEVICE_NATIVE_ENDIAN,
pbrookcdbdb642006-04-09 01:32:52 +0000279};
280
Juan Quintela81986ac2010-12-01 23:12:32 +0100281static const VMStateDescription vmstate_sp804 = {
282 .name = "sp804",
283 .version_id = 1,
284 .minimum_version_id = 1,
Juan Quintela8f1e8842014-05-13 16:09:35 +0100285 .fields = (VMStateField[]) {
Andreas Färber1024d7f2013-07-27 14:15:46 +0200286 VMSTATE_INT32_ARRAY(level, SP804State, 2),
Juan Quintela81986ac2010-12-01 23:12:32 +0100287 VMSTATE_END_OF_LIST()
288 }
289};
pbrook23e39292008-07-02 16:48:32 +0000290
xiaoqiang.zhao0d175e72016-02-18 14:16:20 +0000291static void sp804_init(Object *obj)
pbrookcdbdb642006-04-09 01:32:52 +0000292{
xiaoqiang.zhao0d175e72016-02-18 14:16:20 +0000293 SP804State *s = SP804(obj);
294 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
pbrookcdbdb642006-04-09 01:32:52 +0000295
Andreas Färber0c88dea2013-07-27 14:17:41 +0200296 sysbus_init_irq(sbd, &s->irq);
xiaoqiang.zhao0d175e72016-02-18 14:16:20 +0000297 memory_region_init_io(&s->iomem, obj, &sp804_ops, s,
298 "sp804", 0x1000);
299 sysbus_init_mmio(sbd, &s->iomem);
300}
301
302static void sp804_realize(DeviceState *dev, Error **errp)
303{
304 SP804State *s = SP804(dev);
305
Mark Langsdorf104a26a2011-12-29 06:19:51 +0000306 s->timer[0] = arm_timer_init(s->freq0);
307 s->timer[1] = arm_timer_init(s->freq1);
Shannon Zhaob6412722015-05-29 13:27:02 +0800308 s->timer[0]->irq = qemu_allocate_irq(sp804_set_irq, s, 0);
309 s->timer[1]->irq = qemu_allocate_irq(sp804_set_irq, s, 1);
pbrookcdbdb642006-04-09 01:32:52 +0000310}
311
pbrookcdbdb642006-04-09 01:32:52 +0000312/* Integrator/CP timer module. */
313
Andreas Färbere2051b42013-07-27 14:20:25 +0200314#define TYPE_INTEGRATOR_PIT "integrator_pit"
Eduardo Habkost80633962020-09-16 14:25:19 -0400315OBJECT_DECLARE_SIMPLE_TYPE(icp_pit_state, INTEGRATOR_PIT)
Andreas Färbere2051b42013-07-27 14:20:25 +0200316
Eduardo Habkostdb1015e2020-09-03 16:43:22 -0400317struct icp_pit_state {
Andreas Färbere2051b42013-07-27 14:20:25 +0200318 SysBusDevice parent_obj;
319
Avi Kivitye219dea2011-08-15 17:17:19 +0300320 MemoryRegion iomem;
Paul Brook6a824ec2009-05-14 22:35:07 +0100321 arm_timer_state *timer[3];
Eduardo Habkostdb1015e2020-09-03 16:43:22 -0400322};
pbrookcdbdb642006-04-09 01:32:52 +0000323
Avi Kivitya8170e52012-10-23 12:30:10 +0200324static uint64_t icp_pit_read(void *opaque, hwaddr offset,
Avi Kivitye219dea2011-08-15 17:17:19 +0300325 unsigned size)
pbrookcdbdb642006-04-09 01:32:52 +0000326{
327 icp_pit_state *s = (icp_pit_state *)opaque;
328 int n;
329
330 /* ??? Don't know the PrimeCell ID for this device. */
pbrookcdbdb642006-04-09 01:32:52 +0000331 n = offset >> 8;
Peter Maydellee71c982011-11-11 13:30:15 +0000332 if (n > 2) {
Peter Maydelledb94a42012-10-30 07:45:10 +0000333 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
Peter Maydellcba933b2014-02-26 17:19:58 +0000334 return 0;
Paul Brook2ac71172009-05-08 02:35:15 +0100335 }
pbrookcdbdb642006-04-09 01:32:52 +0000336
337 return arm_timer_read(s->timer[n], offset & 0xff);
338}
339
Avi Kivitya8170e52012-10-23 12:30:10 +0200340static void icp_pit_write(void *opaque, hwaddr offset,
Avi Kivitye219dea2011-08-15 17:17:19 +0300341 uint64_t value, unsigned size)
pbrookcdbdb642006-04-09 01:32:52 +0000342{
343 icp_pit_state *s = (icp_pit_state *)opaque;
344 int n;
345
pbrookcdbdb642006-04-09 01:32:52 +0000346 n = offset >> 8;
Peter Maydellee71c982011-11-11 13:30:15 +0000347 if (n > 2) {
Peter Maydelledb94a42012-10-30 07:45:10 +0000348 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad timer %d\n", __func__, n);
Peter Maydellcba933b2014-02-26 17:19:58 +0000349 return;
Paul Brook2ac71172009-05-08 02:35:15 +0100350 }
pbrookcdbdb642006-04-09 01:32:52 +0000351
352 arm_timer_write(s->timer[n], offset & 0xff, value);
353}
354
Avi Kivitye219dea2011-08-15 17:17:19 +0300355static const MemoryRegionOps icp_pit_ops = {
356 .read = icp_pit_read,
357 .write = icp_pit_write,
358 .endianness = DEVICE_NATIVE_ENDIAN,
pbrookcdbdb642006-04-09 01:32:52 +0000359};
360
xiaoqiang.zhao0d175e72016-02-18 14:16:20 +0000361static void icp_pit_init(Object *obj)
pbrookcdbdb642006-04-09 01:32:52 +0000362{
xiaoqiang.zhao0d175e72016-02-18 14:16:20 +0000363 icp_pit_state *s = INTEGRATOR_PIT(obj);
364 SysBusDevice *dev = SYS_BUS_DEVICE(obj);
pbrookcdbdb642006-04-09 01:32:52 +0000365
pbrookcdbdb642006-04-09 01:32:52 +0000366 /* Timer 0 runs at the system clock speed (40MHz). */
Paul Brook6a824ec2009-05-14 22:35:07 +0100367 s->timer[0] = arm_timer_init(40000000);
pbrookcdbdb642006-04-09 01:32:52 +0000368 /* The other two timers run at 1MHz. */
Paul Brook6a824ec2009-05-14 22:35:07 +0100369 s->timer[1] = arm_timer_init(1000000);
370 s->timer[2] = arm_timer_init(1000000);
371
372 sysbus_init_irq(dev, &s->timer[0]->irq);
373 sysbus_init_irq(dev, &s->timer[1]->irq);
374 sysbus_init_irq(dev, &s->timer[2]->irq);
pbrookcdbdb642006-04-09 01:32:52 +0000375
xiaoqiang.zhao0d175e72016-02-18 14:16:20 +0000376 memory_region_init_io(&s->iomem, obj, &icp_pit_ops, s,
Paolo Bonzini853dca12013-06-06 21:25:08 -0400377 "icp_pit", 0x1000);
Avi Kivity750ecd42011-11-27 11:38:10 +0200378 sysbus_init_mmio(dev, &s->iomem);
pbrook23e39292008-07-02 16:48:32 +0000379 /* This device has no state to save/restore. The component timers will
380 save themselves. */
Anthony Liguori999e12b2012-01-24 13:12:29 -0600381}
382
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100383static const TypeInfo icp_pit_info = {
Andreas Färbere2051b42013-07-27 14:20:25 +0200384 .name = TYPE_INTEGRATOR_PIT,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600385 .parent = TYPE_SYS_BUS_DEVICE,
386 .instance_size = sizeof(icp_pit_state),
xiaoqiang.zhao0d175e72016-02-18 14:16:20 +0000387 .instance_init = icp_pit_init,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600388};
389
390static Property sp804_properties[] = {
Andreas Färber1024d7f2013-07-27 14:15:46 +0200391 DEFINE_PROP_UINT32("freq0", SP804State, freq0, 1000000),
392 DEFINE_PROP_UINT32("freq1", SP804State, freq1, 1000000),
Anthony Liguori39bffca2011-12-07 21:34:16 -0600393 DEFINE_PROP_END_OF_LIST(),
Anthony Liguori999e12b2012-01-24 13:12:29 -0600394};
395
396static void sp804_class_init(ObjectClass *klass, void *data)
397{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600398 DeviceClass *k = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600399
xiaoqiang.zhao0d175e72016-02-18 14:16:20 +0000400 k->realize = sp804_realize;
Marc-André Lureau4f67d302020-01-10 19:30:32 +0400401 device_class_set_props(k, sp804_properties);
xiaoqiang.zhaod712a5a2016-02-18 14:16:20 +0000402 k->vmsd = &vmstate_sp804;
Anthony Liguori999e12b2012-01-24 13:12:29 -0600403}
404
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100405static const TypeInfo sp804_info = {
Andreas Färber0c88dea2013-07-27 14:17:41 +0200406 .name = TYPE_SP804,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600407 .parent = TYPE_SYS_BUS_DEVICE,
Andreas Färber1024d7f2013-07-27 14:15:46 +0200408 .instance_size = sizeof(SP804State),
xiaoqiang.zhao0d175e72016-02-18 14:16:20 +0000409 .instance_init = sp804_init,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600410 .class_init = sp804_class_init,
Anthony Liguori999e12b2012-01-24 13:12:29 -0600411};
412
Andreas Färber83f7d432012-02-09 15:20:55 +0100413static void arm_timer_register_types(void)
Paul Brook6a824ec2009-05-14 22:35:07 +0100414{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600415 type_register_static(&icp_pit_info);
416 type_register_static(&sp804_info);
Paul Brook6a824ec2009-05-14 22:35:07 +0100417}
418
Andreas Färber83f7d432012-02-09 15:20:55 +0100419type_init(arm_timer_register_types)