[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID:
<TY3PR01MB1134655D9D775609DDD421DA48698A@TY3PR01MB11346.jpnprd01.prod.outlook.com>
Date: Wed, 4 Feb 2026 07:08:11 +0000
From: Biju Das <biju.das.jz@...renesas.com>
To: Prabhakar <prabhakar.csengg@...il.com>, Thomas Gleixner <tglx@...nel.org>,
Philipp Zabel <p.zabel@...gutronix.de>, Geert Uytterhoeven
<geert+renesas@...der.be>, magnus.damm <magnus.damm@...il.com>
CC: "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
"linux-renesas-soc@...r.kernel.org" <linux-renesas-soc@...r.kernel.org>,
Fabrizio Castro <fabrizio.castro.jz@...esas.com>, Prabhakar Mahadev Lad
<prabhakar.mahadev-lad.rj@...renesas.com>
Subject: RE: [PATCH v2 5/6] irqchip/renesas-rzv2h: Add CA55 software interrupt
support
Hi Prabhakar,
> -----Original Message-----
> From: Prabhakar <prabhakar.csengg@...il.com>
> Sent: 03 February 2026 23:18
> Subject: [PATCH v2 5/6] irqchip/renesas-rzv2h: Add CA55 software interrupt support
>
> From: Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
>
> The Renesas RZ/V2H ICU provides a software interrupt register (ICU_SWINT) that allows software to
> explicitly assert interrupts toward individual
> CA55 cores. Writing BIT(n) to ICU_SWINT triggers the corresponding interrupt.
>
> Extend the RZ/V2H ICU IRQ domain to include CA55 software interrupts as part of the hierarchical IRQ
> numbering, backed by the ICU_SWINT register.
>
> SW interrupts can now be triggered when GENERIC_IRQ_INJECTION is enabled.
>
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
> ---
> v1->v2:
> - Made CA55 SW interrupt as part of ICU IRQ domain.
> - Implemented rzv2h_icu_irq_set_irqchip_state() to trigger SWINT.
> - Updated commit message accordingly.
> ---
> drivers/irqchip/irq-renesas-rzv2h.c | 89 ++++++++++++++++++++++++++++-
> 1 file changed, 86 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
> index 6c7bbb04c6e4..a2ff7524889c 100644
> --- a/drivers/irqchip/irq-renesas-rzv2h.c
> +++ b/drivers/irqchip/irq-renesas-rzv2h.c
> @@ -12,6 +12,7 @@
> #include <linux/bitfield.h>
> #include <linux/cleanup.h>
> #include <linux/err.h>
> +#include <linux/interrupt.h>
> #include <linux/io.h>
> #include <linux/irqchip.h>
> #include <linux/irqchip/irq-renesas-rzv2h.h>
> @@ -29,7 +30,10 @@
> #define ICU_TINT_START (ICU_IRQ_LAST + 1)
> #define ICU_TINT_COUNT 32
> #define ICU_TINT_LAST (ICU_TINT_START + ICU_TINT_COUNT - 1)
> -#define ICU_NUM_IRQ (ICU_TINT_LAST + 1)
> +#define ICU_CA55_INT_START (ICU_TINT_LAST + 1)
Maybe define this after defining GPT IRQ macros[1] for continuity, when
CONFIG_GENERIC_IRQ_INJECTION is disabled ??
[1]
ICU GPT GPT_U0_gpt_gtciada_n.. ICU GPT GPT_U1_gpt_gtciadb_n
Cheers,
Biju
> +#define ICU_CA55_INT_COUNT 4
> +#define ICU_CA55_INT_LAST (ICU_CA55_INT_START + ICU_CA55_INT_COUNT - 1)
> +#define ICU_NUM_IRQ (ICU_CA55_INT_LAST + 1)
>
> /* Registers */
> #define ICU_NSCNT 0x00
> @@ -42,6 +46,7 @@
> #define ICU_TSCLR 0x24
> #define ICU_TITSR(k) (0x28 + (k) * 4)
> #define ICU_TSSR(k) (0x30 + (k) * 4)
> +#define ICU_SWINT 0x130
> #define ICU_DMkSELy(k, y) (0x420 + (k) * 0x20 + (y) * 4)
> #define ICU_DMACKSELk(k) (0x500 + (k) * 4)
>
> @@ -248,6 +253,30 @@ static void rzv2h_icu_irq_enable(struct irq_data *d)
> irq_chip_enable_parent(d);
> }
>
> +static int rzv2h_icu_irq_set_irqchip_state(struct irq_data *d,
> + enum irqchip_irq_state which,
> + bool state)
> +{
> + unsigned int hwirq = irqd_to_hwirq(d);
> + struct rzv2h_icu_priv *priv;
> + unsigned int bit;
> +
> + if (hwirq < ICU_CA55_INT_START || hwirq > ICU_CA55_INT_LAST ||
> + which != IRQCHIP_STATE_PENDING)
> + return irq_chip_set_parent_state(d, which, state);
> +
> + if (!state)
> + return 0;
> +
> + priv = irq_data_to_priv(d);
> + bit = BIT(hwirq - ICU_CA55_INT_START);
> +
> + guard(raw_spinlock)(&priv->lock);
> + /* Trigger the software interrupt */
> + writel_relaxed(bit, priv->base + ICU_SWINT);
> + return 0;
> +}
> +
> static int rzv2h_nmi_set_type(struct irq_data *d, unsigned int type) {
> struct rzv2h_icu_priv *priv = irq_data_to_priv(d); @@ -429,6 +458,7 @@ static int
> rzv2h_tint_set_type(struct irq_data *d, unsigned int type)
>
> static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type) {
> + unsigned int gic_type = IRQ_TYPE_LEVEL_HIGH;
> unsigned int hw_irq = irqd_to_hwirq(d);
> int ret;
>
> @@ -445,6 +475,11 @@ static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
> /* TINT */
> ret = rzv2h_tint_set_type(d, type);
> break;
> + case ICU_CA55_INT_START ... ICU_CA55_INT_LAST:
> + /* CA55 Software Interrupts have EDGE_RISING type */
> + gic_type = IRQ_TYPE_EDGE_RISING;
> + ret = 0;
> + break;
> default:
> ret = -EINVAL;
> }
> @@ -452,7 +487,7 @@ static int rzv2h_icu_set_type(struct irq_data *d, unsigned int type)
> if (ret)
> return ret;
>
> - return irq_chip_set_type_parent(d, IRQ_TYPE_LEVEL_HIGH);
> + return irq_chip_set_type_parent(d, gic_type);
> }
>
> static int rzv2h_irqc_irq_suspend(void *data) @@ -501,7 +536,7 @@ static const struct irq_chip
> rzv2h_icu_chip = {
> .irq_disable = rzv2h_icu_irq_disable,
> .irq_enable = rzv2h_icu_irq_enable,
> .irq_get_irqchip_state = irq_chip_get_parent_state,
> - .irq_set_irqchip_state = irq_chip_set_parent_state,
> + .irq_set_irqchip_state = rzv2h_icu_irq_set_irqchip_state,
> .irq_retrigger = irq_chip_retrigger_hierarchy,
> .irq_set_type = rzv2h_icu_set_type,
> .irq_set_affinity = irq_chip_set_affinity_parent,
> @@ -571,6 +606,50 @@ static int rzv2h_icu_parse_interrupts(struct rzv2h_icu_priv *priv, struct device
> return 0;
> }
>
> +static irqreturn_t rzv2h_icu_swint_irq(int irq, void *data) {
> + u8 cpu = *(u8 *)data;
> +
> + pr_debug("SWINT interrupt for CA55 core %u\n", cpu);
> + return IRQ_HANDLED;
> +}
> +
> +static int rzv2h_icu_setup_irqs(struct platform_device *pdev,
> + struct irq_domain *irq_domain)
> +{
> + bool irq_inject = IS_ENABLED(CONFIG_GENERIC_IRQ_INJECTION);
> + static const char * const rzv2h_swint_names[] = {
> + "int-ca55-0", "int-ca55-1",
> + "int-ca55-2", "int-ca55-3",
> + };
> + static const u8 swint_idx[] = { 0, 1, 2, 3 };
> + struct device *dev = &pdev->dev;
> + struct irq_fwspec fwspec;
> + unsigned int virq;
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < ICU_CA55_INT_COUNT && irq_inject; i++) {
> + fwspec.fwnode = irq_domain->fwnode;
> + fwspec.param_count = 2;
> + fwspec.param[0] = ICU_CA55_INT_START + i;
> + fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
> +
> + virq = irq_create_fwspec_mapping(&fwspec);
> + if (!virq)
> + return dev_err_probe(dev, -EINVAL, "failed to create IRQ mapping for %s\n",
> + rzv2h_swint_names[i]);
> +
> + ret = devm_request_irq(dev, virq, rzv2h_icu_swint_irq, 0, dev_name(dev),
> + (void *)&swint_idx[i]);
> + if (ret)
> + return dev_err_probe(dev, ret, "Failed to request %s IRQ\n",
> + rzv2h_swint_names[i]);
> + }
> +
> + return 0;
> +}
> +
> static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_node *parent,
> const struct rzv2h_hw_info *hw_info) { @@ -626,6 +705,10 @@ static int
> rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
>
> register_syscore(&rzv2h_irqc_syscore);
>
> + ret = rzv2h_icu_setup_irqs(pdev, irq_domain);
> + if (ret)
> + goto pm_put;
> +
> /*
> * coccicheck complains about a missing put_device call before returning, but it's a false
> * positive. We still need dev after successfully returning from this function.
> --
> 2.52.0
Powered by blists - more mailing lists