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