static int fimc_lite_release(struct file *file) { struct fimc_lite *fimc = video_drvdata(file); struct media_entity *entity = &fimc->ve.vdev.entity; mutex_lock(&fimc->lock); if (v4l2_fh_is_singular_file(file) && atomic_read(&fimc->out_path) == FIMC_IO_DMA) { if (fimc->streaming) { media_entity_pipeline_stop(entity); fimc->streaming = false; } fimc_lite_stop_capture(fimc, false); fimc_pipeline_call(&fimc->ve, close); clear_bit(ST_FLITE_IN_USE, &fimc->state); mutex_lock(&entity->parent->graph_mutex); entity->use_count--; mutex_unlock(&entity->parent->graph_mutex); } _vb2_fop_release(file, NULL); pm_runtime_put(&fimc->pdev->dev); clear_bit(ST_FLITE_SUSPENDED, &fimc->state); mutex_unlock(&fimc->lock); return 0; }
static int fimc_lite_open(struct file *file) { struct fimc_lite *fimc = video_drvdata(file); int ret; if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; set_bit(ST_FLITE_IN_USE, &fimc->state); ret = pm_runtime_get_sync(&fimc->pdev->dev); if (ret < 0) goto done; ret = v4l2_fh_open(file); if (ret < 0) goto done; if (++fimc->ref_count == 1 && fimc->out_path == FIMC_IO_DMA) { ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, &fimc->vfd.entity, true); if (ret < 0) { pm_runtime_put_sync(&fimc->pdev->dev); fimc->ref_count--; v4l2_fh_release(file); clear_bit(ST_FLITE_IN_USE, &fimc->state); } fimc_lite_clear_event_counters(fimc); } done: mutex_unlock(&fimc->lock); return ret; }
static void isp_video_capture_stop_streaming(struct vb2_queue *q) { struct fimc_isp *isp = vb2_get_drv_priv(q); struct fimc_is *is = fimc_isp_to_is(isp); struct param_dma_output *dma = __get_isp_dma2(is); int ret; ret = fimc_pipeline_call(&isp->video_capture.ve, set_stream, 0); if (ret < 0) return; dma->cmd = DMA_OUTPUT_COMMAND_DISABLE; dma->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE; dma->buffer_number = 0; dma->buffer_address = 0; dma->dma_out_mask = 0; fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT); __fimc_is_hw_update_param(is, PARAM_ISP_DMA2_OUTPUT); ret = fimc_is_itf_s_param(is, false); if (ret < 0) dev_warn(&is->pdev->dev, "%s: DMA stop failed\n", __func__); fimc_is_hw_set_isp_buf_mask(is, 0); clear_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state); clear_bit(ST_ISP_VID_CAP_STREAMING, &isp->state); isp->video_capture.buf_count = 0; }
static int fimc_lite_close(struct file *file) { struct fimc_lite *fimc = video_drvdata(file); int ret; if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; if (--fimc->ref_count == 0 && fimc->out_path == FIMC_IO_DMA) { clear_bit(ST_FLITE_IN_USE, &fimc->state); fimc_lite_stop_capture(fimc, false); fimc_pipeline_call(fimc, close, &fimc->pipeline); clear_bit(ST_FLITE_SUSPENDED, &fimc->state); } pm_runtime_put(&fimc->pdev->dev); if (fimc->ref_count == 0) vb2_queue_release(&fimc->vb_queue); ret = v4l2_fh_release(file); mutex_unlock(&fimc->lock); return ret; }
static int isp_video_release(struct file *file) { struct fimc_isp *isp = video_drvdata(file); struct fimc_is_video *ivc = &isp->video_capture; struct media_entity *entity = &ivc->ve.vdev.entity; struct media_device *mdev = entity->graph_obj.mdev; mutex_lock(&isp->video_lock); if (v4l2_fh_is_singular_file(file) && ivc->streaming) { media_entity_pipeline_stop(entity); ivc->streaming = 0; } vb2_fop_release(file); if (v4l2_fh_is_singular_file(file)) { fimc_pipeline_call(&ivc->ve, close); mutex_lock(&mdev->graph_mutex); entity->use_count--; mutex_unlock(&mdev->graph_mutex); } pm_runtime_put(&isp->pdev->dev); mutex_unlock(&isp->video_lock); return 0; }
int fimc_capture_resume(struct fimc_dev *fimc) { struct fimc_vid_cap *vid_cap = &fimc->vid_cap; struct fimc_vid_buffer *buf; int i; if (!test_and_clear_bit(ST_CAPT_SUSPENDED, &fimc->state)) return 0; INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q); vid_cap->buf_index = 0; fimc_pipeline_call(fimc, open, &fimc->pipeline, &vid_cap->vfd.entity, false); fimc_capture_hw_init(fimc); clear_bit(ST_CAPT_SUSPENDED, &fimc->state); for (i = 0; i < vid_cap->reqbufs_count; i++) { if (list_empty(&vid_cap->pending_buf_q)) break; buf = fimc_pending_queue_pop(vid_cap); buffer_queue(&buf->vb); } return 0; }
static int start_streaming(struct vb2_queue *q, unsigned int count) { struct fimc_lite *fimc = q->drv_priv; int ret; fimc->frame_count = 0; ret = fimc_lite_hw_init(fimc); if (ret) { fimc_lite_reinit(fimc, false); return ret; } set_bit(ST_FLITE_PENDING, &fimc->state); if (!list_empty(&fimc->active_buf_q) && !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) { flite_hw_capture_start(fimc); if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state)) fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1); } if (debug > 0) flite_hw_dump_regs(fimc, __func__); return 0; }
static int start_streaming(struct vb2_queue *q, unsigned int count) { struct fimc_lite *fimc = q->drv_priv; unsigned long flags; int ret; spin_lock_irqsave(&fimc->slock, flags); fimc->buf_index = 0; fimc->frame_count = 0; spin_unlock_irqrestore(&fimc->slock, flags); ret = fimc_lite_hw_init(fimc, false); if (ret) { fimc_lite_reinit(fimc, false); return ret; } set_bit(ST_FLITE_PENDING, &fimc->state); if (!list_empty(&fimc->active_buf_q) && !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) { flite_hw_capture_start(fimc); if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state)) fimc_pipeline_call(&fimc->ve, set_stream, 1); } if (debug > 0) flite_hw_dump_regs(fimc, __func__); return 0; }
static int start_streaming(struct vb2_queue *q, unsigned int count) { struct fimc_ctx *ctx = q->drv_priv; struct fimc_dev *fimc = ctx->fimc_dev; struct fimc_vid_cap *vid_cap = &fimc->vid_cap; int min_bufs; int ret; vid_cap->frame_count = 0; ret = fimc_capture_hw_init(fimc); if (ret) { fimc_capture_state_cleanup(fimc, false); return ret; } set_bit(ST_CAPT_PEND, &fimc->state); min_bufs = fimc->vid_cap.reqbufs_count > 1 ? 2 : 1; if (vid_cap->active_buf_cnt >= min_bufs && !test_and_set_bit(ST_CAPT_STREAM, &fimc->state)) { fimc_activate_capture(ctx); if (!test_and_set_bit(ST_CAPT_ISP_STREAM, &fimc->state)) fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1); } return 0; }
static void buffer_queue(struct vb2_buffer *vb) { struct flite_buffer *buf = container_of(vb, struct flite_buffer, vb); struct fimc_lite *fimc = vb2_get_drv_priv(vb->vb2_queue); unsigned long flags; spin_lock_irqsave(&fimc->slock, flags); buf->paddr = vb2_dma_contig_plane_dma_addr(vb, 0); if (!test_bit(ST_FLITE_SUSPENDED, &fimc->state) && !test_bit(ST_FLITE_STREAM, &fimc->state) && list_empty(&fimc->active_buf_q)) { flite_hw_set_output_addr(fimc, buf->paddr); fimc_lite_active_queue_add(fimc, buf); } else { fimc_lite_pending_queue_add(fimc, buf); } if (vb2_is_streaming(&fimc->vb_queue) && !list_empty(&fimc->pending_buf_q) && !test_and_set_bit(ST_FLITE_STREAM, &fimc->state)) { flite_hw_capture_start(fimc); spin_unlock_irqrestore(&fimc->slock, flags); if (!test_and_set_bit(ST_SENSOR_STREAM, &fimc->state)) fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 1); return; } spin_unlock_irqrestore(&fimc->slock, flags); }
static int fimc_capture_close(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); int ret; dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; if (--fimc->vid_cap.refcnt == 0) { clear_bit(ST_CAPT_BUSY, &fimc->state); fimc_stop_capture(fimc, false); fimc_pipeline_call(fimc, close, &fimc->pipeline); clear_bit(ST_CAPT_SUSPENDED, &fimc->state); } pm_runtime_put(&fimc->pdev->dev); if (fimc->vid_cap.refcnt == 0) { vb2_queue_release(&fimc->vid_cap.vbq); fimc_ctrls_delete(fimc->vid_cap.ctx); } ret = v4l2_fh_release(file); mutex_unlock(&fimc->lock); return ret; }
static int fimc_lite_resume(struct device *dev) { struct fimc_lite *fimc = dev_get_drvdata(dev); struct flite_buffer *buf; unsigned long flags; int i; spin_lock_irqsave(&fimc->slock, flags); if (!test_and_clear_bit(ST_LPM, &fimc->state) || !test_bit(ST_FLITE_IN_USE, &fimc->state)) { spin_unlock_irqrestore(&fimc->slock, flags); return 0; } flite_hw_reset(fimc); spin_unlock_irqrestore(&fimc->slock, flags); if (!test_and_clear_bit(ST_FLITE_SUSPENDED, &fimc->state)) return 0; INIT_LIST_HEAD(&fimc->active_buf_q); fimc_pipeline_call(fimc, open, &fimc->pipeline, &fimc->vfd.entity, false); fimc_lite_hw_init(fimc); clear_bit(ST_FLITE_SUSPENDED, &fimc->state); for (i = 0; i < fimc->reqbufs_count; i++) { if (list_empty(&fimc->pending_buf_q)) break; buf = fimc_lite_pending_queue_pop(fimc); buffer_queue(&buf->vb); } return 0; }
int fimc_capture_suspend(struct fimc_dev *fimc) { bool suspend = fimc_capture_busy(fimc); int ret = fimc_stop_capture(fimc, suspend); if (ret) return ret; return fimc_pipeline_call(fimc, close, &fimc->pipeline); }
static int fimc_lite_suspend(struct device *dev) { struct fimc_lite *fimc = dev_get_drvdata(dev); bool suspend = test_bit(ST_FLITE_IN_USE, &fimc->state); int ret; if (test_and_set_bit(ST_LPM, &fimc->state)) return 0; ret = fimc_lite_stop_capture(fimc, suspend); if (ret < 0 || !fimc_lite_active(fimc)) return ret; return fimc_pipeline_call(fimc, close, &fimc->pipeline); }
static int fimc_lite_open(struct file *file) { struct fimc_lite *fimc = video_drvdata(file); struct media_entity *me = &fimc->ve.vdev.entity; int ret; mutex_lock(&fimc->lock); if (atomic_read(&fimc->out_path) != FIMC_IO_DMA) { ret = -EBUSY; goto unlock; } set_bit(ST_FLITE_IN_USE, &fimc->state); ret = pm_runtime_get_sync(&fimc->pdev->dev); if (ret < 0) goto unlock; ret = v4l2_fh_open(file); if (ret < 0) goto err_pm; if (!v4l2_fh_is_singular_file(file) || atomic_read(&fimc->out_path) != FIMC_IO_DMA) goto unlock; mutex_lock(&me->parent->graph_mutex); ret = fimc_pipeline_call(&fimc->ve, open, me, true); /* Mark video pipeline ending at this video node as in use. */ if (ret == 0) me->use_count++; mutex_unlock(&me->parent->graph_mutex); if (!ret) { fimc_lite_clear_event_counters(fimc); goto unlock; } v4l2_fh_release(file); err_pm: pm_runtime_put_sync(&fimc->pdev->dev); clear_bit(ST_FLITE_IN_USE, &fimc->state); unlock: mutex_unlock(&fimc->lock); 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); }
static int fimc_capture_open(struct file *file) { struct fimc_dev *fimc = video_drvdata(file); int ret = -EBUSY; dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state); if (mutex_lock_interruptible(&fimc->lock)) return -ERESTARTSYS; if (fimc_m2m_active(fimc)) goto unlock; set_bit(ST_CAPT_BUSY, &fimc->state); ret = pm_runtime_get_sync(&fimc->pdev->dev); if (ret < 0) goto unlock; ret = v4l2_fh_open(file); if (ret) { pm_runtime_put(&fimc->pdev->dev); goto unlock; } if (++fimc->vid_cap.refcnt == 1) { ret = fimc_pipeline_call(fimc, open, &fimc->pipeline, &fimc->vid_cap.vfd.entity, true); if (!ret && !fimc->vid_cap.user_subdev_api) ret = fimc_capture_set_default_format(fimc); if (!ret) ret = fimc_capture_ctrls_create(fimc); if (ret < 0) { clear_bit(ST_CAPT_BUSY, &fimc->state); pm_runtime_put_sync(&fimc->pdev->dev); fimc->vid_cap.refcnt--; v4l2_fh_release(file); } } unlock: mutex_unlock(&fimc->lock); return ret; }
/* * 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; }
static int isp_video_capture_start_streaming(struct vb2_queue *q, unsigned int count) { struct fimc_isp *isp = vb2_get_drv_priv(q); struct fimc_is *is = fimc_isp_to_is(isp); struct param_dma_output *dma = __get_isp_dma2(is); struct fimc_is_video *video = &isp->video_capture; int ret; if (!test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state) || test_bit(ST_ISP_VID_CAP_STREAMING, &isp->state)) return 0; dma->cmd = DMA_OUTPUT_COMMAND_ENABLE; dma->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_ENABLE; dma->buffer_address = is->is_dma_p_region + DMA2_OUTPUT_ADDR_ARRAY_OFFS; dma->buffer_number = video->reqbufs_count; dma->dma_out_mask = video->buf_mask; isp_dbg(2, &video->ve.vdev, "buf_count: %d, planes: %d, dma addr table: %#x\n", video->buf_count, video->format->memplanes, dma->buffer_address); fimc_is_mem_barrier(); fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT); __fimc_is_hw_update_param(is, PARAM_ISP_DMA2_OUTPUT); ret = fimc_is_itf_s_param(is, false); if (ret < 0) return ret; ret = fimc_pipeline_call(&video->ve, set_stream, 1); if (ret < 0) return ret; set_bit(ST_ISP_VID_CAP_STREAMING, &isp->state); return ret; }
/* * 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_lite_reinit(struct fimc_lite *fimc, bool suspend) { struct flite_buffer *buf; unsigned long flags; bool streaming; spin_lock_irqsave(&fimc->slock, flags); streaming = fimc->state & (1 << ST_SENSOR_STREAM); fimc->state &= ~(1 << ST_FLITE_RUN | 1 << ST_FLITE_OFF | 1 << ST_FLITE_STREAM | 1 << ST_SENSOR_STREAM); if (suspend) fimc->state |= (1 << ST_FLITE_SUSPENDED); else fimc->state &= ~(1 << ST_FLITE_PENDING | 1 << ST_FLITE_SUSPENDED); /* Release unused buffers */ while (!suspend && !list_empty(&fimc->pending_buf_q)) { buf = fimc_lite_pending_queue_pop(fimc); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } /* If suspending put unused buffers onto pending queue */ while (!list_empty(&fimc->active_buf_q)) { buf = fimc_lite_active_queue_pop(fimc); if (suspend) fimc_lite_pending_queue_add(fimc, buf); else vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } spin_unlock_irqrestore(&fimc->slock, flags); flite_hw_reset(fimc); if (!streaming) return 0; return fimc_pipeline_call(fimc, set_stream, &fimc->pipeline, 0); }
static int isp_video_open(struct file *file) { struct fimc_isp *isp = video_drvdata(file); struct exynos_video_entity *ve = &isp->video_capture.ve; struct media_entity *me = &ve->vdev.entity; int ret; if (mutex_lock_interruptible(&isp->video_lock)) return -ERESTARTSYS; ret = v4l2_fh_open(file); if (ret < 0) goto unlock; ret = pm_runtime_get_sync(&isp->pdev->dev); if (ret < 0) goto rel_fh; if (v4l2_fh_is_singular_file(file)) { mutex_lock(&me->graph_obj.mdev->graph_mutex); ret = fimc_pipeline_call(ve, open, me, true); /* Mark the video pipeline as in use. */ if (ret == 0) me->use_count++; mutex_unlock(&me->graph_obj.mdev->graph_mutex); } if (!ret) goto unlock; rel_fh: v4l2_fh_release(file); unlock: mutex_unlock(&isp->video_lock); return ret; }