xref: /openbmc/qemu/hw/intc/imx_avic.c (revision 8e6fe6b8)
1 /*
2  * i.MX31 Vectored Interrupt Controller
3  *
4  * Note this is NOT the PL192 provided by ARM, but
5  * a custom implementation by Freescale.
6  *
7  * Copyright (c) 2008 OKL
8  * Copyright (c) 2011 NICTA Pty Ltd
9  * Originally written by Hans Jiang
10  * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
11  *
12  * This code is licensed under the GPL version 2 or later.  See
13  * the COPYING file in the top-level directory.
14  *
15  * TODO: implement vectors.
16  */
17 
18 #include "qemu/osdep.h"
19 #include "hw/intc/imx_avic.h"
20 #include "qemu/log.h"
21 #include "qemu/module.h"
22 
23 #ifndef DEBUG_IMX_AVIC
24 #define DEBUG_IMX_AVIC 0
25 #endif
26 
27 #define DPRINTF(fmt, args...) \
28     do { \
29         if (DEBUG_IMX_AVIC) { \
30             fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX_AVIC, \
31                                              __func__, ##args); \
32         } \
33     } while (0)
34 
35 static const VMStateDescription vmstate_imx_avic = {
36     .name = TYPE_IMX_AVIC,
37     .version_id = 1,
38     .minimum_version_id = 1,
39     .fields = (VMStateField[]) {
40         VMSTATE_UINT64(pending, IMXAVICState),
41         VMSTATE_UINT64(enabled, IMXAVICState),
42         VMSTATE_UINT64(is_fiq, IMXAVICState),
43         VMSTATE_UINT32(intcntl, IMXAVICState),
44         VMSTATE_UINT32(intmask, IMXAVICState),
45         VMSTATE_UINT32_ARRAY(prio, IMXAVICState, PRIO_WORDS),
46         VMSTATE_END_OF_LIST()
47     },
48 };
49 
50 static inline int imx_avic_prio(IMXAVICState *s, int irq)
51 {
52     uint32_t word = irq / PRIO_PER_WORD;
53     uint32_t part = 4 * (irq % PRIO_PER_WORD);
54     return 0xf & (s->prio[word] >> part);
55 }
56 
57 /* Update interrupts.  */
58 static void imx_avic_update(IMXAVICState *s)
59 {
60     int i;
61     uint64_t new = s->pending & s->enabled;
62     uint64_t flags;
63 
64     flags = new & s->is_fiq;
65     qemu_set_irq(s->fiq, !!flags);
66 
67     flags = new & ~s->is_fiq;
68     if (!flags || (s->intmask == 0x1f)) {
69         qemu_set_irq(s->irq, !!flags);
70         return;
71     }
72 
73     /*
74      * Take interrupt if there's a pending interrupt with
75      * priority higher than the value of intmask
76      */
77     for (i = 0; i < IMX_AVIC_NUM_IRQS; i++) {
78         if (flags & (1UL << i)) {
79             if (imx_avic_prio(s, i) > s->intmask) {
80                 qemu_set_irq(s->irq, 1);
81                 return;
82             }
83         }
84     }
85     qemu_set_irq(s->irq, 0);
86 }
87 
88 static void imx_avic_set_irq(void *opaque, int irq, int level)
89 {
90     IMXAVICState *s = (IMXAVICState *)opaque;
91 
92     if (level) {
93         DPRINTF("Raising IRQ %d, prio %d\n",
94                 irq, imx_avic_prio(s, irq));
95         s->pending |= (1ULL << irq);
96     } else {
97         DPRINTF("Clearing IRQ %d, prio %d\n",
98                 irq, imx_avic_prio(s, irq));
99         s->pending &= ~(1ULL << irq);
100     }
101 
102     imx_avic_update(s);
103 }
104 
105 
106 static uint64_t imx_avic_read(void *opaque,
107                              hwaddr offset, unsigned size)
108 {
109     IMXAVICState *s = (IMXAVICState *)opaque;
110 
111     DPRINTF("read(offset = 0x%" HWADDR_PRIx ")\n", offset);
112 
113     switch (offset >> 2) {
114     case 0: /* INTCNTL */
115         return s->intcntl;
116 
117     case 1: /* Normal Interrupt Mask Register, NIMASK */
118         return s->intmask;
119 
120     case 2: /* Interrupt Enable Number Register, INTENNUM */
121     case 3: /* Interrupt Disable Number Register, INTDISNUM */
122         return 0;
123 
124     case 4: /* Interrupt Enabled Number Register High */
125         return s->enabled >> 32;
126 
127     case 5: /* Interrupt Enabled Number Register Low */
128         return s->enabled & 0xffffffffULL;
129 
130     case 6: /* Interrupt Type Register High */
131         return s->is_fiq >> 32;
132 
133     case 7: /* Interrupt Type Register Low */
134         return s->is_fiq & 0xffffffffULL;
135 
136     case 8: /* Normal Interrupt Priority Register 7 */
137     case 9: /* Normal Interrupt Priority Register 6 */
138     case 10:/* Normal Interrupt Priority Register 5 */
139     case 11:/* Normal Interrupt Priority Register 4 */
140     case 12:/* Normal Interrupt Priority Register 3 */
141     case 13:/* Normal Interrupt Priority Register 2 */
142     case 14:/* Normal Interrupt Priority Register 1 */
143     case 15:/* Normal Interrupt Priority Register 0 */
144         return s->prio[15-(offset>>2)];
145 
146     case 16: /* Normal interrupt vector and status register */
147     {
148         /*
149          * This returns the highest priority
150          * outstanding interrupt.  Where there is more than
151          * one pending IRQ with the same priority,
152          * take the highest numbered one.
153          */
154         uint64_t flags = s->pending & s->enabled & ~s->is_fiq;
155         int i;
156         int prio = -1;
157         int irq = -1;
158         for (i = 63; i >= 0; --i) {
159             if (flags & (1ULL<<i)) {
160                 int irq_prio = imx_avic_prio(s, i);
161                 if (irq_prio > prio) {
162                     irq = i;
163                     prio = irq_prio;
164                 }
165             }
166         }
167         if (irq >= 0) {
168             imx_avic_set_irq(s, irq, 0);
169             return irq << 16 | prio;
170         }
171         return 0xffffffffULL;
172     }
173     case 17:/* Fast Interrupt vector and status register */
174     {
175         uint64_t flags = s->pending & s->enabled & s->is_fiq;
176         int i = ctz64(flags);
177         if (i < 64) {
178             imx_avic_set_irq(opaque, i, 0);
179             return i;
180         }
181         return 0xffffffffULL;
182     }
183     case 18:/* Interrupt source register high */
184         return s->pending >> 32;
185 
186     case 19:/* Interrupt source register low */
187         return s->pending & 0xffffffffULL;
188 
189     case 20:/* Interrupt Force Register high */
190     case 21:/* Interrupt Force Register low */
191         return 0;
192 
193     case 22:/* Normal Interrupt Pending Register High */
194         return (s->pending & s->enabled & ~s->is_fiq) >> 32;
195 
196     case 23:/* Normal Interrupt Pending Register Low */
197         return (s->pending & s->enabled & ~s->is_fiq) & 0xffffffffULL;
198 
199     case 24: /* Fast Interrupt Pending Register High  */
200         return (s->pending & s->enabled & s->is_fiq) >> 32;
201 
202     case 25: /* Fast Interrupt Pending Register Low  */
203         return (s->pending & s->enabled & s->is_fiq) & 0xffffffffULL;
204 
205     case 0x40:            /* AVIC vector 0, use for WFI WAR */
206         return 0x4;
207 
208     default:
209         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
210                       HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset);
211         return 0;
212     }
213 }
214 
215 static void imx_avic_write(void *opaque, hwaddr offset,
216                           uint64_t val, unsigned size)
217 {
218     IMXAVICState *s = (IMXAVICState *)opaque;
219 
220     /* Vector Registers not yet supported */
221     if (offset >= 0x100 && offset <= 0x2fc) {
222         qemu_log_mask(LOG_UNIMP, "[%s]%s: vector %d ignored\n",
223                       TYPE_IMX_AVIC, __func__, (int)((offset - 0x100) >> 2));
224         return;
225     }
226 
227     DPRINTF("(0x%" HWADDR_PRIx ") = 0x%x\n", offset, (unsigned int)val);
228 
229     switch (offset >> 2) {
230     case 0: /* Interrupt Control Register, INTCNTL */
231         s->intcntl = val & (ABFEN | NIDIS | FIDIS | NIAD | FIAD | NM);
232         if (s->intcntl & ABFEN) {
233             s->intcntl &= ~(val & ABFLAG);
234         }
235         break;
236 
237     case 1: /* Normal Interrupt Mask Register, NIMASK */
238         s->intmask = val & 0x1f;
239         break;
240 
241     case 2: /* Interrupt Enable Number Register, INTENNUM */
242         DPRINTF("enable(%d)\n", (int)val);
243         val &= 0x3f;
244         s->enabled |= (1ULL << val);
245         break;
246 
247     case 3: /* Interrupt Disable Number Register, INTDISNUM */
248         DPRINTF("disable(%d)\n", (int)val);
249         val &= 0x3f;
250         s->enabled &= ~(1ULL << val);
251         break;
252 
253     case 4: /* Interrupt Enable Number Register High */
254         s->enabled = (s->enabled & 0xffffffffULL) | (val << 32);
255         break;
256 
257     case 5: /* Interrupt Enable Number Register Low */
258         s->enabled = (s->enabled & 0xffffffff00000000ULL) | val;
259         break;
260 
261     case 6: /* Interrupt Type Register High */
262         s->is_fiq = (s->is_fiq & 0xffffffffULL) | (val << 32);
263         break;
264 
265     case 7: /* Interrupt Type Register Low */
266         s->is_fiq = (s->is_fiq & 0xffffffff00000000ULL) | val;
267         break;
268 
269     case 8: /* Normal Interrupt Priority Register 7 */
270     case 9: /* Normal Interrupt Priority Register 6 */
271     case 10:/* Normal Interrupt Priority Register 5 */
272     case 11:/* Normal Interrupt Priority Register 4 */
273     case 12:/* Normal Interrupt Priority Register 3 */
274     case 13:/* Normal Interrupt Priority Register 2 */
275     case 14:/* Normal Interrupt Priority Register 1 */
276     case 15:/* Normal Interrupt Priority Register 0 */
277         s->prio[15-(offset>>2)] = val;
278         break;
279 
280         /* Read-only registers, writes ignored */
281     case 16:/* Normal Interrupt Vector and Status register */
282     case 17:/* Fast Interrupt vector and status register */
283     case 18:/* Interrupt source register high */
284     case 19:/* Interrupt source register low */
285         return;
286 
287     case 20:/* Interrupt Force Register high */
288         s->pending = (s->pending & 0xffffffffULL) | (val << 32);
289         break;
290 
291     case 21:/* Interrupt Force Register low */
292         s->pending = (s->pending & 0xffffffff00000000ULL) | val;
293         break;
294 
295     case 22:/* Normal Interrupt Pending Register High */
296     case 23:/* Normal Interrupt Pending Register Low */
297     case 24: /* Fast Interrupt Pending Register High  */
298     case 25: /* Fast Interrupt Pending Register Low  */
299         return;
300 
301     default:
302         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
303                       HWADDR_PRIx "\n", TYPE_IMX_AVIC, __func__, offset);
304     }
305     imx_avic_update(s);
306 }
307 
308 static const MemoryRegionOps imx_avic_ops = {
309     .read = imx_avic_read,
310     .write = imx_avic_write,
311     .endianness = DEVICE_NATIVE_ENDIAN,
312 };
313 
314 static void imx_avic_reset(DeviceState *dev)
315 {
316     IMXAVICState *s = IMX_AVIC(dev);
317 
318     s->pending = 0;
319     s->enabled = 0;
320     s->is_fiq = 0;
321     s->intmask = 0x1f;
322     s->intcntl = 0;
323     memset(s->prio, 0, sizeof s->prio);
324 }
325 
326 static void imx_avic_init(Object *obj)
327 {
328     DeviceState *dev = DEVICE(obj);
329     IMXAVICState *s = IMX_AVIC(obj);
330     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
331 
332     memory_region_init_io(&s->iomem, obj, &imx_avic_ops, s,
333                           TYPE_IMX_AVIC, 0x1000);
334     sysbus_init_mmio(sbd, &s->iomem);
335 
336     qdev_init_gpio_in(dev, imx_avic_set_irq, IMX_AVIC_NUM_IRQS);
337     sysbus_init_irq(sbd, &s->irq);
338     sysbus_init_irq(sbd, &s->fiq);
339 }
340 
341 
342 static void imx_avic_class_init(ObjectClass *klass, void *data)
343 {
344     DeviceClass *dc = DEVICE_CLASS(klass);
345 
346     dc->vmsd = &vmstate_imx_avic;
347     dc->reset = imx_avic_reset;
348     dc->desc = "i.MX Advanced Vector Interrupt Controller";
349 }
350 
351 static const TypeInfo imx_avic_info = {
352     .name = TYPE_IMX_AVIC,
353     .parent = TYPE_SYS_BUS_DEVICE,
354     .instance_size = sizeof(IMXAVICState),
355     .instance_init = imx_avic_init,
356     .class_init = imx_avic_class_init,
357 };
358 
359 static void imx_avic_register_types(void)
360 {
361     type_register_static(&imx_avic_info);
362 }
363 
364 type_init(imx_avic_register_types)
365