1 // SPDX-License-Identifier: GPL-2.0
3 * ISI V4L2 memory to memory driver for i.MX8QXP/QM platform
5 * ISI is a Image Sensor Interface of i.MX8QXP/QM platform, which
6 * used to process image from camera sensor or memory to memory or DC
8 * Copyright (c) 2019 NXP Semiconductor
11 #include <linux/container_of.h>
12 #include <linux/device.h>
13 #include <linux/errno.h>
14 #include <linux/kernel.h>
15 #include <linux/limits.h>
16 #include <linux/minmax.h>
17 #include <linux/mutex.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/slab.h>
20 #include <linux/spinlock.h>
21 #include <linux/string.h>
22 #include <linux/types.h>
23 #include <linux/videodev2.h>
25 #include <media/media-entity.h>
26 #include <media/v4l2-ctrls.h>
27 #include <media/v4l2-device.h>
28 #include <media/v4l2-event.h>
29 #include <media/v4l2-fh.h>
30 #include <media/v4l2-ioctl.h>
31 #include <media/v4l2-mem2mem.h>
32 #include <media/videobuf2-core.h>
33 #include <media/videobuf2-dma-contig.h>
35 #include "imx8-isi-core.h"
37 struct mxc_isi_m2m_buffer
{
38 struct v4l2_m2m_buffer buf
;
39 dma_addr_t dma_addrs
[3];
42 struct mxc_isi_m2m_ctx_queue_data
{
43 struct v4l2_pix_format_mplane format
;
44 const struct mxc_isi_format_info
*info
;
48 struct mxc_isi_m2m_ctx
{
50 struct mxc_isi_m2m
*m2m
;
52 /* Protects the m2m vb2 queues */
53 struct mutex vb2_lock
;
56 struct mxc_isi_m2m_ctx_queue_data out
;
57 struct mxc_isi_m2m_ctx_queue_data cap
;
61 struct v4l2_ctrl_handler handler
;
70 static inline struct mxc_isi_m2m_buffer
*
71 to_isi_m2m_buffer(struct vb2_v4l2_buffer
*buf
)
73 return container_of(buf
, struct mxc_isi_m2m_buffer
, buf
.vb
);
76 static inline struct mxc_isi_m2m_ctx
*to_isi_m2m_ctx(struct v4l2_fh
*fh
)
78 return container_of(fh
, struct mxc_isi_m2m_ctx
, fh
);
81 static inline struct mxc_isi_m2m_ctx_queue_data
*
82 mxc_isi_m2m_ctx_qdata(struct mxc_isi_m2m_ctx
*ctx
, enum v4l2_buf_type type
)
84 if (V4L2_TYPE_IS_OUTPUT(type
))
85 return &ctx
->queues
.out
;
87 return &ctx
->queues
.cap
;
90 /* -----------------------------------------------------------------------------
91 * V4L2 M2M device operations
94 static void mxc_isi_m2m_frame_write_done(struct mxc_isi_pipe
*pipe
, u32 status
)
96 struct mxc_isi_m2m
*m2m
= &pipe
->isi
->m2m
;
97 struct vb2_v4l2_buffer
*src_vbuf
, *dst_vbuf
;
98 struct mxc_isi_m2m_ctx
*ctx
;
100 ctx
= v4l2_m2m_get_curr_priv(m2m
->m2m_dev
);
102 dev_err(m2m
->isi
->dev
,
103 "Instance released before the end of transaction\n");
107 src_vbuf
= v4l2_m2m_src_buf_remove(ctx
->fh
.m2m_ctx
);
108 dst_vbuf
= v4l2_m2m_dst_buf_remove(ctx
->fh
.m2m_ctx
);
110 v4l2_m2m_buf_copy_metadata(src_vbuf
, dst_vbuf
, false);
112 src_vbuf
->sequence
= ctx
->queues
.out
.sequence
++;
113 dst_vbuf
->sequence
= ctx
->queues
.cap
.sequence
++;
115 v4l2_m2m_buf_done(src_vbuf
, VB2_BUF_STATE_DONE
);
116 v4l2_m2m_buf_done(dst_vbuf
, VB2_BUF_STATE_DONE
);
118 v4l2_m2m_job_finish(m2m
->m2m_dev
, ctx
->fh
.m2m_ctx
);
121 static void mxc_isi_m2m_device_run(void *priv
)
123 struct mxc_isi_m2m_ctx
*ctx
= priv
;
124 struct mxc_isi_m2m
*m2m
= ctx
->m2m
;
125 struct vb2_v4l2_buffer
*src_vbuf
, *dst_vbuf
;
126 struct mxc_isi_m2m_buffer
*src_buf
, *dst_buf
;
128 mxc_isi_channel_disable(m2m
->pipe
);
130 mutex_lock(&m2m
->lock
);
132 /* If the context has changed, reconfigure the channel. */
133 if (m2m
->last_ctx
!= ctx
) {
134 const struct v4l2_area in_size
= {
135 .width
= ctx
->queues
.out
.format
.width
,
136 .height
= ctx
->queues
.out
.format
.height
,
138 const struct v4l2_area scale
= {
139 .width
= ctx
->queues
.cap
.format
.width
,
140 .height
= ctx
->queues
.cap
.format
.height
,
142 const struct v4l2_rect crop
= {
143 .width
= ctx
->queues
.cap
.format
.width
,
144 .height
= ctx
->queues
.cap
.format
.height
,
147 mxc_isi_channel_config(m2m
->pipe
, MXC_ISI_INPUT_MEM
,
148 &in_size
, &scale
, &crop
,
149 ctx
->queues
.out
.info
->encoding
,
150 ctx
->queues
.cap
.info
->encoding
);
151 mxc_isi_channel_set_input_format(m2m
->pipe
,
152 ctx
->queues
.out
.info
,
153 &ctx
->queues
.out
.format
);
154 mxc_isi_channel_set_output_format(m2m
->pipe
,
155 ctx
->queues
.cap
.info
,
156 &ctx
->queues
.cap
.format
);
161 mutex_unlock(&m2m
->lock
);
163 mutex_lock(ctx
->ctrls
.handler
.lock
);
164 mxc_isi_channel_set_alpha(m2m
->pipe
, ctx
->ctrls
.alpha
);
165 mxc_isi_channel_set_flip(m2m
->pipe
, ctx
->ctrls
.hflip
, ctx
->ctrls
.vflip
);
166 mutex_unlock(ctx
->ctrls
.handler
.lock
);
168 src_vbuf
= v4l2_m2m_next_src_buf(ctx
->fh
.m2m_ctx
);
169 dst_vbuf
= v4l2_m2m_next_dst_buf(ctx
->fh
.m2m_ctx
);
171 src_buf
= to_isi_m2m_buffer(src_vbuf
);
172 dst_buf
= to_isi_m2m_buffer(dst_vbuf
);
174 mxc_isi_channel_set_inbuf(m2m
->pipe
, src_buf
->dma_addrs
[0]);
175 mxc_isi_channel_set_outbuf(m2m
->pipe
, dst_buf
->dma_addrs
, MXC_ISI_BUF1
);
176 mxc_isi_channel_set_outbuf(m2m
->pipe
, dst_buf
->dma_addrs
, MXC_ISI_BUF2
);
178 mxc_isi_channel_enable(m2m
->pipe
);
180 mxc_isi_channel_m2m_start(m2m
->pipe
);
183 static const struct v4l2_m2m_ops mxc_isi_m2m_ops
= {
184 .device_run
= mxc_isi_m2m_device_run
,
187 /* -----------------------------------------------------------------------------
188 * videobuf2 queue operations
191 static int mxc_isi_m2m_vb2_queue_setup(struct vb2_queue
*q
,
192 unsigned int *num_buffers
,
193 unsigned int *num_planes
,
194 unsigned int sizes
[],
195 struct device
*alloc_devs
[])
197 struct mxc_isi_m2m_ctx
*ctx
= vb2_get_drv_priv(q
);
198 const struct mxc_isi_m2m_ctx_queue_data
*qdata
=
199 mxc_isi_m2m_ctx_qdata(ctx
, q
->type
);
201 return mxc_isi_video_queue_setup(&qdata
->format
, qdata
->info
,
202 num_buffers
, num_planes
, sizes
);
205 static int mxc_isi_m2m_vb2_buffer_init(struct vb2_buffer
*vb2
)
207 struct vb2_queue
*vq
= vb2
->vb2_queue
;
208 struct mxc_isi_m2m_buffer
*buf
= to_isi_m2m_buffer(to_vb2_v4l2_buffer(vb2
));
209 struct mxc_isi_m2m_ctx
*ctx
= vb2_get_drv_priv(vb2
->vb2_queue
);
210 const struct mxc_isi_m2m_ctx_queue_data
*qdata
=
211 mxc_isi_m2m_ctx_qdata(ctx
, vq
->type
);
213 mxc_isi_video_buffer_init(vb2
, buf
->dma_addrs
, qdata
->info
,
219 static int mxc_isi_m2m_vb2_buffer_prepare(struct vb2_buffer
*vb2
)
221 struct vb2_queue
*vq
= vb2
->vb2_queue
;
222 struct mxc_isi_m2m_ctx
*ctx
= vb2_get_drv_priv(vq
);
223 const struct mxc_isi_m2m_ctx_queue_data
*qdata
=
224 mxc_isi_m2m_ctx_qdata(ctx
, vq
->type
);
226 return mxc_isi_video_buffer_prepare(ctx
->m2m
->isi
, vb2
, qdata
->info
,
230 static void mxc_isi_m2m_vb2_buffer_queue(struct vb2_buffer
*vb2
)
232 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb2
);
233 struct mxc_isi_m2m_ctx
*ctx
= vb2_get_drv_priv(vb2
->vb2_queue
);
235 v4l2_m2m_buf_queue(ctx
->fh
.m2m_ctx
, vbuf
);
238 static int mxc_isi_m2m_vb2_start_streaming(struct vb2_queue
*q
,
241 struct mxc_isi_m2m_ctx
*ctx
= vb2_get_drv_priv(q
);
242 struct mxc_isi_m2m_ctx_queue_data
*qdata
=
243 mxc_isi_m2m_ctx_qdata(ctx
, q
->type
);
250 static void mxc_isi_m2m_vb2_stop_streaming(struct vb2_queue
*q
)
252 struct mxc_isi_m2m_ctx
*ctx
= vb2_get_drv_priv(q
);
253 struct vb2_v4l2_buffer
*vbuf
;
256 if (q
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
257 vbuf
= v4l2_m2m_src_buf_remove(ctx
->fh
.m2m_ctx
);
259 vbuf
= v4l2_m2m_dst_buf_remove(ctx
->fh
.m2m_ctx
);
263 v4l2_m2m_buf_done(vbuf
, VB2_BUF_STATE_ERROR
);
267 static const struct vb2_ops mxc_isi_m2m_vb2_qops
= {
268 .queue_setup
= mxc_isi_m2m_vb2_queue_setup
,
269 .buf_init
= mxc_isi_m2m_vb2_buffer_init
,
270 .buf_prepare
= mxc_isi_m2m_vb2_buffer_prepare
,
271 .buf_queue
= mxc_isi_m2m_vb2_buffer_queue
,
272 .wait_prepare
= vb2_ops_wait_prepare
,
273 .wait_finish
= vb2_ops_wait_finish
,
274 .start_streaming
= mxc_isi_m2m_vb2_start_streaming
,
275 .stop_streaming
= mxc_isi_m2m_vb2_stop_streaming
,
278 static int mxc_isi_m2m_queue_init(void *priv
, struct vb2_queue
*src_vq
,
279 struct vb2_queue
*dst_vq
)
281 struct mxc_isi_m2m_ctx
*ctx
= priv
;
282 struct mxc_isi_m2m
*m2m
= ctx
->m2m
;
285 src_vq
->type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
286 src_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
287 src_vq
->drv_priv
= ctx
;
288 src_vq
->buf_struct_size
= sizeof(struct mxc_isi_m2m_buffer
);
289 src_vq
->ops
= &mxc_isi_m2m_vb2_qops
;
290 src_vq
->mem_ops
= &vb2_dma_contig_memops
;
291 src_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
292 src_vq
->lock
= &ctx
->vb2_lock
;
293 src_vq
->dev
= m2m
->isi
->dev
;
295 ret
= vb2_queue_init(src_vq
);
299 dst_vq
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
300 dst_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
301 dst_vq
->drv_priv
= ctx
;
302 dst_vq
->buf_struct_size
= sizeof(struct mxc_isi_m2m_buffer
);
303 dst_vq
->ops
= &mxc_isi_m2m_vb2_qops
;
304 dst_vq
->mem_ops
= &vb2_dma_contig_memops
;
305 dst_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
306 dst_vq
->lock
= &ctx
->vb2_lock
;
307 dst_vq
->dev
= m2m
->isi
->dev
;
309 return vb2_queue_init(dst_vq
);
312 /* -----------------------------------------------------------------------------
316 static inline struct mxc_isi_m2m_ctx
*
317 ctrl_to_mxc_isi_m2m_ctx(struct v4l2_ctrl
*ctrl
)
319 return container_of(ctrl
->handler
, struct mxc_isi_m2m_ctx
, ctrls
.handler
);
322 static int mxc_isi_m2m_ctx_s_ctrl(struct v4l2_ctrl
*ctrl
)
324 struct mxc_isi_m2m_ctx
*ctx
= ctrl_to_mxc_isi_m2m_ctx(ctrl
);
328 ctx
->ctrls
.hflip
= ctrl
->val
;
332 ctx
->ctrls
.vflip
= ctrl
->val
;
335 case V4L2_CID_ALPHA_COMPONENT
:
336 ctx
->ctrls
.alpha
= ctrl
->val
;
343 static const struct v4l2_ctrl_ops mxc_isi_m2m_ctx_ctrl_ops
= {
344 .s_ctrl
= mxc_isi_m2m_ctx_s_ctrl
,
347 static int mxc_isi_m2m_ctx_ctrls_create(struct mxc_isi_m2m_ctx
*ctx
)
349 struct v4l2_ctrl_handler
*handler
= &ctx
->ctrls
.handler
;
352 v4l2_ctrl_handler_init(handler
, 3);
354 v4l2_ctrl_new_std(handler
, &mxc_isi_m2m_ctx_ctrl_ops
,
355 V4L2_CID_ALPHA_COMPONENT
, 0, 255, 1, 0);
356 v4l2_ctrl_new_std(handler
, &mxc_isi_m2m_ctx_ctrl_ops
,
357 V4L2_CID_HFLIP
, 0, 1, 1, 0);
358 v4l2_ctrl_new_std(handler
, &mxc_isi_m2m_ctx_ctrl_ops
,
359 V4L2_CID_VFLIP
, 0, 1, 1, 0);
361 if (handler
->error
) {
362 ret
= handler
->error
;
363 v4l2_ctrl_handler_free(handler
);
367 ctx
->fh
.ctrl_handler
= handler
;
372 static void mxc_isi_m2m_ctx_ctrls_delete(struct mxc_isi_m2m_ctx
*ctx
)
374 v4l2_ctrl_handler_free(&ctx
->ctrls
.handler
);
377 /* -----------------------------------------------------------------------------
381 static int mxc_isi_m2m_querycap(struct file
*file
, void *fh
,
382 struct v4l2_capability
*cap
)
384 strscpy(cap
->driver
, MXC_ISI_DRIVER_NAME
, sizeof(cap
->driver
));
385 strscpy(cap
->card
, MXC_ISI_M2M
, sizeof(cap
->card
));
386 cap
->device_caps
= V4L2_CAP_STREAMING
| V4L2_CAP_VIDEO_M2M_MPLANE
;
387 cap
->capabilities
= cap
->device_caps
| V4L2_CAP_DEVICE_CAPS
;
392 static int mxc_isi_m2m_enum_fmt_vid(struct file
*file
, void *fh
,
393 struct v4l2_fmtdesc
*f
)
395 const enum mxc_isi_video_type type
=
396 f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
?
397 MXC_ISI_VIDEO_M2M_OUT
: MXC_ISI_VIDEO_M2M_CAP
;
398 const struct mxc_isi_format_info
*info
;
400 info
= mxc_isi_format_enum(f
->index
, type
);
404 f
->pixelformat
= info
->fourcc
;
405 f
->flags
|= V4L2_FMT_FLAG_CSC_COLORSPACE
| V4L2_FMT_FLAG_CSC_YCBCR_ENC
406 | V4L2_FMT_FLAG_CSC_QUANTIZATION
| V4L2_FMT_FLAG_CSC_XFER_FUNC
;
411 static const struct mxc_isi_format_info
*
412 __mxc_isi_m2m_try_fmt_vid(struct mxc_isi_m2m_ctx
*ctx
,
413 struct v4l2_pix_format_mplane
*pix
,
414 const enum mxc_isi_video_type type
)
416 if (type
== MXC_ISI_VIDEO_M2M_CAP
) {
417 /* Downscaling only */
418 pix
->width
= min(pix
->width
, ctx
->queues
.out
.format
.width
);
419 pix
->height
= min(pix
->height
, ctx
->queues
.out
.format
.height
);
422 return mxc_isi_format_try(ctx
->m2m
->pipe
, pix
, type
);
425 static int mxc_isi_m2m_try_fmt_vid(struct file
*file
, void *fh
,
426 struct v4l2_format
*f
)
428 const enum mxc_isi_video_type type
=
429 f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
?
430 MXC_ISI_VIDEO_M2M_OUT
: MXC_ISI_VIDEO_M2M_CAP
;
431 struct mxc_isi_m2m_ctx
*ctx
= to_isi_m2m_ctx(fh
);
433 __mxc_isi_m2m_try_fmt_vid(ctx
, &f
->fmt
.pix_mp
, type
);
438 static int mxc_isi_m2m_g_fmt_vid(struct file
*file
, void *fh
,
439 struct v4l2_format
*f
)
441 struct mxc_isi_m2m_ctx
*ctx
= to_isi_m2m_ctx(fh
);
442 const struct mxc_isi_m2m_ctx_queue_data
*qdata
=
443 mxc_isi_m2m_ctx_qdata(ctx
, f
->type
);
445 f
->fmt
.pix_mp
= qdata
->format
;
450 static int mxc_isi_m2m_s_fmt_vid(struct file
*file
, void *fh
,
451 struct v4l2_format
*f
)
453 const enum mxc_isi_video_type type
=
454 f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
?
455 MXC_ISI_VIDEO_M2M_OUT
: MXC_ISI_VIDEO_M2M_CAP
;
456 struct mxc_isi_m2m_ctx
*ctx
= to_isi_m2m_ctx(fh
);
457 struct v4l2_pix_format_mplane
*pix
= &f
->fmt
.pix_mp
;
458 const struct mxc_isi_format_info
*info
;
459 struct vb2_queue
*vq
;
461 vq
= v4l2_m2m_get_vq(ctx
->fh
.m2m_ctx
, f
->type
);
468 info
= __mxc_isi_m2m_try_fmt_vid(ctx
, pix
, type
);
470 if (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
) {
471 ctx
->queues
.out
.format
= *pix
;
472 ctx
->queues
.out
.info
= info
;
476 * Always set the format on the capture side, due to either format
477 * propagation or direct setting.
479 ctx
->queues
.cap
.format
= *pix
;
480 ctx
->queues
.cap
.info
= info
;
485 static int mxc_isi_m2m_streamon(struct file
*file
, void *fh
,
486 enum v4l2_buf_type type
)
488 struct mxc_isi_m2m_ctx
*ctx
= to_isi_m2m_ctx(fh
);
489 const struct v4l2_pix_format_mplane
*out_pix
= &ctx
->queues
.out
.format
;
490 const struct v4l2_pix_format_mplane
*cap_pix
= &ctx
->queues
.cap
.format
;
491 const struct mxc_isi_format_info
*cap_info
= ctx
->queues
.cap
.info
;
492 const struct mxc_isi_format_info
*out_info
= ctx
->queues
.out
.info
;
493 struct mxc_isi_m2m
*m2m
= ctx
->m2m
;
498 mutex_lock(&m2m
->lock
);
500 if (m2m
->usage_count
== INT_MAX
) {
505 bypass
= cap_pix
->width
== out_pix
->width
&&
506 cap_pix
->height
== out_pix
->height
&&
507 cap_info
->encoding
== out_info
->encoding
;
510 * Acquire the pipe and initialize the channel with the first user of
513 if (m2m
->usage_count
== 0) {
514 ret
= mxc_isi_channel_acquire(m2m
->pipe
,
515 &mxc_isi_m2m_frame_write_done
,
520 mxc_isi_channel_get(m2m
->pipe
);
526 * Allocate resources for the channel, counting how many users require
529 if (!ctx
->chained
&& out_pix
->width
> MXC_ISI_MAX_WIDTH_UNCHAINED
) {
530 ret
= mxc_isi_channel_chain(m2m
->pipe
, bypass
);
534 m2m
->chained_count
++;
539 * Drop the lock to start the stream, as the .device_run() operation
540 * needs to acquire it.
542 mutex_unlock(&m2m
->lock
);
543 ret
= v4l2_m2m_ioctl_streamon(file
, fh
, type
);
545 /* Reacquire the lock for the cleanup path. */
546 mutex_lock(&m2m
->lock
);
553 if (ctx
->chained
&& --m2m
->chained_count
== 0)
554 mxc_isi_channel_unchain(m2m
->pipe
);
555 ctx
->chained
= false;
558 if (--m2m
->usage_count
== 0) {
559 mxc_isi_channel_put(m2m
->pipe
);
560 mxc_isi_channel_release(m2m
->pipe
);
564 mutex_unlock(&m2m
->lock
);
568 static int mxc_isi_m2m_streamoff(struct file
*file
, void *fh
,
569 enum v4l2_buf_type type
)
571 struct mxc_isi_m2m_ctx
*ctx
= to_isi_m2m_ctx(fh
);
572 struct mxc_isi_m2m
*m2m
= ctx
->m2m
;
574 v4l2_m2m_ioctl_streamoff(file
, fh
, type
);
576 mutex_lock(&m2m
->lock
);
579 * If the last context is this one, reset it to make sure the device
580 * will be reconfigured when streaming is restarted.
582 if (m2m
->last_ctx
== ctx
)
583 m2m
->last_ctx
= NULL
;
585 /* Free the channel resources if this is the last chained context. */
586 if (ctx
->chained
&& --m2m
->chained_count
== 0)
587 mxc_isi_channel_unchain(m2m
->pipe
);
588 ctx
->chained
= false;
590 /* Turn off the light with the last user. */
591 if (--m2m
->usage_count
== 0) {
592 mxc_isi_channel_disable(m2m
->pipe
);
593 mxc_isi_channel_put(m2m
->pipe
);
594 mxc_isi_channel_release(m2m
->pipe
);
597 WARN_ON(m2m
->usage_count
< 0);
599 mutex_unlock(&m2m
->lock
);
604 static const struct v4l2_ioctl_ops mxc_isi_m2m_ioctl_ops
= {
605 .vidioc_querycap
= mxc_isi_m2m_querycap
,
607 .vidioc_enum_fmt_vid_cap
= mxc_isi_m2m_enum_fmt_vid
,
608 .vidioc_enum_fmt_vid_out
= mxc_isi_m2m_enum_fmt_vid
,
609 .vidioc_g_fmt_vid_cap_mplane
= mxc_isi_m2m_g_fmt_vid
,
610 .vidioc_g_fmt_vid_out_mplane
= mxc_isi_m2m_g_fmt_vid
,
611 .vidioc_s_fmt_vid_cap_mplane
= mxc_isi_m2m_s_fmt_vid
,
612 .vidioc_s_fmt_vid_out_mplane
= mxc_isi_m2m_s_fmt_vid
,
613 .vidioc_try_fmt_vid_cap_mplane
= mxc_isi_m2m_try_fmt_vid
,
614 .vidioc_try_fmt_vid_out_mplane
= mxc_isi_m2m_try_fmt_vid
,
616 .vidioc_reqbufs
= v4l2_m2m_ioctl_reqbufs
,
617 .vidioc_querybuf
= v4l2_m2m_ioctl_querybuf
,
618 .vidioc_qbuf
= v4l2_m2m_ioctl_qbuf
,
619 .vidioc_dqbuf
= v4l2_m2m_ioctl_dqbuf
,
620 .vidioc_expbuf
= v4l2_m2m_ioctl_expbuf
,
621 .vidioc_prepare_buf
= v4l2_m2m_ioctl_prepare_buf
,
622 .vidioc_create_bufs
= v4l2_m2m_ioctl_create_bufs
,
624 .vidioc_streamon
= mxc_isi_m2m_streamon
,
625 .vidioc_streamoff
= mxc_isi_m2m_streamoff
,
627 .vidioc_subscribe_event
= v4l2_ctrl_subscribe_event
,
628 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
631 /* -----------------------------------------------------------------------------
632 * Video device file operations
635 static void mxc_isi_m2m_init_format(struct mxc_isi_m2m_ctx
*ctx
,
636 struct mxc_isi_m2m_ctx_queue_data
*qdata
,
637 enum mxc_isi_video_type type
)
639 qdata
->format
.width
= MXC_ISI_DEF_WIDTH
;
640 qdata
->format
.height
= MXC_ISI_DEF_HEIGHT
;
641 qdata
->format
.pixelformat
= MXC_ISI_DEF_PIXEL_FORMAT
;
643 qdata
->info
= mxc_isi_format_try(ctx
->m2m
->pipe
, &qdata
->format
, type
);
646 static int mxc_isi_m2m_open(struct file
*file
)
648 struct video_device
*vdev
= video_devdata(file
);
649 struct mxc_isi_m2m
*m2m
= video_drvdata(file
);
650 struct mxc_isi_m2m_ctx
*ctx
;
653 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
658 mutex_init(&ctx
->vb2_lock
);
660 v4l2_fh_init(&ctx
->fh
, vdev
);
661 file
->private_data
= &ctx
->fh
;
663 ctx
->fh
.m2m_ctx
= v4l2_m2m_ctx_init(m2m
->m2m_dev
, ctx
,
664 &mxc_isi_m2m_queue_init
);
665 if (IS_ERR(ctx
->fh
.m2m_ctx
)) {
666 ret
= PTR_ERR(ctx
->fh
.m2m_ctx
);
667 ctx
->fh
.m2m_ctx
= NULL
;
671 mxc_isi_m2m_init_format(ctx
, &ctx
->queues
.out
, MXC_ISI_VIDEO_M2M_OUT
);
672 mxc_isi_m2m_init_format(ctx
, &ctx
->queues
.cap
, MXC_ISI_VIDEO_M2M_CAP
);
674 ret
= mxc_isi_m2m_ctx_ctrls_create(ctx
);
678 ret
= pm_runtime_resume_and_get(m2m
->isi
->dev
);
682 v4l2_fh_add(&ctx
->fh
);
687 mxc_isi_m2m_ctx_ctrls_delete(ctx
);
689 v4l2_m2m_ctx_release(ctx
->fh
.m2m_ctx
);
691 v4l2_fh_exit(&ctx
->fh
);
692 mutex_destroy(&ctx
->vb2_lock
);
697 static int mxc_isi_m2m_release(struct file
*file
)
699 struct mxc_isi_m2m
*m2m
= video_drvdata(file
);
700 struct mxc_isi_m2m_ctx
*ctx
= to_isi_m2m_ctx(file
->private_data
);
702 v4l2_m2m_ctx_release(ctx
->fh
.m2m_ctx
);
703 mxc_isi_m2m_ctx_ctrls_delete(ctx
);
705 v4l2_fh_del(&ctx
->fh
);
706 v4l2_fh_exit(&ctx
->fh
);
708 mutex_destroy(&ctx
->vb2_lock
);
711 pm_runtime_put(m2m
->isi
->dev
);
716 static const struct v4l2_file_operations mxc_isi_m2m_fops
= {
717 .owner
= THIS_MODULE
,
718 .open
= mxc_isi_m2m_open
,
719 .release
= mxc_isi_m2m_release
,
720 .poll
= v4l2_m2m_fop_poll
,
721 .unlocked_ioctl
= video_ioctl2
,
722 .mmap
= v4l2_m2m_fop_mmap
,
725 /* -----------------------------------------------------------------------------
729 int mxc_isi_m2m_register(struct mxc_isi_dev
*isi
, struct v4l2_device
*v4l2_dev
)
731 struct mxc_isi_m2m
*m2m
= &isi
->m2m
;
732 struct video_device
*vdev
= &m2m
->vdev
;
733 struct media_link
*link
;
737 m2m
->pipe
= &isi
->pipes
[0];
739 mutex_init(&m2m
->lock
);
741 /* Initialize the video device and create controls. */
742 snprintf(vdev
->name
, sizeof(vdev
->name
), "mxc_isi.m2m");
744 vdev
->fops
= &mxc_isi_m2m_fops
;
745 vdev
->ioctl_ops
= &mxc_isi_m2m_ioctl_ops
;
746 vdev
->v4l2_dev
= v4l2_dev
;
748 vdev
->release
= video_device_release_empty
;
749 vdev
->vfl_dir
= VFL_DIR_M2M
;
751 vdev
->device_caps
= V4L2_CAP_STREAMING
| V4L2_CAP_VIDEO_M2M_MPLANE
;
752 video_set_drvdata(vdev
, m2m
);
754 /* Create the M2M device. */
755 m2m
->m2m_dev
= v4l2_m2m_init(&mxc_isi_m2m_ops
);
756 if (IS_ERR(m2m
->m2m_dev
)) {
757 dev_err(isi
->dev
, "failed to initialize m2m device\n");
758 ret
= PTR_ERR(m2m
->m2m_dev
);
762 /* Register the video device. */
763 ret
= video_register_device(vdev
, VFL_TYPE_VIDEO
, -1);
765 dev_err(isi
->dev
, "failed to register m2m device\n");
770 * Populate the media graph. We can't use the mem2mem helper
771 * v4l2_m2m_register_media_controller() as the M2M interface needs to
772 * be connected to the existing entities in the graph, so we have to
773 * wire things up manually:
775 * - The entity in the video_device, which isn't touched by the V4L2
776 * core for M2M devices, is used as the source I/O entity in the
777 * graph, connected to the crossbar switch.
779 * - The video device at the end of the pipeline provides the sink
780 * entity, and is already wired up in the graph.
782 * - A new interface is created, pointing at both entities. The sink
783 * entity will thus have two interfaces pointing to it.
785 m2m
->pad
.flags
= MEDIA_PAD_FL_SOURCE
;
786 vdev
->entity
.name
= "mxc_isi.output";
787 vdev
->entity
.function
= MEDIA_ENT_F_IO_V4L
;
788 ret
= media_entity_pads_init(&vdev
->entity
, 1, &m2m
->pad
);
792 ret
= media_device_register_entity(v4l2_dev
->mdev
, &vdev
->entity
);
794 goto err_entity_cleanup
;
796 ret
= media_create_pad_link(&vdev
->entity
, 0,
797 &m2m
->isi
->crossbar
.sd
.entity
,
798 m2m
->isi
->crossbar
.num_sinks
- 1,
799 MEDIA_LNK_FL_IMMUTABLE
|
800 MEDIA_LNK_FL_ENABLED
);
802 goto err_entity_unreg
;
804 m2m
->intf
= media_devnode_create(v4l2_dev
->mdev
, MEDIA_INTF_T_V4L_VIDEO
,
805 0, VIDEO_MAJOR
, vdev
->minor
);
808 goto err_entity_unreg
;
811 link
= media_create_intf_link(&vdev
->entity
, &m2m
->intf
->intf
,
812 MEDIA_LNK_FL_IMMUTABLE
|
813 MEDIA_LNK_FL_ENABLED
);
819 link
= media_create_intf_link(&m2m
->pipe
->video
.vdev
.entity
,
821 MEDIA_LNK_FL_IMMUTABLE
|
822 MEDIA_LNK_FL_ENABLED
);
831 media_devnode_remove(m2m
->intf
);
833 media_device_unregister_entity(&vdev
->entity
);
835 media_entity_cleanup(&vdev
->entity
);
837 video_unregister_device(vdev
);
839 v4l2_m2m_release(m2m
->m2m_dev
);
841 mutex_destroy(&m2m
->lock
);
845 int mxc_isi_m2m_unregister(struct mxc_isi_dev
*isi
)
847 struct mxc_isi_m2m
*m2m
= &isi
->m2m
;
848 struct video_device
*vdev
= &m2m
->vdev
;
850 video_unregister_device(vdev
);
852 v4l2_m2m_release(m2m
->m2m_dev
);
853 media_devnode_remove(m2m
->intf
);
854 media_entity_cleanup(&vdev
->entity
);
855 mutex_destroy(&m2m
->lock
);