Lines Matching +full:fimc +full:- +full:is

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Samsung S5P/EXYNOS4 SoC series FIMC (video postprocessor) driver
5 * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
22 #include <media/v4l2-ioctl.h>
23 #include <media/videobuf2-v4l2.h>
24 #include <media/videobuf2-dma-contig.h>
27 #include "fimc-core.h"
28 #include "fimc-reg.h"
29 #include "media-dev.h"
43 if (!ctx || !ctx->fh.m2m_ctx) in fimc_m2m_job_finish()
46 src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); in fimc_m2m_job_finish()
47 dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); in fimc_m2m_job_finish()
54 v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev, in fimc_m2m_job_finish()
55 ctx->fh.m2m_ctx); in fimc_m2m_job_finish()
61 struct fimc_dev *fimc = ctx->fimc_dev; in fimc_m2m_shutdown() local
63 if (!fimc_m2m_pending(fimc)) in fimc_m2m_shutdown()
68 wait_event_timeout(fimc->irq_queue, in fimc_m2m_shutdown()
75 struct fimc_ctx *ctx = q->drv_priv; in start_streaming()
77 return pm_runtime_resume_and_get(&ctx->fimc_dev->pdev->dev); in start_streaming()
82 struct fimc_ctx *ctx = q->drv_priv; in stop_streaming()
86 pm_runtime_put(&ctx->fimc_dev->pdev->dev); in stop_streaming()
94 struct fimc_dev *fimc; in fimc_device_run() local
101 fimc = ctx->fimc_dev; in fimc_device_run()
102 spin_lock_irqsave(&fimc->slock, flags); in fimc_device_run()
104 set_bit(ST_M2M_PEND, &fimc->state); in fimc_device_run()
105 sf = &ctx->s_frame; in fimc_device_run()
106 df = &ctx->d_frame; in fimc_device_run()
108 if (ctx->state & FIMC_PARAMS) { in fimc_device_run()
114 src_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); in fimc_device_run()
115 ret = fimc_prepare_addr(ctx, &src_vb->vb2_buf, sf, &sf->addr); in fimc_device_run()
119 dst_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); in fimc_device_run()
120 ret = fimc_prepare_addr(ctx, &dst_vb->vb2_buf, df, &df->addr); in fimc_device_run()
124 dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; in fimc_device_run()
125 dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; in fimc_device_run()
126 dst_vb->flags |= in fimc_device_run()
127 src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; in fimc_device_run()
130 if (fimc->m2m.ctx != ctx) { in fimc_device_run()
131 ctx->state |= FIMC_PARAMS; in fimc_device_run()
132 fimc->m2m.ctx = ctx; in fimc_device_run()
135 if (ctx->state & FIMC_PARAMS) { in fimc_device_run()
148 if (fimc->drv_data->alpha_color) in fimc_device_run()
152 fimc_hw_set_input_addr(fimc, &sf->addr); in fimc_device_run()
153 fimc_hw_set_output_addr(fimc, &df->addr, -1); in fimc_device_run()
156 ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP); in fimc_device_run()
157 fimc_hw_activate_input_dma(fimc, true); in fimc_device_run()
160 spin_unlock_irqrestore(&fimc->slock, flags); in fimc_device_run()
176 f = ctx_get_frame(ctx, vq->type); in fimc_queue_setup()
180 * Return number of non-contiguous planes (plane buffers) in fimc_queue_setup()
183 if (!f->fmt) in fimc_queue_setup()
184 return -EINVAL; in fimc_queue_setup()
186 *num_planes = f->fmt->memplanes; in fimc_queue_setup()
187 for (i = 0; i < f->fmt->memplanes; i++) in fimc_queue_setup()
188 sizes[i] = f->payload[i]; in fimc_queue_setup()
194 struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); in fimc_buf_prepare()
198 frame = ctx_get_frame(ctx, vb->vb2_queue->type); in fimc_buf_prepare()
202 for (i = 0; i < frame->fmt->memplanes; i++) in fimc_buf_prepare()
203 vb2_set_plane_payload(vb, i, frame->payload[i]); in fimc_buf_prepare()
211 struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); in fimc_buf_queue()
212 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); in fimc_buf_queue()
231 struct fimc_dev *fimc = video_drvdata(file); in fimc_m2m_querycap() local
233 __fimc_vidioc_querycap(&fimc->pdev->dev, cap); in fimc_m2m_querycap()
242 fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type), in fimc_m2m_enum_fmt()
243 f->index); in fimc_m2m_enum_fmt()
245 return -EINVAL; in fimc_m2m_enum_fmt()
247 f->pixelformat = fmt->fourcc; in fimc_m2m_enum_fmt()
255 const struct fimc_frame *frame = ctx_get_frame(ctx, f->type); in fimc_m2m_g_fmt_mplane()
266 struct fimc_dev *fimc = ctx->fimc_dev; in fimc_try_fmt_mplane() local
267 const struct fimc_variant *variant = fimc->variant; in fimc_try_fmt_mplane()
268 struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; in fimc_try_fmt_mplane()
272 if (!IS_M2M(f->type)) in fimc_try_fmt_mplane()
273 return -EINVAL; in fimc_try_fmt_mplane()
275 fmt = fimc_find_format(&pix->pixelformat, NULL, in fimc_try_fmt_mplane()
276 get_m2m_fmt_flags(f->type), 0); in fimc_try_fmt_mplane()
278 return -EINVAL; in fimc_try_fmt_mplane()
280 if (pix->field == V4L2_FIELD_ANY) in fimc_try_fmt_mplane()
281 pix->field = V4L2_FIELD_NONE; in fimc_try_fmt_mplane()
282 else if (pix->field != V4L2_FIELD_NONE) in fimc_try_fmt_mplane()
283 return -EINVAL; in fimc_try_fmt_mplane()
285 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { in fimc_try_fmt_mplane()
286 max_w = variant->pix_limit->scaler_dis_w; in fimc_try_fmt_mplane()
287 mod_x = ffs(variant->min_inp_pixsize) - 1; in fimc_try_fmt_mplane()
289 max_w = variant->pix_limit->out_rot_dis_w; in fimc_try_fmt_mplane()
290 mod_x = ffs(variant->min_out_pixsize) - 1; in fimc_try_fmt_mplane()
297 if (variant->min_vsize_align == 1) in fimc_try_fmt_mplane()
298 mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1; in fimc_try_fmt_mplane()
300 mod_y = ffs(variant->min_vsize_align) - 1; in fimc_try_fmt_mplane()
303 v4l_bound_align_image(&pix->width, 16, max_w, mod_x, in fimc_try_fmt_mplane()
304 &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); in fimc_try_fmt_mplane()
306 fimc_adjust_mplane_format(fmt, pix->width, pix->height, &f->fmt.pix_mp); in fimc_try_fmt_mplane()
323 for (i = 0; i < fmt->memplanes; i++) { in __set_frame_format()
324 frame->bytesperline[i] = pixm->plane_fmt[i].bytesperline; in __set_frame_format()
325 frame->payload[i] = pixm->plane_fmt[i].sizeimage; in __set_frame_format()
328 frame->f_width = pixm->width; in __set_frame_format()
329 frame->f_height = pixm->height; in __set_frame_format()
330 frame->o_width = pixm->width; in __set_frame_format()
331 frame->o_height = pixm->height; in __set_frame_format()
332 frame->width = pixm->width; in __set_frame_format()
333 frame->height = pixm->height; in __set_frame_format()
334 frame->offs_h = 0; in __set_frame_format()
335 frame->offs_v = 0; in __set_frame_format()
336 frame->fmt = fmt; in __set_frame_format()
343 struct fimc_dev *fimc = ctx->fimc_dev; in fimc_m2m_s_fmt_mplane() local
353 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); in fimc_m2m_s_fmt_mplane()
356 v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type); in fimc_m2m_s_fmt_mplane()
357 return -EBUSY; in fimc_m2m_s_fmt_mplane()
360 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) in fimc_m2m_s_fmt_mplane()
361 frame = &ctx->s_frame; in fimc_m2m_s_fmt_mplane()
363 frame = &ctx->d_frame; in fimc_m2m_s_fmt_mplane()
365 fmt = fimc_find_format(&f->fmt.pix_mp.pixelformat, NULL, in fimc_m2m_s_fmt_mplane()
366 get_m2m_fmt_flags(f->type), 0); in fimc_m2m_s_fmt_mplane()
368 return -EINVAL; in fimc_m2m_s_fmt_mplane()
370 __set_frame_format(frame, fmt, &f->fmt.pix_mp); in fimc_m2m_s_fmt_mplane()
384 frame = ctx_get_frame(ctx, s->type); in fimc_m2m_g_selection()
388 switch (s->target) { in fimc_m2m_g_selection()
392 if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) in fimc_m2m_g_selection()
393 return -EINVAL; in fimc_m2m_g_selection()
398 if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) in fimc_m2m_g_selection()
399 return -EINVAL; in fimc_m2m_g_selection()
402 return -EINVAL; in fimc_m2m_g_selection()
405 switch (s->target) { in fimc_m2m_g_selection()
408 s->r.left = frame->offs_h; in fimc_m2m_g_selection()
409 s->r.top = frame->offs_v; in fimc_m2m_g_selection()
410 s->r.width = frame->width; in fimc_m2m_g_selection()
411 s->r.height = frame->height; in fimc_m2m_g_selection()
417 s->r.left = 0; in fimc_m2m_g_selection()
418 s->r.top = 0; in fimc_m2m_g_selection()
419 s->r.width = frame->o_width; in fimc_m2m_g_selection()
420 s->r.height = frame->o_height; in fimc_m2m_g_selection()
423 return -EINVAL; in fimc_m2m_g_selection()
431 struct fimc_dev *fimc = ctx->fimc_dev; in fimc_m2m_try_selection() local
436 if (s->r.top < 0 || s->r.left < 0) { in fimc_m2m_try_selection()
437 v4l2_err(&fimc->m2m.vfd, in fimc_m2m_try_selection()
439 return -EINVAL; in fimc_m2m_try_selection()
441 if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { in fimc_m2m_try_selection()
442 f = &ctx->d_frame; in fimc_m2m_try_selection()
443 if (s->target != V4L2_SEL_TGT_COMPOSE) in fimc_m2m_try_selection()
444 return -EINVAL; in fimc_m2m_try_selection()
445 } else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { in fimc_m2m_try_selection()
446 f = &ctx->s_frame; in fimc_m2m_try_selection()
447 if (s->target != V4L2_SEL_TGT_CROP) in fimc_m2m_try_selection()
448 return -EINVAL; in fimc_m2m_try_selection()
450 return -EINVAL; in fimc_m2m_try_selection()
453 min_size = (f == &ctx->s_frame) ? in fimc_m2m_try_selection()
454 fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; in fimc_m2m_try_selection()
457 if (fimc->variant->min_vsize_align == 1) in fimc_m2m_try_selection()
458 halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; in fimc_m2m_try_selection()
460 halign = ffs(fimc->variant->min_vsize_align) - 1; in fimc_m2m_try_selection()
462 for (i = 0; i < f->fmt->memplanes; i++) in fimc_m2m_try_selection()
463 depth += f->fmt->depth[i]; in fimc_m2m_try_selection()
465 v4l_bound_align_image(&s->r.width, min_size, f->o_width, in fimc_m2m_try_selection()
466 ffs(min_size) - 1, in fimc_m2m_try_selection()
467 &s->r.height, min_size, f->o_height, in fimc_m2m_try_selection()
470 /* adjust left/top if cropping rectangle is out of bounds */ in fimc_m2m_try_selection()
471 if (s->r.left + s->r.width > f->o_width) in fimc_m2m_try_selection()
472 s->r.left = f->o_width - s->r.width; in fimc_m2m_try_selection()
473 if (s->r.top + s->r.height > f->o_height) in fimc_m2m_try_selection()
474 s->r.top = f->o_height - s->r.height; in fimc_m2m_try_selection()
476 s->r.left = round_down(s->r.left, min_size); in fimc_m2m_try_selection()
477 s->r.top = round_down(s->r.top, fimc->variant->hor_offs_align); in fimc_m2m_try_selection()
480 s->r.left, s->r.top, s->r.width, s->r.height, in fimc_m2m_try_selection()
481 f->f_width, f->f_height); in fimc_m2m_try_selection()
490 struct fimc_dev *fimc = ctx->fimc_dev; in fimc_m2m_s_selection() local
498 f = (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ? in fimc_m2m_s_selection()
499 &ctx->s_frame : &ctx->d_frame; in fimc_m2m_s_selection()
501 /* Check to see if scaling ratio is within supported range */ in fimc_m2m_s_selection()
502 if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { in fimc_m2m_s_selection()
503 ret = fimc_check_scaler_ratio(ctx, s->r.width, in fimc_m2m_s_selection()
504 s->r.height, ctx->d_frame.width, in fimc_m2m_s_selection()
505 ctx->d_frame.height, ctx->rotation); in fimc_m2m_s_selection()
507 ret = fimc_check_scaler_ratio(ctx, ctx->s_frame.width, in fimc_m2m_s_selection()
508 ctx->s_frame.height, s->r.width, in fimc_m2m_s_selection()
509 s->r.height, ctx->rotation); in fimc_m2m_s_selection()
512 v4l2_err(&fimc->m2m.vfd, "Out of scaler range\n"); in fimc_m2m_s_selection()
513 return -EINVAL; in fimc_m2m_s_selection()
516 f->offs_h = s->r.left; in fimc_m2m_s_selection()
517 f->offs_v = s->r.top; in fimc_m2m_s_selection()
518 f->width = s->r.width; in fimc_m2m_s_selection()
519 f->height = s->r.height; in fimc_m2m_s_selection()
554 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; in queue_init()
555 src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; in queue_init()
556 src_vq->drv_priv = ctx; in queue_init()
557 src_vq->ops = &fimc_qops; in queue_init()
558 src_vq->mem_ops = &vb2_dma_contig_memops; in queue_init()
559 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); in queue_init()
560 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; in queue_init()
561 src_vq->lock = &ctx->fimc_dev->lock; in queue_init()
562 src_vq->dev = &ctx->fimc_dev->pdev->dev; in queue_init()
568 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; in queue_init()
569 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; in queue_init()
570 dst_vq->drv_priv = ctx; in queue_init()
571 dst_vq->ops = &fimc_qops; in queue_init()
572 dst_vq->mem_ops = &vb2_dma_contig_memops; in queue_init()
573 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); in queue_init()
574 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; in queue_init()
575 dst_vq->lock = &ctx->fimc_dev->lock; in queue_init()
576 dst_vq->dev = &ctx->fimc_dev->pdev->dev; in queue_init()
596 return -EINVAL; in fimc_m2m_set_default_format()
598 __set_frame_format(&ctx->s_frame, fmt, &pixm); in fimc_m2m_set_default_format()
599 __set_frame_format(&ctx->d_frame, fmt, &pixm); in fimc_m2m_set_default_format()
606 struct fimc_dev *fimc = video_drvdata(file); in fimc_m2m_open() local
608 int ret = -EBUSY; in fimc_m2m_open()
610 pr_debug("pid: %d, state: %#lx\n", task_pid_nr(current), fimc->state); in fimc_m2m_open()
612 if (mutex_lock_interruptible(&fimc->lock)) in fimc_m2m_open()
613 return -ERESTARTSYS; in fimc_m2m_open()
615 * Don't allow simultaneous open() of the mem-to-mem and the in fimc_m2m_open()
616 * capture video node that belong to same FIMC IP instance. in fimc_m2m_open()
618 if (test_bit(ST_CAPT_BUSY, &fimc->state)) in fimc_m2m_open()
623 ret = -ENOMEM; in fimc_m2m_open()
626 v4l2_fh_init(&ctx->fh, &fimc->m2m.vfd); in fimc_m2m_open()
627 ctx->fimc_dev = fimc; in fimc_m2m_open()
630 ctx->s_frame.fmt = fimc_get_format(0); in fimc_m2m_open()
631 ctx->d_frame.fmt = fimc_get_format(0); in fimc_m2m_open()
638 ctx->fh.ctrl_handler = &ctx->ctrls.handler; in fimc_m2m_open()
639 file->private_data = &ctx->fh; in fimc_m2m_open()
640 v4l2_fh_add(&ctx->fh); in fimc_m2m_open()
642 /* Setup the device context for memory-to-memory mode */ in fimc_m2m_open()
643 ctx->state = FIMC_CTX_M2M; in fimc_m2m_open()
644 ctx->flags = 0; in fimc_m2m_open()
645 ctx->in_path = FIMC_IO_DMA; in fimc_m2m_open()
646 ctx->out_path = FIMC_IO_DMA; in fimc_m2m_open()
647 ctx->scaler.enabled = 1; in fimc_m2m_open()
649 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init); in fimc_m2m_open()
650 if (IS_ERR(ctx->fh.m2m_ctx)) { in fimc_m2m_open()
651 ret = PTR_ERR(ctx->fh.m2m_ctx); in fimc_m2m_open()
655 if (fimc->m2m.refcnt++ == 0) in fimc_m2m_open()
656 set_bit(ST_M2M_RUN, &fimc->state); in fimc_m2m_open()
662 mutex_unlock(&fimc->lock); in fimc_m2m_open()
666 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); in fimc_m2m_open()
669 v4l2_fh_del(&ctx->fh); in fimc_m2m_open()
671 v4l2_fh_exit(&ctx->fh); in fimc_m2m_open()
674 mutex_unlock(&fimc->lock); in fimc_m2m_open()
680 struct fimc_ctx *ctx = fh_to_ctx(file->private_data); in fimc_m2m_release()
681 struct fimc_dev *fimc = ctx->fimc_dev; in fimc_m2m_release() local
684 task_pid_nr(current), fimc->state, fimc->m2m.refcnt); in fimc_m2m_release()
686 mutex_lock(&fimc->lock); in fimc_m2m_release()
688 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); in fimc_m2m_release()
690 v4l2_fh_del(&ctx->fh); in fimc_m2m_release()
691 v4l2_fh_exit(&ctx->fh); in fimc_m2m_release()
693 if (--fimc->m2m.refcnt <= 0) in fimc_m2m_release()
694 clear_bit(ST_M2M_RUN, &fimc->state); in fimc_m2m_release()
697 mutex_unlock(&fimc->lock); in fimc_m2m_release()
715 int fimc_register_m2m_device(struct fimc_dev *fimc, in fimc_register_m2m_device() argument
718 struct video_device *vfd = &fimc->m2m.vfd; in fimc_register_m2m_device()
721 fimc->v4l2_dev = v4l2_dev; in fimc_register_m2m_device()
724 vfd->fops = &fimc_m2m_fops; in fimc_register_m2m_device()
725 vfd->ioctl_ops = &fimc_m2m_ioctl_ops; in fimc_register_m2m_device()
726 vfd->v4l2_dev = v4l2_dev; in fimc_register_m2m_device()
727 vfd->minor = -1; in fimc_register_m2m_device()
728 vfd->release = video_device_release_empty; in fimc_register_m2m_device()
729 vfd->lock = &fimc->lock; in fimc_register_m2m_device()
730 vfd->vfl_dir = VFL_DIR_M2M; in fimc_register_m2m_device()
731 vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; in fimc_register_m2m_device()
732 set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags); in fimc_register_m2m_device()
734 snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id); in fimc_register_m2m_device()
735 video_set_drvdata(vfd, fimc); in fimc_register_m2m_device()
737 fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops); in fimc_register_m2m_device()
738 if (IS_ERR(fimc->m2m.m2m_dev)) { in fimc_register_m2m_device()
739 v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n"); in fimc_register_m2m_device()
740 return PTR_ERR(fimc->m2m.m2m_dev); in fimc_register_m2m_device()
743 ret = media_entity_pads_init(&vfd->entity, 0, NULL); in fimc_register_m2m_device()
747 ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1); in fimc_register_m2m_device()
752 vfd->name, video_device_node_name(vfd)); in fimc_register_m2m_device()
756 media_entity_cleanup(&vfd->entity); in fimc_register_m2m_device()
758 v4l2_m2m_release(fimc->m2m.m2m_dev); in fimc_register_m2m_device()
762 void fimc_unregister_m2m_device(struct fimc_dev *fimc) in fimc_unregister_m2m_device() argument
764 if (!fimc) in fimc_unregister_m2m_device()
767 if (fimc->m2m.m2m_dev) in fimc_unregister_m2m_device()
768 v4l2_m2m_release(fimc->m2m.m2m_dev); in fimc_unregister_m2m_device()
770 if (video_is_registered(&fimc->m2m.vfd)) { in fimc_unregister_m2m_device()
771 video_unregister_device(&fimc->m2m.vfd); in fimc_unregister_m2m_device()
772 media_entity_cleanup(&fimc->m2m.vfd.entity); in fimc_unregister_m2m_device()