1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16: #ifdef DEBUG_GIC
17: #define DPRINTF(fmt, args...) \
18: do { printf("arm_gic: " fmt , ##args); } while (0)
19: #else
20: #define DPRINTF(fmt, args...) do {} while(0)
21: #endif
22:
23: #ifdef NVIC
24: static const uint8_t gic_id[] =
25: { 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 };
26: #define GIC_DIST_OFFSET 0
27:
28:
29: #define GIC_BASE_IRQ 32
30: #else
31: static const uint8_t gic_id[] =
32: { 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
33: #define GIC_DIST_OFFSET 0x1000
34: #define GIC_BASE_IRQ 0
35: #endif
36:
37: typedef struct gic_irq_state
38: {
39:
40:
41: unsigned enabled:1;
42: unsigned pending:NCPU;
43: unsigned active:NCPU;
44: unsigned level:1;
45: unsigned model:1;
46: unsigned trigger:1;
47: } gic_irq_state;
48:
49: #define ALL_CPU_MASK ((1 << NCPU) - 1)
50:
51: #define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1
52: #define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0
53: #define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled
54: #define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
55: #define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
56: #define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
57: #define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
58: #define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
59: #define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
60: #define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
61: #define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
62: #define GIC_TEST_MODEL(irq) s->irq_state[irq].model
63: #define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
64: #define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
65: #define GIC_TEST_LEVEL(irq, cm) (s->irq_state[irq].level & (cm)) != 0
66: #define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
67: #define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
68: #define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
69: #define GIC_GET_PRIORITY(irq, cpu) \
70: (((irq) < 32) ? s->priority1[irq][cpu] : s->priority2[(irq) - 32])
71: #ifdef NVIC
72: #define GIC_TARGET(irq) 1
73: #else
74: #define GIC_TARGET(irq) s->irq_target[irq]
75: #endif
76:
77: typedef struct gic_state
78: {
79: uint32_t base;
80: qemu_irq parent_irq[NCPU];
81: int enabled;
82: int cpu_enabled[NCPU];
83:
84: gic_irq_state irq_state[GIC_NIRQ];
85: #ifndef NVIC
86: int irq_target[GIC_NIRQ];
87: #endif
88: int priority1[32][NCPU];
89: int priority2[GIC_NIRQ - 32];
90: int last_active[GIC_NIRQ][NCPU];
91:
92: int priority_mask[NCPU];
93: int running_irq[NCPU];
94: int running_priority[NCPU];
95: int current_pending[NCPU];
96:
97: qemu_irq *in;
98: #ifdef NVIC
99: void *nvic;
100: #endif
101: } gic_state;
102:
103:
104:
105: static void gic_update(gic_state *s)
106: {
107: int best_irq;
108: int best_prio;
109: int irq;
110: int level;
111: int cpu;
112: int cm;
113:
114: for (cpu = 0; cpu < NCPU; cpu++) {
115: cm = 1 << cpu;
116: s->current_pending[cpu] = 1023;
117: if (!s->enabled || !s->cpu_enabled[cpu]) {
118: qemu_irq_lower(s->parent_irq[cpu]);
119: return;
120: }
121: best_prio = 0x100;
122: best_irq = 1023;
123: for (irq = 0; irq < GIC_NIRQ; irq++) {
124: if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq, cm)) {
125: if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
126: best_prio = GIC_GET_PRIORITY(irq, cpu);
127: best_irq = irq;
128: }
129: }
130: }
131: level = 0;
132: if (best_prio <= s->priority_mask[cpu]) {
133: s->current_pending[cpu] = best_irq;
134: if (best_prio < s->running_priority[cpu]) {
135: DPRINTF("Raised pending IRQ %d\n", best_irq);
136: level = 1;
137: }
138: }
139: qemu_set_irq(s->parent_irq[cpu], level);
140: }
141: }
142:
143: static void __attribute__((unused))
144: gic_set_pending_private(gic_state *s, int cpu, int irq)
145: {
146: int cm = 1 << cpu;
147:
148: if (GIC_TEST_PENDING(irq, cm))
149: return;
150:
151: DPRINTF("Set %d pending cpu %d\n", irq, cpu);
152: GIC_SET_PENDING(irq, cm);
153: gic_update(s);
154: }
155:
156:
157: static void gic_set_irq(void *opaque, int irq, int level)
158: {
159: gic_state *s = (gic_state *)opaque;
160:
161: irq += 32;
162: if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK))
163: return;
164:
165: if (level) {
166: GIC_SET_LEVEL(irq, ALL_CPU_MASK);
167: if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {
168: DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq));
169: GIC_SET_PENDING(irq, GIC_TARGET(irq));
170: }
171: } else {
172: GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK);
173: }
174: gic_update(s);
175: }
176:
177: static void gic_set_running_irq(gic_state *s, int cpu, int irq)
178: {
179: s->running_irq[cpu] = irq;
180: if (irq == 1023) {
181: s->running_priority[cpu] = 0x100;
182: } else {
183: s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
184: }
185: gic_update(s);
186: }
187:
188: static uint32_t gic_acknowledge_irq(gic_state *s, int cpu)
189: {
190: int new_irq;
191: int cm = 1 << cpu;
192: new_irq = s->current_pending[cpu];
193: if (new_irq == 1023
194: || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {
195: DPRINTF("ACK no pending IRQ\n");
196: return 1023;
197: }
198: s->last_active[new_irq][cpu] = s->running_irq[cpu];
199:
200:
201: GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);
202: gic_set_running_irq(s, cpu, new_irq);
203: DPRINTF("ACK %d\n", new_irq);
204: return new_irq;
205: }
206:
207: static void gic_complete_irq(gic_state * s, int cpu, int irq)
208: {
209: int update = 0;
210: int cm = 1 << cpu;
211: DPRINTF("EOI %d\n", irq);
212: if (s->running_irq[cpu] == 1023)
213: return;
214: if (irq != 1023) {
215:
216:
217: if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq)
218: && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
219: DPRINTF("Set %d pending mask %x\n", irq, cm);
220: GIC_SET_PENDING(irq, cm);
221: update = 1;
222: }
223: }
224: if (irq != s->running_irq[cpu]) {
225:
226: int tmp = s->running_irq[cpu];
227: while (s->last_active[tmp][cpu] != 1023) {
228: if (s->last_active[tmp][cpu] == irq) {
229: s->last_active[tmp][cpu] = s->last_active[irq][cpu];
230: break;
231: }
232: tmp = s->last_active[tmp][cpu];
233: }
234: if (update) {
235: gic_update(s);
236: }
237: } else {
238:
239: gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
240: }
241: }
242:
243: static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
244: {
245: gic_state *s = (gic_state *)opaque;
246: uint32_t res;
247: int irq;
248: int i;
249: int cpu;
250: int cm;
251: int mask;
252:
253: cpu = gic_get_current_cpu();
254: cm = 1 << cpu;
255: offset -= s->base + GIC_DIST_OFFSET;
256: if (offset < 0x100) {
257: #ifndef NVIC
258: if (offset == 0)
259: return s->enabled;
260: if (offset == 4)
261: return ((GIC_NIRQ / 32) - 1) | ((NCPU - 1) << 5);
262: if (offset < 0x08)
263: return 0;
264: #endif
265: goto bad_reg;
266: } else if (offset < 0x200) {
267:
268: if (offset < 0x180)
269: irq = (offset - 0x100) * 8;
270: else
271: irq = (offset - 0x180) * 8;
272: irq += GIC_BASE_IRQ;
273: if (irq >= GIC_NIRQ)
274: goto bad_reg;
275: res = 0;
276: for (i = 0; i < 8; i++) {
277: if (GIC_TEST_ENABLED(irq + i)) {
278: res |= (1 << i);
279: }
280: }
281: } else if (offset < 0x300) {
282:
283: if (offset < 0x280)
284: irq = (offset - 0x200) * 8;
285: else
286: irq = (offset - 0x280) * 8;
287: irq += GIC_BASE_IRQ;
288: if (irq >= GIC_NIRQ)
289: goto bad_reg;
290: res = 0;
291: mask = (irq < 32) ? cm : ALL_CPU_MASK;
292: for (i = 0; i < 8; i++) {
293: if (GIC_TEST_PENDING(irq + i, mask)) {
294: res |= (1 << i);
295: }
296: }
297: } else if (offset < 0x400) {
298:
299: irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
300: if (irq >= GIC_NIRQ)
301: goto bad_reg;
302: res = 0;
303: mask = (irq < 32) ? cm : ALL_CPU_MASK;
304: for (i = 0; i < 8; i++) {
305: if (GIC_TEST_ACTIVE(irq + i, mask)) {
306: res |= (1 << i);
307: }
308: }
309: } else if (offset < 0x800) {
310:
311: irq = (offset - 0x400) + GIC_BASE_IRQ;
312: if (irq >= GIC_NIRQ)
313: goto bad_reg;
314: res = GIC_GET_PRIORITY(irq, cpu);
315: #ifndef NVIC
316: } else if (offset < 0xc00) {
317:
318: irq = (offset - 0x800) + GIC_BASE_IRQ;
319: if (irq >= GIC_NIRQ)
320: goto bad_reg;
321: if (irq >= 29 && irq <= 31) {
322: res = cm;
323: } else {
324: res = GIC_TARGET(irq);
325: }
326: } else if (offset < 0xf00) {
327:
328: irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
329: if (irq >= GIC_NIRQ)
330: goto bad_reg;
331: res = 0;
332: for (i = 0; i < 4; i++) {
333: if (GIC_TEST_MODEL(irq + i))
334: res |= (1 << (i * 2));
335: if (GIC_TEST_TRIGGER(irq + i))
336: res |= (2 << (i * 2));
337: }
338: #endif
339: } else if (offset < 0xfe0) {
340: goto bad_reg;
341: } else {
342: if (offset & 3) {
343: res = 0;
344: } else {
345: res = gic_id[(offset - 0xfe0) >> 2];
346: }
347: }
348: return res;
349: bad_reg:
350: cpu_abort(cpu_single_env, "gic_dist_readb: Bad offset %x\n", (int)offset);
351: return 0;
352: }
353:
354: static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset)
355: {
356: uint32_t val;
357: val = gic_dist_readb(opaque, offset);
358: val |= gic_dist_readb(opaque, offset + 1) << 8;
359: return val;
360: }
361:
362: static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset)
363: {
364: uint32_t val;
365: #ifdef NVIC
366: gic_state *s = (gic_state *)opaque;
367: uint32_t addr;
368: addr = offset - s->base;
369: if (addr < 0x100 || addr > 0xd00)
370: return nvic_readl(s->nvic, addr);
371: #endif
372: val = gic_dist_readw(opaque, offset);
373: val |= gic_dist_readw(opaque, offset + 2) << 16;
374: return val;
375: }
376:
377: static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
378: uint32_t value)
379: {
380: gic_state *s = (gic_state *)opaque;
381: int irq;
382: int i;
383: int cpu;
384:
385: cpu = gic_get_current_cpu();
386: offset -= s->base + GIC_DIST_OFFSET;
387: if (offset < 0x100) {
388: #ifdef NVIC
389: goto bad_reg;
390: #else
391: if (offset == 0) {
392: s->enabled = (value & 1);
393: DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
394: } else if (offset < 4) {
395:
396: } else {
397: goto bad_reg;
398: }
399: #endif
400: } else if (offset < 0x180) {
401:
402: irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
403: if (irq >= GIC_NIRQ)
404: goto bad_reg;
405: if (irq < 16)
406: value = 0xff;
407: for (i = 0; i < 8; i++) {
408: if (value & (1 << i)) {
409: int mask = (irq < 32) ? (1 << cpu) : GIC_TARGET(irq);
410: if (!GIC_TEST_ENABLED(irq + i))
411: DPRINTF("Enabled IRQ %d\n", irq + i);
412: GIC_SET_ENABLED(irq + i);
413:
414:
415: if (GIC_TEST_LEVEL(irq + i, mask)
416: && !GIC_TEST_TRIGGER(irq + i)) {
417: DPRINTF("Set %d pending mask %x\n", irq + i, mask);
418: GIC_SET_PENDING(irq + i, mask);
419: }
420: }
421: }
422: } else if (offset < 0x200) {
423:
424: irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
425: if (irq >= GIC_NIRQ)
426: goto bad_reg;
427: if (irq < 16)
428: value = 0;
429: for (i = 0; i < 8; i++) {
430: if (value & (1 << i)) {
431: if (GIC_TEST_ENABLED(irq + i))
432: DPRINTF("Disabled IRQ %d\n", irq + i);
433: GIC_CLEAR_ENABLED(irq + i);
434: }
435: }
436: } else if (offset < 0x280) {
437:
438: irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
439: if (irq >= GIC_NIRQ)
440: goto bad_reg;
441: if (irq < 16)
442: irq = 0;
443:
444: for (i = 0; i < 8; i++) {
445: if (value & (1 << i)) {
446: GIC_SET_PENDING(irq + i, GIC_TARGET(irq));
447: }
448: }
449: } else if (offset < 0x300) {
450:
451: irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
452: if (irq >= GIC_NIRQ)
453: goto bad_reg;
454: for (i = 0; i < 8; i++) {
455:
456:
457:
458: if (value & (1 << i)) {
459: GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
460: }
461: }
462: } else if (offset < 0x400) {
463:
464: goto bad_reg;
465: } else if (offset < 0x800) {
466:
467: irq = (offset - 0x400) + GIC_BASE_IRQ;
468: if (irq >= GIC_NIRQ)
469: goto bad_reg;
470: if (irq < 32) {
471: s->priority1[irq][cpu] = value;
472: } else {
473: s->priority2[irq - 32] = value;
474: }
475: #ifndef NVIC
476: } else if (offset < 0xc00) {
477:
478: irq = (offset - 0x800) + GIC_BASE_IRQ;
479: if (irq >= GIC_NIRQ)
480: goto bad_reg;
481: if (irq < 29)
482: value = 0;
483: else if (irq < 32)
484: value = ALL_CPU_MASK;
485: s->irq_target[irq] = value & ALL_CPU_MASK;
486: } else if (offset < 0xf00) {
487:
488: irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
489: if (irq >= GIC_NIRQ)
490: goto bad_reg;
491: if (irq < 32)
492: value |= 0xaa;
493: for (i = 0; i < 4; i++) {
494: if (value & (1 << (i * 2))) {
495: GIC_SET_MODEL(irq + i);
496: } else {
497: GIC_CLEAR_MODEL(irq + i);
498: }
499: if (value & (2 << (i * 2))) {
500: GIC_SET_TRIGGER(irq + i);
501: } else {
502: GIC_CLEAR_TRIGGER(irq + i);
503: }
504: }
505: #endif
506: } else {
507:
508: goto bad_reg;
509: }
510: gic_update(s);
511: return;
512: bad_reg:
513: cpu_abort(cpu_single_env, "gic_dist_writeb: Bad offset %x\n", (int)offset);
514: }
515:
516: static void gic_dist_writew(void *opaque, target_phys_addr_t offset,
517: uint32_t value)
518: {
519: gic_dist_writeb(opaque, offset, value & 0xff);
520: gic_dist_writeb(opaque, offset + 1, value >> 8);
521: }
522:
523: static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
524: uint32_t value)
525: {
526: gic_state *s = (gic_state *)opaque;
527: #ifdef NVIC
528: uint32_t addr;
529: addr = offset - s->base;
530: if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) {
531: nvic_writel(s->nvic, addr, value);