irqchip/renesas-rzv2h: Add DMA ACK signal routing support

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>
This commit is contained in:
John Madieu 2026-05-25 11:07:49 +00:00 committed by Vinod Koul
parent 57e766bd3d
commit 5d596b9139
2 changed files with 45 additions and 0 deletions

View 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;

View File

@ -11,13 +11,18 @@
#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 */