Statistics
| Branch: | Revision:

root / hw / imx_avic.c @ 9a6ee9fd

History | View | Annotate | Download (11.7 kB)

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