On the Renesas RZ/V2H(P) family of SoCs, DMAC IPs are connected
to the Interrupt Control Unit (ICU).
For DMA transfers, a request number and an ack number must be
registered with the ICU, which means that the DMAC driver has
to be able to instruct the ICU driver with the registration of
such ids.
Export rzv2h_icu_register_dma_req_ack() so that the DMA driver
can register both ids in one go.
Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
---
v3->v4:
* No change.
v2->v3:
* Replaced rzv2h_icu_register_dma_req_ack with
rzv2h_icu_register_dma_req_ack() in changelog.
* Added dummy for rzv2h_icu_register_dma_req_ack().
* Added Rb Thomas.
v1->v2:
* Improved macros.
* Shared new macros for minimum values.
---
drivers/irqchip/irq-renesas-rzv2h.c | 56 +++++++++++++++++++++++
include/linux/irqchip/irq-renesas-rzv2h.h | 26 +++++++++++
2 files changed, 82 insertions(+)
create mode 100644 include/linux/irqchip/irq-renesas-rzv2h.h
diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
index fe2d29e91026..a8e9feda73b0 100644
--- a/drivers/irqchip/irq-renesas-rzv2h.c
+++ b/drivers/irqchip/irq-renesas-rzv2h.c
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/irqchip.h>
+#include <linux/irqchip/irq-renesas-rzv2h.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
@@ -41,6 +42,8 @@
#define ICU_TSCLR 0x24
#define ICU_TITSR(k) (0x28 + (k) * 4)
#define ICU_TSSR(k) (0x30 + (k) * 4)
+#define ICU_DMkSELy(k, y) (0x420 + (k) * 0x20 + (y) * 4)
+#define ICU_DMACKSELk(k) (0x500 + (k) * 4)
/* NMI */
#define ICU_NMI_EDGE_FALLING 0
@@ -80,6 +83,19 @@
#define ICU_TINT_EXTRACT_GPIOINT(x) FIELD_GET(GENMASK(31, 16), (x))
#define ICU_PB5_TINT 0x55
+/* DMAC */
+#define ICU_DMAC_DkRQ_SEL_MASK GENMASK(9, 0)
+
+#define ICU_DMAC_DMAREQ_SHIFT(up) ((up) * 16)
+#define ICU_DMAC_DMAREQ_MASK(up) (ICU_DMAC_DkRQ_SEL_MASK \
+ << ICU_DMAC_DMAREQ_SHIFT(up))
+#define ICU_DMAC_PREP_DMAREQ(sel, up) (FIELD_PREP(ICU_DMAC_DkRQ_SEL_MASK, (sel)) \
+ << ICU_DMAC_DMAREQ_SHIFT(up))
+
+#define ICU_DMAC_DACK_SEL_SHIFT(field_no) ((field_no) * 8)
+#define ICU_DMAC_DACK_SEL_MASK(field_no) (GENMASK(6, 0) << ICU_DMAC_DACK_SEL_SHIFT(field_no))
+#define ICU_DMAC_PREP_DACK_SEL(sel, field_no) ((sel) << ICU_DMAC_DACK_SEL_SHIFT(field_no))
+
/**
* struct rzv2h_icu_priv - Interrupt Control Unit controller private data structure.
* @base: Controller's base address
@@ -94,6 +110,45 @@ struct rzv2h_icu_priv {
raw_spinlock_t lock;
};
+void rzv2h_icu_register_dma_req_ack(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
+ u16 req_no, u8 ack_no)
+{
+ struct rzv2h_icu_priv *priv = platform_get_drvdata(icu_dev);
+ u32 icu_dmackselk, dmaack, dmaack_mask;
+ u32 icu_dmksely, dmareq, dmareq_mask;
+ u8 k, field_no;
+ u8 y, upper;
+
+ if (req_no >= RZV2H_ICU_DMAC_REQ_NO_MIN_FIX_OUTPUT)
+ req_no = RZV2H_ICU_DMAC_REQ_NO_DEFAULT;
+
+ if (ack_no >= RZV2H_ICU_DMAC_ACK_NO_MIN_FIX_OUTPUT)
+ ack_no = RZV2H_ICU_DMAC_ACK_NO_DEFAULT;
+
+ y = dmac_channel / 2;
+ upper = dmac_channel % 2;
+
+ dmareq = ICU_DMAC_PREP_DMAREQ(req_no, upper);
+ dmareq_mask = ICU_DMAC_DMAREQ_MASK(upper);
+
+ k = ack_no / 4;
+ field_no = ack_no % 4;
+
+ dmaack_mask = ICU_DMAC_DACK_SEL_MASK(field_no);
+ dmaack = ICU_DMAC_PREP_DACK_SEL(ack_no, field_no);
+
+ guard(raw_spinlock_irqsave)(&priv->lock);
+
+ icu_dmksely = readl(priv->base + ICU_DMkSELy(dmac_index, y));
+ icu_dmksely = (icu_dmksely & ~dmareq_mask) | dmareq;
+ writel(icu_dmksely, priv->base + ICU_DMkSELy(dmac_index, y));
+
+ icu_dmackselk = readl(priv->base + ICU_DMACKSELk(k));
+ icu_dmackselk = (icu_dmackselk & ~dmaack_mask) | dmaack;
+ writel(icu_dmackselk, priv->base + ICU_DMACKSELk(k));
+}
+EXPORT_SYMBOL_GPL(rzv2h_icu_register_dma_req_ack);
+
static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data)
{
return data->domain->host_data;
@@ -446,6 +501,7 @@ static int rzv2h_icu_init(struct device_node *node, struct device_node *parent)
goto put_dev;
}
+ platform_set_drvdata(pdev, rzv2h_icu_data);
rzv2h_icu_data->irqchip = &rzv2h_icu_chip;
rzv2h_icu_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
diff --git a/include/linux/irqchip/irq-renesas-rzv2h.h b/include/linux/irqchip/irq-renesas-rzv2h.h
new file mode 100644
index 000000000000..d06e01bf969b
--- /dev/null
+++ b/include/linux/irqchip/irq-renesas-rzv2h.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Renesas RZ/V2H(P) Interrupt Control Unit (ICU)
+ *
+ * Copyright (C) 2025 Renesas Electronics Corporation.
+ */
+
+#ifndef __LINUX_IRQ_RENESAS_RZV2H
+#define __LINUX_IRQ_RENESAS_RZV2H
+
+#include <linux/platform_device.h>
+
+#define RZV2H_ICU_DMAC_REQ_NO_DEFAULT 0x3ff
+#define RZV2H_ICU_DMAC_ACK_NO_DEFAULT 0x7f
+#define RZV2H_ICU_DMAC_REQ_NO_MIN_FIX_OUTPUT 0x1b5
+#define RZV2H_ICU_DMAC_ACK_NO_MIN_FIX_OUTPUT 0x50
+
+#ifdef CONFIG_RENESAS_RZV2H_ICU
+void rzv2h_icu_register_dma_req_ack(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
+ u16 req_no, u8 ack_no);
+#else
+static inline void rzv2h_icu_register_dma_req_ack(struct platform_device *icu_dev, u8 dmac_index,
+ u8 dmac_channel, u16 req_no, u8 ack_no) { }
+#endif
+
+#endif
--
2.34.1
Hi Fabrizio,
On Thu, 20 Feb 2025 at 16:01, Fabrizio Castro
<fabrizio.castro.jz@renesas.com> wrote:
> On the Renesas RZ/V2H(P) family of SoCs, DMAC IPs are connected
> to the Interrupt Control Unit (ICU).
> For DMA transfers, a request number and an ack number must be
> registered with the ICU, which means that the DMAC driver has
> to be able to instruct the ICU driver with the registration of
> such ids.
>
> Export rzv2h_icu_register_dma_req_ack() so that the DMA driver
> can register both ids in one go.
>
> Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> v3->v4:
> * No change.
> v2->v3:
> * Replaced rzv2h_icu_register_dma_req_ack with
> rzv2h_icu_register_dma_req_ack() in changelog.
> * Added dummy for rzv2h_icu_register_dma_req_ack().
> * Added Rb Thomas.
Thanks for the update!
> --- a/drivers/irqchip/irq-renesas-rzv2h.c
> +++ b/drivers/irqchip/irq-renesas-rzv2h.c
> @@ -94,6 +110,45 @@ struct rzv2h_icu_priv {
> raw_spinlock_t lock;
> };
>
> +void rzv2h_icu_register_dma_req_ack(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
> + u16 req_no, u8 ack_no)
> +{
> + struct rzv2h_icu_priv *priv = platform_get_drvdata(icu_dev);
> + u32 icu_dmackselk, dmaack, dmaack_mask;
> + u32 icu_dmksely, dmareq, dmareq_mask;
> + u8 k, field_no;
> + u8 y, upper;
> +
> + if (req_no >= RZV2H_ICU_DMAC_REQ_NO_MIN_FIX_OUTPUT)
> + req_no = RZV2H_ICU_DMAC_REQ_NO_DEFAULT;
What is the purpose of this check?
The hardware register field size is 10 bits, so I think it is better
to just limit it to 0x3ff.
Checking for RZV2H_ICU_DMAC_REQ_NO_MIN_FIX_OUTPUT means you will have to
update this check when a new SoC supports higher values than 0x1b5.
> +
> + if (ack_no >= RZV2H_ICU_DMAC_ACK_NO_MIN_FIX_OUTPUT)
> + ack_no = RZV2H_ICU_DMAC_ACK_NO_DEFAULT;
What is the purpose of this check?
There are only 23 DMACKSELk registers, so using
RZV2H_ICU_DMAC_ACK_NO_DEFAULT = 0x7f will write beyond the last
register below. And drivers/dma/sh/rz-dmac.c does call this
function with req_no = RZV2H_ICU_DMAC_REQ_NO_DEFAULT and ack_no =
RZV2H_ICU_DMAC_ACK_NO_DEFAULT...
> +
> + y = dmac_channel / 2;
> + upper = dmac_channel % 2;
> +
> + dmareq = ICU_DMAC_PREP_DMAREQ(req_no, upper);
> + dmareq_mask = ICU_DMAC_DMAREQ_MASK(upper);
> +
> + k = ack_no / 4;
> + field_no = ack_no % 4;
> +
> + dmaack_mask = ICU_DMAC_DACK_SEL_MASK(field_no);
> + dmaack = ICU_DMAC_PREP_DACK_SEL(ack_no, field_no);
> +
> + guard(raw_spinlock_irqsave)(&priv->lock);
> +
> + icu_dmksely = readl(priv->base + ICU_DMkSELy(dmac_index, y));
> + icu_dmksely = (icu_dmksely & ~dmareq_mask) | dmareq;
> + writel(icu_dmksely, priv->base + ICU_DMkSELy(dmac_index, y));
> +
> + icu_dmackselk = readl(priv->base + ICU_DMACKSELk(k));
> + icu_dmackselk = (icu_dmackselk & ~dmaack_mask) | dmaack;
> + writel(icu_dmackselk, priv->base + ICU_DMACKSELk(k));
> +}
> +EXPORT_SYMBOL_GPL(rzv2h_icu_register_dma_req_ack);
> +
> static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data)
> {
> return data->domain->host_data;
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
On Thu, Feb 20, 2025 at 3:06 PM Fabrizio Castro
<fabrizio.castro.jz@renesas.com> wrote:
>
> On the Renesas RZ/V2H(P) family of SoCs, DMAC IPs are connected
> to the Interrupt Control Unit (ICU).
> For DMA transfers, a request number and an ack number must be
> registered with the ICU, which means that the DMAC driver has
> to be able to instruct the ICU driver with the registration of
> such ids.
>
> Export rzv2h_icu_register_dma_req_ack() so that the DMA driver
> can register both ids in one go.
>
> Signed-off-by: Fabrizio Castro <fabrizio.castro.jz@renesas.com>
> Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> v3->v4:
> * No change.
> v2->v3:
> * Replaced rzv2h_icu_register_dma_req_ack with
> rzv2h_icu_register_dma_req_ack() in changelog.
> * Added dummy for rzv2h_icu_register_dma_req_ack().
> * Added Rb Thomas.
> v1->v2:
> * Improved macros.
> * Shared new macros for minimum values.
> ---
> drivers/irqchip/irq-renesas-rzv2h.c | 56 +++++++++++++++++++++++
> include/linux/irqchip/irq-renesas-rzv2h.h | 26 +++++++++++
> 2 files changed, 82 insertions(+)
> create mode 100644 include/linux/irqchip/irq-renesas-rzv2h.h
>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Cheers,
Prabhakar
> diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c
> index fe2d29e91026..a8e9feda73b0 100644
> --- a/drivers/irqchip/irq-renesas-rzv2h.c
> +++ b/drivers/irqchip/irq-renesas-rzv2h.c
> @@ -15,6 +15,7 @@
> #include <linux/err.h>
> #include <linux/io.h>
> #include <linux/irqchip.h>
> +#include <linux/irqchip/irq-renesas-rzv2h.h>
> #include <linux/irqdomain.h>
> #include <linux/of_address.h>
> #include <linux/of_platform.h>
> @@ -41,6 +42,8 @@
> #define ICU_TSCLR 0x24
> #define ICU_TITSR(k) (0x28 + (k) * 4)
> #define ICU_TSSR(k) (0x30 + (k) * 4)
> +#define ICU_DMkSELy(k, y) (0x420 + (k) * 0x20 + (y) * 4)
> +#define ICU_DMACKSELk(k) (0x500 + (k) * 4)
>
> /* NMI */
> #define ICU_NMI_EDGE_FALLING 0
> @@ -80,6 +83,19 @@
> #define ICU_TINT_EXTRACT_GPIOINT(x) FIELD_GET(GENMASK(31, 16), (x))
> #define ICU_PB5_TINT 0x55
>
> +/* DMAC */
> +#define ICU_DMAC_DkRQ_SEL_MASK GENMASK(9, 0)
> +
> +#define ICU_DMAC_DMAREQ_SHIFT(up) ((up) * 16)
> +#define ICU_DMAC_DMAREQ_MASK(up) (ICU_DMAC_DkRQ_SEL_MASK \
> + << ICU_DMAC_DMAREQ_SHIFT(up))
> +#define ICU_DMAC_PREP_DMAREQ(sel, up) (FIELD_PREP(ICU_DMAC_DkRQ_SEL_MASK, (sel)) \
> + << ICU_DMAC_DMAREQ_SHIFT(up))
> +
> +#define ICU_DMAC_DACK_SEL_SHIFT(field_no) ((field_no) * 8)
> +#define ICU_DMAC_DACK_SEL_MASK(field_no) (GENMASK(6, 0) << ICU_DMAC_DACK_SEL_SHIFT(field_no))
> +#define ICU_DMAC_PREP_DACK_SEL(sel, field_no) ((sel) << ICU_DMAC_DACK_SEL_SHIFT(field_no))
> +
> /**
> * struct rzv2h_icu_priv - Interrupt Control Unit controller private data structure.
> * @base: Controller's base address
> @@ -94,6 +110,45 @@ struct rzv2h_icu_priv {
> raw_spinlock_t lock;
> };
>
> +void rzv2h_icu_register_dma_req_ack(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
> + u16 req_no, u8 ack_no)
> +{
> + struct rzv2h_icu_priv *priv = platform_get_drvdata(icu_dev);
> + u32 icu_dmackselk, dmaack, dmaack_mask;
> + u32 icu_dmksely, dmareq, dmareq_mask;
> + u8 k, field_no;
> + u8 y, upper;
> +
> + if (req_no >= RZV2H_ICU_DMAC_REQ_NO_MIN_FIX_OUTPUT)
> + req_no = RZV2H_ICU_DMAC_REQ_NO_DEFAULT;
> +
> + if (ack_no >= RZV2H_ICU_DMAC_ACK_NO_MIN_FIX_OUTPUT)
> + ack_no = RZV2H_ICU_DMAC_ACK_NO_DEFAULT;
> +
> + y = dmac_channel / 2;
> + upper = dmac_channel % 2;
> +
> + dmareq = ICU_DMAC_PREP_DMAREQ(req_no, upper);
> + dmareq_mask = ICU_DMAC_DMAREQ_MASK(upper);
> +
> + k = ack_no / 4;
> + field_no = ack_no % 4;
> +
> + dmaack_mask = ICU_DMAC_DACK_SEL_MASK(field_no);
> + dmaack = ICU_DMAC_PREP_DACK_SEL(ack_no, field_no);
> +
> + guard(raw_spinlock_irqsave)(&priv->lock);
> +
> + icu_dmksely = readl(priv->base + ICU_DMkSELy(dmac_index, y));
> + icu_dmksely = (icu_dmksely & ~dmareq_mask) | dmareq;
> + writel(icu_dmksely, priv->base + ICU_DMkSELy(dmac_index, y));
> +
> + icu_dmackselk = readl(priv->base + ICU_DMACKSELk(k));
> + icu_dmackselk = (icu_dmackselk & ~dmaack_mask) | dmaack;
> + writel(icu_dmackselk, priv->base + ICU_DMACKSELk(k));
> +}
> +EXPORT_SYMBOL_GPL(rzv2h_icu_register_dma_req_ack);
> +
> static inline struct rzv2h_icu_priv *irq_data_to_priv(struct irq_data *data)
> {
> return data->domain->host_data;
> @@ -446,6 +501,7 @@ static int rzv2h_icu_init(struct device_node *node, struct device_node *parent)
> goto put_dev;
> }
>
> + platform_set_drvdata(pdev, rzv2h_icu_data);
> rzv2h_icu_data->irqchip = &rzv2h_icu_chip;
>
> rzv2h_icu_data->base = devm_of_iomap(&pdev->dev, pdev->dev.of_node, 0, NULL);
> diff --git a/include/linux/irqchip/irq-renesas-rzv2h.h b/include/linux/irqchip/irq-renesas-rzv2h.h
> new file mode 100644
> index 000000000000..d06e01bf969b
> --- /dev/null
> +++ b/include/linux/irqchip/irq-renesas-rzv2h.h
> @@ -0,0 +1,26 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Renesas RZ/V2H(P) Interrupt Control Unit (ICU)
> + *
> + * Copyright (C) 2025 Renesas Electronics Corporation.
> + */
> +
> +#ifndef __LINUX_IRQ_RENESAS_RZV2H
> +#define __LINUX_IRQ_RENESAS_RZV2H
> +
> +#include <linux/platform_device.h>
> +
> +#define RZV2H_ICU_DMAC_REQ_NO_DEFAULT 0x3ff
> +#define RZV2H_ICU_DMAC_ACK_NO_DEFAULT 0x7f
> +#define RZV2H_ICU_DMAC_REQ_NO_MIN_FIX_OUTPUT 0x1b5
> +#define RZV2H_ICU_DMAC_ACK_NO_MIN_FIX_OUTPUT 0x50
> +
> +#ifdef CONFIG_RENESAS_RZV2H_ICU
> +void rzv2h_icu_register_dma_req_ack(struct platform_device *icu_dev, u8 dmac_index, u8 dmac_channel,
> + u16 req_no, u8 ack_no);
> +#else
> +static inline void rzv2h_icu_register_dma_req_ack(struct platform_device *icu_dev, u8 dmac_index,
> + u8 dmac_channel, u16 req_no, u8 ack_no) { }
> +#endif
> +
> +#endif
> --
> 2.34.1
>
>
© 2016 - 2025 Red Hat, Inc.