xref: /qemu/hw/intc/aspeed_intc.c (revision 80db93b2b88f9b3ed8927ae7ac74ca30e643a83e)
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 
658872b671SSteven Lee /*
668872b671SSteven Lee  * SSP INTC Registers
678872b671SSteven Lee  */
688872b671SSteven Lee REG32(SSPINT128_EN,             0x2000)
698872b671SSteven Lee REG32(SSPINT128_STATUS,         0x2004)
708872b671SSteven Lee REG32(SSPINT129_EN,             0x2100)
718872b671SSteven Lee REG32(SSPINT129_STATUS,         0x2104)
728872b671SSteven Lee REG32(SSPINT130_EN,             0x2200)
738872b671SSteven Lee REG32(SSPINT130_STATUS,         0x2204)
748872b671SSteven Lee REG32(SSPINT131_EN,             0x2300)
758872b671SSteven Lee REG32(SSPINT131_STATUS,         0x2304)
768872b671SSteven Lee REG32(SSPINT132_EN,             0x2400)
778872b671SSteven Lee REG32(SSPINT132_STATUS,         0x2404)
788872b671SSteven Lee REG32(SSPINT133_EN,             0x2500)
798872b671SSteven Lee REG32(SSPINT133_STATUS,         0x2504)
808872b671SSteven Lee REG32(SSPINT134_EN,             0x2600)
818872b671SSteven Lee REG32(SSPINT134_STATUS,         0x2604)
828872b671SSteven Lee REG32(SSPINT135_EN,             0x2700)
838872b671SSteven Lee REG32(SSPINT135_STATUS,         0x2704)
848872b671SSteven Lee REG32(SSPINT136_EN,             0x2800)
858872b671SSteven Lee REG32(SSPINT136_STATUS,         0x2804)
868872b671SSteven Lee REG32(SSPINT137_EN,             0x2900)
878872b671SSteven Lee REG32(SSPINT137_STATUS,         0x2904)
888872b671SSteven Lee REG32(SSPINT138_EN,             0x2A00)
898872b671SSteven Lee REG32(SSPINT138_STATUS,         0x2A04)
908872b671SSteven Lee REG32(SSPINT160_169_EN,         0x2B00)
918872b671SSteven Lee REG32(SSPINT160_169_STATUS,     0x2B04)
928872b671SSteven Lee 
938872b671SSteven Lee /*
948872b671SSteven Lee  * SSP INTCIO Registers
958872b671SSteven Lee  */
968872b671SSteven Lee REG32(SSPINT160_EN,         0x180)
978872b671SSteven Lee REG32(SSPINT160_STATUS,     0x184)
988872b671SSteven Lee REG32(SSPINT161_EN,         0x190)
998872b671SSteven Lee REG32(SSPINT161_STATUS,     0x194)
1008872b671SSteven Lee REG32(SSPINT162_EN,         0x1A0)
1018872b671SSteven Lee REG32(SSPINT162_STATUS,     0x1A4)
1028872b671SSteven Lee REG32(SSPINT163_EN,         0x1B0)
1038872b671SSteven Lee REG32(SSPINT163_STATUS,     0x1B4)
1048872b671SSteven Lee REG32(SSPINT164_EN,         0x1C0)
1058872b671SSteven Lee REG32(SSPINT164_STATUS,     0x1C4)
1068872b671SSteven Lee REG32(SSPINT165_EN,         0x1D0)
1078872b671SSteven Lee REG32(SSPINT165_STATUS,     0x1D4)
1088872b671SSteven Lee 
109c528f10dSSteven Lee /*
110c528f10dSSteven Lee  * TSP INTC Registers
111c528f10dSSteven Lee  */
112c528f10dSSteven Lee REG32(TSPINT128_EN,             0x3000)
113c528f10dSSteven Lee REG32(TSPINT128_STATUS,         0x3004)
114c528f10dSSteven Lee REG32(TSPINT129_EN,             0x3100)
115c528f10dSSteven Lee REG32(TSPINT129_STATUS,         0x3104)
116c528f10dSSteven Lee REG32(TSPINT130_EN,             0x3200)
117c528f10dSSteven Lee REG32(TSPINT130_STATUS,         0x3204)
118c528f10dSSteven Lee REG32(TSPINT131_EN,             0x3300)
119c528f10dSSteven Lee REG32(TSPINT131_STATUS,         0x3304)
120c528f10dSSteven Lee REG32(TSPINT132_EN,             0x3400)
121c528f10dSSteven Lee REG32(TSPINT132_STATUS,         0x3404)
122c528f10dSSteven Lee REG32(TSPINT133_EN,             0x3500)
123c528f10dSSteven Lee REG32(TSPINT133_STATUS,         0x3504)
124c528f10dSSteven Lee REG32(TSPINT134_EN,             0x3600)
125c528f10dSSteven Lee REG32(TSPINT134_STATUS,         0x3604)
126c528f10dSSteven Lee REG32(TSPINT135_EN,             0x3700)
127c528f10dSSteven Lee REG32(TSPINT135_STATUS,         0x3704)
128c528f10dSSteven Lee REG32(TSPINT136_EN,             0x3800)
129c528f10dSSteven Lee REG32(TSPINT136_STATUS,         0x3804)
130c528f10dSSteven Lee REG32(TSPINT137_EN,             0x3900)
131c528f10dSSteven Lee REG32(TSPINT137_STATUS,         0x3904)
132c528f10dSSteven Lee REG32(TSPINT138_EN,             0x3A00)
133c528f10dSSteven Lee REG32(TSPINT138_STATUS,         0x3A04)
134c528f10dSSteven Lee REG32(TSPINT160_169_EN,         0x3B00)
135c528f10dSSteven Lee REG32(TSPINT160_169_STATUS,     0x3B04)
136c528f10dSSteven Lee 
137c528f10dSSteven Lee /*
138c528f10dSSteven Lee  * TSP INTCIO Registers
139c528f10dSSteven Lee  */
140c528f10dSSteven Lee 
141c528f10dSSteven Lee REG32(TSPINT160_EN,         0x200)
142c528f10dSSteven Lee REG32(TSPINT160_STATUS,     0x204)
143c528f10dSSteven Lee REG32(TSPINT161_EN,         0x210)
144c528f10dSSteven Lee REG32(TSPINT161_STATUS,     0x214)
145c528f10dSSteven Lee REG32(TSPINT162_EN,         0x220)
146c528f10dSSteven Lee REG32(TSPINT162_STATUS,     0x224)
147c528f10dSSteven Lee REG32(TSPINT163_EN,         0x230)
148c528f10dSSteven Lee REG32(TSPINT163_STATUS,     0x234)
149c528f10dSSteven Lee REG32(TSPINT164_EN,         0x240)
150c528f10dSSteven Lee REG32(TSPINT164_STATUS,     0x244)
151c528f10dSSteven Lee REG32(TSPINT165_EN,         0x250)
152c528f10dSSteven Lee REG32(TSPINT165_STATUS,     0x254)
153c528f10dSSteven Lee 
aspeed_intc_get_irq(AspeedINTCClass * aic,uint32_t reg)154ab24c6a2SJamin Lin static const AspeedINTCIRQ *aspeed_intc_get_irq(AspeedINTCClass *aic,
155ab24c6a2SJamin Lin                                                 uint32_t reg)
156ab24c6a2SJamin Lin {
157ab24c6a2SJamin Lin     int i;
158ab24c6a2SJamin Lin 
159ab24c6a2SJamin Lin     for (i = 0; i < aic->irq_table_count; i++) {
160ab24c6a2SJamin Lin         if (aic->irq_table[i].enable_reg == reg ||
161ab24c6a2SJamin Lin             aic->irq_table[i].status_reg == reg) {
162ab24c6a2SJamin Lin             return &aic->irq_table[i];
163ab24c6a2SJamin Lin         }
164ab24c6a2SJamin Lin     }
165ab24c6a2SJamin Lin 
166ab24c6a2SJamin Lin     /*
167ab24c6a2SJamin Lin      * Invalid reg.
168ab24c6a2SJamin Lin      */
169ab24c6a2SJamin Lin     g_assert_not_reached();
170ab24c6a2SJamin Lin }
171d831c5fdSJamin Lin 
172c6c5e63dSJamin Lin /*
173c6c5e63dSJamin Lin  * Update the state of an interrupt controller pin by setting
174c6c5e63dSJamin Lin  * the specified output pin to the given level.
175c6c5e63dSJamin Lin  * The input pin index should be between 0 and the number of input pins.
176c6c5e63dSJamin Lin  * The output pin index should be between 0 and the number of output pins.
177c6c5e63dSJamin Lin  */
aspeed_intc_update(AspeedINTCState * s,int inpin_idx,int outpin_idx,int level)178c6c5e63dSJamin Lin static void aspeed_intc_update(AspeedINTCState *s, int inpin_idx,
179c6c5e63dSJamin Lin                                int outpin_idx, int level)
180d831c5fdSJamin Lin {
181d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
18249da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
183d831c5fdSJamin Lin 
184ab24c6a2SJamin Lin     assert((outpin_idx < aic->num_outpins) && (inpin_idx < aic->num_inpins));
185c6c5e63dSJamin Lin 
186c6c5e63dSJamin Lin     trace_aspeed_intc_update_irq(name, inpin_idx, outpin_idx, level);
187c6c5e63dSJamin Lin     qemu_set_irq(s->output_pins[outpin_idx], level);
188d831c5fdSJamin Lin }
189d831c5fdSJamin Lin 
aspeed_intc_set_irq_handler(AspeedINTCState * s,const AspeedINTCIRQ * intc_irq,uint32_t select)1905824e8bfSJamin Lin static void aspeed_intc_set_irq_handler(AspeedINTCState *s,
1915824e8bfSJamin Lin                                         const AspeedINTCIRQ *intc_irq,
1925824e8bfSJamin Lin                                         uint32_t select)
193d831c5fdSJamin Lin {
19449da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
195ab24c6a2SJamin Lin     uint32_t status_reg;
196c6c5e63dSJamin Lin     int outpin_idx;
197c6c5e63dSJamin Lin     int inpin_idx;
198d831c5fdSJamin Lin 
199ab24c6a2SJamin Lin     status_reg = intc_irq->status_reg;
200ab24c6a2SJamin Lin     outpin_idx = intc_irq->outpin_idx;
201ab24c6a2SJamin Lin     inpin_idx = intc_irq->inpin_idx;
202d831c5fdSJamin Lin 
2037b8cbe51SSteven Lee     if ((s->mask[inpin_idx] & select) || (s->regs[status_reg] & select)) {
204d831c5fdSJamin Lin         /*
205d831c5fdSJamin Lin          * a. mask is not 0 means in ISR mode
206d831c5fdSJamin Lin          * sources interrupt routine are executing.
207d831c5fdSJamin Lin          * b. status register value is not 0 means previous
208d831c5fdSJamin Lin          * source interrupt does not be executed, yet.
209d831c5fdSJamin Lin          *
210d831c5fdSJamin Lin          * save source interrupt to pending variable.
211d831c5fdSJamin Lin          */
212c6c5e63dSJamin Lin         s->pending[inpin_idx] |= select;
213c6c5e63dSJamin Lin         trace_aspeed_intc_pending_irq(name, inpin_idx, s->pending[inpin_idx]);
214d831c5fdSJamin Lin     } else {
215d831c5fdSJamin Lin         /*
216d831c5fdSJamin Lin          * notify firmware which source interrupt are coming
217d831c5fdSJamin Lin          * by setting status register
218d831c5fdSJamin Lin          */
2190cffaaceSJamin Lin         s->regs[status_reg] = select;
220c6c5e63dSJamin Lin         trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
221c6c5e63dSJamin Lin                                       s->regs[status_reg]);
222c6c5e63dSJamin Lin         aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
223d831c5fdSJamin Lin     }
224d831c5fdSJamin Lin }
225d831c5fdSJamin Lin 
aspeed_intc_set_irq_handler_multi_outpins(AspeedINTCState * s,const AspeedINTCIRQ * intc_irq,uint32_t select)2269178ff91SJamin Lin static void aspeed_intc_set_irq_handler_multi_outpins(AspeedINTCState *s,
2279178ff91SJamin Lin                                  const AspeedINTCIRQ *intc_irq, uint32_t select)
2289178ff91SJamin Lin {
2299178ff91SJamin Lin     const char *name = object_get_typename(OBJECT(s));
2309178ff91SJamin Lin     uint32_t status_reg;
2319178ff91SJamin Lin     int num_outpins;
2329178ff91SJamin Lin     int outpin_idx;
2339178ff91SJamin Lin     int inpin_idx;
2349178ff91SJamin Lin     int i;
2359178ff91SJamin Lin 
2369178ff91SJamin Lin     num_outpins = intc_irq->num_outpins;
2379178ff91SJamin Lin     status_reg = intc_irq->status_reg;
2389178ff91SJamin Lin     outpin_idx = intc_irq->outpin_idx;
2399178ff91SJamin Lin     inpin_idx = intc_irq->inpin_idx;
2409178ff91SJamin Lin 
2419178ff91SJamin Lin     for (i = 0; i < num_outpins; i++) {
2429178ff91SJamin Lin         if (select & BIT(i)) {
2439178ff91SJamin Lin             if (s->mask[inpin_idx] & BIT(i) ||
2449178ff91SJamin Lin                 s->regs[status_reg] & BIT(i)) {
2455824e8bfSJamin Lin                 /*
2469178ff91SJamin Lin                  * a. mask bit is not 0 means in ISR mode sources interrupt
2479178ff91SJamin Lin                  * routine are executing.
2489178ff91SJamin Lin                  * b. status bit is not 0 means previous source interrupt
2499178ff91SJamin Lin                  * does not be executed, yet.
2509178ff91SJamin Lin                  *
2519178ff91SJamin Lin                  * save source interrupt to pending bit.
2529178ff91SJamin Lin                  */
2539178ff91SJamin Lin                  s->pending[inpin_idx] |= BIT(i);
2549178ff91SJamin Lin                  trace_aspeed_intc_pending_irq(name, inpin_idx,
2559178ff91SJamin Lin                                                s->pending[inpin_idx]);
2569178ff91SJamin Lin             } else {
2579178ff91SJamin Lin                 /*
2589178ff91SJamin Lin                  * notify firmware which source interrupt are coming
2599178ff91SJamin Lin                  * by setting status bit
2609178ff91SJamin Lin                  */
2619178ff91SJamin Lin                 s->regs[status_reg] |= BIT(i);
2629178ff91SJamin Lin                 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx + i,
2639178ff91SJamin Lin                                               s->regs[status_reg]);
2649178ff91SJamin Lin                 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 1);
2659178ff91SJamin Lin             }
2669178ff91SJamin Lin         }
2679178ff91SJamin Lin     }
2689178ff91SJamin Lin }
2699178ff91SJamin Lin 
2709178ff91SJamin Lin /*
2719178ff91SJamin Lin  * GICINT192_201 maps 1:10 to input IRQ 0 and output IRQs 0 to 9.
2729178ff91SJamin Lin  * GICINT128 to GICINT136 map 1:1 to input IRQs 1 to 9 and output
2739178ff91SJamin Lin  * IRQs 10 to 18. The value of input IRQ should be between 0 and
2749178ff91SJamin Lin  * the number of input pins.
2755824e8bfSJamin Lin  */
aspeed_intc_set_irq(void * opaque,int irq,int level)2765824e8bfSJamin Lin static void aspeed_intc_set_irq(void *opaque, int irq, int level)
2775824e8bfSJamin Lin {
2785824e8bfSJamin Lin     AspeedINTCState *s = (AspeedINTCState *)opaque;
2795824e8bfSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
2805824e8bfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
2815824e8bfSJamin Lin     const AspeedINTCIRQ *intc_irq;
2825824e8bfSJamin Lin     uint32_t select = 0;
2835824e8bfSJamin Lin     uint32_t enable;
2849178ff91SJamin Lin     int num_outpins;
2855824e8bfSJamin Lin     int inpin_idx;
2865824e8bfSJamin Lin     int i;
2875824e8bfSJamin Lin 
2885824e8bfSJamin Lin     assert(irq < aic->num_inpins);
2895824e8bfSJamin Lin 
2905824e8bfSJamin Lin     intc_irq = &aic->irq_table[irq];
2919178ff91SJamin Lin     num_outpins = intc_irq->num_outpins;
2925824e8bfSJamin Lin     inpin_idx = intc_irq->inpin_idx;
2935824e8bfSJamin Lin     trace_aspeed_intc_set_irq(name, inpin_idx, level);
2945824e8bfSJamin Lin     enable = s->enable[inpin_idx];
2955824e8bfSJamin Lin 
2965824e8bfSJamin Lin     if (!level) {
2975824e8bfSJamin Lin         return;
2985824e8bfSJamin Lin     }
2995824e8bfSJamin Lin 
3005824e8bfSJamin Lin     for (i = 0; i < aic->num_lines; i++) {
3015824e8bfSJamin Lin         if (s->orgates[inpin_idx].levels[i]) {
3025824e8bfSJamin Lin             if (enable & BIT(i)) {
3035824e8bfSJamin Lin                 select |= BIT(i);
3045824e8bfSJamin Lin             }
3055824e8bfSJamin Lin         }
3065824e8bfSJamin Lin     }
3075824e8bfSJamin Lin 
3085824e8bfSJamin Lin     if (!select) {
3095824e8bfSJamin Lin         return;
3105824e8bfSJamin Lin     }
3115824e8bfSJamin Lin 
3125824e8bfSJamin Lin     trace_aspeed_intc_select(name, select);
3139178ff91SJamin Lin     if (num_outpins > 1) {
3149178ff91SJamin Lin         aspeed_intc_set_irq_handler_multi_outpins(s, intc_irq, select);
3159178ff91SJamin Lin     } else {
3165824e8bfSJamin Lin         aspeed_intc_set_irq_handler(s, intc_irq, select);
3175824e8bfSJamin Lin     }
3189178ff91SJamin Lin }
3195824e8bfSJamin Lin 
aspeed_intc_enable_handler(AspeedINTCState * s,hwaddr offset,uint64_t data)3203d6e15eaSJamin Lin static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset,
3213d6e15eaSJamin Lin                                        uint64_t data)
322d831c5fdSJamin Lin {
323d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
32449da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
325ab24c6a2SJamin Lin     const AspeedINTCIRQ *intc_irq;
3260cffaaceSJamin Lin     uint32_t reg = offset >> 2;
327d831c5fdSJamin Lin     uint32_t old_enable;
328d831c5fdSJamin Lin     uint32_t change;
329c6c5e63dSJamin Lin     int inpin_idx;
330d831c5fdSJamin Lin 
331ab24c6a2SJamin Lin     intc_irq = aspeed_intc_get_irq(aic, reg);
332ab24c6a2SJamin Lin     inpin_idx = intc_irq->inpin_idx;
333d831c5fdSJamin Lin 
334ab24c6a2SJamin Lin     assert(inpin_idx < aic->num_inpins);
335d831c5fdSJamin Lin 
336d831c5fdSJamin Lin     /*
3373d6e15eaSJamin Lin      * The enable registers are used to enable source interrupts.
3383d6e15eaSJamin Lin      * They also handle masking and unmasking of source interrupts
3393d6e15eaSJamin Lin      * during the execution of the source ISR.
340d831c5fdSJamin Lin      */
341d831c5fdSJamin Lin 
342d831c5fdSJamin Lin     /* disable all source interrupt */
343c6c5e63dSJamin Lin     if (!data && !s->enable[inpin_idx]) {
3440cffaaceSJamin Lin         s->regs[reg] = data;
345d831c5fdSJamin Lin         return;
346d831c5fdSJamin Lin     }
347d831c5fdSJamin Lin 
348c6c5e63dSJamin Lin     old_enable = s->enable[inpin_idx];
349c6c5e63dSJamin Lin     s->enable[inpin_idx] |= data;
350d831c5fdSJamin Lin 
351d831c5fdSJamin Lin     /* enable new source interrupt */
352c6c5e63dSJamin Lin     if (old_enable != s->enable[inpin_idx]) {
353c6c5e63dSJamin Lin         trace_aspeed_intc_enable(name, s->enable[inpin_idx]);
3540cffaaceSJamin Lin         s->regs[reg] = data;
355d831c5fdSJamin Lin         return;
356d831c5fdSJamin Lin     }
357d831c5fdSJamin Lin 
358d831c5fdSJamin Lin     /* mask and unmask source interrupt */
3590cffaaceSJamin Lin     change = s->regs[reg] ^ data;
360d831c5fdSJamin Lin     if (change & data) {
361c6c5e63dSJamin Lin         s->mask[inpin_idx] &= ~change;
362c6c5e63dSJamin Lin         trace_aspeed_intc_unmask(name, change, s->mask[inpin_idx]);
363d831c5fdSJamin Lin     } else {
364c6c5e63dSJamin Lin         s->mask[inpin_idx] |= change;
365c6c5e63dSJamin Lin         trace_aspeed_intc_mask(name, change, s->mask[inpin_idx]);
366d831c5fdSJamin Lin     }
3673d6e15eaSJamin Lin 
3680cffaaceSJamin Lin     s->regs[reg] = data;
3693d6e15eaSJamin Lin }
3703d6e15eaSJamin Lin 
aspeed_intc_status_handler(AspeedINTCState * s,hwaddr offset,uint64_t data)3713d6e15eaSJamin Lin static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset,
3723d6e15eaSJamin Lin                                        uint64_t data)
3733d6e15eaSJamin Lin {
3743d6e15eaSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
37549da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
376ab24c6a2SJamin Lin     const AspeedINTCIRQ *intc_irq;
3773d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
378c6c5e63dSJamin Lin     int outpin_idx;
379c6c5e63dSJamin Lin     int inpin_idx;
3803d6e15eaSJamin Lin 
3813d6e15eaSJamin Lin     if (!data) {
3823d6e15eaSJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
3833d6e15eaSJamin Lin         return;
3843d6e15eaSJamin Lin     }
3853d6e15eaSJamin Lin 
386ab24c6a2SJamin Lin     intc_irq = aspeed_intc_get_irq(aic, reg);
387ab24c6a2SJamin Lin     outpin_idx = intc_irq->outpin_idx;
388ab24c6a2SJamin Lin     inpin_idx = intc_irq->inpin_idx;
389d831c5fdSJamin Lin 
390ab24c6a2SJamin Lin     assert(inpin_idx < aic->num_inpins);
391d831c5fdSJamin Lin 
392d831c5fdSJamin Lin     /* clear status */
3930cffaaceSJamin Lin     s->regs[reg] &= ~data;
394d831c5fdSJamin Lin 
395d831c5fdSJamin Lin     /*
396d831c5fdSJamin Lin      * These status registers are used for notify sources ISR are executed.
397d831c5fdSJamin Lin      * If one source ISR is executed, it will clear one bit.
398d831c5fdSJamin Lin      * If it clear all bits, it means to initialize this register status
399d831c5fdSJamin Lin      * rather than sources ISR are executed.
400d831c5fdSJamin Lin      */
401d831c5fdSJamin Lin     if (data == 0xffffffff) {
402d831c5fdSJamin Lin         return;
403d831c5fdSJamin Lin     }
404d831c5fdSJamin Lin 
405d831c5fdSJamin Lin     /* All source ISR execution are done */
4060cffaaceSJamin Lin     if (!s->regs[reg]) {
407c6c5e63dSJamin Lin         trace_aspeed_intc_all_isr_done(name, inpin_idx);
408c6c5e63dSJamin Lin         if (s->pending[inpin_idx]) {
409d831c5fdSJamin Lin             /*
410d831c5fdSJamin Lin              * handle pending source interrupt
411d831c5fdSJamin Lin              * notify firmware which source interrupt are pending
412d831c5fdSJamin Lin              * by setting status register
413d831c5fdSJamin Lin              */
414c6c5e63dSJamin Lin             s->regs[reg] = s->pending[inpin_idx];
415c6c5e63dSJamin Lin             s->pending[inpin_idx] = 0;
416c6c5e63dSJamin Lin             trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
417c6c5e63dSJamin Lin                                           s->regs[reg]);
418c6c5e63dSJamin Lin             aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
419d831c5fdSJamin Lin         } else {
420d831c5fdSJamin Lin             /* clear irq */
421c6c5e63dSJamin Lin             trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx, 0);
422c6c5e63dSJamin Lin             aspeed_intc_update(s, inpin_idx, outpin_idx, 0);
423d831c5fdSJamin Lin         }
424d831c5fdSJamin Lin     }
4253d6e15eaSJamin Lin }
4263d6e15eaSJamin Lin 
aspeed_intc_status_handler_multi_outpins(AspeedINTCState * s,hwaddr offset,uint64_t data)4279178ff91SJamin Lin static void aspeed_intc_status_handler_multi_outpins(AspeedINTCState *s,
4289178ff91SJamin Lin                                                 hwaddr offset, uint64_t data)
4299178ff91SJamin Lin {
4309178ff91SJamin Lin     const char *name = object_get_typename(OBJECT(s));
4319178ff91SJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
4329178ff91SJamin Lin     const AspeedINTCIRQ *intc_irq;
4339178ff91SJamin Lin     uint32_t reg = offset >> 2;
4349178ff91SJamin Lin     int num_outpins;
4359178ff91SJamin Lin     int outpin_idx;
4369178ff91SJamin Lin     int inpin_idx;
4379178ff91SJamin Lin     int i;
4389178ff91SJamin Lin 
4399178ff91SJamin Lin     if (!data) {
4409178ff91SJamin Lin         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
4419178ff91SJamin Lin         return;
4429178ff91SJamin Lin     }
4439178ff91SJamin Lin 
4449178ff91SJamin Lin     intc_irq = aspeed_intc_get_irq(aic, reg);
4459178ff91SJamin Lin     num_outpins = intc_irq->num_outpins;
4469178ff91SJamin Lin     outpin_idx = intc_irq->outpin_idx;
4479178ff91SJamin Lin     inpin_idx = intc_irq->inpin_idx;
4489178ff91SJamin Lin     assert(inpin_idx < aic->num_inpins);
4499178ff91SJamin Lin 
4509178ff91SJamin Lin     /* clear status */
4519178ff91SJamin Lin     s->regs[reg] &= ~data;
4529178ff91SJamin Lin 
4539178ff91SJamin Lin     /*
4549178ff91SJamin Lin      * The status registers are used for notify sources ISR are executed.
4559178ff91SJamin Lin      * If one source ISR is executed, it will clear one bit.
4569178ff91SJamin Lin      * If it clear all bits, it means to initialize this register status
4579178ff91SJamin Lin      * rather than sources ISR are executed.
4589178ff91SJamin Lin      */
4599178ff91SJamin Lin     if (data == 0xffffffff) {
4609178ff91SJamin Lin         return;
4619178ff91SJamin Lin     }
4629178ff91SJamin Lin 
4639178ff91SJamin Lin     for (i = 0; i < num_outpins; i++) {
4649178ff91SJamin Lin         /* All source ISR executions are done from a specific bit */
4659178ff91SJamin Lin         if (data & BIT(i)) {
4669178ff91SJamin Lin             trace_aspeed_intc_all_isr_done_bit(name, inpin_idx, i);
4679178ff91SJamin Lin             if (s->pending[inpin_idx] & BIT(i)) {
4689178ff91SJamin Lin                 /*
4699178ff91SJamin Lin                  * Handle pending source interrupt.
4709178ff91SJamin Lin                  * Notify firmware which source interrupt is pending
4719178ff91SJamin Lin                  * by setting the status bit.
4729178ff91SJamin Lin                  */
4739178ff91SJamin Lin                 s->regs[reg] |= BIT(i);
4749178ff91SJamin Lin                 s->pending[inpin_idx] &= ~BIT(i);
4759178ff91SJamin Lin                 trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx + i,
4769178ff91SJamin Lin                                               s->regs[reg]);
4779178ff91SJamin Lin                 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 1);
4789178ff91SJamin Lin             } else {
4799178ff91SJamin Lin                 /* clear irq for the specific bit */
4809178ff91SJamin Lin                 trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx + i, 0);
4819178ff91SJamin Lin                 aspeed_intc_update(s, inpin_idx, outpin_idx + i, 0);
4829178ff91SJamin Lin             }
4839178ff91SJamin Lin         }
4849178ff91SJamin Lin     }
4859178ff91SJamin Lin }
4869178ff91SJamin Lin 
aspeed_intc_read(void * opaque,hwaddr offset,unsigned int size)4873d6e15eaSJamin Lin static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
4883d6e15eaSJamin Lin {
4893d6e15eaSJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
49049da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
4913d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
4923d6e15eaSJamin Lin     uint32_t value = 0;
4933d6e15eaSJamin Lin 
4943d6e15eaSJamin Lin     value = s->regs[reg];
49549da40cfSJamin Lin     trace_aspeed_intc_read(name, offset, size, value);
4963d6e15eaSJamin Lin 
4973d6e15eaSJamin Lin     return value;
4983d6e15eaSJamin Lin }
4993d6e15eaSJamin Lin 
aspeed_intc_write(void * opaque,hwaddr offset,uint64_t data,unsigned size)5003d6e15eaSJamin Lin static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
5013d6e15eaSJamin Lin                                         unsigned size)
5023d6e15eaSJamin Lin {
5033d6e15eaSJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
50449da40cfSJamin Lin     const char *name = object_get_typename(OBJECT(s));
5053d6e15eaSJamin Lin     uint32_t reg = offset >> 2;
5063d6e15eaSJamin Lin 
50749da40cfSJamin Lin     trace_aspeed_intc_write(name, offset, size, data);
5083d6e15eaSJamin Lin 
5093d6e15eaSJamin Lin     switch (reg) {
5103d6e15eaSJamin Lin     case R_GICINT128_EN:
5113d6e15eaSJamin Lin     case R_GICINT129_EN:
5123d6e15eaSJamin Lin     case R_GICINT130_EN:
5133d6e15eaSJamin Lin     case R_GICINT131_EN:
5143d6e15eaSJamin Lin     case R_GICINT132_EN:
5153d6e15eaSJamin Lin     case R_GICINT133_EN:
5163d6e15eaSJamin Lin     case R_GICINT134_EN:
5173d6e15eaSJamin Lin     case R_GICINT135_EN:
5183d6e15eaSJamin Lin     case R_GICINT136_EN:
5199178ff91SJamin Lin     case R_GICINT192_201_EN:
5203d6e15eaSJamin Lin         aspeed_intc_enable_handler(s, offset, data);
5213d6e15eaSJamin Lin         break;
5223d6e15eaSJamin Lin     case R_GICINT128_STATUS:
5233d6e15eaSJamin Lin     case R_GICINT129_STATUS:
5243d6e15eaSJamin Lin     case R_GICINT130_STATUS:
5253d6e15eaSJamin Lin     case R_GICINT131_STATUS:
5263d6e15eaSJamin Lin     case R_GICINT132_STATUS:
5273d6e15eaSJamin Lin     case R_GICINT133_STATUS:
5283d6e15eaSJamin Lin     case R_GICINT134_STATUS:
5293d6e15eaSJamin Lin     case R_GICINT135_STATUS:
5303d6e15eaSJamin Lin     case R_GICINT136_STATUS:
5313d6e15eaSJamin Lin         aspeed_intc_status_handler(s, offset, data);
532d831c5fdSJamin Lin         break;
5339178ff91SJamin Lin     case R_GICINT192_201_STATUS:
5349178ff91SJamin Lin         aspeed_intc_status_handler_multi_outpins(s, offset, data);
5359178ff91SJamin Lin         break;
536d831c5fdSJamin Lin     default:
5370cffaaceSJamin Lin         s->regs[reg] = data;
538d831c5fdSJamin Lin         break;
539d831c5fdSJamin Lin     }
540d831c5fdSJamin Lin }
541d831c5fdSJamin Lin 
aspeed_ssp_intc_write(void * opaque,hwaddr offset,uint64_t data,unsigned size)5428872b671SSteven Lee static void aspeed_ssp_intc_write(void *opaque, hwaddr offset, uint64_t data,
5438872b671SSteven Lee                                         unsigned size)
5448872b671SSteven Lee {
5458872b671SSteven Lee     AspeedINTCState *s = ASPEED_INTC(opaque);
5468872b671SSteven Lee     const char *name = object_get_typename(OBJECT(s));
5478872b671SSteven Lee     uint32_t reg = offset >> 2;
5488872b671SSteven Lee 
5498872b671SSteven Lee     trace_aspeed_intc_write(name, offset, size, data);
5508872b671SSteven Lee 
5518872b671SSteven Lee     switch (reg) {
5528872b671SSteven Lee     case R_SSPINT128_EN:
5538872b671SSteven Lee     case R_SSPINT129_EN:
5548872b671SSteven Lee     case R_SSPINT130_EN:
5558872b671SSteven Lee     case R_SSPINT131_EN:
5568872b671SSteven Lee     case R_SSPINT132_EN:
5578872b671SSteven Lee     case R_SSPINT133_EN:
5588872b671SSteven Lee     case R_SSPINT134_EN:
5598872b671SSteven Lee     case R_SSPINT135_EN:
5608872b671SSteven Lee     case R_SSPINT136_EN:
5618872b671SSteven Lee     case R_SSPINT160_169_EN:
5628872b671SSteven Lee         aspeed_intc_enable_handler(s, offset, data);
5638872b671SSteven Lee         break;
5648872b671SSteven Lee     case R_SSPINT128_STATUS:
5658872b671SSteven Lee     case R_SSPINT129_STATUS:
5668872b671SSteven Lee     case R_SSPINT130_STATUS:
5678872b671SSteven Lee     case R_SSPINT131_STATUS:
5688872b671SSteven Lee     case R_SSPINT132_STATUS:
5698872b671SSteven Lee     case R_SSPINT133_STATUS:
5708872b671SSteven Lee     case R_SSPINT134_STATUS:
5718872b671SSteven Lee     case R_SSPINT135_STATUS:
5728872b671SSteven Lee     case R_SSPINT136_STATUS:
5738872b671SSteven Lee         aspeed_intc_status_handler(s, offset, data);
5748872b671SSteven Lee         break;
5758872b671SSteven Lee     case R_SSPINT160_169_STATUS:
5768872b671SSteven Lee         aspeed_intc_status_handler_multi_outpins(s, offset, data);
5778872b671SSteven Lee         break;
5788872b671SSteven Lee     default:
5798872b671SSteven Lee         s->regs[reg] = data;
5808872b671SSteven Lee         break;
5818872b671SSteven Lee     }
582c528f10dSSteven Lee }
5838872b671SSteven Lee 
aspeed_tsp_intc_write(void * opaque,hwaddr offset,uint64_t data,unsigned size)584c528f10dSSteven Lee static void aspeed_tsp_intc_write(void *opaque, hwaddr offset, uint64_t data,
585c528f10dSSteven Lee                                         unsigned size)
586c528f10dSSteven Lee {
587c528f10dSSteven Lee     AspeedINTCState *s = ASPEED_INTC(opaque);
588c528f10dSSteven Lee     const char *name = object_get_typename(OBJECT(s));
589c528f10dSSteven Lee     uint32_t reg = offset >> 2;
590c528f10dSSteven Lee 
591c528f10dSSteven Lee     trace_aspeed_intc_write(name, offset, size, data);
592c528f10dSSteven Lee 
593c528f10dSSteven Lee     switch (reg) {
594c528f10dSSteven Lee     case R_TSPINT128_EN:
595c528f10dSSteven Lee     case R_TSPINT129_EN:
596c528f10dSSteven Lee     case R_TSPINT130_EN:
597c528f10dSSteven Lee     case R_TSPINT131_EN:
598c528f10dSSteven Lee     case R_TSPINT132_EN:
599c528f10dSSteven Lee     case R_TSPINT133_EN:
600c528f10dSSteven Lee     case R_TSPINT134_EN:
601c528f10dSSteven Lee     case R_TSPINT135_EN:
602c528f10dSSteven Lee     case R_TSPINT136_EN:
603c528f10dSSteven Lee     case R_TSPINT160_169_EN:
604c528f10dSSteven Lee         aspeed_intc_enable_handler(s, offset, data);
605c528f10dSSteven Lee         break;
606c528f10dSSteven Lee     case R_TSPINT128_STATUS:
607c528f10dSSteven Lee     case R_TSPINT129_STATUS:
608c528f10dSSteven Lee     case R_TSPINT130_STATUS:
609c528f10dSSteven Lee     case R_TSPINT131_STATUS:
610c528f10dSSteven Lee     case R_TSPINT132_STATUS:
611c528f10dSSteven Lee     case R_TSPINT133_STATUS:
612c528f10dSSteven Lee     case R_TSPINT134_STATUS:
613c528f10dSSteven Lee     case R_TSPINT135_STATUS:
614c528f10dSSteven Lee     case R_TSPINT136_STATUS:
615c528f10dSSteven Lee         aspeed_intc_status_handler(s, offset, data);
616c528f10dSSteven Lee         break;
617c528f10dSSteven Lee     case R_TSPINT160_169_STATUS:
618c528f10dSSteven Lee         aspeed_intc_status_handler_multi_outpins(s, offset, data);
619c528f10dSSteven Lee         break;
620c528f10dSSteven Lee     default:
621c528f10dSSteven Lee         s->regs[reg] = data;
622c528f10dSSteven Lee         break;
623c528f10dSSteven Lee     }
6248872b671SSteven Lee }
6258872b671SSteven Lee 
aspeed_intcio_read(void * opaque,hwaddr offset,unsigned int size)62638ba38d8SJamin Lin static uint64_t aspeed_intcio_read(void *opaque, hwaddr offset,
62738ba38d8SJamin Lin                                    unsigned int size)
62838ba38d8SJamin Lin {
62938ba38d8SJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
63038ba38d8SJamin Lin     const char *name = object_get_typename(OBJECT(s));
63138ba38d8SJamin Lin     uint32_t reg = offset >> 2;
63238ba38d8SJamin Lin     uint32_t value = 0;
63338ba38d8SJamin Lin 
63438ba38d8SJamin Lin     value = s->regs[reg];
63538ba38d8SJamin Lin     trace_aspeed_intc_read(name, offset, size, value);
63638ba38d8SJamin Lin 
63738ba38d8SJamin Lin     return value;
63838ba38d8SJamin Lin }
63938ba38d8SJamin Lin 
aspeed_intcio_write(void * opaque,hwaddr offset,uint64_t data,unsigned size)64038ba38d8SJamin Lin static void aspeed_intcio_write(void *opaque, hwaddr offset, uint64_t data,
64138ba38d8SJamin Lin                                 unsigned size)
64238ba38d8SJamin Lin {
64338ba38d8SJamin Lin     AspeedINTCState *s = ASPEED_INTC(opaque);
64438ba38d8SJamin Lin     const char *name = object_get_typename(OBJECT(s));
64538ba38d8SJamin Lin     uint32_t reg = offset >> 2;
64638ba38d8SJamin Lin 
64738ba38d8SJamin Lin     trace_aspeed_intc_write(name, offset, size, data);
64838ba38d8SJamin Lin 
64938ba38d8SJamin Lin     switch (reg) {
65038ba38d8SJamin Lin     case R_GICINT192_EN:
65138ba38d8SJamin Lin     case R_GICINT193_EN:
65238ba38d8SJamin Lin     case R_GICINT194_EN:
65338ba38d8SJamin Lin     case R_GICINT195_EN:
65438ba38d8SJamin Lin     case R_GICINT196_EN:
65538ba38d8SJamin Lin     case R_GICINT197_EN:
65638ba38d8SJamin Lin         aspeed_intc_enable_handler(s, offset, data);
65738ba38d8SJamin Lin         break;
65838ba38d8SJamin Lin     case R_GICINT192_STATUS:
65938ba38d8SJamin Lin     case R_GICINT193_STATUS:
66038ba38d8SJamin Lin     case R_GICINT194_STATUS:
66138ba38d8SJamin Lin     case R_GICINT195_STATUS:
66238ba38d8SJamin Lin     case R_GICINT196_STATUS:
66338ba38d8SJamin Lin     case R_GICINT197_STATUS:
66438ba38d8SJamin Lin         aspeed_intc_status_handler(s, offset, data);
66538ba38d8SJamin Lin         break;
66638ba38d8SJamin Lin     default:
66738ba38d8SJamin Lin         s->regs[reg] = data;
66838ba38d8SJamin Lin         break;
66938ba38d8SJamin Lin     }
67038ba38d8SJamin Lin }
67138ba38d8SJamin Lin 
aspeed_ssp_intcio_write(void * opaque,hwaddr offset,uint64_t data,unsigned size)6728872b671SSteven Lee static void aspeed_ssp_intcio_write(void *opaque, hwaddr offset, uint64_t data,
6738872b671SSteven Lee                                 unsigned size)
6748872b671SSteven Lee {
6758872b671SSteven Lee     AspeedINTCState *s = ASPEED_INTC(opaque);
6768872b671SSteven Lee     const char *name = object_get_typename(OBJECT(s));
6778872b671SSteven Lee     uint32_t reg = offset >> 2;
6788872b671SSteven Lee 
6798872b671SSteven Lee     trace_aspeed_intc_write(name, offset, size, data);
6808872b671SSteven Lee 
6818872b671SSteven Lee     switch (reg) {
6828872b671SSteven Lee     case R_SSPINT160_EN:
6838872b671SSteven Lee     case R_SSPINT161_EN:
6848872b671SSteven Lee     case R_SSPINT162_EN:
6858872b671SSteven Lee     case R_SSPINT163_EN:
6868872b671SSteven Lee     case R_SSPINT164_EN:
6878872b671SSteven Lee     case R_SSPINT165_EN:
6888872b671SSteven Lee         aspeed_intc_enable_handler(s, offset, data);
6898872b671SSteven Lee         break;
6908872b671SSteven Lee     case R_SSPINT160_STATUS:
6918872b671SSteven Lee     case R_SSPINT161_STATUS:
6928872b671SSteven Lee     case R_SSPINT162_STATUS:
6938872b671SSteven Lee     case R_SSPINT163_STATUS:
6948872b671SSteven Lee     case R_SSPINT164_STATUS:
6958872b671SSteven Lee     case R_SSPINT165_STATUS:
6968872b671SSteven Lee         aspeed_intc_status_handler(s, offset, data);
6978872b671SSteven Lee         break;
6988872b671SSteven Lee     default:
6998872b671SSteven Lee         s->regs[reg] = data;
7008872b671SSteven Lee         break;
7018872b671SSteven Lee     }
702c528f10dSSteven Lee }
7038872b671SSteven Lee 
aspeed_tsp_intcio_write(void * opaque,hwaddr offset,uint64_t data,unsigned size)704c528f10dSSteven Lee static void aspeed_tsp_intcio_write(void *opaque, hwaddr offset, uint64_t data,
705c528f10dSSteven Lee                                 unsigned size)
706c528f10dSSteven Lee {
707c528f10dSSteven Lee     AspeedINTCState *s = ASPEED_INTC(opaque);
708c528f10dSSteven Lee     const char *name = object_get_typename(OBJECT(s));
709c528f10dSSteven Lee     uint32_t reg = offset >> 2;
710c528f10dSSteven Lee 
711c528f10dSSteven Lee     trace_aspeed_intc_write(name, offset, size, data);
712c528f10dSSteven Lee 
713c528f10dSSteven Lee     switch (reg) {
714c528f10dSSteven Lee     case R_TSPINT160_EN:
715c528f10dSSteven Lee     case R_TSPINT161_EN:
716c528f10dSSteven Lee     case R_TSPINT162_EN:
717c528f10dSSteven Lee     case R_TSPINT163_EN:
718c528f10dSSteven Lee     case R_TSPINT164_EN:
719c528f10dSSteven Lee     case R_TSPINT165_EN:
720c528f10dSSteven Lee         aspeed_intc_enable_handler(s, offset, data);
721c528f10dSSteven Lee         break;
722c528f10dSSteven Lee     case R_TSPINT160_STATUS:
723c528f10dSSteven Lee     case R_TSPINT161_STATUS:
724c528f10dSSteven Lee     case R_TSPINT162_STATUS:
725c528f10dSSteven Lee     case R_TSPINT163_STATUS:
726c528f10dSSteven Lee     case R_TSPINT164_STATUS:
727c528f10dSSteven Lee     case R_TSPINT165_STATUS:
728c528f10dSSteven Lee         aspeed_intc_status_handler(s, offset, data);
729c528f10dSSteven Lee         break;
730c528f10dSSteven Lee     default:
731c528f10dSSteven Lee         s->regs[reg] = data;
732c528f10dSSteven Lee         break;
733c528f10dSSteven Lee     }
7348872b671SSteven Lee }
73538ba38d8SJamin Lin 
736d831c5fdSJamin Lin static const MemoryRegionOps aspeed_intc_ops = {
737d831c5fdSJamin Lin     .read = aspeed_intc_read,
738d831c5fdSJamin Lin     .write = aspeed_intc_write,
739d831c5fdSJamin Lin     .endianness = DEVICE_LITTLE_ENDIAN,
7405c14d7cbSJamin Lin     .impl.min_access_size = 4,
741d831c5fdSJamin Lin     .valid = {
742d831c5fdSJamin Lin         .min_access_size = 4,
743d831c5fdSJamin Lin         .max_access_size = 4,
744d831c5fdSJamin Lin     }
745d831c5fdSJamin Lin };
746d831c5fdSJamin Lin 
74738ba38d8SJamin Lin static const MemoryRegionOps aspeed_intcio_ops = {
74838ba38d8SJamin Lin     .read = aspeed_intcio_read,
74938ba38d8SJamin Lin     .write = aspeed_intcio_write,
75038ba38d8SJamin Lin     .endianness = DEVICE_LITTLE_ENDIAN,
7515c14d7cbSJamin Lin     .impl.min_access_size = 4,
75238ba38d8SJamin Lin     .valid = {
75338ba38d8SJamin Lin         .min_access_size = 4,
75438ba38d8SJamin Lin         .max_access_size = 4,
75538ba38d8SJamin Lin     }
75638ba38d8SJamin Lin };
75738ba38d8SJamin Lin 
7588872b671SSteven Lee static const MemoryRegionOps aspeed_ssp_intc_ops = {
7598872b671SSteven Lee     .read = aspeed_intc_read,
7608872b671SSteven Lee     .write = aspeed_ssp_intc_write,
7618872b671SSteven Lee     .endianness = DEVICE_LITTLE_ENDIAN,
7625c14d7cbSJamin Lin     .impl.min_access_size = 4,
7638872b671SSteven Lee     .valid = {
7648872b671SSteven Lee         .min_access_size = 4,
7658872b671SSteven Lee         .max_access_size = 4,
7668872b671SSteven Lee     }
7678872b671SSteven Lee };
7688872b671SSteven Lee 
7698872b671SSteven Lee static const MemoryRegionOps aspeed_ssp_intcio_ops = {
7708872b671SSteven Lee     .read = aspeed_intcio_read,
7718872b671SSteven Lee     .write = aspeed_ssp_intcio_write,
7728872b671SSteven Lee     .endianness = DEVICE_LITTLE_ENDIAN,
7735c14d7cbSJamin Lin     .impl.min_access_size = 4,
7748872b671SSteven Lee     .valid = {
7758872b671SSteven Lee         .min_access_size = 4,
7768872b671SSteven Lee         .max_access_size = 4,
7778872b671SSteven Lee     }
7788872b671SSteven Lee };
7798872b671SSteven Lee 
780c528f10dSSteven Lee static const MemoryRegionOps aspeed_tsp_intc_ops = {
781c528f10dSSteven Lee     .read = aspeed_intc_read,
782c528f10dSSteven Lee     .write = aspeed_tsp_intc_write,
783c528f10dSSteven Lee     .endianness = DEVICE_LITTLE_ENDIAN,
7845c14d7cbSJamin Lin     .impl.min_access_size = 4,
785c528f10dSSteven Lee     .valid = {
786c528f10dSSteven Lee         .min_access_size = 4,
787c528f10dSSteven Lee         .max_access_size = 4,
788c528f10dSSteven Lee     }
789c528f10dSSteven Lee };
790c528f10dSSteven Lee 
791c528f10dSSteven Lee static const MemoryRegionOps aspeed_tsp_intcio_ops = {
792c528f10dSSteven Lee     .read = aspeed_intcio_read,
793c528f10dSSteven Lee     .write = aspeed_tsp_intcio_write,
794c528f10dSSteven Lee     .endianness = DEVICE_LITTLE_ENDIAN,
7955c14d7cbSJamin Lin     .impl.min_access_size = 4,
796c528f10dSSteven Lee     .valid = {
797c528f10dSSteven Lee         .min_access_size = 4,
798c528f10dSSteven Lee         .max_access_size = 4,
799c528f10dSSteven Lee     }
800c528f10dSSteven Lee };
801c528f10dSSteven Lee 
aspeed_intc_instance_init(Object * obj)802d831c5fdSJamin Lin static void aspeed_intc_instance_init(Object *obj)
803d831c5fdSJamin Lin {
804d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(obj);
805d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
806d831c5fdSJamin Lin     int i;
807d831c5fdSJamin Lin 
80863f3618fSJamin Lin     assert(aic->num_inpins <= ASPEED_INTC_MAX_INPINS);
80963f3618fSJamin Lin     for (i = 0; i < aic->num_inpins; i++) {
810d831c5fdSJamin Lin         object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i],
811d831c5fdSJamin Lin                                 TYPE_OR_IRQ);
812d831c5fdSJamin Lin         object_property_set_int(OBJECT(&s->orgates[i]), "num-lines",
813d831c5fdSJamin Lin                                 aic->num_lines, &error_abort);
814d831c5fdSJamin Lin     }
815d831c5fdSJamin Lin }
816d831c5fdSJamin Lin 
aspeed_intc_reset(DeviceState * dev)817d831c5fdSJamin Lin static void aspeed_intc_reset(DeviceState *dev)
818d831c5fdSJamin Lin {
819d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
820b008465dSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
821d831c5fdSJamin Lin 
822b008465dSJamin Lin     memset(s->regs, 0, aic->nr_regs << 2);
823d831c5fdSJamin Lin     memset(s->enable, 0, sizeof(s->enable));
824d831c5fdSJamin Lin     memset(s->mask, 0, sizeof(s->mask));
825d831c5fdSJamin Lin     memset(s->pending, 0, sizeof(s->pending));
826d831c5fdSJamin Lin }
827d831c5fdSJamin Lin 
aspeed_intc_realize(DeviceState * dev,Error ** errp)828d831c5fdSJamin Lin static void aspeed_intc_realize(DeviceState *dev, Error **errp)
829d831c5fdSJamin Lin {
830d831c5fdSJamin Lin     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
831d831c5fdSJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
832d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
833d831c5fdSJamin Lin     int i;
834d831c5fdSJamin Lin 
835c5728c34SJamin Lin     memory_region_init(&s->iomem_container, OBJECT(s),
836c5728c34SJamin Lin             TYPE_ASPEED_INTC ".container", aic->mem_size);
837c5728c34SJamin Lin 
838c5728c34SJamin Lin     sysbus_init_mmio(sbd, &s->iomem_container);
839c5728c34SJamin Lin 
840b008465dSJamin Lin     s->regs = g_new(uint32_t, aic->nr_regs);
84128194d5dSJamin Lin     memory_region_init_io(&s->iomem, OBJECT(s), aic->reg_ops, s,
842b008465dSJamin Lin                           TYPE_ASPEED_INTC ".regs", aic->nr_regs << 2);
843d831c5fdSJamin Lin 
8447ffee511SJamin Lin     memory_region_add_subregion(&s->iomem_container, aic->reg_offset,
8457ffee511SJamin Lin                                 &s->iomem);
846c5728c34SJamin Lin 
84763f3618fSJamin Lin     qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_inpins);
848d831c5fdSJamin Lin 
84963f3618fSJamin Lin     for (i = 0; i < aic->num_inpins; i++) {
850d831c5fdSJamin Lin         if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) {
851d831c5fdSJamin Lin             return;
852d831c5fdSJamin Lin         }
85335c909cdSJamin Lin     }
85435c909cdSJamin Lin 
85535c909cdSJamin Lin     for (i = 0; i < aic->num_outpins; i++) {
856d831c5fdSJamin Lin         sysbus_init_irq(sbd, &s->output_pins[i]);
857d831c5fdSJamin Lin     }
858d831c5fdSJamin Lin }
859d831c5fdSJamin Lin 
aspeed_intc_unrealize(DeviceState * dev)860563afea0SJamin Lin static void aspeed_intc_unrealize(DeviceState *dev)
861563afea0SJamin Lin {
862563afea0SJamin Lin     AspeedINTCState *s = ASPEED_INTC(dev);
863563afea0SJamin Lin 
864563afea0SJamin Lin     g_free(s->regs);
865563afea0SJamin Lin     s->regs = NULL;
866563afea0SJamin Lin }
867563afea0SJamin Lin 
aspeed_intc_class_init(ObjectClass * klass,const void * data)86812d1a768SPhilippe Mathieu-Daudé static void aspeed_intc_class_init(ObjectClass *klass, const void *data)
869d831c5fdSJamin Lin {
870d831c5fdSJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
87128194d5dSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
872d831c5fdSJamin Lin 
873d831c5fdSJamin Lin     dc->desc = "ASPEED INTC Controller";
874d831c5fdSJamin Lin     dc->realize = aspeed_intc_realize;
875563afea0SJamin Lin     dc->unrealize = aspeed_intc_unrealize;
876e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, aspeed_intc_reset);
877d831c5fdSJamin Lin     dc->vmsd = NULL;
87828194d5dSJamin Lin 
87928194d5dSJamin Lin     aic->reg_ops = &aspeed_intc_ops;
880d831c5fdSJamin Lin }
881d831c5fdSJamin Lin 
882d831c5fdSJamin Lin static const TypeInfo aspeed_intc_info = {
883d831c5fdSJamin Lin     .name = TYPE_ASPEED_INTC,
884d831c5fdSJamin Lin     .parent = TYPE_SYS_BUS_DEVICE,
885d831c5fdSJamin Lin     .instance_init = aspeed_intc_instance_init,
886d831c5fdSJamin Lin     .instance_size = sizeof(AspeedINTCState),
887d831c5fdSJamin Lin     .class_init = aspeed_intc_class_init,
888d831c5fdSJamin Lin     .class_size = sizeof(AspeedINTCClass),
889d831c5fdSJamin Lin     .abstract = true,
890d831c5fdSJamin Lin };
891d831c5fdSJamin Lin 
892ab24c6a2SJamin Lin static AspeedINTCIRQ aspeed_2700_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
8939178ff91SJamin Lin     {0, 0, 10, R_GICINT192_201_EN, R_GICINT192_201_STATUS},
8949178ff91SJamin Lin     {1, 10, 1, R_GICINT128_EN, R_GICINT128_STATUS},
8959178ff91SJamin Lin     {2, 11, 1, R_GICINT129_EN, R_GICINT129_STATUS},
8969178ff91SJamin Lin     {3, 12, 1, R_GICINT130_EN, R_GICINT130_STATUS},
8979178ff91SJamin Lin     {4, 13, 1, R_GICINT131_EN, R_GICINT131_STATUS},
8989178ff91SJamin Lin     {5, 14, 1, R_GICINT132_EN, R_GICINT132_STATUS},
8999178ff91SJamin Lin     {6, 15, 1, R_GICINT133_EN, R_GICINT133_STATUS},
9009178ff91SJamin Lin     {7, 16, 1, R_GICINT134_EN, R_GICINT134_STATUS},
9019178ff91SJamin Lin     {8, 17, 1, R_GICINT135_EN, R_GICINT135_STATUS},
9029178ff91SJamin Lin     {9, 18, 1, R_GICINT136_EN, R_GICINT136_STATUS},
903ab24c6a2SJamin Lin };
904ab24c6a2SJamin Lin 
aspeed_2700_intc_class_init(ObjectClass * klass,const void * data)90512d1a768SPhilippe Mathieu-Daudé static void aspeed_2700_intc_class_init(ObjectClass *klass, const void *data)
906d831c5fdSJamin Lin {
907d831c5fdSJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
908d831c5fdSJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
909d831c5fdSJamin Lin 
910d831c5fdSJamin Lin     dc->desc = "ASPEED 2700 INTC Controller";
911d831c5fdSJamin Lin     aic->num_lines = 32;
9129178ff91SJamin Lin     aic->num_inpins = 10;
9139178ff91SJamin Lin     aic->num_outpins = 19;
914c5728c34SJamin Lin     aic->mem_size = 0x4000;
9159178ff91SJamin Lin     aic->nr_regs = 0xB08 >> 2;
9167ffee511SJamin Lin     aic->reg_offset = 0x1000;
917ab24c6a2SJamin Lin     aic->irq_table = aspeed_2700_intc_irqs;
918ab24c6a2SJamin Lin     aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intc_irqs);
919d831c5fdSJamin Lin }
920d831c5fdSJamin Lin 
921d831c5fdSJamin Lin static const TypeInfo aspeed_2700_intc_info = {
922d831c5fdSJamin Lin     .name = TYPE_ASPEED_2700_INTC,
923d831c5fdSJamin Lin     .parent = TYPE_ASPEED_INTC,
924d831c5fdSJamin Lin     .class_init = aspeed_2700_intc_class_init,
925d831c5fdSJamin Lin };
926d831c5fdSJamin Lin 
92738ba38d8SJamin Lin static AspeedINTCIRQ aspeed_2700_intcio_irqs[ASPEED_INTC_MAX_INPINS] = {
92838ba38d8SJamin Lin     {0, 0, 1, R_GICINT192_EN, R_GICINT192_STATUS},
92938ba38d8SJamin Lin     {1, 1, 1, R_GICINT193_EN, R_GICINT193_STATUS},
93038ba38d8SJamin Lin     {2, 2, 1, R_GICINT194_EN, R_GICINT194_STATUS},
93138ba38d8SJamin Lin     {3, 3, 1, R_GICINT195_EN, R_GICINT195_STATUS},
93238ba38d8SJamin Lin     {4, 4, 1, R_GICINT196_EN, R_GICINT196_STATUS},
93338ba38d8SJamin Lin     {5, 5, 1, R_GICINT197_EN, R_GICINT197_STATUS},
93438ba38d8SJamin Lin };
93538ba38d8SJamin Lin 
aspeed_2700_intcio_class_init(ObjectClass * klass,const void * data)93612d1a768SPhilippe Mathieu-Daudé static void aspeed_2700_intcio_class_init(ObjectClass *klass, const void *data)
93738ba38d8SJamin Lin {
93838ba38d8SJamin Lin     DeviceClass *dc = DEVICE_CLASS(klass);
93938ba38d8SJamin Lin     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
94038ba38d8SJamin Lin 
94138ba38d8SJamin Lin     dc->desc = "ASPEED 2700 INTC IO Controller";
94238ba38d8SJamin Lin     aic->num_lines = 32;
94338ba38d8SJamin Lin     aic->num_inpins = 6;
94438ba38d8SJamin Lin     aic->num_outpins = 6;
94538ba38d8SJamin Lin     aic->mem_size = 0x400;
94638ba38d8SJamin Lin     aic->nr_regs = 0x58 >> 2;
94738ba38d8SJamin Lin     aic->reg_offset = 0x100;
94838ba38d8SJamin Lin     aic->reg_ops = &aspeed_intcio_ops;
94938ba38d8SJamin Lin     aic->irq_table = aspeed_2700_intcio_irqs;
95038ba38d8SJamin Lin     aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intcio_irqs);
95138ba38d8SJamin Lin }
95238ba38d8SJamin Lin 
95338ba38d8SJamin Lin static const TypeInfo aspeed_2700_intcio_info = {
95438ba38d8SJamin Lin     .name = TYPE_ASPEED_2700_INTCIO,
95538ba38d8SJamin Lin     .parent = TYPE_ASPEED_INTC,
95638ba38d8SJamin Lin     .class_init = aspeed_2700_intcio_class_init,
95738ba38d8SJamin Lin };
95838ba38d8SJamin Lin 
9598872b671SSteven Lee static AspeedINTCIRQ aspeed_2700ssp_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
9608872b671SSteven Lee     {0, 0, 10, R_SSPINT160_169_EN, R_SSPINT160_169_STATUS},
9618872b671SSteven Lee     {1, 10, 1, R_SSPINT128_EN, R_SSPINT128_STATUS},
9628872b671SSteven Lee     {2, 11, 1, R_SSPINT129_EN, R_SSPINT129_STATUS},
9638872b671SSteven Lee     {3, 12, 1, R_SSPINT130_EN, R_SSPINT130_STATUS},
9648872b671SSteven Lee     {4, 13, 1, R_SSPINT131_EN, R_SSPINT131_STATUS},
9658872b671SSteven Lee     {5, 14, 1, R_SSPINT132_EN, R_SSPINT132_STATUS},
9668872b671SSteven Lee     {6, 15, 1, R_SSPINT133_EN, R_SSPINT133_STATUS},
9678872b671SSteven Lee     {7, 16, 1, R_SSPINT134_EN, R_SSPINT134_STATUS},
9688872b671SSteven Lee     {8, 17, 1, R_SSPINT135_EN, R_SSPINT135_STATUS},
9698872b671SSteven Lee     {9, 18, 1, R_SSPINT136_EN, R_SSPINT136_STATUS},
9708872b671SSteven Lee };
9718872b671SSteven Lee 
aspeed_2700ssp_intc_class_init(ObjectClass * klass,const void * data)9728872b671SSteven Lee static void aspeed_2700ssp_intc_class_init(ObjectClass *klass, const void *data)
9738872b671SSteven Lee {
9748872b671SSteven Lee     DeviceClass *dc = DEVICE_CLASS(klass);
9758872b671SSteven Lee     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
9768872b671SSteven Lee 
9778872b671SSteven Lee     dc->desc = "ASPEED 2700 SSP INTC Controller";
9788872b671SSteven Lee     aic->num_lines = 32;
9798872b671SSteven Lee     aic->num_inpins = 10;
9808872b671SSteven Lee     aic->num_outpins = 19;
9818872b671SSteven Lee     aic->mem_size = 0x4000;
9828872b671SSteven Lee     aic->nr_regs = 0x2B08 >> 2;
9838872b671SSteven Lee     aic->reg_offset = 0x0;
9848872b671SSteven Lee     aic->reg_ops = &aspeed_ssp_intc_ops;
9858872b671SSteven Lee     aic->irq_table = aspeed_2700ssp_intc_irqs;
9868872b671SSteven Lee     aic->irq_table_count = ARRAY_SIZE(aspeed_2700ssp_intc_irqs);
9878872b671SSteven Lee }
9888872b671SSteven Lee 
9898872b671SSteven Lee static const TypeInfo aspeed_2700ssp_intc_info = {
9908872b671SSteven Lee     .name = TYPE_ASPEED_2700SSP_INTC,
9918872b671SSteven Lee     .parent = TYPE_ASPEED_INTC,
9928872b671SSteven Lee     .class_init = aspeed_2700ssp_intc_class_init,
9938872b671SSteven Lee };
9948872b671SSteven Lee 
9958872b671SSteven Lee static AspeedINTCIRQ aspeed_2700ssp_intcio_irqs[ASPEED_INTC_MAX_INPINS] = {
9968872b671SSteven Lee     {0, 0, 1, R_SSPINT160_EN, R_SSPINT160_STATUS},
9978872b671SSteven Lee     {1, 1, 1, R_SSPINT161_EN, R_SSPINT161_STATUS},
9988872b671SSteven Lee     {2, 2, 1, R_SSPINT162_EN, R_SSPINT162_STATUS},
9998872b671SSteven Lee     {3, 3, 1, R_SSPINT163_EN, R_SSPINT163_STATUS},
10008872b671SSteven Lee     {4, 4, 1, R_SSPINT164_EN, R_SSPINT164_STATUS},
10018872b671SSteven Lee     {5, 5, 1, R_SSPINT165_EN, R_SSPINT165_STATUS},
10028872b671SSteven Lee };
10038872b671SSteven Lee 
aspeed_2700ssp_intcio_class_init(ObjectClass * klass,const void * data)1004*567accbaSJamin Lin static void aspeed_2700ssp_intcio_class_init(ObjectClass *klass,
1005*567accbaSJamin Lin                                              const void *data)
10068872b671SSteven Lee {
10078872b671SSteven Lee     DeviceClass *dc = DEVICE_CLASS(klass);
10088872b671SSteven Lee     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
10098872b671SSteven Lee 
10108872b671SSteven Lee     dc->desc = "ASPEED 2700 SSP INTC IO Controller";
10118872b671SSteven Lee     aic->num_lines = 32;
10128872b671SSteven Lee     aic->num_inpins = 6;
10138872b671SSteven Lee     aic->num_outpins = 6;
10148872b671SSteven Lee     aic->mem_size = 0x400;
10158872b671SSteven Lee     aic->nr_regs = 0x1d8 >> 2;
10168872b671SSteven Lee     aic->reg_offset = 0;
10178872b671SSteven Lee     aic->reg_ops = &aspeed_ssp_intcio_ops;
10188872b671SSteven Lee     aic->irq_table = aspeed_2700ssp_intcio_irqs;
10198872b671SSteven Lee     aic->irq_table_count = ARRAY_SIZE(aspeed_2700ssp_intcio_irqs);
10208872b671SSteven Lee }
10218872b671SSteven Lee 
10228872b671SSteven Lee static const TypeInfo aspeed_2700ssp_intcio_info = {
10238872b671SSteven Lee     .name = TYPE_ASPEED_2700SSP_INTCIO,
10248872b671SSteven Lee     .parent = TYPE_ASPEED_INTC,
10258872b671SSteven Lee     .class_init = aspeed_2700ssp_intcio_class_init,
10268872b671SSteven Lee };
10278872b671SSteven Lee 
1028c528f10dSSteven Lee static AspeedINTCIRQ aspeed_2700tsp_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
1029c528f10dSSteven Lee     {0, 0, 10, R_TSPINT160_169_EN, R_TSPINT160_169_STATUS},
1030c528f10dSSteven Lee     {1, 10, 1, R_TSPINT128_EN, R_TSPINT128_STATUS},
1031c528f10dSSteven Lee     {2, 11, 1, R_TSPINT129_EN, R_TSPINT129_STATUS},
1032c528f10dSSteven Lee     {3, 12, 1, R_TSPINT130_EN, R_TSPINT130_STATUS},
1033c528f10dSSteven Lee     {4, 13, 1, R_TSPINT131_EN, R_TSPINT131_STATUS},
1034c528f10dSSteven Lee     {5, 14, 1, R_TSPINT132_EN, R_TSPINT132_STATUS},
1035c528f10dSSteven Lee     {6, 15, 1, R_TSPINT133_EN, R_TSPINT133_STATUS},
1036c528f10dSSteven Lee     {7, 16, 1, R_TSPINT134_EN, R_TSPINT134_STATUS},
1037c528f10dSSteven Lee     {8, 17, 1, R_TSPINT135_EN, R_TSPINT135_STATUS},
1038c528f10dSSteven Lee     {9, 18, 1, R_TSPINT136_EN, R_TSPINT136_STATUS},
1039c528f10dSSteven Lee };
1040c528f10dSSteven Lee 
aspeed_2700tsp_intc_class_init(ObjectClass * klass,const void * data)1041c528f10dSSteven Lee static void aspeed_2700tsp_intc_class_init(ObjectClass *klass, const void *data)
1042c528f10dSSteven Lee {
1043c528f10dSSteven Lee     DeviceClass *dc = DEVICE_CLASS(klass);
1044c528f10dSSteven Lee     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
1045c528f10dSSteven Lee 
1046c528f10dSSteven Lee     dc->desc = "ASPEED 2700 TSP INTC Controller";
1047c528f10dSSteven Lee     aic->num_lines = 32;
1048c528f10dSSteven Lee     aic->num_inpins = 10;
1049c528f10dSSteven Lee     aic->num_outpins = 19;
1050c528f10dSSteven Lee     aic->mem_size = 0x4000;
1051c528f10dSSteven Lee     aic->nr_regs = 0x3B08 >> 2;
1052c528f10dSSteven Lee     aic->reg_offset = 0;
1053c528f10dSSteven Lee     aic->reg_ops = &aspeed_tsp_intc_ops;
1054c528f10dSSteven Lee     aic->irq_table = aspeed_2700tsp_intc_irqs;
1055c528f10dSSteven Lee     aic->irq_table_count = ARRAY_SIZE(aspeed_2700tsp_intc_irqs);
1056c528f10dSSteven Lee }
1057c528f10dSSteven Lee 
1058c528f10dSSteven Lee static const TypeInfo aspeed_2700tsp_intc_info = {
1059c528f10dSSteven Lee     .name = TYPE_ASPEED_2700TSP_INTC,
1060c528f10dSSteven Lee     .parent = TYPE_ASPEED_INTC,
1061c528f10dSSteven Lee     .class_init = aspeed_2700tsp_intc_class_init,
1062c528f10dSSteven Lee };
1063c528f10dSSteven Lee 
1064c528f10dSSteven Lee static AspeedINTCIRQ aspeed_2700tsp_intcio_irqs[ASPEED_INTC_MAX_INPINS] = {
1065c528f10dSSteven Lee     {0, 0, 1, R_TSPINT160_EN, R_TSPINT160_STATUS},
1066c528f10dSSteven Lee     {1, 1, 1, R_TSPINT161_EN, R_TSPINT161_STATUS},
1067c528f10dSSteven Lee     {2, 2, 1, R_TSPINT162_EN, R_TSPINT162_STATUS},
1068c528f10dSSteven Lee     {3, 3, 1, R_TSPINT163_EN, R_TSPINT163_STATUS},
1069c528f10dSSteven Lee     {4, 4, 1, R_TSPINT164_EN, R_TSPINT164_STATUS},
1070c528f10dSSteven Lee     {5, 5, 1, R_TSPINT165_EN, R_TSPINT165_STATUS},
1071c528f10dSSteven Lee };
1072c528f10dSSteven Lee 
aspeed_2700tsp_intcio_class_init(ObjectClass * klass,const void * data)1073*567accbaSJamin Lin static void aspeed_2700tsp_intcio_class_init(ObjectClass *klass,
1074*567accbaSJamin Lin                                              const void *data)
1075c528f10dSSteven Lee {
1076c528f10dSSteven Lee     DeviceClass *dc = DEVICE_CLASS(klass);
1077c528f10dSSteven Lee     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
1078c528f10dSSteven Lee 
1079c528f10dSSteven Lee     dc->desc = "ASPEED 2700 TSP INTC IO Controller";
1080c528f10dSSteven Lee     aic->num_lines = 32;
1081c528f10dSSteven Lee     aic->num_inpins = 6;
1082c528f10dSSteven Lee     aic->num_outpins = 6;
1083c528f10dSSteven Lee     aic->mem_size = 0x400;
1084c528f10dSSteven Lee     aic->nr_regs = 0x258 >> 2;
1085c528f10dSSteven Lee     aic->reg_offset = 0x0;
1086c528f10dSSteven Lee     aic->reg_ops = &aspeed_tsp_intcio_ops;
1087c528f10dSSteven Lee     aic->irq_table = aspeed_2700tsp_intcio_irqs;
1088c528f10dSSteven Lee     aic->irq_table_count = ARRAY_SIZE(aspeed_2700tsp_intcio_irqs);
1089c528f10dSSteven Lee }
1090c528f10dSSteven Lee 
1091c528f10dSSteven Lee static const TypeInfo aspeed_2700tsp_intcio_info = {
1092c528f10dSSteven Lee     .name = TYPE_ASPEED_2700TSP_INTCIO,
1093c528f10dSSteven Lee     .parent = TYPE_ASPEED_INTC,
1094c528f10dSSteven Lee     .class_init = aspeed_2700tsp_intcio_class_init,
1095c528f10dSSteven Lee };
1096c528f10dSSteven Lee 
aspeed_intc_register_types(void)1097d831c5fdSJamin Lin static void aspeed_intc_register_types(void)
1098d831c5fdSJamin Lin {
1099d831c5fdSJamin Lin     type_register_static(&aspeed_intc_info);
1100d831c5fdSJamin Lin     type_register_static(&aspeed_2700_intc_info);
110138ba38d8SJamin Lin     type_register_static(&aspeed_2700_intcio_info);
11028872b671SSteven Lee     type_register_static(&aspeed_2700ssp_intc_info);
11038872b671SSteven Lee     type_register_static(&aspeed_2700ssp_intcio_info);
1104c528f10dSSteven Lee     type_register_static(&aspeed_2700tsp_intc_info);
1105c528f10dSSteven Lee     type_register_static(&aspeed_2700tsp_intcio_info);
1106d831c5fdSJamin Lin }
1107d831c5fdSJamin Lin 
1108d831c5fdSJamin Lin type_init(aspeed_intc_register_types);
1109