1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include "qemu/osdep.h"
23#include "hw/timer/arm_mptimer.h"
24#include "qapi/error.h"
25#include "qemu/timer.h"
26#include "qom/cpu.h"
27
28#include "hw/fdt_generic_devices.h"
29
30
31
32
33
34static inline int get_current_cpu(ARMMPTimerState *s)
35{
36 if (current_cpu->cpu_index >= s->num_cpu) {
37 hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n",
38 s->num_cpu, current_cpu->cpu_index);
39 }
40 return current_cpu->cpu_index;
41}
42
43static inline void timerblock_update_irq(TimerBlock *tb)
44{
45 qemu_set_irq(tb->irq, tb->status && (tb->control & 4));
46}
47
48
49static inline uint32_t timerblock_scale(TimerBlock *tb)
50{
51 return (((tb->control >> 8) & 0xff) + 1) * 10;
52}
53
54static void timerblock_reload(TimerBlock *tb, int restart)
55{
56 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
57
58 if (tb->count == 0) {
59 return;
60 }
61 if (restart) {
62 tb->tick = now;
63 }
64
65 assert(tb->tick <= now);
66 while (tb->tick <= now) {
67 tb->tick += (int64_t)tb->count * timerblock_scale(tb);
68 }
69 timer_mod(tb->timer, tb->tick);
70}
71
72static void timerblock_tick(void *opaque)
73{
74 TimerBlock *tb = (TimerBlock *)opaque;
75 tb->status = 1;
76 if (tb->control & 2) {
77 tb->count = tb->load;
78 timerblock_reload(tb, 0);
79 } else {
80 tb->count = 0;
81 }
82 timerblock_update_irq(tb);
83}
84
85static uint64_t timerblock_read(void *opaque, hwaddr addr,
86 unsigned size)
87{
88 TimerBlock *tb = (TimerBlock *)opaque;
89 int64_t val;
90 switch (addr) {
91 case 0:
92 return tb->load;
93 case 4:
94 if (((tb->control & 1) == 0) || (tb->count == 0)) {
95 return 0;
96 }
97
98 val = tb->tick - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
99 val /= timerblock_scale(tb);
100 if (val < 0) {
101 val = 0;
102 }
103 return val;
104 case 8:
105 return tb->control;
106 case 12:
107 return tb->status;
108 default:
109 return 0;
110 }
111}
112
113static void timerblock_write(void *opaque, hwaddr addr,
114 uint64_t value, unsigned size)
115{
116 TimerBlock *tb = (TimerBlock *)opaque;
117 int64_t old;
118 switch (addr) {
119 case 0:
120 tb->load = value;
121
122 case 4:
123 if ((tb->control & 1) && tb->count) {
124
125 timer_del(tb->timer);
126 }
127 tb->count = value;
128 if (tb->control & 1) {
129 timerblock_reload(tb, 1);
130 }
131 break;
132 case 8:
133 old = tb->control;
134 tb->control = value;
135 if (value & 1) {
136 if ((old & 1) && (tb->count != 0)) {
137
138 break;
139 }
140 if (tb->control & 2) {
141 tb->count = tb->load;
142 }
143 timerblock_reload(tb, 1);
144 } else if (old & 1) {
145
146 timer_del(tb->timer);
147 }
148 break;
149 case 12:
150 tb->status &= ~value;
151 timerblock_update_irq(tb);
152 break;
153 }
154}
155
156
157
158
159static uint64_t arm_thistimer_read(void *opaque, hwaddr addr,
160 unsigned size)
161{
162 ARMMPTimerState *s = (ARMMPTimerState *)opaque;
163 int id = get_current_cpu(s);
164 return timerblock_read(&s->timerblock[id], addr, size);
165}
166
167static void arm_thistimer_write(void *opaque, hwaddr addr,
168 uint64_t value, unsigned size)
169{
170 ARMMPTimerState *s = (ARMMPTimerState *)opaque;
171 int id = get_current_cpu(s);
172 timerblock_write(&s->timerblock[id], addr, value, size);
173}
174
175static const MemoryRegionOps arm_thistimer_ops = {
176 .read = arm_thistimer_read,
177 .write = arm_thistimer_write,
178 .valid = {
179 .min_access_size = 4,
180 .max_access_size = 4,
181 },
182 .endianness = DEVICE_NATIVE_ENDIAN,
183};
184
185static const MemoryRegionOps timerblock_ops = {
186 .read = timerblock_read,
187 .write = timerblock_write,
188 .valid = {
189 .min_access_size = 4,
190 .max_access_size = 4,
191 },
192 .endianness = DEVICE_NATIVE_ENDIAN,
193};
194
195static void timerblock_reset(TimerBlock *tb)
196{
197 tb->count = 0;
198 tb->load = 0;
199 tb->control = 0;
200 tb->status = 0;
201 tb->tick = 0;
202 if (tb->timer) {
203 timer_del(tb->timer);
204 }
205}
206
207static void arm_mptimer_reset(DeviceState *dev)
208{
209 ARMMPTimerState *s = ARM_MPTIMER(dev);
210 int i;
211
212 for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) {
213 timerblock_reset(&s->timerblock[i]);
214 }
215}
216
217static void arm_mptimer_init(Object *obj)
218{
219 ARMMPTimerState *s = ARM_MPTIMER(obj);
220
221 memory_region_init_io(&s->iomem, obj, &arm_thistimer_ops, s,
222 "arm_mptimer_timer", 0x20);
223 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
224}
225
226static void arm_mptimer_realize(DeviceState *dev, Error **errp)
227{
228 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
229 ARMMPTimerState *s = ARM_MPTIMER(dev);
230 int i;
231
232 if (!s->num_cpu) {
233 s->num_cpu = fdt_generic_num_cpus;
234 }
235 if (s->num_cpu < 1 || s->num_cpu > ARM_MPTIMER_MAX_CPUS) {
236 error_setg(errp, "num-cpu must be between 1 and %d",
237 ARM_MPTIMER_MAX_CPUS);
238 return;
239 }
240
241
242
243
244
245
246
247
248
249
250 for (i = 0; i < s->num_cpu; i++) {
251 TimerBlock *tb = &s->timerblock[i];
252 tb->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, timerblock_tick, tb);
253 sysbus_init_irq(sbd, &tb->irq);
254 memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb,
255 "arm_mptimer_timerblock", 0x20);
256 sysbus_init_mmio(sbd, &tb->iomem);
257 }
258}
259
260static const VMStateDescription vmstate_timerblock = {
261 .name = "arm_mptimer_timerblock",
262 .version_id = 2,
263 .minimum_version_id = 2,
264 .fields = (VMStateField[]) {
265 VMSTATE_UINT32(count, TimerBlock),
266 VMSTATE_UINT32(load, TimerBlock),
267 VMSTATE_UINT32(control, TimerBlock),
268 VMSTATE_UINT32(status, TimerBlock),
269 VMSTATE_INT64(tick, TimerBlock),
270 VMSTATE_TIMER_PTR(timer, TimerBlock),
271 VMSTATE_END_OF_LIST()
272 }
273};
274
275static const VMStateDescription vmstate_arm_mptimer = {
276 .name = "arm_mptimer",
277 .version_id = 2,
278 .minimum_version_id = 2,
279 .fields = (VMStateField[]) {
280 VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu,
281 2, vmstate_timerblock, TimerBlock),
282 VMSTATE_END_OF_LIST()
283 }
284};
285
286static Property arm_mptimer_properties[] = {
287 DEFINE_PROP_UINT32("num-cpu", ARMMPTimerState, num_cpu, 0),
288 DEFINE_PROP_END_OF_LIST()
289};
290
291static void arm_mptimer_class_init(ObjectClass *klass, void *data)
292{
293 DeviceClass *dc = DEVICE_CLASS(klass);
294
295 dc->realize = arm_mptimer_realize;
296 dc->vmsd = &vmstate_arm_mptimer;
297 dc->reset = arm_mptimer_reset;
298 dc->props = arm_mptimer_properties;
299}
300
301static const TypeInfo arm_mptimer_info = {
302 .name = TYPE_ARM_MPTIMER,
303 .parent = TYPE_SYS_BUS_DEVICE,
304 .instance_size = sizeof(ARMMPTimerState),
305 .instance_init = arm_mptimer_init,
306 .class_init = arm_mptimer_class_init,
307};
308
309static void arm_mptimer_register_types(void)
310{
311 type_register_static(&arm_mptimer_info);
312}
313
314type_init(arm_mptimer_register_types)
315