xref: /qemu/hw/intc/aspeed_intc.c (revision 49da40cf5ffca090f6918ba882db8fb9536792a7)
1d831c5fdSJamin Lin /*
2d831c5fdSJamin Lin  * ASPEED INTC Controller
3d831c5fdSJamin Lin  *
4d831c5fdSJamin Lin  * Copyright (C) 2024 ASPEED Technology Inc.
5d831c5fdSJamin Lin  *
6d831c5fdSJamin Lin  * SPDX-License-Identifier: GPL-2.0-or-later
7d831c5fdSJamin Lin  */
8d831c5fdSJamin Lin 
9d831c5fdSJamin Lin #include "qemu/osdep.h"
10d831c5fdSJamin Lin #include "hw/intc/aspeed_intc.h"
11d831c5fdSJamin Lin #include "hw/irq.h"
12d831c5fdSJamin Lin #include "qemu/log.h"
13d831c5fdSJamin Lin #include "trace.h"
14d831c5fdSJamin Lin #include "hw/registerfields.h"
15d831c5fdSJamin Lin #include "qapi/error.h"
16d831c5fdSJamin Lin 
177ffee511SJamin Lin /*
187ffee511SJamin Lin  * INTC Registers
197ffee511SJamin Lin  *
207ffee511SJamin Lin  * values below are offset by - 0x1000 from datasheet
217ffee511SJamin Lin  * because its memory region is start at 0x1000
227ffee511SJamin Lin  *
237ffee511SJamin Lin  */
247ffee511SJamin Lin REG32(GICINT128_EN,         0x000)
257ffee511SJamin Lin REG32(GICINT128_STATUS,     0x004)
267ffee511SJamin Lin REG32(GICINT129_EN,         0x100)
277ffee511SJamin Lin REG32(GICINT129_STATUS,     0x104)
287ffee511SJamin Lin REG32(GICINT130_EN,         0x200)
297ffee511SJamin Lin REG32(GICINT130_STATUS,     0x204)
307ffee511SJamin Lin REG32(GICINT131_EN,         0x300)
317ffee511SJamin Lin REG32(GICINT131_STATUS,     0x304)
327ffee511SJamin Lin REG32(GICINT132_EN,         0x400)
337ffee511SJamin Lin REG32(GICINT132_STATUS,     0x404)
347ffee511SJamin Lin REG32(GICINT133_EN,         0x500)
357ffee511SJamin Lin REG32(GICINT133_STATUS,     0x504)
367ffee511SJamin Lin REG32(GICINT134_EN,         0x600)
377ffee511SJamin Lin REG32(GICINT134_STATUS,     0x604)
387ffee511SJamin Lin REG32(GICINT135_EN,         0x700)
397ffee511SJamin Lin REG32(GICINT135_STATUS,     0x704)
407ffee511SJamin Lin REG32(GICINT136_EN,         0x800)
417ffee511SJamin Lin REG32(GICINT136_STATUS,     0x804)
42d831c5fdSJamin Lin 
43d831c5fdSJamin Lin #define GICINT_STATUS_BASE     R_GICINT128_STATUS
44d831c5fdSJamin Lin 
45d831c5fdSJamin Lin static void aspeed_intc_update(AspeedINTCState *s, int irq, int level)
46d831c5fdSJamin Lin {
47d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
48*49da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
49d831c5fdSJamin Lin 
50d831c5fdSJamin Lin     if (irq >= aic->num_ints) {
51d831c5fdSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
52d831c5fdSJamin Lin                       __func__, irq);
53d831c5fdSJamin Lin         return;
54d831c5fdSJamin Lin     }
55d831c5fdSJamin Lin 
56*49da40cfSJamin Lin     trace_aspeed_intc_update_irq(name, irq, level);
57d831c5fdSJamin Lin     qemu_set_irq(s->output_pins[irq], level);
58d831c5fdSJamin Lin }
59d831c5fdSJamin Lin 
60d831c5fdSJamin Lin /*
61d831c5fdSJamin Lin  * The address of GICINT128 to GICINT136 are from 0x1000 to 0x1804.
62d831c5fdSJamin Lin  * Utilize "address & 0x0f00" to get the irq and irq output pin index
63d831c5fdSJamin Lin  * The value of irq should be 0 to num_ints.
64d831c5fdSJamin Lin  * The irq 0 indicates GICINT128, irq 1 indicates GICINT129 and so on.
65d831c5fdSJamin Lin  */
66d831c5fdSJamin Lin static void aspeed_intc_set_irq(void *opaque, int irq, int level)
67d831c5fdSJamin Lin {
68d831c5fdSJamin Lin     AspeedINTCState *s = (AspeedINTCState *)opaque;
69d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
70*49da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
710cffaaceSJamin Lin     uint32_t status_reg = GICINT_STATUS_BASE + ((0x100 * irq) >> 2);
72d831c5fdSJamin Lin     uint32_t select = 0;
73d831c5fdSJamin Lin     uint32_t enable;
74d831c5fdSJamin Lin     int i;
75d831c5fdSJamin Lin 
76d831c5fdSJamin Lin     if (irq >= aic->num_ints) {
77d831c5fdSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
78d831c5fdSJamin Lin                       __func__, irq);
79d831c5fdSJamin Lin         return;
80d831c5fdSJamin Lin     }
81d831c5fdSJamin Lin 
82*49da40cfSJamin Lin     trace_aspeed_intc_set_irq(name, irq, level);
83d831c5fdSJamin Lin     enable = s->enable[irq];
84d831c5fdSJamin Lin 
85d831c5fdSJamin Lin     if (!level) {
86d831c5fdSJamin Lin         return;
87d831c5fdSJamin Lin     }
88d831c5fdSJamin Lin 
89d831c5fdSJamin Lin     for (i = 0; i < aic->num_lines; i++) {
90d831c5fdSJamin Lin         if (s->orgates[irq].levels[i]) {
91d831c5fdSJamin Lin             if (enable & BIT(i)) {
92d831c5fdSJamin Lin                 select |= BIT(i);
93d831c5fdSJamin Lin             }
94d831c5fdSJamin Lin         }
95d831c5fdSJamin Lin     }
96d831c5fdSJamin Lin 
97d831c5fdSJamin Lin     if (!select) {
98d831c5fdSJamin Lin         return;
99d831c5fdSJamin Lin     }
100d831c5fdSJamin Lin 
101*49da40cfSJamin Lin     trace_aspeed_intc_select(name, select);
102d831c5fdSJamin Lin 
1030cffaaceSJamin Lin     if (s->mask[irq] || s->regs[status_reg]) {
104d831c5fdSJamin Lin         /*
105d831c5fdSJamin Lin          * a. mask is not 0 means in ISR mode
106d831c5fdSJamin Lin          * sources interrupt routine are executing.
107d831c5fdSJamin Lin          * b. status register value is not 0 means previous
108d831c5fdSJamin Lin          * source interrupt does not be executed, yet.
109d831c5fdSJamin Lin          *
110d831c5fdSJamin Lin          * save source interrupt to pending variable.
111d831c5fdSJamin Lin          */
112d831c5fdSJamin Lin         s->pending[irq] |= select;
113*49da40cfSJamin Lin         trace_aspeed_intc_pending_irq(name, irq, s->pending[irq]);
114d831c5fdSJamin Lin     } else {
115d831c5fdSJamin Lin         /*
116d831c5fdSJamin Lin          * notify firmware which source interrupt are coming
117d831c5fdSJamin Lin          * by setting status register
118d831c5fdSJamin Lin          */
1190cffaaceSJamin Lin         s->regs[status_reg] = select;
120*49da40cfSJamin Lin         trace_aspeed_intc_trigger_irq(name, irq, s->regs[status_reg]);
121d831c5fdSJamin Lin         aspeed_intc_update(s, irq, 1);
122d831c5fdSJamin Lin     }
123d831c5fdSJamin Lin }
124d831c5fdSJamin Lin 
1253d6e15eaSJamin Lin static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset,
1263d6e15eaSJamin Lin                                        uint64_t data)
127d831c5fdSJamin Lin {
128d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
129*49da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
1300cffaaceSJamin Lin     uint32_t reg = offset >> 2;
131d831c5fdSJamin Lin     uint32_t old_enable;
132d831c5fdSJamin Lin     uint32_t change;
133d831c5fdSJamin Lin     uint32_t irq;
134d831c5fdSJamin Lin 
135d831c5fdSJamin Lin     irq = (offset & 0x0f00) >> 8;
136d831c5fdSJamin Lin 
137d831c5fdSJamin Lin     if (irq >= aic->num_ints) {
138d831c5fdSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
139d831c5fdSJamin Lin                       __func__, irq);
140d831c5fdSJamin Lin         return;
141d831c5fdSJamin Lin     }
142d831c5fdSJamin Lin 
143d831c5fdSJamin Lin     /*
1443d6e15eaSJamin Lin      * The enable registers are used to enable source interrupts.
1453d6e15eaSJamin Lin      * They also handle masking and unmasking of source interrupts
1463d6e15eaSJamin Lin      * during the execution of the source ISR.
147d831c5fdSJamin Lin      */
148d831c5fdSJamin Lin 
149d831c5fdSJamin Lin     /* disable all source interrupt */
150d831c5fdSJamin Lin     if (!data && !s->enable[irq]) {
1510cffaaceSJamin Lin         s->regs[reg] = data;
152d831c5fdSJamin Lin         return;
153d831c5fdSJamin Lin     }
154d831c5fdSJamin Lin 
155d831c5fdSJamin Lin     old_enable = s->enable[irq];
156d831c5fdSJamin Lin     s->enable[irq] |= data;
157d831c5fdSJamin Lin 
158d831c5fdSJamin Lin     /* enable new source interrupt */
159d831c5fdSJamin Lin     if (old_enable != s->enable[irq]) {
160*49da40cfSJamin Lin         trace_aspeed_intc_enable(name, s->enable[irq]);
1610cffaaceSJamin Lin         s->regs[reg] = data;
162d831c5fdSJamin Lin         return;
163d831c5fdSJamin Lin     }
164d831c5fdSJamin Lin 
165d831c5fdSJamin Lin     /* mask and unmask source interrupt */
1660cffaaceSJamin Lin     change = s->regs[reg] ^ data;
167d831c5fdSJamin Lin     if (change & data) {
168d831c5fdSJamin Lin         s->mask[irq] &= ~change;
169*49da40cfSJamin Lin         trace_aspeed_intc_unmask(name, change, s->mask[irq]);
170d831c5fdSJamin Lin     } else {
171d831c5fdSJamin Lin         s->mask[irq] |= change;
172*49da40cfSJamin Lin         trace_aspeed_intc_mask(name, change, s->mask[irq]);
173d831c5fdSJamin Lin     }
1743d6e15eaSJamin Lin 
1750cffaaceSJamin Lin     s->regs[reg] = data;
1763d6e15eaSJamin Lin }
1773d6e15eaSJamin Lin 
1783d6e15eaSJamin Lin static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset,
1793d6e15eaSJamin Lin                                        uint64_t data)
1803d6e15eaSJamin Lin {
1813d6e15eaSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
182*49da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
1833d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
1843d6e15eaSJamin Lin     uint32_t irq;
1853d6e15eaSJamin Lin 
1863d6e15eaSJamin Lin     if (!data) {
1873d6e15eaSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
1883d6e15eaSJamin Lin         return;
1893d6e15eaSJamin Lin     }
1903d6e15eaSJamin Lin 
191d831c5fdSJamin Lin     irq = (offset & 0x0f00) >> 8;
192d831c5fdSJamin Lin 
193d831c5fdSJamin Lin     if (irq >= aic->num_ints) {
194d831c5fdSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid interrupt number: %d\n",
195d831c5fdSJamin Lin                       __func__, irq);
196d831c5fdSJamin Lin         return;
197d831c5fdSJamin Lin     }
198d831c5fdSJamin Lin 
199d831c5fdSJamin Lin     /* clear status */
2000cffaaceSJamin Lin     s->regs[reg] &= ~data;
201d831c5fdSJamin Lin 
202d831c5fdSJamin Lin     /*
203d831c5fdSJamin Lin      * These status registers are used for notify sources ISR are executed.
204d831c5fdSJamin Lin      * If one source ISR is executed, it will clear one bit.
205d831c5fdSJamin Lin      * If it clear all bits, it means to initialize this register status
206d831c5fdSJamin Lin      * rather than sources ISR are executed.
207d831c5fdSJamin Lin      */
208d831c5fdSJamin Lin     if (data == 0xffffffff) {
209d831c5fdSJamin Lin         return;
210d831c5fdSJamin Lin     }
211d831c5fdSJamin Lin 
212d831c5fdSJamin Lin     /* All source ISR execution are done */
2130cffaaceSJamin Lin     if (!s->regs[reg]) {
214*49da40cfSJamin Lin         trace_aspeed_intc_all_isr_done(name, irq);
215d831c5fdSJamin Lin         if (s->pending[irq]) {
216d831c5fdSJamin Lin             /*
217d831c5fdSJamin Lin              * handle pending source interrupt
218d831c5fdSJamin Lin              * notify firmware which source interrupt are pending
219d831c5fdSJamin Lin              * by setting status register
220d831c5fdSJamin Lin              */
2210cffaaceSJamin Lin             s->regs[reg] = s->pending[irq];
222d831c5fdSJamin Lin             s->pending[irq] = 0;
223*49da40cfSJamin Lin             trace_aspeed_intc_trigger_irq(name, irq, s->regs[reg]);
224d831c5fdSJamin Lin             aspeed_intc_update(s, irq, 1);
225d831c5fdSJamin Lin         } else {
226d831c5fdSJamin Lin             /* clear irq */
227*49da40cfSJamin Lin             trace_aspeed_intc_clear_irq(name, irq, 0);
228d831c5fdSJamin Lin             aspeed_intc_update(s, irq, 0);
229d831c5fdSJamin Lin         }
230d831c5fdSJamin Lin     }
2313d6e15eaSJamin Lin }
2323d6e15eaSJamin Lin 
2333d6e15eaSJamin Lin static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
2343d6e15eaSJamin Lin {
2353d6e15eaSJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
236*49da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
2373d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
2383d6e15eaSJamin Lin     uint32_t value = 0;
2393d6e15eaSJamin Lin 
2403d6e15eaSJamin Lin     value = s->regs[reg];
241*49da40cfSJamin Lin     trace_aspeed_intc_read(name, offset, size, value);
2423d6e15eaSJamin Lin 
2433d6e15eaSJamin Lin     return value;
2443d6e15eaSJamin Lin }
2453d6e15eaSJamin Lin 
2463d6e15eaSJamin Lin static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
2473d6e15eaSJamin Lin                                         unsigned size)
2483d6e15eaSJamin Lin {
2493d6e15eaSJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
250*49da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
2513d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
2523d6e15eaSJamin Lin 
253*49da40cfSJamin Lin     trace_aspeed_intc_write(name, offset, size, data);
2543d6e15eaSJamin Lin 
2553d6e15eaSJamin Lin     switch (reg) {
2563d6e15eaSJamin Lin     case R_GICINT128_EN:
2573d6e15eaSJamin Lin     case R_GICINT129_EN:
2583d6e15eaSJamin Lin     case R_GICINT130_EN:
2593d6e15eaSJamin Lin     case R_GICINT131_EN:
2603d6e15eaSJamin Lin     case R_GICINT132_EN:
2613d6e15eaSJamin Lin     case R_GICINT133_EN:
2623d6e15eaSJamin Lin     case R_GICINT134_EN:
2633d6e15eaSJamin Lin     case R_GICINT135_EN:
2643d6e15eaSJamin Lin     case R_GICINT136_EN:
2653d6e15eaSJamin Lin         aspeed_intc_enable_handler(s, offset, data);
2663d6e15eaSJamin Lin         break;
2673d6e15eaSJamin Lin     case R_GICINT128_STATUS:
2683d6e15eaSJamin Lin     case R_GICINT129_STATUS:
2693d6e15eaSJamin Lin     case R_GICINT130_STATUS:
2703d6e15eaSJamin Lin     case R_GICINT131_STATUS:
2713d6e15eaSJamin Lin     case R_GICINT132_STATUS:
2723d6e15eaSJamin Lin     case R_GICINT133_STATUS:
2733d6e15eaSJamin Lin     case R_GICINT134_STATUS:
2743d6e15eaSJamin Lin     case R_GICINT135_STATUS:
2753d6e15eaSJamin Lin     case R_GICINT136_STATUS:
2763d6e15eaSJamin Lin         aspeed_intc_status_handler(s, offset, data);
277d831c5fdSJamin Lin         break;
278d831c5fdSJamin Lin     default:
2790cffaaceSJamin Lin         s->regs[reg] = data;
280d831c5fdSJamin Lin         break;
281d831c5fdSJamin Lin     }
282d831c5fdSJamin Lin 
283d831c5fdSJamin Lin     return;
284d831c5fdSJamin Lin }
285d831c5fdSJamin Lin 
286d831c5fdSJamin Lin static const MemoryRegionOps aspeed_intc_ops = {
287d831c5fdSJamin Lin     .read = aspeed_intc_read,
288d831c5fdSJamin Lin     .write = aspeed_intc_write,
289d831c5fdSJamin Lin     .endianness = DEVICE_LITTLE_ENDIAN,
290d831c5fdSJamin Lin     .valid = {
291d831c5fdSJamin Lin         .min_access_size = 4,
292d831c5fdSJamin Lin         .max_access_size = 4,
293d831c5fdSJamin Lin     }
294d831c5fdSJamin Lin };
295d831c5fdSJamin Lin 
296d831c5fdSJamin Lin static void aspeed_intc_instance_init(Object *obj)
297d831c5fdSJamin Lin {
298d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(obj);
299d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
300d831c5fdSJamin Lin     int i;
301d831c5fdSJamin Lin 
302d831c5fdSJamin Lin     assert(aic->num_ints <= ASPEED_INTC_NR_INTS);
303d831c5fdSJamin Lin     for (i = 0; i < aic->num_ints; i++) {
304d831c5fdSJamin Lin         object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i],
305d831c5fdSJamin Lin                                 TYPE_OR_IRQ);
306d831c5fdSJamin Lin         object_property_set_int(OBJECT(&s->orgates[i]), "num-lines",
307d831c5fdSJamin Lin                                 aic->num_lines, &error_abort);
308d831c5fdSJamin Lin     }
309d831c5fdSJamin Lin }
310d831c5fdSJamin Lin 
311d831c5fdSJamin Lin static void aspeed_intc_reset(DeviceState *dev)
312d831c5fdSJamin Lin {
313d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
314b008465dSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
315d831c5fdSJamin Lin 
316b008465dSJamin Lin     memset(s->regs, 0, aic->nr_regs << 2);
317d831c5fdSJamin Lin     memset(s->enable, 0, sizeof(s->enable));
318d831c5fdSJamin Lin     memset(s->mask, 0, sizeof(s->mask));
319d831c5fdSJamin Lin     memset(s->pending, 0, sizeof(s->pending));
320d831c5fdSJamin Lin }
321d831c5fdSJamin Lin 
322d831c5fdSJamin Lin static void aspeed_intc_realize(DeviceState *dev, Error **errp)
323d831c5fdSJamin Lin {
324d831c5fdSJamin Lin     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
325d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
326d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
327d831c5fdSJamin Lin     int i;
328d831c5fdSJamin Lin 
329c5728c34SJamin Lin     memory_region_init(&s->iomem_container, OBJECT(s),
330c5728c34SJamin Lin             TYPE_ASPEED_INTC ".container", aic->mem_size);
331c5728c34SJamin Lin 
332c5728c34SJamin Lin     sysbus_init_mmio(sbd, &s->iomem_container);
333c5728c34SJamin Lin 
334b008465dSJamin Lin     s->regs = g_new(uint32_t, aic->nr_regs);
335d831c5fdSJamin Lin     memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_intc_ops, s,
336b008465dSJamin Lin                           TYPE_ASPEED_INTC ".regs", aic->nr_regs << 2);
337d831c5fdSJamin Lin 
3387ffee511SJamin Lin     memory_region_add_subregion(&s->iomem_container, aic->reg_offset,
3397ffee511SJamin Lin                                 &s->iomem);
340c5728c34SJamin Lin 
341d831c5fdSJamin Lin     qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_ints);
342d831c5fdSJamin Lin 
343d831c5fdSJamin Lin     for (i = 0; i < aic->num_ints; i++) {
344d831c5fdSJamin Lin         if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) {
345d831c5fdSJamin Lin             return;
346d831c5fdSJamin Lin         }
347d831c5fdSJamin Lin         sysbus_init_irq(sbd, &s->output_pins[i]);
348d831c5fdSJamin Lin     }
349d831c5fdSJamin Lin }
350d831c5fdSJamin Lin 
351563afea0SJamin Lin static void aspeed_intc_unrealize(DeviceState *dev)
352563afea0SJamin Lin {
353563afea0SJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
354563afea0SJamin Lin 
355563afea0SJamin Lin     g_free(s->regs);
356563afea0SJamin Lin     s->regs = NULL;
357563afea0SJamin Lin }
358563afea0SJamin Lin 
359d831c5fdSJamin Lin static void aspeed_intc_class_init(ObjectClass *klass, void *data)
360d831c5fdSJamin Lin {
361d831c5fdSJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
362d831c5fdSJamin Lin 
363d831c5fdSJamin Lin     dc->desc = "ASPEED INTC Controller";
364d831c5fdSJamin Lin     dc->realize = aspeed_intc_realize;
365563afea0SJamin Lin     dc->unrealize = aspeed_intc_unrealize;
366e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, aspeed_intc_reset);
367d831c5fdSJamin Lin     dc->vmsd = NULL;
368d831c5fdSJamin Lin }
369d831c5fdSJamin Lin 
370d831c5fdSJamin Lin static const TypeInfo aspeed_intc_info = {
371d831c5fdSJamin Lin     .name = TYPE_ASPEED_INTC,
372d831c5fdSJamin Lin     .parent = TYPE_SYS_BUS_DEVICE,
373d831c5fdSJamin Lin     .instance_init = aspeed_intc_instance_init,
374d831c5fdSJamin Lin     .instance_size = sizeof(AspeedINTCState),
375d831c5fdSJamin Lin     .class_init = aspeed_intc_class_init,
376d831c5fdSJamin Lin     .class_size = sizeof(AspeedINTCClass),
377d831c5fdSJamin Lin     .abstract = true,
378d831c5fdSJamin Lin };
379d831c5fdSJamin Lin 
380d831c5fdSJamin Lin static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data)
381d831c5fdSJamin Lin {
382d831c5fdSJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
383d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
384d831c5fdSJamin Lin 
385d831c5fdSJamin Lin     dc->desc = "ASPEED 2700 INTC Controller";
386d831c5fdSJamin Lin     aic->num_lines = 32;
387d831c5fdSJamin Lin     aic->num_ints = 9;
388c5728c34SJamin Lin     aic->mem_size = 0x4000;
3897ffee511SJamin Lin     aic->nr_regs = 0x808 >> 2;
3907ffee511SJamin Lin     aic->reg_offset = 0x1000;
391d831c5fdSJamin Lin }
392d831c5fdSJamin Lin 
393d831c5fdSJamin Lin static const TypeInfo aspeed_2700_intc_info = {
394d831c5fdSJamin Lin     .name = TYPE_ASPEED_2700_INTC,
395d831c5fdSJamin Lin     .parent = TYPE_ASPEED_INTC,
396d831c5fdSJamin Lin     .class_init = aspeed_2700_intc_class_init,
397d831c5fdSJamin Lin };
398d831c5fdSJamin Lin 
399d831c5fdSJamin Lin static void aspeed_intc_register_types(void)
400d831c5fdSJamin Lin {
401d831c5fdSJamin Lin     type_register_static(&aspeed_intc_info);
402d831c5fdSJamin Lin     type_register_static(&aspeed_2700_intc_info);
403d831c5fdSJamin Lin }
404d831c5fdSJamin Lin 
405d831c5fdSJamin Lin type_init(aspeed_intc_register_types);
406