162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (C) 2017 Linaro Ltd. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/clk.h> 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 962306a36Sopenharmony_ci#include <linux/platform_device.h> 1062306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <media/v4l2-ioctl.h> 1362306a36Sopenharmony_ci#include <media/v4l2-event.h> 1462306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 1562306a36Sopenharmony_ci#include <media/v4l2-mem2mem.h> 1662306a36Sopenharmony_ci#include <media/videobuf2-dma-contig.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "hfi_venus_io.h" 1962306a36Sopenharmony_ci#include "hfi_parser.h" 2062306a36Sopenharmony_ci#include "core.h" 2162306a36Sopenharmony_ci#include "helpers.h" 2262306a36Sopenharmony_ci#include "vdec.h" 2362306a36Sopenharmony_ci#include "pm_helpers.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 2662306a36Sopenharmony_ci * Three resons to keep MPLANE formats (despite that the number of planes 2762306a36Sopenharmony_ci * currently is one): 2862306a36Sopenharmony_ci * - the MPLANE formats allow only one plane to be used 2962306a36Sopenharmony_ci * - the downstream driver use MPLANE formats too 3062306a36Sopenharmony_ci * - future firmware versions could add support for >1 planes 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_cistatic const struct venus_format vdec_formats[] = { 3362306a36Sopenharmony_ci [VENUS_FMT_NV12] = { 3462306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_NV12, 3562306a36Sopenharmony_ci .num_planes = 1, 3662306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 3762306a36Sopenharmony_ci }, 3862306a36Sopenharmony_ci [VENUS_FMT_QC08C] = { 3962306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_QC08C, 4062306a36Sopenharmony_ci .num_planes = 1, 4162306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 4262306a36Sopenharmony_ci }, 4362306a36Sopenharmony_ci [VENUS_FMT_QC10C] = { 4462306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_QC10C, 4562306a36Sopenharmony_ci .num_planes = 1, 4662306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 4762306a36Sopenharmony_ci }, 4862306a36Sopenharmony_ci [VENUS_FMT_P010] = { 4962306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_P010, 5062306a36Sopenharmony_ci .num_planes = 1, 5162306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 5262306a36Sopenharmony_ci }, 5362306a36Sopenharmony_ci [VENUS_FMT_H264] = { 5462306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_H264, 5562306a36Sopenharmony_ci .num_planes = 1, 5662306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 5762306a36Sopenharmony_ci .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, 5862306a36Sopenharmony_ci }, 5962306a36Sopenharmony_ci [VENUS_FMT_VP8] = { 6062306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_VP8, 6162306a36Sopenharmony_ci .num_planes = 1, 6262306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 6362306a36Sopenharmony_ci .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, 6462306a36Sopenharmony_ci }, 6562306a36Sopenharmony_ci [VENUS_FMT_VP9] = { 6662306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_VP9, 6762306a36Sopenharmony_ci .num_planes = 1, 6862306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 6962306a36Sopenharmony_ci .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, 7062306a36Sopenharmony_ci }, 7162306a36Sopenharmony_ci [VENUS_FMT_HEVC] = { 7262306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_HEVC, 7362306a36Sopenharmony_ci .num_planes = 1, 7462306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 7562306a36Sopenharmony_ci .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, 7662306a36Sopenharmony_ci }, 7762306a36Sopenharmony_ci [VENUS_FMT_VC1_ANNEX_G] = { 7862306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_G, 7962306a36Sopenharmony_ci .num_planes = 1, 8062306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 8162306a36Sopenharmony_ci .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, 8262306a36Sopenharmony_ci }, 8362306a36Sopenharmony_ci [VENUS_FMT_VC1_ANNEX_L] = { 8462306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_L, 8562306a36Sopenharmony_ci .num_planes = 1, 8662306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 8762306a36Sopenharmony_ci .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, 8862306a36Sopenharmony_ci }, 8962306a36Sopenharmony_ci [VENUS_FMT_MPEG4] = { 9062306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_MPEG4, 9162306a36Sopenharmony_ci .num_planes = 1, 9262306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 9362306a36Sopenharmony_ci .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, 9462306a36Sopenharmony_ci }, 9562306a36Sopenharmony_ci [VENUS_FMT_MPEG2] = { 9662306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_MPEG2, 9762306a36Sopenharmony_ci .num_planes = 1, 9862306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 9962306a36Sopenharmony_ci .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, 10062306a36Sopenharmony_ci }, 10162306a36Sopenharmony_ci [VENUS_FMT_H263] = { 10262306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_H263, 10362306a36Sopenharmony_ci .num_planes = 1, 10462306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 10562306a36Sopenharmony_ci .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, 10662306a36Sopenharmony_ci }, 10762306a36Sopenharmony_ci [VENUS_FMT_XVID] = { 10862306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_XVID, 10962306a36Sopenharmony_ci .num_planes = 1, 11062306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 11162306a36Sopenharmony_ci .flags = V4L2_FMT_FLAG_DYN_RESOLUTION, 11262306a36Sopenharmony_ci }, 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic const struct venus_format * 11762306a36Sopenharmony_cifind_format(struct venus_inst *inst, u32 pixfmt, u32 type) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci const struct venus_format *fmt = vdec_formats; 12062306a36Sopenharmony_ci unsigned int size = ARRAY_SIZE(vdec_formats); 12162306a36Sopenharmony_ci unsigned int i; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci for (i = 0; i < size; i++) { 12462306a36Sopenharmony_ci if (fmt[i].pixfmt == pixfmt) 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci if (i == size || fmt[i].type != type) 12962306a36Sopenharmony_ci return NULL; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && 13262306a36Sopenharmony_ci !venus_helper_check_codec(inst, fmt[i].pixfmt)) 13362306a36Sopenharmony_ci return NULL; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (V4L2_TYPE_IS_CAPTURE(type) && 13662306a36Sopenharmony_ci !venus_helper_check_format(inst, fmt[i].pixfmt)) 13762306a36Sopenharmony_ci return NULL; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (V4L2_TYPE_IS_CAPTURE(type) && fmt[i].pixfmt == V4L2_PIX_FMT_QC10C && 14062306a36Sopenharmony_ci !(inst->bit_depth == VIDC_BITDEPTH_10)) 14162306a36Sopenharmony_ci return NULL; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return &fmt[i]; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic const struct venus_format * 14762306a36Sopenharmony_cifind_format_by_index(struct venus_inst *inst, unsigned int index, u32 type) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci const struct venus_format *fmt = vdec_formats; 15062306a36Sopenharmony_ci unsigned int size = ARRAY_SIZE(vdec_formats); 15162306a36Sopenharmony_ci unsigned int i, k = 0; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (index > size) 15462306a36Sopenharmony_ci return NULL; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci for (i = 0; i < size; i++) { 15762306a36Sopenharmony_ci bool valid; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (fmt[i].type != type) 16062306a36Sopenharmony_ci continue; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (V4L2_TYPE_IS_OUTPUT(type)) { 16362306a36Sopenharmony_ci valid = venus_helper_check_codec(inst, fmt[i].pixfmt); 16462306a36Sopenharmony_ci } else if (V4L2_TYPE_IS_CAPTURE(type)) { 16562306a36Sopenharmony_ci valid = venus_helper_check_format(inst, fmt[i].pixfmt); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (fmt[i].pixfmt == V4L2_PIX_FMT_QC10C && 16862306a36Sopenharmony_ci !(inst->bit_depth == VIDC_BITDEPTH_10)) 16962306a36Sopenharmony_ci valid = false; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (k == index && valid) 17362306a36Sopenharmony_ci break; 17462306a36Sopenharmony_ci if (valid) 17562306a36Sopenharmony_ci k++; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (i == size) 17962306a36Sopenharmony_ci return NULL; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return &fmt[i]; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic const struct venus_format * 18562306a36Sopenharmony_civdec_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; 18862306a36Sopenharmony_ci struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt; 18962306a36Sopenharmony_ci const struct venus_format *fmt; 19062306a36Sopenharmony_ci u32 szimage; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved)); 19362306a36Sopenharmony_ci memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci fmt = find_format(inst, pixmp->pixelformat, f->type); 19662306a36Sopenharmony_ci if (!fmt) { 19762306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 19862306a36Sopenharmony_ci pixmp->pixelformat = V4L2_PIX_FMT_NV12; 19962306a36Sopenharmony_ci else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 20062306a36Sopenharmony_ci pixmp->pixelformat = V4L2_PIX_FMT_H264; 20162306a36Sopenharmony_ci else 20262306a36Sopenharmony_ci return NULL; 20362306a36Sopenharmony_ci fmt = find_format(inst, pixmp->pixelformat, f->type); 20462306a36Sopenharmony_ci if (!fmt) 20562306a36Sopenharmony_ci return NULL; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci pixmp->width = clamp(pixmp->width, frame_width_min(inst), 20962306a36Sopenharmony_ci frame_width_max(inst)); 21062306a36Sopenharmony_ci pixmp->height = clamp(pixmp->height, frame_height_min(inst), 21162306a36Sopenharmony_ci frame_height_max(inst)); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 21462306a36Sopenharmony_ci pixmp->height = ALIGN(pixmp->height, 32); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (pixmp->field == V4L2_FIELD_ANY) 21762306a36Sopenharmony_ci pixmp->field = V4L2_FIELD_NONE; 21862306a36Sopenharmony_ci pixmp->num_planes = fmt->num_planes; 21962306a36Sopenharmony_ci pixmp->flags = 0; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci szimage = venus_helper_get_framesz(pixmp->pixelformat, pixmp->width, 22262306a36Sopenharmony_ci pixmp->height); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 22562306a36Sopenharmony_ci unsigned int stride = pixmp->width; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (pixmp->pixelformat == V4L2_PIX_FMT_P010) 22862306a36Sopenharmony_ci stride *= 2; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci pfmt[0].sizeimage = szimage; 23162306a36Sopenharmony_ci pfmt[0].bytesperline = ALIGN(stride, 128); 23262306a36Sopenharmony_ci } else { 23362306a36Sopenharmony_ci pfmt[0].sizeimage = clamp_t(u32, pfmt[0].sizeimage, 0, SZ_8M); 23462306a36Sopenharmony_ci pfmt[0].sizeimage = max(pfmt[0].sizeimage, szimage); 23562306a36Sopenharmony_ci pfmt[0].bytesperline = 0; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return fmt; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci vdec_try_fmt_common(inst, f); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int vdec_check_src_change(struct venus_inst *inst) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci int ret; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (inst->subscriptions & V4L2_EVENT_SOURCE_CHANGE && 25562306a36Sopenharmony_ci inst->codec_state == VENUS_DEC_STATE_INIT && 25662306a36Sopenharmony_ci !inst->reconfig) 25762306a36Sopenharmony_ci return -EINVAL; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci if (inst->subscriptions & V4L2_EVENT_SOURCE_CHANGE) 26062306a36Sopenharmony_ci return 0; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* 26362306a36Sopenharmony_ci * The code snippet below is a workaround for backward compatibility 26462306a36Sopenharmony_ci * with applications which doesn't support V4L2 events. It will be 26562306a36Sopenharmony_ci * dropped in future once those applications are fixed. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (inst->codec_state != VENUS_DEC_STATE_INIT) 26962306a36Sopenharmony_ci goto done; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci ret = wait_event_timeout(inst->reconf_wait, inst->reconfig, 27262306a36Sopenharmony_ci msecs_to_jiffies(100)); 27362306a36Sopenharmony_ci if (!ret) 27462306a36Sopenharmony_ci return -EINVAL; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (!(inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) || 27762306a36Sopenharmony_ci !inst->reconfig) 27862306a36Sopenharmony_ci dev_dbg(inst->core->dev, VDBGH "wrong state\n"); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cidone: 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 28762306a36Sopenharmony_ci const struct venus_format *fmt = NULL; 28862306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; 28962306a36Sopenharmony_ci int ret; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 29262306a36Sopenharmony_ci fmt = inst->fmt_cap; 29362306a36Sopenharmony_ci else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 29462306a36Sopenharmony_ci fmt = inst->fmt_out; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 29762306a36Sopenharmony_ci ret = vdec_check_src_change(inst); 29862306a36Sopenharmony_ci if (ret) 29962306a36Sopenharmony_ci return ret; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci pixmp->pixelformat = fmt->pixfmt; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 30562306a36Sopenharmony_ci pixmp->width = inst->width; 30662306a36Sopenharmony_ci pixmp->height = inst->height; 30762306a36Sopenharmony_ci pixmp->colorspace = inst->colorspace; 30862306a36Sopenharmony_ci pixmp->ycbcr_enc = inst->ycbcr_enc; 30962306a36Sopenharmony_ci pixmp->quantization = inst->quantization; 31062306a36Sopenharmony_ci pixmp->xfer_func = inst->xfer_func; 31162306a36Sopenharmony_ci } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 31262306a36Sopenharmony_ci pixmp->width = inst->out_width; 31362306a36Sopenharmony_ci pixmp->height = inst->out_height; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci vdec_try_fmt_common(inst, f); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int vdec_s_fmt(struct file *file, void *fh, struct v4l2_format *f) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 32462306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; 32562306a36Sopenharmony_ci struct v4l2_pix_format_mplane orig_pixmp; 32662306a36Sopenharmony_ci const struct venus_format *fmt; 32762306a36Sopenharmony_ci struct v4l2_format format; 32862306a36Sopenharmony_ci u32 pixfmt_out = 0, pixfmt_cap = 0; 32962306a36Sopenharmony_ci struct vb2_queue *q; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type); 33262306a36Sopenharmony_ci if (!q) 33362306a36Sopenharmony_ci return -EINVAL; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci if (vb2_is_busy(q)) 33662306a36Sopenharmony_ci return -EBUSY; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci orig_pixmp = *pixmp; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci fmt = vdec_try_fmt_common(inst, f); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 34362306a36Sopenharmony_ci pixfmt_out = pixmp->pixelformat; 34462306a36Sopenharmony_ci pixfmt_cap = inst->fmt_cap->pixfmt; 34562306a36Sopenharmony_ci } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 34662306a36Sopenharmony_ci pixfmt_cap = pixmp->pixelformat; 34762306a36Sopenharmony_ci pixfmt_out = inst->fmt_out->pixfmt; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci memset(&format, 0, sizeof(format)); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 35362306a36Sopenharmony_ci format.fmt.pix_mp.pixelformat = pixfmt_out; 35462306a36Sopenharmony_ci format.fmt.pix_mp.width = orig_pixmp.width; 35562306a36Sopenharmony_ci format.fmt.pix_mp.height = orig_pixmp.height; 35662306a36Sopenharmony_ci vdec_try_fmt_common(inst, &format); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 35962306a36Sopenharmony_ci inst->out_width = format.fmt.pix_mp.width; 36062306a36Sopenharmony_ci inst->out_height = format.fmt.pix_mp.height; 36162306a36Sopenharmony_ci inst->colorspace = pixmp->colorspace; 36262306a36Sopenharmony_ci inst->ycbcr_enc = pixmp->ycbcr_enc; 36362306a36Sopenharmony_ci inst->quantization = pixmp->quantization; 36462306a36Sopenharmony_ci inst->xfer_func = pixmp->xfer_func; 36562306a36Sopenharmony_ci inst->input_buf_size = pixmp->plane_fmt[0].sizeimage; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci memset(&format, 0, sizeof(format)); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 37162306a36Sopenharmony_ci format.fmt.pix_mp.pixelformat = pixfmt_cap; 37262306a36Sopenharmony_ci format.fmt.pix_mp.width = orig_pixmp.width; 37362306a36Sopenharmony_ci format.fmt.pix_mp.height = orig_pixmp.height; 37462306a36Sopenharmony_ci vdec_try_fmt_common(inst, &format); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci inst->width = format.fmt.pix_mp.width; 37762306a36Sopenharmony_ci inst->height = format.fmt.pix_mp.height; 37862306a36Sopenharmony_ci inst->crop.top = 0; 37962306a36Sopenharmony_ci inst->crop.left = 0; 38062306a36Sopenharmony_ci inst->crop.width = inst->width; 38162306a36Sopenharmony_ci inst->crop.height = inst->height; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 38462306a36Sopenharmony_ci inst->fmt_out = fmt; 38562306a36Sopenharmony_ci else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 38662306a36Sopenharmony_ci inst->fmt_cap = fmt; 38762306a36Sopenharmony_ci inst->output2_buf_size = 38862306a36Sopenharmony_ci venus_helper_get_framesz(pixfmt_cap, orig_pixmp.width, orig_pixmp.height); 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return 0; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic int 39562306a36Sopenharmony_civdec_g_selection(struct file *file, void *fh, struct v4l2_selection *s) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && 40062306a36Sopenharmony_ci s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 40162306a36Sopenharmony_ci return -EINVAL; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci s->r.top = 0; 40462306a36Sopenharmony_ci s->r.left = 0; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci switch (s->target) { 40762306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP_BOUNDS: 40862306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP_DEFAULT: 40962306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP: 41062306a36Sopenharmony_ci if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 41162306a36Sopenharmony_ci return -EINVAL; 41262306a36Sopenharmony_ci s->r.width = inst->out_width; 41362306a36Sopenharmony_ci s->r.height = inst->out_height; 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE_BOUNDS: 41662306a36Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE_PADDED: 41762306a36Sopenharmony_ci if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 41862306a36Sopenharmony_ci return -EINVAL; 41962306a36Sopenharmony_ci s->r.width = inst->width; 42062306a36Sopenharmony_ci s->r.height = inst->height; 42162306a36Sopenharmony_ci break; 42262306a36Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE_DEFAULT: 42362306a36Sopenharmony_ci case V4L2_SEL_TGT_COMPOSE: 42462306a36Sopenharmony_ci if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) 42562306a36Sopenharmony_ci return -EINVAL; 42662306a36Sopenharmony_ci s->r = inst->crop; 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci default: 42962306a36Sopenharmony_ci return -EINVAL; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return 0; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistatic int 43662306a36Sopenharmony_civdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci strscpy(cap->driver, "qcom-venus", sizeof(cap->driver)); 43962306a36Sopenharmony_ci strscpy(cap->card, "Qualcomm Venus video decoder", sizeof(cap->card)); 44062306a36Sopenharmony_ci strscpy(cap->bus_info, "platform:qcom-venus", sizeof(cap->bus_info)); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 44862306a36Sopenharmony_ci const struct venus_format *fmt; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci memset(f->reserved, 0, sizeof(f->reserved)); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci fmt = find_format_by_index(inst, f->index, f->type); 45362306a36Sopenharmony_ci if (!fmt) 45462306a36Sopenharmony_ci return -EINVAL; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci f->pixelformat = fmt->pixfmt; 45762306a36Sopenharmony_ci f->flags = fmt->flags; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci return 0; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic int vdec_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 46562306a36Sopenharmony_ci struct v4l2_captureparm *cap = &a->parm.capture; 46662306a36Sopenharmony_ci struct v4l2_fract *timeperframe = &cap->timeperframe; 46762306a36Sopenharmony_ci u64 us_per_frame, fps; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && 47062306a36Sopenharmony_ci a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 47162306a36Sopenharmony_ci return -EINVAL; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci memset(cap->reserved, 0, sizeof(cap->reserved)); 47462306a36Sopenharmony_ci if (!timeperframe->denominator) 47562306a36Sopenharmony_ci timeperframe->denominator = inst->timeperframe.denominator; 47662306a36Sopenharmony_ci if (!timeperframe->numerator) 47762306a36Sopenharmony_ci timeperframe->numerator = inst->timeperframe.numerator; 47862306a36Sopenharmony_ci cap->readbuffers = 0; 47962306a36Sopenharmony_ci cap->extendedmode = 0; 48062306a36Sopenharmony_ci cap->capability = V4L2_CAP_TIMEPERFRAME; 48162306a36Sopenharmony_ci us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; 48262306a36Sopenharmony_ci do_div(us_per_frame, timeperframe->denominator); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (!us_per_frame) 48562306a36Sopenharmony_ci return -EINVAL; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci fps = (u64)USEC_PER_SEC; 48862306a36Sopenharmony_ci do_div(fps, us_per_frame); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci inst->fps = fps; 49162306a36Sopenharmony_ci inst->timeperframe = *timeperframe; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci return 0; 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic int vdec_enum_framesizes(struct file *file, void *fh, 49762306a36Sopenharmony_ci struct v4l2_frmsizeenum *fsize) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 50062306a36Sopenharmony_ci const struct venus_format *fmt; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci fmt = find_format(inst, fsize->pixel_format, 50362306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 50462306a36Sopenharmony_ci if (!fmt) { 50562306a36Sopenharmony_ci fmt = find_format(inst, fsize->pixel_format, 50662306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 50762306a36Sopenharmony_ci if (!fmt) 50862306a36Sopenharmony_ci return -EINVAL; 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (fsize->index) 51262306a36Sopenharmony_ci return -EINVAL; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci fsize->stepwise.min_width = frame_width_min(inst); 51762306a36Sopenharmony_ci fsize->stepwise.max_width = frame_width_max(inst); 51862306a36Sopenharmony_ci fsize->stepwise.step_width = frame_width_step(inst); 51962306a36Sopenharmony_ci fsize->stepwise.min_height = frame_height_min(inst); 52062306a36Sopenharmony_ci fsize->stepwise.max_height = frame_height_max(inst); 52162306a36Sopenharmony_ci fsize->stepwise.step_height = frame_height_step(inst); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic int vdec_subscribe_event(struct v4l2_fh *fh, 52762306a36Sopenharmony_ci const struct v4l2_event_subscription *sub) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci struct venus_inst *inst = container_of(fh, struct venus_inst, fh); 53062306a36Sopenharmony_ci int ret; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci switch (sub->type) { 53362306a36Sopenharmony_ci case V4L2_EVENT_EOS: 53462306a36Sopenharmony_ci return v4l2_event_subscribe(fh, sub, 2, NULL); 53562306a36Sopenharmony_ci case V4L2_EVENT_SOURCE_CHANGE: 53662306a36Sopenharmony_ci ret = v4l2_src_change_event_subscribe(fh, sub); 53762306a36Sopenharmony_ci if (ret) 53862306a36Sopenharmony_ci return ret; 53962306a36Sopenharmony_ci inst->subscriptions |= V4L2_EVENT_SOURCE_CHANGE; 54062306a36Sopenharmony_ci return 0; 54162306a36Sopenharmony_ci case V4L2_EVENT_CTRL: 54262306a36Sopenharmony_ci return v4l2_ctrl_subscribe_event(fh, sub); 54362306a36Sopenharmony_ci default: 54462306a36Sopenharmony_ci return -EINVAL; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic int 54962306a36Sopenharmony_civdec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *cmd) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 55262306a36Sopenharmony_ci struct vb2_queue *dst_vq; 55362306a36Sopenharmony_ci struct hfi_frame_data fdata = {0}; 55462306a36Sopenharmony_ci int ret; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, cmd); 55762306a36Sopenharmony_ci if (ret) 55862306a36Sopenharmony_ci return ret; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci mutex_lock(&inst->lock); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (cmd->cmd == V4L2_DEC_CMD_STOP) { 56362306a36Sopenharmony_ci /* 56462306a36Sopenharmony_ci * Implement V4L2_DEC_CMD_STOP by enqueue an empty buffer on 56562306a36Sopenharmony_ci * decoder input to signal EOS. 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_ci if (!(inst->streamon_out && inst->streamon_cap)) 56862306a36Sopenharmony_ci goto unlock; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci fdata.buffer_type = HFI_BUFFER_INPUT; 57162306a36Sopenharmony_ci fdata.flags |= HFI_BUFFERFLAG_EOS; 57262306a36Sopenharmony_ci if (IS_V6(inst->core) && is_fw_rev_or_older(inst->core, 1, 0, 87)) 57362306a36Sopenharmony_ci fdata.device_addr = 0; 57462306a36Sopenharmony_ci else 57562306a36Sopenharmony_ci fdata.device_addr = 0xdeadb000; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci ret = hfi_session_process_buf(inst, &fdata); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci if (!ret && inst->codec_state == VENUS_DEC_STATE_DECODING) { 58062306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_DRAIN; 58162306a36Sopenharmony_ci inst->drain_active = true; 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci } else if (cmd->cmd == V4L2_DEC_CMD_START && 58462306a36Sopenharmony_ci inst->codec_state == VENUS_DEC_STATE_STOPPED) { 58562306a36Sopenharmony_ci dst_vq = v4l2_m2m_get_vq(inst->fh.m2m_ctx, 58662306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 58762306a36Sopenharmony_ci vb2_clear_last_buffer_dequeued(dst_vq); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_DECODING; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ciunlock: 59362306a36Sopenharmony_ci mutex_unlock(&inst->lock); 59462306a36Sopenharmony_ci return ret; 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops vdec_ioctl_ops = { 59862306a36Sopenharmony_ci .vidioc_querycap = vdec_querycap, 59962306a36Sopenharmony_ci .vidioc_enum_fmt_vid_cap = vdec_enum_fmt, 60062306a36Sopenharmony_ci .vidioc_enum_fmt_vid_out = vdec_enum_fmt, 60162306a36Sopenharmony_ci .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt, 60262306a36Sopenharmony_ci .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt, 60362306a36Sopenharmony_ci .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt, 60462306a36Sopenharmony_ci .vidioc_g_fmt_vid_out_mplane = vdec_g_fmt, 60562306a36Sopenharmony_ci .vidioc_try_fmt_vid_cap_mplane = vdec_try_fmt, 60662306a36Sopenharmony_ci .vidioc_try_fmt_vid_out_mplane = vdec_try_fmt, 60762306a36Sopenharmony_ci .vidioc_g_selection = vdec_g_selection, 60862306a36Sopenharmony_ci .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 60962306a36Sopenharmony_ci .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 61062306a36Sopenharmony_ci .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 61162306a36Sopenharmony_ci .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 61262306a36Sopenharmony_ci .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 61362306a36Sopenharmony_ci .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 61462306a36Sopenharmony_ci .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 61562306a36Sopenharmony_ci .vidioc_streamon = v4l2_m2m_ioctl_streamon, 61662306a36Sopenharmony_ci .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 61762306a36Sopenharmony_ci .vidioc_s_parm = vdec_s_parm, 61862306a36Sopenharmony_ci .vidioc_enum_framesizes = vdec_enum_framesizes, 61962306a36Sopenharmony_ci .vidioc_subscribe_event = vdec_subscribe_event, 62062306a36Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 62162306a36Sopenharmony_ci .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, 62262306a36Sopenharmony_ci .vidioc_decoder_cmd = vdec_decoder_cmd, 62362306a36Sopenharmony_ci}; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_cistatic int vdec_pm_get(struct venus_inst *inst) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci struct venus_core *core = inst->core; 62862306a36Sopenharmony_ci struct device *dev = core->dev_dec; 62962306a36Sopenharmony_ci int ret; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci mutex_lock(&core->pm_lock); 63262306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 63362306a36Sopenharmony_ci mutex_unlock(&core->pm_lock); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci return ret; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic int vdec_pm_put(struct venus_inst *inst, bool autosuspend) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci struct venus_core *core = inst->core; 64162306a36Sopenharmony_ci struct device *dev = core->dev_dec; 64262306a36Sopenharmony_ci int ret; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci mutex_lock(&core->pm_lock); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (autosuspend) 64762306a36Sopenharmony_ci ret = pm_runtime_put_autosuspend(dev); 64862306a36Sopenharmony_ci else 64962306a36Sopenharmony_ci ret = pm_runtime_put_sync(dev); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci mutex_unlock(&core->pm_lock); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return ret < 0 ? ret : 0; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int vdec_pm_get_put(struct venus_inst *inst) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci struct venus_core *core = inst->core; 65962306a36Sopenharmony_ci struct device *dev = core->dev_dec; 66062306a36Sopenharmony_ci int ret = 0; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci mutex_lock(&core->pm_lock); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (pm_runtime_suspended(dev)) { 66562306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 66662306a36Sopenharmony_ci if (ret < 0) 66762306a36Sopenharmony_ci goto error; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci ret = pm_runtime_put_autosuspend(dev); 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cierror: 67362306a36Sopenharmony_ci mutex_unlock(&core->pm_lock); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci return ret < 0 ? ret : 0; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic void vdec_pm_touch(struct venus_inst *inst) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci pm_runtime_mark_last_busy(inst->core->dev_dec); 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int vdec_set_properties(struct venus_inst *inst) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct vdec_controls *ctr = &inst->controls.dec; 68662306a36Sopenharmony_ci struct hfi_enable en = { .enable = 1 }; 68762306a36Sopenharmony_ci u32 ptype, decode_order, conceal; 68862306a36Sopenharmony_ci int ret; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (ctr->post_loop_deb_mode) { 69162306a36Sopenharmony_ci ptype = HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER; 69262306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &en); 69362306a36Sopenharmony_ci if (ret) 69462306a36Sopenharmony_ci return ret; 69562306a36Sopenharmony_ci } 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (ctr->display_delay_enable && ctr->display_delay == 0) { 69862306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER; 69962306a36Sopenharmony_ci decode_order = HFI_OUTPUT_ORDER_DECODE; 70062306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &decode_order); 70162306a36Sopenharmony_ci if (ret) 70262306a36Sopenharmony_ci return ret; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci /* Enabling sufficient sequence change support for VP9 */ 70662306a36Sopenharmony_ci if (is_fw_rev_or_newer(inst->core, 5, 4, 51)) { 70762306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VDEC_ENABLE_SUFFICIENT_SEQCHANGE_EVENT; 70862306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &en); 70962306a36Sopenharmony_ci if (ret) 71062306a36Sopenharmony_ci return ret; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR; 71462306a36Sopenharmony_ci conceal = ctr->conceal_color & 0xffff; 71562306a36Sopenharmony_ci conceal |= ((ctr->conceal_color >> 16) & 0xffff) << 10; 71662306a36Sopenharmony_ci conceal |= ((ctr->conceal_color >> 32) & 0xffff) << 20; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &conceal); 71962306a36Sopenharmony_ci if (ret) 72062306a36Sopenharmony_ci return ret; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci return 0; 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_cistatic int vdec_set_work_route(struct venus_inst *inst) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci u32 ptype = HFI_PROPERTY_PARAM_WORK_ROUTE; 72862306a36Sopenharmony_ci struct hfi_video_work_route wr; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (!(IS_IRIS2(inst->core) || IS_IRIS2_1(inst->core))) 73162306a36Sopenharmony_ci return 0; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci wr.video_work_route = inst->core->res->num_vpp_pipes; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return hfi_session_set_property(inst, ptype, &wr); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci#define is_ubwc_fmt(fmt) (!!((fmt) & HFI_COLOR_FORMAT_UBWC_BASE)) 73962306a36Sopenharmony_ci#define is_10bit_ubwc_fmt(fmt) (!!((fmt) & HFI_COLOR_FORMAT_10_BIT_BASE & \ 74062306a36Sopenharmony_ci HFI_COLOR_FORMAT_UBWC_BASE)) 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic int vdec_output_conf(struct venus_inst *inst) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci struct venus_core *core = inst->core; 74662306a36Sopenharmony_ci struct hfi_enable en = { .enable = 1 }; 74762306a36Sopenharmony_ci struct hfi_buffer_requirements bufreq; 74862306a36Sopenharmony_ci u32 width = inst->width; 74962306a36Sopenharmony_ci u32 height = inst->height; 75062306a36Sopenharmony_ci u32 out_fmt, out2_fmt; 75162306a36Sopenharmony_ci bool ubwc = false; 75262306a36Sopenharmony_ci u32 ptype; 75362306a36Sopenharmony_ci int ret; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci ret = venus_helper_set_work_mode(inst); 75662306a36Sopenharmony_ci if (ret) 75762306a36Sopenharmony_ci return ret; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (core->res->hfi_version == HFI_VERSION_1XX) { 76062306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER; 76162306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &en); 76262306a36Sopenharmony_ci if (ret) 76362306a36Sopenharmony_ci return ret; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* Force searching UBWC formats for bigger then HD resolutions */ 76762306a36Sopenharmony_ci if (width > 1920 && height > ALIGN(1080, 32)) 76862306a36Sopenharmony_ci ubwc = true; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* For Venus v4/v6 UBWC format is mandatory */ 77162306a36Sopenharmony_ci if (IS_V4(core) || IS_V6(core)) 77262306a36Sopenharmony_ci ubwc = true; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci ret = venus_helper_get_out_fmts(inst, inst->fmt_cap->pixfmt, &out_fmt, 77562306a36Sopenharmony_ci &out2_fmt, ubwc); 77662306a36Sopenharmony_ci if (ret) 77762306a36Sopenharmony_ci return ret; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci inst->output_buf_size = 78062306a36Sopenharmony_ci venus_helper_get_framesz_raw(out_fmt, width, height); 78162306a36Sopenharmony_ci inst->output2_buf_size = 78262306a36Sopenharmony_ci venus_helper_get_framesz_raw(out2_fmt, width, height); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (is_ubwc_fmt(out_fmt)) { 78562306a36Sopenharmony_ci inst->opb_buftype = HFI_BUFFER_OUTPUT2; 78662306a36Sopenharmony_ci inst->opb_fmt = out2_fmt; 78762306a36Sopenharmony_ci inst->dpb_buftype = HFI_BUFFER_OUTPUT; 78862306a36Sopenharmony_ci inst->dpb_fmt = out_fmt; 78962306a36Sopenharmony_ci } else if (is_ubwc_fmt(out2_fmt) || is_10bit_ubwc_fmt(out_fmt)) { 79062306a36Sopenharmony_ci inst->opb_buftype = HFI_BUFFER_OUTPUT; 79162306a36Sopenharmony_ci inst->opb_fmt = out_fmt; 79262306a36Sopenharmony_ci inst->dpb_buftype = HFI_BUFFER_OUTPUT2; 79362306a36Sopenharmony_ci inst->dpb_fmt = out2_fmt; 79462306a36Sopenharmony_ci } else { 79562306a36Sopenharmony_ci inst->opb_buftype = HFI_BUFFER_OUTPUT; 79662306a36Sopenharmony_ci inst->opb_fmt = out_fmt; 79762306a36Sopenharmony_ci inst->dpb_buftype = 0; 79862306a36Sopenharmony_ci inst->dpb_fmt = 0; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci ret = venus_helper_set_raw_format(inst, inst->opb_fmt, 80262306a36Sopenharmony_ci inst->opb_buftype); 80362306a36Sopenharmony_ci if (ret) 80462306a36Sopenharmony_ci return ret; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci ret = venus_helper_set_format_constraints(inst); 80762306a36Sopenharmony_ci if (ret) 80862306a36Sopenharmony_ci return ret; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (inst->dpb_fmt) { 81162306a36Sopenharmony_ci ret = venus_helper_set_multistream(inst, false, true); 81262306a36Sopenharmony_ci if (ret) 81362306a36Sopenharmony_ci return ret; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci ret = venus_helper_set_raw_format(inst, inst->dpb_fmt, 81662306a36Sopenharmony_ci inst->dpb_buftype); 81762306a36Sopenharmony_ci if (ret) 81862306a36Sopenharmony_ci return ret; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci ret = venus_helper_set_output_resolution(inst, width, height, 82162306a36Sopenharmony_ci HFI_BUFFER_OUTPUT2); 82262306a36Sopenharmony_ci if (ret) 82362306a36Sopenharmony_ci return ret; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (IS_V3(core) || IS_V4(core) || IS_V6(core)) { 82762306a36Sopenharmony_ci ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq); 82862306a36Sopenharmony_ci if (ret) 82962306a36Sopenharmony_ci return ret; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (bufreq.size > inst->output_buf_size) 83262306a36Sopenharmony_ci return -EINVAL; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (inst->dpb_fmt) { 83562306a36Sopenharmony_ci ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT2, 83662306a36Sopenharmony_ci &bufreq); 83762306a36Sopenharmony_ci if (ret) 83862306a36Sopenharmony_ci return ret; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (bufreq.size > inst->output2_buf_size) 84162306a36Sopenharmony_ci return -EINVAL; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (inst->output2_buf_size) { 84562306a36Sopenharmony_ci ret = venus_helper_set_bufsize(inst, 84662306a36Sopenharmony_ci inst->output2_buf_size, 84762306a36Sopenharmony_ci HFI_BUFFER_OUTPUT2); 84862306a36Sopenharmony_ci if (ret) 84962306a36Sopenharmony_ci return ret; 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (inst->output_buf_size) { 85362306a36Sopenharmony_ci ret = venus_helper_set_bufsize(inst, 85462306a36Sopenharmony_ci inst->output_buf_size, 85562306a36Sopenharmony_ci HFI_BUFFER_OUTPUT); 85662306a36Sopenharmony_ci if (ret) 85762306a36Sopenharmony_ci return ret; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci ret = venus_helper_set_dyn_bufmode(inst); 86262306a36Sopenharmony_ci if (ret) 86362306a36Sopenharmony_ci return ret; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci return 0; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_cistatic int vdec_session_init(struct venus_inst *inst) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci int ret; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci ret = venus_helper_session_init(inst); 87362306a36Sopenharmony_ci if (ret == -EALREADY) 87462306a36Sopenharmony_ci return 0; 87562306a36Sopenharmony_ci else if (ret) 87662306a36Sopenharmony_ci return ret; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci ret = venus_helper_set_input_resolution(inst, frame_width_min(inst), 87962306a36Sopenharmony_ci frame_height_min(inst)); 88062306a36Sopenharmony_ci if (ret) 88162306a36Sopenharmony_ci goto deinit; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci return 0; 88462306a36Sopenharmony_cideinit: 88562306a36Sopenharmony_ci hfi_session_deinit(inst); 88662306a36Sopenharmony_ci return ret; 88762306a36Sopenharmony_ci} 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_cistatic int vdec_num_buffers(struct venus_inst *inst, unsigned int *in_num, 89062306a36Sopenharmony_ci unsigned int *out_num) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci enum hfi_version ver = inst->core->res->hfi_version; 89362306a36Sopenharmony_ci struct hfi_buffer_requirements bufreq; 89462306a36Sopenharmony_ci int ret; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci *in_num = *out_num = 0; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq); 89962306a36Sopenharmony_ci if (ret) 90062306a36Sopenharmony_ci return ret; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci *in_num = hfi_bufreq_get_count_min(&bufreq, ver); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq); 90562306a36Sopenharmony_ci if (ret) 90662306a36Sopenharmony_ci return ret; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci *out_num = hfi_bufreq_get_count_min(&bufreq, ver); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci return 0; 91162306a36Sopenharmony_ci} 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_cistatic int vdec_queue_setup(struct vb2_queue *q, 91462306a36Sopenharmony_ci unsigned int *num_buffers, unsigned int *num_planes, 91562306a36Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci struct venus_inst *inst = vb2_get_drv_priv(q); 91862306a36Sopenharmony_ci struct venus_core *core = inst->core; 91962306a36Sopenharmony_ci unsigned int in_num, out_num; 92062306a36Sopenharmony_ci int ret = 0; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (*num_planes) { 92362306a36Sopenharmony_ci unsigned int output_buf_size = venus_helper_get_opb_size(inst); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && 92662306a36Sopenharmony_ci *num_planes != inst->fmt_out->num_planes) 92762306a36Sopenharmony_ci return -EINVAL; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && 93062306a36Sopenharmony_ci *num_planes != inst->fmt_cap->num_planes) 93162306a36Sopenharmony_ci return -EINVAL; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && 93462306a36Sopenharmony_ci sizes[0] < inst->input_buf_size) 93562306a36Sopenharmony_ci return -EINVAL; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && 93862306a36Sopenharmony_ci sizes[0] < output_buf_size) 93962306a36Sopenharmony_ci return -EINVAL; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci return 0; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (test_bit(0, &core->sys_error)) { 94562306a36Sopenharmony_ci if (inst->nonblock) 94662306a36Sopenharmony_ci return -EAGAIN; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci ret = wait_event_interruptible(core->sys_err_done, 94962306a36Sopenharmony_ci !test_bit(0, &core->sys_error)); 95062306a36Sopenharmony_ci if (ret) 95162306a36Sopenharmony_ci return ret; 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci ret = vdec_pm_get(inst); 95562306a36Sopenharmony_ci if (ret) 95662306a36Sopenharmony_ci return ret; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci ret = vdec_session_init(inst); 95962306a36Sopenharmony_ci if (ret) 96062306a36Sopenharmony_ci goto put_power; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci ret = vdec_num_buffers(inst, &in_num, &out_num); 96362306a36Sopenharmony_ci if (ret) 96462306a36Sopenharmony_ci goto put_power; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci ret = vdec_pm_put(inst, false); 96762306a36Sopenharmony_ci if (ret) 96862306a36Sopenharmony_ci return ret; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci switch (q->type) { 97162306a36Sopenharmony_ci case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 97262306a36Sopenharmony_ci *num_planes = inst->fmt_out->num_planes; 97362306a36Sopenharmony_ci sizes[0] = venus_helper_get_framesz(inst->fmt_out->pixfmt, 97462306a36Sopenharmony_ci inst->out_width, 97562306a36Sopenharmony_ci inst->out_height); 97662306a36Sopenharmony_ci sizes[0] = max(sizes[0], inst->input_buf_size); 97762306a36Sopenharmony_ci inst->input_buf_size = sizes[0]; 97862306a36Sopenharmony_ci *num_buffers = max(*num_buffers, in_num); 97962306a36Sopenharmony_ci inst->num_input_bufs = *num_buffers; 98062306a36Sopenharmony_ci inst->num_output_bufs = out_num; 98162306a36Sopenharmony_ci break; 98262306a36Sopenharmony_ci case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 98362306a36Sopenharmony_ci *num_planes = inst->fmt_cap->num_planes; 98462306a36Sopenharmony_ci sizes[0] = venus_helper_get_framesz(inst->fmt_cap->pixfmt, 98562306a36Sopenharmony_ci inst->width, 98662306a36Sopenharmony_ci inst->height); 98762306a36Sopenharmony_ci inst->output_buf_size = sizes[0]; 98862306a36Sopenharmony_ci *num_buffers = max(*num_buffers, out_num); 98962306a36Sopenharmony_ci inst->num_output_bufs = *num_buffers; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci mutex_lock(&inst->lock); 99262306a36Sopenharmony_ci if (inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) 99362306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_STOPPED; 99462306a36Sopenharmony_ci mutex_unlock(&inst->lock); 99562306a36Sopenharmony_ci break; 99662306a36Sopenharmony_ci default: 99762306a36Sopenharmony_ci ret = -EINVAL; 99862306a36Sopenharmony_ci break; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci return ret; 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_ciput_power: 100462306a36Sopenharmony_ci vdec_pm_put(inst, false); 100562306a36Sopenharmony_ci return ret; 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cistatic int vdec_verify_conf(struct venus_inst *inst) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci enum hfi_version ver = inst->core->res->hfi_version; 101162306a36Sopenharmony_ci struct hfi_buffer_requirements bufreq; 101262306a36Sopenharmony_ci int ret; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci if (!inst->num_input_bufs || !inst->num_output_bufs) 101562306a36Sopenharmony_ci return -EINVAL; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq); 101862306a36Sopenharmony_ci if (ret) 101962306a36Sopenharmony_ci return ret; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci if (inst->num_output_bufs < bufreq.count_actual || 102262306a36Sopenharmony_ci inst->num_output_bufs < hfi_bufreq_get_count_min(&bufreq, ver)) 102362306a36Sopenharmony_ci return -EINVAL; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq); 102662306a36Sopenharmony_ci if (ret) 102762306a36Sopenharmony_ci return ret; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci if (inst->num_input_bufs < hfi_bufreq_get_count_min(&bufreq, ver)) 103062306a36Sopenharmony_ci return -EINVAL; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci return 0; 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_cistatic int vdec_start_capture(struct venus_inst *inst) 103662306a36Sopenharmony_ci{ 103762306a36Sopenharmony_ci int ret; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci if (!inst->streamon_out) 104062306a36Sopenharmony_ci return 0; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (inst->codec_state == VENUS_DEC_STATE_DECODING) { 104362306a36Sopenharmony_ci if (inst->reconfig) 104462306a36Sopenharmony_ci goto reconfigure; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci venus_helper_queue_dpb_bufs(inst); 104762306a36Sopenharmony_ci venus_helper_process_initial_cap_bufs(inst); 104862306a36Sopenharmony_ci inst->streamon_cap = 1; 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (inst->codec_state != VENUS_DEC_STATE_STOPPED) 105362306a36Sopenharmony_ci return 0; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cireconfigure: 105662306a36Sopenharmony_ci ret = vdec_output_conf(inst); 105762306a36Sopenharmony_ci if (ret) 105862306a36Sopenharmony_ci return ret; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs, 106162306a36Sopenharmony_ci VB2_MAX_FRAME, VB2_MAX_FRAME); 106262306a36Sopenharmony_ci if (ret) 106362306a36Sopenharmony_ci return ret; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci ret = venus_helper_intbufs_realloc(inst); 106662306a36Sopenharmony_ci if (ret) 106762306a36Sopenharmony_ci goto err; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci venus_pm_load_scale(inst); 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci inst->next_buf_last = false; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci ret = venus_helper_alloc_dpb_bufs(inst); 107462306a36Sopenharmony_ci if (ret) 107562306a36Sopenharmony_ci goto err; 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci ret = hfi_session_continue(inst); 107862306a36Sopenharmony_ci if (ret) 107962306a36Sopenharmony_ci goto free_dpb_bufs; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci ret = venus_helper_queue_dpb_bufs(inst); 108262306a36Sopenharmony_ci if (ret) 108362306a36Sopenharmony_ci goto free_dpb_bufs; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci ret = venus_helper_process_initial_cap_bufs(inst); 108662306a36Sopenharmony_ci if (ret) 108762306a36Sopenharmony_ci goto free_dpb_bufs; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_DECODING; 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci if (inst->drain_active) 109262306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_DRAIN; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci inst->streamon_cap = 1; 109562306a36Sopenharmony_ci inst->sequence_cap = 0; 109662306a36Sopenharmony_ci inst->reconfig = false; 109762306a36Sopenharmony_ci inst->drain_active = false; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci return 0; 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_cifree_dpb_bufs: 110262306a36Sopenharmony_ci venus_helper_free_dpb_bufs(inst); 110362306a36Sopenharmony_cierr: 110462306a36Sopenharmony_ci return ret; 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic int vdec_start_output(struct venus_inst *inst) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci int ret; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (inst->codec_state == VENUS_DEC_STATE_SEEK) { 111262306a36Sopenharmony_ci ret = venus_helper_process_initial_out_bufs(inst); 111362306a36Sopenharmony_ci if (inst->next_buf_last) 111462306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_DRC; 111562306a36Sopenharmony_ci else 111662306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_DECODING; 111762306a36Sopenharmony_ci goto done; 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci if (inst->codec_state == VENUS_DEC_STATE_INIT || 112162306a36Sopenharmony_ci inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) { 112262306a36Sopenharmony_ci ret = venus_helper_process_initial_out_bufs(inst); 112362306a36Sopenharmony_ci goto done; 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci if (inst->codec_state != VENUS_DEC_STATE_DEINIT) 112762306a36Sopenharmony_ci return -EINVAL; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci venus_helper_init_instance(inst); 113062306a36Sopenharmony_ci inst->sequence_out = 0; 113162306a36Sopenharmony_ci inst->reconfig = false; 113262306a36Sopenharmony_ci inst->next_buf_last = false; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci ret = vdec_set_properties(inst); 113562306a36Sopenharmony_ci if (ret) 113662306a36Sopenharmony_ci return ret; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci ret = vdec_set_work_route(inst); 113962306a36Sopenharmony_ci if (ret) 114062306a36Sopenharmony_ci return ret; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci ret = vdec_output_conf(inst); 114362306a36Sopenharmony_ci if (ret) 114462306a36Sopenharmony_ci return ret; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci ret = vdec_verify_conf(inst); 114762306a36Sopenharmony_ci if (ret) 114862306a36Sopenharmony_ci return ret; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs, 115162306a36Sopenharmony_ci VB2_MAX_FRAME, VB2_MAX_FRAME); 115262306a36Sopenharmony_ci if (ret) 115362306a36Sopenharmony_ci return ret; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci ret = venus_helper_vb2_start_streaming(inst); 115662306a36Sopenharmony_ci if (ret) 115762306a36Sopenharmony_ci return ret; 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci ret = venus_helper_process_initial_out_bufs(inst); 116062306a36Sopenharmony_ci if (ret) 116162306a36Sopenharmony_ci return ret; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_INIT; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_cidone: 116662306a36Sopenharmony_ci inst->streamon_out = 1; 116762306a36Sopenharmony_ci return ret; 116862306a36Sopenharmony_ci} 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_cistatic int vdec_start_streaming(struct vb2_queue *q, unsigned int count) 117162306a36Sopenharmony_ci{ 117262306a36Sopenharmony_ci struct venus_inst *inst = vb2_get_drv_priv(q); 117362306a36Sopenharmony_ci int ret; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci mutex_lock(&inst->lock); 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 117862306a36Sopenharmony_ci ret = vdec_start_capture(inst); 117962306a36Sopenharmony_ci } else { 118062306a36Sopenharmony_ci ret = vdec_pm_get(inst); 118162306a36Sopenharmony_ci if (ret) 118262306a36Sopenharmony_ci goto error; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci ret = venus_pm_acquire_core(inst); 118562306a36Sopenharmony_ci if (ret) 118662306a36Sopenharmony_ci goto put_power; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci ret = vdec_pm_put(inst, true); 118962306a36Sopenharmony_ci if (ret) 119062306a36Sopenharmony_ci goto error; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci ret = vdec_start_output(inst); 119362306a36Sopenharmony_ci } 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (ret) 119662306a36Sopenharmony_ci goto error; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci mutex_unlock(&inst->lock); 119962306a36Sopenharmony_ci return 0; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ciput_power: 120262306a36Sopenharmony_ci vdec_pm_put(inst, false); 120362306a36Sopenharmony_cierror: 120462306a36Sopenharmony_ci venus_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED); 120562306a36Sopenharmony_ci mutex_unlock(&inst->lock); 120662306a36Sopenharmony_ci return ret; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_cistatic void vdec_cancel_dst_buffers(struct venus_inst *inst) 121062306a36Sopenharmony_ci{ 121162306a36Sopenharmony_ci struct vb2_v4l2_buffer *buf; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci while ((buf = v4l2_m2m_dst_buf_remove(inst->m2m_ctx))) 121462306a36Sopenharmony_ci v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR); 121562306a36Sopenharmony_ci} 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_cistatic int vdec_stop_capture(struct venus_inst *inst) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci int ret = 0; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci switch (inst->codec_state) { 122262306a36Sopenharmony_ci case VENUS_DEC_STATE_DECODING: 122362306a36Sopenharmony_ci ret = hfi_session_flush(inst, HFI_FLUSH_ALL, true); 122462306a36Sopenharmony_ci fallthrough; 122562306a36Sopenharmony_ci case VENUS_DEC_STATE_DRAIN: 122662306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_STOPPED; 122762306a36Sopenharmony_ci inst->drain_active = false; 122862306a36Sopenharmony_ci fallthrough; 122962306a36Sopenharmony_ci case VENUS_DEC_STATE_SEEK: 123062306a36Sopenharmony_ci vdec_cancel_dst_buffers(inst); 123162306a36Sopenharmony_ci break; 123262306a36Sopenharmony_ci case VENUS_DEC_STATE_DRC: 123362306a36Sopenharmony_ci ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT, true); 123462306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_CAPTURE_SETUP; 123562306a36Sopenharmony_ci venus_helper_free_dpb_bufs(inst); 123662306a36Sopenharmony_ci break; 123762306a36Sopenharmony_ci default: 123862306a36Sopenharmony_ci break; 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci return ret; 124262306a36Sopenharmony_ci} 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_cistatic int vdec_stop_output(struct venus_inst *inst) 124562306a36Sopenharmony_ci{ 124662306a36Sopenharmony_ci int ret = 0; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci switch (inst->codec_state) { 124962306a36Sopenharmony_ci case VENUS_DEC_STATE_DECODING: 125062306a36Sopenharmony_ci case VENUS_DEC_STATE_DRAIN: 125162306a36Sopenharmony_ci case VENUS_DEC_STATE_STOPPED: 125262306a36Sopenharmony_ci case VENUS_DEC_STATE_DRC: 125362306a36Sopenharmony_ci ret = hfi_session_flush(inst, HFI_FLUSH_ALL, true); 125462306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_SEEK; 125562306a36Sopenharmony_ci break; 125662306a36Sopenharmony_ci case VENUS_DEC_STATE_INIT: 125762306a36Sopenharmony_ci case VENUS_DEC_STATE_CAPTURE_SETUP: 125862306a36Sopenharmony_ci ret = hfi_session_flush(inst, HFI_FLUSH_INPUT, true); 125962306a36Sopenharmony_ci break; 126062306a36Sopenharmony_ci default: 126162306a36Sopenharmony_ci break; 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci return ret; 126562306a36Sopenharmony_ci} 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_cistatic void vdec_stop_streaming(struct vb2_queue *q) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci struct venus_inst *inst = vb2_get_drv_priv(q); 127062306a36Sopenharmony_ci int ret = -EINVAL; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci vdec_pm_get_put(inst); 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci mutex_lock(&inst->lock); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 127762306a36Sopenharmony_ci ret = vdec_stop_capture(inst); 127862306a36Sopenharmony_ci else 127962306a36Sopenharmony_ci ret = vdec_stop_output(inst); 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci venus_helper_buffers_done(inst, q->type, VB2_BUF_STATE_ERROR); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci inst->session_error = 0; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci if (ret) 128662306a36Sopenharmony_ci goto unlock; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 128962306a36Sopenharmony_ci inst->streamon_out = 0; 129062306a36Sopenharmony_ci else 129162306a36Sopenharmony_ci inst->streamon_cap = 0; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ciunlock: 129462306a36Sopenharmony_ci mutex_unlock(&inst->lock); 129562306a36Sopenharmony_ci} 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_cistatic void vdec_session_release(struct venus_inst *inst) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci struct venus_core *core = inst->core; 130062306a36Sopenharmony_ci int ret, abort = 0; 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci vdec_pm_get(inst); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci mutex_lock(&inst->lock); 130562306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_DEINIT; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci ret = hfi_session_stop(inst); 130862306a36Sopenharmony_ci abort = (ret && ret != -EINVAL) ? 1 : 0; 130962306a36Sopenharmony_ci ret = hfi_session_unload_res(inst); 131062306a36Sopenharmony_ci abort = (ret && ret != -EINVAL) ? 1 : 0; 131162306a36Sopenharmony_ci ret = venus_helper_unregister_bufs(inst); 131262306a36Sopenharmony_ci abort = (ret && ret != -EINVAL) ? 1 : 0; 131362306a36Sopenharmony_ci ret = venus_helper_intbufs_free(inst); 131462306a36Sopenharmony_ci abort = (ret && ret != -EINVAL) ? 1 : 0; 131562306a36Sopenharmony_ci ret = hfi_session_deinit(inst); 131662306a36Sopenharmony_ci abort = (ret && ret != -EINVAL) ? 1 : 0; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci if (inst->session_error || test_bit(0, &core->sys_error)) 131962306a36Sopenharmony_ci abort = 1; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci if (abort) 132262306a36Sopenharmony_ci hfi_session_abort(inst); 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci venus_helper_free_dpb_bufs(inst); 132562306a36Sopenharmony_ci venus_pm_load_scale(inst); 132662306a36Sopenharmony_ci INIT_LIST_HEAD(&inst->registeredbufs); 132762306a36Sopenharmony_ci mutex_unlock(&inst->lock); 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci venus_pm_release_core(inst); 133062306a36Sopenharmony_ci vdec_pm_put(inst, false); 133162306a36Sopenharmony_ci} 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_cistatic int vdec_buf_init(struct vb2_buffer *vb) 133462306a36Sopenharmony_ci{ 133562306a36Sopenharmony_ci struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci inst->buf_count++; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci return venus_helper_vb2_buf_init(vb); 134062306a36Sopenharmony_ci} 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_cistatic void vdec_buf_cleanup(struct vb2_buffer *vb) 134362306a36Sopenharmony_ci{ 134462306a36Sopenharmony_ci struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); 134562306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 134662306a36Sopenharmony_ci struct venus_buffer *buf = to_venus_buffer(vbuf); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci mutex_lock(&inst->lock); 134962306a36Sopenharmony_ci if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 135062306a36Sopenharmony_ci if (!list_empty(&inst->registeredbufs)) 135162306a36Sopenharmony_ci list_del_init(&buf->reg_list); 135262306a36Sopenharmony_ci mutex_unlock(&inst->lock); 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci inst->buf_count--; 135562306a36Sopenharmony_ci if (!inst->buf_count) 135662306a36Sopenharmony_ci vdec_session_release(inst); 135762306a36Sopenharmony_ci} 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_cistatic void vdec_vb2_buf_queue(struct vb2_buffer *vb) 136062306a36Sopenharmony_ci{ 136162306a36Sopenharmony_ci struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); 136262306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 136362306a36Sopenharmony_ci static const struct v4l2_event eos = { .type = V4L2_EVENT_EOS }; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_ci vdec_pm_get_put(inst); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci mutex_lock(&inst->lock); 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci if (inst->next_buf_last && V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) && 137062306a36Sopenharmony_ci inst->codec_state == VENUS_DEC_STATE_DRC) { 137162306a36Sopenharmony_ci vbuf->flags |= V4L2_BUF_FLAG_LAST; 137262306a36Sopenharmony_ci vbuf->sequence = inst->sequence_cap++; 137362306a36Sopenharmony_ci vbuf->field = V4L2_FIELD_NONE; 137462306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, 0); 137562306a36Sopenharmony_ci v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); 137662306a36Sopenharmony_ci v4l2_event_queue_fh(&inst->fh, &eos); 137762306a36Sopenharmony_ci inst->next_buf_last = false; 137862306a36Sopenharmony_ci mutex_unlock(&inst->lock); 137962306a36Sopenharmony_ci return; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci venus_helper_vb2_buf_queue(vb); 138362306a36Sopenharmony_ci mutex_unlock(&inst->lock); 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_cistatic const struct vb2_ops vdec_vb2_ops = { 138762306a36Sopenharmony_ci .queue_setup = vdec_queue_setup, 138862306a36Sopenharmony_ci .buf_init = vdec_buf_init, 138962306a36Sopenharmony_ci .buf_cleanup = vdec_buf_cleanup, 139062306a36Sopenharmony_ci .buf_prepare = venus_helper_vb2_buf_prepare, 139162306a36Sopenharmony_ci .start_streaming = vdec_start_streaming, 139262306a36Sopenharmony_ci .stop_streaming = vdec_stop_streaming, 139362306a36Sopenharmony_ci .buf_queue = vdec_vb2_buf_queue, 139462306a36Sopenharmony_ci}; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_cistatic void vdec_buf_done(struct venus_inst *inst, unsigned int buf_type, 139762306a36Sopenharmony_ci u32 tag, u32 bytesused, u32 data_offset, u32 flags, 139862306a36Sopenharmony_ci u32 hfi_flags, u64 timestamp_us) 139962306a36Sopenharmony_ci{ 140062306a36Sopenharmony_ci enum vb2_buffer_state state = VB2_BUF_STATE_DONE; 140162306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf; 140262306a36Sopenharmony_ci struct vb2_buffer *vb; 140362306a36Sopenharmony_ci unsigned int type; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci vdec_pm_touch(inst); 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci if (buf_type == HFI_BUFFER_INPUT) 140862306a36Sopenharmony_ci type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 140962306a36Sopenharmony_ci else 141062306a36Sopenharmony_ci type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci vbuf = venus_helper_find_buf(inst, type, tag); 141362306a36Sopenharmony_ci if (!vbuf) { 141462306a36Sopenharmony_ci venus_helper_change_dpb_owner(inst, vbuf, type, buf_type, tag); 141562306a36Sopenharmony_ci return; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci vbuf->flags = flags; 141962306a36Sopenharmony_ci vbuf->field = V4L2_FIELD_NONE; 142062306a36Sopenharmony_ci vb = &vbuf->vb2_buf; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 142362306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, bytesused); 142462306a36Sopenharmony_ci vb->planes[0].data_offset = data_offset; 142562306a36Sopenharmony_ci vb->timestamp = timestamp_us * NSEC_PER_USEC; 142662306a36Sopenharmony_ci vbuf->sequence = inst->sequence_cap++; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci if (vbuf->flags & V4L2_BUF_FLAG_LAST) { 142962306a36Sopenharmony_ci const struct v4l2_event ev = { .type = V4L2_EVENT_EOS }; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci v4l2_event_queue_fh(&inst->fh, &ev); 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (inst->codec_state == VENUS_DEC_STATE_DRAIN) { 143462306a36Sopenharmony_ci inst->drain_active = false; 143562306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_STOPPED; 143662306a36Sopenharmony_ci } 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (!bytesused) 144062306a36Sopenharmony_ci state = VB2_BUF_STATE_ERROR; 144162306a36Sopenharmony_ci } else { 144262306a36Sopenharmony_ci vbuf->sequence = inst->sequence_out++; 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci venus_helper_get_ts_metadata(inst, timestamp_us, vbuf); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (hfi_flags & HFI_BUFFERFLAG_READONLY) 144862306a36Sopenharmony_ci venus_helper_acquire_buf_ref(vbuf); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci if (hfi_flags & HFI_BUFFERFLAG_DATACORRUPT) 145162306a36Sopenharmony_ci state = VB2_BUF_STATE_ERROR; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci if (hfi_flags & HFI_BUFFERFLAG_DROP_FRAME) { 145462306a36Sopenharmony_ci state = VB2_BUF_STATE_ERROR; 145562306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, 0); 145662306a36Sopenharmony_ci vb->timestamp = 0; 145762306a36Sopenharmony_ci } 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci v4l2_m2m_buf_done(vbuf, state); 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_cistatic void vdec_event_change(struct venus_inst *inst, 146362306a36Sopenharmony_ci struct hfi_event_data *ev_data, bool sufficient) 146462306a36Sopenharmony_ci{ 146562306a36Sopenharmony_ci static const struct v4l2_event ev = { 146662306a36Sopenharmony_ci .type = V4L2_EVENT_SOURCE_CHANGE, 146762306a36Sopenharmony_ci .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION }; 146862306a36Sopenharmony_ci struct device *dev = inst->core->dev_dec; 146962306a36Sopenharmony_ci struct v4l2_format format = {}; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci mutex_lock(&inst->lock); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 147462306a36Sopenharmony_ci format.fmt.pix_mp.pixelformat = inst->fmt_cap->pixfmt; 147562306a36Sopenharmony_ci format.fmt.pix_mp.width = ev_data->width; 147662306a36Sopenharmony_ci format.fmt.pix_mp.height = ev_data->height; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci vdec_try_fmt_common(inst, &format); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci inst->width = format.fmt.pix_mp.width; 148162306a36Sopenharmony_ci inst->height = format.fmt.pix_mp.height; 148262306a36Sopenharmony_ci /* 148362306a36Sopenharmony_ci * Some versions of the firmware do not report crop information for 148462306a36Sopenharmony_ci * all codecs. For these cases, set the crop to the coded resolution. 148562306a36Sopenharmony_ci */ 148662306a36Sopenharmony_ci if (ev_data->input_crop.width > 0 && ev_data->input_crop.height > 0) { 148762306a36Sopenharmony_ci inst->crop.left = ev_data->input_crop.left; 148862306a36Sopenharmony_ci inst->crop.top = ev_data->input_crop.top; 148962306a36Sopenharmony_ci inst->crop.width = ev_data->input_crop.width; 149062306a36Sopenharmony_ci inst->crop.height = ev_data->input_crop.height; 149162306a36Sopenharmony_ci } else { 149262306a36Sopenharmony_ci inst->crop.left = 0; 149362306a36Sopenharmony_ci inst->crop.top = 0; 149462306a36Sopenharmony_ci inst->crop.width = ev_data->width; 149562306a36Sopenharmony_ci inst->crop.height = ev_data->height; 149662306a36Sopenharmony_ci } 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci inst->fw_min_cnt = ev_data->buf_count; 149962306a36Sopenharmony_ci /* overwriting this to 11 for vp9 due to fw bug */ 150062306a36Sopenharmony_ci if (inst->hfi_codec == HFI_VIDEO_CODEC_VP9) 150162306a36Sopenharmony_ci inst->fw_min_cnt = 11; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci inst->out_width = ev_data->width; 150462306a36Sopenharmony_ci inst->out_height = ev_data->height; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci if (inst->bit_depth != ev_data->bit_depth) { 150762306a36Sopenharmony_ci inst->bit_depth = ev_data->bit_depth; 150862306a36Sopenharmony_ci if (inst->bit_depth == VIDC_BITDEPTH_10) 150962306a36Sopenharmony_ci inst->fmt_cap = &vdec_formats[VENUS_FMT_P010]; 151062306a36Sopenharmony_ci else 151162306a36Sopenharmony_ci inst->fmt_cap = &vdec_formats[VENUS_FMT_NV12]; 151262306a36Sopenharmony_ci } 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci if (inst->pic_struct != ev_data->pic_struct) 151562306a36Sopenharmony_ci inst->pic_struct = ev_data->pic_struct; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci dev_dbg(dev, VDBGM "event %s sufficient resources (%ux%u)\n", 151862306a36Sopenharmony_ci sufficient ? "" : "not", ev_data->width, ev_data->height); 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci switch (inst->codec_state) { 152162306a36Sopenharmony_ci case VENUS_DEC_STATE_INIT: 152262306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_CAPTURE_SETUP; 152362306a36Sopenharmony_ci break; 152462306a36Sopenharmony_ci case VENUS_DEC_STATE_DECODING: 152562306a36Sopenharmony_ci case VENUS_DEC_STATE_DRAIN: 152662306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_DRC; 152762306a36Sopenharmony_ci break; 152862306a36Sopenharmony_ci default: 152962306a36Sopenharmony_ci break; 153062306a36Sopenharmony_ci } 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci /* 153362306a36Sopenharmony_ci * The assumption is that the firmware have to return the last buffer 153462306a36Sopenharmony_ci * before this event is received in the v4l2 driver. Also the firmware 153562306a36Sopenharmony_ci * itself doesn't mark the last decoder output buffer with HFI EOS flag. 153662306a36Sopenharmony_ci */ 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci if (inst->codec_state == VENUS_DEC_STATE_DRC) { 153962306a36Sopenharmony_ci int ret; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci inst->next_buf_last = true; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT, false); 154462306a36Sopenharmony_ci if (ret) 154562306a36Sopenharmony_ci dev_dbg(dev, VDBGH "flush output error %d\n", ret); 154662306a36Sopenharmony_ci } 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci inst->next_buf_last = true; 154962306a36Sopenharmony_ci inst->reconfig = true; 155062306a36Sopenharmony_ci v4l2_event_queue_fh(&inst->fh, &ev); 155162306a36Sopenharmony_ci wake_up(&inst->reconf_wait); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci mutex_unlock(&inst->lock); 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cistatic void vdec_event_notify(struct venus_inst *inst, u32 event, 155762306a36Sopenharmony_ci struct hfi_event_data *data) 155862306a36Sopenharmony_ci{ 155962306a36Sopenharmony_ci struct venus_core *core = inst->core; 156062306a36Sopenharmony_ci struct device *dev = core->dev_dec; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci vdec_pm_touch(inst); 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci switch (event) { 156562306a36Sopenharmony_ci case EVT_SESSION_ERROR: 156662306a36Sopenharmony_ci inst->session_error = true; 156762306a36Sopenharmony_ci venus_helper_vb2_queue_error(inst); 156862306a36Sopenharmony_ci dev_err(dev, "dec: event session error %x\n", inst->error); 156962306a36Sopenharmony_ci break; 157062306a36Sopenharmony_ci case EVT_SYS_EVENT_CHANGE: 157162306a36Sopenharmony_ci switch (data->event_type) { 157262306a36Sopenharmony_ci case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES: 157362306a36Sopenharmony_ci vdec_event_change(inst, data, true); 157462306a36Sopenharmony_ci break; 157562306a36Sopenharmony_ci case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES: 157662306a36Sopenharmony_ci vdec_event_change(inst, data, false); 157762306a36Sopenharmony_ci break; 157862306a36Sopenharmony_ci case HFI_EVENT_RELEASE_BUFFER_REFERENCE: 157962306a36Sopenharmony_ci venus_helper_release_buf_ref(inst, data->tag); 158062306a36Sopenharmony_ci break; 158162306a36Sopenharmony_ci default: 158262306a36Sopenharmony_ci break; 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci break; 158562306a36Sopenharmony_ci default: 158662306a36Sopenharmony_ci break; 158762306a36Sopenharmony_ci } 158862306a36Sopenharmony_ci} 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_cistatic void vdec_flush_done(struct venus_inst *inst) 159162306a36Sopenharmony_ci{ 159262306a36Sopenharmony_ci dev_dbg(inst->core->dev_dec, VDBGH "flush done\n"); 159362306a36Sopenharmony_ci} 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_cistatic const struct hfi_inst_ops vdec_hfi_ops = { 159662306a36Sopenharmony_ci .buf_done = vdec_buf_done, 159762306a36Sopenharmony_ci .event_notify = vdec_event_notify, 159862306a36Sopenharmony_ci .flush_done = vdec_flush_done, 159962306a36Sopenharmony_ci}; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_cistatic void vdec_inst_init(struct venus_inst *inst) 160262306a36Sopenharmony_ci{ 160362306a36Sopenharmony_ci inst->hfi_codec = HFI_VIDEO_CODEC_H264; 160462306a36Sopenharmony_ci inst->fmt_out = &vdec_formats[VENUS_FMT_H264]; 160562306a36Sopenharmony_ci inst->fmt_cap = &vdec_formats[VENUS_FMT_NV12]; 160662306a36Sopenharmony_ci inst->width = frame_width_min(inst); 160762306a36Sopenharmony_ci inst->height = ALIGN(frame_height_min(inst), 32); 160862306a36Sopenharmony_ci inst->crop.left = 0; 160962306a36Sopenharmony_ci inst->crop.top = 0; 161062306a36Sopenharmony_ci inst->crop.width = inst->width; 161162306a36Sopenharmony_ci inst->crop.height = inst->height; 161262306a36Sopenharmony_ci inst->fw_min_cnt = 8; 161362306a36Sopenharmony_ci inst->out_width = frame_width_min(inst); 161462306a36Sopenharmony_ci inst->out_height = frame_height_min(inst); 161562306a36Sopenharmony_ci inst->fps = 30; 161662306a36Sopenharmony_ci inst->timeperframe.numerator = 1; 161762306a36Sopenharmony_ci inst->timeperframe.denominator = 30; 161862306a36Sopenharmony_ci inst->opb_buftype = HFI_BUFFER_OUTPUT; 161962306a36Sopenharmony_ci} 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_cistatic void vdec_m2m_device_run(void *priv) 162262306a36Sopenharmony_ci{ 162362306a36Sopenharmony_ci} 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_cistatic const struct v4l2_m2m_ops vdec_m2m_ops = { 162662306a36Sopenharmony_ci .device_run = vdec_m2m_device_run, 162762306a36Sopenharmony_ci .job_abort = venus_helper_m2m_job_abort, 162862306a36Sopenharmony_ci}; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_cistatic int m2m_queue_init(void *priv, struct vb2_queue *src_vq, 163162306a36Sopenharmony_ci struct vb2_queue *dst_vq) 163262306a36Sopenharmony_ci{ 163362306a36Sopenharmony_ci struct venus_inst *inst = priv; 163462306a36Sopenharmony_ci int ret; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 163762306a36Sopenharmony_ci src_vq->io_modes = VB2_MMAP | VB2_DMABUF; 163862306a36Sopenharmony_ci src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 163962306a36Sopenharmony_ci src_vq->ops = &vdec_vb2_ops; 164062306a36Sopenharmony_ci src_vq->mem_ops = &vb2_dma_contig_memops; 164162306a36Sopenharmony_ci src_vq->drv_priv = inst; 164262306a36Sopenharmony_ci src_vq->buf_struct_size = sizeof(struct venus_buffer); 164362306a36Sopenharmony_ci src_vq->allow_zero_bytesused = 1; 164462306a36Sopenharmony_ci src_vq->min_buffers_needed = 0; 164562306a36Sopenharmony_ci src_vq->dev = inst->core->dev; 164662306a36Sopenharmony_ci src_vq->lock = &inst->ctx_q_lock; 164762306a36Sopenharmony_ci ret = vb2_queue_init(src_vq); 164862306a36Sopenharmony_ci if (ret) 164962306a36Sopenharmony_ci return ret; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 165262306a36Sopenharmony_ci dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; 165362306a36Sopenharmony_ci dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 165462306a36Sopenharmony_ci dst_vq->ops = &vdec_vb2_ops; 165562306a36Sopenharmony_ci dst_vq->mem_ops = &vb2_dma_contig_memops; 165662306a36Sopenharmony_ci dst_vq->drv_priv = inst; 165762306a36Sopenharmony_ci dst_vq->buf_struct_size = sizeof(struct venus_buffer); 165862306a36Sopenharmony_ci dst_vq->allow_zero_bytesused = 1; 165962306a36Sopenharmony_ci dst_vq->min_buffers_needed = 0; 166062306a36Sopenharmony_ci dst_vq->dev = inst->core->dev; 166162306a36Sopenharmony_ci dst_vq->lock = &inst->ctx_q_lock; 166262306a36Sopenharmony_ci return vb2_queue_init(dst_vq); 166362306a36Sopenharmony_ci} 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_cistatic int vdec_open(struct file *file) 166662306a36Sopenharmony_ci{ 166762306a36Sopenharmony_ci struct venus_core *core = video_drvdata(file); 166862306a36Sopenharmony_ci struct venus_inst *inst; 166962306a36Sopenharmony_ci int ret; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci inst = kzalloc(sizeof(*inst), GFP_KERNEL); 167262306a36Sopenharmony_ci if (!inst) 167362306a36Sopenharmony_ci return -ENOMEM; 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci INIT_LIST_HEAD(&inst->dpbbufs); 167662306a36Sopenharmony_ci INIT_LIST_HEAD(&inst->registeredbufs); 167762306a36Sopenharmony_ci INIT_LIST_HEAD(&inst->internalbufs); 167862306a36Sopenharmony_ci INIT_LIST_HEAD(&inst->list); 167962306a36Sopenharmony_ci mutex_init(&inst->lock); 168062306a36Sopenharmony_ci mutex_init(&inst->ctx_q_lock); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci inst->core = core; 168362306a36Sopenharmony_ci inst->session_type = VIDC_SESSION_TYPE_DEC; 168462306a36Sopenharmony_ci inst->num_output_bufs = 1; 168562306a36Sopenharmony_ci inst->codec_state = VENUS_DEC_STATE_DEINIT; 168662306a36Sopenharmony_ci inst->buf_count = 0; 168762306a36Sopenharmony_ci inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; 168862306a36Sopenharmony_ci inst->core_acquired = false; 168962306a36Sopenharmony_ci inst->bit_depth = VIDC_BITDEPTH_8; 169062306a36Sopenharmony_ci inst->pic_struct = HFI_INTERLACE_FRAME_PROGRESSIVE; 169162306a36Sopenharmony_ci init_waitqueue_head(&inst->reconf_wait); 169262306a36Sopenharmony_ci inst->nonblock = file->f_flags & O_NONBLOCK; 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci venus_helper_init_instance(inst); 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci ret = vdec_ctrl_init(inst); 169762306a36Sopenharmony_ci if (ret) 169862306a36Sopenharmony_ci goto err_free; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci ret = hfi_session_create(inst, &vdec_hfi_ops); 170162306a36Sopenharmony_ci if (ret) 170262306a36Sopenharmony_ci goto err_ctrl_deinit; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci vdec_inst_init(inst); 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci ida_init(&inst->dpb_ids); 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci /* 170962306a36Sopenharmony_ci * create m2m device for every instance, the m2m context scheduling 171062306a36Sopenharmony_ci * is made by firmware side so we do not need to care about. 171162306a36Sopenharmony_ci */ 171262306a36Sopenharmony_ci inst->m2m_dev = v4l2_m2m_init(&vdec_m2m_ops); 171362306a36Sopenharmony_ci if (IS_ERR(inst->m2m_dev)) { 171462306a36Sopenharmony_ci ret = PTR_ERR(inst->m2m_dev); 171562306a36Sopenharmony_ci goto err_session_destroy; 171662306a36Sopenharmony_ci } 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci inst->m2m_ctx = v4l2_m2m_ctx_init(inst->m2m_dev, inst, m2m_queue_init); 171962306a36Sopenharmony_ci if (IS_ERR(inst->m2m_ctx)) { 172062306a36Sopenharmony_ci ret = PTR_ERR(inst->m2m_ctx); 172162306a36Sopenharmony_ci goto err_m2m_release; 172262306a36Sopenharmony_ci } 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci v4l2_fh_init(&inst->fh, core->vdev_dec); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci inst->fh.ctrl_handler = &inst->ctrl_handler; 172762306a36Sopenharmony_ci v4l2_fh_add(&inst->fh); 172862306a36Sopenharmony_ci inst->fh.m2m_ctx = inst->m2m_ctx; 172962306a36Sopenharmony_ci file->private_data = &inst->fh; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci return 0; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_cierr_m2m_release: 173462306a36Sopenharmony_ci v4l2_m2m_release(inst->m2m_dev); 173562306a36Sopenharmony_cierr_session_destroy: 173662306a36Sopenharmony_ci hfi_session_destroy(inst); 173762306a36Sopenharmony_cierr_ctrl_deinit: 173862306a36Sopenharmony_ci vdec_ctrl_deinit(inst); 173962306a36Sopenharmony_cierr_free: 174062306a36Sopenharmony_ci kfree(inst); 174162306a36Sopenharmony_ci return ret; 174262306a36Sopenharmony_ci} 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_cistatic int vdec_close(struct file *file) 174562306a36Sopenharmony_ci{ 174662306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci vdec_pm_get(inst); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci v4l2_m2m_ctx_release(inst->m2m_ctx); 175162306a36Sopenharmony_ci v4l2_m2m_release(inst->m2m_dev); 175262306a36Sopenharmony_ci vdec_ctrl_deinit(inst); 175362306a36Sopenharmony_ci ida_destroy(&inst->dpb_ids); 175462306a36Sopenharmony_ci hfi_session_destroy(inst); 175562306a36Sopenharmony_ci mutex_destroy(&inst->lock); 175662306a36Sopenharmony_ci mutex_destroy(&inst->ctx_q_lock); 175762306a36Sopenharmony_ci v4l2_fh_del(&inst->fh); 175862306a36Sopenharmony_ci v4l2_fh_exit(&inst->fh); 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_ci vdec_pm_put(inst, false); 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci kfree(inst); 176362306a36Sopenharmony_ci return 0; 176462306a36Sopenharmony_ci} 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_cistatic const struct v4l2_file_operations vdec_fops = { 176762306a36Sopenharmony_ci .owner = THIS_MODULE, 176862306a36Sopenharmony_ci .open = vdec_open, 176962306a36Sopenharmony_ci .release = vdec_close, 177062306a36Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 177162306a36Sopenharmony_ci .poll = v4l2_m2m_fop_poll, 177262306a36Sopenharmony_ci .mmap = v4l2_m2m_fop_mmap, 177362306a36Sopenharmony_ci}; 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_cistatic int vdec_probe(struct platform_device *pdev) 177662306a36Sopenharmony_ci{ 177762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 177862306a36Sopenharmony_ci struct video_device *vdev; 177962306a36Sopenharmony_ci struct venus_core *core; 178062306a36Sopenharmony_ci int ret; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci if (!dev->parent) 178362306a36Sopenharmony_ci return -EPROBE_DEFER; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci core = dev_get_drvdata(dev->parent); 178662306a36Sopenharmony_ci if (!core) 178762306a36Sopenharmony_ci return -EPROBE_DEFER; 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci platform_set_drvdata(pdev, core); 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci if (core->pm_ops->vdec_get) { 179262306a36Sopenharmony_ci ret = core->pm_ops->vdec_get(dev); 179362306a36Sopenharmony_ci if (ret) 179462306a36Sopenharmony_ci return ret; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci vdev = video_device_alloc(); 179862306a36Sopenharmony_ci if (!vdev) 179962306a36Sopenharmony_ci return -ENOMEM; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci strscpy(vdev->name, "qcom-venus-decoder", sizeof(vdev->name)); 180262306a36Sopenharmony_ci vdev->release = video_device_release; 180362306a36Sopenharmony_ci vdev->fops = &vdec_fops; 180462306a36Sopenharmony_ci vdev->ioctl_ops = &vdec_ioctl_ops; 180562306a36Sopenharmony_ci vdev->vfl_dir = VFL_DIR_M2M; 180662306a36Sopenharmony_ci vdev->v4l2_dev = &core->v4l2_dev; 180762306a36Sopenharmony_ci vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 181062306a36Sopenharmony_ci if (ret) 181162306a36Sopenharmony_ci goto err_vdev_release; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci core->vdev_dec = vdev; 181462306a36Sopenharmony_ci core->dev_dec = dev; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci video_set_drvdata(vdev, core); 181762306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, 2000); 181862306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 181962306a36Sopenharmony_ci pm_runtime_enable(dev); 182062306a36Sopenharmony_ci 182162306a36Sopenharmony_ci return 0; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_cierr_vdev_release: 182462306a36Sopenharmony_ci video_device_release(vdev); 182562306a36Sopenharmony_ci return ret; 182662306a36Sopenharmony_ci} 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_cistatic void vdec_remove(struct platform_device *pdev) 182962306a36Sopenharmony_ci{ 183062306a36Sopenharmony_ci struct venus_core *core = dev_get_drvdata(pdev->dev.parent); 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci video_unregister_device(core->vdev_dec); 183362306a36Sopenharmony_ci pm_runtime_disable(core->dev_dec); 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci if (core->pm_ops->vdec_put) 183662306a36Sopenharmony_ci core->pm_ops->vdec_put(core->dev_dec); 183762306a36Sopenharmony_ci} 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_cistatic __maybe_unused int vdec_runtime_suspend(struct device *dev) 184062306a36Sopenharmony_ci{ 184162306a36Sopenharmony_ci struct venus_core *core = dev_get_drvdata(dev); 184262306a36Sopenharmony_ci const struct venus_pm_ops *pm_ops = core->pm_ops; 184362306a36Sopenharmony_ci int ret = 0; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci if (pm_ops->vdec_power) 184662306a36Sopenharmony_ci ret = pm_ops->vdec_power(dev, POWER_OFF); 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci return ret; 184962306a36Sopenharmony_ci} 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_cistatic __maybe_unused int vdec_runtime_resume(struct device *dev) 185262306a36Sopenharmony_ci{ 185362306a36Sopenharmony_ci struct venus_core *core = dev_get_drvdata(dev); 185462306a36Sopenharmony_ci const struct venus_pm_ops *pm_ops = core->pm_ops; 185562306a36Sopenharmony_ci int ret = 0; 185662306a36Sopenharmony_ci 185762306a36Sopenharmony_ci if (pm_ops->vdec_power) 185862306a36Sopenharmony_ci ret = pm_ops->vdec_power(dev, POWER_ON); 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci return ret; 186162306a36Sopenharmony_ci} 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_cistatic const struct dev_pm_ops vdec_pm_ops = { 186462306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 186562306a36Sopenharmony_ci pm_runtime_force_resume) 186662306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(vdec_runtime_suspend, vdec_runtime_resume, NULL) 186762306a36Sopenharmony_ci}; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_cistatic const struct of_device_id vdec_dt_match[] = { 187062306a36Sopenharmony_ci { .compatible = "venus-decoder" }, 187162306a36Sopenharmony_ci { } 187262306a36Sopenharmony_ci}; 187362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, vdec_dt_match); 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_cistatic struct platform_driver qcom_venus_dec_driver = { 187662306a36Sopenharmony_ci .probe = vdec_probe, 187762306a36Sopenharmony_ci .remove_new = vdec_remove, 187862306a36Sopenharmony_ci .driver = { 187962306a36Sopenharmony_ci .name = "qcom-venus-decoder", 188062306a36Sopenharmony_ci .of_match_table = vdec_dt_match, 188162306a36Sopenharmony_ci .pm = &vdec_pm_ops, 188262306a36Sopenharmony_ci }, 188362306a36Sopenharmony_ci}; 188462306a36Sopenharmony_cimodule_platform_driver(qcom_venus_dec_driver); 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ciMODULE_ALIAS("platform:qcom-venus-decoder"); 188762306a36Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm Venus video decoder driver"); 188862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1889