Lines Matching +full:fimc +full:- +full:is
1 // SPDX-License-Identifier: GPL-2.0-only
3 * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
5 * FIMC-IS ISP video input and video output DMA interface driver
26 #include <media/v4l2-device.h>
27 #include <media/v4l2-ioctl.h>
28 #include <media/videobuf2-v4l2.h>
29 #include <media/videobuf2-dma-contig.h>
30 #include <media/drv-intf/exynos-fimc.h>
33 #include "media-dev.h"
34 #include "fimc-is.h"
35 #include "fimc-isp-video.h"
36 #include "fimc-is-param.h"
43 const struct v4l2_pix_format_mplane *vid_fmt = &isp->video_capture.pixfmt; in isp_video_capture_queue_setup()
44 const struct fimc_fmt *fmt = isp->video_capture.format; in isp_video_capture_queue_setup()
47 wh = vid_fmt->width * vid_fmt->height; in isp_video_capture_queue_setup()
50 return -EINVAL; in isp_video_capture_queue_setup()
55 if (*num_planes != fmt->memplanes) in isp_video_capture_queue_setup()
56 return -EINVAL; in isp_video_capture_queue_setup()
58 if (sizes[i] < (wh * fmt->depth[i]) / 8) in isp_video_capture_queue_setup()
59 return -EINVAL; in isp_video_capture_queue_setup()
63 *num_planes = fmt->memplanes; in isp_video_capture_queue_setup()
65 for (i = 0; i < fmt->memplanes; i++) in isp_video_capture_queue_setup()
66 sizes[i] = (wh * fmt->depth[i]) / 8; in isp_video_capture_queue_setup()
71 static inline struct param_dma_output *__get_isp_dma2(struct fimc_is *is) in __get_isp_dma2() argument
73 return &__get_curr_is_config(is)->isp.dma2_output; in __get_isp_dma2()
80 struct fimc_is *is = fimc_isp_to_is(isp); in isp_video_capture_start_streaming() local
81 struct param_dma_output *dma = __get_isp_dma2(is); in isp_video_capture_start_streaming()
82 struct fimc_is_video *video = &isp->video_capture; in isp_video_capture_start_streaming()
85 if (!test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state) || in isp_video_capture_start_streaming()
86 test_bit(ST_ISP_VID_CAP_STREAMING, &isp->state)) in isp_video_capture_start_streaming()
90 dma->cmd = DMA_OUTPUT_COMMAND_ENABLE; in isp_video_capture_start_streaming()
91 dma->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_ENABLE; in isp_video_capture_start_streaming()
92 dma->buffer_address = is->is_dma_p_region + in isp_video_capture_start_streaming()
94 dma->buffer_number = video->reqbufs_count; in isp_video_capture_start_streaming()
95 dma->dma_out_mask = video->buf_mask; in isp_video_capture_start_streaming()
97 isp_dbg(2, &video->ve.vdev, in isp_video_capture_start_streaming()
99 video->buf_count, video->format->memplanes, in isp_video_capture_start_streaming()
100 dma->buffer_address); in isp_video_capture_start_streaming()
104 fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT); in isp_video_capture_start_streaming()
105 __fimc_is_hw_update_param(is, PARAM_ISP_DMA2_OUTPUT); in isp_video_capture_start_streaming()
107 ret = fimc_is_itf_s_param(is, false); in isp_video_capture_start_streaming()
111 ret = fimc_pipeline_call(&video->ve, set_stream, 1); in isp_video_capture_start_streaming()
115 set_bit(ST_ISP_VID_CAP_STREAMING, &isp->state); in isp_video_capture_start_streaming()
122 struct fimc_is *is = fimc_isp_to_is(isp); in isp_video_capture_stop_streaming() local
123 struct param_dma_output *dma = __get_isp_dma2(is); in isp_video_capture_stop_streaming()
126 ret = fimc_pipeline_call(&isp->video_capture.ve, set_stream, 0); in isp_video_capture_stop_streaming()
130 dma->cmd = DMA_OUTPUT_COMMAND_DISABLE; in isp_video_capture_stop_streaming()
131 dma->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE; in isp_video_capture_stop_streaming()
132 dma->buffer_number = 0; in isp_video_capture_stop_streaming()
133 dma->buffer_address = 0; in isp_video_capture_stop_streaming()
134 dma->dma_out_mask = 0; in isp_video_capture_stop_streaming()
136 fimc_is_set_param_bit(is, PARAM_ISP_DMA2_OUTPUT); in isp_video_capture_stop_streaming()
137 __fimc_is_hw_update_param(is, PARAM_ISP_DMA2_OUTPUT); in isp_video_capture_stop_streaming()
139 ret = fimc_is_itf_s_param(is, false); in isp_video_capture_stop_streaming()
141 dev_warn(&is->pdev->dev, "%s: DMA stop failed\n", __func__); in isp_video_capture_stop_streaming()
143 fimc_is_hw_set_isp_buf_mask(is, 0); in isp_video_capture_stop_streaming()
145 clear_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state); in isp_video_capture_stop_streaming()
146 clear_bit(ST_ISP_VID_CAP_STREAMING, &isp->state); in isp_video_capture_stop_streaming()
148 isp->video_capture.buf_count = 0; in isp_video_capture_stop_streaming()
153 struct fimc_isp *isp = vb2_get_drv_priv(vb->vb2_queue); in isp_video_capture_buffer_prepare()
154 struct fimc_is_video *video = &isp->video_capture; in isp_video_capture_buffer_prepare()
157 if (video->format == NULL) in isp_video_capture_buffer_prepare()
158 return -EINVAL; in isp_video_capture_buffer_prepare()
160 for (i = 0; i < video->format->memplanes; i++) { in isp_video_capture_buffer_prepare()
161 unsigned long size = video->pixfmt.plane_fmt[i].sizeimage; in isp_video_capture_buffer_prepare()
164 v4l2_err(&video->ve.vdev, in isp_video_capture_buffer_prepare()
167 return -EINVAL; in isp_video_capture_buffer_prepare()
173 if (test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state)) { in isp_video_capture_buffer_prepare()
177 for (i = 0; i < video->buf_count; i++) in isp_video_capture_buffer_prepare()
178 if (video->buffers[i]->dma_addr[0] == dma_addr) in isp_video_capture_buffer_prepare()
180 return -ENXIO; in isp_video_capture_buffer_prepare()
189 struct fimc_isp *isp = vb2_get_drv_priv(vb->vb2_queue); in isp_video_capture_buffer_queue()
190 struct fimc_is_video *video = &isp->video_capture; in isp_video_capture_buffer_queue()
191 struct fimc_is *is = fimc_isp_to_is(isp); in isp_video_capture_buffer_queue() local
196 if (test_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state)) { in isp_video_capture_buffer_queue()
197 spin_lock_irqsave(&is->slock, flags); in isp_video_capture_buffer_queue()
198 video->buf_mask |= BIT(ivb->index); in isp_video_capture_buffer_queue()
199 spin_unlock_irqrestore(&is->slock, flags); in isp_video_capture_buffer_queue()
201 unsigned int num_planes = video->format->memplanes; in isp_video_capture_buffer_queue()
203 ivb->index = video->buf_count; in isp_video_capture_buffer_queue()
204 video->buffers[ivb->index] = ivb; in isp_video_capture_buffer_queue()
207 int buf_index = ivb->index * num_planes + i; in isp_video_capture_buffer_queue()
209 ivb->dma_addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); in isp_video_capture_buffer_queue()
210 is->is_p_region->shared[32 + buf_index] = in isp_video_capture_buffer_queue()
211 ivb->dma_addr[i]; in isp_video_capture_buffer_queue()
213 isp_dbg(2, &video->ve.vdev, in isp_video_capture_buffer_queue()
215 buf_index, ivb->index, i, vb->index, in isp_video_capture_buffer_queue()
216 &ivb->dma_addr[i]); in isp_video_capture_buffer_queue()
219 if (++video->buf_count < video->reqbufs_count) in isp_video_capture_buffer_queue()
222 video->buf_mask = (1UL << video->buf_count) - 1; in isp_video_capture_buffer_queue()
223 set_bit(ST_ISP_VID_CAP_BUF_PREP, &isp->state); in isp_video_capture_buffer_queue()
226 if (!test_bit(ST_ISP_VID_CAP_STREAMING, &isp->state)) in isp_video_capture_buffer_queue()
227 isp_video_capture_start_streaming(vb->vb2_queue, 0); in isp_video_capture_buffer_queue()
231 * FIMC-IS ISP input and output DMA interface interrupt handler.
232 * Locking: called with is->slock spinlock held.
234 void fimc_isp_video_irq_handler(struct fimc_is *is) in fimc_isp_video_irq_handler() argument
236 struct fimc_is_video *video = &is->isp.video_capture; in fimc_isp_video_irq_handler()
240 /* TODO: Ensure the DMA is really stopped in stop_streaming callback */ in fimc_isp_video_irq_handler()
241 if (!test_bit(ST_ISP_VID_CAP_STREAMING, &is->isp.state)) in fimc_isp_video_irq_handler()
244 buf_index = (is->i2h_cmd.args[1] - 1) % video->buf_count; in fimc_isp_video_irq_handler()
245 vbuf = &video->buffers[buf_index]->vb; in fimc_isp_video_irq_handler()
247 vbuf->vb2_buf.timestamp = ktime_get_ns(); in fimc_isp_video_irq_handler()
248 vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE); in fimc_isp_video_irq_handler()
250 video->buf_mask &= ~BIT(buf_index); in fimc_isp_video_irq_handler()
251 fimc_is_hw_set_isp_buf_mask(is, video->buf_mask); in fimc_isp_video_irq_handler()
267 struct exynos_video_entity *ve = &isp->video_capture.ve; in isp_video_open()
268 struct media_entity *me = &ve->vdev.entity; in isp_video_open()
271 if (mutex_lock_interruptible(&isp->video_lock)) in isp_video_open()
272 return -ERESTARTSYS; in isp_video_open()
278 ret = pm_runtime_resume_and_get(&isp->pdev->dev); in isp_video_open()
283 mutex_lock(&me->graph_obj.mdev->graph_mutex); in isp_video_open()
289 me->use_count++; in isp_video_open()
291 mutex_unlock(&me->graph_obj.mdev->graph_mutex); in isp_video_open()
298 mutex_unlock(&isp->video_lock); in isp_video_open()
305 struct fimc_is_video *ivc = &isp->video_capture; in isp_video_release()
306 struct media_entity *entity = &ivc->ve.vdev.entity; in isp_video_release()
307 struct media_device *mdev = entity->graph_obj.mdev; in isp_video_release()
310 mutex_lock(&isp->video_lock); in isp_video_release()
314 if (is_singular_file && ivc->streaming) { in isp_video_release()
315 video_device_pipeline_stop(&ivc->ve.vdev); in isp_video_release()
316 ivc->streaming = 0; in isp_video_release()
322 fimc_pipeline_call(&ivc->ve, close); in isp_video_release()
324 mutex_lock(&mdev->graph_mutex); in isp_video_release()
325 entity->use_count--; in isp_video_release()
326 mutex_unlock(&mdev->graph_mutex); in isp_video_release()
329 pm_runtime_put(&isp->pdev->dev); in isp_video_release()
330 mutex_unlock(&isp->video_lock); in isp_video_release()
352 __fimc_vidioc_querycap(&isp->pdev->dev, cap); in isp_video_querycap()
361 if (f->index >= FIMC_ISP_NUM_FORMATS) in isp_video_enum_fmt()
362 return -EINVAL; in isp_video_enum_fmt()
364 fmt = fimc_isp_find_format(NULL, NULL, f->index); in isp_video_enum_fmt()
366 return -EINVAL; in isp_video_enum_fmt()
368 f->pixelformat = fmt->fourcc; in isp_video_enum_fmt()
378 f->fmt.pix_mp = isp->video_capture.pixfmt; in isp_video_g_fmt_mplane()
388 __fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, 2); in __isp_video_try_fmt()
393 pixm->colorspace = V4L2_COLORSPACE_SRGB; in __isp_video_try_fmt()
394 pixm->field = V4L2_FIELD_NONE; in __isp_video_try_fmt()
395 pixm->num_planes = __fmt->memplanes; in __isp_video_try_fmt()
396 pixm->pixelformat = __fmt->fourcc; in __isp_video_try_fmt()
401 v4l_bound_align_image(&pixm->width, FIMC_ISP_SOURCE_WIDTH_MIN, in __isp_video_try_fmt()
403 &pixm->height, FIMC_ISP_SOURCE_HEIGHT_MIN, in __isp_video_try_fmt()
412 __isp_video_try_fmt(isp, &f->fmt.pix_mp, NULL); in isp_video_try_fmt_mplane()
420 struct fimc_is *is = fimc_isp_to_is(isp); in isp_video_s_fmt_mplane() local
421 struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; in isp_video_s_fmt_mplane()
423 struct param_dma_output *dma = __get_isp_dma2(is); in isp_video_s_fmt_mplane()
428 return -EINVAL; in isp_video_s_fmt_mplane()
430 dma->format = DMA_OUTPUT_FORMAT_BAYER; in isp_video_s_fmt_mplane()
431 dma->order = DMA_OUTPUT_ORDER_GB_BG; in isp_video_s_fmt_mplane()
432 dma->plane = ifmt->memplanes; in isp_video_s_fmt_mplane()
433 dma->bitwidth = ifmt->depth[0]; in isp_video_s_fmt_mplane()
434 dma->width = pixm->width; in isp_video_s_fmt_mplane()
435 dma->height = pixm->height; in isp_video_s_fmt_mplane()
439 isp->video_capture.format = ifmt; in isp_video_s_fmt_mplane()
440 isp->video_capture.pixfmt = *pixm; in isp_video_s_fmt_mplane()
447 * Return 0 if the formats match or -EPIPE otherwise.
451 struct v4l2_subdev *sd = &isp->subdev; in isp_video_pipeline_validate()
464 pad = &sd->entity.pads[0]; in isp_video_pipeline_validate()
465 if (!(pad->flags & MEDIA_PAD_FL_SINK)) in isp_video_pipeline_validate()
467 sink_fmt.pad = pad->index; in isp_video_pipeline_validate()
469 if (ret < 0 && ret != -ENOIOCTLCMD) in isp_video_pipeline_validate()
470 return -EPIPE; in isp_video_pipeline_validate()
474 if (!pad || !is_media_entity_v4l2_subdev(pad->entity)) in isp_video_pipeline_validate()
477 sd = media_entity_to_v4l2_subdev(pad->entity); in isp_video_pipeline_validate()
478 src_fmt.pad = pad->index; in isp_video_pipeline_validate()
480 if (ret < 0 && ret != -ENOIOCTLCMD) in isp_video_pipeline_validate()
481 return -EPIPE; in isp_video_pipeline_validate()
486 return -EPIPE; in isp_video_pipeline_validate()
496 struct exynos_video_entity *ve = &isp->video_capture.ve; in isp_video_streamon()
499 ret = video_device_pipeline_start(&ve->vdev, &ve->pipe->mp); in isp_video_streamon()
511 isp->video_capture.streaming = 1; in isp_video_streamon()
514 video_device_pipeline_stop(&ve->vdev); in isp_video_streamon()
522 struct fimc_is_video *video = &isp->video_capture; in isp_video_streamoff()
529 video_device_pipeline_stop(&video->ve.vdev); in isp_video_streamoff()
530 video->streaming = 0; in isp_video_streamoff()
544 if (rb->count && rb->count < FIMC_ISP_REQ_BUFS_MIN) { in isp_video_reqbufs()
545 rb->count = 0; in isp_video_reqbufs()
547 ret = -ENOMEM; in isp_video_reqbufs()
550 isp->video_capture.reqbufs_count = rb->count; in isp_video_reqbufs()
574 struct vb2_queue *q = &isp->video_capture.vb_queue; in fimc_isp_video_device_register()
580 iv = &isp->video_capture; in fimc_isp_video_device_register()
582 return -ENOSYS; in fimc_isp_video_device_register()
584 mutex_init(&isp->video_lock); in fimc_isp_video_device_register()
585 INIT_LIST_HEAD(&iv->pending_buf_q); in fimc_isp_video_device_register()
586 INIT_LIST_HEAD(&iv->active_buf_q); in fimc_isp_video_device_register()
587 iv->format = fimc_isp_find_format(NULL, NULL, 0); in fimc_isp_video_device_register()
588 iv->pixfmt.width = IS_DEFAULT_WIDTH; in fimc_isp_video_device_register()
589 iv->pixfmt.height = IS_DEFAULT_HEIGHT; in fimc_isp_video_device_register()
590 iv->pixfmt.pixelformat = iv->format->fourcc; in fimc_isp_video_device_register()
591 iv->pixfmt.colorspace = V4L2_COLORSPACE_SRGB; in fimc_isp_video_device_register()
592 iv->reqbufs_count = 0; in fimc_isp_video_device_register()
595 q->type = type; in fimc_isp_video_device_register()
596 q->io_modes = VB2_MMAP | VB2_USERPTR; in fimc_isp_video_device_register()
597 q->ops = &isp_video_capture_qops; in fimc_isp_video_device_register()
598 q->mem_ops = &vb2_dma_contig_memops; in fimc_isp_video_device_register()
599 q->buf_struct_size = sizeof(struct isp_video_buf); in fimc_isp_video_device_register()
600 q->drv_priv = isp; in fimc_isp_video_device_register()
601 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; in fimc_isp_video_device_register()
602 q->lock = &isp->video_lock; in fimc_isp_video_device_register()
603 q->dev = &isp->pdev->dev; in fimc_isp_video_device_register()
609 vdev = &iv->ve.vdev; in fimc_isp_video_device_register()
611 strscpy(vdev->name, "fimc-is-isp.capture", sizeof(vdev->name)); in fimc_isp_video_device_register()
612 vdev->queue = q; in fimc_isp_video_device_register()
613 vdev->fops = &isp_video_fops; in fimc_isp_video_device_register()
614 vdev->ioctl_ops = &isp_video_ioctl_ops; in fimc_isp_video_device_register()
615 vdev->v4l2_dev = v4l2_dev; in fimc_isp_video_device_register()
616 vdev->minor = -1; in fimc_isp_video_device_register()
617 vdev->release = video_device_release_empty; in fimc_isp_video_device_register()
618 vdev->lock = &isp->video_lock; in fimc_isp_video_device_register()
619 vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE; in fimc_isp_video_device_register()
621 iv->pad.flags = MEDIA_PAD_FL_SINK; in fimc_isp_video_device_register()
622 ret = media_entity_pads_init(&vdev->entity, 1, &iv->pad); in fimc_isp_video_device_register()
628 ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); in fimc_isp_video_device_register()
630 media_entity_cleanup(&vdev->entity); in fimc_isp_video_device_register()
635 vdev->name, video_device_node_name(vdev)); in fimc_isp_video_device_register()
646 ve = &isp->video_capture.ve; in fimc_isp_video_device_unregister()
650 mutex_lock(&isp->video_lock); in fimc_isp_video_device_unregister()
652 if (video_is_registered(&ve->vdev)) { in fimc_isp_video_device_unregister()
653 video_unregister_device(&ve->vdev); in fimc_isp_video_device_unregister()
654 media_entity_cleanup(&ve->vdev.entity); in fimc_isp_video_device_unregister()
655 ve->pipe = NULL; in fimc_isp_video_device_unregister()
658 mutex_unlock(&isp->video_lock); in fimc_isp_video_device_unregister()