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