• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
4  * All rights reserved.
5  * Author: Yong Deng <yong.deng@magewell.com>
6  */
7 
8 #include <linux/of.h>
9 
10 #include <media/v4l2-device.h>
11 #include <media/v4l2-event.h>
12 #include <media/v4l2-ioctl.h>
13 #include <media/v4l2-mc.h>
14 #include <media/videobuf2-dma-contig.h>
15 #include <media/videobuf2-v4l2.h>
16 
17 #include "sun6i_csi.h"
18 #include "sun6i_video.h"
19 
20 /* This is got from BSP sources. */
21 #define MIN_WIDTH	(32)
22 #define MIN_HEIGHT	(32)
23 #define MAX_WIDTH	(4800)
24 #define MAX_HEIGHT	(4800)
25 
26 struct sun6i_csi_buffer {
27 	struct vb2_v4l2_buffer		vb;
28 	struct list_head		list;
29 
30 	dma_addr_t			dma_addr;
31 	bool				queued_to_csi;
32 };
33 
34 static const u32 supported_pixformats[] = {
35 	V4L2_PIX_FMT_SBGGR8,
36 	V4L2_PIX_FMT_SGBRG8,
37 	V4L2_PIX_FMT_SGRBG8,
38 	V4L2_PIX_FMT_SRGGB8,
39 	V4L2_PIX_FMT_SBGGR10,
40 	V4L2_PIX_FMT_SGBRG10,
41 	V4L2_PIX_FMT_SGRBG10,
42 	V4L2_PIX_FMT_SRGGB10,
43 	V4L2_PIX_FMT_SBGGR12,
44 	V4L2_PIX_FMT_SGBRG12,
45 	V4L2_PIX_FMT_SGRBG12,
46 	V4L2_PIX_FMT_SRGGB12,
47 	V4L2_PIX_FMT_YUYV,
48 	V4L2_PIX_FMT_YVYU,
49 	V4L2_PIX_FMT_UYVY,
50 	V4L2_PIX_FMT_VYUY,
51 	V4L2_PIX_FMT_HM12,
52 	V4L2_PIX_FMT_NV12,
53 	V4L2_PIX_FMT_NV21,
54 	V4L2_PIX_FMT_YUV420,
55 	V4L2_PIX_FMT_YVU420,
56 	V4L2_PIX_FMT_NV16,
57 	V4L2_PIX_FMT_NV61,
58 	V4L2_PIX_FMT_YUV422P,
59 	V4L2_PIX_FMT_RGB565,
60 	V4L2_PIX_FMT_RGB565X,
61 	V4L2_PIX_FMT_JPEG,
62 };
63 
is_pixformat_valid(unsigned int pixformat)64 static bool is_pixformat_valid(unsigned int pixformat)
65 {
66 	unsigned int i;
67 
68 	for (i = 0; i < ARRAY_SIZE(supported_pixformats); i++)
69 		if (supported_pixformats[i] == pixformat)
70 			return true;
71 
72 	return false;
73 }
74 
75 static struct v4l2_subdev *
sun6i_video_remote_subdev(struct sun6i_video * video,u32 * pad)76 sun6i_video_remote_subdev(struct sun6i_video *video, u32 *pad)
77 {
78 	struct media_pad *remote;
79 
80 	remote = media_entity_remote_pad(&video->pad);
81 
82 	if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
83 		return NULL;
84 
85 	if (pad)
86 		*pad = remote->index;
87 
88 	return media_entity_to_v4l2_subdev(remote->entity);
89 }
90 
sun6i_video_queue_setup(struct vb2_queue * vq,unsigned int * nbuffers,unsigned int * nplanes,unsigned int sizes[],struct device * alloc_devs[])91 static int sun6i_video_queue_setup(struct vb2_queue *vq,
92 				   unsigned int *nbuffers,
93 				   unsigned int *nplanes,
94 				   unsigned int sizes[],
95 				   struct device *alloc_devs[])
96 {
97 	struct sun6i_video *video = vb2_get_drv_priv(vq);
98 	unsigned int size = video->fmt.fmt.pix.sizeimage;
99 
100 	if (*nplanes)
101 		return sizes[0] < size ? -EINVAL : 0;
102 
103 	*nplanes = 1;
104 	sizes[0] = size;
105 
106 	return 0;
107 }
108 
sun6i_video_buffer_prepare(struct vb2_buffer * vb)109 static int sun6i_video_buffer_prepare(struct vb2_buffer *vb)
110 {
111 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
112 	struct sun6i_csi_buffer *buf =
113 			container_of(vbuf, struct sun6i_csi_buffer, vb);
114 	struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue);
115 	unsigned long size = video->fmt.fmt.pix.sizeimage;
116 
117 	if (vb2_plane_size(vb, 0) < size) {
118 		v4l2_err(video->vdev.v4l2_dev, "buffer too small (%lu < %lu)\n",
119 			 vb2_plane_size(vb, 0), size);
120 		return -EINVAL;
121 	}
122 
123 	vb2_set_plane_payload(vb, 0, size);
124 
125 	buf->dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
126 
127 	vbuf->field = video->fmt.fmt.pix.field;
128 
129 	return 0;
130 }
131 
sun6i_video_start_streaming(struct vb2_queue * vq,unsigned int count)132 static int sun6i_video_start_streaming(struct vb2_queue *vq, unsigned int count)
133 {
134 	struct sun6i_video *video = vb2_get_drv_priv(vq);
135 	struct sun6i_csi_buffer *buf;
136 	struct sun6i_csi_buffer *next_buf;
137 	struct sun6i_csi_config config;
138 	struct v4l2_subdev *subdev;
139 	unsigned long flags;
140 	int ret;
141 
142 	video->sequence = 0;
143 
144 	ret = media_pipeline_start(&video->vdev.entity, &video->vdev.pipe);
145 	if (ret < 0)
146 		goto clear_dma_queue;
147 
148 	if (video->mbus_code == 0) {
149 		ret = -EINVAL;
150 		goto stop_media_pipeline;
151 	}
152 
153 	subdev = sun6i_video_remote_subdev(video, NULL);
154 	if (!subdev) {
155 		ret = -EINVAL;
156 		goto stop_media_pipeline;
157 	}
158 
159 	config.pixelformat = video->fmt.fmt.pix.pixelformat;
160 	config.code = video->mbus_code;
161 	config.field = video->fmt.fmt.pix.field;
162 	config.width = video->fmt.fmt.pix.width;
163 	config.height = video->fmt.fmt.pix.height;
164 
165 	ret = sun6i_csi_update_config(video->csi, &config);
166 	if (ret < 0)
167 		goto stop_media_pipeline;
168 
169 	spin_lock_irqsave(&video->dma_queue_lock, flags);
170 
171 	buf = list_first_entry(&video->dma_queue,
172 			       struct sun6i_csi_buffer, list);
173 	buf->queued_to_csi = true;
174 	sun6i_csi_update_buf_addr(video->csi, buf->dma_addr);
175 
176 	sun6i_csi_set_stream(video->csi, true);
177 
178 	/*
179 	 * CSI will lookup the next dma buffer for next frame before the
180 	 * the current frame done IRQ triggered. This is not documented
181 	 * but reported by Ondřej Jirman.
182 	 * The BSP code has workaround for this too. It skip to mark the
183 	 * first buffer as frame done for VB2 and pass the second buffer
184 	 * to CSI in the first frame done ISR call. Then in second frame
185 	 * done ISR call, it mark the first buffer as frame done for VB2
186 	 * and pass the third buffer to CSI. And so on. The bad thing is
187 	 * that the first buffer will be written twice and the first frame
188 	 * is dropped even the queued buffer is sufficient.
189 	 * So, I make some improvement here. Pass the next buffer to CSI
190 	 * just follow starting the CSI. In this case, the first frame
191 	 * will be stored in first buffer, second frame in second buffer.
192 	 * This method is used to avoid dropping the first frame, it
193 	 * would also drop frame when lacking of queued buffer.
194 	 */
195 	next_buf = list_next_entry(buf, list);
196 	next_buf->queued_to_csi = true;
197 	sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr);
198 
199 	spin_unlock_irqrestore(&video->dma_queue_lock, flags);
200 
201 	ret = v4l2_subdev_call(subdev, video, s_stream, 1);
202 	if (ret && ret != -ENOIOCTLCMD)
203 		goto stop_csi_stream;
204 
205 	return 0;
206 
207 stop_csi_stream:
208 	sun6i_csi_set_stream(video->csi, false);
209 stop_media_pipeline:
210 	media_pipeline_stop(&video->vdev.entity);
211 clear_dma_queue:
212 	spin_lock_irqsave(&video->dma_queue_lock, flags);
213 	list_for_each_entry(buf, &video->dma_queue, list)
214 		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
215 	INIT_LIST_HEAD(&video->dma_queue);
216 	spin_unlock_irqrestore(&video->dma_queue_lock, flags);
217 
218 	return ret;
219 }
220 
sun6i_video_stop_streaming(struct vb2_queue * vq)221 static void sun6i_video_stop_streaming(struct vb2_queue *vq)
222 {
223 	struct sun6i_video *video = vb2_get_drv_priv(vq);
224 	struct v4l2_subdev *subdev;
225 	unsigned long flags;
226 	struct sun6i_csi_buffer *buf;
227 
228 	subdev = sun6i_video_remote_subdev(video, NULL);
229 	if (subdev)
230 		v4l2_subdev_call(subdev, video, s_stream, 0);
231 
232 	sun6i_csi_set_stream(video->csi, false);
233 
234 	media_pipeline_stop(&video->vdev.entity);
235 
236 	/* Release all active buffers */
237 	spin_lock_irqsave(&video->dma_queue_lock, flags);
238 	list_for_each_entry(buf, &video->dma_queue, list)
239 		vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
240 	INIT_LIST_HEAD(&video->dma_queue);
241 	spin_unlock_irqrestore(&video->dma_queue_lock, flags);
242 }
243 
sun6i_video_buffer_queue(struct vb2_buffer * vb)244 static void sun6i_video_buffer_queue(struct vb2_buffer *vb)
245 {
246 	struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
247 	struct sun6i_csi_buffer *buf =
248 			container_of(vbuf, struct sun6i_csi_buffer, vb);
249 	struct sun6i_video *video = vb2_get_drv_priv(vb->vb2_queue);
250 	unsigned long flags;
251 
252 	spin_lock_irqsave(&video->dma_queue_lock, flags);
253 	buf->queued_to_csi = false;
254 	list_add_tail(&buf->list, &video->dma_queue);
255 	spin_unlock_irqrestore(&video->dma_queue_lock, flags);
256 }
257 
sun6i_video_frame_done(struct sun6i_video * video)258 void sun6i_video_frame_done(struct sun6i_video *video)
259 {
260 	struct sun6i_csi_buffer *buf;
261 	struct sun6i_csi_buffer *next_buf;
262 	struct vb2_v4l2_buffer *vbuf;
263 
264 	spin_lock(&video->dma_queue_lock);
265 
266 	buf = list_first_entry(&video->dma_queue,
267 			       struct sun6i_csi_buffer, list);
268 	if (list_is_last(&buf->list, &video->dma_queue)) {
269 		dev_dbg(video->csi->dev, "Frame dropped!\n");
270 		goto unlock;
271 	}
272 
273 	next_buf = list_next_entry(buf, list);
274 	/* If a new buffer (#next_buf) had not been queued to CSI, the old
275 	 * buffer (#buf) is still holding by CSI for storing the next
276 	 * frame. So, we queue a new buffer (#next_buf) to CSI then wait
277 	 * for next ISR call.
278 	 */
279 	if (!next_buf->queued_to_csi) {
280 		next_buf->queued_to_csi = true;
281 		sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr);
282 		dev_dbg(video->csi->dev, "Frame dropped!\n");
283 		goto unlock;
284 	}
285 
286 	list_del(&buf->list);
287 	vbuf = &buf->vb;
288 	vbuf->vb2_buf.timestamp = ktime_get_ns();
289 	vbuf->sequence = video->sequence;
290 	vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
291 
292 	/* Prepare buffer for next frame but one.  */
293 	if (!list_is_last(&next_buf->list, &video->dma_queue)) {
294 		next_buf = list_next_entry(next_buf, list);
295 		next_buf->queued_to_csi = true;
296 		sun6i_csi_update_buf_addr(video->csi, next_buf->dma_addr);
297 	} else {
298 		dev_dbg(video->csi->dev, "Next frame will be dropped!\n");
299 	}
300 
301 unlock:
302 	video->sequence++;
303 	spin_unlock(&video->dma_queue_lock);
304 }
305 
306 static const struct vb2_ops sun6i_csi_vb2_ops = {
307 	.queue_setup		= sun6i_video_queue_setup,
308 	.wait_prepare		= vb2_ops_wait_prepare,
309 	.wait_finish		= vb2_ops_wait_finish,
310 	.buf_prepare		= sun6i_video_buffer_prepare,
311 	.start_streaming	= sun6i_video_start_streaming,
312 	.stop_streaming		= sun6i_video_stop_streaming,
313 	.buf_queue		= sun6i_video_buffer_queue,
314 };
315 
vidioc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)316 static int vidioc_querycap(struct file *file, void *priv,
317 			   struct v4l2_capability *cap)
318 {
319 	struct sun6i_video *video = video_drvdata(file);
320 
321 	strscpy(cap->driver, "sun6i-video", sizeof(cap->driver));
322 	strscpy(cap->card, video->vdev.name, sizeof(cap->card));
323 	snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
324 		 video->csi->dev->of_node->name);
325 
326 	return 0;
327 }
328 
vidioc_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)329 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
330 				   struct v4l2_fmtdesc *f)
331 {
332 	u32 index = f->index;
333 
334 	if (index >= ARRAY_SIZE(supported_pixformats))
335 		return -EINVAL;
336 
337 	f->pixelformat = supported_pixformats[index];
338 
339 	return 0;
340 }
341 
vidioc_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * fmt)342 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
343 				struct v4l2_format *fmt)
344 {
345 	struct sun6i_video *video = video_drvdata(file);
346 
347 	*fmt = video->fmt;
348 
349 	return 0;
350 }
351 
sun6i_video_try_fmt(struct sun6i_video * video,struct v4l2_format * f)352 static int sun6i_video_try_fmt(struct sun6i_video *video,
353 			       struct v4l2_format *f)
354 {
355 	struct v4l2_pix_format *pixfmt = &f->fmt.pix;
356 	int bpp;
357 
358 	if (!is_pixformat_valid(pixfmt->pixelformat))
359 		pixfmt->pixelformat = supported_pixformats[0];
360 
361 	v4l_bound_align_image(&pixfmt->width, MIN_WIDTH, MAX_WIDTH, 1,
362 			      &pixfmt->height, MIN_HEIGHT, MAX_WIDTH, 1, 1);
363 
364 	bpp = sun6i_csi_get_bpp(pixfmt->pixelformat);
365 	pixfmt->bytesperline = (pixfmt->width * bpp) >> 3;
366 	pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height;
367 
368 	if (pixfmt->field == V4L2_FIELD_ANY)
369 		pixfmt->field = V4L2_FIELD_NONE;
370 
371 	pixfmt->colorspace = V4L2_COLORSPACE_RAW;
372 	pixfmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
373 	pixfmt->quantization = V4L2_QUANTIZATION_DEFAULT;
374 	pixfmt->xfer_func = V4L2_XFER_FUNC_DEFAULT;
375 
376 	return 0;
377 }
378 
sun6i_video_set_fmt(struct sun6i_video * video,struct v4l2_format * f)379 static int sun6i_video_set_fmt(struct sun6i_video *video, struct v4l2_format *f)
380 {
381 	int ret;
382 
383 	ret = sun6i_video_try_fmt(video, f);
384 	if (ret)
385 		return ret;
386 
387 	video->fmt = *f;
388 
389 	return 0;
390 }
391 
vidioc_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)392 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
393 				struct v4l2_format *f)
394 {
395 	struct sun6i_video *video = video_drvdata(file);
396 
397 	if (vb2_is_busy(&video->vb2_vidq))
398 		return -EBUSY;
399 
400 	return sun6i_video_set_fmt(video, f);
401 }
402 
vidioc_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)403 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
404 				  struct v4l2_format *f)
405 {
406 	struct sun6i_video *video = video_drvdata(file);
407 
408 	return sun6i_video_try_fmt(video, f);
409 }
410 
vidioc_enum_input(struct file * file,void * fh,struct v4l2_input * inp)411 static int vidioc_enum_input(struct file *file, void *fh,
412 			     struct v4l2_input *inp)
413 {
414 	if (inp->index != 0)
415 		return -EINVAL;
416 
417 	strscpy(inp->name, "camera", sizeof(inp->name));
418 	inp->type = V4L2_INPUT_TYPE_CAMERA;
419 
420 	return 0;
421 }
422 
vidioc_g_input(struct file * file,void * fh,unsigned int * i)423 static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
424 {
425 	*i = 0;
426 
427 	return 0;
428 }
429 
vidioc_s_input(struct file * file,void * fh,unsigned int i)430 static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
431 {
432 	if (i != 0)
433 		return -EINVAL;
434 
435 	return 0;
436 }
437 
438 static const struct v4l2_ioctl_ops sun6i_video_ioctl_ops = {
439 	.vidioc_querycap		= vidioc_querycap,
440 	.vidioc_enum_fmt_vid_cap	= vidioc_enum_fmt_vid_cap,
441 	.vidioc_g_fmt_vid_cap		= vidioc_g_fmt_vid_cap,
442 	.vidioc_s_fmt_vid_cap		= vidioc_s_fmt_vid_cap,
443 	.vidioc_try_fmt_vid_cap		= vidioc_try_fmt_vid_cap,
444 
445 	.vidioc_enum_input		= vidioc_enum_input,
446 	.vidioc_s_input			= vidioc_s_input,
447 	.vidioc_g_input			= vidioc_g_input,
448 
449 	.vidioc_reqbufs			= vb2_ioctl_reqbufs,
450 	.vidioc_querybuf		= vb2_ioctl_querybuf,
451 	.vidioc_qbuf			= vb2_ioctl_qbuf,
452 	.vidioc_expbuf			= vb2_ioctl_expbuf,
453 	.vidioc_dqbuf			= vb2_ioctl_dqbuf,
454 	.vidioc_create_bufs		= vb2_ioctl_create_bufs,
455 	.vidioc_prepare_buf		= vb2_ioctl_prepare_buf,
456 	.vidioc_streamon		= vb2_ioctl_streamon,
457 	.vidioc_streamoff		= vb2_ioctl_streamoff,
458 
459 	.vidioc_log_status		= v4l2_ctrl_log_status,
460 	.vidioc_subscribe_event		= v4l2_ctrl_subscribe_event,
461 	.vidioc_unsubscribe_event	= v4l2_event_unsubscribe,
462 };
463 
464 /* -----------------------------------------------------------------------------
465  * V4L2 file operations
466  */
sun6i_video_open(struct file * file)467 static int sun6i_video_open(struct file *file)
468 {
469 	struct sun6i_video *video = video_drvdata(file);
470 	int ret;
471 
472 	if (mutex_lock_interruptible(&video->lock))
473 		return -ERESTARTSYS;
474 
475 	ret = v4l2_fh_open(file);
476 	if (ret < 0)
477 		goto unlock;
478 
479 	ret = v4l2_pipeline_pm_get(&video->vdev.entity);
480 	if (ret < 0)
481 		goto fh_release;
482 
483 	/* check if already powered */
484 	if (!v4l2_fh_is_singular_file(file))
485 		goto unlock;
486 
487 	ret = sun6i_csi_set_power(video->csi, true);
488 	if (ret < 0)
489 		goto fh_release;
490 
491 	mutex_unlock(&video->lock);
492 	return 0;
493 
494 fh_release:
495 	v4l2_fh_release(file);
496 unlock:
497 	mutex_unlock(&video->lock);
498 	return ret;
499 }
500 
sun6i_video_close(struct file * file)501 static int sun6i_video_close(struct file *file)
502 {
503 	struct sun6i_video *video = video_drvdata(file);
504 	bool last_fh;
505 
506 	mutex_lock(&video->lock);
507 
508 	last_fh = v4l2_fh_is_singular_file(file);
509 
510 	_vb2_fop_release(file, NULL);
511 
512 	v4l2_pipeline_pm_put(&video->vdev.entity);
513 
514 	if (last_fh)
515 		sun6i_csi_set_power(video->csi, false);
516 
517 	mutex_unlock(&video->lock);
518 
519 	return 0;
520 }
521 
522 static const struct v4l2_file_operations sun6i_video_fops = {
523 	.owner		= THIS_MODULE,
524 	.open		= sun6i_video_open,
525 	.release	= sun6i_video_close,
526 	.unlocked_ioctl	= video_ioctl2,
527 	.mmap		= vb2_fop_mmap,
528 	.poll		= vb2_fop_poll
529 };
530 
531 /* -----------------------------------------------------------------------------
532  * Media Operations
533  */
sun6i_video_link_validate_get_format(struct media_pad * pad,struct v4l2_subdev_format * fmt)534 static int sun6i_video_link_validate_get_format(struct media_pad *pad,
535 						struct v4l2_subdev_format *fmt)
536 {
537 	if (is_media_entity_v4l2_subdev(pad->entity)) {
538 		struct v4l2_subdev *sd =
539 				media_entity_to_v4l2_subdev(pad->entity);
540 
541 		fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
542 		fmt->pad = pad->index;
543 		return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
544 	}
545 
546 	return -EINVAL;
547 }
548 
sun6i_video_link_validate(struct media_link * link)549 static int sun6i_video_link_validate(struct media_link *link)
550 {
551 	struct video_device *vdev = container_of(link->sink->entity,
552 						 struct video_device, entity);
553 	struct sun6i_video *video = video_get_drvdata(vdev);
554 	struct v4l2_subdev_format source_fmt;
555 	int ret;
556 
557 	video->mbus_code = 0;
558 
559 	if (!media_entity_remote_pad(link->sink->entity->pads)) {
560 		dev_info(video->csi->dev,
561 			 "video node %s pad not connected\n", vdev->name);
562 		return -ENOLINK;
563 	}
564 
565 	ret = sun6i_video_link_validate_get_format(link->source, &source_fmt);
566 	if (ret < 0)
567 		return ret;
568 
569 	if (!sun6i_csi_is_format_supported(video->csi,
570 					   video->fmt.fmt.pix.pixelformat,
571 					   source_fmt.format.code)) {
572 		dev_err(video->csi->dev,
573 			"Unsupported pixformat: 0x%x with mbus code: 0x%x!\n",
574 			video->fmt.fmt.pix.pixelformat,
575 			source_fmt.format.code);
576 		return -EPIPE;
577 	}
578 
579 	if (source_fmt.format.width != video->fmt.fmt.pix.width ||
580 	    source_fmt.format.height != video->fmt.fmt.pix.height) {
581 		dev_err(video->csi->dev,
582 			"Wrong width or height %ux%u (%ux%u expected)\n",
583 			video->fmt.fmt.pix.width, video->fmt.fmt.pix.height,
584 			source_fmt.format.width, source_fmt.format.height);
585 		return -EPIPE;
586 	}
587 
588 	video->mbus_code = source_fmt.format.code;
589 
590 	return 0;
591 }
592 
593 static const struct media_entity_operations sun6i_video_media_ops = {
594 	.link_validate = sun6i_video_link_validate
595 };
596 
sun6i_video_init(struct sun6i_video * video,struct sun6i_csi * csi,const char * name)597 int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,
598 		     const char *name)
599 {
600 	struct video_device *vdev = &video->vdev;
601 	struct vb2_queue *vidq = &video->vb2_vidq;
602 	struct v4l2_format fmt = { 0 };
603 	int ret;
604 
605 	video->csi = csi;
606 
607 	/* Initialize the media entity... */
608 	video->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
609 	vdev->entity.ops = &sun6i_video_media_ops;
610 	ret = media_entity_pads_init(&vdev->entity, 1, &video->pad);
611 	if (ret < 0)
612 		return ret;
613 
614 	mutex_init(&video->lock);
615 
616 	INIT_LIST_HEAD(&video->dma_queue);
617 	spin_lock_init(&video->dma_queue_lock);
618 
619 	video->sequence = 0;
620 
621 	/* Setup default format */
622 	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
623 	fmt.fmt.pix.pixelformat = supported_pixformats[0];
624 	fmt.fmt.pix.width = 1280;
625 	fmt.fmt.pix.height = 720;
626 	fmt.fmt.pix.field = V4L2_FIELD_NONE;
627 	sun6i_video_set_fmt(video, &fmt);
628 
629 	/* Initialize videobuf2 queue */
630 	vidq->type			= V4L2_BUF_TYPE_VIDEO_CAPTURE;
631 	vidq->io_modes			= VB2_MMAP | VB2_DMABUF;
632 	vidq->drv_priv			= video;
633 	vidq->buf_struct_size		= sizeof(struct sun6i_csi_buffer);
634 	vidq->ops			= &sun6i_csi_vb2_ops;
635 	vidq->mem_ops			= &vb2_dma_contig_memops;
636 	vidq->timestamp_flags		= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
637 	vidq->lock			= &video->lock;
638 	/* Make sure non-dropped frame */
639 	vidq->min_buffers_needed	= 3;
640 	vidq->dev			= csi->dev;
641 
642 	ret = vb2_queue_init(vidq);
643 	if (ret) {
644 		v4l2_err(&csi->v4l2_dev, "vb2_queue_init failed: %d\n", ret);
645 		goto clean_entity;
646 	}
647 
648 	/* Register video device */
649 	strscpy(vdev->name, name, sizeof(vdev->name));
650 	vdev->release		= video_device_release_empty;
651 	vdev->fops		= &sun6i_video_fops;
652 	vdev->ioctl_ops		= &sun6i_video_ioctl_ops;
653 	vdev->vfl_type		= VFL_TYPE_VIDEO;
654 	vdev->vfl_dir		= VFL_DIR_RX;
655 	vdev->v4l2_dev		= &csi->v4l2_dev;
656 	vdev->queue		= vidq;
657 	vdev->lock		= &video->lock;
658 	vdev->device_caps	= V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
659 	video_set_drvdata(vdev, video);
660 
661 	ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
662 	if (ret < 0) {
663 		v4l2_err(&csi->v4l2_dev,
664 			 "video_register_device failed: %d\n", ret);
665 		goto clean_entity;
666 	}
667 
668 	return 0;
669 
670 clean_entity:
671 	media_entity_cleanup(&video->vdev.entity);
672 	mutex_destroy(&video->lock);
673 	return ret;
674 }
675 
sun6i_video_cleanup(struct sun6i_video * video)676 void sun6i_video_cleanup(struct sun6i_video *video)
677 {
678 	vb2_video_unregister_device(&video->vdev);
679 	media_entity_cleanup(&video->vdev.entity);
680 	mutex_destroy(&video->lock);
681 }
682