hw/arm: Restore local modifications
[qemu/ar7.git] / hw / timer / bcm2835_timer.c
bloba16b0d55f5ecce8b4c6b9a0c7946756040a9f997
1 /*
2 * Raspberry Pi emulation (c) 2012 Gregory Estrade
3 * This code is licensed under the GNU GPLv2 and later.
4 */
6 #include "qemu/osdep.h"
7 #include "qemu/log.h"
8 #include "hw/timer/bcm2835_timer.h"
9 #include "qemu/main-loop.h"
11 #define SYSCLOCK_FREQ (252000000)
12 #define APBCLOCK_FREQ (126000000)
14 #define CTRL_FRC_EN (1 << 9)
15 #define CTRL_TIMER_EN (1 << 7)
16 #define CTRL_IRQ_EN (1 << 5)
17 #define CTRL_PS_MASK (3 << 2)
18 #define CTRL_PS_SHIFT 2
19 #define CTRL_CNT_32 (1 << 1)
20 #define CTRL_FRC_PS_MASK (0xff << 16)
21 #define CTRL_FRC_PS_SHIFT 16
23 static void timer_tick(void *opaque)
25 BCM2835TimerState *s = (BCM2835TimerState *)opaque;
26 s->raw_irq = 1;
27 if (s->control & CTRL_IRQ_EN) {
28 qemu_set_irq(s->irq, 1);
31 static void frc_timer_tick(void *opaque)
33 BCM2835TimerState *s = (BCM2835TimerState *)opaque;
34 s->frc_value++;
37 static uint64_t bcm2835_timer_read(void *opaque, hwaddr offset,
38 unsigned size)
40 BCM2835TimerState *s = (BCM2835TimerState *)opaque;
41 uint32_t res = 0;
43 assert(size == 4);
45 switch (offset) {
46 case 0x0:
47 res = s->load;
48 break;
49 case 0x4:
50 res = ptimer_get_count(s->timer);
51 break;
52 case 0x8:
53 res = s->control;
54 break;
55 case 0xc:
56 res = 0x544d5241;
57 break;
58 case 0x10:
59 res = s->raw_irq;
60 break;
61 case 0x14:
62 if (s->control & CTRL_IRQ_EN) {
63 res = s->raw_irq;
65 break;
66 case 0x18:
67 res = s->load;
68 break;
69 case 0x1c:
70 res = s->prediv;
71 break;
72 case 0x20:
73 res = s->frc_value;
74 break;
75 default:
76 qemu_log_mask(LOG_GUEST_ERROR,
77 "bcm2835_timer_read: Bad offset %x\n", (int)offset);
78 return 0;
81 return res;
84 static void bcm2835_timer_write(void *opaque, hwaddr offset,
85 uint64_t value, unsigned size)
87 BCM2835TimerState *s = (BCM2835TimerState *)opaque;
88 uint32_t freq;
90 assert(size == 4);
92 switch (offset) {
93 case 0x0:
94 s->load = value;
95 ptimer_set_limit(s->timer, s->load, 1);
96 break;
97 case 0x4:
98 break;
99 case 0x8:
100 if (s->control & CTRL_FRC_EN) {
101 ptimer_stop(s->frc_timer);
103 if (s->control & CTRL_TIMER_EN) {
104 ptimer_stop(s->timer);
106 s->control = value & 0x00ff03ae;
108 freq = SYSCLOCK_FREQ;
109 ptimer_set_freq(s->frc_timer, freq);
110 ptimer_set_limit(s->frc_timer,
111 ((s->control & CTRL_FRC_PS_MASK) >> CTRL_FRC_PS_SHIFT) + 1,
112 s->control & CTRL_FRC_EN);
114 freq = APBCLOCK_FREQ;
115 freq /= s->prediv + 1;
116 switch ((s->control & CTRL_PS_MASK) >> CTRL_PS_SHIFT) {
117 case 1:
118 freq >>= 4;
119 break;
120 case 2:
121 freq >>= 8;
122 break;
123 default:
124 break;
126 ptimer_set_freq(s->timer, freq);
127 ptimer_set_limit(s->timer, s->load, s->control & CTRL_TIMER_EN);
129 if (s->control & CTRL_TIMER_EN) {
130 ptimer_run(s->timer, 0);
132 if (s->control & CTRL_FRC_EN) {
133 s->frc_value++;
134 ptimer_run(s->frc_timer, 0);
136 break;
137 case 0xc:
138 s->raw_irq = 0;
139 qemu_set_irq(s->irq, 0);
140 break;
141 case 0x10:
142 case 0x14:
143 break;
144 case 0x18:
145 s->load = value;
146 ptimer_set_limit(s->timer, s->load, 0);
147 break;
148 case 0x1c:
149 s->prediv = value & 0x3ff;
150 break;
151 case 0x20:
152 break;
153 default:
154 qemu_log_mask(LOG_GUEST_ERROR,
155 "bcm2835_timer_write: Bad offset %x\n", (int)offset);
156 return;
160 static const MemoryRegionOps bcm2835_timer_ops = {
161 .read = bcm2835_timer_read,
162 .write = bcm2835_timer_write,
163 .endianness = DEVICE_NATIVE_ENDIAN,
166 static const VMStateDescription vmstate_bcm2835_timer = {
167 .name = TYPE_BCM2835_TIMER,
168 .version_id = 1,
169 .minimum_version_id = 1,
170 .minimum_version_id_old = 1,
171 .fields = (VMStateField[]) {
172 VMSTATE_END_OF_LIST()
176 static void bcm2835_timer_init(Object *obj)
178 BCM2835TimerState *s = BCM2835_TIMER(obj);
180 memory_region_init_io(&s->iomem, obj, &bcm2835_timer_ops, s,
181 TYPE_BCM2835_TIMER, 0x100);
182 sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
183 sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
186 static void bcm2835_timer_realize(DeviceState *dev, Error **errp)
188 BCM2835TimerState *s = BCM2835_TIMER(dev);
189 QEMUBH *bh;
191 s->load = 0;
192 s->control = 0x3e << 16;
193 s->raw_irq = 0;
194 s->prediv = 0x7d;
196 bh = qemu_bh_new(timer_tick, s);
197 s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
199 bh = qemu_bh_new(frc_timer_tick, s);
200 s->frc_timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
203 static void bcm2835_timer_class_init(ObjectClass *klass, void *data)
205 DeviceClass *dc = DEVICE_CLASS(klass);
207 dc->realize = bcm2835_timer_realize;
208 dc->vmsd = &vmstate_bcm2835_timer;
211 static TypeInfo bcm2835_timer_info = {
212 .name = TYPE_BCM2835_TIMER,
213 .parent = TYPE_SYS_BUS_DEVICE,
214 .instance_size = sizeof(BCM2835TimerState),
215 .class_init = bcm2835_timer_class_init,
216 .instance_init = bcm2835_timer_init,
219 static void bcm2835_timer_register_types(void)
221 type_register_static(&bcm2835_timer_info);
224 type_init(bcm2835_timer_register_types)