[PATCH 26/48] hw/arm/xlnx-versal: add support for GICv2

Luc Michel posted 48 patches 4 months ago
Maintainers: Alistair Francis <alistair@alistair23.me>, "Edgar E. Iglesias" <edgar.iglesias@gmail.com>, Peter Maydell <peter.maydell@linaro.org>, Jason Wang <jasowang@redhat.com>
There is a newer version of this series
[PATCH 26/48] hw/arm/xlnx-versal: add support for GICv2
Posted by Luc Michel 4 months ago
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>
---
 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
Re: [PATCH 26/48] hw/arm/xlnx-versal: add support for GICv2
Posted by Francisco Iglesias 3 months, 2 weeks ago
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
>