qemu-arm
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-arm] [PATCH 3/8] bcm2835_ic: add bcm2835 interrupt controller


From: Andrew Baumann
Subject: [Qemu-arm] [PATCH 3/8] bcm2835_ic: add bcm2835 interrupt controller
Date: Thu, 3 Dec 2015 22:01:22 -0800

Signed-off-by: Andrew Baumann <address@hidden>
---
 hw/intc/Makefile.objs        |   1 +
 hw/intc/bcm2835_ic.c         | 234 +++++++++++++++++++++++++++++++++++++++++++
 include/hw/intc/bcm2835_ic.h |  26 +++++
 3 files changed, 261 insertions(+)
 create mode 100644 hw/intc/bcm2835_ic.c
 create mode 100644 include/hw/intc/bcm2835_ic.h

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 004b0c2..2ad1204 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -24,6 +24,7 @@ obj-$(CONFIG_GRLIB) += grlib_irqmp.o
 obj-$(CONFIG_IOAPIC) += ioapic.o
 obj-$(CONFIG_OMAP) += omap_intc.o
 obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o
+obj-$(CONFIG_RASPI) += bcm2835_ic.o
 obj-$(CONFIG_SH4) += sh_intc.o
 obj-$(CONFIG_XICS) += xics.o
 obj-$(CONFIG_XICS_KVM) += xics_kvm.o
diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c
new file mode 100644
index 0000000..2419575
--- /dev/null
+++ b/hw/intc/bcm2835_ic.c
@@ -0,0 +1,234 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+/* Heavily based on pl190.c, copyright terms below. */
+
+/*
+ * Arm PrimeCell PL190 Vector Interrupt Controller
+ *
+ * Copyright (c) 2006 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "hw/intc/bcm2835_ic.h"
+
+#define IR_B 2
+#define IR_1 0
+#define IR_2 1
+
+/* Update interrupts.  */
+static void bcm2835_ic_update(BCM2835IcState *s)
+{
+    int set;
+    int i;
+
+    set = 0;
+    if (s->fiq_enable) {
+        set = s->level[s->fiq_select >> 5] & (1u << (s->fiq_select & 0x1f));
+    }
+    qemu_set_irq(s->fiq, set);
+
+    set = 0;
+    for (i = 0; i < 3; i++) {
+        set |= (s->level[i] & s->irq_enable[i]);
+    }
+    qemu_set_irq(s->irq, set);
+
+}
+
+static void bcm2835_ic_set_irq(void *opaque, int irq, int level)
+{
+    BCM2835IcState *s = (BCM2835IcState *)opaque;
+
+    if (irq >= 0 && irq <= 71) {
+        if (level) {
+                s->level[irq >> 5] |= 1u << (irq & 0x1f);
+        } else {
+                s->level[irq >> 5] &= ~(1u << (irq & 0x1f));
+        }
+    } else {
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_ic_set_irq: Bad irq %d\n", irq);
+    }
+
+    bcm2835_ic_update(s);
+}
+
+static const int irq_dups[] = { 7, 9, 10, 18, 19, 53, 54, 55, 56, 57, 62, -1 };
+
+static uint64_t bcm2835_ic_read(void *opaque, hwaddr offset,
+    unsigned size)
+{
+    BCM2835IcState *s = (BCM2835IcState *)opaque;
+    int i;
+    int p = 0;
+    uint32_t res = 0;
+
+    switch (offset) {
+    case 0x00:  /* IRQ basic pending */
+        /* bits 0-7 - ARM irqs */
+        res = (s->level[IR_B] & s->irq_enable[IR_B]) & 0xff;
+        for (i = 0; i < 64; i++) {
+            if (i == irq_dups[p]) {
+                /* bits 10-20 - selected GPU irqs */
+                if (s->level[i >> 5] & s->irq_enable[i >> 5]
+                    & (1u << (i & 0x1f))) {
+                    res |= (1u << (10 + p));
+                }
+                p++;
+            } else {
+                /* bits 8-9 - one or more bits set in pending registers 1-2 */
+                if (s->level[i >> 5] & s->irq_enable[i >> 5]
+                    & (1u << (i & 0x1f))) {
+                    res |= (1u << (8 + (i >> 5)));
+                }
+            }
+        }
+        break;
+    case 0x04:  /* IRQ pending 1 */
+        res = s->level[IR_1] & s->irq_enable[IR_1];
+        break;
+    case 0x08:  /* IRQ pending 2 */
+        res = s->level[IR_2] & s->irq_enable[IR_2];
+        break;
+    case 0x0C:  /* FIQ register */
+        res = (s->fiq_enable << 7) | s->fiq_select;
+        break;
+    case 0x10:  /* Interrupt enable register 1 */
+        res = s->irq_enable[IR_1];
+        break;
+    case 0x14:  /* Interrupt enable register 2 */
+        res = s->irq_enable[IR_2];
+        break;
+    case 0x18:  /* Base interrupt enable register */
+        res = s->irq_enable[IR_B];
+        break;
+    case 0x1C:  /* Interrupt disable register 1 */
+        res = ~s->irq_enable[IR_1];
+        break;
+    case 0x20:  /* Interrupt disable register 2 */
+        res = ~s->irq_enable[IR_2];
+        break;
+    case 0x24:  /* Base interrupt disable register */
+        res = ~s->irq_enable[IR_B];
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_ic_read: Bad offset %x\n", (int)offset);
+        return 0;
+    }
+
+    return res;
+}
+
+static void bcm2835_ic_write(void *opaque, hwaddr offset,
+    uint64_t val, unsigned size)
+{
+    BCM2835IcState *s = (BCM2835IcState *)opaque;
+
+    switch (offset) {
+    case 0x0C:  /* FIQ register */
+        s->fiq_select = (val & 0x7f);
+        s->fiq_enable = (val >> 7) & 0x1;
+        break;
+    case 0x10:  /* Interrupt enable register 1 */
+        s->irq_enable[IR_1] |= val;
+        break;
+    case 0x14:  /* Interrupt enable register 2 */
+        s->irq_enable[IR_2] |= val;
+        break;
+    case 0x18:  /* Base interrupt enable register */
+        s->irq_enable[IR_B] |= (val & 0xff);
+        break;
+    case 0x1C:  /* Interrupt disable register 1 */
+        s->irq_enable[IR_1] &= ~val;
+        break;
+    case 0x20:  /* Interrupt disable register 2 */
+        s->irq_enable[IR_2] &= ~val;
+        break;
+    case 0x24:  /* Base interrupt disable register */
+        s->irq_enable[IR_B] &= (~val & 0xff);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "bcm2835_ic_write: Bad offset %x\n", (int)offset);
+        return;
+    }
+    bcm2835_ic_update(s);
+}
+
+static const MemoryRegionOps bcm2835_ic_ops = {
+    .read = bcm2835_ic_read,
+    .write = bcm2835_ic_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void bcm2835_ic_reset(DeviceState *d)
+{
+    BCM2835IcState *s = BCM2835_IC(d);
+    int i;
+
+    for (i = 0; i < 3; i++) {
+        s->irq_enable[i] = 0;
+    }
+    s->fiq_enable = 0;
+    s->fiq_select = 0;
+}
+
+static void bcm2835_ic_init(Object *obj)
+{
+    BCM2835IcState *s = BCM2835_IC(obj);
+
+    memory_region_init_io(&s->iomem, obj, &bcm2835_ic_ops, s, TYPE_BCM2835_IC,
+                          0x200);
+    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
+
+    qdev_init_gpio_in(DEVICE(s), bcm2835_ic_set_irq, 72);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
+    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->fiq);
+}
+
+static void bcm2835_ic_realize(DeviceState *dev, Error **errp)
+{
+}
+
+static const VMStateDescription vmstate_bcm2835_ic = {
+    .name = TYPE_BCM2835_IC,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(level, BCM2835IcState, 3),
+        VMSTATE_UINT32_ARRAY(irq_enable, BCM2835IcState, 3),
+        VMSTATE_INT32(fiq_enable, BCM2835IcState),
+        VMSTATE_INT32(fiq_select, BCM2835IcState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void bcm2835_ic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->realize = bcm2835_ic_realize;
+    dc->reset = bcm2835_ic_reset;
+    dc->vmsd = &vmstate_bcm2835_ic;
+}
+
+static TypeInfo bcm2835_ic_info = {
+    .name          = TYPE_BCM2835_IC,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(BCM2835IcState),
+    .class_init    = bcm2835_ic_class_init,
+    .instance_init = bcm2835_ic_init,
+};
+
+static void bcm2835_ic_register_types(void)
+{
+    type_register_static(&bcm2835_ic_info);
+}
+
+type_init(bcm2835_ic_register_types)
diff --git a/include/hw/intc/bcm2835_ic.h b/include/hw/intc/bcm2835_ic.h
new file mode 100644
index 0000000..428139d
--- /dev/null
+++ b/include/hw/intc/bcm2835_ic.h
@@ -0,0 +1,26 @@
+/*
+ * Raspberry Pi emulation (c) 2012 Gregory Estrade
+ * This code is licensed under the GNU GPLv2 and later.
+ */
+
+#ifndef BCM2835_IC_H
+#define BCM2835_IC_H
+
+#include "hw/sysbus.h"
+
+#define TYPE_BCM2835_IC "bcm2835_ic"
+#define BCM2835_IC(obj) OBJECT_CHECK(BCM2835IcState, (obj), TYPE_BCM2835_IC)
+
+typedef struct BCM2835IcState {
+    SysBusDevice busdev;
+    MemoryRegion iomem;
+
+    uint32_t level[3];
+    uint32_t irq_enable[3];
+    int fiq_enable;
+    int fiq_select;
+    qemu_irq irq;
+    qemu_irq fiq;
+} BCM2835IcState;
+
+#endif
-- 
2.5.3




reply via email to

[Prev in Thread] Current Thread [Next in Thread]