|
|
1.1 root 1: /*
2: * ARM AMBA Generic/Distributed Interrupt Controller
3: *
4: * Copyright (c) 2006 CodeSourcery.
5: * Written by Paul Brook
6: *
7: * This code is licenced under the GPL.
8: */
9:
10: /* TODO: Some variants of this controller can handle multiple CPUs.
11: Currently only single CPU operation is implemented. */
12:
13: #include "vl.h"
14: #include "arm_pic.h"
15:
16: //#define DEBUG_GIC
17:
18: #ifdef DEBUG_GIC
19: #define DPRINTF(fmt, args...) \
20: do { printf("arm_gic: " fmt , ##args); } while (0)
21: #else
22: #define DPRINTF(fmt, args...) do {} while(0)
23: #endif
24:
25: /* Distributed interrupt controller. */
26:
27: static const uint8_t gic_id[] =
28: { 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
29:
30: #define GIC_NIRQ 96
31:
32: typedef struct gic_irq_state
33: {
34: unsigned enabled:1;
35: unsigned pending:1;
36: unsigned active:1;
37: unsigned level:1;
38: unsigned model:1; /* 0 = 1:N, 1 = N:N */
39: unsigned trigger:1; /* nonzero = edge triggered. */
40: } gic_irq_state;
41:
42: #define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1
43: #define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0
44: #define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled
45: #define GIC_SET_PENDING(irq) s->irq_state[irq].pending = 1
46: #define GIC_CLEAR_PENDING(irq) s->irq_state[irq].pending = 0
47: #define GIC_TEST_PENDING(irq) s->irq_state[irq].pending
48: #define GIC_SET_ACTIVE(irq) s->irq_state[irq].active = 1
49: #define GIC_CLEAR_ACTIVE(irq) s->irq_state[irq].active = 0
50: #define GIC_TEST_ACTIVE(irq) s->irq_state[irq].active
51: #define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
52: #define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
53: #define GIC_TEST_MODEL(irq) s->irq_state[irq].model
54: #define GIC_SET_LEVEL(irq) s->irq_state[irq].level = 1
55: #define GIC_CLEAR_LEVEL(irq) s->irq_state[irq].level = 0
56: #define GIC_TEST_LEVEL(irq) s->irq_state[irq].level
57: #define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
58: #define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
59: #define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
60:
61: typedef struct gic_state
62: {
63: arm_pic_handler handler;
64: uint32_t base;
65: void *parent;
66: int parent_irq;
67: int enabled;
68: int cpu_enabled;
69:
70: gic_irq_state irq_state[GIC_NIRQ];
71: int irq_target[GIC_NIRQ];
72: int priority[GIC_NIRQ];
73: int last_active[GIC_NIRQ];
74:
75: int priority_mask;
76: int running_irq;
77: int running_priority;
78: int current_pending;
79: } gic_state;
80:
81: /* TODO: Many places that call this routine could be optimized. */
82: /* Update interrupt status after enabled or pending bits have been changed. */
83: static void gic_update(gic_state *s)
84: {
85: int best_irq;
86: int best_prio;
87: int irq;
88:
89: s->current_pending = 1023;
90: if (!s->enabled || !s->cpu_enabled) {
91: pic_set_irq_new(s->parent, s->parent_irq, 0);
92: return;
93: }
94: best_prio = 0x100;
95: best_irq = 1023;
96: for (irq = 0; irq < 96; irq++) {
97: if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq)) {
98: if (s->priority[irq] < best_prio) {
99: best_prio = s->priority[irq];
100: best_irq = irq;
101: }
102: }
103: }
104: if (best_prio > s->priority_mask) {
105: pic_set_irq_new(s->parent, s->parent_irq, 0);
106: } else {
107: s->current_pending = best_irq;
108: if (best_prio < s->running_priority) {
109: DPRINTF("Raised pending IRQ %d\n", best_irq);
110: pic_set_irq_new(s->parent, s->parent_irq, 1);
111: }
112: }
113: }
114:
115: static void gic_set_irq(void *opaque, int irq, int level)
116: {
117: gic_state *s = (gic_state *)opaque;
118: /* The first external input line is internal interrupt 32. */
119: irq += 32;
120: if (level == GIC_TEST_LEVEL(irq))
121: return;
122:
123: if (level) {
124: GIC_SET_LEVEL(irq);
125: if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {
126: DPRINTF("Set %d pending\n", irq);
127: GIC_SET_PENDING(irq);
128: }
129: } else {
130: GIC_CLEAR_LEVEL(irq);
131: }
132: gic_update(s);
133: }
134:
135: static void gic_set_running_irq(gic_state *s, int irq)
136: {
137: s->running_irq = irq;
138: if (irq == 1023)
139: s->running_priority = 0x100;
140: else
141: s->running_priority = s->priority[irq];
142: gic_update(s);
143: }
144:
145: static uint32_t gic_acknowledge_irq(gic_state *s)
146: {
147: int new_irq;
148: new_irq = s->current_pending;
149: if (new_irq == 1023 || s->priority[new_irq] >= s->running_priority) {
150: DPRINTF("ACK no pending IRQ\n");
151: return 1023;
152: }
153: pic_set_irq_new(s->parent, s->parent_irq, 0);
154: s->last_active[new_irq] = s->running_irq;
155: /* For level triggered interrupts we clear the pending bit while
156: the interrupt is active. */
157: GIC_CLEAR_PENDING(new_irq);
158: gic_set_running_irq(s, new_irq);
159: DPRINTF("ACK %d\n", new_irq);
160: return new_irq;
161: }
162:
163: static void gic_complete_irq(gic_state * s, int irq)
164: {
165: int update = 0;
166: DPRINTF("EOI %d\n", irq);
167: if (s->running_irq == 1023)
168: return; /* No active IRQ. */
169: if (irq != 1023) {
170: /* Mark level triggered interrupts as pending if they are still
171: raised. */
172: if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq)
173: && GIC_TEST_LEVEL(irq)) {
174: GIC_SET_PENDING(irq);
175: update = 1;
176: }
177: }
178: if (irq != s->running_irq) {
179: /* Complete an IRQ that is not currently running. */
180: int tmp = s->running_irq;
181: while (s->last_active[tmp] != 1023) {
182: if (s->last_active[tmp] == irq) {
183: s->last_active[tmp] = s->last_active[irq];
184: break;
185: }
186: tmp = s->last_active[tmp];
187: }
188: if (update) {
189: gic_update(s);
190: }
191: } else {
192: /* Complete the current running IRQ. */
193: gic_set_running_irq(s, s->last_active[s->running_irq]);
194: }
195: }
196:
197: static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
198: {
199: gic_state *s = (gic_state *)opaque;
200: uint32_t res;
201: int irq;
202: int i;
203:
204: offset -= s->base + 0x1000;
205: if (offset < 0x100) {
206: if (offset == 0)
207: return s->enabled;
208: if (offset == 4)
209: return (GIC_NIRQ / 32) - 1;
210: if (offset < 0x08)
211: return 0;
212: goto bad_reg;
213: } else if (offset < 0x200) {
214: /* Interrupt Set/Clear Enable. */
215: if (offset < 0x180)
216: irq = (offset - 0x100) * 8;
217: else
218: irq = (offset - 0x180) * 8;
219: if (irq >= GIC_NIRQ)
220: goto bad_reg;
221: res = 0;
222: for (i = 0; i < 8; i++) {
223: if (GIC_TEST_ENABLED(irq + i)) {
224: res |= (1 << i);
225: }
226: }
227: } else if (offset < 0x300) {
228: /* Interrupt Set/Clear Pending. */
229: if (offset < 0x280)
230: irq = (offset - 0x200) * 8;
231: else
232: irq = (offset - 0x280) * 8;
233: if (irq >= GIC_NIRQ)
234: goto bad_reg;
235: res = 0;
236: for (i = 0; i < 8; i++) {
237: if (GIC_TEST_PENDING(irq + i)) {
238: res |= (1 << i);
239: }
240: }
241: } else if (offset < 0x400) {
242: /* Interrupt Active. */
243: irq = (offset - 0x300) * 8;
244: if (irq >= GIC_NIRQ)
245: goto bad_reg;
246: res = 0;
247: for (i = 0; i < 8; i++) {
248: if (GIC_TEST_ACTIVE(irq + i)) {
249: res |= (1 << i);
250: }
251: }
252: } else if (offset < 0x800) {
253: /* Interrupt Priority. */
254: irq = offset - 0x400;
255: if (irq >= GIC_NIRQ)
256: goto bad_reg;
257: res = s->priority[irq];
258: } else if (offset < 0xc00) {
259: /* Interrupt CPU Target. */
260: irq = offset - 0x800;
261: if (irq >= GIC_NIRQ)
262: goto bad_reg;
263: res = s->irq_target[irq];
264: } else if (offset < 0xf00) {
265: /* Interrupt Configuration. */
266: irq = (offset - 0xc00) * 2;
267: if (irq >= GIC_NIRQ)
268: goto bad_reg;
269: res = 0;
270: for (i = 0; i < 4; i++) {
271: if (GIC_TEST_MODEL(irq + i))
272: res |= (1 << (i * 2));
273: if (GIC_TEST_TRIGGER(irq + i))
274: res |= (2 << (i * 2));
275: }
276: } else if (offset < 0xfe0) {
277: goto bad_reg;
278: } else /* offset >= 0xfe0 */ {
279: if (offset & 3) {
280: res = 0;
281: } else {
282: res = gic_id[(offset - 0xfe0) >> 2];
283: }
284: }
285: return res;
286: bad_reg:
287: cpu_abort (cpu_single_env, "gic_dist_readb: Bad offset %x\n", offset);
288: return 0;
289: }
290:
291: static uint32_t gic_dist_readw(void *opaque, target_phys_addr_t offset)
292: {
293: uint32_t val;
294: val = gic_dist_readb(opaque, offset);
295: val |= gic_dist_readb(opaque, offset + 1) << 8;
296: return val;
297: }
298:
299: static uint32_t gic_dist_readl(void *opaque, target_phys_addr_t offset)
300: {
301: uint32_t val;
302: val = gic_dist_readw(opaque, offset);
303: val |= gic_dist_readw(opaque, offset + 2) << 16;
304: return val;
305: }
306:
307: static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
308: uint32_t value)
309: {
310: gic_state *s = (gic_state *)opaque;
311: int irq;
312: int i;
313:
314: offset -= s->base + 0x1000;
315: if (offset < 0x100) {
316: if (offset == 0) {
317: s->enabled = (value & 1);
318: DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
319: } else if (offset < 4) {
320: /* ignored. */
321: } else {
322: goto bad_reg;
323: }
324: } else if (offset < 0x180) {
325: /* Interrupt Set Enable. */
326: irq = (offset - 0x100) * 8;
327: if (irq >= GIC_NIRQ)
328: goto bad_reg;
329: for (i = 0; i < 8; i++) {
330: if (value & (1 << i)) {
331: if (!GIC_TEST_ENABLED(irq + i))
332: DPRINTF("Enabled IRQ %d\n", irq + i);
333: GIC_SET_ENABLED(irq + i);
334: /* If a raised level triggered IRQ enabled then mark
335: is as pending. */
336: if (GIC_TEST_LEVEL(irq + i) && !GIC_TEST_TRIGGER(irq + i))
337: GIC_SET_PENDING(irq + i);
338: }
339: }
340: } else if (offset < 0x200) {
341: /* Interrupt Clear Enable. */
342: irq = (offset - 0x180) * 8;
343: if (irq >= GIC_NIRQ)
344: goto bad_reg;
345: for (i = 0; i < 8; i++) {
346: if (value & (1 << i)) {
347: if (GIC_TEST_ENABLED(irq + i))
348: DPRINTF("Disabled IRQ %d\n", irq + i);
349: GIC_CLEAR_ENABLED(irq + i);
350: }
351: }
352: } else if (offset < 0x280) {
353: /* Interrupt Set Pending. */
354: irq = (offset - 0x200) * 8;
355: if (irq >= GIC_NIRQ)
356: goto bad_reg;
357: for (i = 0; i < 8; i++) {
358: if (value & (1 << i)) {
359: GIC_SET_PENDING(irq + i);
360: }
361: }
362: } else if (offset < 0x300) {
363: /* Interrupt Clear Pending. */
364: irq = (offset - 0x280) * 8;
365: if (irq >= GIC_NIRQ)
366: goto bad_reg;
367: for (i = 0; i < 8; i++) {
368: if (value & (1 << i)) {
369: GIC_CLEAR_PENDING(irq + i);
370: }
371: }
372: } else if (offset < 0x400) {
373: /* Interrupt Active. */
374: goto bad_reg;
375: } else if (offset < 0x800) {
376: /* Interrupt Priority. */
377: irq = offset - 0x400;
378: if (irq >= GIC_NIRQ)
379: goto bad_reg;
380: s->priority[irq] = value;
381: } else if (offset < 0xc00) {
382: /* Interrupt CPU Target. */
383: irq = offset - 0x800;
384: if (irq >= GIC_NIRQ)
385: goto bad_reg;
386: s->irq_target[irq] = value;
387: } else if (offset < 0xf00) {
388: /* Interrupt Configuration. */
389: irq = (offset - 0xc00) * 4;
390: if (irq >= GIC_NIRQ)
391: goto bad_reg;
392: for (i = 0; i < 4; i++) {
393: if (value & (1 << (i * 2))) {
394: GIC_SET_MODEL(irq + i);
395: } else {
396: GIC_CLEAR_MODEL(irq + i);
397: }
398: if (value & (2 << (i * 2))) {
399: GIC_SET_TRIGGER(irq + i);
400: } else {
401: GIC_CLEAR_TRIGGER(irq + i);
402: }
403: }
404: } else {
405: /* 0xf00 is only handled for word writes. */
406: goto bad_reg;
407: }
408: gic_update(s);
409: return;
410: bad_reg:
411: cpu_abort (cpu_single_env, "gic_dist_writeb: Bad offset %x\n", offset);
412: }
413:
414: static void gic_dist_writew(void *opaque, target_phys_addr_t offset,
415: uint32_t value)
416: {
417: gic_state *s = (gic_state *)opaque;
418: if (offset - s->base == 0xf00) {
419: GIC_SET_PENDING(value & 0x3ff);
420: gic_update(s);
421: return;
422: }
423: gic_dist_writeb(opaque, offset, value & 0xff);
424: gic_dist_writeb(opaque, offset + 1, value >> 8);
425: }
426:
427: static void gic_dist_writel(void *opaque, target_phys_addr_t offset,
428: uint32_t value)
429: {
430: gic_dist_writew(opaque, offset, value & 0xffff);
431: gic_dist_writew(opaque, offset + 2, value >> 16);
432: }
433:
434: static CPUReadMemoryFunc *gic_dist_readfn[] = {
435: gic_dist_readb,
436: gic_dist_readw,
437: gic_dist_readl
438: };
439:
440: static CPUWriteMemoryFunc *gic_dist_writefn[] = {
441: gic_dist_writeb,
442: gic_dist_writew,
443: gic_dist_writel
444: };
445:
446: static uint32_t gic_cpu_read(void *opaque, target_phys_addr_t offset)
447: {
448: gic_state *s = (gic_state *)opaque;
449: offset -= s->base;
450: switch (offset) {
451: case 0x00: /* Control */
452: return s->cpu_enabled;
453: case 0x04: /* Priority mask */
454: return s->priority_mask;
455: case 0x08: /* Binary Point */
456: /* ??? Not implemented. */
457: return 0;
458: case 0x0c: /* Acknowledge */
459: return gic_acknowledge_irq(s);
460: case 0x14: /* Runing Priority */
461: return s->running_priority;
462: case 0x18: /* Highest Pending Interrupt */
463: return s->current_pending;
464: default:
465: cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
466: return 0;
467: }
468: }
469:
470: static void gic_cpu_write(void *opaque, target_phys_addr_t offset,
471: uint32_t value)
472: {
473: gic_state *s = (gic_state *)opaque;
474: offset -= s->base;
475: switch (offset) {
476: case 0x00: /* Control */
477: s->cpu_enabled = (value & 1);
478: DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis");
479: break;
480: case 0x04: /* Priority mask */
481: s->priority_mask = (value & 0x3ff);
482: break;
483: case 0x08: /* Binary Point */
484: /* ??? Not implemented. */
485: break;
486: case 0x10: /* End Of Interrupt */
487: return gic_complete_irq(s, value & 0x3ff);
488: default:
489: cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
490: return;
491: }
492: gic_update(s);
493: }
494:
495: static CPUReadMemoryFunc *gic_cpu_readfn[] = {
496: gic_cpu_read,
497: gic_cpu_read,
498: gic_cpu_read
499: };
500:
501: static CPUWriteMemoryFunc *gic_cpu_writefn[] = {
502: gic_cpu_write,
503: gic_cpu_write,
504: gic_cpu_write
505: };
506:
507: static void gic_reset(gic_state *s)
508: {
509: int i;
510: memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
511: s->priority_mask = 0xf0;
512: s->current_pending = 1023;
513: s->running_irq = 1023;
514: s->running_priority = 0x100;
515: for (i = 0; i < 15; i++) {
516: GIC_SET_ENABLED(i);
517: GIC_SET_TRIGGER(i);
518: }
519: s->enabled = 0;
520: s->cpu_enabled = 0;
521: }
522:
523: void *arm_gic_init(uint32_t base, void *parent, int parent_irq)
524: {
525: gic_state *s;
526: int iomemtype;
527:
528: s = (gic_state *)qemu_mallocz(sizeof(gic_state));
529: if (!s)
530: return NULL;
531: s->handler = gic_set_irq;
532: s->parent = parent;
533: s->parent_irq = parent_irq;
534: if (base != 0xffffffff) {
535: iomemtype = cpu_register_io_memory(0, gic_cpu_readfn,
536: gic_cpu_writefn, s);
537: cpu_register_physical_memory(base, 0x00000fff, iomemtype);
538: iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
539: gic_dist_writefn, s);
540: cpu_register_physical_memory(base + 0x1000, 0x00000fff, iomemtype);
541: s->base = base;
542: } else {
543: s->base = 0;
544: }
545: gic_reset(s);
546: return s;
547: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.