[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260121150137.3364865-5-prabhakar.mahadev-lad.rj@bp.renesas.com>
Date: Wed, 21 Jan 2026 15:01:35 +0000
From: Prabhakar <prabhakar.csengg@...il.com>
To: 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-renesas-soc@...r.kernel.org,
Prabhakar <prabhakar.csengg@...il.com>,
Biju Das <biju.das.jz@...renesas.com>,
Fabrizio Castro <fabrizio.castro.jz@...esas.com>,
Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
Subject: [PATCH 4/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.
Introduce a debug mechanism to trigger software interrupts on individual
Cortex-A55 cores via the RZ/V2H ICU. The interface is gated behind
CONFIG_DEBUG_FS and a module parameter to ensure it only exists when
explicitly enabled.
Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@...renesas.com>
---
drivers/irqchip/irq-renesas-rzv2h.c | 111 ++++++++++++++++++++++++++++
1 file changed, 111 insertions(+)
diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
index 4aa772ba1a1f..7d3ce1d762f0 100644
--- a/drivers/irqchip/irq-renesas-rzv2h.c
+++ b/drivers/irqchip/irq-renesas-rzv2h.c
@@ -11,16 +11,23 @@
#include <linux/bitfield.h>
#include <linux/cleanup.h>
+#include <linux/cpu.h>
+#include <linux/debugfs.h>
#include <linux/err.h>
+#include <linux/fs.h>
#include <linux/io.h>
#include <linux/irqchip.h>
#include <linux/irqchip/irq-renesas-rzv2h.h>
#include <linux/irqdomain.h>
+#include <linux/kconfig.h>
+#include <linux/kstrtox.h>
+#include <linux/moduleparam.h>
#include <linux/of_platform.h>
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/spinlock.h>
#include <linux/syscore_ops.h>
+#include <linux/uaccess.h>
/* DT "interrupts" indexes */
#define ICU_IRQ_START 1
@@ -40,6 +47,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)
@@ -90,6 +98,13 @@
#define ICU_RZG3E_TSSEL_MAX_VAL 0x8c
#define ICU_RZV2H_TSSEL_MAX_VAL 0x55
+#define ICU_SWINT_NUM 4
+
+static bool enable_icu_debug;
+module_param_named(debug, enable_icu_debug, bool, 0644);
+MODULE_PARM_DESC(debug,
+ "Enable RZ/V2H ICU debug/diagnostic interrupts (default: false)");
+
/**
* struct rzv2h_irqc_reg_cache - registers cache (necessary for suspend/resume)
* @nitsr: ICU_NITSR register
@@ -550,6 +565,98 @@ 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 void rzv2h_icu_remove_debugfs(void *file)
+{
+ debugfs_remove(file);
+}
+
+static ssize_t rzv2h_icu_swint_write(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *ppos)
+{
+ struct rzv2h_icu_priv *priv = file->private_data;
+ unsigned long cpu;
+ char buf[32];
+ int ret;
+
+ len = min(len, sizeof(buf) - 1);
+ if (copy_from_user(buf, ubuf, len))
+ return -EFAULT;
+ buf[len] = '\0';
+
+ ret = kstrtoul(strim(buf), 0, &cpu);
+ if (ret)
+ return ret;
+
+ if (cpu >= ICU_SWINT_NUM || cpu >= nr_cpu_ids)
+ return -EINVAL;
+
+ if (!cpu_online(cpu))
+ return -ENODEV;
+
+ writel(BIT(cpu), priv->base + ICU_SWINT);
+ return len;
+}
+
+static const struct file_operations rzv2h_icu_swint_fops = {
+ .open = simple_open,
+ .write = rzv2h_icu_swint_write,
+ .llseek = noop_llseek,
+};
+
+static int rzv2h_icu_setup_debug_irqs(struct platform_device *pdev)
+{
+ static const u8 swint_idx[ICU_SWINT_NUM] = { 0, 1, 2, 3 };
+ static const char * const rzv2h_swint_names[] = {
+ "int-ca55-0", "int-ca55-1",
+ "int-ca55-2", "int-ca55-3",
+ };
+ struct device *dev = &pdev->dev;
+ struct dentry *dentry;
+ struct dentry *dir;
+ unsigned int i;
+ int icu_irq;
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_DEBUG_FS) || !enable_icu_debug)
+ return 0;
+
+ dev_info(dev, "RZ/V2H ICU debug interrupts enabled\n");
+
+ for (i = 0; i < ICU_SWINT_NUM; i++) {
+ icu_irq = platform_get_irq_byname(pdev, rzv2h_swint_names[i]);
+ if (icu_irq < 0)
+ return dev_err_probe(dev, icu_irq,
+ "Failed to get %s IRQ\n", rzv2h_swint_names[i]);
+ ret = devm_request_irq(dev, icu_irq, rzv2h_icu_swint_irq, 0, dev_name(dev),
+ (void *)&swint_idx[i]);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request SWINT IRQ: %s\n",
+ rzv2h_swint_names[i]);
+ }
+
+ dir = debugfs_create_dir("rzv2h_icu", NULL);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ ret = devm_add_action_or_reset(dev, rzv2h_icu_remove_debugfs, dir);
+ if (ret)
+ return ret;
+
+ dentry = debugfs_create_file("swint", 0200, dir, rzv2h_icu_data, &rzv2h_icu_swint_fops);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+
+ return devm_add_action_or_reset(dev, rzv2h_icu_remove_debugfs, dentry);
+}
+
static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_node *parent,
const struct rzv2h_hw_info *hw_info)
{
@@ -605,6 +712,10 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no
register_syscore(&rzv2h_irqc_syscore);
+ ret = rzv2h_icu_setup_debug_irqs(pdev);
+ 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