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