On Wed, Jul 16, 2025 at 11:54:08AM +0200, Luc Michel wrote:
> 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 58cd874f81f..771f6108558 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;
>
> @@ -504,10 +506,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);
> @@ -543,49 +549,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.0
>