2 * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
3 * Copyright (C) 2017 Linaro Ltd.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 and
7 * only version 2 as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <linux/clk.h>
16 #include <linux/module.h>
17 #include <linux/mod_devicetable.h>
18 #include <linux/platform_device.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/slab.h>
21 #include <media/v4l2-ioctl.h>
22 #include <media/v4l2-event.h>
23 #include <media/v4l2-ctrls.h>
24 #include <media/v4l2-mem2mem.h>
25 #include <media/videobuf2-dma-sg.h>
27 #include "hfi_venus_io.h"
28 #include "hfi_parser.h"
34 * Three resons to keep MPLANE formats (despite that the number of planes
36 * - the MPLANE formats allow only one plane to be used
37 * - the downstream driver use MPLANE formats too
38 * - future firmware versions could add support for >1 planes
40 static const struct venus_format vdec_formats
[] = {
42 .pixfmt
= V4L2_PIX_FMT_NV12
,
44 .type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
,
46 .pixfmt
= V4L2_PIX_FMT_MPEG4
,
48 .type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
,
50 .pixfmt
= V4L2_PIX_FMT_MPEG2
,
52 .type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
,
54 .pixfmt
= V4L2_PIX_FMT_H263
,
56 .type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
,
58 .pixfmt
= V4L2_PIX_FMT_VC1_ANNEX_G
,
60 .type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
,
62 .pixfmt
= V4L2_PIX_FMT_VC1_ANNEX_L
,
64 .type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
,
66 .pixfmt
= V4L2_PIX_FMT_H264
,
68 .type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
,
70 .pixfmt
= V4L2_PIX_FMT_VP8
,
72 .type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
,
74 .pixfmt
= V4L2_PIX_FMT_VP9
,
76 .type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
,
78 .pixfmt
= V4L2_PIX_FMT_XVID
,
80 .type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
,
82 .pixfmt
= V4L2_PIX_FMT_HEVC
,
84 .type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
,
88 static const struct venus_format
*
89 find_format(struct venus_inst
*inst
, u32 pixfmt
, u32 type
)
91 const struct venus_format
*fmt
= vdec_formats
;
92 unsigned int size
= ARRAY_SIZE(vdec_formats
);
95 for (i
= 0; i
< size
; i
++) {
96 if (fmt
[i
].pixfmt
== pixfmt
)
100 if (i
== size
|| fmt
[i
].type
!= type
)
103 if (type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
&&
104 !venus_helper_check_codec(inst
, fmt
[i
].pixfmt
))
110 static const struct venus_format
*
111 find_format_by_index(struct venus_inst
*inst
, unsigned int index
, u32 type
)
113 const struct venus_format
*fmt
= vdec_formats
;
114 unsigned int size
= ARRAY_SIZE(vdec_formats
);
115 unsigned int i
, k
= 0;
120 for (i
= 0; i
< size
; i
++) {
123 if (fmt
[i
].type
!= type
)
125 valid
= type
!= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
||
126 venus_helper_check_codec(inst
, fmt
[i
].pixfmt
);
127 if (k
== index
&& valid
)
139 static const struct venus_format
*
140 vdec_try_fmt_common(struct venus_inst
*inst
, struct v4l2_format
*f
)
142 struct v4l2_pix_format_mplane
*pixmp
= &f
->fmt
.pix_mp
;
143 struct v4l2_plane_pix_format
*pfmt
= pixmp
->plane_fmt
;
144 const struct venus_format
*fmt
;
146 memset(pfmt
[0].reserved
, 0, sizeof(pfmt
[0].reserved
));
147 memset(pixmp
->reserved
, 0, sizeof(pixmp
->reserved
));
149 fmt
= find_format(inst
, pixmp
->pixelformat
, f
->type
);
151 if (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
)
152 pixmp
->pixelformat
= V4L2_PIX_FMT_NV12
;
153 else if (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
154 pixmp
->pixelformat
= V4L2_PIX_FMT_H264
;
157 fmt
= find_format(inst
, pixmp
->pixelformat
, f
->type
);
160 pixmp
->width
= clamp(pixmp
->width
, frame_width_min(inst
),
161 frame_width_max(inst
));
162 pixmp
->height
= clamp(pixmp
->height
, frame_height_min(inst
),
163 frame_height_max(inst
));
165 if (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
)
166 pixmp
->height
= ALIGN(pixmp
->height
, 32);
168 if (pixmp
->field
== V4L2_FIELD_ANY
)
169 pixmp
->field
= V4L2_FIELD_NONE
;
170 pixmp
->num_planes
= fmt
->num_planes
;
173 pfmt
[0].sizeimage
= venus_helper_get_framesz(pixmp
->pixelformat
,
177 if (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
)
178 pfmt
[0].bytesperline
= ALIGN(pixmp
->width
, 128);
180 pfmt
[0].bytesperline
= 0;
185 static int vdec_try_fmt(struct file
*file
, void *fh
, struct v4l2_format
*f
)
187 struct venus_inst
*inst
= to_inst(file
);
189 vdec_try_fmt_common(inst
, f
);
194 static int vdec_g_fmt(struct file
*file
, void *fh
, struct v4l2_format
*f
)
196 struct venus_inst
*inst
= to_inst(file
);
197 const struct venus_format
*fmt
= NULL
;
198 struct v4l2_pix_format_mplane
*pixmp
= &f
->fmt
.pix_mp
;
200 if (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
)
202 else if (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
205 if (inst
->reconfig
) {
206 struct v4l2_format format
= {};
208 inst
->out_width
= inst
->reconfig_width
;
209 inst
->out_height
= inst
->reconfig_height
;
210 inst
->reconfig
= false;
212 format
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
213 format
.fmt
.pix_mp
.pixelformat
= inst
->fmt_cap
->pixfmt
;
214 format
.fmt
.pix_mp
.width
= inst
->out_width
;
215 format
.fmt
.pix_mp
.height
= inst
->out_height
;
217 vdec_try_fmt_common(inst
, &format
);
219 inst
->width
= format
.fmt
.pix_mp
.width
;
220 inst
->height
= format
.fmt
.pix_mp
.height
;
223 pixmp
->pixelformat
= fmt
->pixfmt
;
225 if (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
) {
226 pixmp
->width
= inst
->width
;
227 pixmp
->height
= inst
->height
;
228 pixmp
->colorspace
= inst
->colorspace
;
229 pixmp
->ycbcr_enc
= inst
->ycbcr_enc
;
230 pixmp
->quantization
= inst
->quantization
;
231 pixmp
->xfer_func
= inst
->xfer_func
;
232 } else if (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
) {
233 pixmp
->width
= inst
->out_width
;
234 pixmp
->height
= inst
->out_height
;
237 vdec_try_fmt_common(inst
, f
);
242 static int vdec_s_fmt(struct file
*file
, void *fh
, struct v4l2_format
*f
)
244 struct venus_inst
*inst
= to_inst(file
);
245 struct v4l2_pix_format_mplane
*pixmp
= &f
->fmt
.pix_mp
;
246 struct v4l2_pix_format_mplane orig_pixmp
;
247 const struct venus_format
*fmt
;
248 struct v4l2_format format
;
249 u32 pixfmt_out
= 0, pixfmt_cap
= 0;
253 fmt
= vdec_try_fmt_common(inst
, f
);
255 if (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
) {
256 pixfmt_out
= pixmp
->pixelformat
;
257 pixfmt_cap
= inst
->fmt_cap
->pixfmt
;
258 } else if (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
) {
259 pixfmt_cap
= pixmp
->pixelformat
;
260 pixfmt_out
= inst
->fmt_out
->pixfmt
;
263 memset(&format
, 0, sizeof(format
));
265 format
.type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
266 format
.fmt
.pix_mp
.pixelformat
= pixfmt_out
;
267 format
.fmt
.pix_mp
.width
= orig_pixmp
.width
;
268 format
.fmt
.pix_mp
.height
= orig_pixmp
.height
;
269 vdec_try_fmt_common(inst
, &format
);
271 if (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
) {
272 inst
->out_width
= format
.fmt
.pix_mp
.width
;
273 inst
->out_height
= format
.fmt
.pix_mp
.height
;
274 inst
->colorspace
= pixmp
->colorspace
;
275 inst
->ycbcr_enc
= pixmp
->ycbcr_enc
;
276 inst
->quantization
= pixmp
->quantization
;
277 inst
->xfer_func
= pixmp
->xfer_func
;
280 memset(&format
, 0, sizeof(format
));
282 format
.type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
283 format
.fmt
.pix_mp
.pixelformat
= pixfmt_cap
;
284 format
.fmt
.pix_mp
.width
= orig_pixmp
.width
;
285 format
.fmt
.pix_mp
.height
= orig_pixmp
.height
;
286 vdec_try_fmt_common(inst
, &format
);
288 inst
->width
= format
.fmt
.pix_mp
.width
;
289 inst
->height
= format
.fmt
.pix_mp
.height
;
291 if (f
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
293 else if (f
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
)
300 vdec_g_selection(struct file
*file
, void *fh
, struct v4l2_selection
*s
)
302 struct venus_inst
*inst
= to_inst(file
);
304 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
&&
305 s
->type
!= V4L2_BUF_TYPE_VIDEO_OUTPUT
)
309 case V4L2_SEL_TGT_CROP_BOUNDS
:
310 case V4L2_SEL_TGT_CROP_DEFAULT
:
311 case V4L2_SEL_TGT_CROP
:
312 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_OUTPUT
)
314 s
->r
.width
= inst
->out_width
;
315 s
->r
.height
= inst
->out_height
;
317 case V4L2_SEL_TGT_COMPOSE_BOUNDS
:
318 case V4L2_SEL_TGT_COMPOSE_PADDED
:
319 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
321 s
->r
.width
= inst
->width
;
322 s
->r
.height
= inst
->height
;
324 case V4L2_SEL_TGT_COMPOSE_DEFAULT
:
325 case V4L2_SEL_TGT_COMPOSE
:
326 if (s
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE
)
328 s
->r
.width
= inst
->out_width
;
329 s
->r
.height
= inst
->out_height
;
342 vdec_querycap(struct file
*file
, void *fh
, struct v4l2_capability
*cap
)
344 strlcpy(cap
->driver
, "qcom-venus", sizeof(cap
->driver
));
345 strlcpy(cap
->card
, "Qualcomm Venus video decoder", sizeof(cap
->card
));
346 strlcpy(cap
->bus_info
, "platform:qcom-venus", sizeof(cap
->bus_info
));
351 static int vdec_enum_fmt(struct file
*file
, void *fh
, struct v4l2_fmtdesc
*f
)
353 struct venus_inst
*inst
= to_inst(file
);
354 const struct venus_format
*fmt
;
356 memset(f
->reserved
, 0, sizeof(f
->reserved
));
358 fmt
= find_format_by_index(inst
, f
->index
, f
->type
);
362 f
->pixelformat
= fmt
->pixfmt
;
367 static int vdec_s_parm(struct file
*file
, void *fh
, struct v4l2_streamparm
*a
)
369 struct venus_inst
*inst
= to_inst(file
);
370 struct v4l2_captureparm
*cap
= &a
->parm
.capture
;
371 struct v4l2_fract
*timeperframe
= &cap
->timeperframe
;
372 u64 us_per_frame
, fps
;
374 if (a
->type
!= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
&&
375 a
->type
!= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
378 memset(cap
->reserved
, 0, sizeof(cap
->reserved
));
379 if (!timeperframe
->denominator
)
380 timeperframe
->denominator
= inst
->timeperframe
.denominator
;
381 if (!timeperframe
->numerator
)
382 timeperframe
->numerator
= inst
->timeperframe
.numerator
;
383 cap
->readbuffers
= 0;
384 cap
->extendedmode
= 0;
385 cap
->capability
= V4L2_CAP_TIMEPERFRAME
;
386 us_per_frame
= timeperframe
->numerator
* (u64
)USEC_PER_SEC
;
387 do_div(us_per_frame
, timeperframe
->denominator
);
392 fps
= (u64
)USEC_PER_SEC
;
393 do_div(fps
, us_per_frame
);
396 inst
->timeperframe
= *timeperframe
;
401 static int vdec_enum_framesizes(struct file
*file
, void *fh
,
402 struct v4l2_frmsizeenum
*fsize
)
404 struct venus_inst
*inst
= to_inst(file
);
405 const struct venus_format
*fmt
;
407 fmt
= find_format(inst
, fsize
->pixel_format
,
408 V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
);
410 fmt
= find_format(inst
, fsize
->pixel_format
,
411 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
);
419 fsize
->type
= V4L2_FRMSIZE_TYPE_STEPWISE
;
421 fsize
->stepwise
.min_width
= frame_width_min(inst
);
422 fsize
->stepwise
.max_width
= frame_width_max(inst
);
423 fsize
->stepwise
.step_width
= frame_width_step(inst
);
424 fsize
->stepwise
.min_height
= frame_height_min(inst
);
425 fsize
->stepwise
.max_height
= frame_height_max(inst
);
426 fsize
->stepwise
.step_height
= frame_height_step(inst
);
431 static int vdec_subscribe_event(struct v4l2_fh
*fh
,
432 const struct v4l2_event_subscription
*sub
)
436 return v4l2_event_subscribe(fh
, sub
, 2, NULL
);
437 case V4L2_EVENT_SOURCE_CHANGE
:
438 return v4l2_src_change_event_subscribe(fh
, sub
);
439 case V4L2_EVENT_CTRL
:
440 return v4l2_ctrl_subscribe_event(fh
, sub
);
447 vdec_try_decoder_cmd(struct file
*file
, void *fh
, struct v4l2_decoder_cmd
*cmd
)
450 case V4L2_DEC_CMD_STOP
:
451 if (cmd
->flags
& V4L2_DEC_CMD_STOP_TO_BLACK
)
462 vdec_decoder_cmd(struct file
*file
, void *fh
, struct v4l2_decoder_cmd
*cmd
)
464 struct venus_inst
*inst
= to_inst(file
);
465 struct hfi_frame_data fdata
= {0};
468 ret
= vdec_try_decoder_cmd(file
, fh
, cmd
);
472 mutex_lock(&inst
->lock
);
475 * Implement V4L2_DEC_CMD_STOP by enqueue an empty buffer on decoder
476 * input to signal EOS.
478 if (!(inst
->streamon_out
& inst
->streamon_cap
))
481 fdata
.buffer_type
= HFI_BUFFER_INPUT
;
482 fdata
.flags
|= HFI_BUFFERFLAG_EOS
;
483 fdata
.device_addr
= 0xdeadbeef;
485 ret
= hfi_session_process_buf(inst
, &fdata
);
488 mutex_unlock(&inst
->lock
);
492 static const struct v4l2_ioctl_ops vdec_ioctl_ops
= {
493 .vidioc_querycap
= vdec_querycap
,
494 .vidioc_enum_fmt_vid_cap_mplane
= vdec_enum_fmt
,
495 .vidioc_enum_fmt_vid_out_mplane
= vdec_enum_fmt
,
496 .vidioc_s_fmt_vid_cap_mplane
= vdec_s_fmt
,
497 .vidioc_s_fmt_vid_out_mplane
= vdec_s_fmt
,
498 .vidioc_g_fmt_vid_cap_mplane
= vdec_g_fmt
,
499 .vidioc_g_fmt_vid_out_mplane
= vdec_g_fmt
,
500 .vidioc_try_fmt_vid_cap_mplane
= vdec_try_fmt
,
501 .vidioc_try_fmt_vid_out_mplane
= vdec_try_fmt
,
502 .vidioc_g_selection
= vdec_g_selection
,
503 .vidioc_reqbufs
= v4l2_m2m_ioctl_reqbufs
,
504 .vidioc_querybuf
= v4l2_m2m_ioctl_querybuf
,
505 .vidioc_create_bufs
= v4l2_m2m_ioctl_create_bufs
,
506 .vidioc_prepare_buf
= v4l2_m2m_ioctl_prepare_buf
,
507 .vidioc_qbuf
= v4l2_m2m_ioctl_qbuf
,
508 .vidioc_expbuf
= v4l2_m2m_ioctl_expbuf
,
509 .vidioc_dqbuf
= v4l2_m2m_ioctl_dqbuf
,
510 .vidioc_streamon
= v4l2_m2m_ioctl_streamon
,
511 .vidioc_streamoff
= v4l2_m2m_ioctl_streamoff
,
512 .vidioc_s_parm
= vdec_s_parm
,
513 .vidioc_enum_framesizes
= vdec_enum_framesizes
,
514 .vidioc_subscribe_event
= vdec_subscribe_event
,
515 .vidioc_unsubscribe_event
= v4l2_event_unsubscribe
,
516 .vidioc_try_decoder_cmd
= vdec_try_decoder_cmd
,
517 .vidioc_decoder_cmd
= vdec_decoder_cmd
,
520 static int vdec_set_properties(struct venus_inst
*inst
)
522 struct vdec_controls
*ctr
= &inst
->controls
.dec
;
523 struct hfi_enable en
= { .enable
= 1 };
527 if (ctr
->post_loop_deb_mode
) {
528 ptype
= HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER
;
529 ret
= hfi_session_set_property(inst
, ptype
, &en
);
537 #define is_ubwc_fmt(fmt) (!!((fmt) & HFI_COLOR_FORMAT_UBWC_BASE))
539 static int vdec_output_conf(struct venus_inst
*inst
)
541 struct venus_core
*core
= inst
->core
;
542 struct hfi_enable en
= { .enable
= 1 };
543 u32 width
= inst
->out_width
;
544 u32 height
= inst
->out_height
;
545 u32 out_fmt
, out2_fmt
;
550 ret
= venus_helper_set_work_mode(inst
, VIDC_WORK_MODE_2
);
554 ret
= venus_helper_set_core_usage(inst
, VIDC_CORE_ID_1
);
558 if (core
->res
->hfi_version
== HFI_VERSION_1XX
) {
559 ptype
= HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER
;
560 ret
= hfi_session_set_property(inst
, ptype
, &en
);
565 /* Force searching UBWC formats for bigger then HD resolutions */
566 if (width
> 1920 && height
> ALIGN(1080, 32))
569 /* For Venus v4 UBWC format is mandatory */
573 ret
= venus_helper_get_out_fmts(inst
, inst
->fmt_cap
->pixfmt
, &out_fmt
,
578 inst
->output_buf_size
=
579 venus_helper_get_framesz_raw(out_fmt
, width
, height
);
580 inst
->output2_buf_size
=
581 venus_helper_get_framesz_raw(out2_fmt
, width
, height
);
583 if (is_ubwc_fmt(out_fmt
)) {
584 inst
->opb_buftype
= HFI_BUFFER_OUTPUT2
;
585 inst
->opb_fmt
= out2_fmt
;
586 inst
->dpb_buftype
= HFI_BUFFER_OUTPUT
;
587 inst
->dpb_fmt
= out_fmt
;
588 } else if (is_ubwc_fmt(out2_fmt
)) {
589 inst
->opb_buftype
= HFI_BUFFER_OUTPUT
;
590 inst
->opb_fmt
= out_fmt
;
591 inst
->dpb_buftype
= HFI_BUFFER_OUTPUT2
;
592 inst
->dpb_fmt
= out2_fmt
;
594 inst
->opb_buftype
= HFI_BUFFER_OUTPUT
;
595 inst
->opb_fmt
= out_fmt
;
596 inst
->dpb_buftype
= 0;
600 ret
= venus_helper_set_raw_format(inst
, inst
->opb_fmt
,
606 ret
= venus_helper_set_multistream(inst
, false, true);
610 ret
= venus_helper_set_raw_format(inst
, inst
->dpb_fmt
,
615 ret
= venus_helper_set_output_resolution(inst
, width
, height
,
621 if (IS_V3(core
) || IS_V4(core
)) {
622 if (inst
->output2_buf_size
) {
623 ret
= venus_helper_set_bufsize(inst
,
624 inst
->output2_buf_size
,
630 if (inst
->output_buf_size
) {
631 ret
= venus_helper_set_bufsize(inst
,
632 inst
->output_buf_size
,
639 ret
= venus_helper_set_dyn_bufmode(inst
);
646 static int vdec_init_session(struct venus_inst
*inst
)
650 ret
= hfi_session_init(inst
, inst
->fmt_out
->pixfmt
);
654 ret
= venus_helper_set_input_resolution(inst
, inst
->out_width
,
659 ret
= venus_helper_set_color_format(inst
, inst
->fmt_cap
->pixfmt
);
665 hfi_session_deinit(inst
);
669 static int vdec_num_buffers(struct venus_inst
*inst
, unsigned int *in_num
,
670 unsigned int *out_num
)
672 enum hfi_version ver
= inst
->core
->res
->hfi_version
;
673 struct hfi_buffer_requirements bufreq
;
676 *in_num
= *out_num
= 0;
678 ret
= vdec_init_session(inst
);
682 ret
= venus_helper_get_bufreq(inst
, HFI_BUFFER_INPUT
, &bufreq
);
686 *in_num
= HFI_BUFREQ_COUNT_MIN(&bufreq
, ver
);
688 ret
= venus_helper_get_bufreq(inst
, HFI_BUFFER_OUTPUT
, &bufreq
);
692 *out_num
= HFI_BUFREQ_COUNT_MIN(&bufreq
, ver
);
695 hfi_session_deinit(inst
);
700 static int vdec_queue_setup(struct vb2_queue
*q
,
701 unsigned int *num_buffers
, unsigned int *num_planes
,
702 unsigned int sizes
[], struct device
*alloc_devs
[])
704 struct venus_inst
*inst
= vb2_get_drv_priv(q
);
705 unsigned int in_num
, out_num
;
709 unsigned int output_buf_size
= venus_helper_get_opb_size(inst
);
711 if (q
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
&&
712 *num_planes
!= inst
->fmt_out
->num_planes
)
715 if (q
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
&&
716 *num_planes
!= inst
->fmt_cap
->num_planes
)
719 if (q
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
&&
720 sizes
[0] < inst
->input_buf_size
)
723 if (q
->type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
&&
724 sizes
[0] < output_buf_size
)
730 ret
= vdec_num_buffers(inst
, &in_num
, &out_num
);
735 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
:
736 *num_planes
= inst
->fmt_out
->num_planes
;
737 sizes
[0] = venus_helper_get_framesz(inst
->fmt_out
->pixfmt
,
740 inst
->input_buf_size
= sizes
[0];
741 *num_buffers
= max(*num_buffers
, in_num
);
742 inst
->num_input_bufs
= *num_buffers
;
743 inst
->num_output_bufs
= out_num
;
745 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
:
746 *num_planes
= inst
->fmt_cap
->num_planes
;
747 sizes
[0] = venus_helper_get_framesz(inst
->fmt_cap
->pixfmt
,
750 inst
->output_buf_size
= sizes
[0];
751 *num_buffers
= max(*num_buffers
, out_num
);
752 inst
->num_output_bufs
= *num_buffers
;
762 static int vdec_verify_conf(struct venus_inst
*inst
)
764 enum hfi_version ver
= inst
->core
->res
->hfi_version
;
765 struct hfi_buffer_requirements bufreq
;
768 if (!inst
->num_input_bufs
|| !inst
->num_output_bufs
)
771 ret
= venus_helper_get_bufreq(inst
, HFI_BUFFER_OUTPUT
, &bufreq
);
775 if (inst
->num_output_bufs
< bufreq
.count_actual
||
776 inst
->num_output_bufs
< HFI_BUFREQ_COUNT_MIN(&bufreq
, ver
))
779 ret
= venus_helper_get_bufreq(inst
, HFI_BUFFER_INPUT
, &bufreq
);
783 if (inst
->num_input_bufs
< HFI_BUFREQ_COUNT_MIN(&bufreq
, ver
))
789 static int vdec_start_streaming(struct vb2_queue
*q
, unsigned int count
)
791 struct venus_inst
*inst
= vb2_get_drv_priv(q
);
794 mutex_lock(&inst
->lock
);
796 if (q
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
797 inst
->streamon_out
= 1;
799 inst
->streamon_cap
= 1;
801 if (!(inst
->streamon_out
& inst
->streamon_cap
)) {
802 mutex_unlock(&inst
->lock
);
806 venus_helper_init_instance(inst
);
808 inst
->reconfig
= false;
809 inst
->sequence_cap
= 0;
810 inst
->sequence_out
= 0;
812 ret
= vdec_init_session(inst
);
816 ret
= vdec_set_properties(inst
);
820 ret
= vdec_output_conf(inst
);
824 ret
= vdec_verify_conf(inst
);
828 ret
= venus_helper_set_num_bufs(inst
, inst
->num_input_bufs
,
829 VB2_MAX_FRAME
, VB2_MAX_FRAME
);
833 ret
= venus_helper_alloc_dpb_bufs(inst
);
837 ret
= venus_helper_vb2_start_streaming(inst
);
841 mutex_unlock(&inst
->lock
);
846 hfi_session_deinit(inst
);
848 venus_helper_buffers_done(inst
, VB2_BUF_STATE_QUEUED
);
849 if (q
->type
== V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
)
850 inst
->streamon_out
= 0;
852 inst
->streamon_cap
= 0;
853 mutex_unlock(&inst
->lock
);
857 static const struct vb2_ops vdec_vb2_ops
= {
858 .queue_setup
= vdec_queue_setup
,
859 .buf_init
= venus_helper_vb2_buf_init
,
860 .buf_prepare
= venus_helper_vb2_buf_prepare
,
861 .start_streaming
= vdec_start_streaming
,
862 .stop_streaming
= venus_helper_vb2_stop_streaming
,
863 .buf_queue
= venus_helper_vb2_buf_queue
,
866 static void vdec_buf_done(struct venus_inst
*inst
, unsigned int buf_type
,
867 u32 tag
, u32 bytesused
, u32 data_offset
, u32 flags
,
868 u32 hfi_flags
, u64 timestamp_us
)
870 enum vb2_buffer_state state
= VB2_BUF_STATE_DONE
;
871 struct vb2_v4l2_buffer
*vbuf
;
872 struct vb2_buffer
*vb
;
875 if (buf_type
== HFI_BUFFER_INPUT
)
876 type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
878 type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
880 vbuf
= venus_helper_find_buf(inst
, type
, tag
);
885 vbuf
->field
= V4L2_FIELD_NONE
;
887 if (type
== V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
) {
888 unsigned int opb_sz
= venus_helper_get_opb_size(inst
);
891 vb
->planes
[0].bytesused
=
892 max_t(unsigned int, opb_sz
, bytesused
);
893 vb
->planes
[0].data_offset
= data_offset
;
894 vb
->timestamp
= timestamp_us
* NSEC_PER_USEC
;
895 vbuf
->sequence
= inst
->sequence_cap
++;
897 if (vbuf
->flags
& V4L2_BUF_FLAG_LAST
) {
898 const struct v4l2_event ev
= { .type
= V4L2_EVENT_EOS
};
900 v4l2_event_queue_fh(&inst
->fh
, &ev
);
903 vbuf
->sequence
= inst
->sequence_out
++;
906 if (hfi_flags
& HFI_BUFFERFLAG_READONLY
)
907 venus_helper_acquire_buf_ref(vbuf
);
909 if (hfi_flags
& HFI_BUFFERFLAG_DATACORRUPT
)
910 state
= VB2_BUF_STATE_ERROR
;
912 v4l2_m2m_buf_done(vbuf
, state
);
915 static void vdec_event_notify(struct venus_inst
*inst
, u32 event
,
916 struct hfi_event_data
*data
)
918 struct venus_core
*core
= inst
->core
;
919 struct device
*dev
= core
->dev_dec
;
920 static const struct v4l2_event ev
= {
921 .type
= V4L2_EVENT_SOURCE_CHANGE
,
922 .u
.src_change
.changes
= V4L2_EVENT_SRC_CH_RESOLUTION
};
925 case EVT_SESSION_ERROR
:
926 inst
->session_error
= true;
927 dev_err(dev
, "dec: event session error %x\n", inst
->error
);
929 case EVT_SYS_EVENT_CHANGE
:
930 switch (data
->event_type
) {
931 case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES
:
932 hfi_session_continue(inst
);
933 dev_dbg(dev
, "event sufficient resources\n");
935 case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES
:
936 inst
->reconfig_height
= data
->height
;
937 inst
->reconfig_width
= data
->width
;
938 inst
->reconfig
= true;
940 v4l2_event_queue_fh(&inst
->fh
, &ev
);
942 dev_dbg(dev
, "event not sufficient resources (%ux%u)\n",
943 data
->width
, data
->height
);
945 case HFI_EVENT_RELEASE_BUFFER_REFERENCE
:
946 venus_helper_release_buf_ref(inst
, data
->tag
);
957 static const struct hfi_inst_ops vdec_hfi_ops
= {
958 .buf_done
= vdec_buf_done
,
959 .event_notify
= vdec_event_notify
,
962 static void vdec_inst_init(struct venus_inst
*inst
)
964 inst
->fmt_out
= &vdec_formats
[6];
965 inst
->fmt_cap
= &vdec_formats
[0];
967 inst
->height
= ALIGN(720, 32);
968 inst
->out_width
= 1280;
969 inst
->out_height
= 720;
971 inst
->timeperframe
.numerator
= 1;
972 inst
->timeperframe
.denominator
= 30;
973 inst
->hfi_codec
= HFI_VIDEO_CODEC_H264
;
976 static const struct v4l2_m2m_ops vdec_m2m_ops
= {
977 .device_run
= venus_helper_m2m_device_run
,
978 .job_abort
= venus_helper_m2m_job_abort
,
981 static int m2m_queue_init(void *priv
, struct vb2_queue
*src_vq
,
982 struct vb2_queue
*dst_vq
)
984 struct venus_inst
*inst
= priv
;
987 src_vq
->type
= V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
;
988 src_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
989 src_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
990 src_vq
->ops
= &vdec_vb2_ops
;
991 src_vq
->mem_ops
= &vb2_dma_sg_memops
;
992 src_vq
->drv_priv
= inst
;
993 src_vq
->buf_struct_size
= sizeof(struct venus_buffer
);
994 src_vq
->allow_zero_bytesused
= 1;
995 src_vq
->min_buffers_needed
= 1;
996 src_vq
->dev
= inst
->core
->dev
;
997 ret
= vb2_queue_init(src_vq
);
1001 dst_vq
->type
= V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
;
1002 dst_vq
->io_modes
= VB2_MMAP
| VB2_DMABUF
;
1003 dst_vq
->timestamp_flags
= V4L2_BUF_FLAG_TIMESTAMP_COPY
;
1004 dst_vq
->ops
= &vdec_vb2_ops
;
1005 dst_vq
->mem_ops
= &vb2_dma_sg_memops
;
1006 dst_vq
->drv_priv
= inst
;
1007 dst_vq
->buf_struct_size
= sizeof(struct venus_buffer
);
1008 dst_vq
->allow_zero_bytesused
= 1;
1009 dst_vq
->min_buffers_needed
= 1;
1010 dst_vq
->dev
= inst
->core
->dev
;
1011 ret
= vb2_queue_init(dst_vq
);
1013 vb2_queue_release(src_vq
);
1020 static int vdec_open(struct file
*file
)
1022 struct venus_core
*core
= video_drvdata(file
);
1023 struct venus_inst
*inst
;
1026 inst
= kzalloc(sizeof(*inst
), GFP_KERNEL
);
1030 INIT_LIST_HEAD(&inst
->dpbbufs
);
1031 INIT_LIST_HEAD(&inst
->registeredbufs
);
1032 INIT_LIST_HEAD(&inst
->internalbufs
);
1033 INIT_LIST_HEAD(&inst
->list
);
1034 mutex_init(&inst
->lock
);
1037 inst
->session_type
= VIDC_SESSION_TYPE_DEC
;
1038 inst
->num_output_bufs
= 1;
1040 venus_helper_init_instance(inst
);
1042 ret
= pm_runtime_get_sync(core
->dev_dec
);
1046 ret
= vdec_ctrl_init(inst
);
1050 ret
= hfi_session_create(inst
, &vdec_hfi_ops
);
1052 goto err_ctrl_deinit
;
1054 vdec_inst_init(inst
);
1057 * create m2m device for every instance, the m2m context scheduling
1058 * is made by firmware side so we do not need to care about.
1060 inst
->m2m_dev
= v4l2_m2m_init(&vdec_m2m_ops
);
1061 if (IS_ERR(inst
->m2m_dev
)) {
1062 ret
= PTR_ERR(inst
->m2m_dev
);
1063 goto err_session_destroy
;
1066 inst
->m2m_ctx
= v4l2_m2m_ctx_init(inst
->m2m_dev
, inst
, m2m_queue_init
);
1067 if (IS_ERR(inst
->m2m_ctx
)) {
1068 ret
= PTR_ERR(inst
->m2m_ctx
);
1069 goto err_m2m_release
;
1072 v4l2_fh_init(&inst
->fh
, core
->vdev_dec
);
1074 inst
->fh
.ctrl_handler
= &inst
->ctrl_handler
;
1075 v4l2_fh_add(&inst
->fh
);
1076 inst
->fh
.m2m_ctx
= inst
->m2m_ctx
;
1077 file
->private_data
= &inst
->fh
;
1082 v4l2_m2m_release(inst
->m2m_dev
);
1083 err_session_destroy
:
1084 hfi_session_destroy(inst
);
1086 vdec_ctrl_deinit(inst
);
1088 pm_runtime_put_sync(core
->dev_dec
);
1094 static int vdec_close(struct file
*file
)
1096 struct venus_inst
*inst
= to_inst(file
);
1098 v4l2_m2m_ctx_release(inst
->m2m_ctx
);
1099 v4l2_m2m_release(inst
->m2m_dev
);
1100 vdec_ctrl_deinit(inst
);
1101 hfi_session_destroy(inst
);
1102 mutex_destroy(&inst
->lock
);
1103 v4l2_fh_del(&inst
->fh
);
1104 v4l2_fh_exit(&inst
->fh
);
1106 pm_runtime_put_sync(inst
->core
->dev_dec
);
1112 static const struct v4l2_file_operations vdec_fops
= {
1113 .owner
= THIS_MODULE
,
1115 .release
= vdec_close
,
1116 .unlocked_ioctl
= video_ioctl2
,
1117 .poll
= v4l2_m2m_fop_poll
,
1118 .mmap
= v4l2_m2m_fop_mmap
,
1119 #ifdef CONFIG_COMPAT
1120 .compat_ioctl32
= v4l2_compat_ioctl32
,
1124 static int vdec_probe(struct platform_device
*pdev
)
1126 struct device
*dev
= &pdev
->dev
;
1127 struct video_device
*vdev
;
1128 struct venus_core
*core
;
1132 return -EPROBE_DEFER
;
1134 core
= dev_get_drvdata(dev
->parent
);
1136 return -EPROBE_DEFER
;
1138 if (IS_V3(core
) || IS_V4(core
)) {
1139 core
->core0_clk
= devm_clk_get(dev
, "core");
1140 if (IS_ERR(core
->core0_clk
))
1141 return PTR_ERR(core
->core0_clk
);
1145 core
->core0_bus_clk
= devm_clk_get(dev
, "bus");
1146 if (IS_ERR(core
->core0_bus_clk
))
1147 return PTR_ERR(core
->core0_bus_clk
);
1150 platform_set_drvdata(pdev
, core
);
1152 vdev
= video_device_alloc();
1156 strlcpy(vdev
->name
, "qcom-venus-decoder", sizeof(vdev
->name
));
1157 vdev
->release
= video_device_release
;
1158 vdev
->fops
= &vdec_fops
;
1159 vdev
->ioctl_ops
= &vdec_ioctl_ops
;
1160 vdev
->vfl_dir
= VFL_DIR_M2M
;
1161 vdev
->v4l2_dev
= &core
->v4l2_dev
;
1162 vdev
->device_caps
= V4L2_CAP_VIDEO_M2M_MPLANE
| V4L2_CAP_STREAMING
;
1164 ret
= video_register_device(vdev
, VFL_TYPE_GRABBER
, -1);
1166 goto err_vdev_release
;
1168 core
->vdev_dec
= vdev
;
1169 core
->dev_dec
= dev
;
1171 video_set_drvdata(vdev
, core
);
1172 pm_runtime_enable(dev
);
1177 video_device_release(vdev
);
1181 static int vdec_remove(struct platform_device
*pdev
)
1183 struct venus_core
*core
= dev_get_drvdata(pdev
->dev
.parent
);
1185 video_unregister_device(core
->vdev_dec
);
1186 pm_runtime_disable(core
->dev_dec
);
1191 static __maybe_unused
int vdec_runtime_suspend(struct device
*dev
)
1193 struct venus_core
*core
= dev_get_drvdata(dev
);
1199 ret
= venus_helper_power_enable(core
, VIDC_SESSION_TYPE_DEC
, true);
1204 clk_disable_unprepare(core
->core0_bus_clk
);
1206 clk_disable_unprepare(core
->core0_clk
);
1208 return venus_helper_power_enable(core
, VIDC_SESSION_TYPE_DEC
, false);
1211 static __maybe_unused
int vdec_runtime_resume(struct device
*dev
)
1213 struct venus_core
*core
= dev_get_drvdata(dev
);
1219 ret
= venus_helper_power_enable(core
, VIDC_SESSION_TYPE_DEC
, true);
1223 ret
= clk_prepare_enable(core
->core0_clk
);
1225 goto err_power_disable
;
1228 ret
= clk_prepare_enable(core
->core0_bus_clk
);
1231 goto err_unprepare_core0
;
1233 return venus_helper_power_enable(core
, VIDC_SESSION_TYPE_DEC
, false);
1235 err_unprepare_core0
:
1236 clk_disable_unprepare(core
->core0_clk
);
1238 venus_helper_power_enable(core
, VIDC_SESSION_TYPE_DEC
, false);
1242 static const struct dev_pm_ops vdec_pm_ops
= {
1243 SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend
,
1244 pm_runtime_force_resume
)
1245 SET_RUNTIME_PM_OPS(vdec_runtime_suspend
, vdec_runtime_resume
, NULL
)
1248 static const struct of_device_id vdec_dt_match
[] = {
1249 { .compatible
= "venus-decoder" },
1252 MODULE_DEVICE_TABLE(of
, vdec_dt_match
);
1254 static struct platform_driver qcom_venus_dec_driver
= {
1255 .probe
= vdec_probe
,
1256 .remove
= vdec_remove
,
1258 .name
= "qcom-venus-decoder",
1259 .of_match_table
= vdec_dt_match
,
1263 module_platform_driver(qcom_venus_dec_driver
);
1265 MODULE_ALIAS("platform:qcom-venus-decoder");
1266 MODULE_DESCRIPTION("Qualcomm Venus video decoder driver");
1267 MODULE_LICENSE("GPL v2");