1
2
3
4
5
6
7
8
9
10#include <linux/clk.h>
11#include <linux/mm.h>
12#include <linux/pagemap.h>
13#include <linux/sched.h>
14#include <linux/slab.h>
15#include <linux/vmalloc.h>
16#include <linux/module.h>
17
18#include <media/v4l2-dev.h>
19#include <media/v4l2-ioctl.h>
20#include <media/v4l2-mc.h>
21
22#include <asm/cacheflush.h>
23
24#include "iss_video.h"
25#include "iss.h"
26
27
28
29
30
31static struct iss_format_info formats[] = {
32 { MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8,
33 MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8,
34 V4L2_PIX_FMT_GREY, 8, },
35 { MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10,
36 MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y8_1X8,
37 V4L2_PIX_FMT_Y10, 10, },
38 { MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y10_1X10,
39 MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y8_1X8,
40 V4L2_PIX_FMT_Y12, 12, },
41 { MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8,
42 MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8,
43 V4L2_PIX_FMT_SBGGR8, 8, },
44 { MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
45 MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
46 V4L2_PIX_FMT_SGBRG8, 8, },
47 { MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8,
48 MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8,
49 V4L2_PIX_FMT_SGRBG8, 8, },
50 { MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
51 MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
52 V4L2_PIX_FMT_SRGGB8, 8, },
53 { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
54 MEDIA_BUS_FMT_SGRBG10_1X10, 0,
55 V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
56 { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10,
57 MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR8_1X8,
58 V4L2_PIX_FMT_SBGGR10, 10, },
59 { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10,
60 MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG8_1X8,
61 V4L2_PIX_FMT_SGBRG10, 10, },
62 { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10,
63 MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG8_1X8,
64 V4L2_PIX_FMT_SGRBG10, 10, },
65 { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10,
66 MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB8_1X8,
67 V4L2_PIX_FMT_SRGGB10, 10, },
68 { MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR10_1X10,
69 MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR8_1X8,
70 V4L2_PIX_FMT_SBGGR12, 12, },
71 { MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG10_1X10,
72 MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG8_1X8,
73 V4L2_PIX_FMT_SGBRG12, 12, },
74 { MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG10_1X10,
75 MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG8_1X8,
76 V4L2_PIX_FMT_SGRBG12, 12, },
77 { MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB10_1X10,
78 MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB8_1X8,
79 V4L2_PIX_FMT_SRGGB12, 12, },
80 { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16,
81 MEDIA_BUS_FMT_UYVY8_1X16, 0,
82 V4L2_PIX_FMT_UYVY, 16, },
83 { MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16,
84 MEDIA_BUS_FMT_YUYV8_1X16, 0,
85 V4L2_PIX_FMT_YUYV, 16, },
86 { MEDIA_BUS_FMT_YUYV8_1_5X8, MEDIA_BUS_FMT_YUYV8_1_5X8,
87 MEDIA_BUS_FMT_YUYV8_1_5X8, 0,
88 V4L2_PIX_FMT_NV12, 8, },
89};
90
91const struct iss_format_info *
92omap4iss_video_format_info(u32 code)
93{
94 unsigned int i;
95
96 for (i = 0; i < ARRAY_SIZE(formats); ++i) {
97 if (formats[i].code == code)
98 return &formats[i];
99 }
100
101 return NULL;
102}
103
104
105
106
107
108
109
110
111
112
113
114
115
116static unsigned int iss_video_mbus_to_pix(const struct iss_video *video,
117 const struct v4l2_mbus_framefmt *mbus,
118 struct v4l2_pix_format *pix)
119{
120 unsigned int bpl = pix->bytesperline;
121 unsigned int min_bpl;
122 unsigned int i;
123
124 memset(pix, 0, sizeof(*pix));
125 pix->width = mbus->width;
126 pix->height = mbus->height;
127
128
129
130
131
132 for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) {
133 if (formats[i].code == mbus->code)
134 break;
135 }
136
137 min_bpl = pix->width * ALIGN(formats[i].bpp, 8) / 8;
138
139
140
141
142
143
144 if (video->bpl_max)
145 bpl = clamp(bpl, min_bpl, video->bpl_max);
146 else
147 bpl = min_bpl;
148
149 if (!video->bpl_zero_padding || bpl != min_bpl)
150 bpl = ALIGN(bpl, video->bpl_alignment);
151
152 pix->pixelformat = formats[i].pixelformat;
153 pix->bytesperline = bpl;
154 pix->sizeimage = pix->bytesperline * pix->height;
155 pix->colorspace = mbus->colorspace;
156 pix->field = mbus->field;
157
158
159 if (pix->pixelformat == V4L2_PIX_FMT_NV12)
160 pix->sizeimage += (pix->bytesperline * pix->height) / 2;
161
162 return bpl - min_bpl;
163}
164
165static void iss_video_pix_to_mbus(const struct v4l2_pix_format *pix,
166 struct v4l2_mbus_framefmt *mbus)
167{
168 unsigned int i;
169
170 memset(mbus, 0, sizeof(*mbus));
171 mbus->width = pix->width;
172 mbus->height = pix->height;
173
174
175
176
177
178 for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) {
179 if (formats[i].pixelformat == pix->pixelformat)
180 break;
181 }
182
183 mbus->code = formats[i].code;
184 mbus->colorspace = pix->colorspace;
185 mbus->field = pix->field;
186}
187
188static struct v4l2_subdev *
189iss_video_remote_subdev(struct iss_video *video, u32 *pad)
190{
191 struct media_pad *remote;
192
193 remote = media_entity_remote_pad(&video->pad);
194
195 if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
196 return NULL;
197
198 if (pad)
199 *pad = remote->index;
200
201 return media_entity_to_v4l2_subdev(remote->entity);
202}
203
204
205static struct iss_video *
206iss_video_far_end(struct iss_video *video)
207{
208 struct media_graph graph;
209 struct media_entity *entity = &video->video.entity;
210 struct media_device *mdev = entity->graph_obj.mdev;
211 struct iss_video *far_end = NULL;
212
213 mutex_lock(&mdev->graph_mutex);
214
215 if (media_graph_walk_init(&graph, mdev)) {
216 mutex_unlock(&mdev->graph_mutex);
217 return NULL;
218 }
219
220 media_graph_walk_start(&graph, entity);
221
222 while ((entity = media_graph_walk_next(&graph))) {
223 if (entity == &video->video.entity)
224 continue;
225
226 if (!is_media_entity_v4l2_video_device(entity))
227 continue;
228
229 far_end = to_iss_video(media_entity_to_video_device(entity));
230 if (far_end->type != video->type)
231 break;
232
233 far_end = NULL;
234 }
235
236 mutex_unlock(&mdev->graph_mutex);
237
238 media_graph_walk_cleanup(&graph);
239
240 return far_end;
241}
242
243static int
244__iss_video_get_format(struct iss_video *video,
245 struct v4l2_mbus_framefmt *format)
246{
247 struct v4l2_subdev_format fmt;
248 struct v4l2_subdev *subdev;
249 u32 pad;
250 int ret;
251
252 subdev = iss_video_remote_subdev(video, &pad);
253 if (!subdev)
254 return -EINVAL;
255
256 memset(&fmt, 0, sizeof(fmt));
257 fmt.pad = pad;
258 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
259
260 mutex_lock(&video->mutex);
261 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
262 mutex_unlock(&video->mutex);
263
264 if (ret)
265 return ret;
266
267 *format = fmt.format;
268 return 0;
269}
270
271static int
272iss_video_check_format(struct iss_video *video, struct iss_video_fh *vfh)
273{
274 struct v4l2_mbus_framefmt format;
275 struct v4l2_pix_format pixfmt;
276 int ret;
277
278 ret = __iss_video_get_format(video, &format);
279 if (ret < 0)
280 return ret;
281
282 pixfmt.bytesperline = 0;
283 ret = iss_video_mbus_to_pix(video, &format, &pixfmt);
284
285 if (vfh->format.fmt.pix.pixelformat != pixfmt.pixelformat ||
286 vfh->format.fmt.pix.height != pixfmt.height ||
287 vfh->format.fmt.pix.width != pixfmt.width ||
288 vfh->format.fmt.pix.bytesperline != pixfmt.bytesperline ||
289 vfh->format.fmt.pix.sizeimage != pixfmt.sizeimage)
290 return -EINVAL;
291
292 return ret;
293}
294
295
296
297
298
299static int iss_video_queue_setup(struct vb2_queue *vq,
300 unsigned int *count, unsigned int *num_planes,
301 unsigned int sizes[],
302 struct device *alloc_devs[])
303{
304 struct iss_video_fh *vfh = vb2_get_drv_priv(vq);
305 struct iss_video *video = vfh->video;
306
307
308 *num_planes = 1;
309
310 sizes[0] = vfh->format.fmt.pix.sizeimage;
311 if (sizes[0] == 0)
312 return -EINVAL;
313
314 *count = min(*count, video->capture_mem / PAGE_ALIGN(sizes[0]));
315
316 return 0;
317}
318
319static void iss_video_buf_cleanup(struct vb2_buffer *vb)
320{
321 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
322 struct iss_buffer *buffer = container_of(vbuf, struct iss_buffer, vb);
323
324 if (buffer->iss_addr)
325 buffer->iss_addr = 0;
326}
327
328static int iss_video_buf_prepare(struct vb2_buffer *vb)
329{
330 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
331 struct iss_video_fh *vfh = vb2_get_drv_priv(vb->vb2_queue);
332 struct iss_buffer *buffer = container_of(vbuf, struct iss_buffer, vb);
333 struct iss_video *video = vfh->video;
334 unsigned long size = vfh->format.fmt.pix.sizeimage;
335 dma_addr_t addr;
336
337 if (vb2_plane_size(vb, 0) < size)
338 return -ENOBUFS;
339
340 addr = vb2_dma_contig_plane_dma_addr(vb, 0);
341 if (!IS_ALIGNED(addr, 32)) {
342 dev_dbg(video->iss->dev,
343 "Buffer address must be aligned to 32 bytes boundary.\n");
344 return -EINVAL;
345 }
346
347 vb2_set_plane_payload(vb, 0, size);
348 buffer->iss_addr = addr;
349 return 0;
350}
351
352static void iss_video_buf_queue(struct vb2_buffer *vb)
353{
354 struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
355 struct iss_video_fh *vfh = vb2_get_drv_priv(vb->vb2_queue);
356 struct iss_video *video = vfh->video;
357 struct iss_buffer *buffer = container_of(vbuf, struct iss_buffer, vb);
358 struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity);
359 unsigned long flags;
360 bool empty;
361
362 spin_lock_irqsave(&video->qlock, flags);
363
364
365
366
367
368
369
370 if (unlikely(video->error)) {
371 vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
372 spin_unlock_irqrestore(&video->qlock, flags);
373 return;
374 }
375
376 empty = list_empty(&video->dmaqueue);
377 list_add_tail(&buffer->list, &video->dmaqueue);
378
379 spin_unlock_irqrestore(&video->qlock, flags);
380
381 if (empty) {
382 enum iss_pipeline_state state;
383 unsigned int start;
384
385 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
386 state = ISS_PIPELINE_QUEUE_OUTPUT;
387 else
388 state = ISS_PIPELINE_QUEUE_INPUT;
389
390 spin_lock_irqsave(&pipe->lock, flags);
391 pipe->state |= state;
392 video->ops->queue(video, buffer);
393 video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_QUEUED;
394
395 start = iss_pipeline_ready(pipe);
396 if (start)
397 pipe->state |= ISS_PIPELINE_STREAM;
398 spin_unlock_irqrestore(&pipe->lock, flags);
399
400 if (start)
401 omap4iss_pipeline_set_stream(pipe,
402 ISS_PIPELINE_STREAM_SINGLESHOT);
403 }
404}
405
406static const struct vb2_ops iss_video_vb2ops = {
407 .queue_setup = iss_video_queue_setup,
408 .buf_prepare = iss_video_buf_prepare,
409 .buf_queue = iss_video_buf_queue,
410 .buf_cleanup = iss_video_buf_cleanup,
411};
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video)
429{
430 struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity);
431 enum iss_pipeline_state state;
432 struct iss_buffer *buf;
433 unsigned long flags;
434
435 spin_lock_irqsave(&video->qlock, flags);
436 if (WARN_ON(list_empty(&video->dmaqueue))) {
437 spin_unlock_irqrestore(&video->qlock, flags);
438 return NULL;
439 }
440
441 buf = list_first_entry(&video->dmaqueue, struct iss_buffer,
442 list);
443 list_del(&buf->list);
444 spin_unlock_irqrestore(&video->qlock, flags);
445
446 buf->vb.vb2_buf.timestamp = ktime_get_ns();
447
448
449
450
451
452
453
454
455 if (video == pipe->output && !pipe->do_propagation)
456 buf->vb.sequence =
457 atomic_inc_return(&pipe->frame_number);
458 else
459 buf->vb.sequence = atomic_read(&pipe->frame_number);
460
461 vb2_buffer_done(&buf->vb.vb2_buf, pipe->error ?
462 VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
463 pipe->error = false;
464
465 spin_lock_irqsave(&video->qlock, flags);
466 if (list_empty(&video->dmaqueue)) {
467 spin_unlock_irqrestore(&video->qlock, flags);
468 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
469 state = ISS_PIPELINE_QUEUE_OUTPUT
470 | ISS_PIPELINE_STREAM;
471 else
472 state = ISS_PIPELINE_QUEUE_INPUT
473 | ISS_PIPELINE_STREAM;
474
475 spin_lock_irqsave(&pipe->lock, flags);
476 pipe->state &= ~state;
477 if (video->pipe.stream_state == ISS_PIPELINE_STREAM_CONTINUOUS)
478 video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_UNDERRUN;
479 spin_unlock_irqrestore(&pipe->lock, flags);
480 return NULL;
481 }
482
483 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input) {
484 spin_lock(&pipe->lock);
485 pipe->state &= ~ISS_PIPELINE_STREAM;
486 spin_unlock(&pipe->lock);
487 }
488
489 buf = list_first_entry(&video->dmaqueue, struct iss_buffer,
490 list);
491 spin_unlock_irqrestore(&video->qlock, flags);
492 buf->vb.vb2_buf.state = VB2_BUF_STATE_ACTIVE;
493 return buf;
494}
495
496
497
498
499
500
501
502
503void omap4iss_video_cancel_stream(struct iss_video *video)
504{
505 unsigned long flags;
506
507 spin_lock_irqsave(&video->qlock, flags);
508
509 while (!list_empty(&video->dmaqueue)) {
510 struct iss_buffer *buf;
511
512 buf = list_first_entry(&video->dmaqueue, struct iss_buffer,
513 list);
514 list_del(&buf->list);
515 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
516 }
517
518 vb2_queue_error(video->queue);
519 video->error = true;
520
521 spin_unlock_irqrestore(&video->qlock, flags);
522}
523
524
525
526
527
528static int
529iss_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
530{
531 struct iss_video *video = video_drvdata(file);
532
533 strscpy(cap->driver, ISS_VIDEO_DRIVER_NAME, sizeof(cap->driver));
534 strscpy(cap->card, video->video.name, sizeof(cap->card));
535 strscpy(cap->bus_info, "media", sizeof(cap->bus_info));
536 cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
537 | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
538
539 return 0;
540}
541
542static int
543iss_video_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
544{
545 struct iss_video *video = video_drvdata(file);
546 struct v4l2_mbus_framefmt format;
547 unsigned int index = f->index;
548 unsigned int i;
549 int ret;
550
551 if (f->type != video->type)
552 return -EINVAL;
553
554 ret = __iss_video_get_format(video, &format);
555 if (ret < 0)
556 return ret;
557
558 for (i = 0; i < ARRAY_SIZE(formats); ++i) {
559 const struct iss_format_info *info = &formats[i];
560
561 if (format.code != info->code)
562 continue;
563
564 if (index == 0) {
565 f->pixelformat = info->pixelformat;
566 return 0;
567 }
568
569 index--;
570 }
571
572 return -EINVAL;
573}
574
575static int
576iss_video_get_format(struct file *file, void *fh, struct v4l2_format *format)
577{
578 struct iss_video_fh *vfh = to_iss_video_fh(fh);
579 struct iss_video *video = video_drvdata(file);
580
581 if (format->type != video->type)
582 return -EINVAL;
583
584 mutex_lock(&video->mutex);
585 *format = vfh->format;
586 mutex_unlock(&video->mutex);
587
588 return 0;
589}
590
591static int
592iss_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
593{
594 struct iss_video_fh *vfh = to_iss_video_fh(fh);
595 struct iss_video *video = video_drvdata(file);
596 struct v4l2_mbus_framefmt fmt;
597
598 if (format->type != video->type)
599 return -EINVAL;
600
601 mutex_lock(&video->mutex);
602
603
604
605
606
607 iss_video_pix_to_mbus(&format->fmt.pix, &fmt);
608 iss_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
609
610 vfh->format = *format;
611
612 mutex_unlock(&video->mutex);
613 return 0;
614}
615
616static int
617iss_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
618{
619 struct iss_video *video = video_drvdata(file);
620 struct v4l2_subdev_format fmt;
621 struct v4l2_subdev *subdev;
622 u32 pad;
623 int ret;
624
625 if (format->type != video->type)
626 return -EINVAL;
627
628 subdev = iss_video_remote_subdev(video, &pad);
629 if (!subdev)
630 return -EINVAL;
631
632 iss_video_pix_to_mbus(&format->fmt.pix, &fmt.format);
633
634 fmt.pad = pad;
635 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
636 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
637 if (ret)
638 return ret;
639
640 iss_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
641 return 0;
642}
643
644static int
645iss_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel)
646{
647 struct iss_video *video = video_drvdata(file);
648 struct v4l2_subdev_format format;
649 struct v4l2_subdev *subdev;
650 struct v4l2_subdev_selection sdsel = {
651 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
652 .target = sel->target,
653 };
654 u32 pad;
655 int ret;
656
657 switch (sel->target) {
658 case V4L2_SEL_TGT_CROP:
659 case V4L2_SEL_TGT_CROP_BOUNDS:
660 case V4L2_SEL_TGT_CROP_DEFAULT:
661 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
662 return -EINVAL;
663 break;
664 case V4L2_SEL_TGT_COMPOSE:
665 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
666 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
667 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
668 return -EINVAL;
669 break;
670 default:
671 return -EINVAL;
672 }
673 subdev = iss_video_remote_subdev(video, &pad);
674 if (!subdev)
675 return -EINVAL;
676
677
678
679
680
681 sdsel.pad = pad;
682 ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel);
683 if (!ret)
684 sel->r = sdsel.r;
685 if (ret != -ENOIOCTLCMD)
686 return ret;
687
688 format.pad = pad;
689 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
690 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format);
691 if (ret < 0)
692 return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
693
694 sel->r.left = 0;
695 sel->r.top = 0;
696 sel->r.width = format.format.width;
697 sel->r.height = format.format.height;
698
699 return 0;
700}
701
702static int
703iss_video_set_selection(struct file *file, void *fh, struct v4l2_selection *sel)
704{
705 struct iss_video *video = video_drvdata(file);
706 struct v4l2_subdev *subdev;
707 struct v4l2_subdev_selection sdsel = {
708 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
709 .target = sel->target,
710 .flags = sel->flags,
711 .r = sel->r,
712 };
713 u32 pad;
714 int ret;
715
716 switch (sel->target) {
717 case V4L2_SEL_TGT_CROP:
718 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
719 return -EINVAL;
720 break;
721 case V4L2_SEL_TGT_COMPOSE:
722 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
723 return -EINVAL;
724 break;
725 default:
726 return -EINVAL;
727 }
728 subdev = iss_video_remote_subdev(video, &pad);
729 if (!subdev)
730 return -EINVAL;
731
732 sdsel.pad = pad;
733 mutex_lock(&video->mutex);
734 ret = v4l2_subdev_call(subdev, pad, set_selection, NULL, &sdsel);
735 mutex_unlock(&video->mutex);
736 if (!ret)
737 sel->r = sdsel.r;
738
739 return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
740}
741
742static int
743iss_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a)
744{
745 struct iss_video_fh *vfh = to_iss_video_fh(fh);
746 struct iss_video *video = video_drvdata(file);
747
748 if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
749 video->type != a->type)
750 return -EINVAL;
751
752 memset(a, 0, sizeof(*a));
753 a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
754 a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
755 a->parm.output.timeperframe = vfh->timeperframe;
756
757 return 0;
758}
759
760static int
761iss_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a)
762{
763 struct iss_video_fh *vfh = to_iss_video_fh(fh);
764 struct iss_video *video = video_drvdata(file);
765
766 if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
767 video->type != a->type)
768 return -EINVAL;
769
770 if (a->parm.output.timeperframe.denominator == 0)
771 a->parm.output.timeperframe.denominator = 1;
772
773 vfh->timeperframe = a->parm.output.timeperframe;
774
775 return 0;
776}
777
778static int
779iss_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
780{
781 struct iss_video_fh *vfh = to_iss_video_fh(fh);
782
783 return vb2_reqbufs(&vfh->queue, rb);
784}
785
786static int
787iss_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
788{
789 struct iss_video_fh *vfh = to_iss_video_fh(fh);
790
791 return vb2_querybuf(&vfh->queue, b);
792}
793
794static int
795iss_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
796{
797 struct iss_video *video = video_drvdata(file);
798 struct iss_video_fh *vfh = to_iss_video_fh(fh);
799
800 return vb2_qbuf(&vfh->queue, video->video.v4l2_dev->mdev, b);
801}
802
803static int
804iss_video_expbuf(struct file *file, void *fh, struct v4l2_exportbuffer *e)
805{
806 struct iss_video_fh *vfh = to_iss_video_fh(fh);
807
808 return vb2_expbuf(&vfh->queue, e);
809}
810
811static int
812iss_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
813{
814 struct iss_video_fh *vfh = to_iss_video_fh(fh);
815
816 return vb2_dqbuf(&vfh->queue, b, file->f_flags & O_NONBLOCK);
817}
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850static int
851iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
852{
853 struct iss_video_fh *vfh = to_iss_video_fh(fh);
854 struct iss_video *video = video_drvdata(file);
855 struct media_graph graph;
856 struct media_entity *entity = &video->video.entity;
857 enum iss_pipeline_state state;
858 struct iss_pipeline *pipe;
859 struct iss_video *far_end;
860 unsigned long flags;
861 int ret;
862
863 if (type != video->type)
864 return -EINVAL;
865
866 mutex_lock(&video->stream_lock);
867
868
869
870
871
872 pipe = entity->pipe
873 ? to_iss_pipeline(entity) : &video->pipe;
874 pipe->external = NULL;
875 pipe->external_rate = 0;
876 pipe->external_bpp = 0;
877
878 ret = media_entity_enum_init(&pipe->ent_enum, entity->graph_obj.mdev);
879 if (ret)
880 goto err_graph_walk_init;
881
882 ret = media_graph_walk_init(&graph, entity->graph_obj.mdev);
883 if (ret)
884 goto err_graph_walk_init;
885
886 if (video->iss->pdata->set_constraints)
887 video->iss->pdata->set_constraints(video->iss, true);
888
889 ret = media_pipeline_start(entity, &pipe->pipe);
890 if (ret < 0)
891 goto err_media_pipeline_start;
892
893 media_graph_walk_start(&graph, entity);
894 while ((entity = media_graph_walk_next(&graph)))
895 media_entity_enum_set(&pipe->ent_enum, entity);
896
897
898
899
900
901 ret = iss_video_check_format(video, vfh);
902 if (ret < 0)
903 goto err_iss_video_check_format;
904
905 video->bpl_padding = ret;
906 video->bpl_value = vfh->format.fmt.pix.bytesperline;
907
908
909
910
911
912 far_end = iss_video_far_end(video);
913
914 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
915 state = ISS_PIPELINE_STREAM_OUTPUT | ISS_PIPELINE_IDLE_OUTPUT;
916 pipe->input = far_end;
917 pipe->output = video;
918 } else {
919 if (!far_end) {
920 ret = -EPIPE;
921 goto err_iss_video_check_format;
922 }
923
924 state = ISS_PIPELINE_STREAM_INPUT | ISS_PIPELINE_IDLE_INPUT;
925 pipe->input = video;
926 pipe->output = far_end;
927 }
928
929 spin_lock_irqsave(&pipe->lock, flags);
930 pipe->state &= ~ISS_PIPELINE_STREAM;
931 pipe->state |= state;
932 spin_unlock_irqrestore(&pipe->lock, flags);
933
934
935
936
937
938
939 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
940 pipe->max_timeperframe = vfh->timeperframe;
941
942 video->queue = &vfh->queue;
943 INIT_LIST_HEAD(&video->dmaqueue);
944 video->error = false;
945 atomic_set(&pipe->frame_number, -1);
946
947 ret = vb2_streamon(&vfh->queue, type);
948 if (ret < 0)
949 goto err_iss_video_check_format;
950
951
952
953
954
955
956 if (!pipe->input) {
957 unsigned long flags;
958
959 ret = omap4iss_pipeline_set_stream(pipe,
960 ISS_PIPELINE_STREAM_CONTINUOUS);
961 if (ret < 0)
962 goto err_omap4iss_set_stream;
963 spin_lock_irqsave(&video->qlock, flags);
964 if (list_empty(&video->dmaqueue))
965 video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_UNDERRUN;
966 spin_unlock_irqrestore(&video->qlock, flags);
967 }
968
969 media_graph_walk_cleanup(&graph);
970
971 mutex_unlock(&video->stream_lock);
972
973 return 0;
974
975err_omap4iss_set_stream:
976 vb2_streamoff(&vfh->queue, type);
977err_iss_video_check_format:
978 media_pipeline_stop(&video->video.entity);
979err_media_pipeline_start:
980 if (video->iss->pdata->set_constraints)
981 video->iss->pdata->set_constraints(video->iss, false);
982 video->queue = NULL;
983
984 media_graph_walk_cleanup(&graph);
985
986err_graph_walk_init:
987 media_entity_enum_cleanup(&pipe->ent_enum);
988
989 mutex_unlock(&video->stream_lock);
990
991 return ret;
992}
993
994static int
995iss_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
996{
997 struct iss_video_fh *vfh = to_iss_video_fh(fh);
998 struct iss_video *video = video_drvdata(file);
999 struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity);
1000 enum iss_pipeline_state state;
1001 unsigned long flags;
1002
1003 if (type != video->type)
1004 return -EINVAL;
1005
1006 mutex_lock(&video->stream_lock);
1007
1008 if (!vb2_is_streaming(&vfh->queue))
1009 goto done;
1010
1011
1012 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1013 state = ISS_PIPELINE_STREAM_OUTPUT
1014 | ISS_PIPELINE_QUEUE_OUTPUT;
1015 else
1016 state = ISS_PIPELINE_STREAM_INPUT
1017 | ISS_PIPELINE_QUEUE_INPUT;
1018
1019 spin_lock_irqsave(&pipe->lock, flags);
1020 pipe->state &= ~state;
1021 spin_unlock_irqrestore(&pipe->lock, flags);
1022
1023
1024 omap4iss_pipeline_set_stream(pipe, ISS_PIPELINE_STREAM_STOPPED);
1025 vb2_streamoff(&vfh->queue, type);
1026 video->queue = NULL;
1027
1028 media_entity_enum_cleanup(&pipe->ent_enum);
1029
1030 if (video->iss->pdata->set_constraints)
1031 video->iss->pdata->set_constraints(video->iss, false);
1032 media_pipeline_stop(&video->video.entity);
1033
1034done:
1035 mutex_unlock(&video->stream_lock);
1036 return 0;
1037}
1038
1039static int
1040iss_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
1041{
1042 if (input->index > 0)
1043 return -EINVAL;
1044
1045 strscpy(input->name, "camera", sizeof(input->name));
1046 input->type = V4L2_INPUT_TYPE_CAMERA;
1047
1048 return 0;
1049}
1050
1051static int
1052iss_video_g_input(struct file *file, void *fh, unsigned int *input)
1053{
1054 *input = 0;
1055
1056 return 0;
1057}
1058
1059static int
1060iss_video_s_input(struct file *file, void *fh, unsigned int input)
1061{
1062 return input == 0 ? 0 : -EINVAL;
1063}
1064
1065static const struct v4l2_ioctl_ops iss_video_ioctl_ops = {
1066 .vidioc_querycap = iss_video_querycap,
1067 .vidioc_enum_fmt_vid_cap = iss_video_enum_format,
1068 .vidioc_g_fmt_vid_cap = iss_video_get_format,
1069 .vidioc_s_fmt_vid_cap = iss_video_set_format,
1070 .vidioc_try_fmt_vid_cap = iss_video_try_format,
1071 .vidioc_g_fmt_vid_out = iss_video_get_format,
1072 .vidioc_s_fmt_vid_out = iss_video_set_format,
1073 .vidioc_try_fmt_vid_out = iss_video_try_format,
1074 .vidioc_g_selection = iss_video_get_selection,
1075 .vidioc_s_selection = iss_video_set_selection,
1076 .vidioc_g_parm = iss_video_get_param,
1077 .vidioc_s_parm = iss_video_set_param,
1078 .vidioc_reqbufs = iss_video_reqbufs,
1079 .vidioc_querybuf = iss_video_querybuf,
1080 .vidioc_qbuf = iss_video_qbuf,
1081 .vidioc_expbuf = iss_video_expbuf,
1082 .vidioc_dqbuf = iss_video_dqbuf,
1083 .vidioc_streamon = iss_video_streamon,
1084 .vidioc_streamoff = iss_video_streamoff,
1085 .vidioc_enum_input = iss_video_enum_input,
1086 .vidioc_g_input = iss_video_g_input,
1087 .vidioc_s_input = iss_video_s_input,
1088};
1089
1090
1091
1092
1093
1094static int iss_video_open(struct file *file)
1095{
1096 struct iss_video *video = video_drvdata(file);
1097 struct iss_video_fh *handle;
1098 struct vb2_queue *q;
1099 int ret = 0;
1100
1101 handle = kzalloc(sizeof(*handle), GFP_KERNEL);
1102 if (!handle)
1103 return -ENOMEM;
1104
1105 v4l2_fh_init(&handle->vfh, &video->video);
1106 v4l2_fh_add(&handle->vfh);
1107
1108
1109 if (!omap4iss_get(video->iss)) {
1110 ret = -EBUSY;
1111 goto done;
1112 }
1113
1114 ret = v4l2_pipeline_pm_get(&video->video.entity);
1115 if (ret < 0) {
1116 omap4iss_put(video->iss);
1117 goto done;
1118 }
1119
1120 q = &handle->queue;
1121
1122 q->type = video->type;
1123 q->io_modes = VB2_MMAP | VB2_DMABUF;
1124 q->drv_priv = handle;
1125 q->ops = &iss_video_vb2ops;
1126 q->mem_ops = &vb2_dma_contig_memops;
1127 q->buf_struct_size = sizeof(struct iss_buffer);
1128 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1129 q->dev = video->iss->dev;
1130
1131 ret = vb2_queue_init(q);
1132 if (ret) {
1133 omap4iss_put(video->iss);
1134 goto done;
1135 }
1136
1137 memset(&handle->format, 0, sizeof(handle->format));
1138 handle->format.type = video->type;
1139 handle->timeperframe.denominator = 1;
1140
1141 handle->video = video;
1142 file->private_data = &handle->vfh;
1143
1144done:
1145 if (ret < 0) {
1146 v4l2_fh_del(&handle->vfh);
1147 v4l2_fh_exit(&handle->vfh);
1148 kfree(handle);
1149 }
1150
1151 return ret;
1152}
1153
1154static int iss_video_release(struct file *file)
1155{
1156 struct iss_video *video = video_drvdata(file);
1157 struct v4l2_fh *vfh = file->private_data;
1158 struct iss_video_fh *handle = to_iss_video_fh(vfh);
1159
1160
1161 iss_video_streamoff(file, vfh, video->type);
1162
1163 v4l2_pipeline_pm_put(&video->video.entity);
1164
1165
1166 vb2_queue_release(&handle->queue);
1167
1168 v4l2_fh_del(vfh);
1169 v4l2_fh_exit(vfh);
1170 kfree(handle);
1171 file->private_data = NULL;
1172
1173 omap4iss_put(video->iss);
1174
1175 return 0;
1176}
1177
1178static __poll_t iss_video_poll(struct file *file, poll_table *wait)
1179{
1180 struct iss_video_fh *vfh = to_iss_video_fh(file->private_data);
1181
1182 return vb2_poll(&vfh->queue, file, wait);
1183}
1184
1185static int iss_video_mmap(struct file *file, struct vm_area_struct *vma)
1186{
1187 struct iss_video_fh *vfh = to_iss_video_fh(file->private_data);
1188
1189 return vb2_mmap(&vfh->queue, vma);
1190}
1191
1192static const struct v4l2_file_operations iss_video_fops = {
1193 .owner = THIS_MODULE,
1194 .unlocked_ioctl = video_ioctl2,
1195 .open = iss_video_open,
1196 .release = iss_video_release,
1197 .poll = iss_video_poll,
1198 .mmap = iss_video_mmap,
1199};
1200
1201
1202
1203
1204
1205static const struct iss_video_operations iss_video_dummy_ops = {
1206};
1207
1208int omap4iss_video_init(struct iss_video *video, const char *name)
1209{
1210 const char *direction;
1211 int ret;
1212
1213 switch (video->type) {
1214 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1215 direction = "output";
1216 video->pad.flags = MEDIA_PAD_FL_SINK;
1217 break;
1218 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1219 direction = "input";
1220 video->pad.flags = MEDIA_PAD_FL_SOURCE;
1221 break;
1222
1223 default:
1224 return -EINVAL;
1225 }
1226
1227 ret = media_entity_pads_init(&video->video.entity, 1, &video->pad);
1228 if (ret < 0)
1229 return ret;
1230
1231 spin_lock_init(&video->qlock);
1232 mutex_init(&video->mutex);
1233 atomic_set(&video->active, 0);
1234
1235 spin_lock_init(&video->pipe.lock);
1236 mutex_init(&video->stream_lock);
1237
1238
1239 if (!video->ops)
1240 video->ops = &iss_video_dummy_ops;
1241
1242 video->video.fops = &iss_video_fops;
1243 snprintf(video->video.name, sizeof(video->video.name),
1244 "OMAP4 ISS %s %s", name, direction);
1245 video->video.vfl_type = VFL_TYPE_VIDEO;
1246 video->video.release = video_device_release_empty;
1247 video->video.ioctl_ops = &iss_video_ioctl_ops;
1248 video->pipe.stream_state = ISS_PIPELINE_STREAM_STOPPED;
1249
1250 video_set_drvdata(&video->video, video);
1251
1252 return 0;
1253}
1254
1255void omap4iss_video_cleanup(struct iss_video *video)
1256{
1257 media_entity_cleanup(&video->video.entity);
1258 mutex_destroy(&video->stream_lock);
1259 mutex_destroy(&video->mutex);
1260}
1261
1262int omap4iss_video_register(struct iss_video *video, struct v4l2_device *vdev)
1263{
1264 int ret;
1265
1266 video->video.v4l2_dev = vdev;
1267 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1268 video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE;
1269 else
1270 video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT;
1271 video->video.device_caps |= V4L2_CAP_STREAMING;
1272
1273 ret = video_register_device(&video->video, VFL_TYPE_VIDEO, -1);
1274 if (ret < 0)
1275 dev_err(video->iss->dev,
1276 "could not register video device (%d)\n", ret);
1277
1278 return ret;
1279}
1280
1281void omap4iss_video_unregister(struct iss_video *video)
1282{
1283 video_unregister_device(&video->video);
1284}
1285