On Wed, Jul 16, 2025 at 11:53:55AM +0200, Luc Michel wrote: > Improve the IRQ index in the VersalMap structure to turn it into a > descriptor: > - the lower 16 bits still represent the IRQ index > - bit 18 is used to indicate a shared IRQ connected to a OR gate > - bits 19 to 22 indicate the index on the OR gate. > > This allows to share an IRQ among multiple devices. An OR gate is > created to connect the devices to the actual IRQ pin. > > Signed-off-by: Luc Michel <luc.mic...@amd.com>
Reviewed-by: Francisco Iglesias <francisco.igles...@amd.com> > --- > hw/arm/xlnx-versal.c | 62 +++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 61 insertions(+), 1 deletion(-) > > diff --git a/hw/arm/xlnx-versal.c b/hw/arm/xlnx-versal.c > index 58176fa11e5..89c93278336 100644 > --- a/hw/arm/xlnx-versal.c > +++ b/hw/arm/xlnx-versal.c > @@ -41,10 +41,21 @@ > #define GEM_REVISION 0x40070106 > > #define VERSAL_NUM_PMC_APB_IRQS 18 > #define NUM_OSPI_IRQ_LINES 3 > > +/* > + * IRQ descriptor to catch the following cases: > + * - Multiple devices can connect to the same IRQ. They are OR'ed together. > + */ > +FIELD(VERSAL_IRQ, IRQ, 0, 16) > +FIELD(VERSAL_IRQ, ORED, 18, 1) > +FIELD(VERSAL_IRQ, OR_IDX, 19, 4) /* input index on the IRQ OR gate */ > + > +#define OR_IRQ(irq, or_idx) \ > + (R_VERSAL_IRQ_ORED_MASK | ((or_idx) << R_VERSAL_IRQ_OR_IDX_SHIFT) | > (irq)) > + > typedef struct VersalSimplePeriphMap { > uint64_t addr; > int irq; > } VersalSimplePeriphMap; > > @@ -172,13 +183,56 @@ static inline Object *versal_get_child_idx(Versal *s, > const char *child, > g_autofree char *n = g_strdup_printf("%s[%zu]", child, idx); > > return versal_get_child(s, n); > } > > +/* > + * 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. > + * > + * 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) > +{ > + 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); > + > + name = g_strdup_printf("irq[%d]", 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)); > + qdev_prop_set_uint16(dev, "num-lines", 1 << > R_VERSAL_IRQ_OR_IDX_LENGTH); > + qdev_realize_and_unref(dev, NULL, &error_abort); > + qdev_connect_gpio_out(dev, 0, target_irq); > + } > + > + return qdev_get_gpio_in(dev, or_idx); > +} > + > static qemu_irq versal_get_irq(Versal *s, int irq_idx) > { > - return qdev_get_gpio_in(DEVICE(&s->fpd.apu.gic), irq_idx); > + qemu_irq irq; > + bool ored; > + > + ored = FIELD_EX32(irq_idx, VERSAL_IRQ, ORED); > + > + irq = qdev_get_gpio_in(DEVICE(&s->fpd.apu.gic), irq_idx); > + > + if (ored) { > + irq = versal_get_irq_or_gate_in(s, irq_idx, irq); > + } > + > + return irq; > } > > static void versal_sysbus_connect_irq(Versal *s, SysBusDevice *sbd, > int sbd_idx, int irq_idx) > { > @@ -1209,10 +1263,11 @@ static uint32_t fdt_add_clk_node(Versal *s, const > char *name, > > static void versal_realize(DeviceState *dev, Error **errp) > { > Versal *s = XLNX_VERSAL_BASE(dev); > qemu_irq pic[XLNX_VERSAL_NR_IRQS]; > + Object *container; > const VersalMap *map = versal_get_map(s); > size_t i; > > if (s->cfg.fdt == NULL) { > int fdt_size; > @@ -1223,10 +1278,15 @@ static void versal_realize(DeviceState *dev, Error > **errp) > s->phandle.clk_25mhz = fdt_add_clk_node(s, "/clk25", 25 * 1000 * 1000); > s->phandle.clk_125mhz = fdt_add_clk_node(s, "/clk125", 125 * 1000 * > 1000); > > versal_create_apu_cpus(s); > versal_create_apu_gic(s, pic); > + > + container = object_new(TYPE_CONTAINER); > + object_property_add_child(OBJECT(s), "irq-or-gates", container); > + object_unref(container); > + > versal_create_rpu_cpus(s); > > for (i = 0; i < map->num_uart; i++) { > versal_create_uart(s, &map->uart[i], i); > } > -- > 2.50.0 >