[PATCH v2 6/9] aspeed/intc: Add AST2700 support

Jamin Lin via posted 9 patches 8 months, 3 weeks ago
Only 4 patches received!
There is a newer version of this series
[PATCH v2 6/9] aspeed/intc: Add AST2700 support
Posted by Jamin Lin via 8 months, 3 weeks ago
AST2700 interrupt controller(INTC) provides hardware interrupt interfaces
to interrupt of processors PSP, SSP and TSP. In INTC, each interrupt of
INT 128 to INT136 combines 32 interrupts.

Introduce a new aspeed_intc class with instance_init and realize handlers.

QEMU supports ARM Generic Interrupt Controller, version 3(GICv3)
but not support Shared Peripheral Interrupt (SPI), yet.
This patch added work around to set GICINT132[18] which was BMC UART interrupt
if it received GICINT132, so users are able to type any key from keyboard to
trigger GICINT132 interrupt until AST2700 boot into login prompt.
It is a temporary solution.

Signed-off-by: Troy Lee <troy_lee@aspeedtech.com>
Signed-off-by: Jamin Lin <jamin_lin@aspeedtech.com>
---
 hw/intc/aspeed_intc.c        | 135 +++++++++++++++++++++++++++++++++++
 hw/intc/meson.build          |   1 +
 include/hw/intc/aspeed_vic.h |  29 ++++++++
 3 files changed, 165 insertions(+)
 create mode 100644 hw/intc/aspeed_intc.c

diff --git a/hw/intc/aspeed_intc.c b/hw/intc/aspeed_intc.c
new file mode 100644
index 0000000000..851d43363b
--- /dev/null
+++ b/hw/intc/aspeed_intc.c
@@ -0,0 +1,135 @@
+/*
+ * ASPEED INTC Controller
+ *
+ * Copyright (C) 2024 ASPEED Technology Inc.
+ *
+ * This code is licensed under the GPL version 2 or later.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/intc/aspeed_vic.h"
+#include "hw/irq.h"
+#include "migration/vmstate.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "qemu/module.h"
+#include "hw/intc/arm_gicv3.h"
+#include "trace.h"
+
+#define ASPEED_INTC_NR_IRQS 128
+#define ASPEED_INTC_SIZE 0x4000
+#define TO_REG(N) (N >> 2)
+
+uint64_t regs[ASPEED_INTC_SIZE];
+
+static void aspeed_intc_set_irq(void *opaque, int irq, int level)
+{
+}
+
+static uint64_t aspeed_intc_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AspeedINTCState *s = ASPEED_INTC(opaque);
+    GICv3State *gic = ARM_GICV3(s->gic);
+
+    uint64_t value = 0;
+    switch (TO_REG(offset)) {
+    case TO_REG(0x1404):
+        /* BMC UART interript is GICINT132[18] */
+        if (gic && gicv3_gicd_level_test(gic, 164)) {
+            value = BIT(18);
+        }
+        break;
+    default:
+        value = regs[TO_REG(offset)];
+        break;
+    }
+
+    return value;
+}
+
+static void aspeed_intc_write(void *opaque, hwaddr offset, uint64_t data,
+                                        unsigned size)
+{
+    AspeedINTCState *s = ASPEED_INTC(opaque);
+    GICv3State *gic = ARM_GICV3(s->gic);
+
+    switch (TO_REG(offset)) {
+    case TO_REG(0x1400):
+        regs[TO_REG(offset)] = data;
+        if (regs[TO_REG(offset)]) {
+            gicv3_gicd_enabled_set(gic, 164);
+        } else {
+            gicv3_gicd_enabled_clear(gic, 164);
+        }
+        break;
+    case TO_REG(0x1404):
+        regs[TO_REG(offset)] &= ~(data);
+        gicv3_gicd_level_clear(gic, 164);
+        break;
+    default:
+        regs[TO_REG(offset)] = data;
+        break;
+    }
+}
+
+static const MemoryRegionOps aspeed_intc_ops = {
+    .read = aspeed_intc_read,
+    .write = aspeed_intc_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+    .valid.unaligned = false,
+};
+
+static void aspeed_intc_realize(DeviceState *dev, Error **errp)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
+    AspeedINTCState *s = ASPEED_INTC(dev);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_intc_ops, s,
+                          TYPE_ASPEED_INTC, ASPEED_INTC_SIZE);
+
+    sysbus_init_mmio(sbd, &s->iomem);
+
+    qdev_init_gpio_in(dev, aspeed_intc_set_irq, ASPEED_INTC_NR_IRQS);
+    sysbus_init_irq(sbd, &s->irq);
+    sysbus_init_irq(sbd, &s->fiq);
+}
+
+static void aspeed_intc_reset(DeviceState *dev)
+{
+    AspeedINTCState *s = ASPEED_INTC(dev);
+
+    s->level = 0;
+    s->raw = 0;
+    s->select = 0;
+    s->enable = 0;
+    s->trigger = 0;
+    s->sense = 0x1F07FFF8FFFFULL;
+    s->dual_edge = 0xF800070000ULL;
+    s->event = 0x5F07FFF8FFFFULL;
+}
+
+static void aspeed_intc_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    dc->realize = aspeed_intc_realize;
+    dc->reset = aspeed_intc_reset;
+    dc->desc = "ASPEED Interrupt Controller for AST27x0";
+    dc->vmsd = NULL;
+}
+
+static const TypeInfo aspeed_intc_info = {
+    .name = TYPE_ASPEED_INTC,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(AspeedINTCState),
+    .class_init = aspeed_intc_class_init,
+};
+
+static void aspeed_intc_register_types(void)
+{
+    type_register_static(&aspeed_intc_info);
+}
+
+type_init(aspeed_intc_register_types);
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index ed355941d1..f5c574f584 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -14,6 +14,7 @@ system_ss.add(when: 'CONFIG_ARM_GICV3_TCG', if_true: files(
 ))
 system_ss.add(when: 'CONFIG_ALLWINNER_A10_PIC', if_true: files('allwinner-a10-pic.c'))
 system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_vic.c'))
+system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_intc.c'))
 system_ss.add(when: 'CONFIG_ETRAXFS', if_true: files('etraxfs_pic.c'))
 system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_gic.c', 'exynos4210_combiner.c'))
 system_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
diff --git a/include/hw/intc/aspeed_vic.h b/include/hw/intc/aspeed_vic.h
index 68d6ab997a..673a11d7fd 100644
--- a/include/hw/intc/aspeed_vic.h
+++ b/include/hw/intc/aspeed_vic.h
@@ -17,6 +17,7 @@
 #include "qom/object.h"
 
 #define TYPE_ASPEED_VIC "aspeed.vic"
+#define TYPE_ASPEED_INTC "aspeed.intc"
 OBJECT_DECLARE_SIMPLE_TYPE(AspeedVICState, ASPEED_VIC)
 
 #define ASPEED_VIC_NR_IRQS 51
@@ -46,4 +47,32 @@ struct AspeedVICState {
     uint64_t event;
 };
 
+OBJECT_DECLARE_SIMPLE_TYPE(AspeedINTCState, ASPEED_INTC)
+
+struct AspeedINTCState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    DeviceState *gic;
+
+    /*< public >*/
+    MemoryRegion iomem;
+    qemu_irq irq;
+    qemu_irq fiq;
+
+    uint64_t level;
+    uint64_t raw;
+    uint64_t select;
+    uint64_t enable;
+    uint64_t trigger;
+
+    /* 0=edge, 1=level */
+    uint64_t sense;
+
+    /* 0=single-edge, 1=dual-edge */
+    uint64_t dual_edge;
+
+    /* 0=low-sensitive/falling-edge, 1=high-sensitive/rising-edge */
+    uint64_t event;
+};
+
 #endif /* ASPEED_VIC_H */
-- 
2.25.1