public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements
@ 2025-12-18 18:44 Alain Volmat
  2025-12-18 18:44 ` [PATCH 01/12] media: stm32: dcmi: Switch from __maybe_unused to pm_sleep_ptr() Alain Volmat
                   ` (11 more replies)
  0 siblings, 12 replies; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

This series improve stability of the capture by fixing the
handling of the overrun which was leading to captured
frame corruption.
Locking within the driver is also simplified and the way
DMA is handled is reworked allowing to avoid having a
specific handling for the JPEG data.

Performances of capture can now be increased via the usage
of a DMA->MDMA chaining which allows for capture of higher
resolution / framerate.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
Alain Volmat (12):
      media: stm32: dcmi: Switch from __maybe_unused to pm_sleep_ptr()
      media: stm32: dcmi: perform dmaengine_slave_config at probe
      media: stm32: dcmi: only create dma descriptor once at buf_prepare
      media: stm32: dcmi: stop the dma transfer on overrun
      media: stm32: dcmi: rework spin_lock calls
      media: stm32: dcmi: perform all dma handling within irq_thread
      media: stm32: dcmi: use dmaengine_terminate_async in irq context
      media: stm32: dcmi: continuous mode capture in JPEG
      dt-bindings: media: st: dcmi: add DMA-MDMA chaining properties
      media: stm32: dcmi: addition of DMA-MDMA chaining support
      ARM: dts: stm32: add sram node within stm32mp151.dtsi
      ARM: dts: stm32: enable DCMI DMA-MDMA chaining on stm32mp157c-ev1.dts

 .../devicetree/bindings/media/st,stm32-dcmi.yaml   |  13 +-
 arch/arm/boot/dts/st/stm32mp151.dtsi               |   8 +
 arch/arm/boot/dts/st/stm32mp157c-ev1.dts           |  15 +
 drivers/media/platform/st/stm32/stm32-dcmi.c       | 470 ++++++++++++++-------
 4 files changed, 341 insertions(+), 165 deletions(-)
---
base-commit: f7231cff1f3ff8259bef02dc4999bc132abf29cf
change-id: 20251213-stm32-dcmi-dma-chaining-9ea1da83007d

Best regards,
-- 
Alain Volmat <alain.volmat@foss.st.com>


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH 01/12] media: stm32: dcmi: Switch from __maybe_unused to pm_sleep_ptr()
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  2025-12-20 17:15   ` kernel test robot
  2025-12-18 18:44 ` [PATCH 02/12] media: stm32: dcmi: perform dmaengine_slave_config at probe Alain Volmat
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Letting the compiler remove these functions when the kernel is built
without CONFIG_PM_SLEEP support is simpler and less heavier for builds
than the use of __maybe_unused attributes.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 13762861b769..07b67eb5b9dd 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -2092,7 +2092,7 @@ static void dcmi_remove(struct platform_device *pdev)
 	dma_release_channel(dcmi->dma_chan);
 }
 
-static __maybe_unused int dcmi_runtime_suspend(struct device *dev)
+static int dcmi_runtime_suspend(struct device *dev)
 {
 	struct stm32_dcmi *dcmi = dev_get_drvdata(dev);
 
@@ -2101,7 +2101,7 @@ static __maybe_unused int dcmi_runtime_suspend(struct device *dev)
 	return 0;
 }
 
-static __maybe_unused int dcmi_runtime_resume(struct device *dev)
+static int dcmi_runtime_resume(struct device *dev)
 {
 	struct stm32_dcmi *dcmi = dev_get_drvdata(dev);
 	int ret;
@@ -2113,7 +2113,7 @@ static __maybe_unused int dcmi_runtime_resume(struct device *dev)
 	return ret;
 }
 
-static __maybe_unused int dcmi_suspend(struct device *dev)
+static int dcmi_suspend(struct device *dev)
 {
 	/* disable clock */
 	pm_runtime_force_suspend(dev);
@@ -2124,7 +2124,7 @@ static __maybe_unused int dcmi_suspend(struct device *dev)
 	return 0;
 }
 
-static __maybe_unused int dcmi_resume(struct device *dev)
+static int dcmi_resume(struct device *dev)
 {
 	/* restore pinctl default state */
 	pinctrl_pm_select_default_state(dev);
@@ -2147,7 +2147,7 @@ static struct platform_driver stm32_dcmi_driver = {
 	.driver		= {
 		.name = DRV_NAME,
 		.of_match_table = of_match_ptr(stm32_dcmi_of_match),
-		.pm = &dcmi_pm_ops,
+		.pm = pm_sleep_ptr(&dcmi_pm_ops),
 	},
 };
 

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 02/12] media: stm32: dcmi: perform dmaengine_slave_config at probe
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
  2025-12-18 18:44 ` [PATCH 01/12] media: stm32: dcmi: Switch from __maybe_unused to pm_sleep_ptr() Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  2025-12-18 18:44 ` [PATCH 03/12] media: stm32: dcmi: only create dma descriptor once at buf_prepare Alain Volmat
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Perform the dma channel configuration at probe time right after
the channel allocation since this is fixed for the whole lifetime
of the driver.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 32 +++++++++++++---------------
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 07b67eb5b9dd..27b283474096 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -301,23 +301,6 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
 			  struct dcmi_buf *buf)
 {
 	struct dma_async_tx_descriptor *desc = NULL;
-	struct dma_slave_config config;
-	int ret;
-
-	memset(&config, 0, sizeof(config));
-
-	config.src_addr = (dma_addr_t)dcmi->res->start + DCMI_DR;
-	config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-	config.dst_maxburst = 4;
-
-	/* Configure DMA channel */
-	ret = dmaengine_slave_config(dcmi->dma_chan, &config);
-	if (ret < 0) {
-		dev_err(dcmi->dev, "%s: DMA channel config failed (%d)\n",
-			__func__, ret);
-		return ret;
-	}
 
 	/*
 	 * Avoid call of dmaengine_terminate_sync() between
@@ -1888,6 +1871,7 @@ static int dcmi_probe(struct platform_device *pdev)
 	struct vb2_queue *q;
 	struct dma_chan *chan;
 	struct dma_slave_caps caps;
+	struct dma_slave_config dma_config;
 	struct clk *mclk;
 	int ret = 0;
 
@@ -1954,6 +1938,19 @@ static int dcmi_probe(struct platform_device *pdev)
 	if (!ret && caps.max_sg_burst)
 		dcmi->dma_max_burst = caps.max_sg_burst	* DMA_SLAVE_BUSWIDTH_4_BYTES;
 
+	memset(&dma_config, 0, sizeof(dma_config));
+
+	dma_config.src_addr = (dma_addr_t)dcmi->res->start + DCMI_DR;
+	dma_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+
+	/* Configure DMA channel */
+	ret = dmaengine_slave_config(chan, &dma_config);
+	if (ret < 0) {
+		dev_err(dcmi->dev, "%s: DMA channel config failed (%d)\n",
+			__func__, ret);
+		goto err_dma_slave_config;
+	}
+
 	spin_lock_init(&dcmi->irqlock);
 	mutex_init(&dcmi->lock);
 	mutex_init(&dcmi->dma_lock);
@@ -2072,6 +2069,7 @@ static int dcmi_probe(struct platform_device *pdev)
 	v4l2_device_unregister(&dcmi->v4l2_dev);
 err_media_device_cleanup:
 	media_device_cleanup(&dcmi->mdev);
+err_dma_slave_config:
 	dma_release_channel(dcmi->dma_chan);
 
 	return ret;

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 03/12] media: stm32: dcmi: only create dma descriptor once at buf_prepare
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
  2025-12-18 18:44 ` [PATCH 01/12] media: stm32: dcmi: Switch from __maybe_unused to pm_sleep_ptr() Alain Volmat
  2025-12-18 18:44 ` [PATCH 02/12] media: stm32: dcmi: perform dmaengine_slave_config at probe Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  2025-12-18 18:44 ` [PATCH 04/12] media: stm32: dcmi: stop the dma transfer on overrun Alain Volmat
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Perform the dmaengine prep_slave_sg call within buf_prepare and
mark the descriptor as reusable in order to avoid having to redo
this at every start of the dma.
This also allow to remove the mutex used by the driver to protect
dma descriptors related piece of codes.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 78 ++++++++++++++++------------
 1 file changed, 45 insertions(+), 33 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 27b283474096..d8ef06bd7506 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -113,6 +113,7 @@ struct dcmi_buf {
 	struct vb2_v4l2_buffer	vb;
 	bool			prepared;
 	struct sg_table		sgt;
+	struct dma_async_tx_descriptor *dma_desc;
 	size_t			size;
 	struct list_head	list;
 };
@@ -163,9 +164,6 @@ struct stm32_dcmi {
 	int				overrun_count;
 	int				buffers_count;
 
-	/* Ensure DMA operations atomicity */
-	struct mutex			dma_lock;
-
 	struct media_device		mdev;
 	struct media_pad		vid_cap_pad;
 	struct media_pipeline		pipeline;
@@ -300,39 +298,13 @@ static void dcmi_dma_callback(void *param)
 static int dcmi_start_dma(struct stm32_dcmi *dcmi,
 			  struct dcmi_buf *buf)
 {
-	struct dma_async_tx_descriptor *desc = NULL;
-
-	/*
-	 * Avoid call of dmaengine_terminate_sync() between
-	 * dmaengine_prep_slave_single() and dmaengine_submit()
-	 * by locking the whole DMA submission sequence
-	 */
-	mutex_lock(&dcmi->dma_lock);
-
-	/* Prepare a DMA transaction */
-	desc = dmaengine_prep_slave_sg(dcmi->dma_chan, buf->sgt.sgl, buf->sgt.nents,
-				       DMA_DEV_TO_MEM,
-				       DMA_PREP_INTERRUPT);
-	if (!desc) {
-		dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_sg failed\n", __func__);
-		mutex_unlock(&dcmi->dma_lock);
-		return -EINVAL;
-	}
-
-	/* Set completion callback routine for notification */
-	desc->callback = dcmi_dma_callback;
-	desc->callback_param = dcmi;
-
 	/* Push current DMA transaction in the pending queue */
-	dcmi->dma_cookie = dmaengine_submit(desc);
+	dcmi->dma_cookie = dmaengine_submit(buf->dma_desc);
 	if (dma_submit_error(dcmi->dma_cookie)) {
 		dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__);
-		mutex_unlock(&dcmi->dma_lock);
 		return -ENXIO;
 	}
 
-	mutex_unlock(&dcmi->dma_lock);
-
 	dma_async_issue_pending(dcmi->dma_chan);
 
 	return 0;
@@ -547,6 +519,31 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 			size -= bytes;
 		}
 
+		/* Prepare a DMA transaction */
+		buf->dma_desc = dmaengine_prep_slave_sg(dcmi->dma_chan,
+							buf->sgt.sgl,
+							buf->sgt.nents,
+							DMA_DEV_TO_MEM,
+							DMA_PREP_INTERRUPT);
+		if (!buf->dma_desc) {
+			dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_sg failed\n", __func__);
+			sg_free_table(&buf->sgt);
+			return -EIO;
+		}
+
+		/* Set completion callback routine for notification */
+		buf->dma_desc->callback = dcmi_dma_callback;
+		buf->dma_desc->callback_param = dcmi;
+
+		/* Mark the descriptor as reusable to avoid having to prepare it */
+		ret = dmaengine_desc_set_reuse(buf->dma_desc);
+		if (ret) {
+			dev_err(dcmi->dev, "%s: DMA dmaengine_desc_set_reuse failed\n", __func__);
+			dmaengine_desc_free(buf->dma_desc);
+			sg_free_table(&buf->sgt);
+			return -EIO;
+		}
+
 		buf->prepared = true;
 
 		vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size);
@@ -555,6 +552,23 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 	return 0;
 }
 
+static void dcmi_buf_cleanup(struct vb2_buffer *vb)
+{
+	struct stm32_dcmi *dcmi =  vb2_get_drv_priv(vb->vb2_queue);
+	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+	struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb);
+	int ret;
+
+	if (!buf->prepared)
+		return;
+
+	ret = dmaengine_desc_free(buf->dma_desc);
+	if (ret)
+		dev_err(dcmi->dev, "%s: Failed to free the mdma descriptor (0x%x)\n",
+			__func__, ret);
+	sg_free_table(&buf->sgt);
+}
+
 static void dcmi_buf_queue(struct vb2_buffer *vb)
 {
 	struct stm32_dcmi *dcmi =  vb2_get_drv_priv(vb->vb2_queue);
@@ -859,9 +873,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
 	spin_unlock_irq(&dcmi->irqlock);
 
 	/* Stop all pending DMA operations */
-	mutex_lock(&dcmi->dma_lock);
 	dmaengine_terminate_sync(dcmi->dma_chan);
-	mutex_unlock(&dcmi->dma_lock);
 
 	pm_runtime_put(dcmi->dev);
 
@@ -878,6 +890,7 @@ static const struct vb2_ops dcmi_video_qops = {
 	.queue_setup		= dcmi_queue_setup,
 	.buf_init		= dcmi_buf_init,
 	.buf_prepare		= dcmi_buf_prepare,
+	.buf_cleanup		= dcmi_buf_cleanup,
 	.buf_queue		= dcmi_buf_queue,
 	.start_streaming	= dcmi_start_streaming,
 	.stop_streaming		= dcmi_stop_streaming,
@@ -1953,7 +1966,6 @@ static int dcmi_probe(struct platform_device *pdev)
 
 	spin_lock_init(&dcmi->irqlock);
 	mutex_init(&dcmi->lock);
-	mutex_init(&dcmi->dma_lock);
 	init_completion(&dcmi->complete);
 	INIT_LIST_HEAD(&dcmi->buffers);
 

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 04/12] media: stm32: dcmi: stop the dma transfer on overrun
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
                   ` (2 preceding siblings ...)
  2025-12-18 18:44 ` [PATCH 03/12] media: stm32: dcmi: only create dma descriptor once at buf_prepare Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  2025-12-18 18:44 ` [PATCH 05/12] media: stm32: dcmi: rework spin_lock calls Alain Volmat
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Ensure to stop the dma transfer whenever receiving a overrun
to avoid having a buffer partially filled with a frame and
partially with the next frame.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index d8ef06bd7506..fa33acc34eab 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -402,9 +402,21 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 	spin_lock_irq(&dcmi->irqlock);
 
 	if (dcmi->misr & IT_OVR) {
+		/* Disable capture */
+		reg_clear(dcmi->regs, DCMI_CR, CR_CAPTURE);
+
 		dcmi->overrun_count++;
+
 		if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD)
 			dcmi->errors_count++;
+
+		spin_unlock_irq(&dcmi->irqlock);
+		dmaengine_terminate_sync(dcmi->dma_chan);
+
+		if (dcmi_restart_capture(dcmi))
+			dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__);
+
+		return IRQ_HANDLED;
 	}
 	if (dcmi->misr & IT_ERR)
 		dcmi->errors_count++;

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 05/12] media: stm32: dcmi: rework spin_lock calls
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
                   ` (3 preceding siblings ...)
  2025-12-18 18:44 ` [PATCH 04/12] media: stm32: dcmi: stop the dma transfer on overrun Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  2025-12-18 18:44 ` [PATCH 06/12] media: stm32: dcmi: perform all dma handling within irq_thread Alain Volmat
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Rework of the spin_lock calls in preparation of the rework
of the data handling of the driver. Keep it straight forward
with basically spin_lock protection around everything except
dmaengine calls that might sleep (ex: synchronize / terminate)

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index fa33acc34eab..1015f2d88f54 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -227,25 +227,18 @@ static int dcmi_restart_capture(struct stm32_dcmi *dcmi)
 {
 	struct dcmi_buf *buf;
 
-	spin_lock_irq(&dcmi->irqlock);
-
-	if (dcmi->state != RUNNING) {
-		spin_unlock_irq(&dcmi->irqlock);
+	if (dcmi->state != RUNNING)
 		return -EINVAL;
-	}
 
 	/* Restart a new DMA transfer with next buffer */
 	if (list_empty(&dcmi->buffers)) {
 		dev_dbg(dcmi->dev, "Capture restart is deferred to next buffer queueing\n");
 		dcmi->state = WAIT_FOR_BUFFER;
-		spin_unlock_irq(&dcmi->irqlock);
 		return 0;
 	}
 	buf = list_entry(dcmi->buffers.next, struct dcmi_buf, list);
 	dcmi->active = buf;
 
-	spin_unlock_irq(&dcmi->irqlock);
-
 	return dcmi_start_capture(dcmi, buf);
 }
 
@@ -370,8 +363,10 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
 	 * buffer payload.
 	 */
 
+	spin_unlock_irq(&dcmi->irqlock);
 	/* Drain DMA */
 	dmaengine_synchronize(dcmi->dma_chan);
+	spin_lock_irq(&dcmi->irqlock);
 
 	/* Get DMA residue to get JPEG size */
 	status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
@@ -386,8 +381,10 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
 		dcmi_buffer_done(dcmi, buf, 0, -EIO);
 	}
 
+	spin_unlock_irq(&dcmi->irqlock);
 	/* Abort DMA operation */
 	dmaengine_terminate_sync(dcmi->dma_chan);
+	spin_lock_irq(&dcmi->irqlock);
 
 	/* Restart capture */
 	if (dcmi_restart_capture(dcmi))
@@ -413,8 +410,10 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 		spin_unlock_irq(&dcmi->irqlock);
 		dmaengine_terminate_sync(dcmi->dma_chan);
 
+		spin_lock_irq(&dcmi->irqlock);
 		if (dcmi_restart_capture(dcmi))
 			dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__);
+		spin_unlock_irq(&dcmi->irqlock);
 
 		return IRQ_HANDLED;
 	}
@@ -424,8 +423,8 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG &&
 	    dcmi->misr & IT_FRAME) {
 		/* JPEG received */
-		spin_unlock_irq(&dcmi->irqlock);
 		dcmi_process_jpeg(dcmi);
+		spin_unlock_irq(&dcmi->irqlock);
 		return IRQ_HANDLED;
 	}
 
@@ -599,11 +598,9 @@ static void dcmi_buf_queue(struct vb2_buffer *vb)
 		dev_dbg(dcmi->dev, "Starting capture on buffer[%d] queued\n",
 			buf->vb.vb2_buf.index);
 
-		spin_unlock_irq(&dcmi->irqlock);
 		if (dcmi_start_capture(dcmi, buf))
 			dev_err(dcmi->dev, "%s: Cannot restart capture on overflow or error\n",
 				__func__);
-		return;
 	}
 
 	spin_unlock_irq(&dcmi->irqlock);
@@ -812,11 +809,11 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
 
 	dev_dbg(dcmi->dev, "Start streaming, starting capture\n");
 
-	spin_unlock_irq(&dcmi->irqlock);
 	ret = dcmi_start_capture(dcmi, buf);
 	if (ret) {
 		dev_err(dcmi->dev, "%s: Start streaming failed, cannot start capture\n",
 			__func__);
+		spin_unlock_irq(&dcmi->irqlock);
 		goto err_pipeline_stop;
 	}
 
@@ -826,6 +823,8 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
 	else
 		reg_set(dcmi->regs, DCMI_IER, IT_OVR | IT_ERR);
 
+	spin_unlock_irq(&dcmi->irqlock);
+
 	return 0;
 
 err_pipeline_stop:

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 06/12] media: stm32: dcmi: perform all dma handling within irq_thread
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
                   ` (4 preceding siblings ...)
  2025-12-18 18:44 ` [PATCH 05/12] media: stm32: dcmi: rework spin_lock calls Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  2025-12-18 18:44 ` [PATCH 07/12] media: stm32: dcmi: use dmaengine_terminate_async in irq context Alain Volmat
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Move all the type of frame handling within the dcmi_irq_thread
handler and do not rely on dma_callback as previously.

This simplifies the code by having only a single path for both
compressed and uncompressed data while also making the system
more reactive since irq_handler have more chances to be called
faster than the dma completion callback.  Indeed, in case of the
dma completion callback, this run as a tasklet created by the
dma framework upon getting an interrupt from the dma and run
at a lower priority level than other irq handlers.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 97 ++++++----------------------
 1 file changed, 18 insertions(+), 79 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 1015f2d88f54..06b66095844b 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -227,8 +227,9 @@ static int dcmi_restart_capture(struct stm32_dcmi *dcmi)
 {
 	struct dcmi_buf *buf;
 
+	/* Nothing to do if we are not running */
 	if (dcmi->state != RUNNING)
-		return -EINVAL;
+		return 0;
 
 	/* Restart a new DMA transfer with next buffer */
 	if (list_empty(&dcmi->buffers)) {
@@ -242,52 +243,6 @@ static int dcmi_restart_capture(struct stm32_dcmi *dcmi)
 	return dcmi_start_capture(dcmi, buf);
 }
 
-static void dcmi_dma_callback(void *param)
-{
-	struct stm32_dcmi *dcmi = (struct stm32_dcmi *)param;
-	struct dma_tx_state state;
-	enum dma_status status;
-	struct dcmi_buf *buf = dcmi->active;
-
-	spin_lock_irq(&dcmi->irqlock);
-
-	/* Check DMA status */
-	status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
-
-	switch (status) {
-	case DMA_IN_PROGRESS:
-		dev_dbg(dcmi->dev, "%s: Received DMA_IN_PROGRESS\n", __func__);
-		break;
-	case DMA_PAUSED:
-		dev_err(dcmi->dev, "%s: Received DMA_PAUSED\n", __func__);
-		break;
-	case DMA_ERROR:
-		dev_err(dcmi->dev, "%s: Received DMA_ERROR\n", __func__);
-
-		/* Return buffer to V4L2 in error state */
-		dcmi_buffer_done(dcmi, buf, 0, -EIO);
-		break;
-	case DMA_COMPLETE:
-		dev_dbg(dcmi->dev, "%s: Received DMA_COMPLETE\n", __func__);
-
-		/* Return buffer to V4L2 */
-		dcmi_buffer_done(dcmi, buf, buf->size, 0);
-
-		spin_unlock_irq(&dcmi->irqlock);
-
-		/* Restart capture */
-		if (dcmi_restart_capture(dcmi))
-			dev_err(dcmi->dev, "%s: Cannot restart capture on DMA complete\n",
-				__func__);
-		return;
-	default:
-		dev_err(dcmi->dev, "%s: Received unknown status\n", __func__);
-		break;
-	}
-
-	spin_unlock_irq(&dcmi->irqlock);
-}
-
 static int dcmi_start_dma(struct stm32_dcmi *dcmi,
 			  struct dcmi_buf *buf)
 {
@@ -344,7 +299,7 @@ static void dcmi_set_crop(struct stm32_dcmi *dcmi)
 	reg_set(dcmi->regs, DCMI_CR, CR_CROP);
 }
 
-static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
+static void dcmi_process_frame(struct stm32_dcmi *dcmi)
 {
 	struct dma_tx_state state;
 	enum dma_status status;
@@ -354,13 +309,11 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
 		return;
 
 	/*
-	 * Because of variable JPEG buffer size sent by sensor,
-	 * DMA transfer never completes due to transfer size never reached.
-	 * In order to ensure that all the JPEG data are transferred
-	 * in active buffer memory, DMA is drained.
-	 * Then DMA tx status gives the amount of data transferred
-	 * to memory, which is then returned to V4L2 through the active
-	 * buffer payload.
+	 * At the time FRAME interrupt is received, all dma req have been sent to the DMA,
+	 * however DMA might still be transferring data hence first synchronize prior to
+	 * getting the status of the DMA transfer.
+	 * Then DMA tx status gives the amount of data transferred to memory, which is then
+	 * returned to V4L2 through the active buffer payload.
 	 */
 
 	spin_unlock_irq(&dcmi->irqlock);
@@ -368,16 +321,16 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
 	dmaengine_synchronize(dcmi->dma_chan);
 	spin_lock_irq(&dcmi->irqlock);
 
-	/* Get DMA residue to get JPEG size */
+	/* Get DMA status and residue size */
 	status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
 	if (status != DMA_ERROR && state.residue < buf->size) {
-		/* Return JPEG buffer to V4L2 with received JPEG buffer size */
+		/* Return buffer to V4L2 with received data size */
 		dcmi_buffer_done(dcmi, buf, buf->size - state.residue, 0);
 	} else {
 		dcmi->errors_count++;
-		dev_err(dcmi->dev, "%s: Cannot get JPEG size from DMA\n",
-			__func__);
-		/* Return JPEG buffer to V4L2 in ERROR state */
+		dev_err(dcmi->dev, "%s: DMA error. status: 0x%x, residue: %d\n",
+			__func__, status, state.residue);
+		/* Return buffer to V4L2 in ERROR state */
 		dcmi_buffer_done(dcmi, buf, 0, -EIO);
 	}
 
@@ -385,11 +338,6 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi)
 	/* Abort DMA operation */
 	dmaengine_terminate_sync(dcmi->dma_chan);
 	spin_lock_irq(&dcmi->irqlock);
-
-	/* Restart capture */
-	if (dcmi_restart_capture(dcmi))
-		dev_err(dcmi->dev, "%s: Cannot restart capture on JPEG received\n",
-			__func__);
 }
 
 static irqreturn_t dcmi_irq_thread(int irq, void *arg)
@@ -420,12 +368,10 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 	if (dcmi->misr & IT_ERR)
 		dcmi->errors_count++;
 
-	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG &&
-	    dcmi->misr & IT_FRAME) {
-		/* JPEG received */
-		dcmi_process_jpeg(dcmi);
-		spin_unlock_irq(&dcmi->irqlock);
-		return IRQ_HANDLED;
+	if (dcmi->misr & IT_FRAME) {
+		dcmi_process_frame(dcmi);
+		if (dcmi_restart_capture(dcmi))
+			dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__);
 	}
 
 	spin_unlock_irq(&dcmi->irqlock);
@@ -542,10 +488,6 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 			return -EIO;
 		}
 
-		/* Set completion callback routine for notification */
-		buf->dma_desc->callback = dcmi_dma_callback;
-		buf->dma_desc->callback_param = dcmi;
-
 		/* Mark the descriptor as reusable to avoid having to prepare it */
 		ret = dmaengine_desc_set_reuse(buf->dma_desc);
 		if (ret) {
@@ -818,10 +760,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
 	}
 
 	/* Enable interruptions */
-	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG)
-		reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
-	else
-		reg_set(dcmi->regs, DCMI_IER, IT_OVR | IT_ERR);
+	reg_set(dcmi->regs, DCMI_IER, IT_FRAME | IT_OVR | IT_ERR);
 
 	spin_unlock_irq(&dcmi->irqlock);
 

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 07/12] media: stm32: dcmi: use dmaengine_terminate_async in irq context
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
                   ` (5 preceding siblings ...)
  2025-12-18 18:44 ` [PATCH 06/12] media: stm32: dcmi: perform all dma handling within irq_thread Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  2025-12-18 18:44 ` [PATCH 08/12] media: stm32: dcmi: continuous mode capture in JPEG Alain Volmat
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Whenever receiving an OVERRUN event or an end of frame, the driver stops
currently ongoing DMA transfer since the DCMI stops sending data to dma.
Not doing this would lead to having DMA & DCMI no more synchronized in term
of expected data to be copied.
Since this is done in irq handler context, it is not possible to make any
call that would lead to scheduling hence dmaengine_terminate_sync are not
possible.
Since the dcmi driver is NOT using dma callbacks, it is possible thus to
call instead dmaengine_terminate_async (aka without synchronize) and call
again right after a new dmaengine_submit to setup again a new transfer.
And since this is now a dmaengine_submit_async, there is no need to release
the spinlock around calls to the dmaengine_submit_async.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 06b66095844b..25e95ba2ca84 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -334,10 +334,8 @@ static void dcmi_process_frame(struct stm32_dcmi *dcmi)
 		dcmi_buffer_done(dcmi, buf, 0, -EIO);
 	}
 
-	spin_unlock_irq(&dcmi->irqlock);
 	/* Abort DMA operation */
-	dmaengine_terminate_sync(dcmi->dma_chan);
-	spin_lock_irq(&dcmi->irqlock);
+	dmaengine_terminate_async(dcmi->dma_chan);
 }
 
 static irqreturn_t dcmi_irq_thread(int irq, void *arg)
@@ -355,10 +353,8 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 		if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD)
 			dcmi->errors_count++;
 
-		spin_unlock_irq(&dcmi->irqlock);
-		dmaengine_terminate_sync(dcmi->dma_chan);
+		dmaengine_terminate_async(dcmi->dma_chan);
 
-		spin_lock_irq(&dcmi->irqlock);
 		if (dcmi_restart_capture(dcmi))
 			dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__);
 		spin_unlock_irq(&dcmi->irqlock);

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 08/12] media: stm32: dcmi: continuous mode capture in JPEG
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
                   ` (6 preceding siblings ...)
  2025-12-18 18:44 ` [PATCH 07/12] media: stm32: dcmi: use dmaengine_terminate_async in irq context Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  2025-12-18 18:44 ` [PATCH 09/12] dt-bindings: media: st: dcmi: add DMA-MDMA chaining properties Alain Volmat
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Overall cleanup done allows to now have the JPEG handling
done in the same way as other formats in continuous mode,
allowing to achieve a faster framerate in all resolutions.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 25e95ba2ca84..4c0f8ed0f87e 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -717,10 +717,6 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
 	if (dcmi->do_crop)
 		dcmi_set_crop(dcmi);
 
-	/* Enable jpeg capture */
-	if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG)
-		reg_set(dcmi->regs, DCMI_CR, CR_CM);/* Snapshot mode */
-
 	/* Enable dcmi */
 	reg_set(dcmi->regs, DCMI_CR, CR_ENABLE);
 

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 09/12] dt-bindings: media: st: dcmi: add DMA-MDMA chaining properties
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
                   ` (7 preceding siblings ...)
  2025-12-18 18:44 ` [PATCH 08/12] media: stm32: dcmi: continuous mode capture in JPEG Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  2025-12-29 23:39   ` Rob Herring
  2025-12-18 18:44 ` [PATCH 10/12] media: stm32: dcmi: addition of DMA-MDMA chaining support Alain Volmat
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Add properties update and new sram property necessary in order
to enable the DMA-MDMA chaining.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
index 34147127192f..ccaa2d0a2669 100644
--- a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
+++ b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
@@ -27,11 +27,14 @@ properties:
       - const: mclk
 
   dmas:
-    maxItems: 1
+    minItems: 1
+    maxItems: 2
 
   dma-names:
     items:
       - const: tx
+      - const: mdma_tx
+    minItems: 1
 
   resets:
     maxItems: 1
@@ -40,6 +43,14 @@ properties:
     minItems: 1
     maxItems: 2
 
+  sram:
+    $ref: /schemas/types.yaml#/definitions/phandle
+    description:
+      phandles to a reserved SRAM region which is used as temporary
+      storage memory between DMA and MDMA engines.
+      The region should be defined as child nodes of the AHB SRAM node
+      as per the generic bindings in Documentation/devicetree/bindings/sram/sram.yaml
+
   port:
     $ref: /schemas/graph.yaml#/$defs/port-base
     unevaluatedProperties: false

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 10/12] media: stm32: dcmi: addition of DMA-MDMA chaining support
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
                   ` (8 preceding siblings ...)
  2025-12-18 18:44 ` [PATCH 09/12] dt-bindings: media: st: dcmi: add DMA-MDMA chaining properties Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  2025-12-18 18:44 ` [PATCH 11/12] ARM: dts: stm32: add sram node within stm32mp151.dtsi Alain Volmat
  2025-12-18 18:44 ` [PATCH 12/12] ARM: dts: stm32: enable DCMI DMA-MDMA chaining on stm32mp157c-ev1.dts Alain Volmat
  11 siblings, 0 replies; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Add possibility to rely on an additional MDMA channel and chain
the DMA and MDMA channels allowing to achieve faster capture.
Indeed, on the MP15 platform, the MDMA engine has an higher
bandwidth to the DDR than the DMA engine.  Relying on that
it is possible to capture frames from the DCMI IP into the DDR
by using two channels as follow:

  DCMI -> (DMA) -> SRAM -> (MDMA) -> DDR

The DMA is able by himself to trigger a MDMA request hence, once
properly configured, the DCMI IP can simply trigger the DMA in order
to have the data pushed up to the DDR (via the SRAM and a MDMA
channel).

This behavior is detailed in the document
Documentation/arch/arm/stm32/stm32-dma-mdma-chaining.rst

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 drivers/media/platform/st/stm32/stm32-dcmi.c | 250 +++++++++++++++++++++++----
 1 file changed, 220 insertions(+), 30 deletions(-)

diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index 4c0f8ed0f87e..e4a9f96a989b 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -15,6 +15,7 @@
 #include <linux/completion.h>
 #include <linux/delay.h>
 #include <linux/dmaengine.h>
+#include <linux/genalloc.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
@@ -113,7 +114,9 @@ struct dcmi_buf {
 	struct vb2_v4l2_buffer	vb;
 	bool			prepared;
 	struct sg_table		sgt;
+	struct sg_table		sgt_mdma;
 	struct dma_async_tx_descriptor *dma_desc;
+	struct dma_async_tx_descriptor *mdma_desc;
 	size_t			size;
 	struct list_head	list;
 };
@@ -159,6 +162,15 @@ struct stm32_dcmi {
 	struct dma_chan			*dma_chan;
 	dma_cookie_t			dma_cookie;
 	u32				dma_max_burst;
+
+	/* Elements for the MDMA - DMA chaining */
+	struct gen_pool			*sram_pool;
+	struct dma_chan			*mdma_chan;
+	void				*sram_buf;
+	u32				sram_buf_size;
+	dma_addr_t			sram_dma_buf;
+	dma_cookie_t			mdma_cookie;
+
 	u32				misr;
 	int				errors_count;
 	int				overrun_count;
@@ -247,12 +259,22 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi,
 			  struct dcmi_buf *buf)
 {
 	/* Push current DMA transaction in the pending queue */
+	if (dcmi->mdma_chan) {
+		dcmi->mdma_cookie = dmaengine_submit(buf->mdma_desc);
+		if (dma_submit_error(dcmi->mdma_cookie)) {
+			dev_err(dcmi->dev, "%s: MDMA submission failed\n", __func__);
+			return -ENXIO;
+		}
+	}
+
 	dcmi->dma_cookie = dmaengine_submit(buf->dma_desc);
 	if (dma_submit_error(dcmi->dma_cookie)) {
 		dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__);
 		return -ENXIO;
 	}
 
+	if (dcmi->mdma_chan)
+		dma_async_issue_pending(dcmi->mdma_chan);
 	dma_async_issue_pending(dcmi->dma_chan);
 
 	return 0;
@@ -301,7 +323,9 @@ static void dcmi_set_crop(struct stm32_dcmi *dcmi)
 
 static void dcmi_process_frame(struct stm32_dcmi *dcmi)
 {
-	struct dma_tx_state state;
+	struct dma_tx_state state, state_dma;
+	size_t bytes_used;
+
 	enum dma_status status;
 	struct dcmi_buf *buf = dcmi->active;
 
@@ -309,23 +333,36 @@ static void dcmi_process_frame(struct stm32_dcmi *dcmi)
 		return;
 
 	/*
-	 * At the time FRAME interrupt is received, all dma req have been sent to the DMA,
-	 * however DMA might still be transferring data hence first synchronize prior to
-	 * getting the status of the DMA transfer.
-	 * Then DMA tx status gives the amount of data transferred to memory, which is then
-	 * returned to V4L2 through the active buffer payload.
+	 * Pause the DMA transfer, leading to trigger of the MDMA channel read while
+	 * keeping a valid residue value on the dma channel
 	 */
+	if (dcmi->mdma_chan) {
+		spin_unlock_irq(&dcmi->irqlock);
+		dmaengine_pause(dcmi->dma_chan);
+		spin_lock_irq(&dcmi->irqlock);
+
+		do {
+			status = dmaengine_tx_status(dcmi->mdma_chan, dcmi->mdma_cookie, &state);
+			cpu_relax();
+		} while (status != DMA_ERROR && status != DMA_COMPLETE &&
+			 state.residue && state.in_flight_bytes);
+	} else {
+		status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
+	}
 
-	spin_unlock_irq(&dcmi->irqlock);
-	/* Drain DMA */
-	dmaengine_synchronize(dcmi->dma_chan);
-	spin_lock_irq(&dcmi->irqlock);
-
-	/* Get DMA status and residue size */
-	status = dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state);
 	if (status != DMA_ERROR && state.residue < buf->size) {
+		bytes_used = buf->size - state.residue;
+
+		if (state.residue && dcmi->mdma_chan) {
+			dmaengine_tx_status(dcmi->dma_chan, dcmi->dma_cookie, &state_dma);
+			/* Getting full size residue equal to no residue */
+			if (state_dma.residue == dcmi->sram_buf_size)
+				state_dma.residue = 0;
+			bytes_used -= state_dma.residue;
+		}
+
 		/* Return buffer to V4L2 with received data size */
-		dcmi_buffer_done(dcmi, buf, buf->size - state.residue, 0);
+		dcmi_buffer_done(dcmi, buf, bytes_used, 0);
 	} else {
 		dcmi->errors_count++;
 		dev_err(dcmi->dev, "%s: DMA error. status: 0x%x, residue: %d\n",
@@ -336,6 +373,8 @@ static void dcmi_process_frame(struct stm32_dcmi *dcmi)
 
 	/* Abort DMA operation */
 	dmaengine_terminate_async(dcmi->dma_chan);
+	if (dcmi->mdma_chan)
+		dmaengine_terminate_async(dcmi->mdma_chan);
 }
 
 static irqreturn_t dcmi_irq_thread(int irq, void *arg)
@@ -354,13 +393,15 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg)
 			dcmi->errors_count++;
 
 		dmaengine_terminate_async(dcmi->dma_chan);
+		if (dcmi->mdma_chan)
+			dmaengine_terminate_async(dcmi->mdma_chan);
 
 		if (dcmi_restart_capture(dcmi))
 			dev_err(dcmi->dev, "%s: Cannot restart capture\n", __func__);
 		spin_unlock_irq(&dcmi->irqlock);
-
 		return IRQ_HANDLED;
 	}
+
 	if (dcmi->misr & IT_ERR)
 		dcmi->errors_count++;
 
@@ -447,28 +488,70 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 	vb2_set_plane_payload(vb, 0, size);
 
 	if (!buf->prepared) {
+		u32 max_size = dcmi->dma_max_burst;
+		unsigned int dma_nents;
+
 		/* Get memory addresses */
 		buf->size = vb2_plane_size(&buf->vb.vb2_buf, 0);
-		if (buf->size > dcmi->dma_max_burst)
-			num_sgs = DIV_ROUND_UP(buf->size, dcmi->dma_max_burst);
+		if (dcmi->mdma_chan)
+			max_size = dcmi->sram_buf_size / 2;
 
-		ret = sg_alloc_table(&buf->sgt, num_sgs, GFP_ATOMIC);
+		if (buf->size > max_size)
+			num_sgs = DIV_ROUND_UP(buf->size, max_size);
+
+		/*
+		 * If we use MDMA chaining, DMA is used in cyclic mode and the scatterlist
+		 * maximum size is thus 2
+		 */
+		dma_nents = num_sgs;
+		if (dcmi->mdma_chan)
+			dma_nents = min_t(unsigned int, num_sgs, 2);
+
+		ret = sg_alloc_table(&buf->sgt, dma_nents, GFP_ATOMIC);
 		if (ret) {
-			dev_err(dcmi->dev, "sg table alloc failed\n");
+			dev_err(dcmi->dev, "sg table alloc failed for DMA\n");
 			return ret;
 		}
 
+		if (dcmi->mdma_chan) {
+			ret = sg_alloc_table(&buf->sgt_mdma, num_sgs, GFP_ATOMIC);
+			if (ret) {
+				dev_err(dcmi->dev, "sg table alloc failed for MDMA\n");
+				return ret;
+			}
+		}
+
 		dma_buf = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
 
 		dev_dbg(dcmi->dev, "buffer[%d] phy=%pad size=%zu\n",
 			vb->index, &dma_buf, buf->size);
 
-		for_each_sg(buf->sgt.sgl, sg, num_sgs, i) {
-			size_t bytes = min_t(size_t, size, dcmi->dma_max_burst);
+		for_each_sg(buf->sgt.sgl, sg, dma_nents, i) {
+			size_t bytes = min_t(size_t, size, max_size);
+
+			if (!dcmi->mdma_chan) {
+				sg_dma_address(sg) = dma_buf;
+				dma_buf += bytes;
+			} else {
+				/* Targets the beginning = first half of the sram_buf */
+				sg_dma_address(sg) = dcmi->sram_dma_buf;
+				/*
+				 * Targets the second half of the sram_bubf
+				 * for odd indexes of the item of the sg_list
+				 */
+				if (i & 1)
+					sg->dma_address += (dcmi->sram_buf_size / 2);
+			}
+			/*
+			 * In case of DMA-MDMA chaining, since the DMA is working in cyclic mode,
+			 * we need to provide two linked-list node of same size in order to have
+			 * a correct residue value computed.
+			 */
+			if (!dcmi->mdma_chan)
+				sg_dma_len(sg) = bytes;
+			else
+				sg_dma_len(sg) = dcmi->sram_buf_size / 2;
 
-			sg_dma_address(sg) = dma_buf;
-			sg_dma_len(sg) = bytes;
-			dma_buf += bytes;
 			size -= bytes;
 		}
 
@@ -480,6 +563,8 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 							DMA_PREP_INTERRUPT);
 		if (!buf->dma_desc) {
 			dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_sg failed\n", __func__);
+			if (dcmi->mdma_chan)
+				sg_free_table(&buf->sgt_mdma);
 			sg_free_table(&buf->sgt);
 			return -EIO;
 		}
@@ -489,10 +574,48 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb)
 		if (ret) {
 			dev_err(dcmi->dev, "%s: DMA dmaengine_desc_set_reuse failed\n", __func__);
 			dmaengine_desc_free(buf->dma_desc);
+			if (dcmi->mdma_chan)
+				sg_free_table(&buf->sgt_mdma);
 			sg_free_table(&buf->sgt);
 			return -EIO;
 		}
 
+		if (dcmi->mdma_chan) {
+			size = dcmi->fmt.fmt.pix.sizeimage;
+			for_each_sg(buf->sgt_mdma.sgl, sg, num_sgs, i) {
+				size_t bytes = min_t(size_t, size, max_size);
+
+				sg_dma_address(sg) = dma_buf;
+				sg_dma_len(sg) = bytes;
+				dma_buf += bytes;
+				size -= bytes;
+			}
+
+			buf->mdma_desc = dmaengine_prep_slave_sg(dcmi->mdma_chan, buf->sgt_mdma.sgl,
+								 buf->sgt_mdma.nents,
+								 DMA_DEV_TO_MEM,
+								 DMA_PREP_INTERRUPT);
+			if (!buf->mdma_desc) {
+				dev_err(dcmi->dev, "%s: failed dmaengine_prep_slave_sg for MDMA\n",
+					__func__);
+				dmaengine_desc_free(buf->dma_desc);
+				sg_free_table(&buf->sgt_mdma);
+				sg_free_table(&buf->sgt);
+				return -EIO;
+			}
+
+			ret = dmaengine_desc_set_reuse(buf->mdma_desc);
+			if (ret) {
+				dev_err(dcmi->dev, "%s: failed to set reuse for mdma desc\n",
+					__func__);
+				dmaengine_desc_free(buf->mdma_desc);
+				dmaengine_desc_free(buf->dma_desc);
+				sg_free_table(&buf->sgt_mdma);
+				sg_free_table(&buf->sgt);
+				return -EIO;
+			}
+		}
+
 		buf->prepared = true;
 
 		vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size);
@@ -511,6 +634,14 @@ static void dcmi_buf_cleanup(struct vb2_buffer *vb)
 	if (!buf->prepared)
 		return;
 
+	if (dcmi->mdma_chan) {
+		ret = dmaengine_desc_free(buf->mdma_desc);
+		if (ret)
+			dev_err(dcmi->dev, "%s: Failed to free the mdma descriptor (0x%x)\n",
+				__func__, ret);
+		sg_free_table(&buf->sgt_mdma);
+	}
+
 	ret = dmaengine_desc_free(buf->dma_desc);
 	if (ret)
 		dev_err(dcmi->dev, "%s: Failed to free the mdma descriptor (0x%x)\n",
@@ -816,6 +947,8 @@ static void dcmi_stop_streaming(struct vb2_queue *vq)
 
 	/* Stop all pending DMA operations */
 	dmaengine_terminate_sync(dcmi->dma_chan);
+	if (dcmi->mdma_chan)
+		dmaengine_terminate_sync(dcmi->mdma_chan);
 
 	pm_runtime_put(dcmi->dev);
 
@@ -1824,9 +1957,9 @@ static int dcmi_probe(struct platform_device *pdev)
 	struct v4l2_fwnode_endpoint ep = { .bus_type = 0 };
 	struct stm32_dcmi *dcmi;
 	struct vb2_queue *q;
-	struct dma_chan *chan;
+	struct dma_chan *chan, *mdma_chan;
 	struct dma_slave_caps caps;
-	struct dma_slave_config dma_config;
+	struct dma_slave_config dma_config, mdma_config;
 	struct clk *mclk;
 	int ret = 0;
 
@@ -1888,15 +2021,21 @@ static int dcmi_probe(struct platform_device *pdev)
 		return dev_err_probe(&pdev->dev, PTR_ERR(chan),
 				     "Failed to request DMA channel\n");
 
-	dcmi->dma_max_burst = UINT_MAX;
-	ret = dma_get_slave_caps(chan, &caps);
-	if (!ret && caps.max_sg_burst)
-		dcmi->dma_max_burst = caps.max_sg_burst	* DMA_SLAVE_BUSWIDTH_4_BYTES;
+	mdma_chan = dma_request_chan(&pdev->dev, "mdma_tx");
+	if (IS_ERR(mdma_chan)) {
+		ret = PTR_ERR(mdma_chan);
+		if (ret != -ENODEV)
+			return dev_err_probe(&pdev->dev, ret, "Failed to request MDMA channel\n");
+		mdma_chan = NULL;
+	}
 
+	/* Configure the DMA channel */
 	memset(&dma_config, 0, sizeof(dma_config));
 
 	dma_config.src_addr = (dma_addr_t)dcmi->res->start + DCMI_DR;
 	dma_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+	if (mdma_chan)
+		dma_config.peripheral_size = 1; /* Indicates chaining */
 
 	/* Configure DMA channel */
 	ret = dmaengine_slave_config(chan, &dma_config);
@@ -1906,6 +2045,47 @@ static int dcmi_probe(struct platform_device *pdev)
 		goto err_dma_slave_config;
 	}
 
+	/* If we want MDMA, we also need a sram pool */
+	if (mdma_chan) {
+		dcmi->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
+		if (!dcmi->sram_pool) {
+			dev_info(&pdev->dev, "No SRAM pool, can't use MDMA chaining\n");
+			goto err_dma_slave_config;
+		}
+
+		dev_info(&pdev->dev, "SRAM pool: %zu KiB for DMA/MDMA chaining\n",
+			 gen_pool_size(dcmi->sram_pool) / 1024);
+
+		dcmi->sram_buf_size = gen_pool_size(dcmi->sram_pool);
+		dcmi->sram_buf = gen_pool_dma_zalloc(dcmi->sram_pool, dcmi->sram_buf_size,
+						     &dcmi->sram_dma_buf);
+		if (!dcmi->sram_buf) {
+			dev_err(dcmi->dev, "Failed to allocate from SRAM\n");
+			goto err_dma_slave_config;
+		}
+
+		/* Configure the MDMA Channel */
+		memset(&mdma_config, 0, sizeof(mdma_config));
+		mdma_config.direction = DMA_DEV_TO_MEM;
+		mdma_config.src_addr = dcmi->sram_dma_buf;
+		mdma_config.peripheral_size = dma_config.peripheral_size;
+		mdma_config.peripheral_config = dma_config.peripheral_config;
+		ret = dmaengine_slave_config(mdma_chan, &mdma_config);
+		if (ret < 0) {
+			dev_err(dcmi->dev, "%s: MDMA channel config failed (%d)\n",
+				__func__, ret);
+			goto err_mdma_slave_config;
+		}
+	}
+
+	dcmi->dma_max_burst = UINT_MAX;
+	/* In case of using DMA-MDMA chaining we consider the maximum infini */
+	if (!mdma_chan) {
+		ret = dma_get_slave_caps(chan, &caps);
+		if (!ret && caps.max_sg_burst)
+			dcmi->dma_max_burst = caps.max_sg_burst * DMA_SLAVE_BUSWIDTH_4_BYTES;
+	}
+
 	spin_lock_init(&dcmi->irqlock);
 	mutex_init(&dcmi->lock);
 	init_completion(&dcmi->complete);
@@ -1915,6 +2095,7 @@ static int dcmi_probe(struct platform_device *pdev)
 	dcmi->mclk = mclk;
 	dcmi->state = STOPPED;
 	dcmi->dma_chan = chan;
+	dcmi->mdma_chan = mdma_chan;
 
 	q = &dcmi->queue;
 
@@ -2023,8 +2204,13 @@ static int dcmi_probe(struct platform_device *pdev)
 	v4l2_device_unregister(&dcmi->v4l2_dev);
 err_media_device_cleanup:
 	media_device_cleanup(&dcmi->mdev);
+err_mdma_slave_config:
+	if (dcmi->mdma_chan)
+		gen_pool_free(dcmi->sram_pool, (unsigned long)dcmi->sram_buf, dcmi->sram_buf_size);
 err_dma_slave_config:
 	dma_release_channel(dcmi->dma_chan);
+	if (dcmi->mdma_chan)
+		dma_release_channel(mdma_chan);
 
 	return ret;
 }
@@ -2042,6 +2228,10 @@ static void dcmi_remove(struct platform_device *pdev)
 	media_device_cleanup(&dcmi->mdev);
 
 	dma_release_channel(dcmi->dma_chan);
+	if (dcmi->mdma_chan) {
+		gen_pool_free(dcmi->sram_pool, (unsigned long)dcmi->sram_buf, dcmi->sram_buf_size);
+		dma_release_channel(dcmi->mdma_chan);
+	}
 }
 
 static int dcmi_runtime_suspend(struct device *dev)

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 11/12] ARM: dts: stm32: add sram node within stm32mp151.dtsi
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
                   ` (9 preceding siblings ...)
  2025-12-18 18:44 ` [PATCH 10/12] media: stm32: dcmi: addition of DMA-MDMA chaining support Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  2025-12-18 18:44 ` [PATCH 12/12] ARM: dts: stm32: enable DCMI DMA-MDMA chaining on stm32mp157c-ev1.dts Alain Volmat
  11 siblings, 0 replies; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Introduce the sram node in order to be used by drivers
requiring SRAM memory space.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 arch/arm/boot/dts/st/stm32mp151.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/st/stm32mp151.dtsi b/arch/arm/boot/dts/st/stm32mp151.dtsi
index b1b568dfd126..85cb0f16ca73 100644
--- a/arch/arm/boot/dts/st/stm32mp151.dtsi
+++ b/arch/arm/boot/dts/st/stm32mp151.dtsi
@@ -123,6 +123,14 @@ soc {
 		interrupt-parent = <&intc>;
 		ranges;
 
+		sram4: sram@10050000 {
+			compatible = "mmio-sram";
+			reg = <0x10050000 0x10000>;
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x10050000 0x10000>;
+		};
+
 		ipcc: mailbox@4c001000 {
 			compatible = "st,stm32mp1-ipcc";
 			#mbox-cells = <1>;

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH 12/12] ARM: dts: stm32: enable DCMI DMA-MDMA chaining on stm32mp157c-ev1.dts
  2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
                   ` (10 preceding siblings ...)
  2025-12-18 18:44 ` [PATCH 11/12] ARM: dts: stm32: add sram node within stm32mp151.dtsi Alain Volmat
@ 2025-12-18 18:44 ` Alain Volmat
  11 siblings, 0 replies; 15+ messages in thread
From: Alain Volmat @ 2025-12-18 18:44 UTC (permalink / raw)
  To: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Sumit Semwal, Christian König
  Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel,
	devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Enable the DMA-MDMA chaining for the dcmi (camera capture)
in order to be able to achieve higher resolution.

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 arch/arm/boot/dts/st/stm32mp157c-ev1.dts | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm/boot/dts/st/stm32mp157c-ev1.dts b/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
index 8f99c30f1af1..68b536b0c6ee 100644
--- a/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
+++ b/arch/arm/boot/dts/st/stm32mp157c-ev1.dts
@@ -86,6 +86,14 @@ &dcmi {
 	pinctrl-names = "default", "sleep";
 	pinctrl-0 = <&dcmi_pins_a>;
 	pinctrl-1 = <&dcmi_sleep_pins_a>;
+	/*
+	 * Enable DMA-MDMA chaining by adding a SRAM pool and
+	 * a MDMA channel
+	 */
+	sram = <&dcmi_pool>;
+
+	dmas = <&dmamux1 75 0x400 0x01>, <&mdma1 0 0x3 0x1200000a 0 0>;
+	dma-names = "tx", "mdma_tx";
 
 	port {
 		dcmi_0: endpoint {
@@ -301,6 +309,13 @@ &spi1 {
 	status = "disabled";
 };
 
+&sram4 {
+	dcmi_pool: dcmi-sram@0 {
+		reg = <0x0 0x8000>;
+		pool;
+	};
+};
+
 &timers2 {
 	/* spare dmas for other usage (un-delete to enable pwm capture) */
 	/delete-property/dmas;

-- 
2.34.1


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH 01/12] media: stm32: dcmi: Switch from __maybe_unused to pm_sleep_ptr()
  2025-12-18 18:44 ` [PATCH 01/12] media: stm32: dcmi: Switch from __maybe_unused to pm_sleep_ptr() Alain Volmat
@ 2025-12-20 17:15   ` kernel test robot
  0 siblings, 0 replies; 15+ messages in thread
From: kernel test robot @ 2025-12-20 17:15 UTC (permalink / raw)
  To: Alain Volmat, Hugues Fruchet, Mauro Carvalho Chehab,
	Maxime Coquelin, Alexandre Torgue, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Sumit Semwal,
	Christian König
  Cc: oe-kbuild-all, linux-media, linux-stm32, linux-arm-kernel,
	linux-kernel, devicetree, dri-devel, linaro-mm-sig, Alain Volmat

Hi Alain,

kernel test robot noticed the following build warnings:

[auto build test WARNING on atorgue-stm32/stm32-next]
[also build test WARNING on robh/for-next linus/master v6.19-rc1 next-20251219]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Alain-Volmat/media-stm32-dcmi-Switch-from-__maybe_unused-to-pm_sleep_ptr/20251219-024836
base:   https://git.kernel.org/pub/scm/linux/kernel/git/atorgue/stm32.git stm32-next
patch link:    https://lore.kernel.org/r/20251218-stm32-dcmi-dma-chaining-v1-1-39948ca6cbf6%40foss.st.com
patch subject: [PATCH 01/12] media: stm32: dcmi: Switch from __maybe_unused to pm_sleep_ptr()
config: arc-allyesconfig (https://download.01.org/0day-ci/archive/20251221/202512210044.xNNW6QJZ-lkp@intel.com/config)
compiler: arc-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251221/202512210044.xNNW6QJZ-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202512210044.xNNW6QJZ-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/media/platform/st/stm32/stm32-dcmi.c:2127:12: warning: 'dcmi_resume' defined but not used [-Wunused-function]
    2127 | static int dcmi_resume(struct device *dev)
         |            ^~~~~~~~~~~
>> drivers/media/platform/st/stm32/stm32-dcmi.c:2116:12: warning: 'dcmi_suspend' defined but not used [-Wunused-function]
    2116 | static int dcmi_suspend(struct device *dev)
         |            ^~~~~~~~~~~~


vim +/dcmi_resume +2127 drivers/media/platform/st/stm32/stm32-dcmi.c

  2115	
> 2116	static int dcmi_suspend(struct device *dev)
  2117	{
  2118		/* disable clock */
  2119		pm_runtime_force_suspend(dev);
  2120	
  2121		/* change pinctrl state */
  2122		pinctrl_pm_select_sleep_state(dev);
  2123	
  2124		return 0;
  2125	}
  2126	
> 2127	static int dcmi_resume(struct device *dev)
  2128	{
  2129		/* restore pinctl default state */
  2130		pinctrl_pm_select_default_state(dev);
  2131	
  2132		/* clock enable */
  2133		pm_runtime_force_resume(dev);
  2134	
  2135		return 0;
  2136	}
  2137	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH 09/12] dt-bindings: media: st: dcmi: add DMA-MDMA chaining properties
  2025-12-18 18:44 ` [PATCH 09/12] dt-bindings: media: st: dcmi: add DMA-MDMA chaining properties Alain Volmat
@ 2025-12-29 23:39   ` Rob Herring
  0 siblings, 0 replies; 15+ messages in thread
From: Rob Herring @ 2025-12-29 23:39 UTC (permalink / raw)
  To: Alain Volmat
  Cc: Hugues Fruchet, Mauro Carvalho Chehab, Maxime Coquelin,
	Alexandre Torgue, Krzysztof Kozlowski, Conor Dooley, Sumit Semwal,
	Christian König, linux-media, linux-stm32, linux-arm-kernel,
	linux-kernel, devicetree, dri-devel, linaro-mm-sig

On Thu, Dec 18, 2025 at 07:44:49PM +0100, Alain Volmat wrote:
> Add properties update and new sram property necessary in order
> to enable the DMA-MDMA chaining.
> 
> Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
> ---
>  Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml | 13 ++++++++++++-
>  1 file changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
> index 34147127192f..ccaa2d0a2669 100644
> --- a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
> +++ b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml
> @@ -27,11 +27,14 @@ properties:
>        - const: mclk
>  
>    dmas:
> -    maxItems: 1
> +    minItems: 1
> +    maxItems: 2
>  
>    dma-names:
>      items:
>        - const: tx
> +      - const: mdma_tx
> +    minItems: 1
>  
>    resets:
>      maxItems: 1
> @@ -40,6 +43,14 @@ properties:
>      minItems: 1
>      maxItems: 2
>  
> +  sram:
> +    $ref: /schemas/types.yaml#/definitions/phandle
> +    description:
> +      phandles to a reserved SRAM region which is used as temporary

phandle to...

> +      storage memory between DMA and MDMA engines.

> +      The region should be defined as child nodes of the AHB SRAM node
> +      as per the generic bindings in Documentation/devicetree/bindings/sram/sram.yaml

Drop this sentence.

Rob

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2025-12-29 23:39 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-18 18:44 [PATCH 00/12] media: stm32: dcmi: stability & performance enhancements Alain Volmat
2025-12-18 18:44 ` [PATCH 01/12] media: stm32: dcmi: Switch from __maybe_unused to pm_sleep_ptr() Alain Volmat
2025-12-20 17:15   ` kernel test robot
2025-12-18 18:44 ` [PATCH 02/12] media: stm32: dcmi: perform dmaengine_slave_config at probe Alain Volmat
2025-12-18 18:44 ` [PATCH 03/12] media: stm32: dcmi: only create dma descriptor once at buf_prepare Alain Volmat
2025-12-18 18:44 ` [PATCH 04/12] media: stm32: dcmi: stop the dma transfer on overrun Alain Volmat
2025-12-18 18:44 ` [PATCH 05/12] media: stm32: dcmi: rework spin_lock calls Alain Volmat
2025-12-18 18:44 ` [PATCH 06/12] media: stm32: dcmi: perform all dma handling within irq_thread Alain Volmat
2025-12-18 18:44 ` [PATCH 07/12] media: stm32: dcmi: use dmaengine_terminate_async in irq context Alain Volmat
2025-12-18 18:44 ` [PATCH 08/12] media: stm32: dcmi: continuous mode capture in JPEG Alain Volmat
2025-12-18 18:44 ` [PATCH 09/12] dt-bindings: media: st: dcmi: add DMA-MDMA chaining properties Alain Volmat
2025-12-29 23:39   ` Rob Herring
2025-12-18 18:44 ` [PATCH 10/12] media: stm32: dcmi: addition of DMA-MDMA chaining support Alain Volmat
2025-12-18 18:44 ` [PATCH 11/12] ARM: dts: stm32: add sram node within stm32mp151.dtsi Alain Volmat
2025-12-18 18:44 ` [PATCH 12/12] ARM: dts: stm32: enable DCMI DMA-MDMA chaining on stm32mp157c-ev1.dts Alain Volmat

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox