]> git.proxmox.com Git - mirror_qemu.git/blame - hw/timer/aspeed_timer.c
Include hw/irq.h a lot less
[mirror_qemu.git] / hw / timer / aspeed_timer.c
CommitLineData
c04bd47d
AJ
1/*
2 * ASPEED AST2400 Timer
3 *
4 * Andrew Jeffery <andrew@aj.id.au>
5 *
6 * Copyright (C) 2016 IBM Corp.
7 *
8 * This code is licensed under the GPL version 2 or later. See
9 * the COPYING file in the top-level directory.
10 */
11
12#include "qemu/osdep.h"
9b945a9e 13#include "qapi/error.h"
64552b6b 14#include "hw/irq.h"
c04bd47d
AJ
15#include "hw/sysbus.h"
16#include "hw/timer/aspeed_timer.h"
c04bd47d 17#include "qemu/bitops.h"
c04bd47d 18#include "qemu/timer.h"
22b31af2 19#include "qemu/log.h"
0b8fa32f 20#include "qemu/module.h"
c04bd47d
AJ
21#include "trace.h"
22
23#define TIMER_NR_REGS 4
24
25#define TIMER_CTRL_BITS 4
26#define TIMER_CTRL_MASK ((1 << TIMER_CTRL_BITS) - 1)
27
28#define TIMER_CLOCK_USE_EXT true
29#define TIMER_CLOCK_EXT_HZ 1000000
30#define TIMER_CLOCK_USE_APB false
c04bd47d
AJ
31
32#define TIMER_REG_STATUS 0
33#define TIMER_REG_RELOAD 1
34#define TIMER_REG_MATCH_FIRST 2
35#define TIMER_REG_MATCH_SECOND 3
36
37#define TIMER_FIRST_CAP_PULSE 4
38
39enum timer_ctrl_op {
40 op_enable = 0,
41 op_external_clock,
42 op_overflow_interrupt,
43 op_pulse_enable
44};
45
46/**
47 * Avoid mutual references between AspeedTimerCtrlState and AspeedTimer
48 * structs, as it's a waste of memory. The ptimer BH callback needs to know
49 * whether a specific AspeedTimer is enabled, but this information is held in
50 * AspeedTimerCtrlState. So, provide a helper to hoist ourselves from an
51 * arbitrary AspeedTimer to AspeedTimerCtrlState.
52 */
53static inline AspeedTimerCtrlState *timer_to_ctrl(AspeedTimer *t)
54{
55 const AspeedTimer (*timers)[] = (void *)t - (t->id * sizeof(*t));
56 return container_of(timers, AspeedTimerCtrlState, timers);
57}
58
59static inline bool timer_ctrl_status(AspeedTimer *t, enum timer_ctrl_op op)
60{
61 return !!(timer_to_ctrl(t)->ctrl & BIT(t->id * TIMER_CTRL_BITS + op));
62}
63
64static inline bool timer_enabled(AspeedTimer *t)
65{
66 return timer_ctrl_status(t, op_enable);
67}
68
69static inline bool timer_overflow_interrupt(AspeedTimer *t)
70{
71 return timer_ctrl_status(t, op_overflow_interrupt);
72}
73
74static inline bool timer_can_pulse(AspeedTimer *t)
75{
76 return t->id >= TIMER_FIRST_CAP_PULSE;
77}
78
1d3e65aa
AJ
79static inline bool timer_external_clock(AspeedTimer *t)
80{
81 return timer_ctrl_status(t, op_external_clock);
82}
83
1d3e65aa
AJ
84static inline uint32_t calculate_rate(struct AspeedTimer *t)
85{
9b945a9e
CLG
86 AspeedTimerCtrlState *s = timer_to_ctrl(t);
87
88 return timer_external_clock(t) ? TIMER_CLOCK_EXT_HZ : s->scu->apb_freq;
1d3e65aa
AJ
89}
90
91static inline uint32_t calculate_ticks(struct AspeedTimer *t, uint64_t now_ns)
92{
93 uint64_t delta_ns = now_ns - MIN(now_ns, t->start);
94 uint32_t rate = calculate_rate(t);
95 uint64_t ticks = muldiv64(delta_ns, rate, NANOSECONDS_PER_SECOND);
96
97 return t->reload - MIN(t->reload, ticks);
98}
99
100static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks)
101{
102 uint64_t delta_ns;
103 uint64_t delta_ticks;
104
105 delta_ticks = t->reload - MIN(t->reload, ticks);
106 delta_ns = muldiv64(delta_ticks, NANOSECONDS_PER_SECOND, calculate_rate(t));
107
108 return t->start + delta_ns;
109}
110
696942b8
AJ
111static inline uint32_t calculate_match(struct AspeedTimer *t, int i)
112{
113 return t->match[i] < t->reload ? t->match[i] : 0;
114}
115
1d3e65aa
AJ
116static uint64_t calculate_next(struct AspeedTimer *t)
117{
8137355e
JS
118 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
119 uint64_t next;
120
121 /*
122 * We don't know the relationship between the values in the match
123 * registers, so sort using MAX/MIN/zero. We sort in that order as
124 * the timer counts down to zero.
125 */
126
696942b8 127 next = calculate_time(t, MAX(calculate_match(t, 0), calculate_match(t, 1)));
8137355e
JS
128 if (now < next) {
129 return next;
130 }
131
696942b8 132 next = calculate_time(t, MIN(calculate_match(t, 0), calculate_match(t, 1)));
8137355e
JS
133 if (now < next) {
134 return next;
135 }
136
137 next = calculate_time(t, 0);
138 if (now < next) {
139 return next;
140 }
141
142 /* We've missed all deadlines, fire interrupt and try again */
143 timer_del(&t->timer);
1d3e65aa 144
8137355e
JS
145 if (timer_overflow_interrupt(t)) {
146 t->level = !t->level;
147 qemu_set_irq(t->irq, t->level);
1d3e65aa
AJ
148 }
149
696942b8 150 next = MAX(MAX(calculate_match(t, 0), calculate_match(t, 1)), 0);
8137355e 151 t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
696942b8
AJ
152
153 return calculate_time(t, next);
1d3e65aa
AJ
154}
155
1403f364
CLG
156static void aspeed_timer_mod(AspeedTimer *t)
157{
158 uint64_t next = calculate_next(t);
159 if (next) {
160 timer_mod(&t->timer, next);
161 }
162}
163
c04bd47d
AJ
164static void aspeed_timer_expire(void *opaque)
165{
166 AspeedTimer *t = opaque;
1d3e65aa
AJ
167 bool interrupt = false;
168 uint32_t ticks;
c04bd47d 169
1d3e65aa
AJ
170 if (!timer_enabled(t)) {
171 return;
172 }
173
174 ticks = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
175
176 if (!ticks) {
177 interrupt = timer_overflow_interrupt(t) || !t->match[0] || !t->match[1];
178 } else if (ticks <= MIN(t->match[0], t->match[1])) {
179 interrupt = true;
180 } else if (ticks <= MAX(t->match[0], t->match[1])) {
181 interrupt = true;
182 }
183
184 if (interrupt) {
c04bd47d
AJ
185 t->level = !t->level;
186 qemu_set_irq(t->irq, t->level);
187 }
1d3e65aa 188
1403f364 189 aspeed_timer_mod(t);
c04bd47d
AJ
190}
191
192static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
193{
194 uint64_t value;
195
196 switch (reg) {
197 case TIMER_REG_STATUS:
58044b5c
AJ
198 if (timer_enabled(t)) {
199 value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
200 } else {
201 value = t->reload;
202 }
c04bd47d
AJ
203 break;
204 case TIMER_REG_RELOAD:
205 value = t->reload;
206 break;
207 case TIMER_REG_MATCH_FIRST:
208 case TIMER_REG_MATCH_SECOND:
209 value = t->match[reg - 2];
210 break;
211 default:
212 qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n",
213 __func__, reg);
214 value = 0;
215 break;
216 }
217 return value;
218}
219
220static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size)
221{
222 AspeedTimerCtrlState *s = opaque;
223 const int reg = (offset & 0xf) / 4;
224 uint64_t value;
225
226 switch (offset) {
227 case 0x30: /* Control Register */
228 value = s->ctrl;
229 break;
230 case 0x34: /* Control Register 2 */
231 value = s->ctrl2;
232 break;
233 case 0x00 ... 0x2c: /* Timers 1 - 4 */
234 value = aspeed_timer_get_value(&s->timers[(offset >> 4)], reg);
235 break;
236 case 0x40 ... 0x8c: /* Timers 5 - 8 */
237 value = aspeed_timer_get_value(&s->timers[(offset >> 4) - 1], reg);
238 break;
239 /* Illegal */
240 case 0x38:
241 case 0x3C:
242 default:
243 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
244 __func__, offset);
245 value = 0;
246 break;
247 }
248 trace_aspeed_timer_read(offset, size, value);
249 return value;
250}
251
252static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
253 uint32_t value)
254{
255 AspeedTimer *t;
1403f364 256 uint32_t old_reload;
c04bd47d
AJ
257
258 trace_aspeed_timer_set_value(timer, reg, value);
259 t = &s->timers[timer];
260 switch (reg) {
1403f364
CLG
261 case TIMER_REG_RELOAD:
262 old_reload = t->reload;
263 t->reload = value;
264
265 /* If the reload value was not previously set, or zero, and
266 * the current value is valid, try to start the timer if it is
267 * enabled.
268 */
269 if (old_reload || !t->reload) {
270 break;
271 }
272
c04bd47d
AJ
273 case TIMER_REG_STATUS:
274 if (timer_enabled(t)) {
1d3e65aa
AJ
275 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
276 int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now);
277 uint32_t rate = calculate_rate(t);
278
05576247
CS
279 if (delta >= 0) {
280 t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
281 } else {
282 t->start -= muldiv64(-delta, NANOSECONDS_PER_SECOND, rate);
283 }
1403f364 284 aspeed_timer_mod(t);
c04bd47d
AJ
285 }
286 break;
c04bd47d
AJ
287 case TIMER_REG_MATCH_FIRST:
288 case TIMER_REG_MATCH_SECOND:
1d3e65aa
AJ
289 t->match[reg - 2] = value;
290 if (timer_enabled(t)) {
1403f364 291 aspeed_timer_mod(t);
c04bd47d
AJ
292 }
293 break;
294 default:
295 qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n",
296 __func__, reg);
297 break;
298 }
299}
300
301/* Control register operations are broken out into helpers that can be
cb8d4c8f 302 * explicitly called on aspeed_timer_reset(), but also from
c04bd47d
AJ
303 * aspeed_timer_ctrl_op().
304 */
305
306static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable)
307{
308 trace_aspeed_timer_ctrl_enable(t->id, enable);
309 if (enable) {
1d3e65aa 310 t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
1403f364 311 aspeed_timer_mod(t);
c04bd47d 312 } else {
1d3e65aa 313 timer_del(&t->timer);
c04bd47d
AJ
314 }
315}
316
317static void aspeed_timer_ctrl_external_clock(AspeedTimer *t, bool enable)
318{
319 trace_aspeed_timer_ctrl_external_clock(t->id, enable);
c04bd47d
AJ
320}
321
322static void aspeed_timer_ctrl_overflow_interrupt(AspeedTimer *t, bool enable)
323{
324 trace_aspeed_timer_ctrl_overflow_interrupt(t->id, enable);
325}
326
327static void aspeed_timer_ctrl_pulse_enable(AspeedTimer *t, bool enable)
328{
329 if (timer_can_pulse(t)) {
330 trace_aspeed_timer_ctrl_pulse_enable(t->id, enable);
331 } else {
332 qemu_log_mask(LOG_GUEST_ERROR,
333 "%s: Timer does not support pulse mode\n", __func__);
334 }
335}
336
337/**
338 * Given the actions are fixed in number and completely described in helper
339 * functions, dispatch with a lookup table rather than manage control flow with
340 * a switch statement.
341 */
342static void (*const ctrl_ops[])(AspeedTimer *, bool) = {
343 [op_enable] = aspeed_timer_ctrl_enable,
344 [op_external_clock] = aspeed_timer_ctrl_external_clock,
345 [op_overflow_interrupt] = aspeed_timer_ctrl_overflow_interrupt,
346 [op_pulse_enable] = aspeed_timer_ctrl_pulse_enable,
347};
348
349/**
350 * Conditionally affect changes chosen by a timer's control bit.
351 *
352 * The aspeed_timer_ctrl_op() interface is convenient for the
353 * aspeed_timer_set_ctrl() function as the "no change" early exit can be
354 * calculated for all operations, which cleans up the caller code. However the
355 * interface isn't convenient for the reset function where we want to enter a
356 * specific state without artificially constructing old and new values that
357 * will fall through the change guard (and motivates extracting the actions
358 * out to helper functions).
359 *
360 * @t: The timer to manipulate
361 * @op: The type of operation to be performed
362 * @old: The old state of the timer's control bits
363 * @new: The incoming state for the timer's control bits
364 */
365static void aspeed_timer_ctrl_op(AspeedTimer *t, enum timer_ctrl_op op,
366 uint8_t old, uint8_t new)
367{
368 const uint8_t mask = BIT(op);
369 const bool enable = !!(new & mask);
370 const bool changed = ((old ^ new) & mask);
371 if (!changed) {
372 return;
373 }
374 ctrl_ops[op](t, enable);
375}
376
377static void aspeed_timer_set_ctrl(AspeedTimerCtrlState *s, uint32_t reg)
378{
379 int i;
380 int shift;
381 uint8_t t_old, t_new;
382 AspeedTimer *t;
383 const uint8_t enable_mask = BIT(op_enable);
384
385 /* Handle a dependency between the 'enable' and remaining three
386 * configuration bits - i.e. if more than one bit in the control set has
387 * changed, including the 'enable' bit, then we want either disable the
388 * timer and perform configuration, or perform configuration and then
389 * enable the timer
390 */
391 for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
392 t = &s->timers[i];
393 shift = (i * TIMER_CTRL_BITS);
394 t_old = (s->ctrl >> shift) & TIMER_CTRL_MASK;
395 t_new = (reg >> shift) & TIMER_CTRL_MASK;
396
397 /* If we are disabling, do so first */
398 if ((t_old & enable_mask) && !(t_new & enable_mask)) {
399 aspeed_timer_ctrl_enable(t, false);
400 }
401 aspeed_timer_ctrl_op(t, op_external_clock, t_old, t_new);
402 aspeed_timer_ctrl_op(t, op_overflow_interrupt, t_old, t_new);
403 aspeed_timer_ctrl_op(t, op_pulse_enable, t_old, t_new);
404 /* If we are enabling, do so last */
405 if (!(t_old & enable_mask) && (t_new & enable_mask)) {
406 aspeed_timer_ctrl_enable(t, true);
407 }
408 }
409 s->ctrl = reg;
410}
411
412static void aspeed_timer_set_ctrl2(AspeedTimerCtrlState *s, uint32_t value)
413{
414 trace_aspeed_timer_set_ctrl2(value);
415}
416
417static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value,
418 unsigned size)
419{
420 const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
421 const int reg = (offset & 0xf) / 4;
422 AspeedTimerCtrlState *s = opaque;
423
424 switch (offset) {
425 /* Control Registers */
426 case 0x30:
427 aspeed_timer_set_ctrl(s, tv);
428 break;
429 case 0x34:
430 aspeed_timer_set_ctrl2(s, tv);
431 break;
432 /* Timer Registers */
433 case 0x00 ... 0x2c:
434 aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS), reg, tv);
435 break;
436 case 0x40 ... 0x8c:
437 aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS) - 1, reg, tv);
438 break;
439 /* Illegal */
440 case 0x38:
441 case 0x3C:
442 default:
443 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
444 __func__, offset);
445 break;
446 }
447}
448
449static const MemoryRegionOps aspeed_timer_ops = {
450 .read = aspeed_timer_read,
451 .write = aspeed_timer_write,
452 .endianness = DEVICE_LITTLE_ENDIAN,
453 .valid.min_access_size = 4,
454 .valid.max_access_size = 4,
455 .valid.unaligned = false,
456};
457
458static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id)
459{
c04bd47d
AJ
460 AspeedTimer *t = &s->timers[id];
461
462 t->id = id;
1d3e65aa 463 timer_init_ns(&t->timer, QEMU_CLOCK_VIRTUAL, aspeed_timer_expire, t);
c04bd47d
AJ
464}
465
466static void aspeed_timer_realize(DeviceState *dev, Error **errp)
467{
468 int i;
469 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
470 AspeedTimerCtrlState *s = ASPEED_TIMER(dev);
9b945a9e
CLG
471 Object *obj;
472 Error *err = NULL;
473
474 obj = object_property_get_link(OBJECT(dev), "scu", &err);
475 if (!obj) {
4b576648 476 error_propagate_prepend(errp, err, "required link 'scu' not found: ");
9b945a9e
CLG
477 return;
478 }
479 s->scu = ASPEED_SCU(obj);
c04bd47d
AJ
480
481 for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
482 aspeed_init_one_timer(s, i);
483 sysbus_init_irq(sbd, &s->timers[i].irq);
484 }
485 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_timer_ops, s,
486 TYPE_ASPEED_TIMER, 0x1000);
487 sysbus_init_mmio(sbd, &s->iomem);
488}
489
490static void aspeed_timer_reset(DeviceState *dev)
491{
492 int i;
493 AspeedTimerCtrlState *s = ASPEED_TIMER(dev);
494
495 for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
496 AspeedTimer *t = &s->timers[i];
cb8d4c8f 497 /* Explicitly call helpers to avoid any conditional behaviour through
c04bd47d
AJ
498 * aspeed_timer_set_ctrl().
499 */
500 aspeed_timer_ctrl_enable(t, false);
501 aspeed_timer_ctrl_external_clock(t, TIMER_CLOCK_USE_APB);
502 aspeed_timer_ctrl_overflow_interrupt(t, false);
503 aspeed_timer_ctrl_pulse_enable(t, false);
504 t->level = 0;
505 t->reload = 0;
506 t->match[0] = 0;
507 t->match[1] = 0;
508 }
509 s->ctrl = 0;
510 s->ctrl2 = 0;
511}
512
513static const VMStateDescription vmstate_aspeed_timer = {
514 .name = "aspeed.timer",
1d3e65aa
AJ
515 .version_id = 2,
516 .minimum_version_id = 2,
c04bd47d
AJ
517 .fields = (VMStateField[]) {
518 VMSTATE_UINT8(id, AspeedTimer),
519 VMSTATE_INT32(level, AspeedTimer),
1d3e65aa 520 VMSTATE_TIMER(timer, AspeedTimer),
c04bd47d
AJ
521 VMSTATE_UINT32(reload, AspeedTimer),
522 VMSTATE_UINT32_ARRAY(match, AspeedTimer, 2),
523 VMSTATE_END_OF_LIST()
524 }
525};
526
527static const VMStateDescription vmstate_aspeed_timer_state = {
528 .name = "aspeed.timerctrl",
529 .version_id = 1,
530 .minimum_version_id = 1,
531 .fields = (VMStateField[]) {
532 VMSTATE_UINT32(ctrl, AspeedTimerCtrlState),
533 VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState),
534 VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState,
6b892b2f 535 ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer,
c04bd47d
AJ
536 AspeedTimer),
537 VMSTATE_END_OF_LIST()
538 }
539};
540
541static void timer_class_init(ObjectClass *klass, void *data)
542{
543 DeviceClass *dc = DEVICE_CLASS(klass);
544
545 dc->realize = aspeed_timer_realize;
546 dc->reset = aspeed_timer_reset;
547 dc->desc = "ASPEED Timer";
548 dc->vmsd = &vmstate_aspeed_timer_state;
549}
550
551static const TypeInfo aspeed_timer_info = {
552 .name = TYPE_ASPEED_TIMER,
553 .parent = TYPE_SYS_BUS_DEVICE,
554 .instance_size = sizeof(AspeedTimerCtrlState),
555 .class_init = timer_class_init,
556};
557
558static void aspeed_timer_register_types(void)
559{
560 type_register_static(&aspeed_timer_info);
561}
562
563type_init(aspeed_timer_register_types)