On Wed, Jul 16, 2025 at 11:54:21AM +0200, Luc Michel wrote: > Add the target field in the IRQ descriptor. This allows to target an IRQ > to another IRQ controller than the GIC(s). Other supported targets are > the PMC PPU1 CPU interrupt controller and the EAM (Error management) > device. Those two devices are currently not implemented so IRQs > targeting those will be left unconnected. This is in preparation for > versal2. > > Signed-off-by: Luc Michel <luc.mic...@amd.com>
Reviewed-by: Francisco Iglesias <francisco.igles...@amd.com> > --- > hw/arm/xlnx-versal.c | 41 +++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 39 insertions(+), 2 deletions(-) > > diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c > index 9d900fe3127..551671af425 100644 > --- a/hw/arm/xlnx-versal.c > +++ b/hw/arm/xlnx-versal.c > @@ -50,18 +50,30 @@ > #include "hw/cpu/cluster.h" > #include "hw/arm/bsa.h" > > /* > * IRQ descriptor to catch the following cases: > + * - An IRQ can either connect to the GICs, to the PPU1 intc, or the the > EAM > * - Multiple devices can connect to the same IRQ. They are OR'ed together. > */ > FIELD(VERSAL_IRQ, IRQ, 0, 16) > +FIELD(VERSAL_IRQ, TARGET, 16, 2) > FIELD(VERSAL_IRQ, ORED, 18, 1) > FIELD(VERSAL_IRQ, OR_IDX, 19, 4) /* input index on the IRQ OR gate */ > > +typedef enum VersalIrqTarget { > + IRQ_TARGET_GIC, > + IRQ_TARGET_PPU1, > + IRQ_TARGET_EAM, > +} VersalIrqTarget; > + > +#define PPU1_IRQ(irq) ((IRQ_TARGET_PPU1 << R_VERSAL_IRQ_TARGET_SHIFT) | > (irq)) > +#define EAM_IRQ(irq) ((IRQ_TARGET_EAM << R_VERSAL_IRQ_TARGET_SHIFT) | (irq)) > #define OR_IRQ(irq, or_idx) \ > (R_VERSAL_IRQ_ORED_MASK | ((or_idx) << R_VERSAL_IRQ_OR_IDX_SHIFT) | > (irq)) > +#define PPU1_OR_IRQ(irq, or_idx) \ > + ((IRQ_TARGET_PPU1 << R_VERSAL_IRQ_TARGET_SHIFT) | OR_IRQ(irq, or_idx)) > > typedef struct VersalSimplePeriphMap { > uint64_t addr; > int irq; > } VersalSimplePeriphMap; > @@ -415,19 +427,27 @@ static qemu_irq versal_get_gic_irq(Versal *s, int > irq_idx) > * Or gates are placed under the /soc/irq-or-gates QOM container. > */ > static qemu_irq versal_get_irq_or_gate_in(Versal *s, int irq_idx, > qemu_irq target_irq) > { > + static const char *TARGET_STR[] = { > + [IRQ_TARGET_GIC] = "gic", > + [IRQ_TARGET_PPU1] = "ppu1", > + [IRQ_TARGET_EAM] = "eam", > + }; > + > + VersalIrqTarget target; > Object *container = versal_get_child(s, "irq-or-gates"); > DeviceState *dev; > g_autofree char *name; > int idx, or_idx; > > idx = FIELD_EX32(irq_idx, VERSAL_IRQ, IRQ); > or_idx = FIELD_EX32(irq_idx, VERSAL_IRQ, OR_IDX); > + target = FIELD_EX32(irq_idx, VERSAL_IRQ, TARGET); > > - name = g_strdup_printf("irq[%d]", idx); > + name = g_strdup_printf("%s-irq[%d]", TARGET_STR[target], idx); > dev = DEVICE(object_resolve_path_at(container, name)); > > if (dev == NULL) { > dev = qdev_new(TYPE_OR_IRQ); > object_property_add_child(container, name, OBJECT(dev)); > @@ -439,16 +459,33 @@ static qemu_irq versal_get_irq_or_gate_in(Versal *s, > int irq_idx, > return qdev_get_gpio_in(dev, or_idx); > } > > static qemu_irq versal_get_irq(Versal *s, int irq_idx) > { > + VersalIrqTarget target; > qemu_irq irq; > bool ored; > > + target = FIELD_EX32(irq_idx, VERSAL_IRQ, TARGET); > ored = FIELD_EX32(irq_idx, VERSAL_IRQ, ORED); > > - irq = versal_get_gic_irq(s, irq_idx); > + switch (target) { > + case IRQ_TARGET_EAM: > + /* EAM not implemented */ > + return NULL; > + > + case IRQ_TARGET_PPU1: > + /* PPU1 CPU not implemented */ > + return NULL; > + > + case IRQ_TARGET_GIC: > + irq = versal_get_gic_irq(s, irq_idx); > + break; > + > + default: > + g_assert_not_reached(); > + } > > if (ored) { > irq = versal_get_irq_or_gate_in(s, irq_idx, irq); > } > > -- > 2.50.0 >