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