[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
- [Qemu-arm] [PATCH 0/8] Raspberry Pi 2 support, Andrew Baumann, 2015/12/03
- Re: [Qemu-arm] [PATCH 0/8] Raspberry Pi 2 support, Andrew Baumann, 2015/12/03
- [Qemu-arm] [PATCH 1/8] bcm2835_sbm: add BCM2835 mailboxes, Andrew Baumann, 2015/12/04
- [Qemu-arm] [PATCH 3/8] bcm2835_ic: add bcm2835 interrupt controller,
Andrew Baumann <=
- [Qemu-arm] [PATCH 2/8] bcm2835_property: add bcm2835 property channel, Andrew Baumann, 2015/12/04
- [Qemu-arm] [PATCH 8/8] raspi: add raspberry pi 2 machine, Andrew Baumann, 2015/12/04
- [Qemu-arm] [PATCH 6/8] bcm2836_control: add bcm2836 ARM control logic, Andrew Baumann, 2015/12/04
- [Qemu-arm] [PATCH 5/8] bcm2835_peripherals: add rollup device for bcm2835 peripherals, Andrew Baumann, 2015/12/04
- [Qemu-arm] [PATCH 7/8] bcm2836: add bcm2836 soc device, Andrew Baumann, 2015/12/04
- [Qemu-arm] [PATCH 4/8] bcm2835_emmc: add bcm2835 MMC/SD controller, Andrew Baumann, 2015/12/04