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.michel@amd.com>
Reviewed-by: Francisco Iglesias <francisco.iglesias@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
>