/* * At least one buffer on the pending_buf_q queue is required. * Locking: The caller holds fimc->slock spinlock. */ int fimc_vid_cap_buf_queue(struct fimc_dev *fimc, struct fimc_vid_buffer *fimc_vb) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_ctx *ctx = cap->ctx; int ret = 0; BUG_ON(!fimc || !fimc_vb); ret = fimc_prepare_addr(ctx, fimc_vb, &ctx->d_frame, &fimc_vb->paddr); if (ret) return ret; if (test_bit(ST_CAPT_STREAM, &fimc->state)) { fimc_pending_queue_add(cap, fimc_vb); } else { /* Setup the buffer directly for processing. */ int buf_id = (cap->reqbufs_count == 1) ? -1 : cap->buf_index; fimc_hw_set_output_addr(fimc, &fimc_vb->paddr, buf_id); fimc_vb->index = cap->buf_index; active_queue_add(cap, fimc_vb); if (++cap->buf_index >= FIMC_MAX_OUT_BUFS) cap->buf_index = 0; } return ret; }
static void buffer_queue(struct vb2_buffer *vb) { struct fimc_vid_buffer *buf = container_of(vb, struct fimc_vid_buffer, vb); struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_vid_cap *vid_cap = &fimc->vid_cap; unsigned long flags; int min_bufs; spin_lock_irqsave(&fimc->slock, flags); fimc_prepare_addr(ctx, &buf->vb, &ctx->d_frame, &buf->paddr); if (!test_bit(ST_CAPT_SUSPENDED, &fimc->state) && !test_bit(ST_CAPT_STREAM, &fimc->state) && vid_cap->active_buf_cnt < FIMC_MAX_OUT_BUFS) { /* Setup the buffer directly for processing. */ int buf_id = (vid_cap->reqbufs_count == 1) ? -1 : vid_cap->buf_index; fimc_hw_set_output_addr(fimc, &buf->paddr, buf_id); buf->index = vid_cap->buf_index; fimc_active_queue_add(vid_cap, buf); if (++vid_cap->buf_index >= FIMC_MAX_OUT_BUFS) vid_cap->buf_index = 0; } else { fimc_pending_queue_add(vid_cap, buf); } min_bufs = vid_cap->reqbufs_count > 1 ? 2 : 1; if (vb2_is_streaming(&vid_cap->vbq) && vid_cap->active_buf_cnt >= min_bufs && !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { fimc_activate_capture(ctx); spin_unlock_irqrestore(&fimc->slock, flags); if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1); return; } spin_unlock_irqrestore(&fimc->slock, flags); }
/* * Reinitialize the driver so it is ready to start the streaming again. * Set fimc->state to indicate stream off and the hardware shut down state. * If not suspending (@suspend is false), return any buffers to videobuf2. * Otherwise put any owned buffers onto the pending buffers queue, so they * can be re-spun when the device is being resumed. Also perform FIMC * software reset and disable streaming on the whole pipeline if required. */ static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend) { struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_vid_buffer *buf; unsigned long flags; bool streaming; spin_lock_irqsave(&fimc->slock, flags); streaming = fimc->state & (1 << ST_CAPT_ISP_STREAM); fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_SHUT | 1 << ST_CAPT_STREAM | 1 << ST_CAPT_ISP_STREAM); if (suspend) fimc->state |= (1 << ST_CAPT_SUSPENDED); else fimc->state &= ~(1 << ST_CAPT_PEND | 1 << ST_CAPT_SUSPENDED); /* Release unused buffers */ while (!suspend && !list_empty(&cap->pending_buf_q)) { buf = fimc_pending_queue_pop(cap); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } /* If suspending put unused buffers onto pending queue */ while (!list_empty(&cap->active_buf_q)) { buf = fimc_active_queue_pop(cap); if (suspend) fimc_pending_queue_add(cap, buf); else vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } fimc_hw_reset(fimc); cap->buf_index = 0; spin_unlock_irqrestore(&fimc->slock, flags); if (streaming) return fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 0); else return 0; }