xref: /qemu/hw/intc/aspeed_intc.c (revision ab24c6a2df8e6c8055b6f1dfe80697320b327c50)
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 
43*ab24c6a2SJamin Lin static const AspeedINTCIRQ *aspeed_intc_get_irq(AspeedINTCClass *aic,
44*ab24c6a2SJamin Lin                                                 uint32_t reg)
45*ab24c6a2SJamin Lin {
46*ab24c6a2SJamin Lin     int i;
47*ab24c6a2SJamin Lin 
48*ab24c6a2SJamin Lin     for (i = 0; i < aic->irq_table_count; i++) {
49*ab24c6a2SJamin Lin         if (aic->irq_table[i].enable_reg == reg ||
50*ab24c6a2SJamin Lin             aic->irq_table[i].status_reg == reg) {
51*ab24c6a2SJamin Lin             return &aic->irq_table[i];
52*ab24c6a2SJamin Lin         }
53*ab24c6a2SJamin Lin     }
54*ab24c6a2SJamin Lin 
55*ab24c6a2SJamin Lin     /*
56*ab24c6a2SJamin Lin      * Invalid reg.
57*ab24c6a2SJamin Lin      */
58*ab24c6a2SJamin Lin     g_assert_not_reached();
59*ab24c6a2SJamin Lin }
60d831c5fdSJamin Lin 
61c6c5e63dSJamin Lin /*
62c6c5e63dSJamin Lin  * Update the state of an interrupt controller pin by setting
63c6c5e63dSJamin Lin  * the specified output pin to the given level.
64c6c5e63dSJamin Lin  * The input pin index should be between 0 and the number of input pins.
65c6c5e63dSJamin Lin  * The output pin index should be between 0 and the number of output pins.
66c6c5e63dSJamin Lin  */
67c6c5e63dSJamin Lin static void aspeed_intc_update(AspeedINTCState *s, int inpin_idx,
68c6c5e63dSJamin Lin                                int outpin_idx, int level)
69d831c5fdSJamin Lin {
70d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
7149da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
72d831c5fdSJamin Lin 
73*ab24c6a2SJamin Lin     assert((outpin_idx < aic->num_outpins) && (inpin_idx < aic->num_inpins));
74c6c5e63dSJamin Lin 
75c6c5e63dSJamin Lin     trace_aspeed_intc_update_irq(name, inpin_idx, outpin_idx, level);
76c6c5e63dSJamin Lin     qemu_set_irq(s->output_pins[outpin_idx], level);
77d831c5fdSJamin Lin }
78d831c5fdSJamin Lin 
79d831c5fdSJamin Lin /*
80d831c5fdSJamin Lin  * The address of GICINT128 to GICINT136 are from 0x1000 to 0x1804.
81d831c5fdSJamin Lin  * Utilize "address & 0x0f00" to get the irq and irq output pin index
8263f3618fSJamin Lin  * The value of irq should be 0 to num_inpins.
83d831c5fdSJamin Lin  * The irq 0 indicates GICINT128, irq 1 indicates GICINT129 and so on.
84d831c5fdSJamin Lin  */
85d831c5fdSJamin Lin static void aspeed_intc_set_irq(void *opaque, int irq, int level)
86d831c5fdSJamin Lin {
87d831c5fdSJamin Lin     AspeedINTCState *s = (AspeedINTCState *)opaque;
88d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
8949da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
90*ab24c6a2SJamin Lin     const AspeedINTCIRQ *intc_irq;
91*ab24c6a2SJamin Lin     uint32_t status_reg;
92d831c5fdSJamin Lin     uint32_t select = 0;
93d831c5fdSJamin Lin     uint32_t enable;
94c6c5e63dSJamin Lin     int outpin_idx;
95c6c5e63dSJamin Lin     int inpin_idx;
96d831c5fdSJamin Lin     int i;
97d831c5fdSJamin Lin 
98*ab24c6a2SJamin Lin     assert(irq < aic->num_inpins);
99c6c5e63dSJamin Lin 
100*ab24c6a2SJamin Lin     intc_irq = &aic->irq_table[irq];
101*ab24c6a2SJamin Lin     status_reg = intc_irq->status_reg;
102*ab24c6a2SJamin Lin     outpin_idx = intc_irq->outpin_idx;
103*ab24c6a2SJamin Lin     inpin_idx = intc_irq->inpin_idx;
104d831c5fdSJamin Lin 
105c6c5e63dSJamin Lin     trace_aspeed_intc_set_irq(name, inpin_idx, level);
106c6c5e63dSJamin Lin     enable = s->enable[inpin_idx];
107d831c5fdSJamin Lin 
108d831c5fdSJamin Lin     if (!level) {
109d831c5fdSJamin Lin         return;
110d831c5fdSJamin Lin     }
111d831c5fdSJamin Lin 
112d831c5fdSJamin Lin     for (i = 0; i < aic->num_lines; i++) {
113c6c5e63dSJamin Lin         if (s->orgates[inpin_idx].levels[i]) {
114d831c5fdSJamin Lin             if (enable & BIT(i)) {
115d831c5fdSJamin Lin                 select |= BIT(i);
116d831c5fdSJamin Lin             }
117d831c5fdSJamin Lin         }
118d831c5fdSJamin Lin     }
119d831c5fdSJamin Lin 
120d831c5fdSJamin Lin     if (!select) {
121d831c5fdSJamin Lin         return;
122d831c5fdSJamin Lin     }
123d831c5fdSJamin Lin 
12449da40cfSJamin Lin     trace_aspeed_intc_select(name, select);
125d831c5fdSJamin Lin 
126c6c5e63dSJamin Lin     if (s->mask[inpin_idx] || s->regs[status_reg]) {
127d831c5fdSJamin Lin         /*
128d831c5fdSJamin Lin          * a. mask is not 0 means in ISR mode
129d831c5fdSJamin Lin          * sources interrupt routine are executing.
130d831c5fdSJamin Lin          * b. status register value is not 0 means previous
131d831c5fdSJamin Lin          * source interrupt does not be executed, yet.
132d831c5fdSJamin Lin          *
133d831c5fdSJamin Lin          * save source interrupt to pending variable.
134d831c5fdSJamin Lin          */
135c6c5e63dSJamin Lin         s->pending[inpin_idx] |= select;
136c6c5e63dSJamin Lin         trace_aspeed_intc_pending_irq(name, inpin_idx, s->pending[inpin_idx]);
137d831c5fdSJamin Lin     } else {
138d831c5fdSJamin Lin         /*
139d831c5fdSJamin Lin          * notify firmware which source interrupt are coming
140d831c5fdSJamin Lin          * by setting status register
141d831c5fdSJamin Lin          */
1420cffaaceSJamin Lin         s->regs[status_reg] = select;
143c6c5e63dSJamin Lin         trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
144c6c5e63dSJamin Lin                                       s->regs[status_reg]);
145c6c5e63dSJamin Lin         aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
146d831c5fdSJamin Lin     }
147d831c5fdSJamin Lin }
148d831c5fdSJamin Lin 
1493d6e15eaSJamin Lin static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset,
1503d6e15eaSJamin Lin                                        uint64_t data)
151d831c5fdSJamin Lin {
152d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
15349da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
154*ab24c6a2SJamin Lin     const AspeedINTCIRQ *intc_irq;
1550cffaaceSJamin Lin     uint32_t reg = offset >> 2;
156d831c5fdSJamin Lin     uint32_t old_enable;
157d831c5fdSJamin Lin     uint32_t change;
158c6c5e63dSJamin Lin     int inpin_idx;
159d831c5fdSJamin Lin 
160*ab24c6a2SJamin Lin     intc_irq = aspeed_intc_get_irq(aic, reg);
161*ab24c6a2SJamin Lin     inpin_idx = intc_irq->inpin_idx;
162d831c5fdSJamin Lin 
163*ab24c6a2SJamin Lin     assert(inpin_idx < aic->num_inpins);
164d831c5fdSJamin Lin 
165d831c5fdSJamin Lin     /*
1663d6e15eaSJamin Lin      * The enable registers are used to enable source interrupts.
1673d6e15eaSJamin Lin      * They also handle masking and unmasking of source interrupts
1683d6e15eaSJamin Lin      * during the execution of the source ISR.
169d831c5fdSJamin Lin      */
170d831c5fdSJamin Lin 
171d831c5fdSJamin Lin     /* disable all source interrupt */
172c6c5e63dSJamin Lin     if (!data && !s->enable[inpin_idx]) {
1730cffaaceSJamin Lin         s->regs[reg] = data;
174d831c5fdSJamin Lin         return;
175d831c5fdSJamin Lin     }
176d831c5fdSJamin Lin 
177c6c5e63dSJamin Lin     old_enable = s->enable[inpin_idx];
178c6c5e63dSJamin Lin     s->enable[inpin_idx] |= data;
179d831c5fdSJamin Lin 
180d831c5fdSJamin Lin     /* enable new source interrupt */
181c6c5e63dSJamin Lin     if (old_enable != s->enable[inpin_idx]) {
182c6c5e63dSJamin Lin         trace_aspeed_intc_enable(name, s->enable[inpin_idx]);
1830cffaaceSJamin Lin         s->regs[reg] = data;
184d831c5fdSJamin Lin         return;
185d831c5fdSJamin Lin     }
186d831c5fdSJamin Lin 
187d831c5fdSJamin Lin     /* mask and unmask source interrupt */
1880cffaaceSJamin Lin     change = s->regs[reg] ^ data;
189d831c5fdSJamin Lin     if (change & data) {
190c6c5e63dSJamin Lin         s->mask[inpin_idx] &= ~change;
191c6c5e63dSJamin Lin         trace_aspeed_intc_unmask(name, change, s->mask[inpin_idx]);
192d831c5fdSJamin Lin     } else {
193c6c5e63dSJamin Lin         s->mask[inpin_idx] |= change;
194c6c5e63dSJamin Lin         trace_aspeed_intc_mask(name, change, s->mask[inpin_idx]);
195d831c5fdSJamin Lin     }
1963d6e15eaSJamin Lin 
1970cffaaceSJamin Lin     s->regs[reg] = data;
1983d6e15eaSJamin Lin }
1993d6e15eaSJamin Lin 
2003d6e15eaSJamin Lin static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset,
2013d6e15eaSJamin Lin                                        uint64_t data)
2023d6e15eaSJamin Lin {
2033d6e15eaSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
20449da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
205*ab24c6a2SJamin Lin     const AspeedINTCIRQ *intc_irq;
2063d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
207c6c5e63dSJamin Lin     int outpin_idx;
208c6c5e63dSJamin Lin     int inpin_idx;
2093d6e15eaSJamin Lin 
2103d6e15eaSJamin Lin     if (!data) {
2113d6e15eaSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
2123d6e15eaSJamin Lin         return;
2133d6e15eaSJamin Lin     }
2143d6e15eaSJamin Lin 
215*ab24c6a2SJamin Lin     intc_irq = aspeed_intc_get_irq(aic, reg);
216*ab24c6a2SJamin Lin     outpin_idx = intc_irq->outpin_idx;
217*ab24c6a2SJamin Lin     inpin_idx = intc_irq->inpin_idx;
218d831c5fdSJamin Lin 
219*ab24c6a2SJamin Lin     assert(inpin_idx < aic->num_inpins);
220d831c5fdSJamin Lin 
221d831c5fdSJamin Lin     /* clear status */
2220cffaaceSJamin Lin     s->regs[reg] &= ~data;
223d831c5fdSJamin Lin 
224d831c5fdSJamin Lin     /*
225d831c5fdSJamin Lin      * These status registers are used for notify sources ISR are executed.
226d831c5fdSJamin Lin      * If one source ISR is executed, it will clear one bit.
227d831c5fdSJamin Lin      * If it clear all bits, it means to initialize this register status
228d831c5fdSJamin Lin      * rather than sources ISR are executed.
229d831c5fdSJamin Lin      */
230d831c5fdSJamin Lin     if (data == 0xffffffff) {
231d831c5fdSJamin Lin         return;
232d831c5fdSJamin Lin     }
233d831c5fdSJamin Lin 
234d831c5fdSJamin Lin     /* All source ISR execution are done */
2350cffaaceSJamin Lin     if (!s->regs[reg]) {
236c6c5e63dSJamin Lin         trace_aspeed_intc_all_isr_done(name, inpin_idx);
237c6c5e63dSJamin Lin         if (s->pending[inpin_idx]) {
238d831c5fdSJamin Lin             /*
239d831c5fdSJamin Lin              * handle pending source interrupt
240d831c5fdSJamin Lin              * notify firmware which source interrupt are pending
241d831c5fdSJamin Lin              * by setting status register
242d831c5fdSJamin Lin              */
243c6c5e63dSJamin Lin             s->regs[reg] = s->pending[inpin_idx];
244c6c5e63dSJamin Lin             s->pending[inpin_idx] = 0;
245c6c5e63dSJamin Lin             trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
246c6c5e63dSJamin Lin                                           s->regs[reg]);
247c6c5e63dSJamin Lin             aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
248d831c5fdSJamin Lin         } else {
249d831c5fdSJamin Lin             /* clear irq */
250c6c5e63dSJamin Lin             trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx, 0);
251c6c5e63dSJamin Lin             aspeed_intc_update(s, inpin_idx, outpin_idx, 0);
252d831c5fdSJamin Lin         }
253d831c5fdSJamin Lin     }
2543d6e15eaSJamin Lin }
2553d6e15eaSJamin Lin 
2563d6e15eaSJamin Lin static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
2573d6e15eaSJamin Lin {
2583d6e15eaSJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
25949da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
2603d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
2613d6e15eaSJamin Lin     uint32_t value = 0;
2623d6e15eaSJamin Lin 
2633d6e15eaSJamin Lin     value = s->regs[reg];
26449da40cfSJamin Lin     trace_aspeed_intc_read(name, offset, size, value);
2653d6e15eaSJamin Lin 
2663d6e15eaSJamin Lin     return value;
2673d6e15eaSJamin Lin }
2683d6e15eaSJamin Lin 
2693d6e15eaSJamin Lin static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
2703d6e15eaSJamin Lin                                         unsigned size)
2713d6e15eaSJamin Lin {
2723d6e15eaSJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
27349da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
2743d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
2753d6e15eaSJamin Lin 
27649da40cfSJamin Lin     trace_aspeed_intc_write(name, offset, size, data);
2773d6e15eaSJamin Lin 
2783d6e15eaSJamin Lin     switch (reg) {
2793d6e15eaSJamin Lin     case R_GICINT128_EN:
2803d6e15eaSJamin Lin     case R_GICINT129_EN:
2813d6e15eaSJamin Lin     case R_GICINT130_EN:
2823d6e15eaSJamin Lin     case R_GICINT131_EN:
2833d6e15eaSJamin Lin     case R_GICINT132_EN:
2843d6e15eaSJamin Lin     case R_GICINT133_EN:
2853d6e15eaSJamin Lin     case R_GICINT134_EN:
2863d6e15eaSJamin Lin     case R_GICINT135_EN:
2873d6e15eaSJamin Lin     case R_GICINT136_EN:
2883d6e15eaSJamin Lin         aspeed_intc_enable_handler(s, offset, data);
2893d6e15eaSJamin Lin         break;
2903d6e15eaSJamin Lin     case R_GICINT128_STATUS:
2913d6e15eaSJamin Lin     case R_GICINT129_STATUS:
2923d6e15eaSJamin Lin     case R_GICINT130_STATUS:
2933d6e15eaSJamin Lin     case R_GICINT131_STATUS:
2943d6e15eaSJamin Lin     case R_GICINT132_STATUS:
2953d6e15eaSJamin Lin     case R_GICINT133_STATUS:
2963d6e15eaSJamin Lin     case R_GICINT134_STATUS:
2973d6e15eaSJamin Lin     case R_GICINT135_STATUS:
2983d6e15eaSJamin Lin     case R_GICINT136_STATUS:
2993d6e15eaSJamin Lin         aspeed_intc_status_handler(s, offset, data);
300d831c5fdSJamin Lin         break;
301d831c5fdSJamin Lin     default:
3020cffaaceSJamin Lin         s->regs[reg] = data;
303d831c5fdSJamin Lin         break;
304d831c5fdSJamin Lin     }
305d831c5fdSJamin Lin 
306d831c5fdSJamin Lin     return;
307d831c5fdSJamin Lin }
308d831c5fdSJamin Lin 
309d831c5fdSJamin Lin static const MemoryRegionOps aspeed_intc_ops = {
310d831c5fdSJamin Lin     .read = aspeed_intc_read,
311d831c5fdSJamin Lin     .write = aspeed_intc_write,
312d831c5fdSJamin Lin     .endianness = DEVICE_LITTLE_ENDIAN,
313d831c5fdSJamin Lin     .valid = {
314d831c5fdSJamin Lin         .min_access_size = 4,
315d831c5fdSJamin Lin         .max_access_size = 4,
316d831c5fdSJamin Lin     }
317d831c5fdSJamin Lin };
318d831c5fdSJamin Lin 
319d831c5fdSJamin Lin static void aspeed_intc_instance_init(Object *obj)
320d831c5fdSJamin Lin {
321d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(obj);
322d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
323d831c5fdSJamin Lin     int i;
324d831c5fdSJamin Lin 
32563f3618fSJamin Lin     assert(aic->num_inpins <= ASPEED_INTC_MAX_INPINS);
32663f3618fSJamin Lin     for (i = 0; i < aic->num_inpins; i++) {
327d831c5fdSJamin Lin         object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i],
328d831c5fdSJamin Lin                                 TYPE_OR_IRQ);
329d831c5fdSJamin Lin         object_property_set_int(OBJECT(&s->orgates[i]), "num-lines",
330d831c5fdSJamin Lin                                 aic->num_lines, &error_abort);
331d831c5fdSJamin Lin     }
332d831c5fdSJamin Lin }
333d831c5fdSJamin Lin 
334d831c5fdSJamin Lin static void aspeed_intc_reset(DeviceState *dev)
335d831c5fdSJamin Lin {
336d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
337b008465dSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
338d831c5fdSJamin Lin 
339b008465dSJamin Lin     memset(s->regs, 0, aic->nr_regs << 2);
340d831c5fdSJamin Lin     memset(s->enable, 0, sizeof(s->enable));
341d831c5fdSJamin Lin     memset(s->mask, 0, sizeof(s->mask));
342d831c5fdSJamin Lin     memset(s->pending, 0, sizeof(s->pending));
343d831c5fdSJamin Lin }
344d831c5fdSJamin Lin 
345d831c5fdSJamin Lin static void aspeed_intc_realize(DeviceState *dev, Error **errp)
346d831c5fdSJamin Lin {
347d831c5fdSJamin Lin     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
348d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
349d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
350d831c5fdSJamin Lin     int i;
351d831c5fdSJamin Lin 
352c5728c34SJamin Lin     memory_region_init(&s->iomem_container, OBJECT(s),
353c5728c34SJamin Lin             TYPE_ASPEED_INTC ".container", aic->mem_size);
354c5728c34SJamin Lin 
355c5728c34SJamin Lin     sysbus_init_mmio(sbd, &s->iomem_container);
356c5728c34SJamin Lin 
357b008465dSJamin Lin     s->regs = g_new(uint32_t, aic->nr_regs);
35828194d5dSJamin Lin     memory_region_init_io(&s->iomem, OBJECT(s), aic->reg_ops, s,
359b008465dSJamin Lin                           TYPE_ASPEED_INTC ".regs", aic->nr_regs << 2);
360d831c5fdSJamin Lin 
3617ffee511SJamin Lin     memory_region_add_subregion(&s->iomem_container, aic->reg_offset,
3627ffee511SJamin Lin                                 &s->iomem);
363c5728c34SJamin Lin 
36463f3618fSJamin Lin     qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_inpins);
365d831c5fdSJamin Lin 
36663f3618fSJamin Lin     for (i = 0; i < aic->num_inpins; i++) {
367d831c5fdSJamin Lin         if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) {
368d831c5fdSJamin Lin             return;
369d831c5fdSJamin Lin         }
37035c909cdSJamin Lin     }
37135c909cdSJamin Lin 
37235c909cdSJamin Lin     for (i = 0; i < aic->num_outpins; i++) {
373d831c5fdSJamin Lin         sysbus_init_irq(sbd, &s->output_pins[i]);
374d831c5fdSJamin Lin     }
375d831c5fdSJamin Lin }
376d831c5fdSJamin Lin 
377563afea0SJamin Lin static void aspeed_intc_unrealize(DeviceState *dev)
378563afea0SJamin Lin {
379563afea0SJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
380563afea0SJamin Lin 
381563afea0SJamin Lin     g_free(s->regs);
382563afea0SJamin Lin     s->regs = NULL;
383563afea0SJamin Lin }
384563afea0SJamin Lin 
385d831c5fdSJamin Lin static void aspeed_intc_class_init(ObjectClass *klass, void *data)
386d831c5fdSJamin Lin {
387d831c5fdSJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
38828194d5dSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
389d831c5fdSJamin Lin 
390d831c5fdSJamin Lin     dc->desc = "ASPEED INTC Controller";
391d831c5fdSJamin Lin     dc->realize = aspeed_intc_realize;
392563afea0SJamin Lin     dc->unrealize = aspeed_intc_unrealize;
393e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, aspeed_intc_reset);
394d831c5fdSJamin Lin     dc->vmsd = NULL;
39528194d5dSJamin Lin 
39628194d5dSJamin Lin     aic->reg_ops = &aspeed_intc_ops;
397d831c5fdSJamin Lin }
398d831c5fdSJamin Lin 
399d831c5fdSJamin Lin static const TypeInfo aspeed_intc_info = {
400d831c5fdSJamin Lin     .name = TYPE_ASPEED_INTC,
401d831c5fdSJamin Lin     .parent = TYPE_SYS_BUS_DEVICE,
402d831c5fdSJamin Lin     .instance_init = aspeed_intc_instance_init,
403d831c5fdSJamin Lin     .instance_size = sizeof(AspeedINTCState),
404d831c5fdSJamin Lin     .class_init = aspeed_intc_class_init,
405d831c5fdSJamin Lin     .class_size = sizeof(AspeedINTCClass),
406d831c5fdSJamin Lin     .abstract = true,
407d831c5fdSJamin Lin };
408d831c5fdSJamin Lin 
409*ab24c6a2SJamin Lin static AspeedINTCIRQ aspeed_2700_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
410*ab24c6a2SJamin Lin     {0, 0, 1, R_GICINT128_EN, R_GICINT128_STATUS},
411*ab24c6a2SJamin Lin     {1, 1, 1, R_GICINT129_EN, R_GICINT129_STATUS},
412*ab24c6a2SJamin Lin     {2, 2, 1, R_GICINT130_EN, R_GICINT130_STATUS},
413*ab24c6a2SJamin Lin     {3, 3, 1, R_GICINT131_EN, R_GICINT131_STATUS},
414*ab24c6a2SJamin Lin     {4, 4, 1, R_GICINT132_EN, R_GICINT132_STATUS},
415*ab24c6a2SJamin Lin     {5, 5, 1, R_GICINT133_EN, R_GICINT133_STATUS},
416*ab24c6a2SJamin Lin     {6, 6, 1, R_GICINT134_EN, R_GICINT134_STATUS},
417*ab24c6a2SJamin Lin     {7, 7, 1, R_GICINT135_EN, R_GICINT135_STATUS},
418*ab24c6a2SJamin Lin     {8, 8, 1, R_GICINT136_EN, R_GICINT136_STATUS},
419*ab24c6a2SJamin Lin };
420*ab24c6a2SJamin Lin 
421d831c5fdSJamin Lin static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data)
422d831c5fdSJamin Lin {
423d831c5fdSJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
424d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
425d831c5fdSJamin Lin 
426d831c5fdSJamin Lin     dc->desc = "ASPEED 2700 INTC Controller";
427d831c5fdSJamin Lin     aic->num_lines = 32;
42863f3618fSJamin Lin     aic->num_inpins = 9;
42935c909cdSJamin Lin     aic->num_outpins = 9;
430c5728c34SJamin Lin     aic->mem_size = 0x4000;
4317ffee511SJamin Lin     aic->nr_regs = 0x808 >> 2;
4327ffee511SJamin Lin     aic->reg_offset = 0x1000;
433*ab24c6a2SJamin Lin     aic->irq_table = aspeed_2700_intc_irqs;
434*ab24c6a2SJamin Lin     aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intc_irqs);
435d831c5fdSJamin Lin }
436d831c5fdSJamin Lin 
437d831c5fdSJamin Lin static const TypeInfo aspeed_2700_intc_info = {
438d831c5fdSJamin Lin     .name = TYPE_ASPEED_2700_INTC,
439d831c5fdSJamin Lin     .parent = TYPE_ASPEED_INTC,
440d831c5fdSJamin Lin     .class_init = aspeed_2700_intc_class_init,
441d831c5fdSJamin Lin };
442d831c5fdSJamin Lin 
443d831c5fdSJamin Lin static void aspeed_intc_register_types(void)
444d831c5fdSJamin Lin {
445d831c5fdSJamin Lin     type_register_static(&aspeed_intc_info);
446d831c5fdSJamin Lin     type_register_static(&aspeed_2700_intc_info);
447d831c5fdSJamin Lin }
448d831c5fdSJamin Lin 
449d831c5fdSJamin Lin type_init(aspeed_intc_register_types);
450