xref: /qemu/hw/intc/aspeed_intc.c (revision 8872b6717c37001e8f2e6c4ed0af20b1811d8f58)
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)
429178ff91SJamin Lin REG32(GICINT192_201_EN,         0xB00)
439178ff91SJamin Lin REG32(GICINT192_201_STATUS,     0xB04)
44d831c5fdSJamin Lin 
4538ba38d8SJamin Lin /*
4638ba38d8SJamin Lin  * INTCIO Registers
4738ba38d8SJamin Lin  *
4838ba38d8SJamin Lin  * values below are offset by - 0x100 from datasheet
4938ba38d8SJamin Lin  * because its memory region is start at 0x100
5038ba38d8SJamin Lin  *
5138ba38d8SJamin Lin  */
5238ba38d8SJamin Lin REG32(GICINT192_EN,         0x00)
5338ba38d8SJamin Lin REG32(GICINT192_STATUS,     0x04)
5438ba38d8SJamin Lin REG32(GICINT193_EN,         0x10)
5538ba38d8SJamin Lin REG32(GICINT193_STATUS,     0x14)
5638ba38d8SJamin Lin REG32(GICINT194_EN,         0x20)
5738ba38d8SJamin Lin REG32(GICINT194_STATUS,     0x24)
5838ba38d8SJamin Lin REG32(GICINT195_EN,         0x30)
5938ba38d8SJamin Lin REG32(GICINT195_STATUS,     0x34)
6038ba38d8SJamin Lin REG32(GICINT196_EN,         0x40)
6138ba38d8SJamin Lin REG32(GICINT196_STATUS,     0x44)
6238ba38d8SJamin Lin REG32(GICINT197_EN,         0x50)
6338ba38d8SJamin Lin REG32(GICINT197_STATUS,     0x54)
6438ba38d8SJamin Lin 
65*8872b671SSteven Lee /*
66*8872b671SSteven Lee  * SSP INTC Registers
67*8872b671SSteven Lee  */
68*8872b671SSteven Lee REG32(SSPINT128_EN,             0x2000)
69*8872b671SSteven Lee REG32(SSPINT128_STATUS,         0x2004)
70*8872b671SSteven Lee REG32(SSPINT129_EN,             0x2100)
71*8872b671SSteven Lee REG32(SSPINT129_STATUS,         0x2104)
72*8872b671SSteven Lee REG32(SSPINT130_EN,             0x2200)
73*8872b671SSteven Lee REG32(SSPINT130_STATUS,         0x2204)
74*8872b671SSteven Lee REG32(SSPINT131_EN,             0x2300)
75*8872b671SSteven Lee REG32(SSPINT131_STATUS,         0x2304)
76*8872b671SSteven Lee REG32(SSPINT132_EN,             0x2400)
77*8872b671SSteven Lee REG32(SSPINT132_STATUS,         0x2404)
78*8872b671SSteven Lee REG32(SSPINT133_EN,             0x2500)
79*8872b671SSteven Lee REG32(SSPINT133_STATUS,         0x2504)
80*8872b671SSteven Lee REG32(SSPINT134_EN,             0x2600)
81*8872b671SSteven Lee REG32(SSPINT134_STATUS,         0x2604)
82*8872b671SSteven Lee REG32(SSPINT135_EN,             0x2700)
83*8872b671SSteven Lee REG32(SSPINT135_STATUS,         0x2704)
84*8872b671SSteven Lee REG32(SSPINT136_EN,             0x2800)
85*8872b671SSteven Lee REG32(SSPINT136_STATUS,         0x2804)
86*8872b671SSteven Lee REG32(SSPINT137_EN,             0x2900)
87*8872b671SSteven Lee REG32(SSPINT137_STATUS,         0x2904)
88*8872b671SSteven Lee REG32(SSPINT138_EN,             0x2A00)
89*8872b671SSteven Lee REG32(SSPINT138_STATUS,         0x2A04)
90*8872b671SSteven Lee REG32(SSPINT160_169_EN,         0x2B00)
91*8872b671SSteven Lee REG32(SSPINT160_169_STATUS,     0x2B04)
92*8872b671SSteven Lee 
93*8872b671SSteven Lee /*
94*8872b671SSteven Lee  * SSP INTCIO Registers
95*8872b671SSteven Lee  */
96*8872b671SSteven Lee REG32(SSPINT160_EN,         0x180)
97*8872b671SSteven Lee REG32(SSPINT160_STATUS,     0x184)
98*8872b671SSteven Lee REG32(SSPINT161_EN,         0x190)
99*8872b671SSteven Lee REG32(SSPINT161_STATUS,     0x194)
100*8872b671SSteven Lee REG32(SSPINT162_EN,         0x1A0)
101*8872b671SSteven Lee REG32(SSPINT162_STATUS,     0x1A4)
102*8872b671SSteven Lee REG32(SSPINT163_EN,         0x1B0)
103*8872b671SSteven Lee REG32(SSPINT163_STATUS,     0x1B4)
104*8872b671SSteven Lee REG32(SSPINT164_EN,         0x1C0)
105*8872b671SSteven Lee REG32(SSPINT164_STATUS,     0x1C4)
106*8872b671SSteven Lee REG32(SSPINT165_EN,         0x1D0)
107*8872b671SSteven Lee REG32(SSPINT165_STATUS,     0x1D4)
108*8872b671SSteven Lee 
109ab24c6a2SJamin Lin static const AspeedINTCIRQ *aspeed_intc_get_irq(AspeedINTCClass *aic,
110ab24c6a2SJamin Lin                                                 uint32_t reg)
111ab24c6a2SJamin Lin {
112ab24c6a2SJamin Lin     int i;
113ab24c6a2SJamin Lin 
114ab24c6a2SJamin Lin     for (i = 0; i < aic->irq_table_count; i++) {
115ab24c6a2SJamin Lin         if (aic->irq_table[i].enable_reg == reg ||
116ab24c6a2SJamin Lin             aic->irq_table[i].status_reg == reg) {
117ab24c6a2SJamin Lin             return &aic->irq_table[i];
118ab24c6a2SJamin Lin         }
119ab24c6a2SJamin Lin     }
120ab24c6a2SJamin Lin 
121ab24c6a2SJamin Lin     /*
122ab24c6a2SJamin Lin      * Invalid reg.
123ab24c6a2SJamin Lin      */
124ab24c6a2SJamin Lin     g_assert_not_reached();
125ab24c6a2SJamin Lin }
126d831c5fdSJamin Lin 
127c6c5e63dSJamin Lin /*
128c6c5e63dSJamin Lin  * Update the state of an interrupt controller pin by setting
129c6c5e63dSJamin Lin  * the specified output pin to the given level.
130c6c5e63dSJamin Lin  * The input pin index should be between 0 and the number of input pins.
131c6c5e63dSJamin Lin  * The output pin index should be between 0 and the number of output pins.
132c6c5e63dSJamin Lin  */
133c6c5e63dSJamin Lin static void aspeed_intc_update(AspeedINTCState *s, int inpin_idx,
134c6c5e63dSJamin Lin                                int outpin_idx, int level)
135d831c5fdSJamin Lin {
136d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
13749da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
138d831c5fdSJamin Lin 
139ab24c6a2SJamin Lin     assert((outpin_idx < aic->num_outpins) && (inpin_idx < aic->num_inpins));
140c6c5e63dSJamin Lin 
141c6c5e63dSJamin Lin     trace_aspeed_intc_update_irq(name, inpin_idx, outpin_idx, level);
142c6c5e63dSJamin Lin     qemu_set_irq(s->output_pins[outpin_idx], level);
143d831c5fdSJamin Lin }
144d831c5fdSJamin Lin 
1455824e8bfSJamin Lin static void aspeed_intc_set_irq_handler(AspeedINTCState *s,
1465824e8bfSJamin Lin                                         const AspeedINTCIRQ *intc_irq,
1475824e8bfSJamin Lin                                         uint32_t select)
148d831c5fdSJamin Lin {
14949da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
150ab24c6a2SJamin Lin     uint32_t status_reg;
151c6c5e63dSJamin Lin     int outpin_idx;
152c6c5e63dSJamin Lin     int inpin_idx;
153d831c5fdSJamin Lin 
154ab24c6a2SJamin Lin     status_reg = intc_irq->status_reg;
155ab24c6a2SJamin Lin     outpin_idx = intc_irq->outpin_idx;
156ab24c6a2SJamin Lin     inpin_idx = intc_irq->inpin_idx;
157d831c5fdSJamin Lin 
1587b8cbe51SSteven Lee     if ((s->mask[inpin_idx] & select) || (s->regs[status_reg] & select)) {
159d831c5fdSJamin Lin         /*
160d831c5fdSJamin Lin          * a. mask is not 0 means in ISR mode
161d831c5fdSJamin Lin          * sources interrupt routine are executing.
162d831c5fdSJamin Lin          * b. status register value is not 0 means previous
163d831c5fdSJamin Lin          * source interrupt does not be executed, yet.
164d831c5fdSJamin Lin          *
165d831c5fdSJamin Lin          * save source interrupt to pending variable.
166d831c5fdSJamin Lin          */
167c6c5e63dSJamin Lin         s->pending[inpin_idx] |= select;
168c6c5e63dSJamin Lin         trace_aspeed_intc_pending_irq(name, inpin_idx, s->pending[inpin_idx]);
169d831c5fdSJamin Lin     } else {
170d831c5fdSJamin Lin         /*
171d831c5fdSJamin Lin          * notify firmware which source interrupt are coming
172d831c5fdSJamin Lin          * by setting status register
173d831c5fdSJamin Lin          */
1740cffaaceSJamin Lin         s->regs[status_reg] = select;
175c6c5e63dSJamin Lin         trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
176c6c5e63dSJamin Lin                                       s->regs[status_reg]);
177c6c5e63dSJamin Lin         aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
178d831c5fdSJamin Lin     }
179d831c5fdSJamin Lin }
180d831c5fdSJamin Lin 
1819178ff91SJamin Lin static void aspeed_intc_set_irq_handler_multi_outpins(AspeedINTCState *s,
1829178ff91SJamin Lin                                  const AspeedINTCIRQ *intc_irq, uint32_t select)
1839178ff91SJamin Lin {
1849178ff91SJamin Lin     const char *name = object_get_typename(OBJECT(s));
1859178ff91SJamin Lin     uint32_t status_reg;
1869178ff91SJamin Lin     int num_outpins;
1879178ff91SJamin Lin     int outpin_idx;
1889178ff91SJamin Lin     int inpin_idx;
1899178ff91SJamin Lin     int i;
1909178ff91SJamin Lin 
1919178ff91SJamin Lin     num_outpins = intc_irq->num_outpins;
1929178ff91SJamin Lin     status_reg = intc_irq->status_reg;
1939178ff91SJamin Lin     outpin_idx = intc_irq->outpin_idx;
1949178ff91SJamin Lin     inpin_idx = intc_irq->inpin_idx;
1959178ff91SJamin Lin 
1969178ff91SJamin Lin     for (i = 0; i < num_outpins; i++) {
1979178ff91SJamin Lin         if (select & BIT(i)) {
1989178ff91SJamin Lin             if (s->mask[inpin_idx] & BIT(i) ||
1999178ff91SJamin Lin                 s->regs[status_reg] & BIT(i)) {
2005824e8bfSJamin Lin                 /*
2019178ff91SJamin Lin                  * a. mask bit is not 0 means in ISR mode sources interrupt
2029178ff91SJamin Lin                  * routine are executing.
2039178ff91SJamin Lin                  * b. status bit is not 0 means previous source interrupt
2049178ff91SJamin Lin                  * does not be executed, yet.
2059178ff91SJamin Lin                  *
2069178ff91SJamin Lin                  * save source interrupt to pending bit.
2079178ff91SJamin Lin                  */
2089178ff91SJamin Lin                  s->pending[inpin_idx] |= BIT(i);
2099178ff91SJamin Lin                  trace_aspeed_intc_pending_irq(name, inpin_idx,
2109178ff91SJamin Lin                                                s->pending[inpin_idx]);
2119178ff91SJamin Lin             } else {
2129178ff91SJamin Lin                 /*
2139178ff91SJamin Lin                  * notify firmware which source interrupt are coming
2149178ff91SJamin Lin                  * by setting status bit
2159178ff91SJamin Lin                  */
2169178ff91SJamin Lin                 s->regs[status_reg] |= BIT(i);
2179178ff91SJamin Lin                 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx + i,
2189178ff91SJamin Lin                                               s->regs[status_reg]);
2199178ff91SJamin Lin                 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 1);
2209178ff91SJamin Lin             }
2219178ff91SJamin Lin         }
2229178ff91SJamin Lin     }
2239178ff91SJamin Lin }
2249178ff91SJamin Lin 
2259178ff91SJamin Lin /*
2269178ff91SJamin Lin  * GICINT192_201 maps 1:10 to input IRQ 0 and output IRQs 0 to 9.
2279178ff91SJamin Lin  * GICINT128 to GICINT136 map 1:1 to input IRQs 1 to 9 and output
2289178ff91SJamin Lin  * IRQs 10 to 18. The value of input IRQ should be between 0 and
2299178ff91SJamin Lin  * the number of input pins.
2305824e8bfSJamin Lin  */
2315824e8bfSJamin Lin static void aspeed_intc_set_irq(void *opaque, int irq, int level)
2325824e8bfSJamin Lin {
2335824e8bfSJamin Lin     AspeedINTCState *s = (AspeedINTCState *)opaque;
2345824e8bfSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
2355824e8bfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
2365824e8bfSJamin Lin     const AspeedINTCIRQ *intc_irq;
2375824e8bfSJamin Lin     uint32_t select = 0;
2385824e8bfSJamin Lin     uint32_t enable;
2399178ff91SJamin Lin     int num_outpins;
2405824e8bfSJamin Lin     int inpin_idx;
2415824e8bfSJamin Lin     int i;
2425824e8bfSJamin Lin 
2435824e8bfSJamin Lin     assert(irq < aic->num_inpins);
2445824e8bfSJamin Lin 
2455824e8bfSJamin Lin     intc_irq = &aic->irq_table[irq];
2469178ff91SJamin Lin     num_outpins = intc_irq->num_outpins;
2475824e8bfSJamin Lin     inpin_idx = intc_irq->inpin_idx;
2485824e8bfSJamin Lin     trace_aspeed_intc_set_irq(name, inpin_idx, level);
2495824e8bfSJamin Lin     enable = s->enable[inpin_idx];
2505824e8bfSJamin Lin 
2515824e8bfSJamin Lin     if (!level) {
2525824e8bfSJamin Lin         return;
2535824e8bfSJamin Lin     }
2545824e8bfSJamin Lin 
2555824e8bfSJamin Lin     for (i = 0; i < aic->num_lines; i++) {
2565824e8bfSJamin Lin         if (s->orgates[inpin_idx].levels[i]) {
2575824e8bfSJamin Lin             if (enable & BIT(i)) {
2585824e8bfSJamin Lin                 select |= BIT(i);
2595824e8bfSJamin Lin             }
2605824e8bfSJamin Lin         }
2615824e8bfSJamin Lin     }
2625824e8bfSJamin Lin 
2635824e8bfSJamin Lin     if (!select) {
2645824e8bfSJamin Lin         return;
2655824e8bfSJamin Lin     }
2665824e8bfSJamin Lin 
2675824e8bfSJamin Lin     trace_aspeed_intc_select(name, select);
2689178ff91SJamin Lin     if (num_outpins > 1) {
2699178ff91SJamin Lin         aspeed_intc_set_irq_handler_multi_outpins(s, intc_irq, select);
2709178ff91SJamin Lin     } else {
2715824e8bfSJamin Lin         aspeed_intc_set_irq_handler(s, intc_irq, select);
2725824e8bfSJamin Lin     }
2739178ff91SJamin Lin }
2745824e8bfSJamin Lin 
2753d6e15eaSJamin Lin static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset,
2763d6e15eaSJamin Lin                                        uint64_t data)
277d831c5fdSJamin Lin {
278d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
27949da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
280ab24c6a2SJamin Lin     const AspeedINTCIRQ *intc_irq;
2810cffaaceSJamin Lin     uint32_t reg = offset >> 2;
282d831c5fdSJamin Lin     uint32_t old_enable;
283d831c5fdSJamin Lin     uint32_t change;
284c6c5e63dSJamin Lin     int inpin_idx;
285d831c5fdSJamin Lin 
286ab24c6a2SJamin Lin     intc_irq = aspeed_intc_get_irq(aic, reg);
287ab24c6a2SJamin Lin     inpin_idx = intc_irq->inpin_idx;
288d831c5fdSJamin Lin 
289ab24c6a2SJamin Lin     assert(inpin_idx < aic->num_inpins);
290d831c5fdSJamin Lin 
291d831c5fdSJamin Lin     /*
2923d6e15eaSJamin Lin      * The enable registers are used to enable source interrupts.
2933d6e15eaSJamin Lin      * They also handle masking and unmasking of source interrupts
2943d6e15eaSJamin Lin      * during the execution of the source ISR.
295d831c5fdSJamin Lin      */
296d831c5fdSJamin Lin 
297d831c5fdSJamin Lin     /* disable all source interrupt */
298c6c5e63dSJamin Lin     if (!data && !s->enable[inpin_idx]) {
2990cffaaceSJamin Lin         s->regs[reg] = data;
300d831c5fdSJamin Lin         return;
301d831c5fdSJamin Lin     }
302d831c5fdSJamin Lin 
303c6c5e63dSJamin Lin     old_enable = s->enable[inpin_idx];
304c6c5e63dSJamin Lin     s->enable[inpin_idx] |= data;
305d831c5fdSJamin Lin 
306d831c5fdSJamin Lin     /* enable new source interrupt */
307c6c5e63dSJamin Lin     if (old_enable != s->enable[inpin_idx]) {
308c6c5e63dSJamin Lin         trace_aspeed_intc_enable(name, s->enable[inpin_idx]);
3090cffaaceSJamin Lin         s->regs[reg] = data;
310d831c5fdSJamin Lin         return;
311d831c5fdSJamin Lin     }
312d831c5fdSJamin Lin 
313d831c5fdSJamin Lin     /* mask and unmask source interrupt */
3140cffaaceSJamin Lin     change = s->regs[reg] ^ data;
315d831c5fdSJamin Lin     if (change & data) {
316c6c5e63dSJamin Lin         s->mask[inpin_idx] &= ~change;
317c6c5e63dSJamin Lin         trace_aspeed_intc_unmask(name, change, s->mask[inpin_idx]);
318d831c5fdSJamin Lin     } else {
319c6c5e63dSJamin Lin         s->mask[inpin_idx] |= change;
320c6c5e63dSJamin Lin         trace_aspeed_intc_mask(name, change, s->mask[inpin_idx]);
321d831c5fdSJamin Lin     }
3223d6e15eaSJamin Lin 
3230cffaaceSJamin Lin     s->regs[reg] = data;
3243d6e15eaSJamin Lin }
3253d6e15eaSJamin Lin 
3263d6e15eaSJamin Lin static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset,
3273d6e15eaSJamin Lin                                        uint64_t data)
3283d6e15eaSJamin Lin {
3293d6e15eaSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
33049da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
331ab24c6a2SJamin Lin     const AspeedINTCIRQ *intc_irq;
3323d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
333c6c5e63dSJamin Lin     int outpin_idx;
334c6c5e63dSJamin Lin     int inpin_idx;
3353d6e15eaSJamin Lin 
3363d6e15eaSJamin Lin     if (!data) {
3373d6e15eaSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
3383d6e15eaSJamin Lin         return;
3393d6e15eaSJamin Lin     }
3403d6e15eaSJamin Lin 
341ab24c6a2SJamin Lin     intc_irq = aspeed_intc_get_irq(aic, reg);
342ab24c6a2SJamin Lin     outpin_idx = intc_irq->outpin_idx;
343ab24c6a2SJamin Lin     inpin_idx = intc_irq->inpin_idx;
344d831c5fdSJamin Lin 
345ab24c6a2SJamin Lin     assert(inpin_idx < aic->num_inpins);
346d831c5fdSJamin Lin 
347d831c5fdSJamin Lin     /* clear status */
3480cffaaceSJamin Lin     s->regs[reg] &= ~data;
349d831c5fdSJamin Lin 
350d831c5fdSJamin Lin     /*
351d831c5fdSJamin Lin      * These status registers are used for notify sources ISR are executed.
352d831c5fdSJamin Lin      * If one source ISR is executed, it will clear one bit.
353d831c5fdSJamin Lin      * If it clear all bits, it means to initialize this register status
354d831c5fdSJamin Lin      * rather than sources ISR are executed.
355d831c5fdSJamin Lin      */
356d831c5fdSJamin Lin     if (data == 0xffffffff) {
357d831c5fdSJamin Lin         return;
358d831c5fdSJamin Lin     }
359d831c5fdSJamin Lin 
360d831c5fdSJamin Lin     /* All source ISR execution are done */
3610cffaaceSJamin Lin     if (!s->regs[reg]) {
362c6c5e63dSJamin Lin         trace_aspeed_intc_all_isr_done(name, inpin_idx);
363c6c5e63dSJamin Lin         if (s->pending[inpin_idx]) {
364d831c5fdSJamin Lin             /*
365d831c5fdSJamin Lin              * handle pending source interrupt
366d831c5fdSJamin Lin              * notify firmware which source interrupt are pending
367d831c5fdSJamin Lin              * by setting status register
368d831c5fdSJamin Lin              */
369c6c5e63dSJamin Lin             s->regs[reg] = s->pending[inpin_idx];
370c6c5e63dSJamin Lin             s->pending[inpin_idx] = 0;
371c6c5e63dSJamin Lin             trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
372c6c5e63dSJamin Lin                                           s->regs[reg]);
373c6c5e63dSJamin Lin             aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
374d831c5fdSJamin Lin         } else {
375d831c5fdSJamin Lin             /* clear irq */
376c6c5e63dSJamin Lin             trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx, 0);
377c6c5e63dSJamin Lin             aspeed_intc_update(s, inpin_idx, outpin_idx, 0);
378d831c5fdSJamin Lin         }
379d831c5fdSJamin Lin     }
3803d6e15eaSJamin Lin }
3813d6e15eaSJamin Lin 
3829178ff91SJamin Lin static void aspeed_intc_status_handler_multi_outpins(AspeedINTCState *s,
3839178ff91SJamin Lin                                                 hwaddr offset, uint64_t data)
3849178ff91SJamin Lin {
3859178ff91SJamin Lin     const char *name = object_get_typename(OBJECT(s));
3869178ff91SJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
3879178ff91SJamin Lin     const AspeedINTCIRQ *intc_irq;
3889178ff91SJamin Lin     uint32_t reg = offset >> 2;
3899178ff91SJamin Lin     int num_outpins;
3909178ff91SJamin Lin     int outpin_idx;
3919178ff91SJamin Lin     int inpin_idx;
3929178ff91SJamin Lin     int i;
3939178ff91SJamin Lin 
3949178ff91SJamin Lin     if (!data) {
3959178ff91SJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
3969178ff91SJamin Lin         return;
3979178ff91SJamin Lin     }
3989178ff91SJamin Lin 
3999178ff91SJamin Lin     intc_irq = aspeed_intc_get_irq(aic, reg);
4009178ff91SJamin Lin     num_outpins = intc_irq->num_outpins;
4019178ff91SJamin Lin     outpin_idx = intc_irq->outpin_idx;
4029178ff91SJamin Lin     inpin_idx = intc_irq->inpin_idx;
4039178ff91SJamin Lin     assert(inpin_idx < aic->num_inpins);
4049178ff91SJamin Lin 
4059178ff91SJamin Lin     /* clear status */
4069178ff91SJamin Lin     s->regs[reg] &= ~data;
4079178ff91SJamin Lin 
4089178ff91SJamin Lin     /*
4099178ff91SJamin Lin      * The status registers are used for notify sources ISR are executed.
4109178ff91SJamin Lin      * If one source ISR is executed, it will clear one bit.
4119178ff91SJamin Lin      * If it clear all bits, it means to initialize this register status
4129178ff91SJamin Lin      * rather than sources ISR are executed.
4139178ff91SJamin Lin      */
4149178ff91SJamin Lin     if (data == 0xffffffff) {
4159178ff91SJamin Lin         return;
4169178ff91SJamin Lin     }
4179178ff91SJamin Lin 
4189178ff91SJamin Lin     for (i = 0; i < num_outpins; i++) {
4199178ff91SJamin Lin         /* All source ISR executions are done from a specific bit */
4209178ff91SJamin Lin         if (data & BIT(i)) {
4219178ff91SJamin Lin             trace_aspeed_intc_all_isr_done_bit(name, inpin_idx, i);
4229178ff91SJamin Lin             if (s->pending[inpin_idx] & BIT(i)) {
4239178ff91SJamin Lin                 /*
4249178ff91SJamin Lin                  * Handle pending source interrupt.
4259178ff91SJamin Lin                  * Notify firmware which source interrupt is pending
4269178ff91SJamin Lin                  * by setting the status bit.
4279178ff91SJamin Lin                  */
4289178ff91SJamin Lin                 s->regs[reg] |= BIT(i);
4299178ff91SJamin Lin                 s->pending[inpin_idx] &= ~BIT(i);
4309178ff91SJamin Lin                 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx + i,
4319178ff91SJamin Lin                                               s->regs[reg]);
4329178ff91SJamin Lin                 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 1);
4339178ff91SJamin Lin             } else {
4349178ff91SJamin Lin                 /* clear irq for the specific bit */
4359178ff91SJamin Lin                 trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx + i, 0);
4369178ff91SJamin Lin                 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 0);
4379178ff91SJamin Lin             }
4389178ff91SJamin Lin         }
4399178ff91SJamin Lin     }
4409178ff91SJamin Lin }
4419178ff91SJamin Lin 
4423d6e15eaSJamin Lin static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
4433d6e15eaSJamin Lin {
4443d6e15eaSJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
44549da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
4463d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
4473d6e15eaSJamin Lin     uint32_t value = 0;
4483d6e15eaSJamin Lin 
4493d6e15eaSJamin Lin     value = s->regs[reg];
45049da40cfSJamin Lin     trace_aspeed_intc_read(name, offset, size, value);
4513d6e15eaSJamin Lin 
4523d6e15eaSJamin Lin     return value;
4533d6e15eaSJamin Lin }
4543d6e15eaSJamin Lin 
4553d6e15eaSJamin Lin static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
4563d6e15eaSJamin Lin                                         unsigned size)
4573d6e15eaSJamin Lin {
4583d6e15eaSJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
45949da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
4603d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
4613d6e15eaSJamin Lin 
46249da40cfSJamin Lin     trace_aspeed_intc_write(name, offset, size, data);
4633d6e15eaSJamin Lin 
4643d6e15eaSJamin Lin     switch (reg) {
4653d6e15eaSJamin Lin     case R_GICINT128_EN:
4663d6e15eaSJamin Lin     case R_GICINT129_EN:
4673d6e15eaSJamin Lin     case R_GICINT130_EN:
4683d6e15eaSJamin Lin     case R_GICINT131_EN:
4693d6e15eaSJamin Lin     case R_GICINT132_EN:
4703d6e15eaSJamin Lin     case R_GICINT133_EN:
4713d6e15eaSJamin Lin     case R_GICINT134_EN:
4723d6e15eaSJamin Lin     case R_GICINT135_EN:
4733d6e15eaSJamin Lin     case R_GICINT136_EN:
4749178ff91SJamin Lin     case R_GICINT192_201_EN:
4753d6e15eaSJamin Lin         aspeed_intc_enable_handler(s, offset, data);
4763d6e15eaSJamin Lin         break;
4773d6e15eaSJamin Lin     case R_GICINT128_STATUS:
4783d6e15eaSJamin Lin     case R_GICINT129_STATUS:
4793d6e15eaSJamin Lin     case R_GICINT130_STATUS:
4803d6e15eaSJamin Lin     case R_GICINT131_STATUS:
4813d6e15eaSJamin Lin     case R_GICINT132_STATUS:
4823d6e15eaSJamin Lin     case R_GICINT133_STATUS:
4833d6e15eaSJamin Lin     case R_GICINT134_STATUS:
4843d6e15eaSJamin Lin     case R_GICINT135_STATUS:
4853d6e15eaSJamin Lin     case R_GICINT136_STATUS:
4863d6e15eaSJamin Lin         aspeed_intc_status_handler(s, offset, data);
487d831c5fdSJamin Lin         break;
4889178ff91SJamin Lin     case R_GICINT192_201_STATUS:
4899178ff91SJamin Lin         aspeed_intc_status_handler_multi_outpins(s, offset, data);
4909178ff91SJamin Lin         break;
491d831c5fdSJamin Lin     default:
4920cffaaceSJamin Lin         s->regs[reg] = data;
493d831c5fdSJamin Lin         break;
494d831c5fdSJamin Lin     }
495d831c5fdSJamin Lin }
496d831c5fdSJamin Lin 
497*8872b671SSteven Lee static void aspeed_ssp_intc_write(void *opaque, hwaddr offset, uint64_t data,
498*8872b671SSteven Lee                                         unsigned size)
499*8872b671SSteven Lee {
500*8872b671SSteven Lee     AspeedINTCState *s = ASPEED_INTC(opaque);
501*8872b671SSteven Lee     const char *name = object_get_typename(OBJECT(s));
502*8872b671SSteven Lee     uint32_t reg = offset >> 2;
503*8872b671SSteven Lee 
504*8872b671SSteven Lee     trace_aspeed_intc_write(name, offset, size, data);
505*8872b671SSteven Lee 
506*8872b671SSteven Lee     switch (reg) {
507*8872b671SSteven Lee     case R_SSPINT128_EN:
508*8872b671SSteven Lee     case R_SSPINT129_EN:
509*8872b671SSteven Lee     case R_SSPINT130_EN:
510*8872b671SSteven Lee     case R_SSPINT131_EN:
511*8872b671SSteven Lee     case R_SSPINT132_EN:
512*8872b671SSteven Lee     case R_SSPINT133_EN:
513*8872b671SSteven Lee     case R_SSPINT134_EN:
514*8872b671SSteven Lee     case R_SSPINT135_EN:
515*8872b671SSteven Lee     case R_SSPINT136_EN:
516*8872b671SSteven Lee     case R_SSPINT160_169_EN:
517*8872b671SSteven Lee         aspeed_intc_enable_handler(s, offset, data);
518*8872b671SSteven Lee         break;
519*8872b671SSteven Lee     case R_SSPINT128_STATUS:
520*8872b671SSteven Lee     case R_SSPINT129_STATUS:
521*8872b671SSteven Lee     case R_SSPINT130_STATUS:
522*8872b671SSteven Lee     case R_SSPINT131_STATUS:
523*8872b671SSteven Lee     case R_SSPINT132_STATUS:
524*8872b671SSteven Lee     case R_SSPINT133_STATUS:
525*8872b671SSteven Lee     case R_SSPINT134_STATUS:
526*8872b671SSteven Lee     case R_SSPINT135_STATUS:
527*8872b671SSteven Lee     case R_SSPINT136_STATUS:
528*8872b671SSteven Lee         aspeed_intc_status_handler(s, offset, data);
529*8872b671SSteven Lee         break;
530*8872b671SSteven Lee     case R_SSPINT160_169_STATUS:
531*8872b671SSteven Lee         aspeed_intc_status_handler_multi_outpins(s, offset, data);
532*8872b671SSteven Lee         break;
533*8872b671SSteven Lee     default:
534*8872b671SSteven Lee         s->regs[reg] = data;
535*8872b671SSteven Lee         break;
536*8872b671SSteven Lee     }
537*8872b671SSteven Lee 
538*8872b671SSteven Lee     return;
539*8872b671SSteven Lee }
540*8872b671SSteven Lee 
54138ba38d8SJamin Lin static uint64_t aspeed_intcio_read(void *opaque, hwaddr offset,
54238ba38d8SJamin Lin                                    unsigned int size)
54338ba38d8SJamin Lin {
54438ba38d8SJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
54538ba38d8SJamin Lin     const char *name = object_get_typename(OBJECT(s));
54638ba38d8SJamin Lin     uint32_t reg = offset >> 2;
54738ba38d8SJamin Lin     uint32_t value = 0;
54838ba38d8SJamin Lin 
54938ba38d8SJamin Lin     value = s->regs[reg];
55038ba38d8SJamin Lin     trace_aspeed_intc_read(name, offset, size, value);
55138ba38d8SJamin Lin 
55238ba38d8SJamin Lin     return value;
55338ba38d8SJamin Lin }
55438ba38d8SJamin Lin 
55538ba38d8SJamin Lin static void aspeed_intcio_write(void *opaque, hwaddr offset, uint64_t data,
55638ba38d8SJamin Lin                                 unsigned size)
55738ba38d8SJamin Lin {
55838ba38d8SJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
55938ba38d8SJamin Lin     const char *name = object_get_typename(OBJECT(s));
56038ba38d8SJamin Lin     uint32_t reg = offset >> 2;
56138ba38d8SJamin Lin 
56238ba38d8SJamin Lin     trace_aspeed_intc_write(name, offset, size, data);
56338ba38d8SJamin Lin 
56438ba38d8SJamin Lin     switch (reg) {
56538ba38d8SJamin Lin     case R_GICINT192_EN:
56638ba38d8SJamin Lin     case R_GICINT193_EN:
56738ba38d8SJamin Lin     case R_GICINT194_EN:
56838ba38d8SJamin Lin     case R_GICINT195_EN:
56938ba38d8SJamin Lin     case R_GICINT196_EN:
57038ba38d8SJamin Lin     case R_GICINT197_EN:
57138ba38d8SJamin Lin         aspeed_intc_enable_handler(s, offset, data);
57238ba38d8SJamin Lin         break;
57338ba38d8SJamin Lin     case R_GICINT192_STATUS:
57438ba38d8SJamin Lin     case R_GICINT193_STATUS:
57538ba38d8SJamin Lin     case R_GICINT194_STATUS:
57638ba38d8SJamin Lin     case R_GICINT195_STATUS:
57738ba38d8SJamin Lin     case R_GICINT196_STATUS:
57838ba38d8SJamin Lin     case R_GICINT197_STATUS:
57938ba38d8SJamin Lin         aspeed_intc_status_handler(s, offset, data);
58038ba38d8SJamin Lin         break;
58138ba38d8SJamin Lin     default:
58238ba38d8SJamin Lin         s->regs[reg] = data;
58338ba38d8SJamin Lin         break;
58438ba38d8SJamin Lin     }
58538ba38d8SJamin Lin }
58638ba38d8SJamin Lin 
587*8872b671SSteven Lee static void aspeed_ssp_intcio_write(void *opaque, hwaddr offset, uint64_t data,
588*8872b671SSteven Lee                                 unsigned size)
589*8872b671SSteven Lee {
590*8872b671SSteven Lee     AspeedINTCState *s = ASPEED_INTC(opaque);
591*8872b671SSteven Lee     const char *name = object_get_typename(OBJECT(s));
592*8872b671SSteven Lee     uint32_t reg = offset >> 2;
593*8872b671SSteven Lee 
594*8872b671SSteven Lee     trace_aspeed_intc_write(name, offset, size, data);
595*8872b671SSteven Lee 
596*8872b671SSteven Lee     switch (reg) {
597*8872b671SSteven Lee     case R_SSPINT160_EN:
598*8872b671SSteven Lee     case R_SSPINT161_EN:
599*8872b671SSteven Lee     case R_SSPINT162_EN:
600*8872b671SSteven Lee     case R_SSPINT163_EN:
601*8872b671SSteven Lee     case R_SSPINT164_EN:
602*8872b671SSteven Lee     case R_SSPINT165_EN:
603*8872b671SSteven Lee         aspeed_intc_enable_handler(s, offset, data);
604*8872b671SSteven Lee         break;
605*8872b671SSteven Lee     case R_SSPINT160_STATUS:
606*8872b671SSteven Lee     case R_SSPINT161_STATUS:
607*8872b671SSteven Lee     case R_SSPINT162_STATUS:
608*8872b671SSteven Lee     case R_SSPINT163_STATUS:
609*8872b671SSteven Lee     case R_SSPINT164_STATUS:
610*8872b671SSteven Lee     case R_SSPINT165_STATUS:
611*8872b671SSteven Lee         aspeed_intc_status_handler(s, offset, data);
612*8872b671SSteven Lee         break;
613*8872b671SSteven Lee     default:
614*8872b671SSteven Lee         s->regs[reg] = data;
615*8872b671SSteven Lee         break;
616*8872b671SSteven Lee     }
617*8872b671SSteven Lee 
618*8872b671SSteven Lee     return;
619*8872b671SSteven Lee }
62038ba38d8SJamin Lin 
621d831c5fdSJamin Lin static const MemoryRegionOps aspeed_intc_ops = {
622d831c5fdSJamin Lin     .read = aspeed_intc_read,
623d831c5fdSJamin Lin     .write = aspeed_intc_write,
624d831c5fdSJamin Lin     .endianness = DEVICE_LITTLE_ENDIAN,
625d831c5fdSJamin Lin     .valid = {
626d831c5fdSJamin Lin         .min_access_size = 4,
627d831c5fdSJamin Lin         .max_access_size = 4,
628d831c5fdSJamin Lin     }
629d831c5fdSJamin Lin };
630d831c5fdSJamin Lin 
63138ba38d8SJamin Lin static const MemoryRegionOps aspeed_intcio_ops = {
63238ba38d8SJamin Lin     .read = aspeed_intcio_read,
63338ba38d8SJamin Lin     .write = aspeed_intcio_write,
63438ba38d8SJamin Lin     .endianness = DEVICE_LITTLE_ENDIAN,
63538ba38d8SJamin Lin     .valid = {
63638ba38d8SJamin Lin         .min_access_size = 4,
63738ba38d8SJamin Lin         .max_access_size = 4,
63838ba38d8SJamin Lin     }
63938ba38d8SJamin Lin };
64038ba38d8SJamin Lin 
641*8872b671SSteven Lee static const MemoryRegionOps aspeed_ssp_intc_ops = {
642*8872b671SSteven Lee     .read = aspeed_intc_read,
643*8872b671SSteven Lee     .write = aspeed_ssp_intc_write,
644*8872b671SSteven Lee     .endianness = DEVICE_LITTLE_ENDIAN,
645*8872b671SSteven Lee     .valid = {
646*8872b671SSteven Lee         .min_access_size = 4,
647*8872b671SSteven Lee         .max_access_size = 4,
648*8872b671SSteven Lee     }
649*8872b671SSteven Lee };
650*8872b671SSteven Lee 
651*8872b671SSteven Lee static const MemoryRegionOps aspeed_ssp_intcio_ops = {
652*8872b671SSteven Lee     .read = aspeed_intcio_read,
653*8872b671SSteven Lee     .write = aspeed_ssp_intcio_write,
654*8872b671SSteven Lee     .endianness = DEVICE_LITTLE_ENDIAN,
655*8872b671SSteven Lee     .valid = {
656*8872b671SSteven Lee         .min_access_size = 4,
657*8872b671SSteven Lee         .max_access_size = 4,
658*8872b671SSteven Lee     }
659*8872b671SSteven Lee };
660*8872b671SSteven Lee 
661d831c5fdSJamin Lin static void aspeed_intc_instance_init(Object *obj)
662d831c5fdSJamin Lin {
663d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(obj);
664d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
665d831c5fdSJamin Lin     int i;
666d831c5fdSJamin Lin 
66763f3618fSJamin Lin     assert(aic->num_inpins <= ASPEED_INTC_MAX_INPINS);
66863f3618fSJamin Lin     for (i = 0; i < aic->num_inpins; i++) {
669d831c5fdSJamin Lin         object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i],
670d831c5fdSJamin Lin                                 TYPE_OR_IRQ);
671d831c5fdSJamin Lin         object_property_set_int(OBJECT(&s->orgates[i]), "num-lines",
672d831c5fdSJamin Lin                                 aic->num_lines, &error_abort);
673d831c5fdSJamin Lin     }
674d831c5fdSJamin Lin }
675d831c5fdSJamin Lin 
676d831c5fdSJamin Lin static void aspeed_intc_reset(DeviceState *dev)
677d831c5fdSJamin Lin {
678d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
679b008465dSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
680d831c5fdSJamin Lin 
681b008465dSJamin Lin     memset(s->regs, 0, aic->nr_regs << 2);
682d831c5fdSJamin Lin     memset(s->enable, 0, sizeof(s->enable));
683d831c5fdSJamin Lin     memset(s->mask, 0, sizeof(s->mask));
684d831c5fdSJamin Lin     memset(s->pending, 0, sizeof(s->pending));
685d831c5fdSJamin Lin }
686d831c5fdSJamin Lin 
687d831c5fdSJamin Lin static void aspeed_intc_realize(DeviceState *dev, Error **errp)
688d831c5fdSJamin Lin {
689d831c5fdSJamin Lin     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
690d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
691d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
692d831c5fdSJamin Lin     int i;
693d831c5fdSJamin Lin 
694c5728c34SJamin Lin     memory_region_init(&s->iomem_container, OBJECT(s),
695c5728c34SJamin Lin             TYPE_ASPEED_INTC ".container", aic->mem_size);
696c5728c34SJamin Lin 
697c5728c34SJamin Lin     sysbus_init_mmio(sbd, &s->iomem_container);
698c5728c34SJamin Lin 
699b008465dSJamin Lin     s->regs = g_new(uint32_t, aic->nr_regs);
70028194d5dSJamin Lin     memory_region_init_io(&s->iomem, OBJECT(s), aic->reg_ops, s,
701b008465dSJamin Lin                           TYPE_ASPEED_INTC ".regs", aic->nr_regs << 2);
702d831c5fdSJamin Lin 
7037ffee511SJamin Lin     memory_region_add_subregion(&s->iomem_container, aic->reg_offset,
7047ffee511SJamin Lin                                 &s->iomem);
705c5728c34SJamin Lin 
70663f3618fSJamin Lin     qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_inpins);
707d831c5fdSJamin Lin 
70863f3618fSJamin Lin     for (i = 0; i < aic->num_inpins; i++) {
709d831c5fdSJamin Lin         if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) {
710d831c5fdSJamin Lin             return;
711d831c5fdSJamin Lin         }
71235c909cdSJamin Lin     }
71335c909cdSJamin Lin 
71435c909cdSJamin Lin     for (i = 0; i < aic->num_outpins; i++) {
715d831c5fdSJamin Lin         sysbus_init_irq(sbd, &s->output_pins[i]);
716d831c5fdSJamin Lin     }
717d831c5fdSJamin Lin }
718d831c5fdSJamin Lin 
719563afea0SJamin Lin static void aspeed_intc_unrealize(DeviceState *dev)
720563afea0SJamin Lin {
721563afea0SJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
722563afea0SJamin Lin 
723563afea0SJamin Lin     g_free(s->regs);
724563afea0SJamin Lin     s->regs = NULL;
725563afea0SJamin Lin }
726563afea0SJamin Lin 
72712d1a768SPhilippe Mathieu-Daudé static void aspeed_intc_class_init(ObjectClass *klass, const void *data)
728d831c5fdSJamin Lin {
729d831c5fdSJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
73028194d5dSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
731d831c5fdSJamin Lin 
732d831c5fdSJamin Lin     dc->desc = "ASPEED INTC Controller";
733d831c5fdSJamin Lin     dc->realize = aspeed_intc_realize;
734563afea0SJamin Lin     dc->unrealize = aspeed_intc_unrealize;
735e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, aspeed_intc_reset);
736d831c5fdSJamin Lin     dc->vmsd = NULL;
73728194d5dSJamin Lin 
73828194d5dSJamin Lin     aic->reg_ops = &aspeed_intc_ops;
739d831c5fdSJamin Lin }
740d831c5fdSJamin Lin 
741d831c5fdSJamin Lin static const TypeInfo aspeed_intc_info = {
742d831c5fdSJamin Lin     .name = TYPE_ASPEED_INTC,
743d831c5fdSJamin Lin     .parent = TYPE_SYS_BUS_DEVICE,
744d831c5fdSJamin Lin     .instance_init = aspeed_intc_instance_init,
745d831c5fdSJamin Lin     .instance_size = sizeof(AspeedINTCState),
746d831c5fdSJamin Lin     .class_init = aspeed_intc_class_init,
747d831c5fdSJamin Lin     .class_size = sizeof(AspeedINTCClass),
748d831c5fdSJamin Lin     .abstract = true,
749d831c5fdSJamin Lin };
750d831c5fdSJamin Lin 
751ab24c6a2SJamin Lin static AspeedINTCIRQ aspeed_2700_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
7529178ff91SJamin Lin     {0, 0, 10, R_GICINT192_201_EN, R_GICINT192_201_STATUS},
7539178ff91SJamin Lin     {1, 10, 1, R_GICINT128_EN, R_GICINT128_STATUS},
7549178ff91SJamin Lin     {2, 11, 1, R_GICINT129_EN, R_GICINT129_STATUS},
7559178ff91SJamin Lin     {3, 12, 1, R_GICINT130_EN, R_GICINT130_STATUS},
7569178ff91SJamin Lin     {4, 13, 1, R_GICINT131_EN, R_GICINT131_STATUS},
7579178ff91SJamin Lin     {5, 14, 1, R_GICINT132_EN, R_GICINT132_STATUS},
7589178ff91SJamin Lin     {6, 15, 1, R_GICINT133_EN, R_GICINT133_STATUS},
7599178ff91SJamin Lin     {7, 16, 1, R_GICINT134_EN, R_GICINT134_STATUS},
7609178ff91SJamin Lin     {8, 17, 1, R_GICINT135_EN, R_GICINT135_STATUS},
7619178ff91SJamin Lin     {9, 18, 1, R_GICINT136_EN, R_GICINT136_STATUS},
762ab24c6a2SJamin Lin };
763ab24c6a2SJamin Lin 
76412d1a768SPhilippe Mathieu-Daudé static void aspeed_2700_intc_class_init(ObjectClass *klass, const void *data)
765d831c5fdSJamin Lin {
766d831c5fdSJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
767d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
768d831c5fdSJamin Lin 
769d831c5fdSJamin Lin     dc->desc = "ASPEED 2700 INTC Controller";
770d831c5fdSJamin Lin     aic->num_lines = 32;
7719178ff91SJamin Lin     aic->num_inpins = 10;
7729178ff91SJamin Lin     aic->num_outpins = 19;
773c5728c34SJamin Lin     aic->mem_size = 0x4000;
7749178ff91SJamin Lin     aic->nr_regs = 0xB08 >> 2;
7757ffee511SJamin Lin     aic->reg_offset = 0x1000;
776ab24c6a2SJamin Lin     aic->irq_table = aspeed_2700_intc_irqs;
777ab24c6a2SJamin Lin     aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intc_irqs);
778d831c5fdSJamin Lin }
779d831c5fdSJamin Lin 
780d831c5fdSJamin Lin static const TypeInfo aspeed_2700_intc_info = {
781d831c5fdSJamin Lin     .name = TYPE_ASPEED_2700_INTC,
782d831c5fdSJamin Lin     .parent = TYPE_ASPEED_INTC,
783d831c5fdSJamin Lin     .class_init = aspeed_2700_intc_class_init,
784d831c5fdSJamin Lin };
785d831c5fdSJamin Lin 
78638ba38d8SJamin Lin static AspeedINTCIRQ aspeed_2700_intcio_irqs[ASPEED_INTC_MAX_INPINS] = {
78738ba38d8SJamin Lin     {0, 0, 1, R_GICINT192_EN, R_GICINT192_STATUS},
78838ba38d8SJamin Lin     {1, 1, 1, R_GICINT193_EN, R_GICINT193_STATUS},
78938ba38d8SJamin Lin     {2, 2, 1, R_GICINT194_EN, R_GICINT194_STATUS},
79038ba38d8SJamin Lin     {3, 3, 1, R_GICINT195_EN, R_GICINT195_STATUS},
79138ba38d8SJamin Lin     {4, 4, 1, R_GICINT196_EN, R_GICINT196_STATUS},
79238ba38d8SJamin Lin     {5, 5, 1, R_GICINT197_EN, R_GICINT197_STATUS},
79338ba38d8SJamin Lin };
79438ba38d8SJamin Lin 
79512d1a768SPhilippe Mathieu-Daudé static void aspeed_2700_intcio_class_init(ObjectClass *klass, const void *data)
79638ba38d8SJamin Lin {
79738ba38d8SJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
79838ba38d8SJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
79938ba38d8SJamin Lin 
80038ba38d8SJamin Lin     dc->desc = "ASPEED 2700 INTC IO Controller";
80138ba38d8SJamin Lin     aic->num_lines = 32;
80238ba38d8SJamin Lin     aic->num_inpins = 6;
80338ba38d8SJamin Lin     aic->num_outpins = 6;
80438ba38d8SJamin Lin     aic->mem_size = 0x400;
80538ba38d8SJamin Lin     aic->nr_regs = 0x58 >> 2;
80638ba38d8SJamin Lin     aic->reg_offset = 0x100;
80738ba38d8SJamin Lin     aic->reg_ops = &aspeed_intcio_ops;
80838ba38d8SJamin Lin     aic->irq_table = aspeed_2700_intcio_irqs;
80938ba38d8SJamin Lin     aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intcio_irqs);
81038ba38d8SJamin Lin }
81138ba38d8SJamin Lin 
81238ba38d8SJamin Lin static const TypeInfo aspeed_2700_intcio_info = {
81338ba38d8SJamin Lin     .name = TYPE_ASPEED_2700_INTCIO,
81438ba38d8SJamin Lin     .parent = TYPE_ASPEED_INTC,
81538ba38d8SJamin Lin     .class_init = aspeed_2700_intcio_class_init,
81638ba38d8SJamin Lin };
81738ba38d8SJamin Lin 
818*8872b671SSteven Lee static AspeedINTCIRQ aspeed_2700ssp_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
819*8872b671SSteven Lee     {0, 0, 10, R_SSPINT160_169_EN, R_SSPINT160_169_STATUS},
820*8872b671SSteven Lee     {1, 10, 1, R_SSPINT128_EN, R_SSPINT128_STATUS},
821*8872b671SSteven Lee     {2, 11, 1, R_SSPINT129_EN, R_SSPINT129_STATUS},
822*8872b671SSteven Lee     {3, 12, 1, R_SSPINT130_EN, R_SSPINT130_STATUS},
823*8872b671SSteven Lee     {4, 13, 1, R_SSPINT131_EN, R_SSPINT131_STATUS},
824*8872b671SSteven Lee     {5, 14, 1, R_SSPINT132_EN, R_SSPINT132_STATUS},
825*8872b671SSteven Lee     {6, 15, 1, R_SSPINT133_EN, R_SSPINT133_STATUS},
826*8872b671SSteven Lee     {7, 16, 1, R_SSPINT134_EN, R_SSPINT134_STATUS},
827*8872b671SSteven Lee     {8, 17, 1, R_SSPINT135_EN, R_SSPINT135_STATUS},
828*8872b671SSteven Lee     {9, 18, 1, R_SSPINT136_EN, R_SSPINT136_STATUS},
829*8872b671SSteven Lee };
830*8872b671SSteven Lee 
831*8872b671SSteven Lee static void aspeed_2700ssp_intc_class_init(ObjectClass *klass, const void *data)
832*8872b671SSteven Lee {
833*8872b671SSteven Lee     DeviceClass *dc = DEVICE_CLASS(klass);
834*8872b671SSteven Lee     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
835*8872b671SSteven Lee 
836*8872b671SSteven Lee     dc->desc = "ASPEED 2700 SSP INTC Controller";
837*8872b671SSteven Lee     aic->num_lines = 32;
838*8872b671SSteven Lee     aic->num_inpins = 10;
839*8872b671SSteven Lee     aic->num_outpins = 19;
840*8872b671SSteven Lee     aic->mem_size = 0x4000;
841*8872b671SSteven Lee     aic->nr_regs = 0x2B08 >> 2;
842*8872b671SSteven Lee     aic->reg_offset = 0x0;
843*8872b671SSteven Lee     aic->reg_ops = &aspeed_ssp_intc_ops;
844*8872b671SSteven Lee     aic->irq_table = aspeed_2700ssp_intc_irqs;
845*8872b671SSteven Lee     aic->irq_table_count = ARRAY_SIZE(aspeed_2700ssp_intc_irqs);
846*8872b671SSteven Lee }
847*8872b671SSteven Lee 
848*8872b671SSteven Lee static const TypeInfo aspeed_2700ssp_intc_info = {
849*8872b671SSteven Lee     .name = TYPE_ASPEED_2700SSP_INTC,
850*8872b671SSteven Lee     .parent = TYPE_ASPEED_INTC,
851*8872b671SSteven Lee     .class_init = aspeed_2700ssp_intc_class_init,
852*8872b671SSteven Lee };
853*8872b671SSteven Lee 
854*8872b671SSteven Lee static AspeedINTCIRQ aspeed_2700ssp_intcio_irqs[ASPEED_INTC_MAX_INPINS] = {
855*8872b671SSteven Lee     {0, 0, 1, R_SSPINT160_EN, R_SSPINT160_STATUS},
856*8872b671SSteven Lee     {1, 1, 1, R_SSPINT161_EN, R_SSPINT161_STATUS},
857*8872b671SSteven Lee     {2, 2, 1, R_SSPINT162_EN, R_SSPINT162_STATUS},
858*8872b671SSteven Lee     {3, 3, 1, R_SSPINT163_EN, R_SSPINT163_STATUS},
859*8872b671SSteven Lee     {4, 4, 1, R_SSPINT164_EN, R_SSPINT164_STATUS},
860*8872b671SSteven Lee     {5, 5, 1, R_SSPINT165_EN, R_SSPINT165_STATUS},
861*8872b671SSteven Lee };
862*8872b671SSteven Lee 
863*8872b671SSteven Lee static void aspeed_2700ssp_intcio_class_init(ObjectClass *klass, const void *data)
864*8872b671SSteven Lee {
865*8872b671SSteven Lee     DeviceClass *dc = DEVICE_CLASS(klass);
866*8872b671SSteven Lee     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
867*8872b671SSteven Lee 
868*8872b671SSteven Lee     dc->desc = "ASPEED 2700 SSP INTC IO Controller";
869*8872b671SSteven Lee     aic->num_lines = 32;
870*8872b671SSteven Lee     aic->num_inpins = 6;
871*8872b671SSteven Lee     aic->num_outpins = 6;
872*8872b671SSteven Lee     aic->mem_size = 0x400;
873*8872b671SSteven Lee     aic->nr_regs = 0x1d8 >> 2;
874*8872b671SSteven Lee     aic->reg_offset = 0;
875*8872b671SSteven Lee     aic->reg_ops = &aspeed_ssp_intcio_ops;
876*8872b671SSteven Lee     aic->irq_table = aspeed_2700ssp_intcio_irqs;
877*8872b671SSteven Lee     aic->irq_table_count = ARRAY_SIZE(aspeed_2700ssp_intcio_irqs);
878*8872b671SSteven Lee }
879*8872b671SSteven Lee 
880*8872b671SSteven Lee static const TypeInfo aspeed_2700ssp_intcio_info = {
881*8872b671SSteven Lee     .name = TYPE_ASPEED_2700SSP_INTCIO,
882*8872b671SSteven Lee     .parent = TYPE_ASPEED_INTC,
883*8872b671SSteven Lee     .class_init = aspeed_2700ssp_intcio_class_init,
884*8872b671SSteven Lee };
885*8872b671SSteven Lee 
886d831c5fdSJamin Lin static void aspeed_intc_register_types(void)
887d831c5fdSJamin Lin {
888d831c5fdSJamin Lin     type_register_static(&aspeed_intc_info);
889d831c5fdSJamin Lin     type_register_static(&aspeed_2700_intc_info);
89038ba38d8SJamin Lin     type_register_static(&aspeed_2700_intcio_info);
891*8872b671SSteven Lee     type_register_static(&aspeed_2700ssp_intc_info);
892*8872b671SSteven Lee     type_register_static(&aspeed_2700ssp_intcio_info);
893d831c5fdSJamin Lin }
894d831c5fdSJamin Lin 
895d831c5fdSJamin Lin type_init(aspeed_intc_register_types);
896