xref: /openbmc/linux/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c (revision af9b2ff010f593d81e2f5fb04155e9fc25b9dfd0)
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 
37 struct mxc_isi_m2m_buffer {
38 	struct v4l2_m2m_buffer buf;
39 	dma_addr_t dma_addrs[3];
40 };
41 
42 struct 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 	bool streaming;
47 };
48 
49 struct mxc_isi_m2m_ctx {
50 	struct v4l2_fh fh;
51 	struct mxc_isi_m2m *m2m;
52 
53 	/* Protects the m2m vb2 queues */
54 	struct mutex vb2_lock;
55 
56 	struct {
57 		struct mxc_isi_m2m_ctx_queue_data out;
58 		struct mxc_isi_m2m_ctx_queue_data cap;
59 	} queues;
60 
61 	struct {
62 		struct v4l2_ctrl_handler handler;
63 		unsigned int alpha;
64 		bool hflip;
65 		bool vflip;
66 	} ctrls;
67 
68 	bool chained;
69 };
70 
71 static inline struct mxc_isi_m2m_buffer *
to_isi_m2m_buffer(struct vb2_v4l2_buffer * buf)72 to_isi_m2m_buffer(struct vb2_v4l2_buffer *buf)
73 {
74 	return container_of(buf, struct mxc_isi_m2m_buffer, buf.vb);
75 }
76 
to_isi_m2m_ctx(struct v4l2_fh * fh)77 static inline struct mxc_isi_m2m_ctx *to_isi_m2m_ctx(struct v4l2_fh *fh)
78 {
79 	return container_of(fh, struct mxc_isi_m2m_ctx, fh);
80 }
81 
82 static inline struct mxc_isi_m2m_ctx_queue_data *
mxc_isi_m2m_ctx_qdata(struct mxc_isi_m2m_ctx * ctx,enum v4l2_buf_type type)83 mxc_isi_m2m_ctx_qdata(struct mxc_isi_m2m_ctx *ctx, enum v4l2_buf_type type)
84 {
85 	if (V4L2_TYPE_IS_OUTPUT(type))
86 		return &ctx->queues.out;
87 	else
88 		return &ctx->queues.cap;
89 }
90 
91 /* -----------------------------------------------------------------------------
92  * V4L2 M2M device operations
93  */
94 
mxc_isi_m2m_frame_write_done(struct mxc_isi_pipe * pipe,u32 status)95 static void mxc_isi_m2m_frame_write_done(struct mxc_isi_pipe *pipe, u32 status)
96 {
97 	struct mxc_isi_m2m *m2m = &pipe->isi->m2m;
98 	struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
99 	struct mxc_isi_m2m_ctx *ctx;
100 
101 	ctx = v4l2_m2m_get_curr_priv(m2m->m2m_dev);
102 	if (!ctx) {
103 		dev_err(m2m->isi->dev,
104 			"Instance released before the end of transaction\n");
105 		return;
106 	}
107 
108 	src_vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
109 	dst_vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
110 
111 	v4l2_m2m_buf_copy_metadata(src_vbuf, dst_vbuf, false);
112 
113 	src_vbuf->sequence = ctx->queues.out.sequence++;
114 	dst_vbuf->sequence = ctx->queues.cap.sequence++;
115 
116 	v4l2_m2m_buf_done(src_vbuf, VB2_BUF_STATE_DONE);
117 	v4l2_m2m_buf_done(dst_vbuf, VB2_BUF_STATE_DONE);
118 
119 	v4l2_m2m_job_finish(m2m->m2m_dev, ctx->fh.m2m_ctx);
120 }
121 
mxc_isi_m2m_device_run(void * priv)122 static void mxc_isi_m2m_device_run(void *priv)
123 {
124 	struct mxc_isi_m2m_ctx *ctx = priv;
125 	struct mxc_isi_m2m *m2m = ctx->m2m;
126 	struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf;
127 	struct mxc_isi_m2m_buffer *src_buf, *dst_buf;
128 
129 	mxc_isi_channel_disable(m2m->pipe);
130 
131 	mutex_lock(&m2m->lock);
132 
133 	/* If the context has changed, reconfigure the channel. */
134 	if (m2m->last_ctx != ctx) {
135 		const struct v4l2_area in_size = {
136 			.width = ctx->queues.out.format.width,
137 			.height = ctx->queues.out.format.height,
138 		};
139 		const struct v4l2_area scale = {
140 			.width = ctx->queues.cap.format.width,
141 			.height = ctx->queues.cap.format.height,
142 		};
143 		const struct v4l2_rect crop = {
144 			.width = ctx->queues.cap.format.width,
145 			.height = ctx->queues.cap.format.height,
146 		};
147 
148 		mxc_isi_channel_config(m2m->pipe, MXC_ISI_INPUT_MEM,
149 				       &in_size, &scale, &crop,
150 				       ctx->queues.out.info->encoding,
151 				       ctx->queues.cap.info->encoding);
152 		mxc_isi_channel_set_input_format(m2m->pipe,
153 						 ctx->queues.out.info,
154 						 &ctx->queues.out.format);
155 		mxc_isi_channel_set_output_format(m2m->pipe,
156 						  ctx->queues.cap.info,
157 						  &ctx->queues.cap.format);
158 
159 		m2m->last_ctx = ctx;
160 	}
161 
162 	mutex_unlock(&m2m->lock);
163 
164 	mutex_lock(ctx->ctrls.handler.lock);
165 	mxc_isi_channel_set_alpha(m2m->pipe, ctx->ctrls.alpha);
166 	mxc_isi_channel_set_flip(m2m->pipe, ctx->ctrls.hflip, ctx->ctrls.vflip);
167 	mutex_unlock(ctx->ctrls.handler.lock);
168 
169 	src_vbuf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
170 	dst_vbuf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
171 
172 	src_buf = to_isi_m2m_buffer(src_vbuf);
173 	dst_buf = to_isi_m2m_buffer(dst_vbuf);
174 
175 	mxc_isi_channel_set_inbuf(m2m->pipe, src_buf->dma_addrs[0]);
176 	mxc_isi_channel_set_outbuf(m2m->pipe, dst_buf->dma_addrs, MXC_ISI_BUF1);
177 	mxc_isi_channel_set_outbuf(m2m->pipe, dst_buf->dma_addrs, MXC_ISI_BUF2);
178 
179 	mxc_isi_channel_enable(m2m->pipe);
180 
181 	mxc_isi_channel_m2m_start(m2m->pipe);
182 }
183 
184 static const struct v4l2_m2m_ops mxc_isi_m2m_ops = {
185 	.device_run = mxc_isi_m2m_device_run,
186 };
187 
188 /* -----------------------------------------------------------------------------
189  * videobuf2 queue operations
190  */
191 
mxc_isi_m2m_vb2_queue_setup(struct vb2_queue * q,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])192 static int mxc_isi_m2m_vb2_queue_setup(struct vb2_queue *q,
193 				       unsigned int *num_buffers,
194 				       unsigned int *num_planes,
195 				       unsigned int sizes[],
196 				       struct device *alloc_devs[])
197 {
198 	struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q);
199 	const struct mxc_isi_m2m_ctx_queue_data *qdata =
200 		mxc_isi_m2m_ctx_qdata(ctx, q->type);
201 
202 	return mxc_isi_video_queue_setup(&qdata->format, qdata->info,
203 					 num_buffers, num_planes, sizes);
204 }
205 
mxc_isi_m2m_vb2_buffer_init(struct vb2_buffer * vb2)206 static int mxc_isi_m2m_vb2_buffer_init(struct vb2_buffer *vb2)
207 {
208 	struct vb2_queue *vq = vb2->vb2_queue;
209 	struct mxc_isi_m2m_buffer *buf = to_isi_m2m_buffer(to_vb2_v4l2_buffer(vb2));
210 	struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(vb2->vb2_queue);
211 	const struct mxc_isi_m2m_ctx_queue_data *qdata =
212 		mxc_isi_m2m_ctx_qdata(ctx, vq->type);
213 
214 	mxc_isi_video_buffer_init(vb2, buf->dma_addrs, qdata->info,
215 				  &qdata->format);
216 
217 	return 0;
218 }
219 
mxc_isi_m2m_vb2_buffer_prepare(struct vb2_buffer * vb2)220 static int mxc_isi_m2m_vb2_buffer_prepare(struct vb2_buffer *vb2)
221 {
222 	struct vb2_queue *vq = vb2->vb2_queue;
223 	struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(vq);
224 	const struct mxc_isi_m2m_ctx_queue_data *qdata =
225 		mxc_isi_m2m_ctx_qdata(ctx, vq->type);
226 
227 	return mxc_isi_video_buffer_prepare(ctx->m2m->isi, vb2, qdata->info,
228 					    &qdata->format);
229 }
230 
mxc_isi_m2m_vb2_buffer_queue(struct vb2_buffer * vb2)231 static void mxc_isi_m2m_vb2_buffer_queue(struct vb2_buffer *vb2)
232 {
233 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb2);
234 	struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(vb2->vb2_queue);
235 
236 	v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
237 }
238 
mxc_isi_m2m_vb2_start_streaming(struct vb2_queue * q,unsigned int count)239 static int mxc_isi_m2m_vb2_start_streaming(struct vb2_queue *q,
240 					   unsigned int count)
241 {
242 	struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q);
243 	struct mxc_isi_m2m_ctx_queue_data *qdata =
244 		mxc_isi_m2m_ctx_qdata(ctx, q->type);
245 
246 	qdata->sequence = 0;
247 
248 	return 0;
249 }
250 
mxc_isi_m2m_vb2_stop_streaming(struct vb2_queue * q)251 static void mxc_isi_m2m_vb2_stop_streaming(struct vb2_queue *q)
252 {
253 	struct mxc_isi_m2m_ctx *ctx = vb2_get_drv_priv(q);
254 	struct vb2_v4l2_buffer *vbuf;
255 
256 	for (;;) {
257 		if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
258 			vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
259 		else
260 			vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
261 		if (!vbuf)
262 			break;
263 
264 		v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR);
265 	}
266 }
267 
268 static const struct vb2_ops mxc_isi_m2m_vb2_qops = {
269 	.queue_setup		= mxc_isi_m2m_vb2_queue_setup,
270 	.buf_init		= mxc_isi_m2m_vb2_buffer_init,
271 	.buf_prepare		= mxc_isi_m2m_vb2_buffer_prepare,
272 	.buf_queue		= mxc_isi_m2m_vb2_buffer_queue,
273 	.wait_prepare		= vb2_ops_wait_prepare,
274 	.wait_finish		= vb2_ops_wait_finish,
275 	.start_streaming	= mxc_isi_m2m_vb2_start_streaming,
276 	.stop_streaming		= mxc_isi_m2m_vb2_stop_streaming,
277 };
278 
mxc_isi_m2m_queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)279 static int mxc_isi_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
280 				  struct vb2_queue *dst_vq)
281 {
282 	struct mxc_isi_m2m_ctx *ctx = priv;
283 	struct mxc_isi_m2m *m2m = ctx->m2m;
284 	int ret;
285 
286 	src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
287 	src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
288 	src_vq->drv_priv = ctx;
289 	src_vq->buf_struct_size = sizeof(struct mxc_isi_m2m_buffer);
290 	src_vq->ops = &mxc_isi_m2m_vb2_qops;
291 	src_vq->mem_ops = &vb2_dma_contig_memops;
292 	src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
293 	src_vq->lock = &ctx->vb2_lock;
294 	src_vq->dev = m2m->isi->dev;
295 
296 	ret = vb2_queue_init(src_vq);
297 	if (ret)
298 		return ret;
299 
300 	dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
301 	dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
302 	dst_vq->drv_priv = ctx;
303 	dst_vq->buf_struct_size = sizeof(struct mxc_isi_m2m_buffer);
304 	dst_vq->ops = &mxc_isi_m2m_vb2_qops;
305 	dst_vq->mem_ops = &vb2_dma_contig_memops;
306 	dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
307 	dst_vq->lock = &ctx->vb2_lock;
308 	dst_vq->dev = m2m->isi->dev;
309 
310 	return vb2_queue_init(dst_vq);
311 }
312 
313 /* -----------------------------------------------------------------------------
314  * V4L2 controls
315  */
316 
317 static inline struct mxc_isi_m2m_ctx *
ctrl_to_mxc_isi_m2m_ctx(struct v4l2_ctrl * ctrl)318 ctrl_to_mxc_isi_m2m_ctx(struct v4l2_ctrl *ctrl)
319 {
320 	return container_of(ctrl->handler, struct mxc_isi_m2m_ctx, ctrls.handler);
321 }
322 
mxc_isi_m2m_ctx_s_ctrl(struct v4l2_ctrl * ctrl)323 static int mxc_isi_m2m_ctx_s_ctrl(struct v4l2_ctrl *ctrl)
324 {
325 	struct mxc_isi_m2m_ctx *ctx = ctrl_to_mxc_isi_m2m_ctx(ctrl);
326 
327 	switch (ctrl->id) {
328 	case V4L2_CID_HFLIP:
329 		ctx->ctrls.hflip = ctrl->val;
330 		break;
331 
332 	case V4L2_CID_VFLIP:
333 		ctx->ctrls.vflip = ctrl->val;
334 		break;
335 
336 	case V4L2_CID_ALPHA_COMPONENT:
337 		ctx->ctrls.alpha = ctrl->val;
338 		break;
339 	}
340 
341 	return 0;
342 }
343 
344 static const struct v4l2_ctrl_ops mxc_isi_m2m_ctx_ctrl_ops = {
345 	.s_ctrl = mxc_isi_m2m_ctx_s_ctrl,
346 };
347 
mxc_isi_m2m_ctx_ctrls_create(struct mxc_isi_m2m_ctx * ctx)348 static int mxc_isi_m2m_ctx_ctrls_create(struct mxc_isi_m2m_ctx *ctx)
349 {
350 	struct v4l2_ctrl_handler *handler = &ctx->ctrls.handler;
351 	int ret;
352 
353 	v4l2_ctrl_handler_init(handler, 3);
354 
355 	v4l2_ctrl_new_std(handler, &mxc_isi_m2m_ctx_ctrl_ops,
356 			  V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0);
357 	v4l2_ctrl_new_std(handler, &mxc_isi_m2m_ctx_ctrl_ops,
358 			  V4L2_CID_HFLIP, 0, 1, 1, 0);
359 	v4l2_ctrl_new_std(handler, &mxc_isi_m2m_ctx_ctrl_ops,
360 			  V4L2_CID_VFLIP, 0, 1, 1, 0);
361 
362 	if (handler->error) {
363 		ret = handler->error;
364 		v4l2_ctrl_handler_free(handler);
365 		return ret;
366 	}
367 
368 	ctx->fh.ctrl_handler = handler;
369 
370 	return 0;
371 }
372 
mxc_isi_m2m_ctx_ctrls_delete(struct mxc_isi_m2m_ctx * ctx)373 static void mxc_isi_m2m_ctx_ctrls_delete(struct mxc_isi_m2m_ctx *ctx)
374 {
375 	v4l2_ctrl_handler_free(&ctx->ctrls.handler);
376 }
377 
378 /* -----------------------------------------------------------------------------
379  * V4L2 ioctls
380  */
381 
mxc_isi_m2m_querycap(struct file * file,void * fh,struct v4l2_capability * cap)382 static int mxc_isi_m2m_querycap(struct file *file, void *fh,
383 				struct v4l2_capability *cap)
384 {
385 	strscpy(cap->driver, MXC_ISI_DRIVER_NAME, sizeof(cap->driver));
386 	strscpy(cap->card, MXC_ISI_M2M, sizeof(cap->card));
387 	cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
388 	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
389 
390 	return 0;
391 }
392 
mxc_isi_m2m_enum_fmt_vid(struct file * file,void * fh,struct v4l2_fmtdesc * f)393 static int mxc_isi_m2m_enum_fmt_vid(struct file *file, void *fh,
394 				    struct v4l2_fmtdesc *f)
395 {
396 	const enum mxc_isi_video_type type =
397 		f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
398 		MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP;
399 	const struct mxc_isi_format_info *info;
400 
401 	info = mxc_isi_format_enum(f->index, type);
402 	if (!info)
403 		return -EINVAL;
404 
405 	f->pixelformat = info->fourcc;
406 	f->flags |= V4L2_FMT_FLAG_CSC_COLORSPACE | V4L2_FMT_FLAG_CSC_YCBCR_ENC
407 		 |  V4L2_FMT_FLAG_CSC_QUANTIZATION | V4L2_FMT_FLAG_CSC_XFER_FUNC;
408 
409 	return 0;
410 }
411 
412 static const struct mxc_isi_format_info *
__mxc_isi_m2m_try_fmt_vid(struct mxc_isi_m2m_ctx * ctx,struct v4l2_pix_format_mplane * pix,const enum mxc_isi_video_type type)413 __mxc_isi_m2m_try_fmt_vid(struct mxc_isi_m2m_ctx *ctx,
414 			  struct v4l2_pix_format_mplane *pix,
415 			  const enum mxc_isi_video_type type)
416 {
417 	if (type == MXC_ISI_VIDEO_M2M_CAP) {
418 		/* Downscaling only  */
419 		pix->width = min(pix->width, ctx->queues.out.format.width);
420 		pix->height = min(pix->height, ctx->queues.out.format.height);
421 	}
422 
423 	return mxc_isi_format_try(ctx->m2m->pipe, pix, type);
424 }
425 
mxc_isi_m2m_try_fmt_vid(struct file * file,void * fh,struct v4l2_format * f)426 static int mxc_isi_m2m_try_fmt_vid(struct file *file, void *fh,
427 				   struct v4l2_format *f)
428 {
429 	const enum mxc_isi_video_type type =
430 		f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
431 		MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP;
432 	struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
433 
434 	__mxc_isi_m2m_try_fmt_vid(ctx, &f->fmt.pix_mp, type);
435 
436 	return 0;
437 }
438 
mxc_isi_m2m_g_fmt_vid(struct file * file,void * fh,struct v4l2_format * f)439 static int mxc_isi_m2m_g_fmt_vid(struct file *file, void *fh,
440 				 struct v4l2_format *f)
441 {
442 	struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
443 	const struct mxc_isi_m2m_ctx_queue_data *qdata =
444 		mxc_isi_m2m_ctx_qdata(ctx, f->type);
445 
446 	f->fmt.pix_mp = qdata->format;
447 
448 	return 0;
449 }
450 
mxc_isi_m2m_s_fmt_vid(struct file * file,void * fh,struct v4l2_format * f)451 static int mxc_isi_m2m_s_fmt_vid(struct file *file, void *fh,
452 				 struct v4l2_format *f)
453 {
454 	const enum mxc_isi_video_type type =
455 		f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE ?
456 		MXC_ISI_VIDEO_M2M_OUT : MXC_ISI_VIDEO_M2M_CAP;
457 	struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
458 	struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
459 	const struct mxc_isi_format_info *info;
460 	struct vb2_queue *vq;
461 
462 	vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
463 	if (!vq)
464 		return -EINVAL;
465 
466 	if (vb2_is_busy(vq))
467 		return -EBUSY;
468 
469 	info = __mxc_isi_m2m_try_fmt_vid(ctx, pix, type);
470 
471 	if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
472 		ctx->queues.out.format = *pix;
473 		ctx->queues.out.info = info;
474 	}
475 
476 	/*
477 	 * Always set the format on the capture side, due to either format
478 	 * propagation or direct setting.
479 	 */
480 	ctx->queues.cap.format = *pix;
481 	ctx->queues.cap.info = info;
482 
483 	return 0;
484 }
485 
mxc_isi_m2m_streamon(struct file * file,void * fh,enum v4l2_buf_type type)486 static int mxc_isi_m2m_streamon(struct file *file, void *fh,
487 				enum v4l2_buf_type type)
488 {
489 	struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
490 	struct mxc_isi_m2m_ctx_queue_data *q = mxc_isi_m2m_ctx_qdata(ctx, type);
491 	const struct v4l2_pix_format_mplane *out_pix = &ctx->queues.out.format;
492 	const struct v4l2_pix_format_mplane *cap_pix = &ctx->queues.cap.format;
493 	const struct mxc_isi_format_info *cap_info = ctx->queues.cap.info;
494 	const struct mxc_isi_format_info *out_info = ctx->queues.out.info;
495 	struct mxc_isi_m2m *m2m = ctx->m2m;
496 	bool bypass;
497 	int ret;
498 
499 	if (q->streaming)
500 		return 0;
501 
502 	mutex_lock(&m2m->lock);
503 
504 	if (m2m->usage_count == INT_MAX) {
505 		ret = -EOVERFLOW;
506 		goto unlock;
507 	}
508 
509 	bypass = cap_pix->width == out_pix->width &&
510 		 cap_pix->height == out_pix->height &&
511 		 cap_info->encoding == out_info->encoding;
512 
513 	/*
514 	 * Acquire the pipe and initialize the channel with the first user of
515 	 * the M2M device.
516 	 */
517 	if (m2m->usage_count == 0) {
518 		ret = mxc_isi_channel_acquire(m2m->pipe,
519 					      &mxc_isi_m2m_frame_write_done,
520 					      bypass);
521 		if (ret)
522 			goto unlock;
523 
524 		mxc_isi_channel_get(m2m->pipe);
525 	}
526 
527 	m2m->usage_count++;
528 
529 	/*
530 	 * Allocate resources for the channel, counting how many users require
531 	 * buffer chaining.
532 	 */
533 	if (!ctx->chained && out_pix->width > MXC_ISI_MAX_WIDTH_UNCHAINED) {
534 		ret = mxc_isi_channel_chain(m2m->pipe, bypass);
535 		if (ret)
536 			goto deinit;
537 
538 		m2m->chained_count++;
539 		ctx->chained = true;
540 	}
541 
542 	/*
543 	 * Drop the lock to start the stream, as the .device_run() operation
544 	 * needs to acquire it.
545 	 */
546 	mutex_unlock(&m2m->lock);
547 	ret = v4l2_m2m_ioctl_streamon(file, fh, type);
548 	if (ret) {
549 		/* Reacquire the lock for the cleanup path. */
550 		mutex_lock(&m2m->lock);
551 		goto unchain;
552 	}
553 
554 	q->streaming = true;
555 
556 	return 0;
557 
558 unchain:
559 	if (ctx->chained && --m2m->chained_count == 0)
560 		mxc_isi_channel_unchain(m2m->pipe);
561 	ctx->chained = false;
562 
563 deinit:
564 	if (--m2m->usage_count == 0) {
565 		mxc_isi_channel_put(m2m->pipe);
566 		mxc_isi_channel_release(m2m->pipe);
567 	}
568 
569 unlock:
570 	mutex_unlock(&m2m->lock);
571 	return ret;
572 }
573 
mxc_isi_m2m_streamoff(struct file * file,void * fh,enum v4l2_buf_type type)574 static int mxc_isi_m2m_streamoff(struct file *file, void *fh,
575 				 enum v4l2_buf_type type)
576 {
577 	struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(fh);
578 	struct mxc_isi_m2m_ctx_queue_data *q = mxc_isi_m2m_ctx_qdata(ctx, type);
579 	struct mxc_isi_m2m *m2m = ctx->m2m;
580 
581 	v4l2_m2m_ioctl_streamoff(file, fh, type);
582 
583 	if (!q->streaming)
584 		return 0;
585 
586 	mutex_lock(&m2m->lock);
587 
588 	/*
589 	 * If the last context is this one, reset it to make sure the device
590 	 * will be reconfigured when streaming is restarted.
591 	 */
592 	if (m2m->last_ctx == ctx)
593 		m2m->last_ctx = NULL;
594 
595 	/* Free the channel resources if this is the last chained context. */
596 	if (ctx->chained && --m2m->chained_count == 0)
597 		mxc_isi_channel_unchain(m2m->pipe);
598 	ctx->chained = false;
599 
600 	/* Turn off the light with the last user. */
601 	if (--m2m->usage_count == 0) {
602 		mxc_isi_channel_disable(m2m->pipe);
603 		mxc_isi_channel_put(m2m->pipe);
604 		mxc_isi_channel_release(m2m->pipe);
605 	}
606 
607 	WARN_ON(m2m->usage_count < 0);
608 
609 	mutex_unlock(&m2m->lock);
610 
611 	q->streaming = false;
612 
613 	return 0;
614 }
615 
616 static const struct v4l2_ioctl_ops mxc_isi_m2m_ioctl_ops = {
617 	.vidioc_querycap		= mxc_isi_m2m_querycap,
618 
619 	.vidioc_enum_fmt_vid_cap	= mxc_isi_m2m_enum_fmt_vid,
620 	.vidioc_enum_fmt_vid_out	= mxc_isi_m2m_enum_fmt_vid,
621 	.vidioc_g_fmt_vid_cap_mplane	= mxc_isi_m2m_g_fmt_vid,
622 	.vidioc_g_fmt_vid_out_mplane	= mxc_isi_m2m_g_fmt_vid,
623 	.vidioc_s_fmt_vid_cap_mplane	= mxc_isi_m2m_s_fmt_vid,
624 	.vidioc_s_fmt_vid_out_mplane	= mxc_isi_m2m_s_fmt_vid,
625 	.vidioc_try_fmt_vid_cap_mplane	= mxc_isi_m2m_try_fmt_vid,
626 	.vidioc_try_fmt_vid_out_mplane	= mxc_isi_m2m_try_fmt_vid,
627 
628 	.vidioc_reqbufs			= v4l2_m2m_ioctl_reqbufs,
629 	.vidioc_querybuf		= v4l2_m2m_ioctl_querybuf,
630 	.vidioc_qbuf			= v4l2_m2m_ioctl_qbuf,
631 	.vidioc_dqbuf			= v4l2_m2m_ioctl_dqbuf,
632 	.vidioc_expbuf			= v4l2_m2m_ioctl_expbuf,
633 	.vidioc_prepare_buf		= v4l2_m2m_ioctl_prepare_buf,
634 	.vidioc_create_bufs		= v4l2_m2m_ioctl_create_bufs,
635 
636 	.vidioc_streamon		= mxc_isi_m2m_streamon,
637 	.vidioc_streamoff		= mxc_isi_m2m_streamoff,
638 
639 	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
640 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
641 };
642 
643 /* -----------------------------------------------------------------------------
644  * Video device file operations
645  */
646 
mxc_isi_m2m_init_format(struct mxc_isi_m2m_ctx * ctx,struct mxc_isi_m2m_ctx_queue_data * qdata,enum mxc_isi_video_type type)647 static void mxc_isi_m2m_init_format(struct mxc_isi_m2m_ctx *ctx,
648 				    struct mxc_isi_m2m_ctx_queue_data *qdata,
649 				    enum mxc_isi_video_type type)
650 {
651 	qdata->format.width = MXC_ISI_DEF_WIDTH;
652 	qdata->format.height = MXC_ISI_DEF_HEIGHT;
653 	qdata->format.pixelformat = MXC_ISI_DEF_PIXEL_FORMAT;
654 
655 	qdata->info = mxc_isi_format_try(ctx->m2m->pipe, &qdata->format, type);
656 }
657 
mxc_isi_m2m_open(struct file * file)658 static int mxc_isi_m2m_open(struct file *file)
659 {
660 	struct video_device *vdev = video_devdata(file);
661 	struct mxc_isi_m2m *m2m = video_drvdata(file);
662 	struct mxc_isi_m2m_ctx *ctx;
663 	int ret;
664 
665 	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
666 	if (!ctx)
667 		return -ENOMEM;
668 
669 	ctx->m2m = m2m;
670 	mutex_init(&ctx->vb2_lock);
671 
672 	v4l2_fh_init(&ctx->fh, vdev);
673 	file->private_data = &ctx->fh;
674 
675 	ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(m2m->m2m_dev, ctx,
676 					    &mxc_isi_m2m_queue_init);
677 	if (IS_ERR(ctx->fh.m2m_ctx)) {
678 		ret = PTR_ERR(ctx->fh.m2m_ctx);
679 		ctx->fh.m2m_ctx = NULL;
680 		goto err_fh;
681 	}
682 
683 	mxc_isi_m2m_init_format(ctx, &ctx->queues.out, MXC_ISI_VIDEO_M2M_OUT);
684 	mxc_isi_m2m_init_format(ctx, &ctx->queues.cap, MXC_ISI_VIDEO_M2M_CAP);
685 
686 	ret = mxc_isi_m2m_ctx_ctrls_create(ctx);
687 	if (ret)
688 		goto err_ctx;
689 
690 	ret = pm_runtime_resume_and_get(m2m->isi->dev);
691 	if (ret)
692 		goto err_ctrls;
693 
694 	v4l2_fh_add(&ctx->fh);
695 
696 	return 0;
697 
698 err_ctrls:
699 	mxc_isi_m2m_ctx_ctrls_delete(ctx);
700 err_ctx:
701 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
702 err_fh:
703 	v4l2_fh_exit(&ctx->fh);
704 	mutex_destroy(&ctx->vb2_lock);
705 	kfree(ctx);
706 	return ret;
707 }
708 
mxc_isi_m2m_release(struct file * file)709 static int mxc_isi_m2m_release(struct file *file)
710 {
711 	struct mxc_isi_m2m *m2m = video_drvdata(file);
712 	struct mxc_isi_m2m_ctx *ctx = to_isi_m2m_ctx(file->private_data);
713 
714 	v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
715 	mxc_isi_m2m_ctx_ctrls_delete(ctx);
716 
717 	v4l2_fh_del(&ctx->fh);
718 	v4l2_fh_exit(&ctx->fh);
719 
720 	mutex_destroy(&ctx->vb2_lock);
721 	kfree(ctx);
722 
723 	pm_runtime_put(m2m->isi->dev);
724 
725 	return 0;
726 }
727 
728 static const struct v4l2_file_operations mxc_isi_m2m_fops = {
729 	.owner		= THIS_MODULE,
730 	.open		= mxc_isi_m2m_open,
731 	.release	= mxc_isi_m2m_release,
732 	.poll		= v4l2_m2m_fop_poll,
733 	.unlocked_ioctl	= video_ioctl2,
734 	.mmap		= v4l2_m2m_fop_mmap,
735 };
736 
737 /* -----------------------------------------------------------------------------
738  * Registration
739  */
740 
mxc_isi_m2m_register(struct mxc_isi_dev * isi,struct v4l2_device * v4l2_dev)741 int mxc_isi_m2m_register(struct mxc_isi_dev *isi, struct v4l2_device *v4l2_dev)
742 {
743 	struct mxc_isi_m2m *m2m = &isi->m2m;
744 	struct video_device *vdev = &m2m->vdev;
745 	struct media_link *link;
746 	int ret;
747 
748 	m2m->isi = isi;
749 	m2m->pipe = &isi->pipes[0];
750 
751 	mutex_init(&m2m->lock);
752 
753 	/* Initialize the video device and create controls. */
754 	snprintf(vdev->name, sizeof(vdev->name), "mxc_isi.m2m");
755 
756 	vdev->fops	= &mxc_isi_m2m_fops;
757 	vdev->ioctl_ops	= &mxc_isi_m2m_ioctl_ops;
758 	vdev->v4l2_dev	= v4l2_dev;
759 	vdev->minor	= -1;
760 	vdev->release	= video_device_release_empty;
761 	vdev->vfl_dir	= VFL_DIR_M2M;
762 
763 	vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE;
764 	video_set_drvdata(vdev, m2m);
765 
766 	/* Create the M2M device. */
767 	m2m->m2m_dev = v4l2_m2m_init(&mxc_isi_m2m_ops);
768 	if (IS_ERR(m2m->m2m_dev)) {
769 		dev_err(isi->dev, "failed to initialize m2m device\n");
770 		ret = PTR_ERR(m2m->m2m_dev);
771 		goto err_mutex;
772 	}
773 
774 	/* Register the video device. */
775 	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
776 	if (ret < 0) {
777 		dev_err(isi->dev, "failed to register m2m device\n");
778 		goto err_m2m;
779 	}
780 
781 	/*
782 	 * Populate the media graph. We can't use the mem2mem helper
783 	 * v4l2_m2m_register_media_controller() as the M2M interface needs to
784 	 * be connected to the existing entities in the graph, so we have to
785 	 * wire things up manually:
786 	 *
787 	 * - The entity in the video_device, which isn't touched by the V4L2
788 	 *   core for M2M devices, is used as the source I/O entity in the
789 	 *   graph, connected to the crossbar switch.
790 	 *
791 	 * - The video device at the end of the pipeline provides the sink
792 	 *   entity, and is already wired up in the graph.
793 	 *
794 	 * - A new interface is created, pointing at both entities. The sink
795 	 *   entity will thus have two interfaces pointing to it.
796 	 */
797 	m2m->pad.flags = MEDIA_PAD_FL_SOURCE;
798 	vdev->entity.name = "mxc_isi.output";
799 	vdev->entity.function = MEDIA_ENT_F_IO_V4L;
800 	ret = media_entity_pads_init(&vdev->entity, 1, &m2m->pad);
801 	if (ret)
802 		goto err_video;
803 
804 	ret = media_device_register_entity(v4l2_dev->mdev, &vdev->entity);
805 	if (ret)
806 		goto err_entity_cleanup;
807 
808 	ret = media_create_pad_link(&vdev->entity, 0,
809 				    &m2m->isi->crossbar.sd.entity,
810 				    m2m->isi->crossbar.num_sinks - 1,
811 				    MEDIA_LNK_FL_IMMUTABLE |
812 				    MEDIA_LNK_FL_ENABLED);
813 	if (ret)
814 		goto err_entity_unreg;
815 
816 	m2m->intf = media_devnode_create(v4l2_dev->mdev, MEDIA_INTF_T_V4L_VIDEO,
817 					 0, VIDEO_MAJOR, vdev->minor);
818 	if (!m2m->intf) {
819 		ret = -ENOMEM;
820 		goto err_entity_unreg;
821 	}
822 
823 	link = media_create_intf_link(&vdev->entity, &m2m->intf->intf,
824 				      MEDIA_LNK_FL_IMMUTABLE |
825 				      MEDIA_LNK_FL_ENABLED);
826 	if (!link) {
827 		ret = -ENOMEM;
828 		goto err_devnode;
829 	}
830 
831 	link = media_create_intf_link(&m2m->pipe->video.vdev.entity,
832 				      &m2m->intf->intf,
833 				      MEDIA_LNK_FL_IMMUTABLE |
834 				      MEDIA_LNK_FL_ENABLED);
835 	if (!link) {
836 		ret = -ENOMEM;
837 		goto err_devnode;
838 	}
839 
840 	return 0;
841 
842 err_devnode:
843 	media_devnode_remove(m2m->intf);
844 err_entity_unreg:
845 	media_device_unregister_entity(&vdev->entity);
846 err_entity_cleanup:
847 	media_entity_cleanup(&vdev->entity);
848 err_video:
849 	video_unregister_device(vdev);
850 err_m2m:
851 	v4l2_m2m_release(m2m->m2m_dev);
852 err_mutex:
853 	mutex_destroy(&m2m->lock);
854 	return ret;
855 }
856 
mxc_isi_m2m_unregister(struct mxc_isi_dev * isi)857 int mxc_isi_m2m_unregister(struct mxc_isi_dev *isi)
858 {
859 	struct mxc_isi_m2m *m2m = &isi->m2m;
860 	struct video_device *vdev = &m2m->vdev;
861 
862 	video_unregister_device(vdev);
863 
864 	v4l2_m2m_release(m2m->m2m_dev);
865 	media_devnode_remove(m2m->intf);
866 	media_entity_cleanup(&vdev->entity);
867 	mutex_destroy(&m2m->lock);
868 
869 	return 0;
870 }
871