alistair23-linux/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
Mauro Carvalho Chehab 5800571960 Linux 5.2-rc4
-----BEGIN PGP SIGNATURE-----
 
 iQFSBAABCAA8FiEEq68RxlopcLEwq+PEeb4+QwBBGIYFAlz8fAYeHHRvcnZhbGRz
 QGxpbnV4LWZvdW5kYXRpb24ub3JnAAoJEHm+PkMAQRiG1asH/3ySguxqtqL1MCBa
 4/SZ37PHeWKMerfX6ZyJdgEqK3B+PWlmuLiOMNK5h2bPLzeQQQAmHU/mfKmpXqgB
 dHwUbG9yNnyUtTfsfRqAnCA6vpuw9Yb1oIzTCVQrgJLSWD0j7scBBvmzYqguOkto
 ThwigLUq3AILr8EfR4rh+GM+5Dn9OTEFAxwil9fPHQo7QoczwZxpURhScT6Co9TB
 DqLA3fvXbBvLs/CZy/S5vKM9hKzC+p39ApFTURvFPrelUVnythAM0dPDJg3pIn5u
 g+/+gDxDFa+7ANxvxO2ng1sJPDqJMeY/xmjJYlYyLpA33B7zLNk2vDHhAP06VTtr
 XCMhQ9s=
 =cb80
 -----END PGP SIGNATURE-----

Merge tag 'v5.2-rc4' into media/master

There are some conflicts due to SPDX changes. We also have more
patches being merged via media tree touching them.

So, let's merge back from upstream and address those.

Linux 5.2-rc4

* tag 'v5.2-rc4': (767 commits)
  Linux 5.2-rc4
  MAINTAINERS: Karthikeyan Ramasubramanian is MIA
  i2c: xiic: Add max_read_len quirk
  lockref: Limit number of cmpxchg loop retries
  uaccess: add noop untagged_addr definition
  x86/insn-eval: Fix use-after-free access to LDT entry
  kbuild: use more portable 'command -v' for cc-cross-prefix
  s390/unwind: correct stack switching during unwind
  block, bfq: add weight symlink to the bfq.weight cgroup parameter
  cgroup: let a symlink too be created with a cftype file
  drm/nouveau/secboot/gp10[2467]: support newer FW to fix SEC2 failures on some boards
  drm/nouveau/secboot: enable loading of versioned LS PMU/SEC2 ACR msgqueue FW
  drm/nouveau/secboot: split out FW version-specific LS function pointers
  drm/nouveau/secboot: pass max supported FW version to LS load funcs
  drm/nouveau/core: support versioned firmware loading
  drm/nouveau/core: pass subdev into nvkm_firmware_get, rather than device
  block: free sched's request pool in blk_cleanup_queue
  pktgen: do not sleep with the thread lock held.
  net: mvpp2: Use strscpy to handle stat strings
  net: rds: fix memory leak in rds_ib_flush_mr_pool
  ...

Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2019-06-11 12:09:28 -04:00

2703 lines
72 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* linux/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
*
* Copyright (c) 2010-2011 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* Jeongtae Park <jtp.park@samsung.com>
* Kamil Debski <k.debski@samsung.com>
*/
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/videodev2.h>
#include <media/v4l2-event.h>
#include <linux/workqueue.h>
#include <media/v4l2-ctrls.h>
#include <media/videobuf2-v4l2.h>
#include "s5p_mfc_common.h"
#include "s5p_mfc_ctrl.h"
#include "s5p_mfc_debug.h"
#include "s5p_mfc_enc.h"
#include "s5p_mfc_intr.h"
#include "s5p_mfc_opr.h"
#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12M
#define DEF_DST_FMT_ENC V4L2_PIX_FMT_H264
static struct s5p_mfc_fmt formats[] = {
{
.name = "4:2:0 2 Planes 16x16 Tiles",
.fourcc = V4L2_PIX_FMT_NV12MT_16X16,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
.versions = MFC_V6_BIT | MFC_V7_BIT,
},
{
.name = "4:2:0 2 Planes 64x32 Tiles",
.fourcc = V4L2_PIX_FMT_NV12MT,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
.versions = MFC_V5_BIT,
},
{
.name = "4:2:0 2 Planes Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
.versions = MFC_V5PLUS_BITS,
},
{
.name = "4:2:0 2 Planes Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV21M,
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
.versions = MFC_V6PLUS_BITS,
},
{
.name = "H264 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264,
.codec_mode = S5P_MFC_CODEC_H264_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
.versions = MFC_V5PLUS_BITS,
},
{
.name = "MPEG4 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG4,
.codec_mode = S5P_MFC_CODEC_MPEG4_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
.versions = MFC_V5PLUS_BITS,
},
{
.name = "H263 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H263,
.codec_mode = S5P_MFC_CODEC_H263_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
.versions = MFC_V5PLUS_BITS,
},
{
.name = "VP8 Encoded Stream",
.fourcc = V4L2_PIX_FMT_VP8,
.codec_mode = S5P_MFC_CODEC_VP8_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
.versions = MFC_V7PLUS_BITS,
},
{
.fourcc = V4L2_PIX_FMT_HEVC,
.codec_mode = S5P_FIMV_CODEC_HEVC_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
.versions = MFC_V10_BIT,
},
};
#define NUM_FORMATS ARRAY_SIZE(formats)
static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t)
{
unsigned int i;
for (i = 0; i < NUM_FORMATS; i++) {
if (formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
formats[i].type == t)
return &formats[i];
}
return NULL;
}
static struct mfc_control controls[] = {
{
.id = V4L2_CID_MPEG_VIDEO_GOP_SIZE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 12,
},
{
.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
.maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES,
.default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 1,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 1900,
.maximum = (1 << 30) - 1,
.step = 1,
.default_value = 1900,
},
{
.id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Padding Control Enable",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Padding Color YUV Value",
.minimum = 0,
.maximum = (1 << 25) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_BITRATE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 1,
.maximum = (1 << 30) - 1,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Rate Control Reaction Coeff.",
.minimum = 1,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE,
.type = V4L2_CTRL_TYPE_MENU,
.name = "Force frame type",
.minimum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
.maximum = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_NOT_CODED,
.default_value = V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_DISABLED,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME,
.type = V4L2_CTRL_TYPE_BUTTON,
.minimum = 0,
.maximum = 0,
.step = 0,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_VBV_SIZE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Horizontal MV Search Range",
.minimum = 16,
.maximum = 128,
.step = 16,
.default_value = 32,
},
{
.id = V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Vertical MV Search Range",
.minimum = 16,
.maximum = 128,
.step = 16,
.default_value = 32,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEADER_MODE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
.maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
.default_value = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE,
.type = V4L2_CTRL_TYPE_MENU,
.name = "Frame Skip Enable",
.minimum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
.maximum = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
.menu_skip_mask = 0,
.default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
},
{
.id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Fixed Target Bit Enable",
.minimum = 0,
.maximum = 1,
.default_value = 0,
.step = 1,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_B_FRAMES,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 2,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
.maximum = V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
.default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)
),
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
.maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
.default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
.maximum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY,
.default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = -6,
.maximum = 6,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = -6,
.maximum = 6,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
.maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
.default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "The Number of Ref. Pic for P",
.minimum = 1,
.maximum = 2,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 51,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "H263 I-Frame QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H263_MIN_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "H263 Minimum QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H263_MAX_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "H263 Maximum QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 31,
},
{
.id = V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "H263 P frame QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "H263 B frame QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "MPEG4 I-Frame QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "MPEG4 Minimum QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "MPEG4 Maximum QP value",
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 51,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "MPEG4 P frame QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "MPEG4 B frame QP value",
.minimum = 1,
.maximum = 31,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "H264 Dark Reg Adaptive RC",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "H264 Smooth Reg Adaptive RC",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "H264 Static Reg Adaptive RC",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "H264 Activity Reg Adaptive RC",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
.maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED,
.default_value = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
.maximum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE,
.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_QPEL,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS,
.type = V4L2_CTRL_TYPE_INTEGER_MENU,
.maximum = V4L2_CID_MPEG_VIDEO_VPX_8_PARTITIONS,
.default_value = V4L2_CID_MPEG_VIDEO_VPX_1_PARTITION,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES,
.type = V4L2_CTRL_TYPE_INTEGER_MENU,
.maximum = V4L2_CID_MPEG_VIDEO_VPX_2_REF_FRAME,
.default_value = V4L2_CID_MPEG_VIDEO_VPX_1_REF_FRAME,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 63,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 7,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV,
.maximum = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_REF_PERIOD,
.default_value = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_VPX_MAX_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 127,
.step = 1,
.default_value = 127,
},
{
.id = V4L2_CID_MPEG_VIDEO_VPX_MIN_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 11,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 127,
.step = 1,
.default_value = 10,
},
{
.id = V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 127,
.step = 1,
.default_value = 10,
},
{
.id = V4L2_CID_MPEG_VIDEO_VP8_PROFILE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_VP8_PROFILE_0,
.maximum = V4L2_MPEG_VIDEO_VP8_PROFILE_3,
.default_value = V4L2_MPEG_VIDEO_VP8_PROFILE_0,
.menu_skip_mask = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "HEVC I Frame QP Value",
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "HEVC P Frame QP Value",
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
.maximum = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE,
.step = 1,
.default_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
.maximum = V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
.step = 1,
.default_value = V4L2_MPEG_VIDEO_HEVC_LEVEL_1,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_TIER,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN,
.maximum = V4L2_MPEG_VIDEO_HEVC_TIER_HIGH,
.step = 1,
.default_value = V4L2_MPEG_VIDEO_HEVC_TIER_MAIN,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 1,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 1,
.maximum = 2,
.step = 1,
.default_value = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE,
.maximum = V4L2_MPEG_VIDEO_HEVC_REFRESH_IDR,
.step = 1,
.default_value = V4L2_MPEG_VIDEO_HEVC_REFRESH_NONE,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED,
.maximum = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY,
.step = 1,
.default_value = V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B,
.maximum = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P,
.step = 1,
.default_value = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 6,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 51,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = INT_MIN,
.maximum = INT_MAX,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = INT_MIN,
.maximum = INT_MAX,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = INT_MIN,
.maximum = INT_MAX,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = INT_MIN,
.maximum = INT_MAX,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = INT_MIN,
.maximum = INT_MAX,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = INT_MIN,
.maximum = INT_MAX,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = INT_MIN,
.maximum = INT_MAX,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 4,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = (1 << 16) - 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = -6,
.maximum = 6,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = -6,
.maximum = 6,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD,
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_HEVC_SIZE_0,
.maximum = V4L2_MPEG_VIDEO_HEVC_SIZE_4,
.step = 1,
.default_value = V4L2_MPEG_VIDEO_HEVC_SIZE_0,
},
{
.id = V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR,
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
{
.id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Minimum number of output bufs",
.minimum = 1,
.maximum = 32,
.step = 1,
.default_value = 1,
.is_volatile = 1,
},
};
#define NUM_CTRLS ARRAY_SIZE(controls)
static const char * const *mfc51_get_menu(u32 id)
{
static const char * const mfc51_video_frame_skip[] = {
"Disabled",
"Level Limit",
"VBV/CPB Limit",
NULL,
};
static const char * const mfc51_video_force_frame[] = {
"Disabled",
"I Frame",
"Not Coded",
NULL,
};
switch (id) {
case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
return mfc51_video_frame_skip;
case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
return mfc51_video_force_frame;
}
return NULL;
}
static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
{
mfc_debug(2, "src=%d, dst=%d, state=%d\n",
ctx->src_queue_cnt, ctx->dst_queue_cnt, ctx->state);
/* context is ready to make header */
if (ctx->state == MFCINST_GOT_INST && ctx->dst_queue_cnt >= 1)
return 1;
/* context is ready to encode a frame */
if ((ctx->state == MFCINST_RUNNING ||
ctx->state == MFCINST_HEAD_PRODUCED) &&
ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1)
return 1;
/* context is ready to encode remaining frames */
if (ctx->state == MFCINST_FINISHING &&
ctx->dst_queue_cnt >= 1)
return 1;
mfc_debug(2, "ctx is not ready\n");
return 0;
}
static void cleanup_ref_queue(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_buf *mb_entry;
/* move buffers in ref queue to src queue */
while (!list_empty(&ctx->ref_queue)) {
mb_entry = list_entry((&ctx->ref_queue)->next,
struct s5p_mfc_buf, list);
list_del(&mb_entry->list);
ctx->ref_queue_cnt--;
list_add_tail(&mb_entry->list, &ctx->src_queue);
ctx->src_queue_cnt++;
}
mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
ctx->src_queue_cnt, ctx->ref_queue_cnt);
INIT_LIST_HEAD(&ctx->ref_queue);
ctx->ref_queue_cnt = 0;
}
static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf *dst_mb;
unsigned long dst_addr;
unsigned int dst_size;
dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
dst_size);
return 0;
}
static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_enc_params *p = &ctx->enc_params;
struct s5p_mfc_buf *dst_mb;
unsigned int enc_pb_count;
if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
if (!list_empty(&ctx->dst_queue)) {
dst_mb = list_entry(ctx->dst_queue.next,
struct s5p_mfc_buf, list);
list_del(&dst_mb->list);
ctx->dst_queue_cnt--;
vb2_set_plane_payload(&dst_mb->b->vb2_buf, 0,
s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size,
dev));
vb2_buffer_done(&dst_mb->b->vb2_buf,
VB2_BUF_STATE_DONE);
}
}
if (!IS_MFCV6_PLUS(dev)) {
ctx->state = MFCINST_RUNNING;
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
} else {
enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops,
get_enc_dpb_count, dev);
if (ctx->pb_count < enc_pb_count)
ctx->pb_count = enc_pb_count;
if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) {
ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops,
get_e_min_scratch_buf_size, dev);
ctx->bank1.size += ctx->scratch_buf_size;
}
ctx->state = MFCINST_HEAD_PRODUCED;
}
return 0;
}
static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf *dst_mb;
struct s5p_mfc_buf *src_mb;
unsigned long src_y_addr, src_c_addr, dst_addr;
unsigned int dst_size;
src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1);
s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx,
src_y_addr, src_c_addr);
dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
dst_size);
return 0;
}
static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf *mb_entry;
unsigned long enc_y_addr = 0, enc_c_addr = 0;
unsigned long mb_y_addr, mb_c_addr;
int slice_type;
unsigned int strm_size;
slice_type = s5p_mfc_hw_call(dev->mfc_ops, get_enc_slice_type, dev);
strm_size = s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev);
mfc_debug(2, "Encoded slice type: %d\n", slice_type);
mfc_debug(2, "Encoded stream size: %d\n", strm_size);
mfc_debug(2, "Display order: %d\n",
mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
if (slice_type >= 0) {
s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx,
&enc_y_addr, &enc_c_addr);
list_for_each_entry(mb_entry, &ctx->src_queue, list) {
mb_y_addr = vb2_dma_contig_plane_dma_addr(
&mb_entry->b->vb2_buf, 0);
mb_c_addr = vb2_dma_contig_plane_dma_addr(
&mb_entry->b->vb2_buf, 1);
if ((enc_y_addr == mb_y_addr) &&
(enc_c_addr == mb_c_addr)) {
list_del(&mb_entry->list);
ctx->src_queue_cnt--;
vb2_buffer_done(&mb_entry->b->vb2_buf,
VB2_BUF_STATE_DONE);
break;
}
}
list_for_each_entry(mb_entry, &ctx->ref_queue, list) {
mb_y_addr = vb2_dma_contig_plane_dma_addr(
&mb_entry->b->vb2_buf, 0);
mb_c_addr = vb2_dma_contig_plane_dma_addr(
&mb_entry->b->vb2_buf, 1);
if ((enc_y_addr == mb_y_addr) &&
(enc_c_addr == mb_c_addr)) {
list_del(&mb_entry->list);
ctx->ref_queue_cnt--;
vb2_buffer_done(&mb_entry->b->vb2_buf,
VB2_BUF_STATE_DONE);
break;
}
}
}
if ((ctx->src_queue_cnt > 0) && (ctx->state == MFCINST_RUNNING)) {
mb_entry = list_entry(ctx->src_queue.next, struct s5p_mfc_buf,
list);
if (mb_entry->flags & MFC_BUF_FLAG_USED) {
list_del(&mb_entry->list);
ctx->src_queue_cnt--;
list_add_tail(&mb_entry->list, &ctx->ref_queue);
ctx->ref_queue_cnt++;
}
}
mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
ctx->src_queue_cnt, ctx->ref_queue_cnt);
if ((ctx->dst_queue_cnt > 0) && (strm_size > 0)) {
mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf,
list);
list_del(&mb_entry->list);
ctx->dst_queue_cnt--;
switch (slice_type) {
case S5P_FIMV_ENC_SI_SLICE_TYPE_I:
mb_entry->b->flags |= V4L2_BUF_FLAG_KEYFRAME;
break;
case S5P_FIMV_ENC_SI_SLICE_TYPE_P:
mb_entry->b->flags |= V4L2_BUF_FLAG_PFRAME;
break;
case S5P_FIMV_ENC_SI_SLICE_TYPE_B:
mb_entry->b->flags |= V4L2_BUF_FLAG_BFRAME;
break;
}
vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, strm_size);
vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE);
}
if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0))
clear_work_bit(ctx);
return 0;
}
static const struct s5p_mfc_codec_ops encoder_codec_ops = {
.pre_seq_start = enc_pre_seq_start,
.post_seq_start = enc_post_seq_start,
.pre_frame_start = enc_pre_frame_start,
.post_frame_start = enc_post_frame_start,
};
/* Query capabilities of the device */
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct s5p_mfc_dev *dev = video_drvdata(file);
strscpy(cap->driver, S5P_MFC_NAME, sizeof(cap->driver));
strscpy(cap->card, dev->vfd_enc->name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(&dev->plat_dev->dev));
return 0;
}
static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
bool out)
{
struct s5p_mfc_dev *dev = video_drvdata(file);
struct s5p_mfc_fmt *fmt;
int i, j = 0;
for (i = 0; i < ARRAY_SIZE(formats); ++i) {
if (out && formats[i].type != MFC_FMT_RAW)
continue;
else if (!out && formats[i].type != MFC_FMT_ENC)
continue;
else if ((dev->variant->version_bit & formats[i].versions) == 0)
continue;
if (j == f->index) {
fmt = &formats[i];
strscpy(f->description, fmt->name,
sizeof(f->description));
f->pixelformat = fmt->fourcc;
return 0;
}
++j;
}
return -EINVAL;
}
static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
struct v4l2_fmtdesc *f)
{
return vidioc_enum_fmt(file, f, false);
}
static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
return vidioc_enum_fmt(file, f, true);
}
static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
mfc_debug(2, "f->type = %d ctx->state = %d\n", f->type, ctx->state);
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
/* This is run on output (encoder dest) */
pix_fmt_mp->width = 0;
pix_fmt_mp->height = 0;
pix_fmt_mp->field = V4L2_FIELD_NONE;
pix_fmt_mp->pixelformat = ctx->dst_fmt->fourcc;
pix_fmt_mp->num_planes = ctx->dst_fmt->num_planes;
pix_fmt_mp->plane_fmt[0].bytesperline = ctx->enc_dst_buf_size;
pix_fmt_mp->plane_fmt[0].sizeimage = ctx->enc_dst_buf_size;
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
/* This is run on capture (encoder src) */
pix_fmt_mp->width = ctx->img_width;
pix_fmt_mp->height = ctx->img_height;
pix_fmt_mp->field = V4L2_FIELD_NONE;
pix_fmt_mp->pixelformat = ctx->src_fmt->fourcc;
pix_fmt_mp->num_planes = ctx->src_fmt->num_planes;
pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
} else {
mfc_err("invalid buf type\n");
return -EINVAL;
}
return 0;
}
static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
struct s5p_mfc_dev *dev = video_drvdata(file);
struct s5p_mfc_fmt *fmt;
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
fmt = find_format(f, MFC_FMT_ENC);
if (!fmt) {
mfc_err("failed to try output format\n");
return -EINVAL;
}
if ((dev->variant->version_bit & fmt->versions) == 0) {
mfc_err("Unsupported format by this MFC version.\n");
return -EINVAL;
}
pix_fmt_mp->plane_fmt[0].bytesperline =
pix_fmt_mp->plane_fmt[0].sizeimage;
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
fmt = find_format(f, MFC_FMT_RAW);
if (!fmt) {
mfc_err("failed to try output format\n");
return -EINVAL;
}
if ((dev->variant->version_bit & fmt->versions) == 0) {
mfc_err("Unsupported format by this MFC version.\n");
return -EINVAL;
}
v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1,
&pix_fmt_mp->height, 4, 1080, 1, 0);
} else {
mfc_err("invalid buf type\n");
return -EINVAL;
}
return 0;
}
static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
{
struct s5p_mfc_dev *dev = video_drvdata(file);
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
int ret = 0;
ret = vidioc_try_fmt(file, priv, f);
if (ret)
return ret;
if (ctx->vq_src.streaming || ctx->vq_dst.streaming) {
v4l2_err(&dev->v4l2_dev, "%s queue busy\n", __func__);
ret = -EBUSY;
goto out;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
/* dst_fmt is validated by call to vidioc_try_fmt */
ctx->dst_fmt = find_format(f, MFC_FMT_ENC);
ctx->state = MFCINST_INIT;
ctx->codec_mode = ctx->dst_fmt->codec_mode;
ctx->enc_dst_buf_size = pix_fmt_mp->plane_fmt[0].sizeimage;
pix_fmt_mp->plane_fmt[0].bytesperline = 0;
ctx->dst_bufs_cnt = 0;
ctx->capture_state = QUEUE_FREE;
ret = s5p_mfc_open_mfc_inst(dev, ctx);
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
/* src_fmt is validated by call to vidioc_try_fmt */
ctx->src_fmt = find_format(f, MFC_FMT_RAW);
ctx->img_width = pix_fmt_mp->width;
ctx->img_height = pix_fmt_mp->height;
mfc_debug(2, "codec number: %d\n", ctx->src_fmt->codec_mode);
mfc_debug(2, "fmt - w: %d, h: %d, ctx - w: %d, h: %d\n",
pix_fmt_mp->width, pix_fmt_mp->height,
ctx->img_width, ctx->img_height);
s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
pix_fmt_mp->plane_fmt[1].bytesperline = ctx->buf_width;
ctx->src_bufs_cnt = 0;
ctx->output_state = QUEUE_FREE;
} else {
mfc_err("invalid buf type\n");
ret = -EINVAL;
}
out:
mfc_debug_leave();
return ret;
}
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *reqbufs)
{
struct s5p_mfc_dev *dev = video_drvdata(file);
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
int ret = 0;
/* if memory is not mmp or userptr return error */
if ((reqbufs->memory != V4L2_MEMORY_MMAP) &&
(reqbufs->memory != V4L2_MEMORY_USERPTR))
return -EINVAL;
if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
if (reqbufs->count == 0) {
mfc_debug(2, "Freeing buffers\n");
ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers,
ctx);
ctx->capture_state = QUEUE_FREE;
return ret;
}
if (ctx->capture_state != QUEUE_FREE) {
mfc_err("invalid capture state: %d\n",
ctx->capture_state);
return -EINVAL;
}
ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
if (ret != 0) {
mfc_err("error in vb2_reqbufs() for E(D)\n");
return ret;
}
ctx->capture_state = QUEUE_BUFS_REQUESTED;
ret = s5p_mfc_hw_call(ctx->dev->mfc_ops,
alloc_codec_buffers, ctx);
if (ret) {
mfc_err("Failed to allocate encoding buffers\n");
reqbufs->count = 0;
ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
return -ENOMEM;
}
} else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
if (reqbufs->count == 0) {
mfc_debug(2, "Freeing buffers\n");
ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers,
ctx);
ctx->output_state = QUEUE_FREE;
return ret;
}
if (ctx->output_state != QUEUE_FREE) {
mfc_err("invalid output state: %d\n",
ctx->output_state);
return -EINVAL;
}
if (IS_MFCV6_PLUS(dev)) {
/* Check for min encoder buffers */
if (ctx->pb_count &&
(reqbufs->count < ctx->pb_count)) {
reqbufs->count = ctx->pb_count;
mfc_debug(2, "Minimum %d output buffers needed\n",
ctx->pb_count);
} else {
ctx->pb_count = reqbufs->count;
}
}
ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
if (ret != 0) {
mfc_err("error in vb2_reqbufs() for E(S)\n");
return ret;
}
ctx->output_state = QUEUE_BUFS_REQUESTED;
} else {
mfc_err("invalid buf type\n");
return -EINVAL;
}
return ret;
}
static int vidioc_querybuf(struct file *file, void *priv,
struct v4l2_buffer *buf)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
int ret = 0;
/* if memory is not mmp or userptr return error */
if ((buf->memory != V4L2_MEMORY_MMAP) &&
(buf->memory != V4L2_MEMORY_USERPTR))
return -EINVAL;
if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
if (ctx->state != MFCINST_GOT_INST) {
mfc_err("invalid context state: %d\n", ctx->state);
return -EINVAL;
}
ret = vb2_querybuf(&ctx->vq_dst, buf);
if (ret != 0) {
mfc_err("error in vb2_querybuf() for E(D)\n");
return ret;
}
buf->m.planes[0].m.mem_offset += DST_QUEUE_OFF_BASE;
} else if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
ret = vb2_querybuf(&ctx->vq_src, buf);
if (ret != 0) {
mfc_err("error in vb2_querybuf() for E(S)\n");
return ret;
}
} else {
mfc_err("invalid buf type\n");
return -EINVAL;
}
return ret;
}
/* Queue a buffer */
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
if (ctx->state == MFCINST_ERROR) {
mfc_err("Call on QBUF after unrecoverable error\n");
return -EIO;
}
if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
if (ctx->state == MFCINST_FINISHING) {
mfc_err("Call on QBUF after EOS command\n");
return -EIO;
}
return vb2_qbuf(&ctx->vq_src, NULL, buf);
} else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
return vb2_qbuf(&ctx->vq_dst, NULL, buf);
}
return -EINVAL;
}
/* Dequeue a buffer */
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
{
const struct v4l2_event ev = {
.type = V4L2_EVENT_EOS
};
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
int ret;
if (ctx->state == MFCINST_ERROR) {
mfc_err_limited("Call on DQBUF after unrecoverable error\n");
return -EIO;
}
if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
ret = vb2_dqbuf(&ctx->vq_src, buf, file->f_flags & O_NONBLOCK);
} else if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
ret = vb2_dqbuf(&ctx->vq_dst, buf, file->f_flags & O_NONBLOCK);
if (ret == 0 && ctx->state == MFCINST_FINISHED
&& list_empty(&ctx->vq_dst.done_list))
v4l2_event_queue_fh(&ctx->fh, &ev);
} else {
ret = -EINVAL;
}
return ret;
}
/* Export DMA buffer */
static int vidioc_expbuf(struct file *file, void *priv,
struct v4l2_exportbuffer *eb)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
return vb2_expbuf(&ctx->vq_src, eb);
if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
return vb2_expbuf(&ctx->vq_dst, eb);
return -EINVAL;
}
/* Stream on */
static int vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
return vb2_streamon(&ctx->vq_src, type);
else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
return vb2_streamon(&ctx->vq_dst, type);
return -EINVAL;
}
/* Stream off, which equals to a pause */
static int vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
return vb2_streamoff(&ctx->vq_src, type);
else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
return vb2_streamoff(&ctx->vq_dst, type);
return -EINVAL;
}
static inline int h264_level(enum v4l2_mpeg_video_h264_level lvl)
{
static unsigned int t[V4L2_MPEG_VIDEO_H264_LEVEL_4_0 + 1] = {
/* V4L2_MPEG_VIDEO_H264_LEVEL_1_0 */ 10,
/* V4L2_MPEG_VIDEO_H264_LEVEL_1B */ 9,
/* V4L2_MPEG_VIDEO_H264_LEVEL_1_1 */ 11,
/* V4L2_MPEG_VIDEO_H264_LEVEL_1_2 */ 12,
/* V4L2_MPEG_VIDEO_H264_LEVEL_1_3 */ 13,
/* V4L2_MPEG_VIDEO_H264_LEVEL_2_0 */ 20,
/* V4L2_MPEG_VIDEO_H264_LEVEL_2_1 */ 21,
/* V4L2_MPEG_VIDEO_H264_LEVEL_2_2 */ 22,
/* V4L2_MPEG_VIDEO_H264_LEVEL_3_0 */ 30,
/* V4L2_MPEG_VIDEO_H264_LEVEL_3_1 */ 31,
/* V4L2_MPEG_VIDEO_H264_LEVEL_3_2 */ 32,
/* V4L2_MPEG_VIDEO_H264_LEVEL_4_0 */ 40,
};
return t[lvl];
}
static inline int mpeg4_level(enum v4l2_mpeg_video_mpeg4_level lvl)
{
static unsigned int t[V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 + 1] = {
/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 */ 0,
/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B */ 9,
/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 */ 1,
/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 */ 2,
/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 */ 3,
/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_3B */ 7,
/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 */ 4,
/* V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 */ 5,
};
return t[lvl];
}
static inline int hevc_level(enum v4l2_mpeg_video_hevc_level lvl)
{
static unsigned int t[] = {
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_1 */ 10,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_2 */ 20,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 */ 21,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_3 */ 30,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 */ 31,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_4 */ 40,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 */ 41,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_5 */ 50,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 */ 51,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 */ 52,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_6 */ 60,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 */ 61,
/* V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 */ 62,
};
return t[lvl];
}
static inline int vui_sar_idc(enum v4l2_mpeg_video_h264_vui_sar_idc sar)
{
static unsigned int t[V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED + 1] = {
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED */ 0,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_1x1 */ 1,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_12x11 */ 2,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_10x11 */ 3,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_16x11 */ 4,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_40x33 */ 5,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_24x11 */ 6,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_20x11 */ 7,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_32x11 */ 8,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_80x33 */ 9,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_18x11 */ 10,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_15x11 */ 11,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_64x33 */ 12,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_160x99 */ 13,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_4x3 */ 14,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_3x2 */ 15,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_2x1 */ 16,
/* V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED */ 255,
};
return t[sar];
}
/*
* Update range of all HEVC quantization parameter controls that depend on the
* V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP controls.
*/
static void __enc_update_hevc_qp_ctrls_range(struct s5p_mfc_ctx *ctx,
int min, int max)
{
static const int __hevc_qp_ctrls[] = {
V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP,
V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP,
V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP,
V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP,
V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP,
V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP,
V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP,
V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP,
V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP,
V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP,
};
struct v4l2_ctrl *ctrl = NULL;
int i, j;
for (i = 0; i < ARRAY_SIZE(__hevc_qp_ctrls); i++) {
for (j = 0; j < ARRAY_SIZE(ctx->ctrls); j++) {
if (ctx->ctrls[j]->id == __hevc_qp_ctrls[i]) {
ctrl = ctx->ctrls[j];
break;
}
}
if (WARN_ON(!ctrl))
break;
__v4l2_ctrl_modify_range(ctrl, min, max, ctrl->step, min);
}
}
static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_enc_params *p = &ctx->enc_params;
int ret = 0;
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
p->gop_size = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
p->slice_mode = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
p->slice_mb = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
p->slice_bit = ctrl->val * 8;
break;
case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
p->intra_refresh_mb = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_PADDING:
p->pad = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_PADDING_YUV:
p->pad_luma = (ctrl->val >> 16) & 0xff;
p->pad_cb = (ctrl->val >> 8) & 0xff;
p->pad_cr = (ctrl->val >> 0) & 0xff;
break;
case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
p->rc_frame = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
p->rc_bitrate = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_RC_REACTION_COEFF:
p->rc_reaction_coeff = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE:
ctx->force_frame_type = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
ctx->force_frame_type =
V4L2_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE_I_FRAME;
break;
case V4L2_CID_MPEG_VIDEO_VBV_SIZE:
p->vbv_size = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MV_H_SEARCH_RANGE:
p->mv_h_range = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE:
p->mv_v_range = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE:
p->codec.h264.cpb_size = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
p->seq_hdr_mode = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
p->frame_skip_mode = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT:
p->fixed_target_bit = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_B_FRAMES:
p->num_b_frame = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
switch (ctrl->val) {
case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
p->codec.h264.profile =
S5P_FIMV_ENC_PROFILE_H264_MAIN;
break;
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
p->codec.h264.profile =
S5P_FIMV_ENC_PROFILE_H264_HIGH;
break;
case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
p->codec.h264.profile =
S5P_FIMV_ENC_PROFILE_H264_BASELINE;
break;
case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
if (IS_MFCV6_PLUS(dev))
p->codec.h264.profile =
S5P_FIMV_ENC_PROFILE_H264_CONSTRAINED_BASELINE;
else
ret = -EINVAL;
break;
default:
ret = -EINVAL;
}
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
p->codec.h264.level_v4l2 = ctrl->val;
p->codec.h264.level = h264_level(ctrl->val);
if (p->codec.h264.level < 0) {
mfc_err("Level number is wrong\n");
ret = p->codec.h264.level;
}
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
p->codec.mpeg4.level_v4l2 = ctrl->val;
p->codec.mpeg4.level = mpeg4_level(ctrl->val);
if (p->codec.mpeg4.level < 0) {
mfc_err("Level number is wrong\n");
ret = p->codec.mpeg4.level;
}
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
p->codec.h264.loop_filter_mode = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
p->codec.h264.loop_filter_alpha = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
p->codec.h264.loop_filter_beta = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
p->codec.h264.entropy_mode = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_H264_NUM_REF_PIC_FOR_P:
p->codec.h264.num_ref_pic_4p = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
p->codec.h264._8x8_transform = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE:
p->rc_mb = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
p->codec.h264.rc_frame_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
p->codec.h264.rc_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
p->codec.h264.rc_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
p->codec.h264.rc_p_frame_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
p->codec.h264.rc_b_frame_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP:
p->codec.mpeg4.rc_frame_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_MIN_QP:
case V4L2_CID_MPEG_VIDEO_H263_MIN_QP:
p->codec.mpeg4.rc_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_MAX_QP:
case V4L2_CID_MPEG_VIDEO_H263_MAX_QP:
p->codec.mpeg4.rc_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP:
p->codec.mpeg4.rc_p_frame_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP:
case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP:
p->codec.mpeg4.rc_b_frame_qp = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_DARK:
p->codec.h264.rc_mb_dark = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_SMOOTH:
p->codec.h264.rc_mb_smooth = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_STATIC:
p->codec.h264.rc_mb_static = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_H264_ADAPTIVE_RC_ACTIVITY:
p->codec.h264.rc_mb_activity = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE:
p->codec.h264.vui_sar = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC:
p->codec.h264.vui_sar_idc = vui_sar_idc(ctrl->val);
break;
case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_WIDTH:
p->codec.h264.vui_ext_sar_width = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_VUI_EXT_SAR_HEIGHT:
p->codec.h264.vui_ext_sar_height = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
p->codec.h264.open_gop = !ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
p->codec.h264.open_gop_size = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
switch (ctrl->val) {
case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
p->codec.mpeg4.profile =
S5P_FIMV_ENC_PROFILE_MPEG4_SIMPLE;
break;
case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
p->codec.mpeg4.profile =
S5P_FIMV_ENC_PROFILE_MPEG4_ADVANCED_SIMPLE;
break;
default:
ret = -EINVAL;
}
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_QPEL:
p->codec.mpeg4.quarter_pixel = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS:
p->codec.vp8.num_partitions = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_IMD_DISABLE_4X4:
p->codec.vp8.imd_4x4 = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_NUM_REF_FRAMES:
p->codec.vp8.num_ref = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL:
p->codec.vp8.filter_level = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS:
p->codec.vp8.filter_sharpness = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD:
p->codec.vp8.golden_frame_ref_period = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
p->codec.vp8.golden_frame_sel = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP:
p->codec.vp8.rc_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP:
p->codec.vp8.rc_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP:
p->codec.vp8.rc_frame_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP:
p->codec.vp8.rc_p_frame_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
p->codec.vp8.profile = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP:
p->codec.hevc.rc_frame_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP:
p->codec.hevc.rc_p_frame_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP:
p->codec.hevc.rc_b_frame_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_FRAME_RATE_RESOLUTION:
p->codec.hevc.rc_framerate = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
p->codec.hevc.rc_min_qp = ctrl->val;
__enc_update_hevc_qp_ctrls_range(ctx, ctrl->val,
p->codec.hevc.rc_max_qp);
break;
case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
p->codec.hevc.rc_max_qp = ctrl->val;
__enc_update_hevc_qp_ctrls_range(ctx, p->codec.hevc.rc_min_qp,
ctrl->val);
break;
case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
p->codec.hevc.level_v4l2 = ctrl->val;
p->codec.hevc.level = hevc_level(ctrl->val);
break;
case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
switch (ctrl->val) {
case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
p->codec.hevc.profile =
V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN;
break;
case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE:
p->codec.hevc.profile =
V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE;
break;
default:
ret = -EINVAL;
}
break;
case V4L2_CID_MPEG_VIDEO_HEVC_TIER:
p->codec.hevc.tier = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_MAX_PARTITION_DEPTH:
p->codec.hevc.max_partition_depth = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_REF_NUMBER_FOR_PFRAMES:
p->codec.hevc.num_refs_for_p = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_TYPE:
p->codec.hevc.refreshtype = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_CONST_INTRA_PRED:
p->codec.hevc.const_intra_period_enable = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU:
p->codec.hevc.lossless_cu_enable = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_WAVEFRONT:
p->codec.hevc.wavefront_enable = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE:
p->codec.hevc.loopfilter = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_QP:
p->codec.hevc.hier_qp_enable = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE:
p->codec.hevc.hier_qp_type = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER:
p->codec.hevc.num_hier_layer = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_QP:
p->codec.hevc.hier_qp_layer[0] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_QP:
p->codec.hevc.hier_qp_layer[1] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_QP:
p->codec.hevc.hier_qp_layer[2] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_QP:
p->codec.hevc.hier_qp_layer[3] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_QP:
p->codec.hevc.hier_qp_layer[4] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_QP:
p->codec.hevc.hier_qp_layer[5] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_QP:
p->codec.hevc.hier_qp_layer[6] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR:
p->codec.hevc.hier_bit_layer[0] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR:
p->codec.hevc.hier_bit_layer[1] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR:
p->codec.hevc.hier_bit_layer[2] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR:
p->codec.hevc.hier_bit_layer[3] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR:
p->codec.hevc.hier_bit_layer[4] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR:
p->codec.hevc.hier_bit_layer[5] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L6_BR:
p->codec.hevc.hier_bit_layer[6] = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_GENERAL_PB:
p->codec.hevc.general_pb_enable = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_TEMPORAL_ID:
p->codec.hevc.temporal_id_enable = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_STRONG_SMOOTHING:
p->codec.hevc.strong_intra_smooth = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_INTRA_PU_SPLIT:
p->codec.hevc.intra_pu_split_disable = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_TMV_PREDICTION:
p->codec.hevc.tmv_prediction_disable = !ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_MAX_NUM_MERGE_MV_MINUS1:
p->codec.hevc.max_num_merge_mv = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE:
p->codec.hevc.encoding_nostartcode_enable = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_REFRESH_PERIOD:
p->codec.hevc.refreshperiod = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2:
p->codec.hevc.lf_beta_offset_div2 = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2:
p->codec.hevc.lf_tc_offset_div2 = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD:
p->codec.hevc.size_of_length_field = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:
p->codec.hevc.prepend_sps_pps_to_idr = ctrl->val;
break;
default:
v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
ctrl->id, ctrl->val);
ret = -EINVAL;
}
return ret;
}
static int s5p_mfc_enc_g_v_ctrl(struct v4l2_ctrl *ctrl)
{
struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
struct s5p_mfc_dev *dev = ctx->dev;
switch (ctrl->id) {
case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
if (ctx->state >= MFCINST_HEAD_PARSED &&
ctx->state < MFCINST_ABORT) {
ctrl->val = ctx->pb_count;
break;
} else if (ctx->state != MFCINST_INIT) {
v4l2_err(&dev->v4l2_dev, "Encoding not initialised\n");
return -EINVAL;
}
/* Should wait for the header to be produced */
s5p_mfc_wait_for_done_ctx(ctx,
S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0);
if (ctx->state >= MFCINST_HEAD_PARSED &&
ctx->state < MFCINST_ABORT) {
ctrl->val = ctx->pb_count;
} else {
v4l2_err(&dev->v4l2_dev, "Encoding not initialised\n");
return -EINVAL;
}
break;
}
return 0;
}
static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = {
.s_ctrl = s5p_mfc_enc_s_ctrl,
.g_volatile_ctrl = s5p_mfc_enc_g_v_ctrl,
};
static int vidioc_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *a)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
ctx->enc_params.rc_framerate_num =
a->parm.output.timeperframe.denominator;
ctx->enc_params.rc_framerate_denom =
a->parm.output.timeperframe.numerator;
} else {
mfc_err("Setting FPS is only possible for the output queue\n");
return -EINVAL;
}
return 0;
}
static int vidioc_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *a)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
if (a->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
a->parm.output.timeperframe.denominator =
ctx->enc_params.rc_framerate_num;
a->parm.output.timeperframe.numerator =
ctx->enc_params.rc_framerate_denom;
} else {
mfc_err("Setting FPS is only possible for the output queue\n");
return -EINVAL;
}
return 0;
}
static int vidioc_encoder_cmd(struct file *file, void *priv,
struct v4l2_encoder_cmd *cmd)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf *buf;
unsigned long flags;
switch (cmd->cmd) {
case V4L2_ENC_CMD_STOP:
if (cmd->flags != 0)
return -EINVAL;
if (!ctx->vq_src.streaming)
return -EINVAL;
spin_lock_irqsave(&dev->irqlock, flags);
if (list_empty(&ctx->src_queue)) {
mfc_debug(2, "EOS: empty src queue, entering finishing state\n");
ctx->state = MFCINST_FINISHING;
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
spin_unlock_irqrestore(&dev->irqlock, flags);
s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
} else {
mfc_debug(2, "EOS: marking last buffer of stream\n");
buf = list_entry(ctx->src_queue.prev,
struct s5p_mfc_buf, list);
if (buf->flags & MFC_BUF_FLAG_USED)
ctx->state = MFCINST_FINISHING;
else
buf->flags |= MFC_BUF_FLAG_EOS;
spin_unlock_irqrestore(&dev->irqlock, flags);
}
break;
default:
return -EINVAL;
}
return 0;
}
static int vidioc_subscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
switch (sub->type) {
case V4L2_EVENT_EOS:
return v4l2_event_subscribe(fh, sub, 2, NULL);
default:
return -EINVAL;
}
}
static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
.vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt,
.vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt,
.vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt,
.vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt,
.vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt,
.vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt,
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
.vidioc_dqbuf = vidioc_dqbuf,
.vidioc_expbuf = vidioc_expbuf,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_s_parm = vidioc_s_parm,
.vidioc_g_parm = vidioc_g_parm,
.vidioc_encoder_cmd = vidioc_encoder_cmd,
.vidioc_subscribe_event = vidioc_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
{
int i;
if (!fmt)
return -EINVAL;
if (fmt->num_planes != vb->num_planes) {
mfc_err("invalid plane number for the format\n");
return -EINVAL;
}
for (i = 0; i < fmt->num_planes; i++) {
dma_addr_t dma = vb2_dma_contig_plane_dma_addr(vb, i);
if (!dma) {
mfc_err("failed to get plane cookie\n");
return -EINVAL;
}
mfc_debug(2, "index: %d, plane[%d] cookie: %pad\n",
vb->index, i, &dma);
}
return 0;
}
static int s5p_mfc_queue_setup(struct vb2_queue *vq,
unsigned int *buf_count, unsigned int *plane_count,
unsigned int psize[], struct device *alloc_devs[])
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
struct s5p_mfc_dev *dev = ctx->dev;
if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
if (ctx->state != MFCINST_GOT_INST) {
mfc_err("invalid state: %d\n", ctx->state);
return -EINVAL;
}
if (ctx->dst_fmt)
*plane_count = ctx->dst_fmt->num_planes;
else
*plane_count = MFC_ENC_CAP_PLANE_COUNT;
if (*buf_count < 1)
*buf_count = 1;
if (*buf_count > MFC_MAX_BUFFERS)
*buf_count = MFC_MAX_BUFFERS;
psize[0] = ctx->enc_dst_buf_size;
alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
if (ctx->src_fmt)
*plane_count = ctx->src_fmt->num_planes;
else
*plane_count = MFC_ENC_OUT_PLANE_COUNT;
if (*buf_count < 1)
*buf_count = 1;
if (*buf_count > MFC_MAX_BUFFERS)
*buf_count = MFC_MAX_BUFFERS;
psize[0] = ctx->luma_size;
psize[1] = ctx->chroma_size;
if (IS_MFCV6_PLUS(dev)) {
alloc_devs[0] = ctx->dev->mem_dev[BANK_L_CTX];
alloc_devs[1] = ctx->dev->mem_dev[BANK_L_CTX];
} else {
alloc_devs[0] = ctx->dev->mem_dev[BANK_R_CTX];
alloc_devs[1] = ctx->dev->mem_dev[BANK_R_CTX];
}
} else {
mfc_err("invalid queue type: %d\n", vq->type);
return -EINVAL;
}
return 0;
}
static int s5p_mfc_buf_init(struct vb2_buffer *vb)
{
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vb2_queue *vq = vb->vb2_queue;
struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
unsigned int i;
int ret;
if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
ret = check_vb_with_fmt(ctx->dst_fmt, vb);
if (ret < 0)
return ret;
i = vb->index;
ctx->dst_bufs[i].b = vbuf;
ctx->dst_bufs[i].cookie.stream =
vb2_dma_contig_plane_dma_addr(vb, 0);
ctx->dst_bufs_cnt++;
} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
ret = check_vb_with_fmt(ctx->src_fmt, vb);
if (ret < 0)
return ret;
i = vb->index;
ctx->src_bufs[i].b = vbuf;
ctx->src_bufs[i].cookie.raw.luma =
vb2_dma_contig_plane_dma_addr(vb, 0);
ctx->src_bufs[i].cookie.raw.chroma =
vb2_dma_contig_plane_dma_addr(vb, 1);
ctx->src_bufs_cnt++;
} else {
mfc_err("invalid queue type: %d\n", vq->type);
return -EINVAL;
}
return 0;
}
static int s5p_mfc_buf_prepare(struct vb2_buffer *vb)
{
struct vb2_queue *vq = vb->vb2_queue;
struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
int ret;
if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
ret = check_vb_with_fmt(ctx->dst_fmt, vb);
if (ret < 0)
return ret;
mfc_debug(2, "plane size: %ld, dst size: %zu\n",
vb2_plane_size(vb, 0), ctx->enc_dst_buf_size);
if (vb2_plane_size(vb, 0) < ctx->enc_dst_buf_size) {
mfc_err("plane size is too small for capture\n");
return -EINVAL;
}
} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
ret = check_vb_with_fmt(ctx->src_fmt, vb);
if (ret < 0)
return ret;
mfc_debug(2, "plane size: %ld, luma size: %d\n",
vb2_plane_size(vb, 0), ctx->luma_size);
mfc_debug(2, "plane size: %ld, chroma size: %d\n",
vb2_plane_size(vb, 1), ctx->chroma_size);
if (vb2_plane_size(vb, 0) < ctx->luma_size ||
vb2_plane_size(vb, 1) < ctx->chroma_size) {
mfc_err("plane size is too small for output\n");
return -EINVAL;
}
} else {
mfc_err("invalid queue type: %d\n", vq->type);
return -EINVAL;
}
return 0;
}
static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
struct s5p_mfc_dev *dev = ctx->dev;
if (IS_MFCV6_PLUS(dev) &&
(q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) {
if ((ctx->state == MFCINST_GOT_INST) &&
(dev->curr_ctx == ctx->num) && dev->hw_lock) {
s5p_mfc_wait_for_done_ctx(ctx,
S5P_MFC_R2H_CMD_SEQ_DONE_RET,
0);
}
if (ctx->src_bufs_cnt < ctx->pb_count) {
mfc_err("Need minimum %d OUTPUT buffers\n",
ctx->pb_count);
return -ENOBUFS;
}
}
/* If context is ready then dev = work->data;schedule it to run */
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
return 0;
}
static void s5p_mfc_stop_streaming(struct vb2_queue *q)
{
unsigned long flags;
struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
struct s5p_mfc_dev *dev = ctx->dev;
if ((ctx->state == MFCINST_FINISHING ||
ctx->state == MFCINST_RUNNING) &&
dev->curr_ctx == ctx->num && dev->hw_lock) {
ctx->state = MFCINST_ABORT;
s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_FRAME_DONE_RET,
0);
}
ctx->state = MFCINST_FINISHED;
spin_lock_irqsave(&dev->irqlock, flags);
if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
INIT_LIST_HEAD(&ctx->dst_queue);
ctx->dst_queue_cnt = 0;
}
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
cleanup_ref_queue(ctx);
s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
INIT_LIST_HEAD(&ctx->src_queue);
ctx->src_queue_cnt = 0;
}
spin_unlock_irqrestore(&dev->irqlock, flags);
}
static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
{
struct vb2_queue *vq = vb->vb2_queue;
struct s5p_mfc_ctx *ctx = fh_to_ctx(vq->drv_priv);
struct s5p_mfc_dev *dev = ctx->dev;
unsigned long flags;
struct s5p_mfc_buf *mfc_buf;
if (ctx->state == MFCINST_ERROR) {
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
cleanup_ref_queue(ctx);
return;
}
if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
mfc_buf = &ctx->dst_bufs[vb->index];
mfc_buf->flags &= ~MFC_BUF_FLAG_USED;
/* Mark destination as available for use by MFC */
spin_lock_irqsave(&dev->irqlock, flags);
list_add_tail(&mfc_buf->list, &ctx->dst_queue);
ctx->dst_queue_cnt++;
spin_unlock_irqrestore(&dev->irqlock, flags);
} else if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
mfc_buf = &ctx->src_bufs[vb->index];
mfc_buf->flags &= ~MFC_BUF_FLAG_USED;
spin_lock_irqsave(&dev->irqlock, flags);
list_add_tail(&mfc_buf->list, &ctx->src_queue);
ctx->src_queue_cnt++;
spin_unlock_irqrestore(&dev->irqlock, flags);
} else {
mfc_err("unsupported buffer type (%d)\n", vq->type);
}
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
}
static struct vb2_ops s5p_mfc_enc_qops = {
.queue_setup = s5p_mfc_queue_setup,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
.buf_init = s5p_mfc_buf_init,
.buf_prepare = s5p_mfc_buf_prepare,
.start_streaming = s5p_mfc_start_streaming,
.stop_streaming = s5p_mfc_stop_streaming,
.buf_queue = s5p_mfc_buf_queue,
};
const struct s5p_mfc_codec_ops *get_enc_codec_ops(void)
{
return &encoder_codec_ops;
}
struct vb2_ops *get_enc_queue_ops(void)
{
return &s5p_mfc_enc_qops;
}
const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void)
{
return &s5p_mfc_enc_ioctl_ops;
}
#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_MPEG) \
&& V4L2_CTRL_DRIVER_PRIV(x))
int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx)
{
struct v4l2_ctrl_config cfg;
int i;
v4l2_ctrl_handler_init(&ctx->ctrl_handler, NUM_CTRLS);
if (ctx->ctrl_handler.error) {
mfc_err("v4l2_ctrl_handler_init failed\n");
return ctx->ctrl_handler.error;
}
for (i = 0; i < NUM_CTRLS; i++) {
if (IS_MFC51_PRIV(controls[i].id)) {
memset(&cfg, 0, sizeof(struct v4l2_ctrl_config));
cfg.ops = &s5p_mfc_enc_ctrl_ops;
cfg.id = controls[i].id;
cfg.min = controls[i].minimum;
cfg.max = controls[i].maximum;
cfg.def = controls[i].default_value;
cfg.name = controls[i].name;
cfg.type = controls[i].type;
cfg.flags = 0;
if (cfg.type == V4L2_CTRL_TYPE_MENU) {
cfg.step = 0;
cfg.menu_skip_mask = controls[i].menu_skip_mask;
cfg.qmenu = mfc51_get_menu(cfg.id);
} else {
cfg.step = controls[i].step;
cfg.menu_skip_mask = 0;
}
ctx->ctrls[i] = v4l2_ctrl_new_custom(&ctx->ctrl_handler,
&cfg, NULL);
} else {
if ((controls[i].type == V4L2_CTRL_TYPE_MENU) ||
(controls[i].type ==
V4L2_CTRL_TYPE_INTEGER_MENU)) {
ctx->ctrls[i] = v4l2_ctrl_new_std_menu(
&ctx->ctrl_handler,
&s5p_mfc_enc_ctrl_ops, controls[i].id,
controls[i].maximum, 0,
controls[i].default_value);
} else {
ctx->ctrls[i] = v4l2_ctrl_new_std(
&ctx->ctrl_handler,
&s5p_mfc_enc_ctrl_ops, controls[i].id,
controls[i].minimum,
controls[i].maximum, controls[i].step,
controls[i].default_value);
}
}
if (ctx->ctrl_handler.error) {
mfc_err("Adding control (%d) failed\n", i);
return ctx->ctrl_handler.error;
}
if (controls[i].is_volatile && ctx->ctrls[i])
ctx->ctrls[i]->flags |= V4L2_CTRL_FLAG_VOLATILE;
}
v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
return 0;
}
void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx)
{
int i;
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
for (i = 0; i < NUM_CTRLS; i++)
ctx->ctrls[i] = NULL;
}
void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx)
{
struct v4l2_format f;
f.fmt.pix_mp.pixelformat = DEF_SRC_FMT_ENC;
ctx->src_fmt = find_format(&f, MFC_FMT_RAW);
f.fmt.pix_mp.pixelformat = DEF_DST_FMT_ENC;
ctx->dst_fmt = find_format(&f, MFC_FMT_ENC);
}