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