xref: /openbmc/qemu/hw/intc/aspeed_intc.c (revision d831c5fd)
1*d831c5fdSJamin Lin /*
2*d831c5fdSJamin Lin  * ASPEED INTC Controller
3*d831c5fdSJamin Lin  *
4*d831c5fdSJamin Lin  * Copyright (C) 2024 ASPEED Technology Inc.
5*d831c5fdSJamin Lin  *
6*d831c5fdSJamin Lin  * SPDX-License-Identifier: GPL-2.0-or-later
7*d831c5fdSJamin Lin  */
8*d831c5fdSJamin Lin 
9*d831c5fdSJamin Lin #include "qemu/osdep.h"
10*d831c5fdSJamin Lin #include "hw/intc/aspeed_intc.h"
11*d831c5fdSJamin Lin #include "hw/irq.h"
12*d831c5fdSJamin Lin #include "qemu/log.h"
13*d831c5fdSJamin Lin #include "trace.h"
14*d831c5fdSJamin Lin #include "hw/registerfields.h"
15*d831c5fdSJamin Lin #include "qapi/error.h"
16*d831c5fdSJamin Lin 
17*d831c5fdSJamin Lin /* INTC Registers */
18*d831c5fdSJamin Lin REG32(GICINT128_EN,         0x1000)
19*d831c5fdSJamin Lin REG32(GICINT128_STATUS,     0x1004)
20*d831c5fdSJamin Lin REG32(GICINT129_EN,         0x1100)
21*d831c5fdSJamin Lin REG32(GICINT129_STATUS,     0x1104)
22*d831c5fdSJamin Lin REG32(GICINT130_EN,         0x1200)
23*d831c5fdSJamin Lin REG32(GICINT130_STATUS,     0x1204)
24*d831c5fdSJamin Lin REG32(GICINT131_EN,         0x1300)
25*d831c5fdSJamin Lin REG32(GICINT131_STATUS,     0x1304)
26*d831c5fdSJamin Lin REG32(GICINT132_EN,         0x1400)
27*d831c5fdSJamin Lin REG32(GICINT132_STATUS,     0x1404)
28*d831c5fdSJamin Lin REG32(GICINT133_EN,         0x1500)
29*d831c5fdSJamin Lin REG32(GICINT133_STATUS,     0x1504)
30*d831c5fdSJamin Lin REG32(GICINT134_EN,         0x1600)
31*d831c5fdSJamin Lin REG32(GICINT134_STATUS,     0x1604)
32*d831c5fdSJamin Lin REG32(GICINT135_EN,         0x1700)
33*d831c5fdSJamin Lin REG32(GICINT135_STATUS,     0x1704)
34*d831c5fdSJamin Lin REG32(GICINT136_EN,         0x1800)
35*d831c5fdSJamin Lin REG32(GICINT136_STATUS,     0x1804)
36*d831c5fdSJamin Lin 
37*d831c5fdSJamin Lin #define GICINT_STATUS_BASE     R_GICINT128_STATUS
38*d831c5fdSJamin Lin 
aspeed_intc_update(AspeedINTCState * s,int irq,int level)39*d831c5fdSJamin Lin static void aspeed_intc_update(AspeedINTCState *s, int irq, int level)
40*d831c5fdSJamin Lin {
41*d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
42*d831c5fdSJamin Lin 
43*d831c5fdSJamin Lin     if (irq >= aic->num_ints) {
44*d831c5fdSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
45*d831c5fdSJamin Lin                       __func__, irq);
46*d831c5fdSJamin Lin         return;
47*d831c5fdSJamin Lin     }
48*d831c5fdSJamin Lin 
49*d831c5fdSJamin Lin     trace_aspeed_intc_update_irq(irq, level);
50*d831c5fdSJamin Lin     qemu_set_irq(s->output_pins[irq], level);
51*d831c5fdSJamin Lin }
52*d831c5fdSJamin Lin 
53*d831c5fdSJamin Lin /*
54*d831c5fdSJamin Lin  * The address of GICINT128 to GICINT136 are from 0x1000 to 0x1804.
55*d831c5fdSJamin Lin  * Utilize "address & 0x0f00" to get the irq and irq output pin index
56*d831c5fdSJamin Lin  * The value of irq should be 0 to num_ints.
57*d831c5fdSJamin Lin  * The irq 0 indicates GICINT128, irq 1 indicates GICINT129 and so on.
58*d831c5fdSJamin Lin  */
aspeed_intc_set_irq(void * opaque,int irq,int level)59*d831c5fdSJamin Lin static void aspeed_intc_set_irq(void *opaque, int irq, int level)
60*d831c5fdSJamin Lin {
61*d831c5fdSJamin Lin     AspeedINTCState *s = (AspeedINTCState *)opaque;
62*d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
63*d831c5fdSJamin Lin     uint32_t status_addr = GICINT_STATUS_BASE + ((0x100 * irq) >> 2);
64*d831c5fdSJamin Lin     uint32_t select = 0;
65*d831c5fdSJamin Lin     uint32_t enable;
66*d831c5fdSJamin Lin     int i;
67*d831c5fdSJamin Lin 
68*d831c5fdSJamin Lin     if (irq >= aic->num_ints) {
69*d831c5fdSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
70*d831c5fdSJamin Lin                       __func__, irq);
71*d831c5fdSJamin Lin         return;
72*d831c5fdSJamin Lin     }
73*d831c5fdSJamin Lin 
74*d831c5fdSJamin Lin     trace_aspeed_intc_set_irq(irq, level);
75*d831c5fdSJamin Lin     enable = s->enable[irq];
76*d831c5fdSJamin Lin 
77*d831c5fdSJamin Lin     if (!level) {
78*d831c5fdSJamin Lin         return;
79*d831c5fdSJamin Lin     }
80*d831c5fdSJamin Lin 
81*d831c5fdSJamin Lin     for (i = 0; i < aic->num_lines; i++) {
82*d831c5fdSJamin Lin         if (s->orgates[irq].levels[i]) {
83*d831c5fdSJamin Lin             if (enable & BIT(i)) {
84*d831c5fdSJamin Lin                 select |= BIT(i);
85*d831c5fdSJamin Lin             }
86*d831c5fdSJamin Lin         }
87*d831c5fdSJamin Lin     }
88*d831c5fdSJamin Lin 
89*d831c5fdSJamin Lin     if (!select) {
90*d831c5fdSJamin Lin         return;
91*d831c5fdSJamin Lin     }
92*d831c5fdSJamin Lin 
93*d831c5fdSJamin Lin     trace_aspeed_intc_select(select);
94*d831c5fdSJamin Lin 
95*d831c5fdSJamin Lin     if (s->mask[irq] || s->regs[status_addr]) {
96*d831c5fdSJamin Lin         /*
97*d831c5fdSJamin Lin          * a. mask is not 0 means in ISR mode
98*d831c5fdSJamin Lin          * sources interrupt routine are executing.
99*d831c5fdSJamin Lin          * b. status register value is not 0 means previous
100*d831c5fdSJamin Lin          * source interrupt does not be executed, yet.
101*d831c5fdSJamin Lin          *
102*d831c5fdSJamin Lin          * save source interrupt to pending variable.
103*d831c5fdSJamin Lin          */
104*d831c5fdSJamin Lin         s->pending[irq] |= select;
105*d831c5fdSJamin Lin         trace_aspeed_intc_pending_irq(irq, s->pending[irq]);
106*d831c5fdSJamin Lin     } else {
107*d831c5fdSJamin Lin         /*
108*d831c5fdSJamin Lin          * notify firmware which source interrupt are coming
109*d831c5fdSJamin Lin          * by setting status register
110*d831c5fdSJamin Lin          */
111*d831c5fdSJamin Lin         s->regs[status_addr] = select;
112*d831c5fdSJamin Lin         trace_aspeed_intc_trigger_irq(irq, s->regs[status_addr]);
113*d831c5fdSJamin Lin         aspeed_intc_update(s, irq, 1);
114*d831c5fdSJamin Lin     }
115*d831c5fdSJamin Lin }
116*d831c5fdSJamin Lin 
aspeed_intc_read(void * opaque,hwaddr offset,unsigned int size)117*d831c5fdSJamin Lin static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
118*d831c5fdSJamin Lin {
119*d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
120*d831c5fdSJamin Lin     uint32_t addr = offset >> 2;
121*d831c5fdSJamin Lin     uint32_t value = 0;
122*d831c5fdSJamin Lin 
123*d831c5fdSJamin Lin     if (addr >= ASPEED_INTC_NR_REGS) {
124*d831c5fdSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR,
125*d831c5fdSJamin Lin                       "%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
126*d831c5fdSJamin Lin                       __func__, offset);
127*d831c5fdSJamin Lin         return 0;
128*d831c5fdSJamin Lin     }
129*d831c5fdSJamin Lin 
130*d831c5fdSJamin Lin     value = s->regs[addr];
131*d831c5fdSJamin Lin     trace_aspeed_intc_read(offset, size, value);
132*d831c5fdSJamin Lin 
133*d831c5fdSJamin Lin     return value;
134*d831c5fdSJamin Lin }
135*d831c5fdSJamin Lin 
aspeed_intc_write(void * opaque,hwaddr offset,uint64_t data,unsigned size)136*d831c5fdSJamin Lin static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
137*d831c5fdSJamin Lin                                         unsigned size)
138*d831c5fdSJamin Lin {
139*d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
140*d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
141*d831c5fdSJamin Lin     uint32_t addr = offset >> 2;
142*d831c5fdSJamin Lin     uint32_t old_enable;
143*d831c5fdSJamin Lin     uint32_t change;
144*d831c5fdSJamin Lin     uint32_t irq;
145*d831c5fdSJamin Lin 
146*d831c5fdSJamin Lin     if (addr >= ASPEED_INTC_NR_REGS) {
147*d831c5fdSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR,
148*d831c5fdSJamin Lin                       "%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
149*d831c5fdSJamin Lin                       __func__, offset);
150*d831c5fdSJamin Lin         return;
151*d831c5fdSJamin Lin     }
152*d831c5fdSJamin Lin 
153*d831c5fdSJamin Lin     trace_aspeed_intc_write(offset, size, data);
154*d831c5fdSJamin Lin 
155*d831c5fdSJamin Lin     switch (addr) {
156*d831c5fdSJamin Lin     case R_GICINT128_EN:
157*d831c5fdSJamin Lin     case R_GICINT129_EN:
158*d831c5fdSJamin Lin     case R_GICINT130_EN:
159*d831c5fdSJamin Lin     case R_GICINT131_EN:
160*d831c5fdSJamin Lin     case R_GICINT132_EN:
161*d831c5fdSJamin Lin     case R_GICINT133_EN:
162*d831c5fdSJamin Lin     case R_GICINT134_EN:
163*d831c5fdSJamin Lin     case R_GICINT135_EN:
164*d831c5fdSJamin Lin     case R_GICINT136_EN:
165*d831c5fdSJamin Lin         irq = (offset & 0x0f00) >> 8;
166*d831c5fdSJamin Lin 
167*d831c5fdSJamin Lin         if (irq >= aic->num_ints) {
168*d831c5fdSJamin Lin             qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
169*d831c5fdSJamin Lin                           __func__, irq);
170*d831c5fdSJamin Lin             return;
171*d831c5fdSJamin Lin         }
172*d831c5fdSJamin Lin 
173*d831c5fdSJamin Lin         /*
174*d831c5fdSJamin Lin          * These registers are used for enable sources interrupt and
175*d831c5fdSJamin Lin          * mask and unmask source interrupt while executing source ISR.
176*d831c5fdSJamin Lin          */
177*d831c5fdSJamin Lin 
178*d831c5fdSJamin Lin         /* disable all source interrupt */
179*d831c5fdSJamin Lin         if (!data && !s->enable[irq]) {
180*d831c5fdSJamin Lin             s->regs[addr] = data;
181*d831c5fdSJamin Lin             return;
182*d831c5fdSJamin Lin         }
183*d831c5fdSJamin Lin 
184*d831c5fdSJamin Lin         old_enable = s->enable[irq];
185*d831c5fdSJamin Lin         s->enable[irq] |= data;
186*d831c5fdSJamin Lin 
187*d831c5fdSJamin Lin         /* enable new source interrupt */
188*d831c5fdSJamin Lin         if (old_enable != s->enable[irq]) {
189*d831c5fdSJamin Lin             trace_aspeed_intc_enable(s->enable[irq]);
190*d831c5fdSJamin Lin             s->regs[addr] = data;
191*d831c5fdSJamin Lin             return;
192*d831c5fdSJamin Lin         }
193*d831c5fdSJamin Lin 
194*d831c5fdSJamin Lin         /* mask and unmask source interrupt */
195*d831c5fdSJamin Lin         change = s->regs[addr] ^ data;
196*d831c5fdSJamin Lin         if (change & data) {
197*d831c5fdSJamin Lin             s->mask[irq] &= ~change;
198*d831c5fdSJamin Lin             trace_aspeed_intc_unmask(change, s->mask[irq]);
199*d831c5fdSJamin Lin         } else {
200*d831c5fdSJamin Lin             s->mask[irq] |= change;
201*d831c5fdSJamin Lin             trace_aspeed_intc_mask(change, s->mask[irq]);
202*d831c5fdSJamin Lin         }
203*d831c5fdSJamin Lin         s->regs[addr] = data;
204*d831c5fdSJamin Lin         break;
205*d831c5fdSJamin Lin     case R_GICINT128_STATUS:
206*d831c5fdSJamin Lin     case R_GICINT129_STATUS:
207*d831c5fdSJamin Lin     case R_GICINT130_STATUS:
208*d831c5fdSJamin Lin     case R_GICINT131_STATUS:
209*d831c5fdSJamin Lin     case R_GICINT132_STATUS:
210*d831c5fdSJamin Lin     case R_GICINT133_STATUS:
211*d831c5fdSJamin Lin     case R_GICINT134_STATUS:
212*d831c5fdSJamin Lin     case R_GICINT135_STATUS:
213*d831c5fdSJamin Lin     case R_GICINT136_STATUS:
214*d831c5fdSJamin Lin         irq = (offset & 0x0f00) >> 8;
215*d831c5fdSJamin Lin 
216*d831c5fdSJamin Lin         if (irq >= aic->num_ints) {
217*d831c5fdSJamin Lin             qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
218*d831c5fdSJamin Lin                           __func__, irq);
219*d831c5fdSJamin Lin             return;
220*d831c5fdSJamin Lin         }
221*d831c5fdSJamin Lin 
222*d831c5fdSJamin Lin         /* clear status */
223*d831c5fdSJamin Lin         s->regs[addr] &= ~data;
224*d831c5fdSJamin Lin 
225*d831c5fdSJamin Lin         /*
226*d831c5fdSJamin Lin          * These status registers are used for notify sources ISR are executed.
227*d831c5fdSJamin Lin          * If one source ISR is executed, it will clear one bit.
228*d831c5fdSJamin Lin          * If it clear all bits, it means to initialize this register status
229*d831c5fdSJamin Lin          * rather than sources ISR are executed.
230*d831c5fdSJamin Lin          */
231*d831c5fdSJamin Lin         if (data == 0xffffffff) {
232*d831c5fdSJamin Lin             return;
233*d831c5fdSJamin Lin         }
234*d831c5fdSJamin Lin 
235*d831c5fdSJamin Lin         /* All source ISR execution are done */
236*d831c5fdSJamin Lin         if (!s->regs[addr]) {
237*d831c5fdSJamin Lin             trace_aspeed_intc_all_isr_done(irq);
238*d831c5fdSJamin Lin             if (s->pending[irq]) {
239*d831c5fdSJamin Lin                 /*
240*d831c5fdSJamin Lin                  * handle pending source interrupt
241*d831c5fdSJamin Lin                  * notify firmware which source interrupt are pending
242*d831c5fdSJamin Lin                  * by setting status register
243*d831c5fdSJamin Lin                  */
244*d831c5fdSJamin Lin                 s->regs[addr] = s->pending[irq];
245*d831c5fdSJamin Lin                 s->pending[irq] = 0;
246*d831c5fdSJamin Lin                 trace_aspeed_intc_trigger_irq(irq, s->regs[addr]);
247*d831c5fdSJamin Lin                 aspeed_intc_update(s, irq, 1);
248*d831c5fdSJamin Lin             } else {
249*d831c5fdSJamin Lin                 /* clear irq */
250*d831c5fdSJamin Lin                 trace_aspeed_intc_clear_irq(irq, 0);
251*d831c5fdSJamin Lin                 aspeed_intc_update(s, irq, 0);
252*d831c5fdSJamin Lin             }
253*d831c5fdSJamin Lin         }
254*d831c5fdSJamin Lin         break;
255*d831c5fdSJamin Lin     default:
256*d831c5fdSJamin Lin         s->regs[addr] = data;
257*d831c5fdSJamin Lin         break;
258*d831c5fdSJamin Lin     }
259*d831c5fdSJamin Lin 
260*d831c5fdSJamin Lin     return;
261*d831c5fdSJamin Lin }
262*d831c5fdSJamin Lin 
263*d831c5fdSJamin Lin static const MemoryRegionOps aspeed_intc_ops = {
264*d831c5fdSJamin Lin     .read = aspeed_intc_read,
265*d831c5fdSJamin Lin     .write = aspeed_intc_write,
266*d831c5fdSJamin Lin     .endianness = DEVICE_LITTLE_ENDIAN,
267*d831c5fdSJamin Lin     .valid = {
268*d831c5fdSJamin Lin         .min_access_size = 4,
269*d831c5fdSJamin Lin         .max_access_size = 4,
270*d831c5fdSJamin Lin     }
271*d831c5fdSJamin Lin };
272*d831c5fdSJamin Lin 
aspeed_intc_instance_init(Object * obj)273*d831c5fdSJamin Lin static void aspeed_intc_instance_init(Object *obj)
274*d831c5fdSJamin Lin {
275*d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(obj);
276*d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
277*d831c5fdSJamin Lin     int i;
278*d831c5fdSJamin Lin 
279*d831c5fdSJamin Lin     assert(aic->num_ints <= ASPEED_INTC_NR_INTS);
280*d831c5fdSJamin Lin     for (i = 0; i < aic->num_ints; i++) {
281*d831c5fdSJamin Lin         object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i],
282*d831c5fdSJamin Lin                                 TYPE_OR_IRQ);
283*d831c5fdSJamin Lin         object_property_set_int(OBJECT(&s->orgates[i]), "num-lines",
284*d831c5fdSJamin Lin                                 aic->num_lines, &error_abort);
285*d831c5fdSJamin Lin     }
286*d831c5fdSJamin Lin }
287*d831c5fdSJamin Lin 
aspeed_intc_reset(DeviceState * dev)288*d831c5fdSJamin Lin static void aspeed_intc_reset(DeviceState *dev)
289*d831c5fdSJamin Lin {
290*d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
291*d831c5fdSJamin Lin 
292*d831c5fdSJamin Lin     memset(s->regs, 0, sizeof(s->regs));
293*d831c5fdSJamin Lin     memset(s->enable, 0, sizeof(s->enable));
294*d831c5fdSJamin Lin     memset(s->mask, 0, sizeof(s->mask));
295*d831c5fdSJamin Lin     memset(s->pending, 0, sizeof(s->pending));
296*d831c5fdSJamin Lin }
297*d831c5fdSJamin Lin 
aspeed_intc_realize(DeviceState * dev,Error ** errp)298*d831c5fdSJamin Lin static void aspeed_intc_realize(DeviceState *dev, Error **errp)
299*d831c5fdSJamin Lin {
300*d831c5fdSJamin Lin     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
301*d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
302*d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
303*d831c5fdSJamin Lin     int i;
304*d831c5fdSJamin Lin 
305*d831c5fdSJamin Lin     memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_intc_ops, s,
306*d831c5fdSJamin Lin                           TYPE_ASPEED_INTC ".regs", ASPEED_INTC_NR_REGS << 2);
307*d831c5fdSJamin Lin 
308*d831c5fdSJamin Lin     sysbus_init_mmio(sbd, &s->iomem);
309*d831c5fdSJamin Lin     qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_ints);
310*d831c5fdSJamin Lin 
311*d831c5fdSJamin Lin     for (i = 0; i < aic->num_ints; i++) {
312*d831c5fdSJamin Lin         if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) {
313*d831c5fdSJamin Lin             return;
314*d831c5fdSJamin Lin         }
315*d831c5fdSJamin Lin         sysbus_init_irq(sbd, &s->output_pins[i]);
316*d831c5fdSJamin Lin     }
317*d831c5fdSJamin Lin }
318*d831c5fdSJamin Lin 
aspeed_intc_class_init(ObjectClass * klass,void * data)319*d831c5fdSJamin Lin static void aspeed_intc_class_init(ObjectClass *klass, void *data)
320*d831c5fdSJamin Lin {
321*d831c5fdSJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
322*d831c5fdSJamin Lin 
323*d831c5fdSJamin Lin     dc->desc = "ASPEED INTC Controller";
324*d831c5fdSJamin Lin     dc->realize = aspeed_intc_realize;
325*d831c5fdSJamin Lin     dc->reset = aspeed_intc_reset;
326*d831c5fdSJamin Lin     dc->vmsd = NULL;
327*d831c5fdSJamin Lin }
328*d831c5fdSJamin Lin 
329*d831c5fdSJamin Lin static const TypeInfo aspeed_intc_info = {
330*d831c5fdSJamin Lin     .name = TYPE_ASPEED_INTC,
331*d831c5fdSJamin Lin     .parent = TYPE_SYS_BUS_DEVICE,
332*d831c5fdSJamin Lin     .instance_init = aspeed_intc_instance_init,
333*d831c5fdSJamin Lin     .instance_size = sizeof(AspeedINTCState),
334*d831c5fdSJamin Lin     .class_init = aspeed_intc_class_init,
335*d831c5fdSJamin Lin     .class_size = sizeof(AspeedINTCClass),
336*d831c5fdSJamin Lin     .abstract = true,
337*d831c5fdSJamin Lin };
338*d831c5fdSJamin Lin 
aspeed_2700_intc_class_init(ObjectClass * klass,void * data)339*d831c5fdSJamin Lin static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data)
340*d831c5fdSJamin Lin {
341*d831c5fdSJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
342*d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
343*d831c5fdSJamin Lin 
344*d831c5fdSJamin Lin     dc->desc = "ASPEED 2700 INTC Controller";
345*d831c5fdSJamin Lin     aic->num_lines = 32;
346*d831c5fdSJamin Lin     aic->num_ints = 9;
347*d831c5fdSJamin Lin }
348*d831c5fdSJamin Lin 
349*d831c5fdSJamin Lin static const TypeInfo aspeed_2700_intc_info = {
350*d831c5fdSJamin Lin     .name = TYPE_ASPEED_2700_INTC,
351*d831c5fdSJamin Lin     .parent = TYPE_ASPEED_INTC,
352*d831c5fdSJamin Lin     .class_init = aspeed_2700_intc_class_init,
353*d831c5fdSJamin Lin };
354*d831c5fdSJamin Lin 
aspeed_intc_register_types(void)355*d831c5fdSJamin Lin static void aspeed_intc_register_types(void)
356*d831c5fdSJamin Lin {
357*d831c5fdSJamin Lin     type_register_static(&aspeed_intc_info);
358*d831c5fdSJamin Lin     type_register_static(&aspeed_2700_intc_info);
359*d831c5fdSJamin Lin }
360*d831c5fdSJamin Lin 
361*d831c5fdSJamin Lin type_init(aspeed_intc_register_types);
362