162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Hantro VPU codec driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2018 Collabora, Ltd. 662306a36Sopenharmony_ci * Copyright (C) 2018 Rockchip Electronics Co., Ltd. 762306a36Sopenharmony_ci * Alpha Lin <Alpha.Lin@rock-chips.com> 862306a36Sopenharmony_ci * Jeffy Chen <jeffy.chen@rock-chips.com> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright 2018 Google LLC. 1162306a36Sopenharmony_ci * Tomasz Figa <tfiga@chromium.org> 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Based on s5p-mfc driver by Samsung Electronics Co., Ltd. 1462306a36Sopenharmony_ci * Copyright (C) 2010-2011 Samsung Electronics Co., Ltd. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/interrupt.h> 1862306a36Sopenharmony_ci#include <linux/io.h> 1962306a36Sopenharmony_ci#include <linux/module.h> 2062306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2162306a36Sopenharmony_ci#include <linux/videodev2.h> 2262306a36Sopenharmony_ci#include <linux/workqueue.h> 2362306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 2462306a36Sopenharmony_ci#include <media/v4l2-event.h> 2562306a36Sopenharmony_ci#include <media/v4l2-mem2mem.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "hantro.h" 2862306a36Sopenharmony_ci#include "hantro_hw.h" 2962306a36Sopenharmony_ci#include "hantro_v4l2.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define HANTRO_DEFAULT_BIT_DEPTH 8 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic int hantro_set_fmt_out(struct hantro_ctx *ctx, 3462306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp, 3562306a36Sopenharmony_ci bool need_postproc); 3662306a36Sopenharmony_cistatic int hantro_set_fmt_cap(struct hantro_ctx *ctx, 3762306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic const struct hantro_fmt * 4062306a36Sopenharmony_cihantro_get_formats(const struct hantro_ctx *ctx, unsigned int *num_fmts, bool need_postproc) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci const struct hantro_fmt *formats; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci if (need_postproc) { 4562306a36Sopenharmony_ci *num_fmts = 0; 4662306a36Sopenharmony_ci return NULL; 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (ctx->is_encoder) { 5062306a36Sopenharmony_ci formats = ctx->dev->variant->enc_fmts; 5162306a36Sopenharmony_ci *num_fmts = ctx->dev->variant->num_enc_fmts; 5262306a36Sopenharmony_ci } else { 5362306a36Sopenharmony_ci formats = ctx->dev->variant->dec_fmts; 5462306a36Sopenharmony_ci *num_fmts = ctx->dev->variant->num_dec_fmts; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci return formats; 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic const struct hantro_fmt * 6162306a36Sopenharmony_cihantro_get_postproc_formats(const struct hantro_ctx *ctx, 6262306a36Sopenharmony_ci unsigned int *num_fmts) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct hantro_dev *vpu = ctx->dev; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (ctx->is_encoder || !vpu->variant->postproc_fmts) { 6762306a36Sopenharmony_ci *num_fmts = 0; 6862306a36Sopenharmony_ci return NULL; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci *num_fmts = ctx->dev->variant->num_postproc_fmts; 7262306a36Sopenharmony_ci return ctx->dev->variant->postproc_fmts; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ciint hantro_get_format_depth(u32 fourcc) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci switch (fourcc) { 7862306a36Sopenharmony_ci case V4L2_PIX_FMT_P010: 7962306a36Sopenharmony_ci case V4L2_PIX_FMT_P010_4L4: 8062306a36Sopenharmony_ci case V4L2_PIX_FMT_NV15_4L4: 8162306a36Sopenharmony_ci return 10; 8262306a36Sopenharmony_ci default: 8362306a36Sopenharmony_ci return 8; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic bool 8862306a36Sopenharmony_cihantro_check_depth_match(const struct hantro_fmt *fmt, int bit_depth) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci int fmt_depth; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (!fmt->match_depth && !fmt->postprocessed) 9362306a36Sopenharmony_ci return true; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* 0 means default depth, which is 8 */ 9662306a36Sopenharmony_ci if (!bit_depth) 9762306a36Sopenharmony_ci bit_depth = HANTRO_DEFAULT_BIT_DEPTH; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci fmt_depth = hantro_get_format_depth(fmt->fourcc); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* 10262306a36Sopenharmony_ci * Allow only downconversion for postproc formats for now. 10362306a36Sopenharmony_ci * It may be possible to relax that on some HW. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci if (!fmt->match_depth) 10662306a36Sopenharmony_ci return fmt_depth <= bit_depth; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci return fmt_depth == bit_depth; 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic const struct hantro_fmt * 11262306a36Sopenharmony_cihantro_find_format(const struct hantro_ctx *ctx, u32 fourcc) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci const struct hantro_fmt *formats; 11562306a36Sopenharmony_ci unsigned int i, num_fmts; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci formats = hantro_get_formats(ctx, &num_fmts, HANTRO_AUTO_POSTPROC); 11862306a36Sopenharmony_ci for (i = 0; i < num_fmts; i++) 11962306a36Sopenharmony_ci if (formats[i].fourcc == fourcc) 12062306a36Sopenharmony_ci return &formats[i]; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci formats = hantro_get_postproc_formats(ctx, &num_fmts); 12362306a36Sopenharmony_ci for (i = 0; i < num_fmts; i++) 12462306a36Sopenharmony_ci if (formats[i].fourcc == fourcc) 12562306a36Sopenharmony_ci return &formats[i]; 12662306a36Sopenharmony_ci return NULL; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ciconst struct hantro_fmt * 13062306a36Sopenharmony_cihantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream, 13162306a36Sopenharmony_ci int bit_depth, bool need_postproc) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci const struct hantro_fmt *formats; 13462306a36Sopenharmony_ci unsigned int i, num_fmts; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci formats = hantro_get_formats(ctx, &num_fmts, need_postproc); 13762306a36Sopenharmony_ci for (i = 0; i < num_fmts; i++) { 13862306a36Sopenharmony_ci if (bitstream == (formats[i].codec_mode != 13962306a36Sopenharmony_ci HANTRO_MODE_NONE) && 14062306a36Sopenharmony_ci hantro_check_depth_match(&formats[i], bit_depth)) 14162306a36Sopenharmony_ci return &formats[i]; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci formats = hantro_get_postproc_formats(ctx, &num_fmts); 14562306a36Sopenharmony_ci for (i = 0; i < num_fmts; i++) { 14662306a36Sopenharmony_ci if (bitstream == (formats[i].codec_mode != 14762306a36Sopenharmony_ci HANTRO_MODE_NONE) && 14862306a36Sopenharmony_ci hantro_check_depth_match(&formats[i], bit_depth)) 14962306a36Sopenharmony_ci return &formats[i]; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return NULL; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic int vidioc_querycap(struct file *file, void *priv, 15662306a36Sopenharmony_ci struct v4l2_capability *cap) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct hantro_dev *vpu = video_drvdata(file); 15962306a36Sopenharmony_ci struct video_device *vdev = video_devdata(file); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci strscpy(cap->driver, vpu->dev->driver->name, sizeof(cap->driver)); 16262306a36Sopenharmony_ci strscpy(cap->card, vdev->name, sizeof(cap->card)); 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int vidioc_enum_framesizes(struct file *file, void *priv, 16762306a36Sopenharmony_ci struct v4l2_frmsizeenum *fsize) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct hantro_ctx *ctx = fh_to_ctx(priv); 17062306a36Sopenharmony_ci const struct hantro_fmt *fmt; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci fmt = hantro_find_format(ctx, fsize->pixel_format); 17362306a36Sopenharmony_ci if (!fmt) { 17462306a36Sopenharmony_ci vpu_debug(0, "unsupported bitstream format (%08x)\n", 17562306a36Sopenharmony_ci fsize->pixel_format); 17662306a36Sopenharmony_ci return -EINVAL; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* For non-coded formats check if postprocessing scaling is possible */ 18062306a36Sopenharmony_ci if (fmt->codec_mode == HANTRO_MODE_NONE) { 18162306a36Sopenharmony_ci if (hantro_needs_postproc(ctx, fmt)) 18262306a36Sopenharmony_ci return hanto_postproc_enum_framesizes(ctx, fsize); 18362306a36Sopenharmony_ci else 18462306a36Sopenharmony_ci return -ENOTTY; 18562306a36Sopenharmony_ci } else if (fsize->index != 0) { 18662306a36Sopenharmony_ci vpu_debug(0, "invalid frame size index (expected 0, got %d)\n", 18762306a36Sopenharmony_ci fsize->index); 18862306a36Sopenharmony_ci return -EINVAL; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; 19262306a36Sopenharmony_ci fsize->stepwise = fmt->frmsize; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistatic int vidioc_enum_fmt(struct file *file, void *priv, 19862306a36Sopenharmony_ci struct v4l2_fmtdesc *f, bool capture) 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct hantro_ctx *ctx = fh_to_ctx(priv); 20262306a36Sopenharmony_ci const struct hantro_fmt *fmt, *formats; 20362306a36Sopenharmony_ci unsigned int num_fmts, i, j = 0; 20462306a36Sopenharmony_ci bool skip_mode_none; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* 20762306a36Sopenharmony_ci * When dealing with an encoder: 20862306a36Sopenharmony_ci * - on the capture side we want to filter out all MODE_NONE formats. 20962306a36Sopenharmony_ci * - on the output side we want to filter out all formats that are 21062306a36Sopenharmony_ci * not MODE_NONE. 21162306a36Sopenharmony_ci * When dealing with a decoder: 21262306a36Sopenharmony_ci * - on the capture side we want to filter out all formats that are 21362306a36Sopenharmony_ci * not MODE_NONE. 21462306a36Sopenharmony_ci * - on the output side we want to filter out all MODE_NONE formats. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci skip_mode_none = capture == ctx->is_encoder; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci formats = hantro_get_formats(ctx, &num_fmts, HANTRO_AUTO_POSTPROC); 21962306a36Sopenharmony_ci for (i = 0; i < num_fmts; i++) { 22062306a36Sopenharmony_ci bool mode_none = formats[i].codec_mode == HANTRO_MODE_NONE; 22162306a36Sopenharmony_ci fmt = &formats[i]; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (skip_mode_none == mode_none) 22462306a36Sopenharmony_ci continue; 22562306a36Sopenharmony_ci if (!hantro_check_depth_match(fmt, ctx->bit_depth)) 22662306a36Sopenharmony_ci continue; 22762306a36Sopenharmony_ci if (j == f->index) { 22862306a36Sopenharmony_ci f->pixelformat = fmt->fourcc; 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci ++j; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci /* 23562306a36Sopenharmony_ci * Enumerate post-processed formats. As per the specification, 23662306a36Sopenharmony_ci * we enumerated these formats after natively decoded formats 23762306a36Sopenharmony_ci * as a hint for applications on what's the preferred fomat. 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci if (!capture) 24062306a36Sopenharmony_ci return -EINVAL; 24162306a36Sopenharmony_ci formats = hantro_get_postproc_formats(ctx, &num_fmts); 24262306a36Sopenharmony_ci for (i = 0; i < num_fmts; i++) { 24362306a36Sopenharmony_ci fmt = &formats[i]; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (!hantro_check_depth_match(fmt, ctx->bit_depth)) 24662306a36Sopenharmony_ci continue; 24762306a36Sopenharmony_ci if (j == f->index) { 24862306a36Sopenharmony_ci f->pixelformat = fmt->fourcc; 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci ++j; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci return -EINVAL; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, 25862306a36Sopenharmony_ci struct v4l2_fmtdesc *f) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci return vidioc_enum_fmt(file, priv, f, true); 26162306a36Sopenharmony_ci} 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_cistatic int vidioc_enum_fmt_vid_out(struct file *file, void *priv, 26462306a36Sopenharmony_ci struct v4l2_fmtdesc *f) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci return vidioc_enum_fmt(file, priv, f, false); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic int vidioc_g_fmt_out_mplane(struct file *file, void *priv, 27062306a36Sopenharmony_ci struct v4l2_format *f) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; 27362306a36Sopenharmony_ci struct hantro_ctx *ctx = fh_to_ctx(priv); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci vpu_debug(4, "f->type = %d\n", f->type); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci *pix_mp = ctx->src_fmt; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return 0; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic int vidioc_g_fmt_cap_mplane(struct file *file, void *priv, 28362306a36Sopenharmony_ci struct v4l2_format *f) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; 28662306a36Sopenharmony_ci struct hantro_ctx *ctx = fh_to_ctx(priv); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci vpu_debug(4, "f->type = %d\n", f->type); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci *pix_mp = ctx->dst_fmt; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic int hantro_try_fmt(const struct hantro_ctx *ctx, 29662306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp, 29762306a36Sopenharmony_ci enum v4l2_buf_type type) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci const struct hantro_fmt *fmt; 30062306a36Sopenharmony_ci const struct hantro_fmt *vpu_fmt; 30162306a36Sopenharmony_ci bool capture = V4L2_TYPE_IS_CAPTURE(type); 30262306a36Sopenharmony_ci bool coded; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci coded = capture == ctx->is_encoder; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci vpu_debug(4, "trying format %c%c%c%c\n", 30762306a36Sopenharmony_ci (pix_mp->pixelformat & 0x7f), 30862306a36Sopenharmony_ci (pix_mp->pixelformat >> 8) & 0x7f, 30962306a36Sopenharmony_ci (pix_mp->pixelformat >> 16) & 0x7f, 31062306a36Sopenharmony_ci (pix_mp->pixelformat >> 24) & 0x7f); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci fmt = hantro_find_format(ctx, pix_mp->pixelformat); 31362306a36Sopenharmony_ci if (!fmt) { 31462306a36Sopenharmony_ci fmt = hantro_get_default_fmt(ctx, coded, HANTRO_DEFAULT_BIT_DEPTH, HANTRO_AUTO_POSTPROC); 31562306a36Sopenharmony_ci pix_mp->pixelformat = fmt->fourcc; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (coded) { 31962306a36Sopenharmony_ci pix_mp->num_planes = 1; 32062306a36Sopenharmony_ci vpu_fmt = fmt; 32162306a36Sopenharmony_ci } else if (ctx->is_encoder) { 32262306a36Sopenharmony_ci vpu_fmt = hantro_find_format(ctx, ctx->dst_fmt.pixelformat); 32362306a36Sopenharmony_ci } else { 32462306a36Sopenharmony_ci /* 32562306a36Sopenharmony_ci * Width/height on the CAPTURE end of a decoder are ignored and 32662306a36Sopenharmony_ci * replaced by the OUTPUT ones. 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_ci pix_mp->width = ctx->src_fmt.width; 32962306a36Sopenharmony_ci pix_mp->height = ctx->src_fmt.height; 33062306a36Sopenharmony_ci vpu_fmt = fmt; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci pix_mp->field = V4L2_FIELD_NONE; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci v4l2_apply_frmsize_constraints(&pix_mp->width, &pix_mp->height, 33662306a36Sopenharmony_ci &vpu_fmt->frmsize); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (!coded) { 33962306a36Sopenharmony_ci /* Fill remaining fields */ 34062306a36Sopenharmony_ci v4l2_fill_pixfmt_mp(pix_mp, fmt->fourcc, pix_mp->width, 34162306a36Sopenharmony_ci pix_mp->height); 34262306a36Sopenharmony_ci if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE && 34362306a36Sopenharmony_ci !hantro_needs_postproc(ctx, fmt)) 34462306a36Sopenharmony_ci pix_mp->plane_fmt[0].sizeimage += 34562306a36Sopenharmony_ci hantro_h264_mv_size(pix_mp->width, 34662306a36Sopenharmony_ci pix_mp->height); 34762306a36Sopenharmony_ci else if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_VP9_FRAME && 34862306a36Sopenharmony_ci !hantro_needs_postproc(ctx, fmt)) 34962306a36Sopenharmony_ci pix_mp->plane_fmt[0].sizeimage += 35062306a36Sopenharmony_ci hantro_vp9_mv_size(pix_mp->width, 35162306a36Sopenharmony_ci pix_mp->height); 35262306a36Sopenharmony_ci else if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_HEVC_SLICE && 35362306a36Sopenharmony_ci !hantro_needs_postproc(ctx, fmt)) 35462306a36Sopenharmony_ci pix_mp->plane_fmt[0].sizeimage += 35562306a36Sopenharmony_ci hantro_hevc_mv_size(pix_mp->width, 35662306a36Sopenharmony_ci pix_mp->height); 35762306a36Sopenharmony_ci else if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_AV1_FRAME && 35862306a36Sopenharmony_ci !hantro_needs_postproc(ctx, fmt)) 35962306a36Sopenharmony_ci pix_mp->plane_fmt[0].sizeimage += 36062306a36Sopenharmony_ci hantro_av1_mv_size(pix_mp->width, 36162306a36Sopenharmony_ci pix_mp->height); 36262306a36Sopenharmony_ci } else if (!pix_mp->plane_fmt[0].sizeimage) { 36362306a36Sopenharmony_ci /* 36462306a36Sopenharmony_ci * For coded formats the application can specify 36562306a36Sopenharmony_ci * sizeimage. If the application passes a zero sizeimage, 36662306a36Sopenharmony_ci * let's default to the maximum frame size. 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci pix_mp->plane_fmt[0].sizeimage = fmt->header_size + 36962306a36Sopenharmony_ci pix_mp->width * pix_mp->height * fmt->max_depth; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic int vidioc_try_fmt_cap_mplane(struct file *file, void *priv, 37662306a36Sopenharmony_ci struct v4l2_format *f) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci return hantro_try_fmt(fh_to_ctx(priv), &f->fmt.pix_mp, f->type); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int vidioc_try_fmt_out_mplane(struct file *file, void *priv, 38262306a36Sopenharmony_ci struct v4l2_format *f) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci return hantro_try_fmt(fh_to_ctx(priv), &f->fmt.pix_mp, f->type); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic void 38862306a36Sopenharmony_cihantro_reset_fmt(struct v4l2_pix_format_mplane *fmt, 38962306a36Sopenharmony_ci const struct hantro_fmt *vpu_fmt) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci memset(fmt, 0, sizeof(*fmt)); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci fmt->pixelformat = vpu_fmt->fourcc; 39462306a36Sopenharmony_ci fmt->field = V4L2_FIELD_NONE; 39562306a36Sopenharmony_ci fmt->colorspace = V4L2_COLORSPACE_JPEG; 39662306a36Sopenharmony_ci fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; 39762306a36Sopenharmony_ci fmt->quantization = V4L2_QUANTIZATION_DEFAULT; 39862306a36Sopenharmony_ci fmt->xfer_func = V4L2_XFER_FUNC_DEFAULT; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic void 40262306a36Sopenharmony_cihantro_reset_encoded_fmt(struct hantro_ctx *ctx) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci const struct hantro_fmt *vpu_fmt; 40562306a36Sopenharmony_ci struct v4l2_pix_format_mplane fmt; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci vpu_fmt = hantro_get_default_fmt(ctx, true, HANTRO_DEFAULT_BIT_DEPTH, HANTRO_AUTO_POSTPROC); 40862306a36Sopenharmony_ci if (!vpu_fmt) 40962306a36Sopenharmony_ci return; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci hantro_reset_fmt(&fmt, vpu_fmt); 41262306a36Sopenharmony_ci fmt.width = vpu_fmt->frmsize.min_width; 41362306a36Sopenharmony_ci fmt.height = vpu_fmt->frmsize.min_height; 41462306a36Sopenharmony_ci if (ctx->is_encoder) 41562306a36Sopenharmony_ci hantro_set_fmt_cap(ctx, &fmt); 41662306a36Sopenharmony_ci else 41762306a36Sopenharmony_ci hantro_set_fmt_out(ctx, &fmt, HANTRO_AUTO_POSTPROC); 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ciint 42162306a36Sopenharmony_cihantro_reset_raw_fmt(struct hantro_ctx *ctx, int bit_depth, bool need_postproc) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci const struct hantro_fmt *raw_vpu_fmt; 42462306a36Sopenharmony_ci struct v4l2_pix_format_mplane raw_fmt, *encoded_fmt; 42562306a36Sopenharmony_ci int ret; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci raw_vpu_fmt = hantro_get_default_fmt(ctx, false, bit_depth, need_postproc); 42862306a36Sopenharmony_ci if (!raw_vpu_fmt) 42962306a36Sopenharmony_ci return -EINVAL; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (ctx->is_encoder) { 43262306a36Sopenharmony_ci encoded_fmt = &ctx->dst_fmt; 43362306a36Sopenharmony_ci ctx->vpu_src_fmt = raw_vpu_fmt; 43462306a36Sopenharmony_ci } else { 43562306a36Sopenharmony_ci encoded_fmt = &ctx->src_fmt; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci hantro_reset_fmt(&raw_fmt, raw_vpu_fmt); 43962306a36Sopenharmony_ci raw_fmt.width = encoded_fmt->width; 44062306a36Sopenharmony_ci raw_fmt.height = encoded_fmt->height; 44162306a36Sopenharmony_ci if (ctx->is_encoder) 44262306a36Sopenharmony_ci ret = hantro_set_fmt_out(ctx, &raw_fmt, need_postproc); 44362306a36Sopenharmony_ci else 44462306a36Sopenharmony_ci ret = hantro_set_fmt_cap(ctx, &raw_fmt); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (!ret) { 44762306a36Sopenharmony_ci ctx->bit_depth = bit_depth; 44862306a36Sopenharmony_ci ctx->need_postproc = need_postproc; 44962306a36Sopenharmony_ci } 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci return ret; 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_civoid hantro_reset_fmts(struct hantro_ctx *ctx) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci hantro_reset_encoded_fmt(ctx); 45762306a36Sopenharmony_ci hantro_reset_raw_fmt(ctx, HANTRO_DEFAULT_BIT_DEPTH, HANTRO_AUTO_POSTPROC); 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_cistatic void 46162306a36Sopenharmony_cihantro_update_requires_request(struct hantro_ctx *ctx, u32 fourcc) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci switch (fourcc) { 46462306a36Sopenharmony_ci case V4L2_PIX_FMT_JPEG: 46562306a36Sopenharmony_ci ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = false; 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci case V4L2_PIX_FMT_MPEG2_SLICE: 46862306a36Sopenharmony_ci case V4L2_PIX_FMT_VP8_FRAME: 46962306a36Sopenharmony_ci case V4L2_PIX_FMT_H264_SLICE: 47062306a36Sopenharmony_ci case V4L2_PIX_FMT_HEVC_SLICE: 47162306a36Sopenharmony_ci case V4L2_PIX_FMT_VP9_FRAME: 47262306a36Sopenharmony_ci ctx->fh.m2m_ctx->out_q_ctx.q.requires_requests = true; 47362306a36Sopenharmony_ci break; 47462306a36Sopenharmony_ci default: 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_cistatic void 48062306a36Sopenharmony_cihantro_update_requires_hold_capture_buf(struct hantro_ctx *ctx, u32 fourcc) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct vb2_queue *vq; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 48562306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci switch (fourcc) { 48862306a36Sopenharmony_ci case V4L2_PIX_FMT_JPEG: 48962306a36Sopenharmony_ci case V4L2_PIX_FMT_MPEG2_SLICE: 49062306a36Sopenharmony_ci case V4L2_PIX_FMT_VP8_FRAME: 49162306a36Sopenharmony_ci case V4L2_PIX_FMT_HEVC_SLICE: 49262306a36Sopenharmony_ci case V4L2_PIX_FMT_VP9_FRAME: 49362306a36Sopenharmony_ci vq->subsystem_flags &= ~(VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF); 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci case V4L2_PIX_FMT_H264_SLICE: 49662306a36Sopenharmony_ci vq->subsystem_flags |= VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF; 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci default: 49962306a36Sopenharmony_ci break; 50062306a36Sopenharmony_ci } 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic int hantro_set_fmt_out(struct hantro_ctx *ctx, 50462306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp, 50562306a36Sopenharmony_ci bool need_postproc) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct vb2_queue *vq; 50862306a36Sopenharmony_ci int ret; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 51162306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 51262306a36Sopenharmony_ci ret = hantro_try_fmt(ctx, pix_mp, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 51362306a36Sopenharmony_ci if (ret) 51462306a36Sopenharmony_ci return ret; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (!ctx->is_encoder) { 51762306a36Sopenharmony_ci struct vb2_queue *peer_vq; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* 52062306a36Sopenharmony_ci * In order to support dynamic resolution change, 52162306a36Sopenharmony_ci * the decoder admits a resolution change, as long 52262306a36Sopenharmony_ci * as the pixelformat remains. Can't be done if streaming. 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_ci if (vb2_is_streaming(vq) || (vb2_is_busy(vq) && 52562306a36Sopenharmony_ci pix_mp->pixelformat != ctx->src_fmt.pixelformat)) 52662306a36Sopenharmony_ci return -EBUSY; 52762306a36Sopenharmony_ci /* 52862306a36Sopenharmony_ci * Since format change on the OUTPUT queue will reset 52962306a36Sopenharmony_ci * the CAPTURE queue, we can't allow doing so 53062306a36Sopenharmony_ci * when the CAPTURE queue has buffers allocated. 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_ci peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 53362306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 53462306a36Sopenharmony_ci if (vb2_is_busy(peer_vq)) 53562306a36Sopenharmony_ci return -EBUSY; 53662306a36Sopenharmony_ci } else { 53762306a36Sopenharmony_ci /* 53862306a36Sopenharmony_ci * The encoder doesn't admit a format change if 53962306a36Sopenharmony_ci * there are OUTPUT buffers allocated. 54062306a36Sopenharmony_ci */ 54162306a36Sopenharmony_ci if (vb2_is_busy(vq)) 54262306a36Sopenharmony_ci return -EBUSY; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci ctx->vpu_src_fmt = hantro_find_format(ctx, pix_mp->pixelformat); 54662306a36Sopenharmony_ci ctx->src_fmt = *pix_mp; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci /* 54962306a36Sopenharmony_ci * Current raw format might have become invalid with newly 55062306a36Sopenharmony_ci * selected codec, so reset it to default just to be safe and 55162306a36Sopenharmony_ci * keep internal driver state sane. User is mandated to set 55262306a36Sopenharmony_ci * the raw format again after we return, so we don't need 55362306a36Sopenharmony_ci * anything smarter. 55462306a36Sopenharmony_ci * Note that hantro_reset_raw_fmt() also propagates size 55562306a36Sopenharmony_ci * changes to the raw format. 55662306a36Sopenharmony_ci */ 55762306a36Sopenharmony_ci if (!ctx->is_encoder) 55862306a36Sopenharmony_ci hantro_reset_raw_fmt(ctx, 55962306a36Sopenharmony_ci hantro_get_format_depth(pix_mp->pixelformat), 56062306a36Sopenharmony_ci need_postproc); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* Colorimetry information are always propagated. */ 56362306a36Sopenharmony_ci ctx->dst_fmt.colorspace = pix_mp->colorspace; 56462306a36Sopenharmony_ci ctx->dst_fmt.ycbcr_enc = pix_mp->ycbcr_enc; 56562306a36Sopenharmony_ci ctx->dst_fmt.xfer_func = pix_mp->xfer_func; 56662306a36Sopenharmony_ci ctx->dst_fmt.quantization = pix_mp->quantization; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci hantro_update_requires_request(ctx, pix_mp->pixelformat); 56962306a36Sopenharmony_ci hantro_update_requires_hold_capture_buf(ctx, pix_mp->pixelformat); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci vpu_debug(0, "OUTPUT codec mode: %d\n", ctx->vpu_src_fmt->codec_mode); 57262306a36Sopenharmony_ci vpu_debug(0, "fmt - w: %d, h: %d\n", 57362306a36Sopenharmony_ci pix_mp->width, pix_mp->height); 57462306a36Sopenharmony_ci return 0; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int hantro_set_fmt_cap(struct hantro_ctx *ctx, 57862306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_mp) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci struct vb2_queue *vq; 58162306a36Sopenharmony_ci int ret; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* Change not allowed if queue is busy. */ 58462306a36Sopenharmony_ci vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 58562306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 58662306a36Sopenharmony_ci if (vb2_is_busy(vq)) 58762306a36Sopenharmony_ci return -EBUSY; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (ctx->is_encoder) { 59062306a36Sopenharmony_ci struct vb2_queue *peer_vq; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* 59362306a36Sopenharmony_ci * Since format change on the CAPTURE queue will reset 59462306a36Sopenharmony_ci * the OUTPUT queue, we can't allow doing so 59562306a36Sopenharmony_ci * when the OUTPUT queue has buffers allocated. 59662306a36Sopenharmony_ci */ 59762306a36Sopenharmony_ci peer_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, 59862306a36Sopenharmony_ci V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 59962306a36Sopenharmony_ci if (vb2_is_busy(peer_vq) && 60062306a36Sopenharmony_ci (pix_mp->pixelformat != ctx->dst_fmt.pixelformat || 60162306a36Sopenharmony_ci pix_mp->height != ctx->dst_fmt.height || 60262306a36Sopenharmony_ci pix_mp->width != ctx->dst_fmt.width)) 60362306a36Sopenharmony_ci return -EBUSY; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci ret = hantro_try_fmt(ctx, pix_mp, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); 60762306a36Sopenharmony_ci if (ret) 60862306a36Sopenharmony_ci return ret; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci ctx->vpu_dst_fmt = hantro_find_format(ctx, pix_mp->pixelformat); 61162306a36Sopenharmony_ci ctx->dst_fmt = *pix_mp; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* 61462306a36Sopenharmony_ci * Current raw format might have become invalid with newly 61562306a36Sopenharmony_ci * selected codec, so reset it to default just to be safe and 61662306a36Sopenharmony_ci * keep internal driver state sane. User is mandated to set 61762306a36Sopenharmony_ci * the raw format again after we return, so we don't need 61862306a36Sopenharmony_ci * anything smarter. 61962306a36Sopenharmony_ci * Note that hantro_reset_raw_fmt() also propagates size 62062306a36Sopenharmony_ci * changes to the raw format. 62162306a36Sopenharmony_ci */ 62262306a36Sopenharmony_ci if (ctx->is_encoder) 62362306a36Sopenharmony_ci hantro_reset_raw_fmt(ctx, HANTRO_DEFAULT_BIT_DEPTH, HANTRO_AUTO_POSTPROC); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci /* Colorimetry information are always propagated. */ 62662306a36Sopenharmony_ci ctx->src_fmt.colorspace = pix_mp->colorspace; 62762306a36Sopenharmony_ci ctx->src_fmt.ycbcr_enc = pix_mp->ycbcr_enc; 62862306a36Sopenharmony_ci ctx->src_fmt.xfer_func = pix_mp->xfer_func; 62962306a36Sopenharmony_ci ctx->src_fmt.quantization = pix_mp->quantization; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci vpu_debug(0, "CAPTURE codec mode: %d\n", ctx->vpu_dst_fmt->codec_mode); 63262306a36Sopenharmony_ci vpu_debug(0, "fmt - w: %d, h: %d\n", 63362306a36Sopenharmony_ci pix_mp->width, pix_mp->height); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci hantro_update_requires_request(ctx, pix_mp->pixelformat); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic int 64162306a36Sopenharmony_cividioc_s_fmt_out_mplane(struct file *file, void *priv, struct v4l2_format *f) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci return hantro_set_fmt_out(fh_to_ctx(priv), &f->fmt.pix_mp, HANTRO_AUTO_POSTPROC); 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic int 64762306a36Sopenharmony_cividioc_s_fmt_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) 64862306a36Sopenharmony_ci{ 64962306a36Sopenharmony_ci return hantro_set_fmt_cap(fh_to_ctx(priv), &f->fmt.pix_mp); 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic int vidioc_g_selection(struct file *file, void *priv, 65362306a36Sopenharmony_ci struct v4l2_selection *sel) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct hantro_ctx *ctx = fh_to_ctx(priv); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* Crop only supported on source. */ 65862306a36Sopenharmony_ci if (!ctx->is_encoder || 65962306a36Sopenharmony_ci sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 66062306a36Sopenharmony_ci return -EINVAL; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci switch (sel->target) { 66362306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP_DEFAULT: 66462306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP_BOUNDS: 66562306a36Sopenharmony_ci sel->r.top = 0; 66662306a36Sopenharmony_ci sel->r.left = 0; 66762306a36Sopenharmony_ci sel->r.width = ctx->src_fmt.width; 66862306a36Sopenharmony_ci sel->r.height = ctx->src_fmt.height; 66962306a36Sopenharmony_ci break; 67062306a36Sopenharmony_ci case V4L2_SEL_TGT_CROP: 67162306a36Sopenharmony_ci sel->r.top = 0; 67262306a36Sopenharmony_ci sel->r.left = 0; 67362306a36Sopenharmony_ci sel->r.width = ctx->dst_fmt.width; 67462306a36Sopenharmony_ci sel->r.height = ctx->dst_fmt.height; 67562306a36Sopenharmony_ci break; 67662306a36Sopenharmony_ci default: 67762306a36Sopenharmony_ci return -EINVAL; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci return 0; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic int vidioc_s_selection(struct file *file, void *priv, 68462306a36Sopenharmony_ci struct v4l2_selection *sel) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct hantro_ctx *ctx = fh_to_ctx(priv); 68762306a36Sopenharmony_ci struct v4l2_rect *rect = &sel->r; 68862306a36Sopenharmony_ci struct vb2_queue *vq; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* Crop only supported on source. */ 69162306a36Sopenharmony_ci if (!ctx->is_encoder || 69262306a36Sopenharmony_ci sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) 69362306a36Sopenharmony_ci return -EINVAL; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* Change not allowed if the queue is streaming. */ 69662306a36Sopenharmony_ci vq = v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx); 69762306a36Sopenharmony_ci if (vb2_is_streaming(vq)) 69862306a36Sopenharmony_ci return -EBUSY; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if (sel->target != V4L2_SEL_TGT_CROP) 70162306a36Sopenharmony_ci return -EINVAL; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci /* 70462306a36Sopenharmony_ci * We do not support offsets, and we can crop only inside 70562306a36Sopenharmony_ci * right-most or bottom-most macroblocks. 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci if (rect->left != 0 || rect->top != 0 || 70862306a36Sopenharmony_ci round_up(rect->width, MB_DIM) != ctx->src_fmt.width || 70962306a36Sopenharmony_ci round_up(rect->height, MB_DIM) != ctx->src_fmt.height) { 71062306a36Sopenharmony_ci /* Default to full frame for incorrect settings. */ 71162306a36Sopenharmony_ci rect->left = 0; 71262306a36Sopenharmony_ci rect->top = 0; 71362306a36Sopenharmony_ci rect->width = ctx->src_fmt.width; 71462306a36Sopenharmony_ci rect->height = ctx->src_fmt.height; 71562306a36Sopenharmony_ci } else { 71662306a36Sopenharmony_ci /* We support widths aligned to 4 pixels and arbitrary heights. */ 71762306a36Sopenharmony_ci rect->width = round_up(rect->width, 4); 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci ctx->dst_fmt.width = rect->width; 72162306a36Sopenharmony_ci ctx->dst_fmt.height = rect->height; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic const struct v4l2_event hantro_eos_event = { 72762306a36Sopenharmony_ci .type = V4L2_EVENT_EOS 72862306a36Sopenharmony_ci}; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_cistatic int vidioc_encoder_cmd(struct file *file, void *priv, 73162306a36Sopenharmony_ci struct v4l2_encoder_cmd *ec) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci struct hantro_ctx *ctx = fh_to_ctx(priv); 73462306a36Sopenharmony_ci int ret; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci ret = v4l2_m2m_ioctl_try_encoder_cmd(file, priv, ec); 73762306a36Sopenharmony_ci if (ret < 0) 73862306a36Sopenharmony_ci return ret; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci if (!vb2_is_streaming(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)) || 74162306a36Sopenharmony_ci !vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx))) 74262306a36Sopenharmony_ci return 0; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci ret = v4l2_m2m_ioctl_encoder_cmd(file, priv, ec); 74562306a36Sopenharmony_ci if (ret < 0) 74662306a36Sopenharmony_ci return ret; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (ec->cmd == V4L2_ENC_CMD_STOP && 74962306a36Sopenharmony_ci v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) 75062306a36Sopenharmony_ci v4l2_event_queue_fh(&ctx->fh, &hantro_eos_event); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (ec->cmd == V4L2_ENC_CMD_START) 75362306a36Sopenharmony_ci vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci return 0; 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ciconst struct v4l2_ioctl_ops hantro_ioctl_ops = { 75962306a36Sopenharmony_ci .vidioc_querycap = vidioc_querycap, 76062306a36Sopenharmony_ci .vidioc_enum_framesizes = vidioc_enum_framesizes, 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_cap_mplane, 76362306a36Sopenharmony_ci .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_out_mplane, 76462306a36Sopenharmony_ci .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_out_mplane, 76562306a36Sopenharmony_ci .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap_mplane, 76662306a36Sopenharmony_ci .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_out_mplane, 76762306a36Sopenharmony_ci .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_cap_mplane, 76862306a36Sopenharmony_ci .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, 76962306a36Sopenharmony_ci .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, 77262306a36Sopenharmony_ci .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, 77362306a36Sopenharmony_ci .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, 77462306a36Sopenharmony_ci .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, 77562306a36Sopenharmony_ci .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, 77662306a36Sopenharmony_ci .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, 77762306a36Sopenharmony_ci .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, 78062306a36Sopenharmony_ci .vidioc_unsubscribe_event = v4l2_event_unsubscribe, 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci .vidioc_streamon = v4l2_m2m_ioctl_streamon, 78362306a36Sopenharmony_ci .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci .vidioc_g_selection = vidioc_g_selection, 78662306a36Sopenharmony_ci .vidioc_s_selection = vidioc_s_selection, 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci .vidioc_decoder_cmd = v4l2_m2m_ioctl_stateless_decoder_cmd, 78962306a36Sopenharmony_ci .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_stateless_try_decoder_cmd, 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, 79262306a36Sopenharmony_ci .vidioc_encoder_cmd = vidioc_encoder_cmd, 79362306a36Sopenharmony_ci}; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic int 79662306a36Sopenharmony_cihantro_queue_setup(struct vb2_queue *vq, unsigned int *num_buffers, 79762306a36Sopenharmony_ci unsigned int *num_planes, unsigned int sizes[], 79862306a36Sopenharmony_ci struct device *alloc_devs[]) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct hantro_ctx *ctx = vb2_get_drv_priv(vq); 80162306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pixfmt; 80262306a36Sopenharmony_ci int i; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci switch (vq->type) { 80562306a36Sopenharmony_ci case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: 80662306a36Sopenharmony_ci pixfmt = &ctx->dst_fmt; 80762306a36Sopenharmony_ci break; 80862306a36Sopenharmony_ci case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: 80962306a36Sopenharmony_ci pixfmt = &ctx->src_fmt; 81062306a36Sopenharmony_ci break; 81162306a36Sopenharmony_ci default: 81262306a36Sopenharmony_ci vpu_err("invalid queue type: %d\n", vq->type); 81362306a36Sopenharmony_ci return -EINVAL; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (*num_planes) { 81762306a36Sopenharmony_ci if (*num_planes != pixfmt->num_planes) 81862306a36Sopenharmony_ci return -EINVAL; 81962306a36Sopenharmony_ci for (i = 0; i < pixfmt->num_planes; ++i) 82062306a36Sopenharmony_ci if (sizes[i] < pixfmt->plane_fmt[i].sizeimage) 82162306a36Sopenharmony_ci return -EINVAL; 82262306a36Sopenharmony_ci return 0; 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci *num_planes = pixfmt->num_planes; 82662306a36Sopenharmony_ci for (i = 0; i < pixfmt->num_planes; ++i) 82762306a36Sopenharmony_ci sizes[i] = pixfmt->plane_fmt[i].sizeimage; 82862306a36Sopenharmony_ci return 0; 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic int 83262306a36Sopenharmony_cihantro_buf_plane_check(struct vb2_buffer *vb, 83362306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pixfmt) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci unsigned int sz; 83662306a36Sopenharmony_ci int i; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci for (i = 0; i < pixfmt->num_planes; ++i) { 83962306a36Sopenharmony_ci sz = pixfmt->plane_fmt[i].sizeimage; 84062306a36Sopenharmony_ci vpu_debug(4, "plane %d size: %ld, sizeimage: %u\n", 84162306a36Sopenharmony_ci i, vb2_plane_size(vb, i), sz); 84262306a36Sopenharmony_ci if (vb2_plane_size(vb, i) < sz) { 84362306a36Sopenharmony_ci vpu_err("plane %d is too small for output\n", i); 84462306a36Sopenharmony_ci return -EINVAL; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci return 0; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int hantro_buf_prepare(struct vb2_buffer *vb) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct vb2_queue *vq = vb->vb2_queue; 85362306a36Sopenharmony_ci struct hantro_ctx *ctx = vb2_get_drv_priv(vq); 85462306a36Sopenharmony_ci struct v4l2_pix_format_mplane *pix_fmt; 85562306a36Sopenharmony_ci int ret; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (V4L2_TYPE_IS_OUTPUT(vq->type)) 85862306a36Sopenharmony_ci pix_fmt = &ctx->src_fmt; 85962306a36Sopenharmony_ci else 86062306a36Sopenharmony_ci pix_fmt = &ctx->dst_fmt; 86162306a36Sopenharmony_ci ret = hantro_buf_plane_check(vb, pix_fmt); 86262306a36Sopenharmony_ci if (ret) 86362306a36Sopenharmony_ci return ret; 86462306a36Sopenharmony_ci /* 86562306a36Sopenharmony_ci * Buffer's bytesused must be written by driver for CAPTURE buffers. 86662306a36Sopenharmony_ci * (for OUTPUT buffers, if userspace passes 0 bytesused, v4l2-core sets 86762306a36Sopenharmony_ci * it to buffer length). 86862306a36Sopenharmony_ci */ 86962306a36Sopenharmony_ci if (V4L2_TYPE_IS_CAPTURE(vq->type)) { 87062306a36Sopenharmony_ci if (ctx->is_encoder) 87162306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, 0); 87262306a36Sopenharmony_ci else 87362306a36Sopenharmony_ci vb2_set_plane_payload(vb, 0, pix_fmt->plane_fmt[0].sizeimage); 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci return 0; 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_cistatic void hantro_buf_queue(struct vb2_buffer *vb) 88062306a36Sopenharmony_ci{ 88162306a36Sopenharmony_ci struct hantro_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 88262306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) && 88562306a36Sopenharmony_ci vb2_is_streaming(vb->vb2_queue) && 88662306a36Sopenharmony_ci v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { 88762306a36Sopenharmony_ci unsigned int i; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci for (i = 0; i < vb->num_planes; i++) 89062306a36Sopenharmony_ci vb2_set_plane_payload(vb, i, 0); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci vbuf->field = V4L2_FIELD_NONE; 89362306a36Sopenharmony_ci vbuf->sequence = ctx->sequence_cap++; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf); 89662306a36Sopenharmony_ci v4l2_event_queue_fh(&ctx->fh, &hantro_eos_event); 89762306a36Sopenharmony_ci return; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic bool hantro_vq_is_coded(struct vb2_queue *q) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct hantro_ctx *ctx = vb2_get_drv_priv(q); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci return ctx->is_encoder != V4L2_TYPE_IS_OUTPUT(q->type); 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_cistatic int hantro_start_streaming(struct vb2_queue *q, unsigned int count) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci struct hantro_ctx *ctx = vb2_get_drv_priv(q); 91362306a36Sopenharmony_ci int ret = 0; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci if (V4L2_TYPE_IS_OUTPUT(q->type)) 91862306a36Sopenharmony_ci ctx->sequence_out = 0; 91962306a36Sopenharmony_ci else 92062306a36Sopenharmony_ci ctx->sequence_cap = 0; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (hantro_vq_is_coded(q)) { 92362306a36Sopenharmony_ci enum hantro_codec_mode codec_mode; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (V4L2_TYPE_IS_OUTPUT(q->type)) 92662306a36Sopenharmony_ci codec_mode = ctx->vpu_src_fmt->codec_mode; 92762306a36Sopenharmony_ci else 92862306a36Sopenharmony_ci codec_mode = ctx->vpu_dst_fmt->codec_mode; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci vpu_debug(4, "Codec mode = %d\n", codec_mode); 93162306a36Sopenharmony_ci ctx->codec_ops = &ctx->dev->variant->codec_ops[codec_mode]; 93262306a36Sopenharmony_ci if (ctx->codec_ops->init) { 93362306a36Sopenharmony_ci ret = ctx->codec_ops->init(ctx); 93462306a36Sopenharmony_ci if (ret) 93562306a36Sopenharmony_ci return ret; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci if (hantro_needs_postproc(ctx, ctx->vpu_dst_fmt)) { 93962306a36Sopenharmony_ci ret = hantro_postproc_alloc(ctx); 94062306a36Sopenharmony_ci if (ret) 94162306a36Sopenharmony_ci goto err_codec_exit; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci return ret; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_cierr_codec_exit: 94762306a36Sopenharmony_ci if (ctx->codec_ops->exit) 94862306a36Sopenharmony_ci ctx->codec_ops->exit(ctx); 94962306a36Sopenharmony_ci return ret; 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_cistatic void 95362306a36Sopenharmony_cihantro_return_bufs(struct vb2_queue *q, 95462306a36Sopenharmony_ci struct vb2_v4l2_buffer *(*buf_remove)(struct v4l2_m2m_ctx *)) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci struct hantro_ctx *ctx = vb2_get_drv_priv(q); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci for (;;) { 95962306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci vbuf = buf_remove(ctx->fh.m2m_ctx); 96262306a36Sopenharmony_ci if (!vbuf) 96362306a36Sopenharmony_ci break; 96462306a36Sopenharmony_ci v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, 96562306a36Sopenharmony_ci &ctx->ctrl_handler); 96662306a36Sopenharmony_ci v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci} 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_cistatic void hantro_stop_streaming(struct vb2_queue *q) 97162306a36Sopenharmony_ci{ 97262306a36Sopenharmony_ci struct hantro_ctx *ctx = vb2_get_drv_priv(q); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci if (hantro_vq_is_coded(q)) { 97562306a36Sopenharmony_ci hantro_postproc_free(ctx); 97662306a36Sopenharmony_ci if (ctx->codec_ops && ctx->codec_ops->exit) 97762306a36Sopenharmony_ci ctx->codec_ops->exit(ctx); 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci /* 98162306a36Sopenharmony_ci * The mem2mem framework calls v4l2_m2m_cancel_job before 98262306a36Sopenharmony_ci * .stop_streaming, so there isn't any job running and 98362306a36Sopenharmony_ci * it is safe to return all the buffers. 98462306a36Sopenharmony_ci */ 98562306a36Sopenharmony_ci if (V4L2_TYPE_IS_OUTPUT(q->type)) 98662306a36Sopenharmony_ci hantro_return_bufs(q, v4l2_m2m_src_buf_remove); 98762306a36Sopenharmony_ci else 98862306a36Sopenharmony_ci hantro_return_bufs(q, v4l2_m2m_dst_buf_remove); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (V4L2_TYPE_IS_OUTPUT(q->type) && 99362306a36Sopenharmony_ci v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) 99462306a36Sopenharmony_ci v4l2_event_queue_fh(&ctx->fh, &hantro_eos_event); 99562306a36Sopenharmony_ci} 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cistatic void hantro_buf_request_complete(struct vb2_buffer *vb) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci struct hantro_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->ctrl_handler); 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic int hantro_buf_out_validate(struct vb2_buffer *vb) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci vbuf->field = V4L2_FIELD_NONE; 100962306a36Sopenharmony_ci return 0; 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ciconst struct vb2_ops hantro_queue_ops = { 101362306a36Sopenharmony_ci .queue_setup = hantro_queue_setup, 101462306a36Sopenharmony_ci .buf_prepare = hantro_buf_prepare, 101562306a36Sopenharmony_ci .buf_queue = hantro_buf_queue, 101662306a36Sopenharmony_ci .buf_out_validate = hantro_buf_out_validate, 101762306a36Sopenharmony_ci .buf_request_complete = hantro_buf_request_complete, 101862306a36Sopenharmony_ci .start_streaming = hantro_start_streaming, 101962306a36Sopenharmony_ci .stop_streaming = hantro_stop_streaming, 102062306a36Sopenharmony_ci .wait_prepare = vb2_ops_wait_prepare, 102162306a36Sopenharmony_ci .wait_finish = vb2_ops_wait_finish, 102262306a36Sopenharmony_ci}; 1023