xref: /qemu/hw/intc/aspeed_vic.c (revision 22b31af26ff31ef97a9d482fb5e336d699ae33f3)
10c69996eSAndrew Jeffery /*
20c69996eSAndrew Jeffery  * ASPEED Interrupt Controller (New)
30c69996eSAndrew Jeffery  *
40c69996eSAndrew Jeffery  * Andrew Jeffery <andrew@aj.id.au>
50c69996eSAndrew Jeffery  *
60c69996eSAndrew Jeffery  * Copyright 2015, 2016 IBM Corp.
70c69996eSAndrew Jeffery  *
80c69996eSAndrew Jeffery  * This code is licensed under the GPL version 2 or later.  See
90c69996eSAndrew Jeffery  * the COPYING file in the top-level directory.
100c69996eSAndrew Jeffery  */
110c69996eSAndrew Jeffery 
120c69996eSAndrew Jeffery /* The hardware exposes two register sets, a legacy set and a 'new' set. The
130c69996eSAndrew Jeffery  * model implements the 'new' register set, and logs warnings on accesses to
140c69996eSAndrew Jeffery  * the legacy IO space.
150c69996eSAndrew Jeffery  *
160c69996eSAndrew Jeffery  * The hardware uses 32bit registers to manage 51 IRQs, with low and high
170c69996eSAndrew Jeffery  * registers for each conceptual register. The device model's implementation
180c69996eSAndrew Jeffery  * uses 64bit data types to store both low and high register values (in the one
190c69996eSAndrew Jeffery  * member), but must cope with access offset values in multiples of 4 passed to
200c69996eSAndrew Jeffery  * the callbacks. As such the read() and write() implementations process the
210c69996eSAndrew Jeffery  * provided offset to understand whether the access is requesting the lower or
220c69996eSAndrew Jeffery  * upper 32 bits of the 64bit member.
230c69996eSAndrew Jeffery  *
240c69996eSAndrew Jeffery  * Additionally, the "Interrupt Enable", "Edge Status" and "Software Interrupt"
250c69996eSAndrew Jeffery  * fields have separate "enable"/"status" and "clear" registers, where set bits
260c69996eSAndrew Jeffery  * are written to one or the other to change state (avoiding a
270c69996eSAndrew Jeffery  * read-modify-write sequence).
280c69996eSAndrew Jeffery  */
290c69996eSAndrew Jeffery 
300c69996eSAndrew Jeffery #include "qemu/osdep.h"
310c69996eSAndrew Jeffery #include <inttypes.h>
320c69996eSAndrew Jeffery #include "hw/intc/aspeed_vic.h"
330c69996eSAndrew Jeffery #include "qemu/bitops.h"
34*22b31af2SPaolo Bonzini #include "qemu/log.h"
350c69996eSAndrew Jeffery #include "trace.h"
360c69996eSAndrew Jeffery 
370c69996eSAndrew Jeffery #define AVIC_NEW_BASE_OFFSET 0x80
380c69996eSAndrew Jeffery 
390c69996eSAndrew Jeffery #define AVIC_L_MASK 0xFFFFFFFFU
400c69996eSAndrew Jeffery #define AVIC_H_MASK 0x0007FFFFU
410c69996eSAndrew Jeffery #define AVIC_EVENT_W_MASK (0x78000ULL << 32)
420c69996eSAndrew Jeffery 
430c69996eSAndrew Jeffery static void aspeed_vic_update(AspeedVICState *s)
440c69996eSAndrew Jeffery {
450c69996eSAndrew Jeffery     uint64_t new = (s->raw & s->enable);
460c69996eSAndrew Jeffery     uint64_t flags;
470c69996eSAndrew Jeffery 
480c69996eSAndrew Jeffery     flags = new & s->select;
490c69996eSAndrew Jeffery     trace_aspeed_vic_update_fiq(!!flags);
500c69996eSAndrew Jeffery     qemu_set_irq(s->fiq, !!flags);
510c69996eSAndrew Jeffery 
520c69996eSAndrew Jeffery     flags = new & ~s->select;
530c69996eSAndrew Jeffery     trace_aspeed_vic_update_irq(!!flags);
540c69996eSAndrew Jeffery     qemu_set_irq(s->irq, !!flags);
550c69996eSAndrew Jeffery }
560c69996eSAndrew Jeffery 
570c69996eSAndrew Jeffery static void aspeed_vic_set_irq(void *opaque, int irq, int level)
580c69996eSAndrew Jeffery {
590c69996eSAndrew Jeffery     uint64_t irq_mask;
600c69996eSAndrew Jeffery     bool raise;
610c69996eSAndrew Jeffery     AspeedVICState *s = (AspeedVICState *)opaque;
620c69996eSAndrew Jeffery 
630c69996eSAndrew Jeffery     if (irq > ASPEED_VIC_NR_IRQS) {
640c69996eSAndrew Jeffery         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
650c69996eSAndrew Jeffery                       __func__, irq);
660c69996eSAndrew Jeffery         return;
670c69996eSAndrew Jeffery     }
680c69996eSAndrew Jeffery 
690c69996eSAndrew Jeffery     trace_aspeed_vic_set_irq(irq, level);
700c69996eSAndrew Jeffery 
710c69996eSAndrew Jeffery     irq_mask = BIT(irq);
720c69996eSAndrew Jeffery     if (s->sense & irq_mask) {
730c69996eSAndrew Jeffery         /* level-triggered */
740c69996eSAndrew Jeffery         if (s->event & irq_mask) {
750c69996eSAndrew Jeffery             /* high-sensitive */
760c69996eSAndrew Jeffery             raise = level;
770c69996eSAndrew Jeffery         } else {
780c69996eSAndrew Jeffery             /* low-sensitive */
790c69996eSAndrew Jeffery             raise = !level;
800c69996eSAndrew Jeffery         }
810c69996eSAndrew Jeffery         s->raw = deposit64(s->raw, irq, 1, raise);
820c69996eSAndrew Jeffery     } else {
830c69996eSAndrew Jeffery         uint64_t old_level = s->level & irq_mask;
840c69996eSAndrew Jeffery 
850c69996eSAndrew Jeffery         /* edge-triggered */
860c69996eSAndrew Jeffery         if (s->dual_edge & irq_mask) {
870c69996eSAndrew Jeffery             raise = (!!old_level) != (!!level);
880c69996eSAndrew Jeffery         } else {
890c69996eSAndrew Jeffery             if (s->event & irq_mask) {
900c69996eSAndrew Jeffery                 /* rising-sensitive */
910c69996eSAndrew Jeffery                 raise = !old_level && level;
920c69996eSAndrew Jeffery             } else {
930c69996eSAndrew Jeffery                 /* falling-sensitive */
940c69996eSAndrew Jeffery                 raise = old_level && !level;
950c69996eSAndrew Jeffery             }
960c69996eSAndrew Jeffery         }
970c69996eSAndrew Jeffery         if (raise) {
980c69996eSAndrew Jeffery             s->raw = deposit64(s->raw, irq, 1, raise);
990c69996eSAndrew Jeffery         }
1000c69996eSAndrew Jeffery     }
1010c69996eSAndrew Jeffery     s->level = deposit64(s->level, irq, 1, level);
1020c69996eSAndrew Jeffery     aspeed_vic_update(s);
1030c69996eSAndrew Jeffery }
1040c69996eSAndrew Jeffery 
1050c69996eSAndrew Jeffery static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size)
1060c69996eSAndrew Jeffery {
1070c69996eSAndrew Jeffery     uint64_t val;
1080c69996eSAndrew Jeffery     const bool high = !!(offset & 0x4);
1090c69996eSAndrew Jeffery     hwaddr n_offset = (offset & ~0x4);
1100c69996eSAndrew Jeffery     AspeedVICState *s = (AspeedVICState *)opaque;
1110c69996eSAndrew Jeffery 
1120c69996eSAndrew Jeffery     if (offset < AVIC_NEW_BASE_OFFSET) {
1130c69996eSAndrew Jeffery         qemu_log_mask(LOG_UNIMP, "%s: Ignoring read from legacy registers "
1140c69996eSAndrew Jeffery                       "at 0x%" HWADDR_PRIx "[%u]\n", __func__, offset, size);
1150c69996eSAndrew Jeffery         return 0;
1160c69996eSAndrew Jeffery     }
1170c69996eSAndrew Jeffery 
1180c69996eSAndrew Jeffery     n_offset -= AVIC_NEW_BASE_OFFSET;
1190c69996eSAndrew Jeffery 
1200c69996eSAndrew Jeffery     switch (n_offset) {
1210c69996eSAndrew Jeffery     case 0x0: /* IRQ Status */
1220c69996eSAndrew Jeffery         val = s->raw & ~s->select & s->enable;
1230c69996eSAndrew Jeffery         break;
1240c69996eSAndrew Jeffery     case 0x08: /* FIQ Status */
1250c69996eSAndrew Jeffery         val = s->raw & s->select & s->enable;
1260c69996eSAndrew Jeffery         break;
1270c69996eSAndrew Jeffery     case 0x10: /* Raw Interrupt Status */
1280c69996eSAndrew Jeffery         val = s->raw;
1290c69996eSAndrew Jeffery         break;
1300c69996eSAndrew Jeffery     case 0x18: /* Interrupt Selection */
1310c69996eSAndrew Jeffery         val = s->select;
1320c69996eSAndrew Jeffery         break;
1330c69996eSAndrew Jeffery     case 0x20: /* Interrupt Enable */
1340c69996eSAndrew Jeffery         val = s->enable;
1350c69996eSAndrew Jeffery         break;
1360c69996eSAndrew Jeffery     case 0x30: /* Software Interrupt */
1370c69996eSAndrew Jeffery         val = s->trigger;
1380c69996eSAndrew Jeffery         break;
1390c69996eSAndrew Jeffery     case 0x40: /* Interrupt Sensitivity */
1400c69996eSAndrew Jeffery         val = s->sense;
1410c69996eSAndrew Jeffery         break;
1420c69996eSAndrew Jeffery     case 0x48: /* Interrupt Both Edge Trigger Control */
1430c69996eSAndrew Jeffery         val = s->dual_edge;
1440c69996eSAndrew Jeffery         break;
1450c69996eSAndrew Jeffery     case 0x50: /* Interrupt Event */
1460c69996eSAndrew Jeffery         val = s->event;
1470c69996eSAndrew Jeffery         break;
1480c69996eSAndrew Jeffery     case 0x60: /* Edge Triggered Interrupt Status */
1490c69996eSAndrew Jeffery         val = s->raw & ~s->sense;
1500c69996eSAndrew Jeffery         break;
1510c69996eSAndrew Jeffery         /* Illegal */
1520c69996eSAndrew Jeffery     case 0x28: /* Interrupt Enable Clear */
1530c69996eSAndrew Jeffery     case 0x38: /* Software Interrupt Clear */
1540c69996eSAndrew Jeffery     case 0x58: /* Edge Triggered Interrupt Clear */
1550c69996eSAndrew Jeffery         qemu_log_mask(LOG_GUEST_ERROR,
1560c69996eSAndrew Jeffery                       "%s: Read of write-only register with offset 0x%"
1570c69996eSAndrew Jeffery                       HWADDR_PRIx "\n", __func__, offset);
1580c69996eSAndrew Jeffery         val = 0;
1590c69996eSAndrew Jeffery         break;
1600c69996eSAndrew Jeffery     default:
1610c69996eSAndrew Jeffery         qemu_log_mask(LOG_GUEST_ERROR,
1620c69996eSAndrew Jeffery                       "%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
1630c69996eSAndrew Jeffery                       __func__, offset);
1640c69996eSAndrew Jeffery         val = 0;
1650c69996eSAndrew Jeffery         break;
1660c69996eSAndrew Jeffery     }
1670c69996eSAndrew Jeffery     if (high) {
1680c69996eSAndrew Jeffery         val = extract64(val, 32, 19);
1690c69996eSAndrew Jeffery     }
1700c69996eSAndrew Jeffery     trace_aspeed_vic_read(offset, size, val);
1710c69996eSAndrew Jeffery     return val;
1720c69996eSAndrew Jeffery }
1730c69996eSAndrew Jeffery 
1740c69996eSAndrew Jeffery static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data,
1750c69996eSAndrew Jeffery                              unsigned size)
1760c69996eSAndrew Jeffery {
1770c69996eSAndrew Jeffery     const bool high = !!(offset & 0x4);
1780c69996eSAndrew Jeffery     hwaddr n_offset = (offset & ~0x4);
1790c69996eSAndrew Jeffery     AspeedVICState *s = (AspeedVICState *)opaque;
1800c69996eSAndrew Jeffery 
1810c69996eSAndrew Jeffery     if (offset < AVIC_NEW_BASE_OFFSET) {
1820c69996eSAndrew Jeffery         qemu_log_mask(LOG_UNIMP,
1830c69996eSAndrew Jeffery                       "%s: Ignoring write to legacy registers at 0x%"
1840c69996eSAndrew Jeffery                       HWADDR_PRIx "[%u] <- 0x%" PRIx64 "\n", __func__, offset,
1850c69996eSAndrew Jeffery                       size, data);
1860c69996eSAndrew Jeffery         return;
1870c69996eSAndrew Jeffery     }
1880c69996eSAndrew Jeffery 
1890c69996eSAndrew Jeffery     n_offset -= AVIC_NEW_BASE_OFFSET;
1900c69996eSAndrew Jeffery     trace_aspeed_vic_write(offset, size, data);
1910c69996eSAndrew Jeffery 
1920c69996eSAndrew Jeffery     /* Given we have members using separate enable/clear registers, deposit64()
1930c69996eSAndrew Jeffery      * isn't quite the tool for the job. Instead, relocate the incoming bits to
1940c69996eSAndrew Jeffery      * the required bit offset based on the provided access address
1950c69996eSAndrew Jeffery      */
1960c69996eSAndrew Jeffery     if (high) {
1970c69996eSAndrew Jeffery         data &= AVIC_H_MASK;
1980c69996eSAndrew Jeffery         data <<= 32;
1990c69996eSAndrew Jeffery     } else {
2000c69996eSAndrew Jeffery         data &= AVIC_L_MASK;
2010c69996eSAndrew Jeffery     }
2020c69996eSAndrew Jeffery 
2030c69996eSAndrew Jeffery     switch (n_offset) {
2040c69996eSAndrew Jeffery     case 0x18: /* Interrupt Selection */
2050c69996eSAndrew Jeffery         /* Register has deposit64() semantics - overwrite requested 32 bits */
2060c69996eSAndrew Jeffery         if (high) {
2070c69996eSAndrew Jeffery             s->select &= AVIC_L_MASK;
2080c69996eSAndrew Jeffery         } else {
2090c69996eSAndrew Jeffery             s->select &= ((uint64_t) AVIC_H_MASK) << 32;
2100c69996eSAndrew Jeffery         }
2110c69996eSAndrew Jeffery         s->select |= data;
2120c69996eSAndrew Jeffery         break;
2130c69996eSAndrew Jeffery     case 0x20: /* Interrupt Enable */
2140c69996eSAndrew Jeffery         s->enable |= data;
2150c69996eSAndrew Jeffery         break;
2160c69996eSAndrew Jeffery     case 0x28: /* Interrupt Enable Clear */
2170c69996eSAndrew Jeffery         s->enable &= ~data;
2180c69996eSAndrew Jeffery         break;
2190c69996eSAndrew Jeffery     case 0x30: /* Software Interrupt */
2200c69996eSAndrew Jeffery         qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
2210c69996eSAndrew Jeffery                       "IRQs requested: 0x%016" PRIx64 "\n", __func__, data);
2220c69996eSAndrew Jeffery         break;
2230c69996eSAndrew Jeffery     case 0x38: /* Software Interrupt Clear */
2240c69996eSAndrew Jeffery         qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. "
2250c69996eSAndrew Jeffery                       "IRQs to be cleared: 0x%016" PRIx64 "\n", __func__, data);
2260c69996eSAndrew Jeffery         break;
2270c69996eSAndrew Jeffery     case 0x50: /* Interrupt Event */
2280c69996eSAndrew Jeffery         /* Register has deposit64() semantics - overwrite the top four valid
2290c69996eSAndrew Jeffery          * IRQ bits, as only the top four IRQs (GPIOs) can change their event
2300c69996eSAndrew Jeffery          * type */
2310c69996eSAndrew Jeffery         if (high) {
2320c69996eSAndrew Jeffery             s->event &= ~AVIC_EVENT_W_MASK;
2330c69996eSAndrew Jeffery             s->event |= (data & AVIC_EVENT_W_MASK);
2340c69996eSAndrew Jeffery         } else {
2350c69996eSAndrew Jeffery             qemu_log_mask(LOG_GUEST_ERROR,
2360c69996eSAndrew Jeffery                           "Ignoring invalid write to interrupt event register");
2370c69996eSAndrew Jeffery         }
2380c69996eSAndrew Jeffery         break;
2390c69996eSAndrew Jeffery     case 0x58: /* Edge Triggered Interrupt Clear */
2400c69996eSAndrew Jeffery         s->raw &= ~(data & ~s->sense);
2410c69996eSAndrew Jeffery         break;
2420c69996eSAndrew Jeffery     case 0x00: /* IRQ Status */
2430c69996eSAndrew Jeffery     case 0x08: /* FIQ Status */
2440c69996eSAndrew Jeffery     case 0x10: /* Raw Interrupt Status */
2450c69996eSAndrew Jeffery     case 0x40: /* Interrupt Sensitivity */
2460c69996eSAndrew Jeffery     case 0x48: /* Interrupt Both Edge Trigger Control */
2470c69996eSAndrew Jeffery     case 0x60: /* Edge Triggered Interrupt Status */
2480c69996eSAndrew Jeffery         qemu_log_mask(LOG_GUEST_ERROR,
2490c69996eSAndrew Jeffery                       "%s: Write of read-only register with offset 0x%"
2500c69996eSAndrew Jeffery                       HWADDR_PRIx "\n", __func__, offset);
2510c69996eSAndrew Jeffery         break;
2520c69996eSAndrew Jeffery 
2530c69996eSAndrew Jeffery     default:
2540c69996eSAndrew Jeffery         qemu_log_mask(LOG_GUEST_ERROR,
2550c69996eSAndrew Jeffery                       "%s: Bad register at offset 0x%" HWADDR_PRIx "\n",
2560c69996eSAndrew Jeffery                       __func__, offset);
2570c69996eSAndrew Jeffery         break;
2580c69996eSAndrew Jeffery     }
2590c69996eSAndrew Jeffery     aspeed_vic_update(s);
2600c69996eSAndrew Jeffery }
2610c69996eSAndrew Jeffery 
2620c69996eSAndrew Jeffery static const MemoryRegionOps aspeed_vic_ops = {
2630c69996eSAndrew Jeffery     .read = aspeed_vic_read,
2640c69996eSAndrew Jeffery     .write = aspeed_vic_write,
2650c69996eSAndrew Jeffery     .endianness = DEVICE_LITTLE_ENDIAN,
2660c69996eSAndrew Jeffery     .valid.min_access_size = 4,
2670c69996eSAndrew Jeffery     .valid.max_access_size = 4,
2680c69996eSAndrew Jeffery     .valid.unaligned = false,
2690c69996eSAndrew Jeffery };
2700c69996eSAndrew Jeffery 
2710c69996eSAndrew Jeffery static void aspeed_vic_reset(DeviceState *dev)
2720c69996eSAndrew Jeffery {
2730c69996eSAndrew Jeffery     AspeedVICState *s = ASPEED_VIC(dev);
2740c69996eSAndrew Jeffery 
2750c69996eSAndrew Jeffery     s->level = 0;
2760c69996eSAndrew Jeffery     s->raw = 0;
2770c69996eSAndrew Jeffery     s->select = 0;
2780c69996eSAndrew Jeffery     s->enable = 0;
2790c69996eSAndrew Jeffery     s->trigger = 0;
2800c69996eSAndrew Jeffery     s->sense = 0x1F07FFF8FFFFULL;
2810c69996eSAndrew Jeffery     s->dual_edge = 0xF800070000ULL;
2820c69996eSAndrew Jeffery     s->event = 0x5F07FFF8FFFFULL;
2830c69996eSAndrew Jeffery }
2840c69996eSAndrew Jeffery 
2850c69996eSAndrew Jeffery #define AVIC_IO_REGION_SIZE 0x20000
2860c69996eSAndrew Jeffery 
2870c69996eSAndrew Jeffery static void aspeed_vic_realize(DeviceState *dev, Error **errp)
2880c69996eSAndrew Jeffery {
2890c69996eSAndrew Jeffery     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
2900c69996eSAndrew Jeffery     AspeedVICState *s = ASPEED_VIC(dev);
2910c69996eSAndrew Jeffery 
2920c69996eSAndrew Jeffery     memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_vic_ops, s,
2930c69996eSAndrew Jeffery                           TYPE_ASPEED_VIC, AVIC_IO_REGION_SIZE);
2940c69996eSAndrew Jeffery 
2950c69996eSAndrew Jeffery     sysbus_init_mmio(sbd, &s->iomem);
2960c69996eSAndrew Jeffery 
2970c69996eSAndrew Jeffery     qdev_init_gpio_in(dev, aspeed_vic_set_irq, ASPEED_VIC_NR_IRQS);
2980c69996eSAndrew Jeffery     sysbus_init_irq(sbd, &s->irq);
2990c69996eSAndrew Jeffery     sysbus_init_irq(sbd, &s->fiq);
3000c69996eSAndrew Jeffery }
3010c69996eSAndrew Jeffery 
3020c69996eSAndrew Jeffery static const VMStateDescription vmstate_aspeed_vic = {
3030c69996eSAndrew Jeffery     .name = "aspeed.new-vic",
3040c69996eSAndrew Jeffery     .version_id = 1,
3050c69996eSAndrew Jeffery     .minimum_version_id = 1,
3060c69996eSAndrew Jeffery     .fields = (VMStateField[]) {
3070c69996eSAndrew Jeffery         VMSTATE_UINT64(level, AspeedVICState),
3080c69996eSAndrew Jeffery         VMSTATE_UINT64(raw, AspeedVICState),
3090c69996eSAndrew Jeffery         VMSTATE_UINT64(select, AspeedVICState),
3100c69996eSAndrew Jeffery         VMSTATE_UINT64(enable, AspeedVICState),
3110c69996eSAndrew Jeffery         VMSTATE_UINT64(trigger, AspeedVICState),
3120c69996eSAndrew Jeffery         VMSTATE_UINT64(sense, AspeedVICState),
3130c69996eSAndrew Jeffery         VMSTATE_UINT64(dual_edge, AspeedVICState),
3140c69996eSAndrew Jeffery         VMSTATE_UINT64(event, AspeedVICState),
3150c69996eSAndrew Jeffery         VMSTATE_END_OF_LIST()
3160c69996eSAndrew Jeffery     }
3170c69996eSAndrew Jeffery };
3180c69996eSAndrew Jeffery 
3190c69996eSAndrew Jeffery static void aspeed_vic_class_init(ObjectClass *klass, void *data)
3200c69996eSAndrew Jeffery {
3210c69996eSAndrew Jeffery     DeviceClass *dc = DEVICE_CLASS(klass);
3220c69996eSAndrew Jeffery     dc->realize = aspeed_vic_realize;
3230c69996eSAndrew Jeffery     dc->reset = aspeed_vic_reset;
3240c69996eSAndrew Jeffery     dc->desc = "ASPEED Interrupt Controller (New)";
3250c69996eSAndrew Jeffery     dc->vmsd = &vmstate_aspeed_vic;
3260c69996eSAndrew Jeffery }
3270c69996eSAndrew Jeffery 
3280c69996eSAndrew Jeffery static const TypeInfo aspeed_vic_info = {
3290c69996eSAndrew Jeffery     .name = TYPE_ASPEED_VIC,
3300c69996eSAndrew Jeffery     .parent = TYPE_SYS_BUS_DEVICE,
3310c69996eSAndrew Jeffery     .instance_size = sizeof(AspeedVICState),
3320c69996eSAndrew Jeffery     .class_init = aspeed_vic_class_init,
3330c69996eSAndrew Jeffery };
3340c69996eSAndrew Jeffery 
3350c69996eSAndrew Jeffery static void aspeed_vic_register_types(void)
3360c69996eSAndrew Jeffery {
3370c69996eSAndrew Jeffery     type_register_static(&aspeed_vic_info);
3380c69996eSAndrew Jeffery }
3390c69996eSAndrew Jeffery 
3400c69996eSAndrew Jeffery type_init(aspeed_vic_register_types);
341