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, "Greyscale 8 bpp", },
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, "Greyscale 10 bpp", },
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, "Greyscale 12 bpp", },
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, "BGGR Bayer 8 bpp", },
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, "GBRG Bayer 8 bpp", },
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, "GRBG Bayer 8 bpp", },
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, "RGGB Bayer 8 bpp", },
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, "GRBG Bayer 10 bpp DPCM8", },
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, "BGGR Bayer 10 bpp", },
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, "GBRG Bayer 10 bpp", },
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, "GRBG Bayer 10 bpp", },
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, "RGGB Bayer 10 bpp", },
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, "BGGR Bayer 12 bpp", },
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, "GBRG Bayer 12 bpp", },
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, "GRBG Bayer 12 bpp", },
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, "RGGB Bayer 12 bpp", },
80 { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16,
81 MEDIA_BUS_FMT_UYVY8_1X16, 0,
82 V4L2_PIX_FMT_UYVY, 16, "YUV 4:2:2 (UYVY)", },
83 { MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16,
84 MEDIA_BUS_FMT_YUYV8_1X16, 0,
85 V4L2_PIX_FMT_YUYV, 16, "YUV 4:2:2 (YUYV)", },
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, "YUV 4:2:0 (NV12)", },
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 strscpy(f->description, info->description,
567 sizeof(f->description));
568 return 0;
569 }
570
571 index--;
572 }
573
574 return -EINVAL;
575}
576
577static int
578iss_video_get_format(struct file *file, void *fh, struct v4l2_format *format)
579{
580 struct iss_video_fh *vfh = to_iss_video_fh(fh);
581 struct iss_video *video = video_drvdata(file);
582
583 if (format->type != video->type)
584 return -EINVAL;
585
586 mutex_lock(&video->mutex);
587 *format = vfh->format;
588 mutex_unlock(&video->mutex);
589
590 return 0;
591}
592
593static int
594iss_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
595{
596 struct iss_video_fh *vfh = to_iss_video_fh(fh);
597 struct iss_video *video = video_drvdata(file);
598 struct v4l2_mbus_framefmt fmt;
599
600 if (format->type != video->type)
601 return -EINVAL;
602
603 mutex_lock(&video->mutex);
604
605
606
607
608
609 iss_video_pix_to_mbus(&format->fmt.pix, &fmt);
610 iss_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
611
612 vfh->format = *format;
613
614 mutex_unlock(&video->mutex);
615 return 0;
616}
617
618static int
619iss_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
620{
621 struct iss_video *video = video_drvdata(file);
622 struct v4l2_subdev_format fmt;
623 struct v4l2_subdev *subdev;
624 u32 pad;
625 int ret;
626
627 if (format->type != video->type)
628 return -EINVAL;
629
630 subdev = iss_video_remote_subdev(video, &pad);
631 if (!subdev)
632 return -EINVAL;
633
634 iss_video_pix_to_mbus(&format->fmt.pix, &fmt.format);
635
636 fmt.pad = pad;
637 fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
638 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
639 if (ret)
640 return ret;
641
642 iss_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
643 return 0;
644}
645
646static int
647iss_video_get_selection(struct file *file, void *fh, struct v4l2_selection *sel)
648{
649 struct iss_video *video = video_drvdata(file);
650 struct v4l2_subdev_format format;
651 struct v4l2_subdev *subdev;
652 struct v4l2_subdev_selection sdsel = {
653 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
654 .target = sel->target,
655 };
656 u32 pad;
657 int ret;
658
659 switch (sel->target) {
660 case V4L2_SEL_TGT_CROP:
661 case V4L2_SEL_TGT_CROP_BOUNDS:
662 case V4L2_SEL_TGT_CROP_DEFAULT:
663 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
664 return -EINVAL;
665 break;
666 case V4L2_SEL_TGT_COMPOSE:
667 case V4L2_SEL_TGT_COMPOSE_BOUNDS:
668 case V4L2_SEL_TGT_COMPOSE_DEFAULT:
669 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
670 return -EINVAL;
671 break;
672 default:
673 return -EINVAL;
674 }
675 subdev = iss_video_remote_subdev(video, &pad);
676 if (subdev == NULL)
677 return -EINVAL;
678
679
680
681
682
683 sdsel.pad = pad;
684 ret = v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel);
685 if (!ret)
686 sel->r = sdsel.r;
687 if (ret != -ENOIOCTLCMD)
688 return ret;
689
690 format.pad = pad;
691 format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
692 ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format);
693 if (ret < 0)
694 return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
695
696 sel->r.left = 0;
697 sel->r.top = 0;
698 sel->r.width = format.format.width;
699 sel->r.height = format.format.height;
700
701 return 0;
702}
703
704static int
705iss_video_set_selection(struct file *file, void *fh, struct v4l2_selection *sel)
706{
707 struct iss_video *video = video_drvdata(file);
708 struct v4l2_subdev *subdev;
709 struct v4l2_subdev_selection sdsel = {
710 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
711 .target = sel->target,
712 .flags = sel->flags,
713 .r = sel->r,
714 };
715 u32 pad;
716 int ret;
717
718 switch (sel->target) {
719 case V4L2_SEL_TGT_CROP:
720 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
721 return -EINVAL;
722 break;
723 case V4L2_SEL_TGT_COMPOSE:
724 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
725 return -EINVAL;
726 break;
727 default:
728 return -EINVAL;
729 }
730 subdev = iss_video_remote_subdev(video, &pad);
731 if (subdev == NULL)
732 return -EINVAL;
733
734 sdsel.pad = pad;
735 mutex_lock(&video->mutex);
736 ret = v4l2_subdev_call(subdev, pad, set_selection, NULL, &sdsel);
737 mutex_unlock(&video->mutex);
738 if (!ret)
739 sel->r = sdsel.r;
740
741 return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
742}
743
744static int
745iss_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a)
746{
747 struct iss_video_fh *vfh = to_iss_video_fh(fh);
748 struct iss_video *video = video_drvdata(file);
749
750 if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
751 video->type != a->type)
752 return -EINVAL;
753
754 memset(a, 0, sizeof(*a));
755 a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
756 a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
757 a->parm.output.timeperframe = vfh->timeperframe;
758
759 return 0;
760}
761
762static int
763iss_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a)
764{
765 struct iss_video_fh *vfh = to_iss_video_fh(fh);
766 struct iss_video *video = video_drvdata(file);
767
768 if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
769 video->type != a->type)
770 return -EINVAL;
771
772 if (a->parm.output.timeperframe.denominator == 0)
773 a->parm.output.timeperframe.denominator = 1;
774
775 vfh->timeperframe = a->parm.output.timeperframe;
776
777 return 0;
778}
779
780static int
781iss_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
782{
783 struct iss_video_fh *vfh = to_iss_video_fh(fh);
784
785 return vb2_reqbufs(&vfh->queue, rb);
786}
787
788static int
789iss_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
790{
791 struct iss_video_fh *vfh = to_iss_video_fh(fh);
792
793 return vb2_querybuf(&vfh->queue, b);
794}
795
796static int
797iss_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
798{
799 struct iss_video *video = video_drvdata(file);
800 struct iss_video_fh *vfh = to_iss_video_fh(fh);
801
802 return vb2_qbuf(&vfh->queue, video->video.v4l2_dev->mdev, b);
803}
804
805static int
806iss_video_expbuf(struct file *file, void *fh, struct v4l2_exportbuffer *e)
807{
808 struct iss_video_fh *vfh = to_iss_video_fh(fh);
809
810 return vb2_expbuf(&vfh->queue, e);
811}
812
813static int
814iss_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
815{
816 struct iss_video_fh *vfh = to_iss_video_fh(fh);
817
818 return vb2_dqbuf(&vfh->queue, b, file->f_flags & O_NONBLOCK);
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
850
851
852static int
853iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
854{
855 struct iss_video_fh *vfh = to_iss_video_fh(fh);
856 struct iss_video *video = video_drvdata(file);
857 struct media_graph graph;
858 struct media_entity *entity = &video->video.entity;
859 enum iss_pipeline_state state;
860 struct iss_pipeline *pipe;
861 struct iss_video *far_end;
862 unsigned long flags;
863 int ret;
864
865 if (type != video->type)
866 return -EINVAL;
867
868 mutex_lock(&video->stream_lock);
869
870
871
872
873
874 pipe = entity->pipe
875 ? to_iss_pipeline(entity) : &video->pipe;
876 pipe->external = NULL;
877 pipe->external_rate = 0;
878 pipe->external_bpp = 0;
879
880 ret = media_entity_enum_init(&pipe->ent_enum, entity->graph_obj.mdev);
881 if (ret)
882 goto err_graph_walk_init;
883
884 ret = media_graph_walk_init(&graph, entity->graph_obj.mdev);
885 if (ret)
886 goto err_graph_walk_init;
887
888 if (video->iss->pdata->set_constraints)
889 video->iss->pdata->set_constraints(video->iss, true);
890
891 ret = media_pipeline_start(entity, &pipe->pipe);
892 if (ret < 0)
893 goto err_media_pipeline_start;
894
895 media_graph_walk_start(&graph, entity);
896 while ((entity = media_graph_walk_next(&graph)))
897 media_entity_enum_set(&pipe->ent_enum, entity);
898
899
900
901
902
903 ret = iss_video_check_format(video, vfh);
904 if (ret < 0)
905 goto err_iss_video_check_format;
906
907 video->bpl_padding = ret;
908 video->bpl_value = vfh->format.fmt.pix.bytesperline;
909
910
911
912
913
914 far_end = iss_video_far_end(video);
915
916 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
917 state = ISS_PIPELINE_STREAM_OUTPUT | ISS_PIPELINE_IDLE_OUTPUT;
918 pipe->input = far_end;
919 pipe->output = video;
920 } else {
921 if (!far_end) {
922 ret = -EPIPE;
923 goto err_iss_video_check_format;
924 }
925
926 state = ISS_PIPELINE_STREAM_INPUT | ISS_PIPELINE_IDLE_INPUT;
927 pipe->input = video;
928 pipe->output = far_end;
929 }
930
931 spin_lock_irqsave(&pipe->lock, flags);
932 pipe->state &= ~ISS_PIPELINE_STREAM;
933 pipe->state |= state;
934 spin_unlock_irqrestore(&pipe->lock, flags);
935
936
937
938
939
940
941 if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
942 pipe->max_timeperframe = vfh->timeperframe;
943
944 video->queue = &vfh->queue;
945 INIT_LIST_HEAD(&video->dmaqueue);
946 video->error = false;
947 atomic_set(&pipe->frame_number, -1);
948
949 ret = vb2_streamon(&vfh->queue, type);
950 if (ret < 0)
951 goto err_iss_video_check_format;
952
953
954
955
956
957
958 if (!pipe->input) {
959 unsigned long flags;
960
961 ret = omap4iss_pipeline_set_stream(pipe,
962 ISS_PIPELINE_STREAM_CONTINUOUS);
963 if (ret < 0)
964 goto err_omap4iss_set_stream;
965 spin_lock_irqsave(&video->qlock, flags);
966 if (list_empty(&video->dmaqueue))
967 video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_UNDERRUN;
968 spin_unlock_irqrestore(&video->qlock, flags);
969 }
970
971 media_graph_walk_cleanup(&graph);
972
973 mutex_unlock(&video->stream_lock);
974
975 return 0;
976
977err_omap4iss_set_stream:
978 vb2_streamoff(&vfh->queue, type);
979err_iss_video_check_format:
980 media_pipeline_stop(&video->video.entity);
981err_media_pipeline_start:
982 if (video->iss->pdata->set_constraints)
983 video->iss->pdata->set_constraints(video->iss, false);
984 video->queue = NULL;
985
986 media_graph_walk_cleanup(&graph);
987
988err_graph_walk_init:
989 media_entity_enum_cleanup(&pipe->ent_enum);
990
991 mutex_unlock(&video->stream_lock);
992
993 return ret;
994}
995
996static int
997iss_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
998{
999 struct iss_video_fh *vfh = to_iss_video_fh(fh);
1000 struct iss_video *video = video_drvdata(file);
1001 struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity);
1002 enum iss_pipeline_state state;
1003 unsigned long flags;
1004
1005 if (type != video->type)
1006 return -EINVAL;
1007
1008 mutex_lock(&video->stream_lock);
1009
1010 if (!vb2_is_streaming(&vfh->queue))
1011 goto done;
1012
1013
1014 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1015 state = ISS_PIPELINE_STREAM_OUTPUT
1016 | ISS_PIPELINE_QUEUE_OUTPUT;
1017 else
1018 state = ISS_PIPELINE_STREAM_INPUT
1019 | ISS_PIPELINE_QUEUE_INPUT;
1020
1021 spin_lock_irqsave(&pipe->lock, flags);
1022 pipe->state &= ~state;
1023 spin_unlock_irqrestore(&pipe->lock, flags);
1024
1025
1026 omap4iss_pipeline_set_stream(pipe, ISS_PIPELINE_STREAM_STOPPED);
1027 vb2_streamoff(&vfh->queue, type);
1028 video->queue = NULL;
1029
1030 media_entity_enum_cleanup(&pipe->ent_enum);
1031
1032 if (video->iss->pdata->set_constraints)
1033 video->iss->pdata->set_constraints(video->iss, false);
1034 media_pipeline_stop(&video->video.entity);
1035
1036done:
1037 mutex_unlock(&video->stream_lock);
1038 return 0;
1039}
1040
1041static int
1042iss_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
1043{
1044 if (input->index > 0)
1045 return -EINVAL;
1046
1047 strscpy(input->name, "camera", sizeof(input->name));
1048 input->type = V4L2_INPUT_TYPE_CAMERA;
1049
1050 return 0;
1051}
1052
1053static int
1054iss_video_g_input(struct file *file, void *fh, unsigned int *input)
1055{
1056 *input = 0;
1057
1058 return 0;
1059}
1060
1061static int
1062iss_video_s_input(struct file *file, void *fh, unsigned int input)
1063{
1064 return input == 0 ? 0 : -EINVAL;
1065}
1066
1067static const struct v4l2_ioctl_ops iss_video_ioctl_ops = {
1068 .vidioc_querycap = iss_video_querycap,
1069 .vidioc_enum_fmt_vid_cap = iss_video_enum_format,
1070 .vidioc_g_fmt_vid_cap = iss_video_get_format,
1071 .vidioc_s_fmt_vid_cap = iss_video_set_format,
1072 .vidioc_try_fmt_vid_cap = iss_video_try_format,
1073 .vidioc_g_fmt_vid_out = iss_video_get_format,
1074 .vidioc_s_fmt_vid_out = iss_video_set_format,
1075 .vidioc_try_fmt_vid_out = iss_video_try_format,
1076 .vidioc_g_selection = iss_video_get_selection,
1077 .vidioc_s_selection = iss_video_set_selection,
1078 .vidioc_g_parm = iss_video_get_param,
1079 .vidioc_s_parm = iss_video_set_param,
1080 .vidioc_reqbufs = iss_video_reqbufs,
1081 .vidioc_querybuf = iss_video_querybuf,
1082 .vidioc_qbuf = iss_video_qbuf,
1083 .vidioc_expbuf = iss_video_expbuf,
1084 .vidioc_dqbuf = iss_video_dqbuf,
1085 .vidioc_streamon = iss_video_streamon,
1086 .vidioc_streamoff = iss_video_streamoff,
1087 .vidioc_enum_input = iss_video_enum_input,
1088 .vidioc_g_input = iss_video_g_input,
1089 .vidioc_s_input = iss_video_s_input,
1090};
1091
1092
1093
1094
1095
1096static int iss_video_open(struct file *file)
1097{
1098 struct iss_video *video = video_drvdata(file);
1099 struct iss_video_fh *handle;
1100 struct vb2_queue *q;
1101 int ret = 0;
1102
1103 handle = kzalloc(sizeof(*handle), GFP_KERNEL);
1104 if (!handle)
1105 return -ENOMEM;
1106
1107 v4l2_fh_init(&handle->vfh, &video->video);
1108 v4l2_fh_add(&handle->vfh);
1109
1110
1111 if (!omap4iss_get(video->iss)) {
1112 ret = -EBUSY;
1113 goto done;
1114 }
1115
1116 ret = v4l2_pipeline_pm_use(&video->video.entity, 1);
1117 if (ret < 0) {
1118 omap4iss_put(video->iss);
1119 goto done;
1120 }
1121
1122 q = &handle->queue;
1123
1124 q->type = video->type;
1125 q->io_modes = VB2_MMAP | VB2_DMABUF;
1126 q->drv_priv = handle;
1127 q->ops = &iss_video_vb2ops;
1128 q->mem_ops = &vb2_dma_contig_memops;
1129 q->buf_struct_size = sizeof(struct iss_buffer);
1130 q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
1131 q->dev = video->iss->dev;
1132
1133 ret = vb2_queue_init(q);
1134 if (ret) {
1135 omap4iss_put(video->iss);
1136 goto done;
1137 }
1138
1139 memset(&handle->format, 0, sizeof(handle->format));
1140 handle->format.type = video->type;
1141 handle->timeperframe.denominator = 1;
1142
1143 handle->video = video;
1144 file->private_data = &handle->vfh;
1145
1146done:
1147 if (ret < 0) {
1148 v4l2_fh_del(&handle->vfh);
1149 v4l2_fh_exit(&handle->vfh);
1150 kfree(handle);
1151 }
1152
1153 return ret;
1154}
1155
1156static int iss_video_release(struct file *file)
1157{
1158 struct iss_video *video = video_drvdata(file);
1159 struct v4l2_fh *vfh = file->private_data;
1160 struct iss_video_fh *handle = to_iss_video_fh(vfh);
1161
1162
1163 iss_video_streamoff(file, vfh, video->type);
1164
1165 v4l2_pipeline_pm_use(&video->video.entity, 0);
1166
1167
1168 vb2_queue_release(&handle->queue);
1169
1170 v4l2_fh_del(vfh);
1171 v4l2_fh_exit(vfh);
1172 kfree(handle);
1173 file->private_data = NULL;
1174
1175 omap4iss_put(video->iss);
1176
1177 return 0;
1178}
1179
1180static __poll_t iss_video_poll(struct file *file, poll_table *wait)
1181{
1182 struct iss_video_fh *vfh = to_iss_video_fh(file->private_data);
1183
1184 return vb2_poll(&vfh->queue, file, wait);
1185}
1186
1187static int iss_video_mmap(struct file *file, struct vm_area_struct *vma)
1188{
1189 struct iss_video_fh *vfh = to_iss_video_fh(file->private_data);
1190
1191 return vb2_mmap(&vfh->queue, vma);
1192}
1193
1194static const struct v4l2_file_operations iss_video_fops = {
1195 .owner = THIS_MODULE,
1196 .unlocked_ioctl = video_ioctl2,
1197 .open = iss_video_open,
1198 .release = iss_video_release,
1199 .poll = iss_video_poll,
1200 .mmap = iss_video_mmap,
1201};
1202
1203
1204
1205
1206
1207static const struct iss_video_operations iss_video_dummy_ops = {
1208};
1209
1210int omap4iss_video_init(struct iss_video *video, const char *name)
1211{
1212 const char *direction;
1213 int ret;
1214
1215 switch (video->type) {
1216 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
1217 direction = "output";
1218 video->pad.flags = MEDIA_PAD_FL_SINK;
1219 break;
1220 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
1221 direction = "input";
1222 video->pad.flags = MEDIA_PAD_FL_SOURCE;
1223 break;
1224
1225 default:
1226 return -EINVAL;
1227 }
1228
1229 ret = media_entity_pads_init(&video->video.entity, 1, &video->pad);
1230 if (ret < 0)
1231 return ret;
1232
1233 spin_lock_init(&video->qlock);
1234 mutex_init(&video->mutex);
1235 atomic_set(&video->active, 0);
1236
1237 spin_lock_init(&video->pipe.lock);
1238 mutex_init(&video->stream_lock);
1239
1240
1241 if (!video->ops)
1242 video->ops = &iss_video_dummy_ops;
1243
1244 video->video.fops = &iss_video_fops;
1245 snprintf(video->video.name, sizeof(video->video.name),
1246 "OMAP4 ISS %s %s", name, direction);
1247 video->video.vfl_type = VFL_TYPE_GRABBER;
1248 video->video.release = video_device_release_empty;
1249 video->video.ioctl_ops = &iss_video_ioctl_ops;
1250 video->pipe.stream_state = ISS_PIPELINE_STREAM_STOPPED;
1251
1252 video_set_drvdata(&video->video, video);
1253
1254 return 0;
1255}
1256
1257void omap4iss_video_cleanup(struct iss_video *video)
1258{
1259 media_entity_cleanup(&video->video.entity);
1260 mutex_destroy(&video->stream_lock);
1261 mutex_destroy(&video->mutex);
1262}
1263
1264int omap4iss_video_register(struct iss_video *video, struct v4l2_device *vdev)
1265{
1266 int ret;
1267
1268 video->video.v4l2_dev = vdev;
1269 if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
1270 video->video.device_caps = V4L2_CAP_VIDEO_CAPTURE;
1271 else
1272 video->video.device_caps = V4L2_CAP_VIDEO_OUTPUT;
1273 video->video.device_caps |= V4L2_CAP_STREAMING;
1274
1275 ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1);
1276 if (ret < 0)
1277 dev_err(video->iss->dev,
1278 "could not register video device (%d)\n", ret);
1279
1280 return ret;
1281}
1282
1283void omap4iss_video_unregister(struct iss_video *video)
1284{
1285 video_unregister_device(&video->video);
1286}
1287