18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/*
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * ARM Generic/Distributed Interrupt Controller
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Copyright (c) 2006-2007 CodeSourcery.
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * Written by Paul Brook
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project *
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * This code is licenced under the GPL.
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* This file contains implementation code for the RealView EB interrupt
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   controller, MPCore distributed interrupt controller and ARMv7-M
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   Nested Vectored Interrupt Controller.  */
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project//#define DEBUG_GIC
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef DEBUG_GIC
175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define DPRINTF(fmt, ...) \
185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerdo { printf("arm_gic: " fmt , ## __VA_ARGS__); } while (0)
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define DPRINTF(fmt, ...) do {} while(0)
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic const uint8_t gic_id[] =
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 };
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* The NVIC has 16 internal vectors.  However these are not exposed
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   through the normal GIC interface.  */
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_BASE_IRQ    32
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic const uint8_t gic_id[] =
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_BASE_IRQ    0
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define FROM_SYSBUSGIC(type, dev) \
365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DO_UPCAST(type, gic, FROM_SYSBUS(gic_state, dev))
375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct gic_irq_state
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* ??? The documentation seems to imply the enable bits are global, even
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       for per-cpu interrupts.  This seems strange.  */
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned enabled:1;
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned pending:NCPU;
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned active:NCPU;
455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned level:NCPU;
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned model:1; /* 0 = N:N, 1 = 1:N */
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned trigger:1; /* nonzero = edge triggered.  */
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} gic_irq_state;
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define ALL_CPU_MASK ((1 << NCPU) - 1)
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_ENABLED(irq) s->irq_state[irq].enabled = 1
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_ENABLED(irq) s->irq_state[irq].enabled = 0
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_ENABLED(irq) s->irq_state[irq].enabled
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_PENDING(irq, cm) s->irq_state[irq].pending |= (cm)
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_PENDING(irq, cm) s->irq_state[irq].pending &= ~(cm)
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_PENDING(irq, cm) ((s->irq_state[irq].pending & (cm)) != 0)
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_ACTIVE(irq, cm) s->irq_state[irq].active |= (cm)
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_ACTIVE(irq, cm) s->irq_state[irq].active &= ~(cm)
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_ACTIVE(irq, cm) ((s->irq_state[irq].active & (cm)) != 0)
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_MODEL(irq) s->irq_state[irq].model = 1
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_MODEL(irq) s->irq_state[irq].model = 0
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_MODEL(irq) s->irq_state[irq].model
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_LEVEL(irq, cm) s->irq_state[irq].level = (cm)
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_LEVEL(irq, cm) s->irq_state[irq].level &= ~(cm)
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_LEVEL(irq, cm) ((s->irq_state[irq].level & (cm)) != 0)
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_SET_TRIGGER(irq) s->irq_state[irq].trigger = 1
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_CLEAR_TRIGGER(irq) s->irq_state[irq].trigger = 0
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TEST_TRIGGER(irq) s->irq_state[irq].trigger
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_GET_PRIORITY(irq, cpu) \
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project  (((irq) < 32) ? s->priority1[irq][cpu] : s->priority2[(irq) - 32])
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TARGET(irq) 1
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define GIC_TARGET(irq) s->irq_target[irq]
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct gic_state
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    SysBusDevice busdev;
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_irq parent_irq[NCPU];
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int enabled;
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int cpu_enabled[NCPU];
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_irq_state irq_state[GIC_NIRQ];
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int irq_target[GIC_NIRQ];
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int priority1[32][NCPU];
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int priority2[GIC_NIRQ - 32];
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int last_active[GIC_NIRQ][NCPU];
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int priority_mask[NCPU];
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int running_irq[NCPU];
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int running_priority[NCPU];
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int current_pending[NCPU];
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int iomemtype;
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} gic_state;
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* TODO: Many places that call this routine could be optimized.  */
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Update interrupt status after enabled or pending bits have been changed.  */
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_update(gic_state *s)
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int best_irq;
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int best_prio;
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int irq;
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int level;
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int cpu;
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int cm;
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (cpu = 0; cpu < NCPU; cpu++) {
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cm = 1 << cpu;
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->current_pending[cpu] = 1023;
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!s->enabled || !s->cpu_enabled[cpu]) {
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project	    qemu_irq_lower(s->parent_irq[cpu]);
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return;
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        best_prio = 0x100;
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        best_irq = 1023;
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (irq = 0; irq < GIC_NIRQ; irq++) {
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (GIC_TEST_ENABLED(irq) && GIC_TEST_PENDING(irq, cm)) {
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    best_prio = GIC_GET_PRIORITY(irq, cpu);
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    best_irq = irq;
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                }
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        level = 0;
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (best_prio <= s->priority_mask[cpu]) {
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->current_pending[cpu] = best_irq;
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (best_prio < s->running_priority[cpu]) {
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                DPRINTF("Raised pending IRQ %d\n", best_irq);
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                level = 1;
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_set_irq(s->parent_irq[cpu], level);
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void __attribute__((unused))
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectgic_set_pending_private(gic_state *s, int cpu, int irq)
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int cm = 1 << cpu;
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (GIC_TEST_PENDING(irq, cm))
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    DPRINTF("Set %d pending cpu %d\n", irq, cpu);
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    GIC_SET_PENDING(irq, cm);
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_update(s);
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Process a change in an external IRQ input.  */
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_set_irq(void *opaque, int irq, int level)
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_state *s = (gic_state *)opaque;
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* The first external input line is internal interrupt 32.  */
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    irq += 32;
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (level == GIC_TEST_LEVEL(irq, ALL_CPU_MASK))
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (level) {
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        GIC_SET_LEVEL(irq, ALL_CPU_MASK);
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (GIC_TEST_TRIGGER(irq) || GIC_TEST_ENABLED(irq)) {
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            DPRINTF("Set %d pending mask %x\n", irq, GIC_TARGET(irq));
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            GIC_SET_PENDING(irq, GIC_TARGET(irq));
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        GIC_CLEAR_LEVEL(irq, ALL_CPU_MASK);
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_update(s);
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_set_running_irq(gic_state *s, int cpu, int irq)
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->running_irq[cpu] = irq;
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (irq == 1023) {
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->running_priority[cpu] = 0x100;
1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->running_priority[cpu] = GIC_GET_PRIORITY(irq, cpu);
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_update(s);
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t gic_acknowledge_irq(gic_state *s, int cpu)
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int new_irq;
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int cm = 1 << cpu;
1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    new_irq = s->current_pending[cpu];
1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (new_irq == 1023
1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            || GIC_GET_PRIORITY(new_irq, cpu) >= s->running_priority[cpu]) {
1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        DPRINTF("ACK no pending IRQ\n");
1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 1023;
1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->last_active[new_irq][cpu] = s->running_irq[cpu];
1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* Clear pending flags for both level and edge triggered interrupts.
1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project       Level triggered IRQs will be reasserted once they become inactive.  */
1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    GIC_CLEAR_PENDING(new_irq, GIC_TEST_MODEL(new_irq) ? ALL_CPU_MASK : cm);
2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_set_running_irq(s, cpu, new_irq);
2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    DPRINTF("ACK %d\n", new_irq);
2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return new_irq;
2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_complete_irq(gic_state * s, int cpu, int irq)
2068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int update = 0;
2088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int cm = 1 << cpu;
2098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    DPRINTF("EOI %d\n", irq);
2108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s->running_irq[cpu] == 1023)
2118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return; /* No active IRQ.  */
2128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (irq != 1023) {
2138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Mark level triggered interrupts as pending if they are still
2148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project           raised.  */
2158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (!GIC_TEST_TRIGGER(irq) && GIC_TEST_ENABLED(irq)
2168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                && GIC_TEST_LEVEL(irq, cm) && (GIC_TARGET(irq) & cm) != 0) {
2178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            DPRINTF("Set %d pending mask %x\n", irq, cm);
2188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            GIC_SET_PENDING(irq, cm);
2198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            update = 1;
2208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (irq != s->running_irq[cpu]) {
2238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Complete an IRQ that is not currently running.  */
2248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int tmp = s->running_irq[cpu];
2258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        while (s->last_active[tmp][cpu] != 1023) {
2268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (s->last_active[tmp][cpu] == irq) {
2278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                s->last_active[tmp][cpu] = s->last_active[irq][cpu];
2288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                break;
2298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
2308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            tmp = s->last_active[tmp][cpu];
2318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (update) {
2338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            gic_update(s);
2348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
2368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Complete the current running IRQ.  */
2378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        gic_set_running_irq(s, cpu, s->last_active[s->running_irq[cpu]][cpu]);
2388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
2408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
241bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic uint32_t gic_dist_readb(void *opaque, hwaddr offset)
2428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
2438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_state *s = (gic_state *)opaque;
2448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t res;
2458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int irq;
2468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
2478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int cpu;
2488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int cm;
2498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int mask;
2508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    cpu = gic_get_current_cpu();
2528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    cm = 1 << cpu;
2538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (offset < 0x100) {
2548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC
2558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (offset == 0)
2568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return s->enabled;
2578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (offset == 4)
2588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return ((GIC_NIRQ / 32) - 1) | ((NCPU - 1) << 5);
2598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (offset < 0x08)
2608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return 0;
2618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
2628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto bad_reg;
2638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0x200) {
2648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Set/Clear Enable.  */
2658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (offset < 0x180)
2668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            irq = (offset - 0x100) * 8;
2678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else
2688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            irq = (offset - 0x180) * 8;
2698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq += GIC_BASE_IRQ;
2708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
2718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
2728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        res = 0;
2738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < 8; i++) {
2748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (GIC_TEST_ENABLED(irq + i)) {
2758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                res |= (1 << i);
2768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
2778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0x300) {
2798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Set/Clear Pending.  */
2808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (offset < 0x280)
2818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            irq = (offset - 0x200) * 8;
2828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else
2838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            irq = (offset - 0x280) * 8;
2848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq += GIC_BASE_IRQ;
2858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
2868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
2878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        res = 0;
2888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        mask = (irq < 32) ?  cm : ALL_CPU_MASK;
2898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < 8; i++) {
2908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (GIC_TEST_PENDING(irq + i, mask)) {
2918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                res |= (1 << i);
2928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
2938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
2948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0x400) {
2958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Active.  */
2968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
2978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
2988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
2998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        res = 0;
3008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        mask = (irq < 32) ?  cm : ALL_CPU_MASK;
3018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < 8; i++) {
3028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (GIC_TEST_ACTIVE(irq + i, mask)) {
3038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                res |= (1 << i);
3048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
3058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0x800) {
3078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Priority.  */
3088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = (offset - 0x400) + GIC_BASE_IRQ;
3098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
3108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
3118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        res = GIC_GET_PRIORITY(irq, cpu);
3128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC
3138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0xc00) {
3148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt CPU Target.  */
3158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = (offset - 0x800) + GIC_BASE_IRQ;
3168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
3178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
3188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= 29 && irq <= 31) {
3198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            res = cm;
3208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
3218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            res = GIC_TARGET(irq);
3228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0xf00) {
3248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Configuration.  */
3258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
3268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
3278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
3288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        res = 0;
3298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < 4; i++) {
3308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (GIC_TEST_MODEL(irq + i))
3318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                res |= (1 << (i * 2));
3328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (GIC_TEST_TRIGGER(irq + i))
3338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                res |= (2 << (i * 2));
3348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
3368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0xfe0) {
3378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto bad_reg;
3388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else /* offset >= 0xfe0 */ {
3398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (offset & 3) {
3408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            res = 0;
3418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
3428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            res = gic_id[(offset - 0xfe0) >> 2];
3438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
3458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return res;
3468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectbad_reg:
3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hw_error("gic_dist_readb: Bad offset %x\n", (int)offset);
3488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
3498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
351bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic uint32_t gic_dist_readw(void *opaque, hwaddr offset)
3528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t val;
3548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    val = gic_dist_readb(opaque, offset);
3558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    val |= gic_dist_readb(opaque, offset + 1) << 8;
3568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return val;
3578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
359bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic uint32_t gic_dist_readl(void *opaque, hwaddr offset)
3608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t val;
3628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC
3638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_state *s = (gic_state *)opaque;
3648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t addr;
3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addr = offset;
3668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (addr < 0x100 || addr > 0xd00)
3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return nvic_readl(s, addr);
3688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
3698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    val = gic_dist_readw(opaque, offset);
3708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    val |= gic_dist_readw(opaque, offset + 2) << 16;
3718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return val;
3728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
3738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
374bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic void gic_dist_writeb(void *opaque, hwaddr offset,
3758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            uint32_t value)
3768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
3778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_state *s = (gic_state *)opaque;
3788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int irq;
3798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
3808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int cpu;
3818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
3828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    cpu = gic_get_current_cpu();
3838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (offset < 0x100) {
3848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC
3858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto bad_reg;
3868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
3878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (offset == 0) {
3888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->enabled = (value & 1);
3898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            DPRINTF("Distribution %sabled\n", s->enabled ? "En" : "Dis");
3908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else if (offset < 4) {
3918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* ignored.  */
3928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
3938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
3948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
3958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
3968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0x180) {
3978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Set Enable.  */
3988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
3998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
4008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
4018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq < 16)
4028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project          value = 0xff;
4038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < 8; i++) {
4048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (value & (1 << i)) {
4058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                int mask = (irq < 32) ? (1 << cpu) : GIC_TARGET(irq);
4068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (!GIC_TEST_ENABLED(irq + i))
4078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    DPRINTF("Enabled IRQ %d\n", irq + i);
4088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                GIC_SET_ENABLED(irq + i);
4098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                /* If a raised level triggered IRQ enabled then mark
4108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                   is as pending.  */
4118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (GIC_TEST_LEVEL(irq + i, mask)
4128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        && !GIC_TEST_TRIGGER(irq + i)) {
4138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    DPRINTF("Set %d pending mask %x\n", irq + i, mask);
4148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    GIC_SET_PENDING(irq + i, mask);
4158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                }
4168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
4178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0x200) {
4198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Clear Enable.  */
4208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
4218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
4228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
4238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq < 16)
4248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project          value = 0;
4258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < 8; i++) {
4268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (value & (1 << i)) {
4278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (GIC_TEST_ENABLED(irq + i))
4288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    DPRINTF("Disabled IRQ %d\n", irq + i);
4298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                GIC_CLEAR_ENABLED(irq + i);
4308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
4318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0x280) {
4338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Set Pending.  */
4348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
4358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
4368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
4378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq < 16)
4388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project          irq = 0;
4398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
4408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < 8; i++) {
4418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (value & (1 << i)) {
4428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                GIC_SET_PENDING(irq + i, GIC_TARGET(irq));
4438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
4448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0x300) {
4468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Clear Pending.  */
4478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
4488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
4498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
4508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < 8; i++) {
4518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            /* ??? This currently clears the pending bit for all CPUs, even
4528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               for per-CPU interrupts.  It's unclear whether this is the
4538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               corect behavior.  */
4548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (value & (1 << i)) {
4558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                GIC_CLEAR_PENDING(irq + i, ALL_CPU_MASK);
4568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
4578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0x400) {
4598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Active.  */
4608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto bad_reg;
4618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0x800) {
4628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Priority.  */
4638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = (offset - 0x400) + GIC_BASE_IRQ;
4648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
4658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
4668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq < 32) {
4678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->priority1[irq][cpu] = value;
4688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        } else {
4698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->priority2[irq - 32] = value;
4708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
4718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC
4728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0xc00) {
4738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt CPU Target.  */
4748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = (offset - 0x800) + GIC_BASE_IRQ;
4758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
4768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
4778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq < 29)
4788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            value = 0;
4798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else if (irq < 32)
4808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            value = ALL_CPU_MASK;
4818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->irq_target[irq] = value & ALL_CPU_MASK;
4828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else if (offset < 0xf00) {
4838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* Interrupt Configuration.  */
4848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
4858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq >= GIC_NIRQ)
4868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            goto bad_reg;
4878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (irq < 32)
4888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            value |= 0xaa;
4898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (i = 0; i < 4; i++) {
4908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (value & (1 << (i * 2))) {
4918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                GIC_SET_MODEL(irq + i);
4928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            } else {
4938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                GIC_CLEAR_MODEL(irq + i);
4948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
4958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (value & (2 << (i * 2))) {
4968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                GIC_SET_TRIGGER(irq + i);
4978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            } else {
4988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                GIC_CLEAR_TRIGGER(irq + i);
4998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
5008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
5018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
5028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
5038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* 0xf00 is only handled for 32-bit writes.  */
5048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        goto bad_reg;
5058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_update(s);
5078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return;
5088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectbad_reg:
5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hw_error("gic_dist_writeb: Bad offset %x\n", (int)offset);
5108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
512bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic void gic_dist_writew(void *opaque, hwaddr offset,
5138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            uint32_t value)
5148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_dist_writeb(opaque, offset, value & 0xff);
5168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_dist_writeb(opaque, offset + 1, value >> 8);
5178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
519bcde1092aca184dbd7860078af020de7d1e4e22fDavid 'Digit' Turnerstatic void gic_dist_writel(void *opaque, hwaddr offset,
5208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                            uint32_t value)
5218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_state *s = (gic_state *)opaque;
5238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC
5248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    uint32_t addr;
5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    addr = offset;
5268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (addr < 0x100 || (addr > 0xd00 && addr != 0xf00)) {
5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        nvic_writel(s, addr, value);
5288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
5298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (offset == 0xf00) {
5328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int cpu;
5338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int irq;
5348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int mask;
5358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        cpu = gic_get_current_cpu();
5378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        irq = value & 0x3ff;
5388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        switch ((value >> 24) & 3) {
5398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case 0:
5408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            mask = (value >> 16) & ALL_CPU_MASK;
5418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
5428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case 1:
5438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            mask = 1 << cpu;
5448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
5458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case 2:
5468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            mask = ALL_CPU_MASK ^ (1 << cpu);
5478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
5488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        default:
5498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            DPRINTF("Bad Soft Int target filter\n");
5508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            mask = ALL_CPU_MASK;
5518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
5528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
5538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        GIC_SET_PENDING(irq, mask);
5548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        gic_update(s);
5558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
5568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_dist_writew(opaque, offset, value & 0xffff);
5588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_dist_writew(opaque, offset + 2, value >> 16);
5598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUReadMemoryFunc *gic_dist_readfn[] = {
5628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   gic_dist_readb,
5638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   gic_dist_readw,
5648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   gic_dist_readl
5658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
5668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic CPUWriteMemoryFunc *gic_dist_writefn[] = {
5688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   gic_dist_writeb,
5698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   gic_dist_writew,
5708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project   gic_dist_writel
5718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project};
5728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC
5748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic uint32_t gic_cpu_read(gic_state *s, int cpu, int offset)
5758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (offset) {
5778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x00: /* Control */
5788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return s->cpu_enabled[cpu];
5798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x04: /* Priority mask */
5808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return s->priority_mask[cpu];
5818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x08: /* Binary Point */
5828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* ??? Not implemented.  */
5838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
5848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x0c: /* Acknowledge */
5858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return gic_acknowledge_irq(s, cpu);
5868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x14: /* Runing Priority */
5878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return s->running_priority[cpu];
5888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x18: /* Highest Pending Interrupt */
5898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return s->current_pending[cpu];
5908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
5915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        hw_error("gic_cpu_read: Bad offset %x\n", (int)offset);
5928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return 0;
5938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
5948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
5958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
5968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value)
5978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
5988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (offset) {
5998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x00: /* Control */
6008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->cpu_enabled[cpu] = (value & 1);
6018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        DPRINTF("CPU %sabled\n", s->cpu_enabled ? "En" : "Dis");
6028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
6038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x04: /* Priority mask */
6048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->priority_mask[cpu] = (value & 0xff);
6058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
6068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x08: /* Binary Point */
6078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* ??? Not implemented.  */
6088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        break;
6098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    case 0x10: /* End Of Interrupt */
6108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return gic_complete_irq(s, cpu, value & 0x3ff);
6118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    default:
6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        hw_error("gic_cpu_write: Bad offset %x\n", (int)offset);
6138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
6148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_update(s);
6168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
6178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
6188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_reset(gic_state *s)
6208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
6218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
6228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    memset(s->irq_state, 0, GIC_NIRQ * sizeof(gic_irq_state));
6238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0 ; i < NCPU; i++) {
6248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->priority_mask[i] = 0xf0;
6258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->current_pending[i] = 1023;
6268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->running_irq[i] = 1023;
6278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->running_priority[i] = 0x100;
6288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC
6298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* The NVIC doesn't have per-cpu interfaces, so enable by default.  */
6308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->cpu_enabled[i] = 1;
6318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
6328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->cpu_enabled[i] = 0;
6338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
6348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < 16; i++) {
6368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        GIC_SET_ENABLED(i);
6378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        GIC_SET_TRIGGER(i);
6388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifdef NVIC
6408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* The NVIC is always enabled.  */
6418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->enabled = 1;
6428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#else
6438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->enabled = 0;
6448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
6458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
6468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void gic_save(QEMUFile *f, void *opaque)
6488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
6498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_state *s = (gic_state *)opaque;
6508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
6518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int j;
6528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_put_be32(f, s->enabled);
6548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < NCPU; i++) {
6558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32(f, s->cpu_enabled[i]);
6568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC
6578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32(f, s->irq_target[i]);
6588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
6598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (j = 0; j < 32; j++)
6608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            qemu_put_be32(f, s->priority1[j][i]);
6618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (j = 0; j < GIC_NIRQ; j++)
6628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            qemu_put_be32(f, s->last_active[j][i]);
6638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32(f, s->priority_mask[i]);
6648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32(f, s->running_irq[i]);
6658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32(f, s->running_priority[i]);
6668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32(f, s->current_pending[i]);
6678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < GIC_NIRQ - 32; i++) {
6698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_be32(f, s->priority2[i]);
6708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < GIC_NIRQ; i++) {
6728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_byte(f, s->irq_state[i].enabled);
6738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_byte(f, s->irq_state[i].pending);
6748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_byte(f, s->irq_state[i].active);
6758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_byte(f, s->irq_state[i].level);
6768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_byte(f, s->irq_state[i].model);
6778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_put_byte(f, s->irq_state[i].trigger);
6788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
6798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
6808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int gic_load(QEMUFile *f, void *opaque, int version_id)
6828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
6838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_state *s = (gic_state *)opaque;
6848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
6858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int j;
6868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (version_id != 1)
6888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -EINVAL;
6898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
6908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s->enabled = qemu_get_be32(f);
6918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < NCPU; i++) {
6928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->cpu_enabled[i] = qemu_get_be32(f);
6938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#ifndef NVIC
6948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->irq_target[i] = qemu_get_be32(f);
6958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#endif
6968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (j = 0; j < 32; j++)
6978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->priority1[j][i] = qemu_get_be32(f);
6988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for (j = 0; j < GIC_NIRQ; j++)
6998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            s->last_active[j][i] = qemu_get_be32(f);
7008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->priority_mask[i] = qemu_get_be32(f);
7018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->running_irq[i] = qemu_get_be32(f);
7028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->running_priority[i] = qemu_get_be32(f);
7038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->current_pending[i] = qemu_get_be32(f);
7048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < GIC_NIRQ - 32; i++) {
7068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->priority2[i] = qemu_get_be32(f);
7078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < GIC_NIRQ; i++) {
7098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->irq_state[i].enabled = qemu_get_byte(f);
7108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->irq_state[i].pending = qemu_get_byte(f);
7118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->irq_state[i].active = qemu_get_byte(f);
7128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->irq_state[i].level = qemu_get_byte(f);
7138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->irq_state[i].model = qemu_get_byte(f);
7148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        s->irq_state[i].trigger = qemu_get_byte(f);
7158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
7188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
7198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void gic_init(gic_state *s)
7218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
7228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int i;
7238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
7258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    for (i = 0; i < NCPU; i++) {
7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
7278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->iomemtype = cpu_register_io_memory(gic_dist_readfn,
7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                          gic_dist_writefn, s);
7308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    gic_reset(s);
7315cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner    register_savevm(NULL,
7325cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    "arm_gic",
7335cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    -1,
7345cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    1,
7355cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    gic_save,
7365cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    gic_load,
7375cb5c0b8c5145dc0002b24e1421a3fa7a697475eDavid 'Digit' Turner                    s);
7388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
739