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) |