1e69954b9Spbrook /* 29ee6e8bbSpbrook * ARM Generic/Distributed Interrupt Controller 3e69954b9Spbrook * 49ee6e8bbSpbrook * Copyright (c) 2006-2007 CodeSourcery. 5e69954b9Spbrook * Written by Paul Brook 6e69954b9Spbrook * 78e31bf38SMatthew Fernandez * This code is licensed under the GPL. 8e69954b9Spbrook */ 9e69954b9Spbrook 109ee6e8bbSpbrook /* This file contains implementation code for the RealView EB interrupt 110d256bdcSPeter Maydell * controller, MPCore distributed interrupt controller and ARMv7-M 120d256bdcSPeter Maydell * Nested Vectored Interrupt Controller. 130d256bdcSPeter Maydell * It is compiled in two ways: 140d256bdcSPeter Maydell * (1) as a standalone file to produce a sysbus device which is a GIC 150d256bdcSPeter Maydell * that can be used on the realview board and as one of the builtin 160d256bdcSPeter Maydell * private peripherals for the ARM MP CPUs (11MPCore, A9, etc) 170d256bdcSPeter Maydell * (2) by being directly #included into armv7m_nvic.c to produce the 180d256bdcSPeter Maydell * armv7m_nvic device. 190d256bdcSPeter Maydell */ 20e69954b9Spbrook 2183c9f4caSPaolo Bonzini #include "hw/sysbus.h" 2247b43a1fSPaolo Bonzini #include "gic_internal.h" 23dfc08079SAndreas Färber #include "qom/cpu.h" 24386e2955SPeter Maydell 25e69954b9Spbrook //#define DEBUG_GIC 26e69954b9Spbrook 27e69954b9Spbrook #ifdef DEBUG_GIC 28001faf32SBlue Swirl #define DPRINTF(fmt, ...) \ 295eb98401SPeter A. G. Crosthwaite do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0) 30e69954b9Spbrook #else 31001faf32SBlue Swirl #define DPRINTF(fmt, ...) do {} while(0) 32e69954b9Spbrook #endif 33e69954b9Spbrook 342a29ddeeSPeter Maydell static const uint8_t gic_id[] = { 352a29ddeeSPeter Maydell 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 362a29ddeeSPeter Maydell }; 372a29ddeeSPeter Maydell 38c988bfadSPaul Brook #define NUM_CPU(s) ((s)->num_cpu) 399ee6e8bbSpbrook 40fae15286SPeter Maydell static inline int gic_get_current_cpu(GICState *s) 41926c4affSPeter Maydell { 42926c4affSPeter Maydell if (s->num_cpu > 1) { 434917cf44SAndreas Färber return current_cpu->cpu_index; 44926c4affSPeter Maydell } 45926c4affSPeter Maydell return 0; 46926c4affSPeter Maydell } 47926c4affSPeter Maydell 48e69954b9Spbrook /* TODO: Many places that call this routine could be optimized. */ 49e69954b9Spbrook /* Update interrupt status after enabled or pending bits have been changed. */ 50fae15286SPeter Maydell void gic_update(GICState *s) 51e69954b9Spbrook { 52e69954b9Spbrook int best_irq; 53e69954b9Spbrook int best_prio; 54e69954b9Spbrook int irq; 559ee6e8bbSpbrook int level; 569ee6e8bbSpbrook int cpu; 579ee6e8bbSpbrook int cm; 58e69954b9Spbrook 59c988bfadSPaul Brook for (cpu = 0; cpu < NUM_CPU(s); cpu++) { 609ee6e8bbSpbrook cm = 1 << cpu; 619ee6e8bbSpbrook s->current_pending[cpu] = 1023; 629ee6e8bbSpbrook if (!s->enabled || !s->cpu_enabled[cpu]) { 639ee6e8bbSpbrook qemu_irq_lower(s->parent_irq[cpu]); 64e69954b9Spbrook return; 65e69954b9Spbrook } 66e69954b9Spbrook best_prio = 0x100; 67e69954b9Spbrook best_irq = 1023; 68a32134aaSMark Langsdorf for (irq = 0; irq < s->num_irq; irq++) { 69b52b81e4SSergey Fedorov if (GIC_TEST_ENABLED(irq, cm) && gic_test_pending(s, irq, cm) && 70b52b81e4SSergey Fedorov (irq < GIC_INTERNAL || GIC_TARGET(irq) & cm)) { 719ee6e8bbSpbrook if (GIC_GET_PRIORITY(irq, cpu) < best_prio) { 729ee6e8bbSpbrook best_prio = GIC_GET_PRIORITY(irq, cpu); 73e69954b9Spbrook best_irq = irq; 74e69954b9Spbrook } 75e69954b9Spbrook } 76e69954b9Spbrook } 779ee6e8bbSpbrook level = 0; 78cad065f1SPeter Maydell if (best_prio < s->priority_mask[cpu]) { 799ee6e8bbSpbrook s->current_pending[cpu] = best_irq; 809ee6e8bbSpbrook if (best_prio < s->running_priority[cpu]) { 818c815fb3SPeter Crosthwaite DPRINTF("Raised pending IRQ %d (cpu %d)\n", best_irq, cpu); 829ee6e8bbSpbrook level = 1; 83e69954b9Spbrook } 84e69954b9Spbrook } 859ee6e8bbSpbrook qemu_set_irq(s->parent_irq[cpu], level); 869ee6e8bbSpbrook } 87e69954b9Spbrook } 88e69954b9Spbrook 89fae15286SPeter Maydell void gic_set_pending_private(GICState *s, int cpu, int irq) 909ee6e8bbSpbrook { 919ee6e8bbSpbrook int cm = 1 << cpu; 929ee6e8bbSpbrook 938d999995SChristoffer Dall if (gic_test_pending(s, irq, cm)) { 949ee6e8bbSpbrook return; 958d999995SChristoffer Dall } 969ee6e8bbSpbrook 979ee6e8bbSpbrook DPRINTF("Set %d pending cpu %d\n", irq, cpu); 989ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 999ee6e8bbSpbrook gic_update(s); 1009ee6e8bbSpbrook } 1019ee6e8bbSpbrook 1028d999995SChristoffer Dall static void gic_set_irq_11mpcore(GICState *s, int irq, int level, 1038d999995SChristoffer Dall int cm, int target) 1048d999995SChristoffer Dall { 1058d999995SChristoffer Dall if (level) { 1068d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1078d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq) || GIC_TEST_ENABLED(irq, cm)) { 1088d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1098d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1108d999995SChristoffer Dall } 1118d999995SChristoffer Dall } else { 1128d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1138d999995SChristoffer Dall } 1148d999995SChristoffer Dall } 1158d999995SChristoffer Dall 1168d999995SChristoffer Dall static void gic_set_irq_generic(GICState *s, int irq, int level, 1178d999995SChristoffer Dall int cm, int target) 1188d999995SChristoffer Dall { 1198d999995SChristoffer Dall if (level) { 1208d999995SChristoffer Dall GIC_SET_LEVEL(irq, cm); 1218d999995SChristoffer Dall DPRINTF("Set %d pending mask %x\n", irq, target); 1228d999995SChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq)) { 1238d999995SChristoffer Dall GIC_SET_PENDING(irq, target); 1248d999995SChristoffer Dall } 1258d999995SChristoffer Dall } else { 1268d999995SChristoffer Dall GIC_CLEAR_LEVEL(irq, cm); 1278d999995SChristoffer Dall } 1288d999995SChristoffer Dall } 1298d999995SChristoffer Dall 1309ee6e8bbSpbrook /* Process a change in an external IRQ input. */ 131e69954b9Spbrook static void gic_set_irq(void *opaque, int irq, int level) 132e69954b9Spbrook { 133544d1afaSPeter Maydell /* Meaning of the 'irq' parameter: 134544d1afaSPeter Maydell * [0..N-1] : external interrupts 135544d1afaSPeter Maydell * [N..N+31] : PPI (internal) interrupts for CPU 0 136544d1afaSPeter Maydell * [N+32..N+63] : PPI (internal interrupts for CPU 1 137544d1afaSPeter Maydell * ... 138544d1afaSPeter Maydell */ 139fae15286SPeter Maydell GICState *s = (GICState *)opaque; 140544d1afaSPeter Maydell int cm, target; 141544d1afaSPeter Maydell if (irq < (s->num_irq - GIC_INTERNAL)) { 142e69954b9Spbrook /* The first external input line is internal interrupt 32. */ 143544d1afaSPeter Maydell cm = ALL_CPU_MASK; 14469253800SRusty Russell irq += GIC_INTERNAL; 145544d1afaSPeter Maydell target = GIC_TARGET(irq); 146544d1afaSPeter Maydell } else { 147544d1afaSPeter Maydell int cpu; 148544d1afaSPeter Maydell irq -= (s->num_irq - GIC_INTERNAL); 149544d1afaSPeter Maydell cpu = irq / GIC_INTERNAL; 150544d1afaSPeter Maydell irq %= GIC_INTERNAL; 151544d1afaSPeter Maydell cm = 1 << cpu; 152544d1afaSPeter Maydell target = cm; 153544d1afaSPeter Maydell } 154544d1afaSPeter Maydell 15540d22500SChristoffer Dall assert(irq >= GIC_NR_SGIS); 15640d22500SChristoffer Dall 157544d1afaSPeter Maydell if (level == GIC_TEST_LEVEL(irq, cm)) { 158e69954b9Spbrook return; 159544d1afaSPeter Maydell } 160e69954b9Spbrook 1618d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 1628d999995SChristoffer Dall gic_set_irq_11mpcore(s, irq, level, cm, target); 163e69954b9Spbrook } else { 1648d999995SChristoffer Dall gic_set_irq_generic(s, irq, level, cm, target); 165e69954b9Spbrook } 1668d999995SChristoffer Dall 167e69954b9Spbrook gic_update(s); 168e69954b9Spbrook } 169e69954b9Spbrook 170fae15286SPeter Maydell static void gic_set_running_irq(GICState *s, int cpu, int irq) 171e69954b9Spbrook { 1729ee6e8bbSpbrook s->running_irq[cpu] = irq; 1739ee6e8bbSpbrook if (irq == 1023) { 1749ee6e8bbSpbrook s->running_priority[cpu] = 0x100; 1759ee6e8bbSpbrook } else { 1769ee6e8bbSpbrook s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu); 1779ee6e8bbSpbrook } 178e69954b9Spbrook gic_update(s); 179e69954b9Spbrook } 180e69954b9Spbrook 181fae15286SPeter Maydell uint32_t gic_acknowledge_irq(GICState *s, int cpu) 182e69954b9Spbrook { 18340d22500SChristoffer Dall int ret, irq, src; 1849ee6e8bbSpbrook int cm = 1 << cpu; 18540d22500SChristoffer Dall irq = s->current_pending[cpu]; 18640d22500SChristoffer Dall if (irq == 1023 18740d22500SChristoffer Dall || GIC_GET_PRIORITY(irq, cpu) >= s->running_priority[cpu]) { 188e69954b9Spbrook DPRINTF("ACK no pending IRQ\n"); 189e69954b9Spbrook return 1023; 190e69954b9Spbrook } 19140d22500SChristoffer Dall s->last_active[irq][cpu] = s->running_irq[cpu]; 19240d22500SChristoffer Dall 19387316902SPeter Maydell if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 1949ee6e8bbSpbrook /* Clear pending flags for both level and edge triggered interrupts. 19540d22500SChristoffer Dall * Level triggered IRQs will be reasserted once they become inactive. 19640d22500SChristoffer Dall */ 19740d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 19840d22500SChristoffer Dall ret = irq; 19940d22500SChristoffer Dall } else { 20040d22500SChristoffer Dall if (irq < GIC_NR_SGIS) { 20140d22500SChristoffer Dall /* Lookup the source CPU for the SGI and clear this in the 20240d22500SChristoffer Dall * sgi_pending map. Return the src and clear the overall pending 20340d22500SChristoffer Dall * state on this CPU if the SGI is not pending from any CPUs. 20440d22500SChristoffer Dall */ 20540d22500SChristoffer Dall assert(s->sgi_pending[irq][cpu] != 0); 20640d22500SChristoffer Dall src = ctz32(s->sgi_pending[irq][cpu]); 20740d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~(1 << src); 20840d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 20940d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 21040d22500SChristoffer Dall } 21140d22500SChristoffer Dall ret = irq | ((src & 0x7) << 10); 21240d22500SChristoffer Dall } else { 21340d22500SChristoffer Dall /* Clear pending state for both level and edge triggered 21440d22500SChristoffer Dall * interrupts. (level triggered interrupts with an active line 21540d22500SChristoffer Dall * remain pending, see gic_test_pending) 21640d22500SChristoffer Dall */ 21740d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, GIC_TEST_MODEL(irq) ? ALL_CPU_MASK : cm); 21840d22500SChristoffer Dall ret = irq; 21940d22500SChristoffer Dall } 22040d22500SChristoffer Dall } 22140d22500SChristoffer Dall 22240d22500SChristoffer Dall gic_set_running_irq(s, cpu, irq); 22340d22500SChristoffer Dall DPRINTF("ACK %d\n", irq); 22440d22500SChristoffer Dall return ret; 225e69954b9Spbrook } 226e69954b9Spbrook 2279df90ad0SChristoffer Dall void gic_set_priority(GICState *s, int cpu, int irq, uint8_t val) 2289df90ad0SChristoffer Dall { 2299df90ad0SChristoffer Dall if (irq < GIC_INTERNAL) { 2309df90ad0SChristoffer Dall s->priority1[irq][cpu] = val; 2319df90ad0SChristoffer Dall } else { 2329df90ad0SChristoffer Dall s->priority2[(irq) - GIC_INTERNAL] = val; 2339df90ad0SChristoffer Dall } 2349df90ad0SChristoffer Dall } 2359df90ad0SChristoffer Dall 236fae15286SPeter Maydell void gic_complete_irq(GICState *s, int cpu, int irq) 237e69954b9Spbrook { 238e69954b9Spbrook int update = 0; 2399ee6e8bbSpbrook int cm = 1 << cpu; 240df628ff1Spbrook DPRINTF("EOI %d\n", irq); 241a32134aaSMark Langsdorf if (irq >= s->num_irq) { 242217bfb44SPeter Maydell /* This handles two cases: 243217bfb44SPeter Maydell * 1. If software writes the ID of a spurious interrupt [ie 1023] 244217bfb44SPeter Maydell * to the GICC_EOIR, the GIC ignores that write. 245217bfb44SPeter Maydell * 2. If software writes the number of a non-existent interrupt 246217bfb44SPeter Maydell * this must be a subcase of "value written does not match the last 247217bfb44SPeter Maydell * valid interrupt value read from the Interrupt Acknowledge 248217bfb44SPeter Maydell * register" and so this is UNPREDICTABLE. We choose to ignore it. 249217bfb44SPeter Maydell */ 250217bfb44SPeter Maydell return; 251217bfb44SPeter Maydell } 2529ee6e8bbSpbrook if (s->running_irq[cpu] == 1023) 253e69954b9Spbrook return; /* No active IRQ. */ 2548d999995SChristoffer Dall 2558d999995SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 256e69954b9Spbrook /* Mark level triggered interrupts as pending if they are still 257e69954b9Spbrook raised. */ 25804050c5cSChristoffer Dall if (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_ENABLED(irq, cm) 2599ee6e8bbSpbrook && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) { 2609ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq, cm); 2619ee6e8bbSpbrook GIC_SET_PENDING(irq, cm); 262e69954b9Spbrook update = 1; 263e69954b9Spbrook } 2648d999995SChristoffer Dall } 2658d999995SChristoffer Dall 2669ee6e8bbSpbrook if (irq != s->running_irq[cpu]) { 267e69954b9Spbrook /* Complete an IRQ that is not currently running. */ 2689ee6e8bbSpbrook int tmp = s->running_irq[cpu]; 2699ee6e8bbSpbrook while (s->last_active[tmp][cpu] != 1023) { 2709ee6e8bbSpbrook if (s->last_active[tmp][cpu] == irq) { 2719ee6e8bbSpbrook s->last_active[tmp][cpu] = s->last_active[irq][cpu]; 272e69954b9Spbrook break; 273e69954b9Spbrook } 2749ee6e8bbSpbrook tmp = s->last_active[tmp][cpu]; 275e69954b9Spbrook } 276e69954b9Spbrook if (update) { 277e69954b9Spbrook gic_update(s); 278e69954b9Spbrook } 279e69954b9Spbrook } else { 280e69954b9Spbrook /* Complete the current running IRQ. */ 2819ee6e8bbSpbrook gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]); 282e69954b9Spbrook } 283e69954b9Spbrook } 284e69954b9Spbrook 285a8170e5eSAvi Kivity static uint32_t gic_dist_readb(void *opaque, hwaddr offset) 286e69954b9Spbrook { 287fae15286SPeter Maydell GICState *s = (GICState *)opaque; 288e69954b9Spbrook uint32_t res; 289e69954b9Spbrook int irq; 290e69954b9Spbrook int i; 2919ee6e8bbSpbrook int cpu; 2929ee6e8bbSpbrook int cm; 2939ee6e8bbSpbrook int mask; 294e69954b9Spbrook 295926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 2969ee6e8bbSpbrook cm = 1 << cpu; 297e69954b9Spbrook if (offset < 0x100) { 298e69954b9Spbrook if (offset == 0) 299e69954b9Spbrook return s->enabled; 300e69954b9Spbrook if (offset == 4) 301*5543d1abSFabian Aggeler /* Interrupt Controller Type Register */ 302*5543d1abSFabian Aggeler return ((s->num_irq / 32) - 1) 303*5543d1abSFabian Aggeler | ((NUM_CPU(s) - 1) << 5) 304*5543d1abSFabian Aggeler | (s->security_extn << 10); 305e69954b9Spbrook if (offset < 0x08) 306e69954b9Spbrook return 0; 307b79f2265SRob Herring if (offset >= 0x80) { 308b79f2265SRob Herring /* Interrupt Security , RAZ/WI */ 309b79f2265SRob Herring return 0; 310b79f2265SRob Herring } 311e69954b9Spbrook goto bad_reg; 312e69954b9Spbrook } else if (offset < 0x200) { 313e69954b9Spbrook /* Interrupt Set/Clear Enable. */ 314e69954b9Spbrook if (offset < 0x180) 315e69954b9Spbrook irq = (offset - 0x100) * 8; 316e69954b9Spbrook else 317e69954b9Spbrook irq = (offset - 0x180) * 8; 3189ee6e8bbSpbrook irq += GIC_BASE_IRQ; 319a32134aaSMark Langsdorf if (irq >= s->num_irq) 320e69954b9Spbrook goto bad_reg; 321e69954b9Spbrook res = 0; 322e69954b9Spbrook for (i = 0; i < 8; i++) { 32341bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 324e69954b9Spbrook res |= (1 << i); 325e69954b9Spbrook } 326e69954b9Spbrook } 327e69954b9Spbrook } else if (offset < 0x300) { 328e69954b9Spbrook /* Interrupt Set/Clear Pending. */ 329e69954b9Spbrook if (offset < 0x280) 330e69954b9Spbrook irq = (offset - 0x200) * 8; 331e69954b9Spbrook else 332e69954b9Spbrook irq = (offset - 0x280) * 8; 3339ee6e8bbSpbrook irq += GIC_BASE_IRQ; 334a32134aaSMark Langsdorf if (irq >= s->num_irq) 335e69954b9Spbrook goto bad_reg; 336e69954b9Spbrook res = 0; 33769253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 338e69954b9Spbrook for (i = 0; i < 8; i++) { 3398d999995SChristoffer Dall if (gic_test_pending(s, irq + i, mask)) { 340e69954b9Spbrook res |= (1 << i); 341e69954b9Spbrook } 342e69954b9Spbrook } 343e69954b9Spbrook } else if (offset < 0x400) { 344e69954b9Spbrook /* Interrupt Active. */ 3459ee6e8bbSpbrook irq = (offset - 0x300) * 8 + GIC_BASE_IRQ; 346a32134aaSMark Langsdorf if (irq >= s->num_irq) 347e69954b9Spbrook goto bad_reg; 348e69954b9Spbrook res = 0; 34969253800SRusty Russell mask = (irq < GIC_INTERNAL) ? cm : ALL_CPU_MASK; 350e69954b9Spbrook for (i = 0; i < 8; i++) { 3519ee6e8bbSpbrook if (GIC_TEST_ACTIVE(irq + i, mask)) { 352e69954b9Spbrook res |= (1 << i); 353e69954b9Spbrook } 354e69954b9Spbrook } 355e69954b9Spbrook } else if (offset < 0x800) { 356e69954b9Spbrook /* Interrupt Priority. */ 3579ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 358a32134aaSMark Langsdorf if (irq >= s->num_irq) 359e69954b9Spbrook goto bad_reg; 3609ee6e8bbSpbrook res = GIC_GET_PRIORITY(irq, cpu); 361e69954b9Spbrook } else if (offset < 0xc00) { 362e69954b9Spbrook /* Interrupt CPU Target. */ 3636b9680bbSPeter Maydell if (s->num_cpu == 1 && s->revision != REV_11MPCORE) { 3646b9680bbSPeter Maydell /* For uniprocessor GICs these RAZ/WI */ 3656b9680bbSPeter Maydell res = 0; 3666b9680bbSPeter Maydell } else { 3679ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 3686b9680bbSPeter Maydell if (irq >= s->num_irq) { 369e69954b9Spbrook goto bad_reg; 3706b9680bbSPeter Maydell } 3719ee6e8bbSpbrook if (irq >= 29 && irq <= 31) { 3729ee6e8bbSpbrook res = cm; 3739ee6e8bbSpbrook } else { 3749ee6e8bbSpbrook res = GIC_TARGET(irq); 3759ee6e8bbSpbrook } 3766b9680bbSPeter Maydell } 377e69954b9Spbrook } else if (offset < 0xf00) { 378e69954b9Spbrook /* Interrupt Configuration. */ 37971a62046SAdam Lackorzynski irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 380a32134aaSMark Langsdorf if (irq >= s->num_irq) 381e69954b9Spbrook goto bad_reg; 382e69954b9Spbrook res = 0; 383e69954b9Spbrook for (i = 0; i < 4; i++) { 384e69954b9Spbrook if (GIC_TEST_MODEL(irq + i)) 385e69954b9Spbrook res |= (1 << (i * 2)); 38604050c5cSChristoffer Dall if (GIC_TEST_EDGE_TRIGGER(irq + i)) 387e69954b9Spbrook res |= (2 << (i * 2)); 388e69954b9Spbrook } 38940d22500SChristoffer Dall } else if (offset < 0xf10) { 39040d22500SChristoffer Dall goto bad_reg; 39140d22500SChristoffer Dall } else if (offset < 0xf30) { 39240d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 39340d22500SChristoffer Dall goto bad_reg; 39440d22500SChristoffer Dall } 39540d22500SChristoffer Dall 39640d22500SChristoffer Dall if (offset < 0xf20) { 39740d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 39840d22500SChristoffer Dall irq = (offset - 0xf10); 39940d22500SChristoffer Dall } else { 40040d22500SChristoffer Dall irq = (offset - 0xf20); 40140d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 40240d22500SChristoffer Dall } 40340d22500SChristoffer Dall 40440d22500SChristoffer Dall res = s->sgi_pending[irq][cpu]; 405e69954b9Spbrook } else if (offset < 0xfe0) { 406e69954b9Spbrook goto bad_reg; 407e69954b9Spbrook } else /* offset >= 0xfe0 */ { 408e69954b9Spbrook if (offset & 3) { 409e69954b9Spbrook res = 0; 410e69954b9Spbrook } else { 411e69954b9Spbrook res = gic_id[(offset - 0xfe0) >> 2]; 412e69954b9Spbrook } 413e69954b9Spbrook } 414e69954b9Spbrook return res; 415e69954b9Spbrook bad_reg: 4168c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 4178c8dc39fSPeter Maydell "gic_dist_readb: Bad offset %x\n", (int)offset); 418e69954b9Spbrook return 0; 419e69954b9Spbrook } 420e69954b9Spbrook 421a8170e5eSAvi Kivity static uint32_t gic_dist_readw(void *opaque, hwaddr offset) 422e69954b9Spbrook { 423e69954b9Spbrook uint32_t val; 424e69954b9Spbrook val = gic_dist_readb(opaque, offset); 425e69954b9Spbrook val |= gic_dist_readb(opaque, offset + 1) << 8; 426e69954b9Spbrook return val; 427e69954b9Spbrook } 428e69954b9Spbrook 429a8170e5eSAvi Kivity static uint32_t gic_dist_readl(void *opaque, hwaddr offset) 430e69954b9Spbrook { 431e69954b9Spbrook uint32_t val; 432e69954b9Spbrook val = gic_dist_readw(opaque, offset); 433e69954b9Spbrook val |= gic_dist_readw(opaque, offset + 2) << 16; 434e69954b9Spbrook return val; 435e69954b9Spbrook } 436e69954b9Spbrook 437a8170e5eSAvi Kivity static void gic_dist_writeb(void *opaque, hwaddr offset, 438e69954b9Spbrook uint32_t value) 439e69954b9Spbrook { 440fae15286SPeter Maydell GICState *s = (GICState *)opaque; 441e69954b9Spbrook int irq; 442e69954b9Spbrook int i; 4439ee6e8bbSpbrook int cpu; 444e69954b9Spbrook 445926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 446e69954b9Spbrook if (offset < 0x100) { 447e69954b9Spbrook if (offset == 0) { 448e69954b9Spbrook s->enabled = (value & 1); 449e69954b9Spbrook DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis"); 450e69954b9Spbrook } else if (offset < 4) { 451e69954b9Spbrook /* ignored. */ 452b79f2265SRob Herring } else if (offset >= 0x80) { 453b79f2265SRob Herring /* Interrupt Security Registers, RAZ/WI */ 454e69954b9Spbrook } else { 455e69954b9Spbrook goto bad_reg; 456e69954b9Spbrook } 457e69954b9Spbrook } else if (offset < 0x180) { 458e69954b9Spbrook /* Interrupt Set Enable. */ 4599ee6e8bbSpbrook irq = (offset - 0x100) * 8 + GIC_BASE_IRQ; 460a32134aaSMark Langsdorf if (irq >= s->num_irq) 461e69954b9Spbrook goto bad_reg; 46241ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 4639ee6e8bbSpbrook value = 0xff; 46441ab7b55SChristoffer Dall } 46541ab7b55SChristoffer Dall 466e69954b9Spbrook for (i = 0; i < 8; i++) { 467e69954b9Spbrook if (value & (1 << i)) { 468f47b48fbSDaniel Sangorrin int mask = 469f47b48fbSDaniel Sangorrin (irq < GIC_INTERNAL) ? (1 << cpu) : GIC_TARGET(irq + i); 47069253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 47141bf234dSRabin Vincent 47241bf234dSRabin Vincent if (!GIC_TEST_ENABLED(irq + i, cm)) { 473e69954b9Spbrook DPRINTF("Enabled IRQ %d\n", irq + i); 47441bf234dSRabin Vincent } 47541bf234dSRabin Vincent GIC_SET_ENABLED(irq + i, cm); 476e69954b9Spbrook /* If a raised level triggered IRQ enabled then mark 477e69954b9Spbrook is as pending. */ 4789ee6e8bbSpbrook if (GIC_TEST_LEVEL(irq + i, mask) 47904050c5cSChristoffer Dall && !GIC_TEST_EDGE_TRIGGER(irq + i)) { 4809ee6e8bbSpbrook DPRINTF("Set %d pending mask %x\n", irq + i, mask); 4819ee6e8bbSpbrook GIC_SET_PENDING(irq + i, mask); 4829ee6e8bbSpbrook } 483e69954b9Spbrook } 484e69954b9Spbrook } 485e69954b9Spbrook } else if (offset < 0x200) { 486e69954b9Spbrook /* Interrupt Clear Enable. */ 4879ee6e8bbSpbrook irq = (offset - 0x180) * 8 + GIC_BASE_IRQ; 488a32134aaSMark Langsdorf if (irq >= s->num_irq) 489e69954b9Spbrook goto bad_reg; 49041ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 4919ee6e8bbSpbrook value = 0; 49241ab7b55SChristoffer Dall } 49341ab7b55SChristoffer Dall 494e69954b9Spbrook for (i = 0; i < 8; i++) { 495e69954b9Spbrook if (value & (1 << i)) { 49669253800SRusty Russell int cm = (irq < GIC_INTERNAL) ? (1 << cpu) : ALL_CPU_MASK; 49741bf234dSRabin Vincent 49841bf234dSRabin Vincent if (GIC_TEST_ENABLED(irq + i, cm)) { 499e69954b9Spbrook DPRINTF("Disabled IRQ %d\n", irq + i); 50041bf234dSRabin Vincent } 50141bf234dSRabin Vincent GIC_CLEAR_ENABLED(irq + i, cm); 502e69954b9Spbrook } 503e69954b9Spbrook } 504e69954b9Spbrook } else if (offset < 0x280) { 505e69954b9Spbrook /* Interrupt Set Pending. */ 5069ee6e8bbSpbrook irq = (offset - 0x200) * 8 + GIC_BASE_IRQ; 507a32134aaSMark Langsdorf if (irq >= s->num_irq) 508e69954b9Spbrook goto bad_reg; 50941ab7b55SChristoffer Dall if (irq < GIC_NR_SGIS) { 5105b0adce1SChristoffer Dall value = 0; 51141ab7b55SChristoffer Dall } 5129ee6e8bbSpbrook 513e69954b9Spbrook for (i = 0; i < 8; i++) { 514e69954b9Spbrook if (value & (1 << i)) { 515f47b48fbSDaniel Sangorrin GIC_SET_PENDING(irq + i, GIC_TARGET(irq + i)); 516e69954b9Spbrook } 517e69954b9Spbrook } 518e69954b9Spbrook } else if (offset < 0x300) { 519e69954b9Spbrook /* Interrupt Clear Pending. */ 5209ee6e8bbSpbrook irq = (offset - 0x280) * 8 + GIC_BASE_IRQ; 521a32134aaSMark Langsdorf if (irq >= s->num_irq) 522e69954b9Spbrook goto bad_reg; 5235b0adce1SChristoffer Dall if (irq < GIC_NR_SGIS) { 5245b0adce1SChristoffer Dall value = 0; 5255b0adce1SChristoffer Dall } 5265b0adce1SChristoffer Dall 527e69954b9Spbrook for (i = 0; i < 8; i++) { 5289ee6e8bbSpbrook /* ??? This currently clears the pending bit for all CPUs, even 5299ee6e8bbSpbrook for per-CPU interrupts. It's unclear whether this is the 5309ee6e8bbSpbrook corect behavior. */ 531e69954b9Spbrook if (value & (1 << i)) { 5329ee6e8bbSpbrook GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK); 533e69954b9Spbrook } 534e69954b9Spbrook } 535e69954b9Spbrook } else if (offset < 0x400) { 536e69954b9Spbrook /* Interrupt Active. */ 537e69954b9Spbrook goto bad_reg; 538e69954b9Spbrook } else if (offset < 0x800) { 539e69954b9Spbrook /* Interrupt Priority. */ 5409ee6e8bbSpbrook irq = (offset - 0x400) + GIC_BASE_IRQ; 541a32134aaSMark Langsdorf if (irq >= s->num_irq) 542e69954b9Spbrook goto bad_reg; 5439df90ad0SChristoffer Dall gic_set_priority(s, cpu, irq, value); 544e69954b9Spbrook } else if (offset < 0xc00) { 5456b9680bbSPeter Maydell /* Interrupt CPU Target. RAZ/WI on uniprocessor GICs, with the 5466b9680bbSPeter Maydell * annoying exception of the 11MPCore's GIC. 5476b9680bbSPeter Maydell */ 5486b9680bbSPeter Maydell if (s->num_cpu != 1 || s->revision == REV_11MPCORE) { 5499ee6e8bbSpbrook irq = (offset - 0x800) + GIC_BASE_IRQ; 5506b9680bbSPeter Maydell if (irq >= s->num_irq) { 551e69954b9Spbrook goto bad_reg; 5526b9680bbSPeter Maydell } 5536b9680bbSPeter Maydell if (irq < 29) { 5549ee6e8bbSpbrook value = 0; 5556b9680bbSPeter Maydell } else if (irq < GIC_INTERNAL) { 5569ee6e8bbSpbrook value = ALL_CPU_MASK; 5576b9680bbSPeter Maydell } 5589ee6e8bbSpbrook s->irq_target[irq] = value & ALL_CPU_MASK; 5596b9680bbSPeter Maydell } 560e69954b9Spbrook } else if (offset < 0xf00) { 561e69954b9Spbrook /* Interrupt Configuration. */ 5629ee6e8bbSpbrook irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ; 563a32134aaSMark Langsdorf if (irq >= s->num_irq) 564e69954b9Spbrook goto bad_reg; 565de7a900fSAdam Lackorzynski if (irq < GIC_NR_SGIS) 5669ee6e8bbSpbrook value |= 0xaa; 567e69954b9Spbrook for (i = 0; i < 4; i++) { 56824b790dfSAdam Lackorzynski if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 569e69954b9Spbrook if (value & (1 << (i * 2))) { 570e69954b9Spbrook GIC_SET_MODEL(irq + i); 571e69954b9Spbrook } else { 572e69954b9Spbrook GIC_CLEAR_MODEL(irq + i); 573e69954b9Spbrook } 57424b790dfSAdam Lackorzynski } 575e69954b9Spbrook if (value & (2 << (i * 2))) { 57604050c5cSChristoffer Dall GIC_SET_EDGE_TRIGGER(irq + i); 577e69954b9Spbrook } else { 57804050c5cSChristoffer Dall GIC_CLEAR_EDGE_TRIGGER(irq + i); 579e69954b9Spbrook } 580e69954b9Spbrook } 58140d22500SChristoffer Dall } else if (offset < 0xf10) { 5829ee6e8bbSpbrook /* 0xf00 is only handled for 32-bit writes. */ 583e69954b9Spbrook goto bad_reg; 58440d22500SChristoffer Dall } else if (offset < 0xf20) { 58540d22500SChristoffer Dall /* GICD_CPENDSGIRn */ 58640d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 58740d22500SChristoffer Dall goto bad_reg; 58840d22500SChristoffer Dall } 58940d22500SChristoffer Dall irq = (offset - 0xf10); 59040d22500SChristoffer Dall 59140d22500SChristoffer Dall s->sgi_pending[irq][cpu] &= ~value; 59240d22500SChristoffer Dall if (s->sgi_pending[irq][cpu] == 0) { 59340d22500SChristoffer Dall GIC_CLEAR_PENDING(irq, 1 << cpu); 59440d22500SChristoffer Dall } 59540d22500SChristoffer Dall } else if (offset < 0xf30) { 59640d22500SChristoffer Dall /* GICD_SPENDSGIRn */ 59740d22500SChristoffer Dall if (s->revision == REV_11MPCORE || s->revision == REV_NVIC) { 59840d22500SChristoffer Dall goto bad_reg; 59940d22500SChristoffer Dall } 60040d22500SChristoffer Dall irq = (offset - 0xf20); 60140d22500SChristoffer Dall 60240d22500SChristoffer Dall GIC_SET_PENDING(irq, 1 << cpu); 60340d22500SChristoffer Dall s->sgi_pending[irq][cpu] |= value; 60440d22500SChristoffer Dall } else { 60540d22500SChristoffer Dall goto bad_reg; 606e69954b9Spbrook } 607e69954b9Spbrook gic_update(s); 608e69954b9Spbrook return; 609e69954b9Spbrook bad_reg: 6108c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 6118c8dc39fSPeter Maydell "gic_dist_writeb: Bad offset %x\n", (int)offset); 612e69954b9Spbrook } 613e69954b9Spbrook 614a8170e5eSAvi Kivity static void gic_dist_writew(void *opaque, hwaddr offset, 615e69954b9Spbrook uint32_t value) 616e69954b9Spbrook { 617e69954b9Spbrook gic_dist_writeb(opaque, offset, value & 0xff); 618e69954b9Spbrook gic_dist_writeb(opaque, offset + 1, value >> 8); 619e69954b9Spbrook } 620e69954b9Spbrook 621a8170e5eSAvi Kivity static void gic_dist_writel(void *opaque, hwaddr offset, 622e69954b9Spbrook uint32_t value) 623e69954b9Spbrook { 624fae15286SPeter Maydell GICState *s = (GICState *)opaque; 6258da3ff18Spbrook if (offset == 0xf00) { 6269ee6e8bbSpbrook int cpu; 6279ee6e8bbSpbrook int irq; 6289ee6e8bbSpbrook int mask; 62940d22500SChristoffer Dall int target_cpu; 6309ee6e8bbSpbrook 631926c4affSPeter Maydell cpu = gic_get_current_cpu(s); 6329ee6e8bbSpbrook irq = value & 0x3ff; 6339ee6e8bbSpbrook switch ((value >> 24) & 3) { 6349ee6e8bbSpbrook case 0: 6359ee6e8bbSpbrook mask = (value >> 16) & ALL_CPU_MASK; 6369ee6e8bbSpbrook break; 6379ee6e8bbSpbrook case 1: 638fa250144SAdam Lackorzynski mask = ALL_CPU_MASK ^ (1 << cpu); 6399ee6e8bbSpbrook break; 6409ee6e8bbSpbrook case 2: 641fa250144SAdam Lackorzynski mask = 1 << cpu; 6429ee6e8bbSpbrook break; 6439ee6e8bbSpbrook default: 6449ee6e8bbSpbrook DPRINTF("Bad Soft Int target filter\n"); 6459ee6e8bbSpbrook mask = ALL_CPU_MASK; 6469ee6e8bbSpbrook break; 6479ee6e8bbSpbrook } 6489ee6e8bbSpbrook GIC_SET_PENDING(irq, mask); 64940d22500SChristoffer Dall target_cpu = ctz32(mask); 65040d22500SChristoffer Dall while (target_cpu < GIC_NCPU) { 65140d22500SChristoffer Dall s->sgi_pending[irq][target_cpu] |= (1 << cpu); 65240d22500SChristoffer Dall mask &= ~(1 << target_cpu); 65340d22500SChristoffer Dall target_cpu = ctz32(mask); 65440d22500SChristoffer Dall } 6559ee6e8bbSpbrook gic_update(s); 6569ee6e8bbSpbrook return; 6579ee6e8bbSpbrook } 658e69954b9Spbrook gic_dist_writew(opaque, offset, value & 0xffff); 659e69954b9Spbrook gic_dist_writew(opaque, offset + 2, value >> 16); 660e69954b9Spbrook } 661e69954b9Spbrook 662755c0802SAvi Kivity static const MemoryRegionOps gic_dist_ops = { 663755c0802SAvi Kivity .old_mmio = { 664755c0802SAvi Kivity .read = { gic_dist_readb, gic_dist_readw, gic_dist_readl, }, 665755c0802SAvi Kivity .write = { gic_dist_writeb, gic_dist_writew, gic_dist_writel, }, 666755c0802SAvi Kivity }, 667755c0802SAvi Kivity .endianness = DEVICE_NATIVE_ENDIAN, 668e69954b9Spbrook }; 669e69954b9Spbrook 670fae15286SPeter Maydell static uint32_t gic_cpu_read(GICState *s, int cpu, int offset) 671e69954b9Spbrook { 672e69954b9Spbrook switch (offset) { 673e69954b9Spbrook case 0x00: /* Control */ 6749ee6e8bbSpbrook return s->cpu_enabled[cpu]; 675e69954b9Spbrook case 0x04: /* Priority mask */ 6769ee6e8bbSpbrook return s->priority_mask[cpu]; 677e69954b9Spbrook case 0x08: /* Binary Point */ 678aa7d461aSChristoffer Dall return s->bpr[cpu]; 679e69954b9Spbrook case 0x0c: /* Acknowledge */ 6809ee6e8bbSpbrook return gic_acknowledge_irq(s, cpu); 68166a0a2cbSDong Xu Wang case 0x14: /* Running Priority */ 6829ee6e8bbSpbrook return s->running_priority[cpu]; 683e69954b9Spbrook case 0x18: /* Highest Pending Interrupt */ 6849ee6e8bbSpbrook return s->current_pending[cpu]; 685aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 686aa7d461aSChristoffer Dall return s->abpr[cpu]; 687a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 688a9d477c4SChristoffer Dall return s->apr[(offset - 0xd0) / 4][cpu]; 689e69954b9Spbrook default: 6908c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 6918c8dc39fSPeter Maydell "gic_cpu_read: Bad offset %x\n", (int)offset); 692e69954b9Spbrook return 0; 693e69954b9Spbrook } 694e69954b9Spbrook } 695e69954b9Spbrook 696fae15286SPeter Maydell static void gic_cpu_write(GICState *s, int cpu, int offset, uint32_t value) 697e69954b9Spbrook { 698e69954b9Spbrook switch (offset) { 699e69954b9Spbrook case 0x00: /* Control */ 7009ee6e8bbSpbrook s->cpu_enabled[cpu] = (value & 1); 7019ab1b605SEvgeny Voevodin DPRINTF("CPU %d %sabled\n", cpu, s->cpu_enabled[cpu] ? "En" : "Dis"); 702e69954b9Spbrook break; 703e69954b9Spbrook case 0x04: /* Priority mask */ 7049ee6e8bbSpbrook s->priority_mask[cpu] = (value & 0xff); 705e69954b9Spbrook break; 706e69954b9Spbrook case 0x08: /* Binary Point */ 707aa7d461aSChristoffer Dall s->bpr[cpu] = (value & 0x7); 708e69954b9Spbrook break; 709e69954b9Spbrook case 0x10: /* End Of Interrupt */ 710e7ae771fSStefan Weil gic_complete_irq(s, cpu, value & 0x3ff); 711e7ae771fSStefan Weil return; 712aa7d461aSChristoffer Dall case 0x1c: /* Aliased Binary Point */ 713aa7d461aSChristoffer Dall if (s->revision >= 2) { 714aa7d461aSChristoffer Dall s->abpr[cpu] = (value & 0x7); 715aa7d461aSChristoffer Dall } 716aa7d461aSChristoffer Dall break; 717a9d477c4SChristoffer Dall case 0xd0: case 0xd4: case 0xd8: case 0xdc: 718a9d477c4SChristoffer Dall qemu_log_mask(LOG_UNIMP, "Writing APR not implemented\n"); 719a9d477c4SChristoffer Dall break; 720e69954b9Spbrook default: 7218c8dc39fSPeter Maydell qemu_log_mask(LOG_GUEST_ERROR, 7228c8dc39fSPeter Maydell "gic_cpu_write: Bad offset %x\n", (int)offset); 723e69954b9Spbrook return; 724e69954b9Spbrook } 725e69954b9Spbrook gic_update(s); 726e69954b9Spbrook } 727e2c56465SPeter Maydell 728e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for the current CPU */ 729a8170e5eSAvi Kivity static uint64_t gic_thiscpu_read(void *opaque, hwaddr addr, 730e2c56465SPeter Maydell unsigned size) 731e2c56465SPeter Maydell { 732fae15286SPeter Maydell GICState *s = (GICState *)opaque; 733926c4affSPeter Maydell return gic_cpu_read(s, gic_get_current_cpu(s), addr); 734e2c56465SPeter Maydell } 735e2c56465SPeter Maydell 736a8170e5eSAvi Kivity static void gic_thiscpu_write(void *opaque, hwaddr addr, 737e2c56465SPeter Maydell uint64_t value, unsigned size) 738e2c56465SPeter Maydell { 739fae15286SPeter Maydell GICState *s = (GICState *)opaque; 740926c4affSPeter Maydell gic_cpu_write(s, gic_get_current_cpu(s), addr, value); 741e2c56465SPeter Maydell } 742e2c56465SPeter Maydell 743e2c56465SPeter Maydell /* Wrappers to read/write the GIC CPU interface for a specific CPU. 744fae15286SPeter Maydell * These just decode the opaque pointer into GICState* + cpu id. 745e2c56465SPeter Maydell */ 746a8170e5eSAvi Kivity static uint64_t gic_do_cpu_read(void *opaque, hwaddr addr, 747e2c56465SPeter Maydell unsigned size) 748e2c56465SPeter Maydell { 749fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 750fae15286SPeter Maydell GICState *s = *backref; 751e2c56465SPeter Maydell int id = (backref - s->backref); 7520e4a398aSPeter Maydell return gic_cpu_read(s, id, addr); 753e2c56465SPeter Maydell } 754e2c56465SPeter Maydell 755a8170e5eSAvi Kivity static void gic_do_cpu_write(void *opaque, hwaddr addr, 756e2c56465SPeter Maydell uint64_t value, unsigned size) 757e2c56465SPeter Maydell { 758fae15286SPeter Maydell GICState **backref = (GICState **)opaque; 759fae15286SPeter Maydell GICState *s = *backref; 760e2c56465SPeter Maydell int id = (backref - s->backref); 7610e4a398aSPeter Maydell gic_cpu_write(s, id, addr, value); 762e2c56465SPeter Maydell } 763e2c56465SPeter Maydell 764e2c56465SPeter Maydell static const MemoryRegionOps gic_thiscpu_ops = { 765e2c56465SPeter Maydell .read = gic_thiscpu_read, 766e2c56465SPeter Maydell .write = gic_thiscpu_write, 767e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 768e2c56465SPeter Maydell }; 769e2c56465SPeter Maydell 770e2c56465SPeter Maydell static const MemoryRegionOps gic_cpu_ops = { 771e2c56465SPeter Maydell .read = gic_do_cpu_read, 772e2c56465SPeter Maydell .write = gic_do_cpu_write, 773e2c56465SPeter Maydell .endianness = DEVICE_NATIVE_ENDIAN, 774e2c56465SPeter Maydell }; 775e69954b9Spbrook 7767b95a508SKONRAD Frederic void gic_init_irqs_and_distributor(GICState *s) 777e69954b9Spbrook { 778285b4432SAndreas Färber SysBusDevice *sbd = SYS_BUS_DEVICE(s); 7799ee6e8bbSpbrook int i; 780e69954b9Spbrook 781544d1afaSPeter Maydell i = s->num_irq - GIC_INTERNAL; 782544d1afaSPeter Maydell /* For the GIC, also expose incoming GPIO lines for PPIs for each CPU. 783544d1afaSPeter Maydell * GPIO array layout is thus: 784544d1afaSPeter Maydell * [0..N-1] SPIs 785544d1afaSPeter Maydell * [N..N+31] PPIs for CPU 0 786544d1afaSPeter Maydell * [N+32..N+63] PPIs for CPU 1 787544d1afaSPeter Maydell * ... 788544d1afaSPeter Maydell */ 78984e4fccbSPeter Maydell if (s->revision != REV_NVIC) { 790c48c6522SPeter Maydell i += (GIC_INTERNAL * s->num_cpu); 79184e4fccbSPeter Maydell } 792285b4432SAndreas Färber qdev_init_gpio_in(DEVICE(s), gic_set_irq, i); 793c988bfadSPaul Brook for (i = 0; i < NUM_CPU(s); i++) { 794285b4432SAndreas Färber sysbus_init_irq(sbd, &s->parent_irq[i]); 7959ee6e8bbSpbrook } 79644f55296SFabian Aggeler for (i = 0; i < NUM_CPU(s); i++) { 79744f55296SFabian Aggeler sysbus_init_irq(sbd, &s->parent_fiq[i]); 79844f55296SFabian Aggeler } 7991437c94bSPaolo Bonzini memory_region_init_io(&s->iomem, OBJECT(s), &gic_dist_ops, s, 8001437c94bSPaolo Bonzini "gic_dist", 0x1000); 8012b518c56SPeter Maydell } 8022b518c56SPeter Maydell 80353111180SPeter Maydell static void arm_gic_realize(DeviceState *dev, Error **errp) 8042b518c56SPeter Maydell { 80553111180SPeter Maydell /* Device instance realize function for the GIC sysbus device */ 8062b518c56SPeter Maydell int i; 80753111180SPeter Maydell GICState *s = ARM_GIC(dev); 80853111180SPeter Maydell SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 8091e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_GET_CLASS(s); 8100175ba10SMarkus Armbruster Error *local_err = NULL; 8111e8cae4dSPeter Maydell 8120175ba10SMarkus Armbruster agc->parent_realize(dev, &local_err); 8130175ba10SMarkus Armbruster if (local_err) { 8140175ba10SMarkus Armbruster error_propagate(errp, local_err); 81553111180SPeter Maydell return; 81653111180SPeter Maydell } 8171e8cae4dSPeter Maydell 8187b95a508SKONRAD Frederic gic_init_irqs_and_distributor(s); 8192b518c56SPeter Maydell 820e2c56465SPeter Maydell /* Memory regions for the CPU interfaces (NVIC doesn't have these): 821e2c56465SPeter Maydell * a region for "CPU interface for this core", then a region for 822e2c56465SPeter Maydell * "CPU interface for core 0", "for core 1", ... 823e2c56465SPeter Maydell * NB that the memory region size of 0x100 applies for the 11MPCore 824e2c56465SPeter Maydell * and also cores following the GIC v1 spec (ie A9). 825e2c56465SPeter Maydell * GIC v2 defines a larger memory region (0x1000) so this will need 826e2c56465SPeter Maydell * to be extended when we implement A15. 827e2c56465SPeter Maydell */ 8281437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[0], OBJECT(s), &gic_thiscpu_ops, s, 829e2c56465SPeter Maydell "gic_cpu", 0x100); 830e2c56465SPeter Maydell for (i = 0; i < NUM_CPU(s); i++) { 831e2c56465SPeter Maydell s->backref[i] = s; 8321437c94bSPaolo Bonzini memory_region_init_io(&s->cpuiomem[i+1], OBJECT(s), &gic_cpu_ops, 8331437c94bSPaolo Bonzini &s->backref[i], "gic_cpu", 0x100); 834e2c56465SPeter Maydell } 835496dbcd1SPeter Maydell /* Distributor */ 83653111180SPeter Maydell sysbus_init_mmio(sbd, &s->iomem); 837496dbcd1SPeter Maydell /* cpu interfaces (one for "current cpu" plus one per cpu) */ 838496dbcd1SPeter Maydell for (i = 0; i <= NUM_CPU(s); i++) { 83953111180SPeter Maydell sysbus_init_mmio(sbd, &s->cpuiomem[i]); 840496dbcd1SPeter Maydell } 841496dbcd1SPeter Maydell } 842496dbcd1SPeter Maydell 843496dbcd1SPeter Maydell static void arm_gic_class_init(ObjectClass *klass, void *data) 844496dbcd1SPeter Maydell { 845496dbcd1SPeter Maydell DeviceClass *dc = DEVICE_CLASS(klass); 8461e8cae4dSPeter Maydell ARMGICClass *agc = ARM_GIC_CLASS(klass); 84753111180SPeter Maydell 84853111180SPeter Maydell agc->parent_realize = dc->realize; 84953111180SPeter Maydell dc->realize = arm_gic_realize; 850496dbcd1SPeter Maydell } 851496dbcd1SPeter Maydell 8528c43a6f0SAndreas Färber static const TypeInfo arm_gic_info = { 8531e8cae4dSPeter Maydell .name = TYPE_ARM_GIC, 8541e8cae4dSPeter Maydell .parent = TYPE_ARM_GIC_COMMON, 855fae15286SPeter Maydell .instance_size = sizeof(GICState), 856496dbcd1SPeter Maydell .class_init = arm_gic_class_init, 857998a74bcSPeter Maydell .class_size = sizeof(ARMGICClass), 858496dbcd1SPeter Maydell }; 859496dbcd1SPeter Maydell 860496dbcd1SPeter Maydell static void arm_gic_register_types(void) 861496dbcd1SPeter Maydell { 862496dbcd1SPeter Maydell type_register_static(&arm_gic_info); 863496dbcd1SPeter Maydell } 864496dbcd1SPeter Maydell 865496dbcd1SPeter Maydell type_init(arm_gic_register_types) 866