M7350/kernel/drivers/media/platform/msm/vidc/msm_vdec.c

2774 lines
76 KiB
C
Raw Normal View History

2024-09-09 08:57:42 +00:00
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
2024-09-09 08:52:07 +00:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/slab.h>
2024-09-09 08:57:42 +00:00
#include <soc/qcom/scm.h>
2024-09-09 08:52:07 +00:00
#include "msm_vidc_internal.h"
#include "msm_vidc_common.h"
#include "vidc_hfi_api.h"
#include "msm_vidc_debug.h"
2024-09-09 08:57:42 +00:00
#include "msm_vidc_dcvs.h"
2024-09-09 08:52:07 +00:00
#define MSM_VDEC_DVC_NAME "msm_vdec_8974"
#define MIN_NUM_OUTPUT_BUFFERS 4
2024-09-09 08:57:42 +00:00
#define MIN_NUM_CAPTURE_BUFFERS 6
#define MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS 1
#define MAX_NUM_OUTPUT_BUFFERS VB2_MAX_FRAME
#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8010
#define MB_SIZE_IN_PIXEL (16 * 16)
#define MAX_OPERATING_FRAME_RATE (300 << 16)
#define OPERATING_FRAME_RATE_STEP (1 << 16)
2024-09-09 08:52:07 +00:00
static const char *const mpeg_video_vidc_divx_format[] = {
"DIVX Format 3",
"DIVX Format 4",
"DIVX Format 5",
"DIVX Format 6",
NULL
};
static const char *mpeg_video_stream_format[] = {
"NAL Format Start Codes",
"NAL Format One NAL Per Buffer",
"NAL Format One Byte Length",
"NAL Format Two Byte Length",
"NAL Format Four Byte Length",
NULL
};
static const char *const mpeg_video_output_order[] = {
"Display Order",
"Decode Order",
NULL
};
static const char *const mpeg_video_vidc_extradata[] = {
"Extradata none",
"Extradata MB Quantization",
"Extradata Interlace Video",
"Extradata VC1 Framedisp",
"Extradata VC1 Seqdisp",
"Extradata timestamp",
"Extradata S3D Frame Packing",
"Extradata Frame Rate",
"Extradata Panscan Window",
"Extradata Recovery point SEI",
"Extradata Closed Caption UD",
"Extradata AFD UD",
"Extradata Multislice info",
"Extradata number of concealed MB",
"Extradata metadata filler",
"Extradata input crop",
"Extradata digital zoom",
"Extradata aspect ratio",
"Extradata mpeg2 seqdisp",
2024-09-09 08:57:42 +00:00
"Extradata stream userdata",
"Extradata frame QP",
"Extradata frame bits info",
"Extradata VQZip SEI",
};
static const char *const mpeg_vidc_video_alloc_mode_type[] = {
"Buffer Allocation Static",
"Buffer Allocation Ring Buffer",
"Buffer Allocation Dynamic Buffer"
2024-09-09 08:52:07 +00:00
};
static const char *const perf_level[] = {
"Nominal",
"Performance",
"Turbo"
};
2024-09-09 08:57:42 +00:00
static const char *const h263_level[] = {
"1.0",
"2.0",
"3.0",
"4.0",
"4.5",
"5.0",
"6.0",
"7.0",
};
static const char *const h263_profile[] = {
"Baseline",
"H320 Coding",
"Backward Compatible",
"ISWV2",
"ISWV3",
"High Compression",
"Internet",
"Interlace",
"High Latency",
};
static const char *const vp8_profile_level[] = {
"Unused",
"0.0",
"1.0",
"2.0",
"3.0",
};
static const char *const mpeg2_profile[] = {
"Simple",
"Main",
"422",
"Snr Scalable",
"Spatial Scalable",
"High",
};
static const char *const mpeg2_level[] = {
"0",
"1",
"2",
"3",
};
static const char *const mpeg_vidc_video_entropy_mode[] = {
"CAVLC Entropy Mode",
"CABAC Entropy Mode",
};
static const char *const mpeg_vidc_video_h264_mvc_layout[] = {
"Frame packing arrangement sequential",
"Frame packing arrangement top-bottom",
};
static const char *const mpeg_vidc_video_dpb_color_format[] = {
"DPB Color Format None",
"DPB Color Format UBWC",
"DPB Color Format UBWC TP10",
};
2024-09-09 08:52:07 +00:00
static struct msm_vidc_ctrl msm_vdec_ctrls[] = {
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT,
.name = "NAL Format",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
.maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH,
.default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) |
(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER) |
(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH) |
(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH) |
(1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH)
),
.qmenu = mpeg_video_stream_format,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER,
.name = "Output Order",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
.maximum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE,
.default_value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) |
(1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE)
),
.qmenu = mpeg_video_output_order,
},
{
2024-09-09 08:57:42 +00:00
.id = V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE,
2024-09-09 08:52:07 +00:00
.name = "Picture Type Decoding",
2024-09-09 08:57:42 +00:00
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.default_value = 0,
2024-09-09 08:52:07 +00:00
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO,
.name = "Keep Aspect Ratio",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.default_value = 0,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE,
.name = "Deblocker Mode",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.default_value = 0,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT,
.name = "Divx Format",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
.maximum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6,
.default_value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4) |
(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5) |
(1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6)
),
.qmenu = mpeg_video_vidc_divx_format,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING,
.name = "MB Error Map Reporting",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.default_value = 0,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER,
.name = "control",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.default_value = 0,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE,
.name = "Sync Frame Decode",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE,
.maximum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE,
.default_value = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE,
2024-09-09 08:57:42 +00:00
.step = 1,
2024-09-09 08:52:07 +00:00
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE,
.name = "Secure mode",
.type = V4L2_CTRL_TYPE_BUTTON,
.minimum = 0,
.maximum = 0,
.default_value = 0,
.step = 0,
.menu_skip_mask = 0,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA,
.name = "Extradata Type",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE,
2024-09-09 08:57:42 +00:00
.maximum = V4L2_MPEG_VIDC_EXTRADATA_VQZIP_SEI,
2024-09-09 08:52:07 +00:00
.default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) |
2024-09-09 08:57:42 +00:00
(1 << V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO) |
(1 << V4L2_MPEG_VIDC_EXTRADATA_VQZIP_SEI)
2024-09-09 08:52:07 +00:00
),
.qmenu = mpeg_video_vidc_extradata,
},
{
.id = V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL,
2024-09-09 08:57:42 +00:00
.name = "Decoder Performance Level",
2024-09-09 08:52:07 +00:00
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
.maximum = V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO,
.default_value = V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL,
.menu_skip_mask = ~(
(1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL) |
(1 << V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO)),
.qmenu = perf_level,
2024-09-09 08:57:42 +00:00
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT,
.name = "Buffer allocation mode for input",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
.maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
.default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
(1 << V4L2_MPEG_VIDC_VIDEO_RING) |
(1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
),
.qmenu = mpeg_vidc_video_alloc_mode_type,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT,
.name = "Buffer allocation mode for output",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_STATIC,
.maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC,
.default_value = V4L2_MPEG_VIDC_VIDEO_STATIC,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_STATIC) |
(1 << V4L2_MPEG_VIDC_VIDEO_RING) |
(1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC)
),
.qmenu = mpeg_vidc_video_alloc_mode_type,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY,
.name = "Video frame assembly",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE,
.maximum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE,
.default_value = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE,
.name = "Video decoder multi stream",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum =
V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
.maximum =
V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY,
.default_value =
V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY,
.menu_skip_mask = 0,
.step = 1,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
.name = "MPEG4 Profile",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
.maximum =
V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY,
.default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE,
.menu_skip_mask = 0,
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
},
{
.id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
.name = "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,
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_PROFILE,
.name = "H264 Profile",
.type = V4L2_CTRL_TYPE_MENU,
.maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH,
.default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE,
.menu_skip_mask = 0,
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_LEVEL,
.name = "H264 Level",
.type = V4L2_CTRL_TYPE_MENU,
.maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_2,
.default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0,
.menu_skip_mask = 0,
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE,
.name = "H263 Profile",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
.maximum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY,
.default_value = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)
),
.qmenu = h263_profile,
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL,
.name = "H263 Level",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
.maximum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0,
.default_value = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0) |
(1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)
),
.qmenu = h263_level,
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL,
.name = "VP8 Profile Level",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED,
.maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1,
.default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) |
(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) |
(1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)
),
.qmenu = vp8_profile_level,
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE,
.name = "MPEG2 Profile",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE,
.maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH,
.default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE) |
(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN) |
(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_422) |
(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SNR_SCALABLE) |
(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SPATIAL_SCALABLE) |
(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH)
),
.qmenu = mpeg2_profile,
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL,
.name = "MPEG2 Level",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0,
.maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3,
.default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0) |
(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_1) |
(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2) |
(1 << V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3)
),
.qmenu = mpeg2_level,
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD,
.name = "Video start code search threshold",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 1,
.maximum = INT_MAX,
.default_value = INT_MAX,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT,
.name = "MVC buffer layout",
.type = V4L2_CTRL_TYPE_MENU,
.maximum = V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM,
.default_value = V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL) |
(1 << V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM)
),
.qmenu = mpeg_vidc_video_h264_mvc_layout,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR,
.name = "Picture concealed color",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0x0,
.maximum = 0xffffff,
.default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK,
.step = 1,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT,
.name = "Buffer size limit",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = INT_MAX,
.default_value = 0,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD,
.name = "Secure scaling output2 threshold",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = INT_MAX,
.default_value = 0,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2,
.name = "Non-Secure output2",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = 0,
.maximum = 1,
.default_value = 0,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT,
.name = "Video decoder dpb color format",
.type = V4L2_CTRL_TYPE_MENU,
.minimum = V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE,
.maximum = V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC,
.default_value = V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE,
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE) |
(1 << V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC) |
(1 << V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC)
),
.qmenu = mpeg_vidc_video_dpb_color_format,
},
{
.id = V4L2_CID_VIDC_QBUF_MODE,
.name = "Allows batching of buffers for power savings",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = V4L2_VIDC_QBUF_STANDARD,
.maximum = V4L2_VIDC_QBUF_BATCHED,
.default_value = V4L2_VIDC_QBUF_STANDARD,
.step = 1,
},
{
.id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
.name = "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,
2024-09-09 08:52:07 +00:00
.step = 0,
2024-09-09 08:57:42 +00:00
.menu_skip_mask = ~(
(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) |
(1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)
),
.qmenu = mpeg_vidc_video_entropy_mode,
.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_READ_ONLY,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY,
.name = "Session Priority",
.type = V4L2_CTRL_TYPE_BOOLEAN,
.minimum = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_ENABLE,
.maximum = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE,
.default_value = V4L2_MPEG_VIDC_VIDEO_PRIORITY_REALTIME_DISABLE,
.step = 1,
},
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE,
.name = "Set Decoder Operating rate",
.type = V4L2_CTRL_TYPE_INTEGER,
.minimum = 0,
.maximum = MAX_OPERATING_FRAME_RATE,
.default_value = 0,
.step = OPERATING_FRAME_RATE_STEP,
2024-09-09 08:52:07 +00:00
},
};
#define NUM_CTRLS ARRAY_SIZE(msm_vdec_ctrls)
2024-09-09 08:57:42 +00:00
static int set_buffer_size(struct msm_vidc_inst *inst,
u32 buffer_size, enum hal_buffer buffer_type);
static int update_output_buffer_size(struct msm_vidc_inst *inst,
struct v4l2_format *f, int num_planes);
static int vdec_hal_to_v4l2(int id, int value);
2024-09-09 08:52:07 +00:00
static u32 get_frame_size_nv12(int plane,
u32 height, u32 width)
{
return VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
}
2024-09-09 08:57:42 +00:00
static u32 get_frame_size_nv12_ubwc(int plane, u32 height, u32 width)
{
return VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
}
2024-09-09 08:52:07 +00:00
static u32 get_frame_size_compressed(int plane,
2024-09-09 08:57:42 +00:00
u32 max_mbs_per_frame, u32 size_per_mb)
{
return (max_mbs_per_frame * size_per_mb * 3/2)/2;
}
static u32 get_frame_size(struct msm_vidc_inst *inst,
const struct msm_vidc_format *fmt,
int fmt_type, int plane)
{
u32 frame_size = 0;
if (fmt_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
frame_size = fmt->get_frame_size(plane,
inst->capability.mbs_per_frame.max,
MB_SIZE_IN_PIXEL);
if (inst->buffer_size_limit &&
(inst->buffer_size_limit < frame_size)) {
frame_size = inst->buffer_size_limit;
dprintk(VIDC_DBG, "input buffer size limited to %d\n",
frame_size);
} else {
dprintk(VIDC_DBG, "set input buffer size to %d\n",
frame_size);
}
} else if (fmt_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
frame_size = fmt->get_frame_size(plane,
inst->capability.height.max,
inst->capability.width.max);
dprintk(VIDC_DBG, "set output buffer size to %d\n",
frame_size);
} else {
dprintk(VIDC_WARN, "Wrong format type\n");
}
return frame_size;
}
static int is_ctrl_valid_for_codec(struct msm_vidc_inst *inst,
struct v4l2_ctrl *ctrl)
2024-09-09 08:52:07 +00:00
{
2024-09-09 08:57:42 +00:00
int rc = 0;
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT:
if (inst->fmts[OUTPUT_PORT]->fourcc != V4L2_PIX_FMT_H264_MVC) {
dprintk(VIDC_ERR, "Control %#x only valid for MVC\n",
ctrl->id);
rc = -ENOTSUPP;
break;
}
break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
if (inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_H264_MVC &&
ctrl->val != V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) {
dprintk(VIDC_ERR,
"Profile %#x not supported for MVC\n",
ctrl->val);
rc = -ENOTSUPP;
break;
}
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
if (inst->fmts[OUTPUT_PORT]->fourcc == V4L2_PIX_FMT_H264_MVC &&
ctrl->val >= V4L2_MPEG_VIDEO_H264_LEVEL_5_2) {
dprintk(VIDC_ERR, "Level %#x not supported for MVC\n",
ctrl->val);
rc = -ENOTSUPP;
break;
}
break;
default:
break;
}
return rc;
2024-09-09 08:52:07 +00:00
}
struct msm_vidc_format vdec_formats[] = {
{
.name = "YCbCr Semiplanar 4:2:0",
.description = "Y/CbCr 4:2:0",
.fourcc = V4L2_PIX_FMT_NV12,
.num_planes = 2,
.get_frame_size = get_frame_size_nv12,
.type = CAPTURE_PORT,
},
2024-09-09 08:57:42 +00:00
{
.name = "UBWC YCbCr Semiplanar 4:2:0",
.description = "UBWC Y/CbCr 4:2:0",
.fourcc = V4L2_PIX_FMT_NV12_UBWC,
.num_planes = 2,
.get_frame_size = get_frame_size_nv12_ubwc,
.type = CAPTURE_PORT,
},
2024-09-09 08:52:07 +00:00
{
.name = "Mpeg4",
.description = "Mpeg4 compressed format",
.fourcc = V4L2_PIX_FMT_MPEG4,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
{
.name = "Mpeg2",
.description = "Mpeg2 compressed format",
.fourcc = V4L2_PIX_FMT_MPEG2,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
{
.name = "H263",
.description = "H263 compressed format",
.fourcc = V4L2_PIX_FMT_H263,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
{
.name = "VC1",
.description = "VC-1 compressed format",
.fourcc = V4L2_PIX_FMT_VC1_ANNEX_G,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
{
.name = "VC1 SP",
.description = "VC-1 compressed format G",
.fourcc = V4L2_PIX_FMT_VC1_ANNEX_L,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
{
.name = "H264",
.description = "H264 compressed format",
.fourcc = V4L2_PIX_FMT_H264,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
2024-09-09 08:57:42 +00:00
{
.name = "H264_MVC",
.description = "H264_MVC compressed format",
.fourcc = V4L2_PIX_FMT_H264_MVC,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
2024-09-09 08:52:07 +00:00
{
.name = "HEVC",
.description = "HEVC compressed format",
.fourcc = V4L2_PIX_FMT_HEVC,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
2024-09-09 08:57:42 +00:00
{
.name = "HEVC_HYBRID",
.description = "HEVC compressed format",
.fourcc = V4L2_PIX_FMT_HEVC_HYBRID,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
2024-09-09 08:52:07 +00:00
{
.name = "VP8",
.description = "VP8 compressed format",
.fourcc = V4L2_PIX_FMT_VP8,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
2024-09-09 08:57:42 +00:00
{
.name = "VP9",
.description = "VP9 compressed format",
.fourcc = V4L2_PIX_FMT_VP9,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
2024-09-09 08:52:07 +00:00
{
.name = "DIVX 311",
.description = "DIVX 311 compressed format",
.fourcc = V4L2_PIX_FMT_DIVX_311,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
},
{
.name = "DIVX",
.description = "DIVX 4/5/6 compressed format",
.fourcc = V4L2_PIX_FMT_DIVX,
.num_planes = 1,
.get_frame_size = get_frame_size_compressed,
.type = OUTPUT_PORT,
}
};
int msm_vdec_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
{
int rc = 0;
struct buf_queue *q;
q = msm_comm_get_vb2q(inst, i);
if (!q) {
dprintk(VIDC_ERR,
"Failed to find buffer queue for type = %d\n", i);
return -EINVAL;
}
dprintk(VIDC_DBG, "Calling streamon\n");
mutex_lock(&q->lock);
rc = vb2_streamon(&q->vb2_bufq, i);
mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_ERR, "streamon failed on port: %d\n", i);
return rc;
}
int msm_vdec_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i)
{
int rc = 0;
struct buf_queue *q;
q = msm_comm_get_vb2q(inst, i);
if (!q) {
dprintk(VIDC_ERR,
"Failed to find buffer queue for type = %d\n", i);
return -EINVAL;
}
dprintk(VIDC_DBG, "Calling streamoff\n");
mutex_lock(&q->lock);
rc = vb2_streamoff(&q->vb2_bufq, i);
mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_ERR, "streamoff failed on port: %d\n", i);
return rc;
}
int msm_vdec_prepare_buf(struct msm_vidc_inst *inst,
struct v4l2_buffer *b)
{
int rc = 0;
struct vidc_buffer_addr_info buffer_info;
int extra_idx = 0;
int i;
struct hfi_device *hdev;
if (!inst || !inst->core || !inst->core->device) {
2024-09-09 08:57:42 +00:00
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
2024-09-09 08:52:07 +00:00
return -EINVAL;
}
hdev = inst->core->device;
2024-09-09 08:57:42 +00:00
if (inst->state == MSM_VIDC_CORE_INVALID ||
inst->core->state == VIDC_CORE_INVALID) {
dprintk(VIDC_ERR,
"Core %p in bad state, ignoring prepare buf\n",
inst->core);
goto exit;
}
2024-09-09 08:52:07 +00:00
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
2024-09-09 08:57:42 +00:00
if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
dprintk(VIDC_ERR,
"Planes mismatch: needed: %d, allocated: %d\n",
inst->fmts[CAPTURE_PORT]->num_planes,
b->length);
rc = -EINVAL;
break;
}
for (i = 0; i < min_t(int, b->length, VIDEO_MAX_PLANES); ++i) {
dprintk(VIDC_DBG,
"prepare plane: %d, device_addr = %#lx, size = %d\n",
i, b->m.planes[i].m.userptr,
b->m.planes[i].length);
}
buffer_info.buffer_size = b->m.planes[0].length;
buffer_info.buffer_type = msm_comm_get_hal_output_buffer(inst);
buffer_info.num_buffers = 1;
buffer_info.align_device_addr = b->m.planes[0].m.userptr;
extra_idx = EXTRADATA_IDX(b->length);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES &&
b->m.planes[extra_idx].m.userptr) {
buffer_info.extradata_addr =
b->m.planes[extra_idx].m.userptr;
buffer_info.extradata_size =
b->m.planes[extra_idx].length;
dprintk(VIDC_DBG, "extradata: %pa, length = %d\n",
&buffer_info.extradata_addr,
buffer_info.extradata_size);
} else {
buffer_info.extradata_addr = 0;
buffer_info.extradata_size = 0;
}
rc = call_hfi_op(hdev, session_set_buffers,
(void *)inst->session, &buffer_info);
if (rc) {
dprintk(VIDC_ERR,
"vidc_hal_session_set_buffers failed\n");
}
2024-09-09 08:52:07 +00:00
break;
default:
dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
break;
}
2024-09-09 08:57:42 +00:00
exit:
2024-09-09 08:52:07 +00:00
return rc;
}
int msm_vdec_release_buf(struct msm_vidc_inst *inst,
struct v4l2_buffer *b)
{
int rc = 0;
struct vidc_buffer_addr_info buffer_info;
2024-09-09 08:57:42 +00:00
struct msm_vidc_core *core;
2024-09-09 08:52:07 +00:00
int extra_idx = 0;
int i;
struct hfi_device *hdev;
if (!inst || !inst->core || !inst->core->device) {
2024-09-09 08:57:42 +00:00
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
2024-09-09 08:52:07 +00:00
return -EINVAL;
}
2024-09-09 08:57:42 +00:00
core = inst->core;
2024-09-09 08:52:07 +00:00
hdev = inst->core->device;
if (inst->state == MSM_VIDC_CORE_INVALID ||
core->state == VIDC_CORE_INVALID) {
dprintk(VIDC_ERR,
"Core %p in bad state, ignoring release output buf\n",
core);
goto exit;
}
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
switch (b->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
2024-09-09 08:57:42 +00:00
if (b->length != inst->fmts[CAPTURE_PORT]->num_planes) {
dprintk(VIDC_ERR,
"Planes mismatch: needed: %d, to release: %d\n",
inst->fmts[CAPTURE_PORT]->num_planes, b->length);
rc = -EINVAL;
break;
}
for (i = 0; i < b->length; ++i) {
dprintk(VIDC_DBG,
"Release plane: %d device_addr = %#lx, size = %d\n",
i, b->m.planes[i].m.userptr,
b->m.planes[i].length);
}
buffer_info.buffer_size = b->m.planes[0].length;
buffer_info.buffer_type = msm_comm_get_hal_output_buffer(inst);
buffer_info.num_buffers = 1;
buffer_info.align_device_addr = b->m.planes[0].m.userptr;
buffer_info.response_required = false;
extra_idx = EXTRADATA_IDX(b->length);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES
&& b->m.planes[extra_idx].m.userptr)
buffer_info.extradata_addr =
b->m.planes[extra_idx].m.userptr;
else
buffer_info.extradata_addr = 0;
rc = call_hfi_op(hdev, session_release_buffers,
(void *)inst->session, &buffer_info);
if (rc)
dprintk(VIDC_ERR,
"vidc_hal_session_release_buffers failed\n");
2024-09-09 08:52:07 +00:00
break;
default:
dprintk(VIDC_ERR, "Buffer type not recognized: %d\n", b->type);
break;
}
exit:
return rc;
}
int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
{
struct buf_queue *q = NULL;
int rc = 0;
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
, b->type);
return -EINVAL;
}
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
mutex_lock(&q->lock);
rc = vb2_qbuf(&q->vb2_bufq, b);
mutex_unlock(&q->lock);
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
if (rc)
dprintk(VIDC_ERR, "Failed to qbuf, %d\n", rc);
return rc;
}
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
int msm_vdec_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b)
{
struct buf_queue *q = NULL;
int rc = 0;
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
, b->type);
return -EINVAL;
}
mutex_lock(&q->lock);
rc = vb2_dqbuf(&q->vb2_bufq, b, true);
mutex_unlock(&q->lock);
if (rc)
dprintk(VIDC_DBG, "Failed to dqbuf, %d\n", rc);
return rc;
}
int msm_vdec_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b)
{
struct buf_queue *q = NULL;
int rc = 0;
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
if (!inst || !b) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, buffer = %p\n", inst, b);
return -EINVAL;
}
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
q = msm_comm_get_vb2q(inst, b->type);
if (!q) {
dprintk(VIDC_ERR, "Failed to find buffer queue for type = %d\n"
, b->type);
return -EINVAL;
}
mutex_lock(&q->lock);
rc = vb2_reqbufs(&q->vb2_bufq, b);
mutex_unlock(&q->lock);
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
if (rc)
2024-09-09 08:57:42 +00:00
dprintk(VIDC_DBG, "Failed to get reqbufs, %d\n", rc);
2024-09-09 08:52:07 +00:00
return rc;
}
int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
const struct msm_vidc_format *fmt = NULL;
struct hfi_device *hdev;
2024-09-09 08:57:42 +00:00
int rc = 0, i = 0, stride = 0, scanlines = 0, color_format = 0;
unsigned int *plane_sizes = NULL, extra_idx = 0;
struct hal_buffer_requirements *bufreq;
2024-09-09 08:52:07 +00:00
if (!inst || !f || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, format = %p\n", inst, f);
return -EINVAL;
}
2024-09-09 08:57:42 +00:00
rc = msm_comm_try_get_bufreqs(inst);
if (rc) {
dprintk(VIDC_ERR, "Getting buffer requirements failed: %d\n",
rc);
return rc;
}
2024-09-09 08:52:07 +00:00
hdev = inst->core->device;
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
fmt = inst->fmts[CAPTURE_PORT];
else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
fmt = inst->fmts[OUTPUT_PORT];
2024-09-09 08:57:42 +00:00
else
return -ENOTSUPP;
f->fmt.pix_mp.pixelformat = fmt->fourcc;
f->fmt.pix_mp.num_planes = fmt->num_planes;
if (inst->in_reconfig) {
bool ds_enabled = msm_comm_g_ctrl_for_id(inst,
V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO);
/*
* Do not update height and width on capture port, if
* downscalar is explicitly enabled from v4l2 client.
*/
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY && ds_enabled) {
inst->prop.height[OUTPUT_PORT] = inst->reconfig_height;
inst->prop.width[OUTPUT_PORT] = inst->reconfig_width;
} else {
inst->prop.height[CAPTURE_PORT] = inst->reconfig_height;
inst->prop.width[CAPTURE_PORT] = inst->reconfig_width;
inst->prop.height[OUTPUT_PORT] = inst->reconfig_height;
inst->prop.width[OUTPUT_PORT] = inst->reconfig_width;
2024-09-09 08:52:07 +00:00
}
2024-09-09 08:57:42 +00:00
rc = msm_vidc_check_session_supported(inst);
2024-09-09 08:52:07 +00:00
if (rc) {
dprintk(VIDC_ERR,
2024-09-09 08:57:42 +00:00
"%s: unsupported session\n", __func__);
2024-09-09 08:52:07 +00:00
goto exit;
}
2024-09-09 08:57:42 +00:00
}
f->fmt.pix_mp.height = inst->prop.height[CAPTURE_PORT];
f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
stride = inst->prop.width[CAPTURE_PORT];
scanlines = inst->prop.height[CAPTURE_PORT];
rc = msm_comm_try_get_bufreqs(inst);
if (rc) {
dprintk(VIDC_ERR,
"%s: Failed : Buffer requirements\n", __func__);
goto exit;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
plane_sizes = &inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[0];
for (i = 0; i < fmt->num_planes; ++i) {
if (!plane_sizes[i]) {
2024-09-09 08:52:07 +00:00
f->fmt.pix_mp.plane_fmt[i].sizeimage =
2024-09-09 08:57:42 +00:00
get_frame_size(inst, fmt, f->type, i);
plane_sizes[i] = f->fmt.pix_mp.plane_fmt[i].
sizeimage;
} else
f->fmt.pix_mp.plane_fmt[i].sizeimage =
plane_sizes[i];
}
} else {
switch (fmt->fourcc) {
case V4L2_PIX_FMT_NV12:
color_format = COLOR_FMT_NV12;
break;
case V4L2_PIX_FMT_NV12_UBWC:
color_format = COLOR_FMT_NV12_UBWC;
break;
case V4L2_PIX_FMT_NV12_TP10_UBWC:
color_format = COLOR_FMT_NV12_BPP10_UBWC;
break;
default:
dprintk(VIDC_WARN, "Color format not recognized\n");
rc = -ENOTSUPP;
goto exit;
}
2024-09-09 08:52:07 +00:00
2024-09-09 08:57:42 +00:00
stride = VENUS_Y_STRIDE(color_format,
inst->prop.width[CAPTURE_PORT]);
scanlines = VENUS_Y_SCANLINES(color_format,
inst->prop.height[CAPTURE_PORT]);
bufreq = get_buff_req_buffer(inst,
msm_comm_get_hal_output_buffer(inst));
f->fmt.pix_mp.plane_fmt[0].sizeimage =
bufreq ? bufreq->buffer_size : 0;
extra_idx = EXTRADATA_IDX(fmt->num_planes);
if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
bufreq = get_buff_req_buffer(inst,
2024-09-09 08:52:07 +00:00
HAL_BUFFER_EXTRADATA_OUTPUT);
2024-09-09 08:57:42 +00:00
f->fmt.pix_mp.plane_fmt[extra_idx].sizeimage =
bufreq ? bufreq->buffer_size : 0;
2024-09-09 08:52:07 +00:00
}
2024-09-09 08:57:42 +00:00
for (i = 0; i < fmt->num_planes; ++i)
inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
rc = update_output_buffer_size(inst, f, fmt->num_planes);
if (rc) {
dprintk(VIDC_ERR,
"%s - failed to update buffer size: %d\n",
__func__, rc);
goto exit;
}
}
if (stride && scanlines) {
f->fmt.pix_mp.plane_fmt[0].bytesperline =
(__u16)stride;
f->fmt.pix_mp.plane_fmt[0].reserved[0] =
(__u16)scanlines;
} else {
f->fmt.pix_mp.plane_fmt[0].bytesperline =
(__u16)inst->prop.width[CAPTURE_PORT];
f->fmt.pix_mp.plane_fmt[0].reserved[0] =
(__u16)inst->prop.height[CAPTURE_PORT];
}
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
f->fmt.pix_mp.height = inst->prop.height[CAPTURE_PORT];
f->fmt.pix_mp.width = inst->prop.width[CAPTURE_PORT];
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
f->fmt.pix_mp.height = inst->prop.height[OUTPUT_PORT];
f->fmt.pix_mp.width = inst->prop.width[OUTPUT_PORT];
2024-09-09 08:52:07 +00:00
f->fmt.pix_mp.plane_fmt[0].bytesperline =
2024-09-09 08:57:42 +00:00
(__u16)inst->prop.width[OUTPUT_PORT];
2024-09-09 08:52:07 +00:00
f->fmt.pix_mp.plane_fmt[0].reserved[0] =
2024-09-09 08:57:42 +00:00
(__u16)inst->prop.height[OUTPUT_PORT];
2024-09-09 08:52:07 +00:00
}
}
exit:
return rc;
}
2024-09-09 08:57:42 +00:00
static int set_buffer_size(struct msm_vidc_inst *inst,
u32 buffer_size, enum hal_buffer buffer_type)
2024-09-09 08:52:07 +00:00
{
2024-09-09 08:57:42 +00:00
int rc = 0;
struct hfi_device *hdev;
struct hal_buffer_size_minimum b;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
return -EINVAL;
2024-09-09 08:52:07 +00:00
}
2024-09-09 08:57:42 +00:00
hdev = inst->core->device;
dprintk(VIDC_DBG,
"Set minimum buffer size = %d for buffer type %d to fw\n",
buffer_size, buffer_type);
b.buffer_type = buffer_type;
b.buffer_size = buffer_size;
rc = call_hfi_op(hdev, session_set_property,
inst->session, HAL_PARAM_BUFFER_SIZE_MINIMUM,
&b);
if (rc)
2024-09-09 08:52:07 +00:00
dprintk(VIDC_ERR,
2024-09-09 08:57:42 +00:00
"%s - failed to set actual buffer size %u on firmware\n",
__func__, buffer_size);
return rc;
}
static int update_output_buffer_size(struct msm_vidc_inst *inst,
struct v4l2_format *f, int num_planes)
{
int rc = 0, i = 0;
struct hal_buffer_requirements *bufreq;
if (!inst || !f)
return -EINVAL;
/*
* Firmware expects driver to always set the minimum buffer
* size negotiated with the v4l2 client. Firmware will use this
* size to check for buffer sufficiency in dynamic buffer mode.
*/
for (i = 0; i < num_planes; ++i) {
enum hal_buffer type = msm_comm_get_hal_output_buffer(inst);
if (EXTRADATA_IDX(num_planes) &&
i == EXTRADATA_IDX(num_planes))
continue;
bufreq = get_buff_req_buffer(inst, type);
if (!bufreq)
goto exit;
if (f->fmt.pix_mp.plane_fmt[i].sizeimage >=
bufreq->buffer_size) {
rc = set_buffer_size(inst,
f->fmt.pix_mp.plane_fmt[i].sizeimage, type);
if (rc)
goto exit;
}
}
/*
* Set min buffer size for DPB buffers as well.
* Firmware mandates setting of minimum buffer size
* and actual buffer count for both OUTPUT and OUTPUT2.
* Hence we are setting back the same buffer size
* information back to firmware.
*/
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
bufreq = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT);
if (!bufreq) {
rc = -EINVAL;
goto exit;
}
rc = set_buffer_size(inst, bufreq->buffer_size,
HAL_BUFFER_OUTPUT);
if (rc)
goto exit;
2024-09-09 08:52:07 +00:00
}
2024-09-09 08:57:42 +00:00
/* Query buffer requirements from firmware */
rc = msm_comm_try_get_bufreqs(inst);
if (rc)
dprintk(VIDC_WARN,
"Failed to get buf req, %d\n", rc);
/* Read back updated firmware size */
for (i = 0; i < num_planes; ++i) {
enum hal_buffer type = msm_comm_get_hal_output_buffer(inst);
2024-09-09 08:52:07 +00:00
2024-09-09 08:57:42 +00:00
if (EXTRADATA_IDX(num_planes) &&
i == EXTRADATA_IDX(num_planes)) {
type = HAL_BUFFER_EXTRADATA_OUTPUT;
}
2024-09-09 08:52:07 +00:00
2024-09-09 08:57:42 +00:00
bufreq = get_buff_req_buffer(inst, type);
f->fmt.pix_mp.plane_fmt[i].sizeimage = bufreq ?
bufreq->buffer_size : 0;
dprintk(VIDC_DBG,
"updated buffer size for plane[%d] = %d\n",
i, f->fmt.pix_mp.plane_fmt[i].sizeimage);
2024-09-09 08:52:07 +00:00
}
exit:
return rc;
}
2024-09-09 08:57:42 +00:00
static int set_default_properties(struct msm_vidc_inst *inst)
{
struct hfi_device *hdev;
struct v4l2_control ctrl = {0};
enum hal_default_properties defaults;
int rc = 0;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s - invalid params\n", __func__);
return -EINVAL;
}
hdev = inst->core->device;
defaults = call_hfi_op(hdev, get_default_properties,
hdev->hfi_device_data);
if (defaults & HAL_VIDEO_DYNAMIC_BUF_MODE) {
dprintk(VIDC_DBG, "Enable dynamic buffer mode\n");
ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT;
ctrl.value = V4L2_MPEG_VIDC_VIDEO_DYNAMIC;
rc = msm_comm_s_ctrl(inst, &ctrl);
if (rc)
dprintk(VIDC_ERR,
"Failed to enable dynamic buffer mode by default: %d\n",
rc);
}
return rc;
}
2024-09-09 08:52:07 +00:00
int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f)
{
struct msm_vidc_format *fmt = NULL;
struct hal_frame_size frame_sz;
int rc = 0;
int ret = 0;
int i;
2024-09-09 08:57:42 +00:00
int max_input_size = 0;
2024-09-09 08:52:07 +00:00
if (!inst || !f) {
2024-09-09 08:57:42 +00:00
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
2024-09-09 08:52:07 +00:00
return -EINVAL;
}
2024-09-09 08:57:42 +00:00
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
2024-09-09 08:52:07 +00:00
fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
ARRAY_SIZE(vdec_formats), f->fmt.pix_mp.pixelformat,
CAPTURE_PORT);
2024-09-09 08:57:42 +00:00
if (!fmt || fmt->type != CAPTURE_PORT) {
2024-09-09 08:52:07 +00:00
dprintk(VIDC_ERR,
"Format: %d not supported on CAPTURE port\n",
f->fmt.pix_mp.pixelformat);
rc = -EINVAL;
goto err_invalid_fmt;
}
2024-09-09 08:57:42 +00:00
inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_PRIMARY) {
inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT,
f->fmt.pix_mp.pixelformat);
}
2024-09-09 08:52:07 +00:00
inst->fmts[fmt->type] = fmt;
2024-09-09 08:57:42 +00:00
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
frame_sz.width = inst->prop.width[CAPTURE_PORT];
frame_sz.height = inst->prop.height[CAPTURE_PORT];
msm_comm_set_color_format(inst, HAL_BUFFER_OUTPUT2,
f->fmt.pix_mp.pixelformat);
dprintk(VIDC_DBG,
"buffer type = %d width = %d, height = %d\n",
frame_sz.buffer_type, frame_sz.width,
frame_sz.height);
ret = msm_comm_try_set_prop(inst,
HAL_PARAM_FRAME_SIZE, &frame_sz);
}
2024-09-09 08:52:07 +00:00
ret = ret || msm_comm_try_get_bufreqs(inst);
if (ret) {
for (i = 0; i < fmt->num_planes; ++i) {
f->fmt.pix_mp.plane_fmt[i].sizeimage =
2024-09-09 08:57:42 +00:00
get_frame_size(inst, fmt, f->type, i);
2024-09-09 08:52:07 +00:00
}
} else {
2024-09-09 08:57:42 +00:00
rc = update_output_buffer_size(inst, f,
fmt->num_planes);
if (rc) {
dprintk(VIDC_ERR,
"%s - failed to update buffer size: %d\n",
__func__, rc);
goto err_invalid_fmt;
2024-09-09 08:52:07 +00:00
}
}
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
f->fmt.pix_mp.num_planes = fmt->num_planes;
for (i = 0; i < fmt->num_planes; ++i) {
inst->bufq[CAPTURE_PORT].vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
}
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
2024-09-09 08:57:42 +00:00
inst->prop.width[OUTPUT_PORT] = f->fmt.pix_mp.width;
inst->prop.height[OUTPUT_PORT] = f->fmt.pix_mp.height;
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_PRIMARY) {
inst->prop.width[CAPTURE_PORT] = f->fmt.pix_mp.width;
inst->prop.height[CAPTURE_PORT] = f->fmt.pix_mp.height;
}
2024-09-09 08:52:07 +00:00
rc = msm_vidc_check_session_supported(inst);
if (rc) {
dprintk(VIDC_ERR,
"%s: session not supported\n", __func__);
goto err_invalid_fmt;
}
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
fmt = msm_comm_get_pixel_fmt_fourcc(vdec_formats,
ARRAY_SIZE(vdec_formats),
f->fmt.pix_mp.pixelformat,
OUTPUT_PORT);
if (!fmt || fmt->type != OUTPUT_PORT) {
dprintk(VIDC_ERR,
"Format: %d not supported on OUTPUT port\n",
f->fmt.pix_mp.pixelformat);
rc = -EINVAL;
goto err_invalid_fmt;
}
2024-09-09 08:57:42 +00:00
rc = msm_comm_try_state(inst, MSM_VIDC_CORE_INIT_DONE);
if (rc) {
dprintk(VIDC_ERR, "Failed to initialize instance\n");
goto err_invalid_fmt;
}
if (!(get_hal_codec(fmt->fourcc) &
inst->core->dec_codec_supported)) {
dprintk(VIDC_ERR,
"Codec(%#x) is not present in the supported codecs list(%#x)\n",
get_hal_codec(fmt->fourcc),
inst->core->dec_codec_supported);
rc = -EINVAL;
goto err_invalid_fmt;
}
2024-09-09 08:52:07 +00:00
inst->fmts[fmt->type] = fmt;
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
dprintk(VIDC_ERR, "Failed to open instance\n");
goto err_invalid_fmt;
}
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
frame_sz.buffer_type = HAL_BUFFER_INPUT;
2024-09-09 08:57:42 +00:00
frame_sz.width = inst->prop.width[OUTPUT_PORT];
frame_sz.height = inst->prop.height[OUTPUT_PORT];
dprintk(VIDC_DBG,
"buffer type = %d width = %d, height = %d\n",
frame_sz.buffer_type, frame_sz.width,
frame_sz.height);
2024-09-09 08:52:07 +00:00
msm_comm_try_set_prop(inst, HAL_PARAM_FRAME_SIZE, &frame_sz);
2024-09-09 08:57:42 +00:00
max_input_size = get_frame_size(inst, fmt, f->type, 0);
if (f->fmt.pix_mp.plane_fmt[0].sizeimage > max_input_size ||
!f->fmt.pix_mp.plane_fmt[0].sizeimage) {
f->fmt.pix_mp.plane_fmt[0].sizeimage = max_input_size;
}
2024-09-09 08:52:07 +00:00
f->fmt.pix_mp.num_planes = fmt->num_planes;
for (i = 0; i < fmt->num_planes; ++i) {
inst->bufq[OUTPUT_PORT].vb2_bufq.plane_sizes[i] =
f->fmt.pix_mp.plane_fmt[i].sizeimage;
}
2024-09-09 08:57:42 +00:00
set_default_properties(inst);
2024-09-09 08:52:07 +00:00
}
err_invalid_fmt:
return rc;
}
int msm_vdec_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap)
{
if (!inst || !cap) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, cap = %p\n", inst, cap);
return -EINVAL;
}
strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
strlcpy(cap->card, MSM_VDEC_DVC_NAME, sizeof(cap->card));
cap->bus_info[0] = 0;
cap->version = MSM_VIDC_VERSION;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
V4L2_CAP_VIDEO_OUTPUT_MPLANE |
V4L2_CAP_STREAMING;
memset(cap->reserved, 0, sizeof(cap->reserved));
return 0;
}
int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f)
{
const struct msm_vidc_format *fmt = NULL;
int rc = 0;
if (!inst || !f) {
dprintk(VIDC_ERR,
"Invalid input, inst = %p, f = %p\n", inst, f);
return -EINVAL;
}
if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
ARRAY_SIZE(vdec_formats), f->index, CAPTURE_PORT);
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
fmt = msm_comm_get_pixel_fmt_index(vdec_formats,
ARRAY_SIZE(vdec_formats), f->index, OUTPUT_PORT);
f->flags = V4L2_FMT_FLAG_COMPRESSED;
}
memset(f->reserved, 0 , sizeof(f->reserved));
if (fmt) {
strlcpy(f->description, fmt->description,
sizeof(f->description));
f->pixelformat = fmt->fourcc;
} else {
2024-09-09 08:57:42 +00:00
dprintk(VIDC_DBG, "No more formats found\n");
2024-09-09 08:52:07 +00:00
rc = -EINVAL;
}
return rc;
}
2024-09-09 08:57:42 +00:00
static int set_actual_buffer_count(struct msm_vidc_inst *inst,
int count, enum hal_buffer type)
{
int rc = 0;
struct hfi_device *hdev;
struct hal_buffer_count_actual buf_count;
hdev = inst->core->device;
buf_count.buffer_type = type;
buf_count.buffer_count_actual = count;
rc = call_hfi_op(hdev, session_set_property,
inst->session, HAL_PARAM_BUFFER_COUNT_ACTUAL, &buf_count);
if (rc)
dprintk(VIDC_ERR,
"Failed to set actual buffer count %d for buffer type %d\n",
count, type);
return rc;
}
2024-09-09 08:52:07 +00:00
static int msm_vdec_queue_setup(struct vb2_queue *q,
const struct v4l2_format *fmt,
unsigned int *num_buffers,
unsigned int *num_planes, unsigned int sizes[],
void *alloc_ctxs[])
{
int i, rc = 0;
struct msm_vidc_inst *inst;
struct hal_buffer_requirements *bufreq;
int extra_idx = 0;
2024-09-09 08:57:42 +00:00
int min_buff_count = 0;
2024-09-09 08:52:07 +00:00
if (!q || !num_buffers || !num_planes
|| !sizes || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %p, %p, %p\n",
q, num_buffers, num_planes);
return -EINVAL;
}
inst = q->drv_priv;
if (!inst || !inst->core || !inst->core->device) {
2024-09-09 08:57:42 +00:00
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
2024-09-09 08:52:07 +00:00
return -EINVAL;
}
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
*num_planes = inst->fmts[OUTPUT_PORT]->num_planes;
if (*num_buffers < MIN_NUM_OUTPUT_BUFFERS ||
*num_buffers > MAX_NUM_OUTPUT_BUFFERS)
*num_buffers = MIN_NUM_OUTPUT_BUFFERS;
for (i = 0; i < *num_planes; i++) {
2024-09-09 08:57:42 +00:00
sizes[i] = get_frame_size(inst,
inst->fmts[OUTPUT_PORT], q->type, i);
2024-09-09 08:52:07 +00:00
}
2024-09-09 08:57:42 +00:00
rc = set_actual_buffer_count(inst, *num_buffers,
HAL_BUFFER_INPUT);
2024-09-09 08:52:07 +00:00
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
dprintk(VIDC_DBG, "Getting bufreqs on capture plane\n");
*num_planes = inst->fmts[CAPTURE_PORT]->num_planes;
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
dprintk(VIDC_ERR, "Failed to open instance\n");
break;
}
rc = msm_comm_try_get_bufreqs(inst);
if (rc) {
dprintk(VIDC_ERR,
"Failed to get buffer requirements: %d\n", rc);
break;
}
2024-09-09 08:57:42 +00:00
bufreq = get_buff_req_buffer(inst,
msm_comm_get_hal_output_buffer(inst));
2024-09-09 08:52:07 +00:00
if (!bufreq) {
dprintk(VIDC_ERR,
"No buffer requirement for buffer type %x\n",
HAL_BUFFER_OUTPUT);
rc = -EINVAL;
break;
}
2024-09-09 08:57:42 +00:00
/* Pretend as if FW itself is asking for
* additional buffers.
* *num_buffers += MSM_VIDC_ADDITIONAL_BUFS_FOR_DCVS
* is wrong since it will end up increasing the count
* on every call to reqbufs if *num_bufs is larger
* than min requirement.
*/
*num_buffers = max(*num_buffers, bufreq->buffer_count_min
+ msm_dcvs_get_extra_buff_count(inst));
min_buff_count = (!!(inst->flags & VIDC_THUMBNAIL)) ?
MIN_NUM_THUMBNAIL_MODE_CAPTURE_BUFFERS :
MIN_NUM_CAPTURE_BUFFERS;
*num_buffers = clamp_val(*num_buffers,
min_buff_count, VB2_MAX_FRAME);
dprintk(VIDC_DBG, "Set actual output buffer count: %d\n",
*num_buffers);
rc = set_actual_buffer_count(inst, *num_buffers,
msm_comm_get_hal_output_buffer(inst));
if (rc)
break;
if (*num_buffers != bufreq->buffer_count_actual) {
rc = msm_comm_try_get_bufreqs(inst);
if (rc) {
dprintk(VIDC_WARN,
"Failed to get buf req, %d\n", rc);
break;
}
2024-09-09 08:52:07 +00:00
}
dprintk(VIDC_DBG, "count = %d, size = %d, alignment = %d\n",
inst->buff_req.buffer[1].buffer_count_actual,
inst->buff_req.buffer[1].buffer_size,
inst->buff_req.buffer[1].buffer_alignment);
sizes[0] = bufreq->buffer_size;
2024-09-09 08:57:42 +00:00
/*
* Set actual buffer count to firmware for DPB buffers.
* Firmware mandates setting of minimum buffer size
* and actual buffer count for both OUTPUT and OUTPUT2.
* Hence we are setting back the same buffer size
* information back to firmware.
*/
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
bufreq = get_buff_req_buffer(inst,
HAL_BUFFER_OUTPUT);
if (!bufreq) {
rc = -EINVAL;
break;
}
rc = set_actual_buffer_count(inst,
bufreq->buffer_count_actual,
HAL_BUFFER_OUTPUT);
if (rc)
break;
}
2024-09-09 08:52:07 +00:00
extra_idx =
EXTRADATA_IDX(inst->fmts[CAPTURE_PORT]->num_planes);
2024-09-09 08:57:42 +00:00
if (extra_idx && extra_idx < VIDEO_MAX_PLANES) {
2024-09-09 08:52:07 +00:00
bufreq = get_buff_req_buffer(inst,
HAL_BUFFER_EXTRADATA_OUTPUT);
if (bufreq)
sizes[extra_idx] = bufreq->buffer_size;
else
sizes[extra_idx] = 0;
}
break;
default:
dprintk(VIDC_ERR, "Invalid q type = %d\n", q->type);
rc = -EINVAL;
break;
}
return rc;
}
static inline int start_streaming(struct msm_vidc_inst *inst)
{
int rc = 0;
2024-09-09 08:57:42 +00:00
struct hfi_device *hdev;
hdev = inst->core->device;
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY)
rc = msm_vidc_check_scaling_supported(inst);
if (rc) {
dprintk(VIDC_ERR, "H/w scaling is not in valid range\n");
return -EINVAL;
}
2024-09-09 08:52:07 +00:00
rc = msm_comm_set_scratch_buffers(inst);
if (rc) {
dprintk(VIDC_ERR,
"Failed to set scratch buffers: %d\n", rc);
goto fail_start;
}
rc = msm_comm_set_persist_buffers(inst);
if (rc) {
dprintk(VIDC_ERR,
"Failed to set persist buffers: %d\n", rc);
goto fail_start;
}
2024-09-09 08:57:42 +00:00
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
rc = msm_comm_set_output_buffers(inst);
if (rc) {
dprintk(VIDC_ERR,
"Failed to set output buffers: %d\n", rc);
goto fail_start;
}
}
2024-09-09 08:52:07 +00:00
2024-09-09 08:57:42 +00:00
/*
* For seq_changed_insufficient, driver should set session_continue
* to firmware after the following sequence
* - driver raises insufficient event to v4l2 client
* - all output buffers have been flushed and freed
* - v4l2 client queries buffer requirements and splits/combines OPB-DPB
* - v4l2 client sets new set of buffers to firmware
* - v4l2 client issues CONTINUE to firmware to resume decoding of
* submitted ETBs.
*/
if (inst->in_reconfig) {
dprintk(VIDC_DBG, "send session_continue after reconfig\n");
rc = call_hfi_op(hdev, session_continue,
(void *) inst->session);
if (rc) {
dprintk(VIDC_ERR,
"%s - failed to send session_continue\n",
__func__);
goto fail_start;
}
}
inst->in_reconfig = false;
msm_comm_scale_clocks_and_bus(inst);
rc = msm_comm_try_state(inst, MSM_VIDC_START_DONE);
if (rc) {
2024-09-09 08:52:07 +00:00
dprintk(VIDC_ERR,
"Failed to move inst: %p to start done state\n", inst);
goto fail_start;
}
2024-09-09 08:57:42 +00:00
msm_dcvs_init_load(inst);
if (msm_comm_get_stream_output_mode(inst) ==
HAL_VIDEO_DECODER_SECONDARY) {
rc = msm_comm_queue_output_buffers(inst);
if (rc) {
dprintk(VIDC_ERR,
"Failed to queue output buffers: %d\n", rc);
goto fail_start;
2024-09-09 08:52:07 +00:00
}
}
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
fail_start:
return rc;
}
static inline int stop_streaming(struct msm_vidc_inst *inst)
{
int rc = 0;
rc = msm_comm_try_state(inst, MSM_VIDC_RELEASE_RESOURCES_DONE);
if (rc)
dprintk(VIDC_ERR,
"Failed to move inst: %p to start done state\n", inst);
return rc;
}
static int msm_vdec_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct msm_vidc_inst *inst;
int rc = 0;
2024-09-09 08:57:42 +00:00
struct hfi_device *hdev;
2024-09-09 08:52:07 +00:00
if (!q || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
return -EINVAL;
}
inst = q->drv_priv;
2024-09-09 08:57:42 +00:00
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
return -EINVAL;
}
hdev = inst->core->device;
dprintk(VIDC_DBG, "Streamon called on: %d capability for inst: %p\n",
q->type, inst);
2024-09-09 08:52:07 +00:00
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
rc = start_streaming(inst);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
if (inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
rc = start_streaming(inst);
break;
default:
2024-09-09 08:57:42 +00:00
dprintk(VIDC_ERR, "Queue type is not supported: %d\n", q->type);
2024-09-09 08:52:07 +00:00
rc = -EINVAL;
2024-09-09 08:57:42 +00:00
goto stream_start_failed;
2024-09-09 08:52:07 +00:00
}
2024-09-09 08:57:42 +00:00
if (rc) {
dprintk(VIDC_ERR,
"Streamon failed on: %d capability for inst: %p\n",
q->type, inst);
goto stream_start_failed;
}
rc = msm_comm_qbuf(inst, NULL);
if (rc) {
dprintk(VIDC_ERR,
"Failed to commit buffers queued before STREAM_ON to hardware: %d\n",
rc);
goto stream_start_failed;
}
stream_start_failed:
2024-09-09 08:52:07 +00:00
return rc;
}
2024-09-09 08:57:42 +00:00
static void msm_vdec_stop_streaming(struct vb2_queue *q)
2024-09-09 08:52:07 +00:00
{
struct msm_vidc_inst *inst;
int rc = 0;
if (!q || !q->drv_priv) {
dprintk(VIDC_ERR, "Invalid input, q = %p\n", q);
2024-09-09 08:57:42 +00:00
return;
2024-09-09 08:52:07 +00:00
}
2024-09-09 08:57:42 +00:00
2024-09-09 08:52:07 +00:00
inst = q->drv_priv;
dprintk(VIDC_DBG, "Streamoff called on: %d capability\n", q->type);
switch (q->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
if (!inst->bufq[CAPTURE_PORT].vb2_bufq.streaming)
rc = stop_streaming(inst);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
if (!inst->bufq[OUTPUT_PORT].vb2_bufq.streaming)
rc = stop_streaming(inst);
break;
default:
dprintk(VIDC_ERR,
"Q-type is not supported: %d\n", q->type);
rc = -EINVAL;
break;
}
msm_comm_scale_clocks_and_bus(inst);
if (rc)
dprintk(VIDC_ERR,
"Failed to move inst: %p, cap = %d to state: %d\n",
inst, q->type, MSM_VIDC_RELEASE_RESOURCES_DONE);
}
static void msm_vdec_buf_queue(struct vb2_buffer *vb)
{
2024-09-09 08:57:42 +00:00
int rc = msm_comm_qbuf(vb2_get_drv_priv(vb->vb2_queue), vb);
2024-09-09 08:52:07 +00:00
if (rc)
dprintk(VIDC_ERR, "Failed to queue buffer: %d\n", rc);
}
static const struct vb2_ops msm_vdec_vb2q_ops = {
.queue_setup = msm_vdec_queue_setup,
.start_streaming = msm_vdec_start_streaming,
.buf_queue = msm_vdec_buf_queue,
.stop_streaming = msm_vdec_stop_streaming,
};
const struct vb2_ops *msm_vdec_get_vb2q_ops(void)
{
return &msm_vdec_vb2q_ops;
}
int msm_vdec_inst_init(struct msm_vidc_inst *inst)
{
int rc = 0;
if (!inst) {
dprintk(VIDC_ERR, "Invalid input = %p\n", inst);
return -EINVAL;
}
2024-09-09 08:57:42 +00:00
inst->fmts[OUTPUT_PORT] = &vdec_formats[2];
2024-09-09 08:52:07 +00:00
inst->fmts[CAPTURE_PORT] = &vdec_formats[0];
2024-09-09 08:57:42 +00:00
inst->prop.height[CAPTURE_PORT] = DEFAULT_HEIGHT;
inst->prop.width[CAPTURE_PORT] = DEFAULT_WIDTH;
inst->prop.height[OUTPUT_PORT] = DEFAULT_HEIGHT;
inst->prop.width[OUTPUT_PORT] = DEFAULT_WIDTH;
2024-09-09 08:52:07 +00:00
inst->capability.height.min = MIN_SUPPORTED_HEIGHT;
inst->capability.height.max = DEFAULT_HEIGHT;
inst->capability.width.min = MIN_SUPPORTED_WIDTH;
inst->capability.width.max = DEFAULT_WIDTH;
2024-09-09 08:57:42 +00:00
inst->capability.alloc_mode_in = HAL_BUFFER_MODE_STATIC;
inst->capability.alloc_mode_out = HAL_BUFFER_MODE_STATIC;
inst->capability.secure_output2_threshold.min = 0;
inst->capability.secure_output2_threshold.max = 0;
inst->buffer_mode_set[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC;
inst->buffer_mode_set[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC;
inst->prop.fps = DEFAULT_FPS;
2024-09-09 08:52:07 +00:00
return rc;
}
2024-09-09 08:57:42 +00:00
static inline enum buffer_mode_type get_buf_type(int val)
{
switch (val) {
case V4L2_MPEG_VIDC_VIDEO_STATIC:
return HAL_BUFFER_MODE_STATIC;
case V4L2_MPEG_VIDC_VIDEO_RING:
return HAL_BUFFER_MODE_RING;
case V4L2_MPEG_VIDC_VIDEO_DYNAMIC:
return HAL_BUFFER_MODE_DYNAMIC;
default:
dprintk(VIDC_ERR, "%s: invalid buf type: %d\n", __func__, val);
}
return 0;
}
static int try_get_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
{
int rc = 0;
struct hfi_device *hdev;
union hal_get_property hprop;
if (!inst || !inst->core || !inst->core->device || !ctrl) {
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
return -EINVAL;
}
hdev = inst->core->device;
/*
* HACK: unlock the control prior to querying the hardware. Otherwise
* lower level code that attempts to do g_ctrl() will end up deadlocking
* us.
*/
v4l2_ctrl_unlock(ctrl);
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
rc = msm_comm_try_get_prop(inst,
HAL_PARAM_PROFILE_LEVEL_CURRENT, &hprop);
if (rc) {
dprintk(VIDC_ERR, "%s: Failed getting profile: %d",
__func__, rc);
break;
}
ctrl->val = vdec_hal_to_v4l2(ctrl->id,
hprop.profile_level.profile);
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
rc = msm_comm_try_get_prop(inst,
HAL_PARAM_PROFILE_LEVEL_CURRENT, &hprop);
if (rc) {
dprintk(VIDC_ERR, "%s: Failed getting level: %d",
__func__, rc);
break;
}
ctrl->val = vdec_hal_to_v4l2(ctrl->id,
hprop.profile_level.level);
break;
case V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD:
dprintk(VIDC_DBG, "Secure scaling threshold is: %d",
inst->capability.secure_output2_threshold.max);
ctrl->val = inst->capability.secure_output2_threshold.max;
break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
rc = msm_comm_try_get_prop(inst,
HAL_CONFIG_VDEC_ENTROPY, &hprop);
if (rc) {
dprintk(VIDC_ERR, "%s: Failed getting entropy type: %d",
__func__, rc);
break;
}
switch (hprop.h264_entropy) {
case HAL_H264_ENTROPY_CAVLC:
ctrl->val = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC;
break;
case HAL_H264_ENTROPY_CABAC:
ctrl->val = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC;
break;
case HAL_UNUSED_ENTROPY:
rc = -ENOTSUPP;
break;
}
break;
default:
/* Other controls aren't really volatile, shouldn't need to
* modify ctrl->value */
break;
}
v4l2_ctrl_lock(ctrl);
return rc;
}
static int vdec_v4l2_to_hal(int id, int value)
{
switch (id) {
/* H264 */
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
switch (value) {
case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
return HAL_H264_PROFILE_BASELINE;
case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
return HAL_H264_PROFILE_CONSTRAINED_BASE;
case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH:
return HAL_H264_PROFILE_CONSTRAINED_HIGH;
case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
return HAL_H264_PROFILE_MAIN;
case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED:
return HAL_H264_PROFILE_EXTENDED;
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
return HAL_H264_PROFILE_HIGH;
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10:
return HAL_H264_PROFILE_HIGH10;
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422:
return HAL_H264_PROFILE_HIGH422;
case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE:
return HAL_H264_PROFILE_HIGH444;
default:
goto unknown_value;
}
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
switch (value) {
case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
return HAL_H264_LEVEL_1;
case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
return HAL_H264_LEVEL_1b;
case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
return HAL_H264_LEVEL_11;
case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
return HAL_H264_LEVEL_12;
case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
return HAL_H264_LEVEL_13;
case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
return HAL_H264_LEVEL_2;
case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
return HAL_H264_LEVEL_21;
case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
return HAL_H264_LEVEL_22;
case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
return HAL_H264_LEVEL_3;
case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
return HAL_H264_LEVEL_31;
case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
return HAL_H264_LEVEL_32;
case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
return HAL_H264_LEVEL_4;
case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
return HAL_H264_LEVEL_41;
case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
return HAL_H264_LEVEL_42;
case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
return HAL_H264_LEVEL_5;
case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
return HAL_H264_LEVEL_51;
default:
goto unknown_value;
}
}
unknown_value:
dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value);
return -EINVAL;
}
static int vdec_hal_to_v4l2(int id, int value)
{
switch (id) {
/* H264 */
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
switch (value) {
case HAL_H264_PROFILE_BASELINE:
return V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE;
case HAL_H264_PROFILE_CONSTRAINED_BASE:
return
V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE;
case HAL_H264_PROFILE_MAIN:
return V4L2_MPEG_VIDEO_H264_PROFILE_MAIN;
case HAL_H264_PROFILE_EXTENDED:
return V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED;
case HAL_H264_PROFILE_HIGH:
return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH;
case HAL_H264_PROFILE_HIGH10:
return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10;
case HAL_H264_PROFILE_HIGH422:
return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422;
case HAL_H264_PROFILE_HIGH444:
return V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE;
default:
goto unknown_value;
}
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
switch (value) {
case HAL_H264_LEVEL_1:
return V4L2_MPEG_VIDEO_H264_LEVEL_1_0;
case HAL_H264_LEVEL_1b:
return V4L2_MPEG_VIDEO_H264_LEVEL_1B;
case HAL_H264_LEVEL_11:
return V4L2_MPEG_VIDEO_H264_LEVEL_1_1;
case HAL_H264_LEVEL_12:
return V4L2_MPEG_VIDEO_H264_LEVEL_1_2;
case HAL_H264_LEVEL_13:
return V4L2_MPEG_VIDEO_H264_LEVEL_1_3;
case HAL_H264_LEVEL_2:
return V4L2_MPEG_VIDEO_H264_LEVEL_2_0;
case HAL_H264_LEVEL_21:
return V4L2_MPEG_VIDEO_H264_LEVEL_2_1;
case HAL_H264_LEVEL_22:
return V4L2_MPEG_VIDEO_H264_LEVEL_2_2;
case HAL_H264_LEVEL_3:
return V4L2_MPEG_VIDEO_H264_LEVEL_3_0;
case HAL_H264_LEVEL_31:
return V4L2_MPEG_VIDEO_H264_LEVEL_3_1;
case HAL_H264_LEVEL_32:
return V4L2_MPEG_VIDEO_H264_LEVEL_3_2;
case HAL_H264_LEVEL_4:
return V4L2_MPEG_VIDEO_H264_LEVEL_4_0;
case HAL_H264_LEVEL_41:
return V4L2_MPEG_VIDEO_H264_LEVEL_4_1;
case HAL_H264_LEVEL_42:
return V4L2_MPEG_VIDEO_H264_LEVEL_4_2;
case HAL_H264_LEVEL_5:
return V4L2_MPEG_VIDEO_H264_LEVEL_5_0;
case HAL_H264_LEVEL_51:
return V4L2_MPEG_VIDEO_H264_LEVEL_5_1;
default:
goto unknown_value;
}
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE:
case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL:
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE:
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL:
case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL:
/*
* Extremely dirty hack: we haven't implemented g_ctrl of
* any of these controls and have no intention of doing
* so in the near future. So just return 0 so that we
* don't see the annoying "Unknown control" errors at the
* bottom of this function.
*/
return 0;
}
unknown_value:
dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value);
return -EINVAL;
}
static struct v4l2_ctrl *get_ctrl_from_cluster(int id,
struct v4l2_ctrl **cluster, int ncontrols)
{
int c;
for (c = 0; c < ncontrols; ++c)
if (cluster[c]->id == id)
return cluster[c];
return NULL;
}
2024-09-09 08:52:07 +00:00
static int try_set_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl)
{
int rc = 0;
struct hal_nal_stream_format_supported stream_format;
struct hal_enable_picture enable_picture;
2024-09-09 08:57:42 +00:00
struct hal_enable hal_property;
2024-09-09 08:52:07 +00:00
enum hal_property property_id = 0;
u32 property_val = 0;
void *pdata = NULL;
struct hfi_device *hdev;
2024-09-09 08:57:42 +00:00
struct hal_extradata_enable extra;
struct hal_buffer_alloc_mode alloc_mode;
struct hal_multi_stream multi_stream;
struct hal_scs_threshold scs_threshold;
struct hal_mvc_buffer_layout layout;
struct v4l2_ctrl *temp_ctrl = NULL;
struct hal_profile_level profile_level;
struct hal_frame_size frame_sz;
2024-09-09 08:52:07 +00:00
if (!inst || !inst->core || !inst->core->device) {
2024-09-09 08:57:42 +00:00
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
2024-09-09 08:52:07 +00:00
return -EINVAL;
}
hdev = inst->core->device;
2024-09-09 08:57:42 +00:00
rc = is_ctrl_valid_for_codec(inst, ctrl);
if (rc)
return rc;
/* Small helper macro for quickly getting a control and err checking */
#define TRY_GET_CTRL(__ctrl_id) ({ \
struct v4l2_ctrl *__temp; \
__temp = get_ctrl_from_cluster( \
__ctrl_id, \
ctrl->cluster, ctrl->ncontrols); \
if (!__temp) { \
dprintk(VIDC_ERR, "Can't find %s (%x) in cluster\n", \
#__ctrl_id, __ctrl_id); \
/* Clusters are hardcoded, if we can't find */ \
/* something then things are massively screwed up */ \
BUG_ON(1); \
} \
__temp; \
})
v4l2_ctrl_unlock(ctrl);
2024-09-09 08:52:07 +00:00
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT:
2024-09-09 08:57:42 +00:00
property_id = HAL_PARAM_NAL_STREAM_FORMAT_SELECT;
stream_format.nal_stream_format_supported = BIT(ctrl->val);
2024-09-09 08:52:07 +00:00
pdata = &stream_format;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER:
property_id = HAL_PARAM_VDEC_OUTPUT_ORDER;
property_val = ctrl->val;
pdata = &property_val;
break;
2024-09-09 08:57:42 +00:00
case V4L2_CID_MPEG_VIDC_VIDEO_PICTYPE_DEC_MODE:
property_id = HAL_PARAM_VDEC_PICTURE_TYPE_DECODE;
if (ctrl->val ==
V4L2_MPEG_VIDC_VIDEO_PICTYPE_DECODE_ON)
enable_picture.picture_type = HAL_PICTURE_I;
else
enable_picture.picture_type = HAL_PICTURE_I |
HAL_PICTURE_P | HAL_PICTURE_B |
HAL_PICTURE_IDR;
2024-09-09 08:52:07 +00:00
pdata = &enable_picture;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO:
2024-09-09 08:57:42 +00:00
property_id = HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO;
2024-09-09 08:52:07 +00:00
hal_property.enable = ctrl->val;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE:
2024-09-09 08:57:42 +00:00
property_id = HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER;
2024-09-09 08:52:07 +00:00
hal_property.enable = ctrl->val;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT:
property_id = HAL_PARAM_DIVX_FORMAT;
property_val = ctrl->val;
pdata = &property_val;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING:
2024-09-09 08:57:42 +00:00
property_id = HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING;
2024-09-09 08:52:07 +00:00
hal_property.enable = ctrl->val;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER:
2024-09-09 08:57:42 +00:00
property_id = HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER;
2024-09-09 08:52:07 +00:00
hal_property.enable = ctrl->val;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE:
2024-09-09 08:57:42 +00:00
switch (ctrl->val) {
case V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE:
inst->flags &= ~VIDC_THUMBNAIL;
break;
case V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE:
inst->flags |= VIDC_THUMBNAIL;
break;
}
property_id = HAL_PARAM_VDEC_SYNC_FRAME_DECODE;
2024-09-09 08:52:07 +00:00
hal_property.enable = ctrl->val;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_SECURE:
inst->flags |= VIDC_SECURE;
dprintk(VIDC_DBG, "Setting secure mode to: %d\n",
!!(inst->flags & VIDC_SECURE));
break;
case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA:
property_id = HAL_PARAM_INDEX_EXTRADATA;
extra.index = msm_comm_get_hal_extradata_index(ctrl->val);
extra.enable = 1;
pdata = &extra;
break;
case V4L2_CID_MPEG_VIDC_SET_PERF_LEVEL:
switch (ctrl->val) {
case V4L2_CID_MPEG_VIDC_PERF_LEVEL_NOMINAL:
inst->flags &= ~VIDC_TURBO;
break;
case V4L2_CID_MPEG_VIDC_PERF_LEVEL_TURBO:
inst->flags |= VIDC_TURBO;
break;
default:
2024-09-09 08:57:42 +00:00
dprintk(VIDC_ERR, "Perf mode %x not supported\n",
2024-09-09 08:52:07 +00:00
ctrl->val);
rc = -ENOTSUPP;
break;
}
2024-09-09 08:57:42 +00:00
msm_comm_scale_clocks_and_bus(inst);
break;
case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT:
if (ctrl->val == V4L2_MPEG_VIDC_VIDEO_DYNAMIC) {
rc = -ENOTSUPP;
break;
}
property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
alloc_mode.buffer_mode = get_buf_type(ctrl->val);
alloc_mode.buffer_type = HAL_BUFFER_INPUT;
inst->buffer_mode_set[OUTPUT_PORT] = alloc_mode.buffer_mode;
pdata = &alloc_mode;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY:
property_id = HAL_PARAM_VDEC_FRAME_ASSEMBLY;
hal_property.enable = ctrl->val;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT:
property_id = HAL_PARAM_BUFFER_ALLOC_MODE;
alloc_mode.buffer_mode = get_buf_type(ctrl->val);
if (!(alloc_mode.buffer_mode &
inst->capability.alloc_mode_out)) {
dprintk(VIDC_WARN,
"buffer mode[%d] not supported for capture port[0x%x]\n",
ctrl->val, inst->capability.alloc_mode_out);
rc = -ENOTSUPP;
break;
}
2024-09-09 08:52:07 +00:00
2024-09-09 08:57:42 +00:00
alloc_mode.buffer_type = HAL_BUFFER_OUTPUT;
pdata = &alloc_mode;
inst->buffer_mode_set[CAPTURE_PORT] = alloc_mode.buffer_mode;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
if (ctrl->val && !(inst->capability.pixelprocess_capabilities &
HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)) {
dprintk(VIDC_ERR, "Downscaling not supported: %#x\n",
ctrl->id);
rc = -ENOTSUPP;
break;
}
switch (ctrl->val) {
case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY:
multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
multi_stream.enable = true;
pdata = &multi_stream;
rc = call_hfi_op(hdev, session_set_property, (void *)
inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
pdata);
if (rc) {
dprintk(VIDC_ERR,
"Failed : Enabling OUTPUT port : %d\n",
rc);
break;
}
multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
multi_stream.enable = false;
pdata = &multi_stream;
rc = call_hfi_op(hdev, session_set_property, (void *)
inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
pdata);
if (rc)
dprintk(VIDC_ERR,
"Failed:Disabling OUTPUT2 port : %d\n",
rc);
break;
case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY:
multi_stream.buffer_type = HAL_BUFFER_OUTPUT2;
multi_stream.enable = true;
pdata = &multi_stream;
rc = call_hfi_op(hdev, session_set_property, (void *)
inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
pdata);
if (rc) {
dprintk(VIDC_ERR,
"Failed :Enabling OUTPUT2 port : %d\n",
rc);
break;
}
multi_stream.buffer_type = HAL_BUFFER_OUTPUT;
multi_stream.enable = false;
pdata = &multi_stream;
rc = call_hfi_op(hdev, session_set_property, (void *)
inst->session, HAL_PARAM_VDEC_MULTI_STREAM,
pdata);
if (rc) {
dprintk(VIDC_ERR,
"Failed disabling OUTPUT port : %d\n",
rc);
break;
}
frame_sz.buffer_type = HAL_BUFFER_OUTPUT2;
frame_sz.width = inst->prop.width[CAPTURE_PORT];
frame_sz.height = inst->prop.height[CAPTURE_PORT];
pdata = &frame_sz;
dprintk(VIDC_DBG,
"buffer type = %d width = %d, height = %d\n",
frame_sz.buffer_type, frame_sz.width,
frame_sz.height);
rc = call_hfi_op(hdev, session_set_property, (void *)
inst->session, HAL_PARAM_FRAME_SIZE, pdata);
if (rc)
dprintk(VIDC_ERR,
"Failed setting OUTPUT2 size : %d\n",
rc);
alloc_mode.buffer_mode =
inst->buffer_mode_set[CAPTURE_PORT];
alloc_mode.buffer_type = HAL_BUFFER_OUTPUT2;
rc = call_hfi_op(hdev, session_set_property,
inst->session, HAL_PARAM_BUFFER_ALLOC_MODE,
&alloc_mode);
if (rc)
dprintk(VIDC_ERR,
"Failed to set alloc_mode on OUTPUT2: %d\n",
rc);
break;
default:
dprintk(VIDC_ERR,
"Failed : Unsupported multi stream setting\n");
rc = -ENOTSUPP;
break;
}
break;
case V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD:
property_id = HAL_PARAM_VDEC_SCS_THRESHOLD;
scs_threshold.threshold_value = ctrl->val;
pdata = &scs_threshold;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT:
property_id = HAL_PARAM_MVC_BUFFER_LAYOUT;
layout.layout_type = msm_comm_get_hal_buffer_layout(ctrl->val);
layout.bright_view_first = 0;
layout.ngap = 0;
pdata = &layout;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR:
property_id = HAL_PARAM_VDEC_CONCEAL_COLOR;
property_val = ctrl->val;
pdata = &property_val;
break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL);
property_id =
HAL_PARAM_PROFILE_LEVEL_CURRENT;
profile_level.profile = vdec_v4l2_to_hal(ctrl->id,
ctrl->val);
profile_level.level = vdec_v4l2_to_hal(
V4L2_CID_MPEG_VIDEO_H264_LEVEL,
temp_ctrl->val);
pdata = &profile_level;
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE);
property_id =
HAL_PARAM_PROFILE_LEVEL_CURRENT;
profile_level.level = vdec_v4l2_to_hal(ctrl->id,
ctrl->val);
profile_level.profile = vdec_v4l2_to_hal(
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
temp_ctrl->val);
pdata = &profile_level;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_BUFFER_SIZE_LIMIT:
dprintk(VIDC_DBG,
"Limiting input buffer size from %u to %u\n",
inst->buffer_size_limit, ctrl->val);
inst->buffer_size_limit = ctrl->val;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2:
property_id = HAL_PARAM_VDEC_NON_SECURE_OUTPUT2;
hal_property.enable = ctrl->val;
dprintk(VIDC_DBG, "%s non_secure output2\n",
ctrl->val ? "Enabling" : "Disabling");
pdata = &hal_property;
break;
case V4L2_CID_VIDC_QBUF_MODE:
property_id = HAL_PARAM_SYNC_BASED_INTERRUPT;
hal_property.enable = ctrl->val == V4L2_VIDC_QBUF_BATCHED;
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_PRIORITY:
property_id = HAL_CONFIG_REALTIME;
/* firmware has inverted values for realtime and
* non-realtime priority
*/
hal_property.enable = !(ctrl->val);
pdata = &hal_property;
break;
case V4L2_CID_MPEG_VIDC_VIDEO_OPERATING_RATE:
2024-09-09 08:52:07 +00:00
break;
default:
break;
}
2024-09-09 08:57:42 +00:00
v4l2_ctrl_lock(ctrl);
#undef TRY_GET_CTRL
2024-09-09 08:52:07 +00:00
if (!rc && property_id) {
dprintk(VIDC_DBG,
2024-09-09 08:57:42 +00:00
"Control: HAL property=%#x,ctrl: id=%#x,value=%#x\n",
2024-09-09 08:52:07 +00:00
property_id, ctrl->id, ctrl->val);
2024-09-09 08:57:42 +00:00
rc = call_hfi_op(hdev, session_set_property, (void *)
2024-09-09 08:52:07 +00:00
inst->session, property_id, pdata);
}
return rc;
}
2024-09-09 08:57:42 +00:00
static int try_set_ext_ctrl(struct msm_vidc_inst *inst,
struct v4l2_ext_controls *ctrl)
{
int rc = 0, i = 0, fourcc = 0;
struct v4l2_ext_control *ext_control;
struct v4l2_control control;
if (!inst || !inst->core || !ctrl) {
dprintk(VIDC_ERR,
"%s invalid parameters\n", __func__);
return -EINVAL;
}
ext_control = ctrl->controls;
control.id =
V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE;
for (i = 0; i < ctrl->count; i++) {
switch (ext_control[i].id) {
case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE:
control.value = ext_control[i].value;
rc = msm_comm_s_ctrl(inst, &control);
if (rc)
dprintk(VIDC_ERR,
"%s Failed setting stream output mode : %d\n",
__func__, rc);
break;
case V4L2_CID_MPEG_VIDC_VIDEO_DPB_COLOR_FORMAT:
switch (ext_control[i].value) {
case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_NONE:
if (!msm_comm_g_ctrl_for_id(inst, control.id)) {
rc = msm_comm_release_output_buffers(
inst);
if (rc)
dprintk(VIDC_ERR,
"%s Release output buffers failed\n",
__func__);
}
break;
case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC:
case V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_TP10_UBWC:
if (ext_control[i].value ==
V4L2_MPEG_VIDC_VIDEO_DPB_COLOR_FMT_UBWC)
fourcc = V4L2_PIX_FMT_NV12_UBWC;
else
fourcc = V4L2_PIX_FMT_NV12_TP10_UBWC;
if (msm_comm_g_ctrl_for_id(inst, control.id)) {
rc = msm_comm_set_color_format(inst,
HAL_BUFFER_OUTPUT, fourcc);
if (rc) {
dprintk(VIDC_ERR,
"%s Failed setting output color format : %d\n",
__func__, rc);
break;
}
rc = msm_comm_try_get_bufreqs(inst);
if (rc)
dprintk(VIDC_ERR,
"%s Failed to get buffer requirements : %d\n",
__func__, rc);
}
break;
default:
dprintk(VIDC_ERR,
"%s Unsupported output color format\n",
__func__);
rc = -ENOTSUPP;
break;
}
break;
default:
dprintk(VIDC_ERR
, "%s Unsupported set control %d",
__func__, ext_control[i].id);
rc = -ENOTSUPP;
break;
}
}
return rc;
}
2024-09-09 08:52:07 +00:00
static int msm_vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
{
int rc = 0, c = 0;
struct msm_vidc_inst *inst = container_of(ctrl->handler,
struct msm_vidc_inst, ctrl_handler);
2024-09-09 08:57:42 +00:00
if (!inst) {
dprintk(VIDC_ERR, "%s invalid parameters\n", __func__);
return -EINVAL;
}
2024-09-09 08:52:07 +00:00
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
dprintk(VIDC_ERR,
"Failed to move inst: %p to start done state\n", inst);
goto failed_open_done;
}
for (c = 0; c < ctrl->ncontrols; ++c) {
if (ctrl->cluster[c]->is_new) {
rc = try_set_ctrl(inst, ctrl->cluster[c]);
if (rc) {
2024-09-09 08:57:42 +00:00
dprintk(VIDC_ERR, "Failed setting %x\n",
2024-09-09 08:52:07 +00:00
ctrl->cluster[c]->id);
break;
}
}
}
failed_open_done:
return rc;
}
static int msm_vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
2024-09-09 08:57:42 +00:00
int rc = 0, c = 0;
struct msm_vidc_inst *inst = container_of(ctrl->handler,
struct msm_vidc_inst, ctrl_handler);
struct v4l2_ctrl *master = ctrl->cluster[0];
rc = msm_comm_try_state(inst, MSM_VIDC_OPEN_DONE);
if (rc) {
dprintk(VIDC_ERR,
"Failed to move inst: %p to start done state\n", inst);
goto failed_open_done;
}
for (c = 0; c < master->ncontrols; ++c) {
int d = 0;
for (d = 0; d < NUM_CTRLS; ++d) {
if (master->cluster[c]->id == inst->ctrls[d]->id &&
inst->ctrls[d]->flags &
V4L2_CTRL_FLAG_VOLATILE) {
rc = try_get_ctrl(inst, master->cluster[c]);
if (rc) {
dprintk(VIDC_ERR, "Failed getting %x\n",
master->cluster[c]->id);
return rc;
}
break;
}
}
}
return rc;
failed_open_done:
if (rc)
dprintk(VIDC_ERR, "Failed to get hal property\n");
return rc;
2024-09-09 08:52:07 +00:00
}
static const struct v4l2_ctrl_ops msm_vdec_ctrl_ops = {
.s_ctrl = msm_vdec_op_s_ctrl,
.g_volatile_ctrl = msm_vdec_op_g_volatile_ctrl,
};
const struct v4l2_ctrl_ops *msm_vdec_get_ctrl_ops(void)
{
return &msm_vdec_ctrl_ops;
}
2024-09-09 08:57:42 +00:00
int msm_vdec_s_ext_ctrl(struct msm_vidc_inst *inst,
struct v4l2_ext_controls *ctrl)
2024-09-09 08:52:07 +00:00
{
2024-09-09 08:57:42 +00:00
int rc = 0;
if (ctrl->ctrl_class != V4L2_CTRL_CLASS_MPEG) {
dprintk(VIDC_ERR, "Invalid Class set for extended control\n");
return -EINVAL;
2024-09-09 08:52:07 +00:00
}
2024-09-09 08:57:42 +00:00
rc = try_set_ext_ctrl(inst, ctrl);
if (rc) {
dprintk(VIDC_ERR, "Error setting extended control\n");
return rc;
}
return rc;
2024-09-09 08:52:07 +00:00
}
int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
{
2024-09-09 08:57:42 +00:00
return msm_comm_ctrl_init(inst, msm_vdec_ctrls,
ARRAY_SIZE(msm_vdec_ctrls), &msm_vdec_ctrl_ops);
2024-09-09 08:52:07 +00:00
}