1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ISI V4L2 memory to memory driver for i.MX8QXP/QM platform
4 *
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
7 *
8 * Copyright (c) 2019 NXP Semiconductor
9 */
10
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>
24
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>
34
35#include "imx8-isi-core.h"
36
37struct mxc_isi_m2m_buffer {
38	struct v4l2_m2m_buffer buf;
39	dma_addr_t dma_addrs[3];
40};
41
42struct mxc_isi_m2m_ctx_queue_data {
43	struct v4l2_pix_format_mplane format;
44	const struct mxc_isi_format_info *info;
45	u32 sequence;
46};
47
48struct mxc_isi_m2m_ctx {
49	struct v4l2_fh fh;
50	struct mxc_isi_m2m *m2m;
51
52	/* Protects the m2m vb2 queues */
53	struct mutex vb2_lock;
54
55	struct {
56		struct mxc_isi_m2m_ctx_queue_data out;
57		struct mxc_isi_m2m_ctx_queue_data cap;
58	} queues;
59
60	struct {
61		struct v4l2_ctrl_handler handler;
62		unsigned int alpha;
63		bool hflip;
64		bool vflip;
65	} ctrls;
66
67	bool chained;
68};
69
70static inline struct mxc_isi_m2m_buffer *
71to_isi_m2m_buffer(struct vb2_v4l2_buffer *buf)
72{
73	return container_of(buf, struct mxc_isi_m2m_buffer, buf.vb);
74}
75
76static inline struct mxc_isi_m2m_ctx *to_isi_m2m_ctx(struct v4l2_fh *fh)
77{
78	return container_of(fh, struct mxc_isi_m2m_ctx, fh);
79}
80
81static inline struct mxc_isi_m2m_ctx_queue_data *
82mxc_isi_m2m_ctx_qdata(struct mxc_isi_m2m_ctx *ctx, enum v4l2_buf_type type)
83{
84	if (V4L2_TYPE_IS_OUTPUT(type))
85		return &ctx->queues.out;
86	else
87		return &ctx->queues.cap;
88}
89
90/* -----------------------------------------------------------------------------
91 * V4L2 M2M device operations
92 */
93
94static void mxc_isi_m2m_frame_write_done(struct mxc_isi_pipe *pipe, u32 status)
95{
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;
99
100	ctx = v4l2_m2m_get_curr_priv(m2m->m2m_dev);
101	if (!ctx) {
102		dev_err(m2m->isi->dev,
103			"Instance released before the end of transaction\n");
104		return;
105	}
106
107	src_vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
108	dst_vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
109
110	v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, false);
111
112	src_vbuf->sequence = ctx->queues.out.sequence++;
113	dst_vbuf->sequence = ctx->queues.cap.sequence++;
114
115	v4l2_m2m_buf_done(src_vbuf, VB2_BUF_STATE_DONE);
116	v4l2_m2m_buf_done(dst_vbuf, VB2_BUF_STATE_DONE);
117
118	v4l2_m2m_job_finish(m2m->m2m_dev, ctx->fh.m2m_ctx);
119}
120
121static void mxc_isi_m2m_device_run(void *priv)
122{
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;
127
128	mxc_isi_channel_disable(m2m->pipe);
129
130	mutex_lock(&m2m->lock);
131
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,
137		};
138		const struct v4l2_area scale = {
139			.width = ctx->queues.cap.format.width,
140			.height = ctx->queues.cap.format.height,
141		};
142		const struct v4l2_rect crop = {
143			.width = ctx->queues.cap.format.width,
144			.height = ctx->queues.cap.format.height,
145		};
146
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);
157
158		m2m->last_ctx = ctx;
159	}
160
161	mutex_unlock(&m2m->lock);
162
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);
167
168	src_vbuf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
169	dst_vbuf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
170
171	src_buf = to_isi_m2m_buffer(src_vbuf);
172	dst_buf = to_isi_m2m_buffer(dst_vbuf);
173
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);
177
178	mxc_isi_channel_enable(m2m->pipe);
179
180	mxc_isi_channel_m2m_start(m2m->pipe);
181}
182
183static const struct v4l2_m2m_ops mxc_isi_m2m_ops = {
184	.device_run = mxc_isi_m2m_device_run,
185};
186
187/* -----------------------------------------------------------------------------
188 * videobuf2 queue operations
189 */
190
191static 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[])
196{
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);
200
201	return mxc_isi_video_queue_setup(&qdata->format, qdata->info,
202					 num_buffers, num_planes, sizes);
203}
204
205static int mxc_isi_m2m_vb2_buffer_init(struct vb2_buffer *vb2)
206{
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);
212
213	mxc_isi_video_buffer_init(vb2, buf->dma_addrs, qdata->info,
214				  &qdata->format);
215
216	return 0;
217}
218
219static int mxc_isi_m2m_vb2_buffer_prepare(struct vb2_buffer *vb2)
220{
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);
225
226	return mxc_isi_video_buffer_prepare(ctx->m2m->isi, vb2, qdata->info,
227					    &qdata->format);
228}
229
230static void mxc_isi_m2m_vb2_buffer_queue(struct vb2_buffer *vb2)
231{
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);
234
235	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
236}
237
238static int mxc_isi_m2m_vb2_start_streaming(struct vb2_queue *q,
239					   unsigned int count)
240{
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);
244
245	qdata->sequence = 0;
246
247	return 0;
248}
249
250static void mxc_isi_m2m_vb2_stop_streaming(struct vb2_queue *q)
251{
252	struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q);
253	struct vb2_v4l2_buffer *vbuf;
254
255	for (;;) {
256		if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
257			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
258		else
259			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
260		if (!vbuf)
261			break;
262
263		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
264	}
265}
266
267static 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,
276};
277
278static int mxc_isi_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
279				  struct vb2_queue *dst_vq)
280{
281	struct mxc_isi_m2m_ctx *ctx = priv;
282	struct mxc_isi_m2m *m2m = ctx->m2m;
283	int ret;
284
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;
294
295	ret = vb2_queue_init(src_vq);
296	if (ret)
297		return ret;
298
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;
308
309	return vb2_queue_init(dst_vq);
310}
311
312/* -----------------------------------------------------------------------------
313 * V4L2 controls
314 */
315
316static inline struct mxc_isi_m2m_ctx *
317ctrl_to_mxc_isi_m2m_ctx(struct v4l2_ctrl *ctrl)
318{
319	return container_of(ctrl->handler, struct mxc_isi_m2m_ctx, ctrls.handler);
320}
321
322static int mxc_isi_m2m_ctx_s_ctrl(struct v4l2_ctrl *ctrl)
323{
324	struct mxc_isi_m2m_ctx *ctx = ctrl_to_mxc_isi_m2m_ctx(ctrl);
325
326	switch (ctrl->id) {
327	case V4L2_CID_HFLIP:
328		ctx->ctrls.hflip = ctrl->val;
329		break;
330
331	case V4L2_CID_VFLIP:
332		ctx->ctrls.vflip = ctrl->val;
333		break;
334
335	case V4L2_CID_ALPHA_COMPONENT:
336		ctx->ctrls.alpha = ctrl->val;
337		break;
338	}
339
340	return 0;
341}
342
343static const struct v4l2_ctrl_ops mxc_isi_m2m_ctx_ctrl_ops = {
344	.s_ctrl = mxc_isi_m2m_ctx_s_ctrl,
345};
346
347static int mxc_isi_m2m_ctx_ctrls_create(struct mxc_isi_m2m_ctx *ctx)
348{
349	struct v4l2_ctrl_handler *handler = &ctx->ctrls.handler;
350	int ret;
351
352	v4l2_ctrl_handler_init(handler, 3);
353
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);
360
361	if (handler->error) {
362		ret = handler->error;
363		v4l2_ctrl_handler_free(handler);
364		return ret;
365	}
366
367	ctx->fh.ctrl_handler = handler;
368
369	return 0;
370}
371
372static void mxc_isi_m2m_ctx_ctrls_delete(struct mxc_isi_m2m_ctx *ctx)
373{
374	v4l2_ctrl_handler_free(&ctx->ctrls.handler);
375}
376
377/* -----------------------------------------------------------------------------
378 * V4L2 ioctls
379 */
380
381static int mxc_isi_m2m_querycap(struct file *file, void *fh,
382				struct v4l2_capability *cap)
383{
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;
388
389	return 0;
390}
391
392static int mxc_isi_m2m_enum_fmt_vid(struct file *file, void *fh,
393				    struct v4l2_fmtdesc *f)
394{
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;
399
400	info = mxc_isi_format_enum(f->index, type);
401	if (!info)
402		return -EINVAL;
403
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;
407
408	return 0;
409}
410
411static 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)
415{
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);
420	}
421
422	return mxc_isi_format_try(ctx->m2m->pipe, pix, type);
423}
424
425static int mxc_isi_m2m_try_fmt_vid(struct file *file, void *fh,
426				   struct v4l2_format *f)
427{
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);
432
433	__mxc_isi_m2m_try_fmt_vid(ctx, &f->fmt.pix_mp, type);
434
435	return 0;
436}
437
438static int mxc_isi_m2m_g_fmt_vid(struct file *file, void *fh,
439				 struct v4l2_format *f)
440{
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);
444
445	f->fmt.pix_mp = qdata->format;
446
447	return 0;
448}
449
450static int mxc_isi_m2m_s_fmt_vid(struct file *file, void *fh,
451				 struct v4l2_format *f)
452{
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;
460
461	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
462	if (!vq)
463		return -EINVAL;
464
465	if (vb2_is_busy(vq))
466		return -EBUSY;
467
468	info = __mxc_isi_m2m_try_fmt_vid(ctx, pix, type);
469
470	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
471		ctx->queues.out.format = *pix;
472		ctx->queues.out.info = info;
473	}
474
475	/*
476	 * Always set the format on the capture side, due to either format
477	 * propagation or direct setting.
478	 */
479	ctx->queues.cap.format = *pix;
480	ctx->queues.cap.info = info;
481
482	return 0;
483}
484
485static int mxc_isi_m2m_streamon(struct file *file, void *fh,
486				enum v4l2_buf_type type)
487{
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;
494	bool bypass;
495
496	int ret;
497
498	mutex_lock(&m2m->lock);
499
500	if (m2m->usage_count == INT_MAX) {
501		ret = -EOVERFLOW;
502		goto unlock;
503	}
504
505	bypass = cap_pix->width == out_pix->width &&
506		 cap_pix->height == out_pix->height &&
507		 cap_info->encoding == out_info->encoding;
508
509	/*
510	 * Acquire the pipe and initialize the channel with the first user of
511	 * the M2M device.
512	 */
513	if (m2m->usage_count == 0) {
514		ret = mxc_isi_channel_acquire(m2m->pipe,
515					      &mxc_isi_m2m_frame_write_done,
516					      bypass);
517		if (ret)
518			goto unlock;
519
520		mxc_isi_channel_get(m2m->pipe);
521	}
522
523	m2m->usage_count++;
524
525	/*
526	 * Allocate resources for the channel, counting how many users require
527	 * buffer chaining.
528	 */
529	if (!ctx->chained && out_pix->width > MXC_ISI_MAX_WIDTH_UNCHAINED) {
530		ret = mxc_isi_channel_chain(m2m->pipe, bypass);
531		if (ret)
532			goto deinit;
533
534		m2m->chained_count++;
535		ctx->chained = true;
536	}
537
538	/*
539	 * Drop the lock to start the stream, as the .device_run() operation
540	 * needs to acquire it.
541	 */
542	mutex_unlock(&m2m->lock);
543	ret = v4l2_m2m_ioctl_streamon(file, fh, type);
544	if (ret) {
545		/* Reacquire the lock for the cleanup path. */
546		mutex_lock(&m2m->lock);
547		goto unchain;
548	}
549
550	return 0;
551
552unchain:
553	if (ctx->chained && --m2m->chained_count == 0)
554		mxc_isi_channel_unchain(m2m->pipe);
555	ctx->chained = false;
556
557deinit:
558	if (--m2m->usage_count == 0) {
559		mxc_isi_channel_put(m2m->pipe);
560		mxc_isi_channel_release(m2m->pipe);
561	}
562
563unlock:
564	mutex_unlock(&m2m->lock);
565	return ret;
566}
567
568static int mxc_isi_m2m_streamoff(struct file *file, void *fh,
569				 enum v4l2_buf_type type)
570{
571	struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
572	struct mxc_isi_m2m *m2m = ctx->m2m;
573
574	v4l2_m2m_ioctl_streamoff(file, fh, type);
575
576	mutex_lock(&m2m->lock);
577
578	/*
579	 * If the last context is this one, reset it to make sure the device
580	 * will be reconfigured when streaming is restarted.
581	 */
582	if (m2m->last_ctx == ctx)
583		m2m->last_ctx = NULL;
584
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;
589
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);
595	}
596
597	WARN_ON(m2m->usage_count < 0);
598
599	mutex_unlock(&m2m->lock);
600
601	return 0;
602}
603
604static const struct v4l2_ioctl_ops mxc_isi_m2m_ioctl_ops = {
605	.vidioc_querycap		= mxc_isi_m2m_querycap,
606
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,
615
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,
623
624	.vidioc_streamon		= mxc_isi_m2m_streamon,
625	.vidioc_streamoff		= mxc_isi_m2m_streamoff,
626
627	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
628	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
629};
630
631/* -----------------------------------------------------------------------------
632 * Video device file operations
633 */
634
635static 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)
638{
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;
642
643	qdata->info = mxc_isi_format_try(ctx->m2m->pipe, &qdata->format, type);
644}
645
646static int mxc_isi_m2m_open(struct file *file)
647{
648	struct video_device *vdev = video_devdata(file);
649	struct mxc_isi_m2m *m2m = video_drvdata(file);
650	struct mxc_isi_m2m_ctx *ctx;
651	int ret;
652
653	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
654	if (!ctx)
655		return -ENOMEM;
656
657	ctx->m2m = m2m;
658	mutex_init(&ctx->vb2_lock);
659
660	v4l2_fh_init(&ctx->fh, vdev);
661	file->private_data = &ctx->fh;
662
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;
668		goto err_fh;
669	}
670
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);
673
674	ret = mxc_isi_m2m_ctx_ctrls_create(ctx);
675	if (ret)
676		goto err_ctx;
677
678	ret = pm_runtime_resume_and_get(m2m->isi->dev);
679	if (ret)
680		goto err_ctrls;
681
682	v4l2_fh_add(&ctx->fh);
683
684	return 0;
685
686err_ctrls:
687	mxc_isi_m2m_ctx_ctrls_delete(ctx);
688err_ctx:
689	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
690err_fh:
691	v4l2_fh_exit(&ctx->fh);
692	mutex_destroy(&ctx->vb2_lock);
693	kfree(ctx);
694	return ret;
695}
696
697static int mxc_isi_m2m_release(struct file *file)
698{
699	struct mxc_isi_m2m *m2m = video_drvdata(file);
700	struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(file->private_data);
701
702	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
703	mxc_isi_m2m_ctx_ctrls_delete(ctx);
704
705	v4l2_fh_del(&ctx->fh);
706	v4l2_fh_exit(&ctx->fh);
707
708	mutex_destroy(&ctx->vb2_lock);
709	kfree(ctx);
710
711	pm_runtime_put(m2m->isi->dev);
712
713	return 0;
714}
715
716static 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,
723};
724
725/* -----------------------------------------------------------------------------
726 * Registration
727 */
728
729int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev)
730{
731	struct mxc_isi_m2m *m2m = &isi->m2m;
732	struct video_device *vdev = &m2m->vdev;
733	struct media_link *link;
734	int ret;
735
736	m2m->isi = isi;
737	m2m->pipe = &isi->pipes[0];
738
739	mutex_init(&m2m->lock);
740
741	/* Initialize the video device and create controls. */
742	snprintf(vdev->name, sizeof(vdev->name), "mxc_isi.m2m");
743
744	vdev->fops	= &mxc_isi_m2m_fops;
745	vdev->ioctl_ops	= &mxc_isi_m2m_ioctl_ops;
746	vdev->v4l2_dev	= v4l2_dev;
747	vdev->minor	= -1;
748	vdev->release	= video_device_release_empty;
749	vdev->vfl_dir	= VFL_DIR_M2M;
750
751	vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
752	video_set_drvdata(vdev, m2m);
753
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);
759		goto err_mutex;
760	}
761
762	/* Register the video device. */
763	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
764	if (ret < 0) {
765		dev_err(isi->dev, "failed to register m2m device\n");
766		goto err_m2m;
767	}
768
769	/*
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:
774	 *
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.
778	 *
779	 * - The video device at the end of the pipeline provides the sink
780	 *   entity, and is already wired up in the graph.
781	 *
782	 * - A new interface is created, pointing at both entities. The sink
783	 *   entity will thus have two interfaces pointing to it.
784	 */
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);
789	if (ret)
790		goto err_video;
791
792	ret = media_device_register_entity(v4l2_dev->mdev, &vdev->entity);
793	if (ret)
794		goto err_entity_cleanup;
795
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);
801	if (ret)
802		goto err_entity_unreg;
803
804	m2m->intf = media_devnode_create(v4l2_dev->mdev, MEDIA_INTF_T_V4L_VIDEO,
805					 0, VIDEO_MAJOR, vdev->minor);
806	if (!m2m->intf) {
807		ret = -ENOMEM;
808		goto err_entity_unreg;
809	}
810
811	link = media_create_intf_link(&vdev->entity, &m2m->intf->intf,
812				      MEDIA_LNK_FL_IMMUTABLE |
813				      MEDIA_LNK_FL_ENABLED);
814	if (!link) {
815		ret = -ENOMEM;
816		goto err_devnode;
817	}
818
819	link = media_create_intf_link(&m2m->pipe->video.vdev.entity,
820				      &m2m->intf->intf,
821				      MEDIA_LNK_FL_IMMUTABLE |
822				      MEDIA_LNK_FL_ENABLED);
823	if (!link) {
824		ret = -ENOMEM;
825		goto err_devnode;
826	}
827
828	return 0;
829
830err_devnode:
831	media_devnode_remove(m2m->intf);
832err_entity_unreg:
833	media_device_unregister_entity(&vdev->entity);
834err_entity_cleanup:
835	media_entity_cleanup(&vdev->entity);
836err_video:
837	video_unregister_device(vdev);
838err_m2m:
839	v4l2_m2m_release(m2m->m2m_dev);
840err_mutex:
841	mutex_destroy(&m2m->lock);
842	return ret;
843}
844
845int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi)
846{
847	struct mxc_isi_m2m *m2m = &isi->m2m;
848	struct video_device *vdev = &m2m->vdev;
849
850	video_unregister_device(vdev);
851
852	v4l2_m2m_release(m2m->m2m_dev);
853	media_devnode_remove(m2m->intf);
854	media_entity_cleanup(&vdev->entity);
855	mutex_destroy(&m2m->lock);
856
857	return 0;
858}
859