1*0c69996eSAndrew Jeffery /* 2*0c69996eSAndrew Jeffery * ASPEED Interrupt Controller (New) 3*0c69996eSAndrew Jeffery * 4*0c69996eSAndrew Jeffery * Andrew Jeffery <andrew@aj.id.au> 5*0c69996eSAndrew Jeffery * 6*0c69996eSAndrew Jeffery * Copyright 2015, 2016 IBM Corp. 7*0c69996eSAndrew Jeffery * 8*0c69996eSAndrew Jeffery * This code is licensed under the GPL version 2 or later. See 9*0c69996eSAndrew Jeffery * the COPYING file in the top-level directory. 10*0c69996eSAndrew Jeffery */ 11*0c69996eSAndrew Jeffery 12*0c69996eSAndrew Jeffery /* The hardware exposes two register sets, a legacy set and a 'new' set. The 13*0c69996eSAndrew Jeffery * model implements the 'new' register set, and logs warnings on accesses to 14*0c69996eSAndrew Jeffery * the legacy IO space. 15*0c69996eSAndrew Jeffery * 16*0c69996eSAndrew Jeffery * The hardware uses 32bit registers to manage 51 IRQs, with low and high 17*0c69996eSAndrew Jeffery * registers for each conceptual register. The device model's implementation 18*0c69996eSAndrew Jeffery * uses 64bit data types to store both low and high register values (in the one 19*0c69996eSAndrew Jeffery * member), but must cope with access offset values in multiples of 4 passed to 20*0c69996eSAndrew Jeffery * the callbacks. As such the read() and write() implementations process the 21*0c69996eSAndrew Jeffery * provided offset to understand whether the access is requesting the lower or 22*0c69996eSAndrew Jeffery * upper 32 bits of the 64bit member. 23*0c69996eSAndrew Jeffery * 24*0c69996eSAndrew Jeffery * Additionally, the "Interrupt Enable", "Edge Status" and "Software Interrupt" 25*0c69996eSAndrew Jeffery * fields have separate "enable"/"status" and "clear" registers, where set bits 26*0c69996eSAndrew Jeffery * are written to one or the other to change state (avoiding a 27*0c69996eSAndrew Jeffery * read-modify-write sequence). 28*0c69996eSAndrew Jeffery */ 29*0c69996eSAndrew Jeffery 30*0c69996eSAndrew Jeffery #include "qemu/osdep.h" 31*0c69996eSAndrew Jeffery #include <inttypes.h> 32*0c69996eSAndrew Jeffery #include "hw/intc/aspeed_vic.h" 33*0c69996eSAndrew Jeffery #include "qemu/bitops.h" 34*0c69996eSAndrew Jeffery #include "trace.h" 35*0c69996eSAndrew Jeffery 36*0c69996eSAndrew Jeffery #define AVIC_NEW_BASE_OFFSET 0x80 37*0c69996eSAndrew Jeffery 38*0c69996eSAndrew Jeffery #define AVIC_L_MASK 0xFFFFFFFFU 39*0c69996eSAndrew Jeffery #define AVIC_H_MASK 0x0007FFFFU 40*0c69996eSAndrew Jeffery #define AVIC_EVENT_W_MASK (0x78000ULL << 32) 41*0c69996eSAndrew Jeffery 42*0c69996eSAndrew Jeffery static void aspeed_vic_update(AspeedVICState *s) 43*0c69996eSAndrew Jeffery { 44*0c69996eSAndrew Jeffery uint64_t new = (s->raw & s->enable); 45*0c69996eSAndrew Jeffery uint64_t flags; 46*0c69996eSAndrew Jeffery 47*0c69996eSAndrew Jeffery flags = new & s->select; 48*0c69996eSAndrew Jeffery trace_aspeed_vic_update_fiq(!!flags); 49*0c69996eSAndrew Jeffery qemu_set_irq(s->fiq, !!flags); 50*0c69996eSAndrew Jeffery 51*0c69996eSAndrew Jeffery flags = new & ~s->select; 52*0c69996eSAndrew Jeffery trace_aspeed_vic_update_irq(!!flags); 53*0c69996eSAndrew Jeffery qemu_set_irq(s->irq, !!flags); 54*0c69996eSAndrew Jeffery } 55*0c69996eSAndrew Jeffery 56*0c69996eSAndrew Jeffery static void aspeed_vic_set_irq(void *opaque, int irq, int level) 57*0c69996eSAndrew Jeffery { 58*0c69996eSAndrew Jeffery uint64_t irq_mask; 59*0c69996eSAndrew Jeffery bool raise; 60*0c69996eSAndrew Jeffery AspeedVICState *s = (AspeedVICState *)opaque; 61*0c69996eSAndrew Jeffery 62*0c69996eSAndrew Jeffery if (irq > ASPEED_VIC_NR_IRQS) { 63*0c69996eSAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n", 64*0c69996eSAndrew Jeffery __func__, irq); 65*0c69996eSAndrew Jeffery return; 66*0c69996eSAndrew Jeffery } 67*0c69996eSAndrew Jeffery 68*0c69996eSAndrew Jeffery trace_aspeed_vic_set_irq(irq, level); 69*0c69996eSAndrew Jeffery 70*0c69996eSAndrew Jeffery irq_mask = BIT(irq); 71*0c69996eSAndrew Jeffery if (s->sense & irq_mask) { 72*0c69996eSAndrew Jeffery /* level-triggered */ 73*0c69996eSAndrew Jeffery if (s->event & irq_mask) { 74*0c69996eSAndrew Jeffery /* high-sensitive */ 75*0c69996eSAndrew Jeffery raise = level; 76*0c69996eSAndrew Jeffery } else { 77*0c69996eSAndrew Jeffery /* low-sensitive */ 78*0c69996eSAndrew Jeffery raise = !level; 79*0c69996eSAndrew Jeffery } 80*0c69996eSAndrew Jeffery s->raw = deposit64(s->raw, irq, 1, raise); 81*0c69996eSAndrew Jeffery } else { 82*0c69996eSAndrew Jeffery uint64_t old_level = s->level & irq_mask; 83*0c69996eSAndrew Jeffery 84*0c69996eSAndrew Jeffery /* edge-triggered */ 85*0c69996eSAndrew Jeffery if (s->dual_edge & irq_mask) { 86*0c69996eSAndrew Jeffery raise = (!!old_level) != (!!level); 87*0c69996eSAndrew Jeffery } else { 88*0c69996eSAndrew Jeffery if (s->event & irq_mask) { 89*0c69996eSAndrew Jeffery /* rising-sensitive */ 90*0c69996eSAndrew Jeffery raise = !old_level && level; 91*0c69996eSAndrew Jeffery } else { 92*0c69996eSAndrew Jeffery /* falling-sensitive */ 93*0c69996eSAndrew Jeffery raise = old_level && !level; 94*0c69996eSAndrew Jeffery } 95*0c69996eSAndrew Jeffery } 96*0c69996eSAndrew Jeffery if (raise) { 97*0c69996eSAndrew Jeffery s->raw = deposit64(s->raw, irq, 1, raise); 98*0c69996eSAndrew Jeffery } 99*0c69996eSAndrew Jeffery } 100*0c69996eSAndrew Jeffery s->level = deposit64(s->level, irq, 1, level); 101*0c69996eSAndrew Jeffery aspeed_vic_update(s); 102*0c69996eSAndrew Jeffery } 103*0c69996eSAndrew Jeffery 104*0c69996eSAndrew Jeffery static uint64_t aspeed_vic_read(void *opaque, hwaddr offset, unsigned size) 105*0c69996eSAndrew Jeffery { 106*0c69996eSAndrew Jeffery uint64_t val; 107*0c69996eSAndrew Jeffery const bool high = !!(offset & 0x4); 108*0c69996eSAndrew Jeffery hwaddr n_offset = (offset & ~0x4); 109*0c69996eSAndrew Jeffery AspeedVICState *s = (AspeedVICState *)opaque; 110*0c69996eSAndrew Jeffery 111*0c69996eSAndrew Jeffery if (offset < AVIC_NEW_BASE_OFFSET) { 112*0c69996eSAndrew Jeffery qemu_log_mask(LOG_UNIMP, "%s: Ignoring read from legacy registers " 113*0c69996eSAndrew Jeffery "at 0x%" HWADDR_PRIx "[%u]\n", __func__, offset, size); 114*0c69996eSAndrew Jeffery return 0; 115*0c69996eSAndrew Jeffery } 116*0c69996eSAndrew Jeffery 117*0c69996eSAndrew Jeffery n_offset -= AVIC_NEW_BASE_OFFSET; 118*0c69996eSAndrew Jeffery 119*0c69996eSAndrew Jeffery switch (n_offset) { 120*0c69996eSAndrew Jeffery case 0x0: /* IRQ Status */ 121*0c69996eSAndrew Jeffery val = s->raw & ~s->select & s->enable; 122*0c69996eSAndrew Jeffery break; 123*0c69996eSAndrew Jeffery case 0x08: /* FIQ Status */ 124*0c69996eSAndrew Jeffery val = s->raw & s->select & s->enable; 125*0c69996eSAndrew Jeffery break; 126*0c69996eSAndrew Jeffery case 0x10: /* Raw Interrupt Status */ 127*0c69996eSAndrew Jeffery val = s->raw; 128*0c69996eSAndrew Jeffery break; 129*0c69996eSAndrew Jeffery case 0x18: /* Interrupt Selection */ 130*0c69996eSAndrew Jeffery val = s->select; 131*0c69996eSAndrew Jeffery break; 132*0c69996eSAndrew Jeffery case 0x20: /* Interrupt Enable */ 133*0c69996eSAndrew Jeffery val = s->enable; 134*0c69996eSAndrew Jeffery break; 135*0c69996eSAndrew Jeffery case 0x30: /* Software Interrupt */ 136*0c69996eSAndrew Jeffery val = s->trigger; 137*0c69996eSAndrew Jeffery break; 138*0c69996eSAndrew Jeffery case 0x40: /* Interrupt Sensitivity */ 139*0c69996eSAndrew Jeffery val = s->sense; 140*0c69996eSAndrew Jeffery break; 141*0c69996eSAndrew Jeffery case 0x48: /* Interrupt Both Edge Trigger Control */ 142*0c69996eSAndrew Jeffery val = s->dual_edge; 143*0c69996eSAndrew Jeffery break; 144*0c69996eSAndrew Jeffery case 0x50: /* Interrupt Event */ 145*0c69996eSAndrew Jeffery val = s->event; 146*0c69996eSAndrew Jeffery break; 147*0c69996eSAndrew Jeffery case 0x60: /* Edge Triggered Interrupt Status */ 148*0c69996eSAndrew Jeffery val = s->raw & ~s->sense; 149*0c69996eSAndrew Jeffery break; 150*0c69996eSAndrew Jeffery /* Illegal */ 151*0c69996eSAndrew Jeffery case 0x28: /* Interrupt Enable Clear */ 152*0c69996eSAndrew Jeffery case 0x38: /* Software Interrupt Clear */ 153*0c69996eSAndrew Jeffery case 0x58: /* Edge Triggered Interrupt Clear */ 154*0c69996eSAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 155*0c69996eSAndrew Jeffery "%s: Read of write-only register with offset 0x%" 156*0c69996eSAndrew Jeffery HWADDR_PRIx "\n", __func__, offset); 157*0c69996eSAndrew Jeffery val = 0; 158*0c69996eSAndrew Jeffery break; 159*0c69996eSAndrew Jeffery default: 160*0c69996eSAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 161*0c69996eSAndrew Jeffery "%s: Bad register at offset 0x%" HWADDR_PRIx "\n", 162*0c69996eSAndrew Jeffery __func__, offset); 163*0c69996eSAndrew Jeffery val = 0; 164*0c69996eSAndrew Jeffery break; 165*0c69996eSAndrew Jeffery } 166*0c69996eSAndrew Jeffery if (high) { 167*0c69996eSAndrew Jeffery val = extract64(val, 32, 19); 168*0c69996eSAndrew Jeffery } 169*0c69996eSAndrew Jeffery trace_aspeed_vic_read(offset, size, val); 170*0c69996eSAndrew Jeffery return val; 171*0c69996eSAndrew Jeffery } 172*0c69996eSAndrew Jeffery 173*0c69996eSAndrew Jeffery static void aspeed_vic_write(void *opaque, hwaddr offset, uint64_t data, 174*0c69996eSAndrew Jeffery unsigned size) 175*0c69996eSAndrew Jeffery { 176*0c69996eSAndrew Jeffery const bool high = !!(offset & 0x4); 177*0c69996eSAndrew Jeffery hwaddr n_offset = (offset & ~0x4); 178*0c69996eSAndrew Jeffery AspeedVICState *s = (AspeedVICState *)opaque; 179*0c69996eSAndrew Jeffery 180*0c69996eSAndrew Jeffery if (offset < AVIC_NEW_BASE_OFFSET) { 181*0c69996eSAndrew Jeffery qemu_log_mask(LOG_UNIMP, 182*0c69996eSAndrew Jeffery "%s: Ignoring write to legacy registers at 0x%" 183*0c69996eSAndrew Jeffery HWADDR_PRIx "[%u] <- 0x%" PRIx64 "\n", __func__, offset, 184*0c69996eSAndrew Jeffery size, data); 185*0c69996eSAndrew Jeffery return; 186*0c69996eSAndrew Jeffery } 187*0c69996eSAndrew Jeffery 188*0c69996eSAndrew Jeffery n_offset -= AVIC_NEW_BASE_OFFSET; 189*0c69996eSAndrew Jeffery trace_aspeed_vic_write(offset, size, data); 190*0c69996eSAndrew Jeffery 191*0c69996eSAndrew Jeffery /* Given we have members using separate enable/clear registers, deposit64() 192*0c69996eSAndrew Jeffery * isn't quite the tool for the job. Instead, relocate the incoming bits to 193*0c69996eSAndrew Jeffery * the required bit offset based on the provided access address 194*0c69996eSAndrew Jeffery */ 195*0c69996eSAndrew Jeffery if (high) { 196*0c69996eSAndrew Jeffery data &= AVIC_H_MASK; 197*0c69996eSAndrew Jeffery data <<= 32; 198*0c69996eSAndrew Jeffery } else { 199*0c69996eSAndrew Jeffery data &= AVIC_L_MASK; 200*0c69996eSAndrew Jeffery } 201*0c69996eSAndrew Jeffery 202*0c69996eSAndrew Jeffery switch (n_offset) { 203*0c69996eSAndrew Jeffery case 0x18: /* Interrupt Selection */ 204*0c69996eSAndrew Jeffery /* Register has deposit64() semantics - overwrite requested 32 bits */ 205*0c69996eSAndrew Jeffery if (high) { 206*0c69996eSAndrew Jeffery s->select &= AVIC_L_MASK; 207*0c69996eSAndrew Jeffery } else { 208*0c69996eSAndrew Jeffery s->select &= ((uint64_t) AVIC_H_MASK) << 32; 209*0c69996eSAndrew Jeffery } 210*0c69996eSAndrew Jeffery s->select |= data; 211*0c69996eSAndrew Jeffery break; 212*0c69996eSAndrew Jeffery case 0x20: /* Interrupt Enable */ 213*0c69996eSAndrew Jeffery s->enable |= data; 214*0c69996eSAndrew Jeffery break; 215*0c69996eSAndrew Jeffery case 0x28: /* Interrupt Enable Clear */ 216*0c69996eSAndrew Jeffery s->enable &= ~data; 217*0c69996eSAndrew Jeffery break; 218*0c69996eSAndrew Jeffery case 0x30: /* Software Interrupt */ 219*0c69996eSAndrew Jeffery qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. " 220*0c69996eSAndrew Jeffery "IRQs requested: 0x%016" PRIx64 "\n", __func__, data); 221*0c69996eSAndrew Jeffery break; 222*0c69996eSAndrew Jeffery case 0x38: /* Software Interrupt Clear */ 223*0c69996eSAndrew Jeffery qemu_log_mask(LOG_UNIMP, "%s: Software interrupts unavailable. " 224*0c69996eSAndrew Jeffery "IRQs to be cleared: 0x%016" PRIx64 "\n", __func__, data); 225*0c69996eSAndrew Jeffery break; 226*0c69996eSAndrew Jeffery case 0x50: /* Interrupt Event */ 227*0c69996eSAndrew Jeffery /* Register has deposit64() semantics - overwrite the top four valid 228*0c69996eSAndrew Jeffery * IRQ bits, as only the top four IRQs (GPIOs) can change their event 229*0c69996eSAndrew Jeffery * type */ 230*0c69996eSAndrew Jeffery if (high) { 231*0c69996eSAndrew Jeffery s->event &= ~AVIC_EVENT_W_MASK; 232*0c69996eSAndrew Jeffery s->event |= (data & AVIC_EVENT_W_MASK); 233*0c69996eSAndrew Jeffery } else { 234*0c69996eSAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 235*0c69996eSAndrew Jeffery "Ignoring invalid write to interrupt event register"); 236*0c69996eSAndrew Jeffery } 237*0c69996eSAndrew Jeffery break; 238*0c69996eSAndrew Jeffery case 0x58: /* Edge Triggered Interrupt Clear */ 239*0c69996eSAndrew Jeffery s->raw &= ~(data & ~s->sense); 240*0c69996eSAndrew Jeffery break; 241*0c69996eSAndrew Jeffery case 0x00: /* IRQ Status */ 242*0c69996eSAndrew Jeffery case 0x08: /* FIQ Status */ 243*0c69996eSAndrew Jeffery case 0x10: /* Raw Interrupt Status */ 244*0c69996eSAndrew Jeffery case 0x40: /* Interrupt Sensitivity */ 245*0c69996eSAndrew Jeffery case 0x48: /* Interrupt Both Edge Trigger Control */ 246*0c69996eSAndrew Jeffery case 0x60: /* Edge Triggered Interrupt Status */ 247*0c69996eSAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 248*0c69996eSAndrew Jeffery "%s: Write of read-only register with offset 0x%" 249*0c69996eSAndrew Jeffery HWADDR_PRIx "\n", __func__, offset); 250*0c69996eSAndrew Jeffery break; 251*0c69996eSAndrew Jeffery 252*0c69996eSAndrew Jeffery default: 253*0c69996eSAndrew Jeffery qemu_log_mask(LOG_GUEST_ERROR, 254*0c69996eSAndrew Jeffery "%s: Bad register at offset 0x%" HWADDR_PRIx "\n", 255*0c69996eSAndrew Jeffery __func__, offset); 256*0c69996eSAndrew Jeffery break; 257*0c69996eSAndrew Jeffery } 258*0c69996eSAndrew Jeffery aspeed_vic_update(s); 259*0c69996eSAndrew Jeffery } 260*0c69996eSAndrew Jeffery 261*0c69996eSAndrew Jeffery static const MemoryRegionOps aspeed_vic_ops = { 262*0c69996eSAndrew Jeffery .read = aspeed_vic_read, 263*0c69996eSAndrew Jeffery .write = aspeed_vic_write, 264*0c69996eSAndrew Jeffery .endianness = DEVICE_LITTLE_ENDIAN, 265*0c69996eSAndrew Jeffery .valid.min_access_size = 4, 266*0c69996eSAndrew Jeffery .valid.max_access_size = 4, 267*0c69996eSAndrew Jeffery .valid.unaligned = false, 268*0c69996eSAndrew Jeffery }; 269*0c69996eSAndrew Jeffery 270*0c69996eSAndrew Jeffery static void aspeed_vic_reset(DeviceState *dev) 271*0c69996eSAndrew Jeffery { 272*0c69996eSAndrew Jeffery AspeedVICState *s = ASPEED_VIC(dev); 273*0c69996eSAndrew Jeffery 274*0c69996eSAndrew Jeffery s->level = 0; 275*0c69996eSAndrew Jeffery s->raw = 0; 276*0c69996eSAndrew Jeffery s->select = 0; 277*0c69996eSAndrew Jeffery s->enable = 0; 278*0c69996eSAndrew Jeffery s->trigger = 0; 279*0c69996eSAndrew Jeffery s->sense = 0x1F07FFF8FFFFULL; 280*0c69996eSAndrew Jeffery s->dual_edge = 0xF800070000ULL; 281*0c69996eSAndrew Jeffery s->event = 0x5F07FFF8FFFFULL; 282*0c69996eSAndrew Jeffery } 283*0c69996eSAndrew Jeffery 284*0c69996eSAndrew Jeffery #define AVIC_IO_REGION_SIZE 0x20000 285*0c69996eSAndrew Jeffery 286*0c69996eSAndrew Jeffery static void aspeed_vic_realize(DeviceState *dev, Error **errp) 287*0c69996eSAndrew Jeffery { 288*0c69996eSAndrew Jeffery SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 289*0c69996eSAndrew Jeffery AspeedVICState *s = ASPEED_VIC(dev); 290*0c69996eSAndrew Jeffery 291*0c69996eSAndrew Jeffery memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_vic_ops, s, 292*0c69996eSAndrew Jeffery TYPE_ASPEED_VIC, AVIC_IO_REGION_SIZE); 293*0c69996eSAndrew Jeffery 294*0c69996eSAndrew Jeffery sysbus_init_mmio(sbd, &s->iomem); 295*0c69996eSAndrew Jeffery 296*0c69996eSAndrew Jeffery qdev_init_gpio_in(dev, aspeed_vic_set_irq, ASPEED_VIC_NR_IRQS); 297*0c69996eSAndrew Jeffery sysbus_init_irq(sbd, &s->irq); 298*0c69996eSAndrew Jeffery sysbus_init_irq(sbd, &s->fiq); 299*0c69996eSAndrew Jeffery } 300*0c69996eSAndrew Jeffery 301*0c69996eSAndrew Jeffery static const VMStateDescription vmstate_aspeed_vic = { 302*0c69996eSAndrew Jeffery .name = "aspeed.new-vic", 303*0c69996eSAndrew Jeffery .version_id = 1, 304*0c69996eSAndrew Jeffery .minimum_version_id = 1, 305*0c69996eSAndrew Jeffery .fields = (VMStateField[]) { 306*0c69996eSAndrew Jeffery VMSTATE_UINT64(level, AspeedVICState), 307*0c69996eSAndrew Jeffery VMSTATE_UINT64(raw, AspeedVICState), 308*0c69996eSAndrew Jeffery VMSTATE_UINT64(select, AspeedVICState), 309*0c69996eSAndrew Jeffery VMSTATE_UINT64(enable, AspeedVICState), 310*0c69996eSAndrew Jeffery VMSTATE_UINT64(trigger, AspeedVICState), 311*0c69996eSAndrew Jeffery VMSTATE_UINT64(sense, AspeedVICState), 312*0c69996eSAndrew Jeffery VMSTATE_UINT64(dual_edge, AspeedVICState), 313*0c69996eSAndrew Jeffery VMSTATE_UINT64(event, AspeedVICState), 314*0c69996eSAndrew Jeffery VMSTATE_END_OF_LIST() 315*0c69996eSAndrew Jeffery } 316*0c69996eSAndrew Jeffery }; 317*0c69996eSAndrew Jeffery 318*0c69996eSAndrew Jeffery static void aspeed_vic_class_init(ObjectClass *klass, void *data) 319*0c69996eSAndrew Jeffery { 320*0c69996eSAndrew Jeffery DeviceClass *dc = DEVICE_CLASS(klass); 321*0c69996eSAndrew Jeffery dc->realize = aspeed_vic_realize; 322*0c69996eSAndrew Jeffery dc->reset = aspeed_vic_reset; 323*0c69996eSAndrew Jeffery dc->desc = "ASPEED Interrupt Controller (New)"; 324*0c69996eSAndrew Jeffery dc->vmsd = &vmstate_aspeed_vic; 325*0c69996eSAndrew Jeffery } 326*0c69996eSAndrew Jeffery 327*0c69996eSAndrew Jeffery static const TypeInfo aspeed_vic_info = { 328*0c69996eSAndrew Jeffery .name = TYPE_ASPEED_VIC, 329*0c69996eSAndrew Jeffery .parent = TYPE_SYS_BUS_DEVICE, 330*0c69996eSAndrew Jeffery .instance_size = sizeof(AspeedVICState), 331*0c69996eSAndrew Jeffery .class_init = aspeed_vic_class_init, 332*0c69996eSAndrew Jeffery }; 333*0c69996eSAndrew Jeffery 334*0c69996eSAndrew Jeffery static void aspeed_vic_register_types(void) 335*0c69996eSAndrew Jeffery { 336*0c69996eSAndrew Jeffery type_register_static(&aspeed_vic_info); 337*0c69996eSAndrew Jeffery } 338*0c69996eSAndrew Jeffery 339*0c69996eSAndrew Jeffery type_init(aspeed_vic_register_types); 340