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
> 

Reply via email to