1 //SPDX-License-Identifier: GPL-2.0
3 * Xilinx V4L2 mem2mem driver
5 * Copyright (C) 2017-2018 Xilinx, Inc.
7 * Author: Satish Kumar Nagireddy <satish.nagireddy.nagireddy@xilinx.com>
10 #include <drm/drm_fourcc.h>
11 #include <linux/dma/xilinx_frmbuf.h>
12 #include <linux/lcm.h>
13 #include <linux/list.h>
14 #include <linux/module.h>
16 #include <linux/of_graph.h>
17 #include <linux/platform_device.h>
18 #include <linux/slab.h>
20 #include <media/v4l2-async.h>
21 #include <media/v4l2-common.h>
22 #include <media/v4l2-device.h>
23 #include <media/v4l2-ioctl.h>
24 #include <media/v4l2-mem2mem.h>
25 #include <media/videobuf2-dma-contig.h>
27 #include "xilinx-vip.h"
29 #define XVIP_M2M_NAME "xilinx-mem2mem"
30 #define XVIP_M2M_DEFAULT_FMT V4L2_PIX_FMT_NV12
32 /* Minimum and maximum widths are expressed in bytes */
33 #define XVIP_M2M_MIN_WIDTH 1U
34 #define XVIP_M2M_MAX_WIDTH 65535U
35 #define XVIP_M2M_MIN_HEIGHT 1U
36 #define XVIP_M2M_MAX_HEIGHT 8191U
38 #define XVIP_M2M_DEF_WIDTH 1920
39 #define XVIP_M2M_DEF_HEIGHT 1080
42 * struct xvip_m2m_dev - Xilinx Video mem2mem device structure
43 * @v4l2_dev: V4L2 device
45 * @lock: This is to protect mem2mem context structure data
46 * @queued_lock: This is to protect video buffer information
47 * @dma: Video DMA channels
48 * @m2m_dev: V4L2 mem2mem device structure
49 * @v4l2_caps: V4L2 capabilities of the whole device
52 struct v4l2_device v4l2_dev;
55 /* Protects to m2m context data */
58 /* Protects vb2_v4l2_buffer data */
59 spinlock_t queued_lock;
60 struct xvip_m2m_dma *dma;
61 struct v4l2_m2m_dev *m2m_dev;
66 * struct xvip_m2m_dma - Video DMA channel
67 * @video: V4L2 video device associated with the DMA channel
68 * @xdev: composite mem2mem device the DMA channels belongs to
69 * @chan_tx: DMA engine channel for MEM2DEV transfer
70 * @chan_rx: DMA engine channel for DEV2MEM transfer
71 * @outfmt: active V4L2 OUTPUT port pixel format
72 * @capfmt: active V4L2 CAPTURE port pixel format
73 * @outinfo: format information corresponding to the active @outfmt
74 * @capinfo: format information corresponding to the active @capfmt
75 * @align: transfer alignment required by the DMA channel (in bytes)
78 struct video_device video;
79 struct xvip_m2m_dev *xdev;
80 struct dma_chan *chan_tx;
81 struct dma_chan *chan_rx;
82 struct v4l2_format outfmt;
83 struct v4l2_format capfmt;
84 const struct xvip_video_format *outinfo;
85 const struct xvip_video_format *capinfo;
90 * struct xvip_m2m_ctx - VIPP mem2mem context
91 * @fh: V4L2 file handler
92 * @xdev: composite mem2mem device the DMA channels belongs to
93 * @xt: dma interleaved template for dma configuration
94 * @sgl: data chunk structure for dma_interleaved_template
98 struct xvip_m2m_dev *xdev;
99 struct dma_interleaved_template xt;
100 struct data_chunk sgl[1];
103 static inline struct xvip_m2m_ctx *file2ctx(struct file *file)
105 return container_of(file->private_data, struct xvip_m2m_ctx, fh);
108 static void xvip_m2m_dma_callback_mem2dev(void *data)
112 static void xvip_m2m_dma_callback(void *data)
114 struct xvip_m2m_ctx *ctx = data;
115 struct xvip_m2m_dev *xdev = ctx->xdev;
116 struct vb2_v4l2_buffer *src_vb, *dst_vb;
118 spin_lock(&xdev->queued_lock);
119 src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
120 dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
122 dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
123 dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
125 src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
126 dst_vb->timecode = src_vb->timecode;
128 v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
129 v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
130 v4l2_m2m_job_finish(xdev->m2m_dev, ctx->fh.m2m_ctx);
131 spin_unlock(&xdev->queued_lock);
138 static int xvip_m2m_queue_setup(struct vb2_queue *vq,
139 u32 *nbuffers, u32 *nplanes,
140 u32 sizes[], struct device *alloc_devs[])
142 struct xvip_m2m_ctx *ctx = vb2_get_drv_priv(vq);
143 struct xvip_m2m_dma *dma = ctx->xdev->dma;
144 struct v4l2_format *f;
145 const struct xvip_video_format *info;
148 if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
157 if (*nplanes != f->fmt.pix_mp.num_planes)
160 for (i = 0; i < *nplanes; i++) {
161 if (sizes[i] < f->fmt.pix_mp.plane_fmt[i].sizeimage)
165 *nplanes = info->buffers;
166 for (i = 0; i < info->buffers; i++)
167 sizes[i] = f->fmt.pix_mp.plane_fmt[i].sizeimage;
173 static int xvip_m2m_buf_prepare(struct vb2_buffer *vb)
175 struct xvip_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
176 struct xvip_m2m_dma *dma = ctx->xdev->dma;
177 struct v4l2_format *f;
178 const struct xvip_video_format *info;
181 if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
189 for (i = 0; i < info->buffers; i++) {
190 if (vb2_plane_size(vb, i) <
191 f->fmt.pix_mp.plane_fmt[i].sizeimage) {
192 dev_err(ctx->xdev->dev,
193 "insufficient plane size (%u < %u)\n",
194 (u32)vb2_plane_size(vb, i),
195 f->fmt.pix_mp.plane_fmt[i].sizeimage);
199 vb2_set_plane_payload(vb, i,
200 f->fmt.pix_mp.plane_fmt[i].sizeimage);
206 static void xvip_m2m_buf_queue(struct vb2_buffer *vb)
208 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
209 struct xvip_m2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
211 v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
214 static int xvip_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
219 static void xvip_m2m_stop_streaming(struct vb2_queue *q)
221 struct xvip_m2m_ctx *ctx = vb2_get_drv_priv(q);
222 struct xvip_m2m_dma *dma = ctx->xdev->dma;
223 struct vb2_v4l2_buffer *vbuf;
225 if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
226 dmaengine_terminate_sync(dma->chan_tx);
228 dmaengine_terminate_sync(dma->chan_rx);
231 if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
232 vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
234 vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
238 spin_lock(&ctx->xdev->queued_lock);
239 v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
240 spin_unlock(&ctx->xdev->queued_lock);
244 static const struct vb2_ops m2m_vb2_ops = {
245 .queue_setup = xvip_m2m_queue_setup,
246 .buf_prepare = xvip_m2m_buf_prepare,
247 .buf_queue = xvip_m2m_buf_queue,
248 .start_streaming = xvip_m2m_start_streaming,
249 .stop_streaming = xvip_m2m_stop_streaming,
250 .wait_prepare = vb2_ops_wait_prepare,
251 .wait_finish = vb2_ops_wait_finish,
254 static int xvip_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
255 struct vb2_queue *dst_vq)
257 struct xvip_m2m_ctx *ctx = priv;
260 src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
261 src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
262 src_vq->drv_priv = ctx;
263 src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
264 src_vq->ops = &m2m_vb2_ops;
265 src_vq->mem_ops = &vb2_dma_contig_memops;
266 src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
267 src_vq->dev = ctx->xdev->v4l2_dev.dev;
269 ret = vb2_queue_init(src_vq);
273 dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
274 dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
275 dst_vq->drv_priv = ctx;
276 dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
277 dst_vq->ops = &m2m_vb2_ops;
278 dst_vq->mem_ops = &vb2_dma_contig_memops;
279 dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
280 dst_vq->dev = ctx->xdev->v4l2_dev.dev;
282 return vb2_queue_init(dst_vq);
285 /* -----------------------------------------------------------------------------
290 xvip_dma_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
292 cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
293 cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
295 strlcpy(cap->driver, XVIP_M2M_NAME, sizeof(cap->driver));
296 strlcpy(cap->card, XVIP_M2M_NAME, sizeof(cap->card));
297 strlcpy(cap->bus_info, XVIP_M2M_NAME, sizeof(cap->card));
303 xvip_m2m_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
305 struct xvip_m2m_ctx *ctx = file2ctx(file);
306 struct xvip_m2m_dma *dma = ctx->xdev->dma;
307 struct v4l2_format format = dma->capfmt;
308 const struct xvip_video_format *fmtinfo;
310 /* This logic will just return one pix format */
314 fmtinfo = xvip_get_format_by_fourcc(format.fmt.pix_mp.pixelformat);
315 f->pixelformat = fmtinfo->fourcc;
316 strlcpy(f->description, fmtinfo->description, sizeof(f->description));
321 static int xvip_m2m_get_fmt(struct file *file, void *fh, struct v4l2_format *f)
323 struct xvip_m2m_ctx *ctx = file2ctx(file);
324 struct xvip_m2m_dma *dma = ctx->xdev->dma;
325 struct vb2_queue *vq;
327 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
331 if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
332 f->fmt.pix_mp = dma->outfmt.fmt.pix_mp;
334 f->fmt.pix_mp = dma->capfmt.fmt.pix_mp;
339 static int __xvip_m2m_try_fmt(struct xvip_m2m_ctx *ctx, struct v4l2_format *f)
341 struct xvip_m2m_dma *dma = ctx->xdev->dma;
342 const struct xvip_video_format *info;
343 struct v4l2_pix_format_mplane *pix_mp;
344 struct v4l2_plane_pix_format *plane_fmt;
345 u32 align, min_width, max_width;
346 u32 bpl, min_bpl, max_bpl;
347 u32 padding_factor_nume, padding_factor_deno;
348 u32 bpl_nume, bpl_deno;
349 u32 i, plane_width, plane_height;
351 if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
352 f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
355 pix_mp = &f->fmt.pix_mp;
356 plane_fmt = pix_mp->plane_fmt;
357 info = xvip_get_format_by_fourcc(f->fmt.pix_mp.pixelformat);
359 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
364 info = xvip_get_format_by_fourcc(XVIP_M2M_DEFAULT_FMT);
367 xvip_width_padding_factor(info->fourcc, &padding_factor_nume,
368 &padding_factor_deno);
369 xvip_bpl_scaling_factor(info->fourcc, &bpl_nume, &bpl_deno);
372 * V4L2 specification suggests the driver corrects the format struct
373 * if any of the dimensions is unsupported
375 align = lcm(dma->align, info->bpp >> 3);
376 min_width = roundup(XVIP_M2M_MIN_WIDTH, align);
377 max_width = rounddown(XVIP_M2M_MAX_WIDTH, align);
378 pix_mp->width = clamp(pix_mp->width, min_width, max_width);
379 pix_mp->height = clamp(pix_mp->height, XVIP_M2M_MIN_HEIGHT,
380 XVIP_M2M_MAX_HEIGHT);
383 * Clamp the requested bytes per line value. If the maximum
384 * bytes per line value is zero, the module doesn't support
385 * user configurable line sizes. Override the requested value
386 * with the minimum in that case.
388 max_bpl = rounddown(XVIP_M2M_MAX_WIDTH, align);
390 if (info->buffers == 1) {
391 /* Handling contiguous data with mplanes */
392 min_bpl = (pix_mp->width * info->bpl_factor *
393 padding_factor_nume * bpl_nume) /
394 (padding_factor_deno * bpl_deno);
395 min_bpl = roundup(min_bpl, align);
396 bpl = roundup(plane_fmt[0].bytesperline, align);
397 plane_fmt[0].bytesperline = clamp(bpl, min_bpl, max_bpl);
399 if (info->num_planes == 1) {
400 /* Single plane formats */
401 plane_fmt[0].sizeimage = plane_fmt[0].bytesperline *
404 /* Multi plane formats in contiguous buffer*/
405 plane_fmt[0].sizeimage =
406 DIV_ROUND_UP(plane_fmt[0].bytesperline *
411 /* Handling non-contiguous data with mplanes */
412 for (i = 0; i < info->num_planes; i++) {
413 plane_width = pix_mp->width / (i ? info->hsub : 1);
414 plane_height = pix_mp->height / (i ? info->vsub : 1);
415 min_bpl = (plane_width * info->bpl_factor *
416 padding_factor_nume * bpl_nume) /
417 (padding_factor_deno * bpl_deno);
418 min_bpl = roundup(min_bpl, align);
419 bpl = rounddown(plane_fmt[i].bytesperline, align);
420 plane_fmt[i].bytesperline = clamp(bpl, min_bpl,
422 plane_fmt[i].sizeimage = plane_fmt[i].bytesperline *
430 static int xvip_m2m_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
432 struct xvip_m2m_ctx *ctx = file2ctx(file);
435 ret = __xvip_m2m_try_fmt(ctx, f);
442 static int xvip_m2m_set_fmt(struct file *file, void *fh, struct v4l2_format *f)
444 struct xvip_m2m_ctx *ctx = file2ctx(file);
445 struct xvip_m2m_dma *dma = ctx->xdev->dma;
446 struct vb2_queue *vq;
449 vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
453 if (vb2_is_busy(vq)) {
454 v4l2_err(&ctx->xdev->v4l2_dev, "%s queue busy\n", __func__);
458 ret = __xvip_m2m_try_fmt(ctx, f);
462 if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
463 dma->outfmt.fmt.pix_mp = f->fmt.pix_mp;
465 dma->capfmt.fmt.pix_mp = f->fmt.pix_mp;
470 static const struct v4l2_ioctl_ops xvip_m2m_ioctl_ops = {
471 .vidioc_querycap = xvip_dma_querycap,
473 .vidioc_enum_fmt_vid_cap_mplane = xvip_m2m_enum_fmt,
474 .vidioc_g_fmt_vid_cap_mplane = xvip_m2m_get_fmt,
475 .vidioc_try_fmt_vid_cap_mplane = xvip_m2m_try_fmt,
476 .vidioc_s_fmt_vid_cap_mplane = xvip_m2m_set_fmt,
478 .vidioc_enum_fmt_vid_out_mplane = xvip_m2m_enum_fmt,
479 .vidioc_g_fmt_vid_out_mplane = xvip_m2m_get_fmt,
480 .vidioc_try_fmt_vid_out_mplane = xvip_m2m_try_fmt,
481 .vidioc_s_fmt_vid_out_mplane = xvip_m2m_set_fmt,
483 .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
484 .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
485 .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
486 .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
487 .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
488 .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
489 .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
491 .vidioc_streamon = v4l2_m2m_ioctl_streamon,
492 .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
498 static int xvip_m2m_open(struct file *file)
500 struct xvip_m2m_dev *xdev = video_drvdata(file);
501 struct xvip_m2m_ctx *ctx = NULL;
504 ctx = devm_kzalloc(xdev->dev, sizeof(*ctx), GFP_KERNEL);
508 v4l2_fh_init(&ctx->fh, video_devdata(file));
509 file->private_data = &ctx->fh;
512 ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(xdev->m2m_dev, ctx,
513 &xvip_m2m_queue_init);
514 if (IS_ERR(ctx->fh.m2m_ctx)) {
515 ret = PTR_ERR(ctx->fh.m2m_ctx);
516 v4l2_fh_exit(&ctx->fh);
520 v4l2_fh_add(&ctx->fh);
521 dev_info(xdev->dev, "Created instance %p, m2m_ctx: %p\n", ctx,
526 static int xvip_m2m_release(struct file *file)
528 struct xvip_m2m_ctx *ctx = file->private_data;
530 v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
534 static u32 xvip_m2m_poll(struct file *file,
535 struct poll_table_struct *wait)
537 struct xvip_m2m_ctx *ctx = file->private_data;
540 mutex_lock(&ctx->xdev->lock);
541 ret = v4l2_m2m_poll(file, ctx->fh.m2m_ctx, wait);
542 mutex_unlock(&ctx->xdev->lock);
547 static int xvip_m2m_mmap(struct file *file, struct vm_area_struct *vma)
549 struct xvip_m2m_ctx *ctx = file->private_data;
551 return v4l2_m2m_mmap(file, ctx->fh.m2m_ctx, vma);
558 static int xvip_m2m_job_ready(void *priv)
560 struct xvip_m2m_ctx *ctx = priv;
562 if ((v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) &&
563 (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) > 0))
569 static void xvip_m2m_job_abort(void *priv)
571 struct xvip_m2m_ctx *ctx = priv;
573 /* Will cancel the transaction in the next interrupt handler */
574 v4l2_m2m_job_finish(ctx->xdev->m2m_dev, ctx->fh.m2m_ctx);
577 static void xvip_m2m_prep_submit_dev2mem_desc(struct xvip_m2m_ctx *ctx,
578 struct vb2_v4l2_buffer *dst_buf)
580 struct xvip_m2m_dma *dma = ctx->xdev->dma;
581 struct xvip_m2m_dev *xdev = ctx->xdev;
582 struct dma_async_tx_descriptor *desc;
584 const struct xvip_video_format *info;
585 struct v4l2_pix_format_mplane *pix_mp;
586 u32 padding_factor_nume, padding_factor_deno;
587 u32 bpl_nume, bpl_deno;
589 u32 flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
591 p_out = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
595 "Acquiring kernel pointer to buffer failed\n");
599 ctx->xt.dir = DMA_DEV_TO_MEM;
600 ctx->xt.src_sgl = false;
601 ctx->xt.dst_sgl = true;
602 ctx->xt.dst_start = p_out;
604 pix_mp = &dma->capfmt.fmt.pix_mp;
606 xilinx_xdma_v4l2_config(dma->chan_rx, pix_mp->pixelformat);
607 xvip_width_padding_factor(pix_mp->pixelformat, &padding_factor_nume,
608 &padding_factor_deno);
609 xvip_bpl_scaling_factor(pix_mp->pixelformat, &bpl_nume, &bpl_deno);
611 ctx->xt.frame_size = info->num_planes;
612 ctx->sgl[0].size = (pix_mp->width * info->bpl_factor *
613 padding_factor_nume * bpl_nume) /
614 (padding_factor_deno * bpl_deno);
615 ctx->sgl[0].icg = pix_mp->plane_fmt[0].bytesperline - ctx->sgl[0].size;
616 ctx->xt.numf = pix_mp->height;
619 * dst_icg is the number of bytes to jump after last luma addr
620 * and before first chroma addr
622 ctx->sgl[0].src_icg = 0;
624 if (info->buffers == 1) {
625 /* Handling contiguous data with mplanes */
626 ctx->sgl[0].dst_icg = 0;
628 /* Handling non-contiguous data with mplanes */
629 if (info->buffers == 2) {
630 dma_addr_t chroma_cap =
631 vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1);
632 luma_size = pix_mp->plane_fmt[0].bytesperline *
634 if (chroma_cap > p_out)
635 ctx->sgl[0].dst_icg = chroma_cap - p_out -
640 desc = dmaengine_prep_interleaved_dma(dma->chan_rx, &ctx->xt, flags);
642 dev_err(xdev->dev, "Failed to prepare DMA rx transfer\n");
646 desc->callback = xvip_m2m_dma_callback;
647 desc->callback_param = ctx;
648 dmaengine_submit(desc);
649 dma_async_issue_pending(dma->chan_rx);
652 static void xvip_m2m_prep_submit_mem2dev_desc(struct xvip_m2m_ctx *ctx,
653 struct vb2_v4l2_buffer *src_buf)
655 struct xvip_m2m_dma *dma = ctx->xdev->dma;
656 struct xvip_m2m_dev *xdev = ctx->xdev;
657 struct dma_async_tx_descriptor *desc;
659 const struct xvip_video_format *info;
660 struct v4l2_pix_format_mplane *pix_mp;
661 u32 padding_factor_nume, padding_factor_deno;
662 u32 bpl_nume, bpl_deno;
664 u32 flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK;
666 p_in = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0);
670 "Acquiring kernel pointer to buffer failed\n");
674 ctx->xt.dir = DMA_MEM_TO_DEV;
675 ctx->xt.src_sgl = true;
676 ctx->xt.dst_sgl = false;
677 ctx->xt.src_start = p_in;
679 pix_mp = &dma->outfmt.fmt.pix_mp;
681 xilinx_xdma_v4l2_config(dma->chan_tx, pix_mp->pixelformat);
682 xvip_width_padding_factor(pix_mp->pixelformat, &padding_factor_nume,
683 &padding_factor_deno);
684 xvip_bpl_scaling_factor(pix_mp->pixelformat, &bpl_nume, &bpl_deno);
686 ctx->xt.frame_size = info->num_planes;
687 ctx->sgl[0].size = (pix_mp->width * info->bpl_factor *
688 padding_factor_nume * bpl_nume) /
689 (padding_factor_deno * bpl_deno);
690 ctx->sgl[0].icg = pix_mp->plane_fmt[0].bytesperline - ctx->sgl[0].size;
691 ctx->xt.numf = pix_mp->height;
694 * src_icg is the number of bytes to jump after last luma addr
695 * and before first chroma addr
697 ctx->sgl[0].dst_icg = 0;
699 if (info->buffers == 1) {
700 /* Handling contiguous data with mplanes */
701 ctx->sgl[0].src_icg = 0;
703 /* Handling non-contiguous data with mplanes */
704 if (info->buffers == 2) {
705 dma_addr_t chroma_out =
706 vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 1);
707 luma_size = pix_mp->plane_fmt[0].bytesperline *
709 if (chroma_out > p_in)
710 ctx->sgl[0].src_icg = chroma_out - p_in -
715 desc = dmaengine_prep_interleaved_dma(dma->chan_tx, &ctx->xt, flags);
717 dev_err(xdev->dev, "Failed to prepare DMA tx transfer\n");
721 desc->callback = xvip_m2m_dma_callback_mem2dev;
722 desc->callback_param = ctx;
723 dmaengine_submit(desc);
724 dma_async_issue_pending(dma->chan_tx);
728 * xvip_m2m_device_run - prepares and starts the device
730 * @priv: Instance private data
732 * This simulates all the immediate preparations required before starting
733 * a device. This will be called by the framework when it decides to schedule
734 * a particular instance.
736 static void xvip_m2m_device_run(void *priv)
738 struct xvip_m2m_ctx *ctx = priv;
739 struct vb2_v4l2_buffer *src_buf, *dst_buf;
741 src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
742 dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
744 /* Prepare and submit mem2dev transaction */
745 xvip_m2m_prep_submit_mem2dev_desc(ctx, src_buf);
747 /* Prepare and submit dev2mem transaction */
748 xvip_m2m_prep_submit_dev2mem_desc(ctx, dst_buf);
751 static const struct v4l2_file_operations xvip_m2m_fops = {
752 .owner = THIS_MODULE,
753 .open = xvip_m2m_open,
754 .release = xvip_m2m_release,
755 .poll = xvip_m2m_poll,
756 .unlocked_ioctl = video_ioctl2,
757 .mmap = xvip_m2m_mmap,
760 static struct video_device xvip_m2m_videodev = {
761 .name = XVIP_M2M_NAME,
762 .fops = &xvip_m2m_fops,
763 .ioctl_ops = &xvip_m2m_ioctl_ops,
764 .release = video_device_release_empty,
765 .vfl_dir = VFL_DIR_M2M,
766 .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
767 .vfl_type = VFL_TYPE_GRABBER,
770 static const struct v4l2_m2m_ops xvip_m2m_ops = {
771 .device_run = xvip_m2m_device_run,
772 .job_ready = xvip_m2m_job_ready,
773 .job_abort = xvip_m2m_job_abort,
776 static int xvip_m2m_dma_init(struct xvip_m2m_dma *dma)
778 struct xvip_m2m_dev *xdev;
779 struct v4l2_pix_format_mplane *pix_mp;
783 mutex_init(&xdev->lock);
784 spin_lock_init(&xdev->queued_lock);
786 /* Format info on capture port - NV12 is the default format */
787 dma->capinfo = xvip_get_format_by_fourcc(XVIP_M2M_DEFAULT_FMT);
788 pix_mp = &dma->capfmt.fmt.pix_mp;
789 pix_mp->pixelformat = dma->capinfo->fourcc;
790 pix_mp->field = V4L2_FIELD_NONE;
791 pix_mp->width = XVIP_M2M_DEF_WIDTH;
792 pix_mp->height = XVIP_M2M_DEF_HEIGHT;
793 pix_mp->plane_fmt[0].bytesperline = pix_mp->width *
794 dma->capinfo->bpl_factor;
795 pix_mp->plane_fmt[0].sizeimage =
796 DIV_ROUND_UP(pix_mp->plane_fmt[0].bytesperline *
797 pix_mp->height * dma->capinfo->bpp, 8);
799 /* Format info on output port - NV12 is the default format */
800 dma->outinfo = xvip_get_format_by_fourcc(XVIP_M2M_DEFAULT_FMT);
801 pix_mp = &dma->capfmt.fmt.pix_mp;
802 pix_mp->pixelformat = dma->outinfo->fourcc;
803 pix_mp->field = V4L2_FIELD_NONE;
804 pix_mp->width = XVIP_M2M_DEF_WIDTH;
805 pix_mp->height = XVIP_M2M_DEF_HEIGHT;
806 pix_mp->plane_fmt[0].bytesperline = pix_mp->width *
807 dma->outinfo->bpl_factor;
808 pix_mp->plane_fmt[0].sizeimage =
809 DIV_ROUND_UP(pix_mp->plane_fmt[0].bytesperline *
810 pix_mp->height * dma->outinfo->bpp, 8);
812 /* DMA channels for mem2mem */
813 dma->chan_tx = dma_request_chan(xdev->dev, "tx");
814 if (IS_ERR(dma->chan_tx)) {
815 ret = PTR_ERR(dma->chan_tx);
816 if (ret != -EPROBE_DEFER)
817 dev_err(xdev->dev, "mem2mem DMA tx channel not found");
822 dma->chan_rx = dma_request_chan(xdev->dev, "rx");
823 if (IS_ERR(dma->chan_rx)) {
824 ret = PTR_ERR(dma->chan_rx);
825 if (ret != -EPROBE_DEFER)
826 dev_err(xdev->dev, "mem2mem DMA rx channel not found");
831 dma->align = BIT(dma->chan_tx->device->copy_align);
834 dma->video = xvip_m2m_videodev;
835 dma->video.v4l2_dev = &xdev->v4l2_dev;
836 dma->video.lock = &xdev->lock;
838 ret = video_register_device(&dma->video, VFL_TYPE_GRABBER, -1);
840 dev_err(xdev->dev, "Failed to register mem2mem video device\n");
844 video_set_drvdata(&dma->video, dma->xdev);
848 dma_release_channel(dma->chan_rx);
850 dma_release_channel(dma->chan_tx);
855 static void xvip_m2m_dma_deinit(struct xvip_m2m_dma *dma)
857 if (video_is_registered(&dma->video))
858 video_unregister_device(&dma->video);
860 mutex_destroy(&dma->xdev->lock);
861 dma_release_channel(dma->chan_tx);
862 dma_release_channel(dma->chan_rx);
865 static int xvip_m2m_dma_alloc_init(struct xvip_m2m_dev *xdev)
867 struct xvip_m2m_dma *dma = NULL;
870 dma = devm_kzalloc(xdev->dev, sizeof(*dma), GFP_KERNEL);
877 ret = xvip_m2m_dma_init(xdev->dma);
879 dev_err(xdev->dev, "DMA initialization failed\n");
883 xdev->v4l2_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
887 /* -----------------------------------------------------------------------------
888 * Platform Device Driver
891 static int xvip_m2m_probe(struct platform_device *pdev)
893 struct xvip_m2m_dev *xdev = NULL;
896 xdev = devm_kzalloc(&pdev->dev, sizeof(*xdev), GFP_KERNEL);
900 xdev->dev = &pdev->dev;
902 ret = v4l2_device_register(&pdev->dev, &xdev->v4l2_dev);
906 ret = xvip_m2m_dma_alloc_init(xdev);
910 ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
912 dev_err(&pdev->dev, "dma_set_coherent_mask: %d\n", ret);
916 platform_set_drvdata(pdev, xdev);
918 xdev->m2m_dev = v4l2_m2m_init(&xvip_m2m_ops);
919 if (IS_ERR(xdev->m2m_dev)) {
920 dev_err(xdev->dev, "Failed to init mem2mem device\n");
921 ret = PTR_ERR(xdev->m2m_dev);
925 dev_info(xdev->dev, "mem2mem device registered\n");
929 xvip_m2m_dma_deinit(xdev->dma);
932 v4l2_device_unregister(&xdev->v4l2_dev);
936 static int xvip_m2m_remove(struct platform_device *pdev)
938 struct xvip_m2m_dev *xdev = platform_get_drvdata(pdev);
940 v4l2_device_unregister(&xdev->v4l2_dev);
944 static const struct of_device_id xvip_m2m_of_id_table[] = {
945 { .compatible = "xlnx,mem2mem" },
948 MODULE_DEVICE_TABLE(of, xvip_m2m_of_id_table);
950 static struct platform_driver xvip_m2m_driver = {
952 .name = XVIP_M2M_NAME,
953 .of_match_table = xvip_m2m_of_id_table,
955 .probe = xvip_m2m_probe,
956 .remove = xvip_m2m_remove,
959 module_platform_driver(xvip_m2m_driver);
961 MODULE_AUTHOR("Xilinx Inc.");
962 MODULE_DESCRIPTION("Xilinx V4L2 mem2mem driver");
963 MODULE_LICENSE("GPL v2");