xref: /openbmc/qemu/hw/intc/aspeed_intc.c (revision 63f3618f9be0f28ff36cd4b5685877715b97e669)
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 #define GICINT_STATUS_BASE     R_GICINT128_STATUS
44 
45 static void aspeed_intc_update(AspeedINTCState *s, int irq, int level)
46 {
47     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
48     const char *name = object_get_typename(OBJECT(s));
49 
50     if (irq >= aic->num_inpins) {
51         qemu_log_mask(LOG_GUEST_ERROR,
52                       "%s: Invalid input pin index: %d\n",
53                       __func__, irq);
54         return;
55     }
56 
57     trace_aspeed_intc_update_irq(name, irq, level);
58     qemu_set_irq(s->output_pins[irq], level);
59 }
60 
61 /*
62  * The address of GICINT128 to GICINT136 are from 0x1000 to 0x1804.
63  * Utilize "address & 0x0f00" to get the irq and irq output pin index
64  * The value of irq should be 0 to num_inpins.
65  * The irq 0 indicates GICINT128, irq 1 indicates GICINT129 and so on.
66  */
67 static void aspeed_intc_set_irq(void *opaque, int irq, int level)
68 {
69     AspeedINTCState *s = (AspeedINTCState *)opaque;
70     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
71     const char *name = object_get_typename(OBJECT(s));
72     uint32_t status_reg = GICINT_STATUS_BASE + ((0x100 * irq) >> 2);
73     uint32_t select = 0;
74     uint32_t enable;
75     int i;
76 
77     if (irq >= aic->num_inpins) {
78         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid input pin index: %d\n",
79                       __func__, irq);
80         return;
81     }
82 
83     trace_aspeed_intc_set_irq(name, irq, level);
84     enable = s->enable[irq];
85 
86     if (!level) {
87         return;
88     }
89 
90     for (i = 0; i < aic->num_lines; i++) {
91         if (s->orgates[irq].levels[i]) {
92             if (enable & BIT(i)) {
93                 select |= BIT(i);
94             }
95         }
96     }
97 
98     if (!select) {
99         return;
100     }
101 
102     trace_aspeed_intc_select(name, select);
103 
104     if (s->mask[irq] || s->regs[status_reg]) {
105         /*
106          * a. mask is not 0 means in ISR mode
107          * sources interrupt routine are executing.
108          * b. status register value is not 0 means previous
109          * source interrupt does not be executed, yet.
110          *
111          * save source interrupt to pending variable.
112          */
113         s->pending[irq] |= select;
114         trace_aspeed_intc_pending_irq(name, irq, s->pending[irq]);
115     } else {
116         /*
117          * notify firmware which source interrupt are coming
118          * by setting status register
119          */
120         s->regs[status_reg] = select;
121         trace_aspeed_intc_trigger_irq(name, irq, s->regs[status_reg]);
122         aspeed_intc_update(s, irq, 1);
123     }
124 }
125 
126 static void aspeed_intc_enable_handler(AspeedINTCState *s, hwaddr offset,
127                                        uint64_t data)
128 {
129     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
130     const char *name = object_get_typename(OBJECT(s));
131     uint32_t reg = offset >> 2;
132     uint32_t old_enable;
133     uint32_t change;
134     uint32_t irq;
135 
136     irq = (offset & 0x0f00) >> 8;
137 
138     if (irq >= aic->num_inpins) {
139         qemu_log_mask(LOG_GUEST_ERROR,
140                       "%s: Invalid input pin index: %d\n",
141                       __func__, irq);
142         return;
143     }
144 
145     /*
146      * The enable registers are used to enable source interrupts.
147      * They also handle masking and unmasking of source interrupts
148      * during the execution of the source ISR.
149      */
150 
151     /* disable all source interrupt */
152     if (!data && !s->enable[irq]) {
153         s->regs[reg] = data;
154         return;
155     }
156 
157     old_enable = s->enable[irq];
158     s->enable[irq] |= data;
159 
160     /* enable new source interrupt */
161     if (old_enable != s->enable[irq]) {
162         trace_aspeed_intc_enable(name, s->enable[irq]);
163         s->regs[reg] = data;
164         return;
165     }
166 
167     /* mask and unmask source interrupt */
168     change = s->regs[reg] ^ data;
169     if (change & data) {
170         s->mask[irq] &= ~change;
171         trace_aspeed_intc_unmask(name, change, s->mask[irq]);
172     } else {
173         s->mask[irq] |= change;
174         trace_aspeed_intc_mask(name, change, s->mask[irq]);
175     }
176 
177     s->regs[reg] = data;
178 }
179 
180 static void aspeed_intc_status_handler(AspeedINTCState *s, hwaddr offset,
181                                        uint64_t data)
182 {
183     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
184     const char *name = object_get_typename(OBJECT(s));
185     uint32_t reg = offset >> 2;
186     uint32_t irq;
187 
188     if (!data) {
189         qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid data 0\n", __func__);
190         return;
191     }
192 
193     irq = (offset & 0x0f00) >> 8;
194 
195     if (irq >= aic->num_inpins) {
196         qemu_log_mask(LOG_GUEST_ERROR,
197                       "%s: Invalid input pin index: %d\n",
198                       __func__, irq);
199         return;
200     }
201 
202     /* clear status */
203     s->regs[reg] &= ~data;
204 
205     /*
206      * These status registers are used for notify sources ISR are executed.
207      * If one source ISR is executed, it will clear one bit.
208      * If it clear all bits, it means to initialize this register status
209      * rather than sources ISR are executed.
210      */
211     if (data == 0xffffffff) {
212         return;
213     }
214 
215     /* All source ISR execution are done */
216     if (!s->regs[reg]) {
217         trace_aspeed_intc_all_isr_done(name, irq);
218         if (s->pending[irq]) {
219             /*
220              * handle pending source interrupt
221              * notify firmware which source interrupt are pending
222              * by setting status register
223              */
224             s->regs[reg] = s->pending[irq];
225             s->pending[irq] = 0;
226             trace_aspeed_intc_trigger_irq(name, irq, s->regs[reg]);
227             aspeed_intc_update(s, irq, 1);
228         } else {
229             /* clear irq */
230             trace_aspeed_intc_clear_irq(name, irq, 0);
231             aspeed_intc_update(s, irq, 0);
232         }
233     }
234 }
235 
236 static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned int size)
237 {
238     AspeedINTCState *s = ASPEED_INTC(opaque);
239     const char *name = object_get_typename(OBJECT(s));
240     uint32_t reg = offset >> 2;
241     uint32_t value = 0;
242 
243     value = s->regs[reg];
244     trace_aspeed_intc_read(name, offset, size, value);
245 
246     return value;
247 }
248 
249 static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
250                                         unsigned size)
251 {
252     AspeedINTCState *s = ASPEED_INTC(opaque);
253     const char *name = object_get_typename(OBJECT(s));
254     uint32_t reg = offset >> 2;
255 
256     trace_aspeed_intc_write(name, offset, size, data);
257 
258     switch (reg) {
259     case R_GICINT128_EN:
260     case R_GICINT129_EN:
261     case R_GICINT130_EN:
262     case R_GICINT131_EN:
263     case R_GICINT132_EN:
264     case R_GICINT133_EN:
265     case R_GICINT134_EN:
266     case R_GICINT135_EN:
267     case R_GICINT136_EN:
268         aspeed_intc_enable_handler(s, offset, data);
269         break;
270     case R_GICINT128_STATUS:
271     case R_GICINT129_STATUS:
272     case R_GICINT130_STATUS:
273     case R_GICINT131_STATUS:
274     case R_GICINT132_STATUS:
275     case R_GICINT133_STATUS:
276     case R_GICINT134_STATUS:
277     case R_GICINT135_STATUS:
278     case R_GICINT136_STATUS:
279         aspeed_intc_status_handler(s, offset, data);
280         break;
281     default:
282         s->regs[reg] = data;
283         break;
284     }
285 
286     return;
287 }
288 
289 static const MemoryRegionOps aspeed_intc_ops = {
290     .read = aspeed_intc_read,
291     .write = aspeed_intc_write,
292     .endianness = DEVICE_LITTLE_ENDIAN,
293     .valid = {
294         .min_access_size = 4,
295         .max_access_size = 4,
296     }
297 };
298 
299 static void aspeed_intc_instance_init(Object *obj)
300 {
301     AspeedINTCState *s = ASPEED_INTC(obj);
302     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
303     int i;
304 
305     assert(aic->num_inpins <= ASPEED_INTC_MAX_INPINS);
306     for (i = 0; i < aic->num_inpins; i++) {
307         object_initialize_child(obj, "intc-orgates[*]", &s->orgates[i],
308                                 TYPE_OR_IRQ);
309         object_property_set_int(OBJECT(&s->orgates[i]), "num-lines",
310                                 aic->num_lines, &error_abort);
311     }
312 }
313 
314 static void aspeed_intc_reset(DeviceState *dev)
315 {
316     AspeedINTCState *s = ASPEED_INTC(dev);
317     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
318 
319     memset(s->regs, 0, aic->nr_regs << 2);
320     memset(s->enable, 0, sizeof(s->enable));
321     memset(s->mask, 0, sizeof(s->mask));
322     memset(s->pending, 0, sizeof(s->pending));
323 }
324 
325 static void aspeed_intc_realize(DeviceState *dev, Error **errp)
326 {
327     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
328     AspeedINTCState *s = ASPEED_INTC(dev);
329     AspeedINTCClass *aic = ASPEED_INTC_GET_CLASS(s);
330     int i;
331 
332     memory_region_init(&s->iomem_container, OBJECT(s),
333             TYPE_ASPEED_INTC ".container", aic->mem_size);
334 
335     sysbus_init_mmio(sbd, &s->iomem_container);
336 
337     s->regs = g_new(uint32_t, aic->nr_regs);
338     memory_region_init_io(&s->iomem, OBJECT(s), aic->reg_ops, s,
339                           TYPE_ASPEED_INTC ".regs", aic->nr_regs << 2);
340 
341     memory_region_add_subregion(&s->iomem_container, aic->reg_offset,
342                                 &s->iomem);
343 
344     qdev_init_gpio_in(dev, aspeed_intc_set_irq, aic->num_inpins);
345 
346     for (i = 0; i < aic->num_inpins; i++) {
347         if (!qdev_realize(DEVICE(&s->orgates[i]), NULL, errp)) {
348             return;
349         }
350         sysbus_init_irq(sbd, &s->output_pins[i]);
351     }
352 }
353 
354 static void aspeed_intc_unrealize(DeviceState *dev)
355 {
356     AspeedINTCState *s = ASPEED_INTC(dev);
357 
358     g_free(s->regs);
359     s->regs = NULL;
360 }
361 
362 static void aspeed_intc_class_init(ObjectClass *klass, void *data)
363 {
364     DeviceClass *dc = DEVICE_CLASS(klass);
365     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
366 
367     dc->desc = "ASPEED INTC Controller";
368     dc->realize = aspeed_intc_realize;
369     dc->unrealize = aspeed_intc_unrealize;
370     device_class_set_legacy_reset(dc, aspeed_intc_reset);
371     dc->vmsd = NULL;
372 
373     aic->reg_ops = &aspeed_intc_ops;
374 }
375 
376 static const TypeInfo aspeed_intc_info = {
377     .name = TYPE_ASPEED_INTC,
378     .parent = TYPE_SYS_BUS_DEVICE,
379     .instance_init = aspeed_intc_instance_init,
380     .instance_size = sizeof(AspeedINTCState),
381     .class_init = aspeed_intc_class_init,
382     .class_size = sizeof(AspeedINTCClass),
383     .abstract = true,
384 };
385 
386 static void aspeed_2700_intc_class_init(ObjectClass *klass, void *data)
387 {
388     DeviceClass *dc = DEVICE_CLASS(klass);
389     AspeedINTCClass *aic = ASPEED_INTC_CLASS(klass);
390 
391     dc->desc = "ASPEED 2700 INTC Controller";
392     aic->num_lines = 32;
393     aic->num_inpins = 9;
394     aic->mem_size = 0x4000;
395     aic->nr_regs = 0x808 >> 2;
396     aic->reg_offset = 0x1000;
397 }
398 
399 static const TypeInfo aspeed_2700_intc_info = {
400     .name = TYPE_ASPEED_2700_INTC,
401     .parent = TYPE_ASPEED_INTC,
402     .class_init = aspeed_2700_intc_class_init,
403 };
404 
405 static void aspeed_intc_register_types(void)
406 {
407     type_register_static(&aspeed_intc_info);
408     type_register_static(&aspeed_2700_intc_info);
409 }
410 
411 type_init(aspeed_intc_register_types);
412