* [PATCH 01/14] media: rzg2l-cru: Skip ICnMC configuration when ICnSVC is used
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 02/14] media: rzg2l-cru: Use only frame end interrupts Jacopo Mondi
` (13 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, stable, Jacopo Mondi
From: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
When the CRU is configured to use ICnSVC for virtual channel mapping,
as on the RZ/{G3E, V2H/P} SoC, the ICnMC register must not be
programmed.
Return early after setting up ICnSVC to avoid overriding the ICnMC
register, which is not applicable in this mode.
This prevents unintended register programming when ICnSVC is enabled.
Fixes: 3c5ca0a48bb0 ("media: rzg2l-cru: Drop function pointer to configure CSI")
Cc: stable@vger.kernel.org
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
[Rework to not break image format programming]
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
.../media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h | 1 +
drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 17 +++++++++++------
2 files changed, 12 insertions(+), 6 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
index a5a57369ef0e..10e62f2646d0 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
@@ -60,6 +60,7 @@
#define ICnMC_CSCTHR BIT(5)
#define ICnMC_INF(x) ((x) << 16)
#define ICnMC_VCSEL(x) ((x) << 22)
+#define ICnMC_VCSEL_MASK GENMASK(23, 22)
#define ICnMC_INF_MASK GENMASK(21, 16)
#define ICnMS_IA BIT(2)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 162e2ace6931..6aea7c244df1 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -262,19 +262,24 @@ static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
u8 csi_vc)
{
const struct rzg2l_cru_info *info = cru->info;
- u32 icnmc = ICnMC_INF(ip_fmt->datatype);
+ u32 icnmc = rzg2l_cru_read(cru, info->image_conv) & ~(ICnMC_INF_MASK |
+ ICnMC_VCSEL_MASK);
+ icnmc |= ICnMC_INF(ip_fmt->datatype);
+ /*
+ * VC filtering goes through SVC register on G3E/V2H.
+ *
+ * FIXME: virtual channel filtering is likely broken and only VC=0
+ * works.
+ */
if (cru->info->regs[ICnSVC]) {
rzg2l_cru_write(cru, ICnSVCNUM, csi_vc);
rzg2l_cru_write(cru, ICnSVC, ICnSVC_SVC0(0) | ICnSVC_SVC1(1) |
ICnSVC_SVC2(2) | ICnSVC_SVC3(3));
+ } else {
+ icnmc |= ICnMC_VCSEL(csi_vc);
}
- icnmc |= rzg2l_cru_read(cru, info->image_conv) & ~ICnMC_INF_MASK;
-
- /* Set virtual channel CSI2 */
- icnmc |= ICnMC_VCSEL(csi_vc);
-
rzg2l_cru_write(cru, info->image_conv, icnmc);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 02/14] media: rzg2l-cru: Use only frame end interrupts
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
2026-03-27 17:10 ` [PATCH 01/14] media: rzg2l-cru: Skip ICnMC configuration when ICnSVC is used Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 03/14] media: rzg2l-cru: Modernize spin_lock usage with cleanup.h Jacopo Mondi
` (12 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
On RZ/G3E the CRU driver relies on the frame end interrupt to detect the
completion of an active frame transfer when stopping DMA.
Update the driver to enable only frame end interrupts (CRUnIE2_FExE),
dropping the usage of the frame start interrupts, which is not required
for this operations flow.
Fix the interrupt status handling in the DMA stopping state by checking
the correct frame end status bits (FExS) instead of the frame start one
(FSxS). Add a dedicated CRUnINTS2_FExS() macro to reflect the actual
register bit layout.
This ensures that DMA stopping is triggered by the intended frame end
events and avoids incorrect interrupt handling.
Signed-off-by: Tommaso Merciai <tommaso.merciai.xr@bp.renesas.com>
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h | 1 +
drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 9 ++++-----
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
index 10e62f2646d0..5a6ac9cb09a4 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
@@ -19,6 +19,7 @@
#define CRUnINTS_SFS BIT(16)
+#define CRUnINTS2_FExS(x) BIT(((x) * 3) + 1)
#define CRUnINTS2_FSxS(x) BIT(((x) * 3))
#define CRUnRST_VRESETN BIT(0)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 6aea7c244df1..98b6afbc708d 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -440,7 +440,6 @@ static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
void rzg3e_cru_enable_interrupts(struct rzg2l_cru_dev *cru)
{
- rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FSxE(cru->svc_channel));
rzg2l_cru_write(cru, CRUnIE2, CRUnIE2_FExE(cru->svc_channel));
}
@@ -700,10 +699,10 @@ irqreturn_t rzg3e_cru_irq(int irq, void *data)
}
if (cru->state == RZG2L_CRU_DMA_STOPPING) {
- if (irq_status & CRUnINTS2_FSxS(0) ||
- irq_status & CRUnINTS2_FSxS(1) ||
- irq_status & CRUnINTS2_FSxS(2) ||
- irq_status & CRUnINTS2_FSxS(3))
+ if (irq_status & CRUnINTS2_FExS(0) ||
+ irq_status & CRUnINTS2_FExS(1) ||
+ irq_status & CRUnINTS2_FExS(2) ||
+ irq_status & CRUnINTS2_FExS(3))
dev_dbg(cru->dev, "IRQ while state stopping\n");
return IRQ_HANDLED;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 03/14] media: rzg2l-cru: Modernize spin_lock usage with cleanup.h
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
2026-03-27 17:10 ` [PATCH 01/14] media: rzg2l-cru: Skip ICnMC configuration when ICnSVC is used Jacopo Mondi
2026-03-27 17:10 ` [PATCH 02/14] media: rzg2l-cru: Use only frame end interrupts Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 04/14] media: rzg2l-cru: Use proper guard() in irq handler Jacopo Mondi
` (11 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
Use more modern constructs from cleanup.h to express the locking
sequences in the rzg2l driver.
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
.../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 32 +++++++---------------
1 file changed, 10 insertions(+), 22 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 98b6afbc708d..2d7ac9f37291 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -11,6 +11,7 @@
* Copyright (C) 2008 Magnus Damm
*/
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
@@ -110,10 +111,10 @@ static void return_unused_buffers(struct rzg2l_cru_dev *cru,
enum vb2_buffer_state state)
{
struct rzg2l_cru_buffer *buf, *node;
- unsigned long flags;
unsigned int i;
- spin_lock_irqsave(&cru->qlock, flags);
+ guard(spinlock_irqsave)(&cru->qlock);
+
for (i = 0; i < cru->num_buf; i++) {
if (cru->queue_buf[i]) {
vb2_buffer_done(&cru->queue_buf[i]->vb2_buf,
@@ -126,7 +127,6 @@ static void return_unused_buffers(struct rzg2l_cru_dev *cru,
vb2_buffer_done(&buf->vb.vb2_buf, state);
list_del(&buf->list);
}
- spin_unlock_irqrestore(&cru->qlock, flags);
}
static int rzg2l_cru_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
@@ -165,13 +165,9 @@ static void rzg2l_cru_buffer_queue(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vb->vb2_queue);
- unsigned long flags;
-
- spin_lock_irqsave(&cru->qlock, flags);
+ guard(spinlock_irqsave)(&cru->qlock);
list_add_tail(to_buf_list(vbuf), &cru->buf_list);
-
- spin_unlock_irqrestore(&cru->qlock, flags);
}
static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
@@ -465,7 +461,6 @@ void rzg2l_cru_disable_interrupts(struct rzg2l_cru_dev *cru)
int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
{
struct v4l2_mbus_framefmt *fmt = rzg2l_cru_ip_get_src_fmt(cru);
- unsigned long flags;
u8 csi_vc;
int ret;
@@ -475,7 +470,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
csi_vc = ret;
cru->svc_channel = csi_vc;
- spin_lock_irqsave(&cru->qlock, flags);
+ guard(spinlock_irqsave)(&cru->qlock);
/* Select a video input */
rzg2l_cru_write(cru, CRUnCTRL, CRUnCTRL_VINSEL(0));
@@ -492,7 +487,6 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
/* Initialize image convert */
ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc);
if (ret) {
- spin_unlock_irqrestore(&cru->qlock, flags);
return ret;
}
@@ -502,8 +496,6 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
/* Enable image processing reception */
rzg2l_cru_write(cru, ICnEN, ICnEN_ICEN);
- spin_unlock_irqrestore(&cru->qlock, flags);
-
return 0;
}
@@ -573,16 +565,15 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
{
struct rzg2l_cru_dev *cru = data;
unsigned int handled = 0;
- unsigned long flags;
u32 irq_status;
u32 amnmbs;
int slot;
- spin_lock_irqsave(&cru->qlock, flags);
+ guard(spinlock_irqsave)(&cru->qlock);
irq_status = rzg2l_cru_read(cru, CRUnINTS);
if (!irq_status)
- goto done;
+ return IRQ_RETVAL(handled);
handled = 1;
@@ -591,14 +582,14 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
/* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
if (cru->state == RZG2L_CRU_DMA_STOPPED) {
dev_dbg(cru->dev, "IRQ while state stopped\n");
- goto done;
+ return IRQ_RETVAL(handled);
}
/* Increase stop retries if capture status is 'RZG2L_CRU_DMA_STOPPING' */
if (cru->state == RZG2L_CRU_DMA_STOPPING) {
if (irq_status & CRUnINTS_SFS)
dev_dbg(cru->dev, "IRQ while state stopping\n");
- goto done;
+ return IRQ_RETVAL(handled);
}
/* Prepare for capture and update state */
@@ -621,7 +612,7 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
if (cru->state == RZG2L_CRU_DMA_STARTING) {
if (slot != 0) {
dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
- goto done;
+ return IRQ_RETVAL(handled);
}
dev_dbg(cru->dev, "Capture start synced!\n");
@@ -646,9 +637,6 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
/* Prepare for next frame */
rzg2l_cru_fill_hw_slot(cru, slot);
-done:
- spin_unlock_irqrestore(&cru->qlock, flags);
-
return IRQ_RETVAL(handled);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 04/14] media: rzg2l-cru: Use proper guard() in irq handler
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (2 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 03/14] media: rzg2l-cru: Modernize spin_lock usage with cleanup.h Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 05/14] media: rzg2l-cru: Remove locking from start/stop routines Jacopo Mondi
` (10 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
The irq handler uses a scoped_guard() that covers the whole function
body.
Replace it with a more appropriate guard() and reduce the indentation.
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
.../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 104 ++++++++++-----------
1 file changed, 52 insertions(+), 52 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 2d7ac9f37291..b041c72837c6 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -671,70 +671,70 @@ irqreturn_t rzg3e_cru_irq(int irq, void *data)
u32 irq_status;
int slot;
- scoped_guard(spinlock, &cru->qlock) {
- irq_status = rzg2l_cru_read(cru, CRUnINTS2);
- if (!irq_status)
- return IRQ_NONE;
+ guard(spinlock)(&cru->qlock);
- dev_dbg(cru->dev, "CRUnINTS2 0x%x\n", irq_status);
+ irq_status = rzg2l_cru_read(cru, CRUnINTS2);
+ if (!irq_status)
+ return IRQ_NONE;
- rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
+ dev_dbg(cru->dev, "CRUnINTS2 0x%x\n", irq_status);
- /* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
- if (cru->state == RZG2L_CRU_DMA_STOPPED) {
- dev_dbg(cru->dev, "IRQ while state stopped\n");
- return IRQ_HANDLED;
- }
+ rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
- if (cru->state == RZG2L_CRU_DMA_STOPPING) {
- if (irq_status & CRUnINTS2_FExS(0) ||
- irq_status & CRUnINTS2_FExS(1) ||
- irq_status & CRUnINTS2_FExS(2) ||
- irq_status & CRUnINTS2_FExS(3))
- dev_dbg(cru->dev, "IRQ while state stopping\n");
- return IRQ_HANDLED;
- }
+ /* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
+ if (cru->state == RZG2L_CRU_DMA_STOPPED) {
+ dev_dbg(cru->dev, "IRQ while state stopped\n");
+ return IRQ_HANDLED;
+ }
- slot = rzg3e_cru_get_current_slot(cru);
- if (slot < 0)
- return IRQ_HANDLED;
+ if (cru->state == RZG2L_CRU_DMA_STOPPING) {
+ if (irq_status & CRUnINTS2_FExS(0) ||
+ irq_status & CRUnINTS2_FExS(1) ||
+ irq_status & CRUnINTS2_FExS(2) ||
+ irq_status & CRUnINTS2_FExS(3))
+ dev_dbg(cru->dev, "IRQ while state stopping\n");
+ return IRQ_HANDLED;
+ }
- dev_dbg(cru->dev, "Current written slot: %d\n", slot);
- cru->buf_addr[slot] = 0;
-
- /*
- * To hand buffers back in a known order to userspace start
- * to capture first from slot 0.
- */
- if (cru->state == RZG2L_CRU_DMA_STARTING) {
- if (slot != 0) {
- dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
- return IRQ_HANDLED;
- }
- dev_dbg(cru->dev, "Capture start synced!\n");
- cru->state = RZG2L_CRU_DMA_RUNNING;
- }
+ slot = rzg3e_cru_get_current_slot(cru);
+ if (slot < 0)
+ return IRQ_HANDLED;
- /* Capture frame */
- if (cru->queue_buf[slot]) {
- struct vb2_v4l2_buffer *buf = cru->queue_buf[slot];
-
- buf->field = cru->format.field;
- buf->sequence = cru->sequence;
- buf->vb2_buf.timestamp = ktime_get_ns();
- vb2_buffer_done(&buf->vb2_buf, VB2_BUF_STATE_DONE);
- cru->queue_buf[slot] = NULL;
- } else {
- /* Scratch buffer was used, dropping frame. */
- dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
+ dev_dbg(cru->dev, "Current written slot: %d\n", slot);
+ cru->buf_addr[slot] = 0;
+
+ /*
+ * To hand buffers back in a known order to userspace start
+ * to capture first from slot 0.
+ */
+ if (cru->state == RZG2L_CRU_DMA_STARTING) {
+ if (slot != 0) {
+ dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
+ return IRQ_HANDLED;
}
+ dev_dbg(cru->dev, "Capture start synced!\n");
+ cru->state = RZG2L_CRU_DMA_RUNNING;
+ }
- cru->sequence++;
+ /* Capture frame */
+ if (cru->queue_buf[slot]) {
+ struct vb2_v4l2_buffer *buf = cru->queue_buf[slot];
- /* Prepare for next frame */
- rzg2l_cru_fill_hw_slot(cru, slot);
+ buf->field = cru->format.field;
+ buf->sequence = cru->sequence;
+ buf->vb2_buf.timestamp = ktime_get_ns();
+ vb2_buffer_done(&buf->vb2_buf, VB2_BUF_STATE_DONE);
+ cru->queue_buf[slot] = NULL;
+ } else {
+ /* Scratch buffer was used, dropping frame. */
+ dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
}
+ cru->sequence++;
+
+ /* Prepare for next frame */
+ rzg2l_cru_fill_hw_slot(cru, slot);
+
return IRQ_HANDLED;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 05/14] media: rzg2l-cru: Remove locking from start/stop routines
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (3 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 04/14] media: rzg2l-cru: Use proper guard() in irq handler Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 06/14] media: rzg2l-cru: Do not use irqsave when not needed Jacopo Mondi
` (9 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
The start/stop streaming routines do not need to lock the whole function
body against possible concurrent accesses to the CRU buffers or hardware
registers.
The stop function starts by disabling interrupts, and only this portion
needs to be protected not to race against a possible IRQ.
Once interrupts are disabled, nothing in the video device driver can race
and once the peripheral has been disabled we can release all pending
buffers.
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 18 +++++-------------
1 file changed, 5 insertions(+), 13 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index b041c72837c6..43b1d35fb963 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -341,23 +341,19 @@ bool rzg2l_fifo_empty(struct rzg2l_cru_dev *cru)
void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
{
unsigned int retries = 0;
- unsigned long flags;
u32 icnms;
- spin_lock_irqsave(&cru->qlock, flags);
-
- /* Disable and clear the interrupt */
- cru->info->disable_interrupts(cru);
+ scoped_guard(spinlock_irq, &cru->qlock) {
+ /* Disable and clear the interrupt */
+ cru->info->disable_interrupts(cru);
+ }
/* Stop the operation of image conversion */
rzg2l_cru_write(cru, ICnEN, 0);
/* Wait for streaming to stop */
- while ((rzg2l_cru_read(cru, ICnMS) & ICnMS_IA) && retries++ < RZG2L_RETRIES) {
- spin_unlock_irqrestore(&cru->qlock, flags);
+ while ((rzg2l_cru_read(cru, ICnMS) & ICnMS_IA) && retries++ < RZG2L_RETRIES)
msleep(RZG2L_TIMEOUT_MS);
- spin_lock_irqsave(&cru->qlock, flags);
- }
icnms = rzg2l_cru_read(cru, ICnMS) & ICnMS_IA;
if (icnms)
@@ -401,8 +397,6 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
/* Resets the image processing module */
rzg2l_cru_write(cru, CRUnRST, 0);
-
- spin_unlock_irqrestore(&cru->qlock, flags);
}
static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
@@ -470,8 +464,6 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
csi_vc = ret;
cru->svc_channel = csi_vc;
- guard(spinlock_irqsave)(&cru->qlock);
-
/* Select a video input */
rzg2l_cru_write(cru, CRUnCTRL, CRUnCTRL_VINSEL(0));
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 06/14] media: rzg2l-cru: Do not use irqsave when not needed
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (4 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 05/14] media: rzg2l-cru: Remove locking from start/stop routines Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 07/14] media: rzg2l-cru: Remove wrong locking comment Jacopo Mondi
` (8 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
The return_unused_buffers() and rzg2l_cru_buffer_queue() functions
are never called from an interrupt context, hence they do not need to
use the irqsave version of the spinlock primitives.
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 43b1d35fb963..2e94788c3a13 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -113,7 +113,7 @@ static void return_unused_buffers(struct rzg2l_cru_dev *cru,
struct rzg2l_cru_buffer *buf, *node;
unsigned int i;
- guard(spinlock_irqsave)(&cru->qlock);
+ guard(spinlock_irq)(&cru->qlock);
for (i = 0; i < cru->num_buf; i++) {
if (cru->queue_buf[i]) {
@@ -166,7 +166,7 @@ static void rzg2l_cru_buffer_queue(struct vb2_buffer *vb)
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vb->vb2_queue);
- guard(spinlock_irqsave)(&cru->qlock);
+ guard(spinlock_irq)(&cru->qlock);
list_add_tail(to_buf_list(vbuf), &cru->buf_list);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 07/14] media: rzg2l-cru: Remove wrong locking comment
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (5 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 06/14] media: rzg2l-cru: Do not use irqsave when not needed Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 08/14] media: rz2gl-cru: Introduce a spinlock for hw operations Jacopo Mondi
` (7 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
A function documented as "need to hold qlock before calling" actually
takes the lock itself.
Drop the comment and prepare to replace it with proper annotations where
appropriate.
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 2e94788c3a13..27079c17a54c 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -106,7 +106,6 @@ __rzg2l_cru_read_constant(struct rzg2l_cru_dev *cru, u32 offset)
__rzg2l_cru_read_constant(cru, offset) : \
__rzg2l_cru_read(cru, offset))
-/* Need to hold qlock before calling */
static void return_unused_buffers(struct rzg2l_cru_dev *cru,
enum vb2_buffer_state state)
{
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 08/14] media: rz2gl-cru: Introduce a spinlock for hw operations
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (6 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 07/14] media: rzg2l-cru: Remove wrong locking comment Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 09/14] media: rzg2l-cru: Split hw locking from buffers Jacopo Mondi
` (6 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
The CRU driver uses a single spinlock to protect the buffers queue and
the hardware operations.
This single spinlock is held for the whole duration of the interrupt
handler, causing all other driver's operations to freeze.
Under heavy system stress conditions with userspace not providing
buffers fast enough, this causes loss of frames.
Prepare to re-work the driver locking by introducing (but not using yet)
a new spinlock to protect the hardware registers programming.
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h | 10 +++++++---
drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 1 +
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index 3a200db15730..b46696a0012b 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -109,7 +109,6 @@ struct rzg2l_cru_info {
* @v4l2_dev: V4L2 device
* @num_buf: Holds the current number of buffers enabled
* @svc_channel: SVC0/1/2/3 to use for RZ/G3E
- * @buf_addr: Memory addresses where current video data is written.
* @notifier: V4L2 asynchronous subdevs notifier
*
* @ip: Image processing subdev info
@@ -118,6 +117,10 @@ struct rzg2l_cru_info {
* @mdev_lock: protects the count, notifier and csi members
* @pad: media pad for the video device entity
*
+ * @hw_lock: protects the slot counter, hardware programming of
+ * slot addresses and the @buf_addr[] list
+ * @buf_addr: Memory addresses where current video data is written
+ *
* @lock: protects @queue
* @queue: vb2 buffers queue
* @scratch: cpu address for scratch buffer
@@ -147,8 +150,6 @@ struct rzg2l_cru_dev {
u8 num_buf;
u8 svc_channel;
- dma_addr_t buf_addr[RZG2L_CRU_HW_BUFFER_DEFAULT];
-
struct v4l2_async_notifier notifier;
struct rzg2l_cru_ip ip;
@@ -157,6 +158,9 @@ struct rzg2l_cru_dev {
struct mutex mdev_lock;
struct media_pad pad;
+ spinlock_t hw_lock;
+ dma_addr_t buf_addr[RZG2L_CRU_HW_BUFFER_DEFAULT];
+
struct mutex lock;
struct vb2_queue queue;
void *scratch;
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 27079c17a54c..a79b17e146bf 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -844,6 +844,7 @@ int rzg2l_cru_dma_register(struct rzg2l_cru_dev *cru)
mutex_init(&cru->lock);
INIT_LIST_HEAD(&cru->buf_list);
+ spin_lock_init(&cru->hw_lock);
spin_lock_init(&cru->qlock);
cru->state = RZG2L_CRU_DMA_STOPPED;
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 09/14] media: rzg2l-cru: Split hw locking from buffers
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (7 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 08/14] media: rz2gl-cru: Introduce a spinlock for hw operations Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 10/14] media: rzg2l-cru: Manually track active slot number Jacopo Mondi
` (5 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
Split the locking between a spinlock dedicated to protect the hardware
slots programming (hw_lock) and one lock (qlock) to protect the queue of
buffers submitted by userspace.
Do not rework the locking strategy yet but start simply by splitting the
locking in two.
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
.../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 32 +++++++++++++---------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index a79b17e146bf..9406a089ec9f 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -112,19 +112,21 @@ static void return_unused_buffers(struct rzg2l_cru_dev *cru,
struct rzg2l_cru_buffer *buf, *node;
unsigned int i;
- guard(spinlock_irq)(&cru->qlock);
-
- for (i = 0; i < cru->num_buf; i++) {
- if (cru->queue_buf[i]) {
- vb2_buffer_done(&cru->queue_buf[i]->vb2_buf,
- state);
- cru->queue_buf[i] = NULL;
+ scoped_guard(spinlock_irq, &cru->hw_lock) {
+ for (i = 0; i < cru->num_buf; i++) {
+ if (cru->queue_buf[i]) {
+ vb2_buffer_done(&cru->queue_buf[i]->vb2_buf,
+ state);
+ cru->queue_buf[i] = NULL;
+ }
}
}
- list_for_each_entry_safe(buf, node, &cru->buf_list, list) {
- vb2_buffer_done(&buf->vb.vb2_buf, state);
- list_del(&buf->list);
+ scoped_guard(spinlock_irq, &cru->qlock) {
+ list_for_each_entry_safe(buf, node, &cru->buf_list, list) {
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ list_del(&buf->list);
+ }
}
}
@@ -198,12 +200,16 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
struct rzg2l_cru_buffer *buf;
dma_addr_t phys_addr;
+ lockdep_assert_held(&cru->hw_lock);
+
/* A already populated slot shall never be overwritten. */
if (WARN_ON(cru->queue_buf[slot]))
return;
dev_dbg(cru->dev, "Filling HW slot: %d\n", slot);
+ guard(spinlock)(&cru->qlock);
+
if (list_empty(&cru->buf_list)) {
cru->queue_buf[slot] = NULL;
phys_addr = cru->scratch_phys;
@@ -342,7 +348,7 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
unsigned int retries = 0;
u32 icnms;
- scoped_guard(spinlock_irq, &cru->qlock) {
+ scoped_guard(spinlock_irq, &cru->hw_lock) {
/* Disable and clear the interrupt */
cru->info->disable_interrupts(cru);
}
@@ -560,7 +566,7 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
u32 amnmbs;
int slot;
- guard(spinlock_irqsave)(&cru->qlock);
+ guard(spinlock_irqsave)(&cru->hw_lock);
irq_status = rzg2l_cru_read(cru, CRUnINTS);
if (!irq_status)
@@ -662,7 +668,7 @@ irqreturn_t rzg3e_cru_irq(int irq, void *data)
u32 irq_status;
int slot;
- guard(spinlock)(&cru->qlock);
+ guard(spinlock)(&cru->hw_lock);
irq_status = rzg2l_cru_read(cru, CRUnINTS2);
if (!irq_status)
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 10/14] media: rzg2l-cru: Manually track active slot number
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (8 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 09/14] media: rzg2l-cru: Split hw locking from buffers Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 11/14] media: rz2gl-cru: Return pending buffers in order Jacopo Mondi
` (4 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
The CRU cycles over the hardware slots where the destination address for
the next frame has to be programmed.
The RZ/G2L version of the IP has a register that tells which is the
last used slot by the hardware but, unfortunately, such register is not
available on RZ/G3E and RZ/V2H(P).
The driver currently compares the value of the AMnMADRSL/H register
which report "the memory address which the current video data was
written to" and compares it with the address programmed in the slots.
This heuristic requires a bit of book keeping and proper locking. As the
driver handles the FrameEnd interrupt, it's way easier to keep track
of the slot that has been used by ourselves with a driver variable.
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
.../media/platform/renesas/rzg2l-cru/rzg2l-cru.h | 7 +++--
.../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 35 ++++------------------
2 files changed, 10 insertions(+), 32 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index b46696a0012b..bc66b0c8c15e 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -108,6 +108,7 @@ struct rzg2l_cru_info {
* @vdev: V4L2 video device associated with CRU
* @v4l2_dev: V4L2 device
* @num_buf: Holds the current number of buffers enabled
+ *
* @svc_channel: SVC0/1/2/3 to use for RZ/G3E
* @notifier: V4L2 asynchronous subdevs notifier
*
@@ -117,9 +118,10 @@ struct rzg2l_cru_info {
* @mdev_lock: protects the count, notifier and csi members
* @pad: media pad for the video device entity
*
- * @hw_lock: protects the slot counter, hardware programming of
- * slot addresses and the @buf_addr[] list
+ * @hw_lock: protects the @active_slot counter, hardware programming
+ * of slot addresses and the @buf_addr[] list
* @buf_addr: Memory addresses where current video data is written
+ * @active_slot: The slot in use
*
* @lock: protects @queue
* @queue: vb2 buffers queue
@@ -160,6 +162,7 @@ struct rzg2l_cru_dev {
spinlock_t hw_lock;
dma_addr_t buf_addr[RZG2L_CRU_HW_BUFFER_DEFAULT];
+ unsigned int active_slot;
struct mutex lock;
struct vb2_queue queue;
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 9406a089ec9f..17e0153052e1 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -637,31 +637,6 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
return IRQ_RETVAL(handled);
}
-static int rzg3e_cru_get_current_slot(struct rzg2l_cru_dev *cru)
-{
- u64 amnmadrs;
- int slot;
-
- /*
- * When AMnMADRSL is read, AMnMADRSH of the higher-order
- * address also latches the address.
- *
- * AMnMADRSH must be read after AMnMADRSL has been read.
- */
- amnmadrs = rzg2l_cru_read(cru, AMnMADRSL);
- amnmadrs |= (u64)rzg2l_cru_read(cru, AMnMADRSH) << 32;
-
- /* Ensure amnmadrs is within this buffer range */
- for (slot = 0; slot < cru->num_buf; slot++) {
- if (amnmadrs >= cru->buf_addr[slot] &&
- amnmadrs < cru->buf_addr[slot] + cru->format.sizeimage)
- return slot;
- }
-
- dev_err(cru->dev, "Invalid MB address 0x%llx (out of range)\n", amnmadrs);
- return -EINVAL;
-}
-
irqreturn_t rzg3e_cru_irq(int irq, void *data)
{
struct rzg2l_cru_dev *cru = data;
@@ -693,9 +668,8 @@ irqreturn_t rzg3e_cru_irq(int irq, void *data)
return IRQ_HANDLED;
}
- slot = rzg3e_cru_get_current_slot(cru);
- if (slot < 0)
- return IRQ_HANDLED;
+ slot = cru->active_slot;
+ cru->active_slot = (cru->active_slot + 1) % cru->num_buf;
dev_dbg(cru->dev, "Current written slot: %d\n", slot);
cru->buf_addr[slot] = 0;
@@ -762,6 +736,9 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
goto assert_aresetn;
}
+ cru->active_slot = 0;
+ cru->sequence = 0;
+
/* Allocate scratch buffer */
cru->scratch = dma_alloc_coherent(cru->dev, cru->format.sizeimage,
&cru->scratch_phys, GFP_KERNEL);
@@ -772,8 +749,6 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
goto assert_presetn;
}
- cru->sequence = 0;
-
ret = rzg2l_cru_set_stream(cru, 1);
if (ret) {
return_unused_buffers(cru, VB2_BUF_STATE_QUEUED);
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 11/14] media: rz2gl-cru: Return pending buffers in order
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (9 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 10/14] media: rzg2l-cru: Manually track active slot number Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 12/14] media: rzg2l-cru: Rework rzg2l_cru_fill_hw_slot() Jacopo Mondi
` (3 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
Buffers are programmed into slots in queueing order.
When returning pending buffers we can't simply start from the first slot
but we should actually iterate slots starting from the one is use. The
rzg3e_cru_irq() handler already uses 'active_slot', make rzg2l_cru_irq()
use it as well to know where to start iterating from.
As the pattern of iterating over slots in order will be used for slots
programming in the next patches, provide an helper macro to do that.
While at it, rename return_unused_buffers() to rzg2l_cru_return_buffers().
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
.../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 68 +++++++++++++++-------
1 file changed, 47 insertions(+), 21 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 17e0153052e1..a6b606c63f90 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -43,6 +43,24 @@ struct rzg2l_cru_buffer {
#define to_buf_list(vb2_buffer) \
(&container_of(vb2_buffer, struct rzg2l_cru_buffer, vb)->list)
+/*
+ * The CRU hardware cycles over its slots when transferring frames. All drivers
+ * structure that contains programming data for the slots, such as the memory
+ * destination addresses have to be iterated as they were circular buffers.
+ *
+ * Provide here utilities to iterate over slots and the associated data.
+ */
+static inline unsigned int rzg2l_cru_slot_next(struct rzg2l_cru_dev *cru,
+ unsigned int slot)
+{
+ return (slot + 1) % cru->num_buf;
+}
+
+/* Start cycling on cru slots from the one after 'start'. */
+#define for_each_cru_slot_from(cru, slot, start) \
+ for (slot = rzg2l_cru_slot_next(cru, start); \
+ slot != start; slot = rzg2l_cru_slot_next(cru, slot))
+
/* -----------------------------------------------------------------------------
* DMA operations
*/
@@ -106,28 +124,36 @@ __rzg2l_cru_read_constant(struct rzg2l_cru_dev *cru, u32 offset)
__rzg2l_cru_read_constant(cru, offset) : \
__rzg2l_cru_read(cru, offset))
-static void return_unused_buffers(struct rzg2l_cru_dev *cru,
- enum vb2_buffer_state state)
+static void rzg2l_cru_return_buffers(struct rzg2l_cru_dev *cru,
+ enum vb2_buffer_state state)
{
struct rzg2l_cru_buffer *buf, *node;
- unsigned int i;
scoped_guard(spinlock_irq, &cru->hw_lock) {
- for (i = 0; i < cru->num_buf; i++) {
- if (cru->queue_buf[i]) {
- vb2_buffer_done(&cru->queue_buf[i]->vb2_buf,
- state);
- cru->queue_buf[i] = NULL;
- }
+ /* Return the buffer in progress first, if not completed yet. */
+ unsigned int slot = cru->active_slot;
+
+ if (cru->queue_buf[slot]) {
+ vb2_buffer_done(&cru->queue_buf[slot]->vb2_buf, state);
+ cru->queue_buf[slot] = NULL;
}
- }
- scoped_guard(spinlock_irq, &cru->qlock) {
- list_for_each_entry_safe(buf, node, &cru->buf_list, list) {
- vb2_buffer_done(&buf->vb.vb2_buf, state);
- list_del(&buf->list);
+ /* Return all the pending buffers after the active one. */
+ for_each_cru_slot_from(cru, slot, cru->active_slot) {
+ if (!cru->queue_buf[slot])
+ continue;
+
+ vb2_buffer_done(&cru->queue_buf[slot]->vb2_buf, state);
+ cru->queue_buf[slot] = NULL;
}
}
+
+ guard(spinlock_irq)(&cru->qlock);
+
+ list_for_each_entry_safe(buf, node, &cru->buf_list, list) {
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ list_del(&buf->list);
+ }
}
static int rzg2l_cru_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
@@ -591,16 +617,16 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
/* Prepare for capture and update state */
amnmbs = rzg2l_cru_read(cru, AMnMBS);
- slot = amnmbs & AMnMBS_MBSTS;
+ cru->active_slot = amnmbs & AMnMBS_MBSTS;
/*
* AMnMBS.MBSTS indicates the destination of Memory Bank (MB).
* Recalculate to get the current transfer complete MB.
*/
- if (slot == 0)
+ if (cru->active_slot == 0)
slot = cru->num_buf - 1;
else
- slot--;
+ slot = cru->active_slot - 1;
/*
* To hand buffers back in a known order to userspace start
@@ -669,7 +695,7 @@ irqreturn_t rzg3e_cru_irq(int irq, void *data)
}
slot = cru->active_slot;
- cru->active_slot = (cru->active_slot + 1) % cru->num_buf;
+ cru->active_slot = rzg2l_cru_slot_next(cru, cru->active_slot);
dev_dbg(cru->dev, "Current written slot: %d\n", slot);
cru->buf_addr[slot] = 0;
@@ -743,7 +769,7 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
cru->scratch = dma_alloc_coherent(cru->dev, cru->format.sizeimage,
&cru->scratch_phys, GFP_KERNEL);
if (!cru->scratch) {
- return_unused_buffers(cru, VB2_BUF_STATE_QUEUED);
+ rzg2l_cru_return_buffers(cru, VB2_BUF_STATE_QUEUED);
dev_err(cru->dev, "Failed to allocate scratch buffer\n");
ret = -ENOMEM;
goto assert_presetn;
@@ -751,7 +777,7 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
ret = rzg2l_cru_set_stream(cru, 1);
if (ret) {
- return_unused_buffers(cru, VB2_BUF_STATE_QUEUED);
+ rzg2l_cru_return_buffers(cru, VB2_BUF_STATE_QUEUED);
goto out;
}
@@ -788,7 +814,7 @@ static void rzg2l_cru_stop_streaming_vq(struct vb2_queue *vq)
dma_free_coherent(cru->dev, cru->format.sizeimage,
cru->scratch, cru->scratch_phys);
- return_unused_buffers(cru, VB2_BUF_STATE_ERROR);
+ rzg2l_cru_return_buffers(cru, VB2_BUF_STATE_ERROR);
reset_control_assert(cru->presetn);
clk_disable_unprepare(cru->vclk);
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 12/14] media: rzg2l-cru: Rework rzg2l_cru_fill_hw_slot()
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (10 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 11/14] media: rz2gl-cru: Return pending buffers in order Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 13/14] media: rzg2l-cru: Remove the 'state' variable Jacopo Mondi
` (2 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Daniel Scally,
Jacopo Mondi
From: Daniel Scally <dan.scally+renesas@ideasonboard.com>
The current implementation of rzg2l_cru_fill_hw_slot() results in the
artificial loss of frames. At present whenever a frame-complete IRQ
is received the driver fills the hardware slot that was just written
to with the address of the next buffer in the driver's queue. If the
queue is empty, that hardware slot's address is set to the address of
the scratch buffer to enable the capture loop to keep running. There
is a minimum of a two-frame delay before that slot will be written to
however, and in the intervening period userspace may queue more
buffers which could be used.
To resolve the issue rework rzg2l_cru_fill_hw_slot() so that it
iteratively fills all slots from the queue which currently do not
have a buffer assigned, until the queue is empty. The scratch
buffer is only resorted to in the event that the queue is empty and
the next slot that will be written to does not already have a buffer
assigned.
Signed-off-by: Daniel Scally <dan.scally+renesas@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
.../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 62 ++++++++++++----------
1 file changed, 35 insertions(+), 27 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index a6b606c63f90..45b58e2183bf 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -215,49 +215,52 @@ static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
}
/*
- * Moves a buffer from the queue to the HW slot. If no buffer is
- * available use the scratch buffer. The scratch buffer is never
- * returned to userspace, its only function is to enable the capture
- * loop to keep running.
+ * Move as many buffers as possible from the queue to HW slots If no buffer is
+ * available use the scratch buffer. The scratch buffer is never returned to
+ * userspace, its only function is to enable the capture loop to keep running.
+ *
+ * @cru: the CRU device
+ * @slot: the slot that has just completed
*/
static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
{
- struct vb2_v4l2_buffer *vbuf;
struct rzg2l_cru_buffer *buf;
+ struct vb2_v4l2_buffer *vbuf;
+ unsigned int next_slot;
dma_addr_t phys_addr;
lockdep_assert_held(&cru->hw_lock);
- /* A already populated slot shall never be overwritten. */
- if (WARN_ON(cru->queue_buf[slot]))
- return;
+ /* Find the next slot which hasn't a valid address programmed. */
+ for_each_cru_slot_from(cru, next_slot, slot) {
+ if (cru->queue_buf[next_slot])
+ continue;
- dev_dbg(cru->dev, "Filling HW slot: %d\n", slot);
+ scoped_guard(spinlock_irqsave, &cru->qlock) {
+ buf = list_first_entry_or_null(&cru->buf_list,
+ struct rzg2l_cru_buffer, list);
+ if (buf)
+ list_del_init(&buf->list);
+ }
- guard(spinlock)(&cru->qlock);
+ if (!buf) {
+ /* Direct frames to the scratch buffer. */
+ phys_addr = cru->scratch_phys;
+ cru->queue_buf[next_slot] = NULL;
+ rzg2l_cru_set_slot_addr(cru, next_slot, phys_addr);
+ return;
+ }
- if (list_empty(&cru->buf_list)) {
- cru->queue_buf[slot] = NULL;
- phys_addr = cru->scratch_phys;
- } else {
- /* Keep track of buffer we give to HW */
- buf = list_entry(cru->buf_list.next,
- struct rzg2l_cru_buffer, list);
vbuf = &buf->vb;
- list_del_init(to_buf_list(vbuf));
- cru->queue_buf[slot] = vbuf;
-
- /* Setup DMA */
+ cru->queue_buf[next_slot] = vbuf;
phys_addr = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, 0);
+ rzg2l_cru_set_slot_addr(cru, next_slot, phys_addr);
}
-
- rzg2l_cru_set_slot_addr(cru, slot, phys_addr);
}
static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
{
const struct rzg2l_cru_info *info = cru->info;
- unsigned int slot;
u32 amnaxiattr;
/*
@@ -266,8 +269,14 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
*/
rzg2l_cru_write(cru, AMnMBVALID, AMnMBVALID_MBVALID(cru->num_buf - 1));
- for (slot = 0; slot < cru->num_buf; slot++)
- rzg2l_cru_fill_hw_slot(cru, slot);
+ /*
+ * Program slot#0 with the first available buffer, if any. Pass to the
+ * function 'num_buf - 1' as rzg2l_cru_fill_hw_slot() calculates which
+ * is the next slot to program.
+ */
+ scoped_guard(spinlock_irq, &cru->hw_lock) {
+ rzg2l_cru_fill_hw_slot(cru, cru->num_buf - 1);
+ }
if (info->has_stride) {
u32 stride = cru->format.bytesperline;
@@ -698,7 +707,6 @@ irqreturn_t rzg3e_cru_irq(int irq, void *data)
cru->active_slot = rzg2l_cru_slot_next(cru, cru->active_slot);
dev_dbg(cru->dev, "Current written slot: %d\n", slot);
- cru->buf_addr[slot] = 0;
/*
* To hand buffers back in a known order to userspace start
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 13/14] media: rzg2l-cru: Remove the 'state' variable
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (11 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 12/14] media: rzg2l-cru: Rework rzg2l_cru_fill_hw_slot() Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:10 ` [PATCH 14/14] media: rzg2l-cru: Simplify irq return value handling Jacopo Mondi
2026-03-27 17:25 ` [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Lad, Prabhakar
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
The cru driver uses a 'state' variable for debugging purpose in the
interrupt handler. The state is used to detect invalid usage conditions
that are not meant to happen unless the driver has a bug in handling the
stop and start conditions.
Remove the state variable which seems to be a debugging leftover.
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
.../media/platform/renesas/rzg2l-cru/rzg2l-cru.h | 15 -----
.../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 74 +---------------------
2 files changed, 3 insertions(+), 86 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index bc66b0c8c15e..56359491739e 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -36,20 +36,6 @@ enum rzg2l_csi2_pads {
struct rzg2l_cru_dev;
-/**
- * enum rzg2l_cru_dma_state - DMA states
- * @RZG2L_CRU_DMA_STOPPED: No operation in progress
- * @RZG2L_CRU_DMA_STARTING: Capture starting up
- * @RZG2L_CRU_DMA_RUNNING: Operation in progress have buffers
- * @RZG2L_CRU_DMA_STOPPING: Stopping operation
- */
-enum rzg2l_cru_dma_state {
- RZG2L_CRU_DMA_STOPPED = 0,
- RZG2L_CRU_DMA_STARTING,
- RZG2L_CRU_DMA_RUNNING,
- RZG2L_CRU_DMA_STOPPING,
-};
-
struct rzg2l_cru_csi {
struct v4l2_async_connection *asd;
struct v4l2_subdev *subdev;
@@ -173,7 +159,6 @@ struct rzg2l_cru_dev {
struct vb2_v4l2_buffer *queue_buf[RZG2L_CRU_HW_BUFFER_MAX];
struct list_head buf_list;
unsigned int sequence;
- enum rzg2l_cru_dma_state state;
struct v4l2_pix_format format;
};
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 45b58e2183bf..30424e2b6cc0 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -399,8 +399,6 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
if (icnms)
dev_err(cru->dev, "Failed stop HW, something is seriously broken\n");
- cru->state = RZG2L_CRU_DMA_STOPPED;
-
/* Wait until the FIFO becomes empty */
for (retries = 5; retries > 0; retries--) {
if (cru->info->fifo_empty(cru))
@@ -588,8 +586,6 @@ static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
static void rzg2l_cru_stop_streaming(struct rzg2l_cru_dev *cru)
{
- cru->state = RZG2L_CRU_DMA_STOPPING;
-
rzg2l_cru_set_stream(cru, 0);
}
@@ -601,8 +597,6 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
u32 amnmbs;
int slot;
- guard(spinlock_irqsave)(&cru->hw_lock);
-
irq_status = rzg2l_cru_read(cru, CRUnINTS);
if (!irq_status)
return IRQ_RETVAL(handled);
@@ -611,20 +605,9 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
rzg2l_cru_write(cru, CRUnINTS, rzg2l_cru_read(cru, CRUnINTS));
- /* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
- if (cru->state == RZG2L_CRU_DMA_STOPPED) {
- dev_dbg(cru->dev, "IRQ while state stopped\n");
- return IRQ_RETVAL(handled);
- }
-
- /* Increase stop retries if capture status is 'RZG2L_CRU_DMA_STOPPING' */
- if (cru->state == RZG2L_CRU_DMA_STOPPING) {
- if (irq_status & CRUnINTS_SFS)
- dev_dbg(cru->dev, "IRQ while state stopping\n");
- return IRQ_RETVAL(handled);
- }
+ /* Calculate slot and prepare for new capture. */
+ guard(spinlock_irqsave)(&cru->hw_lock);
- /* Prepare for capture and update state */
amnmbs = rzg2l_cru_read(cru, AMnMBS);
cru->active_slot = amnmbs & AMnMBS_MBSTS;
@@ -637,20 +620,6 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
else
slot = cru->active_slot - 1;
- /*
- * To hand buffers back in a known order to userspace start
- * to capture first from slot 0.
- */
- if (cru->state == RZG2L_CRU_DMA_STARTING) {
- if (slot != 0) {
- dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
- return IRQ_RETVAL(handled);
- }
-
- dev_dbg(cru->dev, "Capture start synced!\n");
- cru->state = RZG2L_CRU_DMA_RUNNING;
- }
-
/* Capture frame */
if (cru->queue_buf[slot]) {
cru->queue_buf[slot]->field = cru->format.field;
@@ -678,49 +647,18 @@ irqreturn_t rzg3e_cru_irq(int irq, void *data)
u32 irq_status;
int slot;
- guard(spinlock)(&cru->hw_lock);
-
irq_status = rzg2l_cru_read(cru, CRUnINTS2);
if (!irq_status)
return IRQ_NONE;
- dev_dbg(cru->dev, "CRUnINTS2 0x%x\n", irq_status);
-
rzg2l_cru_write(cru, CRUnINTS2, rzg2l_cru_read(cru, CRUnINTS2));
- /* Nothing to do if capture status is 'RZG2L_CRU_DMA_STOPPED' */
- if (cru->state == RZG2L_CRU_DMA_STOPPED) {
- dev_dbg(cru->dev, "IRQ while state stopped\n");
- return IRQ_HANDLED;
- }
-
- if (cru->state == RZG2L_CRU_DMA_STOPPING) {
- if (irq_status & CRUnINTS2_FExS(0) ||
- irq_status & CRUnINTS2_FExS(1) ||
- irq_status & CRUnINTS2_FExS(2) ||
- irq_status & CRUnINTS2_FExS(3))
- dev_dbg(cru->dev, "IRQ while state stopping\n");
- return IRQ_HANDLED;
- }
-
+ guard(spinlock)(&cru->hw_lock);
slot = cru->active_slot;
cru->active_slot = rzg2l_cru_slot_next(cru, cru->active_slot);
dev_dbg(cru->dev, "Current written slot: %d\n", slot);
- /*
- * To hand buffers back in a known order to userspace start
- * to capture first from slot 0.
- */
- if (cru->state == RZG2L_CRU_DMA_STARTING) {
- if (slot != 0) {
- dev_dbg(cru->dev, "Starting sync slot: %d\n", slot);
- return IRQ_HANDLED;
- }
- dev_dbg(cru->dev, "Capture start synced!\n");
- cru->state = RZG2L_CRU_DMA_RUNNING;
- }
-
/* Capture frame */
if (cru->queue_buf[slot]) {
struct vb2_v4l2_buffer *buf = cru->queue_buf[slot];
@@ -730,9 +668,6 @@ irqreturn_t rzg3e_cru_irq(int irq, void *data)
buf->vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&buf->vb2_buf, VB2_BUF_STATE_DONE);
cru->queue_buf[slot] = NULL;
- } else {
- /* Scratch buffer was used, dropping frame. */
- dev_dbg(cru->dev, "Dropping frame %u\n", cru->sequence);
}
cru->sequence++;
@@ -789,7 +724,6 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
goto out;
}
- cru->state = RZG2L_CRU_DMA_STARTING;
dev_dbg(cru->dev, "Starting to capture\n");
return 0;
@@ -862,8 +796,6 @@ int rzg2l_cru_dma_register(struct rzg2l_cru_dev *cru)
spin_lock_init(&cru->hw_lock);
spin_lock_init(&cru->qlock);
- cru->state = RZG2L_CRU_DMA_STOPPED;
-
for (i = 0; i < RZG2L_CRU_HW_BUFFER_MAX; i++)
cru->queue_buf[i] = NULL;
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* [PATCH 14/14] media: rzg2l-cru: Simplify irq return value handling
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (12 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 13/14] media: rzg2l-cru: Remove the 'state' variable Jacopo Mondi
@ 2026-03-27 17:10 ` Jacopo Mondi
2026-03-27 17:25 ` [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Lad, Prabhakar
14 siblings, 0 replies; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-27 17:10 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai
Cc: Daniel Scally, Barnabás Pőcze, Lad Prabhakar,
linux-media, linux-kernel, Jacopo Mondi, Jacopo Mondi
From: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
The rzg2l_cru_irq() irq handler uses a local variable to store the
handler return value.
Simplify it by using IRQ_NONE and IRQ_HANDLED.
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
---
drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index 30424e2b6cc0..e81573d0a84c 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -592,16 +592,13 @@ static void rzg2l_cru_stop_streaming(struct rzg2l_cru_dev *cru)
irqreturn_t rzg2l_cru_irq(int irq, void *data)
{
struct rzg2l_cru_dev *cru = data;
- unsigned int handled = 0;
u32 irq_status;
u32 amnmbs;
int slot;
irq_status = rzg2l_cru_read(cru, CRUnINTS);
if (!irq_status)
- return IRQ_RETVAL(handled);
-
- handled = 1;
+ return IRQ_NONE;
rzg2l_cru_write(cru, CRUnINTS, rzg2l_cru_read(cru, CRUnINTS));
@@ -638,7 +635,7 @@ irqreturn_t rzg2l_cru_irq(int irq, void *data)
/* Prepare for next frame */
rzg2l_cru_fill_hw_slot(cru, slot);
- return IRQ_RETVAL(handled);
+ return IRQ_HANDLED;
}
irqreturn_t rzg3e_cru_irq(int irq, void *data)
--
2.53.0
^ permalink raw reply related [flat|nested] 18+ messages in thread* Re: [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E
2026-03-27 17:10 [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Jacopo Mondi
` (13 preceding siblings ...)
2026-03-27 17:10 ` [PATCH 14/14] media: rzg2l-cru: Simplify irq return value handling Jacopo Mondi
@ 2026-03-27 17:25 ` Lad, Prabhakar
2026-03-28 11:55 ` Jacopo Mondi
14 siblings, 1 reply; 18+ messages in thread
From: Lad, Prabhakar @ 2026-03-27 17:25 UTC (permalink / raw)
To: Jacopo Mondi
Cc: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai, Daniel Scally,
Barnabás Pőcze, Lad Prabhakar, linux-media,
linux-kernel, stable, Jacopo Mondi, Daniel Scally
Hi Jacopo,
Thank you for the patches.
On Fri, Mar 27, 2026 at 5:19 PM Jacopo Mondi
<jacopo.mondi@ideasonboard.com> wrote:
>
> This patch series starts by collecting a patch sent from Dan in the past
> which improves the HW slot programming on V2H(P) to avoid losing frames
> under heavy system load conditions.
>
> Tommaso also sent a series a few months ago for the CRU from which I
> collected the first two patches.
>
> Around it, I've reworked a bit the locking in the driver which is a bit
> coarse and causes lost of frames under heavy system load conditions.
>
> Along with these, bit of drive-by cometic changes here and there to
> modernize the driver code.
>
> I've tested on V2H(P) but I've also modified the G2L IRQ handler, so if
> anyone could test on G2L and G3E it would be great!
>
> Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> ---
> Daniel Scally (1):
> media: rzg2l-cru: Rework rzg2l_cru_fill_hw_slot()
>
> Jacopo Mondi (11):
> media: rzg2l-cru: Modernize spin_lock usage with cleanup.h
> media: rzg2l-cru: Use proper guard() in irq handler
> media: rzg2l-cru: Remove locking from start/stop routines
> media: rzg2l-cru: Do not use irqsave when not needed
> media: rzg2l-cru: Remove wrong locking comment
> media: rz2gl-cru: Introduce a spinlock for hw operations
> media: rzg2l-cru: Split hw locking from buffers
> media: rzg2l-cru: Manually track active slot number
You beat me to it, I had a similar patch internally.
> media: rz2gl-cru: Return pending buffers in order
> media: rzg2l-cru: Remove the 'state' variable
> media: rzg2l-cru: Simplify irq return value handling
>
> Tommaso Merciai (2):
> media: rzg2l-cru: Skip ICnMC configuration when ICnSVC is used
> media: rzg2l-cru: Use only frame end interrupts
>
> .../platform/renesas/rzg2l-cru/rzg2l-cru-regs.h | 2 +
> .../media/platform/renesas/rzg2l-cru/rzg2l-cru.h | 28 +-
> .../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 328 ++++++++-------------
> 3 files changed, 140 insertions(+), 218 deletions(-)
I'll test these patches with ISP enabled next week.
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 18+ messages in thread* Re: [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E
2026-03-27 17:25 ` [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E Lad, Prabhakar
@ 2026-03-28 11:55 ` Jacopo Mondi
2026-03-28 12:56 ` Lad, Prabhakar
0 siblings, 1 reply; 18+ messages in thread
From: Jacopo Mondi @ 2026-03-28 11:55 UTC (permalink / raw)
To: Lad, Prabhakar
Cc: Jacopo Mondi, Mauro Carvalho Chehab, Laurent Pinchart, Biju Das,
Hans Verkuil, Sakari Ailus, Tommaso Merciai, Daniel Scally,
Barnabás Pőcze, Lad Prabhakar, linux-media,
linux-kernel, stable, Jacopo Mondi, Daniel Scally
Hi Prabhakar
On Fri, Mar 27, 2026 at 05:25:30PM +0000, Lad, Prabhakar wrote:
> Hi Jacopo,
>
> Thank you for the patches.
>
> On Fri, Mar 27, 2026 at 5:19 PM Jacopo Mondi
> <jacopo.mondi@ideasonboard.com> wrote:
> >
> > This patch series starts by collecting a patch sent from Dan in the past
> > which improves the HW slot programming on V2H(P) to avoid losing frames
> > under heavy system load conditions.
> >
> > Tommaso also sent a series a few months ago for the CRU from which I
> > collected the first two patches.
> >
> > Around it, I've reworked a bit the locking in the driver which is a bit
> > coarse and causes lost of frames under heavy system load conditions.
> >
> > Along with these, bit of drive-by cometic changes here and there to
> > modernize the driver code.
> >
> > I've tested on V2H(P) but I've also modified the G2L IRQ handler, so if
> > anyone could test on G2L and G3E it would be great!
> >
> > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> > ---
> > Daniel Scally (1):
> > media: rzg2l-cru: Rework rzg2l_cru_fill_hw_slot()
> >
> > Jacopo Mondi (11):
> > media: rzg2l-cru: Modernize spin_lock usage with cleanup.h
> > media: rzg2l-cru: Use proper guard() in irq handler
> > media: rzg2l-cru: Remove locking from start/stop routines
> > media: rzg2l-cru: Do not use irqsave when not needed
> > media: rzg2l-cru: Remove wrong locking comment
> > media: rz2gl-cru: Introduce a spinlock for hw operations
> > media: rzg2l-cru: Split hw locking from buffers
> > media: rzg2l-cru: Manually track active slot number
> You beat me to it, I had a similar patch internally.
Oh that's great, I wasn't sure how this was going to be received!
>
> > media: rz2gl-cru: Return pending buffers in order
> > media: rzg2l-cru: Remove the 'state' variable
> > media: rzg2l-cru: Simplify irq return value handling
> >
> > Tommaso Merciai (2):
> > media: rzg2l-cru: Skip ICnMC configuration when ICnSVC is used
> > media: rzg2l-cru: Use only frame end interrupts
> >
> > .../platform/renesas/rzg2l-cru/rzg2l-cru-regs.h | 2 +
> > .../media/platform/renesas/rzg2l-cru/rzg2l-cru.h | 28 +-
> > .../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 328 ++++++++-------------
> > 3 files changed, 140 insertions(+), 218 deletions(-)
>
> I'll test these patches with ISP enabled next week.
My testing platform is v2h with the ISP, if you have a G2L could you
maybe give it a spin there as I don't have any board with that SoC ?
Thanks
j
>
> Cheers,
> Prabhakar
^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH 00/14] media: rzg2l-cru: Rework slot programming for V2H/G3E
2026-03-28 11:55 ` Jacopo Mondi
@ 2026-03-28 12:56 ` Lad, Prabhakar
0 siblings, 0 replies; 18+ messages in thread
From: Lad, Prabhakar @ 2026-03-28 12:56 UTC (permalink / raw)
To: Jacopo Mondi
Cc: Mauro Carvalho Chehab, Laurent Pinchart, Biju Das, Hans Verkuil,
Sakari Ailus, Tommaso Merciai, Daniel Scally,
Barnabás Pőcze, Lad Prabhakar, linux-media,
linux-kernel, stable, Jacopo Mondi, Daniel Scally
Hi Jacopo,
On Sat, Mar 28, 2026 at 11:55 AM Jacopo Mondi
<jacopo.mondi@ideasonboard.com> wrote:
>
> Hi Prabhakar
>
> On Fri, Mar 27, 2026 at 05:25:30PM +0000, Lad, Prabhakar wrote:
> > Hi Jacopo,
> >
> > Thank you for the patches.
> >
> > On Fri, Mar 27, 2026 at 5:19 PM Jacopo Mondi
> > <jacopo.mondi@ideasonboard.com> wrote:
> > >
> > > This patch series starts by collecting a patch sent from Dan in the past
> > > which improves the HW slot programming on V2H(P) to avoid losing frames
> > > under heavy system load conditions.
> > >
> > > Tommaso also sent a series a few months ago for the CRU from which I
> > > collected the first two patches.
> > >
> > > Around it, I've reworked a bit the locking in the driver which is a bit
> > > coarse and causes lost of frames under heavy system load conditions.
> > >
> > > Along with these, bit of drive-by cometic changes here and there to
> > > modernize the driver code.
> > >
> > > I've tested on V2H(P) but I've also modified the G2L IRQ handler, so if
> > > anyone could test on G2L and G3E it would be great!
> > >
> > > Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
> > > ---
> > > Daniel Scally (1):
> > > media: rzg2l-cru: Rework rzg2l_cru_fill_hw_slot()
> > >
> > > Jacopo Mondi (11):
> > > media: rzg2l-cru: Modernize spin_lock usage with cleanup.h
> > > media: rzg2l-cru: Use proper guard() in irq handler
> > > media: rzg2l-cru: Remove locking from start/stop routines
> > > media: rzg2l-cru: Do not use irqsave when not needed
> > > media: rzg2l-cru: Remove wrong locking comment
> > > media: rz2gl-cru: Introduce a spinlock for hw operations
> > > media: rzg2l-cru: Split hw locking from buffers
> > > media: rzg2l-cru: Manually track active slot number
> > You beat me to it, I had a similar patch internally.
>
> Oh that's great, I wasn't sure how this was going to be received!
>
> >
> > > media: rz2gl-cru: Return pending buffers in order
> > > media: rzg2l-cru: Remove the 'state' variable
> > > media: rzg2l-cru: Simplify irq return value handling
> > >
> > > Tommaso Merciai (2):
> > > media: rzg2l-cru: Skip ICnMC configuration when ICnSVC is used
> > > media: rzg2l-cru: Use only frame end interrupts
> > >
> > > .../platform/renesas/rzg2l-cru/rzg2l-cru-regs.h | 2 +
> > > .../media/platform/renesas/rzg2l-cru/rzg2l-cru.h | 28 +-
> > > .../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 328 ++++++++-------------
> > > 3 files changed, 140 insertions(+), 218 deletions(-)
> >
> > I'll test these patches with ISP enabled next week.
>
> My testing platform is v2h with the ISP, if you have a G2L could you
> maybe give it a spin there as I don't have any board with that SoC ?
>
Sure I will.
Cheers,
Prabhakar
^ permalink raw reply [flat|nested] 18+ messages in thread