1
2
3
4
5
6
7
8
9
10
11
12#include "qemu/osdep.h"
13#include "qapi/error.h"
14#include "hw/irq.h"
15#include "hw/sysbus.h"
16#include "hw/timer/aspeed_timer.h"
17#include "migration/vmstate.h"
18#include "qemu/bitops.h"
19#include "qemu/timer.h"
20#include "qemu/log.h"
21#include "qemu/module.h"
22#include "hw/qdev-properties.h"
23#include "trace.h"
24
25#define TIMER_NR_REGS 4
26
27#define TIMER_CTRL_BITS 4
28#define TIMER_CTRL_MASK ((1 << TIMER_CTRL_BITS) - 1)
29
30#define TIMER_CLOCK_USE_EXT true
31#define TIMER_CLOCK_EXT_HZ 1000000
32#define TIMER_CLOCK_USE_APB false
33
34#define TIMER_REG_STATUS 0
35#define TIMER_REG_RELOAD 1
36#define TIMER_REG_MATCH_FIRST 2
37#define TIMER_REG_MATCH_SECOND 3
38
39#define TIMER_FIRST_CAP_PULSE 4
40
41enum timer_ctrl_op {
42 op_enable = 0,
43 op_external_clock,
44 op_overflow_interrupt,
45 op_pulse_enable
46};
47
48
49
50
51
52
53#define TIMER_MIN_NS (20 * SCALE_US)
54
55
56
57
58
59
60
61
62static inline AspeedTimerCtrlState *timer_to_ctrl(AspeedTimer *t)
63{
64 const AspeedTimer (*timers)[] = (void *)t - (t->id * sizeof(*t));
65 return container_of(timers, AspeedTimerCtrlState, timers);
66}
67
68static inline bool timer_ctrl_status(AspeedTimer *t, enum timer_ctrl_op op)
69{
70 return !!(timer_to_ctrl(t)->ctrl & BIT(t->id * TIMER_CTRL_BITS + op));
71}
72
73static inline bool timer_enabled(AspeedTimer *t)
74{
75 return timer_ctrl_status(t, op_enable);
76}
77
78static inline bool timer_overflow_interrupt(AspeedTimer *t)
79{
80 return timer_ctrl_status(t, op_overflow_interrupt);
81}
82
83static inline bool timer_can_pulse(AspeedTimer *t)
84{
85 return t->id >= TIMER_FIRST_CAP_PULSE;
86}
87
88static inline bool timer_external_clock(AspeedTimer *t)
89{
90 return timer_ctrl_status(t, op_external_clock);
91}
92
93static inline uint32_t calculate_rate(struct AspeedTimer *t)
94{
95 AspeedTimerCtrlState *s = timer_to_ctrl(t);
96
97 return timer_external_clock(t) ? TIMER_CLOCK_EXT_HZ :
98 aspeed_scu_get_apb_freq(s->scu);
99}
100
101static inline uint32_t calculate_ticks(struct AspeedTimer *t, uint64_t now_ns)
102{
103 uint64_t delta_ns = now_ns - MIN(now_ns, t->start);
104 uint32_t rate = calculate_rate(t);
105 uint64_t ticks = muldiv64(delta_ns, rate, NANOSECONDS_PER_SECOND);
106
107 return t->reload - MIN(t->reload, ticks);
108}
109
110static uint32_t calculate_min_ticks(AspeedTimer *t, uint32_t value)
111{
112 uint32_t rate = calculate_rate(t);
113 uint32_t min_ticks = muldiv64(TIMER_MIN_NS, rate, NANOSECONDS_PER_SECOND);
114
115 return value < min_ticks ? min_ticks : value;
116}
117
118static inline uint64_t calculate_time(struct AspeedTimer *t, uint32_t ticks)
119{
120 uint64_t delta_ns;
121 uint64_t delta_ticks;
122
123 delta_ticks = t->reload - MIN(t->reload, ticks);
124 delta_ns = muldiv64(delta_ticks, NANOSECONDS_PER_SECOND, calculate_rate(t));
125
126 return t->start + delta_ns;
127}
128
129static inline uint32_t calculate_match(struct AspeedTimer *t, int i)
130{
131 return t->match[i] < t->reload ? t->match[i] : 0;
132}
133
134static uint64_t calculate_next(struct AspeedTimer *t)
135{
136 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
137 uint64_t next;
138
139
140
141
142
143
144
145 next = calculate_time(t, MAX(calculate_match(t, 0), calculate_match(t, 1)));
146 if (now < next) {
147 return next;
148 }
149
150 next = calculate_time(t, MIN(calculate_match(t, 0), calculate_match(t, 1)));
151 if (now < next) {
152 return next;
153 }
154
155 next = calculate_time(t, 0);
156 if (now < next) {
157 return next;
158 }
159
160
161 timer_del(&t->timer);
162
163 if (timer_overflow_interrupt(t)) {
164 AspeedTimerCtrlState *s = timer_to_ctrl(t);
165 t->level = !t->level;
166 s->irq_sts |= BIT(t->id);
167 qemu_set_irq(t->irq, t->level);
168 }
169
170 next = MAX(MAX(calculate_match(t, 0), calculate_match(t, 1)), 0);
171 t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
172
173 return calculate_time(t, next);
174}
175
176static void aspeed_timer_mod(AspeedTimer *t)
177{
178 uint64_t next = calculate_next(t);
179 if (next) {
180 timer_mod(&t->timer, next);
181 }
182}
183
184static void aspeed_timer_expire(void *opaque)
185{
186 AspeedTimer *t = opaque;
187 bool interrupt = false;
188 uint32_t ticks;
189
190 if (!timer_enabled(t)) {
191 return;
192 }
193
194 ticks = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
195
196 if (!ticks) {
197 interrupt = timer_overflow_interrupt(t) || !t->match[0] || !t->match[1];
198 } else if (ticks <= MIN(t->match[0], t->match[1])) {
199 interrupt = true;
200 } else if (ticks <= MAX(t->match[0], t->match[1])) {
201 interrupt = true;
202 }
203
204 if (interrupt) {
205 AspeedTimerCtrlState *s = timer_to_ctrl(t);
206 t->level = !t->level;
207 s->irq_sts |= BIT(t->id);
208 qemu_set_irq(t->irq, t->level);
209 }
210
211 aspeed_timer_mod(t);
212}
213
214static uint64_t aspeed_timer_get_value(AspeedTimer *t, int reg)
215{
216 uint64_t value;
217
218 switch (reg) {
219 case TIMER_REG_STATUS:
220 if (timer_enabled(t)) {
221 value = calculate_ticks(t, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL));
222 } else {
223 value = t->reload;
224 }
225 break;
226 case TIMER_REG_RELOAD:
227 value = t->reload;
228 break;
229 case TIMER_REG_MATCH_FIRST:
230 case TIMER_REG_MATCH_SECOND:
231 value = t->match[reg - 2];
232 break;
233 default:
234 qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n",
235 __func__, reg);
236 value = 0;
237 break;
238 }
239 return value;
240}
241
242static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size)
243{
244 AspeedTimerCtrlState *s = opaque;
245 const int reg = (offset & 0xf) / 4;
246 uint64_t value;
247
248 switch (offset) {
249 case 0x30:
250 value = s->ctrl;
251 break;
252 case 0x00 ... 0x2c:
253 value = aspeed_timer_get_value(&s->timers[(offset >> 4)], reg);
254 break;
255 case 0x40 ... 0x8c:
256 value = aspeed_timer_get_value(&s->timers[(offset >> 4) - 1], reg);
257 break;
258 default:
259 value = ASPEED_TIMER_GET_CLASS(s)->read(s, offset);
260 break;
261 }
262 trace_aspeed_timer_read(offset, size, value);
263 return value;
264}
265
266static void aspeed_timer_set_value(AspeedTimerCtrlState *s, int timer, int reg,
267 uint32_t value)
268{
269 AspeedTimer *t;
270 uint32_t old_reload;
271
272 trace_aspeed_timer_set_value(timer, reg, value);
273 t = &s->timers[timer];
274 switch (reg) {
275 case TIMER_REG_RELOAD:
276 old_reload = t->reload;
277 t->reload = calculate_min_ticks(t, value);
278
279
280
281
282
283 if (old_reload || !t->reload) {
284 break;
285 }
286
287 case TIMER_REG_STATUS:
288 if (timer_enabled(t)) {
289 uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
290 int64_t delta = (int64_t) value - (int64_t) calculate_ticks(t, now);
291 uint32_t rate = calculate_rate(t);
292
293 if (delta >= 0) {
294 t->start += muldiv64(delta, NANOSECONDS_PER_SECOND, rate);
295 } else {
296 t->start -= muldiv64(-delta, NANOSECONDS_PER_SECOND, rate);
297 }
298 aspeed_timer_mod(t);
299 }
300 break;
301 case TIMER_REG_MATCH_FIRST:
302 case TIMER_REG_MATCH_SECOND:
303 t->match[reg - 2] = value;
304 if (timer_enabled(t)) {
305 aspeed_timer_mod(t);
306 }
307 break;
308 default:
309 qemu_log_mask(LOG_UNIMP, "%s: Programming error: unexpected reg: %d\n",
310 __func__, reg);
311 break;
312 }
313}
314
315
316
317
318
319
320static void aspeed_timer_ctrl_enable(AspeedTimer *t, bool enable)
321{
322 trace_aspeed_timer_ctrl_enable(t->id, enable);
323 if (enable) {
324 t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
325 aspeed_timer_mod(t);
326 } else {
327 timer_del(&t->timer);
328 }
329}
330
331static void aspeed_timer_ctrl_external_clock(AspeedTimer *t, bool enable)
332{
333 trace_aspeed_timer_ctrl_external_clock(t->id, enable);
334}
335
336static void aspeed_timer_ctrl_overflow_interrupt(AspeedTimer *t, bool enable)
337{
338 trace_aspeed_timer_ctrl_overflow_interrupt(t->id, enable);
339}
340
341static void aspeed_timer_ctrl_pulse_enable(AspeedTimer *t, bool enable)
342{
343 if (timer_can_pulse(t)) {
344 trace_aspeed_timer_ctrl_pulse_enable(t->id, enable);
345 } else {
346 qemu_log_mask(LOG_GUEST_ERROR,
347 "%s: Timer does not support pulse mode\n", __func__);
348 }
349}
350
351
352
353
354
355
356static void (*const ctrl_ops[])(AspeedTimer *, bool) = {
357 [op_enable] = aspeed_timer_ctrl_enable,
358 [op_external_clock] = aspeed_timer_ctrl_external_clock,
359 [op_overflow_interrupt] = aspeed_timer_ctrl_overflow_interrupt,
360 [op_pulse_enable] = aspeed_timer_ctrl_pulse_enable,
361};
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379static void aspeed_timer_ctrl_op(AspeedTimer *t, enum timer_ctrl_op op,
380 uint8_t old, uint8_t new)
381{
382 const uint8_t mask = BIT(op);
383 const bool enable = !!(new & mask);
384 const bool changed = ((old ^ new) & mask);
385 if (!changed) {
386 return;
387 }
388 ctrl_ops[op](t, enable);
389}
390
391static void aspeed_timer_set_ctrl(AspeedTimerCtrlState *s, uint32_t reg)
392{
393 int i;
394 int shift;
395 uint8_t t_old, t_new;
396 AspeedTimer *t;
397 const uint8_t enable_mask = BIT(op_enable);
398
399
400
401
402
403
404
405 for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
406 t = &s->timers[i];
407 shift = (i * TIMER_CTRL_BITS);
408 t_old = (s->ctrl >> shift) & TIMER_CTRL_MASK;
409 t_new = (reg >> shift) & TIMER_CTRL_MASK;
410
411
412 if ((t_old & enable_mask) && !(t_new & enable_mask)) {
413 aspeed_timer_ctrl_enable(t, false);
414 }
415 aspeed_timer_ctrl_op(t, op_external_clock, t_old, t_new);
416 aspeed_timer_ctrl_op(t, op_overflow_interrupt, t_old, t_new);
417 aspeed_timer_ctrl_op(t, op_pulse_enable, t_old, t_new);
418
419 if (!(t_old & enable_mask) && (t_new & enable_mask)) {
420 aspeed_timer_ctrl_enable(t, true);
421 }
422 }
423 s->ctrl = reg;
424}
425
426static void aspeed_timer_set_ctrl2(AspeedTimerCtrlState *s, uint32_t value)
427{
428 trace_aspeed_timer_set_ctrl2(value);
429}
430
431static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value,
432 unsigned size)
433{
434 const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
435 const int reg = (offset & 0xf) / 4;
436 AspeedTimerCtrlState *s = opaque;
437
438 switch (offset) {
439
440 case 0x30:
441 aspeed_timer_set_ctrl(s, tv);
442 break;
443
444 case 0x00 ... 0x2c:
445 aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS), reg, tv);
446 break;
447 case 0x40 ... 0x8c:
448 aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS) - 1, reg, tv);
449 break;
450 default:
451 ASPEED_TIMER_GET_CLASS(s)->write(s, offset, value);
452 break;
453 }
454}
455
456static const MemoryRegionOps aspeed_timer_ops = {
457 .read = aspeed_timer_read,
458 .write = aspeed_timer_write,
459 .endianness = DEVICE_LITTLE_ENDIAN,
460 .valid.min_access_size = 4,
461 .valid.max_access_size = 4,
462 .valid.unaligned = false,
463};
464
465static uint64_t aspeed_2400_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
466{
467 uint64_t value;
468
469 switch (offset) {
470 case 0x34:
471 value = s->ctrl2;
472 break;
473 case 0x38:
474 case 0x3C:
475 default:
476 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
477 __func__, offset);
478 value = 0;
479 break;
480 }
481 return value;
482}
483
484static void aspeed_2400_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
485 uint64_t value)
486{
487 const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
488
489 switch (offset) {
490 case 0x34:
491 aspeed_timer_set_ctrl2(s, tv);
492 break;
493 case 0x38:
494 case 0x3C:
495 default:
496 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
497 __func__, offset);
498 break;
499 }
500}
501
502static uint64_t aspeed_2500_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
503{
504 uint64_t value;
505
506 switch (offset) {
507 case 0x34:
508 value = s->ctrl2;
509 break;
510 case 0x38:
511 value = s->ctrl3 & BIT(0);
512 break;
513 case 0x3C:
514 default:
515 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
516 __func__, offset);
517 value = 0;
518 break;
519 }
520 return value;
521}
522
523static void aspeed_2500_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
524 uint64_t value)
525{
526 const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
527 uint8_t command;
528
529 switch (offset) {
530 case 0x34:
531 aspeed_timer_set_ctrl2(s, tv);
532 break;
533 case 0x38:
534 command = (value >> 1) & 0xFF;
535 if (command == 0xAE) {
536 s->ctrl3 = 0x1;
537 } else if (command == 0xEA) {
538 s->ctrl3 = 0x0;
539 }
540 break;
541 case 0x3C:
542 if (s->ctrl3 & BIT(0)) {
543 aspeed_timer_set_ctrl(s, s->ctrl & ~tv);
544 }
545 break;
546
547 default:
548 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
549 __func__, offset);
550 break;
551 }
552}
553
554static uint64_t aspeed_2600_timer_read(AspeedTimerCtrlState *s, hwaddr offset)
555{
556 uint64_t value;
557
558 switch (offset) {
559 case 0x34:
560 value = s->irq_sts;
561 break;
562 case 0x38:
563 case 0x3C:
564 default:
565 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
566 __func__, offset);
567 value = 0;
568 break;
569 }
570 return value;
571}
572
573static void aspeed_2600_timer_write(AspeedTimerCtrlState *s, hwaddr offset,
574 uint64_t value)
575{
576 const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
577
578 switch (offset) {
579 case 0x34:
580 s->irq_sts &= tv;
581 break;
582 case 0x3C:
583 aspeed_timer_set_ctrl(s, s->ctrl & ~tv);
584 break;
585
586 case 0x38:
587 default:
588 qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n",
589 __func__, offset);
590 break;
591 }
592}
593
594static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id)
595{
596 AspeedTimer *t = &s->timers[id];
597
598 t->id = id;
599 timer_init_ns(&t->timer, QEMU_CLOCK_VIRTUAL, aspeed_timer_expire, t);
600}
601
602static void aspeed_timer_realize(DeviceState *dev, Error **errp)
603{
604 int i;
605 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
606 AspeedTimerCtrlState *s = ASPEED_TIMER(dev);
607
608 assert(s->scu);
609
610 for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
611 aspeed_init_one_timer(s, i);
612 sysbus_init_irq(sbd, &s->timers[i].irq);
613 }
614 memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_timer_ops, s,
615 TYPE_ASPEED_TIMER, 0x1000);
616 sysbus_init_mmio(sbd, &s->iomem);
617}
618
619static void aspeed_timer_reset(DeviceState *dev)
620{
621 int i;
622 AspeedTimerCtrlState *s = ASPEED_TIMER(dev);
623
624 for (i = 0; i < ASPEED_TIMER_NR_TIMERS; i++) {
625 AspeedTimer *t = &s->timers[i];
626
627
628
629 aspeed_timer_ctrl_enable(t, false);
630 aspeed_timer_ctrl_external_clock(t, TIMER_CLOCK_USE_APB);
631 aspeed_timer_ctrl_overflow_interrupt(t, false);
632 aspeed_timer_ctrl_pulse_enable(t, false);
633 t->level = 0;
634 t->reload = 0;
635 t->match[0] = 0;
636 t->match[1] = 0;
637 }
638 s->ctrl = 0;
639 s->ctrl2 = 0;
640 s->ctrl3 = 0;
641 s->irq_sts = 0;
642}
643
644static const VMStateDescription vmstate_aspeed_timer = {
645 .name = "aspeed.timer",
646 .version_id = 2,
647 .minimum_version_id = 2,
648 .fields = (VMStateField[]) {
649 VMSTATE_UINT8(id, AspeedTimer),
650 VMSTATE_INT32(level, AspeedTimer),
651 VMSTATE_TIMER(timer, AspeedTimer),
652 VMSTATE_UINT32(reload, AspeedTimer),
653 VMSTATE_UINT32_ARRAY(match, AspeedTimer, 2),
654 VMSTATE_END_OF_LIST()
655 }
656};
657
658static const VMStateDescription vmstate_aspeed_timer_state = {
659 .name = "aspeed.timerctrl",
660 .version_id = 2,
661 .minimum_version_id = 2,
662 .fields = (VMStateField[]) {
663 VMSTATE_UINT32(ctrl, AspeedTimerCtrlState),
664 VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState),
665 VMSTATE_UINT32(ctrl3, AspeedTimerCtrlState),
666 VMSTATE_UINT32(irq_sts, AspeedTimerCtrlState),
667 VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState,
668 ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer,
669 AspeedTimer),
670 VMSTATE_END_OF_LIST()
671 }
672};
673
674static Property aspeed_timer_properties[] = {
675 DEFINE_PROP_LINK("scu", AspeedTimerCtrlState, scu, TYPE_ASPEED_SCU,
676 AspeedSCUState *),
677 DEFINE_PROP_END_OF_LIST(),
678};
679
680static void timer_class_init(ObjectClass *klass, void *data)
681{
682 DeviceClass *dc = DEVICE_CLASS(klass);
683
684 dc->realize = aspeed_timer_realize;
685 dc->reset = aspeed_timer_reset;
686 dc->desc = "ASPEED Timer";
687 dc->vmsd = &vmstate_aspeed_timer_state;
688 device_class_set_props(dc, aspeed_timer_properties);
689}
690
691static const TypeInfo aspeed_timer_info = {
692 .name = TYPE_ASPEED_TIMER,
693 .parent = TYPE_SYS_BUS_DEVICE,
694 .instance_size = sizeof(AspeedTimerCtrlState),
695 .class_init = timer_class_init,
696 .class_size = sizeof(AspeedTimerClass),
697 .abstract = true,
698};
699
700static void aspeed_2400_timer_class_init(ObjectClass *klass, void *data)
701{
702 DeviceClass *dc = DEVICE_CLASS(klass);
703 AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
704
705 dc->desc = "ASPEED 2400 Timer";
706 awc->read = aspeed_2400_timer_read;
707 awc->write = aspeed_2400_timer_write;
708}
709
710static const TypeInfo aspeed_2400_timer_info = {
711 .name = TYPE_ASPEED_2400_TIMER,
712 .parent = TYPE_ASPEED_TIMER,
713 .class_init = aspeed_2400_timer_class_init,
714};
715
716static void aspeed_2500_timer_class_init(ObjectClass *klass, void *data)
717{
718 DeviceClass *dc = DEVICE_CLASS(klass);
719 AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
720
721 dc->desc = "ASPEED 2500 Timer";
722 awc->read = aspeed_2500_timer_read;
723 awc->write = aspeed_2500_timer_write;
724}
725
726static const TypeInfo aspeed_2500_timer_info = {
727 .name = TYPE_ASPEED_2500_TIMER,
728 .parent = TYPE_ASPEED_TIMER,
729 .class_init = aspeed_2500_timer_class_init,
730};
731
732static void aspeed_2600_timer_class_init(ObjectClass *klass, void *data)
733{
734 DeviceClass *dc = DEVICE_CLASS(klass);
735 AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
736
737 dc->desc = "ASPEED 2600 Timer";
738 awc->read = aspeed_2600_timer_read;
739 awc->write = aspeed_2600_timer_write;
740}
741
742static const TypeInfo aspeed_2600_timer_info = {
743 .name = TYPE_ASPEED_2600_TIMER,
744 .parent = TYPE_ASPEED_TIMER,
745 .class_init = aspeed_2600_timer_class_init,
746};
747
748static void aspeed_1030_timer_class_init(ObjectClass *klass, void *data)
749{
750 DeviceClass *dc = DEVICE_CLASS(klass);
751 AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass);
752
753 dc->desc = "ASPEED 1030 Timer";
754 awc->read = aspeed_2600_timer_read;
755 awc->write = aspeed_2600_timer_write;
756}
757
758static const TypeInfo aspeed_1030_timer_info = {
759 .name = TYPE_ASPEED_1030_TIMER,
760 .parent = TYPE_ASPEED_TIMER,
761 .class_init = aspeed_1030_timer_class_init,
762};
763
764static void aspeed_timer_register_types(void)
765{
766 type_register_static(&aspeed_timer_info);
767 type_register_static(&aspeed_2400_timer_info);
768 type_register_static(&aspeed_2500_timer_info);
769 type_register_static(&aspeed_2600_timer_info);
770 type_register_static(&aspeed_1030_timer_info);
771}
772
773type_init(aspeed_timer_register_types)
774