Add support for GICv2 instantiation in the Versal SoC. This is in
preparation for the RPU refactoring.
Signed-off-by: Luc Michel <luc.michel@amd.com>
Reviewed-by: Francisco Iglesias <francisco.iglesias@amd.com>
---
hw/arm/xlnx-versal.c | 82 +++++++++++++++++++++++++++++++++-----------
1 file changed, 62 insertions(+), 20 deletions(-)
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c
index 1c79a3aa047..d5dbbe10a6d 100644
--- a/hw/arm/xlnx-versal.c
+++ b/hw/arm/xlnx-versal.c
@@ -43,10 +43,11 @@
#include "hw/misc/xlnx-versal-cframe-reg.h"
#include "hw/or-irq.h"
#include "hw/misc/xlnx-versal-crl.h"
#include "hw/intc/arm_gicv3_common.h"
#include "hw/intc/arm_gicv3_its_common.h"
+#include "hw/intc/arm_gic.h"
#include "hw/core/split-irq.h"
#define XLNX_VERSAL_ACPU_TYPE ARM_CPU_TYPE_NAME("cortex-a72")
#define XLNX_VERSAL_RCPU_TYPE ARM_CPU_TYPE_NAME("cortex-r5f")
#define GEM_REVISION 0x40070106
@@ -72,10 +73,11 @@ typedef struct VersalSimplePeriphMap {
typedef struct VersalGicMap {
int version;
uint64_t dist;
uint64_t redist;
+ uint64_t cpu_iface;
uint64_t its;
size_t num_irq;
bool has_its;
} VersalGicMap;
@@ -501,10 +503,14 @@ static void versal_create_gic_its(Versal *s,
DeviceState *dev;
SysBusDevice *sbd;
g_autofree char *node_pat = NULL, *node = NULL;
const char compatible[] = "arm,gic-v3-its";
+ if (map->gic.version != 3) {
+ return;
+ }
+
if (!map->gic.has_its) {
return;
}
dev = qdev_new(TYPE_ARM_GICV3_ITS);
@@ -540,49 +546,85 @@ static DeviceState *versal_create_gic(Versal *s,
int first_cpu_idx,
size_t num_cpu)
{
DeviceState *dev;
SysBusDevice *sbd;
- QList *redist_region_count;
g_autofree char *node = NULL;
g_autofree char *name = NULL;
- const char compatible[] = "arm,gic-v3";
+ const char gicv3_compat[] = "arm,gic-v3";
+ const char gicv2_compat[] = "arm,cortex-a15-gic";
+
+ switch (map->gic.version) {
+ case 2:
+ dev = qdev_new(gic_class_name());
+ break;
+
+ case 3:
+ dev = qdev_new(gicv3_class_name());
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
- dev = qdev_new(gicv3_class_name());
name = g_strdup_printf("%s-gic[*]", map->name);
object_property_add_child(OBJECT(s), name, OBJECT(dev));
sbd = SYS_BUS_DEVICE(dev);
- qdev_prop_set_uint32(dev, "revision", 3);
+ qdev_prop_set_uint32(dev, "revision", map->gic.version);
qdev_prop_set_uint32(dev, "num-cpu", num_cpu);
qdev_prop_set_uint32(dev, "num-irq", map->gic.num_irq + 32);
-
- redist_region_count = qlist_new();
- qlist_append_int(redist_region_count, num_cpu);
- qdev_prop_set_array(dev, "redist-region-count", redist_region_count);
-
qdev_prop_set_bit(dev, "has-security-extensions", true);
- qdev_prop_set_bit(dev, "has-lpi", map->gic.has_its);
- object_property_set_link(OBJECT(dev), "sysmem", OBJECT(mr), &error_abort);
qdev_prop_set_uint32(dev, "first-cpu-index", first_cpu_idx);
+ if (map->gic.version == 3) {
+ QList *redist_region_count;
+
+ redist_region_count = qlist_new();
+ qlist_append_int(redist_region_count, num_cpu);
+ qdev_prop_set_array(dev, "redist-region-count", redist_region_count);
+ qdev_prop_set_bit(dev, "has-lpi", map->gic.has_its);
+ object_property_set_link(OBJECT(dev), "sysmem", OBJECT(mr),
+ &error_abort);
+
+ }
+
sysbus_realize_and_unref(sbd, &error_fatal);
memory_region_add_subregion(mr, map->gic.dist,
sysbus_mmio_get_region(sbd, 0));
- memory_region_add_subregion(mr, map->gic.redist,
- sysbus_mmio_get_region(sbd, 1));
+
+ if (map->gic.version == 3) {
+ memory_region_add_subregion(mr, map->gic.redist,
+ sysbus_mmio_get_region(sbd, 1));
+ } else {
+ memory_region_add_subregion(mr, map->gic.cpu_iface,
+ sysbus_mmio_get_region(sbd, 1));
+ }
if (map->dtb_expose) {
- node = versal_fdt_add_subnode(s, "/gic", map->gic.dist, compatible,
- sizeof(compatible));
+ if (map->gic.version == 3) {
+ node = versal_fdt_add_subnode(s, "/gic", map->gic.dist,
+ gicv3_compat,
+ sizeof(gicv3_compat));
+ qemu_fdt_setprop_sized_cells(s->cfg.fdt, node, "reg",
+ 2, map->gic.dist,
+ 2, 0x10000,
+ 2, map->gic.redist,
+ 2, GICV3_REDIST_SIZE * num_cpu);
+ } else {
+ node = versal_fdt_add_subnode(s, "/gic", map->gic.dist,
+ gicv2_compat,
+ sizeof(gicv2_compat));
+ qemu_fdt_setprop_sized_cells(s->cfg.fdt, node, "reg",
+ 2, map->gic.dist,
+ 2, 0x1000,
+ 2, map->gic.cpu_iface,
+ 2, 0x1000);
+ }
+
qemu_fdt_setprop_cell(s->cfg.fdt, node, "phandle", s->phandle.gic);
qemu_fdt_setprop_cell(s->cfg.fdt, node, "#interrupt-cells", 3);
- qemu_fdt_setprop_sized_cells(s->cfg.fdt, node, "reg",
- 2, map->gic.dist,
- 2, 0x10000,
- 2, map->gic.redist,
- 2, GICV3_REDIST_SIZE * num_cpu);
qemu_fdt_setprop_cells(s->cfg.fdt, node, "interrupts",
GIC_FDT_IRQ_TYPE_PPI, VERSAL_GIC_MAINT_IRQ,
GIC_FDT_IRQ_FLAGS_LEVEL_HI);
qemu_fdt_setprop(s->cfg.fdt, node, "interrupt-controller", NULL, 0);
}
--
2.50.1