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 <[email protected]> --- 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
