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