]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
irqchip/renesas-rzt2h: Add error interrupts support
authorCosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
Wed, 20 May 2026 20:31:17 +0000 (23:31 +0300)
committerThomas Gleixner <tglx@kernel.org>
Wed, 3 Jun 2026 16:27:05 +0000 (18:27 +0200)
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 <cosmin-gabriel.tanislav.xa@renesas.com>
Signed-off-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260520203117.1516442-4-cosmin-gabriel.tanislav.xa@renesas.com
drivers/irqchip/irq-renesas-rzt2h.c

index f7813d3d9cb1c5043c0bdd2f926052d993dbf4be..e06264add3cc0d794a0d4dc7e94b8e9c510f3fc5 100644 (file)
                                                 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 &&                                     \
 #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))
@@ -284,6 +332,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)
@@ -314,10 +406,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;
 
@@ -327,6 +422,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;
 }