2 * Raspberry Pi emulation (c) 2012 Gregory Estrade
3 * This code is licensed under the GNU GPLv2 and later.
6 /* Based on several timers code found in various QEMU source files. */
8 #include "hw/timer/bcm2835_st.h"
10 static void bcm2835_st_update(BCM2835StState
*s
)
12 int64_t now
= qemu_clock_get_us(QEMU_CLOCK_VIRTUAL
);
13 uint32_t clo
= (uint32_t)now
;
18 /* Calculate new "next" value and reschedule */
19 for (i
= 0; i
< 4; i
++) {
20 if (!(s
->match
& (1 << i
))) {
21 if (!set
|| s
->compare
[i
] - clo
< delta
) {
23 s
->next
= s
->compare
[i
];
24 delta
= s
->next
- clo
;
30 timer_mod(s
->timer
, now
+ delta
);
36 static void bcm2835_st_tick(void *opaque
)
38 BCM2835StState
*s
= (BCM2835StState
*)opaque
;
41 /* Trigger irqs for current "next" value */
42 for (i
= 0; i
< 4; i
++) {
43 if (!(s
->match
& (1 << i
)) && (s
->next
== s
->compare
[i
])) {
45 qemu_set_irq(s
->irq
[i
], 1);
52 static uint64_t bcm2835_st_read(void *opaque
, hwaddr offset
,
55 BCM2835StState
*s
= (BCM2835StState
*)opaque
;
57 uint64_t now
= qemu_clock_get_us(QEMU_CLOCK_VIRTUAL
);
67 /* Ugly temporary hack to get Plan9 to boot... */
68 /* see http://plan9.bell-labs.com/sources/contrib/ \
69 * miller/rpi/sys/src/9/bcm/clock.c */
70 /* res = (now / 10000) * 10000; */
88 qemu_log_mask(LOG_GUEST_ERROR
,
89 "bcm2835_st_read: Bad offset %x\n", (int)offset
);
96 static void bcm2835_st_write(void *opaque
, hwaddr offset
,
97 uint64_t value
, unsigned size
)
99 BCM2835StState
*s
= (BCM2835StState
*)opaque
;
106 s
->match
&= ~value
& 0x0f;
107 for (i
= 0; i
< 4; i
++) {
108 if (value
& (1 << i
)) {
109 qemu_set_irq(s
->irq
[i
], 0);
114 s
->compare
[0] = value
;
117 s
->compare
[1] = value
;
120 s
->compare
[2] = value
;
123 s
->compare
[3] = value
;
126 qemu_log_mask(LOG_GUEST_ERROR
,
127 "bcm2835_st_write: Bad offset %x\n", (int)offset
);
130 bcm2835_st_update(s
);
133 static const MemoryRegionOps bcm2835_st_ops
= {
134 .read
= bcm2835_st_read
,
135 .write
= bcm2835_st_write
,
136 .endianness
= DEVICE_NATIVE_ENDIAN
,
139 static const VMStateDescription vmstate_bcm2835_st
= {
140 .name
= TYPE_BCM2835_ST
,
142 .minimum_version_id
= 1,
143 .minimum_version_id_old
= 1,
144 .fields
= (VMStateField
[]) {
145 VMSTATE_UINT32_ARRAY(compare
, BCM2835StState
, 4),
146 VMSTATE_UINT32(match
, BCM2835StState
),
147 VMSTATE_END_OF_LIST()
151 static void bcm2835_st_init(Object
*obj
)
153 BCM2835StState
*s
= BCM2835_ST(obj
);
156 for (i
= 0; i
< 4; i
++) {
157 sysbus_init_irq(SYS_BUS_DEVICE(s
), &s
->irq
[i
]);
160 memory_region_init_io(&s
->iomem
, obj
, &bcm2835_st_ops
, s
,
161 TYPE_BCM2835_ST
, 0x20);
162 sysbus_init_mmio(SYS_BUS_DEVICE(s
), &s
->iomem
);
165 static void bcm2835_st_realize(DeviceState
*dev
, Error
**errp
)
167 BCM2835StState
*s
= BCM2835_ST(dev
);
170 for (i
= 0; i
< 4; i
++) {
174 s
->timer
= timer_new_us(QEMU_CLOCK_VIRTUAL
, bcm2835_st_tick
, s
);
176 bcm2835_st_update(s
);
179 static void bcm2835_st_class_init(ObjectClass
*klass
, void *data
)
181 DeviceClass
*dc
= DEVICE_CLASS(klass
);
183 dc
->realize
= bcm2835_st_realize
;
184 dc
->vmsd
= &vmstate_bcm2835_st
;
187 static TypeInfo bcm2835_st_info
= {
188 .name
= TYPE_BCM2835_ST
,
189 .parent
= TYPE_SYS_BUS_DEVICE
,
190 .instance_size
= sizeof(BCM2835StState
),
191 .class_init
= bcm2835_st_class_init
,
192 .instance_init
= bcm2835_st_init
,
195 static void bcm2835_st_register_types(void)
197 type_register_static(&bcm2835_st_info
);
200 type_init(bcm2835_st_register_types
)