.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Support eMMa-PrP through mem2mem framework. |
---|
3 | 4 | * |
---|
.. | .. |
---|
10 | 11 | * |
---|
11 | 12 | * Copyright (c) 2011 Vista Silicon S.L. |
---|
12 | 13 | * Javier Martin <javier.martin@vista-silicon.com> |
---|
13 | | - * |
---|
14 | | - * This program is free software; you can redistribute it and/or modify |
---|
15 | | - * it under the terms of the GNU General Public License as published by the |
---|
16 | | - * Free Software Foundation; either version 2 of the |
---|
17 | | - * License, or (at your option) any later version |
---|
18 | 14 | */ |
---|
19 | 15 | #include <linux/module.h> |
---|
20 | 16 | #include <linux/clk.h> |
---|
.. | .. |
---|
124 | 120 | #define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27) |
---|
125 | 121 | #define PRP_CNTL_CH2B1EN (1 << 29) |
---|
126 | 122 | #define PRP_CNTL_CH2B2EN (1 << 30) |
---|
127 | | -#define PRP_CNTL_CH2FEN (1 << 31) |
---|
| 123 | +#define PRP_CNTL_CH2FEN (1UL << 31) |
---|
128 | 124 | |
---|
129 | 125 | #define PRP_SIZE_HEIGHT(x) (x) |
---|
130 | 126 | #define PRP_SIZE_WIDTH(x) ((x) << 16) |
---|
.. | .. |
---|
149 | 145 | #define PRP_INTR_ST_CH2OVF (1 << 8) |
---|
150 | 146 | |
---|
151 | 147 | struct emmaprp_fmt { |
---|
152 | | - char *name; |
---|
153 | 148 | u32 fourcc; |
---|
154 | 149 | /* Types the format can be used for */ |
---|
155 | 150 | u32 types; |
---|
.. | .. |
---|
157 | 152 | |
---|
158 | 153 | static struct emmaprp_fmt formats[] = { |
---|
159 | 154 | { |
---|
160 | | - .name = "YUV 4:2:0 Planar", |
---|
161 | 155 | .fourcc = V4L2_PIX_FMT_YUV420, |
---|
162 | 156 | .types = MEM2MEM_CAPTURE, |
---|
163 | 157 | }, |
---|
164 | 158 | { |
---|
165 | | - .name = "4:2:2, packed, YUYV", |
---|
166 | 159 | .fourcc = V4L2_PIX_FMT_YUYV, |
---|
167 | 160 | .types = MEM2MEM_OUTPUT, |
---|
168 | 161 | }, |
---|
.. | .. |
---|
214 | 207 | }; |
---|
215 | 208 | |
---|
216 | 209 | struct emmaprp_ctx { |
---|
| 210 | + struct v4l2_fh fh; |
---|
217 | 211 | struct emmaprp_dev *dev; |
---|
218 | 212 | /* Abort requested by m2m */ |
---|
219 | 213 | int aborting; |
---|
220 | 214 | struct emmaprp_q_data q_data[2]; |
---|
221 | | - struct v4l2_m2m_ctx *m2m_ctx; |
---|
222 | 215 | }; |
---|
223 | 216 | |
---|
224 | 217 | static struct emmaprp_q_data *get_q_data(struct emmaprp_ctx *ctx, |
---|
.. | .. |
---|
247 | 240 | |
---|
248 | 241 | dprintk(pcdev, "Aborting task\n"); |
---|
249 | 242 | |
---|
250 | | - v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx); |
---|
| 243 | + v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->fh.m2m_ctx); |
---|
251 | 244 | } |
---|
252 | 245 | |
---|
253 | 246 | static inline void emmaprp_dump_regs(struct emmaprp_dev *pcdev) |
---|
.. | .. |
---|
282 | 275 | dma_addr_t p_in, p_out; |
---|
283 | 276 | u32 tmp; |
---|
284 | 277 | |
---|
285 | | - src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); |
---|
286 | | - dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); |
---|
| 278 | + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); |
---|
| 279 | + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); |
---|
287 | 280 | |
---|
288 | 281 | s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); |
---|
289 | 282 | s_width = s_q_data->width; |
---|
.. | .. |
---|
357 | 350 | pr_err("PrP bus error occurred, this transfer is probably corrupted\n"); |
---|
358 | 351 | writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL); |
---|
359 | 352 | } else if (irqst & PRP_INTR_ST_CH2B1CI) { /* buffer ready */ |
---|
360 | | - src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx); |
---|
361 | | - dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx); |
---|
| 353 | + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); |
---|
| 354 | + dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); |
---|
362 | 355 | |
---|
363 | 356 | dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp; |
---|
364 | 357 | dst_vb->flags &= |
---|
.. | .. |
---|
375 | 368 | } |
---|
376 | 369 | } |
---|
377 | 370 | |
---|
378 | | - v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx); |
---|
| 371 | + v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->fh.m2m_ctx); |
---|
379 | 372 | return IRQ_HANDLED; |
---|
380 | 373 | } |
---|
381 | 374 | |
---|
.. | .. |
---|
385 | 378 | static int vidioc_querycap(struct file *file, void *priv, |
---|
386 | 379 | struct v4l2_capability *cap) |
---|
387 | 380 | { |
---|
388 | | - strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); |
---|
389 | | - strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); |
---|
390 | | - cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; |
---|
391 | | - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; |
---|
| 381 | + strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); |
---|
| 382 | + strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); |
---|
392 | 383 | return 0; |
---|
393 | 384 | } |
---|
394 | 385 | |
---|
.. | .. |
---|
413 | 404 | if (i < NUM_FORMATS) { |
---|
414 | 405 | /* Format found */ |
---|
415 | 406 | fmt = &formats[i]; |
---|
416 | | - strlcpy(f->description, fmt->name, sizeof(f->description) - 1); |
---|
417 | 407 | f->pixelformat = fmt->fourcc; |
---|
418 | 408 | return 0; |
---|
419 | 409 | } |
---|
.. | .. |
---|
439 | 429 | struct vb2_queue *vq; |
---|
440 | 430 | struct emmaprp_q_data *q_data; |
---|
441 | 431 | |
---|
442 | | - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); |
---|
| 432 | + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
---|
443 | 433 | if (!vq) |
---|
444 | 434 | return -EINVAL; |
---|
445 | 435 | |
---|
.. | .. |
---|
544 | 534 | struct vb2_queue *vq; |
---|
545 | 535 | int ret; |
---|
546 | 536 | |
---|
547 | | - vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); |
---|
| 537 | + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); |
---|
548 | 538 | if (!vq) |
---|
549 | 539 | return -EINVAL; |
---|
550 | 540 | |
---|
.. | .. |
---|
600 | 590 | return vidioc_s_fmt(priv, f); |
---|
601 | 591 | } |
---|
602 | 592 | |
---|
603 | | -static int vidioc_reqbufs(struct file *file, void *priv, |
---|
604 | | - struct v4l2_requestbuffers *reqbufs) |
---|
605 | | -{ |
---|
606 | | - struct emmaprp_ctx *ctx = priv; |
---|
607 | | - |
---|
608 | | - return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); |
---|
609 | | -} |
---|
610 | | - |
---|
611 | | -static int vidioc_querybuf(struct file *file, void *priv, |
---|
612 | | - struct v4l2_buffer *buf) |
---|
613 | | -{ |
---|
614 | | - struct emmaprp_ctx *ctx = priv; |
---|
615 | | - |
---|
616 | | - return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf); |
---|
617 | | -} |
---|
618 | | - |
---|
619 | | -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) |
---|
620 | | -{ |
---|
621 | | - struct emmaprp_ctx *ctx = priv; |
---|
622 | | - |
---|
623 | | - return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); |
---|
624 | | -} |
---|
625 | | - |
---|
626 | | -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) |
---|
627 | | -{ |
---|
628 | | - struct emmaprp_ctx *ctx = priv; |
---|
629 | | - |
---|
630 | | - return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); |
---|
631 | | -} |
---|
632 | | - |
---|
633 | | -static int vidioc_streamon(struct file *file, void *priv, |
---|
634 | | - enum v4l2_buf_type type) |
---|
635 | | -{ |
---|
636 | | - struct emmaprp_ctx *ctx = priv; |
---|
637 | | - |
---|
638 | | - return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); |
---|
639 | | -} |
---|
640 | | - |
---|
641 | | -static int vidioc_streamoff(struct file *file, void *priv, |
---|
642 | | - enum v4l2_buf_type type) |
---|
643 | | -{ |
---|
644 | | - struct emmaprp_ctx *ctx = priv; |
---|
645 | | - |
---|
646 | | - return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type); |
---|
647 | | -} |
---|
648 | | - |
---|
649 | 593 | static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = { |
---|
650 | 594 | .vidioc_querycap = vidioc_querycap, |
---|
651 | 595 | |
---|
.. | .. |
---|
659 | 603 | .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, |
---|
660 | 604 | .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, |
---|
661 | 605 | |
---|
662 | | - .vidioc_reqbufs = vidioc_reqbufs, |
---|
663 | | - .vidioc_querybuf = vidioc_querybuf, |
---|
664 | | - |
---|
665 | | - .vidioc_qbuf = vidioc_qbuf, |
---|
666 | | - .vidioc_dqbuf = vidioc_dqbuf, |
---|
667 | | - |
---|
668 | | - .vidioc_streamon = vidioc_streamon, |
---|
669 | | - .vidioc_streamoff = vidioc_streamoff, |
---|
| 606 | + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, |
---|
| 607 | + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, |
---|
| 608 | + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, |
---|
| 609 | + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, |
---|
| 610 | + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, |
---|
| 611 | + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, |
---|
| 612 | + .vidioc_streamon = v4l2_m2m_ioctl_streamon, |
---|
| 613 | + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, |
---|
670 | 614 | }; |
---|
671 | 615 | |
---|
672 | 616 | |
---|
.. | .. |
---|
726 | 670 | { |
---|
727 | 671 | struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); |
---|
728 | 672 | struct emmaprp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); |
---|
729 | | - v4l2_m2m_buf_queue(ctx->m2m_ctx, vbuf); |
---|
| 673 | + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); |
---|
730 | 674 | } |
---|
731 | 675 | |
---|
732 | 676 | static const struct vb2_ops emmaprp_qops = { |
---|
.. | .. |
---|
744 | 688 | int ret; |
---|
745 | 689 | |
---|
746 | 690 | src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; |
---|
747 | | - src_vq->io_modes = VB2_MMAP | VB2_USERPTR; |
---|
| 691 | + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; |
---|
748 | 692 | src_vq->drv_priv = ctx; |
---|
749 | 693 | src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
---|
750 | 694 | src_vq->ops = &emmaprp_qops; |
---|
.. | .. |
---|
758 | 702 | return ret; |
---|
759 | 703 | |
---|
760 | 704 | dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
---|
761 | | - dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; |
---|
| 705 | + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; |
---|
762 | 706 | dst_vq->drv_priv = ctx; |
---|
763 | 707 | dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); |
---|
764 | 708 | dst_vq->ops = &emmaprp_qops; |
---|
.. | .. |
---|
782 | 726 | if (!ctx) |
---|
783 | 727 | return -ENOMEM; |
---|
784 | 728 | |
---|
785 | | - file->private_data = ctx; |
---|
| 729 | + v4l2_fh_init(&ctx->fh, video_devdata(file)); |
---|
| 730 | + file->private_data = &ctx->fh; |
---|
786 | 731 | ctx->dev = pcdev; |
---|
787 | 732 | |
---|
788 | 733 | if (mutex_lock_interruptible(&pcdev->dev_mutex)) { |
---|
.. | .. |
---|
790 | 735 | return -ERESTARTSYS; |
---|
791 | 736 | } |
---|
792 | 737 | |
---|
793 | | - ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); |
---|
| 738 | + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init); |
---|
794 | 739 | |
---|
795 | | - if (IS_ERR(ctx->m2m_ctx)) { |
---|
796 | | - int ret = PTR_ERR(ctx->m2m_ctx); |
---|
| 740 | + if (IS_ERR(ctx->fh.m2m_ctx)) { |
---|
| 741 | + int ret = PTR_ERR(ctx->fh.m2m_ctx); |
---|
797 | 742 | |
---|
798 | 743 | mutex_unlock(&pcdev->dev_mutex); |
---|
799 | 744 | kfree(ctx); |
---|
.. | .. |
---|
804 | 749 | clk_prepare_enable(pcdev->clk_emma_ahb); |
---|
805 | 750 | ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1]; |
---|
806 | 751 | ctx->q_data[V4L2_M2M_DST].fmt = &formats[0]; |
---|
| 752 | + v4l2_fh_add(&ctx->fh); |
---|
807 | 753 | mutex_unlock(&pcdev->dev_mutex); |
---|
808 | 754 | |
---|
809 | | - dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx); |
---|
| 755 | + dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->fh.m2m_ctx); |
---|
810 | 756 | |
---|
811 | 757 | return 0; |
---|
812 | 758 | } |
---|
.. | .. |
---|
821 | 767 | mutex_lock(&pcdev->dev_mutex); |
---|
822 | 768 | clk_disable_unprepare(pcdev->clk_emma_ahb); |
---|
823 | 769 | clk_disable_unprepare(pcdev->clk_emma_ipg); |
---|
824 | | - v4l2_m2m_ctx_release(ctx->m2m_ctx); |
---|
| 770 | + v4l2_fh_del(&ctx->fh); |
---|
| 771 | + v4l2_fh_exit(&ctx->fh); |
---|
| 772 | + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); |
---|
825 | 773 | mutex_unlock(&pcdev->dev_mutex); |
---|
826 | 774 | kfree(ctx); |
---|
827 | 775 | |
---|
828 | 776 | return 0; |
---|
829 | 777 | } |
---|
830 | 778 | |
---|
831 | | -static __poll_t emmaprp_poll(struct file *file, |
---|
832 | | - struct poll_table_struct *wait) |
---|
833 | | -{ |
---|
834 | | - struct emmaprp_dev *pcdev = video_drvdata(file); |
---|
835 | | - struct emmaprp_ctx *ctx = file->private_data; |
---|
836 | | - __poll_t res; |
---|
837 | | - |
---|
838 | | - mutex_lock(&pcdev->dev_mutex); |
---|
839 | | - res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait); |
---|
840 | | - mutex_unlock(&pcdev->dev_mutex); |
---|
841 | | - return res; |
---|
842 | | -} |
---|
843 | | - |
---|
844 | | -static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma) |
---|
845 | | -{ |
---|
846 | | - struct emmaprp_dev *pcdev = video_drvdata(file); |
---|
847 | | - struct emmaprp_ctx *ctx = file->private_data; |
---|
848 | | - int ret; |
---|
849 | | - |
---|
850 | | - if (mutex_lock_interruptible(&pcdev->dev_mutex)) |
---|
851 | | - return -ERESTARTSYS; |
---|
852 | | - ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma); |
---|
853 | | - mutex_unlock(&pcdev->dev_mutex); |
---|
854 | | - return ret; |
---|
855 | | -} |
---|
856 | | - |
---|
857 | 779 | static const struct v4l2_file_operations emmaprp_fops = { |
---|
858 | 780 | .owner = THIS_MODULE, |
---|
859 | 781 | .open = emmaprp_open, |
---|
860 | 782 | .release = emmaprp_release, |
---|
861 | | - .poll = emmaprp_poll, |
---|
| 783 | + .poll = v4l2_m2m_fop_poll, |
---|
862 | 784 | .unlocked_ioctl = video_ioctl2, |
---|
863 | | - .mmap = emmaprp_mmap, |
---|
| 785 | + .mmap = v4l2_m2m_fop_mmap, |
---|
864 | 786 | }; |
---|
865 | 787 | |
---|
866 | 788 | static const struct video_device emmaprp_videodev = { |
---|
.. | .. |
---|
870 | 792 | .minor = -1, |
---|
871 | 793 | .release = video_device_release, |
---|
872 | 794 | .vfl_dir = VFL_DIR_M2M, |
---|
| 795 | + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, |
---|
873 | 796 | }; |
---|
874 | 797 | |
---|
875 | 798 | static const struct v4l2_m2m_ops m2m_ops = { |
---|
.. | .. |
---|
946 | 869 | goto rel_vdev; |
---|
947 | 870 | } |
---|
948 | 871 | |
---|
949 | | - ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); |
---|
| 872 | + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); |
---|
950 | 873 | if (ret) { |
---|
951 | 874 | v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n"); |
---|
952 | 875 | goto rel_m2m; |
---|