diff options
| author | Luc Michel <luc.michel@amd.com> | 2025-09-26 09:07:42 +0200 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2025-10-07 10:35:36 +0100 |
| commit | d95bf385567dc635f4cf275af118f3774e3b3d29 (patch) | |
| tree | 9d01ffef391393ce33a99d4baf7f3f42115ab716 /hw/arm/xlnx-versal.c | |
| parent | 27493e5e687e65829f548bf0145dd44bc223fbe5 (diff) | |
| download | focaccia-qemu-d95bf385567dc635f4cf275af118f3774e3b3d29.tar.gz focaccia-qemu-d95bf385567dc635f4cf275af118f3774e3b3d29.zip | |
hw/arm/xlnx-versal: add support for multiple GICs
The Versal SoC contains two GICs: one GICv3 in the APU and one GICv2 in the RPU (currently not instantiated). To prepare for the GICv2 instantiation, add support for multiple GICs when connecting interrupts. When a GIC is created, the first-cpu-index property is set on it, and a pointer to the GIC is stored in the intc array. When connecting an IRQ, a TYPE_SPLIT_IRQ device is created with its num-lines property set to the number of GICs in the SoC. The split device is used to fan out the IRQ to all the GICs. Signed-off-by: Luc Michel <luc.michel@amd.com> Reviewed-by: Francisco Iglesias <francisco.iglesias@amd.com> Reviewed-by: Edgar E. Iglesias <edgar.iglesias@amd.com> Tested-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20250926070806.292065-25-luc.michel@amd.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/arm/xlnx-versal.c')
| -rw-r--r-- | hw/arm/xlnx-versal.c | 56 |
1 files changed, 52 insertions, 4 deletions
diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c index e03411bc21..9256eceffc 100644 --- a/hw/arm/xlnx-versal.c +++ b/hw/arm/xlnx-versal.c @@ -45,6 +45,7 @@ #include "hw/misc/xlnx-versal-crl.h" #include "hw/intc/arm_gicv3_common.h" #include "hw/intc/arm_gicv3_its_common.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") @@ -318,6 +319,43 @@ static inline Object *versal_get_child_idx(Versal *s, const char *child, } /* + * The SoC embeds multiple GICs. They all receives the same IRQ lines at the + * same index. This function creates a TYPE_SPLIT_IRQ device to fan out the + * given IRQ input to all the GICs. + * + * The TYPE_SPLIT_IRQ devices lie in the /soc/irq-splits QOM container + */ +static qemu_irq versal_get_gic_irq(Versal *s, int irq_idx) +{ + DeviceState *split; + Object *container = versal_get_child(s, "irq-splits"); + int idx = FIELD_EX32(irq_idx, VERSAL_IRQ, IRQ); + g_autofree char *name = g_strdup_printf("irq[%d]", idx); + + split = DEVICE(object_resolve_path_at(container, name)); + + if (split == NULL) { + size_t i; + + split = qdev_new(TYPE_SPLIT_IRQ); + qdev_prop_set_uint16(split, "num-lines", s->intc->len); + object_property_add_child(container, name, OBJECT(split)); + qdev_realize_and_unref(split, NULL, &error_abort); + + for (i = 0; i < s->intc->len; i++) { + DeviceState *gic; + + gic = g_array_index(s->intc, DeviceState *, i); + qdev_connect_gpio_out(split, i, qdev_get_gpio_in(gic, idx)); + } + } else { + g_assert(FIELD_EX32(irq_idx, VERSAL_IRQ, ORED)); + } + + return qdev_get_gpio_in(split, 0); +} + +/* * When the R_VERSAL_IRQ_ORED flag is set on an IRQ descriptor, this function is * used to return the corresponding or gate input IRQ. The or gate is created if * not already existant. @@ -353,12 +391,10 @@ static qemu_irq versal_get_irq(Versal *s, int irq_idx) { qemu_irq irq; bool ored; - DeviceState *gic; ored = FIELD_EX32(irq_idx, VERSAL_IRQ, ORED); - gic = DEVICE(versal_get_child_idx(s, "apu-gic", 0)); - irq = qdev_get_gpio_in(gic, FIELD_EX32(irq_idx, VERSAL_IRQ, IRQ)); + irq = versal_get_gic_irq(s, irq_idx); if (ored) { irq = versal_get_irq_or_gate_in(s, irq_idx, irq); @@ -501,6 +537,7 @@ static void versal_create_gic_its(Versal *s, static DeviceState *versal_create_gic(Versal *s, const VersalCpuClusterMap *map, MemoryRegion *mr, + int first_cpu_idx, size_t num_cpu) { DeviceState *dev; @@ -525,6 +562,7 @@ static DeviceState *versal_create_gic(Versal *s, 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); sysbus_realize_and_unref(sbd, &error_fatal); @@ -551,6 +589,8 @@ static DeviceState *versal_create_gic(Versal *s, versal_create_gic_its(s, map, dev, mr, node); + g_array_append_val(s->intc, dev); + return dev; } @@ -608,9 +648,11 @@ static inline void versal_create_and_connect_gic(Versal *s, size_t num_cpu) { DeviceState *gic; + int first_cpu_idx; size_t i; - gic = versal_create_gic(s, map, mr, num_cpu); + first_cpu_idx = CPU(cpus[0])->cpu_index; + gic = versal_create_gic(s, map, mr, first_cpu_idx, num_cpu); for (i = 0; i < num_cpu; i++) { connect_gic_to_cpu(map, gic, cpus[i], i, num_cpu); @@ -1540,6 +1582,10 @@ static void versal_realize(DeviceState *dev, Error **errp) s->phandle.gic = qemu_fdt_alloc_phandle(s->cfg.fdt); container = object_new(TYPE_CONTAINER); + object_property_add_child(OBJECT(s), "irq-splits", container); + object_unref(container); + + container = object_new(TYPE_CONTAINER); object_property_add_child(OBJECT(s), "irq-or-gates", container); object_unref(container); @@ -1720,6 +1766,7 @@ static void versal_base_init(Object *obj) memory_region_init(&s->mr_ps, obj, "mr-ps-switch", UINT64_MAX); memory_region_init_alias(&s->lpd.rpu.mr_ps_alias, OBJECT(s), "mr-rpu-ps-alias", &s->mr_ps, 0, UINT64_MAX); + s->intc = g_array_new(false, false, sizeof(DeviceState *)); num_can = versal_get_map(s)->num_canfd; s->cfg.canbus = g_new0(CanBusState *, num_can); @@ -1737,6 +1784,7 @@ static void versal_base_finalize(Object *obj) { Versal *s = XLNX_VERSAL_BASE(obj); + g_array_free(s->intc, true); g_free(s->cfg.canbus); } |