]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
irqchip/renesas-rzv2h: Add DMA ACK signal routing support
authorJohn Madieu <john.madieu.xa@bp.renesas.com>
Mon, 25 May 2026 11:07:49 +0000 (11:07 +0000)
committerVinod Koul <vkoul@kernel.org>
Mon, 8 Jun 2026 11:32:21 +0000 (17:02 +0530)
Some peripherals on RZ/G3E SoCs (SSIU, SPDIF, SCU/SRC, DVC) require
explicit ACK signal routing through the ICU via the ICU_DMACKSELk
registers for level-based DMA handshaking.

Add rzv2h_icu_register_dma_ack() to configure ICU_DMACKSELk, routing
a DMAC channel's ACK signal to the specified peripheral.

Signed-off-by: John Madieu <john.madieu.xa@bp.renesas.com>
Acked-by: Thomas Gleixner <tglx@kernel.org>
Link: https://patch.msgid.link/20260525110750.4020112-2-john.madieu.xa@bp.renesas.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
drivers/irqchip/irq-renesas-rzv2h.c
include/linux/irqchip/irq-renesas-rzv2h.h

index 31c543c876b1692cdf575d88aa18ced8bfc76be3..971ac83eee90ef52b307b145e50439c7ea0b7f8d 100644 (file)
@@ -151,6 +151,12 @@ struct rzv2h_hw_info {
 #define ICU_DMAC_PREP_DMAREQ(sel, up)          (FIELD_PREP(ICU_DMAC_DkRQ_SEL_MASK, (sel)) \
                                                 << ICU_DMAC_DMAREQ_SHIFT(up))
 
+/* DMAC ACK routing - 4 x 7-bit fields per 32-bit register, 8-bit spacing */
+#define ICU_DMAC_DACK_SEL_MASK                 GENMASK(6, 0)
+#define ICU_DMAC_DACK_SHIFT(n)                 ((n) * 8)
+#define ICU_DMAC_DACK_FIELD_MASK(n)            (ICU_DMAC_DACK_SEL_MASK << ICU_DMAC_DACK_SHIFT(n))
+#define ICU_DMAC_PREP_DACK(val, n)             (((val) & ICU_DMAC_DACK_SEL_MASK) << ICU_DMAC_DACK_SHIFT(n))
+
 /**
  * struct rzv2h_icu_priv - Interrupt Control Unit controller private data structure.
  * @base:      Controller's base address
@@ -188,6 +194,40 @@ void rzv2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index,
 }
 EXPORT_SYMBOL_GPL(rzv2h_icu_register_dma_req);
 
+/**
+ * rzv2h_icu_register_dma_ack - Configure DMA ACK signal routing
+ * @icu_dev:      ICU platform device
+ * @dmac_index:   DMAC instance index (0-4)
+ * @dmac_channel: DMAC channel number (0-15), or RZV2H_ICU_DMAC_ACK_NO_DEFAULT
+ *                to disconnect routing for a given ack_no
+ * @ack_no:       Peripheral ACK number (0-88) per RZ/G3E manual Table 4.6-28,
+ *                used as index into ICU_DMACKSELk
+ *
+ * Routes the ACK signal of the peripheral identified by @ack_no to DMAC
+ * channel @dmac_channel of instance @dmac_index. When @dmac_channel is
+ * RZV2H_ICU_DMAC_ACK_NO_DEFAULT the field is reset, disconnecting any
+ * previously configured routing for that peripheral.
+ */
+void rzv2h_icu_register_dma_ack(struct platform_device *icu_dev, u8 dmac_index,
+                               u8 dmac_channel, u16 ack_no)
+{
+       struct rzv2h_icu_priv *priv = platform_get_drvdata(icu_dev);
+       u8 reg_idx = ack_no / 4;
+       u8 field_idx = ack_no & 0x3;
+       u8 dmac_ack_src = (dmac_channel == RZV2H_ICU_DMAC_ACK_NO_DEFAULT) ?
+                         RZV2H_ICU_DMAC_ACK_NO_DEFAULT :
+                         (dmac_index * 16 + dmac_channel);
+       u32 val;
+
+       guard(raw_spinlock_irqsave)(&priv->lock);
+
+       val = readl(priv->base + ICU_DMACKSELk(reg_idx));
+       val &= ~ICU_DMAC_DACK_FIELD_MASK(field_idx);
+       val |= ICU_DMAC_PREP_DACK(dmac_ack_src, field_idx);
+       writel(val, priv->base + ICU_DMACKSELk(reg_idx));
+}
+EXPORT_SYMBOL_GPL(rzv2h_icu_register_dma_ack);
+
 static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data)
 {
        return data->domain->host_data;
index 618a60d2eac00c2d5fabfe1e9fa3a23501df86b1..4ffa898eaaf23d3e97a6b9a50cc2c2f631086b1c 100644 (file)
 #include <linux/platform_device.h>
 
 #define RZV2H_ICU_DMAC_REQ_NO_DEFAULT          0x3ff
+#define RZV2H_ICU_DMAC_ACK_NO_DEFAULT          0x7f
 
 #ifdef CONFIG_RENESAS_RZV2H_ICU
 void rzv2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
                                u16 req_no);
+void rzv2h_icu_register_dma_ack(struct platform_device *icu_dev, u8 dmac_index,
+                               u8 dmac_channel, u16 ack_no);
 #else
 static inline void rzv2h_icu_register_dma_req(struct platform_device *icu_dev, u8 dmac_index,
                                              u8 dmac_channel, u16 req_no) { }
+static inline void rzv2h_icu_register_dma_ack(struct platform_device *icu_dev, u8 dmac_index,
+                                             u8 dmac_channel, u16 ack_no) { }
 #endif
 
 #endif /* __LINUX_IRQ_RENESAS_RZV2H */