2 * vsp1_histo.c -- R-Car VSP1 Histogram API
4 * Copyright (C) 2016 Renesas Electronics Corporation
5 * Copyright (C) 2016 Laurent Pinchart
7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
15 #include <linux/device.h>
16 #include <linux/gfp.h>
18 #include <media/v4l2-ioctl.h>
19 #include <media/v4l2-subdev.h>
20 #include <media/videobuf2-vmalloc.h>
23 #include "vsp1_histo.h"
24 #include "vsp1_pipe.h"
26 #define HISTO_MIN_SIZE 4U
27 #define HISTO_MAX_SIZE 8192U
29 /* -----------------------------------------------------------------------------
33 static inline struct vsp1_histogram_buffer
*
34 to_vsp1_histogram_buffer(struct vb2_v4l2_buffer
*vbuf
)
36 return container_of(vbuf
, struct vsp1_histogram_buffer
, buf
);
39 struct vsp1_histogram_buffer
*
40 vsp1_histogram_buffer_get(struct vsp1_histogram
*histo
)
42 struct vsp1_histogram_buffer
*buf
= NULL
;
45 spin_lock_irqsave(&histo
->irqlock
, flags
);
47 if (list_empty(&histo
->irqqueue
))
50 buf
= list_first_entry(&histo
->irqqueue
, struct vsp1_histogram_buffer
,
52 list_del(&buf
->queue
);
53 histo
->readout
= true;
56 spin_unlock_irqrestore(&histo
->irqlock
, flags
);
60 void vsp1_histogram_buffer_complete(struct vsp1_histogram
*histo
,
61 struct vsp1_histogram_buffer
*buf
,
64 struct vsp1_pipeline
*pipe
= histo
->pipe
;
68 * The pipeline pointer is guaranteed to be valid as this function is
69 * called from the frame completion interrupt handler, which can only
70 * occur when video streaming is active.
72 buf
->buf
.sequence
= pipe
->sequence
;
73 buf
->buf
.vb2_buf
.timestamp
= ktime_get_ns();
74 vb2_set_plane_payload(&buf
->buf
.vb2_buf
, 0, size
);
75 vb2_buffer_done(&buf
->buf
.vb2_buf
, VB2_BUF_STATE_DONE
);
77 spin_lock_irqsave(&histo
->irqlock
, flags
);
78 histo
->readout
= false;
79 wake_up(&histo
->wait_queue
);
80 spin_unlock_irqrestore(&histo
->irqlock
, flags
);
83 /* -----------------------------------------------------------------------------
84 * videobuf2 Queue Operations
87 static int histo_queue_setup(struct vb2_queue
*vq
, unsigned int *nbuffers
,
88 unsigned int *nplanes
, unsigned int sizes
[],
89 struct device
*alloc_devs
[])
91 struct vsp1_histogram
*histo
= vb2_get_drv_priv(vq
);
97 if (sizes
[0] < histo
->data_size
)
104 sizes
[0] = histo
->data_size
;
109 static int histo_buffer_prepare(struct vb2_buffer
*vb
)
111 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
112 struct vsp1_histogram
*histo
= vb2_get_drv_priv(vb
->vb2_queue
);
113 struct vsp1_histogram_buffer
*buf
= to_vsp1_histogram_buffer(vbuf
);
115 if (vb
->num_planes
!= 1)
118 if (vb2_plane_size(vb
, 0) < histo
->data_size
)
121 buf
->addr
= vb2_plane_vaddr(vb
, 0);
126 static void histo_buffer_queue(struct vb2_buffer
*vb
)
128 struct vb2_v4l2_buffer
*vbuf
= to_vb2_v4l2_buffer(vb
);
129 struct vsp1_histogram
*histo
= vb2_get_drv_priv(vb
->vb2_queue
);
130 struct vsp1_histogram_buffer
*buf
= to_vsp1_histogram_buffer(vbuf
);
133 spin_lock_irqsave(&histo
->irqlock
, flags
);
134 list_add_tail(&buf
->queue
, &histo
->irqqueue
);
135 spin_unlock_irqrestore(&histo
->irqlock
, flags
);
138 static int histo_start_streaming(struct vb2_queue
*vq
, unsigned int count
)
143 static void histo_stop_streaming(struct vb2_queue
*vq
)
145 struct vsp1_histogram
*histo
= vb2_get_drv_priv(vq
);
146 struct vsp1_histogram_buffer
*buffer
;
149 spin_lock_irqsave(&histo
->irqlock
, flags
);
151 /* Remove all buffers from the IRQ queue. */
152 list_for_each_entry(buffer
, &histo
->irqqueue
, queue
)
153 vb2_buffer_done(&buffer
->buf
.vb2_buf
, VB2_BUF_STATE_ERROR
);
154 INIT_LIST_HEAD(&histo
->irqqueue
);
156 /* Wait for the buffer being read out (if any) to complete. */
157 wait_event_lock_irq(histo
->wait_queue
, !histo
->readout
, histo
->irqlock
);
159 spin_unlock_irqrestore(&histo
->irqlock
, flags
);
162 static const struct vb2_ops histo_video_queue_qops
= {
163 .queue_setup
= histo_queue_setup
,
164 .buf_prepare
= histo_buffer_prepare
,
165 .buf_queue
= histo_buffer_queue
,
166 .wait_prepare
= vb2_ops_wait_prepare
,
167 .wait_finish
= vb2_ops_wait_finish
,
168 .start_streaming
= histo_start_streaming
,
169 .stop_streaming
= histo_stop_streaming
,
172 /* -----------------------------------------------------------------------------
173 * V4L2 Subdevice Operations
176 static int histo_enum_mbus_code(struct v4l2_subdev
*subdev
,
177 struct v4l2_subdev_pad_config
*cfg
,
178 struct v4l2_subdev_mbus_code_enum
*code
)
180 struct vsp1_histogram
*histo
= subdev_to_histo(subdev
);
182 if (code
->pad
== HISTO_PAD_SOURCE
) {
183 code
->code
= MEDIA_BUS_FMT_FIXED
;
187 return vsp1_subdev_enum_mbus_code(subdev
, cfg
, code
, histo
->formats
,
191 static int histo_enum_frame_size(struct v4l2_subdev
*subdev
,
192 struct v4l2_subdev_pad_config
*cfg
,
193 struct v4l2_subdev_frame_size_enum
*fse
)
195 if (fse
->pad
!= HISTO_PAD_SINK
)
198 return vsp1_subdev_enum_frame_size(subdev
, cfg
, fse
, HISTO_MIN_SIZE
,
199 HISTO_MIN_SIZE
, HISTO_MAX_SIZE
,
203 static int histo_get_selection(struct v4l2_subdev
*subdev
,
204 struct v4l2_subdev_pad_config
*cfg
,
205 struct v4l2_subdev_selection
*sel
)
207 struct vsp1_histogram
*histo
= subdev_to_histo(subdev
);
208 struct v4l2_subdev_pad_config
*config
;
209 struct v4l2_mbus_framefmt
*format
;
210 struct v4l2_rect
*crop
;
213 if (sel
->pad
!= HISTO_PAD_SINK
)
216 mutex_lock(&histo
->entity
.lock
);
218 config
= vsp1_entity_get_pad_config(&histo
->entity
, cfg
, sel
->which
);
224 switch (sel
->target
) {
225 case V4L2_SEL_TGT_COMPOSE_BOUNDS
:
226 case V4L2_SEL_TGT_COMPOSE_DEFAULT
:
227 crop
= vsp1_entity_get_pad_selection(&histo
->entity
, config
,
232 sel
->r
.width
= crop
->width
;
233 sel
->r
.height
= crop
->height
;
236 case V4L2_SEL_TGT_CROP_BOUNDS
:
237 case V4L2_SEL_TGT_CROP_DEFAULT
:
238 format
= vsp1_entity_get_pad_format(&histo
->entity
, config
,
242 sel
->r
.width
= format
->width
;
243 sel
->r
.height
= format
->height
;
246 case V4L2_SEL_TGT_COMPOSE
:
247 case V4L2_SEL_TGT_CROP
:
248 sel
->r
= *vsp1_entity_get_pad_selection(&histo
->entity
, config
,
249 sel
->pad
, sel
->target
);
258 mutex_unlock(&histo
->entity
.lock
);
262 static int histo_set_crop(struct v4l2_subdev
*subdev
,
263 struct v4l2_subdev_pad_config
*config
,
264 struct v4l2_subdev_selection
*sel
)
266 struct vsp1_histogram
*histo
= subdev_to_histo(subdev
);
267 struct v4l2_mbus_framefmt
*format
;
268 struct v4l2_rect
*selection
;
270 /* The crop rectangle must be inside the input frame. */
271 format
= vsp1_entity_get_pad_format(&histo
->entity
, config
,
273 sel
->r
.left
= clamp_t(unsigned int, sel
->r
.left
, 0, format
->width
- 1);
274 sel
->r
.top
= clamp_t(unsigned int, sel
->r
.top
, 0, format
->height
- 1);
275 sel
->r
.width
= clamp_t(unsigned int, sel
->r
.width
, HISTO_MIN_SIZE
,
276 format
->width
- sel
->r
.left
);
277 sel
->r
.height
= clamp_t(unsigned int, sel
->r
.height
, HISTO_MIN_SIZE
,
278 format
->height
- sel
->r
.top
);
280 /* Set the crop rectangle and reset the compose rectangle. */
281 selection
= vsp1_entity_get_pad_selection(&histo
->entity
, config
,
282 sel
->pad
, V4L2_SEL_TGT_CROP
);
285 selection
= vsp1_entity_get_pad_selection(&histo
->entity
, config
,
287 V4L2_SEL_TGT_COMPOSE
);
293 static int histo_set_compose(struct v4l2_subdev
*subdev
,
294 struct v4l2_subdev_pad_config
*config
,
295 struct v4l2_subdev_selection
*sel
)
297 struct vsp1_histogram
*histo
= subdev_to_histo(subdev
);
298 struct v4l2_rect
*compose
;
299 struct v4l2_rect
*crop
;
303 * The compose rectangle is used to configure downscaling, the top left
304 * corner is fixed to (0,0) and the size to 1/2 or 1/4 of the crop
310 crop
= vsp1_entity_get_pad_selection(&histo
->entity
, config
, sel
->pad
,
314 * Clamp the width and height to acceptable values first and then
315 * compute the closest rounded dividing ratio.
317 * Ratio Rounded ratio
318 * --------------------------
323 * The rounded ratio can be computed using
325 * 1 << (ceil(ratio * 2) / 3)
327 sel
->r
.width
= clamp(sel
->r
.width
, crop
->width
/ 4, crop
->width
);
328 ratio
= 1 << (crop
->width
* 2 / sel
->r
.width
/ 3);
329 sel
->r
.width
= crop
->width
/ ratio
;
332 sel
->r
.height
= clamp(sel
->r
.height
, crop
->height
/ 4, crop
->height
);
333 ratio
= 1 << (crop
->height
* 2 / sel
->r
.height
/ 3);
334 sel
->r
.height
= crop
->height
/ ratio
;
336 compose
= vsp1_entity_get_pad_selection(&histo
->entity
, config
,
338 V4L2_SEL_TGT_COMPOSE
);
344 static int histo_set_selection(struct v4l2_subdev
*subdev
,
345 struct v4l2_subdev_pad_config
*cfg
,
346 struct v4l2_subdev_selection
*sel
)
348 struct vsp1_histogram
*histo
= subdev_to_histo(subdev
);
349 struct v4l2_subdev_pad_config
*config
;
352 if (sel
->pad
!= HISTO_PAD_SINK
)
355 mutex_lock(&histo
->entity
.lock
);
357 config
= vsp1_entity_get_pad_config(&histo
->entity
, cfg
, sel
->which
);
363 if (sel
->target
== V4L2_SEL_TGT_CROP
)
364 ret
= histo_set_crop(subdev
, config
, sel
);
365 else if (sel
->target
== V4L2_SEL_TGT_COMPOSE
)
366 ret
= histo_set_compose(subdev
, config
, sel
);
371 mutex_unlock(&histo
->entity
.lock
);
375 static int histo_get_format(struct v4l2_subdev
*subdev
,
376 struct v4l2_subdev_pad_config
*cfg
,
377 struct v4l2_subdev_format
*fmt
)
379 if (fmt
->pad
== HISTO_PAD_SOURCE
) {
380 fmt
->format
.code
= MEDIA_BUS_FMT_FIXED
;
381 fmt
->format
.width
= 0;
382 fmt
->format
.height
= 0;
383 fmt
->format
.field
= V4L2_FIELD_NONE
;
384 fmt
->format
.colorspace
= V4L2_COLORSPACE_RAW
;
388 return vsp1_subdev_get_pad_format(subdev
, cfg
, fmt
);
391 static int histo_set_format(struct v4l2_subdev
*subdev
,
392 struct v4l2_subdev_pad_config
*cfg
,
393 struct v4l2_subdev_format
*fmt
)
395 struct vsp1_histogram
*histo
= subdev_to_histo(subdev
);
396 struct v4l2_subdev_pad_config
*config
;
397 struct v4l2_mbus_framefmt
*format
;
398 struct v4l2_rect
*selection
;
402 if (fmt
->pad
!= HISTO_PAD_SINK
)
403 return histo_get_format(subdev
, cfg
, fmt
);
405 mutex_lock(&histo
->entity
.lock
);
407 config
= vsp1_entity_get_pad_config(&histo
->entity
, cfg
, fmt
->which
);
414 * Default to the first format if the requested format is not
417 for (i
= 0; i
< histo
->num_formats
; ++i
) {
418 if (fmt
->format
.code
== histo
->formats
[i
])
421 if (i
== histo
->num_formats
)
422 fmt
->format
.code
= histo
->formats
[0];
424 format
= vsp1_entity_get_pad_format(&histo
->entity
, config
, fmt
->pad
);
426 format
->code
= fmt
->format
.code
;
427 format
->width
= clamp_t(unsigned int, fmt
->format
.width
,
428 HISTO_MIN_SIZE
, HISTO_MAX_SIZE
);
429 format
->height
= clamp_t(unsigned int, fmt
->format
.height
,
430 HISTO_MIN_SIZE
, HISTO_MAX_SIZE
);
431 format
->field
= V4L2_FIELD_NONE
;
432 format
->colorspace
= V4L2_COLORSPACE_SRGB
;
434 fmt
->format
= *format
;
436 /* Reset the crop and compose rectangles */
437 selection
= vsp1_entity_get_pad_selection(&histo
->entity
, config
,
438 fmt
->pad
, V4L2_SEL_TGT_CROP
);
441 selection
->width
= format
->width
;
442 selection
->height
= format
->height
;
444 selection
= vsp1_entity_get_pad_selection(&histo
->entity
, config
,
446 V4L2_SEL_TGT_COMPOSE
);
449 selection
->width
= format
->width
;
450 selection
->height
= format
->height
;
453 mutex_unlock(&histo
->entity
.lock
);
457 static const struct v4l2_subdev_pad_ops histo_pad_ops
= {
458 .enum_mbus_code
= histo_enum_mbus_code
,
459 .enum_frame_size
= histo_enum_frame_size
,
460 .get_fmt
= histo_get_format
,
461 .set_fmt
= histo_set_format
,
462 .get_selection
= histo_get_selection
,
463 .set_selection
= histo_set_selection
,
466 static const struct v4l2_subdev_ops histo_ops
= {
467 .pad
= &histo_pad_ops
,
470 /* -----------------------------------------------------------------------------
474 static int histo_v4l2_querycap(struct file
*file
, void *fh
,
475 struct v4l2_capability
*cap
)
477 struct v4l2_fh
*vfh
= file
->private_data
;
478 struct vsp1_histogram
*histo
= vdev_to_histo(vfh
->vdev
);
480 cap
->capabilities
= V4L2_CAP_DEVICE_CAPS
| V4L2_CAP_STREAMING
481 | V4L2_CAP_VIDEO_CAPTURE_MPLANE
482 | V4L2_CAP_VIDEO_OUTPUT_MPLANE
483 | V4L2_CAP_META_CAPTURE
;
484 cap
->device_caps
= V4L2_CAP_META_CAPTURE
485 | V4L2_CAP_STREAMING
;
487 strlcpy(cap
->driver
, "vsp1", sizeof(cap
->driver
));
488 strlcpy(cap
->card
, histo
->video
.name
, sizeof(cap
->card
));
489 snprintf(cap
->bus_info
, sizeof(cap
->bus_info
), "platform:%s",
490 dev_name(histo
->entity
.vsp1
->dev
));
495 static int histo_v4l2_enum_format(struct file
*file
, void *fh
,
496 struct v4l2_fmtdesc
*f
)
498 struct v4l2_fh
*vfh
= file
->private_data
;
499 struct vsp1_histogram
*histo
= vdev_to_histo(vfh
->vdev
);
501 if (f
->index
> 0 || f
->type
!= histo
->queue
.type
)
504 f
->pixelformat
= histo
->meta_format
;
509 static int histo_v4l2_get_format(struct file
*file
, void *fh
,
510 struct v4l2_format
*format
)
512 struct v4l2_fh
*vfh
= file
->private_data
;
513 struct vsp1_histogram
*histo
= vdev_to_histo(vfh
->vdev
);
514 struct v4l2_meta_format
*meta
= &format
->fmt
.meta
;
516 if (format
->type
!= histo
->queue
.type
)
519 memset(meta
, 0, sizeof(*meta
));
521 meta
->dataformat
= histo
->meta_format
;
522 meta
->buffersize
= histo
->data_size
;
527 static const struct v4l2_ioctl_ops histo_v4l2_ioctl_ops
= {
528 .vidioc_querycap
= histo_v4l2_querycap
,
529 .vidioc_enum_fmt_meta_cap
= histo_v4l2_enum_format
,
530 .vidioc_g_fmt_meta_cap
= histo_v4l2_get_format
,
531 .vidioc_s_fmt_meta_cap
= histo_v4l2_get_format
,
532 .vidioc_try_fmt_meta_cap
= histo_v4l2_get_format
,
533 .vidioc_reqbufs
= vb2_ioctl_reqbufs
,
534 .vidioc_querybuf
= vb2_ioctl_querybuf
,
535 .vidioc_qbuf
= vb2_ioctl_qbuf
,
536 .vidioc_dqbuf
= vb2_ioctl_dqbuf
,
537 .vidioc_create_bufs
= vb2_ioctl_create_bufs
,
538 .vidioc_prepare_buf
= vb2_ioctl_prepare_buf
,
539 .vidioc_streamon
= vb2_ioctl_streamon
,
540 .vidioc_streamoff
= vb2_ioctl_streamoff
,
543 /* -----------------------------------------------------------------------------
544 * V4L2 File Operations
547 static const struct v4l2_file_operations histo_v4l2_fops
= {
548 .owner
= THIS_MODULE
,
549 .unlocked_ioctl
= video_ioctl2
,
550 .open
= v4l2_fh_open
,
551 .release
= vb2_fop_release
,
552 .poll
= vb2_fop_poll
,
553 .mmap
= vb2_fop_mmap
,
556 static void vsp1_histogram_cleanup(struct vsp1_histogram
*histo
)
558 if (video_is_registered(&histo
->video
))
559 video_unregister_device(&histo
->video
);
561 media_entity_cleanup(&histo
->video
.entity
);
564 void vsp1_histogram_destroy(struct vsp1_entity
*entity
)
566 struct vsp1_histogram
*histo
= subdev_to_histo(&entity
->subdev
);
568 vsp1_histogram_cleanup(histo
);
571 int vsp1_histogram_init(struct vsp1_device
*vsp1
, struct vsp1_histogram
*histo
,
572 enum vsp1_entity_type type
, const char *name
,
573 const struct vsp1_entity_operations
*ops
,
574 const unsigned int *formats
, unsigned int num_formats
,
575 size_t data_size
, u32 meta_format
)
579 histo
->formats
= formats
;
580 histo
->num_formats
= num_formats
;
581 histo
->data_size
= data_size
;
582 histo
->meta_format
= meta_format
;
584 histo
->pad
.flags
= MEDIA_PAD_FL_SINK
;
585 histo
->video
.vfl_dir
= VFL_DIR_RX
;
587 mutex_init(&histo
->lock
);
588 spin_lock_init(&histo
->irqlock
);
589 INIT_LIST_HEAD(&histo
->irqqueue
);
590 init_waitqueue_head(&histo
->wait_queue
);
592 /* Initialize the VSP entity... */
593 histo
->entity
.ops
= ops
;
594 histo
->entity
.type
= type
;
596 ret
= vsp1_entity_init(vsp1
, &histo
->entity
, name
, 2, &histo_ops
,
597 MEDIA_ENT_F_PROC_VIDEO_STATISTICS
);
601 /* ... and the media entity... */
602 ret
= media_entity_pads_init(&histo
->video
.entity
, 1, &histo
->pad
);
606 /* ... and the video node... */
607 histo
->video
.v4l2_dev
= &vsp1
->v4l2_dev
;
608 histo
->video
.fops
= &histo_v4l2_fops
;
609 snprintf(histo
->video
.name
, sizeof(histo
->video
.name
),
610 "%s histo", histo
->entity
.subdev
.name
);
611 histo
->video
.vfl_type
= VFL_TYPE_GRABBER
;
612 histo
->video
.release
= video_device_release_empty
;
613 histo
->video
.ioctl_ops
= &histo_v4l2_ioctl_ops
;
615 video_set_drvdata(&histo
->video
, histo
);
617 /* ... and the buffers queue... */
618 histo
->queue
.type
= V4L2_BUF_TYPE_META_CAPTURE
;
619 histo
->queue
.io_modes
= VB2_MMAP
| VB2_USERPTR
| VB2_DMABUF
;
620 histo
->queue
.lock
= &histo
->lock
;
621 histo
->queue
.drv_priv
= histo
;
622 histo
->queue
.buf_struct_size
= sizeof(struct vsp1_histogram_buffer
);
623 histo
->queue
.ops
= &histo_video_queue_qops
;
624 histo
->queue
.mem_ops
= &vb2_vmalloc_memops
;
625 histo
->queue
.timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
626 histo
->queue
.dev
= vsp1
->dev
;
627 ret
= vb2_queue_init(&histo
->queue
);
629 dev_err(vsp1
->dev
, "failed to initialize vb2 queue\n");
633 /* ... and register the video device. */
634 histo
->video
.queue
= &histo
->queue
;
635 ret
= video_register_device(&histo
->video
, VFL_TYPE_GRABBER
, -1);
637 dev_err(vsp1
->dev
, "failed to register video device\n");
644 vsp1_histogram_cleanup(histo
);