|
|
1.1.1.2 ! root 1: /* ! 2: * ARM Generic/Distributed Interrupt Controller 1.1 root 3: * 1.1.1.2 ! root 4: * Copyright (c) 2006-2007 CodeSourcery. 1.1 root 5: * Written by Paul Brook 6: * 7: * This code is licenced under the GPL. 8: */ 9: 1.1.1.2 ! root 10: /* This file contains implementation code for the RealView EB interrupt ! 11: controller, MPCore distributed interrupt controller and ARMv7-M ! 12: Nested Vectored Interrupt Controller. */ 1.1 root 13: 14: //#define DEBUG_GIC 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: 1.1.1.2 ! root 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: /* The NVIC has 16 internal vectors. However these are not exposed ! 28: through the normal GIC interface. */ ! 29: #define GIC_BASE_IRQ 32 ! 30: #else 1.1 root 31: static const uint8_t gic_id[] = 32: { 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 }; 1.1.1.2 ! root 33: #define GIC_DIST_OFFSET 0x1000 ! 34: #define GIC_BASE_IRQ 0 ! 35: #endif 1.1 root 36: 37: typedef struct gic_irq_state 38: { 1.1.1.2 ! root 39: /* ??? The documentation seems to imply the enable bits are global, even ! 40: for per-cpu interrupts. This seems strange. */ 1.1 root 41: unsigned enabled:1; 1.1.1.2 ! root 42: unsigned pending:NCPU; ! 43: unsigned active:NCPU; 1.1 root 44: unsigned level:1; 1.1.1.2 ! root 45: unsigned model:1; /* 0 = N:N, 1 = 1:N */ 1.1 root 46: unsigned trigger:1; /* nonzero = edge triggered. */ 47: } gic_irq_state; 48: 1.1.1.2 ! root 49: #define ALL_CPU_MASK ((1 << NCPU) - 1) ! 50: 1.1 root 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 1.1.1.2 ! root 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) 1.1 root 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 1.1.1.2 ! root 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 1.1 root 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 1.1.1.2 ! root 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 1.1 root 76: 77: typedef struct gic_state 78: { 79: uint32_t base; 1.1.1.2 ! root 80: qemu_irq parent_irq[NCPU]; 1.1 root 81: int enabled; 1.1.1.2 ! root 82: int cpu_enabled[NCPU]; 1.1 root 83: 84: gic_irq_state irq_state[GIC_NIRQ]; 1.1.1.2 ! root 85: #ifndef NVIC 1.1 root 86: int irq_target[GIC_NIRQ]; 1.1.1.2 ! root 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 1.1 root 101: } gic_state; 102: 103: /* TODO: Many places that call this routine could be optimized. */ 104: /* Update interrupt status after enabled or pending bits have been changed. */ 105: static void gic_update(gic_state *s) 106: { 107: int best_irq; 108: int best_prio; 109: int irq; 1.1.1.2 ! root 110: int level; ! 111: int cpu; ! 112: int cm; 1.1 root 113: 1.1.1.2 ! root 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: } 1.1 root 129: } 130: } 1.1.1.2 ! root 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: } 1.1 root 138: } 1.1.1.2 ! root 139: qemu_set_irq(s->parent_irq[cpu], level); 1.1 root 140: } 141: } 142: 1.1.1.2 ! root 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: /* Process a change in an external IRQ input. */ 1.1 root 157: static void gic_set_irq(void *opaque, int irq, int level) 158: { 159: gic_state *s = (gic_state *)opaque; 160: /* The first external input line is internal interrupt 32. */ 161: irq += 32; 1.1.1.2 ! root 162: if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK)) 1.1 root 163: return; 164: 165: if (level) { 1.1.1.2 ! root 166: GIC_SET_LEVEL(irq, ALL_CPU_MASK); 1.1 root 167: if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) { 1.1.1.2 ! root 168: DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq)); ! 169: GIC_SET_PENDING(irq, GIC_TARGET(irq)); 1.1 root 170: } 171: } else { 1.1.1.2 ! root 172: GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK); 1.1 root 173: } 174: gic_update(s); 175: } 176: 1.1.1.2 ! root 177: static void gic_set_running_irq(gic_state *s, int cpu, int irq) 1.1 root 178: { 1.1.1.2 ! root 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: } 1.1 root 185: gic_update(s); 186: } 187: 1.1.1.2 ! root 188: static uint32_t gic_acknowledge_irq(gic_state *s, int cpu) 1.1 root 189: { 190: int new_irq; 1.1.1.2 ! root 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]) { 1.1 root 195: DPRINTF("ACK no pending IRQ\n"); 196: return 1023; 197: } 1.1.1.2 ! root 198: s->last_active[new_irq][cpu] = s->running_irq[cpu]; ! 199: /* Clear pending flags for both level and edge triggered interrupts. ! 200: Level triggered IRQs will be reasserted once they become inactive. */ ! 201: GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm); ! 202: gic_set_running_irq(s, cpu, new_irq); 1.1 root 203: DPRINTF("ACK %d\n", new_irq); 204: return new_irq; 205: } 206: 1.1.1.2 ! root 207: static void gic_complete_irq(gic_state * s, int cpu, int irq) 1.1 root 208: { 209: int update = 0; 1.1.1.2 ! root 210: int cm = 1 << cpu; 1.1 root 211: DPRINTF("EOI %d\n", irq); 1.1.1.2 ! root 212: if (s->running_irq[cpu] == 1023) 1.1 root 213: return; /* No active IRQ. */ 214: if (irq != 1023) { 215: /* Mark level triggered interrupts as pending if they are still 216: raised. */ 217: if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq) 1.1.1.2 ! root 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); 1.1 root 221: update = 1; 222: } 223: } 1.1.1.2 ! root 224: if (irq != s->running_irq[cpu]) { 1.1 root 225: /* Complete an IRQ that is not currently running. */ 1.1.1.2 ! root 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]; 1.1 root 230: break; 231: } 1.1.1.2 ! root 232: tmp = s->last_active[tmp][cpu]; 1.1 root 233: } 234: if (update) { 235: gic_update(s); 236: } 237: } else { 238: /* Complete the current running IRQ. */ 1.1.1.2 ! root 239: gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]); 1.1 root 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; 1.1.1.2 ! root 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; 1.1 root 256: if (offset < 0x100) { 1.1.1.2 ! root 257: #ifndef NVIC 1.1 root 258: if (offset == 0) 259: return s->enabled; 260: if (offset == 4) 1.1.1.2 ! root 261: return ((GIC_NIRQ / 32) - 1) | ((NCPU - 1) << 5); 1.1 root 262: if (offset < 0x08) 263: return 0; 1.1.1.2 ! root 264: #endif 1.1 root 265: goto bad_reg; 266: } else if (offset < 0x200) { 267: /* Interrupt Set/Clear Enable. */ 268: if (offset < 0x180) 269: irq = (offset - 0x100) * 8; 270: else 271: irq = (offset - 0x180) * 8; 1.1.1.2 ! root 272: irq += GIC_BASE_IRQ; 1.1 root 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: /* Interrupt Set/Clear Pending. */ 283: if (offset < 0x280) 284: irq = (offset - 0x200) * 8; 285: else 286: irq = (offset - 0x280) * 8; 1.1.1.2 ! root 287: irq += GIC_BASE_IRQ; 1.1 root 288: if (irq >= GIC_NIRQ) 289: goto bad_reg; 290: res = 0; 1.1.1.2 ! root 291: mask = (irq < 32) ? cm : ALL_CPU_MASK; 1.1 root 292: for (i = 0; i < 8; i++) { 1.1.1.2 ! root 293: if (GIC_TEST_PENDING(irq + i, mask)) { 1.1 root 294: res |= (1 << i); 295: } 296: } 297: } else if (offset < 0x400) { 298: /* Interrupt Active. */ 1.1.1.2 ! root 299: irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 1.1 root 300: if (irq >= GIC_NIRQ) 301: goto bad_reg; 302: res = 0; 1.1.1.2 ! root 303: mask = (irq < 32) ? cm : ALL_CPU_MASK; 1.1 root 304: for (i = 0; i < 8; i++) { 1.1.1.2 ! root 305: if (GIC_TEST_ACTIVE(irq + i, mask)) { 1.1 root 306: res |= (1 << i); 307: } 308: } 309: } else if (offset < 0x800) { 310: /* Interrupt Priority. */ 1.1.1.2 ! root 311: irq = (offset - 0x400) + GIC_BASE_IRQ; 1.1 root 312: if (irq >= GIC_NIRQ) 313: goto bad_reg; 1.1.1.2 ! root 314: res = GIC_GET_PRIORITY(irq, cpu); ! 315: #ifndef NVIC 1.1 root 316: } else if (offset < 0xc00) { 317: /* Interrupt CPU Target. */ 1.1.1.2 ! root 318: irq = (offset - 0x800) + GIC_BASE_IRQ; 1.1 root 319: if (irq >= GIC_NIRQ) 320: goto bad_reg; 1.1.1.2 ! root 321: if (irq >= 29 && irq <= 31) { ! 322: res = cm; ! 323: } else { ! 324: res = GIC_TARGET(irq); ! 325: } 1.1 root 326: } else if (offset < 0xf00) { 327: /* Interrupt Configuration. */ 1.1.1.2 ! root 328: irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ; 1.1 root 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: } 1.1.1.2 ! root 338: #endif 1.1 root 339: } else if (offset < 0xfe0) { 340: goto bad_reg; 341: } else /* offset >= 0xfe0 */ { 342: if (offset & 3) { 343: res = 0; 344: } else { 345: res = gic_id[(offset - 0xfe0) >> 2]; 346: } 347: } 348: return res; 349: bad_reg: 1.1.1.2 ! root 350: cpu_abort(cpu_single_env, "gic_dist_readb: Bad offset %x\n", (int)offset); 1.1 root 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; 1.1.1.2 ! root 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 1.1 root 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; 1.1.1.2 ! root 383: int cpu; 1.1 root 384: 1.1.1.2 ! root 385: cpu = gic_get_current_cpu(); ! 386: offset -= s->base + GIC_DIST_OFFSET; 1.1 root 387: if (offset < 0x100) { 1.1.1.2 ! root 388: #ifdef NVIC ! 389: goto bad_reg; ! 390: #else 1.1 root 391: if (offset == 0) { 392: s->enabled = (value & 1); 393: DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis"); 394: } else if (offset < 4) { 395: /* ignored. */ 396: } else { 397: goto bad_reg; 398: } 1.1.1.2 ! root 399: #endif 1.1 root 400: } else if (offset < 0x180) { 401: /* Interrupt Set Enable. */ 1.1.1.2 ! root 402: irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 1.1 root 403: if (irq >= GIC_NIRQ) 404: goto bad_reg; 1.1.1.2 ! root 405: if (irq < 16) ! 406: value = 0xff; 1.1 root 407: for (i = 0; i < 8; i++) { 408: if (value & (1 << i)) { 1.1.1.2 ! root 409: int mask = (irq < 32) ? (1 << cpu) : GIC_TARGET(irq); 1.1 root 410: if (!GIC_TEST_ENABLED(irq + i)) 411: DPRINTF("Enabled IRQ %d\n", irq + i); 412: GIC_SET_ENABLED(irq + i); 413: /* If a raised level triggered IRQ enabled then mark 414: is as pending. */ 1.1.1.2 ! root 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: } 1.1 root 420: } 421: } 422: } else if (offset < 0x200) { 423: /* Interrupt Clear Enable. */ 1.1.1.2 ! root 424: irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 1.1 root 425: if (irq >= GIC_NIRQ) 426: goto bad_reg; 1.1.1.2 ! root 427: if (irq < 16) ! 428: value = 0; 1.1 root 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: /* Interrupt Set Pending. */ 1.1.1.2 ! root 438: irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 1.1 root 439: if (irq >= GIC_NIRQ) 440: goto bad_reg; 1.1.1.2 ! root 441: if (irq < 16) ! 442: irq = 0; ! 443: 1.1 root 444: for (i = 0; i < 8; i++) { 445: if (value & (1 << i)) { 1.1.1.2 ! root 446: GIC_SET_PENDING(irq + i, GIC_TARGET(irq)); 1.1 root 447: } 448: } 449: } else if (offset < 0x300) { 450: /* Interrupt Clear Pending. */ 1.1.1.2 ! root 451: irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 1.1 root 452: if (irq >= GIC_NIRQ) 453: goto bad_reg; 454: for (i = 0; i < 8; i++) { 1.1.1.2 ! root 455: /* ??? This currently clears the pending bit for all CPUs, even ! 456: for per-CPU interrupts. It's unclear whether this is the ! 457: corect behavior. */ 1.1 root 458: if (value & (1 << i)) { 1.1.1.2 ! root 459: GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 1.1 root 460: } 461: } 462: } else if (offset < 0x400) { 463: /* Interrupt Active. */ 464: goto bad_reg; 465: } else if (offset < 0x800) { 466: /* Interrupt Priority. */ 1.1.1.2 ! root 467: irq = (offset - 0x400) + GIC_BASE_IRQ; 1.1 root 468: if (irq >= GIC_NIRQ) 469: goto bad_reg; 1.1.1.2 ! root 470: if (irq < 32) { ! 471: s->priority1[irq][cpu] = value; ! 472: } else { ! 473: s->priority2[irq - 32] = value; ! 474: } ! 475: #ifndef NVIC 1.1 root 476: } else if (offset < 0xc00) { 477: /* Interrupt CPU Target. */ 1.1.1.2 ! root 478: irq = (offset - 0x800) + GIC_BASE_IRQ; 1.1 root 479: if (irq >= GIC_NIRQ) 480: goto bad_reg; 1.1.1.2 ! root 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; 1.1 root 486: } else if (offset < 0xf00) { 487: /* Interrupt Configuration. */ 1.1.1.2 ! root 488: irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 1.1 root 489: if (irq >= GIC_NIRQ) 490: goto bad_reg; 1.1.1.2 ! root 491: if (irq < 32) ! 492: value |= 0xaa; 1.1 root 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: } 1.1.1.2 ! root 505: #endif 1.1 root 506: } else { 1.1.1.2 ! root 507: /* 0xf00 is only handled for 32-bit writes. */ 1.1 root 508: goto bad_reg; 509: } 510: gic_update(s); 511: return; 512: bad_reg: 1.1.1.2 ! root 513: cpu_abort(cpu_single_env, "gic_dist_writeb: Bad offset %x\n", (int)offset); 1.1 root 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: { 1.1.1.2 ! root 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); ! 532: return; ! 533: } ! 534: #endif ! 535: if (offset - s->base == GIC_DIST_OFFSET + 0xf00) { ! 536: int cpu; ! 537: int irq; ! 538: int mask; ! 539: ! 540: cpu = gic_get_current_cpu(); ! 541: irq = value & 0x3ff; ! 542: switch ((value >> 24) & 3) { ! 543: case 0: ! 544: mask = (value >> 16) & ALL_CPU_MASK; ! 545: break; ! 546: case 1: ! 547: mask = 1 << cpu; ! 548: break; ! 549: case 2: ! 550: mask = ALL_CPU_MASK ^ (1 << cpu); ! 551: break; ! 552: default: ! 553: DPRINTF("Bad Soft Int target filter\n"); ! 554: mask = ALL_CPU_MASK; ! 555: break; ! 556: } ! 557: GIC_SET_PENDING(irq, mask); ! 558: gic_update(s); ! 559: return; ! 560: } 1.1 root 561: gic_dist_writew(opaque, offset, value & 0xffff); 562: gic_dist_writew(opaque, offset + 2, value >> 16); 563: } 564: 565: static CPUReadMemoryFunc *gic_dist_readfn[] = { 566: gic_dist_readb, 567: gic_dist_readw, 568: gic_dist_readl 569: }; 570: 571: static CPUWriteMemoryFunc *gic_dist_writefn[] = { 572: gic_dist_writeb, 573: gic_dist_writew, 574: gic_dist_writel 575: }; 576: 1.1.1.2 ! root 577: #ifndef NVIC ! 578: static uint32_t gic_cpu_read(gic_state *s, int cpu, int offset) 1.1 root 579: { 580: switch (offset) { 581: case 0x00: /* Control */ 1.1.1.2 ! root 582: return s->cpu_enabled[cpu]; 1.1 root 583: case 0x04: /* Priority mask */ 1.1.1.2 ! root 584: return s->priority_mask[cpu]; 1.1 root 585: case 0x08: /* Binary Point */ 586: /* ??? Not implemented. */ 587: return 0; 588: case 0x0c: /* Acknowledge */ 1.1.1.2 ! root 589: return gic_acknowledge_irq(s, cpu); 1.1 root 590: case 0x14: /* Runing Priority */ 1.1.1.2 ! root 591: return s->running_priority[cpu]; 1.1 root 592: case 0x18: /* Highest Pending Interrupt */ 1.1.1.2 ! root 593: return s->current_pending[cpu]; 1.1 root 594: default: 1.1.1.2 ! root 595: cpu_abort(cpu_single_env, "gic_cpu_read: Bad offset %x\n", ! 596: (int)offset); 1.1 root 597: return 0; 598: } 599: } 600: 1.1.1.2 ! root 601: static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value) 1.1 root 602: { 603: switch (offset) { 604: case 0x00: /* Control */ 1.1.1.2 ! root 605: s->cpu_enabled[cpu] = (value & 1); 1.1 root 606: DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis"); 607: break; 608: case 0x04: /* Priority mask */ 1.1.1.2 ! root 609: s->priority_mask[cpu] = (value & 0xff); 1.1 root 610: break; 611: case 0x08: /* Binary Point */ 612: /* ??? Not implemented. */ 613: break; 614: case 0x10: /* End Of Interrupt */ 1.1.1.2 ! root 615: return gic_complete_irq(s, cpu, value & 0x3ff); 1.1 root 616: default: 1.1.1.2 ! root 617: cpu_abort(cpu_single_env, "gic_cpu_write: Bad offset %x\n", ! 618: (int)offset); 1.1 root 619: return; 620: } 621: gic_update(s); 622: } 1.1.1.2 ! root 623: #endif 1.1 root 624: 625: static void gic_reset(gic_state *s) 626: { 627: int i; 628: memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state)); 1.1.1.2 ! root 629: for (i = 0 ; i < NCPU; i++) { ! 630: s->priority_mask[i] = 0xf0; ! 631: s->current_pending[i] = 1023; ! 632: s->running_irq[i] = 1023; ! 633: s->running_priority[i] = 0x100; ! 634: #ifdef NVIC ! 635: /* The NVIC doesn't have per-cpu interfaces, so enable by default. */ ! 636: s->cpu_enabled[i] = 1; ! 637: #else ! 638: s->cpu_enabled[i] = 0; ! 639: #endif ! 640: } ! 641: for (i = 0; i < 16; i++) { 1.1 root 642: GIC_SET_ENABLED(i); 643: GIC_SET_TRIGGER(i); 644: } 1.1.1.2 ! root 645: #ifdef NVIC ! 646: /* The NVIC is always enabled. */ ! 647: s->enabled = 1; ! 648: #else 1.1 root 649: s->enabled = 0; 1.1.1.2 ! root 650: #endif 1.1 root 651: } 652: 1.1.1.2 ! root 653: static gic_state *gic_init(uint32_t base, qemu_irq *parent_irq) 1.1 root 654: { 655: gic_state *s; 656: int iomemtype; 1.1.1.2 ! root 657: int i; 1.1 root 658: 659: s = (gic_state *)qemu_mallocz(sizeof(gic_state)); 660: if (!s) 661: return NULL; 1.1.1.2 ! root 662: s->in = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ); ! 663: for (i = 0; i < NCPU; i++) { ! 664: s->parent_irq[i] = parent_irq[i]; ! 665: } ! 666: iomemtype = cpu_register_io_memory(0, gic_dist_readfn, ! 667: gic_dist_writefn, s); ! 668: cpu_register_physical_memory(base + GIC_DIST_OFFSET, 0x00001000, ! 669: iomemtype); ! 670: s->base = base; 1.1 root 671: gic_reset(s); 672: return s; 673: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.