[PATCH 6.12.y-cip 12/18] irqchip/renesas-rzt2h: Add error interrupts support

Cosmin Tanislav <[email protected]>
Newsgroups org.cip-project.lists.cip-dev
Message-ID <[email protected]>
commit 8d721c08dd67af96664ce381f6b2790d15de7213 upstream.

The Renesas RZ/T2H ICU is able to report errors for CA55, GIC, and
various IPs. Unmask these errors, request the IRQs and report them when
they occur.

Signed-off-by: Cosmin Tanislav <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Cosmin Tanislav <[email protected]>
---
 drivers/irqchip/irq-renesas-rzt2h.c | 151 +++++++++++++++++++++++++++-
 1 file changed, 147 insertions(+), 4 deletions(-)

diff --git a/drivers/irqchip/irq-renesas-rzt2h.c b/drivers/irqchip/irq-renesas-rzt2h.c
index 54d9e82e5de5..a536ebd792ff 100644
--- a/drivers/irqchip/irq-renesas-rzt2h.c
+++ b/drivers/irqchip/irq-renesas-rzt2h.c
@@ -32,11 +32,36 @@
 						 RZT2H_ICU_IRQ_S_COUNT)
 #define RZT2H_ICU_SEI_COUNT			1
 
+#define RZT2H_ICU_CA55_ERR_START		(RZT2H_ICU_SEI_START +		\
+						 RZT2H_ICU_SEI_COUNT)
+#define RZT2H_ICU_CA55_ERR_COUNT		2
+
+#define RZT2H_ICU_CR52_ERR_START		(RZT2H_ICU_CA55_ERR_START +	\
+						 RZT2H_ICU_CA55_ERR_COUNT)
+#define RZT2H_ICU_CR52_ERR_COUNT		4
+
+#define RZT2H_ICU_PERI_ERR_START		(RZT2H_ICU_CR52_ERR_START +	\
+						 RZT2H_ICU_CR52_ERR_COUNT)
+#define RZT2H_ICU_PERI_ERR_COUNT		2
+
+#define RZT2H_ICU_DSMIF_ERR_START		(RZT2H_ICU_PERI_ERR_START +	\
+						 RZT2H_ICU_PERI_ERR_COUNT)
+#define RZT2H_ICU_DSMIF_ERR_COUNT		2
+
+#define RZT2H_ICU_ENCIF_ERR_START		(RZT2H_ICU_DSMIF_ERR_START +	\
+						 RZT2H_ICU_DSMIF_ERR_COUNT)
+#define RZT2H_ICU_ENCIF_ERR_COUNT		2
+
 #define RZT2H_ICU_NUM_IRQ			(RZT2H_ICU_INTCPU_NS_COUNT +	\
 						 RZT2H_ICU_INTCPU_S_COUNT +	\
 						 RZT2H_ICU_IRQ_NS_COUNT +	\
 						 RZT2H_ICU_IRQ_S_COUNT +	\
-						 RZT2H_ICU_SEI_COUNT)
+						 RZT2H_ICU_SEI_COUNT +		\
+						 RZT2H_ICU_CA55_ERR_COUNT +	\
+						 RZT2H_ICU_CR52_ERR_COUNT +	\
+						 RZT2H_ICU_PERI_ERR_COUNT +	\
+						 RZT2H_ICU_DSMIF_ERR_COUNT +	\
+						 RZT2H_ICU_ENCIF_ERR_COUNT)
 
 #define RZT2H_ICU_IRQ_IN_RANGE(n, type)						\
 	((n) >= RZT2H_ICU_##type##_START &&					\
@@ -54,6 +79,29 @@
 #define RZT2H_ICU_MD_RISING_EDGE		0b10
 #define RZT2H_ICU_MD_BOTH_EDGES			0b11
 
+#define RZT2H_ICU_CA55ERR_E0MSK			0x50
+#define RZT2H_ICU_CA55ERR_CLR			0x60
+#define RZT2H_ICU_CA55ERR_STAT			0x64
+#define RZT2H_ICU_CA55ERR_MASK			GENMASK(12, 0)
+
+#define RZT2H_ICU_PERIERR_E0MSKn(n)		(0x98 + 0x4 * (n))
+#define RZT2H_ICU_PERIERR_CLRn(n)		(0xc8 + 0x4 * (n))
+#define RZT2H_ICU_PERIERR_STAT			0xd4
+#define RZT2H_ICU_PERIERR_NUM			3
+#define RZT2H_ICU_PERIERR_MASK			GENMASK(31, 0)
+
+#define RZT2H_ICU_DSMIFERR_E0MSKn(n)		(0xe0 + 0x4 * (n))
+#define RZT2H_ICU_DSMIFERR_CLRn(n)		(0x1a0 + 0x4 * (n))
+#define RZT2H_ICU_DSMIFERR_STAT			0x1d0
+#define RZT2H_ICU_DSMIFERR_NUM			12
+#define RZT2H_ICU_DSMIFERR_MASK			GENMASK(31, 0)
+
+#define RZT2H_ICU_ENCIFERR_E0MSKn(n)		(0x200 + 0x4 * (n))
+#define RZT2H_ICU_ENCIFERR_CLRn(n)		(0x250 + 0x4 * (n))
+#define RZT2H_ICU_ENCIFERR_STAT			0x264
+#define RZT2H_ICU_ENCIFERR_NUM			5
+#define RZT2H_ICU_ENCIFERR_MASK			GENMASK(31, 0)
+
 #define RZT2H_ICU_DMACn_RSSELi(n, i)		(0x7d0 + 0x18 * (n) + 0x4 * (i))
 #define RZT2H_ICU_DMAC_REQ_SELx_MASK(x)		(GENMASK(9, 0) << ((x) * 10))
 #define RZT2H_ICU_DMAC_REQ_SELx_PREP(x, val)	(FIELD_PREP(GENMASK(9, 0), val) << ((x) * 10))
@@ -285,6 +333,50 @@ static irqreturn_t rzt2h_icu_intcpu_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+static irqreturn_t rzt2h_icu_err_irq(struct rzt2h_icu_priv *priv, const char *name,
+				     unsigned int num, u32 stat_base, u32 clr_base)
+{
+	bool handled = false;
+
+	for (unsigned int n = 0; n < num; n++) {
+		u32 stat = readl(priv->base_ns + stat_base + n * 0x4);
+
+		if (!stat)
+			continue;
+
+		handled = true;
+
+		pr_err("rzt2h-icu: %s error n=%u status=0x%08x\n", name, n, stat);
+
+		writel_relaxed(stat, priv->base_ns + clr_base + n * 0x4);
+	}
+
+	return handled ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static irqreturn_t rzt2h_icu_ca55_err_irq(int irq, void *data)
+{
+	return rzt2h_icu_err_irq(data, "CA55", 1, RZT2H_ICU_CA55ERR_STAT, RZT2H_ICU_CA55ERR_CLR);
+}
+
+static irqreturn_t rzt2h_icu_peri_err_irq(int irq, void *data)
+{
+	return rzt2h_icu_err_irq(data, "peripheral", RZT2H_ICU_PERIERR_NUM, RZT2H_ICU_PERIERR_STAT,
+				 RZT2H_ICU_PERIERR_CLRn(0));
+}
+
+static irqreturn_t rzt2h_icu_dsmif_err_irq(int irq, void *data)
+{
+	return rzt2h_icu_err_irq(data, "DSMIF", RZT2H_ICU_DSMIFERR_NUM, RZT2H_ICU_DSMIFERR_STAT,
+				 RZT2H_ICU_DSMIFERR_CLRn(0));
+}
+
+static irqreturn_t rzt2h_icu_encif_err_irq(int irq, void *data)
+{
+	return rzt2h_icu_err_irq(data, "ENCIF", RZT2H_ICU_ENCIFERR_NUM, RZT2H_ICU_ENCIFERR_STAT,
+				 RZT2H_ICU_ENCIFERR_CLRn(0));
+}
+
 static int rzt2h_icu_request_irqs(struct platform_device *pdev, struct irq_domain *irq_domain,
 				  unsigned int start, unsigned int count, irq_handler_t handler,
 				  void *data)
@@ -315,10 +407,13 @@ static int rzt2h_icu_request_irqs(struct platform_device *pdev, struct irq_domai
 
 static int rzt2h_icu_setup_irqs(struct platform_device *pdev, struct irq_domain *irq_domain)
 {
+	struct rzt2h_icu_priv *priv = platform_get_drvdata(pdev);
+	unsigned int n;
+	int ret;
+
 	if (IS_ENABLED(CONFIG_GENERIC_IRQ_INJECTION)) {
-		int ret = rzt2h_icu_request_irqs(pdev, irq_domain, RZT2H_ICU_INTCPU_NS_START,
-						 RZT2H_ICU_INTCPU_NS_COUNT, rzt2h_icu_intcpu_irq,
-						 NULL);
+		ret = rzt2h_icu_request_irqs(pdev, irq_domain, RZT2H_ICU_INTCPU_NS_START,
+					     RZT2H_ICU_INTCPU_NS_COUNT, rzt2h_icu_intcpu_irq, NULL);
 		if (ret)
 			return ret;
 
@@ -328,6 +423,54 @@ static int rzt2h_icu_setup_irqs(struct platform_device *pdev, struct irq_domain
 			return ret;
 	}
 
+	/*
+	 * There are two error interrupts and two error masks that can be used
+	 * separately for each error type. It would not be very useful to
+	 * receive two interrupts for the same error, so use only the first one.
+	 */
+
+	ret = rzt2h_icu_request_irqs(pdev, irq_domain, RZT2H_ICU_CA55_ERR_START, 1,
+				     rzt2h_icu_ca55_err_irq, priv);
+	if (ret)
+		return ret;
+
+	ret = rzt2h_icu_request_irqs(pdev, irq_domain, RZT2H_ICU_PERI_ERR_START, 1,
+				     rzt2h_icu_peri_err_irq, priv);
+	if (ret)
+		return ret;
+
+	ret = rzt2h_icu_request_irqs(pdev, irq_domain, RZT2H_ICU_DSMIF_ERR_START, 1,
+				     rzt2h_icu_dsmif_err_irq, priv);
+	if (ret)
+		return ret;
+
+	ret = rzt2h_icu_request_irqs(pdev, irq_domain, RZT2H_ICU_ENCIF_ERR_START, 1,
+				     rzt2h_icu_encif_err_irq, priv);
+	if (ret)
+		return ret;
+
+	/* Clear and unmask CA55 error events */
+	writel_relaxed(RZT2H_ICU_CA55ERR_MASK, priv->base_ns + RZT2H_ICU_CA55ERR_CLR);
+	writel_relaxed(0, priv->base_ns + RZT2H_ICU_CA55ERR_E0MSK);
+
+	/* Clear and unmask peripheral error events */
+	for (n = 0; n < RZT2H_ICU_PERIERR_NUM; n++) {
+		writel_relaxed(RZT2H_ICU_PERIERR_MASK, priv->base_ns + RZT2H_ICU_PERIERR_CLRn(n));
+		writel_relaxed(0, priv->base_ns + RZT2H_ICU_PERIERR_E0MSKn(n));
+	}
+
+	/* Clear and unmask DSMIF error events */
+	for (n = 0; n < RZT2H_ICU_DSMIFERR_NUM; n++) {
+		writel_relaxed(RZT2H_ICU_DSMIFERR_MASK, priv->base_ns + RZT2H_ICU_DSMIFERR_CLRn(n));
+		writel_relaxed(0, priv->base_ns + RZT2H_ICU_DSMIFERR_E0MSKn(n));
+	}
+
+	/* Clear and unmask ENCIF error events */
+	for (n = 0; n < RZT2H_ICU_ENCIFERR_NUM; n++) {
+		writel_relaxed(RZT2H_ICU_ENCIFERR_MASK, priv->base_ns + RZT2H_ICU_ENCIFERR_CLRn(n));
+		writel_relaxed(0, priv->base_ns + RZT2H_ICU_ENCIFERR_E0MSKn(n));
+	}
+
 	return 0;
 }
 
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.