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
> 

Reply via email to