Signed-off-by: Sergey Kambalin
---
hw/arm/bcm2838.c | 167 ++-
hw/arm/trace-events | 3 +
include/hw/arm/bcm2838.h | 2 +
include/hw/arm/bcm2838_peripherals.h | 37 ++
4 files changed, 207 insertions(+), 2 deletions(-)
diff --git a/hw/arm/bcm2838.c b/hw/arm/bcm2838.c
index 05281e247f..332e906a84 100644
--- a/hw/arm/bcm2838.c
+++ b/hw/arm/bcm2838.c
@@ -14,8 +14,36 @@
#include "hw/arm/bcm2838.h"
#include "trace.h"
+#define GIC400_MAINTENANCE_IRQ 9
+#define GIC400_TIMER_NS_EL2_IRQ 10
+#define GIC400_TIMER_VIRT_IRQ 11
+#define GIC400_LEGACY_FIQ 12
+#define GIC400_TIMER_S_EL1_IRQ 13
+#define GIC400_TIMER_NS_EL1_IRQ 14
+#define GIC400_LEGACY_IRQ 15
+
+/* Number of external interrupt lines to configure the GIC with */
+#define GIC_NUM_IRQS192
+
+#define PPI(cpu, irq) (GIC_NUM_IRQS + (cpu) * GIC_INTERNAL + GIC_NR_SGIS + irq)
+
+#define GIC_BASE_OFS0x
+#define GIC_DIST_OFS0x1000
+#define GIC_CPU_OFS 0x2000
+#define GIC_VIFACE_THIS_OFS 0x4000
+#define GIC_VIFACE_OTHER_OFS(cpu) (0x5000 + (cpu) * 0x200)
+#define GIC_VCPU_OFS0x6000
+
#define VIRTUAL_PMU_IRQ 7
+static void bcm2838_gic_set_irq(void *opaque, int irq, int level)
+{
+BCM2838State *s = (BCM2838State *)opaque;
+
+trace_bcm2838_gic_set_irq(irq, level);
+qemu_set_irq(qdev_get_gpio_in(DEVICE(&s->gic), irq), level);
+}
+
static void bcm2838_init(Object *obj)
{
BCM2838State *s = BCM2838(obj);
@@ -28,11 +56,12 @@ static void bcm2838_init(Object *obj)
"vcram-size");
object_property_add_alias(obj, "command-line", OBJECT(&s->peripherals),
"command-line");
+
+object_initialize_child(obj, "gic", &s->gic, TYPE_ARM_GIC);
}
static void bcm2838_realize(DeviceState *dev, Error **errp)
{
-int n;
BCM2838State *s = BCM2838(dev);
BCM283XBaseState *s_base = BCM283X_BASE(dev);
BCM283XBaseClass *bc_base = BCM283X_BASE_GET_CLASS(dev);
@@ -40,6 +69,8 @@ static void bcm2838_realize(DeviceState *dev, Error **errp)
BCMSocPeripheralBaseState *ps_base =
BCM_SOC_PERIPHERALS_BASE(&s->peripherals);
+DeviceState *gicdev = NULL;
+
if (!bcm283x_common_realize(dev, ps_base, errp)) {
return;
}
@@ -52,11 +83,15 @@ static void bcm2838_realize(DeviceState *dev, Error **errp)
sysbus_mmio_map(SYS_BUS_DEVICE(&s_base->control), 0, bc_base->ctrl_base);
/* Create cores */
-for (n = 0; n < bc_base->core_count; n++) {
+for (int n = 0; n < bc_base->core_count; n++) {
object_property_set_int(OBJECT(&s_base->cpu[n].core), "mp-affinity",
(bc_base->clusterid << 8) | n, &error_abort);
+/* set periphbase/CBAR value for CPU-local registers */
+object_property_set_int(OBJECT(&s_base->cpu[n].core), "reset-cbar",
+bc_base->peri_base, &error_abort);
+
/* start powered off if not enabled */
object_property_set_bool(OBJECT(&s_base->cpu[n].core),
"start-powered-off",
@@ -66,6 +101,134 @@ static void bcm2838_realize(DeviceState *dev, Error **errp)
return;
}
}
+
+if (!object_property_set_uint(OBJECT(&s->gic), "revision", 2, errp)) {
+return;
+}
+
+if (!object_property_set_uint(OBJECT(&s->gic), "num-cpu", BCM283X_NCPUS,
+ errp)) {
+return;
+}
+
+if (!object_property_set_uint(OBJECT(&s->gic), "num-irq",
+ GIC_NUM_IRQS + GIC_INTERNAL, errp)) {
+return;
+}
+
+if (!object_property_set_bool(OBJECT(&s->gic),
+ "has-virtualization-extensions", true,
+ errp)) {
+return;
+}
+
+if (!sysbus_realize(SYS_BUS_DEVICE(&s->gic), errp)) {
+return;
+}
+
+sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 0,
+bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_DIST_OFS);
+sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 1,
+bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_CPU_OFS);
+sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 2,
+bc_base->ctrl_base + BCM2838_GIC_BASE +
GIC_VIFACE_THIS_OFS);
+sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 3,
+bc_base->ctrl_base + BCM2838_GIC_BASE + GIC_VCPU_OFS);
+
+for (int n = 0; n < BCM283X_NCPUS; n++) {
+sysbus_mmio_map(SYS_BUS_DEVICE(&s->gic), 4 + n,
+bc_base->ctrl_base + BCM2838_GIC_BASE
++ GIC_VIFACE_OTHER_OFS(n));
+}
+
+gicdev = DEVICE(&s->gic);
+
+for (int n = 0; n < BCM283X_NCPUS; n++) {
+DeviceState *cpudev = DEVICE(&s_base->cpu[n]);
+
+/* Connect the GICv2 outputs to the CPU */
+