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-mem2mem.h> 1362306a36Sopenharmony_ci#include <media/videobuf2-dma-contig.h> 1462306a36Sopenharmony_ci#include <media/v4l2-ioctl.h> 1562306a36Sopenharmony_ci#include <media/v4l2-event.h> 1662306a36Sopenharmony_ci#include <media/v4l2-ctrls.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 "venc.h" 2362306a36Sopenharmony_ci#include "pm_helpers.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define NUM_B_FRAMES_MAX 4 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * Three resons to keep MPLANE formats (despite that the number of planes 2962306a36Sopenharmony_ci * currently is one): 3062306a36Sopenharmony_ci * - the MPLANE formats allow only one plane to be used 3162306a36Sopenharmony_ci * - the downstream driver use MPLANE formats too 3262306a36Sopenharmony_ci * - future firmware versions could add support for >1 planes 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_cistatic const struct venus_format venc_formats[] = { 3562306a36Sopenharmony_ci [VENUS_FMT_NV12] = { 3662306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_NV12, 3762306a36Sopenharmony_ci .num_planes = 1, 3862306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, 3962306a36Sopenharmony_ci }, 4062306a36Sopenharmony_ci [VENUS_FMT_H264] = { 4162306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_H264, 4262306a36Sopenharmony_ci .num_planes = 1, 4362306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 4462306a36Sopenharmony_ci }, 4562306a36Sopenharmony_ci [VENUS_FMT_VP8] = { 4662306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_VP8, 4762306a36Sopenharmony_ci .num_planes = 1, 4862306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 4962306a36Sopenharmony_ci }, 5062306a36Sopenharmony_ci [VENUS_FMT_HEVC] = { 5162306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_HEVC, 5262306a36Sopenharmony_ci .num_planes = 1, 5362306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 5462306a36Sopenharmony_ci }, 5562306a36Sopenharmony_ci [VENUS_FMT_MPEG4] = { 5662306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_MPEG4, 5762306a36Sopenharmony_ci .num_planes = 1, 5862306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 5962306a36Sopenharmony_ci }, 6062306a36Sopenharmony_ci [VENUS_FMT_H263] = { 6162306a36Sopenharmony_ci .pixfmt = V4L2_PIX_FMT_H263, 6262306a36Sopenharmony_ci .num_planes = 1, 6362306a36Sopenharmony_ci .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, 6462306a36Sopenharmony_ci }, 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic const struct venus_format * 6862306a36Sopenharmony_cifind_format(struct venus_inst *inst, u32 pixfmt, u32 type) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci const struct venus_format *fmt = venc_formats; 7162306a36Sopenharmony_ci unsigned int size = ARRAY_SIZE(venc_formats); 7262306a36Sopenharmony_ci unsigned int i; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci for (i = 0; i < size; i++) { 7562306a36Sopenharmony_ci if (fmt[i].pixfmt == pixfmt) 7662306a36Sopenharmony_ci break; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (i == size || fmt[i].type != type) 8062306a36Sopenharmony_ci return NULL; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && 8362306a36Sopenharmony_ci !venus_helper_check_codec(inst, fmt[i].pixfmt)) 8462306a36Sopenharmony_ci return NULL; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return &fmt[i]; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic const struct venus_format * 9062306a36Sopenharmony_cifind_format_by_index(struct venus_inst *inst, unsigned int index, u32 type) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci const struct venus_format *fmt = venc_formats; 9362306a36Sopenharmony_ci unsigned int size = ARRAY_SIZE(venc_formats); 9462306a36Sopenharmony_ci unsigned int i, k = 0; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (index > size) 9762306a36Sopenharmony_ci return NULL; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci for (i = 0; i < size; i++) { 10062306a36Sopenharmony_ci bool valid; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (fmt[i].type != type) 10362306a36Sopenharmony_ci continue; 10462306a36Sopenharmony_ci valid = type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE || 10562306a36Sopenharmony_ci venus_helper_check_codec(inst, fmt[i].pixfmt); 10662306a36Sopenharmony_ci if (k == index && valid) 10762306a36Sopenharmony_ci break; 10862306a36Sopenharmony_ci if (valid) 10962306a36Sopenharmony_ci k++; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (i == size) 11362306a36Sopenharmony_ci return NULL; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return &fmt[i]; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic int venc_v4l2_to_hfi(int id, int value) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci switch (id) { 12162306a36Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: 12262306a36Sopenharmony_ci switch (value) { 12362306a36Sopenharmony_ci case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC: 12462306a36Sopenharmony_ci default: 12562306a36Sopenharmony_ci return HFI_H264_ENTROPY_CAVLC; 12662306a36Sopenharmony_ci case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC: 12762306a36Sopenharmony_ci return HFI_H264_ENTROPY_CABAC; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: 13062306a36Sopenharmony_ci switch (value) { 13162306a36Sopenharmony_ci case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED: 13262306a36Sopenharmony_ci default: 13362306a36Sopenharmony_ci return HFI_H264_DB_MODE_ALL_BOUNDARY; 13462306a36Sopenharmony_ci case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED: 13562306a36Sopenharmony_ci return HFI_H264_DB_MODE_DISABLE; 13662306a36Sopenharmony_ci case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY: 13762306a36Sopenharmony_ci return HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic int 14562306a36Sopenharmony_civenc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci strscpy(cap->driver, "qcom-venus", sizeof(cap->driver)); 14862306a36Sopenharmony_ci strscpy(cap->card, "Qualcomm Venus video encoder", sizeof(cap->card)); 14962306a36Sopenharmony_ci strscpy(cap->bus_info, "platform:qcom-venus", sizeof(cap->bus_info)); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int venc_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 15762306a36Sopenharmony_ci const struct venus_format *fmt; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci fmt = find_format_by_index(inst, f->index, f->type); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci memset(f->reserved, 0, sizeof(f->reserved)); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (!fmt) 16462306a36Sopenharmony_ci return -EINVAL; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci f->pixelformat = fmt->pixfmt; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic const struct venus_format * 17262306a36Sopenharmony_civenc_try_fmt_common(struct venus_inst *inst, struct v4l2_format *f) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; 17562306a36Sopenharmony_ci struct v4l2_plane_pix_format *pfmt = pixmp->plane_fmt; 17662306a36Sopenharmony_ci const struct venus_format *fmt; 17762306a36Sopenharmony_ci u32 sizeimage; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci memset(pfmt[0].reserved, 0, sizeof(pfmt[0].reserved)); 18062306a36Sopenharmony_ci memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci fmt = find_format(inst, pixmp->pixelformat, f->type); 18362306a36Sopenharmony_ci if (!fmt) { 18462306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 18562306a36Sopenharmony_ci pixmp->pixelformat = V4L2_PIX_FMT_H264; 18662306a36Sopenharmony_ci else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 18762306a36Sopenharmony_ci pixmp->pixelformat = V4L2_PIX_FMT_NV12; 18862306a36Sopenharmony_ci else 18962306a36Sopenharmony_ci return NULL; 19062306a36Sopenharmony_ci fmt = find_format(inst, pixmp->pixelformat, f->type); 19162306a36Sopenharmony_ci if (!fmt) 19262306a36Sopenharmony_ci return NULL; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci pixmp->width = clamp(pixmp->width, frame_width_min(inst), 19662306a36Sopenharmony_ci frame_width_max(inst)); 19762306a36Sopenharmony_ci pixmp->height = clamp(pixmp->height, frame_height_min(inst), 19862306a36Sopenharmony_ci frame_height_max(inst)); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci pixmp->width = ALIGN(pixmp->width, 128); 20162306a36Sopenharmony_ci pixmp->height = ALIGN(pixmp->height, 32); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci pixmp->width = ALIGN(pixmp->width, 2); 20462306a36Sopenharmony_ci pixmp->height = ALIGN(pixmp->height, 2); 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci if (pixmp->field == V4L2_FIELD_ANY) 20762306a36Sopenharmony_ci pixmp->field = V4L2_FIELD_NONE; 20862306a36Sopenharmony_ci pixmp->num_planes = fmt->num_planes; 20962306a36Sopenharmony_ci pixmp->flags = 0; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci sizeimage = venus_helper_get_framesz(pixmp->pixelformat, 21262306a36Sopenharmony_ci pixmp->width, 21362306a36Sopenharmony_ci pixmp->height); 21462306a36Sopenharmony_ci pfmt[0].sizeimage = max(ALIGN(pfmt[0].sizeimage, SZ_4K), sizeimage); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 21762306a36Sopenharmony_ci pfmt[0].bytesperline = ALIGN(pixmp->width, 128); 21862306a36Sopenharmony_ci else 21962306a36Sopenharmony_ci pfmt[0].bytesperline = 0; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci return fmt; 22262306a36Sopenharmony_ci} 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic int venc_try_fmt(struct file *file, void *fh, struct v4l2_format *f) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci venc_try_fmt_common(inst, f); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci return 0; 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 23662306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; 23762306a36Sopenharmony_ci struct v4l2_pix_format_mplane orig_pixmp; 23862306a36Sopenharmony_ci const struct venus_format *fmt; 23962306a36Sopenharmony_ci struct v4l2_format format; 24062306a36Sopenharmony_ci u32 pixfmt_out = 0, pixfmt_cap = 0; 24162306a36Sopenharmony_ci struct vb2_queue *q; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci q = v4l2_m2m_get_vq(inst->m2m_ctx, f->type); 24462306a36Sopenharmony_ci if (!q) 24562306a36Sopenharmony_ci return -EINVAL; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (vb2_is_busy(q)) 24862306a36Sopenharmony_ci return -EBUSY; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci orig_pixmp = *pixmp; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci fmt = venc_try_fmt_common(inst, f); 25362306a36Sopenharmony_ci if (!fmt) 25462306a36Sopenharmony_ci return -EINVAL; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 25762306a36Sopenharmony_ci pixfmt_out = pixmp->pixelformat; 25862306a36Sopenharmony_ci pixfmt_cap = inst->fmt_cap->pixfmt; 25962306a36Sopenharmony_ci } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 26062306a36Sopenharmony_ci pixfmt_cap = pixmp->pixelformat; 26162306a36Sopenharmony_ci pixfmt_out = inst->fmt_out->pixfmt; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci memset(&format, 0, sizeof(format)); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 26762306a36Sopenharmony_ci format.fmt.pix_mp.pixelformat = pixfmt_out; 26862306a36Sopenharmony_ci format.fmt.pix_mp.width = orig_pixmp.width; 26962306a36Sopenharmony_ci format.fmt.pix_mp.height = orig_pixmp.height; 27062306a36Sopenharmony_ci venc_try_fmt_common(inst, &format); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 27362306a36Sopenharmony_ci inst->out_width = format.fmt.pix_mp.width; 27462306a36Sopenharmony_ci inst->out_height = format.fmt.pix_mp.height; 27562306a36Sopenharmony_ci inst->colorspace = pixmp->colorspace; 27662306a36Sopenharmony_ci inst->ycbcr_enc = pixmp->ycbcr_enc; 27762306a36Sopenharmony_ci inst->quantization = pixmp->quantization; 27862306a36Sopenharmony_ci inst->xfer_func = pixmp->xfer_func; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci memset(&format, 0, sizeof(format)); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 28462306a36Sopenharmony_ci format.fmt.pix_mp.pixelformat = pixfmt_cap; 28562306a36Sopenharmony_ci format.fmt.pix_mp.width = orig_pixmp.width; 28662306a36Sopenharmony_ci format.fmt.pix_mp.height = orig_pixmp.height; 28762306a36Sopenharmony_ci venc_try_fmt_common(inst, &format); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci inst->width = format.fmt.pix_mp.width; 29062306a36Sopenharmony_ci inst->height = format.fmt.pix_mp.height; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 29362306a36Sopenharmony_ci inst->fmt_out = fmt; 29462306a36Sopenharmony_ci else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 29562306a36Sopenharmony_ci inst->fmt_cap = fmt; 29662306a36Sopenharmony_ci inst->output_buf_size = pixmp->plane_fmt[0].sizeimage; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic int venc_g_fmt(struct file *file, void *fh, struct v4l2_format *f) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; 30562306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 30662306a36Sopenharmony_ci const struct venus_format *fmt; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 30962306a36Sopenharmony_ci fmt = inst->fmt_cap; 31062306a36Sopenharmony_ci else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 31162306a36Sopenharmony_ci fmt = inst->fmt_out; 31262306a36Sopenharmony_ci else 31362306a36Sopenharmony_ci return -EINVAL; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci pixmp->pixelformat = fmt->pixfmt; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 31862306a36Sopenharmony_ci pixmp->width = inst->width; 31962306a36Sopenharmony_ci pixmp->height = inst->height; 32062306a36Sopenharmony_ci pixmp->colorspace = inst->colorspace; 32162306a36Sopenharmony_ci pixmp->ycbcr_enc = inst->ycbcr_enc; 32262306a36Sopenharmony_ci pixmp->quantization = inst->quantization; 32362306a36Sopenharmony_ci pixmp->xfer_func = inst->xfer_func; 32462306a36Sopenharmony_ci } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { 32562306a36Sopenharmony_ci pixmp->width = inst->out_width; 32662306a36Sopenharmony_ci pixmp->height = inst->out_height; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci venc_try_fmt_common(inst, f); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return 0; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic int 33562306a36Sopenharmony_civenc_g_selection(struct file *file, void *fh, struct v4l2_selection *s) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 34062306a36Sopenharmony_ci return -EINVAL; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci switch (s->target) { 34362306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP_DEFAULT: 34462306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP_BOUNDS: 34562306a36Sopenharmony_ci s->r.width = inst->out_width; 34662306a36Sopenharmony_ci s->r.height = inst->out_height; 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP: 34962306a36Sopenharmony_ci s->r.width = inst->width; 35062306a36Sopenharmony_ci s->r.height = inst->height; 35162306a36Sopenharmony_ci break; 35262306a36Sopenharmony_ci default: 35362306a36Sopenharmony_ci return -EINVAL; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci s->r.top = 0; 35762306a36Sopenharmony_ci s->r.left = 0; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return 0; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic int 36362306a36Sopenharmony_civenc_s_selection(struct file *file, void *fh, struct v4l2_selection *s) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 36862306a36Sopenharmony_ci return -EINVAL; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (s->r.width > inst->out_width || 37162306a36Sopenharmony_ci s->r.height > inst->out_height) 37262306a36Sopenharmony_ci return -EINVAL; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci s->r.width = ALIGN(s->r.width, 2); 37562306a36Sopenharmony_ci s->r.height = ALIGN(s->r.height, 2); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci switch (s->target) { 37862306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP: 37962306a36Sopenharmony_ci s->r.top = 0; 38062306a36Sopenharmony_ci s->r.left = 0; 38162306a36Sopenharmony_ci inst->width = s->r.width; 38262306a36Sopenharmony_ci inst->height = s->r.height; 38362306a36Sopenharmony_ci break; 38462306a36Sopenharmony_ci default: 38562306a36Sopenharmony_ci return -EINVAL; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return 0; 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_cistatic int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 39462306a36Sopenharmony_ci struct v4l2_outputparm *out = &a->parm.output; 39562306a36Sopenharmony_ci struct v4l2_fract *timeperframe = &out->timeperframe; 39662306a36Sopenharmony_ci u64 us_per_frame, fps; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && 39962306a36Sopenharmony_ci a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 40062306a36Sopenharmony_ci return -EINVAL; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci memset(out->reserved, 0, sizeof(out->reserved)); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (!timeperframe->denominator) 40562306a36Sopenharmony_ci timeperframe->denominator = inst->timeperframe.denominator; 40662306a36Sopenharmony_ci if (!timeperframe->numerator) 40762306a36Sopenharmony_ci timeperframe->numerator = inst->timeperframe.numerator; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci out->capability = V4L2_CAP_TIMEPERFRAME; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; 41262306a36Sopenharmony_ci do_div(us_per_frame, timeperframe->denominator); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci if (!us_per_frame) 41562306a36Sopenharmony_ci return -EINVAL; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci fps = (u64)USEC_PER_SEC; 41862306a36Sopenharmony_ci do_div(fps, us_per_frame); 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci inst->timeperframe = *timeperframe; 42162306a36Sopenharmony_ci inst->fps = fps; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci return 0; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && 43162306a36Sopenharmony_ci a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 43262306a36Sopenharmony_ci return -EINVAL; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci a->parm.output.capability |= V4L2_CAP_TIMEPERFRAME; 43562306a36Sopenharmony_ci a->parm.output.timeperframe = inst->timeperframe; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic int venc_enum_framesizes(struct file *file, void *fh, 44162306a36Sopenharmony_ci struct v4l2_frmsizeenum *fsize) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 44462306a36Sopenharmony_ci const struct venus_format *fmt; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci fmt = find_format(inst, fsize->pixel_format, 44962306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 45062306a36Sopenharmony_ci if (!fmt) { 45162306a36Sopenharmony_ci fmt = find_format(inst, fsize->pixel_format, 45262306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 45362306a36Sopenharmony_ci if (!fmt) 45462306a36Sopenharmony_ci return -EINVAL; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (fsize->index) 45862306a36Sopenharmony_ci return -EINVAL; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci fsize->stepwise.min_width = frame_width_min(inst); 46162306a36Sopenharmony_ci fsize->stepwise.max_width = frame_width_max(inst); 46262306a36Sopenharmony_ci fsize->stepwise.step_width = frame_width_step(inst); 46362306a36Sopenharmony_ci fsize->stepwise.min_height = frame_height_min(inst); 46462306a36Sopenharmony_ci fsize->stepwise.max_height = frame_height_max(inst); 46562306a36Sopenharmony_ci fsize->stepwise.step_height = frame_height_step(inst); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci} 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cistatic int venc_enum_frameintervals(struct file *file, void *fh, 47162306a36Sopenharmony_ci struct v4l2_frmivalenum *fival) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 47462306a36Sopenharmony_ci const struct venus_format *fmt; 47562306a36Sopenharmony_ci unsigned int framerate_factor = 1; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci fmt = find_format(inst, fival->pixel_format, 48062306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 48162306a36Sopenharmony_ci if (!fmt) { 48262306a36Sopenharmony_ci fmt = find_format(inst, fival->pixel_format, 48362306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 48462306a36Sopenharmony_ci if (!fmt) 48562306a36Sopenharmony_ci return -EINVAL; 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci if (fival->index) 48962306a36Sopenharmony_ci return -EINVAL; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (!fival->width || !fival->height) 49262306a36Sopenharmony_ci return -EINVAL; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (fival->width > frame_width_max(inst) || 49562306a36Sopenharmony_ci fival->width < frame_width_min(inst) || 49662306a36Sopenharmony_ci fival->height > frame_height_max(inst) || 49762306a36Sopenharmony_ci fival->height < frame_height_min(inst)) 49862306a36Sopenharmony_ci return -EINVAL; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (IS_V1(inst->core)) { 50162306a36Sopenharmony_ci /* framerate is reported in 1/65535 fps unit */ 50262306a36Sopenharmony_ci framerate_factor = (1 << 16); 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci fival->stepwise.min.numerator = 1; 50662306a36Sopenharmony_ci fival->stepwise.min.denominator = frate_max(inst) / framerate_factor; 50762306a36Sopenharmony_ci fival->stepwise.max.numerator = 1; 50862306a36Sopenharmony_ci fival->stepwise.max.denominator = frate_min(inst) / framerate_factor; 50962306a36Sopenharmony_ci fival->stepwise.step.numerator = 1; 51062306a36Sopenharmony_ci fival->stepwise.step.denominator = frate_max(inst) / framerate_factor; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci return 0; 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic int venc_subscribe_event(struct v4l2_fh *fh, 51662306a36Sopenharmony_ci const struct v4l2_event_subscription *sub) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci switch (sub->type) { 51962306a36Sopenharmony_ci case V4L2_EVENT_EOS: 52062306a36Sopenharmony_ci return v4l2_event_subscribe(fh, sub, 2, NULL); 52162306a36Sopenharmony_ci case V4L2_EVENT_CTRL: 52262306a36Sopenharmony_ci return v4l2_ctrl_subscribe_event(fh, sub); 52362306a36Sopenharmony_ci default: 52462306a36Sopenharmony_ci return -EINVAL; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic int 52962306a36Sopenharmony_civenc_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *cmd) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 53262306a36Sopenharmony_ci struct hfi_frame_data fdata = {0}; 53362306a36Sopenharmony_ci int ret = 0; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, cmd); 53662306a36Sopenharmony_ci if (ret) 53762306a36Sopenharmony_ci return ret; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci mutex_lock(&inst->lock); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci if (cmd->cmd == V4L2_ENC_CMD_STOP && 54262306a36Sopenharmony_ci inst->enc_state == VENUS_ENC_STATE_ENCODING) { 54362306a36Sopenharmony_ci /* 54462306a36Sopenharmony_ci * Implement V4L2_ENC_CMD_STOP by enqueue an empty buffer on 54562306a36Sopenharmony_ci * encoder input to signal EOS. 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_ci if (!(inst->streamon_out && inst->streamon_cap)) 54862306a36Sopenharmony_ci goto unlock; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci fdata.buffer_type = HFI_BUFFER_INPUT; 55162306a36Sopenharmony_ci fdata.flags |= HFI_BUFFERFLAG_EOS; 55262306a36Sopenharmony_ci fdata.device_addr = 0xdeadb000; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci ret = hfi_session_process_buf(inst, &fdata); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci inst->enc_state = VENUS_ENC_STATE_DRAIN; 55762306a36Sopenharmony_ci } else if (cmd->cmd == V4L2_ENC_CMD_START) { 55862306a36Sopenharmony_ci if (inst->enc_state == VENUS_ENC_STATE_DRAIN) { 55962306a36Sopenharmony_ci ret = -EBUSY; 56062306a36Sopenharmony_ci goto unlock; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci if (inst->enc_state == VENUS_ENC_STATE_STOPPED) { 56362306a36Sopenharmony_ci vb2_clear_last_buffer_dequeued(&inst->fh.m2m_ctx->cap_q_ctx.q); 56462306a36Sopenharmony_ci inst->enc_state = VENUS_ENC_STATE_ENCODING; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ciunlock: 56962306a36Sopenharmony_ci mutex_unlock(&inst->lock); 57062306a36Sopenharmony_ci return ret; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic const struct v4l2_ioctl_ops venc_ioctl_ops = { 57462306a36Sopenharmony_ci .vidioc_querycap = venc_querycap, 57562306a36Sopenharmony_ci .vidioc_enum_fmt_vid_cap = venc_enum_fmt, 57662306a36Sopenharmony_ci .vidioc_enum_fmt_vid_out = venc_enum_fmt, 57762306a36Sopenharmony_ci .vidioc_s_fmt_vid_cap_mplane = venc_s_fmt, 57862306a36Sopenharmony_ci .vidioc_s_fmt_vid_out_mplane = venc_s_fmt, 57962306a36Sopenharmony_ci .vidioc_g_fmt_vid_cap_mplane = venc_g_fmt, 58062306a36Sopenharmony_ci .vidioc_g_fmt_vid_out_mplane = venc_g_fmt, 58162306a36Sopenharmony_ci .vidioc_try_fmt_vid_cap_mplane = venc_try_fmt, 58262306a36Sopenharmony_ci .vidioc_try_fmt_vid_out_mplane = venc_try_fmt, 58362306a36Sopenharmony_ci .vidioc_g_selection = venc_g_selection, 58462306a36Sopenharmony_ci .vidioc_s_selection = venc_s_selection, 58562306a36Sopenharmony_ci .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 58662306a36Sopenharmony_ci .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 58762306a36Sopenharmony_ci .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 58862306a36Sopenharmony_ci .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 58962306a36Sopenharmony_ci .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 59062306a36Sopenharmony_ci .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 59162306a36Sopenharmony_ci .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 59262306a36Sopenharmony_ci .vidioc_streamon = v4l2_m2m_ioctl_streamon, 59362306a36Sopenharmony_ci .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 59462306a36Sopenharmony_ci .vidioc_s_parm = venc_s_parm, 59562306a36Sopenharmony_ci .vidioc_g_parm = venc_g_parm, 59662306a36Sopenharmony_ci .vidioc_enum_framesizes = venc_enum_framesizes, 59762306a36Sopenharmony_ci .vidioc_enum_frameintervals = venc_enum_frameintervals, 59862306a36Sopenharmony_ci .vidioc_subscribe_event = venc_subscribe_event, 59962306a36Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 60062306a36Sopenharmony_ci .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, 60162306a36Sopenharmony_ci .vidioc_encoder_cmd = venc_encoder_cmd, 60262306a36Sopenharmony_ci}; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistatic int venc_pm_get(struct venus_inst *inst) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci struct venus_core *core = inst->core; 60762306a36Sopenharmony_ci struct device *dev = core->dev_enc; 60862306a36Sopenharmony_ci int ret; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci mutex_lock(&core->pm_lock); 61162306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 61262306a36Sopenharmony_ci mutex_unlock(&core->pm_lock); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci return ret < 0 ? ret : 0; 61562306a36Sopenharmony_ci} 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic int venc_pm_put(struct venus_inst *inst, bool autosuspend) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct venus_core *core = inst->core; 62062306a36Sopenharmony_ci struct device *dev = core->dev_enc; 62162306a36Sopenharmony_ci int ret; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci mutex_lock(&core->pm_lock); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci if (autosuspend) 62662306a36Sopenharmony_ci ret = pm_runtime_put_autosuspend(dev); 62762306a36Sopenharmony_ci else 62862306a36Sopenharmony_ci ret = pm_runtime_put_sync(dev); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci mutex_unlock(&core->pm_lock); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci return ret < 0 ? ret : 0; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic int venc_pm_get_put(struct venus_inst *inst) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct venus_core *core = inst->core; 63862306a36Sopenharmony_ci struct device *dev = core->dev_enc; 63962306a36Sopenharmony_ci int ret = 0; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci mutex_lock(&core->pm_lock); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (pm_runtime_suspended(dev)) { 64462306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 64562306a36Sopenharmony_ci if (ret < 0) 64662306a36Sopenharmony_ci goto error; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci ret = pm_runtime_put_autosuspend(dev); 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cierror: 65262306a36Sopenharmony_ci mutex_unlock(&core->pm_lock); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci return ret < 0 ? ret : 0; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic void venc_pm_touch(struct venus_inst *inst) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci pm_runtime_mark_last_busy(inst->core->dev_enc); 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_cistatic int venc_set_properties(struct venus_inst *inst) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci struct venc_controls *ctr = &inst->controls.enc; 66562306a36Sopenharmony_ci struct hfi_intra_period intra_period; 66662306a36Sopenharmony_ci struct hfi_framerate frate; 66762306a36Sopenharmony_ci struct hfi_bitrate brate; 66862306a36Sopenharmony_ci struct hfi_idr_period idrp; 66962306a36Sopenharmony_ci struct hfi_quantization quant; 67062306a36Sopenharmony_ci struct hfi_quantization_range quant_range; 67162306a36Sopenharmony_ci struct hfi_quantization_range_v2 quant_range_v2; 67262306a36Sopenharmony_ci struct hfi_enable en; 67362306a36Sopenharmony_ci struct hfi_ltr_mode ltr_mode; 67462306a36Sopenharmony_ci struct hfi_intra_refresh intra_refresh = {}; 67562306a36Sopenharmony_ci u32 ptype, rate_control, bitrate; 67662306a36Sopenharmony_ci u32 profile, level; 67762306a36Sopenharmony_ci int ret; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci ret = venus_helper_set_work_mode(inst); 68062306a36Sopenharmony_ci if (ret) 68162306a36Sopenharmony_ci return ret; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci ptype = HFI_PROPERTY_CONFIG_FRAME_RATE; 68462306a36Sopenharmony_ci frate.buffer_type = HFI_BUFFER_OUTPUT; 68562306a36Sopenharmony_ci frate.framerate = inst->fps * (1 << 16); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &frate); 68862306a36Sopenharmony_ci if (ret) 68962306a36Sopenharmony_ci return ret; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264) { 69262306a36Sopenharmony_ci struct hfi_h264_vui_timing_info info; 69362306a36Sopenharmony_ci struct hfi_h264_entropy_control entropy; 69462306a36Sopenharmony_ci struct hfi_h264_db_control deblock; 69562306a36Sopenharmony_ci struct hfi_h264_8x8_transform h264_transform; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO; 69862306a36Sopenharmony_ci info.enable = 1; 69962306a36Sopenharmony_ci info.fixed_framerate = 1; 70062306a36Sopenharmony_ci info.time_scale = NSEC_PER_SEC; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &info); 70362306a36Sopenharmony_ci if (ret) 70462306a36Sopenharmony_ci return ret; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL; 70762306a36Sopenharmony_ci entropy.entropy_mode = venc_v4l2_to_hfi( 70862306a36Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, 70962306a36Sopenharmony_ci ctr->h264_entropy_mode); 71062306a36Sopenharmony_ci entropy.cabac_model = HFI_H264_CABAC_MODEL_0; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &entropy); 71362306a36Sopenharmony_ci if (ret) 71462306a36Sopenharmony_ci return ret; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL; 71762306a36Sopenharmony_ci deblock.mode = venc_v4l2_to_hfi( 71862306a36Sopenharmony_ci V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, 71962306a36Sopenharmony_ci ctr->h264_loop_filter_mode); 72062306a36Sopenharmony_ci deblock.slice_alpha_offset = ctr->h264_loop_filter_alpha; 72162306a36Sopenharmony_ci deblock.slice_beta_offset = ctr->h264_loop_filter_beta; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &deblock); 72462306a36Sopenharmony_ci if (ret) 72562306a36Sopenharmony_ci return ret; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_H264_TRANSFORM_8X8; 72862306a36Sopenharmony_ci h264_transform.enable_type = 0; 72962306a36Sopenharmony_ci if (ctr->profile.h264 == V4L2_MPEG_VIDEO_H264_PROFILE_HIGH || 73062306a36Sopenharmony_ci ctr->profile.h264 == V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) 73162306a36Sopenharmony_ci h264_transform.enable_type = ctr->h264_8x8_transform; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &h264_transform); 73462306a36Sopenharmony_ci if (ret) 73562306a36Sopenharmony_ci return ret; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || 74062306a36Sopenharmony_ci inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { 74162306a36Sopenharmony_ci /* IDR periodicity, n: 74262306a36Sopenharmony_ci * n = 0 - only the first I-frame is IDR frame 74362306a36Sopenharmony_ci * n = 1 - all I-frames will be IDR frames 74462306a36Sopenharmony_ci * n > 1 - every n-th I-frame will be IDR frame 74562306a36Sopenharmony_ci */ 74662306a36Sopenharmony_ci ptype = HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD; 74762306a36Sopenharmony_ci idrp.idr_period = 0; 74862306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &idrp); 74962306a36Sopenharmony_ci if (ret) 75062306a36Sopenharmony_ci return ret; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC && 75462306a36Sopenharmony_ci ctr->profile.hevc == V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) { 75562306a36Sopenharmony_ci struct hfi_hdr10_pq_sei hdr10; 75662306a36Sopenharmony_ci unsigned int c; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_HDR10_PQ_SEI; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci for (c = 0; c < 3; c++) { 76162306a36Sopenharmony_ci hdr10.mastering.display_primaries_x[c] = 76262306a36Sopenharmony_ci ctr->mastering.display_primaries_x[c]; 76362306a36Sopenharmony_ci hdr10.mastering.display_primaries_y[c] = 76462306a36Sopenharmony_ci ctr->mastering.display_primaries_y[c]; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci hdr10.mastering.white_point_x = ctr->mastering.white_point_x; 76862306a36Sopenharmony_ci hdr10.mastering.white_point_y = ctr->mastering.white_point_y; 76962306a36Sopenharmony_ci hdr10.mastering.max_display_mastering_luminance = 77062306a36Sopenharmony_ci ctr->mastering.max_display_mastering_luminance; 77162306a36Sopenharmony_ci hdr10.mastering.min_display_mastering_luminance = 77262306a36Sopenharmony_ci ctr->mastering.min_display_mastering_luminance; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci hdr10.cll.max_content_light = ctr->cll.max_content_light_level; 77562306a36Sopenharmony_ci hdr10.cll.max_pic_average_light = 77662306a36Sopenharmony_ci ctr->cll.max_pic_average_light_level; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &hdr10); 77962306a36Sopenharmony_ci if (ret) 78062306a36Sopenharmony_ci return ret; 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (ctr->num_b_frames) { 78462306a36Sopenharmony_ci u32 max_num_b_frames = NUM_B_FRAMES_MAX; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES; 78762306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &max_num_b_frames); 78862306a36Sopenharmony_ci if (ret) 78962306a36Sopenharmony_ci return ret; 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci ptype = HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD; 79362306a36Sopenharmony_ci intra_period.pframes = ctr->num_p_frames; 79462306a36Sopenharmony_ci intra_period.bframes = ctr->num_b_frames; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &intra_period); 79762306a36Sopenharmony_ci if (ret) 79862306a36Sopenharmony_ci return ret; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (!ctr->rc_enable) 80162306a36Sopenharmony_ci rate_control = HFI_RATE_CONTROL_OFF; 80262306a36Sopenharmony_ci else if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) 80362306a36Sopenharmony_ci rate_control = ctr->frame_skip_mode ? HFI_RATE_CONTROL_VBR_VFR : 80462306a36Sopenharmony_ci HFI_RATE_CONTROL_VBR_CFR; 80562306a36Sopenharmony_ci else if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) 80662306a36Sopenharmony_ci rate_control = ctr->frame_skip_mode ? HFI_RATE_CONTROL_CBR_VFR : 80762306a36Sopenharmony_ci HFI_RATE_CONTROL_CBR_CFR; 80862306a36Sopenharmony_ci else if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) 80962306a36Sopenharmony_ci rate_control = HFI_RATE_CONTROL_CQ; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_RATE_CONTROL; 81262306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &rate_control); 81362306a36Sopenharmony_ci if (ret) 81462306a36Sopenharmony_ci return ret; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (rate_control == HFI_RATE_CONTROL_CQ && ctr->const_quality) { 81762306a36Sopenharmony_ci struct hfi_heic_frame_quality quality = {}; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci ptype = HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY; 82062306a36Sopenharmony_ci quality.frame_quality = ctr->const_quality; 82162306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &quality); 82262306a36Sopenharmony_ci if (ret) 82362306a36Sopenharmony_ci return ret; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (!ctr->bitrate) 82762306a36Sopenharmony_ci bitrate = 64000; 82862306a36Sopenharmony_ci else 82962306a36Sopenharmony_ci bitrate = ctr->bitrate; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; 83262306a36Sopenharmony_ci brate.bitrate = bitrate; 83362306a36Sopenharmony_ci brate.layer_id = 0; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &brate); 83662306a36Sopenharmony_ci if (ret) 83762306a36Sopenharmony_ci return ret; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || 84062306a36Sopenharmony_ci inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { 84162306a36Sopenharmony_ci ptype = HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER; 84262306a36Sopenharmony_ci if (ctr->header_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) 84362306a36Sopenharmony_ci en.enable = 0; 84462306a36Sopenharmony_ci else 84562306a36Sopenharmony_ci en.enable = 1; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &en); 84862306a36Sopenharmony_ci if (ret) 84962306a36Sopenharmony_ci return ret; 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (!ctr->bitrate_peak) 85362306a36Sopenharmony_ci bitrate *= 2; 85462306a36Sopenharmony_ci else 85562306a36Sopenharmony_ci bitrate = ctr->bitrate_peak; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci ptype = HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE; 85862306a36Sopenharmony_ci brate.bitrate = bitrate; 85962306a36Sopenharmony_ci brate.layer_id = 0; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &brate); 86262306a36Sopenharmony_ci if (ret) 86362306a36Sopenharmony_ci return ret; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP; 86662306a36Sopenharmony_ci if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { 86762306a36Sopenharmony_ci quant.qp_i = ctr->hevc_i_qp; 86862306a36Sopenharmony_ci quant.qp_p = ctr->hevc_p_qp; 86962306a36Sopenharmony_ci quant.qp_b = ctr->hevc_b_qp; 87062306a36Sopenharmony_ci } else { 87162306a36Sopenharmony_ci quant.qp_i = ctr->h264_i_qp; 87262306a36Sopenharmony_ci quant.qp_p = ctr->h264_p_qp; 87362306a36Sopenharmony_ci quant.qp_b = ctr->h264_b_qp; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci quant.layer_id = 0; 87662306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &quant); 87762306a36Sopenharmony_ci if (ret) 87862306a36Sopenharmony_ci return ret; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (inst->core->res->hfi_version == HFI_VERSION_4XX || 88162306a36Sopenharmony_ci inst->core->res->hfi_version == HFI_VERSION_6XX) { 88262306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE_V2; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { 88562306a36Sopenharmony_ci quant_range_v2.min_qp.qp_packed = ctr->hevc_min_qp; 88662306a36Sopenharmony_ci quant_range_v2.max_qp.qp_packed = ctr->hevc_max_qp; 88762306a36Sopenharmony_ci } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_VP8) { 88862306a36Sopenharmony_ci quant_range_v2.min_qp.qp_packed = ctr->vp8_min_qp; 88962306a36Sopenharmony_ci quant_range_v2.max_qp.qp_packed = ctr->vp8_max_qp; 89062306a36Sopenharmony_ci } else { 89162306a36Sopenharmony_ci quant_range_v2.min_qp.qp_packed = ctr->h264_min_qp; 89262306a36Sopenharmony_ci quant_range_v2.max_qp.qp_packed = ctr->h264_max_qp; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &quant_range_v2); 89662306a36Sopenharmony_ci } else { 89762306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { 90062306a36Sopenharmony_ci quant_range.min_qp = ctr->hevc_min_qp; 90162306a36Sopenharmony_ci quant_range.max_qp = ctr->hevc_max_qp; 90262306a36Sopenharmony_ci } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_VP8) { 90362306a36Sopenharmony_ci quant_range.min_qp = ctr->vp8_min_qp; 90462306a36Sopenharmony_ci quant_range.max_qp = ctr->vp8_max_qp; 90562306a36Sopenharmony_ci } else { 90662306a36Sopenharmony_ci quant_range.min_qp = ctr->h264_min_qp; 90762306a36Sopenharmony_ci quant_range.max_qp = ctr->h264_max_qp; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci quant_range.layer_id = 0; 91162306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &quant_range); 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (ret) 91562306a36Sopenharmony_ci return ret; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_LTRMODE; 91862306a36Sopenharmony_ci ltr_mode.ltr_count = ctr->ltr_count; 91962306a36Sopenharmony_ci ltr_mode.ltr_mode = HFI_LTR_MODE_MANUAL; 92062306a36Sopenharmony_ci ltr_mode.trust_mode = 1; 92162306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, <r_mode); 92262306a36Sopenharmony_ci if (ret) 92362306a36Sopenharmony_ci return ret; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci switch (inst->hfi_codec) { 92662306a36Sopenharmony_ci case HFI_VIDEO_CODEC_H264: 92762306a36Sopenharmony_ci profile = ctr->profile.h264; 92862306a36Sopenharmony_ci level = ctr->level.h264; 92962306a36Sopenharmony_ci break; 93062306a36Sopenharmony_ci case HFI_VIDEO_CODEC_MPEG4: 93162306a36Sopenharmony_ci profile = ctr->profile.mpeg4; 93262306a36Sopenharmony_ci level = ctr->level.mpeg4; 93362306a36Sopenharmony_ci break; 93462306a36Sopenharmony_ci case HFI_VIDEO_CODEC_VP8: 93562306a36Sopenharmony_ci profile = ctr->profile.vp8; 93662306a36Sopenharmony_ci level = 0; 93762306a36Sopenharmony_ci break; 93862306a36Sopenharmony_ci case HFI_VIDEO_CODEC_VP9: 93962306a36Sopenharmony_ci profile = ctr->profile.vp9; 94062306a36Sopenharmony_ci level = ctr->level.vp9; 94162306a36Sopenharmony_ci break; 94262306a36Sopenharmony_ci case HFI_VIDEO_CODEC_HEVC: 94362306a36Sopenharmony_ci profile = ctr->profile.hevc; 94462306a36Sopenharmony_ci level = ctr->level.hevc; 94562306a36Sopenharmony_ci break; 94662306a36Sopenharmony_ci case HFI_VIDEO_CODEC_MPEG2: 94762306a36Sopenharmony_ci default: 94862306a36Sopenharmony_ci profile = 0; 94962306a36Sopenharmony_ci level = 0; 95062306a36Sopenharmony_ci break; 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci ret = venus_helper_set_profile_level(inst, profile, level); 95462306a36Sopenharmony_ci if (ret) 95562306a36Sopenharmony_ci return ret; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || 95862306a36Sopenharmony_ci inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) { 95962306a36Sopenharmony_ci struct hfi_enable en = {}; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_H264_GENERATE_AUDNAL; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci if (ctr->aud_enable) 96462306a36Sopenharmony_ci en.enable = 1; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &en); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci if ((inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || 97062306a36Sopenharmony_ci inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) && 97162306a36Sopenharmony_ci (rate_control == HFI_RATE_CONTROL_CBR_VFR || 97262306a36Sopenharmony_ci rate_control == HFI_RATE_CONTROL_CBR_CFR)) { 97362306a36Sopenharmony_ci intra_refresh.mode = HFI_INTRA_REFRESH_NONE; 97462306a36Sopenharmony_ci intra_refresh.cir_mbs = 0; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci if (ctr->intra_refresh_period) { 97762306a36Sopenharmony_ci u32 mbs; 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci mbs = ALIGN(inst->width, 16) * ALIGN(inst->height, 16); 98062306a36Sopenharmony_ci mbs /= 16 * 16; 98162306a36Sopenharmony_ci if (mbs % ctr->intra_refresh_period) 98262306a36Sopenharmony_ci mbs++; 98362306a36Sopenharmony_ci mbs /= ctr->intra_refresh_period; 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci intra_refresh.cir_mbs = mbs; 98662306a36Sopenharmony_ci if (ctr->intra_refresh_type == 98762306a36Sopenharmony_ci V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC) 98862306a36Sopenharmony_ci intra_refresh.mode = HFI_INTRA_REFRESH_CYCLIC; 98962306a36Sopenharmony_ci else 99062306a36Sopenharmony_ci intra_refresh.mode = HFI_INTRA_REFRESH_RANDOM; 99162306a36Sopenharmony_ci } 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci ptype = HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci ret = hfi_session_set_property(inst, ptype, &intra_refresh); 99662306a36Sopenharmony_ci if (ret) 99762306a36Sopenharmony_ci return ret; 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci return 0; 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic int venc_init_session(struct venus_inst *inst) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci int ret; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci ret = venus_helper_session_init(inst); 100862306a36Sopenharmony_ci if (ret == -EALREADY) 100962306a36Sopenharmony_ci return 0; 101062306a36Sopenharmony_ci else if (ret) 101162306a36Sopenharmony_ci return ret; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci ret = venus_helper_set_stride(inst, inst->out_width, 101462306a36Sopenharmony_ci inst->out_height); 101562306a36Sopenharmony_ci if (ret) 101662306a36Sopenharmony_ci goto deinit; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci ret = venus_helper_set_input_resolution(inst, inst->width, 101962306a36Sopenharmony_ci inst->height); 102062306a36Sopenharmony_ci if (ret) 102162306a36Sopenharmony_ci goto deinit; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci ret = venus_helper_set_output_resolution(inst, inst->width, 102462306a36Sopenharmony_ci inst->height, 102562306a36Sopenharmony_ci HFI_BUFFER_OUTPUT); 102662306a36Sopenharmony_ci if (ret) 102762306a36Sopenharmony_ci goto deinit; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci ret = venus_helper_set_color_format(inst, inst->fmt_out->pixfmt); 103062306a36Sopenharmony_ci if (ret) 103162306a36Sopenharmony_ci goto deinit; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci ret = venc_set_properties(inst); 103462306a36Sopenharmony_ci if (ret) 103562306a36Sopenharmony_ci goto deinit; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci return 0; 103862306a36Sopenharmony_cideinit: 103962306a36Sopenharmony_ci hfi_session_deinit(inst); 104062306a36Sopenharmony_ci return ret; 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_cistatic int venc_out_num_buffers(struct venus_inst *inst, unsigned int *num) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci struct hfi_buffer_requirements bufreq; 104662306a36Sopenharmony_ci int ret; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq); 104962306a36Sopenharmony_ci if (ret) 105062306a36Sopenharmony_ci return ret; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci *num = bufreq.count_actual; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci return 0; 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cistatic int venc_queue_setup(struct vb2_queue *q, 105862306a36Sopenharmony_ci unsigned int *num_buffers, unsigned int *num_planes, 105962306a36Sopenharmony_ci unsigned int sizes[], struct device *alloc_devs[]) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci struct venus_inst *inst = vb2_get_drv_priv(q); 106262306a36Sopenharmony_ci struct venus_core *core = inst->core; 106362306a36Sopenharmony_ci unsigned int num, min = 4; 106462306a36Sopenharmony_ci int ret; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci if (*num_planes) { 106762306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && 106862306a36Sopenharmony_ci *num_planes != inst->fmt_out->num_planes) 106962306a36Sopenharmony_ci return -EINVAL; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && 107262306a36Sopenharmony_ci *num_planes != inst->fmt_cap->num_planes) 107362306a36Sopenharmony_ci return -EINVAL; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE && 107662306a36Sopenharmony_ci sizes[0] < inst->input_buf_size) 107762306a36Sopenharmony_ci return -EINVAL; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && 108062306a36Sopenharmony_ci sizes[0] < inst->output_buf_size) 108162306a36Sopenharmony_ci return -EINVAL; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci return 0; 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (test_bit(0, &core->sys_error)) { 108762306a36Sopenharmony_ci if (inst->nonblock) 108862306a36Sopenharmony_ci return -EAGAIN; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci ret = wait_event_interruptible(core->sys_err_done, 109162306a36Sopenharmony_ci !test_bit(0, &core->sys_error)); 109262306a36Sopenharmony_ci if (ret) 109362306a36Sopenharmony_ci return ret; 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci ret = venc_pm_get(inst); 109762306a36Sopenharmony_ci if (ret) 109862306a36Sopenharmony_ci return ret; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci mutex_lock(&inst->lock); 110162306a36Sopenharmony_ci ret = venc_init_session(inst); 110262306a36Sopenharmony_ci mutex_unlock(&inst->lock); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci if (ret) 110562306a36Sopenharmony_ci goto put_power; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci ret = venc_pm_put(inst, false); 110862306a36Sopenharmony_ci if (ret) 110962306a36Sopenharmony_ci return ret; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci switch (q->type) { 111262306a36Sopenharmony_ci case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 111362306a36Sopenharmony_ci *num_planes = inst->fmt_out->num_planes; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci ret = venc_out_num_buffers(inst, &num); 111662306a36Sopenharmony_ci if (ret) 111762306a36Sopenharmony_ci break; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci num = max(num, min); 112062306a36Sopenharmony_ci *num_buffers = max(*num_buffers, num); 112162306a36Sopenharmony_ci inst->num_input_bufs = *num_buffers; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci sizes[0] = venus_helper_get_framesz(inst->fmt_out->pixfmt, 112462306a36Sopenharmony_ci inst->out_width, 112562306a36Sopenharmony_ci inst->out_height); 112662306a36Sopenharmony_ci inst->input_buf_size = sizes[0]; 112762306a36Sopenharmony_ci break; 112862306a36Sopenharmony_ci case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 112962306a36Sopenharmony_ci *num_planes = inst->fmt_cap->num_planes; 113062306a36Sopenharmony_ci *num_buffers = max(*num_buffers, min); 113162306a36Sopenharmony_ci inst->num_output_bufs = *num_buffers; 113262306a36Sopenharmony_ci sizes[0] = venus_helper_get_framesz(inst->fmt_cap->pixfmt, 113362306a36Sopenharmony_ci inst->width, 113462306a36Sopenharmony_ci inst->height); 113562306a36Sopenharmony_ci sizes[0] = max(sizes[0], inst->output_buf_size); 113662306a36Sopenharmony_ci inst->output_buf_size = sizes[0]; 113762306a36Sopenharmony_ci break; 113862306a36Sopenharmony_ci default: 113962306a36Sopenharmony_ci ret = -EINVAL; 114062306a36Sopenharmony_ci break; 114162306a36Sopenharmony_ci } 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci return ret; 114462306a36Sopenharmony_ciput_power: 114562306a36Sopenharmony_ci venc_pm_put(inst, false); 114662306a36Sopenharmony_ci return ret; 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_cistatic int venc_buf_init(struct vb2_buffer *vb) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci inst->buf_count++; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci return venus_helper_vb2_buf_init(vb); 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_cistatic void venc_release_session(struct venus_inst *inst) 115962306a36Sopenharmony_ci{ 116062306a36Sopenharmony_ci int ret; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci venc_pm_get(inst); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci mutex_lock(&inst->lock); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci ret = hfi_session_deinit(inst); 116762306a36Sopenharmony_ci if (ret || inst->session_error) 116862306a36Sopenharmony_ci hfi_session_abort(inst); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci mutex_unlock(&inst->lock); 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci venus_pm_load_scale(inst); 117362306a36Sopenharmony_ci INIT_LIST_HEAD(&inst->registeredbufs); 117462306a36Sopenharmony_ci venus_pm_release_core(inst); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci venc_pm_put(inst, false); 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic void venc_buf_cleanup(struct vb2_buffer *vb) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); 118262306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 118362306a36Sopenharmony_ci struct venus_buffer *buf = to_venus_buffer(vbuf); 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci mutex_lock(&inst->lock); 118662306a36Sopenharmony_ci if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 118762306a36Sopenharmony_ci if (!list_empty(&inst->registeredbufs)) 118862306a36Sopenharmony_ci list_del_init(&buf->reg_list); 118962306a36Sopenharmony_ci mutex_unlock(&inst->lock); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci inst->buf_count--; 119262306a36Sopenharmony_ci if (!inst->buf_count) 119362306a36Sopenharmony_ci venc_release_session(inst); 119462306a36Sopenharmony_ci} 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_cistatic int venc_verify_conf(struct venus_inst *inst) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci enum hfi_version ver = inst->core->res->hfi_version; 119962306a36Sopenharmony_ci struct hfi_buffer_requirements bufreq; 120062306a36Sopenharmony_ci int ret; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci if (!inst->num_input_bufs || !inst->num_output_bufs) 120362306a36Sopenharmony_ci return -EINVAL; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq); 120662306a36Sopenharmony_ci if (ret) 120762306a36Sopenharmony_ci return ret; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci if (inst->num_output_bufs < bufreq.count_actual || 121062306a36Sopenharmony_ci inst->num_output_bufs < hfi_bufreq_get_count_min(&bufreq, ver)) 121162306a36Sopenharmony_ci return -EINVAL; 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq); 121462306a36Sopenharmony_ci if (ret) 121562306a36Sopenharmony_ci return ret; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci if (inst->num_input_bufs < bufreq.count_actual || 121862306a36Sopenharmony_ci inst->num_input_bufs < hfi_bufreq_get_count_min(&bufreq, ver)) 121962306a36Sopenharmony_ci return -EINVAL; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci return 0; 122262306a36Sopenharmony_ci} 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_cistatic int venc_start_streaming(struct vb2_queue *q, unsigned int count) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci struct venus_inst *inst = vb2_get_drv_priv(q); 122762306a36Sopenharmony_ci int ret; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci mutex_lock(&inst->lock); 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 123262306a36Sopenharmony_ci inst->streamon_out = 1; 123362306a36Sopenharmony_ci else 123462306a36Sopenharmony_ci inst->streamon_cap = 1; 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci if (!(inst->streamon_out & inst->streamon_cap)) { 123762306a36Sopenharmony_ci mutex_unlock(&inst->lock); 123862306a36Sopenharmony_ci return 0; 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci venus_helper_init_instance(inst); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci inst->sequence_cap = 0; 124462306a36Sopenharmony_ci inst->sequence_out = 0; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci ret = venc_pm_get(inst); 124762306a36Sopenharmony_ci if (ret) 124862306a36Sopenharmony_ci goto error; 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci ret = venus_pm_acquire_core(inst); 125162306a36Sopenharmony_ci if (ret) 125262306a36Sopenharmony_ci goto put_power; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci ret = venc_pm_put(inst, true); 125562306a36Sopenharmony_ci if (ret) 125662306a36Sopenharmony_ci goto error; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci ret = venc_set_properties(inst); 125962306a36Sopenharmony_ci if (ret) 126062306a36Sopenharmony_ci goto error; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci ret = venc_verify_conf(inst); 126362306a36Sopenharmony_ci if (ret) 126462306a36Sopenharmony_ci goto error; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci ret = venus_helper_set_num_bufs(inst, inst->num_input_bufs, 126762306a36Sopenharmony_ci inst->num_output_bufs, 0); 126862306a36Sopenharmony_ci if (ret) 126962306a36Sopenharmony_ci goto error; 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci ret = venus_helper_vb2_start_streaming(inst); 127262306a36Sopenharmony_ci if (ret) 127362306a36Sopenharmony_ci goto error; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci inst->enc_state = VENUS_ENC_STATE_ENCODING; 127662306a36Sopenharmony_ci 127762306a36Sopenharmony_ci mutex_unlock(&inst->lock); 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci return 0; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ciput_power: 128262306a36Sopenharmony_ci venc_pm_put(inst, false); 128362306a36Sopenharmony_cierror: 128462306a36Sopenharmony_ci venus_helper_buffers_done(inst, q->type, VB2_BUF_STATE_QUEUED); 128562306a36Sopenharmony_ci if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) 128662306a36Sopenharmony_ci inst->streamon_out = 0; 128762306a36Sopenharmony_ci else 128862306a36Sopenharmony_ci inst->streamon_cap = 0; 128962306a36Sopenharmony_ci mutex_unlock(&inst->lock); 129062306a36Sopenharmony_ci return ret; 129162306a36Sopenharmony_ci} 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_cistatic void venc_vb2_buf_queue(struct vb2_buffer *vb) 129462306a36Sopenharmony_ci{ 129562306a36Sopenharmony_ci struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue); 129662306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci venc_pm_get_put(inst); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci mutex_lock(&inst->lock); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci if (inst->enc_state == VENUS_ENC_STATE_STOPPED) { 130362306a36Sopenharmony_ci vbuf->sequence = inst->sequence_cap++; 130462306a36Sopenharmony_ci vbuf->field = V4L2_FIELD_NONE; 130562306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, 0); 130662306a36Sopenharmony_ci v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); 130762306a36Sopenharmony_ci mutex_unlock(&inst->lock); 130862306a36Sopenharmony_ci return; 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci venus_helper_vb2_buf_queue(vb); 131262306a36Sopenharmony_ci mutex_unlock(&inst->lock); 131362306a36Sopenharmony_ci} 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_cistatic const struct vb2_ops venc_vb2_ops = { 131662306a36Sopenharmony_ci .queue_setup = venc_queue_setup, 131762306a36Sopenharmony_ci .buf_init = venc_buf_init, 131862306a36Sopenharmony_ci .buf_cleanup = venc_buf_cleanup, 131962306a36Sopenharmony_ci .buf_prepare = venus_helper_vb2_buf_prepare, 132062306a36Sopenharmony_ci .start_streaming = venc_start_streaming, 132162306a36Sopenharmony_ci .stop_streaming = venus_helper_vb2_stop_streaming, 132262306a36Sopenharmony_ci .buf_queue = venc_vb2_buf_queue, 132362306a36Sopenharmony_ci}; 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_cistatic void venc_buf_done(struct venus_inst *inst, unsigned int buf_type, 132662306a36Sopenharmony_ci u32 tag, u32 bytesused, u32 data_offset, u32 flags, 132762306a36Sopenharmony_ci u32 hfi_flags, u64 timestamp_us) 132862306a36Sopenharmony_ci{ 132962306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf; 133062306a36Sopenharmony_ci struct vb2_buffer *vb; 133162306a36Sopenharmony_ci unsigned int type; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci venc_pm_touch(inst); 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci if (buf_type == HFI_BUFFER_INPUT) 133662306a36Sopenharmony_ci type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 133762306a36Sopenharmony_ci else 133862306a36Sopenharmony_ci type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci vbuf = venus_helper_find_buf(inst, type, tag); 134162306a36Sopenharmony_ci if (!vbuf) 134262306a36Sopenharmony_ci return; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci vbuf->flags = flags; 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 134762306a36Sopenharmony_ci vb = &vbuf->vb2_buf; 134862306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, bytesused + data_offset); 134962306a36Sopenharmony_ci vb->planes[0].data_offset = data_offset; 135062306a36Sopenharmony_ci vb->timestamp = timestamp_us * NSEC_PER_USEC; 135162306a36Sopenharmony_ci vbuf->sequence = inst->sequence_cap++; 135262306a36Sopenharmony_ci if ((vbuf->flags & V4L2_BUF_FLAG_LAST) && 135362306a36Sopenharmony_ci inst->enc_state == VENUS_ENC_STATE_DRAIN) { 135462306a36Sopenharmony_ci inst->enc_state = VENUS_ENC_STATE_STOPPED; 135562306a36Sopenharmony_ci } 135662306a36Sopenharmony_ci } else { 135762306a36Sopenharmony_ci vbuf->sequence = inst->sequence_out++; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); 136162306a36Sopenharmony_ci} 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_cistatic void venc_event_notify(struct venus_inst *inst, u32 event, 136462306a36Sopenharmony_ci struct hfi_event_data *data) 136562306a36Sopenharmony_ci{ 136662306a36Sopenharmony_ci struct device *dev = inst->core->dev_enc; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci venc_pm_touch(inst); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci if (event == EVT_SESSION_ERROR) { 137162306a36Sopenharmony_ci inst->session_error = true; 137262306a36Sopenharmony_ci venus_helper_vb2_queue_error(inst); 137362306a36Sopenharmony_ci dev_err(dev, "enc: event session error %x\n", inst->error); 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci} 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_cistatic const struct hfi_inst_ops venc_hfi_ops = { 137862306a36Sopenharmony_ci .buf_done = venc_buf_done, 137962306a36Sopenharmony_ci .event_notify = venc_event_notify, 138062306a36Sopenharmony_ci}; 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_cistatic const struct v4l2_m2m_ops venc_m2m_ops = { 138362306a36Sopenharmony_ci .device_run = venus_helper_m2m_device_run, 138462306a36Sopenharmony_ci .job_abort = venus_helper_m2m_job_abort, 138562306a36Sopenharmony_ci}; 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_cistatic int m2m_queue_init(void *priv, struct vb2_queue *src_vq, 138862306a36Sopenharmony_ci struct vb2_queue *dst_vq) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci struct venus_inst *inst = priv; 139162306a36Sopenharmony_ci int ret; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; 139462306a36Sopenharmony_ci src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 139562306a36Sopenharmony_ci src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 139662306a36Sopenharmony_ci src_vq->ops = &venc_vb2_ops; 139762306a36Sopenharmony_ci src_vq->mem_ops = &vb2_dma_contig_memops; 139862306a36Sopenharmony_ci src_vq->drv_priv = inst; 139962306a36Sopenharmony_ci src_vq->buf_struct_size = sizeof(struct venus_buffer); 140062306a36Sopenharmony_ci src_vq->allow_zero_bytesused = 1; 140162306a36Sopenharmony_ci src_vq->min_buffers_needed = 1; 140262306a36Sopenharmony_ci src_vq->dev = inst->core->dev; 140362306a36Sopenharmony_ci src_vq->lock = &inst->ctx_q_lock; 140462306a36Sopenharmony_ci if (inst->core->res->hfi_version == HFI_VERSION_1XX) 140562306a36Sopenharmony_ci src_vq->bidirectional = 1; 140662306a36Sopenharmony_ci ret = vb2_queue_init(src_vq); 140762306a36Sopenharmony_ci if (ret) 140862306a36Sopenharmony_ci return ret; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; 141162306a36Sopenharmony_ci dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; 141262306a36Sopenharmony_ci dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; 141362306a36Sopenharmony_ci dst_vq->ops = &venc_vb2_ops; 141462306a36Sopenharmony_ci dst_vq->mem_ops = &vb2_dma_contig_memops; 141562306a36Sopenharmony_ci dst_vq->drv_priv = inst; 141662306a36Sopenharmony_ci dst_vq->buf_struct_size = sizeof(struct venus_buffer); 141762306a36Sopenharmony_ci dst_vq->allow_zero_bytesused = 1; 141862306a36Sopenharmony_ci dst_vq->min_buffers_needed = 1; 141962306a36Sopenharmony_ci dst_vq->dev = inst->core->dev; 142062306a36Sopenharmony_ci dst_vq->lock = &inst->ctx_q_lock; 142162306a36Sopenharmony_ci return vb2_queue_init(dst_vq); 142262306a36Sopenharmony_ci} 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_cistatic void venc_inst_init(struct venus_inst *inst) 142562306a36Sopenharmony_ci{ 142662306a36Sopenharmony_ci inst->fmt_cap = &venc_formats[VENUS_FMT_H264]; 142762306a36Sopenharmony_ci inst->fmt_out = &venc_formats[VENUS_FMT_NV12]; 142862306a36Sopenharmony_ci inst->width = 1280; 142962306a36Sopenharmony_ci inst->height = ALIGN(720, 32); 143062306a36Sopenharmony_ci inst->out_width = 1280; 143162306a36Sopenharmony_ci inst->out_height = 720; 143262306a36Sopenharmony_ci inst->fps = 15; 143362306a36Sopenharmony_ci inst->timeperframe.numerator = 1; 143462306a36Sopenharmony_ci inst->timeperframe.denominator = 15; 143562306a36Sopenharmony_ci inst->hfi_codec = HFI_VIDEO_CODEC_H264; 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic int venc_open(struct file *file) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci struct venus_core *core = video_drvdata(file); 144162306a36Sopenharmony_ci struct venus_inst *inst; 144262306a36Sopenharmony_ci int ret; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci inst = kzalloc(sizeof(*inst), GFP_KERNEL); 144562306a36Sopenharmony_ci if (!inst) 144662306a36Sopenharmony_ci return -ENOMEM; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci INIT_LIST_HEAD(&inst->dpbbufs); 144962306a36Sopenharmony_ci INIT_LIST_HEAD(&inst->registeredbufs); 145062306a36Sopenharmony_ci INIT_LIST_HEAD(&inst->internalbufs); 145162306a36Sopenharmony_ci INIT_LIST_HEAD(&inst->list); 145262306a36Sopenharmony_ci mutex_init(&inst->lock); 145362306a36Sopenharmony_ci mutex_init(&inst->ctx_q_lock); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci inst->core = core; 145662306a36Sopenharmony_ci inst->session_type = VIDC_SESSION_TYPE_ENC; 145762306a36Sopenharmony_ci inst->clk_data.core_id = VIDC_CORE_ID_DEFAULT; 145862306a36Sopenharmony_ci inst->core_acquired = false; 145962306a36Sopenharmony_ci inst->nonblock = file->f_flags & O_NONBLOCK; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci if (inst->enc_state == VENUS_ENC_STATE_DEINIT) 146262306a36Sopenharmony_ci inst->enc_state = VENUS_ENC_STATE_INIT; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci venus_helper_init_instance(inst); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci ret = venc_ctrl_init(inst); 146762306a36Sopenharmony_ci if (ret) 146862306a36Sopenharmony_ci goto err_free; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci ret = hfi_session_create(inst, &venc_hfi_ops); 147162306a36Sopenharmony_ci if (ret) 147262306a36Sopenharmony_ci goto err_ctrl_deinit; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci venc_inst_init(inst); 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci /* 147762306a36Sopenharmony_ci * create m2m device for every instance, the m2m context scheduling 147862306a36Sopenharmony_ci * is made by firmware side so we do not need to care about. 147962306a36Sopenharmony_ci */ 148062306a36Sopenharmony_ci inst->m2m_dev = v4l2_m2m_init(&venc_m2m_ops); 148162306a36Sopenharmony_ci if (IS_ERR(inst->m2m_dev)) { 148262306a36Sopenharmony_ci ret = PTR_ERR(inst->m2m_dev); 148362306a36Sopenharmony_ci goto err_session_destroy; 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci inst->m2m_ctx = v4l2_m2m_ctx_init(inst->m2m_dev, inst, m2m_queue_init); 148762306a36Sopenharmony_ci if (IS_ERR(inst->m2m_ctx)) { 148862306a36Sopenharmony_ci ret = PTR_ERR(inst->m2m_ctx); 148962306a36Sopenharmony_ci goto err_m2m_release; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci v4l2_fh_init(&inst->fh, core->vdev_enc); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci inst->fh.ctrl_handler = &inst->ctrl_handler; 149562306a36Sopenharmony_ci v4l2_fh_add(&inst->fh); 149662306a36Sopenharmony_ci inst->fh.m2m_ctx = inst->m2m_ctx; 149762306a36Sopenharmony_ci file->private_data = &inst->fh; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci return 0; 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_cierr_m2m_release: 150262306a36Sopenharmony_ci v4l2_m2m_release(inst->m2m_dev); 150362306a36Sopenharmony_cierr_session_destroy: 150462306a36Sopenharmony_ci hfi_session_destroy(inst); 150562306a36Sopenharmony_cierr_ctrl_deinit: 150662306a36Sopenharmony_ci venc_ctrl_deinit(inst); 150762306a36Sopenharmony_cierr_free: 150862306a36Sopenharmony_ci kfree(inst); 150962306a36Sopenharmony_ci return ret; 151062306a36Sopenharmony_ci} 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_cistatic int venc_close(struct file *file) 151362306a36Sopenharmony_ci{ 151462306a36Sopenharmony_ci struct venus_inst *inst = to_inst(file); 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci venc_pm_get(inst); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci v4l2_m2m_ctx_release(inst->m2m_ctx); 151962306a36Sopenharmony_ci v4l2_m2m_release(inst->m2m_dev); 152062306a36Sopenharmony_ci venc_ctrl_deinit(inst); 152162306a36Sopenharmony_ci hfi_session_destroy(inst); 152262306a36Sopenharmony_ci mutex_destroy(&inst->lock); 152362306a36Sopenharmony_ci mutex_destroy(&inst->ctx_q_lock); 152462306a36Sopenharmony_ci v4l2_fh_del(&inst->fh); 152562306a36Sopenharmony_ci v4l2_fh_exit(&inst->fh); 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci inst->enc_state = VENUS_ENC_STATE_DEINIT; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci venc_pm_put(inst, false); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci kfree(inst); 153262306a36Sopenharmony_ci return 0; 153362306a36Sopenharmony_ci} 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_cistatic const struct v4l2_file_operations venc_fops = { 153662306a36Sopenharmony_ci .owner = THIS_MODULE, 153762306a36Sopenharmony_ci .open = venc_open, 153862306a36Sopenharmony_ci .release = venc_close, 153962306a36Sopenharmony_ci .unlocked_ioctl = video_ioctl2, 154062306a36Sopenharmony_ci .poll = v4l2_m2m_fop_poll, 154162306a36Sopenharmony_ci .mmap = v4l2_m2m_fop_mmap, 154262306a36Sopenharmony_ci}; 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_cistatic int venc_probe(struct platform_device *pdev) 154562306a36Sopenharmony_ci{ 154662306a36Sopenharmony_ci struct device *dev = &pdev->dev; 154762306a36Sopenharmony_ci struct video_device *vdev; 154862306a36Sopenharmony_ci struct venus_core *core; 154962306a36Sopenharmony_ci int ret; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci if (!dev->parent) 155262306a36Sopenharmony_ci return -EPROBE_DEFER; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci core = dev_get_drvdata(dev->parent); 155562306a36Sopenharmony_ci if (!core) 155662306a36Sopenharmony_ci return -EPROBE_DEFER; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci platform_set_drvdata(pdev, core); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci if (core->pm_ops->venc_get) { 156162306a36Sopenharmony_ci ret = core->pm_ops->venc_get(dev); 156262306a36Sopenharmony_ci if (ret) 156362306a36Sopenharmony_ci return ret; 156462306a36Sopenharmony_ci } 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci vdev = video_device_alloc(); 156762306a36Sopenharmony_ci if (!vdev) 156862306a36Sopenharmony_ci return -ENOMEM; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci strscpy(vdev->name, "qcom-venus-encoder", sizeof(vdev->name)); 157162306a36Sopenharmony_ci vdev->release = video_device_release; 157262306a36Sopenharmony_ci vdev->fops = &venc_fops; 157362306a36Sopenharmony_ci vdev->ioctl_ops = &venc_ioctl_ops; 157462306a36Sopenharmony_ci vdev->vfl_dir = VFL_DIR_M2M; 157562306a36Sopenharmony_ci vdev->v4l2_dev = &core->v4l2_dev; 157662306a36Sopenharmony_ci vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); 157962306a36Sopenharmony_ci if (ret) 158062306a36Sopenharmony_ci goto err_vdev_release; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci core->vdev_enc = vdev; 158362306a36Sopenharmony_ci core->dev_enc = dev; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci video_set_drvdata(vdev, core); 158662306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, 2000); 158762306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 158862306a36Sopenharmony_ci pm_runtime_enable(dev); 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci return 0; 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_cierr_vdev_release: 159362306a36Sopenharmony_ci video_device_release(vdev); 159462306a36Sopenharmony_ci return ret; 159562306a36Sopenharmony_ci} 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_cistatic void venc_remove(struct platform_device *pdev) 159862306a36Sopenharmony_ci{ 159962306a36Sopenharmony_ci struct venus_core *core = dev_get_drvdata(pdev->dev.parent); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci video_unregister_device(core->vdev_enc); 160262306a36Sopenharmony_ci pm_runtime_disable(core->dev_enc); 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci if (core->pm_ops->venc_put) 160562306a36Sopenharmony_ci core->pm_ops->venc_put(core->dev_enc); 160662306a36Sopenharmony_ci} 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_cistatic __maybe_unused int venc_runtime_suspend(struct device *dev) 160962306a36Sopenharmony_ci{ 161062306a36Sopenharmony_ci struct venus_core *core = dev_get_drvdata(dev); 161162306a36Sopenharmony_ci const struct venus_pm_ops *pm_ops = core->pm_ops; 161262306a36Sopenharmony_ci int ret = 0; 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci if (pm_ops->venc_power) 161562306a36Sopenharmony_ci ret = pm_ops->venc_power(dev, POWER_OFF); 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci return ret; 161862306a36Sopenharmony_ci} 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cistatic __maybe_unused int venc_runtime_resume(struct device *dev) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci struct venus_core *core = dev_get_drvdata(dev); 162362306a36Sopenharmony_ci const struct venus_pm_ops *pm_ops = core->pm_ops; 162462306a36Sopenharmony_ci int ret = 0; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci if (pm_ops->venc_power) 162762306a36Sopenharmony_ci ret = pm_ops->venc_power(dev, POWER_ON); 162862306a36Sopenharmony_ci 162962306a36Sopenharmony_ci return ret; 163062306a36Sopenharmony_ci} 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_cistatic const struct dev_pm_ops venc_pm_ops = { 163362306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 163462306a36Sopenharmony_ci pm_runtime_force_resume) 163562306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(venc_runtime_suspend, venc_runtime_resume, NULL) 163662306a36Sopenharmony_ci}; 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_cistatic const struct of_device_id venc_dt_match[] = { 163962306a36Sopenharmony_ci { .compatible = "venus-encoder" }, 164062306a36Sopenharmony_ci { } 164162306a36Sopenharmony_ci}; 164262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, venc_dt_match); 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_cistatic struct platform_driver qcom_venus_enc_driver = { 164562306a36Sopenharmony_ci .probe = venc_probe, 164662306a36Sopenharmony_ci .remove_new = venc_remove, 164762306a36Sopenharmony_ci .driver = { 164862306a36Sopenharmony_ci .name = "qcom-venus-encoder", 164962306a36Sopenharmony_ci .of_match_table = venc_dt_match, 165062306a36Sopenharmony_ci .pm = &venc_pm_ops, 165162306a36Sopenharmony_ci }, 165262306a36Sopenharmony_ci}; 165362306a36Sopenharmony_cimodule_platform_driver(qcom_venus_enc_driver); 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ciMODULE_ALIAS("platform:qcom-venus-encoder"); 165662306a36Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm Venus video encoder driver"); 165762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1658