xref: /openbmc/qemu/hw/intc/aspeed_intc.c (revision 5824e8bf6beb226aa5dee94d4e92b671e9b082f1)
1 /*
2  * ASPEED INTC Controller
3  *
4  * Copyright (C) 2024 ASPEED Technology Inc.
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 
9 #include "qemu/osdep.h"
10 #include "hw/intc/aspeed_intc.h"
11 #include "hw/irq.h"
12 #include "qemu/log.h"
13 #include "trace.h"
14 #include "hw/registerfields.h"
15 #include "qapi/error.h"
16 
17 /*
18  * INTC Registers
19  *
20  * values below are offset by - 0x1000 from datasheet
21  * because its memory region is start at 0x1000
22  *
23  */
24 REG32(GICINT128_EN,         0x000)
25 REG32(GICINT128_STATUS,     0x004)
26 REG32(GICINT129_EN,         0x100)
27 REG32(GICINT129_STATUS,     0x104)
28 REG32(GICINT130_EN,         0x200)
29 REG32(GICINT130_STATUS,     0x204)
30 REG32(GICINT131_EN,         0x300)
31 REG32(GICINT131_STATUS,     0x304)
32 REG32(GICINT132_EN,         0x400)
33 REG32(GICINT132_STATUS,     0x404)
34 REG32(GICINT133_EN,         0x500)
35 REG32(GICINT133_STATUS,     0x504)
36 REG32(GICINT134_EN,         0x600)
37 REG32(GICINT134_STATUS,     0x604)
38 REG32(GICINT135_EN,         0x700)
39 REG32(GICINT135_STATUS,     0x704)
40 REG32(GICINT136_EN,         0x800)
41 REG32(GICINT136_STATUS,     0x804)
42 
43 static const AspeedINTCIRQ *aspeed_intc_get_irq(AspeedINTCClass *aic,
44                                                 uint32_t reg)
45 {
46     int i;
47 
48     for (i = 0; i < aic->irq_table_count; i++) {
49         if (aic->irq_table[i].enable_reg == reg ||
50             aic->irq_table[i].status_reg == reg) {
51             return &aic->irq_table[i];
52         }
53     }
54 
55     /*
56      * Invalid reg.
57      */
58     g_assert_not_reached();
59 }
60 
61 /*
62  * Update the state of an interrupt controller pin by setting
63  * the specified output pin to the given level.
64  * The input pin index should be between 0 and the number of input pins.
65  * The output pin index should be between 0 and the number of output pins.
66  */
67 static void aspeed_intc_update(AspeedINTCState *s, int inpin_idx,
68                                int outpin_idx, int level)
69 {
70     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
71     const char *name = object_get_typename(OBJECT(s));
72 
73     assert((outpin_idx < aic->num_outpins) && (inpin_idx < aic->num_inpins));
74 
75     trace_aspeed_intc_update_irq(name, inpin_idx, outpin_idx, level);
76     qemu_set_irq(s->output_pins[outpin_idx], level);
77 }
78 
79 static void aspeed_intc_set_irq_handler(AspeedINTCState *s,
80                                         const AspeedINTCIRQ *intc_irq,
81                                         uint32_t select)
82 {
83     const char *name = object_get_typename(OBJECT(s));
84     uint32_t status_reg;
85     int outpin_idx;
86     int inpin_idx;
87 
88     status_reg = intc_irq->status_reg;
89     outpin_idx = intc_irq->outpin_idx;
90     inpin_idx = intc_irq->inpin_idx;
91 
92     if (s->mask[inpin_idx] || s->regs[status_reg]) {
93         /*
94          * a. mask is not 0 means in ISR mode
95          * sources interrupt routine are executing.
96          * b. status register value is not 0 means previous
97          * source interrupt does not be executed, yet.
98          *
99          * save source interrupt to pending variable.
100          */
101         s->pending[inpin_idx] |= select;
102         trace_aspeed_intc_pending_irq(name, inpin_idx, s->pending[inpin_idx]);
103     } else {
104         /*
105          * notify firmware which source interrupt are coming
106          * by setting status register
107          */
108         s->regs[status_reg] = select;
109         trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
110                                       s->regs[status_reg]);
111         aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
112     }
113 }
114 
115 /*
116  * GICINT128 to GICINT136 map 1:1 to input and output IRQs 0 to 8.
117  * The value of input IRQ should be between 0 and the number of inputs.
118  */
119 static void aspeed_intc_set_irq(void *opaque, int irq, int level)
120 {
121     AspeedINTCState *s = (AspeedINTCState *)opaque;
122     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
123     const char *name = object_get_typename(OBJECT(s));
124     const AspeedINTCIRQ *intc_irq;
125     uint32_t select = 0;
126     uint32_t enable;
127     int inpin_idx;
128     int i;
129 
130     assert(irq < aic->num_inpins);
131 
132     intc_irq = &aic->irq_table[irq];
133     inpin_idx = intc_irq->inpin_idx;
134     trace_aspeed_intc_set_irq(name, inpin_idx, level);
135     enable = s->enable[inpin_idx];
136 
137     if (!level) {
138         return;
139     }
140 
141     for (i = 0; i < aic->num_lines; i++) {
142         if (s->orgates[inpin_idx].levels[i]) {
143             if (enable & BIT(i)) {
144                 select |= BIT(i);
145             }
146         }
147     }
148 
149     if (!select) {
150         return;
151     }
152 
153     trace_aspeed_intc_select(name, select);
154     aspeed_intc_set_irq_handler(s, intc_irq, select);
155 }
156 
157 static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset,
158                                        uint64_t data)
159 {
160     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
161     const char *name = object_get_typename(OBJECT(s));
162     const AspeedINTCIRQ *intc_irq;
163     uint32_t reg = offset >> 2;
164     uint32_t old_enable;
165     uint32_t change;
166     int inpin_idx;
167 
168     intc_irq = aspeed_intc_get_irq(aic, reg);
169     inpin_idx = intc_irq->inpin_idx;
170 
171     assert(inpin_idx < aic->num_inpins);
172 
173     /*
174      * The enable registers are used to enable source interrupts.
175      * They also handle masking and unmasking of source interrupts
176      * during the execution of the source ISR.
177      */
178 
179     /* disable all source interrupt */
180     if (!data && !s->enable[inpin_idx]) {
181         s->regs[reg] = data;
182         return;
183     }
184 
185     old_enable = s->enable[inpin_idx];
186     s->enable[inpin_idx] |= data;
187 
188     /* enable new source interrupt */
189     if (old_enable != s->enable[inpin_idx]) {
190         trace_aspeed_intc_enable(name, s->enable[inpin_idx]);
191         s->regs[reg] = data;
192         return;
193     }
194 
195     /* mask and unmask source interrupt */
196     change = s->regs[reg] ^ data;
197     if (change & data) {
198         s->mask[inpin_idx] &= ~change;
199         trace_aspeed_intc_unmask(name, change, s->mask[inpin_idx]);
200     } else {
201         s->mask[inpin_idx] |= change;
202         trace_aspeed_intc_mask(name, change, s->mask[inpin_idx]);
203     }
204 
205     s->regs[reg] = data;
206 }
207 
208 static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset,
209                                        uint64_t data)
210 {
211     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
212     const char *name = object_get_typename(OBJECT(s));
213     const AspeedINTCIRQ *intc_irq;
214     uint32_t reg = offset >> 2;
215     int outpin_idx;
216     int inpin_idx;
217 
218     if (!data) {
219         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
220         return;
221     }
222 
223     intc_irq = aspeed_intc_get_irq(aic, reg);
224     outpin_idx = intc_irq->outpin_idx;
225     inpin_idx = intc_irq->inpin_idx;
226 
227     assert(inpin_idx < aic->num_inpins);
228 
229     /* clear status */
230     s->regs[reg] &= ~data;
231 
232     /*
233      * These status registers are used for notify sources ISR are executed.
234      * If one source ISR is executed, it will clear one bit.
235      * If it clear all bits, it means to initialize this register status
236      * rather than sources ISR are executed.
237      */
238     if (data == 0xffffffff) {
239         return;
240     }
241 
242     /* All source ISR execution are done */
243     if (!s->regs[reg]) {
244         trace_aspeed_intc_all_isr_done(name, inpin_idx);
245         if (s->pending[inpin_idx]) {
246             /*
247              * handle pending source interrupt
248              * notify firmware which source interrupt are pending
249              * by setting status register
250              */
251             s->regs[reg] = s->pending[inpin_idx];
252             s->pending[inpin_idx] = 0;
253             trace_aspeed_intc_trigger_irq(name, inpin_idx, outpin_idx,
254                                           s->regs[reg]);
255             aspeed_intc_update(s, inpin_idx, outpin_idx, 1);
256         } else {
257             /* clear irq */
258             trace_aspeed_intc_clear_irq(name, inpin_idx, outpin_idx, 0);
259             aspeed_intc_update(s, inpin_idx, outpin_idx, 0);
260         }
261     }
262 }
263 
264 static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
265 {
266     AspeedINTCState *s = ASPEED_INTC(opaque);
267     const char *name = object_get_typename(OBJECT(s));
268     uint32_t reg = offset >> 2;
269     uint32_t value = 0;
270 
271     value = s->regs[reg];
272     trace_aspeed_intc_read(name, offset, size, value);
273 
274     return value;
275 }
276 
277 static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
278                                         unsigned size)
279 {
280     AspeedINTCState *s = ASPEED_INTC(opaque);
281     const char *name = object_get_typename(OBJECT(s));
282     uint32_t reg = offset >> 2;
283 
284     trace_aspeed_intc_write(name, offset, size, data);
285 
286     switch (reg) {
287     case R_GICINT128_EN:
288     case R_GICINT129_EN:
289     case R_GICINT130_EN:
290     case R_GICINT131_EN:
291     case R_GICINT132_EN:
292     case R_GICINT133_EN:
293     case R_GICINT134_EN:
294     case R_GICINT135_EN:
295     case R_GICINT136_EN:
296         aspeed_intc_enable_handler(s, offset, data);
297         break;
298     case R_GICINT128_STATUS:
299     case R_GICINT129_STATUS:
300     case R_GICINT130_STATUS:
301     case R_GICINT131_STATUS:
302     case R_GICINT132_STATUS:
303     case R_GICINT133_STATUS:
304     case R_GICINT134_STATUS:
305     case R_GICINT135_STATUS:
306     case R_GICINT136_STATUS:
307         aspeed_intc_status_handler(s, offset, data);
308         break;
309     default:
310         s->regs[reg] = data;
311         break;
312     }
313 
314     return;
315 }
316 
317 static const MemoryRegionOps aspeed_intc_ops = {
318     .read = aspeed_intc_read,
319     .write = aspeed_intc_write,
320     .endianness = DEVICE_LITTLE_ENDIAN,
321     .valid = {
322         .min_access_size = 4,
323         .max_access_size = 4,
324     }
325 };
326 
327 static void aspeed_intc_instance_init(Object *obj)
328 {
329     AspeedINTCState *s = ASPEED_INTC(obj);
330     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
331     int i;
332 
333     assert(aic->num_inpins <= ASPEED_INTC_MAX_INPINS);
334     for (i = 0; i < aic->num_inpins; i++) {
335         object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i],
336                                 TYPE_OR_IRQ);
337         object_property_set_int(OBJECT(&s->orgates[i]), "num-lines",
338                                 aic->num_lines, &error_abort);
339     }
340 }
341 
342 static void aspeed_intc_reset(DeviceState *dev)
343 {
344     AspeedINTCState *s = ASPEED_INTC(dev);
345     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
346 
347     memset(s->regs, 0, aic->nr_regs << 2);
348     memset(s->enable, 0, sizeof(s->enable));
349     memset(s->mask, 0, sizeof(s->mask));
350     memset(s->pending, 0, sizeof(s->pending));
351 }
352 
353 static void aspeed_intc_realize(DeviceState *dev, Error **errp)
354 {
355     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
356     AspeedINTCState *s = ASPEED_INTC(dev);
357     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
358     int i;
359 
360     memory_region_init(&s->iomem_container, OBJECT(s),
361             TYPE_ASPEED_INTC ".container", aic->mem_size);
362 
363     sysbus_init_mmio(sbd, &s->iomem_container);
364 
365     s->regs = g_new(uint32_t, aic->nr_regs);
366     memory_region_init_io(&s->iomem, OBJECT(s), aic->reg_ops, s,
367                           TYPE_ASPEED_INTC ".regs", aic->nr_regs << 2);
368 
369     memory_region_add_subregion(&s->iomem_container, aic->reg_offset,
370                                 &s->iomem);
371 
372     qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_inpins);
373 
374     for (i = 0; i < aic->num_inpins; i++) {
375         if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) {
376             return;
377         }
378     }
379 
380     for (i = 0; i < aic->num_outpins; i++) {
381         sysbus_init_irq(sbd, &s->output_pins[i]);
382     }
383 }
384 
385 static void aspeed_intc_unrealize(DeviceState *dev)
386 {
387     AspeedINTCState *s = ASPEED_INTC(dev);
388 
389     g_free(s->regs);
390     s->regs = NULL;
391 }
392 
393 static void aspeed_intc_class_init(ObjectClass *klass, void *data)
394 {
395     DeviceClass *dc = DEVICE_CLASS(klass);
396     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
397 
398     dc->desc = "ASPEED INTC Controller";
399     dc->realize = aspeed_intc_realize;
400     dc->unrealize = aspeed_intc_unrealize;
401     device_class_set_legacy_reset(dc, aspeed_intc_reset);
402     dc->vmsd = NULL;
403 
404     aic->reg_ops = &aspeed_intc_ops;
405 }
406 
407 static const TypeInfo aspeed_intc_info = {
408     .name = TYPE_ASPEED_INTC,
409     .parent = TYPE_SYS_BUS_DEVICE,
410     .instance_init = aspeed_intc_instance_init,
411     .instance_size = sizeof(AspeedINTCState),
412     .class_init = aspeed_intc_class_init,
413     .class_size = sizeof(AspeedINTCClass),
414     .abstract = true,
415 };
416 
417 static AspeedINTCIRQ aspeed_2700_intc_irqs[ASPEED_INTC_MAX_INPINS] = {
418     {0, 0, 1, R_GICINT128_EN, R_GICINT128_STATUS},
419     {1, 1, 1, R_GICINT129_EN, R_GICINT129_STATUS},
420     {2, 2, 1, R_GICINT130_EN, R_GICINT130_STATUS},
421     {3, 3, 1, R_GICINT131_EN, R_GICINT131_STATUS},
422     {4, 4, 1, R_GICINT132_EN, R_GICINT132_STATUS},
423     {5, 5, 1, R_GICINT133_EN, R_GICINT133_STATUS},
424     {6, 6, 1, R_GICINT134_EN, R_GICINT134_STATUS},
425     {7, 7, 1, R_GICINT135_EN, R_GICINT135_STATUS},
426     {8, 8, 1, R_GICINT136_EN, R_GICINT136_STATUS},
427 };
428 
429 static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data)
430 {
431     DeviceClass *dc = DEVICE_CLASS(klass);
432     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
433 
434     dc->desc = "ASPEED 2700 INTC Controller";
435     aic->num_lines = 32;
436     aic->num_inpins = 9;
437     aic->num_outpins = 9;
438     aic->mem_size = 0x4000;
439     aic->nr_regs = 0x808 >> 2;
440     aic->reg_offset = 0x1000;
441     aic->irq_table = aspeed_2700_intc_irqs;
442     aic->irq_table_count = ARRAY_SIZE(aspeed_2700_intc_irqs);
443 }
444 
445 static const TypeInfo aspeed_2700_intc_info = {
446     .name = TYPE_ASPEED_2700_INTC,
447     .parent = TYPE_ASPEED_INTC,
448     .class_init = aspeed_2700_intc_class_init,
449 };
450 
451 static void aspeed_intc_register_types(void)
452 {
453     type_register_static(&aspeed_intc_info);
454     type_register_static(&aspeed_2700_intc_info);
455 }
456 
457 type_init(aspeed_intc_register_types);
458