From 3abf65738c67f85c2cecec403bb65e2ba5043304 Mon Sep 17 00:00:00 2001 From: Pratyush Yadav <p.yadav@ti.com> Date: Thu, 18 Feb 2021 17:39:41 +0530 Subject: [PATCH] HACK: media: ti-vpe: csi2rx: Drain DMA when stopping stream Some data might be stuck in the DMA pipeline because the application does not tell us how many frames it wants to capture. So there will always be some time delay between the application requesting the last frame it needs and stopping the stream which will stop DMA. Drain that data so it does not corrupt the next frame captured when the stream is re-started later. Marking this as a hack for now because it is not clear yet whether this is a hardware problem or a software problem. If it does turn out to be a hardware problem, it can be presented as a workaround instead. Signed-off-by: Pratyush Yadav <p.yadav@ti.com> Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com> --- drivers/media/platform/ti-vpe/ti-csi2rx.c | 64 +++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/drivers/media/platform/ti-vpe/ti-csi2rx.c b/drivers/media/platform/ti-vpe/ti-csi2rx.c index 967afb073348b..4345d80778823 100644 --- a/drivers/media/platform/ti-vpe/ti-csi2rx.c +++ b/drivers/media/platform/ti-vpe/ti-csi2rx.c @@ -40,6 +40,8 @@ #define CSI_DF_RGB444 0x20 #define CSI_DF_RGB888 0x24 +#define DRAIN_TIMEOUT_MS 50 + struct ti_csi2rx_fmt { u32 fourcc; /* Four character code. */ u32 code; /* Mbus code. */ @@ -73,6 +75,7 @@ struct ti_csi2rx_dev { struct dma_chan *dma; struct ti_csi2rx_dmaq dmaq; u32 sequence; + struct completion drain_complete; }; static const struct ti_csi2rx_fmt formats[] = { @@ -693,6 +696,57 @@ static int ti_csi2rx_start_dma(struct ti_csi2rx_dev *csi, return 0; } +static void ti_csi2rx_drain_callback(void *param) +{ + struct ti_csi2rx_dev *csi = param; + + complete(&csi->drain_complete); +} + +static int ti_csi2rx_drain_dma(struct ti_csi2rx_dev *csi) +{ + void *buf; + struct dma_async_tx_descriptor *desc; + struct device *dev = csi->dma->device->dev; + size_t len = csi->v_fmt.fmt.pix.sizeimage; + dma_addr_t addr; + dma_cookie_t cookie; + int ret; + + buf = dma_alloc_coherent(dev, len, &addr, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + desc = dmaengine_prep_slave_single(csi->dma, addr, len, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + ret = -EIO; + goto out; + } + + desc->callback = ti_csi2rx_drain_callback; + desc->callback_param = csi; + init_completion(&csi->drain_complete); + + cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); + if (ret) + goto out; + + dma_async_issue_pending(csi->dma); + + if (!wait_for_completion_timeout(&csi->drain_complete, + msecs_to_jiffies(DRAIN_TIMEOUT_MS))) { + dmaengine_terminate_sync(csi->dma); + ret = -ETIMEDOUT; + goto out; + } + +out: + dma_free_coherent(dev, len, buf, addr); + return ret; +} + static int ti_csi2rx_queue_setup(struct vb2_queue *q, unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[], struct device *alloc_devs[]) @@ -790,6 +844,16 @@ static void ti_csi2rx_stop_streaming(struct vb2_queue *vq) if (ret) dev_err(csi->dev, "Failed to stop DMA\n"); + /* + * Some data might be stuck in the DMA pipeline because the application + * does not tell us how many frames it wants to capture. So there will + * always be some time delay between the application requesting the last + * frame it needs and stopping the stream which will stop DMA. Drain + * that data so it does not corrupt the next frame captured when the + * stream is re-started later. + */ + ti_csi2rx_drain_dma(csi); + writel(0, csi->shim + SHIM_DMACNTX); list_for_each_entry_safe(buf, tmp, &csi->dmaq.list, list) { -- GitLab