197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27472c1c6SStanimir Varbanov /*
37472c1c6SStanimir Varbanov * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
47472c1c6SStanimir Varbanov * Copyright (C) 2017 Linaro Ltd.
57472c1c6SStanimir Varbanov */
67472c1c6SStanimir Varbanov #include <linux/clk.h>
77472c1c6SStanimir Varbanov #include <linux/module.h>
81b7369acSArnd Bergmann #include <linux/mod_devicetable.h>
97472c1c6SStanimir Varbanov #include <linux/platform_device.h>
107472c1c6SStanimir Varbanov #include <linux/pm_runtime.h>
117472c1c6SStanimir Varbanov #include <linux/slab.h>
127472c1c6SStanimir Varbanov #include <media/v4l2-ioctl.h>
137472c1c6SStanimir Varbanov #include <media/v4l2-event.h>
147472c1c6SStanimir Varbanov #include <media/v4l2-ctrls.h>
157472c1c6SStanimir Varbanov #include <media/v4l2-mem2mem.h>
16cc82fd69SAlexandre Courbot #include <media/videobuf2-dma-contig.h>
177472c1c6SStanimir Varbanov
187472c1c6SStanimir Varbanov #include "hfi_venus_io.h"
191a73374aSStanimir Varbanov #include "hfi_parser.h"
207472c1c6SStanimir Varbanov #include "core.h"
217472c1c6SStanimir Varbanov #include "helpers.h"
227472c1c6SStanimir Varbanov #include "vdec.h"
237482a983SStanimir Varbanov #include "pm_helpers.h"
247472c1c6SStanimir Varbanov
257472c1c6SStanimir Varbanov /*
267472c1c6SStanimir Varbanov * Three resons to keep MPLANE formats (despite that the number of planes
277472c1c6SStanimir Varbanov * currently is one):
287472c1c6SStanimir Varbanov * - the MPLANE formats allow only one plane to be used
297472c1c6SStanimir Varbanov * - the downstream driver use MPLANE formats too
307472c1c6SStanimir Varbanov * - future firmware versions could add support for >1 planes
317472c1c6SStanimir Varbanov */
327472c1c6SStanimir Varbanov static const struct venus_format vdec_formats[] = {
332b832a06SDikshita Agarwal [VENUS_FMT_NV12] = {
34a9d45ec7SJavier Martinez Canillas .pixfmt = V4L2_PIX_FMT_NV12,
35a9d45ec7SJavier Martinez Canillas .num_planes = 1,
36a9d45ec7SJavier Martinez Canillas .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
372b832a06SDikshita Agarwal },
382b832a06SDikshita Agarwal [VENUS_FMT_QC08C] = {
399593126dSStanimir Varbanov .pixfmt = V4L2_PIX_FMT_QC08C,
409593126dSStanimir Varbanov .num_planes = 1,
419593126dSStanimir Varbanov .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
422b832a06SDikshita Agarwal },
432b832a06SDikshita Agarwal [VENUS_FMT_QC10C] = {
44cef92b14SStanimir Varbanov .pixfmt = V4L2_PIX_FMT_QC10C,
45cef92b14SStanimir Varbanov .num_planes = 1,
46cef92b14SStanimir Varbanov .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
472b832a06SDikshita Agarwal },
4830956077SDikshita Agarwal [VENUS_FMT_P010] = {
4930956077SDikshita Agarwal .pixfmt = V4L2_PIX_FMT_P010,
5030956077SDikshita Agarwal .num_planes = 1,
5130956077SDikshita Agarwal .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
5230956077SDikshita Agarwal },
532b832a06SDikshita Agarwal [VENUS_FMT_H264] = {
547472c1c6SStanimir Varbanov .pixfmt = V4L2_PIX_FMT_H264,
557472c1c6SStanimir Varbanov .num_planes = 1,
567472c1c6SStanimir Varbanov .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
575aecb7d0SMaxime Jourdan .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
582b832a06SDikshita Agarwal },
592b832a06SDikshita Agarwal [VENUS_FMT_VP8] = {
607472c1c6SStanimir Varbanov .pixfmt = V4L2_PIX_FMT_VP8,
617472c1c6SStanimir Varbanov .num_planes = 1,
627472c1c6SStanimir Varbanov .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
635aecb7d0SMaxime Jourdan .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
642b832a06SDikshita Agarwal },
652b832a06SDikshita Agarwal [VENUS_FMT_VP9] = {
667472c1c6SStanimir Varbanov .pixfmt = V4L2_PIX_FMT_VP9,
677472c1c6SStanimir Varbanov .num_planes = 1,
687472c1c6SStanimir Varbanov .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
695aecb7d0SMaxime Jourdan .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
702b832a06SDikshita Agarwal },
712b832a06SDikshita Agarwal [VENUS_FMT_HEVC] = {
721fb9a605SStanimir Varbanov .pixfmt = V4L2_PIX_FMT_HEVC,
731fb9a605SStanimir Varbanov .num_planes = 1,
741fb9a605SStanimir Varbanov .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
755aecb7d0SMaxime Jourdan .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
767472c1c6SStanimir Varbanov },
772b832a06SDikshita Agarwal [VENUS_FMT_VC1_ANNEX_G] = {
782b832a06SDikshita Agarwal .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_G,
792b832a06SDikshita Agarwal .num_planes = 1,
802b832a06SDikshita Agarwal .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
812b832a06SDikshita Agarwal .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
822b832a06SDikshita Agarwal },
832b832a06SDikshita Agarwal [VENUS_FMT_VC1_ANNEX_L] = {
842b832a06SDikshita Agarwal .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_L,
852b832a06SDikshita Agarwal .num_planes = 1,
862b832a06SDikshita Agarwal .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
872b832a06SDikshita Agarwal .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
882b832a06SDikshita Agarwal },
892b832a06SDikshita Agarwal [VENUS_FMT_MPEG4] = {
902b832a06SDikshita Agarwal .pixfmt = V4L2_PIX_FMT_MPEG4,
912b832a06SDikshita Agarwal .num_planes = 1,
922b832a06SDikshita Agarwal .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
932b832a06SDikshita Agarwal .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
942b832a06SDikshita Agarwal },
952b832a06SDikshita Agarwal [VENUS_FMT_MPEG2] = {
962b832a06SDikshita Agarwal .pixfmt = V4L2_PIX_FMT_MPEG2,
972b832a06SDikshita Agarwal .num_planes = 1,
982b832a06SDikshita Agarwal .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
992b832a06SDikshita Agarwal .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
1002b832a06SDikshita Agarwal },
1012b832a06SDikshita Agarwal [VENUS_FMT_H263] = {
1022b832a06SDikshita Agarwal .pixfmt = V4L2_PIX_FMT_H263,
1032b832a06SDikshita Agarwal .num_planes = 1,
1042b832a06SDikshita Agarwal .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
1052b832a06SDikshita Agarwal .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
1062b832a06SDikshita Agarwal },
1072b832a06SDikshita Agarwal [VENUS_FMT_XVID] = {
1082b832a06SDikshita Agarwal .pixfmt = V4L2_PIX_FMT_XVID,
1092b832a06SDikshita Agarwal .num_planes = 1,
1102b832a06SDikshita Agarwal .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
1112b832a06SDikshita Agarwal .flags = V4L2_FMT_FLAG_DYN_RESOLUTION,
1122b832a06SDikshita Agarwal },
1132b832a06SDikshita Agarwal
1147472c1c6SStanimir Varbanov };
1157472c1c6SStanimir Varbanov
11629f0133eSStanimir Varbanov static const struct venus_format *
find_format(struct venus_inst * inst,u32 pixfmt,u32 type)11729f0133eSStanimir Varbanov find_format(struct venus_inst *inst, u32 pixfmt, u32 type)
1187472c1c6SStanimir Varbanov {
1197472c1c6SStanimir Varbanov const struct venus_format *fmt = vdec_formats;
1207472c1c6SStanimir Varbanov unsigned int size = ARRAY_SIZE(vdec_formats);
1217472c1c6SStanimir Varbanov unsigned int i;
1227472c1c6SStanimir Varbanov
1237472c1c6SStanimir Varbanov for (i = 0; i < size; i++) {
1247472c1c6SStanimir Varbanov if (fmt[i].pixfmt == pixfmt)
1257472c1c6SStanimir Varbanov break;
1267472c1c6SStanimir Varbanov }
1277472c1c6SStanimir Varbanov
1287472c1c6SStanimir Varbanov if (i == size || fmt[i].type != type)
1297472c1c6SStanimir Varbanov return NULL;
1307472c1c6SStanimir Varbanov
13129f0133eSStanimir Varbanov if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
13229f0133eSStanimir Varbanov !venus_helper_check_codec(inst, fmt[i].pixfmt))
13329f0133eSStanimir Varbanov return NULL;
13429f0133eSStanimir Varbanov
1359593126dSStanimir Varbanov if (V4L2_TYPE_IS_CAPTURE(type) &&
1369593126dSStanimir Varbanov !venus_helper_check_format(inst, fmt[i].pixfmt))
1379593126dSStanimir Varbanov return NULL;
1389593126dSStanimir Varbanov
139cef92b14SStanimir Varbanov if (V4L2_TYPE_IS_CAPTURE(type) && fmt[i].pixfmt == V4L2_PIX_FMT_QC10C &&
140cef92b14SStanimir Varbanov !(inst->bit_depth == VIDC_BITDEPTH_10))
141cef92b14SStanimir Varbanov return NULL;
142cef92b14SStanimir Varbanov
1437472c1c6SStanimir Varbanov return &fmt[i];
1447472c1c6SStanimir Varbanov }
1457472c1c6SStanimir Varbanov
1467472c1c6SStanimir Varbanov static const struct venus_format *
find_format_by_index(struct venus_inst * inst,unsigned int index,u32 type)14729f0133eSStanimir Varbanov find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type)
1487472c1c6SStanimir Varbanov {
1497472c1c6SStanimir Varbanov const struct venus_format *fmt = vdec_formats;
1507472c1c6SStanimir Varbanov unsigned int size = ARRAY_SIZE(vdec_formats);
1517472c1c6SStanimir Varbanov unsigned int i, k = 0;
1527472c1c6SStanimir Varbanov
1537472c1c6SStanimir Varbanov if (index > size)
1547472c1c6SStanimir Varbanov return NULL;
1557472c1c6SStanimir Varbanov
1567472c1c6SStanimir Varbanov for (i = 0; i < size; i++) {
15782e071e2SAlexandre Courbot bool valid;
15882e071e2SAlexandre Courbot
1597472c1c6SStanimir Varbanov if (fmt[i].type != type)
1607472c1c6SStanimir Varbanov continue;
1619593126dSStanimir Varbanov
162cef92b14SStanimir Varbanov if (V4L2_TYPE_IS_OUTPUT(type)) {
1639593126dSStanimir Varbanov valid = venus_helper_check_codec(inst, fmt[i].pixfmt);
164cef92b14SStanimir Varbanov } else if (V4L2_TYPE_IS_CAPTURE(type)) {
1659593126dSStanimir Varbanov valid = venus_helper_check_format(inst, fmt[i].pixfmt);
1669593126dSStanimir Varbanov
167cef92b14SStanimir Varbanov if (fmt[i].pixfmt == V4L2_PIX_FMT_QC10C &&
168cef92b14SStanimir Varbanov !(inst->bit_depth == VIDC_BITDEPTH_10))
169cef92b14SStanimir Varbanov valid = false;
170cef92b14SStanimir Varbanov }
171cef92b14SStanimir Varbanov
17282e071e2SAlexandre Courbot if (k == index && valid)
1737472c1c6SStanimir Varbanov break;
17482e071e2SAlexandre Courbot if (valid)
1757472c1c6SStanimir Varbanov k++;
1767472c1c6SStanimir Varbanov }
1777472c1c6SStanimir Varbanov
1787472c1c6SStanimir Varbanov if (i == size)
1797472c1c6SStanimir Varbanov return NULL;
1807472c1c6SStanimir Varbanov
1817472c1c6SStanimir Varbanov return &fmt[i];
1827472c1c6SStanimir Varbanov }
1837472c1c6SStanimir Varbanov
1847472c1c6SStanimir Varbanov static const struct venus_format *
vdec_try_fmt_common(struct venus_inst * inst,struct v4l2_format * f)1857472c1c6SStanimir Varbanov vdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f)
1867472c1c6SStanimir Varbanov {
1877472c1c6SStanimir Varbanov struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
1887472c1c6SStanimir Varbanov struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt;
1897472c1c6SStanimir Varbanov const struct venus_format *fmt;
190be76f150SStanimir Varbanov u32 szimage;
1917472c1c6SStanimir Varbanov
1927472c1c6SStanimir Varbanov memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved));
1937472c1c6SStanimir Varbanov memset(pixmp->reserved, 0, sizeof(pixmp->reserved));
1947472c1c6SStanimir Varbanov
19529f0133eSStanimir Varbanov fmt = find_format(inst, pixmp->pixelformat, f->type);
1967472c1c6SStanimir Varbanov if (!fmt) {
1977472c1c6SStanimir Varbanov if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
1987472c1c6SStanimir Varbanov pixmp->pixelformat = V4L2_PIX_FMT_NV12;
1997472c1c6SStanimir Varbanov else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
2007472c1c6SStanimir Varbanov pixmp->pixelformat = V4L2_PIX_FMT_H264;
2017472c1c6SStanimir Varbanov else
2027472c1c6SStanimir Varbanov return NULL;
20329f0133eSStanimir Varbanov fmt = find_format(inst, pixmp->pixelformat, f->type);
20406a2da34SBryan O'Donoghue if (!fmt)
20506a2da34SBryan O'Donoghue return NULL;
2067472c1c6SStanimir Varbanov }
2077472c1c6SStanimir Varbanov
2081a73374aSStanimir Varbanov pixmp->width = clamp(pixmp->width, frame_width_min(inst),
2091a73374aSStanimir Varbanov frame_width_max(inst));
2101a73374aSStanimir Varbanov pixmp->height = clamp(pixmp->height, frame_height_min(inst),
2111a73374aSStanimir Varbanov frame_height_max(inst));
2127472c1c6SStanimir Varbanov
2137472c1c6SStanimir Varbanov if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
2147472c1c6SStanimir Varbanov pixmp->height = ALIGN(pixmp->height, 32);
2157472c1c6SStanimir Varbanov
2167472c1c6SStanimir Varbanov if (pixmp->field == V4L2_FIELD_ANY)
2177472c1c6SStanimir Varbanov pixmp->field = V4L2_FIELD_NONE;
2187472c1c6SStanimir Varbanov pixmp->num_planes = fmt->num_planes;
2197472c1c6SStanimir Varbanov pixmp->flags = 0;
2207472c1c6SStanimir Varbanov
221be76f150SStanimir Varbanov szimage = venus_helper_get_framesz(pixmp->pixelformat, pixmp->width,
2227472c1c6SStanimir Varbanov pixmp->height);
223e1cb72deSStanimir Varbanov
224be76f150SStanimir Varbanov if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
225a47a3ae5SFritz Koenig unsigned int stride = pixmp->width;
226a47a3ae5SFritz Koenig
227a47a3ae5SFritz Koenig if (pixmp->pixelformat == V4L2_PIX_FMT_P010)
228a47a3ae5SFritz Koenig stride *= 2;
229a47a3ae5SFritz Koenig
230be76f150SStanimir Varbanov pfmt[0].sizeimage = szimage;
231a47a3ae5SFritz Koenig pfmt[0].bytesperline = ALIGN(stride, 128);
232be76f150SStanimir Varbanov } else {
233be76f150SStanimir Varbanov pfmt[0].sizeimage = clamp_t(u32, pfmt[0].sizeimage, 0, SZ_8M);
234be76f150SStanimir Varbanov pfmt[0].sizeimage = max(pfmt[0].sizeimage, szimage);
2357472c1c6SStanimir Varbanov pfmt[0].bytesperline = 0;
236be76f150SStanimir Varbanov }
2377472c1c6SStanimir Varbanov
2387472c1c6SStanimir Varbanov return fmt;
2397472c1c6SStanimir Varbanov }
2407472c1c6SStanimir Varbanov
vdec_try_fmt(struct file * file,void * fh,struct v4l2_format * f)2417472c1c6SStanimir Varbanov static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
2427472c1c6SStanimir Varbanov {
2437472c1c6SStanimir Varbanov struct venus_inst *inst = to_inst(file);
2447472c1c6SStanimir Varbanov
2457472c1c6SStanimir Varbanov vdec_try_fmt_common(inst, f);
2467472c1c6SStanimir Varbanov
2477472c1c6SStanimir Varbanov return 0;
2487472c1c6SStanimir Varbanov }
2497472c1c6SStanimir Varbanov
vdec_check_src_change(struct venus_inst * inst)250beac8290SStanimir Varbanov static int vdec_check_src_change(struct venus_inst *inst)
251beac8290SStanimir Varbanov {
252beac8290SStanimir Varbanov int ret;
253beac8290SStanimir Varbanov
254beac8290SStanimir Varbanov if (inst->subscriptions & V4L2_EVENT_SOURCE_CHANGE &&
255beac8290SStanimir Varbanov inst->codec_state == VENUS_DEC_STATE_INIT &&
256beac8290SStanimir Varbanov !inst->reconfig)
257beac8290SStanimir Varbanov return -EINVAL;
258beac8290SStanimir Varbanov
259beac8290SStanimir Varbanov if (inst->subscriptions & V4L2_EVENT_SOURCE_CHANGE)
260beac8290SStanimir Varbanov return 0;
261beac8290SStanimir Varbanov
262beac8290SStanimir Varbanov /*
263beac8290SStanimir Varbanov * The code snippet below is a workaround for backward compatibility
264beac8290SStanimir Varbanov * with applications which doesn't support V4L2 events. It will be
265beac8290SStanimir Varbanov * dropped in future once those applications are fixed.
266beac8290SStanimir Varbanov */
267beac8290SStanimir Varbanov
268beac8290SStanimir Varbanov if (inst->codec_state != VENUS_DEC_STATE_INIT)
269beac8290SStanimir Varbanov goto done;
270beac8290SStanimir Varbanov
271beac8290SStanimir Varbanov ret = wait_event_timeout(inst->reconf_wait, inst->reconfig,
272beac8290SStanimir Varbanov msecs_to_jiffies(100));
273beac8290SStanimir Varbanov if (!ret)
274beac8290SStanimir Varbanov return -EINVAL;
275beac8290SStanimir Varbanov
276beac8290SStanimir Varbanov if (!(inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) ||
277beac8290SStanimir Varbanov !inst->reconfig)
2788c91dc08SStanimir Varbanov dev_dbg(inst->core->dev, VDBGH "wrong state\n");
279beac8290SStanimir Varbanov
280beac8290SStanimir Varbanov done:
281beac8290SStanimir Varbanov return 0;
282beac8290SStanimir Varbanov }
283beac8290SStanimir Varbanov
vdec_g_fmt(struct file * file,void * fh,struct v4l2_format * f)2847472c1c6SStanimir Varbanov static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
2857472c1c6SStanimir Varbanov {
2867472c1c6SStanimir Varbanov struct venus_inst *inst = to_inst(file);
2877472c1c6SStanimir Varbanov const struct venus_format *fmt = NULL;
2887472c1c6SStanimir Varbanov struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
289beac8290SStanimir Varbanov int ret;
2907472c1c6SStanimir Varbanov
2917472c1c6SStanimir Varbanov if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
2927472c1c6SStanimir Varbanov fmt = inst->fmt_cap;
2937472c1c6SStanimir Varbanov else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
2947472c1c6SStanimir Varbanov fmt = inst->fmt_out;
2957472c1c6SStanimir Varbanov
296beac8290SStanimir Varbanov if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
297beac8290SStanimir Varbanov ret = vdec_check_src_change(inst);
298beac8290SStanimir Varbanov if (ret)
299beac8290SStanimir Varbanov return ret;
3007472c1c6SStanimir Varbanov }
3017472c1c6SStanimir Varbanov
3027472c1c6SStanimir Varbanov pixmp->pixelformat = fmt->pixfmt;
3037472c1c6SStanimir Varbanov
3047472c1c6SStanimir Varbanov if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
3057472c1c6SStanimir Varbanov pixmp->width = inst->width;
3067472c1c6SStanimir Varbanov pixmp->height = inst->height;
3077472c1c6SStanimir Varbanov pixmp->colorspace = inst->colorspace;
3087472c1c6SStanimir Varbanov pixmp->ycbcr_enc = inst->ycbcr_enc;
3097472c1c6SStanimir Varbanov pixmp->quantization = inst->quantization;
3107472c1c6SStanimir Varbanov pixmp->xfer_func = inst->xfer_func;
3117472c1c6SStanimir Varbanov } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
3127472c1c6SStanimir Varbanov pixmp->width = inst->out_width;
3137472c1c6SStanimir Varbanov pixmp->height = inst->out_height;
3147472c1c6SStanimir Varbanov }
3157472c1c6SStanimir Varbanov
3167472c1c6SStanimir Varbanov vdec_try_fmt_common(inst, f);
3177472c1c6SStanimir Varbanov
3187472c1c6SStanimir Varbanov return 0;
3197472c1c6SStanimir Varbanov }
3207472c1c6SStanimir Varbanov
vdec_s_fmt(struct file * file,void * fh,struct v4l2_format * f)3217472c1c6SStanimir Varbanov static int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
3227472c1c6SStanimir Varbanov {
3237472c1c6SStanimir Varbanov struct venus_inst *inst = to_inst(file);
3247472c1c6SStanimir Varbanov struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp;
3257472c1c6SStanimir Varbanov struct v4l2_pix_format_mplane orig_pixmp;
3267472c1c6SStanimir Varbanov const struct venus_format *fmt;
3277472c1c6SStanimir Varbanov struct v4l2_format format;
3287472c1c6SStanimir Varbanov u32 pixfmt_out = 0, pixfmt_cap = 0;
3294470ff69SStanimir Varbanov struct vb2_queue *q;
3304470ff69SStanimir Varbanov
3314470ff69SStanimir Varbanov q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type);
3324470ff69SStanimir Varbanov if (!q)
3334470ff69SStanimir Varbanov return -EINVAL;
3344470ff69SStanimir Varbanov
3354470ff69SStanimir Varbanov if (vb2_is_busy(q))
3364470ff69SStanimir Varbanov return -EBUSY;
3377472c1c6SStanimir Varbanov
3387472c1c6SStanimir Varbanov orig_pixmp = *pixmp;
3397472c1c6SStanimir Varbanov
3407472c1c6SStanimir Varbanov fmt = vdec_try_fmt_common(inst, f);
3417472c1c6SStanimir Varbanov
3427472c1c6SStanimir Varbanov if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
3437472c1c6SStanimir Varbanov pixfmt_out = pixmp->pixelformat;
3447472c1c6SStanimir Varbanov pixfmt_cap = inst->fmt_cap->pixfmt;
3457472c1c6SStanimir Varbanov } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
3467472c1c6SStanimir Varbanov pixfmt_cap = pixmp->pixelformat;
3477472c1c6SStanimir Varbanov pixfmt_out = inst->fmt_out->pixfmt;
3487472c1c6SStanimir Varbanov }
3497472c1c6SStanimir Varbanov
3507472c1c6SStanimir Varbanov memset(&format, 0, sizeof(format));
3517472c1c6SStanimir Varbanov
3527472c1c6SStanimir Varbanov format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
3537472c1c6SStanimir Varbanov format.fmt.pix_mp.pixelformat = pixfmt_out;
3547472c1c6SStanimir Varbanov format.fmt.pix_mp.width = orig_pixmp.width;
3557472c1c6SStanimir Varbanov format.fmt.pix_mp.height = orig_pixmp.height;
3567472c1c6SStanimir Varbanov vdec_try_fmt_common(inst, &format);
3577472c1c6SStanimir Varbanov
3587472c1c6SStanimir Varbanov if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
3597472c1c6SStanimir Varbanov inst->out_width = format.fmt.pix_mp.width;
3607472c1c6SStanimir Varbanov inst->out_height = format.fmt.pix_mp.height;
3617472c1c6SStanimir Varbanov inst->colorspace = pixmp->colorspace;
3627472c1c6SStanimir Varbanov inst->ycbcr_enc = pixmp->ycbcr_enc;
3637472c1c6SStanimir Varbanov inst->quantization = pixmp->quantization;
3647472c1c6SStanimir Varbanov inst->xfer_func = pixmp->xfer_func;
365be76f150SStanimir Varbanov inst->input_buf_size = pixmp->plane_fmt[0].sizeimage;
3667472c1c6SStanimir Varbanov }
3677472c1c6SStanimir Varbanov
3687472c1c6SStanimir Varbanov memset(&format, 0, sizeof(format));
3697472c1c6SStanimir Varbanov
3707472c1c6SStanimir Varbanov format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
3717472c1c6SStanimir Varbanov format.fmt.pix_mp.pixelformat = pixfmt_cap;
3727472c1c6SStanimir Varbanov format.fmt.pix_mp.width = orig_pixmp.width;
3737472c1c6SStanimir Varbanov format.fmt.pix_mp.height = orig_pixmp.height;
3747472c1c6SStanimir Varbanov vdec_try_fmt_common(inst, &format);
3757472c1c6SStanimir Varbanov
3767472c1c6SStanimir Varbanov inst->width = format.fmt.pix_mp.width;
3777472c1c6SStanimir Varbanov inst->height = format.fmt.pix_mp.height;
378de04408fSAlexandre Courbot inst->crop.top = 0;
379de04408fSAlexandre Courbot inst->crop.left = 0;
380de04408fSAlexandre Courbot inst->crop.width = inst->width;
381de04408fSAlexandre Courbot inst->crop.height = inst->height;
3827472c1c6SStanimir Varbanov
3837472c1c6SStanimir Varbanov if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
3847472c1c6SStanimir Varbanov inst->fmt_out = fmt;
3858c404ebaSMansur Alisha Shaik else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
3867472c1c6SStanimir Varbanov inst->fmt_cap = fmt;
3878c404ebaSMansur Alisha Shaik inst->output2_buf_size =
3888c404ebaSMansur Alisha Shaik venus_helper_get_framesz(pixfmt_cap, orig_pixmp.width, orig_pixmp.height);
3898c404ebaSMansur Alisha Shaik }
3907472c1c6SStanimir Varbanov
3917472c1c6SStanimir Varbanov return 0;
3927472c1c6SStanimir Varbanov }
3937472c1c6SStanimir Varbanov
3947472c1c6SStanimir Varbanov static int
vdec_g_selection(struct file * file,void * fh,struct v4l2_selection * s)3957472c1c6SStanimir Varbanov vdec_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
3967472c1c6SStanimir Varbanov {
3977472c1c6SStanimir Varbanov struct venus_inst *inst = to_inst(file);
3987472c1c6SStanimir Varbanov
3997472c1c6SStanimir Varbanov if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
4007472c1c6SStanimir Varbanov s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
4017472c1c6SStanimir Varbanov return -EINVAL;
4027472c1c6SStanimir Varbanov
403de04408fSAlexandre Courbot s->r.top = 0;
404de04408fSAlexandre Courbot s->r.left = 0;
405de04408fSAlexandre Courbot
4067472c1c6SStanimir Varbanov switch (s->target) {
4077472c1c6SStanimir Varbanov case V4L2_SEL_TGT_CROP_BOUNDS:
4087472c1c6SStanimir Varbanov case V4L2_SEL_TGT_CROP_DEFAULT:
4097472c1c6SStanimir Varbanov case V4L2_SEL_TGT_CROP:
4107472c1c6SStanimir Varbanov if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
4117472c1c6SStanimir Varbanov return -EINVAL;
4127472c1c6SStanimir Varbanov s->r.width = inst->out_width;
4137472c1c6SStanimir Varbanov s->r.height = inst->out_height;
4147472c1c6SStanimir Varbanov break;
4157472c1c6SStanimir Varbanov case V4L2_SEL_TGT_COMPOSE_BOUNDS:
4167472c1c6SStanimir Varbanov case V4L2_SEL_TGT_COMPOSE_PADDED:
4177472c1c6SStanimir Varbanov if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
4187472c1c6SStanimir Varbanov return -EINVAL;
4197472c1c6SStanimir Varbanov s->r.width = inst->width;
4207472c1c6SStanimir Varbanov s->r.height = inst->height;
4217472c1c6SStanimir Varbanov break;
4227472c1c6SStanimir Varbanov case V4L2_SEL_TGT_COMPOSE_DEFAULT:
4237472c1c6SStanimir Varbanov case V4L2_SEL_TGT_COMPOSE:
4247472c1c6SStanimir Varbanov if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
4257472c1c6SStanimir Varbanov return -EINVAL;
426de04408fSAlexandre Courbot s->r = inst->crop;
4277472c1c6SStanimir Varbanov break;
4287472c1c6SStanimir Varbanov default:
4297472c1c6SStanimir Varbanov return -EINVAL;
4307472c1c6SStanimir Varbanov }
4317472c1c6SStanimir Varbanov
4327472c1c6SStanimir Varbanov return 0;
4337472c1c6SStanimir Varbanov }
4347472c1c6SStanimir Varbanov
4357472c1c6SStanimir Varbanov static int
vdec_querycap(struct file * file,void * fh,struct v4l2_capability * cap)4367472c1c6SStanimir Varbanov vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
4377472c1c6SStanimir Varbanov {
438c0decac1SMauro Carvalho Chehab strscpy(cap->driver, "qcom-venus", sizeof(cap->driver));
439c0decac1SMauro Carvalho Chehab strscpy(cap->card, "Qualcomm Venus video decoder", sizeof(cap->card));
440c0decac1SMauro Carvalho Chehab strscpy(cap->bus_info, "platform:qcom-venus", sizeof(cap->bus_info));
4417472c1c6SStanimir Varbanov
4427472c1c6SStanimir Varbanov return 0;
4437472c1c6SStanimir Varbanov }
4447472c1c6SStanimir Varbanov
vdec_enum_fmt(struct file * file,void * fh,struct v4l2_fmtdesc * f)4457472c1c6SStanimir Varbanov static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
4467472c1c6SStanimir Varbanov {
44729f0133eSStanimir Varbanov struct venus_inst *inst = to_inst(file);
4487472c1c6SStanimir Varbanov const struct venus_format *fmt;
4497472c1c6SStanimir Varbanov
4507472c1c6SStanimir Varbanov memset(f->reserved, 0, sizeof(f->reserved));
4517472c1c6SStanimir Varbanov
45229f0133eSStanimir Varbanov fmt = find_format_by_index(inst, f->index, f->type);
4537472c1c6SStanimir Varbanov if (!fmt)
4547472c1c6SStanimir Varbanov return -EINVAL;
4557472c1c6SStanimir Varbanov
4567472c1c6SStanimir Varbanov f->pixelformat = fmt->pixfmt;
4575aecb7d0SMaxime Jourdan f->flags = fmt->flags;
4587472c1c6SStanimir Varbanov
4597472c1c6SStanimir Varbanov return 0;
4607472c1c6SStanimir Varbanov }
4617472c1c6SStanimir Varbanov
vdec_s_parm(struct file * file,void * fh,struct v4l2_streamparm * a)4627472c1c6SStanimir Varbanov static int vdec_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
4637472c1c6SStanimir Varbanov {
4647472c1c6SStanimir Varbanov struct venus_inst *inst = to_inst(file);
4657472c1c6SStanimir Varbanov struct v4l2_captureparm *cap = &a->parm.capture;
4667472c1c6SStanimir Varbanov struct v4l2_fract *timeperframe = &cap->timeperframe;
4677472c1c6SStanimir Varbanov u64 us_per_frame, fps;
4687472c1c6SStanimir Varbanov
4697472c1c6SStanimir Varbanov if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
4707472c1c6SStanimir Varbanov a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
4717472c1c6SStanimir Varbanov return -EINVAL;
4727472c1c6SStanimir Varbanov
4737472c1c6SStanimir Varbanov memset(cap->reserved, 0, sizeof(cap->reserved));
4747472c1c6SStanimir Varbanov if (!timeperframe->denominator)
4757472c1c6SStanimir Varbanov timeperframe->denominator = inst->timeperframe.denominator;
4767472c1c6SStanimir Varbanov if (!timeperframe->numerator)
4777472c1c6SStanimir Varbanov timeperframe->numerator = inst->timeperframe.numerator;
4787472c1c6SStanimir Varbanov cap->readbuffers = 0;
4797472c1c6SStanimir Varbanov cap->extendedmode = 0;
4807472c1c6SStanimir Varbanov cap->capability = V4L2_CAP_TIMEPERFRAME;
4817472c1c6SStanimir Varbanov us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC;
4827472c1c6SStanimir Varbanov do_div(us_per_frame, timeperframe->denominator);
4837472c1c6SStanimir Varbanov
4847472c1c6SStanimir Varbanov if (!us_per_frame)
4857472c1c6SStanimir Varbanov return -EINVAL;
4867472c1c6SStanimir Varbanov
4877472c1c6SStanimir Varbanov fps = (u64)USEC_PER_SEC;
4887472c1c6SStanimir Varbanov do_div(fps, us_per_frame);
4897472c1c6SStanimir Varbanov
4907472c1c6SStanimir Varbanov inst->fps = fps;
4917472c1c6SStanimir Varbanov inst->timeperframe = *timeperframe;
4927472c1c6SStanimir Varbanov
4937472c1c6SStanimir Varbanov return 0;
4947472c1c6SStanimir Varbanov }
4957472c1c6SStanimir Varbanov
vdec_enum_framesizes(struct file * file,void * fh,struct v4l2_frmsizeenum * fsize)4967472c1c6SStanimir Varbanov static int vdec_enum_framesizes(struct file *file, void *fh,
4977472c1c6SStanimir Varbanov struct v4l2_frmsizeenum *fsize)
4987472c1c6SStanimir Varbanov {
4997472c1c6SStanimir Varbanov struct venus_inst *inst = to_inst(file);
5007472c1c6SStanimir Varbanov const struct venus_format *fmt;
5017472c1c6SStanimir Varbanov
50229f0133eSStanimir Varbanov fmt = find_format(inst, fsize->pixel_format,
5037472c1c6SStanimir Varbanov V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
5047472c1c6SStanimir Varbanov if (!fmt) {
50529f0133eSStanimir Varbanov fmt = find_format(inst, fsize->pixel_format,
5067472c1c6SStanimir Varbanov V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
5077472c1c6SStanimir Varbanov if (!fmt)
5087472c1c6SStanimir Varbanov return -EINVAL;
5097472c1c6SStanimir Varbanov }
5107472c1c6SStanimir Varbanov
5117472c1c6SStanimir Varbanov if (fsize->index)
5127472c1c6SStanimir Varbanov return -EINVAL;
5137472c1c6SStanimir Varbanov
5147472c1c6SStanimir Varbanov fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
5157472c1c6SStanimir Varbanov
5161a73374aSStanimir Varbanov fsize->stepwise.min_width = frame_width_min(inst);
5171a73374aSStanimir Varbanov fsize->stepwise.max_width = frame_width_max(inst);
5181a73374aSStanimir Varbanov fsize->stepwise.step_width = frame_width_step(inst);
5191a73374aSStanimir Varbanov fsize->stepwise.min_height = frame_height_min(inst);
5201a73374aSStanimir Varbanov fsize->stepwise.max_height = frame_height_max(inst);
5211a73374aSStanimir Varbanov fsize->stepwise.step_height = frame_height_step(inst);
5227472c1c6SStanimir Varbanov
5237472c1c6SStanimir Varbanov return 0;
5247472c1c6SStanimir Varbanov }
5257472c1c6SStanimir Varbanov
vdec_subscribe_event(struct v4l2_fh * fh,const struct v4l2_event_subscription * sub)5267472c1c6SStanimir Varbanov static int vdec_subscribe_event(struct v4l2_fh *fh,
5277472c1c6SStanimir Varbanov const struct v4l2_event_subscription *sub)
5287472c1c6SStanimir Varbanov {
529beac8290SStanimir Varbanov struct venus_inst *inst = container_of(fh, struct venus_inst, fh);
530beac8290SStanimir Varbanov int ret;
531beac8290SStanimir Varbanov
5327472c1c6SStanimir Varbanov switch (sub->type) {
5337472c1c6SStanimir Varbanov case V4L2_EVENT_EOS:
5347472c1c6SStanimir Varbanov return v4l2_event_subscribe(fh, sub, 2, NULL);
5357472c1c6SStanimir Varbanov case V4L2_EVENT_SOURCE_CHANGE:
536beac8290SStanimir Varbanov ret = v4l2_src_change_event_subscribe(fh, sub);
537beac8290SStanimir Varbanov if (ret)
538beac8290SStanimir Varbanov return ret;
539beac8290SStanimir Varbanov inst->subscriptions |= V4L2_EVENT_SOURCE_CHANGE;
540beac8290SStanimir Varbanov return 0;
5417472c1c6SStanimir Varbanov case V4L2_EVENT_CTRL:
5427472c1c6SStanimir Varbanov return v4l2_ctrl_subscribe_event(fh, sub);
5437472c1c6SStanimir Varbanov default:
5447472c1c6SStanimir Varbanov return -EINVAL;
5457472c1c6SStanimir Varbanov }
5467472c1c6SStanimir Varbanov }
5477472c1c6SStanimir Varbanov
5487472c1c6SStanimir Varbanov static int
vdec_decoder_cmd(struct file * file,void * fh,struct v4l2_decoder_cmd * cmd)5497472c1c6SStanimir Varbanov vdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd)
5507472c1c6SStanimir Varbanov {
5517472c1c6SStanimir Varbanov struct venus_inst *inst = to_inst(file);
55250248ad9SMichał Krawczyk struct vb2_queue *dst_vq;
553e69b987aSStanimir Varbanov struct hfi_frame_data fdata = {0};
5547472c1c6SStanimir Varbanov int ret;
5557472c1c6SStanimir Varbanov
556beac8290SStanimir Varbanov ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd);
5577472c1c6SStanimir Varbanov if (ret)
5587472c1c6SStanimir Varbanov return ret;
5597472c1c6SStanimir Varbanov
5607472c1c6SStanimir Varbanov mutex_lock(&inst->lock);
561e69b987aSStanimir Varbanov
562beac8290SStanimir Varbanov if (cmd->cmd == V4L2_DEC_CMD_STOP) {
563e69b987aSStanimir Varbanov /*
564beac8290SStanimir Varbanov * Implement V4L2_DEC_CMD_STOP by enqueue an empty buffer on
565beac8290SStanimir Varbanov * decoder input to signal EOS.
566e69b987aSStanimir Varbanov */
567beac8290SStanimir Varbanov if (!(inst->streamon_out && inst->streamon_cap))
568e69b987aSStanimir Varbanov goto unlock;
569e69b987aSStanimir Varbanov
570e69b987aSStanimir Varbanov fdata.buffer_type = HFI_BUFFER_INPUT;
571e69b987aSStanimir Varbanov fdata.flags |= HFI_BUFFERFLAG_EOS;
57247f867cbSDikshita Agarwal if (IS_V6(inst->core) && is_fw_rev_or_older(inst->core, 1, 0, 87))
57383af5738SStanimir Varbanov fdata.device_addr = 0;
57483af5738SStanimir Varbanov else
575beac8290SStanimir Varbanov fdata.device_addr = 0xdeadb000;
576e69b987aSStanimir Varbanov
577e69b987aSStanimir Varbanov ret = hfi_session_process_buf(inst, &fdata);
578e69b987aSStanimir Varbanov
579c8e8dabcSFritz Koenig if (!ret && inst->codec_state == VENUS_DEC_STATE_DECODING) {
580beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_DRAIN;
581c8e8dabcSFritz Koenig inst->drain_active = true;
582c8e8dabcSFritz Koenig }
58350248ad9SMichał Krawczyk } else if (cmd->cmd == V4L2_DEC_CMD_START &&
58450248ad9SMichał Krawczyk inst->codec_state == VENUS_DEC_STATE_STOPPED) {
58550248ad9SMichał Krawczyk dst_vq = v4l2_m2m_get_vq(inst->fh.m2m_ctx,
58650248ad9SMichał Krawczyk V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
58750248ad9SMichał Krawczyk vb2_clear_last_buffer_dequeued(dst_vq);
58850248ad9SMichał Krawczyk
58950248ad9SMichał Krawczyk inst->codec_state = VENUS_DEC_STATE_DECODING;
590beac8290SStanimir Varbanov }
591beac8290SStanimir Varbanov
592e69b987aSStanimir Varbanov unlock:
5937472c1c6SStanimir Varbanov mutex_unlock(&inst->lock);
594e69b987aSStanimir Varbanov return ret;
5957472c1c6SStanimir Varbanov }
5967472c1c6SStanimir Varbanov
5977472c1c6SStanimir Varbanov static const struct v4l2_ioctl_ops vdec_ioctl_ops = {
5987472c1c6SStanimir Varbanov .vidioc_querycap = vdec_querycap,
5997e98b7b5SBoris Brezillon .vidioc_enum_fmt_vid_cap = vdec_enum_fmt,
6007e98b7b5SBoris Brezillon .vidioc_enum_fmt_vid_out = vdec_enum_fmt,
6017472c1c6SStanimir Varbanov .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt,
6027472c1c6SStanimir Varbanov .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt,
6037472c1c6SStanimir Varbanov .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt,
6047472c1c6SStanimir Varbanov .vidioc_g_fmt_vid_out_mplane = vdec_g_fmt,
6057472c1c6SStanimir Varbanov .vidioc_try_fmt_vid_cap_mplane = vdec_try_fmt,
6067472c1c6SStanimir Varbanov .vidioc_try_fmt_vid_out_mplane = vdec_try_fmt,
6077472c1c6SStanimir Varbanov .vidioc_g_selection = vdec_g_selection,
6087472c1c6SStanimir Varbanov .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
6097472c1c6SStanimir Varbanov .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
6107472c1c6SStanimir Varbanov .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
6117472c1c6SStanimir Varbanov .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
6127472c1c6SStanimir Varbanov .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
6137472c1c6SStanimir Varbanov .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
6147472c1c6SStanimir Varbanov .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
6157472c1c6SStanimir Varbanov .vidioc_streamon = v4l2_m2m_ioctl_streamon,
6167472c1c6SStanimir Varbanov .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
6177472c1c6SStanimir Varbanov .vidioc_s_parm = vdec_s_parm,
6187472c1c6SStanimir Varbanov .vidioc_enum_framesizes = vdec_enum_framesizes,
6197472c1c6SStanimir Varbanov .vidioc_subscribe_event = vdec_subscribe_event,
6207472c1c6SStanimir Varbanov .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
621beac8290SStanimir Varbanov .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
6227472c1c6SStanimir Varbanov .vidioc_decoder_cmd = vdec_decoder_cmd,
6237472c1c6SStanimir Varbanov };
6247472c1c6SStanimir Varbanov
vdec_pm_get(struct venus_inst * inst)62563342afeSStanimir Varbanov static int vdec_pm_get(struct venus_inst *inst)
62663342afeSStanimir Varbanov {
62763342afeSStanimir Varbanov struct venus_core *core = inst->core;
62863342afeSStanimir Varbanov struct device *dev = core->dev_dec;
62963342afeSStanimir Varbanov int ret;
63063342afeSStanimir Varbanov
63163342afeSStanimir Varbanov mutex_lock(&core->pm_lock);
6321938ab0dSMauro Carvalho Chehab ret = pm_runtime_resume_and_get(dev);
63363342afeSStanimir Varbanov mutex_unlock(&core->pm_lock);
63463342afeSStanimir Varbanov
6351938ab0dSMauro Carvalho Chehab return ret;
63663342afeSStanimir Varbanov }
63763342afeSStanimir Varbanov
vdec_pm_put(struct venus_inst * inst,bool autosuspend)63863342afeSStanimir Varbanov static int vdec_pm_put(struct venus_inst *inst, bool autosuspend)
63963342afeSStanimir Varbanov {
64063342afeSStanimir Varbanov struct venus_core *core = inst->core;
64163342afeSStanimir Varbanov struct device *dev = core->dev_dec;
64263342afeSStanimir Varbanov int ret;
64363342afeSStanimir Varbanov
64463342afeSStanimir Varbanov mutex_lock(&core->pm_lock);
64563342afeSStanimir Varbanov
64663342afeSStanimir Varbanov if (autosuspend)
64763342afeSStanimir Varbanov ret = pm_runtime_put_autosuspend(dev);
64863342afeSStanimir Varbanov else
64963342afeSStanimir Varbanov ret = pm_runtime_put_sync(dev);
65063342afeSStanimir Varbanov
65163342afeSStanimir Varbanov mutex_unlock(&core->pm_lock);
65263342afeSStanimir Varbanov
65363342afeSStanimir Varbanov return ret < 0 ? ret : 0;
65463342afeSStanimir Varbanov }
65563342afeSStanimir Varbanov
vdec_pm_get_put(struct venus_inst * inst)65663342afeSStanimir Varbanov static int vdec_pm_get_put(struct venus_inst *inst)
65763342afeSStanimir Varbanov {
65863342afeSStanimir Varbanov struct venus_core *core = inst->core;
65963342afeSStanimir Varbanov struct device *dev = core->dev_dec;
66063342afeSStanimir Varbanov int ret = 0;
66163342afeSStanimir Varbanov
66263342afeSStanimir Varbanov mutex_lock(&core->pm_lock);
66363342afeSStanimir Varbanov
66463342afeSStanimir Varbanov if (pm_runtime_suspended(dev)) {
6651938ab0dSMauro Carvalho Chehab ret = pm_runtime_resume_and_get(dev);
66663342afeSStanimir Varbanov if (ret < 0)
66763342afeSStanimir Varbanov goto error;
66863342afeSStanimir Varbanov
66963342afeSStanimir Varbanov ret = pm_runtime_put_autosuspend(dev);
67063342afeSStanimir Varbanov }
67163342afeSStanimir Varbanov
67263342afeSStanimir Varbanov error:
67363342afeSStanimir Varbanov mutex_unlock(&core->pm_lock);
67463342afeSStanimir Varbanov
67563342afeSStanimir Varbanov return ret < 0 ? ret : 0;
67663342afeSStanimir Varbanov }
67763342afeSStanimir Varbanov
vdec_pm_touch(struct venus_inst * inst)67863342afeSStanimir Varbanov static void vdec_pm_touch(struct venus_inst *inst)
67963342afeSStanimir Varbanov {
68063342afeSStanimir Varbanov pm_runtime_mark_last_busy(inst->core->dev_dec);
68163342afeSStanimir Varbanov }
68263342afeSStanimir Varbanov
vdec_set_properties(struct venus_inst * inst)6837472c1c6SStanimir Varbanov static int vdec_set_properties(struct venus_inst *inst)
6847472c1c6SStanimir Varbanov {
6857472c1c6SStanimir Varbanov struct vdec_controls *ctr = &inst->controls.dec;
686ea8ce235SStanimir Varbanov struct hfi_enable en = { .enable = 1 };
6874ef6039fSStanimir Varbanov u32 ptype, decode_order, conceal;
688ea8ce235SStanimir Varbanov int ret;
689ea8ce235SStanimir Varbanov
690ea8ce235SStanimir Varbanov if (ctr->post_loop_deb_mode) {
691ea8ce235SStanimir Varbanov ptype = HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
692ea8ce235SStanimir Varbanov ret = hfi_session_set_property(inst, ptype, &en);
693ea8ce235SStanimir Varbanov if (ret)
694ea8ce235SStanimir Varbanov return ret;
695ea8ce235SStanimir Varbanov }
696ea8ce235SStanimir Varbanov
6978ec0b7b0SStanimir Varbanov if (ctr->display_delay_enable && ctr->display_delay == 0) {
6988ec0b7b0SStanimir Varbanov ptype = HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER;
6998ec0b7b0SStanimir Varbanov decode_order = HFI_OUTPUT_ORDER_DECODE;
7008ec0b7b0SStanimir Varbanov ret = hfi_session_set_property(inst, ptype, &decode_order);
7018ec0b7b0SStanimir Varbanov if (ret)
7028ec0b7b0SStanimir Varbanov return ret;
7038ec0b7b0SStanimir Varbanov }
7048ec0b7b0SStanimir Varbanov
705938beb48SDikshita Agarwal /* Enabling sufficient sequence change support for VP9 */
706938beb48SDikshita Agarwal if (is_fw_rev_or_newer(inst->core, 5, 4, 51)) {
707938beb48SDikshita Agarwal ptype = HFI_PROPERTY_PARAM_VDEC_ENABLE_SUFFICIENT_SEQCHANGE_EVENT;
708938beb48SDikshita Agarwal ret = hfi_session_set_property(inst, ptype, &en);
709938beb48SDikshita Agarwal if (ret)
710938beb48SDikshita Agarwal return ret;
711938beb48SDikshita Agarwal }
712938beb48SDikshita Agarwal
7134ef6039fSStanimir Varbanov ptype = HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR;
7144ef6039fSStanimir Varbanov conceal = ctr->conceal_color & 0xffff;
7154ef6039fSStanimir Varbanov conceal |= ((ctr->conceal_color >> 16) & 0xffff) << 10;
7164ef6039fSStanimir Varbanov conceal |= ((ctr->conceal_color >> 32) & 0xffff) << 20;
7174ef6039fSStanimir Varbanov
7184ef6039fSStanimir Varbanov ret = hfi_session_set_property(inst, ptype, &conceal);
7194ef6039fSStanimir Varbanov if (ret)
7204ef6039fSStanimir Varbanov return ret;
7214ef6039fSStanimir Varbanov
722ea8ce235SStanimir Varbanov return 0;
723ea8ce235SStanimir Varbanov }
724ea8ce235SStanimir Varbanov
vdec_set_work_route(struct venus_inst * inst)7256483a8cbSDikshita Agarwal static int vdec_set_work_route(struct venus_inst *inst)
7266483a8cbSDikshita Agarwal {
7276483a8cbSDikshita Agarwal u32 ptype = HFI_PROPERTY_PARAM_WORK_ROUTE;
7286483a8cbSDikshita Agarwal struct hfi_video_work_route wr;
7296483a8cbSDikshita Agarwal
73004e3a072SKonrad Dybcio if (!(IS_IRIS2(inst->core) || IS_IRIS2_1(inst->core)))
7316483a8cbSDikshita Agarwal return 0;
7326483a8cbSDikshita Agarwal
7336483a8cbSDikshita Agarwal wr.video_work_route = inst->core->res->num_vpp_pipes;
7346483a8cbSDikshita Agarwal
7356483a8cbSDikshita Agarwal return hfi_session_set_property(inst, ptype, &wr);
7366483a8cbSDikshita Agarwal }
7376483a8cbSDikshita Agarwal
738f012b23dSStanimir Varbanov #define is_ubwc_fmt(fmt) (!!((fmt) & HFI_COLOR_FORMAT_UBWC_BASE))
739996d2155SDikshita Agarwal #define is_10bit_ubwc_fmt(fmt) (!!((fmt) & HFI_COLOR_FORMAT_10_BIT_BASE & \
740996d2155SDikshita Agarwal HFI_COLOR_FORMAT_UBWC_BASE))
741996d2155SDikshita Agarwal
742f012b23dSStanimir Varbanov
vdec_output_conf(struct venus_inst * inst)743ea8ce235SStanimir Varbanov static int vdec_output_conf(struct venus_inst *inst)
744ea8ce235SStanimir Varbanov {
7457472c1c6SStanimir Varbanov struct venus_core *core = inst->core;
7467472c1c6SStanimir Varbanov struct hfi_enable en = { .enable = 1 };
747a4ca67afSStanimir Varbanov struct hfi_buffer_requirements bufreq;
748ef15219cSStanimir Varbanov u32 width = inst->width;
749ef15219cSStanimir Varbanov u32 height = inst->height;
750f012b23dSStanimir Varbanov u32 out_fmt, out2_fmt;
751f012b23dSStanimir Varbanov bool ubwc = false;
7527472c1c6SStanimir Varbanov u32 ptype;
7537472c1c6SStanimir Varbanov int ret;
7547472c1c6SStanimir Varbanov
7551ad17595SDikshita Agarwal ret = venus_helper_set_work_mode(inst);
75601165b84SStanimir Varbanov if (ret)
75701165b84SStanimir Varbanov return ret;
75801165b84SStanimir Varbanov
7597472c1c6SStanimir Varbanov if (core->res->hfi_version == HFI_VERSION_1XX) {
7607472c1c6SStanimir Varbanov ptype = HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
7617472c1c6SStanimir Varbanov ret = hfi_session_set_property(inst, ptype, &en);
7627472c1c6SStanimir Varbanov if (ret)
7637472c1c6SStanimir Varbanov return ret;
7647472c1c6SStanimir Varbanov }
7657472c1c6SStanimir Varbanov
766f012b23dSStanimir Varbanov /* Force searching UBWC formats for bigger then HD resolutions */
767f012b23dSStanimir Varbanov if (width > 1920 && height > ALIGN(1080, 32))
768f012b23dSStanimir Varbanov ubwc = true;
769f012b23dSStanimir Varbanov
7707ed9e0b3SBryan O'Donoghue /* For Venus v4/v6 UBWC format is mandatory */
7717ed9e0b3SBryan O'Donoghue if (IS_V4(core) || IS_V6(core))
772f012b23dSStanimir Varbanov ubwc = true;
773f012b23dSStanimir Varbanov
774f012b23dSStanimir Varbanov ret = venus_helper_get_out_fmts(inst, inst->fmt_cap->pixfmt, &out_fmt,
775f012b23dSStanimir Varbanov &out2_fmt, ubwc);
776f012b23dSStanimir Varbanov if (ret)
777f012b23dSStanimir Varbanov return ret;
778f012b23dSStanimir Varbanov
779f012b23dSStanimir Varbanov inst->output_buf_size =
780f012b23dSStanimir Varbanov venus_helper_get_framesz_raw(out_fmt, width, height);
781f012b23dSStanimir Varbanov inst->output2_buf_size =
782f012b23dSStanimir Varbanov venus_helper_get_framesz_raw(out2_fmt, width, height);
783f012b23dSStanimir Varbanov
784f012b23dSStanimir Varbanov if (is_ubwc_fmt(out_fmt)) {
785f012b23dSStanimir Varbanov inst->opb_buftype = HFI_BUFFER_OUTPUT2;
786f012b23dSStanimir Varbanov inst->opb_fmt = out2_fmt;
787f012b23dSStanimir Varbanov inst->dpb_buftype = HFI_BUFFER_OUTPUT;
788f012b23dSStanimir Varbanov inst->dpb_fmt = out_fmt;
789996d2155SDikshita Agarwal } else if (is_ubwc_fmt(out2_fmt) || is_10bit_ubwc_fmt(out_fmt)) {
790f012b23dSStanimir Varbanov inst->opb_buftype = HFI_BUFFER_OUTPUT;
791f012b23dSStanimir Varbanov inst->opb_fmt = out_fmt;
792f012b23dSStanimir Varbanov inst->dpb_buftype = HFI_BUFFER_OUTPUT2;
793f012b23dSStanimir Varbanov inst->dpb_fmt = out2_fmt;
794f012b23dSStanimir Varbanov } else {
795f012b23dSStanimir Varbanov inst->opb_buftype = HFI_BUFFER_OUTPUT;
796f012b23dSStanimir Varbanov inst->opb_fmt = out_fmt;
797f012b23dSStanimir Varbanov inst->dpb_buftype = 0;
798f012b23dSStanimir Varbanov inst->dpb_fmt = 0;
799f012b23dSStanimir Varbanov }
800f012b23dSStanimir Varbanov
801f012b23dSStanimir Varbanov ret = venus_helper_set_raw_format(inst, inst->opb_fmt,
802f012b23dSStanimir Varbanov inst->opb_buftype);
803f012b23dSStanimir Varbanov if (ret)
804f012b23dSStanimir Varbanov return ret;
805f012b23dSStanimir Varbanov
806bc28936bSDikshita Agarwal ret = venus_helper_set_format_constraints(inst);
807bc28936bSDikshita Agarwal if (ret)
808bc28936bSDikshita Agarwal return ret;
809bc28936bSDikshita Agarwal
810f012b23dSStanimir Varbanov if (inst->dpb_fmt) {
811f012b23dSStanimir Varbanov ret = venus_helper_set_multistream(inst, false, true);
812f012b23dSStanimir Varbanov if (ret)
813f012b23dSStanimir Varbanov return ret;
814f012b23dSStanimir Varbanov
815f012b23dSStanimir Varbanov ret = venus_helper_set_raw_format(inst, inst->dpb_fmt,
816f012b23dSStanimir Varbanov inst->dpb_buftype);
817f012b23dSStanimir Varbanov if (ret)
818f012b23dSStanimir Varbanov return ret;
819f012b23dSStanimir Varbanov
820f012b23dSStanimir Varbanov ret = venus_helper_set_output_resolution(inst, width, height,
821f012b23dSStanimir Varbanov HFI_BUFFER_OUTPUT2);
822f012b23dSStanimir Varbanov if (ret)
823f012b23dSStanimir Varbanov return ret;
824f012b23dSStanimir Varbanov }
825f012b23dSStanimir Varbanov
8267ed9e0b3SBryan O'Donoghue if (IS_V3(core) || IS_V4(core) || IS_V6(core)) {
827a4ca67afSStanimir Varbanov ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq);
828a4ca67afSStanimir Varbanov if (ret)
829a4ca67afSStanimir Varbanov return ret;
830a4ca67afSStanimir Varbanov
831a4ca67afSStanimir Varbanov if (bufreq.size > inst->output_buf_size)
832a4ca67afSStanimir Varbanov return -EINVAL;
833a4ca67afSStanimir Varbanov
834a4ca67afSStanimir Varbanov if (inst->dpb_fmt) {
835a4ca67afSStanimir Varbanov ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT2,
836a4ca67afSStanimir Varbanov &bufreq);
837a4ca67afSStanimir Varbanov if (ret)
838a4ca67afSStanimir Varbanov return ret;
839a4ca67afSStanimir Varbanov
840a4ca67afSStanimir Varbanov if (bufreq.size > inst->output2_buf_size)
841a4ca67afSStanimir Varbanov return -EINVAL;
842a4ca67afSStanimir Varbanov }
843a4ca67afSStanimir Varbanov
844f012b23dSStanimir Varbanov if (inst->output2_buf_size) {
845f012b23dSStanimir Varbanov ret = venus_helper_set_bufsize(inst,
846f012b23dSStanimir Varbanov inst->output2_buf_size,
847f012b23dSStanimir Varbanov HFI_BUFFER_OUTPUT2);
848f012b23dSStanimir Varbanov if (ret)
849f012b23dSStanimir Varbanov return ret;
850f012b23dSStanimir Varbanov }
851f012b23dSStanimir Varbanov
852f012b23dSStanimir Varbanov if (inst->output_buf_size) {
853f012b23dSStanimir Varbanov ret = venus_helper_set_bufsize(inst,
854f012b23dSStanimir Varbanov inst->output_buf_size,
855f012b23dSStanimir Varbanov HFI_BUFFER_OUTPUT);
856f012b23dSStanimir Varbanov if (ret)
857f012b23dSStanimir Varbanov return ret;
858f012b23dSStanimir Varbanov }
859f012b23dSStanimir Varbanov }
860f012b23dSStanimir Varbanov
8612b0a8517SStanimir Varbanov ret = venus_helper_set_dyn_bufmode(inst);
8627472c1c6SStanimir Varbanov if (ret)
8637472c1c6SStanimir Varbanov return ret;
8647472c1c6SStanimir Varbanov
8657472c1c6SStanimir Varbanov return 0;
8667472c1c6SStanimir Varbanov }
8677472c1c6SStanimir Varbanov
vdec_session_init(struct venus_inst * inst)868beac8290SStanimir Varbanov static int vdec_session_init(struct venus_inst *inst)
8697472c1c6SStanimir Varbanov {
8707472c1c6SStanimir Varbanov int ret;
8717472c1c6SStanimir Varbanov
872aa603389SStanimir Varbanov ret = venus_helper_session_init(inst);
873e922a33eSStanimir Varbanov if (ret == -EALREADY)
874beac8290SStanimir Varbanov return 0;
875beac8290SStanimir Varbanov else if (ret)
8767472c1c6SStanimir Varbanov return ret;
8777472c1c6SStanimir Varbanov
878beac8290SStanimir Varbanov ret = venus_helper_set_input_resolution(inst, frame_width_min(inst),
879beac8290SStanimir Varbanov frame_height_min(inst));
8807472c1c6SStanimir Varbanov if (ret)
8817472c1c6SStanimir Varbanov goto deinit;
8827472c1c6SStanimir Varbanov
8837472c1c6SStanimir Varbanov return 0;
8847472c1c6SStanimir Varbanov deinit:
8857472c1c6SStanimir Varbanov hfi_session_deinit(inst);
8867472c1c6SStanimir Varbanov return ret;
8877472c1c6SStanimir Varbanov }
8887472c1c6SStanimir Varbanov
vdec_num_buffers(struct venus_inst * inst,unsigned int * in_num,unsigned int * out_num)8897094af54SStanimir Varbanov static int vdec_num_buffers(struct venus_inst *inst, unsigned int *in_num,
8907094af54SStanimir Varbanov unsigned int *out_num)
8917472c1c6SStanimir Varbanov {
8927094af54SStanimir Varbanov enum hfi_version ver = inst->core->res->hfi_version;
8937472c1c6SStanimir Varbanov struct hfi_buffer_requirements bufreq;
8947472c1c6SStanimir Varbanov int ret;
8957472c1c6SStanimir Varbanov
8967094af54SStanimir Varbanov *in_num = *out_num = 0;
8977094af54SStanimir Varbanov
8987094af54SStanimir Varbanov ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq);
8997094af54SStanimir Varbanov if (ret)
900beac8290SStanimir Varbanov return ret;
9017094af54SStanimir Varbanov
902bbfc89e6SKonrad Dybcio *in_num = hfi_bufreq_get_count_min(&bufreq, ver);
9037094af54SStanimir Varbanov
9047472c1c6SStanimir Varbanov ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq);
9057094af54SStanimir Varbanov if (ret)
906beac8290SStanimir Varbanov return ret;
9077472c1c6SStanimir Varbanov
908bbfc89e6SKonrad Dybcio *out_num = hfi_bufreq_get_count_min(&bufreq, ver);
9097472c1c6SStanimir Varbanov
910beac8290SStanimir Varbanov return 0;
9117472c1c6SStanimir Varbanov }
9127472c1c6SStanimir Varbanov
vdec_queue_setup(struct vb2_queue * q,unsigned int * num_buffers,unsigned int * num_planes,unsigned int sizes[],struct device * alloc_devs[])9137472c1c6SStanimir Varbanov static int vdec_queue_setup(struct vb2_queue *q,
9147472c1c6SStanimir Varbanov unsigned int *num_buffers, unsigned int *num_planes,
9157472c1c6SStanimir Varbanov unsigned int sizes[], struct device *alloc_devs[])
9167472c1c6SStanimir Varbanov {
9177472c1c6SStanimir Varbanov struct venus_inst *inst = vb2_get_drv_priv(q);
9183227a8f7SStanimir Varbanov struct venus_core *core = inst->core;
919e1cb72deSStanimir Varbanov unsigned int in_num, out_num;
9207472c1c6SStanimir Varbanov int ret = 0;
9217472c1c6SStanimir Varbanov
9227472c1c6SStanimir Varbanov if (*num_planes) {
923f012b23dSStanimir Varbanov unsigned int output_buf_size = venus_helper_get_opb_size(inst);
924f012b23dSStanimir Varbanov
9257472c1c6SStanimir Varbanov if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
9267472c1c6SStanimir Varbanov *num_planes != inst->fmt_out->num_planes)
9277472c1c6SStanimir Varbanov return -EINVAL;
9287472c1c6SStanimir Varbanov
9297472c1c6SStanimir Varbanov if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
9307472c1c6SStanimir Varbanov *num_planes != inst->fmt_cap->num_planes)
9317472c1c6SStanimir Varbanov return -EINVAL;
9327472c1c6SStanimir Varbanov
9337472c1c6SStanimir Varbanov if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE &&
9347472c1c6SStanimir Varbanov sizes[0] < inst->input_buf_size)
9357472c1c6SStanimir Varbanov return -EINVAL;
9367472c1c6SStanimir Varbanov
9377472c1c6SStanimir Varbanov if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE &&
938f012b23dSStanimir Varbanov sizes[0] < output_buf_size)
9397472c1c6SStanimir Varbanov return -EINVAL;
9407472c1c6SStanimir Varbanov
9417472c1c6SStanimir Varbanov return 0;
9427472c1c6SStanimir Varbanov }
9437472c1c6SStanimir Varbanov
9443227a8f7SStanimir Varbanov if (test_bit(0, &core->sys_error)) {
9453227a8f7SStanimir Varbanov if (inst->nonblock)
9463227a8f7SStanimir Varbanov return -EAGAIN;
9473227a8f7SStanimir Varbanov
9483227a8f7SStanimir Varbanov ret = wait_event_interruptible(core->sys_err_done,
9493227a8f7SStanimir Varbanov !test_bit(0, &core->sys_error));
9503227a8f7SStanimir Varbanov if (ret)
9513227a8f7SStanimir Varbanov return ret;
9523227a8f7SStanimir Varbanov }
9533227a8f7SStanimir Varbanov
95463342afeSStanimir Varbanov ret = vdec_pm_get(inst);
955beac8290SStanimir Varbanov if (ret)
956beac8290SStanimir Varbanov return ret;
957beac8290SStanimir Varbanov
95863342afeSStanimir Varbanov ret = vdec_session_init(inst);
95963342afeSStanimir Varbanov if (ret)
96063342afeSStanimir Varbanov goto put_power;
96163342afeSStanimir Varbanov
9627094af54SStanimir Varbanov ret = vdec_num_buffers(inst, &in_num, &out_num);
9637094af54SStanimir Varbanov if (ret)
96463342afeSStanimir Varbanov goto put_power;
96563342afeSStanimir Varbanov
96663342afeSStanimir Varbanov ret = vdec_pm_put(inst, false);
96763342afeSStanimir Varbanov if (ret)
9687094af54SStanimir Varbanov return ret;
9697094af54SStanimir Varbanov
9707472c1c6SStanimir Varbanov switch (q->type) {
9717472c1c6SStanimir Varbanov case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
9727472c1c6SStanimir Varbanov *num_planes = inst->fmt_out->num_planes;
973e1cb72deSStanimir Varbanov sizes[0] = venus_helper_get_framesz(inst->fmt_out->pixfmt,
974e1cb72deSStanimir Varbanov inst->out_width,
9757472c1c6SStanimir Varbanov inst->out_height);
976be76f150SStanimir Varbanov sizes[0] = max(sizes[0], inst->input_buf_size);
9777472c1c6SStanimir Varbanov inst->input_buf_size = sizes[0];
9787094af54SStanimir Varbanov *num_buffers = max(*num_buffers, in_num);
9797472c1c6SStanimir Varbanov inst->num_input_bufs = *num_buffers;
9807094af54SStanimir Varbanov inst->num_output_bufs = out_num;
9817472c1c6SStanimir Varbanov break;
9827472c1c6SStanimir Varbanov case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
9837472c1c6SStanimir Varbanov *num_planes = inst->fmt_cap->num_planes;
984e1cb72deSStanimir Varbanov sizes[0] = venus_helper_get_framesz(inst->fmt_cap->pixfmt,
985e1cb72deSStanimir Varbanov inst->width,
9867472c1c6SStanimir Varbanov inst->height);
9877472c1c6SStanimir Varbanov inst->output_buf_size = sizes[0];
9887094af54SStanimir Varbanov *num_buffers = max(*num_buffers, out_num);
9897094af54SStanimir Varbanov inst->num_output_bufs = *num_buffers;
990beac8290SStanimir Varbanov
991beac8290SStanimir Varbanov mutex_lock(&inst->lock);
992beac8290SStanimir Varbanov if (inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP)
993beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_STOPPED;
994beac8290SStanimir Varbanov mutex_unlock(&inst->lock);
9957472c1c6SStanimir Varbanov break;
9967472c1c6SStanimir Varbanov default:
9977472c1c6SStanimir Varbanov ret = -EINVAL;
9987472c1c6SStanimir Varbanov break;
9997472c1c6SStanimir Varbanov }
10007472c1c6SStanimir Varbanov
10017472c1c6SStanimir Varbanov return ret;
100263342afeSStanimir Varbanov
100363342afeSStanimir Varbanov put_power:
100463342afeSStanimir Varbanov vdec_pm_put(inst, false);
100563342afeSStanimir Varbanov return ret;
10067472c1c6SStanimir Varbanov }
10077472c1c6SStanimir Varbanov
vdec_verify_conf(struct venus_inst * inst)10087472c1c6SStanimir Varbanov static int vdec_verify_conf(struct venus_inst *inst)
10097472c1c6SStanimir Varbanov {
1010f04997bdSStanimir Varbanov enum hfi_version ver = inst->core->res->hfi_version;
10117472c1c6SStanimir Varbanov struct hfi_buffer_requirements bufreq;
10127472c1c6SStanimir Varbanov int ret;
10137472c1c6SStanimir Varbanov
10147472c1c6SStanimir Varbanov if (!inst->num_input_bufs || !inst->num_output_bufs)
10157472c1c6SStanimir Varbanov return -EINVAL;
10167472c1c6SStanimir Varbanov
10177472c1c6SStanimir Varbanov ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq);
10187472c1c6SStanimir Varbanov if (ret)
10197472c1c6SStanimir Varbanov return ret;
10207472c1c6SStanimir Varbanov
10217472c1c6SStanimir Varbanov if (inst->num_output_bufs < bufreq.count_actual ||
1022bbfc89e6SKonrad Dybcio inst->num_output_bufs < hfi_bufreq_get_count_min(&bufreq, ver))
10237472c1c6SStanimir Varbanov return -EINVAL;
10247472c1c6SStanimir Varbanov
10257472c1c6SStanimir Varbanov ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq);
10267472c1c6SStanimir Varbanov if (ret)
10277472c1c6SStanimir Varbanov return ret;
10287472c1c6SStanimir Varbanov
1029bbfc89e6SKonrad Dybcio if (inst->num_input_bufs < hfi_bufreq_get_count_min(&bufreq, ver))
10307472c1c6SStanimir Varbanov return -EINVAL;
10317472c1c6SStanimir Varbanov
10327472c1c6SStanimir Varbanov return 0;
10337472c1c6SStanimir Varbanov }
10347472c1c6SStanimir Varbanov
vdec_start_capture(struct venus_inst * inst)1035beac8290SStanimir Varbanov static int vdec_start_capture(struct venus_inst *inst)
1036beac8290SStanimir Varbanov {
1037beac8290SStanimir Varbanov int ret;
1038beac8290SStanimir Varbanov
1039beac8290SStanimir Varbanov if (!inst->streamon_out)
1040beac8290SStanimir Varbanov return 0;
1041beac8290SStanimir Varbanov
1042beac8290SStanimir Varbanov if (inst->codec_state == VENUS_DEC_STATE_DECODING) {
1043beac8290SStanimir Varbanov if (inst->reconfig)
1044beac8290SStanimir Varbanov goto reconfigure;
1045beac8290SStanimir Varbanov
1046beac8290SStanimir Varbanov venus_helper_queue_dpb_bufs(inst);
1047beac8290SStanimir Varbanov venus_helper_process_initial_cap_bufs(inst);
1048beac8290SStanimir Varbanov inst->streamon_cap = 1;
1049beac8290SStanimir Varbanov return 0;
1050beac8290SStanimir Varbanov }
1051beac8290SStanimir Varbanov
1052beac8290SStanimir Varbanov if (inst->codec_state != VENUS_DEC_STATE_STOPPED)
1053beac8290SStanimir Varbanov return 0;
1054beac8290SStanimir Varbanov
1055beac8290SStanimir Varbanov reconfigure:
1056beac8290SStanimir Varbanov ret = vdec_output_conf(inst);
1057beac8290SStanimir Varbanov if (ret)
1058beac8290SStanimir Varbanov return ret;
1059beac8290SStanimir Varbanov
1060beac8290SStanimir Varbanov ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs,
1061beac8290SStanimir Varbanov VB2_MAX_FRAME, VB2_MAX_FRAME);
1062beac8290SStanimir Varbanov if (ret)
1063beac8290SStanimir Varbanov return ret;
1064beac8290SStanimir Varbanov
1065beac8290SStanimir Varbanov ret = venus_helper_intbufs_realloc(inst);
1066beac8290SStanimir Varbanov if (ret)
1067beac8290SStanimir Varbanov goto err;
1068beac8290SStanimir Varbanov
106916545aa3SDikshita Agarwal venus_pm_load_scale(inst);
107016545aa3SDikshita Agarwal
107116545aa3SDikshita Agarwal inst->next_buf_last = false;
107216545aa3SDikshita Agarwal
1073beac8290SStanimir Varbanov ret = venus_helper_alloc_dpb_bufs(inst);
1074beac8290SStanimir Varbanov if (ret)
1075beac8290SStanimir Varbanov goto err;
1076beac8290SStanimir Varbanov
107716545aa3SDikshita Agarwal ret = hfi_session_continue(inst);
107816545aa3SDikshita Agarwal if (ret)
107916545aa3SDikshita Agarwal goto free_dpb_bufs;
108016545aa3SDikshita Agarwal
1081beac8290SStanimir Varbanov ret = venus_helper_queue_dpb_bufs(inst);
1082beac8290SStanimir Varbanov if (ret)
1083beac8290SStanimir Varbanov goto free_dpb_bufs;
1084beac8290SStanimir Varbanov
1085beac8290SStanimir Varbanov ret = venus_helper_process_initial_cap_bufs(inst);
1086beac8290SStanimir Varbanov if (ret)
1087beac8290SStanimir Varbanov goto free_dpb_bufs;
1088beac8290SStanimir Varbanov
1089beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_DECODING;
1090beac8290SStanimir Varbanov
1091c8e8dabcSFritz Koenig if (inst->drain_active)
1092c8e8dabcSFritz Koenig inst->codec_state = VENUS_DEC_STATE_DRAIN;
1093c8e8dabcSFritz Koenig
1094beac8290SStanimir Varbanov inst->streamon_cap = 1;
1095beac8290SStanimir Varbanov inst->sequence_cap = 0;
1096beac8290SStanimir Varbanov inst->reconfig = false;
1097c8e8dabcSFritz Koenig inst->drain_active = false;
1098beac8290SStanimir Varbanov
1099beac8290SStanimir Varbanov return 0;
1100beac8290SStanimir Varbanov
1101beac8290SStanimir Varbanov free_dpb_bufs:
1102beac8290SStanimir Varbanov venus_helper_free_dpb_bufs(inst);
1103beac8290SStanimir Varbanov err:
1104beac8290SStanimir Varbanov return ret;
1105beac8290SStanimir Varbanov }
1106beac8290SStanimir Varbanov
vdec_start_output(struct venus_inst * inst)1107beac8290SStanimir Varbanov static int vdec_start_output(struct venus_inst *inst)
1108beac8290SStanimir Varbanov {
1109beac8290SStanimir Varbanov int ret;
1110beac8290SStanimir Varbanov
1111beac8290SStanimir Varbanov if (inst->codec_state == VENUS_DEC_STATE_SEEK) {
1112beac8290SStanimir Varbanov ret = venus_helper_process_initial_out_bufs(inst);
1113d5ee32d7SAlexandre Courbot if (inst->next_buf_last)
1114d5ee32d7SAlexandre Courbot inst->codec_state = VENUS_DEC_STATE_DRC;
1115d5ee32d7SAlexandre Courbot else
1116beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_DECODING;
1117beac8290SStanimir Varbanov goto done;
1118beac8290SStanimir Varbanov }
1119beac8290SStanimir Varbanov
1120beac8290SStanimir Varbanov if (inst->codec_state == VENUS_DEC_STATE_INIT ||
1121beac8290SStanimir Varbanov inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) {
1122beac8290SStanimir Varbanov ret = venus_helper_process_initial_out_bufs(inst);
1123beac8290SStanimir Varbanov goto done;
1124beac8290SStanimir Varbanov }
1125beac8290SStanimir Varbanov
1126beac8290SStanimir Varbanov if (inst->codec_state != VENUS_DEC_STATE_DEINIT)
1127beac8290SStanimir Varbanov return -EINVAL;
1128beac8290SStanimir Varbanov
1129beac8290SStanimir Varbanov venus_helper_init_instance(inst);
1130beac8290SStanimir Varbanov inst->sequence_out = 0;
1131beac8290SStanimir Varbanov inst->reconfig = false;
1132acf8a57dSStanimir Varbanov inst->next_buf_last = false;
1133beac8290SStanimir Varbanov
1134beac8290SStanimir Varbanov ret = vdec_set_properties(inst);
1135beac8290SStanimir Varbanov if (ret)
1136beac8290SStanimir Varbanov return ret;
1137beac8290SStanimir Varbanov
11386483a8cbSDikshita Agarwal ret = vdec_set_work_route(inst);
11396483a8cbSDikshita Agarwal if (ret)
11406483a8cbSDikshita Agarwal return ret;
11416483a8cbSDikshita Agarwal
1142beac8290SStanimir Varbanov ret = vdec_output_conf(inst);
1143beac8290SStanimir Varbanov if (ret)
1144beac8290SStanimir Varbanov return ret;
1145beac8290SStanimir Varbanov
1146beac8290SStanimir Varbanov ret = vdec_verify_conf(inst);
1147beac8290SStanimir Varbanov if (ret)
1148beac8290SStanimir Varbanov return ret;
1149beac8290SStanimir Varbanov
1150beac8290SStanimir Varbanov ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs,
1151beac8290SStanimir Varbanov VB2_MAX_FRAME, VB2_MAX_FRAME);
1152beac8290SStanimir Varbanov if (ret)
1153beac8290SStanimir Varbanov return ret;
1154beac8290SStanimir Varbanov
1155beac8290SStanimir Varbanov ret = venus_helper_vb2_start_streaming(inst);
1156beac8290SStanimir Varbanov if (ret)
1157beac8290SStanimir Varbanov return ret;
1158beac8290SStanimir Varbanov
1159beac8290SStanimir Varbanov ret = venus_helper_process_initial_out_bufs(inst);
1160beac8290SStanimir Varbanov if (ret)
1161beac8290SStanimir Varbanov return ret;
1162beac8290SStanimir Varbanov
1163beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_INIT;
1164beac8290SStanimir Varbanov
1165beac8290SStanimir Varbanov done:
1166beac8290SStanimir Varbanov inst->streamon_out = 1;
1167beac8290SStanimir Varbanov return ret;
1168beac8290SStanimir Varbanov }
1169beac8290SStanimir Varbanov
vdec_start_streaming(struct vb2_queue * q,unsigned int count)11707472c1c6SStanimir Varbanov static int vdec_start_streaming(struct vb2_queue *q, unsigned int count)
11717472c1c6SStanimir Varbanov {
11727472c1c6SStanimir Varbanov struct venus_inst *inst = vb2_get_drv_priv(q);
11737472c1c6SStanimir Varbanov int ret;
11747472c1c6SStanimir Varbanov
11757472c1c6SStanimir Varbanov mutex_lock(&inst->lock);
11767472c1c6SStanimir Varbanov
117763342afeSStanimir Varbanov if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
117863342afeSStanimir Varbanov ret = vdec_start_capture(inst);
117963342afeSStanimir Varbanov } else {
118063342afeSStanimir Varbanov ret = vdec_pm_get(inst);
11814ebf9693SAniket Masule if (ret)
1182808431d6SStanimir Varbanov goto error;
11834ebf9693SAniket Masule
118463342afeSStanimir Varbanov ret = venus_pm_acquire_core(inst);
118563342afeSStanimir Varbanov if (ret)
118663342afeSStanimir Varbanov goto put_power;
118763342afeSStanimir Varbanov
118863342afeSStanimir Varbanov ret = vdec_pm_put(inst, true);
118963342afeSStanimir Varbanov if (ret)
119063342afeSStanimir Varbanov goto error;
119163342afeSStanimir Varbanov
1192beac8290SStanimir Varbanov ret = vdec_start_output(inst);
119363342afeSStanimir Varbanov }
11947472c1c6SStanimir Varbanov
1195beac8290SStanimir Varbanov if (ret)
1196beac8290SStanimir Varbanov goto error;
1197beac8290SStanimir Varbanov
11987472c1c6SStanimir Varbanov mutex_unlock(&inst->lock);
11997472c1c6SStanimir Varbanov return 0;
12007472c1c6SStanimir Varbanov
120163342afeSStanimir Varbanov put_power:
120263342afeSStanimir Varbanov vdec_pm_put(inst, false);
1203beac8290SStanimir Varbanov error:
12040febf923SStanimir Varbanov venus_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED);
12057472c1c6SStanimir Varbanov mutex_unlock(&inst->lock);
12067472c1c6SStanimir Varbanov return ret;
12077472c1c6SStanimir Varbanov }
12087472c1c6SStanimir Varbanov
vdec_cancel_dst_buffers(struct venus_inst * inst)1209beac8290SStanimir Varbanov static void vdec_cancel_dst_buffers(struct venus_inst *inst)
1210beac8290SStanimir Varbanov {
1211beac8290SStanimir Varbanov struct vb2_v4l2_buffer *buf;
1212beac8290SStanimir Varbanov
1213beac8290SStanimir Varbanov while ((buf = v4l2_m2m_dst_buf_remove(inst->m2m_ctx)))
1214beac8290SStanimir Varbanov v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
1215beac8290SStanimir Varbanov }
1216beac8290SStanimir Varbanov
vdec_stop_capture(struct venus_inst * inst)1217beac8290SStanimir Varbanov static int vdec_stop_capture(struct venus_inst *inst)
1218beac8290SStanimir Varbanov {
1219beac8290SStanimir Varbanov int ret = 0;
1220beac8290SStanimir Varbanov
1221beac8290SStanimir Varbanov switch (inst->codec_state) {
1222beac8290SStanimir Varbanov case VENUS_DEC_STATE_DECODING:
122385872f86SStanimir Varbanov ret = hfi_session_flush(inst, HFI_FLUSH_ALL, true);
12241771e9fbSGustavo A. R. Silva fallthrough;
1225beac8290SStanimir Varbanov case VENUS_DEC_STATE_DRAIN:
1226beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_STOPPED;
1227c8e8dabcSFritz Koenig inst->drain_active = false;
1228d5ee32d7SAlexandre Courbot fallthrough;
1229d5ee32d7SAlexandre Courbot case VENUS_DEC_STATE_SEEK:
1230d5ee32d7SAlexandre Courbot vdec_cancel_dst_buffers(inst);
1231beac8290SStanimir Varbanov break;
1232beac8290SStanimir Varbanov case VENUS_DEC_STATE_DRC:
1233acf8a57dSStanimir Varbanov ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT, true);
1234beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_CAPTURE_SETUP;
1235beac8290SStanimir Varbanov venus_helper_free_dpb_bufs(inst);
1236beac8290SStanimir Varbanov break;
1237beac8290SStanimir Varbanov default:
1238bc3d870eSStanimir Varbanov break;
1239beac8290SStanimir Varbanov }
1240beac8290SStanimir Varbanov
1241beac8290SStanimir Varbanov return ret;
1242beac8290SStanimir Varbanov }
1243beac8290SStanimir Varbanov
vdec_stop_output(struct venus_inst * inst)1244beac8290SStanimir Varbanov static int vdec_stop_output(struct venus_inst *inst)
1245beac8290SStanimir Varbanov {
1246beac8290SStanimir Varbanov int ret = 0;
1247beac8290SStanimir Varbanov
1248beac8290SStanimir Varbanov switch (inst->codec_state) {
1249beac8290SStanimir Varbanov case VENUS_DEC_STATE_DECODING:
1250beac8290SStanimir Varbanov case VENUS_DEC_STATE_DRAIN:
1251beac8290SStanimir Varbanov case VENUS_DEC_STATE_STOPPED:
1252d5ee32d7SAlexandre Courbot case VENUS_DEC_STATE_DRC:
125385872f86SStanimir Varbanov ret = hfi_session_flush(inst, HFI_FLUSH_ALL, true);
1254beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_SEEK;
1255beac8290SStanimir Varbanov break;
1256beac8290SStanimir Varbanov case VENUS_DEC_STATE_INIT:
1257beac8290SStanimir Varbanov case VENUS_DEC_STATE_CAPTURE_SETUP:
1258645753ceSDikshita Agarwal ret = hfi_session_flush(inst, HFI_FLUSH_ALL, true);
1259beac8290SStanimir Varbanov break;
1260beac8290SStanimir Varbanov default:
1261beac8290SStanimir Varbanov break;
1262beac8290SStanimir Varbanov }
1263beac8290SStanimir Varbanov
1264beac8290SStanimir Varbanov return ret;
1265beac8290SStanimir Varbanov }
1266beac8290SStanimir Varbanov
vdec_stop_streaming(struct vb2_queue * q)1267beac8290SStanimir Varbanov static void vdec_stop_streaming(struct vb2_queue *q)
1268beac8290SStanimir Varbanov {
1269beac8290SStanimir Varbanov struct venus_inst *inst = vb2_get_drv_priv(q);
1270beac8290SStanimir Varbanov int ret = -EINVAL;
1271beac8290SStanimir Varbanov
127259685fdfSVikash Garodia vdec_pm_get_put(inst);
127359685fdfSVikash Garodia
1274beac8290SStanimir Varbanov mutex_lock(&inst->lock);
1275beac8290SStanimir Varbanov
1276beac8290SStanimir Varbanov if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
1277beac8290SStanimir Varbanov ret = vdec_stop_capture(inst);
1278beac8290SStanimir Varbanov else
1279beac8290SStanimir Varbanov ret = vdec_stop_output(inst);
1280beac8290SStanimir Varbanov
12810febf923SStanimir Varbanov venus_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR);
1282beac8290SStanimir Varbanov
12833227a8f7SStanimir Varbanov inst->session_error = 0;
12843227a8f7SStanimir Varbanov
1285beac8290SStanimir Varbanov if (ret)
1286beac8290SStanimir Varbanov goto unlock;
1287beac8290SStanimir Varbanov
1288beac8290SStanimir Varbanov if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
1289beac8290SStanimir Varbanov inst->streamon_out = 0;
1290beac8290SStanimir Varbanov else
1291beac8290SStanimir Varbanov inst->streamon_cap = 0;
1292beac8290SStanimir Varbanov
1293beac8290SStanimir Varbanov unlock:
1294beac8290SStanimir Varbanov mutex_unlock(&inst->lock);
1295beac8290SStanimir Varbanov }
1296beac8290SStanimir Varbanov
vdec_session_release(struct venus_inst * inst)1297beac8290SStanimir Varbanov static void vdec_session_release(struct venus_inst *inst)
1298beac8290SStanimir Varbanov {
1299beac8290SStanimir Varbanov struct venus_core *core = inst->core;
1300beac8290SStanimir Varbanov int ret, abort = 0;
1301beac8290SStanimir Varbanov
130263342afeSStanimir Varbanov vdec_pm_get(inst);
1303beac8290SStanimir Varbanov
130463342afeSStanimir Varbanov mutex_lock(&inst->lock);
1305beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_DEINIT;
1306beac8290SStanimir Varbanov
1307beac8290SStanimir Varbanov ret = hfi_session_stop(inst);
1308beac8290SStanimir Varbanov abort = (ret && ret != -EINVAL) ? 1 : 0;
1309beac8290SStanimir Varbanov ret = hfi_session_unload_res(inst);
1310beac8290SStanimir Varbanov abort = (ret && ret != -EINVAL) ? 1 : 0;
1311beac8290SStanimir Varbanov ret = venus_helper_unregister_bufs(inst);
1312beac8290SStanimir Varbanov abort = (ret && ret != -EINVAL) ? 1 : 0;
1313beac8290SStanimir Varbanov ret = venus_helper_intbufs_free(inst);
1314beac8290SStanimir Varbanov abort = (ret && ret != -EINVAL) ? 1 : 0;
1315beac8290SStanimir Varbanov ret = hfi_session_deinit(inst);
1316beac8290SStanimir Varbanov abort = (ret && ret != -EINVAL) ? 1 : 0;
1317beac8290SStanimir Varbanov
1318b46ff4ebSStanimir Varbanov if (inst->session_error || test_bit(0, &core->sys_error))
1319beac8290SStanimir Varbanov abort = 1;
1320beac8290SStanimir Varbanov
1321beac8290SStanimir Varbanov if (abort)
1322beac8290SStanimir Varbanov hfi_session_abort(inst);
1323beac8290SStanimir Varbanov
1324beac8290SStanimir Varbanov venus_helper_free_dpb_bufs(inst);
13257482a983SStanimir Varbanov venus_pm_load_scale(inst);
1326beac8290SStanimir Varbanov INIT_LIST_HEAD(&inst->registeredbufs);
1327beac8290SStanimir Varbanov mutex_unlock(&inst->lock);
132863342afeSStanimir Varbanov
132963342afeSStanimir Varbanov venus_pm_release_core(inst);
133063342afeSStanimir Varbanov vdec_pm_put(inst, false);
1331beac8290SStanimir Varbanov }
1332beac8290SStanimir Varbanov
vdec_buf_init(struct vb2_buffer * vb)1333beac8290SStanimir Varbanov static int vdec_buf_init(struct vb2_buffer *vb)
1334beac8290SStanimir Varbanov {
1335beac8290SStanimir Varbanov struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1336beac8290SStanimir Varbanov
1337beac8290SStanimir Varbanov inst->buf_count++;
1338beac8290SStanimir Varbanov
1339beac8290SStanimir Varbanov return venus_helper_vb2_buf_init(vb);
1340beac8290SStanimir Varbanov }
1341beac8290SStanimir Varbanov
vdec_buf_cleanup(struct vb2_buffer * vb)1342beac8290SStanimir Varbanov static void vdec_buf_cleanup(struct vb2_buffer *vb)
1343beac8290SStanimir Varbanov {
1344beac8290SStanimir Varbanov struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1345e1c69c4eSVikash Garodia struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1346e1c69c4eSVikash Garodia struct venus_buffer *buf = to_venus_buffer(vbuf);
1347e1c69c4eSVikash Garodia
1348e1c69c4eSVikash Garodia mutex_lock(&inst->lock);
1349e1c69c4eSVikash Garodia if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
1350e1c69c4eSVikash Garodia if (!list_empty(&inst->registeredbufs))
1351e1c69c4eSVikash Garodia list_del_init(&buf->reg_list);
1352e1c69c4eSVikash Garodia mutex_unlock(&inst->lock);
1353beac8290SStanimir Varbanov
1354beac8290SStanimir Varbanov inst->buf_count--;
1355beac8290SStanimir Varbanov if (!inst->buf_count)
1356beac8290SStanimir Varbanov vdec_session_release(inst);
1357beac8290SStanimir Varbanov }
1358beac8290SStanimir Varbanov
vdec_vb2_buf_queue(struct vb2_buffer * vb)135963342afeSStanimir Varbanov static void vdec_vb2_buf_queue(struct vb2_buffer *vb)
136063342afeSStanimir Varbanov {
136163342afeSStanimir Varbanov struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
1362acf8a57dSStanimir Varbanov struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
1363acf8a57dSStanimir Varbanov static const struct v4l2_event eos = { .type = V4L2_EVENT_EOS };
136463342afeSStanimir Varbanov
136563342afeSStanimir Varbanov vdec_pm_get_put(inst);
136663342afeSStanimir Varbanov
1367acf8a57dSStanimir Varbanov mutex_lock(&inst->lock);
1368acf8a57dSStanimir Varbanov
1369acf8a57dSStanimir Varbanov if (inst->next_buf_last && V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) &&
1370acf8a57dSStanimir Varbanov inst->codec_state == VENUS_DEC_STATE_DRC) {
1371acf8a57dSStanimir Varbanov vbuf->flags |= V4L2_BUF_FLAG_LAST;
1372acf8a57dSStanimir Varbanov vbuf->sequence = inst->sequence_cap++;
1373acf8a57dSStanimir Varbanov vbuf->field = V4L2_FIELD_NONE;
1374acf8a57dSStanimir Varbanov vb2_set_plane_payload(vb, 0, 0);
1375acf8a57dSStanimir Varbanov v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
1376acf8a57dSStanimir Varbanov v4l2_event_queue_fh(&inst->fh, &eos);
1377acf8a57dSStanimir Varbanov inst->next_buf_last = false;
1378acf8a57dSStanimir Varbanov mutex_unlock(&inst->lock);
1379acf8a57dSStanimir Varbanov return;
1380acf8a57dSStanimir Varbanov }
1381acf8a57dSStanimir Varbanov
138263342afeSStanimir Varbanov venus_helper_vb2_buf_queue(vb);
138321560ddfSStanimir Varbanov mutex_unlock(&inst->lock);
138463342afeSStanimir Varbanov }
138563342afeSStanimir Varbanov
13867472c1c6SStanimir Varbanov static const struct vb2_ops vdec_vb2_ops = {
13877472c1c6SStanimir Varbanov .queue_setup = vdec_queue_setup,
1388beac8290SStanimir Varbanov .buf_init = vdec_buf_init,
1389beac8290SStanimir Varbanov .buf_cleanup = vdec_buf_cleanup,
13907472c1c6SStanimir Varbanov .buf_prepare = venus_helper_vb2_buf_prepare,
13917472c1c6SStanimir Varbanov .start_streaming = vdec_start_streaming,
1392beac8290SStanimir Varbanov .stop_streaming = vdec_stop_streaming,
139363342afeSStanimir Varbanov .buf_queue = vdec_vb2_buf_queue,
13947472c1c6SStanimir Varbanov };
13957472c1c6SStanimir Varbanov
vdec_buf_done(struct venus_inst * inst,unsigned int buf_type,u32 tag,u32 bytesused,u32 data_offset,u32 flags,u32 hfi_flags,u64 timestamp_us)13967472c1c6SStanimir Varbanov static void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type,
13977472c1c6SStanimir Varbanov u32 tag, u32 bytesused, u32 data_offset, u32 flags,
13987472c1c6SStanimir Varbanov u32 hfi_flags, u64 timestamp_us)
13997472c1c6SStanimir Varbanov {
14007472c1c6SStanimir Varbanov enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
14017472c1c6SStanimir Varbanov struct vb2_v4l2_buffer *vbuf;
14027472c1c6SStanimir Varbanov struct vb2_buffer *vb;
14037472c1c6SStanimir Varbanov unsigned int type;
14047472c1c6SStanimir Varbanov
140563342afeSStanimir Varbanov vdec_pm_touch(inst);
140663342afeSStanimir Varbanov
14077472c1c6SStanimir Varbanov if (buf_type == HFI_BUFFER_INPUT)
14087472c1c6SStanimir Varbanov type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
14097472c1c6SStanimir Varbanov else
14107472c1c6SStanimir Varbanov type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
14117472c1c6SStanimir Varbanov
14127472c1c6SStanimir Varbanov vbuf = venus_helper_find_buf(inst, type, tag);
141340d87aafSMansur Alisha Shaik if (!vbuf) {
141440d87aafSMansur Alisha Shaik venus_helper_change_dpb_owner(inst, vbuf, type, buf_type, tag);
14157472c1c6SStanimir Varbanov return;
141640d87aafSMansur Alisha Shaik }
14177472c1c6SStanimir Varbanov
14187472c1c6SStanimir Varbanov vbuf->flags = flags;
14197472c1c6SStanimir Varbanov vbuf->field = V4L2_FIELD_NONE;
1420beac8290SStanimir Varbanov vb = &vbuf->vb2_buf;
14217472c1c6SStanimir Varbanov
14227472c1c6SStanimir Varbanov if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
142387e25f4bSAlexandre Courbot vb2_set_plane_payload(vb, 0, bytesused);
14247472c1c6SStanimir Varbanov vb->planes[0].data_offset = data_offset;
14257472c1c6SStanimir Varbanov vb->timestamp = timestamp_us * NSEC_PER_USEC;
14267472c1c6SStanimir Varbanov vbuf->sequence = inst->sequence_cap++;
14277472c1c6SStanimir Varbanov
14287472c1c6SStanimir Varbanov if (vbuf->flags & V4L2_BUF_FLAG_LAST) {
14297472c1c6SStanimir Varbanov const struct v4l2_event ev = { .type = V4L2_EVENT_EOS };
14307472c1c6SStanimir Varbanov
14317472c1c6SStanimir Varbanov v4l2_event_queue_fh(&inst->fh, &ev);
1432beac8290SStanimir Varbanov
1433c8e8dabcSFritz Koenig if (inst->codec_state == VENUS_DEC_STATE_DRAIN) {
1434c8e8dabcSFritz Koenig inst->drain_active = false;
1435beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_STOPPED;
14367472c1c6SStanimir Varbanov }
1437c8e8dabcSFritz Koenig }
143851df3c81SStanimir Varbanov
143951df3c81SStanimir Varbanov if (!bytesused)
144051df3c81SStanimir Varbanov state = VB2_BUF_STATE_ERROR;
14417472c1c6SStanimir Varbanov } else {
14427472c1c6SStanimir Varbanov vbuf->sequence = inst->sequence_out++;
14437472c1c6SStanimir Varbanov }
14447472c1c6SStanimir Varbanov
1445d42974e4SStanimir Varbanov venus_helper_get_ts_metadata(inst, timestamp_us, vbuf);
1446d42974e4SStanimir Varbanov
14477472c1c6SStanimir Varbanov if (hfi_flags & HFI_BUFFERFLAG_READONLY)
14487472c1c6SStanimir Varbanov venus_helper_acquire_buf_ref(vbuf);
14497472c1c6SStanimir Varbanov
14507472c1c6SStanimir Varbanov if (hfi_flags & HFI_BUFFERFLAG_DATACORRUPT)
14517472c1c6SStanimir Varbanov state = VB2_BUF_STATE_ERROR;
14527472c1c6SStanimir Varbanov
1453beac8290SStanimir Varbanov if (hfi_flags & HFI_BUFFERFLAG_DROP_FRAME) {
1454beac8290SStanimir Varbanov state = VB2_BUF_STATE_ERROR;
1455beac8290SStanimir Varbanov vb2_set_plane_payload(vb, 0, 0);
1456beac8290SStanimir Varbanov vb->timestamp = 0;
1457beac8290SStanimir Varbanov }
1458beac8290SStanimir Varbanov
14597472c1c6SStanimir Varbanov v4l2_m2m_buf_done(vbuf, state);
14607472c1c6SStanimir Varbanov }
14617472c1c6SStanimir Varbanov
vdec_event_change(struct venus_inst * inst,struct hfi_event_data * ev_data,bool sufficient)1462beac8290SStanimir Varbanov static void vdec_event_change(struct venus_inst *inst,
1463beac8290SStanimir Varbanov struct hfi_event_data *ev_data, bool sufficient)
1464beac8290SStanimir Varbanov {
1465beac8290SStanimir Varbanov static const struct v4l2_event ev = {
1466beac8290SStanimir Varbanov .type = V4L2_EVENT_SOURCE_CHANGE,
1467beac8290SStanimir Varbanov .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION };
1468beac8290SStanimir Varbanov struct device *dev = inst->core->dev_dec;
1469beac8290SStanimir Varbanov struct v4l2_format format = {};
1470beac8290SStanimir Varbanov
1471beac8290SStanimir Varbanov mutex_lock(&inst->lock);
1472beac8290SStanimir Varbanov
1473beac8290SStanimir Varbanov format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
1474beac8290SStanimir Varbanov format.fmt.pix_mp.pixelformat = inst->fmt_cap->pixfmt;
1475beac8290SStanimir Varbanov format.fmt.pix_mp.width = ev_data->width;
1476beac8290SStanimir Varbanov format.fmt.pix_mp.height = ev_data->height;
1477beac8290SStanimir Varbanov
1478beac8290SStanimir Varbanov vdec_try_fmt_common(inst, &format);
1479beac8290SStanimir Varbanov
1480beac8290SStanimir Varbanov inst->width = format.fmt.pix_mp.width;
1481beac8290SStanimir Varbanov inst->height = format.fmt.pix_mp.height;
1482de04408fSAlexandre Courbot /*
1483de04408fSAlexandre Courbot * Some versions of the firmware do not report crop information for
1484de04408fSAlexandre Courbot * all codecs. For these cases, set the crop to the coded resolution.
1485de04408fSAlexandre Courbot */
1486de04408fSAlexandre Courbot if (ev_data->input_crop.width > 0 && ev_data->input_crop.height > 0) {
1487de04408fSAlexandre Courbot inst->crop.left = ev_data->input_crop.left;
1488de04408fSAlexandre Courbot inst->crop.top = ev_data->input_crop.top;
1489de04408fSAlexandre Courbot inst->crop.width = ev_data->input_crop.width;
1490de04408fSAlexandre Courbot inst->crop.height = ev_data->input_crop.height;
1491de04408fSAlexandre Courbot } else {
1492de04408fSAlexandre Courbot inst->crop.left = 0;
1493de04408fSAlexandre Courbot inst->crop.top = 0;
1494de04408fSAlexandre Courbot inst->crop.width = ev_data->width;
1495de04408fSAlexandre Courbot inst->crop.height = ev_data->height;
1496de04408fSAlexandre Courbot }
1497beac8290SStanimir Varbanov
149816545aa3SDikshita Agarwal inst->fw_min_cnt = ev_data->buf_count;
149916545aa3SDikshita Agarwal /* overwriting this to 11 for vp9 due to fw bug */
150016545aa3SDikshita Agarwal if (inst->hfi_codec == HFI_VIDEO_CODEC_VP9)
150116545aa3SDikshita Agarwal inst->fw_min_cnt = 11;
150216545aa3SDikshita Agarwal
1503beac8290SStanimir Varbanov inst->out_width = ev_data->width;
1504beac8290SStanimir Varbanov inst->out_height = ev_data->height;
1505beac8290SStanimir Varbanov
150608998cf3SDikshita Agarwal if (inst->bit_depth != ev_data->bit_depth) {
1507ab1eda44SAniket Masule inst->bit_depth = ev_data->bit_depth;
150808998cf3SDikshita Agarwal if (inst->bit_depth == VIDC_BITDEPTH_10)
150908998cf3SDikshita Agarwal inst->fmt_cap = &vdec_formats[VENUS_FMT_P010];
151008998cf3SDikshita Agarwal else
151108998cf3SDikshita Agarwal inst->fmt_cap = &vdec_formats[VENUS_FMT_NV12];
151208998cf3SDikshita Agarwal }
1513ab1eda44SAniket Masule
1514b8201f3eSStanimir Varbanov if (inst->pic_struct != ev_data->pic_struct)
1515b8201f3eSStanimir Varbanov inst->pic_struct = ev_data->pic_struct;
1516b8201f3eSStanimir Varbanov
15178c91dc08SStanimir Varbanov dev_dbg(dev, VDBGM "event %s sufficient resources (%ux%u)\n",
1518beac8290SStanimir Varbanov sufficient ? "" : "not", ev_data->width, ev_data->height);
1519beac8290SStanimir Varbanov
1520beac8290SStanimir Varbanov switch (inst->codec_state) {
1521beac8290SStanimir Varbanov case VENUS_DEC_STATE_INIT:
1522beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_CAPTURE_SETUP;
1523beac8290SStanimir Varbanov break;
1524beac8290SStanimir Varbanov case VENUS_DEC_STATE_DECODING:
1525c8e8dabcSFritz Koenig case VENUS_DEC_STATE_DRAIN:
1526beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_DRC;
1527beac8290SStanimir Varbanov break;
1528beac8290SStanimir Varbanov default:
1529beac8290SStanimir Varbanov break;
1530beac8290SStanimir Varbanov }
1531beac8290SStanimir Varbanov
153285872f86SStanimir Varbanov /*
153385872f86SStanimir Varbanov * The assumption is that the firmware have to return the last buffer
153485872f86SStanimir Varbanov * before this event is received in the v4l2 driver. Also the firmware
153585872f86SStanimir Varbanov * itself doesn't mark the last decoder output buffer with HFI EOS flag.
153685872f86SStanimir Varbanov */
153785872f86SStanimir Varbanov
1538a4ca67afSStanimir Varbanov if (inst->codec_state == VENUS_DEC_STATE_DRC) {
153985872f86SStanimir Varbanov int ret;
154085872f86SStanimir Varbanov
1541acf8a57dSStanimir Varbanov inst->next_buf_last = true;
154285872f86SStanimir Varbanov
154385872f86SStanimir Varbanov ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT, false);
154485872f86SStanimir Varbanov if (ret)
15458c91dc08SStanimir Varbanov dev_dbg(dev, VDBGH "flush output error %d\n", ret);
154685872f86SStanimir Varbanov }
154785872f86SStanimir Varbanov
1548d5ee32d7SAlexandre Courbot inst->next_buf_last = true;
1549beac8290SStanimir Varbanov inst->reconfig = true;
1550beac8290SStanimir Varbanov v4l2_event_queue_fh(&inst->fh, &ev);
1551beac8290SStanimir Varbanov wake_up(&inst->reconf_wait);
1552beac8290SStanimir Varbanov
1553beac8290SStanimir Varbanov mutex_unlock(&inst->lock);
1554beac8290SStanimir Varbanov }
1555beac8290SStanimir Varbanov
vdec_event_notify(struct venus_inst * inst,u32 event,struct hfi_event_data * data)15567472c1c6SStanimir Varbanov static void vdec_event_notify(struct venus_inst *inst, u32 event,
15577472c1c6SStanimir Varbanov struct hfi_event_data *data)
15587472c1c6SStanimir Varbanov {
15597472c1c6SStanimir Varbanov struct venus_core *core = inst->core;
15607472c1c6SStanimir Varbanov struct device *dev = core->dev_dec;
15617472c1c6SStanimir Varbanov
156263342afeSStanimir Varbanov vdec_pm_touch(inst);
156363342afeSStanimir Varbanov
15647472c1c6SStanimir Varbanov switch (event) {
15657472c1c6SStanimir Varbanov case EVT_SESSION_ERROR:
15667472c1c6SStanimir Varbanov inst->session_error = true;
15673227a8f7SStanimir Varbanov venus_helper_vb2_queue_error(inst);
15687472c1c6SStanimir Varbanov dev_err(dev, "dec: event session error %x\n", inst->error);
15697472c1c6SStanimir Varbanov break;
15707472c1c6SStanimir Varbanov case EVT_SYS_EVENT_CHANGE:
15717472c1c6SStanimir Varbanov switch (data->event_type) {
15727472c1c6SStanimir Varbanov case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES:
1573beac8290SStanimir Varbanov vdec_event_change(inst, data, true);
15747472c1c6SStanimir Varbanov break;
15757472c1c6SStanimir Varbanov case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES:
1576beac8290SStanimir Varbanov vdec_event_change(inst, data, false);
15777472c1c6SStanimir Varbanov break;
15787472c1c6SStanimir Varbanov case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
15797472c1c6SStanimir Varbanov venus_helper_release_buf_ref(inst, data->tag);
15807472c1c6SStanimir Varbanov break;
15817472c1c6SStanimir Varbanov default:
15827472c1c6SStanimir Varbanov break;
15837472c1c6SStanimir Varbanov }
15847472c1c6SStanimir Varbanov break;
15857472c1c6SStanimir Varbanov default:
15867472c1c6SStanimir Varbanov break;
15877472c1c6SStanimir Varbanov }
15887472c1c6SStanimir Varbanov }
15897472c1c6SStanimir Varbanov
vdec_flush_done(struct venus_inst * inst)159085872f86SStanimir Varbanov static void vdec_flush_done(struct venus_inst *inst)
159185872f86SStanimir Varbanov {
1592acf8a57dSStanimir Varbanov dev_dbg(inst->core->dev_dec, VDBGH "flush done\n");
159385872f86SStanimir Varbanov }
159485872f86SStanimir Varbanov
15957472c1c6SStanimir Varbanov static const struct hfi_inst_ops vdec_hfi_ops = {
15967472c1c6SStanimir Varbanov .buf_done = vdec_buf_done,
15977472c1c6SStanimir Varbanov .event_notify = vdec_event_notify,
159885872f86SStanimir Varbanov .flush_done = vdec_flush_done,
15997472c1c6SStanimir Varbanov };
16007472c1c6SStanimir Varbanov
vdec_inst_init(struct venus_inst * inst)16017472c1c6SStanimir Varbanov static void vdec_inst_init(struct venus_inst *inst)
16027472c1c6SStanimir Varbanov {
1603beac8290SStanimir Varbanov inst->hfi_codec = HFI_VIDEO_CODEC_H264;
16042b832a06SDikshita Agarwal inst->fmt_out = &vdec_formats[VENUS_FMT_H264];
16052b832a06SDikshita Agarwal inst->fmt_cap = &vdec_formats[VENUS_FMT_NV12];
1606beac8290SStanimir Varbanov inst->width = frame_width_min(inst);
1607beac8290SStanimir Varbanov inst->height = ALIGN(frame_height_min(inst), 32);
1608de04408fSAlexandre Courbot inst->crop.left = 0;
1609de04408fSAlexandre Courbot inst->crop.top = 0;
1610de04408fSAlexandre Courbot inst->crop.width = inst->width;
1611de04408fSAlexandre Courbot inst->crop.height = inst->height;
161216545aa3SDikshita Agarwal inst->fw_min_cnt = 8;
1613beac8290SStanimir Varbanov inst->out_width = frame_width_min(inst);
1614beac8290SStanimir Varbanov inst->out_height = frame_height_min(inst);
16157472c1c6SStanimir Varbanov inst->fps = 30;
16167472c1c6SStanimir Varbanov inst->timeperframe.numerator = 1;
16177472c1c6SStanimir Varbanov inst->timeperframe.denominator = 30;
1618beac8290SStanimir Varbanov inst->opb_buftype = HFI_BUFFER_OUTPUT;
1619beac8290SStanimir Varbanov }
1620beac8290SStanimir Varbanov
vdec_m2m_device_run(void * priv)1621beac8290SStanimir Varbanov static void vdec_m2m_device_run(void *priv)
1622beac8290SStanimir Varbanov {
16237472c1c6SStanimir Varbanov }
16247472c1c6SStanimir Varbanov
16257472c1c6SStanimir Varbanov static const struct v4l2_m2m_ops vdec_m2m_ops = {
1626beac8290SStanimir Varbanov .device_run = vdec_m2m_device_run,
16277472c1c6SStanimir Varbanov .job_abort = venus_helper_m2m_job_abort,
16287472c1c6SStanimir Varbanov };
16297472c1c6SStanimir Varbanov
m2m_queue_init(void * priv,struct vb2_queue * src_vq,struct vb2_queue * dst_vq)16307472c1c6SStanimir Varbanov static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
16317472c1c6SStanimir Varbanov struct vb2_queue *dst_vq)
16327472c1c6SStanimir Varbanov {
16337472c1c6SStanimir Varbanov struct venus_inst *inst = priv;
16347472c1c6SStanimir Varbanov int ret;
16357472c1c6SStanimir Varbanov
16367472c1c6SStanimir Varbanov src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
16377472c1c6SStanimir Varbanov src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
16387472c1c6SStanimir Varbanov src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
16397472c1c6SStanimir Varbanov src_vq->ops = &vdec_vb2_ops;
1640cc82fd69SAlexandre Courbot src_vq->mem_ops = &vb2_dma_contig_memops;
16417472c1c6SStanimir Varbanov src_vq->drv_priv = inst;
16427472c1c6SStanimir Varbanov src_vq->buf_struct_size = sizeof(struct venus_buffer);
16437472c1c6SStanimir Varbanov src_vq->allow_zero_bytesused = 1;
1644beac8290SStanimir Varbanov src_vq->min_buffers_needed = 0;
16457472c1c6SStanimir Varbanov src_vq->dev = inst->core->dev;
164634318b80SSergey Senozhatsky src_vq->lock = &inst->ctx_q_lock;
16477472c1c6SStanimir Varbanov ret = vb2_queue_init(src_vq);
16487472c1c6SStanimir Varbanov if (ret)
16497472c1c6SStanimir Varbanov return ret;
16507472c1c6SStanimir Varbanov
16517472c1c6SStanimir Varbanov dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
16527472c1c6SStanimir Varbanov dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
16537472c1c6SStanimir Varbanov dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
16547472c1c6SStanimir Varbanov dst_vq->ops = &vdec_vb2_ops;
1655cc82fd69SAlexandre Courbot dst_vq->mem_ops = &vb2_dma_contig_memops;
16567472c1c6SStanimir Varbanov dst_vq->drv_priv = inst;
16577472c1c6SStanimir Varbanov dst_vq->buf_struct_size = sizeof(struct venus_buffer);
16587472c1c6SStanimir Varbanov dst_vq->allow_zero_bytesused = 1;
1659beac8290SStanimir Varbanov dst_vq->min_buffers_needed = 0;
16607472c1c6SStanimir Varbanov dst_vq->dev = inst->core->dev;
166134318b80SSergey Senozhatsky dst_vq->lock = &inst->ctx_q_lock;
1662f4ab5d0bSHans Verkuil return vb2_queue_init(dst_vq);
16637472c1c6SStanimir Varbanov }
16647472c1c6SStanimir Varbanov
vdec_open(struct file * file)16657472c1c6SStanimir Varbanov static int vdec_open(struct file *file)
16667472c1c6SStanimir Varbanov {
16677472c1c6SStanimir Varbanov struct venus_core *core = video_drvdata(file);
16687472c1c6SStanimir Varbanov struct venus_inst *inst;
16697472c1c6SStanimir Varbanov int ret;
16707472c1c6SStanimir Varbanov
16717472c1c6SStanimir Varbanov inst = kzalloc(sizeof(*inst), GFP_KERNEL);
16727472c1c6SStanimir Varbanov if (!inst)
16737472c1c6SStanimir Varbanov return -ENOMEM;
16747472c1c6SStanimir Varbanov
1675f012b23dSStanimir Varbanov INIT_LIST_HEAD(&inst->dpbbufs);
16767472c1c6SStanimir Varbanov INIT_LIST_HEAD(&inst->registeredbufs);
16777472c1c6SStanimir Varbanov INIT_LIST_HEAD(&inst->internalbufs);
16787472c1c6SStanimir Varbanov INIT_LIST_HEAD(&inst->list);
16797472c1c6SStanimir Varbanov mutex_init(&inst->lock);
168034318b80SSergey Senozhatsky mutex_init(&inst->ctx_q_lock);
16817472c1c6SStanimir Varbanov
16827472c1c6SStanimir Varbanov inst->core = core;
16837472c1c6SStanimir Varbanov inst->session_type = VIDC_SESSION_TYPE_DEC;
1684ebebc593SStanimir Varbanov inst->num_output_bufs = 1;
1685beac8290SStanimir Varbanov inst->codec_state = VENUS_DEC_STATE_DEINIT;
1686beac8290SStanimir Varbanov inst->buf_count = 0;
16874ebf9693SAniket Masule inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT;
16884ebf9693SAniket Masule inst->core_acquired = false;
1689ab1eda44SAniket Masule inst->bit_depth = VIDC_BITDEPTH_8;
1690b8201f3eSStanimir Varbanov inst->pic_struct = HFI_INTERLACE_FRAME_PROGRESSIVE;
1691beac8290SStanimir Varbanov init_waitqueue_head(&inst->reconf_wait);
16923227a8f7SStanimir Varbanov inst->nonblock = file->f_flags & O_NONBLOCK;
16933227a8f7SStanimir Varbanov
16947472c1c6SStanimir Varbanov venus_helper_init_instance(inst);
16957472c1c6SStanimir Varbanov
16967472c1c6SStanimir Varbanov ret = vdec_ctrl_init(inst);
16977472c1c6SStanimir Varbanov if (ret)
169863342afeSStanimir Varbanov goto err_free;
16997472c1c6SStanimir Varbanov
17007472c1c6SStanimir Varbanov ret = hfi_session_create(inst, &vdec_hfi_ops);
17017472c1c6SStanimir Varbanov if (ret)
17027472c1c6SStanimir Varbanov goto err_ctrl_deinit;
17037472c1c6SStanimir Varbanov
17047472c1c6SStanimir Varbanov vdec_inst_init(inst);
17057472c1c6SStanimir Varbanov
170640d87aafSMansur Alisha Shaik ida_init(&inst->dpb_ids);
170740d87aafSMansur Alisha Shaik
17087472c1c6SStanimir Varbanov /*
17097472c1c6SStanimir Varbanov * create m2m device for every instance, the m2m context scheduling
17107472c1c6SStanimir Varbanov * is made by firmware side so we do not need to care about.
17117472c1c6SStanimir Varbanov */
17127472c1c6SStanimir Varbanov inst->m2m_dev = v4l2_m2m_init(&vdec_m2m_ops);
17137472c1c6SStanimir Varbanov if (IS_ERR(inst->m2m_dev)) {
17147472c1c6SStanimir Varbanov ret = PTR_ERR(inst->m2m_dev);
17157472c1c6SStanimir Varbanov goto err_session_destroy;
17167472c1c6SStanimir Varbanov }
17177472c1c6SStanimir Varbanov
17187472c1c6SStanimir Varbanov inst->m2m_ctx = v4l2_m2m_ctx_init(inst->m2m_dev, inst, m2m_queue_init);
17197472c1c6SStanimir Varbanov if (IS_ERR(inst->m2m_ctx)) {
17207472c1c6SStanimir Varbanov ret = PTR_ERR(inst->m2m_ctx);
17217472c1c6SStanimir Varbanov goto err_m2m_release;
17227472c1c6SStanimir Varbanov }
17237472c1c6SStanimir Varbanov
17247472c1c6SStanimir Varbanov v4l2_fh_init(&inst->fh, core->vdev_dec);
17257472c1c6SStanimir Varbanov
17267472c1c6SStanimir Varbanov inst->fh.ctrl_handler = &inst->ctrl_handler;
17277472c1c6SStanimir Varbanov v4l2_fh_add(&inst->fh);
17287472c1c6SStanimir Varbanov inst->fh.m2m_ctx = inst->m2m_ctx;
17297472c1c6SStanimir Varbanov file->private_data = &inst->fh;
17307472c1c6SStanimir Varbanov
17317472c1c6SStanimir Varbanov return 0;
17327472c1c6SStanimir Varbanov
17337472c1c6SStanimir Varbanov err_m2m_release:
17347472c1c6SStanimir Varbanov v4l2_m2m_release(inst->m2m_dev);
17357472c1c6SStanimir Varbanov err_session_destroy:
17367472c1c6SStanimir Varbanov hfi_session_destroy(inst);
17377472c1c6SStanimir Varbanov err_ctrl_deinit:
17387472c1c6SStanimir Varbanov vdec_ctrl_deinit(inst);
173963342afeSStanimir Varbanov err_free:
17407472c1c6SStanimir Varbanov kfree(inst);
17417472c1c6SStanimir Varbanov return ret;
17427472c1c6SStanimir Varbanov }
17437472c1c6SStanimir Varbanov
vdec_close(struct file * file)17447472c1c6SStanimir Varbanov static int vdec_close(struct file *file)
17457472c1c6SStanimir Varbanov {
17467472c1c6SStanimir Varbanov struct venus_inst *inst = to_inst(file);
17477472c1c6SStanimir Varbanov
174863342afeSStanimir Varbanov vdec_pm_get(inst);
174963342afeSStanimir Varbanov
1750*66fa52edSDikshita Agarwal cancel_work_sync(&inst->delayed_process_work);
17517472c1c6SStanimir Varbanov v4l2_m2m_ctx_release(inst->m2m_ctx);
17527472c1c6SStanimir Varbanov v4l2_m2m_release(inst->m2m_dev);
17537472c1c6SStanimir Varbanov vdec_ctrl_deinit(inst);
175440d87aafSMansur Alisha Shaik ida_destroy(&inst->dpb_ids);
17557472c1c6SStanimir Varbanov hfi_session_destroy(inst);
17567472c1c6SStanimir Varbanov mutex_destroy(&inst->lock);
175734318b80SSergey Senozhatsky mutex_destroy(&inst->ctx_q_lock);
17587472c1c6SStanimir Varbanov v4l2_fh_del(&inst->fh);
17597472c1c6SStanimir Varbanov v4l2_fh_exit(&inst->fh);
17607472c1c6SStanimir Varbanov
176163342afeSStanimir Varbanov vdec_pm_put(inst, false);
176217571ed6SStanimir Varbanov
176317571ed6SStanimir Varbanov kfree(inst);
17647472c1c6SStanimir Varbanov return 0;
17657472c1c6SStanimir Varbanov }
17667472c1c6SStanimir Varbanov
17677472c1c6SStanimir Varbanov static const struct v4l2_file_operations vdec_fops = {
17687472c1c6SStanimir Varbanov .owner = THIS_MODULE,
17697472c1c6SStanimir Varbanov .open = vdec_open,
17707472c1c6SStanimir Varbanov .release = vdec_close,
17717472c1c6SStanimir Varbanov .unlocked_ioctl = video_ioctl2,
17727472c1c6SStanimir Varbanov .poll = v4l2_m2m_fop_poll,
17737472c1c6SStanimir Varbanov .mmap = v4l2_m2m_fop_mmap,
17747472c1c6SStanimir Varbanov };
17757472c1c6SStanimir Varbanov
vdec_probe(struct platform_device * pdev)17767472c1c6SStanimir Varbanov static int vdec_probe(struct platform_device *pdev)
17777472c1c6SStanimir Varbanov {
17787472c1c6SStanimir Varbanov struct device *dev = &pdev->dev;
17797472c1c6SStanimir Varbanov struct video_device *vdev;
17807472c1c6SStanimir Varbanov struct venus_core *core;
17817472c1c6SStanimir Varbanov int ret;
17827472c1c6SStanimir Varbanov
17837472c1c6SStanimir Varbanov if (!dev->parent)
17847472c1c6SStanimir Varbanov return -EPROBE_DEFER;
17857472c1c6SStanimir Varbanov
17867472c1c6SStanimir Varbanov core = dev_get_drvdata(dev->parent);
17877472c1c6SStanimir Varbanov if (!core)
17887472c1c6SStanimir Varbanov return -EPROBE_DEFER;
17897472c1c6SStanimir Varbanov
17907472c1c6SStanimir Varbanov platform_set_drvdata(pdev, core);
17917472c1c6SStanimir Varbanov
17927482a983SStanimir Varbanov if (core->pm_ops->vdec_get) {
17937482a983SStanimir Varbanov ret = core->pm_ops->vdec_get(dev);
17947482a983SStanimir Varbanov if (ret)
17957482a983SStanimir Varbanov return ret;
17967482a983SStanimir Varbanov }
17977482a983SStanimir Varbanov
17987472c1c6SStanimir Varbanov vdev = video_device_alloc();
17997472c1c6SStanimir Varbanov if (!vdev)
18007472c1c6SStanimir Varbanov return -ENOMEM;
18017472c1c6SStanimir Varbanov
1802c0decac1SMauro Carvalho Chehab strscpy(vdev->name, "qcom-venus-decoder", sizeof(vdev->name));
18037472c1c6SStanimir Varbanov vdev->release = video_device_release;
18047472c1c6SStanimir Varbanov vdev->fops = &vdec_fops;
18057472c1c6SStanimir Varbanov vdev->ioctl_ops = &vdec_ioctl_ops;
18067472c1c6SStanimir Varbanov vdev->vfl_dir = VFL_DIR_M2M;
18077472c1c6SStanimir Varbanov vdev->v4l2_dev = &core->v4l2_dev;
18087472c1c6SStanimir Varbanov vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
18097472c1c6SStanimir Varbanov
181070cad449SHans Verkuil ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
18117472c1c6SStanimir Varbanov if (ret)
18127472c1c6SStanimir Varbanov goto err_vdev_release;
18137472c1c6SStanimir Varbanov
18147472c1c6SStanimir Varbanov core->vdev_dec = vdev;
18157472c1c6SStanimir Varbanov core->dev_dec = dev;
18167472c1c6SStanimir Varbanov
18177472c1c6SStanimir Varbanov video_set_drvdata(vdev, core);
181863342afeSStanimir Varbanov pm_runtime_set_autosuspend_delay(dev, 2000);
181963342afeSStanimir Varbanov pm_runtime_use_autosuspend(dev);
18207472c1c6SStanimir Varbanov pm_runtime_enable(dev);
18217472c1c6SStanimir Varbanov
18227472c1c6SStanimir Varbanov return 0;
18237472c1c6SStanimir Varbanov
18247472c1c6SStanimir Varbanov err_vdev_release:
18257472c1c6SStanimir Varbanov video_device_release(vdev);
18267472c1c6SStanimir Varbanov return ret;
18277472c1c6SStanimir Varbanov }
18287472c1c6SStanimir Varbanov
vdec_remove(struct platform_device * pdev)182968f9c1deSUwe Kleine-König static void vdec_remove(struct platform_device *pdev)
18307472c1c6SStanimir Varbanov {
18317472c1c6SStanimir Varbanov struct venus_core *core = dev_get_drvdata(pdev->dev.parent);
18327472c1c6SStanimir Varbanov
18337472c1c6SStanimir Varbanov video_unregister_device(core->vdev_dec);
18347472c1c6SStanimir Varbanov pm_runtime_disable(core->dev_dec);
18357472c1c6SStanimir Varbanov
18367482a983SStanimir Varbanov if (core->pm_ops->vdec_put)
18377482a983SStanimir Varbanov core->pm_ops->vdec_put(core->dev_dec);
18387472c1c6SStanimir Varbanov }
18397472c1c6SStanimir Varbanov
vdec_runtime_suspend(struct device * dev)184062d625c9SStanimir Varbanov static __maybe_unused int vdec_runtime_suspend(struct device *dev)
18417472c1c6SStanimir Varbanov {
18427472c1c6SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
18437482a983SStanimir Varbanov const struct venus_pm_ops *pm_ops = core->pm_ops;
18447482a983SStanimir Varbanov int ret = 0;
18457472c1c6SStanimir Varbanov
18467482a983SStanimir Varbanov if (pm_ops->vdec_power)
18477482a983SStanimir Varbanov ret = pm_ops->vdec_power(dev, POWER_OFF);
18487472c1c6SStanimir Varbanov
1849aa3a8414SStanimir Varbanov return ret;
18507472c1c6SStanimir Varbanov }
18517472c1c6SStanimir Varbanov
vdec_runtime_resume(struct device * dev)185262d625c9SStanimir Varbanov static __maybe_unused int vdec_runtime_resume(struct device *dev)
18537472c1c6SStanimir Varbanov {
18547472c1c6SStanimir Varbanov struct venus_core *core = dev_get_drvdata(dev);
18557482a983SStanimir Varbanov const struct venus_pm_ops *pm_ops = core->pm_ops;
18567482a983SStanimir Varbanov int ret = 0;
18577472c1c6SStanimir Varbanov
18587482a983SStanimir Varbanov if (pm_ops->vdec_power)
18597482a983SStanimir Varbanov ret = pm_ops->vdec_power(dev, POWER_ON);
18607472c1c6SStanimir Varbanov
18617472c1c6SStanimir Varbanov return ret;
18627472c1c6SStanimir Varbanov }
18637472c1c6SStanimir Varbanov
18647472c1c6SStanimir Varbanov static const struct dev_pm_ops vdec_pm_ops = {
18657472c1c6SStanimir Varbanov SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
18667472c1c6SStanimir Varbanov pm_runtime_force_resume)
18677472c1c6SStanimir Varbanov SET_RUNTIME_PM_OPS(vdec_runtime_suspend, vdec_runtime_resume, NULL)
18687472c1c6SStanimir Varbanov };
18697472c1c6SStanimir Varbanov
18707472c1c6SStanimir Varbanov static const struct of_device_id vdec_dt_match[] = {
18717472c1c6SStanimir Varbanov { .compatible = "venus-decoder" },
18727472c1c6SStanimir Varbanov { }
18737472c1c6SStanimir Varbanov };
18747472c1c6SStanimir Varbanov MODULE_DEVICE_TABLE(of, vdec_dt_match);
18757472c1c6SStanimir Varbanov
18767472c1c6SStanimir Varbanov static struct platform_driver qcom_venus_dec_driver = {
18777472c1c6SStanimir Varbanov .probe = vdec_probe,
187868f9c1deSUwe Kleine-König .remove_new = vdec_remove,
18797472c1c6SStanimir Varbanov .driver = {
18807472c1c6SStanimir Varbanov .name = "qcom-venus-decoder",
18817472c1c6SStanimir Varbanov .of_match_table = vdec_dt_match,
18827472c1c6SStanimir Varbanov .pm = &vdec_pm_ops,
18837472c1c6SStanimir Varbanov },
18847472c1c6SStanimir Varbanov };
18857472c1c6SStanimir Varbanov module_platform_driver(qcom_venus_dec_driver);
18867472c1c6SStanimir Varbanov
18877472c1c6SStanimir Varbanov MODULE_ALIAS("platform:qcom-venus-decoder");
18887472c1c6SStanimir Varbanov MODULE_DESCRIPTION("Qualcomm Venus video decoder driver");
18897472c1c6SStanimir Varbanov MODULE_LICENSE("GPL v2");
1890