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