diff --git a/qcom/opensource/video-driver/Android.bp b/qcom/opensource/video-driver/Android.bp new file mode 100644 index 0000000000..9b144883fc --- /dev/null +++ b/qcom/opensource/video-driver/Android.bp @@ -0,0 +1,35 @@ +headers_src = [ + "include/uapi/*/**/*.h", +] + +video_headers_out = [ + "vidc/media/v4l2_vidc_extensions.h", +] + +video_kernel_headers_verbose = "--verbose " +genrule { + name: "qti_generate_video_kernel_headers", + tools: ["headers_install.sh", + "unifdef" + ], + tool_files: [ + "video_kernel_headers.py", + ], + srcs: headers_src, + cmd: "python3 -u $(location video_kernel_headers.py) " + + video_kernel_headers_verbose + + "--header_arch arm64 " + + "--gen_dir $(genDir) " + + "--video_include_uapi $(locations include/uapi/*/**/*.h) " + + "--unifdef $(location unifdef) " + + "--headers_install $(location headers_install.sh)", + out: video_headers_out, +} + +cc_library_headers { + name: "qti_video_kernel_uapi", + generated_headers: ["qti_generate_video_kernel_headers"], + export_generated_headers: ["qti_generate_video_kernel_headers"], + vendor: true, + recovery_available: true +} diff --git a/qcom/opensource/video-driver/Android.mk b/qcom/opensource/video-driver/Android.mk new file mode 100644 index 0000000000..a81dc1228c --- /dev/null +++ b/qcom/opensource/video-driver/Android.mk @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: GPL-2.0-only +TARGET_VIDC_ENABLE := false +ifeq ($(TARGET_KERNEL_DLKM_DISABLE), true) + ifeq ($(TARGET_KERNEL_DLKM_VIDEO_OVERRIDE), true) + TARGET_VIDC_ENABLE := true + endif +else +TARGET_VIDC_ENABLE := true +endif + +ifeq ($(TARGET_VIDC_ENABLE),true) +VIDEO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/video-driver +VIDEO_SELECT := CONFIG_MSM_VIDC_V4L2=m + +# Build msm_video.ko +########################################################### +# This is set once per LOCAL_PATH, not per (kernel) module +KBUILD_OPTIONS := VIDEO_ROOT=$(VIDEO_BLD_DIR) + +KBUILD_OPTIONS += $(VIDEO_SELECT) + +KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS=$(shell pwd)/$(call intermediates-dir-for,DLKM,mmrm-module-symvers)/Module.symvers +KBUILD_OPTIONS += KBUILD_EXTRA_SYMBOLS+=$(shell pwd)/$(call intermediates-dir-for,DLKM,hw-fence-module-symvers)/Module.symvers +########################################################### + +DLKM_DIR := device/qcom/common/dlkm + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +# For incremental compilation +LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/**/*) $(wildcard $(LOCAL_PATH)/*) +LOCAL_MODULE := msm_video.ko +LOCAL_MODULE_KBUILD_NAME := msm_video/msm_video.ko +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_DEBUG_ENABLE := true +LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) +LOCAL_MODULE_DDK_BUILD := true +LOCAL_MODULE_DDK_SUBTARGET_REGEX := "video.*" +ifeq ($(TARGET_BOARD_PLATFORM), volcano) + LOCAL_MODULE_DDK_SUBTARGET_REGEX := "$(TARGET_BOARD_PLATFORM)_video.*" +endif +LOCAL_MODULE_KO_DIRS := msm_video/msm_video.ko + +LOCAL_REQUIRED_MODULES := mmrm-module-symvers +LOCAL_REQUIRED_MODULES += hw-fence-module-symvers +LOCAL_ADDITIONAL_DEPENDENCIES := $(call intermediates-dir-for,DLKM,mmrm-module-symvers)/Module.symvers +LOCAL_ADDITIONAL_DEPENDENCIES += $(call intermediates-dir-for,DLKM,hw-fence-module-symvers)/Module.symvers + +include $(DLKM_DIR)/Build_external_kernelmodule.mk +endif diff --git a/qcom/opensource/video-driver/BUILD.bazel b/qcom/opensource/video-driver/BUILD.bazel new file mode 100644 index 0000000000..d5d674cbfd --- /dev/null +++ b/qcom/opensource/video-driver/BUILD.bazel @@ -0,0 +1,73 @@ +load("//build/kernel/kleaf:kernel.bzl", "ddk_headers") + +package( + default_visibility = [ + "//visibility:public"], +) + +ddk_headers( + name = "uapi_headers", + hdrs = glob([ + "include/uapi/vidc/media/*.h", + ]), + includes = ["include/uapi/vidc"] +) + +ddk_headers( + name = "pineapple_headers", + hdrs = glob([ + "driver/platform/pineapple/inc/*.h", + ]), + includes = ["driver/platform/pineapple/inc"] +) + +ddk_headers( + name = "cliffs_headers", + hdrs = glob([ + "driver/platform/cliffs/inc/*.h", + ]), + includes = ["driver/platform/cliffs/inc"] +) + +ddk_headers( + name = "iris33_headers", + hdrs = glob([ + "driver/variant/iris33/inc/*.h", + ]), + includes = ["driver/variant/iris33/inc"] +) + +ddk_headers( + name = "iris2_headers", + hdrs = glob([ + "driver/variant/iris2/inc/*.h", + ]), + includes = ["driver/variant/iris2/inc"] +) + +ddk_headers( + name = "volcano_headers", + hdrs = glob([ + "driver/platform/volcano/inc/*.h", + ]), + includes = ["driver/platform/volcano/inc"] +) + +ddk_headers( + name = "vidc_headers", + hdrs = glob([ + "driver/vidc/inc/*.h", + "driver/variant/common/inc/*.h", + "driver/platform/common/inc/*.h" + ]), + includes = ["driver/vidc/inc", "driver/variant/common/inc", "driver/platform/common/inc"] +) + +ddk_headers( + name = "video_driver_headers", + # hdrs = [":pineapple_configs", "uapi_headers", "pineapple_headers", "iris33_headers", "vidc_headers"] + hdrs = [":uapi_headers", "pineapple_headers", "cliffs_headers", "iris33_headers", "volcano_headers", "iris2_headers", "vidc_headers"] +) + +load(":target.bzl", "define_target_modules") +define_target_modules() diff --git a/qcom/opensource/video-driver/Kbuild b/qcom/opensource/video-driver/Kbuild new file mode 100644 index 0000000000..ef3e358001 --- /dev/null +++ b/qcom/opensource/video-driver/Kbuild @@ -0,0 +1 @@ +obj-m := msm_video/ video/ diff --git a/qcom/opensource/video-driver/Makefile b/qcom/opensource/video-driver/Makefile new file mode 100644 index 0000000000..04a894a58b --- /dev/null +++ b/qcom/opensource/video-driver/Makefile @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0-only + +VIDEO_COMPILE_TIME = $(shell date) +VIDEO_COMPILE_BY = $(shell whoami | sed 's/\\/\\\\/') +VIDEO_COMPILE_HOST = $(shell uname -n) +VIDEO_GEN_PATH = $(VIDEO_ROOT)/driver/vidc/inc/video_generated_h + +all: modules + +$(VIDEO_GEN_PATH): $(shell find . -type f \( -iname \*.c -o -iname \*.h -o -iname \*.mk \)) + echo '#define VIDEO_COMPILE_TIME "$(VIDEO_COMPILE_TIME)"' > $(VIDEO_GEN_PATH) + echo '#define VIDEO_COMPILE_BY "$(VIDEO_COMPILE_BY)"' >> $(VIDEO_GEN_PATH) + echo '#define VIDEO_COMPILE_HOST "$(VIDEO_COMPILE_HOST)"' >> $(VIDEO_GEN_PATH) + +modules: $(VIDEO_GEN_PATH) + ln -sf $(VIDEO_ROOT)/driver $(VIDEO_ROOT)/msm_video/driver + ln -sf $(VIDEO_ROOT)/driver $(VIDEO_ROOT)/video/driver + $(MAKE) -C $(KERNEL_SRC) M=$(M) modules $(KBUILD_OPTIONS) + rm $(VIDEO_ROOT)/msm_video/driver + rm $(VIDEO_ROOT)/video/driver + +modules_install: + $(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(M) modules_install + +%: + $(MAKE) -C $(KERNEL_SRC) M=$(M) $@ $(KBUILD_OPTIONS) + +clean: + rm -f *.o *.ko *.mod.c *.mod.o *~ .*.cmd Module.symvers + rm -rf .tmp_versions diff --git a/qcom/opensource/video-driver/config/kalama_video.conf b/qcom/opensource/video-driver/config/kalama_video.conf new file mode 100644 index 0000000000..545bba0e96 --- /dev/null +++ b/qcom/opensource/video-driver/config/kalama_video.conf @@ -0,0 +1 @@ +export CONFIG_MSM_VIDC_KALAMA=y diff --git a/qcom/opensource/video-driver/config/kalama_video.h b/qcom/opensource/video-driver/config/kalama_video.h new file mode 100644 index 0000000000..f5665b1f85 --- /dev/null +++ b/qcom/opensource/video-driver/config/kalama_video.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#define CONFIG_MSM_VIDC_KALAMA 1 diff --git a/qcom/opensource/video-driver/config/pineapple_video.conf b/qcom/opensource/video-driver/config/pineapple_video.conf new file mode 100644 index 0000000000..c5ccde9008 --- /dev/null +++ b/qcom/opensource/video-driver/config/pineapple_video.conf @@ -0,0 +1 @@ +export CONFIG_MSM_VIDC_PINEAPPLE=y diff --git a/qcom/opensource/video-driver/config/pineapple_video.h b/qcom/opensource/video-driver/config/pineapple_video.h new file mode 100644 index 0000000000..62e7ebd927 --- /dev/null +++ b/qcom/opensource/video-driver/config/pineapple_video.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#define CONFIG_MSM_VIDC_PINEAPPLE 1 diff --git a/qcom/opensource/video-driver/config/volcano_video.conf b/qcom/opensource/video-driver/config/volcano_video.conf new file mode 100644 index 0000000000..3c30d2db62 --- /dev/null +++ b/qcom/opensource/video-driver/config/volcano_video.conf @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +export CONFIG_MSM_VIDC_VOLCANO=y \ No newline at end of file diff --git a/qcom/opensource/video-driver/config/volcano_video.h b/qcom/opensource/video-driver/config/volcano_video.h new file mode 100644 index 0000000000..4e16ba8a5b --- /dev/null +++ b/qcom/opensource/video-driver/config/volcano_video.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#define CONFIG_MSM_VIDC_VOLCANO 1 diff --git a/qcom/opensource/video-driver/driver/platform/cliffs/inc/msm_vidc_cliffs.h b/qcom/opensource/video-driver/driver/platform/cliffs/inc/msm_vidc_cliffs.h new file mode 100644 index 0000000000..7d4a8dde09 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/cliffs/inc/msm_vidc_cliffs.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_CLIFFS_H_ +#define _MSM_VIDC_CLIFFS_H_ + +#include "msm_vidc_core.h" + +#if defined(CONFIG_MSM_VIDC_PINEAPPLE) +int msm_vidc_init_platform_cliffs(struct msm_vidc_core *core); +int msm_vidc_deinit_platform_cliffs(struct msm_vidc_core *core); +#else +int msm_vidc_init_platform_cliffs(struct msm_vidc_core *core) +{ + return -EINVAL; +} + +int msm_vidc_deinit_platform_cliffs(struct msm_vidc_core *core) +{ + return -EINVAL; +} +#endif + +#endif // _MSM_VIDC_CLIFFS_H_ diff --git a/qcom/opensource/video-driver/driver/platform/cliffs/src/cliffs.c b/qcom/opensource/video-driver/driver/platform/cliffs/src/cliffs.c new file mode 100644 index 0000000000..d0c0441441 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/cliffs/src/cliffs.c @@ -0,0 +1,1757 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include + +#include "msm_vidc_control.h" +#include "msm_vidc_cliffs.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_iris33.h" +#include "hfi_property.h" +#include "hfi_command.h" +#include "venus_hfi.h" + +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010 +#define MAX_BASE_LAYER_PRIORITY_ID 63 +#define MAX_OP_POINT 31 +#define MAX_BITRATE 245000000 +#define DEFAULT_BITRATE 20000000 +#define MINIMUM_FPS 1 +#define MAXIMUM_FPS 480 +#define MAX_QP 51 +#define DEFAULT_QP 20 +#define MAX_CONSTANT_QUALITY 100 +#define MIN_SLICE_BYTE_SIZE 512 +#define MAX_SLICE_BYTE_SIZE \ + ((MAX_BITRATE) >> 3) +#define MAX_SLICE_MB_SIZE \ + (((4096 + 15) >> 4) * ((2304 + 15) >> 4)) + +#define ENC MSM_VIDC_ENCODER +#define DEC MSM_VIDC_DECODER +#define H264 MSM_VIDC_H264 +#define HEVC MSM_VIDC_HEVC +#define VP9 MSM_VIDC_VP9 +#define CODECS_ALL (H264 | HEVC | VP9) +#define MAXIMUM_OVERRIDE_VP9_FPS 180 + +#ifndef V4L2_PIX_FMT_QC08C +#define V4L2_PIX_FMT_QC08C v4l2_fourcc('Q', '0', '8', 'C') +#endif + +#ifndef V4L2_PIX_FMT_QC10C +#define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') +#endif + +static struct codec_info codec_data_cliffs[] = { + { + .v4l2_codec = V4L2_PIX_FMT_H264, + .vidc_codec = MSM_VIDC_H264, + .pixfmt_name = "AVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_HEVC, + .vidc_codec = MSM_VIDC_HEVC, + .pixfmt_name = "HEVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VP9, + .vidc_codec = MSM_VIDC_VP9, + .pixfmt_name = "VP9", + }, +}; + +static struct color_format_info color_format_data_cliffs[] = { + { + .v4l2_color_format = V4L2_PIX_FMT_NV12, + .vidc_color_format = MSM_VIDC_FMT_NV12, + .pixfmt_name = "NV12", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_NV21, + .vidc_color_format = MSM_VIDC_FMT_NV21, + .pixfmt_name = "NV21", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC08C, + .vidc_color_format = MSM_VIDC_FMT_NV12C, + .pixfmt_name = "NV12C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC10C, + .vidc_color_format = MSM_VIDC_FMT_TP10C, + .pixfmt_name = "TP10C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_RGBA32, + .vidc_color_format = MSM_VIDC_FMT_RGBA8888, + .pixfmt_name = "RGBA", + }, +}; + +static struct color_primaries_info color_primaries_data_cliffs[] = { + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_RESERVED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_REC709, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT709, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_BG, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE170M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT601_525, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE240M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_ST240M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_BT2020, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT2020, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DCI_P3, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_RP431_2, + }, +}; + +static struct transfer_char_info transfer_char_data_cliffs[] = { + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_RESERVED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_709, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT709, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE240M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST240M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SRGB, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SRGB_SYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE2084, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ, + }, +}; + +static struct matrix_coeff_info matrix_coeff_data_cliffs[] = { + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_SMPTE240M, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020_CONST_LUM, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT, + }, +}; + +static struct msm_platform_core_capability core_data_cliffs[] = { + /* {type, value} */ + {ENC_CODECS, H264 | HEVC}, + {DEC_CODECS, H264 | HEVC | VP9}, + {MAX_SESSION_COUNT, 16}, + {MAX_NUM_720P_SESSIONS, 16}, + {MAX_NUM_1080P_SESSIONS, 16}, + {MAX_NUM_4K_SESSIONS, 8}, + {MAX_NUM_8K_SESSIONS, 2}, + {MAX_RT_MBPF, 174080}, /* (8192x4352)/256 + (4096x2176)/256*/ + {MAX_MBPF, 278528}, /* ((8192x4352)/256) * 2 */ + {MAX_MBPS, 7833600}, + /* max_load + * 7680x4320@60fps or 3840x2176@240fps + * which is greater than 4096x2176@120fps, + * 8192x4320@48fps + */ + {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */ + {MAX_MBPS_HQ, 489600}, /* ((1920x1088)/256)@60fps */ + {MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */ + {MAX_MBPS_B_FRAME, 1958400}, /* 3840x2176/256 MBs@60fps */ + {MAX_MBPS_ALL_INTRA, 1044480}, /* 4096x2176/256 MBs@30fps */ + {MAX_ENH_LAYER_COUNT, 5}, + {NUM_VPP_PIPE, 4}, + {SW_PC, 1}, + {FW_UNLOAD, 0}, + {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */ + {SW_PC_DELAY, SW_PC_DELAY_VALUE }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/ + {FW_UNLOAD_DELAY, FW_UNLOAD_DELAY_VALUE }, /* 3000 ms (>SW_PC_DELAY)*/ + {DCVS, 1}, + {DECODE_BATCH, 1}, + {DECODE_BATCH_TIMEOUT, 200}, + {STATS_TIMEOUT_MS, 2000}, + {NON_FATAL_FAULTS, 1}, + {ENC_AUTO_FRAMERATE, 1}, + {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING}, + {SUPPORTS_SYNX_FENCE, 0}, + {SUPPORTS_REQUESTS, 0}, +}; + +static int msm_vidc_set_ring_buffer_count_cliffs(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + struct v4l2_format *output_fmt, *input_fmt; + struct msm_vidc_core *core; + u32 count = 0, data_size = 0, pixel_count = 0, fps = 0; + u32 frame_rate = 0, operating_rate = 0; + + core = inst->core; + output_fmt = &inst->fmts[OUTPUT_PORT]; + input_fmt = &inst->fmts[INPUT_PORT]; + + frame_rate = inst->capabilities[FRAME_RATE].value >> 16; + operating_rate = inst->capabilities[OPERATING_RATE].value >> 16; + fps = max(frame_rate, operating_rate); + pixel_count = output_fmt->fmt.pix_mp.width * + output_fmt->fmt.pix_mp.height; + + /* + * try to enable ring buffer feature if +  * resolution >= 8k and fps >= 30fps and +  * resolution >= 4k and fps >= 120fps and +  * resolution >= 1080p and fps >= 480fps and +  * resolution >= 720p and fps >= 960fps + */ + if ((pixel_count >= 7680 * 4320 && fps >= 30) && + (pixel_count >= 3840 * 2160 && fps >= 120) && + (pixel_count >= 1920 * 1080 && fps >= 480) && + (pixel_count >= 1280 * 720 && fps >= 960)) { + data_size = input_fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + i_vpr_h(inst, "%s: calculate ring buffer count\n", __func__); + rc = call_session_op(core, ring_buf_count, inst, data_size); + if (rc) { + i_vpr_e(inst, "%s: failed to calculate ring buf count\n", + __func__); + /* ignore error */ + rc = 0; + inst->capabilities[cap_id].value = 0; + } + } else { + i_vpr_h(inst, + "%s: session %ux%u@%u fps does not support ring buffer\n", + __func__, output_fmt->fmt.pix_mp.width, + output_fmt->fmt.pix_mp.height, fps); + inst->capabilities[cap_id].value = 0; + } + + count = inst->capabilities[cap_id].value; + i_vpr_h(inst, "%s: ring buffer count: %u\n", __func__, count); + rc = venus_hfi_session_property(inst, + HFI_PROP_ENC_RING_BIN_BUF, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_U32, + &count, + sizeof(u32)); + if (rc) + return rc; + + return rc; +} + +static struct msm_platform_inst_capability instance_cap_data_cliffs[] = { + /* {cap, domain, codec, + * min, max, step_or_mask, value, + * v4l2_id, + * hfi_id, + * flags} + */ + + {FRAME_WIDTH, DEC, CODECS_ALL, 96, 8192, 1, 1920}, + + {FRAME_WIDTH, DEC, VP9, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, CODECS_ALL, 128, 8192, 1, 1920}, + + {FRAME_WIDTH, ENC, HEVC, 96, 8192, 1, 1920}, + + {LOSSLESS_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {LOSSLESS_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {FRAME_HEIGHT, DEC, CODECS_ALL, 96, 8192, 1, 1080}, + + {FRAME_HEIGHT, DEC, VP9, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, CODECS_ALL, 128, 8192, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEVC, 96, 8192, 1, 1080}, + + {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {LOSSLESS_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {PIX_FMTS, ENC | DEC, H264, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC | DEC, HEVC | VP9, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + + {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL, + 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE}, + + /* (8192 * 4320) / 256 */ + {MBPF, ENC, CODECS_ALL, 64, 138240, 1, 138240}, + + {MBPF, ENC, HEVC, 36, 138240, 1, 138240}, + + {MBPF, DEC, CODECS_ALL, 36, 138240, 1, 138240}, + + /* (4096 * 2304) / 256 */ + {MBPF, DEC, VP9, 36, 36864, 1, 36864}, + + /* (4096 * 2304) / 256 */ + {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 36864, 1, 36864}, + + /* Batch Mode Decode */ + /* TODO: update with new values based on updated voltage corner */ + {BATCH_MBPF, DEC, H264 | HEVC | VP9, 64, 34816, 1, 34816}, + + /* (4096 * 2304) / 256 */ + {BATCH_FPS, DEC, H264 | HEVC | VP9, 1, 120, 1, 120}, + + {FRAME_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {OPERATING_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16)}, + + {INPUT_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8}, + + {MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60}, + + {MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675}, + + {MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320}, + + {MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 489583, 489583, 1, 489583}, + + {MB_CYCLES_FW_VPP, ENC, CODECS_ALL, 48405, 48405, 1, 48405}, + + {MB_CYCLES_FW_VPP, DEC, CODECS_ALL, 66234, 66234, 1, 66234}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + 0, MAX_ENC_RING_BUF_COUNT, 1, 0}, + + {CLIENT_ID, ENC | DEC, CODECS_ALL, + INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, + 0}, + + {HFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_HFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {VFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_VFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ROTATION, ENC, CODECS_ALL, + 0, 270, 90, 0, + V4L2_CID_ROTATE, + HFI_PROP_ROTATION, + CAP_FLAG_OUTPUT_PORT}, + + {SUPER_FRAME, ENC, H264 | HEVC, + 0, 32, 1, 0, + 0, 0, + CAP_FLAG_NONE}, + + {SLICE_DECODE, DEC, CODECS_ALL, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, + 0}, + + {HEADER_MODE, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + HFI_PROP_SEQ_HEADER_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_OUTPUT_PORT}, + + {NAL_LENGTH_FIELD, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_MPEG_VIDEO_HEVC_SIZE_4, + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) | + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4), + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* TODO: Firmware introduced enumeration type for this + * with and without seq header. + */ + {REQUEST_I_FRAME, ENC, H264 | HEVC, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + HFI_PROP_REQUEST_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* Enc: Keeping CABAC and CAVLC as same bitrate. + * Dec: there's no use of Bitrate cap + */ + {BIT_RATE, ENC, H264 | HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE, + HFI_PROP_TOTAL_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITRATE_MODE, ENC, H264, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {CAVLC_MAX_BITRATE, ENC, H264, 0, + 220000000, 1, 220000000}, + + {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0, + 245000000, 1, 245000000}, + + {LOWLATENCY_MAX_BITRATE, ENC, H264 | HEVC, 0, + 70000000, 1, 70000000}, + + {LOSSLESS, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU}, + + {FRAME_SKIP_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {FRAME_RC_ENABLE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE}, + + {CONSTANT_QUALITY, ENC, HEVC, + 1, MAX_CONSTANT_QUALITY, 1, 90, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, CODECS_ALL, + 0, INT_MAX, 1, 2 * DEFAULT_FPS - 1, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_CLOSURE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + 0}, + + {B_FRAME, ENC, H264 | HEVC, + 0, 7, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {BLUR_TYPES, ENC, H264 | HEVC, + MSM_VIDC_BLUR_NONE, MSM_VIDC_BLUR_EXTERNAL, + BIT(MSM_VIDC_BLUR_NONE) | BIT(MSM_VIDC_BLUR_EXTERNAL), + MSM_VIDC_BLUR_NONE, + 0, + HFI_PROP_BLUR_TYPES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CSC, ENC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_CSC, + CAP_FLAG_OUTPUT_PORT}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_NONE}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {LTR_COUNT, ENC, H264 | HEVC, + 0, MAX_LTR_FRAME_COUNT_5, 1, 0, + V4L2_CID_MPEG_VIDEO_LTR_COUNT, + HFI_PROP_LTR_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {USE_LTR, ENC, H264 | HEVC, + 0, + ((1 << MAX_LTR_FRAME_COUNT_5) - 1), + 0, 0, + V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, + HFI_PROP_LTR_USE, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {MARK_LTR, ENC, H264 | HEVC, + INVALID_DEFAULT_MARK_OR_USE_LTR, + (MAX_LTR_FRAME_COUNT_5 - 1), + 1, INVALID_DEFAULT_MARK_OR_USE_LTR, + V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, + HFI_PROP_LTR_MARK, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {BASELAYER_PRIORITY, ENC, H264, + 0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0, + V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, + HFI_PROP_BASELAYER_PRIORITYID, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {AU_DELIMITER, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + HFI_PROP_AUD, + CAP_FLAG_OUTPUT_PORT}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + 0, 1, 1, 1, + 0, + HFI_PROP_CONTENT_ADAPTIVE_CODING, + CAP_FLAG_OUTPUT_PORT}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + MSM_VIDC_PREPROCESS_NONE, + MSM_VIDC_PREPROCESS_TYPE0, + BIT(MSM_VIDC_PREPROCESS_NONE) | + BIT(MSM_VIDC_PREPROCESS_TYPE0), + MSM_VIDC_PREPROCESS_NONE, + 0, HFI_PROP_REQUEST_PREPROCESS, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {MIN_QUALITY, ENC, H264 | HEVC, + 0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY, + 0, + HFI_PROP_MAINTAIN_MIN_QUALITY, + CAP_FLAG_OUTPUT_PORT}, + + {VBV_DELAY, ENC, H264 | HEVC, + 200, 300, 100, 300, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, + HFI_PROP_VBV_DELAY, + CAP_FLAG_OUTPUT_PORT}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + /* default peak bitrate is 10% larger than avg bitrate */ + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + HFI_PROP_TOTAL_PEAK_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {MIN_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP}, + + {I_FRAME_MIN_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP}, + + {MAX_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MAX_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP}, + + {I_FRAME_MAX_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP}, + + {I_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {I_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {LAYER_TYPE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_TYPE, ENC, H264, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_ENABLE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT}, + + {LAYER_ENABLE, ENC, HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {ENH_LAYER_COUNT, ENC, HEVC, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, ENC, H264, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L3_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L3_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENTROPY_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + HFI_PROP_CABAC_SESSION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {ENTROPY_MODE, DEC, H264 | HEVC | VP9, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + 0, + HFI_PROP_CABAC_SESSION}, + + {PROFILE, ENC | DEC, H264, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE, + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_MPEG_VIDEO_VP9_PROFILE_2, + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6), + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), + V4L2_MPEG_VIDEO_H264_LEVEL_6_1, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1)| + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), + V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + DB_H264_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + BIT(DB_H264_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + DB_HEVC_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) | + BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_ALPHA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA}, + + {LF_ALPHA, ENC, HEVC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2}, + + {LF_BETA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA}, + + {LF_BETA, ENC, HEVC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2}, + + {SLICE_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MAX_BYTES, ENC, H264 | HEVC, + MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE, + 1, MIN_SLICE_BYTE_SIZE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + HFI_PROP_MULTI_SLICE_BYTES_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {SLICE_MAX_MB, ENC, H264 | HEVC, + 1, MAX_SLICE_MB_SIZE, 1, 1, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + HFI_PROP_MULTI_SLICE_MB_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {MB_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {TRANSFORM_8X8, ENC, H264, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + HFI_PROP_8X8_TRANSFORM, + CAP_FLAG_OUTPUT_PORT}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET, + 1, MAX_CHROMA_QP_OFFSET, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + HFI_PROP_CHROMA_QP_OFFSET, + CAP_FLAG_OUTPUT_PORT}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_8BIT, + CAP_FLAG_INPUT_PORT}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_10BIT, + CAP_FLAG_INPUT_PORT}, + + {STAGE, DEC | ENC, CODECS_ALL, + MSM_VIDC_STAGE_1, + MSM_VIDC_STAGE_2, 1, + MSM_VIDC_STAGE_2, + 0, + HFI_PROP_STAGE}, + + {PIPE, DEC | ENC, CODECS_ALL, + MSM_VIDC_PIPE_1, + MSM_VIDC_PIPE_4, 1, + MSM_VIDC_PIPE_4, + 0, + HFI_PROP_PIPE}, + + {POC, DEC, H264, 0, 2, 1, 1, + 0, + HFI_PROP_PIC_ORDER_CNT_TYPE}, + + {QUALITY_MODE, ENC, CODECS_ALL, + MSM_VIDC_MAX_QUALITY_MODE, + MSM_VIDC_POWER_SAVE_MODE, 1, + MSM_VIDC_POWER_SAVE_MODE}, + + {CODED_FRAMES, DEC, H264 | HEVC, + CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE, + 1, CODED_FRAMES_PROGRESSIVE, + 0, + HFI_PROP_CODED_FRAMES}, + + {BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8, + 0, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH}, + + {CODEC_CONFIG, DEC, H264 | HEVC, 0, 1, 1, 0, + 0, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0, + 0}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_THUMBNAIL_MODE, + CAP_FLAG_INPUT_PORT}, + + {DEFAULT_HEADER, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_DEC_DEFAULT_HEADER}, + + {RAP_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_DEC_START_FROM_RAP_FRAME, + CAP_FLAG_INPUT_PORT}, + + {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + 1, 1, 1, 1}, + + {ALL_INTRA, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {COMPLEXITY, ENC, H264 | HEVC, + 0, 100, + 1, DEFAULT_COMPLEXITY, + 0}, +}; + +static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_cliffs[] = { + /* {cap, domain, codec, + * parents, + * children, + * adjust, set} + */ + + {PIX_FMTS, ENC, HEVC, + {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, MIN_QUALITY, BLUR_TYPES, LTR_COUNT}}, + + {PIX_FMTS, DEC, HEVC, + {PROFILE}}, + + {FRAME_RATE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_q16}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_ring_buffer_count_cliffs}, + + {HFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {VFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {ROTATION, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_rotation}, + + {SUPER_FRAME, ENC, H264 | HEVC, + {INPUT_BUF_HOST_MAX_COUNT, OUTPUT_BUF_HOST_MAX_COUNT}, + NULL, + NULL}, + + {HEADER_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_header_mode}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_nal_length}, + + {REQUEST_I_FRAME, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_req_sync_frame}, + + {BIT_RATE, ENC, H264, + {PEAK_BITRATE, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BIT_RATE, ENC, HEVC, + {PEAK_BITRATE, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BITRATE_MODE, ENC, H264, + {LTR_COUNT, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE, + MIN_QUALITY, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEVC, + {LTR_COUNT, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT, + BIT_RATE, MIN_QUALITY, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {CONSTANT_QUALITY, ENC, HEVC, + {0}, + NULL, + msm_vidc_set_constant_quality}, + + {GOP_SIZE, ENC, CODECS_ALL, + {ALL_INTRA}, + msm_vidc_adjust_gop_size, + msm_vidc_set_gop_size}, + + {B_FRAME, ENC, H264 | HEVC, + {ALL_INTRA}, + msm_vidc_adjust_b_frame, + msm_vidc_set_u32}, + + {BLUR_TYPES, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_blur_type, + msm_vidc_set_u32_enum}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + {STAGE, BIT_RATE}, + msm_vidc_adjust_enc_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LTR_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ltr_count, + msm_vidc_set_u32}, + + {USE_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_use_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {MARK_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_mark_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {AU_DELIMITER, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_u32}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + {REQUEST_PREPROCESS}, + msm_vidc_adjust_brs, + msm_vidc_set_vbr_related_properties}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_preprocess, + msm_vidc_set_preprocess}, + + {MIN_QUALITY, ENC, H264, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {MIN_QUALITY, ENC, HEVC, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {VBV_DELAY, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_cbr_related_properties}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_peak_bitrate, + msm_vidc_set_cbr_related_properties}, + + {MIN_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_min_qp}, + + {MIN_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_min_qp, + msm_vidc_set_min_qp}, + + {MAX_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_max_qp}, + + {MAX_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_max_qp, + msm_vidc_set_max_qp}, + + {I_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_i_frame_qp, + msm_vidc_set_frame_qp}, + + {I_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_p_frame_qp, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_b_frame_qp, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {LAYER_TYPE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING, LTR_COUNT}}, + + {LAYER_ENABLE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING}}, + + {ENH_LAYER_COUNT, ENC, H264 | HEVC, + {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, LTR_COUNT}, + msm_vidc_adjust_layer_count, + msm_vidc_set_layer_count_and_type}, + + {L0_BR, ENC, H264 | HEVC, + {L1_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L1_BR, ENC, H264 | HEVC, + {L2_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L2_BR, ENC, H264 | HEVC, + {L3_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L3_BR, ENC, H264 | HEVC, + {L4_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L4_BR, ENC, H264 | HEVC, + {L5_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L5_BR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {ENTROPY_MODE, ENC, H264, + {BIT_RATE}, + msm_vidc_adjust_entropy_mode, + msm_vidc_set_u32}, + + {PROFILE, ENC, H264, + {ENTROPY_MODE, TRANSFORM_8X8}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, H264, + {ENTROPY_MODE}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, ENC | DEC, HEVC, + {0}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, VP9, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_level}, + + {HEVC_TIER, ENC | DEC, HEVC, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LF_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_deblock_mode}, + + {SLICE_MODE, ENC, H264 | HEVC, + {STAGE, DELIVERY_MODE}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {TRANSFORM_8X8, ENC, H264, + {0}, + msm_vidc_adjust_transform_8x8, + msm_vidc_set_u32}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + {0}, + msm_vidc_adjust_chroma_qp_index_offset, + msm_vidc_set_chroma_qp_index_offset}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_output_order, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {STAGE, ENC | DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_stage}, + + {PIPE, DEC | ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_pipe}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL, + {OUTPUT_ORDER}, + NULL, + msm_vidc_set_u32}, + + {RAP_FRAME, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + {0}, + NULL, + NULL}, + + {ALL_INTRA, ENC, H264 | HEVC, + {LTR_COUNT, SLICE_MODE, BIT_RATE}, + msm_vidc_adjust_all_intra, + NULL}, +}; + +/* Default UBWC config for LPDDR5 */ +static struct msm_vidc_ubwc_config_data ubwc_config_cliffs[] = { + UBWC_CONFIG(8, 32, 16, 0, 1, 1, 1), +}; + +static struct msm_vidc_format_capability format_data_cliffs = { + .codec_info = codec_data_cliffs, + .codec_info_size = ARRAY_SIZE(codec_data_cliffs), + .color_format_info = color_format_data_cliffs, + .color_format_info_size = ARRAY_SIZE(color_format_data_cliffs), + .color_prim_info = color_primaries_data_cliffs, + .color_prim_info_size = ARRAY_SIZE(color_primaries_data_cliffs), + .transfer_char_info = transfer_char_data_cliffs, + .transfer_char_info_size = ARRAY_SIZE(transfer_char_data_cliffs), + .matrix_coeff_info = matrix_coeff_data_cliffs, + .matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_cliffs), +}; + +static const struct msm_vidc_platform_data cliffs_data = { + .core_data = core_data_cliffs, + .core_data_size = ARRAY_SIZE(core_data_cliffs), + .inst_cap_data = instance_cap_data_cliffs, + .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_cliffs), + .inst_cap_dependency_data = instance_cap_dependency_data_cliffs, + .inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_cliffs), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .ubwc_config = ubwc_config_cliffs, + .format_data = &format_data_cliffs, +}; + +int msm_vidc_cliffs_check_ddr_type(void) +{ + u32 ddr_type; + + ddr_type = of_fdt_get_ddrtype(); + if (ddr_type != DDR_TYPE_LPDDR5 && + ddr_type != DDR_TYPE_LPDDR5X) { + d_vpr_e("%s: wrong ddr type %d\n", __func__, ddr_type); + return -EINVAL; + } + + d_vpr_h("%s: ddr type %d\n", __func__, ddr_type); + return 0; +} + +static int msm_vidc_init_data(struct msm_vidc_core *core) +{ + int rc = 0; + + d_vpr_h("%s: initialize cliffs data\n", __func__); + + core->platform->data = cliffs_data; + + rc = msm_vidc_cliffs_check_ddr_type(); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_init_platform_cliffs(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = msm_vidc_init_data(core); + if (rc) + return rc; + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/platform/cliffs/src/msm_vidc_cliffs.c b/qcom/opensource/video-driver/driver/platform/cliffs/src/msm_vidc_cliffs.c new file mode 100644 index 0000000000..e0aebef9c0 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/cliffs/src/msm_vidc_cliffs.c @@ -0,0 +1,5301 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include + +#include +#include + +#include +#include "msm_vidc_cliffs.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_platform_ext.h" +#include "msm_vidc_memory_ext.h" +#include "msm_vidc_synx.h" +#include "resources_ext.h" +#include "msm_vidc_iris33.h" +#include "hfi_property.h" +#include "hfi_command.h" +#include "venus_hfi.h" + +/* version: major[24:31], minor[16:23], revision[0:15] */ +#define DRIVER_VERSION 0x04000000 +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010 +#define MAX_BASE_LAYER_PRIORITY_ID 63 +#define MAX_OP_POINT 31 +#define MAX_BITRATE 160000000 +#define MAX_BITRATE_V1 100000000 +#define DEFAULT_BITRATE 20000000 +#define MINIMUM_FPS 1 +#define MAXIMUM_FPS 480 +#define MAX_QP 51 +#define DEFAULT_QP 20 +#define MAX_CONSTANT_QUALITY 100 +#define MIN_SLICE_BYTE_SIZE 512 +#define MAX_SLICE_BYTE_SIZE \ + ((MAX_BITRATE) >> 3) +#define MAX_SLICE_BYTE_SIZE_V1 \ + ((MAX_BITRATE_V1) >> 3) +#define MAX_SLICE_MB_SIZE \ + (((4096 + 15) >> 4) * ((2160 + 15) >> 4)) + +#define ENC MSM_VIDC_ENCODER +#define DEC MSM_VIDC_DECODER +#define H264 MSM_VIDC_H264 +#define HEVC MSM_VIDC_HEVC +#define VP9 MSM_VIDC_VP9 +#define AV1 MSM_VIDC_AV1 +#define HEIC MSM_VIDC_HEIC +#define CODECS_ALL_V0 (H264 | HEVC | VP9 | HEIC | AV1) +#define CODECS_ALL_V1 (H264 | HEVC | VP9 | HEIC) +#define MAXIMUM_OVERRIDE_VP9_FPS 200 + +static struct codec_info codec_data_cliffs_v0[] = { + { + .v4l2_codec = V4L2_PIX_FMT_H264, + .vidc_codec = MSM_VIDC_H264, + .pixfmt_name = "AVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_HEVC, + .vidc_codec = MSM_VIDC_HEVC, + .pixfmt_name = "HEVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VP9, + .vidc_codec = MSM_VIDC_VP9, + .pixfmt_name = "VP9", + }, + { + .v4l2_codec = V4L2_PIX_FMT_AV1, + .vidc_codec = MSM_VIDC_AV1, + .pixfmt_name = "AV1", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VIDC_HEIC, + .vidc_codec = MSM_VIDC_HEIC, + .pixfmt_name = "HEIC", + }, +}; + +static struct codec_info codec_data_cliffs_v1[] = { + { + .v4l2_codec = V4L2_PIX_FMT_H264, + .vidc_codec = MSM_VIDC_H264, + .pixfmt_name = "AVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_HEVC, + .vidc_codec = MSM_VIDC_HEVC, + .pixfmt_name = "HEVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VP9, + .vidc_codec = MSM_VIDC_VP9, + .pixfmt_name = "VP9", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VIDC_HEIC, + .vidc_codec = MSM_VIDC_HEIC, + .pixfmt_name = "HEIC", + }, +}; + +static struct color_format_info color_format_data_cliffs[] = { + { + .v4l2_color_format = V4L2_PIX_FMT_NV12, + .vidc_color_format = MSM_VIDC_FMT_NV12, + .pixfmt_name = "NV12", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_NV21, + .vidc_color_format = MSM_VIDC_FMT_NV21, + .pixfmt_name = "NV21", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC08C, + .vidc_color_format = MSM_VIDC_FMT_NV12C, + .pixfmt_name = "NV12C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC10C, + .vidc_color_format = MSM_VIDC_FMT_TP10C, + .pixfmt_name = "TP10C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_RGBA32, + .vidc_color_format = MSM_VIDC_FMT_RGBA8888, + .pixfmt_name = "RGBA", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_P010, + .vidc_color_format = MSM_VIDC_FMT_P010, + .pixfmt_name = "P010", + }, + { + .v4l2_color_format = V4L2_META_FMT_VIDC, + .vidc_color_format = MSM_VIDC_FMT_META, + .pixfmt_name = "META", + }, +}; + +static struct color_primaries_info color_primaries_data_cliffs[] = { + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_RESERVED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_UNSPECIFIED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_REC709, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT709, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_BG, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE170M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT601_525, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE240M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_ST240M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_GENERIC_FILM, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_GENERIC_FILM, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_BT2020, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT2020, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DCI_P3, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_RP431_2, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_EG431, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_EG431_1, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_EBU_TECH, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_EBU_TECH, + }, +}; + +static struct transfer_char_info transfer_char_data_cliffs[] = { + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_RESERVED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_UNSPECIFIED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_709, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT709, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT470_SYSTEM_M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT470_SYSTEM_M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT470_SYSTEM_BG, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT470_SYSTEM_BG, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT601_525_OR_625, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT601_525_OR_625, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE240M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST240M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_LINEAR, + .vidc_transfer_char = MSM_VIDC_TRANSFER_LINEAR, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_XVYCC, + .vidc_transfer_char = MSM_VIDC_TRANSFER_XVYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT1361, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT1361_0, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SRGB, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SRGB_SYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT2020, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT2020_14, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE2084, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_ST428, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST428_1, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_HLG, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT2100_2_HLG, + }, +}; + +static struct matrix_coeff_info matrix_coeff_data_cliffs[] = { + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_UNSPECIFIED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_VIDC_SRGB_OR_SMPTE_ST428, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SRGB_SMPTE_ST428_1, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_VIDC_FCC47_73_682, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_FCC_TITLE_47, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_SMPTE240M, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020_CONST_LUM, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT, + }, +}; + +static struct msm_platform_core_capability core_data_cliffs_v0[] = { + /* {type, value} */ + {ENC_CODECS, H264 | HEVC | HEIC}, + {DEC_CODECS, H264 | HEVC | VP9 | AV1 | HEIC}, + {MAX_SESSION_COUNT, 16}, + {MAX_NUM_720P_SESSIONS, 16}, + {MAX_NUM_1080P_SESSIONS, 16}, + {MAX_NUM_4K_SESSIONS, 4}, + {MAX_NUM_8K_SESSIONS, 1}, + {MAX_SECURE_SESSION_COUNT, 3}, + {MAX_RT_MBPF, 129600}, /* ((7680*4320)/256)) */ + {MAX_MBPF, 139264}, /* (4 * ((4096*2176)/256)) */ + /* max_load 1920x1080@480fps which is greater than 7680x4320@30fps */ + /* Concurrency: UHD@30 decode + uhd@30 encode */ + {MAX_MBPS, 3916800}, + {MAX_IMAGE_MBPF, 1048576}, /* (16384x16384)/256 */ + {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */ + {MAX_MBPS_HQ, 244800}, /* ((1920x1088)/256)@30fps */ + {MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */ + {MAX_MBPS_B_FRAME, 979200}, /* 3840x2176/256 MBs@30fps */ + {MAX_MBPS_ALL_INTRA, 489600}, /* ((1920x1088)/256)@60fps */ + {MAX_ENH_LAYER_COUNT, 5}, + {NUM_VPP_PIPE, 2}, + {SW_PC, 1}, + {FW_UNLOAD, 0}, + {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */ + {SW_PC_DELAY, SW_PC_DELAY_VALUE }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/ + {FW_UNLOAD_DELAY, FW_UNLOAD_DELAY_VALUE }, /* 3000 ms (>SW_PC_DELAY)*/ + {PAGEFAULT_NON_FATAL, 1}, + {PAGETABLE_CACHING, 0}, + {DCVS, 1}, + {DECODE_BATCH, 1}, + {DECODE_BATCH_TIMEOUT, 200}, + {STATS_TIMEOUT_MS, 2000}, + {AV_SYNC_WINDOW_SIZE, 40}, + {NON_FATAL_FAULTS, 1}, + {ENC_AUTO_FRAMERATE, 1}, + {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_META_CAPTURE | + V4L2_CAP_STREAMING}, + {SUPPORTS_SYNX_FENCE, 1}, + {SUPPORTS_REQUESTS, 0}, +}; + +static struct msm_platform_core_capability core_data_cliffs_v1[] = { + /* {type, value} */ + {ENC_CODECS, H264 | HEVC | HEIC}, + {DEC_CODECS, H264 | HEVC | VP9 | HEIC}, + {MAX_SESSION_COUNT, 16}, + {MAX_NUM_720P_SESSIONS, 16}, + {MAX_NUM_1080P_SESSIONS, 8}, + {MAX_NUM_4K_SESSIONS, 2}, + {MAX_SECURE_SESSION_COUNT, 3}, + {MAX_RT_MBPF, 69632}, /* (2 * ((4096x2176)/256)) */ + {MAX_MBPF, 104448}, /* (3 * ((4096x2176)/256))*/ + /* max_load 4096x2176@60fps*/ + {MAX_MBPS, 2088960}, /* Concurrency: UHD@30 decode + 1080p@30 encode */ + {MAX_IMAGE_MBPF, 1048576}, /* (16384x16384)/256 */ + {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */ + {MAX_MBPS_HQ, 244800}, /* ((1920x1088)/256)@30fps */ + {MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */ + {MAX_MBPS_B_FRAME, 979200}, /* 3840x2176/256 MBs@30fps */ + {MAX_MBPS_ALL_INTRA, 489600}, /* ((1920x1088)/256)@60fps */ + {MAX_ENH_LAYER_COUNT, 5}, + {NUM_VPP_PIPE, 2}, + {SW_PC, 1}, + {FW_UNLOAD, 0}, + {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */ + {SW_PC_DELAY, SW_PC_DELAY_VALUE }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/ + {FW_UNLOAD_DELAY, FW_UNLOAD_DELAY_VALUE }, /* 3000 ms (>SW_PC_DELAY)*/ + {PAGEFAULT_NON_FATAL, 1}, + {PAGETABLE_CACHING, 0}, + {DCVS, 1}, + {DECODE_BATCH, 1}, + {DECODE_BATCH_TIMEOUT, 200}, + {STATS_TIMEOUT_MS, 2000}, + {AV_SYNC_WINDOW_SIZE, 40}, + {NON_FATAL_FAULTS, 1}, + {ENC_AUTO_FRAMERATE, 1}, + {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_META_CAPTURE | + V4L2_CAP_STREAMING}, + {SUPPORTS_SYNX_FENCE, 1}, + {SUPPORTS_REQUESTS, 0}, +}; + +static struct msm_platform_inst_capability instance_cap_data_cliffs_v0[] = { + /* {cap, domain, codec, + * min, max, step_or_mask, value, + * v4l2_id, + * hfi_id, + * flags} + */ + {DRV_VERSION, DEC|ENC, CODECS_ALL_V0, + 0, INT_MAX, 1, DRIVER_VERSION, + V4L2_CID_MPEG_VIDC_DRIVER_VERSION}, + + {FRAME_WIDTH, DEC, CODECS_ALL_V0, 96, 7680, 1, 1920}, + + {FRAME_WIDTH, DEC, VP9 | AV1, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, CODECS_ALL_V0, 128, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_WIDTH, ENC, CODECS_ALL_V0, 128, 4096, 1, 1920}, + + {LOSSLESS_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, DEC, CODECS_ALL_V0, 96, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, ENC, CODECS_ALL_V0, 128, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {FRAME_HEIGHT, DEC, CODECS_ALL_V0, 96, 7680, 1, 1080}, + + {FRAME_HEIGHT, DEC, VP9 | AV1, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, CODECS_ALL_V0, 128, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL_V0, 128, 4096, 1, 1080}, + + {LOSSLESS_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, DEC, CODECS_ALL_V0, 96, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, ENC, CODECS_ALL_V0, 128, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {PIX_FMTS, ENC | DEC, H264, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC | DEC, HEVC | VP9 | AV1, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12}, + + {PIX_FMTS, DEC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL_V0, 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_INPUT, ENC | DEC, HEIC, 0, 64, 1, 1, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL_V0, + 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE}, + + /* (4096 * 2176) / 256 */ + {MBPF, ENC, CODECS_ALL_V0, 64, 34816, 1, 34816}, + + {MBPF, ENC, HEVC, 36, 34816, 1, 34816}, + + /* ((16384x16384)/256) */ + {MBPF, ENC, HEIC, 36, 1048576, 1, 1048576}, + + /* (4 * ((4096 * 2176)/256) */ + {MBPF, DEC, CODECS_ALL_V0, 36, 139264, 1, 139264}, + + /* (4096 * 2160) / 256 */ + {MBPF, DEC, VP9 | AV1, 36, 34560, 1, 34560}, + + /* ((8192x8192)/256) */ + {MBPF, DEC, HEIC, 64, 262144, 1, 262144 }, + + /* (4096 * 2176) / 256 */ + {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 34816, 1, 34816}, + + /* Batch Mode Decode */ + /* BATCH_MBPF + 2 is done for chipsets other than lanai + * due to timeline constraints since msm_vidc_allow_decode_batch + * has checks to allow batching for less than BATCH_MBPF. + * Same applies for BATCH_FPS. + */ + {BATCH_MBPF, DEC, H264 | HEVC | VP9 | AV1, 64, 8162, 1, 8162}, + + /* (1920 * 1088) / 256 */ + {BATCH_FPS, DEC, H264 | HEVC | VP9 | AV1, 1, 61, 1, 61}, + + {SECURE_MBPF, ENC | DEC, H264 | HEVC | VP9 | AV1, 64, 36864, 1, 36864}, + + {SECURE_MBPF, ENC, HEVC, 36, 36864, 1, 36864}, + + {FRAME_RATE, ENC, CODECS_ALL_V0, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, ENC, HEIC, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (MINIMUM_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, DEC, CODECS_ALL_V0, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {FRAME_RATE, DEC, VP9, + (MINIMUM_FPS << 16), (MAXIMUM_OVERRIDE_VP9_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {OPERATING_RATE, ENC, CODECS_ALL_V0, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {OPERATING_RATE, DEC, CODECS_ALL_V0, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_OPERATING_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {INPUT_RATE, ENC | DEC, CODECS_ALL_V0, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL_V0, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8}, + + {MB_CYCLES_VSP, ENC, CODECS_ALL_V0, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, CODECS_ALL_V0, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, VP9 | AV1, 60, 60, 1, 60}, + + {MB_CYCLES_VPP, ENC, CODECS_ALL_V0, 675, 675, 1, 675}, + + {MB_CYCLES_VPP, DEC, CODECS_ALL_V0, 200, 200, 1, 200}, + + {MB_CYCLES_LP, ENC, CODECS_ALL_V0, 320, 320, 1, 320}, + + {MB_CYCLES_LP, DEC, CODECS_ALL_V0, 200, 200, 1, 200}, + + {MB_CYCLES_FW, ENC | DEC, CODECS_ALL_V0, 489583, 489583, 1, 489583}, + + {MB_CYCLES_FW_VPP, ENC, CODECS_ALL_V0, 48405, 48405, 1, 48405}, + + {MB_CYCLES_FW_VPP, DEC, CODECS_ALL_V0, 66234, 66234, 1, 66234}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL_V0, + 0, 0, 1, 0}, + + {CLIENT_ID, ENC | DEC, CODECS_ALL_V0, + INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, + V4L2_CID_MPEG_VIDC_CLIENT_ID}, + + {SECURE_MODE, ENC | DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_SECURE, + HFI_PROP_SECURE, + CAP_FLAG_NONE}, + + /* + * Client will enable V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE + * to get fence_id in input metadata buffer done. + */ + {META_OUTBUF_FENCE, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE, + HFI_PROP_FENCE, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* + * Client to do set_ctrl with FENCE_ID to set fence_id + * and then client will do get_ctrl with FENCE_FD to get + * fence_fd corresponding to client set fence_id. + */ + {FENCE_ID, DEC, CODECS_ALL_V0, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SW_FENCE_ID, + 0, + CAP_FLAG_DYNAMIC_ALLOWED | CAP_FLAG_OUTPUT_PORT}, + + {FENCE_FD, DEC, CODECS_ALL_V0, + INVALID_FD, INT_MAX, 1, INVALID_FD, + V4L2_CID_MPEG_VIDC_SW_FENCE_FD, + 0, + CAP_FLAG_VOLATILE}, + + /* Fence type for input buffer. Currently unused */ + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_NONE, MSM_VIDC_FENCE_NONE, + BIT(MSM_VIDC_FENCE_NONE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_NONE, MSM_VIDC_SYNX_V2_FENCE, + BIT(MSM_VIDC_FENCE_NONE) | BIT(MSM_VIDC_SW_FENCE) | + BIT(MSM_VIDC_SYNX_V2_FENCE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* Fence direction for input buffer. Currently unused */ + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_NONE, + BIT(MSM_VIDC_FENCE_DIR_NONE), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_RX, + BIT(MSM_VIDC_FENCE_DIR_NONE) | BIT(MSM_VIDC_FENCE_DIR_TX) | + BIT(MSM_VIDC_FENCE_DIR_RX), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + {FENCE_ERROR_DATA_CORRUPT, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + 0, + HFI_PROP_FENCE_ERROR_DATA_CORRUPT}, + + {TS_REORDER, DEC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TS_REORDER}, + + {HFLIP, ENC, CODECS_ALL_V0, + 0, 1, 1, 0, + V4L2_CID_HFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {VFLIP, ENC, CODECS_ALL_V0, + 0, 1, 1, 0, + V4L2_CID_VFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ROTATION, ENC, CODECS_ALL_V0, + 0, 270, 90, 0, + V4L2_CID_ROTATE, + HFI_PROP_ROTATION, + CAP_FLAG_OUTPUT_PORT}, + + {SUPER_FRAME, ENC, H264 | HEVC, + 0, 32, 1, 0, + V4L2_CID_MPEG_VIDC_SUPERFRAME, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {SLICE_DECODE, DEC, H264 | HEVC | AV1, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_MPEG_MSM_VIDC_DISABLE, + 0, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, + 0}, + + {HEADER_MODE, ENC, CODECS_ALL_V0, + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + HFI_PROP_SEQ_HEADER_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL_V0, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL_V0, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_MPEG_MSM_VIDC_ENABLE, + 1, V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDC_VUI_TIMING_INFO, + HFI_PROP_DISABLE_VUI_TIMING_INFO, + CAP_FLAG_OUTPUT_PORT}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL_V0, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_OUTPUT_PORT}, + + {WITHOUT_STARTCODE, DEC, AV1, + 0, 0, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_INPUT_PORT}, + + {NAL_LENGTH_FIELD, ENC, CODECS_ALL_V0, + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_MPEG_VIDEO_HEVC_SIZE_4, + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) | + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4), + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* TODO: Firmware introduced enumeration type for this + * with and without seq header. + */ + {REQUEST_I_FRAME, ENC, H264 | HEVC, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + HFI_PROP_REQUEST_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* Enc: Keeping CABAC and CAVLC as same bitrate. + * Dec: there's no use of Bitrate cap + */ + {BIT_RATE, ENC, H264 | HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE, + HFI_PROP_TOTAL_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITRATE_MODE, ENC, H264, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {CAVLC_MAX_BITRATE, ENC, H264, 0, + 160000000, 1, 160000000}, + + {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {LOWLATENCY_MAX_BITRATE, ENC, H264 | HEVC, 0, + 70000000, 1, 70000000}, + + {NUM_COMV, DEC, CODECS_ALL_V0, + 0, INT_MAX, 1, 0}, + + {LOSSLESS, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU}, + + {FRAME_SKIP_MODE, ENC, H264 | HEVC | HEIC, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {FRAME_RC_ENABLE, ENC, H264 | HEVC | HEIC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE}, + + {CONSTANT_QUALITY, ENC, HEVC, + 1, MAX_CONSTANT_QUALITY, 1, 90, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CONSTANT_QUALITY, ENC, HEIC, + 1, MAX_CONSTANT_QUALITY, 1, 100, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, CODECS_ALL_V0, + 0, INT_MAX, 1, 2 * DEFAULT_FPS - 1, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, HEIC, + 0, INT_MAX, 1, 0 /* all intra */, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_CLOSURE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + 0}, + + {B_FRAME, ENC, H264 | HEVC, + 0, 7, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {B_FRAME, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {BLUR_TYPES, ENC, H264 | HEVC, + MSM_VIDC_BLUR_NONE, MSM_VIDC_BLUR_EXTERNAL, + BIT(MSM_VIDC_BLUR_NONE) | BIT(MSM_VIDC_BLUR_EXTERNAL), + MSM_VIDC_BLUR_NONE, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_TYPES, + HFI_PROP_BLUR_TYPES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_RESOLUTION, + HFI_PROP_BLUR_RESOLUTION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CSC, ENC, CODECS_ALL_V0, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CSC, + HFI_PROP_CSC, + CAP_FLAG_OUTPUT_PORT}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL_V0, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX, + HFI_PROP_CSC_MATRIX, + CAP_FLAG_OUTPUT_PORT}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + 0, + CAP_FLAG_NONE}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {LTR_COUNT, ENC, H264 | HEVC, + 0, MAX_LTR_FRAME_COUNT_5, 1, 0, + V4L2_CID_MPEG_VIDEO_LTR_COUNT, + HFI_PROP_LTR_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {USE_LTR, ENC, H264 | HEVC, + 0, + ((1 << MAX_LTR_FRAME_COUNT_5) - 1), + 0, 0, + V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, + HFI_PROP_LTR_USE, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {MARK_LTR, ENC, H264 | HEVC, + INVALID_DEFAULT_MARK_OR_USE_LTR, + (MAX_LTR_FRAME_COUNT_5 - 1), + 1, INVALID_DEFAULT_MARK_OR_USE_LTR, + V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, + HFI_PROP_LTR_MARK, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {BASELAYER_PRIORITY, ENC, H264, + 0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0, + V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, + HFI_PROP_BASELAYER_PRIORITYID, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {IR_TYPE, ENC, H264 | HEVC, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC, + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) | + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC), + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {IR_PERIOD, ENC, H264 | HEVC, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, + 0, + CAP_FLAG_INPUT_PORT | CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {AU_DELIMITER, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + HFI_PROP_AUD, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_CONTENT_ADAPTIVE_CODING, + HFI_PROP_CONTENT_ADAPTIVE_CODING, + CAP_FLAG_OUTPUT_PORT}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + MSM_VIDC_PREPROCESS_NONE, + MSM_VIDC_PREPROCESS_TYPE0, + BIT(MSM_VIDC_PREPROCESS_NONE) | + BIT(MSM_VIDC_PREPROCESS_TYPE0), + MSM_VIDC_PREPROCESS_NONE, + 0, HFI_PROP_REQUEST_PREPROCESS, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + 0, MAX_BITRATE_BOOST, 25, MAX_BITRATE_BOOST, + V4L2_CID_MPEG_VIDC_QUALITY_BITRATE_BOOST, + HFI_PROP_BITRATE_BOOST, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_QUALITY, ENC, H264 | HEVC, + 0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY, + 0, + HFI_PROP_MAINTAIN_MIN_QUALITY, + CAP_FLAG_OUTPUT_PORT}, + + {VBV_DELAY, ENC, H264 | HEVC, + 200, 300, 100, 300, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, + HFI_PROP_VBV_DELAY, + CAP_FLAG_OUTPUT_PORT}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + /* default peak bitrate is 10% larger than avg bitrate */ + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + HFI_PROP_TOTAL_PEAK_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {MIN_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP}, + + {I_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP}, + + {MAX_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MAX_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP}, + + {I_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP}, + + {I_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {I_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {LAYER_TYPE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_TYPE, ENC, H264, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_ENABLE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT}, + + {LAYER_ENABLE, ENC, HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {ENH_LAYER_COUNT, ENC, HEVC, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, ENC, H264, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, DEC, AV1, + 0, MAX_OP_POINT, 1, 0, + 0, + HFI_PROP_AV1_OP_POINT, + CAP_FLAG_INPUT_PORT}, + + {L0_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L3_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L3_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENTROPY_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + HFI_PROP_CABAC_SESSION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {ENTROPY_MODE, DEC, H264 | HEVC | VP9 | AV1, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + 0, + HFI_PROP_CABAC_SESSION}, + + {PROFILE, ENC | DEC, H264, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, ENC | DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE, + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_MPEG_VIDEO_VP9_PROFILE_2, + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, AV1, + V4L2_MPEG_VIDC_AV1_PROFILE_MAIN, + V4L2_MPEG_VIDC_AV1_PROFILE_MAIN, + BIT(V4L2_MPEG_VIDC_AV1_PROFILE_MAIN), + V4L2_MPEG_VIDC_AV1_PROFILE_MAIN, + V4L2_CID_MPEG_VIDC_AV1_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2), + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1), + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6), + V4L2_MPEG_VIDEO_HEVC_LEVEL_6, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + V4L2_MPEG_VIDEO_VP9_LEVEL_5_1, + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1), + V4L2_MPEG_VIDEO_VP9_LEVEL_5_1, + V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, AV1, + V4L2_MPEG_VIDC_AV1_LEVEL_2_0, + V4L2_MPEG_VIDC_AV1_LEVEL_5_1, + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_3) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_3) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_3) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_5_1), + V4L2_MPEG_VIDC_AV1_LEVEL_5_1, + V4L2_CID_MPEG_VIDC_AV1_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {AV1_TIER, DEC, AV1, + V4L2_MPEG_VIDC_AV1_TIER_MAIN, + V4L2_MPEG_VIDC_AV1_TIER_HIGH, + BIT(V4L2_MPEG_VIDC_AV1_TIER_MAIN) | + BIT(V4L2_MPEG_VIDC_AV1_TIER_HIGH), + V4L2_MPEG_VIDC_AV1_TIER_HIGH, + V4L2_CID_MPEG_VIDC_AV1_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEIC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN), + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + DB_H264_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + BIT(DB_H264_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + DB_HEVC_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) | + BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_ALPHA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA}, + + {LF_ALPHA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2}, + + {LF_BETA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA}, + + {LF_BETA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2}, + + {SLICE_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MAX_BYTES, ENC, H264 | HEVC, + MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE, + 1, MIN_SLICE_BYTE_SIZE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + HFI_PROP_MULTI_SLICE_BYTES_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {SLICE_MAX_MB, ENC, H264 | HEVC, + 1, MAX_SLICE_MB_SIZE, 1, 1, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + HFI_PROP_MULTI_SLICE_MB_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {MB_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {TRANSFORM_8X8, ENC, H264, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + HFI_PROP_8X8_TRANSFORM, + CAP_FLAG_OUTPUT_PORT}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET, + 1, MAX_CHROMA_QP_OFFSET, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + HFI_PROP_CHROMA_QP_OFFSET, + CAP_FLAG_OUTPUT_PORT}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + 0, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL_V0, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL_V0, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL_V0, 0x0, 0xff3fcff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_8BIT, + CAP_FLAG_INPUT_PORT}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL_V0, 0x0, 0x3fffffff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_10BIT, + CAP_FLAG_INPUT_PORT}, + + {STAGE, DEC|ENC, CODECS_ALL_V0, + MSM_VIDC_STAGE_1, + MSM_VIDC_STAGE_2, 1, + MSM_VIDC_STAGE_2, + 0, + HFI_PROP_STAGE}, + + {PIPE, DEC|ENC, CODECS_ALL_V0, + MSM_VIDC_PIPE_1, + MSM_VIDC_PIPE_2, 1, + MSM_VIDC_PIPE_2, + 0, + HFI_PROP_PIPE}, + + {POC, DEC, H264, + 0, 2, 1, 1, + 0, + HFI_PROP_PIC_ORDER_CNT_TYPE, + CAP_FLAG_VOLATILE}, + + /* + * value of MAX_NUM_REORDER_FRAMES is 32 packed as mentioned below + * (max_num_reorder_count << 16) | max_dec_frame_buffering_count + */ + {MAX_NUM_REORDER_FRAMES, DEC, H264 | HEVC, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_MAX_NUM_REORDER_FRAMES, + HFI_PROP_MAX_NUM_REORDER_FRAMES, + CAP_FLAG_VOLATILE}, + + {QUALITY_MODE, ENC, CODECS_ALL_V0, + MSM_VIDC_MAX_QUALITY_MODE, + MSM_VIDC_POWER_SAVE_MODE, 1, + MSM_VIDC_POWER_SAVE_MODE}, + + {CODED_FRAMES, DEC, H264 | HEVC | HEIC, + CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE, + 1, CODED_FRAMES_PROGRESSIVE, + V4L2_CID_MPEG_VIDC_INTERLACE, + HFI_PROP_CODED_FRAMES, + CAP_FLAG_VOLATILE}, + + {BIT_DEPTH, DEC, CODECS_ALL_V0, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8, + 0, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH}, + + {CODEC_CONFIG, DEC, H264 | HEVC | HEIC | AV1, 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CODEC_CONFIG, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL_V0, 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_MIN_BITSTREAM_SIZE_OVERWRITE}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL_V0, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_THUMBNAIL_MODE, + HFI_PROP_THUMBNAIL_MODE, + CAP_FLAG_INPUT_PORT}, + + {DEFAULT_HEADER, DEC, CODECS_ALL_V0, + 0, 1, 1, 0, + 0, + HFI_PROP_DEC_DEFAULT_HEADER}, + + {RAP_FRAME, DEC, CODECS_ALL_V0, + 0, 1, 1, 1, + 0, + HFI_PROP_DEC_START_FROM_RAP_FRAME, + CAP_FLAG_INPUT_PORT}, + + {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL_V0, + 0, 1, 1, 1, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {PRIORITY, DEC|ENC, CODECS_ALL_V0, + 0, 4, 1, 4, + V4L2_CID_MPEG_VIDC_PRIORITY, + HFI_PROP_SESSION_PRIORITY, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL_V0, + 1, 1, 1, 1}, + + {CRITICAL_PRIORITY, ENC, CODECS_ALL_V0, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CRITICAL_PRIORITY}, + + {RESERVE_DURATION, ENC, CODECS_ALL_V0, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_RESERVE_DURATION, + HFI_CMD_RESERVE, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENC_IP_CR, ENC, CODECS_ALL_V0, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_ENC_INPUT_COMPRESSION_RATIO, + 0, CAP_FLAG_DYNAMIC_ALLOWED}, + + {FILM_GRAIN, DEC, AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_AV1D_FILM_GRAIN_PRESENT, + HFI_PROP_AV1_FILM_GRAIN_PRESENT, + CAP_FLAG_VOLATILE}, + + {SUPER_BLOCK, DEC, AV1, + 0, 1, 1, 0, + 0, + HFI_PROP_AV1_SUPER_BLOCK_ENABLED}, + + {DRAP, DEC, AV1, + 0, S32_MAX, 1, 0, + 0, + HFI_PROP_AV1_DRAP_CONFIG, + CAP_FLAG_INPUT_PORT}, + + {LAST_FLAG_EVENT_ENABLE, DEC|ENC, CODECS_ALL_V0, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LAST_FLAG_EVENT_ENABLE}, + + {META_BITSTREAM_RESOLUTION, DEC, AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BITSTREAM_RESOLUTION, + HFI_PROP_BITSTREAM_RESOLUTION, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_CROP_OFFSETS, DEC, AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_CROP_OFFSETS, + HFI_PROP_CROP_OFFSETS, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {ALL_INTRA, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {META_LTR_MARK_USE, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_LTR_MARK_USE_DETAILS, + HFI_PROP_LTR_MARK_USE_DETAILS, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEQ_HDR_NAL, ENC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEQ_HEADER_NAL, + HFI_PROP_METADATA_SEQ_HEADER_NAL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DPB_MISR, DEC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_LUMA_CHROMA_MISR, + HFI_PROP_DPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_OPB_MISR, DEC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OPB_LUMA_CHROMA_MISR, + HFI_PROP_OPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_INTERLACE, DEC, H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_INTERLACE, + HFI_PROP_INTERLACE_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TIMESTAMP, DEC | ENC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TIMESTAMP, + HFI_PROP_TIMESTAMP, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_CONCEALED_MB_CNT, DEC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_CONCEALED_MB_COUNT, + HFI_PROP_CONEALED_MB_COUNT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HIST_INFO, DEC, HEVC | AV1 | VP9, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HISTOGRAM_INFO, + HFI_PROP_HISTOGRAM_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TRANSCODING_STAT_INFO, DEC, HEVC|H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TRANSCODE_STAT_INFO, + HFI_PROP_TRANSCODING_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TRANSCODING_STAT_INFO, ENC, HEVC|H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TRANSCODE_STAT_INFO, + HFI_PROP_TRANSCODING_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_PICTURE_TYPE, DEC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_PICTURE_TYPE, + HFI_PROP_PICTURE_TYPE, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + {META_SEI_MASTERING_DISP, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_MASTERING_DISP, DEC, HEVC | HEIC | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, DEC, HEVC | HEIC | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, DEC, HEVC | HEIC | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DOLBY_RPU, ENC, HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DOLBY_RPU, + HFI_PROP_DOLBY_RPU_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DOLBY_RPU, DEC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DOLBY_RPU, + HFI_PROP_DOLBY_RPU_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_EVA_STATS, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_EVA_STATS, + HFI_PROP_EVA_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_BUF_TAG, ENC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + /* + * when fence enabled, client needs output buffer_tag + * in input metadata buffer done. + */ + {META_BUF_TAG, DEC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_TX_OUTPUT | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + {META_DPB_TAG_LIST, DEC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_TAG_LIST, + HFI_PROP_DPB_TAG_LIST, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, ENC, HEIC | H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, DEC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ENC_QP_METADATA, ENC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ENC_QP_METADATA, + HFI_PROP_ENC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ROI_INFO, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ROI_INFO, + HFI_PROP_ROI_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SALIENCY_INFO, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SALIENCY_INFO, + HFI_PROP_ROI_AS_SALIENCY_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DEC_QP_METADATA, DEC, CODECS_ALL_V0, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DEC_QP_METADATA, + HFI_PROP_DEC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {GRID_ENABLE, ENC, HEIC, + 0, 1, 1, 1, + 0, + HFI_PROP_HEIC_GRID_ENABLE, + CAP_FLAG_OUTPUT_PORT}, + + {GRID_SIZE, ENC, HEIC, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH * 2, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH, + V4L2_CID_MPEG_VIDC_GRID_WIDTH}, + + {COMPLEXITY, ENC, H264 | HEVC, + 0, 100, + 1, DEFAULT_COMPLEXITY, + V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY}, + + {DELIVERY_MODE, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_HEVC_ENCODE_DELIVERY_MODE, + HFI_PROP_ENABLE_SLICE_DELIVERY, + CAP_FLAG_OUTPUT_PORT}, + + {DELIVERY_MODE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_H264_ENCODE_DELIVERY_MODE, + HFI_PROP_ENABLE_SLICE_DELIVERY, + CAP_FLAG_OUTPUT_PORT}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL_V0, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SIGNAL_COLOR_INFO, + HFI_PROP_SIGNAL_COLOR_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, +}; + +static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_cliffs_v0[] = { + /* {cap, domain, codec, + * parents, + * children, + * adjust, set} + */ + + {PIX_FMTS, ENC, H264, + {META_ROI_INFO, IR_PERIOD, CSC}}, + + {PIX_FMTS, ENC, HEVC, + {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, META_ROI_INFO, MIN_QUALITY, BLUR_TYPES, IR_PERIOD, + LTR_COUNT, CSC}}, + + {PIX_FMTS, ENC, HEIC, + {PROFILE, CSC}}, + + {PIX_FMTS, DEC, HEVC | HEIC, + {PROFILE}}, + + {FRAME_RATE, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_q16}, + + {FRAME_RATE, DEC, CODECS_ALL_V0, + {0}, + msm_vidc_adjust_dec_frame_rate}, + + {OPERATING_RATE, DEC, CODECS_ALL_V0, + {0}, + msm_vidc_adjust_dec_operating_rate}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL_V0, + {0}, + NULL, + NULL}, + + {SECURE_MODE, ENC | DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {META_OUTBUF_FENCE, DEC, H264 | HEVC | AV1 | VP9, + {LOWLATENCY_MODE, OUTBUF_FENCE_TYPE, OUTBUF_FENCE_DIRECTION}, + NULL, + NULL}, + + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + {0}, + msm_vidc_adjust_dec_outbuf_fence_type, + msm_vidc_set_outbuf_fence_type}, + + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + {0}, + msm_vidc_adjust_dec_outbuf_fence_direction, + msm_vidc_set_outbuf_fence_direction}, + + {FENCE_ERROR_DATA_CORRUPT, DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {HFLIP, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_flip}, + + {VFLIP, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_flip}, + + {ROTATION, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_rotation}, + + {SUPER_FRAME, ENC, H264 | HEVC, + {INPUT_BUF_HOST_MAX_COUNT, OUTPUT_BUF_HOST_MAX_COUNT}, + NULL, + NULL}, + + {SLICE_DECODE, DEC, H264 | HEVC | AV1, + {0}, + NULL, + NULL}, + + {HEADER_MODE, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_header_mode}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_nal_length}, + + {WITHOUT_STARTCODE, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {REQUEST_I_FRAME, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_req_sync_frame}, + + {BIT_RATE, ENC, H264, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BIT_RATE, ENC, HEVC, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BITRATE_MODE, ENC, H264, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE, + META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE, META_TRANSCODING_STAT_INFO}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEVC, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT, + BIT_RATE, META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE, META_EVA_STATS, META_TRANSCODING_STAT_INFO}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEIC, + {TIME_DELTA_BASED_RC, CONSTANT_QUALITY}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {CONSTANT_QUALITY, ENC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_constant_quality}, + + {GOP_SIZE, ENC, CODECS_ALL_V0, + {ALL_INTRA}, + msm_vidc_adjust_gop_size, + msm_vidc_set_gop_size}, + + {GOP_SIZE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {B_FRAME, ENC, H264 | HEVC, + {ALL_INTRA}, + msm_vidc_adjust_b_frame, + msm_vidc_set_u32}, + + {B_FRAME, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {BLUR_TYPES, ENC, H264 | HEVC, + {BLUR_RESOLUTION}, + msm_vidc_adjust_blur_type, + msm_vidc_set_u32_enum}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_blur_resolution, + msm_vidc_set_blur_resolution}, + + {CSC, ENC, CODECS_ALL_V0, + {0}, + msm_vidc_adjust_csc, + msm_vidc_set_u32}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_csc_custom_matrix}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + {STAGE, BIT_RATE}, + msm_vidc_adjust_enc_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | AV1, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, VP9, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LTR_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ltr_count, + msm_vidc_set_u32}, + + {USE_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_use_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {MARK_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_mark_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {IR_PERIOD, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ir_period, + msm_vidc_set_ir_period}, + + {AU_DELIMITER, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_u32}, + + {BASELAYER_PRIORITY, ENC, H264, + {0}, + NULL, + msm_vidc_set_u32}, + + {TIME_DELTA_BASED_RC, ENC, CODECS_ALL_V0, + {0}, + msm_vidc_adjust_delta_based_rc, + msm_vidc_set_u32}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + {REQUEST_PREPROCESS}, + msm_vidc_adjust_brs, + msm_vidc_set_vbr_related_properties}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_preprocess, + msm_vidc_set_preprocess}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_bitrate_boost_iris33, + msm_vidc_set_vbr_related_properties}, + + {MIN_QUALITY, ENC, H264 | HEVC, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {VBV_DELAY, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_cbr_related_properties}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_peak_bitrate, + msm_vidc_set_cbr_related_properties}, + + {MIN_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_min_qp}, + + {MIN_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_min_qp, + msm_vidc_set_min_qp}, + + {MAX_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_max_qp}, + + {MAX_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_max_qp, + msm_vidc_set_max_qp}, + + {I_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_i_frame_qp, + msm_vidc_set_frame_qp}, + + {I_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_p_frame_qp, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_b_frame_qp, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {LAYER_TYPE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING, LTR_COUNT}}, + + {LAYER_ENABLE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING}}, + + {ENH_LAYER_COUNT, ENC, H264 | HEVC, + {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE, LTR_COUNT}, + msm_vidc_adjust_layer_count, + msm_vidc_set_layer_count_and_type}, + + {ENH_LAYER_COUNT, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {L0_BR, ENC, H264 | HEVC, + {L1_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L1_BR, ENC, H264 | HEVC, + {L2_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L2_BR, ENC, H264 | HEVC, + {L3_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L3_BR, ENC, H264 | HEVC, + {L4_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L4_BR, ENC, H264 | HEVC, + {L5_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L5_BR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {ENTROPY_MODE, ENC, H264, + {BIT_RATE}, + msm_vidc_adjust_entropy_mode, + msm_vidc_set_u32}, + + {PROFILE, ENC, H264, + {ENTROPY_MODE, TRANSFORM_8X8}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, H264, + {ENTROPY_MODE}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, ENC, HEVC | HEIC, + {META_SEI_MASTERING_DISP, META_SEI_CLL, META_HDR10PLUS}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, HEVC | HEIC, + {0}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, VP9 | AV1, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, DEC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_level}, + + {AV1_TIER, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {HEVC_TIER, ENC | DEC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LF_MODE, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_deblock_mode}, + + {SLICE_MODE, ENC, H264 | HEVC, + {STAGE, DELIVERY_MODE}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {SLICE_MODE, ENC, HEIC, + {0}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {TRANSFORM_8X8, ENC, H264, + {0}, + msm_vidc_adjust_transform_8x8, + msm_vidc_set_u32}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + {0}, + msm_vidc_adjust_chroma_qp_index_offset, + msm_vidc_set_chroma_qp_index_offset}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9 | AV1, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9 | AV1, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | AV1 | VP9, + {0}, + msm_vidc_adjust_output_order, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL_V0, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL_V0, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {STAGE, ENC | DEC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_stage}, + + {STAGE, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_stage}, + + {STAGE, DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + msm_vidc_set_stage}, + + {PIPE, DEC|ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_pipe}, + + {THUMBNAIL_MODE, DEC, H264 | HEVC | VP9 | AV1, + {OUTPUT_ORDER}, + NULL, + msm_vidc_set_u32}, + + {THUMBNAIL_MODE, DEC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {RAP_FRAME, DEC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_u32}, + + {PRIORITY, DEC|ENC, CODECS_ALL_V0, + {0}, + msm_vidc_adjust_session_priority, + msm_vidc_set_session_priority}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL_V0, + {0}, + NULL, + NULL}, + + {CRITICAL_PRIORITY, ENC, CODECS_ALL_V0, + {0}, + NULL, + NULL}, + + {RESERVE_DURATION, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_reserve_duration}, + + {DRAP, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {ALL_INTRA, ENC, H264 | HEVC, + {LTR_COUNT, IR_PERIOD, SLICE_MODE, BIT_RATE}, + msm_vidc_adjust_all_intra, + NULL}, + + {META_EVA_STATS, ENC, HEVC, + {0}, + msm_vidc_adjust_eva_stats, + NULL}, + + {META_ROI_INFO, ENC, H264 | HEVC, + {MIN_QUALITY, IR_PERIOD, BLUR_TYPES}, + msm_vidc_adjust_roi_info, + NULL}, + + {GRID_ENABLE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {DELIVERY_MODE, ENC, H264 | HEVC, + {LOWLATENCY_MODE, OUTPUT_BUF_HOST_MAX_COUNT}, + msm_vidc_adjust_delivery_mode, + msm_vidc_set_u32}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_vui_timing_info}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL_V0, + {0}, + NULL, + msm_vidc_set_signal_color_info}, + + {META_SEI_MASTERING_DISP, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_sei_mastering_disp, + NULL}, + + {META_SEI_CLL, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_sei_cll, + NULL}, + + {META_HDR10PLUS, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_hdr10plus, + NULL}, + + {META_TRANSCODING_STAT_INFO, ENC, HEVC|H264, + {0}, + msm_vidc_adjust_transcoding_stats, + NULL}, +}; + +static struct msm_platform_inst_capability instance_cap_data_cliffs_v1[] = { + /* {cap, domain, codec, + * min, max, step_or_mask, value, + * v4l2_id, + * hfi_id, + * flags} + */ + {DRV_VERSION, DEC|ENC, CODECS_ALL_V1, + 0, INT_MAX, 1, DRIVER_VERSION, + V4L2_CID_MPEG_VIDC_DRIVER_VERSION}, + + {FRAME_WIDTH, DEC, CODECS_ALL_V1, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, CODECS_ALL_V1, 128, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_WIDTH, ENC, CODECS_ALL_V1, 128, 4096, 1, 1920}, + + {LOSSLESS_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, DEC, CODECS_ALL_V1, 96, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, ENC, CODECS_ALL_V1, 128, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {FRAME_HEIGHT, DEC, CODECS_ALL_V1, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, CODECS_ALL_V1, 128, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL_V1, 128, 4096, 1, 1080}, + + {LOSSLESS_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, DEC, CODECS_ALL_V1, 96, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, ENC, CODECS_ALL_V1, 128, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {PIX_FMTS, ENC | DEC, H264, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC | DEC, HEVC|VP9, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12}, + + {PIX_FMTS, DEC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL_V1, 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_INPUT, ENC | DEC, HEIC, 0, 64, 1, 1, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL_V1, + 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE}, + + /* (4096 * 2304) / 256 */ + {MBPF, ENC, CODECS_ALL_V1, 64, 36864, 1, 36864}, + + {MBPF, ENC, HEVC, 36, 36864, 1, 36864}, + + /* ((16384x16384)/256) */ + {MBPF, ENC, HEIC, 36, 1048576, 1, 1048576}, + + /* (4096 * 2304) / 256 */ + {MBPF, DEC, CODECS_ALL_V1, 36, 36864, 1, 36864}, + + /* ((8192x8192)/256) */ + {MBPF, DEC, HEIC, 64, 262144, 1, 262144 }, + + /* (4096 * 2304) / 256 */ + {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 36864, 1, 36864}, + + /* Batch Mode Decode */ + /* BATCH_MBPF + 2 is done for chipsets other than waipio + * due to timeline constraints since msm_vidc_allow_decode_batch + * has checks to allow batching for less than BATCH_MBPF. + * Same applies for BATCH_FPS. + */ + /* (1920 * 1088) / 256 */ + {BATCH_MBPF, DEC, H264 | HEVC | VP9, 64, 8162, 1, 8162}, + + /* (4096 * 2304) / 256 */ + {BATCH_FPS, DEC, H264 | HEVC | VP9, 1, 61, 1, 61}, + + {SECURE_MBPF, ENC | DEC, H264 | HEVC | VP9, 64, 36864, 1, 36864}, + + {SECURE_MBPF, ENC, HEVC, 36, 36864, 1, 36864}, + + {FRAME_RATE, ENC, CODECS_ALL_V1, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, ENC, HEIC, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (MINIMUM_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, DEC, CODECS_ALL_V1, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {FRAME_RATE, DEC, VP9, + (MINIMUM_FPS << 16), (MAXIMUM_OVERRIDE_VP9_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {OPERATING_RATE, ENC, CODECS_ALL_V1, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {OPERATING_RATE, DEC, CODECS_ALL_V1, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_OPERATING_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {INPUT_RATE, ENC | DEC, CODECS_ALL_V1, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL_V1, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8}, + + {MB_CYCLES_VSP, ENC, CODECS_ALL_V1, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, CODECS_ALL_V1, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60}, + + {MB_CYCLES_VPP, ENC, CODECS_ALL_V1, 675, 675, 1, 675}, + + {MB_CYCLES_VPP, DEC, CODECS_ALL_V1, 200, 200, 1, 200}, + + {MB_CYCLES_LP, ENC, CODECS_ALL_V1, 320, 320, 1, 320}, + + {MB_CYCLES_LP, DEC, CODECS_ALL_V1, 200, 200, 1, 200}, + + {MB_CYCLES_FW, ENC | DEC, CODECS_ALL_V1, 489583, 489583, 1, 489583}, + + {MB_CYCLES_FW_VPP, ENC, CODECS_ALL_V1, 48405, 48405, 1, 48405}, + + {MB_CYCLES_FW_VPP, DEC, CODECS_ALL_V1, 66234, 66234, 1, 66234}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL_V1, + 0, 0, 1, 0}, + + {CLIENT_ID, ENC | DEC, CODECS_ALL_V1, + INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, + V4L2_CID_MPEG_VIDC_CLIENT_ID}, + + {SECURE_MODE, ENC | DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_SECURE, + HFI_PROP_SECURE, + CAP_FLAG_NONE}, + + /* + * Client will enable V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE + * to get fence_id in input metadata buffer done. + */ + {META_OUTBUF_FENCE, DEC, H264 | HEVC | VP9, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE, + HFI_PROP_FENCE, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* + * Client to do set_ctrl with FENCE_ID to set fence_id + * and then client will do get_ctrl with FENCE_FD to get + * fence_fd corresponding to client set fence_id. + */ + {FENCE_ID, DEC, CODECS_ALL_V1, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SW_FENCE_ID, + 0, + CAP_FLAG_DYNAMIC_ALLOWED | CAP_FLAG_OUTPUT_PORT}, + + {FENCE_FD, DEC, CODECS_ALL_V1, + INVALID_FD, INT_MAX, 1, INVALID_FD, + V4L2_CID_MPEG_VIDC_SW_FENCE_FD, + 0, + CAP_FLAG_VOLATILE}, + + /* Fence type for input buffer. Currently unsed */ + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_NONE, MSM_VIDC_FENCE_NONE, + BIT(MSM_VIDC_FENCE_NONE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_NONE, MSM_VIDC_SYNX_V2_FENCE, + BIT(MSM_VIDC_FENCE_NONE) | BIT(MSM_VIDC_SW_FENCE) | + BIT(MSM_VIDC_SYNX_V2_FENCE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* Fence direction for input buffer. Currently unsed */ + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_NONE, + BIT(MSM_VIDC_FENCE_DIR_NONE), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_RX, + BIT(MSM_VIDC_FENCE_DIR_NONE) | BIT(MSM_VIDC_FENCE_DIR_TX) | + BIT(MSM_VIDC_FENCE_DIR_RX), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + {FENCE_ERROR_DATA_CORRUPT, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_FENCE_ERROR_DATA_CORRUPT}, + + {TS_REORDER, DEC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TS_REORDER}, + + {HFLIP, ENC, CODECS_ALL_V1, + 0, 1, 1, 0, + V4L2_CID_HFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {VFLIP, ENC, CODECS_ALL_V1, + 0, 1, 1, 0, + V4L2_CID_VFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ROTATION, ENC, CODECS_ALL_V1, + 0, 270, 90, 0, + V4L2_CID_ROTATE, + HFI_PROP_ROTATION, + CAP_FLAG_OUTPUT_PORT}, + + {SUPER_FRAME, ENC, H264 | HEVC, + 0, 32, 1, 0, + V4L2_CID_MPEG_VIDC_SUPERFRAME, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {SLICE_DECODE, DEC, H264 | HEVC, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_MPEG_MSM_VIDC_DISABLE, + 0, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, + 0}, + + {HEADER_MODE, ENC, CODECS_ALL_V1, + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + HFI_PROP_SEQ_HEADER_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL_V1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL_V1, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_MPEG_MSM_VIDC_ENABLE, + 1, V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDC_VUI_TIMING_INFO, + HFI_PROP_DISABLE_VUI_TIMING_INFO, + CAP_FLAG_OUTPUT_PORT}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL_V1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_OUTPUT_PORT}, + + {WITHOUT_STARTCODE, DEC, AV1, + 0, 0, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + 0, + CAP_FLAG_INPUT_PORT}, + + {NAL_LENGTH_FIELD, ENC, CODECS_ALL_V1, + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_MPEG_VIDEO_HEVC_SIZE_4, + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) | + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4), + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* TODO: Firmware introduced enumeration type for this + * with and without seq header. + */ + {REQUEST_I_FRAME, ENC, H264 | HEVC, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + HFI_PROP_REQUEST_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* Enc: Keeping CABAC and CAVLC as same bitrate. + * Dec: there's no use of Bitrate cap + */ + {BIT_RATE, ENC, H264 | HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE, + HFI_PROP_TOTAL_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITRATE_MODE, ENC, H264, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {CAVLC_MAX_BITRATE, ENC, H264, 0, + 160000000, 1, 160000000}, + + {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {LOWLATENCY_MAX_BITRATE, ENC, H264 | HEVC, 0, + 70000000, 1, 70000000}, + + {NUM_COMV, DEC, CODECS_ALL_V1, + 0, INT_MAX, 1, 0}, + + {LOSSLESS, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU}, + + {FRAME_SKIP_MODE, ENC, H264 | HEVC | HEIC, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {FRAME_RC_ENABLE, ENC, H264 | HEVC | HEIC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE}, + + {CONSTANT_QUALITY, ENC, HEVC, + 1, MAX_CONSTANT_QUALITY, 1, 90, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CONSTANT_QUALITY, ENC, HEIC, + 1, MAX_CONSTANT_QUALITY, 1, 100, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, CODECS_ALL_V1, + 0, INT_MAX, 1, 2 * DEFAULT_FPS - 1, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, HEIC, + 0, INT_MAX, 1, 0 /* all intra */, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_CLOSURE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + 0}, + + {B_FRAME, ENC, H264 | HEVC, + 0, 7, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {B_FRAME, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {BLUR_TYPES, ENC, H264 | HEVC, + MSM_VIDC_BLUR_NONE, MSM_VIDC_BLUR_EXTERNAL, + BIT(MSM_VIDC_BLUR_NONE) | BIT(MSM_VIDC_BLUR_EXTERNAL), + MSM_VIDC_BLUR_NONE, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_TYPES, + HFI_PROP_BLUR_TYPES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_RESOLUTION, + HFI_PROP_BLUR_RESOLUTION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CSC, ENC, CODECS_ALL_V1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CSC, + HFI_PROP_CSC, + CAP_FLAG_OUTPUT_PORT}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL_V1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX, + HFI_PROP_CSC_MATRIX, + CAP_FLAG_OUTPUT_PORT}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + 0, + CAP_FLAG_NONE}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {LTR_COUNT, ENC, H264 | HEVC, + 0, MAX_LTR_FRAME_COUNT_5, 1, 0, + V4L2_CID_MPEG_VIDEO_LTR_COUNT, + HFI_PROP_LTR_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {USE_LTR, ENC, H264 | HEVC, + 0, + ((1 << MAX_LTR_FRAME_COUNT_5) - 1), + 0, 0, + V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, + HFI_PROP_LTR_USE, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {MARK_LTR, ENC, H264 | HEVC, + INVALID_DEFAULT_MARK_OR_USE_LTR, + (MAX_LTR_FRAME_COUNT_5 - 1), + 1, INVALID_DEFAULT_MARK_OR_USE_LTR, + V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, + HFI_PROP_LTR_MARK, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {BASELAYER_PRIORITY, ENC, H264, + 0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0, + V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, + HFI_PROP_BASELAYER_PRIORITYID, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {IR_TYPE, ENC, H264 | HEVC, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC, + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) | + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC), + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {IR_PERIOD, ENC, H264 | HEVC, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, + 0, + CAP_FLAG_INPUT_PORT | CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {AU_DELIMITER, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + HFI_PROP_AUD, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_CONTENT_ADAPTIVE_CODING, + HFI_PROP_CONTENT_ADAPTIVE_CODING, + CAP_FLAG_OUTPUT_PORT}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + MSM_VIDC_PREPROCESS_NONE, + MSM_VIDC_PREPROCESS_TYPE0, + BIT(MSM_VIDC_PREPROCESS_NONE) | + BIT(MSM_VIDC_PREPROCESS_TYPE0), + MSM_VIDC_PREPROCESS_NONE, + 0, HFI_PROP_REQUEST_PREPROCESS, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + 0, MAX_BITRATE_BOOST, 25, MAX_BITRATE_BOOST, + V4L2_CID_MPEG_VIDC_QUALITY_BITRATE_BOOST, + HFI_PROP_BITRATE_BOOST, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_QUALITY, ENC, H264 | HEVC, + 0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY, + 0, + HFI_PROP_MAINTAIN_MIN_QUALITY, + CAP_FLAG_OUTPUT_PORT}, + + {VBV_DELAY, ENC, H264 | HEVC, + 200, 300, 100, 300, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, + HFI_PROP_VBV_DELAY, + CAP_FLAG_OUTPUT_PORT}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + /* default peak bitrate is 10% larger than avg bitrate */ + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + HFI_PROP_TOTAL_PEAK_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {MIN_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP}, + + {I_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP}, + + {MAX_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MAX_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP}, + + {I_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP}, + + {I_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {I_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {LAYER_TYPE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_TYPE, ENC, H264, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_ENABLE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT}, + + {LAYER_ENABLE, ENC, HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {ENH_LAYER_COUNT, ENC, HEVC, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, ENC, H264, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L3_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L3_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENTROPY_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + HFI_PROP_CABAC_SESSION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {ENTROPY_MODE, DEC, H264 | HEVC | VP9, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + 0, + HFI_PROP_CABAC_SESSION}, + + {PROFILE, ENC | DEC, H264, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, ENC | DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE, + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_MPEG_VIDEO_VP9_PROFILE_2, + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2), + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1), + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2), + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1), + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + V4L2_MPEG_VIDEO_VP9_LEVEL_5_1, + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1), + V4L2_MPEG_VIDEO_VP9_LEVEL_5_1, + V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEIC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN), + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + DB_H264_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + BIT(DB_H264_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + DB_HEVC_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) | + BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_ALPHA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA}, + + {LF_ALPHA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2}, + + {LF_BETA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA}, + + {LF_BETA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2}, + + {SLICE_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MAX_BYTES, ENC, H264 | HEVC, + MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE_V1, + 1, MIN_SLICE_BYTE_SIZE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + HFI_PROP_MULTI_SLICE_BYTES_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {SLICE_MAX_MB, ENC, H264 | HEVC, + 1, MAX_SLICE_MB_SIZE, 1, 1, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + HFI_PROP_MULTI_SLICE_MB_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {MB_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {TRANSFORM_8X8, ENC, H264, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + HFI_PROP_8X8_TRANSFORM, + CAP_FLAG_OUTPUT_PORT}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET, + 1, MAX_CHROMA_QP_OFFSET, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + HFI_PROP_CHROMA_QP_OFFSET, + CAP_FLAG_OUTPUT_PORT}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL_V1, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL_V1, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL_V1, 0x0, 0xff3fcff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_8BIT, + CAP_FLAG_INPUT_PORT}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL_V1, 0x0, 0x3fffffff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_10BIT, + CAP_FLAG_INPUT_PORT}, + + {STAGE, DEC|ENC, CODECS_ALL_V1, + MSM_VIDC_STAGE_1, + MSM_VIDC_STAGE_2, 1, + MSM_VIDC_STAGE_2, + 0, + HFI_PROP_STAGE}, + + {PIPE, DEC|ENC, CODECS_ALL_V1, + MSM_VIDC_PIPE_1, + MSM_VIDC_PIPE_2, 1, + MSM_VIDC_PIPE_2, + 0, + HFI_PROP_PIPE}, + + {POC, DEC, H264, + 0, 2, 1, 1, + 0, + HFI_PROP_PIC_ORDER_CNT_TYPE, + CAP_FLAG_VOLATILE}, + + /* + * value of MAX_NUM_REORDER_FRAMES is 32 packed as mentioned below + * (max_num_reorder_count << 16) | max_dec_frame_buffering_count + */ + {MAX_NUM_REORDER_FRAMES, DEC, H264 | HEVC, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_MAX_NUM_REORDER_FRAMES, + HFI_PROP_MAX_NUM_REORDER_FRAMES, + CAP_FLAG_VOLATILE}, + + {QUALITY_MODE, ENC, CODECS_ALL_V1, + MSM_VIDC_MAX_QUALITY_MODE, + MSM_VIDC_POWER_SAVE_MODE, 1, + MSM_VIDC_POWER_SAVE_MODE}, + + {CODED_FRAMES, DEC, H264 | HEVC | HEIC, + CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE, + 1, CODED_FRAMES_PROGRESSIVE, + V4L2_CID_MPEG_VIDC_INTERLACE, + HFI_PROP_CODED_FRAMES, + CAP_FLAG_VOLATILE}, + + {BIT_DEPTH, DEC, CODECS_ALL_V1, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8, + 0, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH}, + + {CODEC_CONFIG, DEC, H264 | HEVC | HEIC, 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CODEC_CONFIG, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL_V1, 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_MIN_BITSTREAM_SIZE_OVERWRITE}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL_V1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_THUMBNAIL_MODE, + HFI_PROP_THUMBNAIL_MODE, + CAP_FLAG_INPUT_PORT}, + + {DEFAULT_HEADER, DEC, CODECS_ALL_V1, + 0, 1, 1, 0, + 0, + HFI_PROP_DEC_DEFAULT_HEADER}, + + {RAP_FRAME, DEC, CODECS_ALL_V1, + 0, 1, 1, 1, + 0, + HFI_PROP_DEC_START_FROM_RAP_FRAME, + CAP_FLAG_INPUT_PORT}, + + {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL_V1, + 0, 1, 1, 1, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {PRIORITY, DEC|ENC, CODECS_ALL_V1, + 0, 4, 1, 4, + V4L2_CID_MPEG_VIDC_PRIORITY, + HFI_PROP_SESSION_PRIORITY, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL_V1, + 1, 1, 1, 1}, + + {CRITICAL_PRIORITY, ENC, CODECS_ALL_V1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CRITICAL_PRIORITY}, + + {RESERVE_DURATION, ENC, CODECS_ALL_V1, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_RESERVE_DURATION, + HFI_CMD_RESERVE, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENC_IP_CR, ENC, CODECS_ALL_V1, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_ENC_INPUT_COMPRESSION_RATIO, + 0, CAP_FLAG_DYNAMIC_ALLOWED}, + + {FILM_GRAIN, DEC, AV1, + 0, 0, 1, 0, + V4L2_CID_MPEG_VIDC_AV1D_FILM_GRAIN_PRESENT}, + + {SUPER_BLOCK, DEC, AV1, + 0, 0, 1, 0}, + + {DRAP, DEC, AV1, + 0, 0, 1, 0}, + + {LAST_FLAG_EVENT_ENABLE, DEC|ENC, CODECS_ALL_V1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LAST_FLAG_EVENT_ENABLE}, + + {META_BITSTREAM_RESOLUTION, DEC, AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_DISABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BITSTREAM_RESOLUTION}, + + {META_CROP_OFFSETS, DEC, AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_DISABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_CROP_OFFSETS}, + + {ALL_INTRA, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {META_LTR_MARK_USE, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_LTR_MARK_USE_DETAILS, + HFI_PROP_LTR_MARK_USE_DETAILS, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEQ_HDR_NAL, ENC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEQ_HEADER_NAL, + HFI_PROP_METADATA_SEQ_HEADER_NAL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DPB_MISR, DEC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_LUMA_CHROMA_MISR, + HFI_PROP_DPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_OPB_MISR, DEC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OPB_LUMA_CHROMA_MISR, + HFI_PROP_OPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_INTERLACE, DEC, H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_INTERLACE, + HFI_PROP_INTERLACE_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TIMESTAMP, DEC | ENC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TIMESTAMP, + HFI_PROP_TIMESTAMP, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_CONCEALED_MB_CNT, DEC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_CONCEALED_MB_COUNT, + HFI_PROP_CONEALED_MB_COUNT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HIST_INFO, DEC, HEVC | VP9, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HISTOGRAM_INFO, + HFI_PROP_HISTOGRAM_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TRANSCODING_STAT_INFO, DEC, HEVC|H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TRANSCODE_STAT_INFO, + HFI_PROP_TRANSCODING_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TRANSCODING_STAT_INFO, ENC, HEVC|H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TRANSCODE_STAT_INFO, + HFI_PROP_TRANSCODING_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_PICTURE_TYPE, DEC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_PICTURE_TYPE, + HFI_PROP_PICTURE_TYPE, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + {META_SEI_MASTERING_DISP, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_MASTERING_DISP, DEC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, DEC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, DEC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DOLBY_RPU, ENC, HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DOLBY_RPU, + HFI_PROP_DOLBY_RPU_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DOLBY_RPU, DEC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DOLBY_RPU, + HFI_PROP_DOLBY_RPU_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_EVA_STATS, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_EVA_STATS, + HFI_PROP_EVA_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_BUF_TAG, ENC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + /* + * when fence enabled, client needs output buffer_tag + * in input metadata buffer done. + */ + {META_BUF_TAG, DEC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_TX_OUTPUT | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + {META_DPB_TAG_LIST, DEC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_TAG_LIST, + HFI_PROP_DPB_TAG_LIST, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, ENC, HEIC | H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, DEC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ENC_QP_METADATA, ENC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ENC_QP_METADATA, + HFI_PROP_ENC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ROI_INFO, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ROI_INFO, + HFI_PROP_ROI_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SALIENCY_INFO, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SALIENCY_INFO, + HFI_PROP_ROI_AS_SALIENCY_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DEC_QP_METADATA, DEC, CODECS_ALL_V1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DEC_QP_METADATA, + HFI_PROP_DEC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {GRID_ENABLE, ENC, HEIC, + 0, 1, 1, 1, + 0, + HFI_PROP_HEIC_GRID_ENABLE, + CAP_FLAG_OUTPUT_PORT}, + + {GRID_SIZE, ENC, HEIC, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH * 2, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH, + V4L2_CID_MPEG_VIDC_GRID_WIDTH}, + + {COMPLEXITY, ENC, H264 | HEVC, + 0, 100, + 1, DEFAULT_COMPLEXITY, + V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY}, + + {DELIVERY_MODE, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_HEVC_ENCODE_DELIVERY_MODE, + HFI_PROP_ENABLE_SLICE_DELIVERY, + CAP_FLAG_OUTPUT_PORT}, + + {DELIVERY_MODE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_H264_ENCODE_DELIVERY_MODE, + HFI_PROP_ENABLE_SLICE_DELIVERY, + CAP_FLAG_OUTPUT_PORT}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL_V1, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SIGNAL_COLOR_INFO, + HFI_PROP_SIGNAL_COLOR_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, +}; + +static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_cliffs_v1[] = { + /* {cap, domain, codec, + * parents, + * children, + * adjust, set} + */ + + {PIX_FMTS, ENC, H264, + {META_ROI_INFO, IR_PERIOD, CSC}}, + + {PIX_FMTS, ENC, HEVC, + {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, META_ROI_INFO, MIN_QUALITY, BLUR_TYPES, IR_PERIOD, + LTR_COUNT, CSC}}, + + {PIX_FMTS, ENC, HEIC, + {PROFILE, CSC}}, + + {PIX_FMTS, DEC, HEVC | HEIC, + {PROFILE}}, + + {FRAME_RATE, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_q16}, + + {FRAME_RATE, DEC, CODECS_ALL_V1, + {0}, + msm_vidc_adjust_dec_frame_rate}, + + {OPERATING_RATE, DEC, CODECS_ALL_V1, + {0}, + msm_vidc_adjust_dec_operating_rate}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL_V1, + {0}, + NULL, + NULL}, + + {SECURE_MODE, ENC|DEC, H264 | HEVC | VP9, + {0}, + NULL, + msm_vidc_set_u32}, + + {META_OUTBUF_FENCE, DEC, H264 | HEVC | VP9, + {LOWLATENCY_MODE, OUTBUF_FENCE_TYPE, OUTBUF_FENCE_DIRECTION}, + NULL, + NULL}, + + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_dec_outbuf_fence_type, + msm_vidc_set_outbuf_fence_type}, + + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_dec_outbuf_fence_direction, + msm_vidc_set_outbuf_fence_direction}, + + {FENCE_ERROR_DATA_CORRUPT, DEC, H264 | HEVC | VP9, + {0}, + NULL, + msm_vidc_set_u32}, + + {HFLIP, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_flip}, + + {VFLIP, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_flip}, + + {ROTATION, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_rotation}, + + {SUPER_FRAME, ENC, H264 | HEVC, + {INPUT_BUF_HOST_MAX_COUNT, OUTPUT_BUF_HOST_MAX_COUNT}, + NULL, + NULL}, + + {SLICE_DECODE, DEC, H264 | HEVC, + {0}, + NULL, + NULL}, + + {HEADER_MODE, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_header_mode}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_nal_length}, + + {WITHOUT_STARTCODE, DEC, AV1, + {0}, + NULL, + NULL}, + + {REQUEST_I_FRAME, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_req_sync_frame}, + + {BIT_RATE, ENC, H264, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BIT_RATE, ENC, HEVC, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BITRATE_MODE, ENC, H264, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE, + META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE, META_TRANSCODING_STAT_INFO}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEVC, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT, + BIT_RATE, META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE, META_EVA_STATS, META_TRANSCODING_STAT_INFO}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEIC, + {TIME_DELTA_BASED_RC, CONSTANT_QUALITY}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {CONSTANT_QUALITY, ENC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_constant_quality}, + + {GOP_SIZE, ENC, CODECS_ALL_V1, + {ALL_INTRA}, + msm_vidc_adjust_gop_size, + msm_vidc_set_gop_size}, + + {GOP_SIZE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {B_FRAME, ENC, H264 | HEVC, + {ALL_INTRA}, + msm_vidc_adjust_b_frame, + msm_vidc_set_u32}, + + {B_FRAME, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {BLUR_TYPES, ENC, H264 | HEVC, + {BLUR_RESOLUTION}, + msm_vidc_adjust_blur_type, + msm_vidc_set_u32_enum}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_blur_resolution, + msm_vidc_set_blur_resolution}, + + {CSC, ENC, CODECS_ALL_V1, + {0}, + msm_vidc_adjust_csc, + msm_vidc_set_u32}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_csc_custom_matrix}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + {STAGE, BIT_RATE}, + msm_vidc_adjust_enc_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LTR_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ltr_count, + msm_vidc_set_u32}, + + {USE_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_use_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {MARK_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_mark_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {IR_PERIOD, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ir_period, + msm_vidc_set_ir_period}, + + {AU_DELIMITER, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_u32}, + + {BASELAYER_PRIORITY, ENC, H264, + {0}, + NULL, + msm_vidc_set_u32}, + + {TIME_DELTA_BASED_RC, ENC, CODECS_ALL_V1, + {0}, + msm_vidc_adjust_delta_based_rc, + msm_vidc_set_u32}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + {REQUEST_PREPROCESS}, + msm_vidc_adjust_brs, + msm_vidc_set_vbr_related_properties}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_preprocess, + msm_vidc_set_preprocess}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_bitrate_boost_iris33, + msm_vidc_set_vbr_related_properties}, + + {MIN_QUALITY, ENC, H264 | HEVC, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {VBV_DELAY, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_cbr_related_properties}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_peak_bitrate, + msm_vidc_set_cbr_related_properties}, + + {MIN_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_min_qp}, + + {MIN_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_min_qp, + msm_vidc_set_min_qp}, + + {MAX_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_max_qp}, + + {MAX_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_max_qp, + msm_vidc_set_max_qp}, + + {I_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_i_frame_qp, + msm_vidc_set_frame_qp}, + + {I_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_p_frame_qp, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_b_frame_qp, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {LAYER_TYPE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING, LTR_COUNT}}, + + {LAYER_ENABLE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING}}, + + {ENH_LAYER_COUNT, ENC, H264 | HEVC, + {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE, LTR_COUNT}, + msm_vidc_adjust_layer_count, + msm_vidc_set_layer_count_and_type}, + + {L0_BR, ENC, H264 | HEVC, + {L1_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L1_BR, ENC, H264 | HEVC, + {L2_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L2_BR, ENC, H264 | HEVC, + {L3_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L3_BR, ENC, H264 | HEVC, + {L4_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L4_BR, ENC, H264 | HEVC, + {L5_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L5_BR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {ENTROPY_MODE, ENC, H264, + {BIT_RATE}, + msm_vidc_adjust_entropy_mode, + msm_vidc_set_u32}, + + {PROFILE, ENC, H264, + {ENTROPY_MODE, TRANSFORM_8X8}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, H264, + {ENTROPY_MODE}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, ENC, HEVC | HEIC, + {META_SEI_MASTERING_DISP, META_SEI_CLL, META_HDR10PLUS}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, HEVC | HEIC, + {0}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, VP9, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, DEC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_level}, + + {HEVC_TIER, ENC | DEC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LF_MODE, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_deblock_mode}, + + {SLICE_MODE, ENC, H264 | HEVC, + {STAGE, DELIVERY_MODE}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {SLICE_MODE, ENC, HEIC, + {0}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {TRANSFORM_8X8, ENC, H264, + {0}, + msm_vidc_adjust_transform_8x8, + msm_vidc_set_u32}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + {0}, + msm_vidc_adjust_chroma_qp_index_offset, + msm_vidc_set_chroma_qp_index_offset}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_output_order, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL_V1, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL_V1, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {STAGE, ENC | DEC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_stage}, + + {STAGE, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_stage}, + + {STAGE, DEC, H264 | HEVC | VP9, + {0}, + NULL, + msm_vidc_set_stage}, + + {PIPE, DEC|ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_pipe}, + + {THUMBNAIL_MODE, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + msm_vidc_set_u32}, + + {THUMBNAIL_MODE, DEC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {RAP_FRAME, DEC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_u32}, + + {PRIORITY, DEC|ENC, CODECS_ALL_V1, + {0}, + msm_vidc_adjust_session_priority, + msm_vidc_set_session_priority}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL_V1, + {0}, + NULL, + NULL}, + + {CRITICAL_PRIORITY, ENC, CODECS_ALL_V1, + {0}, + NULL, + NULL}, + + {RESERVE_DURATION, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_reserve_duration}, + + {DRAP, DEC, AV1, + {0}, + NULL, + NULL}, + + {ALL_INTRA, ENC, H264 | HEVC, + {LTR_COUNT, IR_PERIOD, SLICE_MODE, BIT_RATE}, + msm_vidc_adjust_all_intra, + NULL}, + + {META_EVA_STATS, ENC, HEVC, + {0}, + msm_vidc_adjust_eva_stats, + NULL}, + + {META_ROI_INFO, ENC, H264 | HEVC, + {MIN_QUALITY, IR_PERIOD, BLUR_TYPES}, + msm_vidc_adjust_roi_info, + NULL}, + + {GRID_ENABLE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {DELIVERY_MODE, ENC, H264 | HEVC, + {LOWLATENCY_MODE, OUTPUT_BUF_HOST_MAX_COUNT}, + msm_vidc_adjust_delivery_mode, + msm_vidc_set_u32}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_vui_timing_info}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL_V1, + {0}, + NULL, + msm_vidc_set_signal_color_info}, + + {META_SEI_MASTERING_DISP, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_sei_mastering_disp, + NULL}, + + {META_SEI_CLL, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_sei_cll, + NULL}, + + {META_HDR10PLUS, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_hdr10plus, + NULL}, + + {META_TRANSCODING_STAT_INFO, ENC, HEVC|H264, + {0}, + msm_vidc_adjust_transcoding_stats, + NULL}, +}; + +/* Default UBWC config for LPDDR5 */ +static struct msm_vidc_ubwc_config_data ubwc_config_cliffs[] = { + UBWC_CONFIG(8, 32, 16, 0, 1, 1, 1), +}; + +static struct msm_vidc_format_capability format_data_cliffs_v0 = { + .codec_info = codec_data_cliffs_v0, + .codec_info_size = ARRAY_SIZE(codec_data_cliffs_v0), + .color_format_info = color_format_data_cliffs, + .color_format_info_size = ARRAY_SIZE(color_format_data_cliffs), + .color_prim_info = color_primaries_data_cliffs, + .color_prim_info_size = ARRAY_SIZE(color_primaries_data_cliffs), + .transfer_char_info = transfer_char_data_cliffs, + .transfer_char_info_size = ARRAY_SIZE(transfer_char_data_cliffs), + .matrix_coeff_info = matrix_coeff_data_cliffs, + .matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_cliffs), +}; + +static struct msm_vidc_format_capability format_data_cliffs_v1 = { + .codec_info = codec_data_cliffs_v1, + .codec_info_size = ARRAY_SIZE(codec_data_cliffs_v1), + .color_format_info = color_format_data_cliffs, + .color_format_info_size = ARRAY_SIZE(color_format_data_cliffs), + .color_prim_info = color_primaries_data_cliffs, + .color_prim_info_size = ARRAY_SIZE(color_primaries_data_cliffs), + .transfer_char_info = transfer_char_data_cliffs, + .transfer_char_info_size = ARRAY_SIZE(transfer_char_data_cliffs), + .matrix_coeff_info = matrix_coeff_data_cliffs, + .matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_cliffs), +}; + +/* name, min_kbps, max_kbps */ +static const struct bw_table cliffs_bw_table[] = { + { "venus-cnoc", 1000, 1000 }, + { "venus-ddr", 1000, 15000000 }, + { "venus-llcc", 1000, 15000000 }, +}; + +/* name, hw_trigger */ +static const struct regulator_table cliffs_regulator_table[] = { + { "iris-ctl", 0 }, + { "vcodec", 1 }, +}; + +/* name, clock id, scaling */ +static const struct clk_table cliffs_clk_table[] = { + { "gcc_video_axi0_clk", GCC_VIDEO_AXI0_CLK, 0 }, + { "video_cc_mvs0c_clk", VIDEO_CC_MVS0C_CLK, 0 }, + { "video_cc_mvs0_clk", VIDEO_CC_MVS0_CLK, 0 }, + { "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 }, +}; + +/* name, exclusive_release */ +static const struct clk_rst_table cliffs_clk_reset_table[] = { + { "video_axi_reset", 0 }, + { "video_xo_reset", 1 }, + { "video_mvs0c_reset", 0 }, + { "video_mvs0_reset", 0 }, +}; + +/* name, llcc_id */ +static const struct subcache_table cliffs_subcache_table[] = { + { "vidsc0", LLCC_VIDSC0 }, +}; + +/* name, start, size, secure, dma_coherant, region, dma_mask */ +const struct context_bank_table cliffs_context_bank_table[] = { + {"qcom,vidc,cb-ns", + 0x25800000, 0xba800000, 0, 1, MSM_VIDC_NON_SECURE, 0 }, + {"qcom,vidc,cb-ns-pxl", + 0x00100000, 0xdff00000, 0, 1, MSM_VIDC_NON_SECURE_PIXEL, 0 }, + {"qcom,vidc,cb-sec-pxl", + 0x00500000, 0xdfb00000, 1, 0, MSM_VIDC_SECURE_PIXEL, 0 }, + {"qcom,vidc,cb-sec-non-pxl", + 0x01000000, 0x24800000, 1, 0, MSM_VIDC_SECURE_NONPIXEL, 0 }, + {"qcom,vidc,cb-sec-bitstream", + 0x00500000, 0xdfb00000, 1, 0, MSM_VIDC_SECURE_BITSTREAM, 0 }, +}; + +/* freq */ +static struct freq_table cliffs_freq_table_sku0[] = { + {533333333}, {444000000}, {366000000}, {338000000}, {240000000}, {192000000} +}; + +static struct freq_table cliffs_freq_table_sku1[] = { + {366000000}, {338000000}, {240000000}, {192000000} +}; + +/* register, value, mask */ +static const struct reg_preset_table cliffs_reg_preset_table[] = { + { 0xB0088, 0x0, 0x11 }, + { 0x10830, 0x33332222, 0xFFFFFFFF}, + { 0x10834, 0x44444444, 0xFFFFFFFF}, + { 0x10838, 0x00001022, 0xFFFFFFFF}, + { 0xA013C, 0x99, 0xFFFFFFFF}, +}; + +/* name, phys_addr, size, device_addr, device region type */ +static const struct device_region_table cliffs_device_region_table[] = { + { + "aon-registers", + 0x0AAE0000, 0x1000, 0xFFAE0000, + MSM_VIDC_AON + }, + { + "ipc_protocol4_client8_version-registers", + 0x00508000, 0x1000, 0xFFADF000, + MSM_VIDC_PROTOCOL_FENCE_CLIENT_VPU + }, + { + "qtimer_f0v1_qtmr_v1_cntpct_lo", + 0x17421000, 0x1000, 0xFFADE000, + MSM_VIDC_QTIMER + }, +}; + +/* decoder properties */ +static const u32 cliffs_vdec_psc_avc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_CODED_FRAMES, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PIC_ORDER_CNT_TYPE, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_SIGNAL_COLOR_INFO, + HFI_PROP_MAX_NUM_REORDER_FRAMES, +}; + +static const u32 cliffs_vdec_psc_hevc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_TIER, + HFI_PROP_SIGNAL_COLOR_INFO, + HFI_PROP_MAX_NUM_REORDER_FRAMES, +}; + +static const u32 cliffs_vdec_psc_vp9[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, +}; + +static const u32 cliffs_vdec_psc_av1[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_AV1_FILM_GRAIN_PRESENT, + HFI_PROP_AV1_SUPER_BLOCK_ENABLED, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_TIER, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 cliffs_vdec_input_properties_avc[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, + HFI_PROP_DPB_LIST, +}; + +static const u32 cliffs_vdec_input_properties_hevc[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, + HFI_PROP_DPB_LIST, +}; + +static const u32 cliffs_vdec_input_properties_vp9[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, + HFI_PROP_DPB_LIST, +}; + +static const u32 cliffs_vdec_input_properties_av1[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, + HFI_PROP_DPB_LIST, + HFI_PROP_AV1_TILE_ROWS_COLUMNS, + HFI_PROP_AV1_UNIFORM_TILE_SPACING, +}; + +static const u32 cliffs_vdec_output_properties_avc[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_CABAC_SESSION, + HFI_PROP_FENCE, +}; + +static const u32 cliffs_vdec_output_properties_hevc[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_FENCE, +}; + +static const u32 cliffs_vdec_output_properties_vp9[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_FENCE, +}; + +static const u32 cliffs_vdec_output_properties_av1[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_FENCE, +}; + +static const u32 cliffs_msm_vidc_ssr_type[] = { + HFI_SSR_TYPE_SW_ERR_FATAL, + HFI_SSR_TYPE_SW_DIV_BY_ZERO, + HFI_SSR_TYPE_CPU_WDOG_IRQ, + HFI_SSR_TYPE_NOC_ERROR, +}; + +static struct msm_vidc_efuse_data efuse_data_cliffs[] = { + /* IRIS_DISABLE_AV1, SKU VERSION: 1 */ + EFUSE_ENTRY(0x221C8118, 4, 0x2000, 0xD, SKU_VERSION), +}; + +static const struct msm_vidc_platform_data cliffs_data_v0 = { + /* resources dependent on other module */ + .bw_tbl = cliffs_bw_table, + .bw_tbl_size = ARRAY_SIZE(cliffs_bw_table), + .regulator_tbl = cliffs_regulator_table, + .regulator_tbl_size = ARRAY_SIZE(cliffs_regulator_table), + .clk_tbl = cliffs_clk_table, + .clk_tbl_size = ARRAY_SIZE(cliffs_clk_table), + .clk_rst_tbl = cliffs_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(cliffs_clk_reset_table), + .subcache_tbl = cliffs_subcache_table, + .subcache_tbl_size = ARRAY_SIZE(cliffs_subcache_table), + + /* populate context bank */ + .context_bank_tbl = cliffs_context_bank_table, + .context_bank_tbl_size = ARRAY_SIZE(cliffs_context_bank_table), + + /* platform specific resources */ + .freq_tbl = cliffs_freq_table_sku0, + .freq_tbl_size = ARRAY_SIZE(cliffs_freq_table_sku0), + .reg_prst_tbl = cliffs_reg_preset_table, + .reg_prst_tbl_size = ARRAY_SIZE(cliffs_reg_preset_table), + .dev_reg_tbl = cliffs_device_region_table, + .dev_reg_tbl_size = ARRAY_SIZE(cliffs_device_region_table), + .fwname = "vpu30_2v", + .pas_id = 9, + .supports_mmrm = 0, + .vpu_ver = VPU_VERSION_IRIS33_2P, + + /* caps related resorces */ + .core_data = core_data_cliffs_v0, + .core_data_size = ARRAY_SIZE(core_data_cliffs_v0), + .inst_cap_data = instance_cap_data_cliffs_v0, + .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_cliffs_v0), + .inst_cap_dependency_data = instance_cap_dependency_data_cliffs_v0, + .inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_cliffs_v0), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .ubwc_config = ubwc_config_cliffs, + .format_data = &format_data_cliffs_v0, + + /* decoder properties related*/ + .psc_avc_tbl = cliffs_vdec_psc_avc, + .psc_avc_tbl_size = ARRAY_SIZE(cliffs_vdec_psc_avc), + .psc_hevc_tbl = cliffs_vdec_psc_hevc, + .psc_hevc_tbl_size = ARRAY_SIZE(cliffs_vdec_psc_hevc), + .psc_vp9_tbl = cliffs_vdec_psc_vp9, + .psc_vp9_tbl_size = ARRAY_SIZE(cliffs_vdec_psc_vp9), + .psc_av1_tbl = cliffs_vdec_psc_av1, + .psc_av1_tbl_size = ARRAY_SIZE(cliffs_vdec_psc_av1), + .dec_input_prop_avc = cliffs_vdec_input_properties_avc, + .dec_input_prop_hevc = cliffs_vdec_input_properties_hevc, + .dec_input_prop_vp9 = cliffs_vdec_input_properties_vp9, + .dec_input_prop_av1 = cliffs_vdec_input_properties_av1, + .dec_input_prop_size_avc = ARRAY_SIZE(cliffs_vdec_input_properties_avc), + .dec_input_prop_size_hevc = ARRAY_SIZE(cliffs_vdec_input_properties_hevc), + .dec_input_prop_size_vp9 = ARRAY_SIZE(cliffs_vdec_input_properties_vp9), + .dec_input_prop_size_av1 = ARRAY_SIZE(cliffs_vdec_input_properties_av1), + .dec_output_prop_avc = cliffs_vdec_output_properties_avc, + .dec_output_prop_hevc = cliffs_vdec_output_properties_hevc, + .dec_output_prop_vp9 = cliffs_vdec_output_properties_vp9, + .dec_output_prop_av1 = cliffs_vdec_output_properties_av1, + .dec_output_prop_size_avc = ARRAY_SIZE(cliffs_vdec_output_properties_avc), + .dec_output_prop_size_hevc = ARRAY_SIZE(cliffs_vdec_output_properties_hevc), + .dec_output_prop_size_vp9 = ARRAY_SIZE(cliffs_vdec_output_properties_vp9), + .dec_output_prop_size_av1 = ARRAY_SIZE(cliffs_vdec_output_properties_av1), + + .msm_vidc_ssr_type = cliffs_msm_vidc_ssr_type, + .msm_vidc_ssr_type_size = ARRAY_SIZE(cliffs_msm_vidc_ssr_type), + + /* Fuse specific resources */ + .efuse_data = efuse_data_cliffs, + .efuse_data_size = ARRAY_SIZE(efuse_data_cliffs), + .sku_version = SKU_VERSION_0, +}; + +static const struct msm_vidc_platform_data cliffs_data_v1 = { + /* resources dependent on other module */ + .bw_tbl = cliffs_bw_table, + .bw_tbl_size = ARRAY_SIZE(cliffs_bw_table), + .regulator_tbl = cliffs_regulator_table, + .regulator_tbl_size = ARRAY_SIZE(cliffs_regulator_table), + .clk_tbl = cliffs_clk_table, + .clk_tbl_size = ARRAY_SIZE(cliffs_clk_table), + .clk_rst_tbl = cliffs_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(cliffs_clk_reset_table), + .subcache_tbl = cliffs_subcache_table, + .subcache_tbl_size = ARRAY_SIZE(cliffs_subcache_table), + + /* populate context bank */ + .context_bank_tbl = cliffs_context_bank_table, + .context_bank_tbl_size = ARRAY_SIZE(cliffs_context_bank_table), + + /* platform specific resources */ + .freq_tbl = cliffs_freq_table_sku1, + .freq_tbl_size = ARRAY_SIZE(cliffs_freq_table_sku1), + .reg_prst_tbl = cliffs_reg_preset_table, + .reg_prst_tbl_size = ARRAY_SIZE(cliffs_reg_preset_table), + .dev_reg_tbl = cliffs_device_region_table, + .dev_reg_tbl_size = ARRAY_SIZE(cliffs_device_region_table), + .fwname = "vpu30_2v", + .pas_id = 9, + .supports_mmrm = 0, + + /* caps related resorces */ + .core_data = core_data_cliffs_v1, + .core_data_size = ARRAY_SIZE(core_data_cliffs_v1), + .inst_cap_data = instance_cap_data_cliffs_v1, + .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_cliffs_v1), + .inst_cap_dependency_data = instance_cap_dependency_data_cliffs_v1, + .inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_cliffs_v1), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .ubwc_config = ubwc_config_cliffs, + .format_data = &format_data_cliffs_v1, + .vpu_ver = VPU_VERSION_IRIS33_2P, + + /* decoder properties related*/ + .psc_avc_tbl = cliffs_vdec_psc_avc, + .psc_avc_tbl_size = ARRAY_SIZE(cliffs_vdec_psc_avc), + .psc_hevc_tbl = cliffs_vdec_psc_hevc, + .psc_hevc_tbl_size = ARRAY_SIZE(cliffs_vdec_psc_hevc), + .psc_vp9_tbl = cliffs_vdec_psc_vp9, + .psc_vp9_tbl_size = ARRAY_SIZE(cliffs_vdec_psc_vp9), + .dec_input_prop_avc = cliffs_vdec_input_properties_avc, + .dec_input_prop_hevc = cliffs_vdec_input_properties_hevc, + .dec_input_prop_vp9 = cliffs_vdec_input_properties_vp9, + .dec_input_prop_size_avc = ARRAY_SIZE(cliffs_vdec_input_properties_avc), + .dec_input_prop_size_hevc = ARRAY_SIZE(cliffs_vdec_input_properties_hevc), + .dec_input_prop_size_vp9 = ARRAY_SIZE(cliffs_vdec_input_properties_vp9), + .dec_output_prop_avc = cliffs_vdec_output_properties_avc, + .dec_output_prop_hevc = cliffs_vdec_output_properties_hevc, + .dec_output_prop_vp9 = cliffs_vdec_output_properties_vp9, + .dec_output_prop_size_avc = ARRAY_SIZE(cliffs_vdec_output_properties_avc), + .dec_output_prop_size_hevc = ARRAY_SIZE(cliffs_vdec_output_properties_hevc), + .dec_output_prop_size_vp9 = ARRAY_SIZE(cliffs_vdec_output_properties_vp9), + + .msm_vidc_ssr_type = cliffs_msm_vidc_ssr_type, + .msm_vidc_ssr_type_size = ARRAY_SIZE(cliffs_msm_vidc_ssr_type), + + /* Fuse specific resources */ + .efuse_data = efuse_data_cliffs, + .efuse_data_size = ARRAY_SIZE(efuse_data_cliffs), + .sku_version = SKU_VERSION_1, +}; + +int msm_vidc_cliffs_check_ddr_type(void) +{ + u32 ddr_type; + + ddr_type = of_fdt_get_ddrtype(); + if (ddr_type != DDR_TYPE_LPDDR5 && + ddr_type != DDR_TYPE_LPDDR5X) { + d_vpr_e("%s: wrong ddr type %d\n", __func__, ddr_type); + return -EINVAL; + } + + d_vpr_h("%s: ddr type %d\n", __func__, ddr_type); + return 0; +} + +static int msm_vidc_init_data(struct msm_vidc_core *core) +{ + struct device *dev = NULL; + int rc = 0; + + dev = &core->pdev->dev; + + d_vpr_h("%s: initialize cliffs data\n", __func__); + + core->platform->data = cliffs_data_v0; + + /* Check for sku version */ + rc = msm_vidc_read_efuse(core); + if (rc) { + d_vpr_e("%s: Failed to read efuse\n", __func__); + return rc; + } + + if (core->platform->data.sku_version == SKU_VERSION_1) + core->platform->data = cliffs_data_v1; + + core->mem_ops = get_mem_ops_ext(); + if (!core->mem_ops) { + d_vpr_e("%s: invalid memory ext ops\n", __func__); + return -EINVAL; + } + core->res_ops = get_res_ops_ext(); + if (!core->res_ops) { + d_vpr_e("%s: invalid resource ext ops\n", __func__); + return -EINVAL; + } + core->fence_ops = get_synx_fence_ops(); + if (!core->fence_ops) { + d_vpr_e("%s: invalid synx fence ops\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_cliffs_check_ddr_type(); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_init_platform_cliffs(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = msm_vidc_init_data(core); + if (rc) + return rc; + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/platform/common/inc/msm_vidc_platform.h b/qcom/opensource/video-driver/driver/platform/common/inc/msm_vidc_platform.h new file mode 100644 index 0000000000..c9c62897e1 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/common/inc/msm_vidc_platform.h @@ -0,0 +1,388 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_PLATFORM_H_ +#define _MSM_VIDC_PLATFORM_H_ + +#include +#include + +#include "msm_vidc_internal.h" +#include "msm_vidc_core.h" + +#define DDR_TYPE_LPDDR4 0x6 +#define DDR_TYPE_LPDDR4X 0x7 +#define DDR_TYPE_LPDDR5 0x8 +#define DDR_TYPE_LPDDR5X 0x9 + +#define UBWC_CONFIG(mc, ml, hbb, bs1, bs2, bs3, bsp) \ +{ \ + .max_channels = mc, \ + .mal_length = ml, \ + .highest_bank_bit = hbb, \ + .bank_swzl_level = bs1, \ + .bank_swz2_level = bs2, \ + .bank_swz3_level = bs3, \ + .bank_spreading = bsp, \ +} + +#define EFUSE_ENTRY(sa, s, m, sh, p) \ +{ \ + .start_address = sa, \ + .size = s, \ + .mask = m, \ + .shift = sh, \ + .purpose = p \ +} + +extern u32 vpe_csc_custom_matrix_coeff[MAX_MATRIX_COEFFS]; +extern u32 vpe_csc_custom_bias_coeff[MAX_BIAS_COEFFS]; +extern u32 vpe_csc_custom_limit_coeff[MAX_LIMIT_COEFFS]; + +struct bw_table { + const char *name; + u32 min_kbps; + u32 max_kbps; +}; + +struct pd_table { + const char *name; +}; + +struct regulator_table { + const char *name; + bool hw_trigger; +}; + +struct clk_table { + const char *name; + u32 clk_id; + bool scaling; +}; + +struct clk_rst_table { + const char *name; + bool exclusive_release; +}; + +struct subcache_table { + const char *name; + u32 llcc_id; +}; + +struct context_bank_table { + const char *name; + u32 start; + u32 size; + bool secure; + bool dma_coherant; + u32 region; + u64 dma_mask; +}; + +struct freq_table { + unsigned long freq; +}; + +struct reg_preset_table { + u32 reg; + u32 value; + u32 mask; +}; + +struct device_region_table { + const char *name; + phys_addr_t phy_addr; + u32 size; + u32 dev_addr; + u32 region; +}; + +struct msm_vidc_ubwc_config_data { + u32 max_channels; + u32 mal_length; + u32 highest_bank_bit; + u32 bank_swzl_level; + u32 bank_swz2_level; + u32 bank_swz3_level; + u32 bank_spreading; +}; + +struct codec_info { + u32 v4l2_codec; + enum msm_vidc_codec_type vidc_codec; + const char *pixfmt_name; +}; + +struct color_format_info { + u32 v4l2_color_format; + enum msm_vidc_colorformat_type vidc_color_format; + const char *pixfmt_name; +}; + +struct color_primaries_info { + u32 v4l2_color_primaries; + enum msm_vidc_color_primaries vidc_color_primaries; +}; + +struct transfer_char_info { + u32 v4l2_transfer_char; + enum msm_vidc_transfer_characteristics vidc_transfer_char; +}; + +struct matrix_coeff_info { + u32 v4l2_matrix_coeff; + enum msm_vidc_matrix_coefficients vidc_matrix_coeff; +}; + +struct msm_platform_core_capability { + enum msm_vidc_core_capability_type type; + u32 value; +}; + +struct msm_platform_inst_capability { + enum msm_vidc_inst_capability_type cap_id; + enum msm_vidc_domain_type domain; + enum msm_vidc_codec_type codec; + s32 min; + s32 max; + u32 step_or_mask; + s32 value; + u32 v4l2_id; + u32 hfi_id; + enum msm_vidc_inst_capability_flags flags; +}; + +struct msm_platform_inst_cap_dependency { + enum msm_vidc_inst_capability_type cap_id; + enum msm_vidc_domain_type domain; + enum msm_vidc_codec_type codec; + enum msm_vidc_inst_capability_type children[MAX_CAP_CHILDREN]; + int (*adjust)(void *inst, struct v4l2_ctrl *ctrl); + int (*set)(void *inst, enum msm_vidc_inst_capability_type cap_id); +}; + +struct msm_vidc_compat_handle { + const char *compat; + int (*init_platform)(struct msm_vidc_core *core); + int (*init_iris)(struct msm_vidc_core *core); +}; + +struct msm_vidc_csc_coeff { + u32 *vpe_csc_custom_matrix_coeff; + u32 *vpe_csc_custom_bias_coeff; + u32 *vpe_csc_custom_limit_coeff; +}; + +struct msm_vidc_efuse_data { + u32 start_address; + u32 size; + u32 mask; + u32 shift; + enum efuse_purpose purpose; +}; + +struct msm_vidc_format_capability { + struct codec_info *codec_info; + u32 codec_info_size; + struct color_format_info *color_format_info; + u32 color_format_info_size; + struct color_primaries_info *color_prim_info; + u32 color_prim_info_size; + struct transfer_char_info *transfer_char_info; + u32 transfer_char_info_size; + struct matrix_coeff_info *matrix_coeff_info; + u32 matrix_coeff_info_size; +}; + +enum vpu_version { + VPU_VERSION_IRIS33 = 1, + VPU_VERSION_IRIS33_2P, // IRIS3 2 PIPE + VPU_VERSION_IRIS2_2P, // IRIS2 2 PIPE +}; + +struct msm_vidc_platform_data { + const struct bw_table *bw_tbl; + unsigned int bw_tbl_size; + const struct regulator_table *regulator_tbl; + unsigned int regulator_tbl_size; + const struct pd_table *pd_tbl; + unsigned int pd_tbl_size; + const char * const *opp_tbl; + unsigned int opp_tbl_size; + const struct clk_table *clk_tbl; + unsigned int clk_tbl_size; + const struct clk_rst_table *clk_rst_tbl; + unsigned int clk_rst_tbl_size; + const struct subcache_table *subcache_tbl; + unsigned int subcache_tbl_size; + const struct context_bank_table *context_bank_tbl; + unsigned int context_bank_tbl_size; + struct freq_table *freq_tbl; + unsigned int freq_tbl_size; + const struct reg_preset_table *reg_prst_tbl; + unsigned int reg_prst_tbl_size; + const struct device_region_table *dev_reg_tbl; + unsigned int dev_reg_tbl_size; + struct msm_vidc_ubwc_config_data *ubwc_config; + const char *fwname; + u32 pas_id; + bool supports_mmrm; + struct msm_platform_core_capability *core_data; + u32 core_data_size; + struct msm_platform_inst_capability *inst_cap_data; + u32 inst_cap_data_size; + struct msm_platform_inst_cap_dependency *inst_cap_dependency_data; + u32 inst_cap_dependency_data_size; + struct msm_vidc_csc_coeff csc_data; + struct msm_vidc_efuse_data *efuse_data; + unsigned int efuse_data_size; + unsigned int sku_version; + unsigned int vpu_ver; + struct msm_vidc_format_capability *format_data; + const u32 *psc_avc_tbl; + unsigned int psc_avc_tbl_size; + const u32 *psc_hevc_tbl; + unsigned int psc_hevc_tbl_size; + const u32 *psc_vp9_tbl; + unsigned int psc_vp9_tbl_size; + const u32 *psc_av1_tbl; + unsigned int psc_av1_tbl_size; + const u32 *dec_input_prop_avc; + unsigned int dec_input_prop_size_avc; + const u32 *dec_input_prop_hevc; + unsigned int dec_input_prop_size_hevc; + const u32 *dec_input_prop_vp9; + unsigned int dec_input_prop_size_vp9; + const u32 *dec_input_prop_av1; + unsigned int dec_input_prop_size_av1; + const u32 *dec_output_prop_avc; + unsigned int dec_output_prop_size_avc; + const u32 *dec_output_prop_hevc; + unsigned int dec_output_prop_size_hevc; + const u32 *dec_output_prop_vp9; + unsigned int dec_output_prop_size_vp9; + const u32 *dec_output_prop_av1; + unsigned int dec_output_prop_size_av1; + const u32 *msm_vidc_ssr_type; + unsigned int msm_vidc_ssr_type_size; + +}; + +struct msm_vidc_platform { + struct msm_vidc_platform_data data; +}; + +static inline bool is_sys_cache_present(struct msm_vidc_core *core) +{ + return !!core->platform->data.subcache_tbl_size; +} + +static inline bool is_mmrm_supported(struct msm_vidc_core *core) +{ + return !!core->platform->data.supports_mmrm; +} + +int msm_vidc_init_platform(struct msm_vidc_core *core); +int msm_vidc_read_efuse(struct msm_vidc_core *core); + +/* control framework support functions */ + +enum msm_vidc_inst_capability_type msm_vidc_get_cap_id(struct msm_vidc_inst *inst, u32 id); +int msm_vidc_update_cap_value(struct msm_vidc_inst *inst, u32 cap, + s32 adjusted_val, const char *func); +bool is_parent_available(struct msm_vidc_inst *inst, u32 cap_id, + u32 check_parent, const char *func); +int msm_vidc_get_parent_value(struct msm_vidc_inst *inst, u32 cap, u32 parent, + s32 *value, const char *func); +u32 msm_vidc_get_port_info(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_v4l2_menu_to_hfi(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id, u32 *value); +int msm_vidc_v4l2_to_hfi_enum(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id, u32 *value); +int msm_vidc_packetize_control(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id, u32 payload_type, + void *hfi_val, u32 payload_size, const char *func); +int msm_vidc_adjust_bitrate(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_layer_bitrate(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_bitrate_mode(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_entropy_mode(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_profile(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_ltr_count(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_use_ltr(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_mark_ltr(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_delta_based_rc(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_output_order(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_input_buf_host_max_count(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_output_buf_host_max_count(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_transform_8x8(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_chroma_qp_index_offset(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_slice_count(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_layer_count(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_gop_size(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_b_frame(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_peak_bitrate(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_hevc_min_qp(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_hevc_max_qp(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_hevc_i_frame_qp(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_hevc_p_frame_qp(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_hevc_b_frame_qp(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_blur_type(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_blur_resolution(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_brs(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_bitrate_boost(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_min_quality(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_enc_lowlatency_mode(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_dec_lowlatency_mode(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_session_priority(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_roi_info(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_all_intra(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_dec_outbuf_fence_type(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_dec_outbuf_fence_direction(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_dec_slice_mode(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_preprocess(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_eva_stats(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_sei_mastering_disp(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_sei_cll(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_hdr10plus(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_transcoding_stats(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_set_header_mode(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_deblock_mode(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_min_qp(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_max_qp(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_frame_qp(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_req_sync_frame(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_chroma_qp_index_offset(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_slice_count(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_layer_count_and_type(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_gop_size(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_bitrate(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_layer_bitrate(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_u32(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_u32_packed(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_u32_enum(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_constant_quality(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_vbr_related_properties(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_cbr_related_properties(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_use_and_mark_ltr(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_nal_length(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_session_priority(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_flip(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_rotation(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_blur_resolution(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_stage(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_pipe(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_csc_custom_matrix(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_level(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_preprocess(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_reserve_duration(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_q16(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_vui_timing_info(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_outbuf_fence_type(void *instance, enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_outbuf_fence_direction(void *instance, enum msm_vidc_inst_capability_type cap_id); + +#endif // _MSM_VIDC_PLATFORM_H_ diff --git a/qcom/opensource/video-driver/driver/platform/common/inc/msm_vidc_platform_ext.h b/qcom/opensource/video-driver/driver/platform/common/inc/msm_vidc_platform_ext.h new file mode 100644 index 0000000000..ecb8c38736 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/common/inc/msm_vidc_platform_ext.h @@ -0,0 +1,268 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_PLATFORM_EXT_H_ +#define _MSM_VIDC_PLATFORM_EXT_H_ + +#include "msm_vidc_control.h" + +/* HEIC encoder and decoder */ +#define V4L2_PIX_FMT_VIDC_HEIC v4l2_fourcc('H', 'E', 'I', 'C') + +#define V4L2_META_FMT_VIDC v4l2_fourcc('Q', 'M', 'E', 'T') + +#ifndef V4L2_CID_MPEG_VIDC_SECURE +#define V4L2_CID_MPEG_VIDC_SECURE (V4L2_CID_MPEG_VIDC_BASE + 0x1) +#endif + +#ifndef V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST +#define V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST (V4L2_CID_MPEG_VIDC_BASE + 0x3) +#endif + +/* FIXme: */ +#define V4L2_CID_MPEG_VIDC_CODEC_CONFIG (V4L2_CID_MPEG_VIDC_BASE + 0x4) +#define V4L2_CID_MPEG_VIDC_FRAME_RATE (V4L2_CID_MPEG_VIDC_BASE + 0x5) +#define V4L2_CID_MPEG_VIDC_OPERATING_RATE (V4L2_CID_MPEG_VIDC_BASE + 0x6) + +#ifndef V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC +#define V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC (V4L2_CID_MPEG_VIDC_BASE + 0xD) +#endif + +/* Encoder quality controls */ +#define V4L2_CID_MPEG_VIDC_CONTENT_ADAPTIVE_CODING \ + (V4L2_CID_MPEG_VIDC_BASE + 0xE) +#define V4L2_CID_MPEG_VIDC_QUALITY_BITRATE_BOOST \ + (V4L2_CID_MPEG_VIDC_BASE + 0xF) +#define V4L2_CID_MPEG_VIDC_VIDEO_BLUR_TYPES \ + (V4L2_CID_MPEG_VIDC_BASE + 0x10) +enum v4l2_mpeg_vidc_blur_types { + VIDC_BLUR_NONE = 0x0, + VIDC_BLUR_EXTERNAL = 0x1, + VIDC_BLUR_ADAPTIVE = 0x2, +}; + +/* (blur width) << 16 | (blur height) */ +#define V4L2_CID_MPEG_VIDC_VIDEO_BLUR_RESOLUTION \ + (V4L2_CID_MPEG_VIDC_BASE + 0x11) +/* TODO: jdas: compound control for matrix */ +#define V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX \ + (V4L2_CID_MPEG_VIDC_BASE + 0x12) +#define V4L2_CID_MPEG_VIDC_METADATA_LTR_MARK_USE_DETAILS \ + (V4L2_CID_MPEG_VIDC_BASE + 0x13) +#define V4L2_CID_MPEG_VIDC_METADATA_SEQ_HEADER_NAL \ + (V4L2_CID_MPEG_VIDC_BASE + 0x14) +#define V4L2_CID_MPEG_VIDC_METADATA_DPB_LUMA_CHROMA_MISR \ + (V4L2_CID_MPEG_VIDC_BASE + 0x15) +#define V4L2_CID_MPEG_VIDC_METADATA_OPB_LUMA_CHROMA_MISR \ + (V4L2_CID_MPEG_VIDC_BASE + 0x16) +#define V4L2_CID_MPEG_VIDC_METADATA_INTERLACE \ + (V4L2_CID_MPEG_VIDC_BASE + 0x17) +#define V4L2_CID_MPEG_VIDC_METADATA_CONCEALED_MB_COUNT \ + (V4L2_CID_MPEG_VIDC_BASE + 0x18) +#define V4L2_CID_MPEG_VIDC_METADATA_HISTOGRAM_INFO \ + (V4L2_CID_MPEG_VIDC_BASE + 0x19) +#define V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR \ + (V4L2_CID_MPEG_VIDC_BASE + 0x1A) +#define V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL \ + (V4L2_CID_MPEG_VIDC_BASE + 0x1B) +#define V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS \ + (V4L2_CID_MPEG_VIDC_BASE + 0x1C) +#define V4L2_CID_MPEG_VIDC_METADATA_EVA_STATS \ + (V4L2_CID_MPEG_VIDC_BASE + 0x1D) +#define V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG \ + (V4L2_CID_MPEG_VIDC_BASE + 0x1E) +#define V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT \ + (V4L2_CID_MPEG_VIDC_BASE + 0x1F) +#define V4L2_CID_MPEG_VIDC_METADATA_ROI_INFO \ + (V4L2_CID_MPEG_VIDC_BASE + 0x20) +#define V4L2_CID_MPEG_VIDC_METADATA_TIMESTAMP \ + (V4L2_CID_MPEG_VIDC_BASE + 0x21) +#define V4L2_CID_MPEG_VIDC_METADATA_ENC_QP_METADATA \ + (V4L2_CID_MPEG_VIDC_BASE + 0x22) +#define V4L2_CID_MPEG_VIDC_MIN_BITSTREAM_SIZE_OVERWRITE \ + (V4L2_CID_MPEG_VIDC_BASE + 0x23) +#define V4L2_CID_MPEG_VIDC_METADATA_BITSTREAM_RESOLUTION \ + (V4L2_CID_MPEG_VIDC_BASE + 0x24) +#define V4L2_CID_MPEG_VIDC_METADATA_CROP_OFFSETS \ + (V4L2_CID_MPEG_VIDC_BASE + 0x25) +#define V4L2_CID_MPEG_VIDC_METADATA_SALIENCY_INFO \ + (V4L2_CID_MPEG_VIDC_BASE + 0x26) +#define V4L2_CID_MPEG_VIDC_METADATA_TRANSCODE_STAT_INFO \ + (V4L2_CID_MPEG_VIDC_BASE + 0x27) + +/* Encoder Super frame control */ +#define V4L2_CID_MPEG_VIDC_SUPERFRAME (V4L2_CID_MPEG_VIDC_BASE + 0x28) +/* Thumbnail Mode control */ +#define V4L2_CID_MPEG_VIDC_THUMBNAIL_MODE (V4L2_CID_MPEG_VIDC_BASE + 0x29) + +/* Priority control */ +#ifndef V4L2_CID_MPEG_VIDC_PRIORITY +#define V4L2_CID_MPEG_VIDC_PRIORITY (V4L2_CID_MPEG_VIDC_BASE + 0x2A) +#endif + +/* Metadata DPB Tag List*/ +#define V4L2_CID_MPEG_VIDC_METADATA_DPB_TAG_LIST \ + (V4L2_CID_MPEG_VIDC_BASE + 0x2B) +/* Encoder Input Compression Ratio control */ +#define V4L2_CID_MPEG_VIDC_ENC_INPUT_COMPRESSION_RATIO \ + (V4L2_CID_MPEG_VIDC_BASE + 0x2C) +#define V4L2_CID_MPEG_VIDC_METADATA_DEC_QP_METADATA \ + (V4L2_CID_MPEG_VIDC_BASE + 0x2E) + +/* Encoder Complexity control */ +#ifndef V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY +#define V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY \ + (V4L2_CID_MPEG_VIDC_BASE + 0x2F) +#endif + +/* Decoder Max Number of Reorder Frames */ +#ifndef V4L2_CID_MPEG_VIDC_METADATA_MAX_NUM_REORDER_FRAMES +#define V4L2_CID_MPEG_VIDC_METADATA_MAX_NUM_REORDER_FRAMES \ + (V4L2_CID_MPEG_VIDC_BASE + 0x30) +#endif + +/* Control IDs for AV1 */ +#define V4L2_CID_MPEG_VIDC_AV1_PROFILE (V4L2_CID_MPEG_VIDC_BASE + 0x31) +enum v4l2_mpeg_vidc_av1_profile { + V4L2_MPEG_VIDC_AV1_PROFILE_MAIN = 0, + V4L2_MPEG_VIDC_AV1_PROFILE_HIGH = 1, + V4L2_MPEG_VIDC_AV1_PROFILE_PROFESSIONAL = 2, +}; + +#define V4L2_CID_MPEG_VIDC_AV1_LEVEL (V4L2_CID_MPEG_VIDC_BASE + 0x32) +enum v4l2_mpeg_vidc_av1_level { + V4L2_MPEG_VIDC_AV1_LEVEL_2_0 = 0, + V4L2_MPEG_VIDC_AV1_LEVEL_2_1 = 1, + V4L2_MPEG_VIDC_AV1_LEVEL_2_2 = 2, + V4L2_MPEG_VIDC_AV1_LEVEL_2_3 = 3, + V4L2_MPEG_VIDC_AV1_LEVEL_3_0 = 4, + V4L2_MPEG_VIDC_AV1_LEVEL_3_1 = 5, + V4L2_MPEG_VIDC_AV1_LEVEL_3_2 = 6, + V4L2_MPEG_VIDC_AV1_LEVEL_3_3 = 7, + V4L2_MPEG_VIDC_AV1_LEVEL_4_0 = 8, + V4L2_MPEG_VIDC_AV1_LEVEL_4_1 = 9, + V4L2_MPEG_VIDC_AV1_LEVEL_4_2 = 10, + V4L2_MPEG_VIDC_AV1_LEVEL_4_3 = 11, + V4L2_MPEG_VIDC_AV1_LEVEL_5_0 = 12, + V4L2_MPEG_VIDC_AV1_LEVEL_5_1 = 13, + V4L2_MPEG_VIDC_AV1_LEVEL_5_2 = 14, + V4L2_MPEG_VIDC_AV1_LEVEL_5_3 = 15, + V4L2_MPEG_VIDC_AV1_LEVEL_6_0 = 16, + V4L2_MPEG_VIDC_AV1_LEVEL_6_1 = 17, + V4L2_MPEG_VIDC_AV1_LEVEL_6_2 = 18, + V4L2_MPEG_VIDC_AV1_LEVEL_6_3 = 19, + V4L2_MPEG_VIDC_AV1_LEVEL_7_0 = 20, + V4L2_MPEG_VIDC_AV1_LEVEL_7_1 = 21, + V4L2_MPEG_VIDC_AV1_LEVEL_7_2 = 22, + V4L2_MPEG_VIDC_AV1_LEVEL_7_3 = 23, +}; + +#define V4L2_CID_MPEG_VIDC_AV1_TIER (V4L2_CID_MPEG_VIDC_BASE + 0x33) +enum v4l2_mpeg_vidc_av1_tier { + V4L2_MPEG_VIDC_AV1_TIER_MAIN = 0, + V4L2_MPEG_VIDC_AV1_TIER_HIGH = 1, +}; + +/* Decoder Timestamp Reorder control */ +#define V4L2_CID_MPEG_VIDC_TS_REORDER (V4L2_CID_MPEG_VIDC_BASE + 0x34) +/* AV1 Decoder Film Grain */ +#define V4L2_CID_MPEG_VIDC_AV1D_FILM_GRAIN_PRESENT \ + (V4L2_CID_MPEG_VIDC_BASE + 0x35) +/* Enables Output buffer fence id via input metadata */ +#define V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE \ + (V4L2_CID_MPEG_VIDC_BASE + 0x38) +/* Control to set fence id to driver in order get corresponding fence fd */ +#define V4L2_CID_MPEG_VIDC_SW_FENCE_ID \ + (V4L2_CID_MPEG_VIDC_BASE + 0x39) +/* + * Control to get fence fd from driver for the fence id + * set via V4L2_CID_MPEG_VIDC_SW_FENCE_ID + */ +#define V4L2_CID_MPEG_VIDC_SW_FENCE_FD \ + (V4L2_CID_MPEG_VIDC_BASE + 0x3A) +#define V4L2_CID_MPEG_VIDC_METADATA_PICTURE_TYPE \ + (V4L2_CID_MPEG_VIDC_BASE + 0x3B) + +/* Encoder Slice Delivery Mode + * set format has a dependency on this control + * and gets invoked when this control is updated. + */ +#define V4L2_CID_MPEG_VIDC_HEVC_ENCODE_DELIVERY_MODE \ + (V4L2_CID_MPEG_VIDC_BASE + 0x3C) + +#define V4L2_CID_MPEG_VIDC_H264_ENCODE_DELIVERY_MODE \ + (V4L2_CID_MPEG_VIDC_BASE + 0x3D) + +#define V4L2_CID_MPEG_VIDC_CRITICAL_PRIORITY \ + (V4L2_CID_MPEG_VIDC_BASE + 0x3E) +#define V4L2_CID_MPEG_VIDC_RESERVE_DURATION \ + (V4L2_CID_MPEG_VIDC_BASE + 0x3F) + +#define V4L2_CID_MPEG_VIDC_METADATA_DOLBY_RPU \ + (V4L2_CID_MPEG_VIDC_BASE + 0x40) + +#define V4L2_CID_MPEG_VIDC_CLIENT_ID \ + (V4L2_CID_MPEG_VIDC_BASE + 0x41) + +#define V4L2_CID_MPEG_VIDC_LAST_FLAG_EVENT_ENABLE \ + (V4L2_CID_MPEG_VIDC_BASE + 0x42) + +#ifndef V4L2_CID_MPEG_VIDC_VUI_TIMING_INFO +#define V4L2_CID_MPEG_VIDC_VUI_TIMING_INFO \ + (V4L2_CID_MPEG_VIDC_BASE + 0x43) +#endif + +#define V4L2_CID_MPEG_VIDC_EARLY_NOTIFY_ENABLE \ + (V4L2_CID_MPEG_VIDC_BASE + 0x44) + +#define V4L2_CID_MPEG_VIDC_EARLY_NOTIFY_LINE_COUNT \ + (V4L2_CID_MPEG_VIDC_BASE + 0x45) + +/* + * This control is introduced to overcome v4l2 limitation + * of allowing only standard colorspace info via s_fmt. + * v4l_sanitize_colorspace() is introduced in s_fmt ioctl + * to reject private colorspace. Through this control, client + * can set private colorspace info and/or use this control + * to set colorspace dynamically. + * The control value is 32 bits packed as: + * [ 0 - 7] : matrix coefficients + * [ 8 - 15] : transfer characteristics + * [16 - 23] : colour primaries + * [24 - 31] : range + * This control is only for encoder. + * Currently g_fmt in v4l2 does not santize colorspace, + * hence this control is not introduced for decoder. + */ +#define V4L2_CID_MPEG_VIDC_SIGNAL_COLOR_INFO \ + (V4L2_CID_MPEG_VIDC_BASE + 0x46) + +/* control to enable csc */ +#define V4L2_CID_MPEG_VIDC_CSC \ + (V4L2_CID_MPEG_VIDC_BASE + 0x47) + +#define V4L2_CID_MPEG_VIDC_DRIVER_VERSION \ + (V4L2_CID_MPEG_VIDC_BASE + 0x48) + +#define V4L2_CID_MPEG_VIDC_GRID_WIDTH \ + (V4L2_CID_MPEG_VIDC_BASE + 0x49) + +#define V4L2_CID_MPEG_VIDC_MAX_NUM_REORDER_FRAMES \ + (V4L2_CID_MPEG_VIDC_BASE + 0x4A) + +#define V4L2_CID_MPEG_VIDC_INTERLACE \ + (V4L2_CID_MPEG_VIDC_BASE + 0x4B) + +int msm_vidc_adjust_ir_period(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_dec_frame_rate(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_dec_operating_rate(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_adjust_delivery_mode(void *instance, struct v4l2_ctrl *ctrl); +int msm_vidc_set_ir_period(void *instance, + enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_set_signal_color_info(void *instance, + enum msm_vidc_inst_capability_type cap_id); +int msm_vidc_adjust_csc(void *instance, struct v4l2_ctrl *ctrl); + +#endif diff --git a/qcom/opensource/video-driver/driver/platform/common/inc/perf_static_model.h b/qcom/opensource/video-driver/driver/platform/common/inc/perf_static_model.h new file mode 100644 index 0000000000..23d87d8bc3 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/common/inc/perf_static_model.h @@ -0,0 +1,240 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _PERF_STATIC_MODEL_H_ +#define _PERF_STATIC_MODEL_H_ + +#include + +/* Reordered CODECS to match Bitrate Table rows */ +#define CODEC_H264_CAVLC 0 +#define CODEC_H264 1 +#define CODEC_HEVC 2 +#define CODEC_VP9 3 +#define CODEC_AV1 4 + +#define CODEC_BSE_FrameFactor 0 +#define CODEC_BSE_MBFactor 1 +#define CODEC_BSE_LUC_SIZE 2 + +#define CODEC_GOP_IPP 0 +#define CODEC_GOP_IbP 1 +#define CODEC_GOP_I1B2b1P 2 +#define CODEC_GOP_I3B4b1P 3 +#define CODEC_GOP_PONLY 4 +#define CODEC_GOP_bONLY 5 +#define CODEC_GOP_BONLY 6 +#define CODEC_GOP_IONLY 7 + +#define CODEC_ENCODER_GOP_Bb_ENTRY 0 +#define CODEC_ENCODER_GOP_P_ENTRY 1 +#define CODEC_ENCODER_GOP_FACTORY_ENTRY 2 + +#define CODEC_ENTROPY_CODING_CAVLC 0 +#define CODEC_ENTROPY_CODING_CABAC 1 + +#define CODEC_VSPVPP_MODE_1S 1 +#define CODEC_VSPVPP_MODE_2S 2 + +#define COMP_SETTING_PWC 0 +#define COMP_SETTING_AVG 1 +#define COMP_SETTING_POWER 2 + +#define CODEC_BITDEPTH_8 8 +#define CODEC_BITDEPTH_10 10 + +#define ENCODE_YUV 0 +#define ENCODE_RGB 1 + +#define COMPLEXITY_PWC 0 +#define COMPLEXITY_AVG 1 +#define COMPLEXITY_POWER 2 + +#define MAX_LINE 2048 +#ifndef VENUS_MAX_FILENAME_LENGTH +#define VENUS_MAX_FILENAME_LENGTH 1024 +#endif + +#define CODEC_ENCODER 1 +#define CODEC_DECODER 2 + +#define COMPLEXITY_THRESHOLD 2 + +enum chipset_generation { + MSM_KONA = 0, + MSM_LAHAINA, + MSM_WAIPIO, + MSM_MAKENA, + MSM_KALAMA, + MSM_QOGNITION, + MSM_PINEAPPLE, + MSM_MAX, +}; + +enum regression_mode { + /* ignores client set cr and bitrate settings */ + REGRESSION_MODE_SANITY = 1, + /* cr and bitrate default mode */ + REGRESSION_MODE_DEFAULT, + /* custom mode where client will set cr and bitrate values */ + REGRESSION_MODE_CUSTOM, +}; + +/* + * If firmware provided motion_vector_complexity is >= 2 then set the + * complexity_setting as PWC (performance worst case) + * If the motion_vector_complexity is < 2 then set the complexity_setting + * as AVG (average case value) + */ +enum complexity_setting { + COMPLEXITY_SETTING_PWC = 0, + COMPLEXITY_SETTING_AVG = 1, + COMPLEXITY_SETTING_PWR = 2, +}; + +/* + * If firmware provided motion_vector_complexity is >= 2 then set the + * refframe_complexity as PWC (performance worst case) + * If the motion_vector_complexity is < 2 then set the refframe_complexity + * as AVG (average case value) + */ +enum refframe_complexity { + REFFRAME_COMPLEXITY_PWC = 4, + REFFRAME_COMPLEXITY_AVG = 2, + REFFRAME_COMPLEXITY_PWR = 1, +}; + +struct api_calculation_input { + /*2: decoder; 1: encoder */ + u32 decoder_or_encoder; + + /* enum chipset_generation */ + u32 chipset_gen; + + u32 codec; + u32 lcu_size; + u32 pipe_num; + u32 frame_rate; + u32 frame_width; + u32 frame_height; + u32 vsp_vpp_mode; + u32 entropy_coding_mode; + u32 hierachical_layer; + + /* PWC, AVG/POWER */ + u32 complexity_setting; + + u32 status_llc_onoff; + u32 bitdepth; + u32 linear_opb; + + /* AV1D FG */ + u32 split_opb; + + u32 linear_ipb; + u32 lossy_ipb; + u32 ipb_yuvrgb; + u32 encoder_multiref; + u32 bitrate_mbps; + u32 refframe_complexity; + u32 cr_ipb; + u32 cr_rpb; + u32 cr_dpb; + u32 cr_opb; + u32 av1d_commer_tile_enable; + u32 regression_mode; + + /* used in aurora for depth map decode */ + u32 lumaonly_decode; + + /* used in freq and bitrate table selection*/ + u32 vpu_ver; +}; + +struct corner_voting { + u32 percent_lowbound; + u32 percent_highbound; +}; + +struct api_calculation_freq_output { + u32 vpp_min_freq; + u32 vsp_min_freq; + u32 tensilica_min_freq; + u32 hw_min_freq; + u32 enc_hqmode; + struct corner_voting usecase_corner; +}; + +struct api_calculation_bw_output { + u32 vsp_read_noc; + u32 vsp_write_noc; + u32 vsp_read_ddr; + u32 vsp_write_ddr; + u32 vsp_rd_wr_total_noc; + u32 vsp_rd_wr_total_ddr; + + u32 collocated_rd_noc; + u32 collocated_wr_noc; + u32 collocated_rd_ddr; + u32 collocated_wr_ddr; + u32 collocated_rd_wr_total_noc; + u32 collocated_rd_wr_total_ddr; + + u32 dpb_rd_y_noc; + u32 dpb_rd_crcb_noc; + u32 dpb_rdwr_duetooverlap_noc; + u32 dpb_wr_noc; + u32 dpb_rd_y_ddr; + u32 dpb_rd_crcb_ddr; + u32 dpb_rdwr_duetooverlap_ddr; + u32 dpb_wr_ddr; + u32 dpb_rd_wr_total_noc; + u32 dpb_rd_wr_total_ddr; + + u32 opb_write_total_noc; + u32 opb_write_total_ddr; + + u32 ipb_rd_total_noc; + u32 ipb_rd_total_ddr; + + u32 bse_tlb_rd_noc; + u32 bse_tlb_wr_noc; + u32 bse_tlb_rd_ddr; + u32 bse_tlb_wr_ddr; + u32 bse_rd_wr_total_noc; + u32 bse_rd_wr_total_ddr; + + u32 statistics_rd_noc; + u32 statistics_wr_noc; + u32 statistics_rd_ddr; + u32 statistics_wr_ddr; + + u32 mmu_rd_noc; + u32 mmu_rd_ddr; + + u32 noc_bw_rd; + u32 noc_bw_wr; + u32 ddr_bw_rd; + u32 ddr_bw_wr; + + /* llc BW components for aurora */ + u32 dpb_rd_y_llc; + u32 dpb_rd_crcb_llc; + u32 dpb_wr_llc; + u32 bse_tlb_rd_llc; + u32 bse_tlb_wr_llc; + u32 vsp_read_llc; + u32 vsp_write_llc; + + u32 llc_bw_rd; + u32 llc_bw_wr; +}; + +int msm_vidc_calculate_frequency(struct api_calculation_input codec_input, + struct api_calculation_freq_output *codec_output); +int msm_vidc_calculate_bandwidth(struct api_calculation_input codec_input, + struct api_calculation_bw_output *codec_output); + +#endif /*_PERF_STATIC_MODEL_H_ */ diff --git a/qcom/opensource/video-driver/driver/platform/common/src/msm_vidc_platform.c b/qcom/opensource/video-driver/driver/platform/common/src/msm_vidc_platform.c new file mode 100644 index 0000000000..a137134fd9 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/common/src/msm_vidc_platform.c @@ -0,0 +1,3593 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include + +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_v4l2.h" +#include "msm_vidc_vb2.h" +#include "msm_vidc_core.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_memory.h" +#include "msm_vidc_control.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_fence.h" +#include "hfi_packet.h" +#include "hfi_property.h" +#include "venus_hfi.h" + +#if defined(CONFIG_MSM_VIDC_VOLCANO) +#include "msm_vidc_volcano.h" +#include "msm_vidc_iris2.h" +#endif +#if defined(CONFIG_MSM_VIDC_PINEAPPLE) +#include "msm_vidc_pineapple.h" +#include "msm_vidc_cliffs.h" +#include "msm_vidc_iris33.h" +#endif +#if defined(CONFIG_MSM_VIDC_KALAMA) +#include "msm_vidc_kalama.h" +#include "msm_vidc_iris3.h" +#endif +#if defined(CONFIG_MSM_VIDC_WAIPIO) +#include "msm_vidc_waipio.h" +#include "msm_vidc_iris2.h" +#endif + +#define CAP_TO_8BIT_QP(a) { \ + if ((a) < MIN_QP_8BIT) \ + (a) = MIN_QP_8BIT; \ +} + +/* + * Below calculation for number of reference frames + * is picked up from hfi macro HFI_IRIS3_ENC_RECON_BUF_COUNT + */ +#define SLIDING_WINDOW_REF_FRAMES(codec, total_hp_layers, ltr_count, num_ref) { \ + if (codec == MSM_VIDC_HEVC) { \ + num_ref = (total_hp_layers + 1) >> 1; \ + } else if (codec == MSM_VIDC_H264) { \ + if (total_hp_layers < 4) \ + num_ref = (total_hp_layers - 1); \ + else \ + num_ref = total_hp_layers; \ + } \ + if (ltr_count) \ + num_ref = num_ref + ltr_count; \ +} + +/* + * Custom conversion coefficients for resolution: 176x144 negative + * coeffs are converted to s4.9 format + * (e.g. -22 converted to ((1 << 13) - 22) + * 3x3 transformation matrix coefficients in s4.9 fixed point format + */ +u32 vpe_csc_custom_matrix_coeff[MAX_MATRIX_COEFFS] = { + 440, 8140, 8098, 0, 460, 52, 0, 34, 463 +}; + +/* offset coefficients in s9 fixed point format */ +u32 vpe_csc_custom_bias_coeff[MAX_BIAS_COEFFS] = { + 53, 0, 4 +}; + +/* clamping value for Y/U/V([min,max] for Y/U/V) */ +u32 vpe_csc_custom_limit_coeff[MAX_LIMIT_COEFFS] = { + 16, 235, 16, 240, 16, 240 +}; + +static struct v4l2_file_operations msm_v4l2_file_operations = { + .owner = THIS_MODULE, + .open = msm_v4l2_open, + .release = msm_v4l2_close, + .unlocked_ioctl = video_ioctl2, + .poll = msm_v4l2_poll, +}; + +static struct v4l2_ioctl_ops msm_v4l2_ioctl_ops_enc = { + .vidioc_querycap = msm_v4l2_querycap, + .vidioc_enum_fmt_vid_cap = msm_v4l2_enum_fmt, + .vidioc_enum_fmt_vid_out = msm_v4l2_enum_fmt, + .vidioc_enum_fmt_meta_cap = msm_v4l2_enum_fmt, + .vidioc_enum_fmt_meta_out = msm_v4l2_enum_fmt, + .vidioc_enum_framesizes = msm_v4l2_enum_framesizes, + .vidioc_enum_frameintervals = msm_v4l2_enum_frameintervals, + .vidioc_try_fmt_vid_cap_mplane = msm_v4l2_try_fmt, + .vidioc_try_fmt_vid_out_mplane = msm_v4l2_try_fmt, + .vidioc_try_fmt_meta_cap = msm_v4l2_try_fmt, + .vidioc_try_fmt_meta_out = msm_v4l2_try_fmt, + .vidioc_s_fmt_vid_cap = msm_v4l2_s_fmt, + .vidioc_s_fmt_vid_out = msm_v4l2_s_fmt, + .vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt, + .vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt, + .vidioc_s_fmt_meta_out = msm_v4l2_s_fmt, + .vidioc_s_fmt_meta_cap = msm_v4l2_s_fmt, + .vidioc_g_fmt_vid_cap = msm_v4l2_g_fmt, + .vidioc_g_fmt_vid_out = msm_v4l2_g_fmt, + .vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt, + .vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt, + .vidioc_g_fmt_meta_out = msm_v4l2_g_fmt, + .vidioc_g_fmt_meta_cap = msm_v4l2_g_fmt, + .vidioc_g_selection = msm_v4l2_g_selection, + .vidioc_s_selection = msm_v4l2_s_selection, + .vidioc_s_parm = msm_v4l2_s_parm, + .vidioc_g_parm = msm_v4l2_g_parm, + .vidioc_reqbufs = msm_v4l2_reqbufs, + .vidioc_querybuf = msm_v4l2_querybuf, + .vidioc_create_bufs = msm_v4l2_create_bufs, + .vidioc_prepare_buf = msm_v4l2_prepare_buf, + .vidioc_qbuf = msm_v4l2_qbuf, + .vidioc_dqbuf = msm_v4l2_dqbuf, + .vidioc_streamon = msm_v4l2_streamon, + .vidioc_streamoff = msm_v4l2_streamoff, + .vidioc_queryctrl = msm_v4l2_queryctrl, + .vidioc_querymenu = msm_v4l2_querymenu, + .vidioc_subscribe_event = msm_v4l2_subscribe_event, + .vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event, + .vidioc_try_encoder_cmd = msm_v4l2_try_encoder_cmd, + .vidioc_encoder_cmd = msm_v4l2_encoder_cmd, +}; + +static struct v4l2_ioctl_ops msm_v4l2_ioctl_ops_dec = { + .vidioc_querycap = msm_v4l2_querycap, + .vidioc_enum_fmt_vid_cap = msm_v4l2_enum_fmt, + .vidioc_enum_fmt_vid_out = msm_v4l2_enum_fmt, + .vidioc_enum_fmt_meta_cap = msm_v4l2_enum_fmt, + .vidioc_enum_fmt_meta_out = msm_v4l2_enum_fmt, + .vidioc_enum_framesizes = msm_v4l2_enum_framesizes, + .vidioc_enum_frameintervals = msm_v4l2_enum_frameintervals, + .vidioc_try_fmt_vid_cap_mplane = msm_v4l2_try_fmt, + .vidioc_try_fmt_vid_out_mplane = msm_v4l2_try_fmt, + .vidioc_try_fmt_meta_cap = msm_v4l2_try_fmt, + .vidioc_try_fmt_meta_out = msm_v4l2_try_fmt, + .vidioc_s_fmt_vid_cap = msm_v4l2_s_fmt, + .vidioc_s_fmt_vid_out = msm_v4l2_s_fmt, + .vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt, + .vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt, + .vidioc_s_fmt_meta_out = msm_v4l2_s_fmt, + .vidioc_s_fmt_meta_cap = msm_v4l2_s_fmt, + .vidioc_g_fmt_vid_cap = msm_v4l2_g_fmt, + .vidioc_g_fmt_vid_out = msm_v4l2_g_fmt, + .vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt, + .vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt, + .vidioc_g_fmt_meta_out = msm_v4l2_g_fmt, + .vidioc_g_fmt_meta_cap = msm_v4l2_g_fmt, + .vidioc_g_selection = msm_v4l2_g_selection, + .vidioc_s_selection = msm_v4l2_s_selection, + .vidioc_reqbufs = msm_v4l2_reqbufs, + .vidioc_querybuf = msm_v4l2_querybuf, + .vidioc_create_bufs = msm_v4l2_create_bufs, + .vidioc_prepare_buf = msm_v4l2_prepare_buf, + .vidioc_qbuf = msm_v4l2_qbuf, + .vidioc_dqbuf = msm_v4l2_dqbuf, + .vidioc_streamon = msm_v4l2_streamon, + .vidioc_streamoff = msm_v4l2_streamoff, + .vidioc_queryctrl = msm_v4l2_queryctrl, + .vidioc_querymenu = msm_v4l2_querymenu, + .vidioc_subscribe_event = msm_v4l2_subscribe_event, + .vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event, + .vidioc_try_decoder_cmd = msm_v4l2_try_decoder_cmd, + .vidioc_decoder_cmd = msm_v4l2_decoder_cmd, +}; + +static struct v4l2_ctrl_ops msm_v4l2_ctrl_ops = { + .s_ctrl = msm_v4l2_op_s_ctrl, + .g_volatile_ctrl = msm_v4l2_op_g_volatile_ctrl, +}; + +static struct vb2_ops msm_vb2_ops = { + .queue_setup = msm_vb2_queue_setup, + .start_streaming = msm_vb2_start_streaming, + .buf_queue = msm_vb2_buf_queue, + .stop_streaming = msm_vb2_stop_streaming, + .buf_out_validate = msm_vb2_buf_out_validate, + .buf_request_complete = msm_vb2_request_complete, +}; + +static struct vb2_mem_ops msm_vb2_mem_ops = { + .alloc = msm_vb2_alloc, + .put = msm_vb2_put, + .mmap = msm_vb2_mmap, + .attach_dmabuf = msm_vb2_attach_dmabuf, + .detach_dmabuf = msm_vb2_detach_dmabuf, + .map_dmabuf = msm_vb2_map_dmabuf, + .unmap_dmabuf = msm_vb2_unmap_dmabuf, +}; + +static struct media_device_ops msm_v4l2_media_ops = { + .req_validate = msm_v4l2_request_validate, + .req_queue = msm_v4l2_request_queue, +}; + +static struct v4l2_m2m_ops msm_v4l2_m2m_ops = { + .device_run = msm_v4l2_m2m_device_run, + .job_abort = msm_v4l2_m2m_job_abort, +}; + +static const struct msm_vidc_compat_handle compat_handle[] = { +#if defined(CONFIG_MSM_VIDC_PINEAPPLE) + { + .compat = "qcom,sm8650-vidc", + .init_platform = msm_vidc_init_platform_pineapple, + .init_iris = msm_vidc_init_iris33, + }, + { + .compat = "qcom,sm8650-vidc-v2", + .init_platform = msm_vidc_init_platform_pineapple, + .init_iris = msm_vidc_init_iris33, + }, + { + .compat = "qcom,cliffs-vidc", + .init_platform = msm_vidc_init_platform_cliffs, + .init_iris = msm_vidc_init_iris33, + }, +#endif +#if defined(CONFIG_MSM_VIDC_KALAMA) + { + .compat = "qcom,sm8550-vidc", + .init_platform = msm_vidc_init_platform_kalama, + .init_iris = msm_vidc_init_iris3, + }, + { + .compat = "qcom,sm8550-vidc-v2", + .init_platform = msm_vidc_init_platform_kalama, + .init_iris = msm_vidc_init_iris3, + }, +#endif +#if defined(CONFIG_MSM_VIDC_WAIPIO) + { + .compat = "qcom,sm8450-vidc", + .init_platform = msm_vidc_init_platform_waipio, + .init_iris = msm_vidc_init_iris2, + }, +#endif +#if defined(CONFIG_MSM_VIDC_VOLCANO) + { + .compat = "qcom,volcano-vidc", + .init_platform = msm_vidc_init_platform_volcano, + .init_iris = msm_vidc_init_iris2, + }, +#endif +}; + +static int msm_vidc_init_ops(struct msm_vidc_core *core) +{ + d_vpr_h("%s: initialize ops\n", __func__); + core->v4l2_file_ops = &msm_v4l2_file_operations; + core->v4l2_ioctl_ops_enc = &msm_v4l2_ioctl_ops_enc; + core->v4l2_ioctl_ops_dec = &msm_v4l2_ioctl_ops_dec; + core->v4l2_ctrl_ops = &msm_v4l2_ctrl_ops; + core->vb2_ops = &msm_vb2_ops; + core->vb2_mem_ops = &msm_vb2_mem_ops; + core->media_device_ops = &msm_v4l2_media_ops; + core->v4l2_m2m_ops = &msm_v4l2_m2m_ops; + core->mem_ops = get_mem_ops(); + if (!core->mem_ops) { + d_vpr_e("%s: invalid memory ops\n", __func__); + return -EINVAL; + } + core->res_ops = get_resources_ops(); + if (!core->res_ops) { + d_vpr_e("%s: invalid resource ops\n", __func__); + return -EINVAL; + } + core->fence_ops = get_dma_fence_ops(); + if (!core->fence_ops) { + d_vpr_e("%s: invalid dma fence ops\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int msm_vidc_init_platform_variant(struct msm_vidc_core *core) +{ + struct device *dev = NULL; + int i, rc = 0; + + dev = &core->pdev->dev; + + d_vpr_h("%s()\n", __func__); + + /* select platform based on compatible match */ + for (i = 0; i < ARRAY_SIZE(compat_handle); i++) { + if (of_device_is_compatible(dev->of_node, compat_handle[i].compat)) { + rc = compat_handle[i].init_platform(core); + if (rc) { + d_vpr_e("%s: (%s) init failed with %d\n", + __func__, compat_handle[i].compat, rc); + return rc; + } + break; + } + } + + /* handle unknown compat type */ + if (i == ARRAY_SIZE(compat_handle)) { + d_vpr_e("%s: Unsupported device: (%s)\n", __func__, dev_name(dev)); + return -EINVAL; + } + + return rc; +} + +static int msm_vidc_init_vpu(struct msm_vidc_core *core) +{ + struct device *dev = NULL; + int i, rc = 0; + + dev = &core->pdev->dev; + + /* select platform based on compatible match */ + for (i = 0; i < ARRAY_SIZE(compat_handle); i++) { + if (of_device_is_compatible(dev->of_node, compat_handle[i].compat)) { + rc = compat_handle[i].init_iris(core); + if (rc) { + d_vpr_e("%s: (%s) init failed with %d\n", + __func__, compat_handle[i].compat, rc); + return rc; + } + break; + } + } + + /* handle unknown compat type */ + if (i == ARRAY_SIZE(compat_handle)) { + d_vpr_e("%s: Unsupported device: (%s)\n", __func__, dev_name(dev)); + return -EINVAL; + } + + return rc; +} + +int msm_vidc_init_platform(struct msm_vidc_core *core) +{ + int rc = 0; + struct msm_vidc_platform *platform = NULL; + + d_vpr_h("%s()\n", __func__); + + platform = devm_kzalloc(&core->pdev->dev, + sizeof(struct msm_vidc_platform), GFP_KERNEL); + if (!platform) { + d_vpr_e("%s: failed to alloc memory for platform\n", __func__); + return -ENOMEM; + } + + core->platform = platform; + + /* selected ops can be re-assigned in platform specific file */ + rc = msm_vidc_init_ops(core); + if (rc) + return rc; + + rc = msm_vidc_init_platform_variant(core); + if (rc) + return rc; + + rc = msm_vidc_init_vpu(core); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_read_efuse(struct msm_vidc_core *core) +{ + int rc = 0; + void __iomem *base; + u32 i = 0, efuse = 0, efuse_data_count = 0; + struct msm_vidc_efuse_data *efuse_data = NULL; + struct msm_vidc_platform_data *platform_data; + + platform_data = &core->platform->data; + efuse_data = platform_data->efuse_data; + efuse_data_count = platform_data->efuse_data_size; + + if (!efuse_data) + return 0; + + for (i = 0; i < efuse_data_count; i++) { + switch (efuse_data[i].purpose) { + case SKU_VERSION: + base = devm_ioremap(&core->pdev->dev, efuse_data[i].start_address, + efuse_data[i].size); + if (!base) { + d_vpr_e("failed efuse: start %#x, size %d\n", + efuse_data[i].start_address, + efuse_data[i].size); + return -EINVAL; + } + efuse = readl_relaxed(base); + platform_data->sku_version = + (efuse & efuse_data[i].mask) >> + efuse_data[i].shift; + break; + default: + break; + } + if (platform_data->sku_version) { + d_vpr_h("efuse 0x%x, platform version 0x%x\n", + efuse, platform_data->sku_version); + break; + } + } + return rc; +} + +/****************** control framework utility functions **********************/ + +enum msm_vidc_inst_capability_type msm_vidc_get_cap_id(struct msm_vidc_inst *inst, u32 id) +{ + enum msm_vidc_inst_capability_type i = INST_CAP_NONE + 1; + + enum msm_vidc_inst_capability_type cap_id = INST_CAP_NONE; + + do { + if (inst->capabilities[i].v4l2_id == id) { + cap_id = inst->capabilities[i].cap_id; + break; + } + i++; + } while (i < INST_CAP_MAX); + + return cap_id; +} + +int msm_vidc_update_cap_value(struct msm_vidc_inst *inst, u32 cap_id, + s32 adjusted_val, const char *func) +{ + int prev_value = 0; + + prev_value = inst->capabilities[cap_id].value; + + if (is_meta_cap(inst, cap_id)) { + if (adjusted_val & MSM_VIDC_META_ENABLE && + adjusted_val & MSM_VIDC_META_DYN_ENABLE) { + i_vpr_e(inst, + "%s: %s cannot be enabled both statically and dynamically", + __func__, cap_name(cap_id)); + return -EINVAL; + } + /* + * cumulative control value if client set same metadata + * control multiple times. + */ + if (adjusted_val & MSM_VIDC_META_ENABLE || + adjusted_val & MSM_VIDC_META_DYN_ENABLE) { + /* enable metadata */ + inst->capabilities[cap_id].value |= adjusted_val; + } else { + /* disable metadata */ + inst->capabilities[cap_id].value &= ~adjusted_val; + } + } else { + inst->capabilities[cap_id].value = adjusted_val; + } + + if (prev_value != inst->capabilities[cap_id].value) { + i_vpr_h(inst, + "%s: updated database: name: %s, value: %#x -> %#x\n", + func, cap_name(cap_id), + prev_value, inst->capabilities[cap_id].value); + } + + return 0; +} + +bool is_parent_available(struct msm_vidc_inst *inst, + u32 cap_id, u32 check_parent, const char *func) +{ + int i = 0; + u32 cap_child; + + if (!is_valid_cap_id(cap_id) || !is_valid_cap_id(check_parent)) + return false; + + while (i < MAX_CAP_CHILDREN && + inst->capabilities[check_parent].children[i]) { + cap_child = inst->capabilities[check_parent].children[i]; + if (cap_child == cap_id) + return true; + i++; + } + + i_vpr_e(inst, + "%s: missing parent %s for %s\n", + func, cap_name(check_parent), cap_name(cap_id)); + return false; +} + +int msm_vidc_get_parent_value(struct msm_vidc_inst *inst, + u32 cap_id, u32 parent, s32 *value, const char *func) +{ + int rc = 0; + + if (is_parent_available(inst, cap_id, parent, func)) { + switch (parent) { + case BITRATE_MODE: + *value = inst->hfi_rc_type; + break; + case LAYER_TYPE: + *value = inst->hfi_layer_type; + break; + default: + *value = inst->capabilities[parent].value; + break; + } + } else { + rc = -EINVAL; + } + + return rc; +} + +u32 msm_vidc_get_port_info(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id) +{ + if (inst->capabilities[cap_id].flags & CAP_FLAG_INPUT_PORT && + inst->capabilities[cap_id].flags & CAP_FLAG_OUTPUT_PORT) { + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) + return get_hfi_port(inst, INPUT_PORT); + else + return get_hfi_port(inst, OUTPUT_PORT); + } + + if (inst->capabilities[cap_id].flags & CAP_FLAG_INPUT_PORT) + return get_hfi_port(inst, INPUT_PORT); + else if (inst->capabilities[cap_id].flags & CAP_FLAG_OUTPUT_PORT) + return get_hfi_port(inst, OUTPUT_PORT); + else + return HFI_PORT_NONE; +} + +int msm_vidc_v4l2_menu_to_hfi(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id, u32 *value) +{ + switch (cap_id) { + case ENTROPY_MODE: + switch (inst->capabilities[cap_id].value) { + case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC: + *value = 1; + break; + case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC: + *value = 0; + break; + default: + *value = 1; + goto set_default; + } + return 0; + default: + i_vpr_e(inst, + "%s: mapping not specified for ctrl_id: %#x\n", + __func__, inst->capabilities[cap_id].v4l2_id); + return -EINVAL; + } + +set_default: + i_vpr_e(inst, + "%s: invalid value %d for ctrl id: %#x. Set default: %u\n", + __func__, inst->capabilities[cap_id].value, + inst->capabilities[cap_id].v4l2_id, *value); + return 0; +} + +int msm_vidc_v4l2_to_hfi_enum(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id, u32 *value) +{ + switch (cap_id) { + case BITRATE_MODE: + *value = inst->hfi_rc_type; + return 0; + case PROFILE: + case LEVEL: + case HEVC_TIER: + case AV1_TIER: + case BLUR_TYPES: + *value = inst->capabilities[cap_id].value; + return 0; + case LAYER_TYPE: + if (inst->codec == MSM_VIDC_HEVC) { + switch (inst->capabilities[cap_id].value) { + case V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B: + *value = HFI_HIER_B; + break; + case V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P: + //TODO (AS): check if this is right mapping + *value = HFI_HIER_P_SLIDING_WINDOW; + break; + default: + *value = HFI_HIER_P_SLIDING_WINDOW; + goto set_default; + } + } + return 0; + case ROTATION: + switch (inst->capabilities[cap_id].value) { + case 0: + *value = HFI_ROTATION_NONE; + break; + case 90: + *value = HFI_ROTATION_90; + break; + case 180: + *value = HFI_ROTATION_180; + break; + case 270: + *value = HFI_ROTATION_270; + break; + default: + *value = HFI_ROTATION_NONE; + goto set_default; + } + return 0; + case LF_MODE: + if (inst->codec == MSM_VIDC_HEVC) { + switch (inst->capabilities[cap_id].value) { + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED: + *value = HFI_DEBLOCK_ALL_BOUNDARY; + break; + case V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED: + *value = HFI_DEBLOCK_DISABLE; + break; + case DB_HEVC_DISABLE_SLICE_BOUNDARY: + *value = HFI_DEBLOCK_DISABLE_AT_SLICE_BOUNDARY; + break; + default: + *value = HFI_DEBLOCK_ALL_BOUNDARY; + goto set_default; + } + } else if (inst->codec == MSM_VIDC_H264) { + switch (inst->capabilities[cap_id].value) { + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED: + *value = HFI_DEBLOCK_ALL_BOUNDARY; + break; + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED: + *value = HFI_DEBLOCK_DISABLE; + break; + case DB_H264_DISABLE_SLICE_BOUNDARY: + *value = HFI_DEBLOCK_DISABLE_AT_SLICE_BOUNDARY; + break; + default: + *value = HFI_DEBLOCK_ALL_BOUNDARY; + goto set_default; + } + } + return 0; + case NAL_LENGTH_FIELD: + switch (inst->capabilities[cap_id].value) { + case V4L2_MPEG_VIDEO_HEVC_SIZE_4: + *value = HFI_NAL_LENGTH_SIZE_4; + break; + default: + *value = HFI_NAL_LENGTH_STARTCODES; + goto set_default; + } + return 0; + default: + i_vpr_e(inst, + "%s: mapping not specified for ctrl_id: %#x\n", + __func__, inst->capabilities[cap_id].v4l2_id); + return -EINVAL; + } + +set_default: + i_vpr_e(inst, + "%s: invalid value %d for ctrl id: %#x. Set default: %u\n", + __func__, inst->capabilities[cap_id].value, + inst->capabilities[cap_id].v4l2_id, *value); + return 0; +} + +int msm_vidc_packetize_control(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id, u32 payload_type, + void *hfi_val, u32 payload_size, const char *func) +{ + int rc = 0; + u64 payload = 0; + + if (payload_size > sizeof(u32)) { + i_vpr_e(inst, "%s: payload size is more than u32 for cap[%d] %s\n", + func, cap_id, cap_name(cap_id)); + return -EINVAL; + } + + if (payload_size == sizeof(u32)) + payload = *(u32 *)hfi_val; + else if (payload_size == sizeof(u8)) + payload = *(u8 *)hfi_val; + else if (payload_size == sizeof(u16)) + payload = *(u16 *)hfi_val; + + i_vpr_h(inst, FMT_STRING_SET_CAP, + cap_name(cap_id), inst->capabilities[cap_id].value, payload); + + rc = venus_hfi_session_property(inst, + inst->capabilities[cap_id].hfi_id, + HFI_HOST_FLAGS_NONE, + msm_vidc_get_port_info(inst, cap_id), + payload_type, + hfi_val, + payload_size); + if (rc) { + i_vpr_e(inst, "%s: failed to set cap[%d] %s to fw\n", + func, cap_id, cap_name(cap_id)); + return rc; + } + + return 0; +} + +/*************** End of control framework utility functions ******************/ + +/*********************** Control Adjust functions ****************************/ + +int msm_vidc_adjust_entropy_mode(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 profile = -1; + + /* ctrl is always NULL in streamon case */ + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[ENTROPY_MODE].value; + + if (inst->codec != MSM_VIDC_H264) { + i_vpr_e(inst, + "%s: incorrect entry in database. fix the database\n", + __func__); + return 0; + } + + if (msm_vidc_get_parent_value(inst, ENTROPY_MODE, PROFILE, &profile, __func__)) + return -EINVAL; + + if (profile == V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE || + profile == V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) + adjusted_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC; + + msm_vidc_update_cap_value(inst, ENTROPY_MODE, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_bitrate_mode(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + int lossless, frame_rc, bitrate_mode, frame_skip; + u32 hfi_value = 0; + + bitrate_mode = inst->capabilities[BITRATE_MODE].value; + lossless = inst->capabilities[LOSSLESS].value; + frame_rc = inst->capabilities[FRAME_RC_ENABLE].value; + frame_skip = inst->capabilities[FRAME_SKIP_MODE].value; + + if (lossless || + (msm_vidc_lossless_encode && inst->codec == MSM_VIDC_HEVC)) { + hfi_value = HFI_RC_LOSSLESS; + goto update; + } + + if (!frame_rc && !is_image_session(inst)) { + hfi_value = HFI_RC_OFF; + goto update; + } + + if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) { + hfi_value = HFI_RC_VBR_CFR; + } else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) { + if (frame_skip) + hfi_value = HFI_RC_CBR_VFR; + else + hfi_value = HFI_RC_CBR_CFR; + } else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) { + hfi_value = HFI_RC_CQ; + } + +update: + inst->hfi_rc_type = hfi_value; + i_vpr_h(inst, "%s: hfi rc type: %#x\n", + __func__, inst->hfi_rc_type); + + return 0; +} + +int msm_vidc_adjust_profile(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 pix_fmt = -1; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[PROFILE].value; + + /* PIX_FMTS dependency is common across all chipsets. + * Hence, PIX_FMTS must be specified as Parent for HEVC profile. + * Otherwise it would be a database error that should be fixed. + */ + if (msm_vidc_get_parent_value(inst, PROFILE, PIX_FMTS, + &pix_fmt, __func__)) + return -EINVAL; + + /* 10 bit profile for 10 bit color format */ + if (pix_fmt == MSM_VIDC_FMT_TP10C || pix_fmt == MSM_VIDC_FMT_P010) { + if (is_image_session(inst)) + adjusted_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE; + else + adjusted_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10; + } else { + /* 8 bit profile for 8 bit color format */ + if (is_image_session(inst)) + adjusted_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; + else + adjusted_value = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN; + } + + msm_vidc_update_cap_value(inst, PROFILE, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_ltr_count(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1, all_intra = 0, pix_fmts = MSM_VIDC_FMT_NONE; + s32 layer_type = -1, enh_layer_count = -1; + u32 num_ref_frames = 0, max_exceeding_ref_frames = 0; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[LTR_COUNT].value; + + if (msm_vidc_get_parent_value(inst, LTR_COUNT, BITRATE_MODE, + &rc_type, __func__)) + return -EINVAL; + + if ((rc_type != HFI_RC_OFF && + rc_type != HFI_RC_CBR_CFR && + rc_type != HFI_RC_CBR_VFR)) { + adjusted_value = 0; + i_vpr_h(inst, + "%s: ltr count unsupported, rc_type: %#x\n", + __func__, rc_type); + goto exit; + } + + if (is_valid_cap(inst, ALL_INTRA)) { + if (msm_vidc_get_parent_value(inst, LTR_COUNT, + ALL_INTRA, &all_intra, __func__)) + return -EINVAL; + if (all_intra) { + adjusted_value = 0; + goto exit; + } + } + + if (!msm_vidc_get_parent_value(inst, LTR_COUNT, PIX_FMTS, + &pix_fmts, __func__)) { + if (is_10bit_colorformat(pix_fmts)) + adjusted_value = 0; + } + + if (!msm_vidc_get_parent_value(inst, LTR_COUNT, ENH_LAYER_COUNT, + &enh_layer_count, __func__) && + !msm_vidc_get_parent_value(inst, LTR_COUNT, LAYER_TYPE, + &layer_type, __func__)) { + if (layer_type == HFI_HIER_P_SLIDING_WINDOW) { + SLIDING_WINDOW_REF_FRAMES(inst->codec, + inst->capabilities[ENH_LAYER_COUNT].value + 1, + adjusted_value, num_ref_frames); + if (num_ref_frames > MAX_ENCODING_REFERNCE_FRAMES) { + /* + * reduce ltr count to avoid num ref + * frames going beyond limit + */ + max_exceeding_ref_frames = num_ref_frames - + MAX_ENCODING_REFERNCE_FRAMES; + if (adjusted_value >= max_exceeding_ref_frames) + adjusted_value -= max_exceeding_ref_frames; + else + adjusted_value = 0; + } + } + i_vpr_h(inst, + "%s: ltr count %d enh_layers %d layer_type %d\n", + __func__, adjusted_value, + inst->capabilities[ENH_LAYER_COUNT].value, + layer_type); + } + +exit: + msm_vidc_update_cap_value(inst, LTR_COUNT, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_use_ltr(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value, ltr_count; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[USE_LTR].value; + + /* + * Since USE_LTR is only set dynamically, and LTR_COUNT is static + * control, no need to make LTR_COUNT as parent for USE_LTR as + * LTR_COUNT value will always be updated when dynamically USE_LTR + * is set + */ + ltr_count = inst->capabilities[LTR_COUNT].value; + if (!ltr_count) + return 0; + + if (adjusted_value <= 0 || + adjusted_value > ((1 << ltr_count) - 1)) { + /* + * USE_LTR is bitmask value, hence should be + * > 0 and <= (2 ^ LTR_COUNT) - 1 + */ + i_vpr_e(inst, "%s: invalid value %d\n", + __func__, adjusted_value); + return 0; + } + + /* USE_LTR value is a bitmask value */ + msm_vidc_update_cap_value(inst, USE_LTR, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_mark_ltr(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value, ltr_count; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[MARK_LTR].value; + + /* + * Since MARK_LTR is only set dynamically, and LTR_COUNT is static + * control, no need to make LTR_COUNT as parent for MARK_LTR as + * LTR_COUNT value will always be updated when dynamically MARK_LTR + * is set + */ + ltr_count = inst->capabilities[LTR_COUNT].value; + if (!ltr_count) + return 0; + + if (adjusted_value < 0 || + adjusted_value > (ltr_count - 1)) { + /* MARK_LTR value should be >= 0 and <= (LTR_COUNT - 1) */ + i_vpr_e(inst, "%s: invalid value %d\n", + __func__, adjusted_value); + return 0; + } + + msm_vidc_update_cap_value(inst, MARK_LTR, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_delta_based_rc(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[TIME_DELTA_BASED_RC].value; + + if (msm_vidc_get_parent_value(inst, TIME_DELTA_BASED_RC, BITRATE_MODE, &rc_type, __func__)) + return -EINVAL; + + if (rc_type == HFI_RC_OFF || rc_type == HFI_RC_CQ) + adjusted_value = 0; + + msm_vidc_update_cap_value(inst, TIME_DELTA_BASED_RC, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_output_order(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + s32 tn_mode = -1, display_delay = -1, display_delay_enable = -1; + u32 adjusted_value; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[OUTPUT_ORDER].value; + + if (msm_vidc_get_parent_value(inst, OUTPUT_ORDER, DISPLAY_DELAY, + &display_delay, __func__) || + msm_vidc_get_parent_value(inst, OUTPUT_ORDER, DISPLAY_DELAY_ENABLE, + &display_delay_enable, __func__)) + return -EINVAL; + + if (display_delay_enable && !display_delay) + adjusted_value = 1; + + if (is_valid_cap(inst, THUMBNAIL_MODE)) { + if (msm_vidc_get_parent_value(inst, OUTPUT_ORDER, THUMBNAIL_MODE, + &tn_mode, __func__)) + return -EINVAL; + + if (tn_mode == 1) + adjusted_value = 1; + } + + msm_vidc_update_cap_value(inst, OUTPUT_ORDER, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_input_buf_host_max_count(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + u32 adjusted_value; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[INPUT_BUF_HOST_MAX_COUNT].value; + + if (msm_vidc_is_super_buffer(inst) || is_image_session(inst)) + adjusted_value = DEFAULT_MAX_HOST_BURST_BUF_COUNT; + + msm_vidc_update_cap_value(inst, INPUT_BUF_HOST_MAX_COUNT, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_output_buf_host_max_count(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + u32 adjusted_value; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[OUTPUT_BUF_HOST_MAX_COUNT].value; + + if (msm_vidc_is_super_buffer(inst) || is_image_session(inst) || + is_enc_slice_delivery_mode(inst)) + adjusted_value = DEFAULT_MAX_HOST_BURST_BUF_COUNT; + + msm_vidc_update_cap_value(inst, OUTPUT_BUF_HOST_MAX_COUNT, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_transform_8x8(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 profile = -1; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[TRANSFORM_8X8].value; + + if (inst->codec != MSM_VIDC_H264) { + i_vpr_e(inst, + "%s: incorrect entry in database. fix the database\n", + __func__); + return 0; + } + + if (msm_vidc_get_parent_value(inst, TRANSFORM_8X8, + PROFILE, &profile, __func__)) + return -EINVAL; + + if (profile != V4L2_MPEG_VIDEO_H264_PROFILE_HIGH && + profile != V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) + adjusted_value = 0; + + msm_vidc_update_cap_value(inst, TRANSFORM_8X8, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_chroma_qp_index_offset(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[CHROMA_QP_INDEX_OFFSET].value; + + if (adjusted_value != MIN_CHROMA_QP_OFFSET) + adjusted_value = MAX_CHROMA_QP_OFFSET; + + msm_vidc_update_cap_value(inst, CHROMA_QP_INDEX_OFFSET, adjusted_value, __func__); + + return 0; +} + +static bool msm_vidc_check_all_layer_bitrate_set(struct msm_vidc_inst *inst) +{ + bool layer_bitrate_set = true; + u32 cap_id = 0, i, enh_layer_count; + u32 layer_br_caps[6] = {L0_BR, L1_BR, L2_BR, L3_BR, L4_BR, L5_BR}; + + enh_layer_count = inst->capabilities[ENH_LAYER_COUNT].value; + + for (i = 0; i <= enh_layer_count; i++) { + if (i >= ARRAY_SIZE(layer_br_caps)) + break; + cap_id = layer_br_caps[i]; + if (!(inst->capabilities[cap_id].flags & CAP_FLAG_CLIENT_SET)) { + layer_bitrate_set = false; + break; + } + } + + return layer_bitrate_set; +} + +static u32 msm_vidc_get_cumulative_bitrate(struct msm_vidc_inst *inst) +{ + int i; + u32 cap_id = 0; + u32 cumulative_br = 0; + s32 enh_layer_count; + u32 layer_br_caps[6] = {L0_BR, L1_BR, L2_BR, L3_BR, L4_BR, L5_BR}; + + enh_layer_count = inst->capabilities[ENH_LAYER_COUNT].value; + + for (i = 0; i <= enh_layer_count; i++) { + if (i >= ARRAY_SIZE(layer_br_caps)) + break; + cap_id = layer_br_caps[i]; + cumulative_br += inst->capabilities[cap_id].value; + } + + return cumulative_br; +} + +int msm_vidc_adjust_slice_count(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + struct v4l2_format *output_fmt; + s32 adjusted_value, rc_type = -1, slice_mode, all_intra = 0, + enh_layer_count = 0; + u32 slice_val, mbpf = 0, mbps = 0, max_mbpf = 0, max_mbps = 0, bitrate = 0; + u32 update_cap, max_avg_slicesize, output_width, output_height; + u32 min_width, min_height, max_width, max_height, fps; + + slice_mode = ctrl ? ctrl->val : + inst->capabilities[SLICE_MODE].value; + + if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) + return 0; + + bitrate = inst->capabilities[BIT_RATE].value; + + if (msm_vidc_get_parent_value(inst, SLICE_MODE, + BITRATE_MODE, &rc_type, __func__) || + msm_vidc_get_parent_value(inst, SLICE_MODE, + ENH_LAYER_COUNT, &enh_layer_count, __func__)) + return -EINVAL; + + if (enh_layer_count && msm_vidc_check_all_layer_bitrate_set(inst)) + bitrate = msm_vidc_get_cumulative_bitrate(inst); + + fps = inst->capabilities[FRAME_RATE].value >> 16; + if (fps > MAX_SLICES_FRAME_RATE || + (rc_type != HFI_RC_OFF && rc_type != HFI_RC_CBR_CFR && + rc_type != HFI_RC_CBR_VFR && rc_type != HFI_RC_VBR_CFR)) { + adjusted_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE; + update_cap = SLICE_MODE; + i_vpr_h(inst, + "%s: slice unsupported, fps: %u, rc_type: %#x\n", + __func__, fps, rc_type); + goto exit; + } + + if (is_valid_cap(inst, ALL_INTRA)) { + if (msm_vidc_get_parent_value(inst, SLICE_MODE, + ALL_INTRA, &all_intra, __func__)) + return -EINVAL; + + if (all_intra == 1) { + adjusted_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE; + update_cap = SLICE_MODE; + i_vpr_h(inst, "%s: slice unsupported, all_intra %d\n", __func__, all_intra); + goto exit; + } + } + + output_fmt = &inst->fmts[OUTPUT_PORT]; + output_width = output_fmt->fmt.pix_mp.width; + output_height = output_fmt->fmt.pix_mp.height; + + max_width = (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) ? + MAX_MB_SLICE_WIDTH : MAX_BYTES_SLICE_WIDTH; + max_height = (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) ? + MAX_MB_SLICE_HEIGHT : MAX_BYTES_SLICE_HEIGHT; + min_width = (inst->codec == MSM_VIDC_HEVC) ? + MIN_HEVC_SLICE_WIDTH : MIN_AVC_SLICE_WIDTH; + min_height = MIN_SLICE_HEIGHT; + + /* + * For V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB: + * - width >= 384 and height >= 128 + * - width and height <= 4096 + * For V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES: + * - width >= 192 and height >= 128 + * - width and height <= 1920 + */ + if (output_width < min_width || output_height < min_height || + output_width > max_width || output_height > max_width) { + adjusted_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE; + update_cap = SLICE_MODE; + i_vpr_h(inst, + "%s: slice unsupported, codec: %#x wxh: [%dx%d]\n", + __func__, inst->codec, output_width, output_height); + goto exit; + } + + mbpf = NUM_MBS_PER_FRAME(output_height, output_width); + mbps = NUM_MBS_PER_SEC(output_height, output_width, fps); + max_mbpf = NUM_MBS_PER_FRAME(max_height, max_width); + max_mbps = NUM_MBS_PER_SEC(max_height, max_width, MAX_SLICES_FRAME_RATE); + + if (mbpf > max_mbpf || mbps > max_mbps) { + adjusted_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE; + update_cap = SLICE_MODE; + i_vpr_h(inst, + "%s: Unsupported, mbpf[%u] > max[%u], mbps[%u] > max[%u]\n", + __func__, mbpf, max_mbpf, mbps, max_mbps); + goto exit; + } + + if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { + update_cap = SLICE_MAX_MB; + slice_val = inst->capabilities[SLICE_MAX_MB].value; + slice_val = max(slice_val, mbpf / MAX_SLICES_PER_FRAME); + } else { + slice_val = inst->capabilities[SLICE_MAX_BYTES].value; + update_cap = SLICE_MAX_BYTES; + if (rc_type != HFI_RC_OFF) { + max_avg_slicesize = ((bitrate / fps) / 8) / + MAX_SLICES_PER_FRAME; + slice_val = max(slice_val, max_avg_slicesize); + } + } + adjusted_value = slice_val; + +exit: + msm_vidc_update_cap_value(inst, update_cap, adjusted_value, __func__); + + return 0; +} + +static int msm_vidc_adjust_static_layer_count_and_type(struct msm_vidc_inst *inst, s32 layer_count) +{ + bool hb_requested = false; + + if (!layer_count) { + i_vpr_h(inst, "client not enabled layer encoding\n"); + goto exit; + } + + if (inst->hfi_rc_type == HFI_RC_CQ) { + i_vpr_h(inst, "rc type is CQ, disabling layer encoding\n"); + layer_count = 0; + goto exit; + } + + if (inst->codec == MSM_VIDC_H264) { + if (!inst->capabilities[LAYER_ENABLE].value) { + layer_count = 0; + goto exit; + } + + hb_requested = (inst->capabilities[LAYER_TYPE].value == + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) ? + true : false; + } else if (inst->codec == MSM_VIDC_HEVC) { + hb_requested = (inst->capabilities[LAYER_TYPE].value == + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) ? + true : false; + } + + if (hb_requested && inst->hfi_rc_type != HFI_RC_VBR_CFR) { + i_vpr_h(inst, + "%s: HB layer encoding is supported for VBR rc only\n", + __func__); + layer_count = 0; + goto exit; + } + + /* decide hfi layer type */ + if (hb_requested) { + inst->hfi_layer_type = HFI_HIER_B; + } else { + /* HP requested */ + inst->hfi_layer_type = HFI_HIER_P_SLIDING_WINDOW; + if (inst->codec == MSM_VIDC_H264 && + inst->hfi_rc_type == HFI_RC_VBR_CFR) + inst->hfi_layer_type = HFI_HIER_P_HYBRID_LTR; + } + + /* sanitize layer count based on layer type and codec, and rc type */ + if (inst->hfi_layer_type == HFI_HIER_B) { + if (layer_count > MAX_ENH_LAYER_HB) + layer_count = MAX_ENH_LAYER_HB; + } else if (inst->hfi_layer_type == HFI_HIER_P_HYBRID_LTR) { + if (layer_count > MAX_AVC_ENH_LAYER_HYBRID_HP) + layer_count = MAX_AVC_ENH_LAYER_HYBRID_HP; + } else if (inst->hfi_layer_type == HFI_HIER_P_SLIDING_WINDOW) { + if (inst->codec == MSM_VIDC_H264) { + if (layer_count > MAX_AVC_ENH_LAYER_SLIDING_WINDOW) + layer_count = MAX_AVC_ENH_LAYER_SLIDING_WINDOW; + } else if (inst->codec == MSM_VIDC_HEVC) { + if (inst->hfi_rc_type == HFI_RC_VBR_CFR) { + if (layer_count > MAX_HEVC_VBR_ENH_LAYER_SLIDING_WINDOW) + layer_count = MAX_HEVC_VBR_ENH_LAYER_SLIDING_WINDOW; + } else { + if (layer_count > MAX_HEVC_NON_VBR_ENH_LAYER_SLIDING_WINDOW) + layer_count = MAX_HEVC_NON_VBR_ENH_LAYER_SLIDING_WINDOW; + } + } + } + +exit: + msm_vidc_update_cap_value(inst, ENH_LAYER_COUNT, layer_count, __func__); + inst->capabilities[ENH_LAYER_COUNT].max = layer_count; + return 0; +} + +int msm_vidc_adjust_layer_count(void *instance, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + + s32 client_layer_count; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + client_layer_count = ctrl ? ctrl->val : + inst->capabilities[ENH_LAYER_COUNT].value; + + if (!is_parent_available(inst, ENH_LAYER_COUNT, + BITRATE_MODE, __func__)) + return -EINVAL; + + if (!inst->bufq[OUTPUT_PORT].vb2q->streaming) { + rc = msm_vidc_adjust_static_layer_count_and_type(inst, client_layer_count); + if (rc) + goto exit; + } else { + if (inst->hfi_rc_type == HFI_RC_CBR_CFR || + inst->hfi_rc_type == HFI_RC_CBR_VFR) { + i_vpr_h(inst, + "%s: ignoring dynamic layer count change for CBR mode\n", + __func__); + goto exit; + } + + if (inst->hfi_layer_type == HFI_HIER_P_HYBRID_LTR || + inst->hfi_layer_type == HFI_HIER_P_SLIDING_WINDOW) { + /* dynamic layer count change is only supported for HP */ + if (client_layer_count > + inst->capabilities[ENH_LAYER_COUNT].max) + client_layer_count = + inst->capabilities[ENH_LAYER_COUNT].max; + + msm_vidc_update_cap_value(inst, ENH_LAYER_COUNT, + client_layer_count, __func__); + } + } + +exit: + return rc; +} + +int msm_vidc_adjust_gop_size(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 adjusted_value, enh_layer_count = -1; + u32 min_gop_size, num_subgops; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[GOP_SIZE].value; + + if (msm_vidc_get_parent_value(inst, GOP_SIZE, + ENH_LAYER_COUNT, &enh_layer_count, __func__)) + return -EINVAL; + + if (!enh_layer_count) + goto exit; + + /* + * Layer encoding needs GOP size to be multiple of subgop size + * And subgop size is 2 ^ number of enhancement layers. + */ + + /* v4l2 layer count is the number of enhancement layers */ + min_gop_size = 1 << enh_layer_count; + num_subgops = (adjusted_value + (min_gop_size >> 1)) / + min_gop_size; + if (num_subgops) + adjusted_value = num_subgops * min_gop_size; + else + adjusted_value = min_gop_size; + +exit: + msm_vidc_update_cap_value(inst, GOP_SIZE, adjusted_value, __func__); + return 0; +} + +int msm_vidc_adjust_b_frame(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 adjusted_value, enh_layer_count = -1; + const u32 max_bframe_size = 7; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[B_FRAME].value; + + if (msm_vidc_get_parent_value(inst, B_FRAME, + ENH_LAYER_COUNT, &enh_layer_count, __func__)) + return -EINVAL; + + if (!enh_layer_count || inst->hfi_layer_type != HFI_HIER_B) { + adjusted_value = 0; + goto exit; + } + + adjusted_value = (1 << enh_layer_count) - 1; + /* Allowed Bframe values are 0, 1, 3, 7 */ + if (adjusted_value > max_bframe_size) + adjusted_value = max_bframe_size; + +exit: + msm_vidc_update_cap_value(inst, B_FRAME, adjusted_value, __func__); + return 0; +} + +int msm_vidc_adjust_bitrate(void *instance, struct v4l2_ctrl *ctrl) +{ + int i, rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + s32 adjusted_value, enh_layer_count; + u32 cumulative_bitrate = 0, cap_id = 0, cap_value = 0; + u32 layer_br_caps[6] = {L0_BR, L1_BR, L2_BR, L3_BR, L4_BR, L5_BR}; + u32 max_bitrate = 0; + + /* ignore layer bitrate when total bitrate is set */ + if (inst->capabilities[BIT_RATE].flags & CAP_FLAG_CLIENT_SET) { + /* + * For static case, ctrl is null. + * For dynamic case, only BIT_RATE cap uses this adjust function. + * Hence, no need to check for ctrl id to be BIT_RATE control, and not + * any of layer bitrate controls. + */ + adjusted_value = ctrl ? ctrl->val : inst->capabilities[BIT_RATE].value; + msm_vidc_update_cap_value(inst, BIT_RATE, adjusted_value, __func__); + + return 0; + } + + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) + return 0; + + if (msm_vidc_get_parent_value(inst, BIT_RATE, + ENH_LAYER_COUNT, &enh_layer_count, __func__)) + return -EINVAL; + + /* get max bit rate for current session config*/ + max_bitrate = msm_vidc_get_max_bitrate(inst); + if (inst->capabilities[BIT_RATE].value > max_bitrate) + msm_vidc_update_cap_value(inst, BIT_RATE, max_bitrate, __func__); + + /* + * ENH_LAYER_COUNT cap max is positive only if + * layer encoding is enabled during streamon. + */ + if (inst->capabilities[ENH_LAYER_COUNT].max) { + if (!msm_vidc_check_all_layer_bitrate_set(inst)) { + i_vpr_h(inst, + "%s: client did not set all layer bitrates\n", + __func__); + return 0; + } + + cumulative_bitrate = msm_vidc_get_cumulative_bitrate(inst); + + /* cap layer bitrates to max supported bitrate */ + if (cumulative_bitrate > max_bitrate) { + u32 decrement_in_value = 0; + u32 decrement_in_percent = ((cumulative_bitrate - max_bitrate) * 100) / + max_bitrate; + + cumulative_bitrate = 0; + for (i = 0; i <= enh_layer_count; i++) { + if (i >= ARRAY_SIZE(layer_br_caps)) + break; + cap_id = layer_br_caps[i]; + cap_value = inst->capabilities[cap_id].value; + + decrement_in_value = (cap_value * + decrement_in_percent) / 100; + cumulative_bitrate += (cap_value - decrement_in_value); + + /* + * cap value for the L*_BR is changed. Hence, update cap, + * and add to FW_LIST to set new values to firmware. + */ + msm_vidc_update_cap_value(inst, cap_id, + (cap_value - decrement_in_value), + __func__); + } + } + + i_vpr_h(inst, + "%s: update BIT_RATE with cumulative bitrate\n", + __func__); + msm_vidc_update_cap_value(inst, BIT_RATE, cumulative_bitrate, __func__); + } + + return rc; +} + +int msm_vidc_adjust_layer_bitrate(void *instance, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + u32 cumulative_bitrate = 0; + u32 client_set_cap_id = INST_CAP_NONE; + u32 old_br = 0, new_br = 0, exceeded_br = 0; + s32 max_bitrate; + + if (!ctrl) + return 0; + + /* ignore layer bitrate when total bitrate is set */ + if (inst->capabilities[BIT_RATE].flags & CAP_FLAG_CLIENT_SET) + return 0; + + /* + * This is no-op function because layer bitrates were already adjusted + * in msm_vidc_adjust_bitrate function + */ + if (!inst->bufq[OUTPUT_PORT].vb2q->streaming) + return 0; + + /* + * ENH_LAYER_COUNT cap max is positive only if + * layer encoding is enabled during streamon. + */ + if (!inst->capabilities[ENH_LAYER_COUNT].max) { + i_vpr_e(inst, "%s: layers not enabled\n", __func__); + return -EINVAL; + } + + if (!msm_vidc_check_all_layer_bitrate_set(inst)) { + i_vpr_h(inst, + "%s: client did not set all layer bitrates\n", + __func__); + return 0; + } + + client_set_cap_id = msm_vidc_get_cap_id(inst, ctrl->id); + if (client_set_cap_id == INST_CAP_NONE) { + i_vpr_e(inst, "%s: could not find cap_id for ctrl %s\n", + __func__, ctrl->name); + return -EINVAL; + } + + cumulative_bitrate = msm_vidc_get_cumulative_bitrate(inst); + max_bitrate = inst->capabilities[BIT_RATE].max; + old_br = inst->capabilities[client_set_cap_id].value; + new_br = ctrl->val; + + /* + * new bitrate is not supposed to cause cumulative bitrate to + * exceed max supported bitrate + */ + + if ((cumulative_bitrate - old_br + new_br) > max_bitrate) { + /* adjust new bitrate */ + exceeded_br = (cumulative_bitrate - old_br + new_br) - max_bitrate; + new_br = ctrl->val - exceeded_br; + } + msm_vidc_update_cap_value(inst, client_set_cap_id, new_br, __func__); + + /* adjust totol bitrate cap */ + i_vpr_h(inst, + "%s: update BIT_RATE with cumulative bitrate\n", + __func__); + msm_vidc_update_cap_value(inst, BIT_RATE, + msm_vidc_get_cumulative_bitrate(inst), __func__); + + return rc; +} + +int msm_vidc_adjust_peak_bitrate(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1, bitrate = -1; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[PEAK_BITRATE].value; + + if (msm_vidc_get_parent_value(inst, PEAK_BITRATE, + BITRATE_MODE, &rc_type, __func__)) + return -EINVAL; + + if (rc_type != HFI_RC_CBR_CFR && + rc_type != HFI_RC_CBR_VFR) + return 0; + + if (msm_vidc_get_parent_value(inst, PEAK_BITRATE, + BIT_RATE, &bitrate, __func__)) + return -EINVAL; + + /* Peak Bitrate should be larger than or equal to avg bitrate */ + if (inst->capabilities[PEAK_BITRATE].flags & CAP_FLAG_CLIENT_SET) { + if (adjusted_value < bitrate) + adjusted_value = bitrate; + } else { + adjusted_value = inst->capabilities[BIT_RATE].value; + } + + msm_vidc_update_cap_value(inst, PEAK_BITRATE, + adjusted_value, __func__); + + return 0; +} + +static int msm_vidc_adjust_hevc_qp(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id) +{ + s32 pix_fmt = -1; + + if (!(inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC)) { + i_vpr_e(inst, + "%s: incorrect cap[%d] %s entry in database, fix database\n", + __func__, cap_id, cap_name(cap_id)); + return -EINVAL; + } + + if (msm_vidc_get_parent_value(inst, cap_id, + PIX_FMTS, &pix_fmt, __func__)) + return -EINVAL; + + if (pix_fmt == MSM_VIDC_FMT_P010 || pix_fmt == MSM_VIDC_FMT_TP10C) + goto exit; + + CAP_TO_8BIT_QP(inst->capabilities[cap_id].value); + if (cap_id == MIN_FRAME_QP) { + CAP_TO_8BIT_QP(inst->capabilities[I_FRAME_MIN_QP].value); + CAP_TO_8BIT_QP(inst->capabilities[P_FRAME_MIN_QP].value); + CAP_TO_8BIT_QP(inst->capabilities[B_FRAME_MIN_QP].value); + } else if (cap_id == MAX_FRAME_QP) { + CAP_TO_8BIT_QP(inst->capabilities[I_FRAME_MAX_QP].value); + CAP_TO_8BIT_QP(inst->capabilities[P_FRAME_MAX_QP].value); + CAP_TO_8BIT_QP(inst->capabilities[B_FRAME_MAX_QP].value); + } + +exit: + return 0; +} + +int msm_vidc_adjust_hevc_min_qp(void *instance, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + if (ctrl) + msm_vidc_update_cap_value(inst, MIN_FRAME_QP, + ctrl->val, __func__); + + rc = msm_vidc_adjust_hevc_qp(inst, MIN_FRAME_QP); + + return rc; +} + +int msm_vidc_adjust_hevc_max_qp(void *instance, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + if (ctrl) + msm_vidc_update_cap_value(inst, MAX_FRAME_QP, ctrl->val, __func__); + + rc = msm_vidc_adjust_hevc_qp(inst, MAX_FRAME_QP); + + return rc; +} + +int msm_vidc_adjust_hevc_i_frame_qp(void *instance, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + if (ctrl) + msm_vidc_update_cap_value(inst, I_FRAME_QP, ctrl->val, __func__); + + rc = msm_vidc_adjust_hevc_qp(inst, I_FRAME_QP); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_adjust_hevc_p_frame_qp(void *instance, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + if (ctrl) + msm_vidc_update_cap_value(inst, P_FRAME_QP, ctrl->val, __func__); + + rc = msm_vidc_adjust_hevc_qp(inst, P_FRAME_QP); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_adjust_hevc_b_frame_qp(void *instance, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + if (ctrl) + msm_vidc_update_cap_value(inst, B_FRAME_QP, ctrl->val, __func__); + + rc = msm_vidc_adjust_hevc_qp(inst, B_FRAME_QP); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_adjust_blur_type(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1, roi_enable = -1; + s32 pix_fmts = -1, min_quality = -1; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[BLUR_TYPES].value; + + if (adjusted_value == MSM_VIDC_BLUR_NONE) + return 0; + + if (msm_vidc_get_parent_value(inst, BLUR_TYPES, BITRATE_MODE, + &rc_type, __func__) || + msm_vidc_get_parent_value(inst, BLUR_TYPES, MIN_QUALITY, + &min_quality, __func__)) + return -EINVAL; + + if (adjusted_value == MSM_VIDC_BLUR_EXTERNAL) { + if (is_scaling_enabled(inst) || min_quality) + adjusted_value = MSM_VIDC_BLUR_NONE; + } else if (adjusted_value == MSM_VIDC_BLUR_ADAPTIVE) { + if (is_valid_cap(inst, META_ROI_INFO)) { + if (msm_vidc_get_parent_value(inst, BLUR_TYPES, + META_ROI_INFO, &roi_enable, __func__)) + return -EINVAL; + if (is_meta_tx_inp_enabled(inst, META_ROI_INFO)) { + adjusted_value = MSM_VIDC_BLUR_NONE; + goto exit; + } + } + + if (is_scaling_enabled(inst) || min_quality || + (rc_type != HFI_RC_VBR_CFR && + rc_type != HFI_RC_CBR_CFR && + rc_type != HFI_RC_CBR_VFR)) { + adjusted_value = MSM_VIDC_BLUR_NONE; + goto exit; + } + + if (inst->codec == MSM_VIDC_HEVC) { + if (msm_vidc_get_parent_value(inst, BLUR_TYPES, PIX_FMTS, + &pix_fmts, __func__)) + return -EINVAL; + if (is_10bit_colorformat(pix_fmts)) + adjusted_value = MSM_VIDC_BLUR_NONE; + } + } + +exit: + msm_vidc_update_cap_value(inst, BLUR_TYPES, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_all_intra(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_core *core; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 gop_size = -1, bframe = -1; + u32 width, height, fps, mbps, max_mbps; + + adjusted_value = inst->capabilities[ALL_INTRA].value; + + if (msm_vidc_get_parent_value(inst, ALL_INTRA, GOP_SIZE, + &gop_size, __func__) || + msm_vidc_get_parent_value(inst, ALL_INTRA, B_FRAME, + &bframe, __func__)) + return -EINVAL; + + width = inst->crop.width; + height = inst->crop.height; + fps = msm_vidc_get_fps(inst); + mbps = NUM_MBS_PER_SEC(height, width, fps); + core = inst->core; + max_mbps = core->capabilities[MAX_MBPS_ALL_INTRA].value; + + if (mbps > max_mbps) { + adjusted_value = 0; + i_vpr_h(inst, "%s: mbps %d exceeds max supported mbps %d\n", + __func__, mbps, max_mbps); + goto exit; + } + + if (!gop_size && !bframe) + adjusted_value = 1; + +exit: + msm_vidc_update_cap_value(inst, ALL_INTRA, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_blur_resolution(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 blur_type = -1; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[BLUR_RESOLUTION].value; + + if (msm_vidc_get_parent_value(inst, BLUR_RESOLUTION, BLUR_TYPES, + &blur_type, __func__)) + return -EINVAL; + + if (blur_type != MSM_VIDC_BLUR_EXTERNAL) + return 0; + + msm_vidc_update_cap_value(inst, BLUR_RESOLUTION, + adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_brs(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1, layer_enabled = -1, layer_type = -1; + bool hp_requested = false; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[CONTENT_ADAPTIVE_CODING].value; + + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) + return 0; + + if (msm_vidc_get_parent_value(inst, CONTENT_ADAPTIVE_CODING, + BITRATE_MODE, &rc_type, __func__) || + msm_vidc_get_parent_value(inst, CONTENT_ADAPTIVE_CODING, + LAYER_ENABLE, &layer_enabled, __func__) || + msm_vidc_get_parent_value(inst, CONTENT_ADAPTIVE_CODING, + LAYER_TYPE, &layer_type, __func__)) + return -EINVAL; + + /* + * -BRS is supported only for VBR rc type. + * Hence, do not adjust or set to firmware for non VBR rc's + * -If HP is enabled then BRS is not allowed. + */ + if (rc_type != HFI_RC_VBR_CFR) { + adjusted_value = 0; + goto adjust; + } + + if (inst->codec == MSM_VIDC_H264) + layer_type = V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P; + else if (inst->codec == MSM_VIDC_HEVC) + layer_type = V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P; + + hp_requested = (inst->capabilities[LAYER_TYPE].value == layer_type); + + /* + * Disable BRS in case of HP encoding + * Hence set adjust value to 0. + */ + if (layer_enabled == 1 && hp_requested) { + adjusted_value = 0; + goto adjust; + } + +adjust: + msm_vidc_update_cap_value(inst, CONTENT_ADAPTIVE_CODING, + adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_bitrate_boost(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 min_quality = -1, rc_type = -1; + u32 max_bitrate = 0, bitrate = 0; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[BITRATE_BOOST].value; + + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) + return 0; + + if (msm_vidc_get_parent_value(inst, BITRATE_BOOST, + MIN_QUALITY, &min_quality, __func__) || + msm_vidc_get_parent_value(inst, BITRATE_BOOST, + BITRATE_MODE, &rc_type, __func__)) + return -EINVAL; + + /* + * Bitrate Boost are supported only for VBR rc type. + * Hence, do not adjust or set to firmware for non VBR rc's + */ + if (rc_type != HFI_RC_VBR_CFR) { + adjusted_value = 0; + goto adjust; + } + + if (min_quality) { + adjusted_value = MAX_BITRATE_BOOST; + goto adjust; + } + + max_bitrate = msm_vidc_get_max_bitrate(inst); + bitrate = inst->capabilities[BIT_RATE].value; + if (adjusted_value) { + if ((bitrate + bitrate / (100 / adjusted_value)) > max_bitrate) { + i_vpr_h(inst, + "%s: bitrate %d is beyond max bitrate %d, remove bitrate boost\n", + __func__, max_bitrate, bitrate); + adjusted_value = 0; + } + } + +adjust: + msm_vidc_update_cap_value(inst, BITRATE_BOOST, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_min_quality(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 roi_enable = -1, rc_type = -1, enh_layer_count = -1, pix_fmts = -1; + u32 width, height, frame_rate; + struct v4l2_format *f; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[MIN_QUALITY].value; + + /* + * Although MIN_QUALITY is static, one of its parents, + * ENH_LAYER_COUNT is dynamic cap. Hence, dynamic call + * may be made for MIN_QUALITY via ENH_LAYER_COUNT. + * Therefore, below streaming check is required to avoid + * runtime modification of MIN_QUALITY. + */ + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) + return 0; + + if (msm_vidc_get_parent_value(inst, MIN_QUALITY, + BITRATE_MODE, &rc_type, __func__) || + msm_vidc_get_parent_value(inst, MIN_QUALITY, + ENH_LAYER_COUNT, &enh_layer_count, __func__)) + return -EINVAL; + + /* + * Min Quality is supported only for VBR rc type. + * Hence, do not adjust or set to firmware for non VBR rc's + */ + if (rc_type != HFI_RC_VBR_CFR) { + adjusted_value = 0; + goto update_and_exit; + } + + frame_rate = inst->capabilities[FRAME_RATE].value >> 16; + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + /* + * VBR Min Quality not supported for: + * - HEVC 10bit + * - ROI support + * - HP encoding + * - External Blur + * - Resolution beyond 1080P + * (It will fall back to CQCAC 25% or 0% (CAC) or CQCAC-OFF) + */ + if (inst->codec == MSM_VIDC_HEVC) { + if (msm_vidc_get_parent_value(inst, MIN_QUALITY, + PIX_FMTS, &pix_fmts, __func__)) + return -EINVAL; + + if (is_10bit_colorformat(pix_fmts)) { + i_vpr_h(inst, + "%s: min quality is supported only for 8 bit\n", + __func__); + adjusted_value = 0; + goto update_and_exit; + } + } + + if (res_is_greater_than(width, height, 1920, 1080)) { + i_vpr_h(inst, "%s: unsupported res, wxh %ux%u\n", + __func__, width, height); + adjusted_value = 0; + goto update_and_exit; + } + + if (frame_rate > 60) { + i_vpr_h(inst, "%s: unsupported fps %u\n", + __func__, frame_rate); + adjusted_value = 0; + goto update_and_exit; + } + + if (is_valid_cap(inst, META_ROI_INFO)) { + if (msm_vidc_get_parent_value(inst, MIN_QUALITY, + META_ROI_INFO, &roi_enable, __func__)) + return -EINVAL; + if (is_meta_tx_inp_enabled(inst, META_ROI_INFO)) { + i_vpr_h(inst, + "%s: min quality not supported with roi metadata\n", + __func__); + adjusted_value = 0; + goto update_and_exit; + } + } + + if (enh_layer_count > 0 && inst->hfi_layer_type != HFI_HIER_B) { + i_vpr_h(inst, + "%s: min quality not supported for HP encoding\n", + __func__); + adjusted_value = 0; + goto update_and_exit; + } + + /* Above conditions are met. Hence enable min quality */ + adjusted_value = MAX_SUPPORTED_MIN_QUALITY; + +update_and_exit: + msm_vidc_update_cap_value(inst, MIN_QUALITY, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_preprocess(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 brs = 0; + u32 width, height, frame_rate, operating_rate, max_fps; + struct v4l2_format *f; + + adjusted_value = inst->capabilities[REQUEST_PREPROCESS].value; + + width = inst->crop.width; + height = inst->crop.height; + frame_rate = msm_vidc_get_frame_rate(inst); + operating_rate = msm_vidc_get_operating_rate(inst); + + max_fps = max(frame_rate, operating_rate); + f = &inst->fmts[OUTPUT_PORT]; + + /* + * enable preprocess if + * BRS enabled and upto 4k @ 60 fps + */ + if (is_valid_cap(inst, CONTENT_ADAPTIVE_CODING)) { + if (msm_vidc_get_parent_value(inst, + REQUEST_PREPROCESS, + CONTENT_ADAPTIVE_CODING, + &brs, __func__)) + return -EINVAL; + if (brs == 0) { + /* preprocess not required as BRS not enabled */ + adjusted_value = 0; + goto update_preprocess; + } + } else { + /* preprocess not required as BRS not available */ + adjusted_value = 0; + goto update_preprocess; + } + + if (res_is_less_than_or_equal_to(width, height, 3840, 2160) && + max_fps <= 60) + adjusted_value = 1; + else + adjusted_value = 0; + +update_preprocess: + msm_vidc_update_cap_value(inst, REQUEST_PREPROCESS, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_enc_lowlatency_mode(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[LOWLATENCY_MODE].value; + + if (msm_vidc_get_parent_value(inst, LOWLATENCY_MODE, BITRATE_MODE, + &rc_type, __func__)) + return -EINVAL; + + if (rc_type == HFI_RC_CBR_CFR || + rc_type == HFI_RC_CBR_VFR || + is_enc_slice_delivery_mode(inst)) + adjusted_value = 1; + + msm_vidc_update_cap_value(inst, LOWLATENCY_MODE, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_dec_lowlatency_mode(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 outbuf_fence = MSM_VIDC_META_DISABLE; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[LOWLATENCY_MODE].value; + + if (is_valid_cap(inst, META_OUTBUF_FENCE)) { + if (msm_vidc_get_parent_value(inst, LOWLATENCY_MODE, META_OUTBUF_FENCE, + &outbuf_fence, __func__)) + return -EINVAL; + /* enable lowlatency if outbuf fence is enabled */ + if (outbuf_fence & MSM_VIDC_META_ENABLE && + outbuf_fence & MSM_VIDC_META_RX_INPUT) + adjusted_value = 1; + } + + msm_vidc_update_cap_value(inst, LOWLATENCY_MODE, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_session_priority(void *instance, struct v4l2_ctrl *ctrl) +{ + int adjusted_value; + + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + /* + * Priority handling + * Client will set 0 (realtime), (1 to 4) (non-realtime) + * When driver setting priority to firmware, driver adds + * FIRMWARE_PRIORITY_OFFSET (1) for all sessions except + * non-critical sessions. So finally firmware priority values ranges + * from 0 (Critical session), 1 (realtime session), + * (2 to 5) (non-realtime session). + * Driver may move decode realtime sessions to non-realtime by + * increasing priority by 1 to RT sessions in HW overloaded cases. + * Following will be priority based on requirement - + * ___________________________________________________________ + * | Description | HAL Value |Driver value|FW Value| + * |_________________|__________________|____________|________| + * |Critical Priority| Vendor Extension | Via control| 0 | + * | RT | 0 | 0 | 1 | + * | NRT | -1 to -4 | 1-4 | 2-5 | + * |_________________|__________________|____________|________| + */ + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[PRIORITY].value; + + msm_vidc_update_cap_value(inst, PRIORITY, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_roi_info(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1, pix_fmt = -1; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[META_ROI_INFO].value; + + if (msm_vidc_get_parent_value(inst, META_ROI_INFO, BITRATE_MODE, + &rc_type, __func__)) + return -EINVAL; + + if (msm_vidc_get_parent_value(inst, META_ROI_INFO, PIX_FMTS, + &pix_fmt, __func__)) + return -EINVAL; + + if ((rc_type != HFI_RC_VBR_CFR && rc_type != HFI_RC_CBR_CFR && + rc_type != HFI_RC_CBR_VFR) || !is_8bit_colorformat(pix_fmt) || + is_scaling_enabled(inst) || is_rotation_90_or_270(inst)) + adjusted_value = 0; + + msm_vidc_update_cap_value(inst, META_ROI_INFO, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_dec_outbuf_fence_type(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst_cap *capability; + s32 adjusted_value, meta_outbuf_fence = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + struct msm_vidc_core *core; + + capability = inst->capabilities; + core = inst->core; + + adjusted_value = ctrl ? ctrl->val : + capability[OUTBUF_FENCE_TYPE].value; + + if (msm_vidc_get_parent_value(inst, OUTBUF_FENCE_TYPE, + META_OUTBUF_FENCE, &meta_outbuf_fence, __func__)) + return -EINVAL; + + if (is_meta_rx_inp_enabled(inst, META_OUTBUF_FENCE)) { + if (core->capabilities[SUPPORTS_SYNX_FENCE].value) + adjusted_value = MSM_VIDC_SYNX_V2_FENCE; + else + adjusted_value = MSM_VIDC_SW_FENCE; + } else { + adjusted_value = MSM_VIDC_FENCE_NONE; + } + + msm_vidc_update_cap_value(inst, OUTBUF_FENCE_TYPE, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_dec_outbuf_fence_direction(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst_cap *capability; + s32 adjusted_value, meta_outbuf_fence = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + struct msm_vidc_core *core; + + capability = inst->capabilities; + core = inst->core; + + adjusted_value = ctrl ? ctrl->val : + capability[OUTBUF_FENCE_DIRECTION].value; + + if (msm_vidc_get_parent_value(inst, OUTBUF_FENCE_DIRECTION, + META_OUTBUF_FENCE, &meta_outbuf_fence, __func__)) + return -EINVAL; + + if (is_meta_rx_inp_enabled(inst, META_OUTBUF_FENCE)) + adjusted_value = MSM_VIDC_FENCE_DIR_TX; + else + adjusted_value = MSM_VIDC_FENCE_DIR_NONE; + + msm_vidc_update_cap_value(inst, OUTBUF_FENCE_DIRECTION, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_dec_slice_mode(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 adjusted_value = 0; + s32 low_latency = -1; + s32 picture_order = -1; + s32 outbuf_fence = 0; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[SLICE_DECODE].value; + + if (msm_vidc_get_parent_value(inst, SLICE_DECODE, LOWLATENCY_MODE, + &low_latency, __func__) || + msm_vidc_get_parent_value(inst, SLICE_DECODE, OUTPUT_ORDER, + &picture_order, __func__) || + msm_vidc_get_parent_value(inst, SLICE_DECODE, META_OUTBUF_FENCE, + &outbuf_fence, __func__)) + return -EINVAL; + + if (!low_latency || !picture_order || + !is_meta_rx_inp_enabled(inst, META_OUTBUF_FENCE)) + adjusted_value = 0; + + msm_vidc_update_cap_value(inst, SLICE_DECODE, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_eva_stats(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[META_EVA_STATS].value; + + if (msm_vidc_get_parent_value(inst, META_EVA_STATS, BITRATE_MODE, + &rc_type, __func__)) + return -EINVAL; + + /* disable Eva stats metadata for CQ rate control */ + if (rc_type == HFI_RC_CQ) { + i_vpr_h(inst, "%s: unsupported for CQ rate control\n", __func__); + adjusted_value = 0; + } + + msm_vidc_update_cap_value(inst, META_EVA_STATS, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_sei_mastering_disp(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 profile = -1; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[META_SEI_MASTERING_DISP].value; + + if (msm_vidc_get_parent_value(inst, META_SEI_MASTERING_DISP, PROFILE, + &profile, __func__)) + return -EINVAL; + + if (inst->codec != MSM_VIDC_HEVC && inst->codec != MSM_VIDC_HEIC) { + adjusted_value = 0; + goto adjust; + } + + if ((inst->codec == MSM_VIDC_HEVC && + profile != V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) || + (inst->codec == MSM_VIDC_HEIC && + profile != V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE)) { + adjusted_value = 0; + goto adjust; + } + +adjust: + msm_vidc_update_cap_value(inst, META_SEI_MASTERING_DISP, + adjusted_value, __func__); + return 0; +} + +int msm_vidc_adjust_sei_cll(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 profile = -1; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[META_SEI_CLL].value; + + if (msm_vidc_get_parent_value(inst, META_SEI_CLL, PROFILE, + &profile, __func__)) + return -EINVAL; + + if (inst->codec != MSM_VIDC_HEVC && inst->codec != MSM_VIDC_HEIC) { + adjusted_value = 0; + goto adjust; + } + + if ((inst->codec == MSM_VIDC_HEVC && + profile != V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) || + (inst->codec == MSM_VIDC_HEIC && + profile != V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE)) { + adjusted_value = 0; + goto adjust; + } + +adjust: + msm_vidc_update_cap_value(inst, META_SEI_CLL, adjusted_value, __func__); + return 0; +} + +int msm_vidc_adjust_hdr10plus(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 profile = -1; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[META_HDR10PLUS].value; + + if (msm_vidc_get_parent_value(inst, META_HDR10PLUS, PROFILE, + &profile, __func__)) + return -EINVAL; + + if (inst->codec != MSM_VIDC_HEVC && inst->codec != MSM_VIDC_HEIC) { + adjusted_value = 0; + goto adjust; + } + + if ((inst->codec == MSM_VIDC_HEVC && + profile != V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) || + (inst->codec == MSM_VIDC_HEIC && + profile != V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE)) { + adjusted_value = 0; + goto adjust; + } + +adjust: + msm_vidc_update_cap_value(inst, META_HDR10PLUS, adjusted_value, __func__); + return 0; +} + +int msm_vidc_adjust_transcoding_stats(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1; + u32 width, height, fps; + struct v4l2_format *f; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[META_TRANSCODING_STAT_INFO].value; + + if (msm_vidc_get_parent_value(inst, META_TRANSCODING_STAT_INFO, + BITRATE_MODE, &rc_type, __func__)) + return -EINVAL; + + /* + * transcoding stats metadata is supported for: + * - VBR bitrate mode + * - fps <= 60 + * - Resolution <= 4K + */ + if (rc_type != HFI_RC_VBR_CFR) { + i_vpr_h(inst, "%s: unsupported rc_type: %#x\n", + __func__, rc_type); + adjusted_value = 0; + goto exit; + } + + fps = inst->capabilities[FRAME_RATE].value >> 16; + if (fps > MAX_TRANSCODING_STATS_FRAME_RATE) { + i_vpr_h(inst, "%s: unsupported fps %u\n", __func__, fps); + adjusted_value = 0; + goto exit; + } + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + if (res_is_greater_than(width, height, + MAX_TRANSCODING_STATS_WIDTH, MAX_TRANSCODING_STATS_HEIGHT)) { + i_vpr_h(inst, "%s: unsupported res, wxh %ux%u\n", + __func__, width, height); + adjusted_value = 0; + goto exit; + } + +exit: + msm_vidc_update_cap_value(inst, META_TRANSCODING_STAT_INFO, + adjusted_value, __func__); + + return 0; +} + +/******************* End of Control Adjust functions *************************/ + +/************************* Control Set functions *****************************/ + +int msm_vidc_set_header_mode(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + int header_mode, prepend_sps_pps; + u32 hfi_value = 0; + + header_mode = inst->capabilities[cap_id].value; + prepend_sps_pps = inst->capabilities[PREPEND_SPSPPS_TO_IDR].value; + + /* prioritize PREPEND_SPSPPS_TO_IDR mode over other header modes */ + if (prepend_sps_pps) + hfi_value = HFI_SEQ_HEADER_PREFIX_WITH_SYNC_FRAME; + else if (header_mode == V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME) + hfi_value = HFI_SEQ_HEADER_JOINED_WITH_1ST_FRAME; + else + hfi_value = HFI_SEQ_HEADER_SEPERATE_FRAME; + + if (is_meta_rx_out_enabled(inst, META_SEQ_HDR_NAL)) + hfi_value |= HFI_SEQ_HEADER_METADATA; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_deblock_mode(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 alpha = 0, beta = 0; + u32 lf_mode, hfi_value = 0, lf_offset = 6; + + rc = msm_vidc_v4l2_to_hfi_enum(inst, LF_MODE, &lf_mode); + if (rc) + return -EINVAL; + + beta = inst->capabilities[LF_BETA].value + lf_offset; + alpha = inst->capabilities[LF_ALPHA].value + lf_offset; + hfi_value = (alpha << 16) | (beta << 8) | lf_mode; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_constant_quality(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value = 0; + s32 rc_type = -1; + + if (msm_vidc_get_parent_value(inst, cap_id, + BITRATE_MODE, &rc_type, __func__)) + return -EINVAL; + + if (rc_type != HFI_RC_CQ) + return 0; + + hfi_value = inst->capabilities[cap_id].value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_vbr_related_properties(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value = 0; + s32 rc_type = -1; + + if (msm_vidc_get_parent_value(inst, cap_id, + BITRATE_MODE, &rc_type, __func__)) + return -EINVAL; + + if (rc_type != HFI_RC_VBR_CFR) + return 0; + + hfi_value = inst->capabilities[cap_id].value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_cbr_related_properties(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value = 0; + s32 rc_type = -1; + + if (msm_vidc_get_parent_value(inst, cap_id, + BITRATE_MODE, &rc_type, __func__)) + return -EINVAL; + + if (rc_type != HFI_RC_CBR_VFR && + rc_type != HFI_RC_CBR_CFR) + return 0; + + hfi_value = inst->capabilities[cap_id].value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_use_and_mark_ltr(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value = 0; + + if (!inst->capabilities[LTR_COUNT].value || + inst->capabilities[cap_id].value == + INVALID_DEFAULT_MARK_OR_USE_LTR) { + i_vpr_h(inst, + "%s: LTR_COUNT: %d %s: %d, cap %s is not set\n", + __func__, inst->capabilities[LTR_COUNT].value, + cap_name(cap_id), + inst->capabilities[cap_id].value, + cap_name(cap_id)); + return 0; + } + + hfi_value = inst->capabilities[cap_id].value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_min_qp(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + s32 i_frame_qp = 0, p_frame_qp = 0, b_frame_qp = 0, min_qp_enable = 0; + u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0; + u32 client_qp_enable = 0, hfi_value = 0, offset = 0; + + if (inst->capabilities[MIN_FRAME_QP].flags & CAP_FLAG_CLIENT_SET) + min_qp_enable = 1; + + if (min_qp_enable || + (inst->capabilities[I_FRAME_MIN_QP].flags & CAP_FLAG_CLIENT_SET)) + i_qp_enable = 1; + if (min_qp_enable || + (inst->capabilities[P_FRAME_MIN_QP].flags & CAP_FLAG_CLIENT_SET)) + p_qp_enable = 1; + if (min_qp_enable || + (inst->capabilities[B_FRAME_MIN_QP].flags & CAP_FLAG_CLIENT_SET)) + b_qp_enable = 1; + + client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2; + if (!client_qp_enable) { + i_vpr_h(inst, + "%s: client did not set min qp, cap %s is not set\n", + __func__, cap_name(cap_id)); + return 0; + } + + if (is_10bit_colorformat(inst->capabilities[PIX_FMTS].value)) + offset = 12; + + /* + * I_FRAME_MIN_QP, P_FRAME_MIN_QP, B_FRAME_MIN_QP, + * MIN_FRAME_QP caps have default value as MIN_QP_10BIT values. + * Hence, if client sets either one among MIN_FRAME_QP + * and (I_FRAME_MIN_QP or P_FRAME_MIN_QP or B_FRAME_MIN_QP), + * max of both caps will result into client set value. + */ + i_frame_qp = max(inst->capabilities[I_FRAME_MIN_QP].value, + inst->capabilities[MIN_FRAME_QP].value) + offset; + p_frame_qp = max(inst->capabilities[P_FRAME_MIN_QP].value, + inst->capabilities[MIN_FRAME_QP].value) + offset; + b_frame_qp = max(inst->capabilities[B_FRAME_MIN_QP].value, + inst->capabilities[MIN_FRAME_QP].value) + offset; + + hfi_value = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 | + client_qp_enable << 24; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_max_qp(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + s32 i_frame_qp = 0, p_frame_qp = 0, b_frame_qp = 0, max_qp_enable = 0; + u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0; + u32 client_qp_enable = 0, hfi_value = 0, offset = 0; + + if (inst->capabilities[MAX_FRAME_QP].flags & CAP_FLAG_CLIENT_SET) + max_qp_enable = 1; + + if (max_qp_enable || + (inst->capabilities[I_FRAME_MAX_QP].flags & CAP_FLAG_CLIENT_SET)) + i_qp_enable = 1; + if (max_qp_enable || + (inst->capabilities[P_FRAME_MAX_QP].flags & CAP_FLAG_CLIENT_SET)) + p_qp_enable = 1; + if (max_qp_enable || + (inst->capabilities[B_FRAME_MAX_QP].flags & CAP_FLAG_CLIENT_SET)) + b_qp_enable = 1; + + client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2; + if (!client_qp_enable) { + i_vpr_h(inst, + "%s: client did not set max qp, cap %s is not set\n", + __func__, cap_name(cap_id)); + return 0; + } + + if (is_10bit_colorformat(inst->capabilities[PIX_FMTS].value)) + offset = 12; + + /* + * I_FRAME_MAX_QP, P_FRAME_MAX_QP, B_FRAME_MAX_QP, + * MAX_FRAME_QP caps have default value as MAX_QP values. + * Hence, if client sets either one among MAX_FRAME_QP + * and (I_FRAME_MAX_QP or P_FRAME_MAX_QP or B_FRAME_MAX_QP), + * min of both caps will result into client set value. + */ + i_frame_qp = min(inst->capabilities[I_FRAME_MAX_QP].value, + inst->capabilities[MAX_FRAME_QP].value) + offset; + p_frame_qp = min(inst->capabilities[P_FRAME_MAX_QP].value, + inst->capabilities[MAX_FRAME_QP].value) + offset; + b_frame_qp = min(inst->capabilities[B_FRAME_MAX_QP].value, + inst->capabilities[MAX_FRAME_QP].value) + offset; + + hfi_value = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 | + client_qp_enable << 24; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_frame_qp(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + struct msm_vidc_inst_cap *capab; + s32 i_frame_qp = 0, p_frame_qp = 0, b_frame_qp = 0; + u32 i_qp_enable = 0, p_qp_enable = 0, b_qp_enable = 0; + u32 client_qp_enable = 0, hfi_value = 0, offset = 0; + s32 rc_type = -1; + + capab = inst->capabilities; + + if (msm_vidc_get_parent_value(inst, cap_id, + BITRATE_MODE, &rc_type, __func__)) + return -EINVAL; + + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) { + if (rc_type != HFI_RC_OFF) { + i_vpr_h(inst, + "%s: dynamic qp not allowed for rc type %d\n", + __func__, rc_type); + return 0; + } + } + + if (rc_type == HFI_RC_OFF) { + /* Mandatorily set for rc off case */ + i_qp_enable = 1; + p_qp_enable = 1; + b_qp_enable = 1; + } else { + /* Set only if client has set for NON rc off case */ + if (capab[I_FRAME_QP].flags & CAP_FLAG_CLIENT_SET) + i_qp_enable = 1; + if (capab[P_FRAME_QP].flags & CAP_FLAG_CLIENT_SET) + p_qp_enable = 1; + if (capab[B_FRAME_QP].flags & CAP_FLAG_CLIENT_SET) + b_qp_enable = 1; + } + + client_qp_enable = i_qp_enable | p_qp_enable << 1 | b_qp_enable << 2; + if (!client_qp_enable) { + i_vpr_h(inst, + "%s: client did not set frame qp, cap %s is not set\n", + __func__, cap_name(cap_id)); + return 0; + } + + if (is_10bit_colorformat(capab[PIX_FMTS].value)) + offset = 12; + + i_frame_qp = capab[I_FRAME_QP].value + offset; + p_frame_qp = capab[P_FRAME_QP].value + offset; + b_frame_qp = capab[B_FRAME_QP].value + offset; + + hfi_value = i_frame_qp | p_frame_qp << 8 | b_frame_qp << 16 | + client_qp_enable << 24; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_req_sync_frame(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 prepend_spspps; + u32 hfi_value = 0; + + prepend_spspps = inst->capabilities[PREPEND_SPSPPS_TO_IDR].value; + if (prepend_spspps) + hfi_value = HFI_SYNC_FRAME_REQUEST_WITH_PREFIX_SEQ_HDR; + else + hfi_value = HFI_SYNC_FRAME_REQUEST_WITHOUT_SEQ_HDR; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_chroma_qp_index_offset(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value = 0, chroma_qp_offset_mode = 0, chroma_qp = 0; + u32 offset = 12; + + if (inst->capabilities[cap_id].flags & CAP_FLAG_CLIENT_SET) + chroma_qp_offset_mode = HFI_FIXED_CHROMAQP_OFFSET; + else + chroma_qp_offset_mode = HFI_ADAPTIVE_CHROMAQP_OFFSET; + + chroma_qp = inst->capabilities[cap_id].value + offset; + hfi_value = chroma_qp_offset_mode | chroma_qp << 8 | chroma_qp << 16; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_slice_count(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 slice_mode = -1; + u32 hfi_value = 0, set_cap_id = 0; + + slice_mode = inst->capabilities[SLICE_MODE].value; + + if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) { + i_vpr_h(inst, "%s: slice mode is: %u, ignore setting to fw\n", + __func__, slice_mode); + return 0; + } + if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { + hfi_value = (inst->codec == MSM_VIDC_HEVC) ? + ((inst->capabilities[SLICE_MAX_MB].value + 3) / 4) : + inst->capabilities[SLICE_MAX_MB].value; + set_cap_id = SLICE_MAX_MB; + } else if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { + hfi_value = inst->capabilities[SLICE_MAX_BYTES].value; + set_cap_id = SLICE_MAX_BYTES; + } + + rc = msm_vidc_packetize_control(inst, set_cap_id, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_nal_length(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value = HFI_NAL_LENGTH_STARTCODES; + + if (!inst->capabilities[WITHOUT_STARTCODE].value) { + hfi_value = HFI_NAL_LENGTH_STARTCODES; + } else { + rc = msm_vidc_v4l2_to_hfi_enum(inst, NAL_LENGTH_FIELD, &hfi_value); + if (rc) + return -EINVAL; + } + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_layer_count_and_type(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_layer_count, hfi_layer_type = 0; + + if (!inst->bufq[OUTPUT_PORT].vb2q->streaming) { + /* set layer type */ + hfi_layer_type = inst->hfi_layer_type; + cap_id = LAYER_TYPE; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM, + &hfi_layer_type, sizeof(u32), __func__); + if (rc) + goto exit; + } else { + if (inst->hfi_layer_type == HFI_HIER_B) { + i_vpr_l(inst, + "%s: HB dyn layers change is not supported\n", + __func__); + return 0; + } + } + + /* set layer count */ + cap_id = ENH_LAYER_COUNT; + /* hfi baselayer starts from 1 */ + hfi_layer_count = inst->capabilities[ENH_LAYER_COUNT].value + 1; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &hfi_layer_count, sizeof(u32), __func__); + if (rc) + goto exit; + +exit: + return rc; +} + +int msm_vidc_set_gop_size(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value; + + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) { + if (inst->hfi_layer_type == HFI_HIER_B) { + i_vpr_l(inst, + "%s: HB dyn GOP setting is not supported\n", + __func__); + return 0; + } + } + + hfi_value = inst->capabilities[GOP_SIZE].value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_bitrate(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value = 0; + + /* set Total Bitrate */ + if (inst->capabilities[BIT_RATE].flags & CAP_FLAG_CLIENT_SET) + goto set_total_bitrate; + + /* + * During runtime, if BIT_RATE cap CLIENT_SET flag is not set, + * then this function will be called due to change in ENH_LAYER_COUNT. + * In this case, client did not change bitrate, hence, no need to set + * to fw. + */ + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) + return 0; + +set_total_bitrate: + hfi_value = inst->capabilities[BIT_RATE].value; + rc = msm_vidc_packetize_control(inst, BIT_RATE, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_layer_bitrate(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value = 0; + + if (!inst->bufq[OUTPUT_PORT].vb2q->streaming) + return 0; + + /* set Total Bitrate */ + if (inst->capabilities[BIT_RATE].flags & CAP_FLAG_CLIENT_SET) { + i_vpr_h(inst, + "%s: Total bitrate is set, ignore layer bitrate\n", + __func__); + return 0; + } + + /* + * ENH_LAYER_COUNT cap max is positive only if + * layer encoding is enabled during streamon. + */ + if (!inst->capabilities[ENH_LAYER_COUNT].max || + !msm_vidc_check_all_layer_bitrate_set(inst)) { + i_vpr_h(inst, + "%s: invalid layer bitrate, ignore setting to fw\n", + __func__); + return 0; + } + + /* + * Accept layerwise bitrate but set total bitrate which was already + * adjusted based on layer bitrate + */ + hfi_value = inst->capabilities[BIT_RATE].value; + rc = msm_vidc_packetize_control(inst, BIT_RATE, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_session_priority(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + u32 hfi_value = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + hfi_value = inst->capabilities[cap_id].value; + if (!is_critical_priority_session(inst)) + hfi_value = inst->capabilities[cap_id].value + + inst->capabilities[FIRMWARE_PRIORITY_OFFSET].value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_flip(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + u32 hflip, vflip, hfi_value = HFI_DISABLE_FLIP; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + hflip = inst->capabilities[HFLIP].value; + vflip = inst->capabilities[VFLIP].value; + + if (hflip) + hfi_value |= HFI_HORIZONTAL_FLIP; + + if (vflip) + hfi_value |= HFI_VERTICAL_FLIP; + + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) { + if (hfi_value != HFI_DISABLE_FLIP) { + rc = msm_vidc_set_req_sync_frame(inst, + REQUEST_I_FRAME); + if (rc) + return rc; + } + } + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_preprocess(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_rotation(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value; + + rc = msm_vidc_v4l2_to_hfi_enum(inst, cap_id, &hfi_value); + if (rc) + return -EINVAL; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_blur_resolution(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 blur_type = -1; + u32 hfi_value, blur_width, blur_height; + + if (msm_vidc_get_parent_value(inst, cap_id, + BLUR_TYPES, &blur_type, __func__)) + return -EINVAL; + + if (blur_type != MSM_VIDC_BLUR_EXTERNAL) + return 0; + + hfi_value = inst->capabilities[cap_id].value; + + blur_width = (hfi_value & 0xFFFF0000) >> 16; + blur_height = hfi_value & 0xFFFF; + + if (blur_width > inst->crop.width || + blur_height > inst->crop.height) { + i_vpr_e(inst, + "%s: blur wxh: %dx%d exceeds crop wxh: %dx%d\n", + __func__, blur_width, blur_height, + inst->crop.width, inst->crop.height); + hfi_value = 0; + } + + if (blur_width == inst->crop.width && + blur_height == inst->crop.height) { + i_vpr_e(inst, + "%s: blur wxh: %dx%d is equal to crop wxh: %dx%d\n", + __func__, blur_width, blur_height, + inst->crop.width, inst->crop.height); + hfi_value = 0; + } + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +static int msm_venc_set_csc_coeff(struct msm_vidc_inst *inst, + const char *prop_name, u32 hfi_id, void *payload, + u32 payload_size, u32 row_count, u32 column_count) +{ + int rc = 0; + + i_vpr_h(inst, + "set cap: name: %24s, hard coded %dx%d matrix array\n", + prop_name, row_count, column_count); + rc = venus_hfi_session_property(inst, + hfi_id, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_S32_ARRAY, + payload, + payload_size); + if (rc) { + i_vpr_e(inst, + "%s: failed to set %s to fw\n", + __func__, prop_name); + } + + return rc; +} + +int msm_vidc_set_csc_custom_matrix(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + int i; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + struct msm_vidc_core *core; + struct msm_vidc_csc_coeff *csc_coeff; + s32 matrix_payload[MAX_MATRIX_COEFFS + 2]; + s32 csc_bias_payload[MAX_BIAS_COEFFS + 2]; + s32 csc_limit_payload[MAX_LIMIT_COEFFS + 2]; + + core = inst->core; + csc_coeff = &core->platform->data.csc_data; + + if (!inst->capabilities[cap_id].value || + !inst->capabilities[CSC].value) { + i_vpr_h(inst, + "%s: ignored as custom martix %u, csc %u\n", + __func__, inst->capabilities[cap_id].value, + inst->capabilities[CSC].value); + return 0; + } + + /* + * first 2 u32's of payload in each case are for + * row and column count, next remaining u32's are + * for the actual payload values. + */ + + /* set custom matrix */ + matrix_payload[0] = 3; + matrix_payload[1] = 3; + + for (i = 0; i < MAX_MATRIX_COEFFS; i++) { + if ((i + 2) >= ARRAY_SIZE(matrix_payload)) + break; + matrix_payload[i + 2] = + csc_coeff->vpe_csc_custom_matrix_coeff[i]; + } + + rc = msm_venc_set_csc_coeff(inst, "CSC_CUSTOM_MATRIX", + HFI_PROP_CSC_MATRIX, &matrix_payload[0], + ARRAY_SIZE(matrix_payload) * sizeof(s32), + matrix_payload[0], matrix_payload[1]); + if (rc) + return rc; + + /* set csc bias */ + csc_bias_payload[0] = 1; + csc_bias_payload[1] = 3; + + for (i = 0; i < MAX_BIAS_COEFFS; i++) { + if ((i + 2) >= ARRAY_SIZE(csc_bias_payload)) + break; + csc_bias_payload[i + 2] = + csc_coeff->vpe_csc_custom_bias_coeff[i]; + } + + rc = msm_venc_set_csc_coeff(inst, "CSC_BIAS", + HFI_PROP_CSC_BIAS, &csc_bias_payload[0], + ARRAY_SIZE(csc_bias_payload) * sizeof(s32), + csc_bias_payload[0], csc_bias_payload[1]); + if (rc) + return rc; + + /* set csc limit */ + csc_limit_payload[0] = 1; + csc_limit_payload[1] = 6; + + for (i = 0; i < MAX_LIMIT_COEFFS; i++) { + if ((i + 2) >= ARRAY_SIZE(csc_limit_payload)) + break; + csc_limit_payload[i + 2] = + csc_coeff->vpe_csc_custom_limit_coeff[i]; + } + + rc = msm_venc_set_csc_coeff(inst, "CSC_LIMIT", + HFI_PROP_CSC_LIMIT, &csc_limit_payload[0], + ARRAY_SIZE(csc_limit_payload) * sizeof(s32), + csc_limit_payload[0], csc_limit_payload[1]); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_reserve_duration(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + u32 hfi_value = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + /* reserve hardware only when input port is streaming*/ + if (!inst->bufq[INPUT_PORT].vb2q->streaming) + return 0; + + if (!(inst->capabilities[cap_id].flags & CAP_FLAG_CLIENT_SET)) + return 0; + + inst->capabilities[cap_id].flags &= (~CAP_FLAG_CLIENT_SET); + + if (!is_critical_priority_session(inst)) { + i_vpr_h(inst, "%s: reserve duration allowed only for critical session\n", __func__); + return 0; + } + + hfi_value = inst->capabilities[cap_id].value; + + rc = venus_hfi_reserve_hardware(inst, hfi_value); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_level(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value = 0; + + hfi_value = inst->capabilities[cap_id].value; + if (!(inst->capabilities[cap_id].flags & CAP_FLAG_CLIENT_SET)) + hfi_value = HFI_LEVEL_NONE; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_q16(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value = 0; + + hfi_value = inst->capabilities[cap_id].value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_Q16, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_u32(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value; + + if (inst->capabilities[cap_id].flags & CAP_FLAG_MENU) { + rc = msm_vidc_v4l2_menu_to_hfi(inst, cap_id, &hfi_value); + if (rc) + return -EINVAL; + } else { + hfi_value = inst->capabilities[cap_id].value; + } + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_u32_packed(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value; + + if (inst->capabilities[cap_id].flags & CAP_FLAG_MENU) { + rc = msm_vidc_v4l2_menu_to_hfi(inst, cap_id, &hfi_value); + if (rc) + return -EINVAL; + } else { + hfi_value = inst->capabilities[cap_id].value; + } + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_u32_enum(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value; + + rc = msm_vidc_v4l2_to_hfi_enum(inst, cap_id, &hfi_value); + if (rc) + return -EINVAL; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_s32(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 hfi_value = 0; + + hfi_value = inst->capabilities[cap_id].value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_S32, + &hfi_value, sizeof(s32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_stage(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + u32 stage = 0; + struct msm_vidc_core *core; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + core = inst->core; + + rc = call_session_op(core, decide_work_mode, inst); + if (rc) { + i_vpr_e(inst, "%s: decide_work_mode failed\n", __func__); + return -EINVAL; + } + + stage = inst->capabilities[STAGE].value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &stage, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_pipe(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + u32 pipe; + struct msm_vidc_core *core; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + core = inst->core; + + rc = call_session_op(core, decide_work_route, inst); + if (rc) { + i_vpr_e(inst, "%s: decide_work_route failed\n", + __func__); + return -EINVAL; + } + + pipe = inst->capabilities[PIPE].value; + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &pipe, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_vui_timing_info(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value; + + /* + * hfi is HFI_PROP_DISABLE_VUI_TIMING_INFO and v4l2 cap is + * V4L2_CID_MPEG_VIDC_VUI_TIMING_INFO and hence reverse + * the hfi_value from cap_id value. + */ + if (inst->capabilities[cap_id].value == 1) + hfi_value = 0; + else + hfi_value = 1; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_outbuf_fence_type(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value; + + if (inst->capabilities[OUTBUF_FENCE_TYPE].value == + MSM_VIDC_FENCE_NONE) + return 0; + + hfi_value = inst->capabilities[cap_id].value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_set_outbuf_fence_direction(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 hfi_value; + + if (inst->capabilities[OUTBUF_FENCE_DIRECTION].value == + MSM_VIDC_FENCE_DIR_NONE) + return 0; + + hfi_value = inst->capabilities[cap_id].value; + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_U32_ENUM, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +/********************* End of Control Set functions **************************/ diff --git a/qcom/opensource/video-driver/driver/platform/common/src/msm_vidc_platform_ext.c b/qcom/opensource/video-driver/driver/platform/common/src/msm_vidc_platform_ext.c new file mode 100644 index 0000000000..82c9d07893 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/common/src/msm_vidc_platform_ext.c @@ -0,0 +1,259 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "msm_vidc_platform_ext.h" +#include "hfi_packet.h" +#include "hfi_property.h" +#include "venus_hfi.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_driver.h" +#include "msm_venc.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" + +int msm_vidc_adjust_ir_period(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value, all_intra = 0, roi_enable = 0, + pix_fmts = MSM_VIDC_FMT_NONE; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[IR_PERIOD].value; + + if (msm_vidc_get_parent_value(inst, IR_PERIOD, ALL_INTRA, + &all_intra, __func__) || + msm_vidc_get_parent_value(inst, IR_PERIOD, META_ROI_INFO, + &roi_enable, __func__)) + return -EINVAL; + + if (all_intra) { + adjusted_value = 0; + i_vpr_h(inst, "%s: intra refresh unsupported, all intra: %d\n", + __func__, all_intra); + goto exit; + } + + if (roi_enable) { + i_vpr_h(inst, + "%s: intra refresh unsupported with roi metadata\n", + __func__); + adjusted_value = 0; + goto exit; + } + + if (inst->codec == MSM_VIDC_HEVC) { + if (msm_vidc_get_parent_value(inst, IR_PERIOD, + PIX_FMTS, &pix_fmts, __func__)) + return -EINVAL; + + if (is_10bit_colorformat(pix_fmts)) { + i_vpr_h(inst, + "%s: intra refresh is supported only for 8 bit\n", + __func__); + adjusted_value = 0; + goto exit; + } + } + + /* + * BITRATE_MODE dependency is NOT common across all chipsets. + * Hence, do not return error if not specified as one of the parent. + */ + if (is_parent_available(inst, IR_PERIOD, BITRATE_MODE, __func__) && + inst->hfi_rc_type != HFI_RC_CBR_CFR && + inst->hfi_rc_type != HFI_RC_CBR_VFR) + adjusted_value = 0; + +exit: + msm_vidc_update_cap_value(inst, IR_PERIOD, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_dec_frame_rate(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 adjusted_value = 0; + + if (is_encode_session(inst)) { + d_vpr_e("%s: adjust framerate invalid for enc\n", __func__); + return -EINVAL; + } + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[FRAME_RATE].value; + msm_vidc_update_cap_value(inst, FRAME_RATE, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_dec_operating_rate(void *instance, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 adjusted_value = 0; + + if (is_encode_session(inst)) { + d_vpr_e("%s: adjust operating rate invalid for enc\n", __func__); + return -EINVAL; + } + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[OPERATING_RATE].value; + msm_vidc_update_cap_value(inst, OPERATING_RATE, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_adjust_delivery_mode(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + s32 slice_mode = -1; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + if (is_decode_session(inst)) + return 0; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[DELIVERY_MODE].value; + + if (msm_vidc_get_parent_value(inst, DELIVERY_MODE, SLICE_MODE, + &slice_mode, __func__)) + return -EINVAL; + + /* Slice encode delivery mode is only supported for Max MB slice mode */ + if (slice_mode != V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) + adjusted_value = 0; + + msm_vidc_update_cap_value(inst, DELIVERY_MODE, adjusted_value, __func__); + + return 0; +} + +int msm_vidc_set_ir_period(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 ir_type = 0; + struct msm_vidc_core *core; + + core = inst->core; + + if (inst->capabilities[IR_TYPE].value == + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) { + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) { + i_vpr_h(inst, "%s: dynamic random intra refresh not allowed\n", + __func__); + return 0; + } + ir_type = HFI_PROP_IR_RANDOM_PERIOD; + } else if (inst->capabilities[IR_TYPE].value == + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC) { + ir_type = HFI_PROP_IR_CYCLIC_PERIOD; + } else { + i_vpr_e(inst, "%s: invalid ir_type %d\n", + __func__, inst->capabilities[IR_TYPE]); + return -EINVAL; + } + + rc = venus_hfi_set_ir_period(inst, ir_type, cap_id); + if (rc) { + i_vpr_e(inst, "%s: failed to set ir period %d\n", + __func__, inst->capabilities[IR_PERIOD].value); + return rc; + } + + return rc; +} + +int msm_vidc_set_signal_color_info(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + u32 color_info, matrix_coeff, transfer_char, primaries, range; + u32 full_range = 0; + u32 colour_description_present_flag = 0; + u32 video_signal_type_present_flag = 0, hfi_value = 0; + struct v4l2_format *input_fmt; + u32 pix_fmt; + /* Unspecified video format */ + u32 video_format = 5; + + if (!(inst->capabilities[cap_id].flags & CAP_FLAG_CLIENT_SET)) { + i_vpr_h(inst, "%s: colorspace not configured via control\n", __func__); + return 0; + } + + color_info = inst->capabilities[cap_id].value; + matrix_coeff = color_info & 0xFF; + transfer_char = (color_info & 0xFF00) >> 8; + primaries = (color_info & 0xFF0000) >> 16; + range = (color_info & 0xFF000000) >> 24; + + input_fmt = &inst->fmts[INPUT_PORT]; + pix_fmt = v4l2_colorformat_to_driver(inst, + input_fmt->fmt.pix_mp.pixelformat, __func__); + if (primaries != V4L2_COLORSPACE_DEFAULT || + matrix_coeff != V4L2_YCBCR_ENC_DEFAULT || + transfer_char != V4L2_XFER_FUNC_DEFAULT) { + colour_description_present_flag = 1; + video_signal_type_present_flag = 1; + primaries = v4l2_color_primaries_to_driver(inst, + primaries, __func__); + matrix_coeff = v4l2_matrix_coeff_to_driver(inst, + matrix_coeff, __func__); + transfer_char = v4l2_transfer_char_to_driver(inst, + transfer_char, __func__); + } else if (is_rgba_colorformat(pix_fmt)) { + colour_description_present_flag = 1; + video_signal_type_present_flag = 1; + primaries = MSM_VIDC_PRIMARIES_BT709; + matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709; + transfer_char = MSM_VIDC_TRANSFER_BT709; + full_range = 0; + } + + if (range != V4L2_QUANTIZATION_DEFAULT) { + video_signal_type_present_flag = 1; + full_range = range == V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0; + } + + hfi_value = (matrix_coeff & 0xFF) | + ((transfer_char << 8) & 0xFF00) | + ((primaries << 16) & 0xFF0000) | + ((colour_description_present_flag << 24) & 0x1000000) | + ((full_range << 25) & 0x2000000) | + ((video_format << 26) & 0x1C000000) | + ((video_signal_type_present_flag << 29) & 0x20000000); + + rc = msm_vidc_packetize_control(inst, cap_id, HFI_PAYLOAD_32_PACKED, + &hfi_value, sizeof(u32), __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_adjust_csc(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + s32 pix_fmt = -1; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + + if (is_decode_session(inst)) + return 0; + + adjusted_value = ctrl ? ctrl->val : inst->capabilities[CSC].value; + + if (msm_vidc_get_parent_value(inst, CSC, PIX_FMTS, + &pix_fmt, __func__)) + return -EINVAL; + + /* disable csc for 10-bit encoding */ + if (is_10bit_colorformat(pix_fmt)) + adjusted_value = 0; + + msm_vidc_update_cap_value(inst, CSC, adjusted_value, __func__); + + return 0; +} \ No newline at end of file diff --git a/qcom/opensource/video-driver/driver/platform/kalama/inc/kalama_technology.h b/qcom/opensource/video-driver/driver/platform/kalama/inc/kalama_technology.h new file mode 100644 index 0000000000..c75fbb5e5b --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/kalama/inc/kalama_technology.h @@ -0,0 +1,238 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "perf_static_model.h" + +#define ENABLE_FINEBITRATE_SUBUHD60 0 + +/* + * Chipset Generation Technology: SW/FW overhead profiling + * need update with new numbers + */ +static u32 frequency_table_kalama[2][6] = { + /* //make lowsvs_D1 as invalid; */ + {533, 444, 366, 338, 240, 0}, + {800, 666, 549, 507, 360, 0}, +}; + + /* + * TODO Move to kalama.c + * TODO Replace hardcoded values with + * ENCODER_VPP_TARGET_CLK_PER_MB_KALAMA in CPP file. + */ + + /* Tensilica cycles */ +#define DECODER_VPP_FW_OVERHEAD_KALAMA 66234 + +/* Tensilica cycles; this is measured in Lahaina 1stage with FW profiling */ +#define DECODER_VPPVSP1STAGE_FW_OVERHEAD_KALAMA 93000 + +#define DECODER_VSP_FW_OVERHEAD_KALAMA \ + (DECODER_VPPVSP1STAGE_FW_OVERHEAD_KALAMA - DECODER_VPP_FW_OVERHEAD_KALAMA) + +/* Tensilica cycles; encoder has ARP register */ +#define ENCODER_VPP_FW_OVERHEAD_KALAMA 48405 + +#define ENCODER_VPPVSP1STAGE_FW_OVERHEAD_KALAMA \ + (ENCODER_VPP_FW_OVERHEAD_KALAMA + DECODER_VSP_FW_OVERHEAD_KALAMA) + +#define DECODER_SW_OVERHEAD_KALAMA 489583 +#define ENCODER_SW_OVERHEAD_KALAMA 489583 + +/* Video IP Core Technology: pipefloor and pipe penlaty */ +static u32 encoder_vpp_target_clk_per_mb_kalama[2] = {320, 675}; +static u32 decoder_vpp_target_clk_per_mb_kalama = 200; + +/* + * These pipe penalty numbers only applies to 4 pipe + * For 2pipe and 1pipe, these numbers need recalibrate + */ +static u32 pipe_penalty_kalama[3][3] = { + /* NON AV1 */ + {1059, 1059, 1059}, + /* AV1 RECOMMENDED TILE 1080P_V2XH1, UHD_V2X2, 8KUHD_V8X2 */ + {1410, 1248, 1226}, + /* AV1 YOUTUBE/NETFLIX TILE 1080P_V4XH2_V4X1, UHD_V8X4_V8X1, 8KUHD_V8X8_V8X1 */ + {2039, 2464, 1191}, +}; + +/* + * Video IP Core Technology: bitrate constraint + * HW limit bitrate table (these values are measured end to end fw/sw impacts are also considered) + * TODO Can we convert to Cycles/MB? This will remove DIVISION. + */ +static u32 bitrate_table_kalama_2stage_fp[5][10] = { + /* h264 cavlc */ + {0, 220, 220, 220, 220, 220, 220, 220, 220, 220}, + /* h264 cabac */ + {0, 140, 150, 160, 175, 190, 190, 190, 190, 190}, + /* h265 */ + {90, 140, 160, 180, 190, 200, 200, 200, 200, 200}, + /* vp9 */ + {90, 90, 90, 90, 90, 90, 90, 90, 90, 90}, + /* av1 */ + {130, 130, 120, 120, 120, 120, 120, 120, 120, 120}, +}; + +/* + * HW limit bitrate table (these values are measured + * end to end fw/sw impacts are also considered) + */ +static u32 bitrate_table_kalama_1stage_fp[5][10] = { /* 1-stage assume IPPP */ + /* h264 cavlc */ + {0, 220, 220, 220, 220, 220, 220, 220, 220, 220}, + /* h264 cabac */ + {0, 110, 150, 150, 150, 150, 150, 150, 150, 150}, + /* h265 */ + {0, 140, 150, 150, 150, 150, 150, 150, 150, 150}, + /* vp9 */ + {0, 70, 70, 70, 70, 70, 70, 70, 70, 70}, + /* av1 */ + {0, 100, 100, 100, 100, 100, 100, 100, 100, 100}, +}; + +/* rec pwc and power bitrate table */ +static u32 bitrate_table_kalama_rec_fp[5][10] = { + /* rec. worst bitrate based on bitrate table */ +#if ENABLE_FINEBITRATE_SUBUHD60 + /* h264 cavlc */ + {0, 168, 150, 120, 100, 90, 50, 32, 20, 14}, + /* h264 cabac 8bit */ + {0, 134, 109, 84, 67, 56, 35, 23, 14, 10}, + /* h265 10bit assumption */ + {70, 140, 116, 92, 74, 62, 39, 25, 16, 11}, + /* vp9 (profiled content from youtube and nflx) */ + {70, 70, 65, 55, 45, 35, 20, 8, 6, 5}, + /* av1 (profiled content from youtube and nflx) */ + {100, 100, 85, 70, 55, 30, 15, 5, 5, 5}, +#else + /* h264 cavlc */ + {0, 168, 150, 120, 100, 90, 90, 90, 90, 90}, + /* h264 cabac 8bit */ + {0, 134, 109, 84, 67, 56, 56, 56, 56, 56}, + /* h265 10bit assumption */ + {70, 140, 116, 92, 74, 62, 62, 62, 62, 62}, + /* vp9 */ + {70, 70, 65, 55, 45, 35, 35, 35, 35, 35}, + /* av1 */ + {100, 100, 85, 70, 55, 50, 50, 50, 50, 50}, +#endif +}; + +static u32 input_bitrate_fp; + +/* 8KUHD60; UHD240; 1080p960 with B */ +static u32 fp_pixel_count_bar0 = 3840 * 2160 * 240; +/* 8KUHD60; UHD240; 1080p960 without B */ +static u32 fp_pixel_count_bar1 = 3840 * 2160 * 240; +/* 1080p720 */ +static u32 fp_pixel_count_bar2 = 3840 * 2160 * 180; +/* UHD120 */ +static u32 fp_pixel_count_bar3 = 3840 * 2160 * 120; +/* UHD90 */ +static u32 fp_pixel_count_bar4 = 3840 * 2160 * 90; +/* UHD60 */ +static u32 fp_pixel_count_bar5 = 3840 * 2160 * 60; +/* UHD30; FHD120; HD240 */ +static u32 fp_pixel_count_bar6 = 3840 * 2160 * 30; +/* FHD60 */ +static u32 fp_pixel_count_bar7 = 1920 * 1080 * 60; +/* FHD30 */ +static u32 fp_pixel_count_bar8 = 1920 * 1080 * 30; +/* HD30 */ +static u32 fp_pixel_count_bar9 = 1280 * 720 * 30; + +static u32 codec_encoder_gop_complexity_table_fp[8][3]; +static u32 codec_mbspersession_kalama; + +static u32 cr_table_basic_kalama[7][4] = { + {1920, 1080, 20, 40}, + {3840, 2160, 42, 84}, + {4096, 2160, 44, 88}, + {4096, 2304, 48, 96}, + {1280, 720, 7, 14}, + {2560, 1440, 32, 64}, + {7680, 4320, 84, 168}, +}; + +/* 100x */ +static u32 dpbopb_ubwc30_cr_table_cratio_kalama[7][12] = { + {237, 399, 272, 137, 225, 158, 185, 259, 203, 138, 167, 152}, + {269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149}, + {269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149}, + {269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149}, + {237, 399, 272, 137, 225, 158, 185, 259, 203, 138, 167, 152}, + {269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149}, + {269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149}, +}; + +/* 100x */ +static u32 rpb_ubwc30_cr_table_cratio_kalama[7][12] = { + {193, 294, 218, 135, 214, 155, 175, 241, 191, 139, 162, 149}, + {285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152}, + {285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152}, + {285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152}, + {193, 294, 218, 135, 214, 155, 175, 241, 191, 139, 162, 149}, + {285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152}, + {285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152}, +}; + +/* 100x */ +static u32 ipblossy_ubwc30_cr_table_cratio_kalama[7][12] = { + {215, 215, 215, 174, 174, 174, 266, 266, 266, 231, 231, 231}, + {254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249}, + {254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249}, + {254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249}, + {215, 215, 215, 174, 174, 174, 266, 266, 266, 231, 231, 231}, + {254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249}, + {254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249}, +}; + +/* 100x */ +static u32 ipblossless_ubwc30_cr_table_cratio_kalama[7][12] = { + {185, 215, 194, 147, 178, 159, 162, 181, 169, 138, 161, 146}, + {186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148}, + {186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148}, + {186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148}, + {185, 215, 194, 147, 178, 159, 162, 181, 169, 138, 161, 146}, + {186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148}, + {186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148}, +}; + +/* 100x */ +static u32 en_original_compression_factor_rgba_pwd_kalama = 243; +/* 100x */ +static u32 en_original_compression_factor_rgba_avg_kalama = 454; + +static u32 av1_num_tiles_kalama[7][3] = { + {2, 1, 1}, + {4, 2, 2}, + {4, 2, 2}, + {4, 2, 2}, + {1, 1, 1}, + {2, 1, 1}, + {16, 4, 4}, +}; + +/* H I J K L M N O P + * TotalW Total R Frequency Write Read + * Name B b P B b P B b P + * I3B4b1P 0.5 1.875 3 4 1 1 0 1 2 2 1 + * I1B2b1P 0.5 1.75 1 2 1 1 0 1 2 2 1 + * IbP 0.5 1.5 0 1 1 1 0 1 2 2 1 + * IPP 1 1 0 0 1 1 0 1 2 2 1 + * P 1 1 0 0 1 1 0 1 2 2 1 + * smallB 0 2 0 1 0 1 0 1 2 2 1 + * bigB 1 2 1 0 0 1 0 1 2 2 1 + * + * Total W = SUMPRODUCT(H16:J16, K16 : M16) / SUM(H16:J16) + * Total R = SUMPRODUCT(H16:J16, N16 : P16) / SUM(H16:J16) + */ + +/* 1000x */ +static u32 kalama_en_readfactor[7] = {1000, 1500, 1750, 1875, 1000, 2000, 2000}; +/* 1000x */ +static u32 kalama_en_writefactor[7] = {1000, 500, 500, 500, 1000, 0, 1000}; +static u32 kalama_en_frame_num_parallel = 1; diff --git a/qcom/opensource/video-driver/driver/platform/kalama/inc/msm_vidc_kalama.h b/qcom/opensource/video-driver/driver/platform/kalama/inc/msm_vidc_kalama.h new file mode 100644 index 0000000000..7ba1fc88b1 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/kalama/inc/msm_vidc_kalama.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_KALAMA_H_ +#define _MSM_VIDC_KALAMA_H_ + +#include "msm_vidc_core.h" + +#if defined(CONFIG_MSM_VIDC_KALAMA) +int msm_vidc_init_platform_kalama(struct msm_vidc_core *core); +#else +int msm_vidc_init_platform_kalama(struct msm_vidc_core *core) +{ + return -EINVAL; +} +#endif + +#endif // _MSM_VIDC_KALAMA_H_ diff --git a/qcom/opensource/video-driver/driver/platform/kalama/src/msm_vidc_kalama.c b/qcom/opensource/video-driver/driver/platform/kalama/src/msm_vidc_kalama.c new file mode 100644 index 0000000000..887078e223 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/kalama/src/msm_vidc_kalama.c @@ -0,0 +1,2871 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include + +#include +#include +#include + +#include "msm_vidc_kalama.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_platform_ext.h" +#include "msm_vidc_memory_ext.h" +#include "resources_ext.h" +#include "msm_vidc_iris3.h" +#include "hfi_property.h" +#include "hfi_command.h" + +/* version: major[24:31], minor[16:23], revision[0:15] */ +#define DRIVER_VERSION 0x04000000 +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010 +#define MAX_BASE_LAYER_PRIORITY_ID 63 +#define MAX_OP_POINT 31 +#define MAX_BITRATE 245000000 +#define DEFAULT_BITRATE 20000000 +#define MINIMUM_FPS 1 +#define MAXIMUM_FPS 480 +#define MAXIMUM_DEC_FPS 960 +#define MAX_QP 51 +#define DEFAULT_QP 20 +#define MAX_CONSTANT_QUALITY 100 +#define MIN_SLICE_BYTE_SIZE 512 +#define MAX_SLICE_BYTE_SIZE \ + ((MAX_BITRATE) >> 3) +#define MAX_SLICE_MB_SIZE \ + (((4096 + 15) >> 4) * ((2304 + 15) >> 4)) + +#define ENC MSM_VIDC_ENCODER +#define DEC MSM_VIDC_DECODER +#define H264 MSM_VIDC_H264 +#define HEVC MSM_VIDC_HEVC +#define VP9 MSM_VIDC_VP9 +#define AV1 MSM_VIDC_AV1 +#define HEIC MSM_VIDC_HEIC +#define CODECS_ALL (H264 | HEVC | VP9 | HEIC | AV1) +#define MAXIMUM_OVERRIDE_VP9_FPS 200 + +static struct codec_info codec_data_kalama[] = { + { + .v4l2_codec = V4L2_PIX_FMT_H264, + .vidc_codec = MSM_VIDC_H264, + .pixfmt_name = "AVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_HEVC, + .vidc_codec = MSM_VIDC_HEVC, + .pixfmt_name = "HEVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VP9, + .vidc_codec = MSM_VIDC_VP9, + .pixfmt_name = "VP9", + }, + { + .v4l2_codec = V4L2_PIX_FMT_AV1, + .vidc_codec = MSM_VIDC_AV1, + .pixfmt_name = "AV1", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VIDC_HEIC, + .vidc_codec = MSM_VIDC_HEIC, + .pixfmt_name = "HEIC", + }, +}; + +static struct color_format_info color_format_data_kalama[] = { + { + .v4l2_color_format = V4L2_PIX_FMT_NV12, + .vidc_color_format = MSM_VIDC_FMT_NV12, + .pixfmt_name = "NV12", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_NV21, + .vidc_color_format = MSM_VIDC_FMT_NV21, + .pixfmt_name = "NV21", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC08C, + .vidc_color_format = MSM_VIDC_FMT_NV12C, + .pixfmt_name = "NV12C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC10C, + .vidc_color_format = MSM_VIDC_FMT_TP10C, + .pixfmt_name = "TP10C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_RGBA32, + .vidc_color_format = MSM_VIDC_FMT_RGBA8888, + .pixfmt_name = "RGBA", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_P010, + .vidc_color_format = MSM_VIDC_FMT_P010, + .pixfmt_name = "P010", + }, + { + .v4l2_color_format = V4L2_META_FMT_VIDC, + .vidc_color_format = MSM_VIDC_FMT_META, + .pixfmt_name = "META", + }, +}; + +static struct color_primaries_info color_primaries_data_kalama[] = { + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_RESERVED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_UNSPECIFIED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_REC709, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT709, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_BG, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE170M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT601_525, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE240M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_ST240M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_GENERIC_FILM, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_GENERIC_FILM, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_BT2020, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT2020, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DCI_P3, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_RP431_2, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_EG431, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_EG431_1, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_EBU_TECH, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_EBU_TECH, + }, +}; + +static struct transfer_char_info transfer_char_data_kalama[] = { + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_RESERVED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_UNSPECIFIED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_709, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT709, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT470_SYSTEM_M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT470_SYSTEM_M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT470_SYSTEM_BG, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT470_SYSTEM_BG, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT601_525_OR_625, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT601_525_OR_625, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE240M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST240M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_LINEAR, + .vidc_transfer_char = MSM_VIDC_TRANSFER_LINEAR, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_XVYCC, + .vidc_transfer_char = MSM_VIDC_TRANSFER_XVYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT1361, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT1361_0, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SRGB, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SRGB_SYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT2020, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT2020_14, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE2084, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_ST428, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST428_1, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_HLG, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT2100_2_HLG, + }, +}; + +static struct matrix_coeff_info matrix_coeff_data_kalama[] = { + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_UNSPECIFIED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_VIDC_SRGB_OR_SMPTE_ST428, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SRGB_SMPTE_ST428_1, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_VIDC_FCC47_73_682, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_FCC_TITLE_47, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_SMPTE240M, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020_CONST_LUM, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT, + }, +}; + +static struct msm_platform_core_capability core_data_kalama[] = { + /* {type, value} */ + {ENC_CODECS, H264 | HEVC | HEIC}, + {DEC_CODECS, H264 | HEVC | VP9 | AV1 | HEIC}, + {MAX_SESSION_COUNT, 16}, + {MAX_NUM_720P_SESSIONS, 16}, + {MAX_NUM_1080P_SESSIONS, 16}, + {MAX_NUM_4K_SESSIONS, 8}, + {MAX_NUM_8K_SESSIONS, 2}, + {MAX_SECURE_SESSION_COUNT, 3}, + {MAX_RT_MBPF, 174080}, /* (8192x4352)/256 + (4096x2176)/256*/ + {MAX_MBPF, 278528}, /* ((8192x4352)/256) * 2 */ + {MAX_MBPS, 7833600}, + /* max_load + * 7680x4320@60fps or 3840x2176@240fps + * which is greater than 4096x2176@120fps, + * 8192x4320@48fps + */ + {MAX_IMAGE_MBPF, 1048576}, /* (16384x16384)/256 */ + {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */ + {MAX_MBPS_HQ, 489600}, /* ((1920x1088)/256)@60fps */ + {MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */ + {MAX_MBPS_B_FRAME, 1958400}, /* 3840x2176/256 MBs@60fps */ + {MAX_MBPS_ALL_INTRA, 1044480}, /* 4096x2176/256 MBs@30fps */ + {MAX_ENH_LAYER_COUNT, 5}, + {NUM_VPP_PIPE, 4}, + {SW_PC, 1}, + {FW_UNLOAD, 0}, + {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */ + {SW_PC_DELAY, SW_PC_DELAY_VALUE }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/ + {FW_UNLOAD_DELAY, FW_UNLOAD_DELAY_VALUE }, /* 3000 ms (>SW_PC_DELAY)*/ + {PAGEFAULT_NON_FATAL, 1}, + {PAGETABLE_CACHING, 0}, + {DCVS, 1}, + {DECODE_BATCH, 1}, + {DECODE_BATCH_TIMEOUT, 200}, + {STATS_TIMEOUT_MS, 2000}, + {AV_SYNC_WINDOW_SIZE, 40}, + {NON_FATAL_FAULTS, 1}, + {ENC_AUTO_FRAMERATE, 1}, + {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_META_CAPTURE | + V4L2_CAP_STREAMING}, + {SUPPORTS_SYNX_FENCE, 0}, + {SUPPORTS_REQUESTS, 0}, +}; + +static struct msm_platform_inst_capability instance_cap_data_kalama[] = { + /* {cap, domain, codec, + * min, max, step_or_mask, value, + * v4l2_id, + * hfi_id, + * flags} + */ + {DRV_VERSION, DEC | ENC, CODECS_ALL, + 0, INT_MAX, 1, DRIVER_VERSION, + V4L2_CID_MPEG_VIDC_DRIVER_VERSION}, + + {FRAME_WIDTH, DEC, CODECS_ALL, 96, 8192, 1, 1920}, + + {FRAME_WIDTH, DEC, VP9, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, CODECS_ALL, 128, 8192, 1, 1920}, + + {FRAME_WIDTH, ENC, HEVC, 96, 8192, 1, 1920}, + + {FRAME_WIDTH, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {LOSSLESS_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, DEC, CODECS_ALL, 96, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {FRAME_HEIGHT, DEC, CODECS_ALL, 96, 8192, 1, 1080}, + + {FRAME_HEIGHT, DEC, VP9, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, CODECS_ALL, 128, 8192, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEVC, 96, 8192, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {LOSSLESS_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, DEC, CODECS_ALL, 96, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {PIX_FMTS, ENC | DEC, H264, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC | DEC, HEVC | VP9 | AV1, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12}, + + {PIX_FMTS, DEC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_INPUT, ENC | DEC, HEIC, 0, 64, 1, 1, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL, + 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE}, + + /* (8192 * 4320) / 256 */ + {MBPF, ENC, CODECS_ALL, 64, 138240, 1, 138240}, + + {MBPF, ENC, HEVC, 36, 138240, 1, 138240}, + + /* ((16384x16384)/256) */ + {MBPF, ENC, HEIC, 36, 1048576, 1, 1048576}, + + {MBPF, DEC, CODECS_ALL, 36, 138240, 1, 138240}, + + /* (4096 * 2304) / 256 */ + {MBPF, DEC, VP9, 36, 36864, 1, 36864}, + + /* ((8192x8192)/256) */ + {MBPF, DEC, HEIC, 64, 262144, 1, 262144 }, + + /* (4096 * 2304) / 256 */ + {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 36864, 1, 36864}, + + /* Batch Mode Decode */ + /* TODO: update with new values based on updated voltage corner */ + {BATCH_MBPF, DEC, H264 | HEVC | VP9 | AV1, 64, 34816, 1, 34816}, + + /* (4096 * 2304) / 256 */ + {BATCH_FPS, DEC, H264 | HEVC | VP9 | AV1, 1, 120, 1, 120}, + + {SECURE_MBPF, ENC | DEC, H264 | HEVC | VP9 | AV1, 64, 36864, 1, 36864}, + + {SECURE_MBPF, ENC, HEVC, 36, 36864, 1, 36864}, + + {FRAME_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, ENC, HEIC, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (MINIMUM_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, DEC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_DEC_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {FRAME_RATE, DEC, VP9, + (MINIMUM_FPS << 16), (MAXIMUM_OVERRIDE_VP9_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {OPERATING_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16)}, + + {OPERATING_RATE, DEC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_DEC_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_OPERATING_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {OPERATING_RATE, DEC, VP9, + (MINIMUM_FPS << 16), (MAXIMUM_OVERRIDE_VP9_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_OPERATING_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {INPUT_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8}, + + {MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, VP9 | AV1, 60, 60, 1, 60}, + + {MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675}, + + {MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320}, + + {MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 489583, 489583, 1, 489583}, + + {MB_CYCLES_FW_VPP, ENC, CODECS_ALL, 48405, 48405, 1, 48405}, + + {MB_CYCLES_FW_VPP, DEC, CODECS_ALL, 66234, 66234, 1, 66234}, + + {CLIENT_ID, ENC | DEC, CODECS_ALL, + INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, + V4L2_CID_MPEG_VIDC_CLIENT_ID}, + + {SECURE_MODE, ENC | DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_SECURE, + HFI_PROP_SECURE, + CAP_FLAG_NONE}, + + /* + * Client will enable V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE + * to get fence_id in input metadata buffer done. + */ + {META_OUTBUF_FENCE, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE, + HFI_PROP_FENCE, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* + * Client to do set_ctrl with FENCE_ID to set fence_id + * and then client will do get_ctrl with FENCE_FD to get + * fence_fd corresponding to client set fence_id. + */ + {FENCE_ID, DEC, CODECS_ALL, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SW_FENCE_ID, + 0, + CAP_FLAG_DYNAMIC_ALLOWED | CAP_FLAG_OUTPUT_PORT}, + + {FENCE_FD, DEC, CODECS_ALL, + INVALID_FD, INT_MAX, 1, INVALID_FD, + V4L2_CID_MPEG_VIDC_SW_FENCE_FD, + 0, + CAP_FLAG_VOLATILE}, + + /* Fence type for input buffer. Currently unused */ + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_NONE, MSM_VIDC_FENCE_NONE, + BIT(MSM_VIDC_FENCE_NONE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_NONE, MSM_VIDC_SYNX_V2_FENCE, + BIT(MSM_VIDC_FENCE_NONE) | BIT(MSM_VIDC_SW_FENCE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* Fence direction for input buffer. Currently unused */ + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_NONE, + BIT(MSM_VIDC_FENCE_DIR_NONE), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_RX, + BIT(MSM_VIDC_FENCE_DIR_NONE) | BIT(MSM_VIDC_FENCE_DIR_TX), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + {TS_REORDER, DEC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TS_REORDER}, + + {HFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_HFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {VFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_VFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ROTATION, ENC, CODECS_ALL, + 0, 270, 90, 0, + V4L2_CID_ROTATE, + HFI_PROP_ROTATION, + CAP_FLAG_OUTPUT_PORT}, + + {SUPER_FRAME, ENC, H264 | HEVC, + 0, 32, 1, 0, + V4L2_CID_MPEG_VIDC_SUPERFRAME, 0, + CAP_FLAG_NONE}, + + {HEADER_MODE, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + HFI_PROP_SEQ_HEADER_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_MPEG_MSM_VIDC_ENABLE, + 1, V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDC_VUI_TIMING_INFO, + HFI_PROP_DISABLE_VUI_TIMING_INFO, + CAP_FLAG_OUTPUT_PORT}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_OUTPUT_PORT}, + + {WITHOUT_STARTCODE, DEC, AV1, + 0, 0, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_INPUT_PORT}, + + {NAL_LENGTH_FIELD, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_MPEG_VIDEO_HEVC_SIZE_4, + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) | + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4), + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* TODO: Firmware introduced enumeration type for this + * with and without seq header. + */ + {REQUEST_I_FRAME, ENC, H264 | HEVC, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + HFI_PROP_REQUEST_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* Enc: Keeping CABAC and CAVLC as same bitrate. + * Dec: there's no use of Bitrate cap + */ + {BIT_RATE, ENC, H264 | HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE, + HFI_PROP_TOTAL_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITRATE_MODE, ENC, H264, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {CAVLC_MAX_BITRATE, ENC, H264, 0, + 220000000, 1, 220000000}, + + {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0, + 245000000, 1, 245000000}, + + {LOWLATENCY_MAX_BITRATE, ENC, H264 | HEVC, 0, + 70000000, 1, 70000000}, + + {NUM_COMV, DEC, CODECS_ALL, + 0, INT_MAX, 1, 0}, + + {LOSSLESS, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU}, + + {FRAME_SKIP_MODE, ENC, H264 | HEVC | HEIC, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {FRAME_RC_ENABLE, ENC, H264 | HEVC | HEIC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE}, + + {CONSTANT_QUALITY, ENC, HEVC, + 1, MAX_CONSTANT_QUALITY, 1, 90, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CONSTANT_QUALITY, ENC, HEIC, + 1, MAX_CONSTANT_QUALITY, 1, 100, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, CODECS_ALL, + 0, INT_MAX, 1, 2 * DEFAULT_FPS - 1, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, HEIC, + 0, INT_MAX, 1, 0 /* all intra */, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_CLOSURE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + 0}, + + {B_FRAME, ENC, H264 | HEVC, + 0, 7, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {B_FRAME, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {BLUR_TYPES, ENC, H264 | HEVC, + MSM_VIDC_BLUR_NONE, MSM_VIDC_BLUR_EXTERNAL, + BIT(MSM_VIDC_BLUR_NONE) | BIT(MSM_VIDC_BLUR_EXTERNAL), + MSM_VIDC_BLUR_NONE, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_TYPES, + HFI_PROP_BLUR_TYPES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_RESOLUTION, + HFI_PROP_BLUR_RESOLUTION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CSC, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CSC, + HFI_PROP_CSC, + CAP_FLAG_OUTPUT_PORT}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX, + HFI_PROP_CSC_MATRIX, + CAP_FLAG_OUTPUT_PORT}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + 0, + CAP_FLAG_NONE}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {LTR_COUNT, ENC, H264 | HEVC, + 0, MAX_LTR_FRAME_COUNT_2, 1, 0, + V4L2_CID_MPEG_VIDEO_LTR_COUNT, + HFI_PROP_LTR_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {USE_LTR, ENC, H264 | HEVC, + 0, + ((1 << MAX_LTR_FRAME_COUNT_2) - 1), + 0, 0, + V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, + HFI_PROP_LTR_USE, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {MARK_LTR, ENC, H264 | HEVC, + INVALID_DEFAULT_MARK_OR_USE_LTR, + (MAX_LTR_FRAME_COUNT_2 - 1), + 1, INVALID_DEFAULT_MARK_OR_USE_LTR, + V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, + HFI_PROP_LTR_MARK, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {BASELAYER_PRIORITY, ENC, H264, + 0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0, + V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, + HFI_PROP_BASELAYER_PRIORITYID, + CAP_FLAG_OUTPUT_PORT}, + + {IR_TYPE, ENC, H264 | HEVC, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC, + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) | + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC), + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {IR_PERIOD, ENC, H264 | HEVC, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, + 0, + CAP_FLAG_INPUT_PORT | CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {AU_DELIMITER, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + HFI_PROP_AUD, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_CONTENT_ADAPTIVE_CODING, + HFI_PROP_CONTENT_ADAPTIVE_CODING, + CAP_FLAG_OUTPUT_PORT}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + MSM_VIDC_PREPROCESS_NONE, + MSM_VIDC_PREPROCESS_TYPE0, + BIT(MSM_VIDC_PREPROCESS_NONE) | + BIT(MSM_VIDC_PREPROCESS_TYPE0), + MSM_VIDC_PREPROCESS_NONE, + 0, HFI_PROP_REQUEST_PREPROCESS, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + 0, MAX_BITRATE_BOOST, 25, MAX_BITRATE_BOOST, + V4L2_CID_MPEG_VIDC_QUALITY_BITRATE_BOOST, + HFI_PROP_BITRATE_BOOST, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_QUALITY, ENC, H264 | HEVC, + 0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY, + 0, + HFI_PROP_MAINTAIN_MIN_QUALITY, + CAP_FLAG_OUTPUT_PORT}, + + {VBV_DELAY, ENC, H264 | HEVC, + 200, 300, 100, 300, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, + HFI_PROP_VBV_DELAY, + CAP_FLAG_OUTPUT_PORT}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + /* default peak bitrate is 10% larger than avg bitrate */ + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + HFI_PROP_TOTAL_PEAK_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {MIN_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP}, + + {I_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP}, + + {MAX_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MAX_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP}, + + {I_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP}, + + {I_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {I_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {LAYER_TYPE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_TYPE, ENC, H264, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_ENABLE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT}, + + {LAYER_ENABLE, ENC, HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {ENH_LAYER_COUNT, ENC, HEVC, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, ENC, H264, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, DEC, AV1, + 0, MAX_OP_POINT, 1, 0, + 0, + HFI_PROP_AV1_OP_POINT, + CAP_FLAG_INPUT_PORT}, + + {L0_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L3_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L3_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENTROPY_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + HFI_PROP_CABAC_SESSION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {ENTROPY_MODE, DEC, H264 | HEVC | VP9 | AV1, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + 0, + HFI_PROP_CABAC_SESSION}, + + {PROFILE, ENC | DEC, H264, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, ENC | DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE, + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_MPEG_VIDEO_VP9_PROFILE_2, + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, AV1, + V4L2_MPEG_VIDC_AV1_PROFILE_MAIN, + V4L2_MPEG_VIDC_AV1_PROFILE_MAIN, + BIT(V4L2_MPEG_VIDC_AV1_PROFILE_MAIN), + V4L2_MPEG_VIDC_AV1_PROFILE_MAIN, + V4L2_CID_MPEG_VIDC_AV1_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), + V4L2_MPEG_VIDEO_H264_LEVEL_6_1, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), + V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, AV1, + V4L2_MPEG_VIDC_AV1_LEVEL_2_0, + V4L2_MPEG_VIDC_AV1_LEVEL_6_1, + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_3) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_3) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_3) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_5_3) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_6_1), + V4L2_MPEG_VIDC_AV1_LEVEL_6_1, + V4L2_CID_MPEG_VIDC_AV1_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {AV1_TIER, DEC, AV1, + V4L2_MPEG_VIDC_AV1_TIER_MAIN, + V4L2_MPEG_VIDC_AV1_TIER_HIGH, + BIT(V4L2_MPEG_VIDC_AV1_TIER_MAIN) | + BIT(V4L2_MPEG_VIDC_AV1_TIER_HIGH), + V4L2_MPEG_VIDC_AV1_TIER_HIGH, + V4L2_CID_MPEG_VIDC_AV1_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEIC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN), + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + DB_H264_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + BIT(DB_H264_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + DB_HEVC_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) | + BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_ALPHA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA}, + + {LF_ALPHA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2}, + + {LF_BETA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA}, + + {LF_BETA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2}, + + {SLICE_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MAX_BYTES, ENC, H264 | HEVC, + MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE, + 1, MIN_SLICE_BYTE_SIZE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + HFI_PROP_MULTI_SLICE_BYTES_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {SLICE_MAX_MB, ENC, H264 | HEVC, + 1, MAX_SLICE_MB_SIZE, 1, 1, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + HFI_PROP_MULTI_SLICE_MB_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {MB_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {TRANSFORM_8X8, ENC, H264, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + HFI_PROP_8X8_TRANSFORM, + CAP_FLAG_OUTPUT_PORT}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET, + 1, MAX_CHROMA_QP_OFFSET, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + HFI_PROP_CHROMA_QP_OFFSET, + CAP_FLAG_OUTPUT_PORT}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + 0, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_8BIT, + CAP_FLAG_INPUT_PORT}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_10BIT, + CAP_FLAG_INPUT_PORT}, + + {STAGE, DEC | ENC, CODECS_ALL, + MSM_VIDC_STAGE_1, + MSM_VIDC_STAGE_2, 1, + MSM_VIDC_STAGE_2, + 0, + HFI_PROP_STAGE}, + + {PIPE, DEC | ENC, CODECS_ALL, + MSM_VIDC_PIPE_1, + MSM_VIDC_PIPE_4, 1, + MSM_VIDC_PIPE_4, + 0, + HFI_PROP_PIPE}, + + {POC, DEC, H264, + 0, 2, 1, 1, + 0, + HFI_PROP_PIC_ORDER_CNT_TYPE, + CAP_FLAG_VOLATILE}, + + {MAX_NUM_REORDER_FRAMES, DEC, H264 | HEVC, + 0, 16, 1, 0, + V4L2_CID_MPEG_VIDC_MAX_NUM_REORDER_FRAMES, + HFI_PROP_MAX_NUM_REORDER_FRAMES, + CAP_FLAG_VOLATILE}, + + {QUALITY_MODE, ENC, CODECS_ALL, + MSM_VIDC_MAX_QUALITY_MODE, + MSM_VIDC_POWER_SAVE_MODE, 1, + MSM_VIDC_POWER_SAVE_MODE}, + + {CODED_FRAMES, DEC, H264 | HEVC | HEIC, + CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE, + 1, CODED_FRAMES_PROGRESSIVE, + V4L2_CID_MPEG_VIDC_INTERLACE, + HFI_PROP_CODED_FRAMES, + CAP_FLAG_VOLATILE}, + + {BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8, + 0, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH}, + + {CODEC_CONFIG, DEC, H264 | HEVC | HEIC | AV1, 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CODEC_CONFIG, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_MIN_BITSTREAM_SIZE_OVERWRITE}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_THUMBNAIL_MODE, + HFI_PROP_THUMBNAIL_MODE, + CAP_FLAG_INPUT_PORT}, + + {DEFAULT_HEADER, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_DEC_DEFAULT_HEADER}, + + {RAP_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_DEC_START_FROM_RAP_FRAME, + CAP_FLAG_INPUT_PORT}, + + {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {PRIORITY, DEC | ENC, CODECS_ALL, + 0, 4, 1, 4, + V4L2_CID_MPEG_VIDC_PRIORITY, + HFI_PROP_SESSION_PRIORITY, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + 1, 1, 1, 1}, + + {CRITICAL_PRIORITY, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CRITICAL_PRIORITY}, + + {RESERVE_DURATION, ENC, CODECS_ALL, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_RESERVE_DURATION, + HFI_CMD_RESERVE, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENC_IP_CR, ENC, CODECS_ALL, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_ENC_INPUT_COMPRESSION_RATIO, + 0, CAP_FLAG_DYNAMIC_ALLOWED}, + + {FILM_GRAIN, DEC, AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_AV1D_FILM_GRAIN_PRESENT, + HFI_PROP_AV1_FILM_GRAIN_PRESENT, + CAP_FLAG_VOLATILE}, + + {SUPER_BLOCK, DEC, AV1, + 0, 1, 1, 0, + 0, + HFI_PROP_AV1_SUPER_BLOCK_ENABLED}, + + {DRAP, DEC, AV1, + 0, S32_MAX, 1, 0, + 0, + HFI_PROP_AV1_DRAP_CONFIG, + CAP_FLAG_INPUT_PORT}, + + {LAST_FLAG_EVENT_ENABLE, DEC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LAST_FLAG_EVENT_ENABLE}, + + {META_BITSTREAM_RESOLUTION, DEC, AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BITSTREAM_RESOLUTION, + HFI_PROP_BITSTREAM_RESOLUTION, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_CROP_OFFSETS, DEC, AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_CROP_OFFSETS, + HFI_PROP_CROP_OFFSETS, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {ALL_INTRA, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {META_LTR_MARK_USE, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_LTR_MARK_USE_DETAILS, + HFI_PROP_LTR_MARK_USE_DETAILS, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEQ_HDR_NAL, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEQ_HEADER_NAL, + HFI_PROP_METADATA_SEQ_HEADER_NAL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DPB_MISR, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_LUMA_CHROMA_MISR, + HFI_PROP_DPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_OPB_MISR, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OPB_LUMA_CHROMA_MISR, + HFI_PROP_OPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_INTERLACE, DEC, H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_INTERLACE, + HFI_PROP_INTERLACE_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TIMESTAMP, DEC | ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TIMESTAMP, + HFI_PROP_TIMESTAMP, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_CONCEALED_MB_CNT, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_CONCEALED_MB_COUNT, + HFI_PROP_CONEALED_MB_COUNT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HIST_INFO, DEC, HEVC|AV1|VP9, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HISTOGRAM_INFO, + HFI_PROP_HISTOGRAM_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TRANSCODING_STAT_INFO, DEC, HEVC|H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TRANSCODE_STAT_INFO, + HFI_PROP_TRANSCODING_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TRANSCODING_STAT_INFO, ENC, HEVC|H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TRANSCODE_STAT_INFO, + HFI_PROP_TRANSCODING_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_PICTURE_TYPE, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_PICTURE_TYPE, + HFI_PROP_PICTURE_TYPE, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_MASTERING_DISP, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_MASTERING_DISP, DEC, HEVC | HEIC | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, DEC, HEVC | HEIC | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, DEC, HEVC | HEIC | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DOLBY_RPU, ENC, HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DOLBY_RPU, + HFI_PROP_DOLBY_RPU_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DOLBY_RPU, DEC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DOLBY_RPU, + HFI_PROP_DOLBY_RPU_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_EVA_STATS, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_EVA_STATS, + HFI_PROP_EVA_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_BUF_TAG, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + /* + * when fence enabled, client needs output buffer_tag + * in input metadata buffer done. + */ + {META_BUF_TAG, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_TX_OUTPUT | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DPB_TAG_LIST, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_TAG_LIST, + HFI_PROP_DPB_TAG_LIST, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, ENC, HEIC | H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ENC_QP_METADATA, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ENC_QP_METADATA, + HFI_PROP_ENC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ROI_INFO, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ROI_INFO, + HFI_PROP_ROI_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SALIENCY_INFO, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SALIENCY_INFO, + HFI_PROP_ROI_AS_SALIENCY_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DEC_QP_METADATA, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DEC_QP_METADATA, + HFI_PROP_DEC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {GRID_ENABLE, ENC, HEIC, + 0, 1, 1, 1, + 0, + HFI_PROP_HEIC_GRID_ENABLE, + CAP_FLAG_OUTPUT_PORT}, + + {GRID_SIZE, ENC, HEIC, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH * 2, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH, + V4L2_CID_MPEG_VIDC_GRID_WIDTH}, + + {COMPLEXITY, ENC, H264 | HEVC, + 0, 100, + 1, DEFAULT_COMPLEXITY, + V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY}, + + {META_MAX_NUM_REORDER_FRAMES, DEC, HEVC | H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_MAX_NUM_REORDER_FRAMES, + HFI_PROP_MAX_NUM_REORDER_FRAMES, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {DELIVERY_MODE, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_HEVC_ENCODE_DELIVERY_MODE, + HFI_PROP_ENABLE_SLICE_DELIVERY, + CAP_FLAG_OUTPUT_PORT}, + + {DELIVERY_MODE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_H264_ENCODE_DELIVERY_MODE, + HFI_PROP_ENABLE_SLICE_DELIVERY, + CAP_FLAG_OUTPUT_PORT}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SIGNAL_COLOR_INFO, + HFI_PROP_SIGNAL_COLOR_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, +}; + +static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_kalama[] = { + /* {cap, domain, codec, + * parents, + * children, + * adjust, set} + */ + + {PIX_FMTS, ENC, H264, + {META_ROI_INFO, IR_PERIOD}}, + + {PIX_FMTS, ENC, HEVC, + {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, META_ROI_INFO, MIN_QUALITY, BLUR_TYPES, IR_PERIOD, + LTR_COUNT}}, + + {PIX_FMTS, ENC, HEIC, + {PROFILE}}, + + {PIX_FMTS, DEC, HEVC | HEIC, + {PROFILE}}, + + {FRAME_RATE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_q16}, + + {FRAME_RATE, DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_dec_frame_rate}, + + {OPERATING_RATE, DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_dec_operating_rate}, + + {SECURE_MODE, ENC | DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {META_OUTBUF_FENCE, DEC, H264 | HEVC | VP9 | AV1, + {LOWLATENCY_MODE, OUTBUF_FENCE_TYPE, OUTBUF_FENCE_DIRECTION}, + NULL, + NULL}, + + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + {0}, + msm_vidc_adjust_dec_outbuf_fence_type, + msm_vidc_set_outbuf_fence_type}, + + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + {0}, + msm_vidc_adjust_dec_outbuf_fence_direction, + msm_vidc_set_outbuf_fence_direction}, + + {HFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {VFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {ROTATION, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_rotation}, + + {SUPER_FRAME, ENC, H264 | HEVC, + {INPUT_BUF_HOST_MAX_COUNT, OUTPUT_BUF_HOST_MAX_COUNT}, + NULL, + NULL}, + + {HEADER_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_header_mode}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_nal_length}, + + {WITHOUT_STARTCODE, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {REQUEST_I_FRAME, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_req_sync_frame}, + + {BIT_RATE, ENC, H264 | HEVC, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BITRATE_MODE, ENC, H264, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE, + META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEVC, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT, + BIT_RATE, META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEIC, + {TIME_DELTA_BASED_RC, CONSTANT_QUALITY}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {CONSTANT_QUALITY, ENC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_constant_quality}, + + {GOP_SIZE, ENC, CODECS_ALL, + {ALL_INTRA}, + msm_vidc_adjust_gop_size, + msm_vidc_set_gop_size}, + + {GOP_SIZE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {B_FRAME, ENC, H264 | HEVC, + {ALL_INTRA}, + msm_vidc_adjust_b_frame, + msm_vidc_set_u32}, + + {B_FRAME, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {BLUR_TYPES, ENC, H264 | HEVC, + {BLUR_RESOLUTION}, + msm_vidc_adjust_blur_type, + msm_vidc_set_u32_enum}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_blur_resolution, + msm_vidc_set_blur_resolution}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_csc_custom_matrix}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + {STAGE, BIT_RATE}, + msm_vidc_adjust_enc_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9 | AV1, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LTR_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ltr_count, + msm_vidc_set_u32}, + + {USE_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_use_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {MARK_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_mark_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {IR_PERIOD, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ir_period, + msm_vidc_set_ir_period}, + + {AU_DELIMITER, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_u32}, + + {TIME_DELTA_BASED_RC, ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_delta_based_rc, + msm_vidc_set_u32}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + {REQUEST_PREPROCESS}, + msm_vidc_adjust_brs, + msm_vidc_set_vbr_related_properties}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_preprocess, + msm_vidc_set_preprocess}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_bitrate_boost_iris3, + msm_vidc_set_vbr_related_properties}, + + {MIN_QUALITY, ENC, H264, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {MIN_QUALITY, ENC, HEVC, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {VBV_DELAY, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_cbr_related_properties}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_peak_bitrate, + msm_vidc_set_cbr_related_properties}, + + {MIN_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_min_qp}, + + {MIN_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_min_qp, + msm_vidc_set_min_qp}, + + {MAX_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_max_qp}, + + {MAX_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_max_qp, + msm_vidc_set_max_qp}, + + {I_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_i_frame_qp, + msm_vidc_set_frame_qp}, + + {I_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_p_frame_qp, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_b_frame_qp, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {LAYER_TYPE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING, LTR_COUNT}}, + + {LAYER_ENABLE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING}}, + + {ENH_LAYER_COUNT, ENC, H264 | HEVC, + {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE, + LTR_COUNT}, + msm_vidc_adjust_layer_count, + msm_vidc_set_layer_count_and_type}, + + {ENH_LAYER_COUNT, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {L0_BR, ENC, H264 | HEVC, + {L1_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L1_BR, ENC, H264 | HEVC, + {L2_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L2_BR, ENC, H264 | HEVC, + {L3_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L3_BR, ENC, H264 | HEVC, + {L4_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L4_BR, ENC, H264 | HEVC, + {L5_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L5_BR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {ENTROPY_MODE, ENC, H264, + {BIT_RATE}, + msm_vidc_adjust_entropy_mode, + msm_vidc_set_u32}, + + {PROFILE, ENC, H264, + {ENTROPY_MODE, TRANSFORM_8X8}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, H264, + {ENTROPY_MODE}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, ENC | DEC, HEVC | HEIC, + {0}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, VP9 | AV1, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_level}, + + {AV1_TIER, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {HEVC_TIER, ENC | DEC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LF_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_deblock_mode}, + + {SLICE_MODE, ENC, H264 | HEVC, + {STAGE, DELIVERY_MODE}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {SLICE_MODE, ENC, HEIC, + {0}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {TRANSFORM_8X8, ENC, H264, + {0}, + msm_vidc_adjust_transform_8x8, + msm_vidc_set_u32}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + {0}, + msm_vidc_adjust_chroma_qp_index_offset, + msm_vidc_set_chroma_qp_index_offset}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9 | AV1, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9 | AV1, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9 | AV1, + {0}, + msm_vidc_adjust_output_order, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {STAGE, ENC | DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_stage}, + + {PIPE, DEC | ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_pipe}, + + {THUMBNAIL_MODE, DEC, H264 | HEVC | VP9 | AV1, + {OUTPUT_ORDER}, + NULL, + msm_vidc_set_u32}, + + {THUMBNAIL_MODE, DEC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {RAP_FRAME, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32}, + + {PRIORITY, DEC | ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_session_priority, + msm_vidc_set_session_priority}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + {0}, + NULL, + NULL}, + + {CRITICAL_PRIORITY, ENC, CODECS_ALL, + {0}, + NULL, + NULL}, + + {RESERVE_DURATION, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_reserve_duration}, + + {DRAP, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {ALL_INTRA, ENC, H264 | HEVC, + {LTR_COUNT, IR_PERIOD, SLICE_MODE, BIT_RATE}, + msm_vidc_adjust_all_intra, + NULL}, + + {META_EVA_STATS, ENC, H264 | HEVC, + {ENH_LAYER_COUNT, REQUEST_PREPROCESS}}, + + {META_EVA_STATS, ENC, HEIC, + {0}}, + + {META_ROI_INFO, ENC, H264 | HEVC, + {MIN_QUALITY, IR_PERIOD, BLUR_TYPES}, + msm_vidc_adjust_roi_info, + NULL}, + + {GRID_ENABLE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {DELIVERY_MODE, ENC, H264 | HEVC, + {LOWLATENCY_MODE, OUTPUT_BUF_HOST_MAX_COUNT}, + msm_vidc_adjust_delivery_mode, + msm_vidc_set_u32}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_vui_timing_info}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_signal_color_info}, +}; + +/* Default UBWC config for LPDDR5 */ +static struct msm_vidc_ubwc_config_data ubwc_config_kalama[] = { + UBWC_CONFIG(8, 32, 16, 0, 1, 1, 1), +}; + +static struct msm_vidc_format_capability format_data_kalama = { + .codec_info = codec_data_kalama, + .codec_info_size = ARRAY_SIZE(codec_data_kalama), + .color_format_info = color_format_data_kalama, + .color_format_info_size = ARRAY_SIZE(color_format_data_kalama), + .color_prim_info = color_primaries_data_kalama, + .color_prim_info_size = ARRAY_SIZE(color_primaries_data_kalama), + .transfer_char_info = transfer_char_data_kalama, + .transfer_char_info_size = ARRAY_SIZE(transfer_char_data_kalama), + .matrix_coeff_info = matrix_coeff_data_kalama, + .matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_kalama), +}; + +/* name, min_kbps, max_kbps */ +static const struct bw_table kalama_bw_table[] = { + { "venus-cnoc", 1000, 1000 }, + { "venus-ddr", 1000, 15000000 }, + { "venus-llcc", 1000, 15000000 }, +}; + +/* name, hw_trigger */ +static const struct regulator_table kalama_regulator_table[] = { + { "iris-ctl", 0 }, + { "vcodec", 1 }, +}; + +/* name, clock id, scaling */ +static const struct clk_table kalama_clk_table[] = { + { "gcc_video_axi0", GCC_VIDEO_AXI0_CLK, 0 }, + { "core_clk", VIDEO_CC_MVS0C_CLK, 0 }, + { "vcodec_clk", VIDEO_CC_MVS0_CLK, 0 }, + { "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 }, +}; + +/* name, exclusive_release */ +static const struct clk_rst_table kalama_clk_reset_table[] = { + { "video_axi_reset", 0 }, +}; + +/* name, llcc_id */ +static const struct subcache_table kalama_subcache_table[] = { + { "vidsc0", LLCC_VIDSC0 }, + { "vidvsp", LLCC_VIDVSP }, +}; + +/* name, start, size, secure, dma_coherant, region, dma_mask */ +const struct context_bank_table kalama_context_bank_table[] = { + {"qcom,vidc,cb-ns", 0x25800000, 0xba800000, 0, 1, MSM_VIDC_NON_SECURE, 0 }, + {"qcom,vidc,cb-ns-pxl", 0x00100000, 0xdff00000, 0, 1, MSM_VIDC_NON_SECURE_PIXEL, 0 }, + {"qcom,vidc,cb-sec-pxl", 0x00500000, 0xdfb00000, 1, 0, MSM_VIDC_SECURE_PIXEL, 0 }, + {"qcom,vidc,cb-sec-non-pxl", 0x01000000, 0x24800000, 1, 0, MSM_VIDC_SECURE_NONPIXEL, 0 }, + {"qcom,vidc,cb-sec-bitstream", 0x00500000, 0xdfb00000, 1, 0, MSM_VIDC_SECURE_BITSTREAM, 0 }, +}; + +/* freq */ +static struct freq_table kalama_freq_table[] = { + {481000000}, {444000000}, {366000000}, {338000000}, {240000000} +}; + +static struct freq_table kalama_freq_table_v2[] = { + {533333333}, {444000000}, {366000000}, {338000000}, {240000000} +}; + +/* register, value, mask */ +static const struct reg_preset_table kalama_reg_preset_table[] = { + { 0xB0088, 0x0, 0x11 }, +}; + +/* decoder properties */ +static const u32 kalama_vdec_psc_avc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_CODED_FRAMES, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PIC_ORDER_CNT_TYPE, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 kalama_vdec_psc_hevc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_TIER, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 kalama_vdec_psc_vp9[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, +}; + +static const u32 kalama_vdec_psc_av1[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_AV1_FILM_GRAIN_PRESENT, + HFI_PROP_AV1_SUPER_BLOCK_ENABLED, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_TIER, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 kalama_vdec_input_properties_avc[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, +}; + +static const u32 kalama_vdec_input_properties_hevc[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, +}; + +static const u32 kalama_vdec_input_properties_vp9[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, +}; + +static const u32 kalama_vdec_input_properties_av1[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, + HFI_PROP_AV1_TILE_ROWS_COLUMNS, + HFI_PROP_AV1_UNIFORM_TILE_SPACING, +}; + +static const u32 kalama_vdec_output_properties_avc[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_DPB_LIST, + HFI_PROP_CABAC_SESSION, + HFI_PROP_FENCE, +}; + +static const u32 kalama_vdec_output_properties_hevc[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_DPB_LIST, + HFI_PROP_FENCE, +}; + +static const u32 kalama_vdec_output_properties_vp9[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_DPB_LIST, + HFI_PROP_FENCE, +}; + +static const u32 kalama_vdec_output_properties_av1[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_DPB_LIST, + HFI_PROP_FENCE, +}; + +static const u32 kalama_msm_vidc_ssr_type[] = { + HFI_SSR_TYPE_SW_ERR_FATAL, + HFI_SSR_TYPE_SW_DIV_BY_ZERO, + HFI_SSR_TYPE_CPU_WDOG_IRQ, + HFI_SSR_TYPE_NOC_ERROR, +}; + +static const struct msm_vidc_platform_data kalama_data = { + /* resources dependent on other module */ + .bw_tbl = kalama_bw_table, + .bw_tbl_size = ARRAY_SIZE(kalama_bw_table), + .regulator_tbl = kalama_regulator_table, + .regulator_tbl_size = ARRAY_SIZE(kalama_regulator_table), + .clk_tbl = kalama_clk_table, + .clk_tbl_size = ARRAY_SIZE(kalama_clk_table), + .clk_rst_tbl = kalama_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(kalama_clk_reset_table), + .subcache_tbl = kalama_subcache_table, + .subcache_tbl_size = ARRAY_SIZE(kalama_subcache_table), + + /* populate context bank */ + .context_bank_tbl = kalama_context_bank_table, + .context_bank_tbl_size = ARRAY_SIZE(kalama_context_bank_table), + + /* platform specific resources */ + .freq_tbl = kalama_freq_table, + .freq_tbl_size = ARRAY_SIZE(kalama_freq_table), + .reg_prst_tbl = kalama_reg_preset_table, + .reg_prst_tbl_size = ARRAY_SIZE(kalama_reg_preset_table), + .fwname = "vpu30_4v", + .pas_id = 9, + .supports_mmrm = 1, + + /* caps related resorces */ + .core_data = core_data_kalama, + .core_data_size = ARRAY_SIZE(core_data_kalama), + .inst_cap_data = instance_cap_data_kalama, + .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_kalama), + .inst_cap_dependency_data = instance_cap_dependency_data_kalama, + .inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_kalama), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .ubwc_config = ubwc_config_kalama, + .format_data = &format_data_kalama, + + /* decoder properties related*/ + .psc_avc_tbl = kalama_vdec_psc_avc, + .psc_avc_tbl_size = ARRAY_SIZE(kalama_vdec_psc_avc), + .psc_hevc_tbl = kalama_vdec_psc_hevc, + .psc_hevc_tbl_size = ARRAY_SIZE(kalama_vdec_psc_hevc), + .psc_vp9_tbl = kalama_vdec_psc_vp9, + .psc_vp9_tbl_size = ARRAY_SIZE(kalama_vdec_psc_vp9), + .psc_av1_tbl = kalama_vdec_psc_av1, + .psc_av1_tbl_size = ARRAY_SIZE(kalama_vdec_psc_av1), + .dec_input_prop_avc = kalama_vdec_input_properties_avc, + .dec_input_prop_hevc = kalama_vdec_input_properties_hevc, + .dec_input_prop_vp9 = kalama_vdec_input_properties_vp9, + .dec_input_prop_av1 = kalama_vdec_input_properties_av1, + .dec_input_prop_size_avc = ARRAY_SIZE(kalama_vdec_input_properties_avc), + .dec_input_prop_size_hevc = ARRAY_SIZE(kalama_vdec_input_properties_hevc), + .dec_input_prop_size_vp9 = ARRAY_SIZE(kalama_vdec_input_properties_vp9), + .dec_input_prop_size_av1 = ARRAY_SIZE(kalama_vdec_input_properties_av1), + .dec_output_prop_avc = kalama_vdec_output_properties_avc, + .dec_output_prop_hevc = kalama_vdec_output_properties_hevc, + .dec_output_prop_vp9 = kalama_vdec_output_properties_vp9, + .dec_output_prop_av1 = kalama_vdec_output_properties_av1, + .dec_output_prop_size_avc = ARRAY_SIZE(kalama_vdec_output_properties_avc), + .dec_output_prop_size_hevc = ARRAY_SIZE(kalama_vdec_output_properties_hevc), + .dec_output_prop_size_vp9 = ARRAY_SIZE(kalama_vdec_output_properties_vp9), + .dec_output_prop_size_av1 = ARRAY_SIZE(kalama_vdec_output_properties_av1), + + .msm_vidc_ssr_type = kalama_msm_vidc_ssr_type, + .msm_vidc_ssr_type_size = ARRAY_SIZE(kalama_msm_vidc_ssr_type), + +}; + +static const struct msm_vidc_platform_data kalama_data_v2 = { + /* resources dependent on other module */ + .bw_tbl = kalama_bw_table, + .bw_tbl_size = ARRAY_SIZE(kalama_bw_table), + .regulator_tbl = kalama_regulator_table, + .regulator_tbl_size = ARRAY_SIZE(kalama_regulator_table), + .clk_tbl = kalama_clk_table, + .clk_tbl_size = ARRAY_SIZE(kalama_clk_table), + .clk_rst_tbl = kalama_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(kalama_clk_reset_table), + .subcache_tbl = kalama_subcache_table, + .subcache_tbl_size = ARRAY_SIZE(kalama_subcache_table), + + /* populate context bank */ + .context_bank_tbl = kalama_context_bank_table, + .context_bank_tbl_size = ARRAY_SIZE(kalama_context_bank_table), + + /* platform specific resources */ + .freq_tbl = kalama_freq_table_v2, + .freq_tbl_size = ARRAY_SIZE(kalama_freq_table_v2), + .reg_prst_tbl = kalama_reg_preset_table, + .reg_prst_tbl_size = ARRAY_SIZE(kalama_reg_preset_table), + .fwname = "vpu30_4v", + .pas_id = 9, + .supports_mmrm = 1, + + /* caps related resorces */ + .core_data = core_data_kalama, + .core_data_size = ARRAY_SIZE(core_data_kalama), + .inst_cap_data = instance_cap_data_kalama, + .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_kalama), + .inst_cap_dependency_data = instance_cap_dependency_data_kalama, + .inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_kalama), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .ubwc_config = ubwc_config_kalama, + .format_data = &format_data_kalama, +}; + +int msm_vidc_kalama_check_ddr_type(void) +{ + u32 ddr_type; + + ddr_type = of_fdt_get_ddrtype(); + if (ddr_type != DDR_TYPE_LPDDR5 && + ddr_type != DDR_TYPE_LPDDR5X) { + d_vpr_e("%s: wrong ddr type %d\n", __func__, ddr_type); + return -EINVAL; + } else { + d_vpr_h("%s: ddr type %d\n", __func__, ddr_type); + } + return 0; +} + +static int msm_vidc_init_data(struct msm_vidc_core *core) +{ + struct device *dev = NULL; + int rc = 0; + + dev = &core->pdev->dev; + + d_vpr_h("%s: initialize kalama data\n", __func__); + + if (of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc-v2")) + core->platform->data = kalama_data_v2; + else + core->platform->data = kalama_data; + + core->mem_ops = get_mem_ops_ext(); + if (!core->mem_ops) { + d_vpr_e("%s: invalid memory ext ops\n", __func__); + return -EINVAL; + } + core->res_ops = get_res_ops_ext(); + if (!core->res_ops) { + d_vpr_e("%s: invalid resource ext ops\n", __func__); + return -EINVAL; + } + rc = msm_vidc_kalama_check_ddr_type(); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_init_platform_kalama(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = msm_vidc_init_data(core); + if (rc) + return rc; + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/platform/pineapple/inc/msm_vidc_pineapple.h b/qcom/opensource/video-driver/driver/platform/pineapple/inc/msm_vidc_pineapple.h new file mode 100644 index 0000000000..9f474bbf60 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/pineapple/inc/msm_vidc_pineapple.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_PINEAPPLE_H_ +#define _MSM_VIDC_PINEAPPLE_H_ + +#include "msm_vidc_core.h" + +#if defined(CONFIG_MSM_VIDC_PINEAPPLE) +int msm_vidc_init_platform_pineapple(struct msm_vidc_core *core); +#else +int msm_vidc_init_platform_pineapple(struct msm_vidc_core *core) +{ + return -EINVAL; +} +#endif + +#endif // _MSM_VIDC_PINEAPPLE_H_ diff --git a/qcom/opensource/video-driver/driver/platform/pineapple/src/msm_vidc_pineapple.c b/qcom/opensource/video-driver/driver/platform/pineapple/src/msm_vidc_pineapple.c new file mode 100644 index 0000000000..e7024e08f8 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/pineapple/src/msm_vidc_pineapple.c @@ -0,0 +1,3026 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include + +#include +#include + +#include +#include "msm_vidc_pineapple.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_platform_ext.h" +#include "msm_vidc_memory_ext.h" +#include "msm_vidc_synx.h" +#include "resources_ext.h" +#include "msm_vidc_iris33.h" +#include "hfi_property.h" +#include "hfi_command.h" +#include "venus_hfi.h" + +/* version: major[24:31], minor[16:23], revision[0:15] */ +#define DRIVER_VERSION 0x04000000 +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010 +#define MAX_BASE_LAYER_PRIORITY_ID 63 +#define MAX_OP_POINT 31 +#define MAX_BITRATE 245000000 +#define DEFAULT_BITRATE 20000000 +#define MINIMUM_FPS 1 +#define MAXIMUM_FPS 480 +#define MAXIMUM_DEC_FPS 960 +#define MAX_QP 51 +#define DEFAULT_QP 20 +#define MAX_CONSTANT_QUALITY 100 +#define MIN_SLICE_BYTE_SIZE 512 +#define MAX_SLICE_BYTE_SIZE \ + ((MAX_BITRATE) >> 3) +#define MAX_SLICE_MB_SIZE \ + (((4096 + 15) >> 4) * ((2304 + 15) >> 4)) + +#define ENC MSM_VIDC_ENCODER +#define DEC MSM_VIDC_DECODER +#define H264 MSM_VIDC_H264 +#define HEVC MSM_VIDC_HEVC +#define VP9 MSM_VIDC_VP9 +#define AV1 MSM_VIDC_AV1 +#define HEIC MSM_VIDC_HEIC +#define CODECS_ALL (H264 | HEVC | VP9 | HEIC | AV1) +#define MAXIMUM_OVERRIDE_VP9_FPS 200 + +static struct codec_info codec_data_pineapple[] = { + { + .v4l2_codec = V4L2_PIX_FMT_H264, + .vidc_codec = MSM_VIDC_H264, + .pixfmt_name = "AVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_HEVC, + .vidc_codec = MSM_VIDC_HEVC, + .pixfmt_name = "HEVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VP9, + .vidc_codec = MSM_VIDC_VP9, + .pixfmt_name = "VP9", + }, + { + .v4l2_codec = V4L2_PIX_FMT_AV1, + .vidc_codec = MSM_VIDC_AV1, + .pixfmt_name = "AV1", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VIDC_HEIC, + .vidc_codec = MSM_VIDC_HEIC, + .pixfmt_name = "HEIC", + }, +}; + +static struct color_format_info color_format_data_pineapple[] = { + { + .v4l2_color_format = V4L2_PIX_FMT_NV12, + .vidc_color_format = MSM_VIDC_FMT_NV12, + .pixfmt_name = "NV12", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_NV21, + .vidc_color_format = MSM_VIDC_FMT_NV21, + .pixfmt_name = "NV21", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC08C, + .vidc_color_format = MSM_VIDC_FMT_NV12C, + .pixfmt_name = "NV12C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC10C, + .vidc_color_format = MSM_VIDC_FMT_TP10C, + .pixfmt_name = "TP10C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_RGBA32, + .vidc_color_format = MSM_VIDC_FMT_RGBA8888, + .pixfmt_name = "RGBA", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_P010, + .vidc_color_format = MSM_VIDC_FMT_P010, + .pixfmt_name = "P010", + }, + { + .v4l2_color_format = V4L2_META_FMT_VIDC, + .vidc_color_format = MSM_VIDC_FMT_META, + .pixfmt_name = "META", + }, +}; + +static struct color_primaries_info color_primaries_data_pineapple[] = { + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_RESERVED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_UNSPECIFIED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_REC709, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT709, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_BG, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE170M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT601_525, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE240M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_ST240M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_GENERIC_FILM, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_GENERIC_FILM, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_BT2020, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT2020, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DCI_P3, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_RP431_2, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_EG431, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_EG431_1, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_EBU_TECH, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_EBU_TECH, + }, +}; + +static struct transfer_char_info transfer_char_data_pineapple[] = { + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_RESERVED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_UNSPECIFIED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_709, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT709, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT470_SYSTEM_M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT470_SYSTEM_M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT470_SYSTEM_BG, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT470_SYSTEM_BG, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT601_525_OR_625, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT601_525_OR_625, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE240M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST240M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_LINEAR, + .vidc_transfer_char = MSM_VIDC_TRANSFER_LINEAR, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_XVYCC, + .vidc_transfer_char = MSM_VIDC_TRANSFER_XVYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT1361, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT1361_0, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SRGB, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SRGB_SYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT2020, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT2020_14, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE2084, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_ST428, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST428_1, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_HLG, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT2100_2_HLG, + }, +}; + +static struct matrix_coeff_info matrix_coeff_data_pineapple[] = { + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_UNSPECIFIED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_VIDC_SRGB_OR_SMPTE_ST428, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SRGB_SMPTE_ST428_1, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_VIDC_FCC47_73_682, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_FCC_TITLE_47, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_SMPTE240M, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020_CONST_LUM, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT, + }, +}; + +static struct msm_platform_core_capability core_data_pineapple[] = { + /* {type, value} */ + {ENC_CODECS, H264 | HEVC | HEIC}, + {DEC_CODECS, H264 | HEVC | VP9 | AV1 | HEIC}, + {MAX_SESSION_COUNT, 16}, + {MAX_NUM_720P_SESSIONS, 16}, + {MAX_NUM_1080P_SESSIONS, 16}, + {MAX_NUM_4K_SESSIONS, 8}, + {MAX_NUM_8K_SESSIONS, 2}, + {MAX_SECURE_SESSION_COUNT, 3}, + {MAX_RT_MBPF, 259200}, /* ((7680x4320)/256) * 2)*/ + {MAX_MBPF, 278528}, /* ((8192x4352)/256) * 2 */ + {MAX_MBPS, 7833600}, + /* max_load + * 7680x4320@60fps or 3840x2176@240fps + * which is greater than 4096x2176@120fps, + * 8192x4320@48fps + */ + {MAX_IMAGE_MBPF, 1048576}, /* (16384x16384)/256 */ + {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */ + {MAX_MBPS_HQ, 489600}, /* ((1920x1088)/256)@60fps */ + {MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */ + {MAX_MBPS_B_FRAME, 1958400}, /* 3840x2176/256 MBs@60fps */ + {MAX_MBPS_ALL_INTRA, 1044480}, /* 4096x2176/256 MBs@30fps */ + {MAX_ENH_LAYER_COUNT, 5}, + {NUM_VPP_PIPE, 4}, + {SW_PC, 1}, + {FW_UNLOAD, 0}, + {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */ + {SW_PC_DELAY, SW_PC_DELAY_VALUE }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/ + {FW_UNLOAD_DELAY, FW_UNLOAD_DELAY_VALUE }, /* 3000 ms (>SW_PC_DELAY)*/ + {PAGEFAULT_NON_FATAL, 1}, + {PAGETABLE_CACHING, 0}, + {DCVS, 1}, + {DECODE_BATCH, 1}, + {DECODE_BATCH_TIMEOUT, 200}, + {STATS_TIMEOUT_MS, 2000}, + {AV_SYNC_WINDOW_SIZE, 40}, + {NON_FATAL_FAULTS, 1}, + {ENC_AUTO_FRAMERATE, 1}, + {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_META_CAPTURE | + V4L2_CAP_STREAMING}, + {SUPPORTS_SYNX_FENCE, 1}, + {SUPPORTS_REQUESTS, 0}, +}; + +static int msm_vidc_set_ring_buffer_count_pineapple(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + struct v4l2_format *output_fmt, *input_fmt; + struct msm_vidc_core *core; + u32 count = 0, data_size = 0, pixel_count = 0, fps = 0; + u32 frame_rate = 0, operating_rate = 0; + + core = inst->core; + output_fmt = &inst->fmts[OUTPUT_PORT]; + input_fmt = &inst->fmts[INPUT_PORT]; + + frame_rate = inst->capabilities[FRAME_RATE].value >> 16; + operating_rate = inst->capabilities[OPERATING_RATE].value >> 16; + fps = max(frame_rate, operating_rate); + pixel_count = output_fmt->fmt.pix_mp.width * + output_fmt->fmt.pix_mp.height; + + /* + * try to enable ring buffer feature if +  * resolution >= 8k and fps >= 30fps and +  * resolution >= 4k and fps >= 120fps and +  * resolution >= 1080p and fps >= 480fps and +  * resolution >= 720p and fps >= 960fps + */ + if ((pixel_count >= 7680 * 4320 && fps >= 30) || + (pixel_count >= 3840 * 2160 && fps >= 120) || + (pixel_count >= 1920 * 1080 && fps >= 480) || + (pixel_count >= 1280 * 720 && fps >= 960)) { + data_size = input_fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + i_vpr_h(inst, "%s: calculate ring buffer count\n", __func__); + rc = call_session_op(core, ring_buf_count, inst, data_size); + if (rc) { + i_vpr_e(inst, "%s: failed to calculate ring buffer count\n", + __func__); + /* ignore error */ + rc = 0; + inst->capabilities[cap_id].value = 0; + } + } else { + i_vpr_h(inst, + "%s: session %ux%u@%u fps does not support ring buffer\n", + __func__, output_fmt->fmt.pix_mp.width, + output_fmt->fmt.pix_mp.height, fps); + inst->capabilities[cap_id].value = 0; + } + + count = inst->capabilities[cap_id].value; + i_vpr_h(inst, "%s: ring buffer count: %u\n", __func__, count); + rc = venus_hfi_session_property(inst, + HFI_PROP_ENC_RING_BIN_BUF, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_U32, + &count, + sizeof(u32)); + if (rc) + return rc; + + return rc; +} + +static struct msm_platform_inst_capability instance_cap_data_pineapple[] = { + /* {cap, domain, codec, + * min, max, step_or_mask, value, + * v4l2_id, + * hfi_id, + * flags} + */ + {DRV_VERSION, DEC | ENC, CODECS_ALL, + 0, INT_MAX, 1, DRIVER_VERSION, + V4L2_CID_MPEG_VIDC_DRIVER_VERSION}, + + {FRAME_WIDTH, DEC, CODECS_ALL, 96, 8192, 1, 1920}, + + {FRAME_WIDTH, DEC, VP9, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, CODECS_ALL, 128, 8192, 1, 1920}, + + {FRAME_WIDTH, ENC, HEVC, 96, 8192, 1, 1920}, + + {FRAME_WIDTH, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {LOSSLESS_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, DEC, CODECS_ALL, 96, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {FRAME_HEIGHT, DEC, CODECS_ALL, 96, 8192, 1, 1080}, + + {FRAME_HEIGHT, DEC, VP9, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, CODECS_ALL, 128, 8192, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEVC, 96, 8192, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {LOSSLESS_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, DEC, CODECS_ALL, 96, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {PIX_FMTS, ENC | DEC, H264, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC | DEC, HEVC | VP9 | AV1, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12}, + + {PIX_FMTS, DEC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_INPUT, ENC | DEC, HEIC, 0, 64, 1, 1, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL, + 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE}, + + /* (8192 * 4320) / 256 */ + {MBPF, ENC, CODECS_ALL, 64, 138240, 1, 138240}, + + {MBPF, ENC, HEVC, 36, 138240, 1, 138240}, + + /* ((16384x16384)/256) */ + {MBPF, ENC, HEIC, 36, 1048576, 1, 1048576}, + + {MBPF, DEC, CODECS_ALL, 36, 138240, 1, 138240}, + + /* (4096 * 2304) / 256 */ + {MBPF, DEC, VP9, 36, 36864, 1, 36864}, + + /* ((8192x8192)/256) */ + {MBPF, DEC, HEIC, 64, 262144, 1, 262144 }, + + /* (4096 * 2304) / 256 */ + {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 36864, 1, 36864}, + + /* Batch Mode Decode */ + /* TODO: update with new values based on updated voltage corner */ + {BATCH_MBPF, DEC, H264 | HEVC | VP9 | AV1, 64, 34816, 1, 34816}, + + /* (4096 * 2304) / 256 */ + {BATCH_FPS, DEC, H264 | HEVC | VP9 | AV1, 1, 120, 1, 120}, + + {SECURE_MBPF, ENC | DEC, H264 | HEVC | VP9 | AV1, 64, 36864, 1, 36864}, + + {SECURE_MBPF, ENC, HEVC, 36, 36864, 1, 36864}, + + {FRAME_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, ENC, HEIC, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (MINIMUM_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, DEC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_DEC_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {FRAME_RATE, DEC, VP9, + (MINIMUM_FPS << 16), (MAXIMUM_OVERRIDE_VP9_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {OPERATING_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {OPERATING_RATE, DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_OPERATING_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {INPUT_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8}, + + {MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, VP9 | AV1, 60, 60, 1, 60}, + + {MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675}, + + {MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320}, + + {MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 489583, 489583, 1, 489583}, + + {MB_CYCLES_FW_VPP, ENC, CODECS_ALL, 48405, 48405, 1, 48405}, + + {MB_CYCLES_FW_VPP, DEC, CODECS_ALL, 66234, 66234, 1, 66234}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + 0, MAX_ENC_RING_BUF_COUNT, 1, 0}, + + {CLIENT_ID, ENC | DEC, CODECS_ALL, + INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, + V4L2_CID_MPEG_VIDC_CLIENT_ID}, + + {SECURE_MODE, ENC | DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_SECURE, + HFI_PROP_SECURE, + CAP_FLAG_NONE}, + + /* + * Client will enable V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE + * to get fence_id in input metadata buffer done. + */ + {META_OUTBUF_FENCE, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE, + HFI_PROP_FENCE, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* + * Client to do set_ctrl with FENCE_ID to set fence_id + * and then client will do get_ctrl with FENCE_FD to get + * fence_fd corresponding to client set fence_id. + */ + {FENCE_ID, DEC, CODECS_ALL, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SW_FENCE_ID, + 0, + CAP_FLAG_DYNAMIC_ALLOWED | CAP_FLAG_OUTPUT_PORT}, + + {FENCE_FD, DEC, CODECS_ALL, + INVALID_FD, INT_MAX, 1, INVALID_FD, + V4L2_CID_MPEG_VIDC_SW_FENCE_FD, + 0, + CAP_FLAG_VOLATILE}, + + /* Fence type for input buffer. Currently unused */ + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_NONE, MSM_VIDC_FENCE_NONE, + BIT(MSM_VIDC_FENCE_NONE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_NONE, MSM_VIDC_SYNX_V2_FENCE, + BIT(MSM_VIDC_FENCE_NONE) | BIT(MSM_VIDC_SW_FENCE) | + BIT(MSM_VIDC_SYNX_V2_FENCE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* Fence direction for input buffer. Currently unused */ + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_NONE, + BIT(MSM_VIDC_FENCE_DIR_NONE), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_RX, + BIT(MSM_VIDC_FENCE_DIR_NONE) | BIT(MSM_VIDC_FENCE_DIR_TX) | + BIT(MSM_VIDC_FENCE_DIR_RX), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + {FENCE_ERROR_DATA_CORRUPT, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + 0, + HFI_PROP_FENCE_ERROR_DATA_CORRUPT}, + + {TS_REORDER, DEC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TS_REORDER}, + + {HFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_HFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {VFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_VFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ROTATION, ENC, CODECS_ALL, + 0, 270, 90, 0, + V4L2_CID_ROTATE, + HFI_PROP_ROTATION, + CAP_FLAG_OUTPUT_PORT}, + + {SUPER_FRAME, ENC, H264 | HEVC, + 0, 32, 1, 0, + V4L2_CID_MPEG_VIDC_SUPERFRAME, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {SLICE_DECODE, DEC, H264 | HEVC | AV1, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_MPEG_MSM_VIDC_DISABLE, + 0, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, + 0}, + + {HEADER_MODE, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + HFI_PROP_SEQ_HEADER_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_MPEG_MSM_VIDC_ENABLE, + 1, V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDC_VUI_TIMING_INFO, + HFI_PROP_DISABLE_VUI_TIMING_INFO, + CAP_FLAG_OUTPUT_PORT}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_OUTPUT_PORT}, + + {WITHOUT_STARTCODE, DEC, AV1, + 0, 0, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_INPUT_PORT}, + + {NAL_LENGTH_FIELD, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_MPEG_VIDEO_HEVC_SIZE_4, + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) | + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4), + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* TODO: Firmware introduced enumeration type for this + * with and without seq header. + */ + {REQUEST_I_FRAME, ENC, H264 | HEVC, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + HFI_PROP_REQUEST_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* Enc: Keeping CABAC and CAVLC as same bitrate. + * Dec: there's no use of Bitrate cap + */ + {BIT_RATE, ENC, H264 | HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE, + HFI_PROP_TOTAL_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITRATE_MODE, ENC, H264, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {CAVLC_MAX_BITRATE, ENC, H264, 0, + 220000000, 1, 220000000}, + + {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0, + 245000000, 1, 245000000}, + + {LOWLATENCY_MAX_BITRATE, ENC, H264 | HEVC, 0, + 70000000, 1, 70000000}, + + {NUM_COMV, DEC, CODECS_ALL, + 0, INT_MAX, 1, 0}, + + {LOSSLESS, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU}, + + {FRAME_SKIP_MODE, ENC, H264 | HEVC | HEIC, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {FRAME_RC_ENABLE, ENC, H264 | HEVC | HEIC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE}, + + {CONSTANT_QUALITY, ENC, HEVC, + 1, MAX_CONSTANT_QUALITY, 1, 90, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CONSTANT_QUALITY, ENC, HEIC, + 1, MAX_CONSTANT_QUALITY, 1, 100, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, CODECS_ALL, + 0, INT_MAX, 1, 2 * DEFAULT_FPS - 1, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, HEIC, + 0, INT_MAX, 1, 0 /* all intra */, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_CLOSURE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + 0}, + + {B_FRAME, ENC, H264 | HEVC, + 0, 7, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {B_FRAME, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {BLUR_TYPES, ENC, H264 | HEVC, + MSM_VIDC_BLUR_NONE, MSM_VIDC_BLUR_EXTERNAL, + BIT(MSM_VIDC_BLUR_NONE) | BIT(MSM_VIDC_BLUR_EXTERNAL), + MSM_VIDC_BLUR_NONE, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_TYPES, + HFI_PROP_BLUR_TYPES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_RESOLUTION, + HFI_PROP_BLUR_RESOLUTION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CSC, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CSC, + HFI_PROP_CSC, + CAP_FLAG_OUTPUT_PORT}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX, + HFI_PROP_CSC_MATRIX, + CAP_FLAG_OUTPUT_PORT}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + 0, + CAP_FLAG_NONE}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {LTR_COUNT, ENC, H264 | HEVC, + 0, MAX_LTR_FRAME_COUNT_5, 1, 0, + V4L2_CID_MPEG_VIDEO_LTR_COUNT, + HFI_PROP_LTR_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {USE_LTR, ENC, H264 | HEVC, + 0, + ((1 << MAX_LTR_FRAME_COUNT_5) - 1), + 0, 0, + V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, + HFI_PROP_LTR_USE, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {MARK_LTR, ENC, H264 | HEVC, + INVALID_DEFAULT_MARK_OR_USE_LTR, + (MAX_LTR_FRAME_COUNT_5 - 1), + 1, INVALID_DEFAULT_MARK_OR_USE_LTR, + V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, + HFI_PROP_LTR_MARK, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {BASELAYER_PRIORITY, ENC, H264, + 0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0, + V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, + HFI_PROP_BASELAYER_PRIORITYID, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {IR_TYPE, ENC, H264 | HEVC, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC, + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM) | + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC), + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {IR_PERIOD, ENC, H264 | HEVC, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, + 0, + CAP_FLAG_INPUT_PORT | CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {AU_DELIMITER, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + HFI_PROP_AUD, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_CONTENT_ADAPTIVE_CODING, + HFI_PROP_CONTENT_ADAPTIVE_CODING, + CAP_FLAG_OUTPUT_PORT}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + MSM_VIDC_PREPROCESS_NONE, + MSM_VIDC_PREPROCESS_TYPE0, + BIT(MSM_VIDC_PREPROCESS_NONE) | + BIT(MSM_VIDC_PREPROCESS_TYPE0), + MSM_VIDC_PREPROCESS_NONE, + 0, HFI_PROP_REQUEST_PREPROCESS, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + 0, MAX_BITRATE_BOOST, 25, MAX_BITRATE_BOOST, + V4L2_CID_MPEG_VIDC_QUALITY_BITRATE_BOOST, + HFI_PROP_BITRATE_BOOST, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_QUALITY, ENC, H264 | HEVC, + 0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY, + 0, + HFI_PROP_MAINTAIN_MIN_QUALITY, + CAP_FLAG_OUTPUT_PORT}, + + {VBV_DELAY, ENC, H264 | HEVC, + 200, 300, 100, 300, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, + HFI_PROP_VBV_DELAY, + CAP_FLAG_OUTPUT_PORT}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + /* default peak bitrate is 10% larger than avg bitrate */ + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + HFI_PROP_TOTAL_PEAK_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {MIN_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP}, + + {I_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP}, + + {MAX_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MAX_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP}, + + {I_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP}, + + {I_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {I_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {LAYER_TYPE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_TYPE, ENC, H264, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_ENABLE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT}, + + {LAYER_ENABLE, ENC, HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {ENH_LAYER_COUNT, ENC, HEVC, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, ENC, H264, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, DEC, AV1, + 0, MAX_OP_POINT, 1, 0, + 0, + HFI_PROP_AV1_OP_POINT, + CAP_FLAG_INPUT_PORT}, + + {L0_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L3_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L3_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENTROPY_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + HFI_PROP_CABAC_SESSION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {ENTROPY_MODE, DEC, H264 | HEVC | VP9 | AV1, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + 0, + HFI_PROP_CABAC_SESSION}, + + {PROFILE, ENC | DEC, H264, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, ENC | DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE, + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_MPEG_VIDEO_VP9_PROFILE_2, + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, AV1, + V4L2_MPEG_VIDC_AV1_PROFILE_MAIN, + V4L2_MPEG_VIDC_AV1_PROFILE_MAIN, + BIT(V4L2_MPEG_VIDC_AV1_PROFILE_MAIN), + V4L2_MPEG_VIDC_AV1_PROFILE_MAIN, + V4L2_CID_MPEG_VIDC_AV1_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), + V4L2_MPEG_VIDEO_H264_LEVEL_6_1, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), + V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, AV1, + V4L2_MPEG_VIDC_AV1_LEVEL_2_0, + V4L2_MPEG_VIDC_AV1_LEVEL_6_1, + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_2_3) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_3_3) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_4_3) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_5_3) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDC_AV1_LEVEL_6_1), + V4L2_MPEG_VIDC_AV1_LEVEL_6_1, + V4L2_CID_MPEG_VIDC_AV1_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {AV1_TIER, DEC, AV1, + V4L2_MPEG_VIDC_AV1_TIER_MAIN, + V4L2_MPEG_VIDC_AV1_TIER_HIGH, + BIT(V4L2_MPEG_VIDC_AV1_TIER_MAIN) | + BIT(V4L2_MPEG_VIDC_AV1_TIER_HIGH), + V4L2_MPEG_VIDC_AV1_TIER_HIGH, + V4L2_CID_MPEG_VIDC_AV1_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEIC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN), + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + DB_H264_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + BIT(DB_H264_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + DB_HEVC_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) | + BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_ALPHA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA}, + + {LF_ALPHA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2}, + + {LF_BETA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA}, + + {LF_BETA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2}, + + {SLICE_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MAX_BYTES, ENC, H264 | HEVC, + MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE, + 1, MIN_SLICE_BYTE_SIZE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + HFI_PROP_MULTI_SLICE_BYTES_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {SLICE_MAX_MB, ENC, H264 | HEVC, + 1, MAX_SLICE_MB_SIZE, 1, 1, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + HFI_PROP_MULTI_SLICE_MB_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {MB_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {TRANSFORM_8X8, ENC, H264, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + HFI_PROP_8X8_TRANSFORM, + CAP_FLAG_OUTPUT_PORT}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET, + 1, MAX_CHROMA_QP_OFFSET, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + HFI_PROP_CHROMA_QP_OFFSET, + CAP_FLAG_OUTPUT_PORT}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9 | AV1, + 0, 1, 1, 0, + 0, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_8BIT, + CAP_FLAG_INPUT_PORT}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_10BIT, + CAP_FLAG_INPUT_PORT}, + + {STAGE, DEC | ENC, CODECS_ALL, + MSM_VIDC_STAGE_1, + MSM_VIDC_STAGE_2, 1, + MSM_VIDC_STAGE_2, + 0, + HFI_PROP_STAGE}, + + {PIPE, DEC | ENC, CODECS_ALL, + MSM_VIDC_PIPE_1, + MSM_VIDC_PIPE_4, 1, + MSM_VIDC_PIPE_4, + 0, + HFI_PROP_PIPE}, + + {POC, DEC, H264, + 0, 2, 1, 1, + 0, + HFI_PROP_PIC_ORDER_CNT_TYPE, + CAP_FLAG_VOLATILE}, + + /* + * value of MAX_NUM_REORDER_FRAMES is 32 packed as mentioned below + * (max_num_reorder_count << 16) | max_dec_frame_buffering_count + */ + {MAX_NUM_REORDER_FRAMES, DEC, H264 | HEVC, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_MAX_NUM_REORDER_FRAMES, + HFI_PROP_MAX_NUM_REORDER_FRAMES, + CAP_FLAG_VOLATILE}, + + {QUALITY_MODE, ENC, CODECS_ALL, + MSM_VIDC_MAX_QUALITY_MODE, + MSM_VIDC_POWER_SAVE_MODE, 1, + MSM_VIDC_POWER_SAVE_MODE}, + + {CODED_FRAMES, DEC, H264 | HEVC | HEIC, + CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE, + 1, CODED_FRAMES_PROGRESSIVE, + V4L2_CID_MPEG_VIDC_INTERLACE, + HFI_PROP_CODED_FRAMES, + CAP_FLAG_VOLATILE}, + + {BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8, + 0, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH}, + + {CODEC_CONFIG, DEC, H264 | HEVC | HEIC | AV1, 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CODEC_CONFIG, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_MIN_BITSTREAM_SIZE_OVERWRITE}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_THUMBNAIL_MODE, + HFI_PROP_THUMBNAIL_MODE, + CAP_FLAG_INPUT_PORT}, + + {DEFAULT_HEADER, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_DEC_DEFAULT_HEADER}, + + {RAP_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_DEC_START_FROM_RAP_FRAME, + CAP_FLAG_INPUT_PORT}, + + {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {PRIORITY, DEC | ENC, CODECS_ALL, + 0, 4, 1, 4, + V4L2_CID_MPEG_VIDC_PRIORITY, + HFI_PROP_SESSION_PRIORITY, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + 1, 1, 1, 1}, + + {CRITICAL_PRIORITY, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CRITICAL_PRIORITY}, + + {RESERVE_DURATION, ENC, CODECS_ALL, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_RESERVE_DURATION, + HFI_CMD_RESERVE, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENC_IP_CR, ENC, CODECS_ALL, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_ENC_INPUT_COMPRESSION_RATIO, + 0, CAP_FLAG_DYNAMIC_ALLOWED}, + + {FILM_GRAIN, DEC, AV1, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_AV1D_FILM_GRAIN_PRESENT, + HFI_PROP_AV1_FILM_GRAIN_PRESENT, + CAP_FLAG_VOLATILE}, + + {SUPER_BLOCK, DEC, AV1, + 0, 1, 1, 0, + 0, + HFI_PROP_AV1_SUPER_BLOCK_ENABLED}, + + {DRAP, DEC, AV1, + 0, S32_MAX, 1, 0, + 0, + HFI_PROP_AV1_DRAP_CONFIG, + CAP_FLAG_INPUT_PORT}, + + {LAST_FLAG_EVENT_ENABLE, DEC | ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LAST_FLAG_EVENT_ENABLE}, + + {META_BITSTREAM_RESOLUTION, DEC, AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BITSTREAM_RESOLUTION, + HFI_PROP_BITSTREAM_RESOLUTION, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_CROP_OFFSETS, DEC, AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_CROP_OFFSETS, + HFI_PROP_CROP_OFFSETS, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {ALL_INTRA, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {META_LTR_MARK_USE, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_LTR_MARK_USE_DETAILS, + HFI_PROP_LTR_MARK_USE_DETAILS, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEQ_HDR_NAL, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEQ_HEADER_NAL, + HFI_PROP_METADATA_SEQ_HEADER_NAL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DPB_MISR, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_LUMA_CHROMA_MISR, + HFI_PROP_DPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_OPB_MISR, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OPB_LUMA_CHROMA_MISR, + HFI_PROP_OPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_INTERLACE, DEC, H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_INTERLACE, + HFI_PROP_INTERLACE_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TIMESTAMP, DEC | ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TIMESTAMP, + HFI_PROP_TIMESTAMP, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_CONCEALED_MB_CNT, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_CONCEALED_MB_COUNT, + HFI_PROP_CONEALED_MB_COUNT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HIST_INFO, DEC, HEVC | AV1 | VP9, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HISTOGRAM_INFO, + HFI_PROP_HISTOGRAM_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TRANSCODING_STAT_INFO, DEC, HEVC|H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TRANSCODE_STAT_INFO, + HFI_PROP_TRANSCODING_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TRANSCODING_STAT_INFO, ENC, HEVC|H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TRANSCODE_STAT_INFO, + HFI_PROP_TRANSCODING_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_PICTURE_TYPE, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_PICTURE_TYPE, + HFI_PROP_PICTURE_TYPE, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + {META_SEI_MASTERING_DISP, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_MASTERING_DISP, DEC, HEVC | HEIC | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, DEC, HEVC | HEIC | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, DEC, HEVC | HEIC | AV1, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DOLBY_RPU, ENC, HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DOLBY_RPU, + HFI_PROP_DOLBY_RPU_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DOLBY_RPU, DEC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DOLBY_RPU, + HFI_PROP_DOLBY_RPU_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_EVA_STATS, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_EVA_STATS, + HFI_PROP_EVA_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_BUF_TAG, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + /* + * when fence enabled, client needs output buffer_tag + * in input metadata buffer done. + */ + {META_BUF_TAG, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_TX_OUTPUT | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + {META_DPB_TAG_LIST, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_TAG_LIST, + HFI_PROP_DPB_TAG_LIST, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, ENC, HEIC | H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ENC_QP_METADATA, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ENC_QP_METADATA, + HFI_PROP_ENC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ROI_INFO, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ROI_INFO, + HFI_PROP_ROI_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SALIENCY_INFO, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SALIENCY_INFO, + HFI_PROP_ROI_AS_SALIENCY_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DEC_QP_METADATA, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DEC_QP_METADATA, + HFI_PROP_DEC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {GRID_ENABLE, ENC, HEIC, + 0, 1, 1, 1, + 0, + HFI_PROP_HEIC_GRID_ENABLE, + CAP_FLAG_OUTPUT_PORT}, + + {GRID_SIZE, ENC, HEIC, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH * 2, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH, + V4L2_CID_MPEG_VIDC_GRID_WIDTH}, + + {COMPLEXITY, ENC, H264 | HEVC, + 0, 100, + 1, DEFAULT_COMPLEXITY, + V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY}, + + {DELIVERY_MODE, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_HEVC_ENCODE_DELIVERY_MODE, + HFI_PROP_ENABLE_SLICE_DELIVERY, + CAP_FLAG_OUTPUT_PORT}, + + {DELIVERY_MODE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_H264_ENCODE_DELIVERY_MODE, + HFI_PROP_ENABLE_SLICE_DELIVERY, + CAP_FLAG_OUTPUT_PORT}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SIGNAL_COLOR_INFO, + HFI_PROP_SIGNAL_COLOR_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, +}; + +static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_pineapple[] = { + /* {cap, domain, codec, + * parents, + * children, + * adjust, set} + */ + + {PIX_FMTS, ENC, H264, + {META_ROI_INFO, IR_PERIOD, CSC}}, + + {PIX_FMTS, ENC, HEVC, + {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, META_ROI_INFO, MIN_QUALITY, BLUR_TYPES, IR_PERIOD, + LTR_COUNT, CSC}}, + + {PIX_FMTS, ENC, HEIC, + {PROFILE, CSC}}, + + {PIX_FMTS, DEC, HEVC | HEIC, + {PROFILE}}, + + {FRAME_RATE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_q16}, + + {FRAME_RATE, DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_dec_frame_rate}, + + {OPERATING_RATE, DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_dec_operating_rate}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_ring_buffer_count_pineapple}, + + {SECURE_MODE, ENC | DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {META_OUTBUF_FENCE, DEC, H264 | HEVC | AV1 | VP9, + {LOWLATENCY_MODE, OUTBUF_FENCE_TYPE, OUTBUF_FENCE_DIRECTION}, + NULL, + NULL}, + + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9 | AV1, + {0}, + msm_vidc_adjust_dec_outbuf_fence_type, + msm_vidc_set_outbuf_fence_type}, + + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9 | AV1, + {0}, + msm_vidc_adjust_dec_outbuf_fence_direction, + msm_vidc_set_outbuf_fence_direction}, + + {FENCE_ERROR_DATA_CORRUPT, DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {HFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {VFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {ROTATION, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_rotation}, + + {SUPER_FRAME, ENC, H264 | HEVC, + {INPUT_BUF_HOST_MAX_COUNT, OUTPUT_BUF_HOST_MAX_COUNT}, + NULL, + NULL}, + + {SLICE_DECODE, DEC, H264 | HEVC | AV1, + {0}, + NULL, + NULL}, + + {HEADER_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_header_mode}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_nal_length}, + + {WITHOUT_STARTCODE, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {REQUEST_I_FRAME, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_req_sync_frame}, + + {BIT_RATE, ENC, H264, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BIT_RATE, ENC, HEVC, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BITRATE_MODE, ENC, H264, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE, + META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE, META_TRANSCODING_STAT_INFO}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEVC, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT, + BIT_RATE, META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE, META_EVA_STATS, META_TRANSCODING_STAT_INFO}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEIC, + {TIME_DELTA_BASED_RC, CONSTANT_QUALITY}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {CONSTANT_QUALITY, ENC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_constant_quality}, + + {GOP_SIZE, ENC, CODECS_ALL, + {ALL_INTRA}, + msm_vidc_adjust_gop_size, + msm_vidc_set_gop_size}, + + {GOP_SIZE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {B_FRAME, ENC, H264 | HEVC, + {ALL_INTRA}, + msm_vidc_adjust_b_frame, + msm_vidc_set_u32}, + + {B_FRAME, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {BLUR_TYPES, ENC, H264 | HEVC, + {BLUR_RESOLUTION}, + msm_vidc_adjust_blur_type, + msm_vidc_set_u32_enum}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_blur_resolution, + msm_vidc_set_blur_resolution}, + + {CSC, ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_csc, + msm_vidc_set_u32}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_csc_custom_matrix}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + {STAGE, BIT_RATE}, + msm_vidc_adjust_enc_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | AV1, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, VP9, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LTR_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ltr_count, + msm_vidc_set_u32}, + + {USE_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_use_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {MARK_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_mark_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {IR_PERIOD, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ir_period, + msm_vidc_set_ir_period}, + + {AU_DELIMITER, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_u32}, + + {BASELAYER_PRIORITY, ENC, H264, + {0}, + NULL, + msm_vidc_set_u32}, + + {TIME_DELTA_BASED_RC, ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_delta_based_rc, + msm_vidc_set_u32}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + {REQUEST_PREPROCESS}, + msm_vidc_adjust_brs, + msm_vidc_set_vbr_related_properties}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_preprocess, + msm_vidc_set_preprocess}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_bitrate_boost_iris33, + msm_vidc_set_vbr_related_properties}, + + {MIN_QUALITY, ENC, H264 | HEVC, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {VBV_DELAY, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_cbr_related_properties}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_peak_bitrate, + msm_vidc_set_cbr_related_properties}, + + {MIN_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_min_qp}, + + {MIN_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_min_qp, + msm_vidc_set_min_qp}, + + {MAX_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_max_qp}, + + {MAX_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_max_qp, + msm_vidc_set_max_qp}, + + {I_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_i_frame_qp, + msm_vidc_set_frame_qp}, + + {I_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_p_frame_qp, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_b_frame_qp, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {LAYER_TYPE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING, LTR_COUNT}}, + + {LAYER_ENABLE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING}}, + + {ENH_LAYER_COUNT, ENC, H264 | HEVC, + {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE, LTR_COUNT}, + msm_vidc_adjust_layer_count, + msm_vidc_set_layer_count_and_type}, + + {ENH_LAYER_COUNT, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {L0_BR, ENC, H264 | HEVC, + {L1_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L1_BR, ENC, H264 | HEVC, + {L2_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L2_BR, ENC, H264 | HEVC, + {L3_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L3_BR, ENC, H264 | HEVC, + {L4_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L4_BR, ENC, H264 | HEVC, + {L5_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L5_BR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {ENTROPY_MODE, ENC, H264, + {BIT_RATE}, + msm_vidc_adjust_entropy_mode, + msm_vidc_set_u32}, + + {PROFILE, ENC, H264, + {ENTROPY_MODE, TRANSFORM_8X8}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, H264, + {ENTROPY_MODE}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, ENC, HEVC | HEIC, + {META_SEI_MASTERING_DISP, META_SEI_CLL, META_HDR10PLUS}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, HEVC | HEIC, + {0}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, VP9 | AV1, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_level}, + + {AV1_TIER, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {HEVC_TIER, ENC | DEC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LF_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_deblock_mode}, + + {SLICE_MODE, ENC, H264 | HEVC, + {STAGE, DELIVERY_MODE}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {SLICE_MODE, ENC, HEIC, + {0}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {TRANSFORM_8X8, ENC, H264, + {0}, + msm_vidc_adjust_transform_8x8, + msm_vidc_set_u32}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + {0}, + msm_vidc_adjust_chroma_qp_index_offset, + msm_vidc_set_chroma_qp_index_offset}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9 | AV1, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9 | AV1, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | AV1 | VP9, + {0}, + msm_vidc_adjust_output_order, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {STAGE, ENC | DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_stage}, + + {STAGE, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_stage}, + + {STAGE, DEC, H264 | HEVC | VP9 | AV1, + {0}, + NULL, + msm_vidc_set_stage}, + + {PIPE, DEC | ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_pipe}, + + {THUMBNAIL_MODE, DEC, H264 | HEVC | VP9 | AV1, + {OUTPUT_ORDER}, + NULL, + msm_vidc_set_u32}, + + {THUMBNAIL_MODE, DEC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {RAP_FRAME, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32}, + + {PRIORITY, DEC | ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_session_priority, + msm_vidc_set_session_priority}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + {0}, + NULL, + NULL}, + + {CRITICAL_PRIORITY, ENC, CODECS_ALL, + {0}, + NULL, + NULL}, + + {RESERVE_DURATION, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_reserve_duration}, + + {DRAP, DEC, AV1, + {0}, + NULL, + msm_vidc_set_u32}, + + {ALL_INTRA, ENC, H264 | HEVC, + {LTR_COUNT, IR_PERIOD, SLICE_MODE, BIT_RATE}, + msm_vidc_adjust_all_intra, + NULL}, + + {META_EVA_STATS, ENC, HEVC, + {0}, + msm_vidc_adjust_eva_stats, + NULL}, + + {META_ROI_INFO, ENC, H264 | HEVC, + {MIN_QUALITY, IR_PERIOD, BLUR_TYPES}, + msm_vidc_adjust_roi_info, + NULL}, + + {GRID_ENABLE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {DELIVERY_MODE, ENC, H264 | HEVC, + {LOWLATENCY_MODE, OUTPUT_BUF_HOST_MAX_COUNT}, + msm_vidc_adjust_delivery_mode, + msm_vidc_set_u32}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_vui_timing_info}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_signal_color_info}, + + {META_SEI_MASTERING_DISP, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_sei_mastering_disp, + NULL}, + + {META_SEI_CLL, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_sei_cll, + NULL}, + + {META_HDR10PLUS, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_hdr10plus, + NULL}, + + {META_TRANSCODING_STAT_INFO, ENC, HEVC|H264, + {0}, + msm_vidc_adjust_transcoding_stats, + NULL}, +}; + +/* Default UBWC config for LPDDR5 */ +static struct msm_vidc_ubwc_config_data ubwc_config_pineapple[] = { + UBWC_CONFIG(8, 32, 16, 0, 1, 1, 1), +}; + +static struct msm_vidc_format_capability format_data_pineapple = { + .codec_info = codec_data_pineapple, + .codec_info_size = ARRAY_SIZE(codec_data_pineapple), + .color_format_info = color_format_data_pineapple, + .color_format_info_size = ARRAY_SIZE(color_format_data_pineapple), + .color_prim_info = color_primaries_data_pineapple, + .color_prim_info_size = ARRAY_SIZE(color_primaries_data_pineapple), + .transfer_char_info = transfer_char_data_pineapple, + .transfer_char_info_size = ARRAY_SIZE(transfer_char_data_pineapple), + .matrix_coeff_info = matrix_coeff_data_pineapple, + .matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_pineapple), +}; + +/* name, min_kbps, max_kbps */ +static const struct bw_table pineapple_bw_table[] = { + { "venus-cnoc", 1000, 1000 }, + { "venus-ddr", 1000, 15000000 }, + { "venus-llcc", 1000, 15000000 }, +}; + +/* name, hw_trigger */ +static const struct regulator_table pineapple_regulator_table[] = { + { "iris-ctl", 0 }, + { "vcodec", 1 }, +}; + +/* name, clock id, scaling */ +static const struct clk_table pineapple_clk_table[] = { + { "gcc_video_axi0_clk", GCC_VIDEO_AXI0_CLK, 0 }, + { "video_cc_mvs0c_clk", VIDEO_CC_MVS0C_CLK, 0 }, + { "video_cc_mvs0_clk", VIDEO_CC_MVS0_CLK, 0 }, + { "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 }, +}; + +/* name, exclusive_release */ +static const struct clk_rst_table pineapple_clk_reset_table[] = { + { "video_axi_reset", 0 }, + { "video_xo_reset", 1 }, + { "video_mvs0c_reset", 0 }, + { "video_mvs0_reset", 0 }, +}; + +/* name, llcc_id */ +static const struct subcache_table pineapple_subcache_table[] = { + { "vidsc0", LLCC_VIDSC0 }, + { "vidvsp", LLCC_VIDVSP }, +}; + +/* name, start, size, secure, dma_coherant, region, dma_mask */ +const struct context_bank_table pineapple_context_bank_table[] = { + {"qcom,vidc,cb-ns", 0x25800000, 0xba800000, 0, 1, MSM_VIDC_NON_SECURE, 0}, + {"qcom,vidc,cb-ns-pxl", 0x00100000, 0xdff00000, 0, 1, MSM_VIDC_NON_SECURE_PIXEL, 0}, + {"qcom,vidc,cb-sec-pxl", 0x00500000, 0xdfb00000, 1, 0, MSM_VIDC_SECURE_PIXEL, 0}, + {"qcom,vidc,cb-sec-non-pxl", 0x01000000, 0x24800000, 1, 0, MSM_VIDC_SECURE_NONPIXEL, 0}, + {"qcom,vidc,cb-sec-bitstream", 0x00500000, 0xdfb00000, 1, 0, MSM_VIDC_SECURE_BITSTREAM, 0}, +}; + +/* freq */ +static struct freq_table pineapple_freq_table[] = { + {533333333}, {480000000}, {435000000}, {380000000}, {280000000}, {196000000} +}; + +static struct freq_table pineapple_freq_table_v2[] = { + {533333333}, {480000000}, {435000000}, {380000000}, {300000000}, {196000000} +}; + +/* register, value, mask */ +static const struct reg_preset_table pineapple_reg_preset_table[] = { + { 0xB0088, 0x0, 0x11 }, + { 0x13030, 0x33332222, 0xFFFFFFFF}, + { 0x13034, 0x44444444, 0xFFFFFFFF}, + { 0x13038, 0x1022, 0xFFFFFFFF}, + { 0x13040, 0x0, 0xFFFFFFFF}, + { 0x13048, 0xFFFF, 0xFFFFFFFF}, + { 0x13430, 0x33332222, 0xFFFFFFFF}, + { 0x13434, 0x44444444, 0xFFFFFFFF}, + { 0x13438, 0x1022, 0xFFFFFFFF}, + { 0x13440, 0x0, 0xFFFFFFFF}, + { 0x13448, 0xFFFF, 0xFFFFFFFF}, + { 0xA013C, 0x99, 0xFFFFFFFF}, +}; + +/* name, phys_addr, size, device_addr, device region type */ +static const struct device_region_table pineapple_device_region_table[] = { + { + "aon-registers", + 0x0AAE0000, 0x1000, 0xFFAE0000, + MSM_VIDC_AON + }, + { + "ipc_protocol4_client8_version-registers", + 0x00508000, 0x1000, 0xFFADF000, + MSM_VIDC_PROTOCOL_FENCE_CLIENT_VPU + }, + { + "qtimer_f0v1_qtmr_v1_cntpct_lo", + 0x17421000, 0x1000, 0xFFADE000, + MSM_VIDC_QTIMER + }, +}; + +/* decoder properties */ +static const u32 pineapple_vdec_psc_avc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_CODED_FRAMES, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PIC_ORDER_CNT_TYPE, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_SIGNAL_COLOR_INFO, + HFI_PROP_MAX_NUM_REORDER_FRAMES, +}; + +static const u32 pineapple_vdec_psc_hevc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_TIER, + HFI_PROP_SIGNAL_COLOR_INFO, + HFI_PROP_MAX_NUM_REORDER_FRAMES, +}; + +static const u32 pineapple_vdec_psc_vp9[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, +}; + +static const u32 pineapple_vdec_psc_av1[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_AV1_FILM_GRAIN_PRESENT, + HFI_PROP_AV1_SUPER_BLOCK_ENABLED, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_TIER, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 pineapple_vdec_input_properties_avc[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, + HFI_PROP_DPB_LIST, +}; + +static const u32 pineapple_vdec_input_properties_hevc[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, + HFI_PROP_DPB_LIST, +}; + +static const u32 pineapple_vdec_input_properties_vp9[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, + HFI_PROP_DPB_LIST, +}; + +static const u32 pineapple_vdec_input_properties_av1[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, + HFI_PROP_DPB_LIST, + HFI_PROP_AV1_TILE_ROWS_COLUMNS, + HFI_PROP_AV1_UNIFORM_TILE_SPACING, +}; + +static const u32 pineapple_vdec_output_properties_avc[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_CABAC_SESSION, + HFI_PROP_FENCE, +}; + +static const u32 pineapple_vdec_output_properties_hevc[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_FENCE, +}; + +static const u32 pineapple_vdec_output_properties_vp9[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_FENCE, +}; + +static const u32 pineapple_vdec_output_properties_av1[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_FENCE, +}; + +static const u32 pineapple_msm_vidc_ssr_type[] = { + HFI_SSR_TYPE_SW_ERR_FATAL, + HFI_SSR_TYPE_SW_DIV_BY_ZERO, + HFI_SSR_TYPE_CPU_WDOG_IRQ, + HFI_SSR_TYPE_NOC_ERROR, +}; + +static const struct msm_vidc_platform_data pineapple_data = { + /* resources dependent on other module */ + .bw_tbl = pineapple_bw_table, + .bw_tbl_size = ARRAY_SIZE(pineapple_bw_table), + .regulator_tbl = pineapple_regulator_table, + .regulator_tbl_size = ARRAY_SIZE(pineapple_regulator_table), + .clk_tbl = pineapple_clk_table, + .clk_tbl_size = ARRAY_SIZE(pineapple_clk_table), + .clk_rst_tbl = pineapple_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(pineapple_clk_reset_table), + .subcache_tbl = pineapple_subcache_table, + .subcache_tbl_size = ARRAY_SIZE(pineapple_subcache_table), + + /* populate context bank */ + .context_bank_tbl = pineapple_context_bank_table, + .context_bank_tbl_size = ARRAY_SIZE(pineapple_context_bank_table), + + /* platform specific resources */ + .freq_tbl = pineapple_freq_table, + .freq_tbl_size = ARRAY_SIZE(pineapple_freq_table), + .reg_prst_tbl = pineapple_reg_preset_table, + .reg_prst_tbl_size = ARRAY_SIZE(pineapple_reg_preset_table), + .dev_reg_tbl = pineapple_device_region_table, + .dev_reg_tbl_size = ARRAY_SIZE(pineapple_device_region_table), + .fwname = "vpu33_4v", + .pas_id = 9, + .supports_mmrm = 1, + .vpu_ver = VPU_VERSION_IRIS33, + + /* caps related resorces */ + .core_data = core_data_pineapple, + .core_data_size = ARRAY_SIZE(core_data_pineapple), + .inst_cap_data = instance_cap_data_pineapple, + .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_pineapple), + .inst_cap_dependency_data = instance_cap_dependency_data_pineapple, + .inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_pineapple), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .ubwc_config = ubwc_config_pineapple, + .format_data = &format_data_pineapple, + + /* decoder properties related*/ + .psc_avc_tbl = pineapple_vdec_psc_avc, + .psc_avc_tbl_size = ARRAY_SIZE(pineapple_vdec_psc_avc), + .psc_hevc_tbl = pineapple_vdec_psc_hevc, + .psc_hevc_tbl_size = ARRAY_SIZE(pineapple_vdec_psc_hevc), + .psc_vp9_tbl = pineapple_vdec_psc_vp9, + .psc_vp9_tbl_size = ARRAY_SIZE(pineapple_vdec_psc_vp9), + .psc_av1_tbl = pineapple_vdec_psc_av1, + .psc_av1_tbl_size = ARRAY_SIZE(pineapple_vdec_psc_av1), + .dec_input_prop_avc = pineapple_vdec_input_properties_avc, + .dec_input_prop_hevc = pineapple_vdec_input_properties_hevc, + .dec_input_prop_vp9 = pineapple_vdec_input_properties_vp9, + .dec_input_prop_av1 = pineapple_vdec_input_properties_av1, + .dec_input_prop_size_avc = ARRAY_SIZE(pineapple_vdec_input_properties_avc), + .dec_input_prop_size_hevc = ARRAY_SIZE(pineapple_vdec_input_properties_hevc), + .dec_input_prop_size_vp9 = ARRAY_SIZE(pineapple_vdec_input_properties_vp9), + .dec_input_prop_size_av1 = ARRAY_SIZE(pineapple_vdec_input_properties_av1), + .dec_output_prop_avc = pineapple_vdec_output_properties_avc, + .dec_output_prop_hevc = pineapple_vdec_output_properties_hevc, + .dec_output_prop_vp9 = pineapple_vdec_output_properties_vp9, + .dec_output_prop_av1 = pineapple_vdec_output_properties_av1, + .dec_output_prop_size_avc = ARRAY_SIZE(pineapple_vdec_output_properties_avc), + .dec_output_prop_size_hevc = ARRAY_SIZE(pineapple_vdec_output_properties_hevc), + .dec_output_prop_size_vp9 = ARRAY_SIZE(pineapple_vdec_output_properties_vp9), + .dec_output_prop_size_av1 = ARRAY_SIZE(pineapple_vdec_output_properties_av1), + + .msm_vidc_ssr_type = pineapple_msm_vidc_ssr_type, + .msm_vidc_ssr_type_size = ARRAY_SIZE(pineapple_msm_vidc_ssr_type), + +}; + +int msm_vidc_pineapple_check_ddr_type(void) +{ + u32 ddr_type; + + ddr_type = of_fdt_get_ddrtype(); + if (ddr_type != DDR_TYPE_LPDDR5 && + ddr_type != DDR_TYPE_LPDDR5X) { + d_vpr_e("%s: wrong ddr type %d\n", __func__, ddr_type); + return -EINVAL; + } else { + d_vpr_h("%s: ddr type %d\n", __func__, ddr_type); + } + return 0; +} + +static int msm_vidc_init_data(struct msm_vidc_core *core) +{ + struct device *dev = NULL; + int rc = 0; + + dev = &core->pdev->dev; + + d_vpr_h("%s: initialize pineapple data\n", __func__); + + core->platform->data = pineapple_data; + if (of_device_is_compatible(dev->of_node, "qcom,sm8650-vidc-v2")) { + d_vpr_h("%s: update frequency table for pineapple v2\n", __func__); + core->platform->data.freq_tbl = pineapple_freq_table_v2; + core->platform->data.freq_tbl_size = ARRAY_SIZE(pineapple_freq_table_v2); + } + + core->mem_ops = get_mem_ops_ext(); + if (!core->mem_ops) { + d_vpr_e("%s: invalid memory ext ops\n", __func__); + return -EINVAL; + } + core->res_ops = get_res_ops_ext(); + if (!core->res_ops) { + d_vpr_e("%s: invalid resource ext ops\n", __func__); + return -EINVAL; + } + core->fence_ops = get_synx_fence_ops(); + if (!core->fence_ops) { + d_vpr_e("%s: invalid synx fence ops\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_pineapple_check_ddr_type(); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_init_platform_pineapple(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = msm_vidc_init_data(core); + if (rc) + return rc; + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/platform/pineapple/src/pineapple.c b/qcom/opensource/video-driver/driver/platform/pineapple/src/pineapple.c new file mode 100644 index 0000000000..d240ad630b --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/pineapple/src/pineapple.c @@ -0,0 +1,1757 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include + +#include "msm_vidc_control.h" +#include "msm_vidc_pineapple.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_iris33.h" +#include "hfi_property.h" +#include "hfi_command.h" +#include "venus_hfi.h" + +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010 +#define MAX_BASE_LAYER_PRIORITY_ID 63 +#define MAX_OP_POINT 31 +#define MAX_BITRATE 245000000 +#define DEFAULT_BITRATE 20000000 +#define MINIMUM_FPS 1 +#define MAXIMUM_FPS 480 +#define MAX_QP 51 +#define DEFAULT_QP 20 +#define MAX_CONSTANT_QUALITY 100 +#define MIN_SLICE_BYTE_SIZE 512 +#define MAX_SLICE_BYTE_SIZE \ + ((MAX_BITRATE) >> 3) +#define MAX_SLICE_MB_SIZE \ + (((4096 + 15) >> 4) * ((2304 + 15) >> 4)) + +#define ENC MSM_VIDC_ENCODER +#define DEC MSM_VIDC_DECODER +#define H264 MSM_VIDC_H264 +#define HEVC MSM_VIDC_HEVC +#define VP9 MSM_VIDC_VP9 +#define CODECS_ALL (H264 | HEVC | VP9) +#define MAXIMUM_OVERRIDE_VP9_FPS 180 + +#ifndef V4L2_PIX_FMT_QC08C +#define V4L2_PIX_FMT_QC08C v4l2_fourcc('Q', '0', '8', 'C') +#endif + +#ifndef V4L2_PIX_FMT_QC10C +#define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') +#endif + +static struct codec_info codec_data_pineapple[] = { + { + .v4l2_codec = V4L2_PIX_FMT_H264, + .vidc_codec = MSM_VIDC_H264, + .pixfmt_name = "AVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_HEVC, + .vidc_codec = MSM_VIDC_HEVC, + .pixfmt_name = "HEVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VP9, + .vidc_codec = MSM_VIDC_VP9, + .pixfmt_name = "VP9", + }, +}; + +static struct color_format_info color_format_data_pineapple[] = { + { + .v4l2_color_format = V4L2_PIX_FMT_NV12, + .vidc_color_format = MSM_VIDC_FMT_NV12, + .pixfmt_name = "NV12", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_NV21, + .vidc_color_format = MSM_VIDC_FMT_NV21, + .pixfmt_name = "NV21", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC08C, + .vidc_color_format = MSM_VIDC_FMT_NV12C, + .pixfmt_name = "NV12C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC10C, + .vidc_color_format = MSM_VIDC_FMT_TP10C, + .pixfmt_name = "TP10C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_RGBA32, + .vidc_color_format = MSM_VIDC_FMT_RGBA8888, + .pixfmt_name = "RGBA", + }, +}; + +static struct color_primaries_info color_primaries_data_pineapple[] = { + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_RESERVED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_REC709, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT709, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_BG, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE170M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT601_525, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE240M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_ST240M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_BT2020, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT2020, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DCI_P3, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_RP431_2, + }, +}; + +static struct transfer_char_info transfer_char_data_pineapple[] = { + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_RESERVED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_709, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT709, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE240M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST240M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SRGB, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SRGB_SYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE2084, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ, + }, +}; + +static struct matrix_coeff_info matrix_coeff_data_pineapple[] = { + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_SMPTE240M, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020_CONST_LUM, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT, + }, +}; + +static struct msm_platform_core_capability core_data_pineapple[] = { + /* {type, value} */ + {ENC_CODECS, H264 | HEVC}, + {DEC_CODECS, H264 | HEVC | VP9}, + {MAX_SESSION_COUNT, 16}, + {MAX_NUM_720P_SESSIONS, 16}, + {MAX_NUM_1080P_SESSIONS, 16}, + {MAX_NUM_4K_SESSIONS, 8}, + {MAX_NUM_8K_SESSIONS, 2}, + {MAX_RT_MBPF, 174080}, /* (8192x4352)/256 + (4096x2176)/256*/ + {MAX_MBPF, 278528}, /* ((8192x4352)/256) * 2 */ + {MAX_MBPS, 7833600}, + /* max_load + * 7680x4320@60fps or 3840x2176@240fps + * which is greater than 4096x2176@120fps, + * 8192x4320@48fps + */ + {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */ + {MAX_MBPS_HQ, 489600}, /* ((1920x1088)/256)@60fps */ + {MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */ + {MAX_MBPS_B_FRAME, 1958400}, /* 3840x2176/256 MBs@60fps */ + {MAX_MBPS_ALL_INTRA, 1044480}, /* 4096x2176/256 MBs@30fps */ + {MAX_ENH_LAYER_COUNT, 5}, + {NUM_VPP_PIPE, 4}, + {SW_PC, 1}, + {FW_UNLOAD, 0}, + {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */ + {SW_PC_DELAY, SW_PC_DELAY_VALUE }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/ + {FW_UNLOAD_DELAY, FW_UNLOAD_DELAY_VALUE }, /* 3000 ms (>SW_PC_DELAY)*/ + {DCVS, 1}, + {DECODE_BATCH, 1}, + {DECODE_BATCH_TIMEOUT, 200}, + {STATS_TIMEOUT_MS, 2000}, + {NON_FATAL_FAULTS, 1}, + {ENC_AUTO_FRAMERATE, 1}, + {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING}, + {SUPPORTS_SYNX_FENCE, 0}, + {SUPPORTS_REQUESTS, 0}, +}; + +static int msm_vidc_set_ring_buffer_count_pineapple(void *instance, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + struct v4l2_format *output_fmt, *input_fmt; + struct msm_vidc_core *core; + u32 count = 0, data_size = 0, pixel_count = 0, fps = 0; + u32 frame_rate = 0, operating_rate = 0; + + core = inst->core; + output_fmt = &inst->fmts[OUTPUT_PORT]; + input_fmt = &inst->fmts[INPUT_PORT]; + + frame_rate = inst->capabilities[FRAME_RATE].value >> 16; + operating_rate = inst->capabilities[OPERATING_RATE].value >> 16; + fps = max(frame_rate, operating_rate); + pixel_count = output_fmt->fmt.pix_mp.width * + output_fmt->fmt.pix_mp.height; + + /* + * try to enable ring buffer feature if +  * resolution >= 8k and fps >= 30fps and +  * resolution >= 4k and fps >= 120fps and +  * resolution >= 1080p and fps >= 480fps and +  * resolution >= 720p and fps >= 960fps + */ + if ((pixel_count >= 7680 * 4320 && fps >= 30) && + (pixel_count >= 3840 * 2160 && fps >= 120) && + (pixel_count >= 1920 * 1080 && fps >= 480) && + (pixel_count >= 1280 * 720 && fps >= 960)) { + data_size = input_fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + i_vpr_h(inst, "%s: calculate ring buffer count\n", __func__); + rc = call_session_op(core, ring_buf_count, inst, data_size); + if (rc) { + i_vpr_e(inst, "%s: failed to calculate ring buf count\n", + __func__); + /* ignore error */ + rc = 0; + inst->capabilities[cap_id].value = 0; + } + } else { + i_vpr_h(inst, + "%s: session %ux%u@%u fps does not support ring buffer\n", + __func__, output_fmt->fmt.pix_mp.width, + output_fmt->fmt.pix_mp.height, fps); + inst->capabilities[cap_id].value = 0; + } + + count = inst->capabilities[cap_id].value; + i_vpr_h(inst, "%s: ring buffer count: %u\n", __func__, count); + rc = venus_hfi_session_property(inst, + HFI_PROP_ENC_RING_BIN_BUF, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_U32, + &count, + sizeof(u32)); + if (rc) + return rc; + + return rc; +} + +static struct msm_platform_inst_capability instance_cap_data_pineapple[] = { + /* {cap, domain, codec, + * min, max, step_or_mask, value, + * v4l2_id, + * hfi_id, + * flags} + */ + + {FRAME_WIDTH, DEC, CODECS_ALL, 96, 8192, 1, 1920}, + + {FRAME_WIDTH, DEC, VP9, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, CODECS_ALL, 128, 8192, 1, 1920}, + + {FRAME_WIDTH, ENC, HEVC, 96, 8192, 1, 1920}, + + {LOSSLESS_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {LOSSLESS_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {FRAME_HEIGHT, DEC, CODECS_ALL, 96, 8192, 1, 1080}, + + {FRAME_HEIGHT, DEC, VP9, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, CODECS_ALL, 128, 8192, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEVC, 96, 8192, 1, 1080}, + + {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {LOSSLESS_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {PIX_FMTS, ENC | DEC, H264, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC | DEC, HEVC | VP9, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + + {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL, + 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE}, + + /* (8192 * 4320) / 256 */ + {MBPF, ENC, CODECS_ALL, 64, 138240, 1, 138240}, + + {MBPF, ENC, HEVC, 36, 138240, 1, 138240}, + + {MBPF, DEC, CODECS_ALL, 36, 138240, 1, 138240}, + + /* (4096 * 2304) / 256 */ + {MBPF, DEC, VP9, 36, 36864, 1, 36864}, + + /* (4096 * 2304) / 256 */ + {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 36864, 1, 36864}, + + /* Batch Mode Decode */ + /* TODO: update with new values based on updated voltage corner */ + {BATCH_MBPF, DEC, H264 | HEVC | VP9, 64, 34816, 1, 34816}, + + /* (4096 * 2304) / 256 */ + {BATCH_FPS, DEC, H264 | HEVC | VP9, 1, 120, 1, 120}, + + {FRAME_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {OPERATING_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16)}, + + {INPUT_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8}, + + {MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60}, + + {MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675}, + + {MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320}, + + {MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 489583, 489583, 1, 489583}, + + {MB_CYCLES_FW_VPP, ENC, CODECS_ALL, 48405, 48405, 1, 48405}, + + {MB_CYCLES_FW_VPP, DEC, CODECS_ALL, 66234, 66234, 1, 66234}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + 0, MAX_ENC_RING_BUF_COUNT, 1, 0}, + + {CLIENT_ID, ENC | DEC, CODECS_ALL, + INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, + 0}, + + {HFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_HFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {VFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_VFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ROTATION, ENC, CODECS_ALL, + 0, 270, 90, 0, + V4L2_CID_ROTATE, + HFI_PROP_ROTATION, + CAP_FLAG_OUTPUT_PORT}, + + {SUPER_FRAME, ENC, H264 | HEVC, + 0, 32, 1, 0, + 0, 0, + CAP_FLAG_NONE}, + + {SLICE_DECODE, DEC, CODECS_ALL, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, + 0}, + + {HEADER_MODE, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + HFI_PROP_SEQ_HEADER_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_OUTPUT_PORT}, + + {NAL_LENGTH_FIELD, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_MPEG_VIDEO_HEVC_SIZE_4, + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) | + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4), + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* TODO: Firmware introduced enumeration type for this + * with and without seq header. + */ + {REQUEST_I_FRAME, ENC, H264 | HEVC, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + HFI_PROP_REQUEST_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* Enc: Keeping CABAC and CAVLC as same bitrate. + * Dec: there's no use of Bitrate cap + */ + {BIT_RATE, ENC, H264 | HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE, + HFI_PROP_TOTAL_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITRATE_MODE, ENC, H264, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {CAVLC_MAX_BITRATE, ENC, H264, 0, + 220000000, 1, 220000000}, + + {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0, + 245000000, 1, 245000000}, + + {LOWLATENCY_MAX_BITRATE, ENC, H264 | HEVC, 0, + 70000000, 1, 70000000}, + + {LOSSLESS, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU}, + + {FRAME_SKIP_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {FRAME_RC_ENABLE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE}, + + {CONSTANT_QUALITY, ENC, HEVC, + 1, MAX_CONSTANT_QUALITY, 1, 90, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, CODECS_ALL, + 0, INT_MAX, 1, 2 * DEFAULT_FPS - 1, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_CLOSURE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + 0}, + + {B_FRAME, ENC, H264 | HEVC, + 0, 7, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {BLUR_TYPES, ENC, H264 | HEVC, + MSM_VIDC_BLUR_NONE, MSM_VIDC_BLUR_EXTERNAL, + BIT(MSM_VIDC_BLUR_NONE) | BIT(MSM_VIDC_BLUR_EXTERNAL), + MSM_VIDC_BLUR_NONE, + 0, + HFI_PROP_BLUR_TYPES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CSC, ENC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_CSC, + CAP_FLAG_OUTPUT_PORT}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_NONE}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {LTR_COUNT, ENC, H264 | HEVC, + 0, MAX_LTR_FRAME_COUNT_5, 1, 0, + V4L2_CID_MPEG_VIDEO_LTR_COUNT, + HFI_PROP_LTR_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {USE_LTR, ENC, H264 | HEVC, + 0, + ((1 << MAX_LTR_FRAME_COUNT_5) - 1), + 0, 0, + V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, + HFI_PROP_LTR_USE, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {MARK_LTR, ENC, H264 | HEVC, + INVALID_DEFAULT_MARK_OR_USE_LTR, + (MAX_LTR_FRAME_COUNT_5 - 1), + 1, INVALID_DEFAULT_MARK_OR_USE_LTR, + V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, + HFI_PROP_LTR_MARK, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {BASELAYER_PRIORITY, ENC, H264, + 0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0, + V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, + HFI_PROP_BASELAYER_PRIORITYID, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {AU_DELIMITER, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + HFI_PROP_AUD, + CAP_FLAG_OUTPUT_PORT}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + 0, 1, 1, 1, + 0, + HFI_PROP_CONTENT_ADAPTIVE_CODING, + CAP_FLAG_OUTPUT_PORT}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + MSM_VIDC_PREPROCESS_NONE, + MSM_VIDC_PREPROCESS_TYPE0, + BIT(MSM_VIDC_PREPROCESS_NONE) | + BIT(MSM_VIDC_PREPROCESS_TYPE0), + MSM_VIDC_PREPROCESS_NONE, + 0, HFI_PROP_REQUEST_PREPROCESS, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {MIN_QUALITY, ENC, H264 | HEVC, + 0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY, + 0, + HFI_PROP_MAINTAIN_MIN_QUALITY, + CAP_FLAG_OUTPUT_PORT}, + + {VBV_DELAY, ENC, H264 | HEVC, + 200, 300, 100, 300, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, + HFI_PROP_VBV_DELAY, + CAP_FLAG_OUTPUT_PORT}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + /* default peak bitrate is 10% larger than avg bitrate */ + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + HFI_PROP_TOTAL_PEAK_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {MIN_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP}, + + {I_FRAME_MIN_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP}, + + {MAX_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MAX_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP}, + + {I_FRAME_MAX_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP}, + + {I_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {I_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {LAYER_TYPE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_TYPE, ENC, H264, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_ENABLE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT}, + + {LAYER_ENABLE, ENC, HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {ENH_LAYER_COUNT, ENC, HEVC, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, ENC, H264, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L3_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L3_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENTROPY_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + HFI_PROP_CABAC_SESSION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {ENTROPY_MODE, DEC, H264 | HEVC | VP9, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + 0, + HFI_PROP_CABAC_SESSION}, + + {PROFILE, ENC | DEC, H264, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE, + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_MPEG_VIDEO_VP9_PROFILE_2, + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6), + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), + V4L2_MPEG_VIDEO_H264_LEVEL_6_1, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), + V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + DB_H264_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + BIT(DB_H264_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + DB_HEVC_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) | + BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_ALPHA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA}, + + {LF_ALPHA, ENC, HEVC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2}, + + {LF_BETA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA}, + + {LF_BETA, ENC, HEVC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2}, + + {SLICE_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MAX_BYTES, ENC, H264 | HEVC, + MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE, + 1, MIN_SLICE_BYTE_SIZE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + HFI_PROP_MULTI_SLICE_BYTES_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {SLICE_MAX_MB, ENC, H264 | HEVC, + 1, MAX_SLICE_MB_SIZE, 1, 1, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + HFI_PROP_MULTI_SLICE_MB_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {MB_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {TRANSFORM_8X8, ENC, H264, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + HFI_PROP_8X8_TRANSFORM, + CAP_FLAG_OUTPUT_PORT}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET, + 1, MAX_CHROMA_QP_OFFSET, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + HFI_PROP_CHROMA_QP_OFFSET, + CAP_FLAG_OUTPUT_PORT}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_8BIT, + CAP_FLAG_INPUT_PORT}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_10BIT, + CAP_FLAG_INPUT_PORT}, + + {STAGE, DEC | ENC, CODECS_ALL, + MSM_VIDC_STAGE_1, + MSM_VIDC_STAGE_2, 1, + MSM_VIDC_STAGE_2, + 0, + HFI_PROP_STAGE}, + + {PIPE, DEC | ENC, CODECS_ALL, + MSM_VIDC_PIPE_1, + MSM_VIDC_PIPE_4, 1, + MSM_VIDC_PIPE_4, + 0, + HFI_PROP_PIPE}, + + {POC, DEC, H264, 0, 2, 1, 1, + 0, + HFI_PROP_PIC_ORDER_CNT_TYPE}, + + {QUALITY_MODE, ENC, CODECS_ALL, + MSM_VIDC_MAX_QUALITY_MODE, + MSM_VIDC_POWER_SAVE_MODE, 1, + MSM_VIDC_POWER_SAVE_MODE}, + + {CODED_FRAMES, DEC, H264 | HEVC, + CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE, + 1, CODED_FRAMES_PROGRESSIVE, + 0, + HFI_PROP_CODED_FRAMES}, + + {BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8, + 0, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH}, + + {CODEC_CONFIG, DEC, H264 | HEVC, 0, 1, 1, 0, + 0, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0, + 0}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_THUMBNAIL_MODE, + CAP_FLAG_INPUT_PORT}, + + {DEFAULT_HEADER, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_DEC_DEFAULT_HEADER}, + + {RAP_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_DEC_START_FROM_RAP_FRAME, + CAP_FLAG_INPUT_PORT}, + + {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + 1, 1, 1, 1}, + + {ALL_INTRA, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {COMPLEXITY, ENC, H264 | HEVC, + 0, 100, + 1, DEFAULT_COMPLEXITY, + 0}, +}; + +static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_pineapple[] = { + /* {cap, domain, codec, + * parents, + * children, + * adjust, set} + */ + + {PIX_FMTS, ENC, HEVC, + {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, MIN_QUALITY, BLUR_TYPES, LTR_COUNT}}, + + {PIX_FMTS, DEC, HEVC, + {PROFILE}}, + + {FRAME_RATE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_q16}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_ring_buffer_count_pineapple}, + + {HFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {VFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {ROTATION, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_rotation}, + + {SUPER_FRAME, ENC, H264 | HEVC, + {INPUT_BUF_HOST_MAX_COUNT, OUTPUT_BUF_HOST_MAX_COUNT}, + NULL, + NULL}, + + {HEADER_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_header_mode}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_nal_length}, + + {REQUEST_I_FRAME, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_req_sync_frame}, + + {BIT_RATE, ENC, H264, + {PEAK_BITRATE, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BIT_RATE, ENC, HEVC, + {PEAK_BITRATE, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BITRATE_MODE, ENC, H264, + {LTR_COUNT, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE, + MIN_QUALITY, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEVC, + {LTR_COUNT, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT, + BIT_RATE, MIN_QUALITY, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {CONSTANT_QUALITY, ENC, HEVC, + {0}, + NULL, + msm_vidc_set_constant_quality}, + + {GOP_SIZE, ENC, CODECS_ALL, + {ALL_INTRA}, + msm_vidc_adjust_gop_size, + msm_vidc_set_gop_size}, + + {B_FRAME, ENC, H264 | HEVC, + {ALL_INTRA}, + msm_vidc_adjust_b_frame, + msm_vidc_set_u32}, + + {BLUR_TYPES, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_blur_type, + msm_vidc_set_u32_enum}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + {STAGE, BIT_RATE}, + msm_vidc_adjust_enc_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LTR_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ltr_count, + msm_vidc_set_u32}, + + {USE_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_use_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {MARK_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_mark_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {AU_DELIMITER, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_u32}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + {REQUEST_PREPROCESS}, + msm_vidc_adjust_brs, + msm_vidc_set_vbr_related_properties}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_preprocess, + msm_vidc_set_preprocess}, + + {MIN_QUALITY, ENC, H264, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {MIN_QUALITY, ENC, HEVC, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {VBV_DELAY, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_cbr_related_properties}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_peak_bitrate, + msm_vidc_set_cbr_related_properties}, + + {MIN_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_min_qp}, + + {MIN_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_min_qp, + msm_vidc_set_min_qp}, + + {MAX_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_max_qp}, + + {MAX_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_max_qp, + msm_vidc_set_max_qp}, + + {I_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_i_frame_qp, + msm_vidc_set_frame_qp}, + + {I_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_p_frame_qp, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_b_frame_qp, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {LAYER_TYPE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING, LTR_COUNT}}, + + {LAYER_ENABLE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING}}, + + {ENH_LAYER_COUNT, ENC, H264 | HEVC, + {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, LTR_COUNT}, + msm_vidc_adjust_layer_count, + msm_vidc_set_layer_count_and_type}, + + {L0_BR, ENC, H264 | HEVC, + {L1_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L1_BR, ENC, H264 | HEVC, + {L2_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L2_BR, ENC, H264 | HEVC, + {L3_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L3_BR, ENC, H264 | HEVC, + {L4_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L4_BR, ENC, H264 | HEVC, + {L5_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L5_BR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {ENTROPY_MODE, ENC, H264, + {BIT_RATE}, + msm_vidc_adjust_entropy_mode, + msm_vidc_set_u32}, + + {PROFILE, ENC, H264, + {ENTROPY_MODE, TRANSFORM_8X8}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, H264, + {ENTROPY_MODE}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, ENC | DEC, HEVC, + {0}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, VP9, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_level}, + + {HEVC_TIER, ENC | DEC, HEVC, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LF_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_deblock_mode}, + + {SLICE_MODE, ENC, H264 | HEVC, + {STAGE, DELIVERY_MODE}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {TRANSFORM_8X8, ENC, H264, + {0}, + msm_vidc_adjust_transform_8x8, + msm_vidc_set_u32}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + {0}, + msm_vidc_adjust_chroma_qp_index_offset, + msm_vidc_set_chroma_qp_index_offset}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_output_order, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {STAGE, ENC | DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_stage}, + + {PIPE, DEC | ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_pipe}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL, + {OUTPUT_ORDER}, + NULL, + msm_vidc_set_u32}, + + {RAP_FRAME, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + {0}, + NULL, + NULL}, + + {ALL_INTRA, ENC, H264 | HEVC, + {LTR_COUNT, SLICE_MODE, BIT_RATE}, + msm_vidc_adjust_all_intra, + NULL}, +}; + +/* Default UBWC config for LPDDR5 */ +static struct msm_vidc_ubwc_config_data ubwc_config_pineapple[] = { + UBWC_CONFIG(8, 32, 16, 0, 1, 1, 1), +}; + +static struct msm_vidc_format_capability format_data_pineapple = { + .codec_info = codec_data_pineapple, + .codec_info_size = ARRAY_SIZE(codec_data_pineapple), + .color_format_info = color_format_data_pineapple, + .color_format_info_size = ARRAY_SIZE(color_format_data_pineapple), + .color_prim_info = color_primaries_data_pineapple, + .color_prim_info_size = ARRAY_SIZE(color_primaries_data_pineapple), + .transfer_char_info = transfer_char_data_pineapple, + .transfer_char_info_size = ARRAY_SIZE(transfer_char_data_pineapple), + .matrix_coeff_info = matrix_coeff_data_pineapple, + .matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_pineapple), +}; + +static const struct msm_vidc_platform_data pineapple_data = { + .core_data = core_data_pineapple, + .core_data_size = ARRAY_SIZE(core_data_pineapple), + .inst_cap_data = instance_cap_data_pineapple, + .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_pineapple), + .inst_cap_dependency_data = instance_cap_dependency_data_pineapple, + .inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_pineapple), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .ubwc_config = ubwc_config_pineapple, + .format_data = &format_data_pineapple, +}; + +int msm_vidc_pineapple_check_ddr_type(void) +{ + u32 ddr_type; + + ddr_type = of_fdt_get_ddrtype(); + if (ddr_type != DDR_TYPE_LPDDR5 && + ddr_type != DDR_TYPE_LPDDR5X) { + d_vpr_e("%s: wrong ddr type %d\n", __func__, ddr_type); + return -EINVAL; + } else { + d_vpr_h("%s: ddr type %d\n", __func__, ddr_type); + } + return 0; +} + +static int msm_vidc_init_data(struct msm_vidc_core *core) +{ + int rc = 0; + + d_vpr_h("%s: initialize pineapple data\n", __func__); + + core->platform->data = pineapple_data; + + rc = msm_vidc_pineapple_check_ddr_type(); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_init_platform_pineapple(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = msm_vidc_init_data(core); + if (rc) + return rc; + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/platform/volcano/inc/msm_vidc_volcano.h b/qcom/opensource/video-driver/driver/platform/volcano/inc/msm_vidc_volcano.h new file mode 100644 index 0000000000..5279b0e95d --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/volcano/inc/msm_vidc_volcano.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_VOLCANO_H_ +#define _MSM_VIDC_VOLCANO_H_ + +#include "msm_vidc_core.h" + +#if defined(CONFIG_MSM_VIDC_VOLCANO) +int msm_vidc_init_platform_volcano(struct msm_vidc_core *core); +int msm_vidc_deinit_platform_volcano(struct msm_vidc_core *core); +#else +int msm_vidc_init_platform_volcano(struct msm_vidc_core *core) +{ + return -EINVAL; +} + +int msm_vidc_deinit_platform_volcano(struct msm_vidc_core *core) +{ + return -EINVAL; +} +#endif + +#endif // _MSM_VIDC_VOLCANO_H_ diff --git a/qcom/opensource/video-driver/driver/platform/volcano/src/msm_vidc_volcano.c b/qcom/opensource/video-driver/driver/platform/volcano/src/msm_vidc_volcano.c new file mode 100644 index 0000000000..9d18472b48 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/volcano/src/msm_vidc_volcano.c @@ -0,0 +1,4821 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include + +#include +#include + +#include +#include "msm_vidc_volcano.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_platform_ext.h" +#include "msm_vidc_memory_ext.h" +#include "msm_vidc_synx.h" +#include "resources_ext.h" +#include "msm_vidc_iris2.h" +#include "hfi_property.h" +#include "hfi_command.h" +#include "venus_hfi.h" + +/* version: major[24:31], minor[16:23], revision[0:15] */ +#define DRIVER_VERSION 0x04000000 +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010 +#define MAX_BASE_LAYER_PRIORITY_ID 63 +#define MAX_OP_POINT 31 +#define MAX_BITRATE_V0 160000000 +#define MAX_BITRATE_V1 100000000 +#define DEFAULT_BITRATE 20000000 +#define MINIMUM_FPS 1 +#define MAXIMUM_FPS_V0 480 +#define MAXIMUM_FPS_V1 240 +#define MAX_QP 51 +#define DEFAULT_QP 20 +#define MAX_CONSTANT_QUALITY 100 +#define MIN_SLICE_BYTE_SIZE 512 +#define MAX_SLICE_BYTE_SIZE_V0 \ + ((MAX_BITRATE_V0) >> 3) +#define MAX_SLICE_BYTE_SIZE_V1 \ + ((MAX_BITRATE_V1) >> 3) +#define MAX_SLICE_MB_SIZE \ + (((4096 + 15) >> 4) * ((2160 + 15) >> 4)) +#define MAX_LTR_FRAME_COUNT 2 + +#define ENC MSM_VIDC_ENCODER +#define DEC MSM_VIDC_DECODER +#define H264 MSM_VIDC_H264 +#define HEVC MSM_VIDC_HEVC +#define VP9 MSM_VIDC_VP9 +#define HEIC MSM_VIDC_HEIC +#define CODECS_ALL (H264 | HEVC | VP9 | HEIC) +#define MAXIMUM_OVERRIDE_VP9_FPS 60 + +static struct codec_info codec_data_volcano[] = { + { + .v4l2_codec = V4L2_PIX_FMT_H264, + .vidc_codec = MSM_VIDC_H264, + .pixfmt_name = "AVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_HEVC, + .vidc_codec = MSM_VIDC_HEVC, + .pixfmt_name = "HEVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VP9, + .vidc_codec = MSM_VIDC_VP9, + .pixfmt_name = "VP9", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VIDC_HEIC, + .vidc_codec = MSM_VIDC_HEIC, + .pixfmt_name = "HEIC", + }, +}; + +static struct color_format_info color_format_data_volcano[] = { + { + .v4l2_color_format = V4L2_PIX_FMT_NV12, + .vidc_color_format = MSM_VIDC_FMT_NV12, + .pixfmt_name = "NV12", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_NV21, + .vidc_color_format = MSM_VIDC_FMT_NV21, + .pixfmt_name = "NV21", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC08C, + .vidc_color_format = MSM_VIDC_FMT_NV12C, + .pixfmt_name = "NV12C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC10C, + .vidc_color_format = MSM_VIDC_FMT_TP10C, + .pixfmt_name = "TP10C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_RGBA32, + .vidc_color_format = MSM_VIDC_FMT_RGBA8888, + .pixfmt_name = "RGBA", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_P010, + .vidc_color_format = MSM_VIDC_FMT_P010, + .pixfmt_name = "P010", + }, + { + .v4l2_color_format = V4L2_META_FMT_VIDC, + .vidc_color_format = MSM_VIDC_FMT_META, + .pixfmt_name = "META", + }, +}; + +static struct color_primaries_info color_primaries_data_volcano[] = { + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_RESERVED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_UNSPECIFIED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_REC709, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT709, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_BG, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE170M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT601_525, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE240M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_ST240M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_GENERIC_FILM, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_GENERIC_FILM, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_BT2020, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT2020, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DCI_P3, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_RP431_2, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_EG431, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_EG431_1, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_VIDC_EBU_TECH, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_EBU_TECH, + }, +}; + +static struct transfer_char_info transfer_char_data_volcano[] = { + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_RESERVED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_UNSPECIFIED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_709, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT709, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT470_SYSTEM_M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT470_SYSTEM_M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT470_SYSTEM_BG, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT470_SYSTEM_BG, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT601_525_OR_625, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT601_525_OR_625, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE240M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST240M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_LINEAR, + .vidc_transfer_char = MSM_VIDC_TRANSFER_LINEAR, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_XVYCC, + .vidc_transfer_char = MSM_VIDC_TRANSFER_XVYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT1361, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT1361_0, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SRGB, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SRGB_SYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_BT2020, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT2020_14, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE2084, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_ST428, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST428_1, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_VIDC_HLG, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT2100_2_HLG, + }, +}; + +static struct matrix_coeff_info matrix_coeff_data_volcano[] = { + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_UNSPECIFIED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_VIDC_SRGB_OR_SMPTE_ST428, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SRGB_SMPTE_ST428_1, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_VIDC_FCC47_73_682, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_FCC_TITLE_47, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_SMPTE240M, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020_CONST_LUM, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT, + }, +}; + +static struct msm_platform_core_capability core_data_volcano_v0[] = { + /* {type, value} */ + {ENC_CODECS, H264 | HEVC | HEIC}, + {DEC_CODECS, H264 | HEVC | VP9 | HEIC}, + {MAX_SESSION_COUNT, 16}, + {MAX_NUM_720P_SESSIONS, 16}, + {MAX_NUM_1080P_SESSIONS, 16}, + {MAX_NUM_4K_SESSIONS, 4}, + {MAX_SECURE_SESSION_COUNT, 3}, + {MAX_RT_MBPF, 130560}, /* (4 * ((3840*2176)/256)) */ + {MAX_MBPF, 139264}, /* (4 * ((4096*2176)/256)) */ + /* max_load 3840x2176@120fps*/ + /* Concurrency: UHD@30 decode + UHD@30 encode */ + {MAX_MBPS, 3916800}, + {MAX_IMAGE_MBPF, 1048576}, /* (16384x16384)/256 */ + {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */ + {MAX_MBPS_HQ, 244800}, /* ((1920x1088)/256)@30fps */ + {MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */ + {MAX_MBPS_B_FRAME, 979200}, /* 3840x2176/256 MBs@30fps */ + {MAX_MBPS_ALL_INTRA, 489600}, /* ((1920x1088)/256)@60fps */ + {MAX_ENH_LAYER_COUNT, 5}, + {NUM_VPP_PIPE, 2}, + {SW_PC, 1}, + {FW_UNLOAD, 0}, + {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */ + {SW_PC_DELAY, SW_PC_DELAY_VALUE }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/ + {FW_UNLOAD_DELAY, FW_UNLOAD_DELAY_VALUE }, /* 3000 ms (>SW_PC_DELAY)*/ + {PAGEFAULT_NON_FATAL, 1}, + {PAGETABLE_CACHING, 0}, + {DCVS, 1}, + {DECODE_BATCH, 1}, + {DECODE_BATCH_TIMEOUT, 200}, + {STATS_TIMEOUT_MS, 2000}, + {AV_SYNC_WINDOW_SIZE, 40}, + {NON_FATAL_FAULTS, 1}, + {ENC_AUTO_FRAMERATE, 0}, + {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_META_CAPTURE | + V4L2_CAP_STREAMING}, + {SUPPORTS_SYNX_FENCE, 1}, + {SUPPORTS_REQUESTS, 0}, +}; + +static struct msm_platform_core_capability core_data_volcano_v1[] = { + /* {type, value} */ + {ENC_CODECS, H264 | HEVC | HEIC}, + {DEC_CODECS, H264 | HEVC | VP9 | HEIC}, + {MAX_SESSION_COUNT, 16}, + {MAX_NUM_720P_SESSIONS, 8}, + {MAX_NUM_1080P_SESSIONS, 4}, + {MAX_NUM_4K_SESSIONS, 2}, + {MAX_SECURE_SESSION_COUNT, 3}, + {MAX_RT_MBPF, 65280}, /* ((3840x2176)/256) x 2 */ + {MAX_MBPF, 69632}, /* ((4096x2176)/256) x 2 */ + /* max_load 4096x2160@30fps*/ + /* Concurrency:UHD@30fps decode + 1080p@30fps encode */ + {MAX_MBPS, 1224000}, + {MAX_IMAGE_MBPF, 1048576}, /* (16384x16384)/256 */ + {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */ + {MAX_MBPS_HQ, 244800}, /* ((1920x1088)/256)@30fps */ + {MAX_MBPF_B_FRAME, 8160},/* ((1920x1088)/256) */ + {MAX_MBPS_B_FRAME, 489600}, /* ((1920x1088)/256) MBs@60fps */ + {MAX_MBPS_ALL_INTRA, 489600}, /* ((1920x1088)/256)@60fps */ + {MAX_ENH_LAYER_COUNT, 5}, + {NUM_VPP_PIPE, 2}, + {SW_PC, 1}, + {FW_UNLOAD, 0}, + {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */ + {SW_PC_DELAY, SW_PC_DELAY_VALUE }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/ + {FW_UNLOAD_DELAY, FW_UNLOAD_DELAY_VALUE }, /* 3000 ms (>SW_PC_DELAY)*/ + {PAGEFAULT_NON_FATAL, 1}, + {PAGETABLE_CACHING, 0}, + {DCVS, 1}, + {DECODE_BATCH, 1}, + {DECODE_BATCH_TIMEOUT, 200}, + {STATS_TIMEOUT_MS, 2000}, + {AV_SYNC_WINDOW_SIZE, 40}, + {NON_FATAL_FAULTS, 1}, + {ENC_AUTO_FRAMERATE, 0}, + {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_META_CAPTURE | + V4L2_CAP_STREAMING}, + {SUPPORTS_SYNX_FENCE, 1}, + {SUPPORTS_REQUESTS, 0}, +}; + +static struct msm_platform_inst_capability instance_cap_data_volcano_v0[] = { + /* {cap, domain, codec, + * min, max, step_or_mask, value, + * v4l2_id, + * hfi_id, + * flags} + */ + {DRV_VERSION, DEC|ENC, CODECS_ALL, + 0, INT_MAX, 1, DRIVER_VERSION, + V4L2_CID_MPEG_VIDC_DRIVER_VERSION}, + + {FRAME_WIDTH, DEC, CODECS_ALL, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_WIDTH, ENC, H264 | HEVC, 128, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, DEC, CODECS_ALL, 96, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {FRAME_HEIGHT, DEC, CODECS_ALL, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, DEC, CODECS_ALL, 96, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {PIX_FMTS, ENC | DEC, H264, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC | DEC, HEVC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12}, + + {PIX_FMTS, DEC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, DEC, VP9, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_INPUT, ENC | DEC, HEIC, 0, 64, 1, 1, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL, + 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE}, + + /* (4096 * 2176) / 256 */ + {MBPF, ENC, CODECS_ALL, 64, 34816, 1, 34816}, + + /* ((16384x16384)/256) */ + {MBPF, ENC, HEIC, 64, 1048576, 1, 1048576}, + + /* (4096 * 2176) / 256 */ + {MBPF, DEC, CODECS_ALL, 36, 34816, 1, 34816}, + + /* ((8192x8192)/256) */ + {MBPF, DEC, HEIC, 64, 262144, 1, 262144 }, + + /* (4096 * 2176) / 256 */ + {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 34816, 1, 34816}, + + /* Batch Mode Decode */ + /* BATCH_MBPF + 2 is done for chipsets other than lanai + * due to timeline constraints since msm_vidc_allow_decode_batch + * has checks to allow batching for less than BATCH_MBPF. + * Same applies for BATCH_FPS. + */ + /* (1920 * 1088) / 256 */ + {BATCH_MBPF, DEC, H264 | HEVC | VP9, 64, 8162, 1, 8162}, + + {BATCH_FPS, DEC, H264 | HEVC | VP9, 1, 61, 1, 61}, + + /* (4096 * 2176) / 256 */ + {SECURE_MBPF, ENC | DEC, H264 | HEVC | VP9, 64, 34816, 1, 34816}, + + {FRAME_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS_V0 << 16), + 1, (DEFAULT_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, ENC, HEIC, + (MINIMUM_FPS << 16), (MAXIMUM_FPS_V0 << 16), + 1, (MINIMUM_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, DEC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS_V0 << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {FRAME_RATE, DEC, VP9, + (MINIMUM_FPS << 16), (MAXIMUM_OVERRIDE_VP9_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {OPERATING_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {OPERATING_RATE, DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_OPERATING_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {INPUT_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8}, + + {MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60}, + + {MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675}, + + {MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320}, + + {MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 326389, 326389, 1, 326389}, + + {MB_CYCLES_FW_VPP, ENC | DEC, CODECS_ALL, 44156, 44156, 1, 44156}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + 0, 0, 1, 0}, + + {CLIENT_ID, ENC | DEC, CODECS_ALL, + INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, + V4L2_CID_MPEG_VIDC_CLIENT_ID}, + + {SECURE_MODE, ENC | DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_SECURE, + HFI_PROP_SECURE, + CAP_FLAG_NONE}, + + /* + * Client will enable V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE + * to get fence_id in input metadata buffer done. + */ + {META_OUTBUF_FENCE, DEC, H264 | HEVC | VP9, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE, + HFI_PROP_FENCE, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* + * Client to do set_ctrl with FENCE_ID to set fence_id + * and then client will do get_ctrl with FENCE_FD to get + * fence_fd corresponding to client set fence_id. + */ + {FENCE_ID, DEC, CODECS_ALL, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SW_FENCE_ID, + 0, + CAP_FLAG_DYNAMIC_ALLOWED | CAP_FLAG_OUTPUT_PORT}, + + {FENCE_FD, DEC, CODECS_ALL, + INVALID_FD, INT_MAX, 1, INVALID_FD, + V4L2_CID_MPEG_VIDC_SW_FENCE_FD, + 0, + CAP_FLAG_VOLATILE}, + + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_NONE, MSM_VIDC_FENCE_NONE, + BIT(MSM_VIDC_FENCE_NONE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_NONE, MSM_VIDC_SYNX_V2_FENCE, + BIT(MSM_VIDC_FENCE_NONE) | BIT(MSM_VIDC_SW_FENCE) | + BIT(MSM_VIDC_SYNX_V2_FENCE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* Fence direction for input buffer. Currently unused */ + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_NONE, + BIT(MSM_VIDC_FENCE_DIR_NONE), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_RX, + BIT(MSM_VIDC_FENCE_DIR_NONE) | BIT(MSM_VIDC_FENCE_DIR_TX) | + BIT(MSM_VIDC_FENCE_DIR_RX), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + {FENCE_ERROR_DATA_CORRUPT, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_FENCE_ERROR_DATA_CORRUPT}, + + {TS_REORDER, DEC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TS_REORDER}, + + {HFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_HFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {VFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_VFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ROTATION, ENC, CODECS_ALL, + 0, 270, 90, 0, + V4L2_CID_ROTATE, + HFI_PROP_ROTATION, + CAP_FLAG_OUTPUT_PORT}, + + {SUPER_FRAME, ENC, H264 | HEVC, + 0, 32, 1, 0, + V4L2_CID_MPEG_VIDC_SUPERFRAME, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {SLICE_DECODE, DEC, H264 | HEVC, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_MPEG_MSM_VIDC_DISABLE, + 0, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, + 0}, + + {HEADER_MODE, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + HFI_PROP_SEQ_HEADER_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_MPEG_MSM_VIDC_ENABLE, + 1, V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDC_VUI_TIMING_INFO, + HFI_PROP_DISABLE_VUI_TIMING_INFO, + CAP_FLAG_OUTPUT_PORT}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_OUTPUT_PORT}, + + {NAL_LENGTH_FIELD, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_MPEG_VIDEO_HEVC_SIZE_4, + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) | + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4), + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* TODO: Firmware introduced enumeration type for this + * with and without seq header. + */ + {REQUEST_I_FRAME, ENC, H264 | HEVC, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + HFI_PROP_REQUEST_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* Enc: Keeping CABAC and CAVLC as same bitrate. + * Dec: there's no use of Bitrate cap + */ + {BIT_RATE, ENC, H264 | HEVC, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE, + HFI_PROP_TOTAL_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITRATE_MODE, ENC, H264, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {CAVLC_MAX_BITRATE, ENC, H264, 0, + 160000000, 1, 160000000}, + + {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {LOWLATENCY_MAX_BITRATE, ENC, H264 | HEVC, 0, + 70000000, 1, 70000000}, + + {NUM_COMV, DEC, CODECS_ALL, + 0, INT_MAX, 1, 0}, + + {LOSSLESS, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU}, + + {FRAME_SKIP_MODE, ENC, H264 | HEVC | HEIC, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {FRAME_RC_ENABLE, ENC, H264 | HEVC | HEIC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE}, + + {CONSTANT_QUALITY, ENC, HEVC, + 1, MAX_CONSTANT_QUALITY, 1, 90, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CONSTANT_QUALITY, ENC, HEIC, + 1, MAX_CONSTANT_QUALITY, 1, 100, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, CODECS_ALL, + 0, INT_MAX, 1, 2 * DEFAULT_FPS - 1, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, HEIC, + 0, INT_MAX, 1, 0 /* all intra */, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_CLOSURE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + 0}, + + {B_FRAME, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {B_FRAME, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {BLUR_TYPES, ENC, H264 | HEVC, + MSM_VIDC_BLUR_NONE, MSM_VIDC_BLUR_EXTERNAL, + BIT(MSM_VIDC_BLUR_NONE) | BIT(MSM_VIDC_BLUR_EXTERNAL), + MSM_VIDC_BLUR_NONE, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_TYPES, + HFI_PROP_BLUR_TYPES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_RESOLUTION, + HFI_PROP_BLUR_RESOLUTION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CSC, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CSC, + HFI_PROP_CSC, + CAP_FLAG_OUTPUT_PORT}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX, + HFI_PROP_CSC_MATRIX, + CAP_FLAG_OUTPUT_PORT}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + 0, + CAP_FLAG_NONE}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {LTR_COUNT, ENC, H264 | HEVC, + 0, MAX_LTR_FRAME_COUNT, 1, 0, + V4L2_CID_MPEG_VIDEO_LTR_COUNT, + HFI_PROP_LTR_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {USE_LTR, ENC, H264 | HEVC, + 0, + ((1 << MAX_LTR_FRAME_COUNT) - 1), + 0, 0, + V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, + HFI_PROP_LTR_USE, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {MARK_LTR, ENC, H264 | HEVC, + INVALID_DEFAULT_MARK_OR_USE_LTR, + (MAX_LTR_FRAME_COUNT - 1), + 1, INVALID_DEFAULT_MARK_OR_USE_LTR, + V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, + HFI_PROP_LTR_MARK, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {BASELAYER_PRIORITY, ENC, H264, + 0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0, + V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, + HFI_PROP_BASELAYER_PRIORITYID, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {IR_TYPE, ENC, H264 | HEVC, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM), + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {IR_PERIOD, ENC, H264 | HEVC, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, + 0, + CAP_FLAG_INPUT_PORT | CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {AU_DELIMITER, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + HFI_PROP_AUD, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_CONTENT_ADAPTIVE_CODING, + HFI_PROP_CONTENT_ADAPTIVE_CODING, + CAP_FLAG_OUTPUT_PORT}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + MSM_VIDC_PREPROCESS_NONE, + MSM_VIDC_PREPROCESS_NONE, + BIT(MSM_VIDC_PREPROCESS_NONE), + MSM_VIDC_PREPROCESS_NONE, + 0, HFI_PROP_REQUEST_PREPROCESS, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + 0, MAX_BITRATE_BOOST, 25, MAX_BITRATE_BOOST, + V4L2_CID_MPEG_VIDC_QUALITY_BITRATE_BOOST, + HFI_PROP_BITRATE_BOOST, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_QUALITY, ENC, H264 | HEVC, + 0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY, + 0, + HFI_PROP_MAINTAIN_MIN_QUALITY, + CAP_FLAG_OUTPUT_PORT}, + + {VBV_DELAY, ENC, H264 | HEVC, + 200, 300, 100, 300, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, + HFI_PROP_VBV_DELAY, + CAP_FLAG_OUTPUT_PORT}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + /* default peak bitrate is 10% larger than avg bitrate */ + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + HFI_PROP_TOTAL_PEAK_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {MIN_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP}, + + {I_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP}, + + {MAX_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MAX_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP}, + + {I_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP}, + + {I_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {I_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {LAYER_TYPE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_TYPE, ENC, H264, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_ENABLE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT}, + + {LAYER_ENABLE, ENC, HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {ENH_LAYER_COUNT, ENC, HEVC, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, ENC, H264, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L0_BR, ENC, H264, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, HEVC, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, H264, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, HEVC, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, H264, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, HEVC, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L3_BR, ENC, H264, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L3_BR, ENC, HEVC, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, H264, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, HEVC, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, H264, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, HEVC, + 1, MAX_BITRATE_V0, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENTROPY_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + HFI_PROP_CABAC_SESSION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {ENTROPY_MODE, DEC, H264 | HEVC | VP9, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + 0, + HFI_PROP_CABAC_SESSION}, + + {PROFILE, ENC | DEC, H264, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, ENC | DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE, + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_MPEG_VIDEO_VP9_PROFILE_2, + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + {LEVEL, ENC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2), + V4L2_MPEG_VIDEO_H264_LEVEL_5_2, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1), + V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6), + V4L2_MPEG_VIDEO_HEVC_LEVEL_6, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + V4L2_MPEG_VIDEO_VP9_LEVEL_5_2, + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2), + V4L2_MPEG_VIDEO_VP9_LEVEL_5_2, + V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + {HEVC_TIER, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEIC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN), + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + DB_H264_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + BIT(DB_H264_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + DB_HEVC_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) | + BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_ALPHA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA}, + + {LF_ALPHA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2}, + + {LF_BETA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA}, + + {LF_BETA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2}, + + {SLICE_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MAX_BYTES, ENC, H264 | HEVC, + MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE_V0, + 1, MIN_SLICE_BYTE_SIZE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + HFI_PROP_MULTI_SLICE_BYTES_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {SLICE_MAX_MB, ENC, H264 | HEVC, + 1, MAX_SLICE_MB_SIZE, 1, 1, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + HFI_PROP_MULTI_SLICE_MB_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {MB_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {TRANSFORM_8X8, ENC, H264, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + HFI_PROP_8X8_TRANSFORM, + CAP_FLAG_OUTPUT_PORT}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET, + 1, MAX_CHROMA_QP_OFFSET, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + HFI_PROP_CHROMA_QP_OFFSET, + CAP_FLAG_OUTPUT_PORT}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_8BIT, + CAP_FLAG_INPUT_PORT}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_10BIT, + CAP_FLAG_INPUT_PORT}, + + {STAGE, DEC|ENC, CODECS_ALL, + MSM_VIDC_STAGE_1, + MSM_VIDC_STAGE_2, 1, + MSM_VIDC_STAGE_2, + 0, + HFI_PROP_STAGE}, + + {PIPE, DEC|ENC, CODECS_ALL, + MSM_VIDC_PIPE_1, + MSM_VIDC_PIPE_2, 1, + MSM_VIDC_PIPE_2, + 0, + HFI_PROP_PIPE}, + + {POC, DEC, H264, + 0, 2, 1, 1, + 0, + HFI_PROP_PIC_ORDER_CNT_TYPE, + CAP_FLAG_VOLATILE}, + + /* + * value of MAX_NUM_REORDER_FRAMES is 32 packed as mentioned below + * (max_num_reorder_count << 16) | max_dec_frame_buffering_count + */ + {MAX_NUM_REORDER_FRAMES, DEC, H264 | HEVC, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_MAX_NUM_REORDER_FRAMES, + HFI_PROP_MAX_NUM_REORDER_FRAMES, + CAP_FLAG_VOLATILE}, + + {QUALITY_MODE, ENC, CODECS_ALL, + MSM_VIDC_MAX_QUALITY_MODE, + MSM_VIDC_POWER_SAVE_MODE, 1, + MSM_VIDC_POWER_SAVE_MODE}, + + {CODED_FRAMES, DEC, H264 | HEVC | HEIC, + CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE, + 1, CODED_FRAMES_PROGRESSIVE, + V4L2_CID_MPEG_VIDC_INTERLACE, + HFI_PROP_CODED_FRAMES, + CAP_FLAG_VOLATILE}, + + {BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8, + 0, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH}, + + {CODEC_CONFIG, DEC, H264 | HEVC | HEIC, 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CODEC_CONFIG, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_MIN_BITSTREAM_SIZE_OVERWRITE}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_THUMBNAIL_MODE, + HFI_PROP_THUMBNAIL_MODE, + CAP_FLAG_INPUT_PORT}, + + {DEFAULT_HEADER, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_DEC_DEFAULT_HEADER}, + + {RAP_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_DEC_START_FROM_RAP_FRAME, + CAP_FLAG_INPUT_PORT}, + + {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {PRIORITY, DEC|ENC, CODECS_ALL, + 0, 4, 1, 4, + V4L2_CID_MPEG_VIDC_PRIORITY, + HFI_PROP_SESSION_PRIORITY, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENC_IP_CR, ENC, CODECS_ALL, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_ENC_INPUT_COMPRESSION_RATIO, + 0, CAP_FLAG_DYNAMIC_ALLOWED}, + {LAST_FLAG_EVENT_ENABLE, DEC | ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LAST_FLAG_EVENT_ENABLE}, + {ALL_INTRA, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {META_LTR_MARK_USE, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_LTR_MARK_USE_DETAILS, + HFI_PROP_LTR_MARK_USE_DETAILS, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEQ_HDR_NAL, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEQ_HEADER_NAL, + HFI_PROP_METADATA_SEQ_HEADER_NAL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DPB_MISR, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_LUMA_CHROMA_MISR, + HFI_PROP_DPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_OPB_MISR, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OPB_LUMA_CHROMA_MISR, + HFI_PROP_OPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_INTERLACE, DEC, H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_INTERLACE, + HFI_PROP_INTERLACE_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TIMESTAMP, DEC | ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TIMESTAMP, + HFI_PROP_TIMESTAMP, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_CONCEALED_MB_CNT, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_CONCEALED_MB_COUNT, + HFI_PROP_CONEALED_MB_COUNT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HIST_INFO, DEC, HEVC | VP9, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HISTOGRAM_INFO, + HFI_PROP_HISTOGRAM_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_PICTURE_TYPE, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_PICTURE_TYPE, + HFI_PROP_PICTURE_TYPE, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + {META_SEI_MASTERING_DISP, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_MASTERING_DISP, DEC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, DEC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, DEC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_EVA_STATS, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_EVA_STATS, + HFI_PROP_EVA_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_BUF_TAG, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + /* + * when fence enabled, client needs output buffer_tag + * in input metadata buffer done. + */ + {META_BUF_TAG, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_TX_OUTPUT | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + {META_DPB_TAG_LIST, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_TAG_LIST, + HFI_PROP_DPB_TAG_LIST, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, ENC, HEIC | H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ENC_QP_METADATA, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ENC_QP_METADATA, + HFI_PROP_ENC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ROI_INFO, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ROI_INFO, + HFI_PROP_ROI_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DEC_QP_METADATA, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DEC_QP_METADATA, + HFI_PROP_DEC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {GRID_ENABLE, ENC, HEIC, + 0, 1, 1, 1, + 0, + HFI_PROP_HEIC_GRID_ENABLE, + CAP_FLAG_OUTPUT_PORT}, + + {GRID_SIZE, ENC, HEIC, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH * 2, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH, + V4L2_CID_MPEG_VIDC_GRID_WIDTH}, + + {COMPLEXITY, ENC, H264 | HEVC, + 0, 100, + 1, DEFAULT_COMPLEXITY, + V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SIGNAL_COLOR_INFO, + HFI_PROP_SIGNAL_COLOR_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, +}; + +static struct msm_platform_inst_capability instance_cap_data_volcano_v1[] = { + /* {cap, domain, codec, + * min, max, step_or_mask, value, + * v4l2_id, + * hfi_id, + * flags} + */ + {DRV_VERSION, DEC | ENC, CODECS_ALL, + 0, INT_MAX, 1, DRIVER_VERSION, + V4L2_CID_MPEG_VIDC_DRIVER_VERSION}, + + {FRAME_WIDTH, DEC, CODECS_ALL, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_WIDTH, ENC, H264 | HEVC, 128, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, DEC, CODECS_ALL, 96, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {FRAME_HEIGHT, DEC, CODECS_ALL, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, DEC, CODECS_ALL, 96, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {PIX_FMTS, ENC | DEC, H264, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC | DEC, HEVC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12}, + + {PIX_FMTS, DEC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, DEC, VP9, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_INPUT, ENC | DEC, HEIC, 0, 64, 1, 1, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL, + 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE}, + + /* (4096 * 2176) / 256 */ + {MBPF, ENC, CODECS_ALL, 64, 34816, 1, 34816}, + + /* ((16384x16384)/256) */ + {MBPF, ENC, HEIC, 64, 1048576, 1, 1048576}, + + /* (4096 * 2176) / 256 */ + {MBPF, DEC, CODECS_ALL, 36, 34816, 1, 34816}, + + /* ((8192x8192)/256) */ + {MBPF, DEC, HEIC, 64, 262144, 1, 262144 }, //DBT + + /* (4096 * 2176) / 256 */ + {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 34816, 1, 34816}, + + /* Batch Mode Decode */ + /* BATCH_MBPF + 2 is done for chipsets other than lanai + * due to timeline constraints since msm_vidc_allow_decode_batch + * has checks to allow batching for less than BATCH_MBPF. + * Same applies for BATCH_FPS. + */ + /* (1920 * 1088) / 256 */ + {BATCH_MBPF, DEC, H264 | HEVC | VP9, 64, 8162, 1, 8162}, + + {BATCH_FPS, DEC, H264 | HEVC | VP9, 1, 61, 1, 61}, + + /* (4096 * 2176) / 256 */ + {SECURE_MBPF, ENC | DEC, H264 | HEVC | VP9, 64, 34816, 1, 34816}, + + {FRAME_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS_V1 << 16), + 1, (DEFAULT_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, ENC, HEIC, + (MINIMUM_FPS << 16), (MAXIMUM_FPS_V1 << 16), + 1, (MINIMUM_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {FRAME_RATE, DEC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS_V1 << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {FRAME_RATE, DEC, VP9, + (MINIMUM_FPS << 16), (MAXIMUM_OVERRIDE_VP9_FPS << 16), + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_FRAME_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {OPERATING_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {OPERATING_RATE, DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16), + V4L2_CID_MPEG_VIDC_OPERATING_RATE, + 0, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {INPUT_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8}, + + {MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60}, + + {MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675}, + + {MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320}, + + {MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 326389, 326389, 1, 326389}, + + {MB_CYCLES_FW_VPP, ENC | DEC, CODECS_ALL, 44156, 44156, 1, 44156}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + 0, 0, 1, 0}, + + {CLIENT_ID, ENC | DEC, CODECS_ALL, + INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, + V4L2_CID_MPEG_VIDC_CLIENT_ID}, + + {SECURE_MODE, ENC | DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_SECURE, + HFI_PROP_SECURE, + CAP_FLAG_NONE}, + + /* + * Client will enable V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE + * to get fence_id in input metadata buffer done. + */ + {META_OUTBUF_FENCE, DEC, H264 | HEVC | VP9, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OUTBUF_FENCE, + HFI_PROP_FENCE, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* + * Client to do set_ctrl with FENCE_ID to set fence_id + * and then client will do get_ctrl with FENCE_FD to get + * fence_fd corresponding to client set fence_id. + */ + {FENCE_ID, DEC, CODECS_ALL, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SW_FENCE_ID, + 0, + CAP_FLAG_DYNAMIC_ALLOWED | CAP_FLAG_OUTPUT_PORT}, + + {FENCE_FD, DEC, CODECS_ALL, + INVALID_FD, INT_MAX, 1, INVALID_FD, + V4L2_CID_MPEG_VIDC_SW_FENCE_FD, + 0, + CAP_FLAG_VOLATILE}, + + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_NONE, MSM_VIDC_FENCE_NONE, + BIT(MSM_VIDC_FENCE_NONE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_NONE, MSM_VIDC_SYNX_V2_FENCE, + BIT(MSM_VIDC_FENCE_NONE) | BIT(MSM_VIDC_SW_FENCE) | + BIT(MSM_VIDC_SYNX_V2_FENCE), + MSM_VIDC_FENCE_NONE, + 0, + HFI_PROP_FENCE_TYPE, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* Fence direction for input buffer. Currently unused */ + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_NONE, + BIT(MSM_VIDC_FENCE_DIR_NONE), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_INPUT_PORT}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + MSM_VIDC_FENCE_DIR_NONE, MSM_VIDC_FENCE_DIR_RX, + BIT(MSM_VIDC_FENCE_DIR_NONE) | BIT(MSM_VIDC_FENCE_DIR_TX) | + BIT(MSM_VIDC_FENCE_DIR_RX), + MSM_VIDC_FENCE_DIR_NONE, + 0, + HFI_PROP_FENCE_DIRECTION, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + {FENCE_ERROR_DATA_CORRUPT, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_FENCE_ERROR_DATA_CORRUPT}, + + {TS_REORDER, DEC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TS_REORDER}, + + {HFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_HFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {VFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_VFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ROTATION, ENC, CODECS_ALL, + 0, 270, 90, 0, + V4L2_CID_ROTATE, + HFI_PROP_ROTATION, + CAP_FLAG_OUTPUT_PORT}, + + {SUPER_FRAME, ENC, H264 | HEVC, + 0, 32, 1, 0, + V4L2_CID_MPEG_VIDC_SUPERFRAME, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {SLICE_DECODE, DEC, H264 | HEVC, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_MPEG_MSM_VIDC_DISABLE, + 0, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, + 0}, + + {HEADER_MODE, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + HFI_PROP_SEQ_HEADER_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL, + V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_MPEG_MSM_VIDC_ENABLE, + 1, V4L2_MPEG_MSM_VIDC_DISABLE, + V4L2_CID_MPEG_VIDC_VUI_TIMING_INFO, + HFI_PROP_DISABLE_VUI_TIMING_INFO, + CAP_FLAG_OUTPUT_PORT}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_OUTPUT_PORT}, + + {NAL_LENGTH_FIELD, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_MPEG_VIDEO_HEVC_SIZE_4, + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) | + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4), + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* TODO: Firmware introduced enumeration type for this + * with and without seq header. + */ + {REQUEST_I_FRAME, ENC, H264 | HEVC, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + HFI_PROP_REQUEST_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* Enc: Keeping CABAC and CAVLC as same bitrate. + * Dec: there's no use of Bitrate cap + */ + {BIT_RATE, ENC, H264 | HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE, + HFI_PROP_TOTAL_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITRATE_MODE, ENC, H264, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0, + MAX_BITRATE_V1, 1, MAX_BITRATE_V1}, + + {CAVLC_MAX_BITRATE, ENC, H264, 0, + MAX_BITRATE_V1, 1, MAX_BITRATE_V1}, + + {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0, + MAX_BITRATE_V1, 1, MAX_BITRATE_V1}, + + {LOWLATENCY_MAX_BITRATE, ENC, H264 | HEVC, 0, + 70000000, 1, 70000000}, + + {NUM_COMV, DEC, CODECS_ALL, + 0, INT_MAX, 1, 0}, + + {LOSSLESS, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU}, + + {FRAME_SKIP_MODE, ENC, H264 | HEVC | HEIC, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {FRAME_RC_ENABLE, ENC, H264 | HEVC | HEIC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE}, + + {CONSTANT_QUALITY, ENC, HEVC, + 1, MAX_CONSTANT_QUALITY, 1, 90, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CONSTANT_QUALITY, ENC, HEIC, + 1, MAX_CONSTANT_QUALITY, 1, 100, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, CODECS_ALL, + 0, INT_MAX, 1, 2 * DEFAULT_FPS - 1, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, HEIC, + 0, INT_MAX, 1, 0 /* all intra */, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_CLOSURE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + 0}, + + {B_FRAME, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {B_FRAME, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {BLUR_TYPES, ENC, H264 | HEVC, + MSM_VIDC_BLUR_NONE, MSM_VIDC_BLUR_EXTERNAL, + BIT(MSM_VIDC_BLUR_NONE) | BIT(MSM_VIDC_BLUR_EXTERNAL), + MSM_VIDC_BLUR_NONE, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_TYPES, + HFI_PROP_BLUR_TYPES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_BLUR_RESOLUTION, + HFI_PROP_BLUR_RESOLUTION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {CSC, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CSC, + HFI_PROP_CSC, + CAP_FLAG_OUTPUT_PORT}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_VIDEO_VPE_CSC_CUSTOM_MATRIX, + HFI_PROP_CSC_MATRIX, + CAP_FLAG_OUTPUT_PORT}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + 0, + CAP_FLAG_NONE}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LOWLATENCY_REQUEST, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {LTR_COUNT, ENC, H264 | HEVC, + 0, MAX_LTR_FRAME_COUNT, 1, 0, + V4L2_CID_MPEG_VIDEO_LTR_COUNT, + HFI_PROP_LTR_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {USE_LTR, ENC, H264 | HEVC, + 0, + ((1 << MAX_LTR_FRAME_COUNT) - 1), + 0, 0, + V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, + HFI_PROP_LTR_USE, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {MARK_LTR, ENC, H264 | HEVC, + INVALID_DEFAULT_MARK_OR_USE_LTR, + (MAX_LTR_FRAME_COUNT - 1), + 1, INVALID_DEFAULT_MARK_OR_USE_LTR, + V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, + HFI_PROP_LTR_MARK, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {BASELAYER_PRIORITY, ENC, H264, + 0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0, + V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, + HFI_PROP_BASELAYER_PRIORITYID, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {IR_TYPE, ENC, H264 | HEVC, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + BIT(V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM), + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {IR_PERIOD, ENC, H264 | HEVC, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, + 0, + CAP_FLAG_INPUT_PORT | CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {AU_DELIMITER, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + HFI_PROP_AUD, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {TIME_DELTA_BASED_RC, ENC, HEIC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_TIME_DELTA_BASED_RC, + HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDC_CONTENT_ADAPTIVE_CODING, + HFI_PROP_CONTENT_ADAPTIVE_CODING, + CAP_FLAG_OUTPUT_PORT}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + MSM_VIDC_PREPROCESS_NONE, + MSM_VIDC_PREPROCESS_NONE, + BIT(MSM_VIDC_PREPROCESS_NONE), + MSM_VIDC_PREPROCESS_NONE, + 0, HFI_PROP_REQUEST_PREPROCESS, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + 0, MAX_BITRATE_BOOST, 25, MAX_BITRATE_BOOST, + V4L2_CID_MPEG_VIDC_QUALITY_BITRATE_BOOST, + HFI_PROP_BITRATE_BOOST, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_QUALITY, ENC, H264 | HEVC, + 0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY, + 0, + HFI_PROP_MAINTAIN_MIN_QUALITY, + CAP_FLAG_OUTPUT_PORT}, + + {VBV_DELAY, ENC, H264 | HEVC, + 200, 300, 100, 300, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, + HFI_PROP_VBV_DELAY, + CAP_FLAG_OUTPUT_PORT}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + /* default peak bitrate is 10% larger than avg bitrate */ + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + HFI_PROP_TOTAL_PEAK_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {MIN_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP}, + + {I_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP}, + + {MAX_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MAX_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP}, + + {I_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP}, + + {I_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {I_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {LAYER_TYPE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_TYPE, ENC, H264, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_ENABLE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT}, + + {LAYER_ENABLE, ENC, HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {ENH_LAYER_COUNT, ENC, HEVC, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, ENC, H264, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L0_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L3_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L3_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, H264, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, HEVC, + 1, MAX_BITRATE_V1, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENTROPY_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + HFI_PROP_CABAC_SESSION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {ENTROPY_MODE, DEC, H264 | HEVC | VP9, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + 0, + HFI_PROP_CABAC_SESSION}, + + {PROFILE, ENC | DEC, H264, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, ENC | DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE, + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_MPEG_VIDEO_VP9_PROFILE_2, + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5), + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1), + V4L2_MPEG_VIDEO_H264_LEVEL_5_1, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5), + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + V4L2_MPEG_VIDEO_VP9_LEVEL_5_0, + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0), + V4L2_MPEG_VIDEO_VP9_LEVEL_5_0, + V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEIC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN), + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + DB_H264_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + BIT(DB_H264_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + DB_HEVC_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) | + BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_ALPHA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA}, + + {LF_ALPHA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2}, + + {LF_BETA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA}, + + {LF_BETA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2}, + + {SLICE_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MODE, ENC, HEIC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MAX_BYTES, ENC, H264 | HEVC, + MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE_V1, + 1, MIN_SLICE_BYTE_SIZE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + HFI_PROP_MULTI_SLICE_BYTES_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {SLICE_MAX_MB, ENC, H264 | HEVC, + 1, MAX_SLICE_MB_SIZE, 1, 1, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + HFI_PROP_MULTI_SLICE_MB_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {MB_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {TRANSFORM_8X8, ENC, H264, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + HFI_PROP_8X8_TRANSFORM, + CAP_FLAG_OUTPUT_PORT}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET, + 1, MAX_CHROMA_QP_OFFSET, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + HFI_PROP_CHROMA_QP_OFFSET, + CAP_FLAG_OUTPUT_PORT}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_8BIT, + CAP_FLAG_INPUT_PORT}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_10BIT, + CAP_FLAG_INPUT_PORT}, + + {STAGE, DEC | ENC, CODECS_ALL, + MSM_VIDC_STAGE_1, + MSM_VIDC_STAGE_2, 1, + MSM_VIDC_STAGE_2, + 0, + HFI_PROP_STAGE}, + + {PIPE, DEC | ENC, CODECS_ALL, + MSM_VIDC_PIPE_1, + MSM_VIDC_PIPE_2, 1, + MSM_VIDC_PIPE_2, + 0, + HFI_PROP_PIPE}, + + {POC, DEC, H264, + 0, 2, 1, 1, + 0, + HFI_PROP_PIC_ORDER_CNT_TYPE, + CAP_FLAG_VOLATILE}, + + /* + * value of MAX_NUM_REORDER_FRAMES is 32 packed as mentioned below + * (max_num_reorder_count << 16) | max_dec_frame_buffering_count + */ + {MAX_NUM_REORDER_FRAMES, DEC, H264 | HEVC, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_MAX_NUM_REORDER_FRAMES, + HFI_PROP_MAX_NUM_REORDER_FRAMES, + CAP_FLAG_VOLATILE}, + + {QUALITY_MODE, ENC, CODECS_ALL, + MSM_VIDC_MAX_QUALITY_MODE, + MSM_VIDC_POWER_SAVE_MODE, 1, + MSM_VIDC_POWER_SAVE_MODE}, + + {CODED_FRAMES, DEC, H264 | HEVC | HEIC, + CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE, + 1, CODED_FRAMES_PROGRESSIVE, + V4L2_CID_MPEG_VIDC_INTERLACE, + HFI_PROP_CODED_FRAMES, + CAP_FLAG_VOLATILE}, + + {BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8, + 0, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH}, + + {CODEC_CONFIG, DEC, H264 | HEVC | HEIC, 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_CODEC_CONFIG, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_MIN_BITSTREAM_SIZE_OVERWRITE}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_THUMBNAIL_MODE, + HFI_PROP_THUMBNAIL_MODE, + CAP_FLAG_INPUT_PORT}, + + {DEFAULT_HEADER, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_DEC_DEFAULT_HEADER}, + + {RAP_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_DEC_START_FROM_RAP_FRAME, + CAP_FLAG_INPUT_PORT}, + + {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {PRIORITY, DEC | ENC, CODECS_ALL, + 0, 4, 1, 1, + V4L2_CID_MPEG_VIDC_PRIORITY, + HFI_PROP_SESSION_PRIORITY, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENC_IP_CR, ENC, CODECS_ALL, + 0, S32_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_ENC_INPUT_COMPRESSION_RATIO, + 0, CAP_FLAG_DYNAMIC_ALLOWED}, + {LAST_FLAG_EVENT_ENABLE, DEC | ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDC_LAST_FLAG_EVENT_ENABLE}, + {ALL_INTRA, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {META_LTR_MARK_USE, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_LTR_MARK_USE_DETAILS, + HFI_PROP_LTR_MARK_USE_DETAILS, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEQ_HDR_NAL, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEQ_HEADER_NAL, + HFI_PROP_METADATA_SEQ_HEADER_NAL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DPB_MISR, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_LUMA_CHROMA_MISR, + HFI_PROP_DPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_OPB_MISR, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_OPB_LUMA_CHROMA_MISR, + HFI_PROP_OPB_LUMA_CHROMA_MISR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_INTERLACE, DEC, H264, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_INTERLACE, + HFI_PROP_INTERLACE_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_TIMESTAMP, DEC | ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_TIMESTAMP, + HFI_PROP_TIMESTAMP, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_CONCEALED_MB_CNT, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_CONCEALED_MB_COUNT, + HFI_PROP_CONEALED_MB_COUNT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HIST_INFO, DEC, HEVC | VP9, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HISTOGRAM_INFO, + HFI_PROP_HISTOGRAM_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_PICTURE_TYPE, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_PICTURE_TYPE, + HFI_PROP_PICTURE_TYPE, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + {META_SEI_MASTERING_DISP, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_MASTERING_DISP, DEC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_MASTERING_DISPLAY_COLOUR, + HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SEI_CLL, DEC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SEI_CONTENT_LIGHT_LEVEL, + HFI_PROP_SEI_CONTENT_LIGHT_LEVEL, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, ENC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_HDR10PLUS, DEC, HEVC | HEIC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_HDR10PLUS, + HFI_PROP_SEI_HDR10PLUS_USERDATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_EVA_STATS, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | + MSM_VIDC_META_DYN_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_EVA_STATS, + HFI_PROP_EVA_STAT_INFO, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_BUF_TAG, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + /* + * when fence enabled, client needs output buffer_tag + * in input metadata buffer done. + */ + {META_BUF_TAG, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT | + MSM_VIDC_META_TX_OUTPUT | MSM_VIDC_META_RX_INPUT | + MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_BUFFER_TAG, + HFI_PROP_BUFFER_TAG, + CAP_FLAG_BITMASK | CAP_FLAG_META | CAP_FLAG_DYNAMIC_ALLOWED}, + + {META_DPB_TAG_LIST, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DPB_TAG_LIST, + HFI_PROP_DPB_TAG_LIST, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, ENC, HEIC | H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_SUBFRAME_OUTPUT, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_SUBFRAME_OUTPUT, + HFI_PROP_SUBFRAME_OUTPUT, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ENC_QP_METADATA, ENC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ENC_QP_METADATA, + HFI_PROP_ENC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_ROI_INFO, ENC, H264 | HEVC, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_TX_INPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_ROI_INFO, + HFI_PROP_ROI_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {META_DEC_QP_METADATA, DEC, CODECS_ALL, + MSM_VIDC_META_DISABLE, + MSM_VIDC_META_ENABLE | MSM_VIDC_META_RX_OUTPUT, + 0, MSM_VIDC_META_DISABLE, + V4L2_CID_MPEG_VIDC_METADATA_DEC_QP_METADATA, + HFI_PROP_DEC_QP_METADATA, + CAP_FLAG_BITMASK | CAP_FLAG_META}, + + {GRID_ENABLE, ENC, HEIC, + 0, 1, 1, 1, + 0, + HFI_PROP_HEIC_GRID_ENABLE, + CAP_FLAG_OUTPUT_PORT}, + + {GRID_SIZE, ENC, HEIC, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH * 2, + HEIC_GRID_WIDTH, HEIC_GRID_WIDTH, + V4L2_CID_MPEG_VIDC_GRID_WIDTH}, + + {COMPLEXITY, ENC, H264 | HEVC, + 0, 100, + 1, DEFAULT_COMPLEXITY, + V4L2_CID_MPEG_VIDC_VENC_COMPLEXITY}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL, + 0, INT_MAX, 1, 0, + V4L2_CID_MPEG_VIDC_SIGNAL_COLOR_INFO, + HFI_PROP_SIGNAL_COLOR_INFO, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, +}; + +static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_volcano_v0[] = { + /* {cap, domain, codec, + * parents, + * children, + * adjust, set} + */ + + {PIX_FMTS, ENC, H264, + {META_ROI_INFO, IR_PERIOD, CSC}}, + + {PIX_FMTS, ENC, HEVC, + {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, META_ROI_INFO, MIN_QUALITY, BLUR_TYPES, IR_PERIOD, + LTR_COUNT, CSC}}, + + {PIX_FMTS, ENC, HEIC, + {PROFILE, CSC}}, + + {PIX_FMTS, DEC, HEVC | HEIC, + {PROFILE}}, + + {FRAME_RATE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_q16}, + + {FRAME_RATE, DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_dec_frame_rate}, + + {OPERATING_RATE, DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_dec_operating_rate}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + {0}, + NULL, + NULL}, + + {SECURE_MODE, ENC | DEC, H264 | HEVC | VP9, + {0}, + NULL, + msm_vidc_set_u32}, + + {META_OUTBUF_FENCE, DEC, H264 | HEVC | VP9, + {LOWLATENCY_MODE, OUTBUF_FENCE_TYPE, OUTBUF_FENCE_DIRECTION}, + NULL, + NULL}, + + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_dec_outbuf_fence_type, + msm_vidc_set_outbuf_fence_type}, + + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_dec_outbuf_fence_direction, + msm_vidc_set_outbuf_fence_direction}, + + {FENCE_ERROR_DATA_CORRUPT, DEC, H264 | HEVC | VP9, + {0}, + NULL, + msm_vidc_set_u32}, + + {HFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {VFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {ROTATION, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_rotation}, + + {SUPER_FRAME, ENC, H264 | HEVC, + {INPUT_BUF_HOST_MAX_COUNT, OUTPUT_BUF_HOST_MAX_COUNT}, + NULL, + NULL}, + + {SLICE_DECODE, DEC, H264 | HEVC, + {0}, + NULL, + NULL}, + + {HEADER_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_header_mode}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_nal_length}, + + {REQUEST_I_FRAME, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_req_sync_frame}, + + {BIT_RATE, ENC, H264, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BIT_RATE, ENC, HEVC, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BITRATE_MODE, ENC, H264, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE, + META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEVC, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT, + BIT_RATE, META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE, META_EVA_STATS}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEIC, + {TIME_DELTA_BASED_RC, CONSTANT_QUALITY}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {CONSTANT_QUALITY, ENC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_constant_quality}, + + {GOP_SIZE, ENC, CODECS_ALL, + {ALL_INTRA}, + msm_vidc_adjust_gop_size, + msm_vidc_set_gop_size}, + + {GOP_SIZE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {B_FRAME, ENC, H264 | HEVC, + {ALL_INTRA}, + msm_vidc_adjust_b_frame, + msm_vidc_set_u32}, + + {B_FRAME, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {BLUR_TYPES, ENC, H264 | HEVC, + {BLUR_RESOLUTION}, + msm_vidc_adjust_blur_type, + msm_vidc_set_u32_enum}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_blur_resolution, + msm_vidc_set_blur_resolution}, + + {CSC, ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_csc, + msm_vidc_set_u32}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_csc_custom_matrix}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + {STAGE, BIT_RATE}, + msm_vidc_adjust_enc_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LTR_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ltr_count, + msm_vidc_set_u32}, + + {USE_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_use_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {MARK_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_mark_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {IR_PERIOD, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ir_period, + msm_vidc_set_ir_period}, + + {AU_DELIMITER, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_u32}, + + {BASELAYER_PRIORITY, ENC, H264, + {0}, + NULL, + msm_vidc_set_u32}, + + {TIME_DELTA_BASED_RC, ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_delta_based_rc, + msm_vidc_set_u32}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + {REQUEST_PREPROCESS}, + msm_vidc_adjust_brs, + msm_vidc_set_vbr_related_properties}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_preprocess, + msm_vidc_set_preprocess}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_bitrate_boost, + msm_vidc_set_vbr_related_properties}, + + {MIN_QUALITY, ENC, H264 | HEVC, + {BLUR_TYPES, BITRATE_BOOST}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {VBV_DELAY, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_cbr_related_properties}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_peak_bitrate, + msm_vidc_set_cbr_related_properties}, + + {MIN_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_min_qp}, + + {MIN_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_min_qp, + msm_vidc_set_min_qp}, + + {MAX_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_max_qp}, + + {MAX_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_max_qp, + msm_vidc_set_max_qp}, + + {I_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_i_frame_qp, + msm_vidc_set_frame_qp}, + + {I_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_p_frame_qp, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_b_frame_qp, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {LAYER_TYPE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING, LTR_COUNT}}, + + {LAYER_ENABLE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING}}, + + {ENH_LAYER_COUNT, ENC, H264 | HEVC, + {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE, LTR_COUNT}, + msm_vidc_adjust_layer_count, + msm_vidc_set_layer_count_and_type}, + + {L0_BR, ENC, H264 | HEVC, + {L1_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L1_BR, ENC, H264 | HEVC, + {L2_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L2_BR, ENC, H264 | HEVC, + {L3_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L3_BR, ENC, H264 | HEVC, + {L4_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L4_BR, ENC, H264 | HEVC, + {L5_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L5_BR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {ENTROPY_MODE, ENC, H264, + {BIT_RATE}, + msm_vidc_adjust_entropy_mode, + msm_vidc_set_u32}, + + {PROFILE, ENC, H264, + {ENTROPY_MODE, TRANSFORM_8X8}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, H264, + {ENTROPY_MODE}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, ENC, HEVC | HEIC, + {META_SEI_MASTERING_DISP, META_SEI_CLL, META_HDR10PLUS}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, HEVC | HEIC, + {0}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, VP9, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_level}, + + {HEVC_TIER, ENC | DEC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LF_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_deblock_mode}, + + {SLICE_MODE, ENC, H264 | HEVC, + {STAGE}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {SLICE_MODE, ENC, HEIC, + {0}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {TRANSFORM_8X8, ENC, H264, + {0}, + msm_vidc_adjust_transform_8x8, + msm_vidc_set_u32}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + {0}, + msm_vidc_adjust_chroma_qp_index_offset, + msm_vidc_set_chroma_qp_index_offset}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_output_order, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {STAGE, ENC | DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_stage}, + + {STAGE, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_stage}, + + {STAGE, DEC, H264 | HEVC | VP9, + {0}, + NULL, + msm_vidc_set_stage}, + + {PIPE, DEC | ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_pipe}, + + {THUMBNAIL_MODE, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + msm_vidc_set_u32}, + + {THUMBNAIL_MODE, DEC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {RAP_FRAME, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32}, + + {PRIORITY, DEC | ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_session_priority, + msm_vidc_set_session_priority}, + + {ALL_INTRA, ENC, H264 | HEVC, + {LTR_COUNT, IR_PERIOD, SLICE_MODE, BIT_RATE}, + msm_vidc_adjust_all_intra, + NULL}, + + {META_EVA_STATS, ENC, HEVC, + {0}, + msm_vidc_adjust_eva_stats, + NULL}, + + {META_ROI_INFO, ENC, H264 | HEVC, + {MIN_QUALITY, IR_PERIOD, BLUR_TYPES}, + msm_vidc_adjust_roi_info, + NULL}, + + {GRID_ENABLE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_vui_timing_info}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_signal_color_info}, + + {META_SEI_MASTERING_DISP, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_sei_mastering_disp, + NULL}, + + {META_SEI_CLL, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_sei_cll, + NULL}, + + {META_HDR10PLUS, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_hdr10plus, + NULL}, +}; + +static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_volcano_v1[] = { + /* {cap, domain, codec, + * parents, + * children, + * adjust, set} + */ + + {PIX_FMTS, ENC, H264, + {META_ROI_INFO, IR_PERIOD, CSC}}, + + {PIX_FMTS, ENC, HEVC, + {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, META_ROI_INFO, MIN_QUALITY, BLUR_TYPES, IR_PERIOD, + LTR_COUNT, CSC}}, + + {PIX_FMTS, ENC, HEIC, + {PROFILE, CSC}}, + + {PIX_FMTS, DEC, HEVC | HEIC, + {PROFILE}}, + + {FRAME_RATE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_q16}, + + {FRAME_RATE, DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_dec_frame_rate}, + + {OPERATING_RATE, DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_dec_operating_rate}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + {0}, + NULL, + NULL}, + + {SECURE_MODE, ENC | DEC, H264 | HEVC | VP9, + {0}, + NULL, + msm_vidc_set_u32}, + + {META_OUTBUF_FENCE, DEC, H264 | HEVC | VP9, + {LOWLATENCY_MODE, OUTBUF_FENCE_TYPE, OUTBUF_FENCE_DIRECTION}, + NULL, + NULL}, + + {INBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_TYPE, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_dec_outbuf_fence_type, + msm_vidc_set_outbuf_fence_type}, + + {INBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + {0}, + NULL, + NULL}, + + {OUTBUF_FENCE_DIRECTION, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_dec_outbuf_fence_direction, + msm_vidc_set_outbuf_fence_direction}, + + {FENCE_ERROR_DATA_CORRUPT, DEC, H264 | HEVC | VP9, + {0}, + NULL, + msm_vidc_set_u32}, + + {HFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {VFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {ROTATION, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_rotation}, + + {SUPER_FRAME, ENC, H264 | HEVC, + {INPUT_BUF_HOST_MAX_COUNT, OUTPUT_BUF_HOST_MAX_COUNT}, + NULL, + NULL}, + + {SLICE_DECODE, DEC, H264 | HEVC, + {0}, + NULL, + NULL}, + + {HEADER_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_header_mode}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_nal_length}, + + {REQUEST_I_FRAME, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_req_sync_frame}, + + {BIT_RATE, ENC, H264, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BIT_RATE, ENC, HEVC, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BITRATE_MODE, ENC, H264, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE, + META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEVC, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT, + BIT_RATE, META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE, META_EVA_STATS}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEIC, + {TIME_DELTA_BASED_RC, CONSTANT_QUALITY}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {CONSTANT_QUALITY, ENC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_constant_quality}, + + {GOP_SIZE, ENC, CODECS_ALL, + {ALL_INTRA}, + msm_vidc_adjust_gop_size, + msm_vidc_set_gop_size}, + + {GOP_SIZE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {B_FRAME, ENC, H264 | HEVC, + {ALL_INTRA}, + msm_vidc_adjust_b_frame, + msm_vidc_set_u32}, + + {B_FRAME, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {BLUR_TYPES, ENC, H264 | HEVC, + {BLUR_RESOLUTION}, + msm_vidc_adjust_blur_type, + msm_vidc_set_u32_enum}, + + {BLUR_RESOLUTION, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_blur_resolution, + msm_vidc_set_blur_resolution}, + + {CSC, ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_csc, + msm_vidc_set_u32}, + + {CSC_CUSTOM_MATRIX, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_csc_custom_matrix}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + {STAGE, BIT_RATE}, + msm_vidc_adjust_enc_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LTR_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ltr_count, + msm_vidc_set_u32}, + + {USE_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_use_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {MARK_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_mark_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {IR_PERIOD, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ir_period, + msm_vidc_set_ir_period}, + + {AU_DELIMITER, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_u32}, + + {BASELAYER_PRIORITY, ENC, H264, + {0}, + NULL, + msm_vidc_set_u32}, + + {TIME_DELTA_BASED_RC, ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_delta_based_rc, + msm_vidc_set_u32}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + {REQUEST_PREPROCESS}, + msm_vidc_adjust_brs, + msm_vidc_set_vbr_related_properties}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_preprocess, + msm_vidc_set_preprocess}, + + {BITRATE_BOOST, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_bitrate_boost, + msm_vidc_set_vbr_related_properties}, + + {MIN_QUALITY, ENC, H264 | HEVC, + {BLUR_TYPES, BITRATE_BOOST}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {VBV_DELAY, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_cbr_related_properties}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_peak_bitrate, + msm_vidc_set_cbr_related_properties}, + + {MIN_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_min_qp}, + + {MIN_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_min_qp, + msm_vidc_set_min_qp}, + + {MAX_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_max_qp}, + + {MAX_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_max_qp, + msm_vidc_set_max_qp}, + + {I_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_i_frame_qp, + msm_vidc_set_frame_qp}, + + {I_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_p_frame_qp, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_b_frame_qp, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {LAYER_TYPE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING, LTR_COUNT}}, + + {LAYER_ENABLE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING}}, + + {ENH_LAYER_COUNT, ENC, H264 | HEVC, + {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE, LTR_COUNT}, + msm_vidc_adjust_layer_count, + msm_vidc_set_layer_count_and_type}, + + {L0_BR, ENC, H264 | HEVC, + {L1_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L1_BR, ENC, H264 | HEVC, + {L2_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L2_BR, ENC, H264 | HEVC, + {L3_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L3_BR, ENC, H264 | HEVC, + {L4_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L4_BR, ENC, H264 | HEVC, + {L5_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L5_BR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {ENTROPY_MODE, ENC, H264, + {BIT_RATE}, + msm_vidc_adjust_entropy_mode, + msm_vidc_set_u32}, + + {PROFILE, ENC, H264, + {ENTROPY_MODE, TRANSFORM_8X8}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, H264, + {ENTROPY_MODE}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, ENC, HEVC | HEIC, + {META_SEI_MASTERING_DISP, META_SEI_CLL, META_HDR10PLUS}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, HEVC | HEIC, + {0}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, VP9, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_level}, + + {HEVC_TIER, ENC | DEC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LF_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_deblock_mode}, + + {SLICE_MODE, ENC, H264 | HEVC, + {STAGE}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {SLICE_MODE, ENC, HEIC, + {0}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {TRANSFORM_8X8, ENC, H264, + {0}, + msm_vidc_adjust_transform_8x8, + msm_vidc_set_u32}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + {0}, + msm_vidc_adjust_chroma_qp_index_offset, + msm_vidc_set_chroma_qp_index_offset}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_output_order, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {STAGE, ENC | DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_stage}, + + {STAGE, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_stage}, + + {STAGE, DEC, H264 | HEVC | VP9, + {0}, + NULL, + msm_vidc_set_stage}, + + {PIPE, DEC|ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_pipe}, + + {THUMBNAIL_MODE, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + msm_vidc_set_u32}, + + {THUMBNAIL_MODE, DEC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {RAP_FRAME, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32}, + + {PRIORITY, DEC | ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_session_priority, + msm_vidc_set_session_priority}, + + {ALL_INTRA, ENC, H264 | HEVC, + {LTR_COUNT, IR_PERIOD, SLICE_MODE, BIT_RATE}, + msm_vidc_adjust_all_intra, + NULL}, + + {META_EVA_STATS, ENC, HEVC, + {0}, + msm_vidc_adjust_eva_stats, + NULL}, + + {META_ROI_INFO, ENC, H264 | HEVC, + {MIN_QUALITY, IR_PERIOD, BLUR_TYPES}, + msm_vidc_adjust_roi_info, + NULL}, + + {GRID_ENABLE, ENC, HEIC, + {0}, + NULL, + msm_vidc_set_u32}, + + {VUI_TIMING_INFO, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_vui_timing_info}, + + {SIGNAL_COLOR_INFO, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_signal_color_info}, + + {META_SEI_MASTERING_DISP, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_sei_mastering_disp, + NULL}, + + {META_SEI_CLL, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_sei_cll, + NULL}, + + {META_HDR10PLUS, ENC, HEVC | HEIC, + {0}, + msm_vidc_adjust_hdr10plus, + NULL}, +}; + +static const u32 volcano_msm_vidc_ssr_type[] = { + HFI_SSR_TYPE_SW_ERR_FATAL, + HFI_SSR_TYPE_NOC_ERROR, +}; + +/* Default UBWC config for LPDDR5 */ +static struct msm_vidc_ubwc_config_data ubwc_config_volcano[] = { + UBWC_CONFIG(8, 32, 15, 0, 1, 1, 1), +}; + +static struct msm_vidc_efuse_data efuse_data_volcano[] = { + /* IRIS_MULTIPIPE_DISABLE - max 4K@30 */ + EFUSE_ENTRY(0x221C8118, 4, 0x400, 0xA, SKU_VERSION), +}; + +static struct msm_vidc_format_capability format_data_volcano = { + .codec_info = codec_data_volcano, + .codec_info_size = ARRAY_SIZE(codec_data_volcano), + .color_format_info = color_format_data_volcano, + .color_format_info_size = ARRAY_SIZE(color_format_data_volcano), + .color_prim_info = color_primaries_data_volcano, + .color_prim_info_size = ARRAY_SIZE(color_primaries_data_volcano), + .transfer_char_info = transfer_char_data_volcano, + .transfer_char_info_size = ARRAY_SIZE(transfer_char_data_volcano), + .matrix_coeff_info = matrix_coeff_data_volcano, + .matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_volcano), +}; + +/* name, min_kbps, max_kbps */ +static const struct bw_table volcano_bw_table[] = { + { "venus-cnoc", 1000, 1000 }, + { "venus-ddr", 1000, 10000000 } +}; + +/* name, hw_trigger */ +static const struct regulator_table volcano_regulator_table[] = { + { "iris-ctl", 0 }, + { "vcodec", 1 }, +}; + +/* name, clock id, scaling */ +static const struct clk_table volcano_clk_table[] = { + { "gcc_video_axi0_clk", GCC_VIDEO_AXI0_CLK, 0 }, + { "video_cc_mvs0c_clk", VIDEO_CC_MVS0C_CLK, 0 }, + { "video_cc_mvs0_clk", VIDEO_CC_MVS0_CLK, 0 }, + { "video_cc_mvs0_clk_src", VIDEO_CC_MVS0_CLK_SRC, 1 }, +}; + +/* name, exclusive_release */ +static const struct clk_rst_table volcano_clk_reset_table[] = { + { "video_axi_reset", 0 }, + { "video_mvs0c_reset", 0 }, +}; + +/* name, start, size, secure, dma_coherant, region, dma_mask */ +const struct context_bank_table volcano_context_bank_table[] = { + {"qcom,vidc,cb-ns", + 0x25800000, 0xba800000, 0, 1, MSM_VIDC_NON_SECURE, 0 }, + {"qcom,vidc,cb-ns-pxl", + 0x00100000, 0xdff00000, 0, 1, MSM_VIDC_NON_SECURE_PIXEL, 0 }, + {"qcom,vidc,cb-sec-pxl", + 0x00500000, 0xdfb00000, 1, 0, MSM_VIDC_SECURE_PIXEL, 0 }, + {"qcom,vidc,cb-sec-non-pxl", + 0x01000000, 0x24800000, 1, 0, MSM_VIDC_SECURE_NONPIXEL, 0 }, + {"qcom,vidc,cb-sec-bitstream", + 0x00500000, 0xdfb00000, 1, 0, MSM_VIDC_SECURE_BITSTREAM, 0 }, +}; + +/* freq */ +static struct freq_table volcano_freq_table_sku0[] = { + {444000000}, {366000000}, {338000000}, {240000000} +}; + +static struct freq_table volcano_freq_table_sku1[] = { + {201600000} +}; + +/* register, value, mask */ +static const struct reg_preset_table volcano_reg_preset_table[] = { + { 0xB0088, 0x0, 0x11 }, +}; + +/* decoder properties */ +static const u32 volcano_vdec_psc_avc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_CODED_FRAMES, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PIC_ORDER_CNT_TYPE, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_SIGNAL_COLOR_INFO, + HFI_PROP_MAX_NUM_REORDER_FRAMES, +}; + +static const u32 volcano_vdec_psc_hevc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_TIER, + HFI_PROP_SIGNAL_COLOR_INFO, + HFI_PROP_MAX_NUM_REORDER_FRAMES, +}; + +static const u32 volcano_vdec_psc_vp9[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, +}; + +static const u32 volcano_vdec_input_properties_avc[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, +}; + +static const u32 volcano_vdec_input_properties_hevc[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, +}; + +static const u32 volcano_vdec_input_properties_vp9[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, +}; + +static const u32 volcano_vdec_output_properties_avc[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_CABAC_SESSION, + HFI_PROP_FENCE, + HFI_PROP_DPB_LIST, +}; + +static const u32 volcano_vdec_output_properties_hevc[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_FENCE, + HFI_PROP_DPB_LIST, +}; + +static const u32 volcano_vdec_output_properties_vp9[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_FENCE, + HFI_PROP_DPB_LIST, +}; + +static const struct msm_vidc_platform_data volcano_data_v0 = { + /* resources dependent on other module */ + .bw_tbl = volcano_bw_table, + .bw_tbl_size = ARRAY_SIZE(volcano_bw_table), + .regulator_tbl = volcano_regulator_table, + .regulator_tbl_size = ARRAY_SIZE(volcano_regulator_table), + .clk_tbl = volcano_clk_table, + .clk_tbl_size = ARRAY_SIZE(volcano_clk_table), + .clk_rst_tbl = volcano_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(volcano_clk_reset_table), + + /* populate context bank */ + .context_bank_tbl = volcano_context_bank_table, + .context_bank_tbl_size = ARRAY_SIZE(volcano_context_bank_table), + + /* platform specific resources */ + .freq_tbl = volcano_freq_table_sku0, + .freq_tbl_size = ARRAY_SIZE(volcano_freq_table_sku0), + .reg_prst_tbl = volcano_reg_preset_table, + .reg_prst_tbl_size = ARRAY_SIZE(volcano_reg_preset_table), + .fwname = "vpu20_2v", + .pas_id = 9, + .supports_mmrm = 0, + .vpu_ver = VPU_VERSION_IRIS2_2P, + + /* caps related resorces */ + .core_data = core_data_volcano_v0, + .core_data_size = ARRAY_SIZE(core_data_volcano_v0), + .inst_cap_data = instance_cap_data_volcano_v0, + .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_volcano_v0), + .inst_cap_dependency_data = instance_cap_dependency_data_volcano_v0, + .inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_volcano_v0), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .ubwc_config = ubwc_config_volcano, + .format_data = &format_data_volcano, + + /* decoder properties related*/ + .psc_avc_tbl = volcano_vdec_psc_avc, + .psc_avc_tbl_size = ARRAY_SIZE(volcano_vdec_psc_avc), + .psc_hevc_tbl = volcano_vdec_psc_hevc, + .psc_hevc_tbl_size = ARRAY_SIZE(volcano_vdec_psc_hevc), + .psc_vp9_tbl = volcano_vdec_psc_vp9, + .psc_vp9_tbl_size = ARRAY_SIZE(volcano_vdec_psc_vp9), + .dec_input_prop_avc = volcano_vdec_input_properties_avc, + .dec_input_prop_hevc = volcano_vdec_input_properties_hevc, + .dec_input_prop_vp9 = volcano_vdec_input_properties_vp9, + .dec_input_prop_size_avc = ARRAY_SIZE(volcano_vdec_input_properties_avc), + .dec_input_prop_size_hevc = ARRAY_SIZE(volcano_vdec_input_properties_hevc), + .dec_input_prop_size_vp9 = ARRAY_SIZE(volcano_vdec_input_properties_vp9), + .dec_output_prop_avc = volcano_vdec_output_properties_avc, + .dec_output_prop_hevc = volcano_vdec_output_properties_hevc, + .dec_output_prop_vp9 = volcano_vdec_output_properties_vp9, + .dec_output_prop_size_avc = ARRAY_SIZE(volcano_vdec_output_properties_avc), + .dec_output_prop_size_hevc = ARRAY_SIZE(volcano_vdec_output_properties_hevc), + .dec_output_prop_size_vp9 = ARRAY_SIZE(volcano_vdec_output_properties_vp9), + + .msm_vidc_ssr_type = volcano_msm_vidc_ssr_type, + .msm_vidc_ssr_type_size = ARRAY_SIZE(volcano_msm_vidc_ssr_type), + + /* Fuse specific resources */ + .efuse_data = efuse_data_volcano, + .efuse_data_size = ARRAY_SIZE(efuse_data_volcano), + .sku_version = SKU_VERSION_0, +}; + +static const struct msm_vidc_platform_data volcano_data_v1 = { + /* resources dependent on other module */ + .bw_tbl = volcano_bw_table, + .bw_tbl_size = ARRAY_SIZE(volcano_bw_table), + .regulator_tbl = volcano_regulator_table, + .regulator_tbl_size = ARRAY_SIZE(volcano_regulator_table), + .clk_tbl = volcano_clk_table, + .clk_tbl_size = ARRAY_SIZE(volcano_clk_table), + .clk_rst_tbl = volcano_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(volcano_clk_reset_table), + + /* populate context bank */ + .context_bank_tbl = volcano_context_bank_table, + .context_bank_tbl_size = ARRAY_SIZE(volcano_context_bank_table), + + /* platform specific resources */ + .freq_tbl = volcano_freq_table_sku1, + .freq_tbl_size = ARRAY_SIZE(volcano_freq_table_sku1), + .reg_prst_tbl = volcano_reg_preset_table, + .reg_prst_tbl_size = ARRAY_SIZE(volcano_reg_preset_table), + .fwname = "vpu20_2v", + .pas_id = 9, + .supports_mmrm = 0, + .vpu_ver = VPU_VERSION_IRIS2_2P, + + /* caps related resorces */ + .core_data = core_data_volcano_v1, + .core_data_size = ARRAY_SIZE(core_data_volcano_v1), + .inst_cap_data = instance_cap_data_volcano_v1, + .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_volcano_v1), + .inst_cap_dependency_data = instance_cap_dependency_data_volcano_v1, + .inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_volcano_v1), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .ubwc_config = ubwc_config_volcano, + .format_data = &format_data_volcano, + + /* decoder properties related*/ + .psc_avc_tbl = volcano_vdec_psc_avc, + .psc_avc_tbl_size = ARRAY_SIZE(volcano_vdec_psc_avc), + .psc_hevc_tbl = volcano_vdec_psc_hevc, + .psc_hevc_tbl_size = ARRAY_SIZE(volcano_vdec_psc_hevc), + .psc_vp9_tbl = volcano_vdec_psc_vp9, + .psc_vp9_tbl_size = ARRAY_SIZE(volcano_vdec_psc_vp9), + .dec_input_prop_avc = volcano_vdec_input_properties_avc, + .dec_input_prop_hevc = volcano_vdec_input_properties_hevc, + .dec_input_prop_vp9 = volcano_vdec_input_properties_vp9, + .dec_input_prop_size_avc = ARRAY_SIZE(volcano_vdec_input_properties_avc), + .dec_input_prop_size_hevc = ARRAY_SIZE(volcano_vdec_input_properties_hevc), + .dec_input_prop_size_vp9 = ARRAY_SIZE(volcano_vdec_input_properties_vp9), + .dec_output_prop_avc = volcano_vdec_output_properties_avc, + .dec_output_prop_hevc = volcano_vdec_output_properties_hevc, + .dec_output_prop_vp9 = volcano_vdec_output_properties_vp9, + .dec_output_prop_size_avc = ARRAY_SIZE(volcano_vdec_output_properties_avc), + .dec_output_prop_size_hevc = ARRAY_SIZE(volcano_vdec_output_properties_hevc), + .dec_output_prop_size_vp9 = ARRAY_SIZE(volcano_vdec_output_properties_vp9), + + .msm_vidc_ssr_type = volcano_msm_vidc_ssr_type, + .msm_vidc_ssr_type_size = ARRAY_SIZE(volcano_msm_vidc_ssr_type), + + /* Fuse specific resources */ + .efuse_data = efuse_data_volcano, + .efuse_data_size = ARRAY_SIZE(efuse_data_volcano), + .sku_version = SKU_VERSION_1, +}; + +int msm_vidc_volcano_check_ddr_type(struct msm_vidc_platform_data *platform_data, + u32 hbb_override_val) +{ + u32 ddr_type = DDR_TYPE_LPDDR5; + + if (!platform_data || !platform_data->ubwc_config) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + ddr_type = of_fdt_get_ddrtype(); + if (ddr_type == -ENOENT) + d_vpr_e("Failed to get ddr type, use LPDDR5\n"); + + if (platform_data->ubwc_config && + (ddr_type == DDR_TYPE_LPDDR4 || + ddr_type == DDR_TYPE_LPDDR4X)) + platform_data->ubwc_config->highest_bank_bit = hbb_override_val; + + d_vpr_h("DDR Type 0x%x hbb 0x%x\n", + ddr_type, platform_data->ubwc_config ? + platform_data->ubwc_config->highest_bank_bit : -1); + + return 0; +} + +static int msm_vidc_init_data(struct msm_vidc_core *core) +{ + struct device *dev = NULL; + int rc = 0; + + dev = &core->pdev->dev; + + d_vpr_h("%s: initialize volcano data\n", __func__); + + core->platform->data = volcano_data_v0; + + /* Check for sku version */ + rc = msm_vidc_read_efuse(core); + if (rc) { + d_vpr_e("%s: Failed to read efuse\n", __func__); + return rc; + } + + if (core->platform->data.sku_version == SKU_VERSION_1) + core->platform->data = volcano_data_v1; + + + core->mem_ops = get_mem_ops_ext(); + if (!core->mem_ops) { + d_vpr_e("%s: invalid memory ext ops\n", __func__); + return -EINVAL; + } + core->res_ops = get_res_ops_ext(); + if (!core->res_ops) { + d_vpr_e("%s: invalid resource ext ops\n", __func__); + return -EINVAL; + } + core->fence_ops = get_synx_fence_ops(); + if (!core->fence_ops) { + d_vpr_e("%s: invalid synx fence ops\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_volcano_check_ddr_type(&core->platform->data, 0xe); + if (rc) + return rc; + + /* Enable bug on for WD_TIMEOUT */ + msm_vidc_enable_bugon = MSM_VIDC_BUG_ON_WD_TIMEOUT; + + return rc; +} + +int msm_vidc_init_platform_volcano(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = msm_vidc_init_data(core); + if (rc) + return rc; + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/platform/volcano/src/volcano.c b/qcom/opensource/video-driver/driver/platform/volcano/src/volcano.c new file mode 100644 index 0000000000..209d162ead --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/volcano/src/volcano.c @@ -0,0 +1,1681 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include + +#include "msm_vidc_control.h" +#include "msm_vidc_volcano.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_iris2.h" +#include "hfi_property.h" +#include "hfi_command.h" +#include "venus_hfi.h" + +/* version: major[24:31], minor[16:23], revision[0:15] */ +#define DRIVER_VERSION 0x04000000 +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010 +#define MAX_BASE_LAYER_PRIORITY_ID 63 +#define MAX_OP_POINT 31 +#define MAX_BITRATE 160000000 +#define MAX_BITRATE_V1 100000000 +#define DEFAULT_BITRATE 20000000 +#define MINIMUM_FPS 1 +#define MAXIMUM_FPS 480 +#define MAX_QP 51 +#define DEFAULT_QP 20 +#define MAX_CONSTANT_QUALITY 100 +#define MIN_SLICE_BYTE_SIZE 512 +#define MAX_SLICE_BYTE_SIZE \ + ((MAX_BITRATE) >> 3) +#define MAX_SLICE_BYTE_SIZE_V1 \ + ((MAX_BITRATE_V1) >> 3) +#define MAX_SLICE_MB_SIZE \ + (((4096 + 15) >> 4) * ((2160 + 15) >> 4)) +#define MAX_LTR_FRAME_COUNT 2 + +#define ENC MSM_VIDC_ENCODER +#define DEC MSM_VIDC_DECODER +#define H264 MSM_VIDC_H264 +#define HEVC MSM_VIDC_HEVC +#define VP9 MSM_VIDC_VP9 +#define HEIC MSM_VIDC_HEIC +#define CODECS_ALL (H264 | HEVC | VP9 | HEIC) +#define MAXIMUM_OVERRIDE_VP9_FPS 200 + +#ifndef V4L2_PIX_FMT_QC08C +#define V4L2_PIX_FMT_QC08C v4l2_fourcc('Q', '0', '8', 'C') +#endif + +#ifndef V4L2_PIX_FMT_QC10C +#define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') +#endif + +static struct codec_info codec_data_volcano[] = { + { + .v4l2_codec = V4L2_PIX_FMT_H264, + .vidc_codec = MSM_VIDC_H264, + .pixfmt_name = "AVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_HEVC, + .vidc_codec = MSM_VIDC_HEVC, + .pixfmt_name = "HEVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VP9, + .vidc_codec = MSM_VIDC_VP9, + .pixfmt_name = "VP9", + }, +}; + +static struct color_format_info color_format_data_volcano[] = { + { + .v4l2_color_format = V4L2_PIX_FMT_NV12, + .vidc_color_format = MSM_VIDC_FMT_NV12, + .pixfmt_name = "NV12", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_NV21, + .vidc_color_format = MSM_VIDC_FMT_NV21, + .pixfmt_name = "NV21", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC08C, + .vidc_color_format = MSM_VIDC_FMT_NV12C, + .pixfmt_name = "NV12C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC10C, + .vidc_color_format = MSM_VIDC_FMT_TP10C, + .pixfmt_name = "TP10C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_RGBA32, + .vidc_color_format = MSM_VIDC_FMT_RGBA8888, + .pixfmt_name = "RGBA", + }, +}; + +static struct color_primaries_info color_primaries_data_volcano[] = { + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_RESERVED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_REC709, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT709, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_BG, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE170M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT601_525, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE240M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_ST240M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_BT2020, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT2020, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DCI_P3, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_RP431_2, + }, +}; + +static struct transfer_char_info transfer_char_data_volcano[] = { + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_RESERVED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_709, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT709, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE240M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST240M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SRGB, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SRGB_SYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE2084, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ, + }, +}; + +static struct matrix_coeff_info matrix_coeff_data_volcano[] = { + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_SMPTE240M, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020_CONST_LUM, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT, + }, +}; + +static struct msm_platform_core_capability core_data_volcano_v0[] = { + /* {type, value} */ + {ENC_CODECS, H264 | HEVC | HEIC}, + {DEC_CODECS, H264 | HEVC | VP9 | HEIC}, + {MAX_SESSION_COUNT, 16}, + {MAX_NUM_720P_SESSIONS, 16}, + {MAX_NUM_1080P_SESSIONS, 16}, + {MAX_NUM_4K_SESSIONS, 4}, + {MAX_SECURE_SESSION_COUNT, 3}, + {MAX_RT_MBPF, 130560}, /* (4 * ((3840*2176)/256)) */ + {MAX_MBPF, 139264}, /* (4 * ((4096*2176)/256)) */ + /* max_load 3840x2176@120fps*/ + /* Concurrency: UHD@30 decode + UHD@30 encode */ + {MAX_MBPS, 3916800}, + {MAX_IMAGE_MBPF, 1048576}, /* (16384x16384)/256 */ + {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */ + {MAX_MBPS_HQ, 244800}, /* ((1920x1088)/256)@30fps */ + {MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */ + {MAX_MBPS_B_FRAME, 979200}, /* 3840x2176/256 MBs@30fps */ + {MAX_MBPS_ALL_INTRA, 489600}, /* ((1920x1088)/256)@60fps */ + {MAX_ENH_LAYER_COUNT, 5}, + {NUM_VPP_PIPE, 2}, + {SW_PC, 1}, + {FW_UNLOAD, 0}, + {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */ + {SW_PC_DELAY, SW_PC_DELAY_VALUE }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/ + {FW_UNLOAD_DELAY, FW_UNLOAD_DELAY_VALUE }, /* 3000 ms (>SW_PC_DELAY)*/ + {PAGEFAULT_NON_FATAL, 1}, + {PAGETABLE_CACHING, 0}, + {DCVS, 1}, + {DECODE_BATCH, 1}, + {DECODE_BATCH_TIMEOUT, 200}, + {STATS_TIMEOUT_MS, 2000}, + {AV_SYNC_WINDOW_SIZE, 40}, + {NON_FATAL_FAULTS, 1}, + {ENC_AUTO_FRAMERATE, 0}, + {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_META_CAPTURE | + V4L2_CAP_STREAMING}, + {SUPPORTS_SYNX_FENCE, 1}, + {SUPPORTS_REQUESTS, 0}, +}; + +static struct msm_platform_inst_capability instance_cap_data_volcano_v0[] = { + /* {cap, domain, codec, + * min, max, step_or_mask, value, + * v4l2_id, + * hfi_id, + * flags} + */ + + {FRAME_WIDTH, DEC, CODECS_ALL, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_WIDTH, ENC, H264|HEVC, 128, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, DEC, CODECS_ALL, 96, 4096, 1, 1920}, + + {SECURE_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {FRAME_HEIGHT, DEC, CODECS_ALL, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEIC, 128, 16384, 1, 16384}, + + {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, DEC, CODECS_ALL, 96, 4096, 1, 1080}, + + {SECURE_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {PIX_FMTS, ENC | DEC, H264, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC | DEC, HEVC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_P010, + MSM_VIDC_FMT_NV12}, + + {PIX_FMTS, DEC, HEIC, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, DEC, VP9, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_P010 | MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_INPUT, ENC | DEC, HEIC, 0, 64, 1, 1, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL, + 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE}, + + /* (4096 * 2176) / 256 */ + {MBPF, ENC, CODECS_ALL, 64, 34816, 1, 34816}, + + /* ((16384x16384)/256) */ + {MBPF, ENC, HEIC, 64, 1048576, 1, 1048576}, + + /* (4 * ((4096 * 2176)/256) */ + {MBPF, DEC, CODECS_ALL, 36, 139264, 1, 139264}, + + /* (4096 * 2176) / 256 */ + {MBPF, DEC, VP9, 36, 34816, 1, 34816}, + + /* ((8192x8192)/256) */ + {MBPF, DEC, HEIC, 64, 262144, 1, 262144 }, + + /* (4096 * 2176) / 256 */ + {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 34816, 1, 34816}, + + /* Batch Mode Decode */ + /* BATCH_MBPF + 2 is done for chipsets other than lanai + * due to timeline constraints since msm_vidc_allow_decode_batch + * has checks to allow batching for less than BATCH_MBPF. + * Same applies for BATCH_FPS. + */ + /* (1920 * 1088) / 256 */ + {BATCH_MBPF, DEC, H264 | HEVC | VP9, 64, 8162, 1, 8162}, + + {BATCH_FPS, DEC, H264 | HEVC | VP9, 1, 61, 1, 61}, + + /* (4096 * 2176) / 256 */ + {SECURE_MBPF, ENC | DEC, H264 | HEVC | VP9, 64, 34816, 1, 34816}, + + {FRAME_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {OPERATING_RATE, ENC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16)}, + + {INPUT_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8}, + + {MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60}, + + {MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675}, + + {MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320}, + + {MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 326389, 326389, 1, 326389}, + + {MB_CYCLES_FW_VPP, ENC | DEC, CODECS_ALL, 44156, 44156, 1, 44156}, + + {ENC_RING_BUFFER_COUNT, ENC, CODECS_ALL, + 0, 0, 1, 0}, + + {CLIENT_ID, ENC | DEC, CODECS_ALL, + INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, + 0}, + + {HFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_HFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {VFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_VFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ROTATION, ENC, CODECS_ALL, + 0, 270, 90, 0, + V4L2_CID_ROTATE, + HFI_PROP_ROTATION, + CAP_FLAG_OUTPUT_PORT}, + + {SUPER_FRAME, ENC, H264 | HEVC, + 0, 32, 1, 0, + 0, 0, + CAP_FLAG_NONE}, + + {SLICE_DECODE, DEC, CODECS_ALL, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_DECODER_SLICE_INTERFACE, + 0}, + + {HEADER_MODE, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + HFI_PROP_SEQ_HEADER_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_OUTPUT_PORT}, + + {NAL_LENGTH_FIELD, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_MPEG_VIDEO_HEVC_SIZE_4, + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) | + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4), + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* TODO: Firmware introduced enumeration type for this + * with and without seq header. + */ + {REQUEST_I_FRAME, ENC, H264 | HEVC, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + HFI_PROP_REQUEST_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* Enc: Keeping CABAC and CAVLC as same bitrate. + * Dec: there's no use of Bitrate cap + */ + {BIT_RATE, ENC, H264 | HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE, + HFI_PROP_TOTAL_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITRATE_MODE, ENC, H264, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {CAVLC_MAX_BITRATE, ENC, H264, 0, + 160000000, 1, 160000000}, + + {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {LOWLATENCY_MAX_BITRATE, ENC, H264 | HEVC, 0, + 70000000, 1, 70000000}, + + {LOSSLESS, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU}, + + {FRAME_SKIP_MODE, ENC, H264 | HEVC | HEIC, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {FRAME_RC_ENABLE, ENC, H264 | HEVC | HEIC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE}, + + {CONSTANT_QUALITY, ENC, HEVC, + 1, MAX_CONSTANT_QUALITY, 1, 90, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, CODECS_ALL, + 0, INT_MAX, 1, 2 * DEFAULT_FPS - 1, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_CLOSURE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + 0}, + + {B_FRAME, ENC, H264 | HEVC, + 0, 7, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {BLUR_TYPES, ENC, H264 | HEVC, + MSM_VIDC_BLUR_NONE, MSM_VIDC_BLUR_EXTERNAL, + BIT(MSM_VIDC_BLUR_NONE) | BIT(MSM_VIDC_BLUR_EXTERNAL), + MSM_VIDC_BLUR_NONE, + 0, + HFI_PROP_BLUR_TYPES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CSC, ENC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_CSC, + CAP_FLAG_OUTPUT_PORT}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_NONE}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {LTR_COUNT, ENC, H264 | HEVC, + 0, MAX_LTR_FRAME_COUNT, 1, 0, + V4L2_CID_MPEG_VIDEO_LTR_COUNT, + HFI_PROP_LTR_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {USE_LTR, ENC, H264 | HEVC, + 0, + ((1 << MAX_LTR_FRAME_COUNT) - 1), + 0, 0, + V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, + HFI_PROP_LTR_USE, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {MARK_LTR, ENC, H264 | HEVC, + INVALID_DEFAULT_MARK_OR_USE_LTR, + (MAX_LTR_FRAME_COUNT - 1), + 1, INVALID_DEFAULT_MARK_OR_USE_LTR, + V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, + HFI_PROP_LTR_MARK, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {BASELAYER_PRIORITY, ENC, H264, + 0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0, + V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, + HFI_PROP_BASELAYER_PRIORITYID, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {AU_DELIMITER, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + HFI_PROP_AUD, + CAP_FLAG_OUTPUT_PORT}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + 0, 1, 1, 1, + 0, + HFI_PROP_CONTENT_ADAPTIVE_CODING, + CAP_FLAG_OUTPUT_PORT}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + MSM_VIDC_PREPROCESS_NONE, + MSM_VIDC_PREPROCESS_TYPE0, + BIT(MSM_VIDC_PREPROCESS_NONE) | + BIT(MSM_VIDC_PREPROCESS_TYPE0), + MSM_VIDC_PREPROCESS_NONE, + 0, HFI_PROP_REQUEST_PREPROCESS, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {MIN_QUALITY, ENC, H264 | HEVC, + 0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY, + 0, + HFI_PROP_MAINTAIN_MIN_QUALITY, + CAP_FLAG_OUTPUT_PORT}, + + {VBV_DELAY, ENC, H264 | HEVC, + 200, 300, 100, 300, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, + HFI_PROP_VBV_DELAY, + CAP_FLAG_OUTPUT_PORT}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + /* default peak bitrate is 10% larger than avg bitrate */ + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + HFI_PROP_TOTAL_PEAK_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {MIN_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP}, + + {I_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP}, + + {MAX_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MAX_FRAME_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP}, + + {I_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, HEVC | HEIC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP}, + + {I_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {I_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {LAYER_TYPE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_TYPE, ENC, H264, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_ENABLE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT}, + + {LAYER_ENABLE, ENC, HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {ENH_LAYER_COUNT, ENC, HEVC, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, ENC, H264, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L0_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L3_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L3_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENTROPY_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + HFI_PROP_CABAC_SESSION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {ENTROPY_MODE, DEC, H264 | HEVC | VP9, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + 0, + HFI_PROP_CABAC_SESSION}, + + {PROFILE, ENC | DEC, H264, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, ENC | DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE, + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_MPEG_VIDEO_VP9_PROFILE_2, + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, HEVC | HEIC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6), + V4L2_MPEG_VIDEO_HEVC_LEVEL_6, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + V4L2_MPEG_VIDEO_VP9_LEVEL_5_2, + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2), + V4L2_MPEG_VIDEO_VP9_LEVEL_5_2, + V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + {HEVC_TIER, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + DB_H264_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + BIT(DB_H264_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + DB_HEVC_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) | + BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_ALPHA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA}, + + {LF_ALPHA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2}, + + {LF_BETA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA}, + + {LF_BETA, ENC, HEVC | HEIC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2}, + + {SLICE_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MAX_BYTES, ENC, H264 | HEVC, + MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE, + 1, MIN_SLICE_BYTE_SIZE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + HFI_PROP_MULTI_SLICE_BYTES_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {SLICE_MAX_MB, ENC, H264 | HEVC, + 1, MAX_SLICE_MB_SIZE, 1, 1, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + HFI_PROP_MULTI_SLICE_MB_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {MB_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {TRANSFORM_8X8, ENC, H264, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + HFI_PROP_8X8_TRANSFORM, + CAP_FLAG_OUTPUT_PORT}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET, + 1, MAX_CHROMA_QP_OFFSET, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + HFI_PROP_CHROMA_QP_OFFSET, + CAP_FLAG_OUTPUT_PORT}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_8BIT, + CAP_FLAG_INPUT_PORT}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_10BIT, + CAP_FLAG_INPUT_PORT}, + + {STAGE, DEC|ENC, CODECS_ALL, + MSM_VIDC_STAGE_1, + MSM_VIDC_STAGE_2, 1, + MSM_VIDC_STAGE_2, + 0, + HFI_PROP_STAGE}, + + {PIPE, DEC|ENC, CODECS_ALL, + MSM_VIDC_PIPE_1, + MSM_VIDC_PIPE_2, 1, + MSM_VIDC_PIPE_2, + 0, + HFI_PROP_PIPE}, + + {POC, DEC, H264, 0, 2, 1, 1, + 0, + HFI_PROP_PIC_ORDER_CNT_TYPE}, + + {QUALITY_MODE, ENC, CODECS_ALL, + MSM_VIDC_MAX_QUALITY_MODE, + MSM_VIDC_POWER_SAVE_MODE, 1, + MSM_VIDC_POWER_SAVE_MODE}, + + {CODED_FRAMES, DEC, H264 | HEVC, + CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE, + 1, CODED_FRAMES_PROGRESSIVE, + 0, + HFI_PROP_CODED_FRAMES}, + + {BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8, + 0, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH}, + + {CODEC_CONFIG, DEC, H264 | HEVC, 0, 1, 1, 0, + 0, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0, + 0}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_THUMBNAIL_MODE, + CAP_FLAG_INPUT_PORT}, + + {DEFAULT_HEADER, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_DEC_DEFAULT_HEADER}, + + {RAP_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_DEC_START_FROM_RAP_FRAME, + CAP_FLAG_INPUT_PORT}, + + {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + 1, 1, 1, 1}, + + {ALL_INTRA, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {COMPLEXITY, ENC, H264 | HEVC, + 0, 100, + 1, DEFAULT_COMPLEXITY, + 0}, +}; + +static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_volcano_v0[] = { + /* {cap, domain, codec, + * parents, + * children, + * adjust, set} + */ + + {PIX_FMTS, ENC, HEVC, + {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, MIN_QUALITY, BLUR_TYPES, LTR_COUNT}}, + + {PIX_FMTS, DEC, HEVC, + {PROFILE}}, + + {FRAME_RATE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_q16}, + + {HFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {VFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {ROTATION, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_rotation}, + + {SUPER_FRAME, ENC, H264 | HEVC, + {INPUT_BUF_HOST_MAX_COUNT, OUTPUT_BUF_HOST_MAX_COUNT}, + NULL, + NULL}, + + {HEADER_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_header_mode}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_nal_length}, + + {REQUEST_I_FRAME, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_req_sync_frame}, + + {BIT_RATE, ENC, H264, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BIT_RATE, ENC, HEVC, + {PEAK_BITRATE, BITRATE_BOOST, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BITRATE_MODE, ENC, H264, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE, + META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE, META_TRANSCODING_STAT_INFO}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEVC, + {LTR_COUNT, IR_PERIOD, TIME_DELTA_BASED_RC, I_FRAME_QP, + P_FRAME_QP, B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT, + BIT_RATE, META_ROI_INFO, MIN_QUALITY, BITRATE_BOOST, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {CONSTANT_QUALITY, ENC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_constant_quality}, + + {GOP_SIZE, ENC, CODECS_ALL, + {ALL_INTRA}, + msm_vidc_adjust_gop_size, + msm_vidc_set_gop_size}, + + {B_FRAME, ENC, H264 | HEVC, + {ALL_INTRA}, + msm_vidc_adjust_b_frame, + msm_vidc_set_u32}, + + {B_FRAME, ENC, HEIC, + {0}, + msm_vidc_adjust_blur_type, + msm_vidc_set_u32_enum}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + {STAGE, BIT_RATE}, + msm_vidc_adjust_enc_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LTR_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ltr_count, + msm_vidc_set_u32}, + + {USE_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_use_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {MARK_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_mark_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {AU_DELIMITER, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_u32}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + {REQUEST_PREPROCESS}, + msm_vidc_adjust_brs, + msm_vidc_set_vbr_related_properties}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_preprocess, + msm_vidc_set_preprocess}, + + {MIN_QUALITY, ENC, H264, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {MIN_QUALITY, ENC, H264 | HEVC, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {VBV_DELAY, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_cbr_related_properties}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_peak_bitrate, + msm_vidc_set_cbr_related_properties}, + + {MIN_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_min_qp}, + + {MIN_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_min_qp, + msm_vidc_set_min_qp}, + + {MAX_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_max_qp}, + + {MAX_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_max_qp, + msm_vidc_set_max_qp}, + + {I_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_i_frame_qp, + msm_vidc_set_frame_qp}, + + {I_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_p_frame_qp, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_b_frame_qp, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {LAYER_TYPE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING, LTR_COUNT}}, + + {LAYER_ENABLE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING}}, + + {ENH_LAYER_COUNT, ENC, H264 | HEVC, + {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE, LTR_COUNT}, + msm_vidc_adjust_layer_count, + msm_vidc_set_layer_count_and_type}, + + {L0_BR, ENC, H264 | HEVC, + {L1_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L1_BR, ENC, H264 | HEVC, + {L2_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L2_BR, ENC, H264 | HEVC, + {L3_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L3_BR, ENC, H264 | HEVC, + {L4_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L4_BR, ENC, H264 | HEVC, + {L5_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L5_BR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {ENTROPY_MODE, ENC, H264, + {BIT_RATE}, + msm_vidc_adjust_entropy_mode, + msm_vidc_set_u32}, + + {PROFILE, ENC, H264, + {ENTROPY_MODE, TRANSFORM_8X8}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, H264, + {ENTROPY_MODE}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, ENC | DEC, HEVC, + {0}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, VP9, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_level}, + + {HEVC_TIER, ENC | DEC, HEVC | HEIC, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LF_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_deblock_mode}, + + {SLICE_MODE, ENC, H264 | HEVC, + {STAGE, DELIVERY_MODE}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {TRANSFORM_8X8, ENC, H264, + {0}, + msm_vidc_adjust_transform_8x8, + msm_vidc_set_u32}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + {0}, + msm_vidc_adjust_chroma_qp_index_offset, + msm_vidc_set_chroma_qp_index_offset}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_output_order, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {STAGE, ENC | DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_stage}, + + {PIPE, DEC|ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_pipe}, + + {THUMBNAIL_MODE, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + msm_vidc_set_u32}, + + {RAP_FRAME, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + {0}, + NULL, + NULL}, + + {ALL_INTRA, ENC, H264 | HEVC, + {LTR_COUNT, IR_PERIOD, SLICE_MODE, BIT_RATE}, + msm_vidc_adjust_all_intra, + NULL}, +}; + +/* Default UBWC config for LPDDR5 */ +static struct msm_vidc_ubwc_config_data ubwc_config_volcano[] = { + UBWC_CONFIG(8, 32, 15, 0, 1, 1, 1), +}; + +static struct msm_vidc_format_capability format_data_volcano = { + .codec_info = codec_data_volcano, + .codec_info_size = ARRAY_SIZE(codec_data_volcano), + .color_format_info = color_format_data_volcano, + .color_format_info_size = ARRAY_SIZE(color_format_data_volcano), + .color_prim_info = color_primaries_data_volcano, + .color_prim_info_size = ARRAY_SIZE(color_primaries_data_volcano), + .transfer_char_info = transfer_char_data_volcano, + .transfer_char_info_size = ARRAY_SIZE(transfer_char_data_volcano), + .matrix_coeff_info = matrix_coeff_data_volcano, + .matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_volcano), +}; +static const struct msm_vidc_platform_data volcano_data_v0 = { + /* caps related resorces */ + .core_data = core_data_volcano_v0, + .core_data_size = ARRAY_SIZE(core_data_volcano_v0), + .inst_cap_data = instance_cap_data_volcano_v0, + .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_volcano_v0), + .inst_cap_dependency_data = instance_cap_dependency_data_volcano_v0, + .inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_volcano_v0), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .ubwc_config = ubwc_config_volcano, + .format_data = &format_data_volcano, +}; + +int msm_vidc_volcano_check_ddr_type( + struct msm_vidc_platform_data *platform_data, u32 hbb_override_val) +{ + u32 ddr_type; + + ddr_type = of_fdt_get_ddrtype(); + if (ddr_type != DDR_TYPE_LPDDR5 && + ddr_type != DDR_TYPE_LPDDR5X) { + d_vpr_e("%s: wrong ddr type %d\n", __func__, ddr_type); + return -EINVAL; + } + + d_vpr_h("%s: ddr type %d\n", __func__, ddr_type); + return 0; +} + +static int msm_vidc_init_data(struct msm_vidc_core *core) +{ + int rc = 0; + + d_vpr_h("%s: initialize volcano", __func__); + + core->platform->data = volcano_data_v0; + + rc = msm_vidc_volcano_check_ddr_type(&core->platform->data, 0xe); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_init_platform_volcano(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = msm_vidc_init_data(core); + if (rc) + return rc; + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/platform/waipio/inc/msm_vidc_waipio.h b/qcom/opensource/video-driver/driver/platform/waipio/inc/msm_vidc_waipio.h new file mode 100644 index 0000000000..7342891c4c --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/waipio/inc/msm_vidc_waipio.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_WAIPIO_H_ +#define _MSM_VIDC_WAIPIO_H_ + +#include "msm_vidc_core.h" +#include "msm_vidc_iris2.h" + +#if defined(CONFIG_MSM_VIDC_WAIPIO) +struct context_bank_info *msm_vidc_context_bank(struct msm_vidc_core *core, + enum msm_vidc_buffer_region region); +int msm_vidc_init_platform_waipio(struct msm_vidc_core *core); +#else +struct context_bank_info *msm_vidc_context_bank(struct msm_vidc_core *core, + enum msm_vidc_buffer_region region) +{ + return NULL; +} + +int msm_vidc_init_platform_waipio(struct msm_vidc_core *core) +{ + return -EINVAL; +} +#endif + +#endif // _MSM_VIDC_WAIPIO_H_ diff --git a/qcom/opensource/video-driver/driver/platform/waipio/src/waipio.c b/qcom/opensource/video-driver/driver/platform/waipio/src/waipio.c new file mode 100644 index 0000000000..44690f9410 --- /dev/null +++ b/qcom/opensource/video-driver/driver/platform/waipio/src/waipio.c @@ -0,0 +1,1841 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include + +#include "msm_vidc_control.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_waipio.h" +#include "msm_vidc_debug.h" +#include "hfi_property.h" +#include "hfi_command.h" + +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8020010 +#define MAX_LTR_FRAME_COUNT 2 +#define MAX_BASE_LAYER_PRIORITY_ID 63 +#define MAX_OP_POINT 31 +#define MAX_BITRATE 220000000 +#define DEFAULT_BITRATE 20000000 +#define MINIMUM_FPS 1 +#define MAXIMUM_FPS 480 +#define MAXIMUM_DEC_FPS 960 +#define MAX_QP 51 +#define DEFAULT_QP 20 +#define MAX_CONSTANT_QUALITY 100 +#define MIN_SLICE_BYTE_SIZE 512 +#define MAX_SLICE_BYTE_SIZE \ + ((MAX_BITRATE) >> 3) +#define MAX_SLICE_MB_SIZE \ + (((4096 + 15) >> 4) * ((2304 + 15) >> 4)) + +#define ENC MSM_VIDC_ENCODER +#define DEC MSM_VIDC_DECODER +#define H264 MSM_VIDC_H264 +#define HEVC MSM_VIDC_HEVC +#define VP9 MSM_VIDC_VP9 +#define CODECS_ALL (H264 | HEVC | VP9) +#define MAXIMUM_OVERRIDE_VP9_FPS 200 + +#ifndef V4L2_PIX_FMT_QC08C +#define V4L2_PIX_FMT_QC08C v4l2_fourcc('Q', '0', '8', 'C') +#endif + +#ifndef V4L2_PIX_FMT_QC10C +#define V4L2_PIX_FMT_QC10C v4l2_fourcc('Q', '1', '0', 'C') +#endif + +static struct codec_info codec_data_waipio[] = { + { + .v4l2_codec = V4L2_PIX_FMT_H264, + .vidc_codec = MSM_VIDC_H264, + .pixfmt_name = "AVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_HEVC, + .vidc_codec = MSM_VIDC_HEVC, + .pixfmt_name = "HEVC", + }, + { + .v4l2_codec = V4L2_PIX_FMT_VP9, + .vidc_codec = MSM_VIDC_VP9, + .pixfmt_name = "VP9", + }, +}; + +static struct color_format_info color_format_data_waipio[] = { + { + .v4l2_color_format = V4L2_PIX_FMT_NV12, + .vidc_color_format = MSM_VIDC_FMT_NV12, + .pixfmt_name = "NV12", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_NV21, + .vidc_color_format = MSM_VIDC_FMT_NV21, + .pixfmt_name = "NV21", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC08C, + .vidc_color_format = MSM_VIDC_FMT_NV12C, + .pixfmt_name = "NV12C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_QC10C, + .vidc_color_format = MSM_VIDC_FMT_TP10C, + .pixfmt_name = "TP10C", + }, + { + .v4l2_color_format = V4L2_PIX_FMT_RGBA32, + .vidc_color_format = MSM_VIDC_FMT_RGBA8888, + .pixfmt_name = "RGBA", + }, +}; + +static struct color_primaries_info color_primaries_data_waipio[] = { + { + .v4l2_color_primaries = V4L2_COLORSPACE_DEFAULT, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_RESERVED, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_REC709, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT709, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_470_SYSTEM_BG, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE170M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT601_525, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_SMPTE240M, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_ST240M, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_BT2020, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_BT2020, + }, + { + .v4l2_color_primaries = V4L2_COLORSPACE_DCI_P3, + .vidc_color_primaries = MSM_VIDC_PRIMARIES_SMPTE_RP431_2, + }, +}; + +static struct transfer_char_info transfer_char_data_waipio[] = { + { + .v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT, + .vidc_transfer_char = MSM_VIDC_TRANSFER_RESERVED, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_709, + .vidc_transfer_char = MSM_VIDC_TRANSFER_BT709, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE240M, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST240M, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SRGB, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SRGB_SYCC, + }, + { + .v4l2_transfer_char = V4L2_XFER_FUNC_SMPTE2084, + .vidc_transfer_char = MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ, + }, +}; + +static struct matrix_coeff_info matrix_coeff_data_waipio[] = { + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV709, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_XV601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_601, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_SMPTE240M, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_SMPTE_ST240, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT, + }, + { + .v4l2_matrix_coeff = V4L2_YCBCR_ENC_BT2020_CONST_LUM, + .vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT, + }, +}; + +static struct msm_platform_core_capability core_data_waipio[] = { + /* {type, value} */ + {ENC_CODECS, H264 | HEVC}, + {DEC_CODECS, H264 | HEVC | VP9}, + {MAX_SESSION_COUNT, 16}, + {MAX_NUM_720P_SESSIONS, 16}, + {MAX_NUM_1080P_SESSIONS, 16}, + {MAX_NUM_4K_SESSIONS, 8}, + {MAX_NUM_8K_SESSIONS, 2}, + {MAX_RT_MBPF, 174080}, /* (8192x4352)/256 + (4096x2176)/256*/ + {MAX_MBPF, 278528}, /* ((8192x4352)/256) * 2 */ + {MAX_MBPS, 7833600}, /* max_load + * 7680x4320@60fps or 3840x2176@240fps + * which is greater than 4096x2176@120fps, + * 8192x4320@48fps + */ + {MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */ + {MAX_MBPS_HQ, 489600}, /* ((1920x1088)/256)@60fps */ + {MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */ + {MAX_MBPS_B_FRAME, 1958400}, /* 3840x2176/256 MBs@60fps */ + {MAX_MBPS_ALL_INTRA, 1044480}, /* 4096x2176/256 MBs@30fps */ + {MAX_ENH_LAYER_COUNT, 5}, + {NUM_VPP_PIPE, 4}, + {SW_PC, 1}, + {FW_UNLOAD, 0}, + {HW_RESPONSE_TIMEOUT, HW_RESPONSE_TIMEOUT_VALUE}, /* 1000 ms */ + {SW_PC_DELAY, SW_PC_DELAY_VALUE }, /* 1500 ms (>HW_RESPONSE_TIMEOUT)*/ + {FW_UNLOAD_DELAY, FW_UNLOAD_DELAY_VALUE }, /* 3000 ms (>SW_PC_DELAY)*/ + {DCVS, 1}, + {DECODE_BATCH, 1}, + {DECODE_BATCH_TIMEOUT, 200}, + {STATS_TIMEOUT_MS, 2000}, + {NON_FATAL_FAULTS, 1}, + {ENC_AUTO_FRAMERATE, 1}, + {DEVICE_CAPS, V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING}, + {SUPPORTS_SYNX_FENCE, 0}, + {SUPPORTS_REQUESTS, 0}, +}; + +static struct msm_platform_inst_capability instance_cap_data_waipio[] = { + /* {cap, domain, codec, + * min, max, step_or_mask, value, + * v4l2_id, + * hfi_id, + * flags} + */ + + {FRAME_WIDTH, DEC, CODECS_ALL, 96, 8192, 1, 1920}, + + {FRAME_WIDTH, DEC, VP9, 96, 4096, 1, 1920}, + + {FRAME_WIDTH, ENC, CODECS_ALL, 128, 8192, 1, 1920}, + + {FRAME_WIDTH, ENC, HEVC, 96, 8192, 1, 1920}, + + {LOSSLESS_FRAME_WIDTH, ENC, CODECS_ALL, 128, 4096, 1, 1920}, + + {LOSSLESS_FRAME_WIDTH, ENC, HEVC, 96, 4096, 1, 1920}, + + {FRAME_HEIGHT, DEC, CODECS_ALL, 96, 8192, 1, 1080}, + + {FRAME_HEIGHT, DEC, VP9, 96, 4096, 1, 1080}, + + {FRAME_HEIGHT, ENC, CODECS_ALL, 128, 8192, 1, 1080}, + + {FRAME_HEIGHT, ENC, HEVC, 96, 8192, 1, 1080}, + + {LOSSLESS_FRAME_HEIGHT, ENC, CODECS_ALL, 128, 4096, 1, 1080}, + + {LOSSLESS_FRAME_HEIGHT, ENC, HEVC, 96, 4096, 1, 1080}, + + {PIX_FMTS, ENC | DEC, H264, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C, + MSM_VIDC_FMT_NV12C}, + + {PIX_FMTS, ENC | DEC, HEVC | VP9, + MSM_VIDC_FMT_NV12, + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12 | MSM_VIDC_FMT_NV21 | MSM_VIDC_FMT_NV12C | + MSM_VIDC_FMT_TP10C, + MSM_VIDC_FMT_NV12C}, + + {MIN_BUFFERS_INPUT, ENC | DEC, CODECS_ALL, 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 0, + CAP_FLAG_VOLATILE}, + + + {MIN_BUFFERS_OUTPUT, ENC | DEC, CODECS_ALL, + 0, 64, 1, 4, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_VOLATILE}, + + /* (8192 * 4320) / 256 */ + {MBPF, ENC, CODECS_ALL, 64, 138240, 1, 138240}, + + {MBPF, ENC, HEVC, 36, 138240, 1, 138240}, + + {MBPF, DEC, CODECS_ALL, 36, 138240, 1, 138240}, + + /* (4096 * 2304) / 256 */ + {MBPF, DEC, VP9, 36, 36864, 1, 36864}, + + /* (4096 * 2304) / 256 */ + {LOSSLESS_MBPF, ENC, H264 | HEVC, 64, 36864, 1, 36864}, + + /* Batch Mode Decode */ + /* TODO: update with new values based on updated voltage corner */ + {BATCH_MBPF, DEC, H264 | HEVC | VP9, 64, 34816, 1, 34816}, + + /* (4096 * 2304) / 256 */ + {BATCH_FPS, DEC, H264 | HEVC | VP9, 1, 120, 1, 120}, + + {FRAME_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16), + 0, + HFI_PROP_FRAME_RATE, + CAP_FLAG_OUTPUT_PORT}, + + {OPERATING_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), (MAXIMUM_FPS << 16), + 1, (DEFAULT_FPS << 16)}, + + {INPUT_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {TIMESTAMP_RATE, ENC | DEC, CODECS_ALL, + (MINIMUM_FPS << 16), INT_MAX, + 1, (DEFAULT_FPS << 16)}, + + {SCALE_FACTOR, ENC, H264 | HEVC, 1, 8, 1, 8}, + + {MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25}, + + {MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60}, + + {MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675}, + + {MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320}, + + {MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200}, + + {MB_CYCLES_FW, ENC | DEC, CODECS_ALL, 326389, 326389, 1, 326389}, + + {MB_CYCLES_FW_VPP, ENC | DEC, CODECS_ALL, 44156, 44156, 1, 44156}, + + {MB_CYCLES_FW_VPP, DEC, CODECS_ALL, 66234, 66234, 1, 66234}, + + {CLIENT_ID, ENC | DEC, CODECS_ALL, + INVALID_CLIENT_ID, INT_MAX, 1, INVALID_CLIENT_ID, + 0}, + + {HFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_HFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {VFLIP, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_VFLIP, + HFI_PROP_FLIP, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ROTATION, ENC, CODECS_ALL, + 0, 270, 90, 0, + V4L2_CID_ROTATE, + HFI_PROP_ROTATION, + CAP_FLAG_OUTPUT_PORT}, + + {SUPER_FRAME, ENC, H264 | HEVC, + 0, 32, 1, 0, + 0, 0, + CAP_FLAG_NONE}, + + {HEADER_MODE, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME, + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + BIT(V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), + V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + V4L2_CID_MPEG_VIDEO_HEADER_MODE, + HFI_PROP_SEQ_HEADER_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PREPEND_SPSPPS_TO_IDR, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_WITHOUT_STARTCODE, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_OUTPUT_PORT}, + + {NAL_LENGTH_FIELD, ENC, CODECS_ALL, + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_MPEG_VIDEO_HEVC_SIZE_4, + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_0) | + BIT(V4L2_MPEG_VIDEO_HEVC_SIZE_4), + V4L2_MPEG_VIDEO_HEVC_SIZE_0, + V4L2_CID_MPEG_VIDEO_HEVC_SIZE_OF_LENGTH_FIELD, + HFI_PROP_NAL_LENGTH_FIELD, + CAP_FLAG_MENU | CAP_FLAG_OUTPUT_PORT}, + + /* TODO: Firmware introduced enumeration type for this + * with and without seq header. + */ + {REQUEST_I_FRAME, ENC, H264 | HEVC, + 0, 0, 0, 0, + V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, + HFI_PROP_REQUEST_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + /* Enc: Keeping CABAC and CAVLC as same bitrate. + * Dec: there's no use of Bitrate cap + */ + {BIT_RATE, ENC, H264 | HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE, + HFI_PROP_TOTAL_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITRATE_MODE, ENC, H264, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {BITRATE_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_MPEG_VIDEO_BITRATE_MODE_CQ, + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) | + BIT(V4L2_MPEG_VIDEO_BITRATE_MODE_CQ), + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + HFI_PROP_RATE_CONTROL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CABAC_MAX_BITRATE, ENC, H264 | HEVC, 0, + 160000000, 1, 160000000}, + + {CAVLC_MAX_BITRATE, ENC, H264, 0, + 220000000, 1, 220000000}, + + {ALLINTRA_MAX_BITRATE, ENC, H264 | HEVC, 0, + 245000000, 1, 245000000}, + + {LOWLATENCY_MAX_BITRATE, ENC, H264 | HEVC, 0, + 70000000, 1, 70000000}, + + {NUM_COMV, DEC, CODECS_ALL, + 0, INT_MAX, 1, 0}, + + {LOSSLESS, ENC, HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LOSSLESS_CU}, + + {FRAME_SKIP_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT, + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_LEVEL_LIMIT) | + BIT(V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT), + V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED, + V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {FRAME_RC_ENABLE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE}, + + {CONSTANT_QUALITY, ENC, HEVC, + 1, MAX_CONSTANT_QUALITY, 1, 90, + V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, + HFI_PROP_CONSTANT_QUALITY, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_SIZE, ENC, CODECS_ALL, + 0, INT_MAX, 1, 2 * DEFAULT_FPS - 1, + V4L2_CID_MPEG_VIDEO_GOP_SIZE, + HFI_PROP_MAX_GOP_FRAMES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {GOP_CLOSURE, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, + 0}, + + {B_FRAME, ENC, H264 | HEVC, + 0, 7, 1, 0, + V4L2_CID_MPEG_VIDEO_B_FRAMES, + HFI_PROP_MAX_B_FRAMES, + CAP_FLAG_OUTPUT_PORT}, + + {BLUR_TYPES, ENC, H264 | HEVC, + MSM_VIDC_BLUR_NONE, MSM_VIDC_BLUR_EXTERNAL, + BIT(MSM_VIDC_BLUR_NONE) | BIT(MSM_VIDC_BLUR_EXTERNAL), + MSM_VIDC_BLUR_NONE, + 0, + HFI_PROP_BLUR_TYPES, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {CSC, ENC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_CSC, + CAP_FLAG_OUTPUT_PORT}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_NONE}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {LTR_COUNT, ENC, H264 | HEVC, + 0, 2, 1, 0, + V4L2_CID_MPEG_VIDEO_LTR_COUNT, + HFI_PROP_LTR_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {USE_LTR, ENC, H264 | HEVC, + 0, + ((1 << MAX_LTR_FRAME_COUNT) - 1), + 0, 0, + V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, + HFI_PROP_LTR_USE, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {MARK_LTR, ENC, H264 | HEVC, + INVALID_DEFAULT_MARK_OR_USE_LTR, + (MAX_LTR_FRAME_COUNT - 1), + 1, INVALID_DEFAULT_MARK_OR_USE_LTR, + V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, + HFI_PROP_LTR_MARK, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {BASELAYER_PRIORITY, ENC, H264, + 0, MAX_BASE_LAYER_PRIORITY_ID, 1, 0, + V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, + HFI_PROP_BASELAYER_PRIORITYID, + CAP_FLAG_OUTPUT_PORT}, + + {AU_DELIMITER, ENC, H264 | HEVC, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_AU_DELIMITER, + HFI_PROP_AUD, + CAP_FLAG_OUTPUT_PORT}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + 0, 1, 1, 1, + 0, + HFI_PROP_CONTENT_ADAPTIVE_CODING, + CAP_FLAG_OUTPUT_PORT}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + MSM_VIDC_PREPROCESS_NONE, + MSM_VIDC_PREPROCESS_TYPE0, + BIT(MSM_VIDC_PREPROCESS_NONE) | + BIT(MSM_VIDC_PREPROCESS_TYPE0), + MSM_VIDC_PREPROCESS_NONE, + 0, HFI_PROP_REQUEST_PREPROCESS, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {MIN_QUALITY, ENC, H264 | HEVC, + 0, MAX_SUPPORTED_MIN_QUALITY, 70, MAX_SUPPORTED_MIN_QUALITY, + 0, + HFI_PROP_MAINTAIN_MIN_QUALITY, + CAP_FLAG_OUTPUT_PORT}, + + {VBV_DELAY, ENC, H264 | HEVC, + 200, 300, 100, 300, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, + HFI_PROP_VBV_DELAY, + CAP_FLAG_OUTPUT_PORT}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + /* default peak bitrate is 10% larger than avg bitrate */ + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + HFI_PROP_TOTAL_PEAK_BITRATE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {MIN_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MIN_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, + HFI_PROP_MIN_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP}, + + {I_FRAME_MIN_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP}, + + {P_FRAME_MIN_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MIN_QP_8BIT, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP}, + + {B_FRAME_MIN_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MIN_QP_10BIT, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP}, + + {MAX_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {MAX_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, + HFI_PROP_MAX_QP_PACKED, + CAP_FLAG_OUTPUT_PORT}, + + {I_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP}, + + {I_FRAME_MAX_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP}, + + {P_FRAME_MAX_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP}, + + {B_FRAME_MAX_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, MAX_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP}, + + {I_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {I_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {P_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, HEVC, + MIN_QP_10BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {B_FRAME_QP, ENC, H264, + MIN_QP_8BIT, MAX_QP, 1, DEFAULT_QP, + V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + HFI_PROP_QP_PACKED, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {LAYER_TYPE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_TYPE, ENC, H264, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B, + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) | + BIT(V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P), + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LAYER_ENABLE, ENC, H264, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, + HFI_PROP_LAYER_ENCODING_TYPE, + CAP_FLAG_OUTPUT_PORT}, + + {LAYER_ENABLE, ENC, HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {ENH_LAYER_COUNT, ENC, HEVC, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENH_LAYER_COUNT, ENC, H264, + 0, 5, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, + HFI_PROP_LAYER_COUNT, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L0_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L0_BR, + HFI_PROP_BITRATE_LAYER1, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L1_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L1_BR, + HFI_PROP_BITRATE_LAYER2, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L2_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L2_BR, + HFI_PROP_BITRATE_LAYER3, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L3_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + {L3_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L3_BR, + HFI_PROP_BITRATE_LAYER4, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L4_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L4_BR, + HFI_PROP_BITRATE_LAYER5, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, H264, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {L5_BR, ENC, HEVC, + 1, MAX_BITRATE, 1, DEFAULT_BITRATE, + V4L2_CID_MPEG_VIDEO_HEVC_HIER_CODING_L5_BR, + HFI_PROP_BITRATE_LAYER6, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_INPUT_PORT | + CAP_FLAG_DYNAMIC_ALLOWED}, + + {ENTROPY_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + HFI_PROP_CABAC_SESSION, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {ENTROPY_MODE, DEC, H264 | HEVC | VP9, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + BIT(V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC), + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + 0, + HFI_PROP_CABAC_SESSION}, + + {PROFILE, ENC | DEC, H264, + V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH), + V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE, + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10) | + BIT(V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {PROFILE, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_MPEG_VIDEO_VP9_PROFILE_2, + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_0) | + BIT(V4L2_MPEG_VIDEO_VP9_PROFILE_2), + V4L2_MPEG_VIDEO_VP9_PROFILE_0, + V4L2_CID_MPEG_VIDEO_VP9_PROFILE, + HFI_PROP_PROFILE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0), + V4L2_MPEG_VIDEO_H264_LEVEL_5_0, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + V4L2_MPEG_VIDEO_HEVC_LEVEL_5, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, H264, + V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + V4L2_MPEG_VIDEO_H264_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_6_2), + V4L2_MPEG_VIDEO_H264_LEVEL_6_1, + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_LEVEL_1, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1) | + BIT(V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2), + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LEVEL, DEC, VP9, + V4L2_MPEG_VIDEO_VP9_LEVEL_1_0, + V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_4_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_0) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_1) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_5_2) | + BIT(V4L2_MPEG_VIDEO_VP9_LEVEL_6_0), + V4L2_MPEG_VIDEO_VP9_LEVEL_6_0, + V4L2_CID_MPEG_VIDEO_VP9_LEVEL, + HFI_PROP_LEVEL, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {HEVC_TIER, ENC | DEC, HEVC, + V4L2_MPEG_VIDEO_HEVC_TIER_MAIN, + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_MAIN) | + BIT(V4L2_MPEG_VIDEO_HEVC_TIER_HIGH), + V4L2_MPEG_VIDEO_HEVC_TIER_HIGH, + V4L2_CID_MPEG_VIDEO_HEVC_TIER, + HFI_PROP_TIER, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, H264, + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + DB_H264_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + BIT(V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + BIT(DB_H264_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_MODE, ENC, HEVC, + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED, + DB_HEVC_DISABLE_SLICE_BOUNDARY, + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED) | + BIT(V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED) | + BIT(DB_HEVC_DISABLE_SLICE_BOUNDARY), + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_ENABLED, + V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE, + HFI_PROP_DEBLOCKING_MODE, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {LF_ALPHA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA}, + + {LF_ALPHA, ENC, HEVC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_TC_OFFSET_DIV2}, + + {LF_BETA, ENC, H264, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA}, + + {LF_BETA, ENC, HEVC, + -6, 6, 1, 0, + V4L2_CID_MPEG_VIDEO_HEVC_LF_BETA_OFFSET_DIV2}, + + {SLICE_MODE, ENC, H264 | HEVC, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) | + BIT(V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES), + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + 0, + CAP_FLAG_OUTPUT_PORT | CAP_FLAG_MENU}, + + {SLICE_MAX_BYTES, ENC, H264 | HEVC, + MIN_SLICE_BYTE_SIZE, MAX_SLICE_BYTE_SIZE, + 1, MIN_SLICE_BYTE_SIZE, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + HFI_PROP_MULTI_SLICE_BYTES_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {SLICE_MAX_MB, ENC, H264 | HEVC, + 1, MAX_SLICE_MB_SIZE, 1, 1, + V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + HFI_PROP_MULTI_SLICE_MB_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {MB_RC, ENC, H264 | HEVC, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {TRANSFORM_8X8, ENC, H264, + 0, 1, 1, 1, + V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + HFI_PROP_8X8_TRANSFORM, + CAP_FLAG_OUTPUT_PORT}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + MIN_CHROMA_QP_OFFSET, MAX_CHROMA_QP_OFFSET, + 1, MAX_CHROMA_QP_OFFSET, + V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, + HFI_PROP_CHROMA_QP_OFFSET, + CAP_FLAG_OUTPUT_PORT}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + 0, 1, 1, 0, + 0, + HFI_PROP_DECODE_ORDER_OUTPUT, + CAP_FLAG_INPUT_PORT}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_INPUT_PORT}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + DEFAULT_MAX_HOST_BUF_COUNT, DEFAULT_MAX_HOST_BURST_BUF_COUNT, + 1, DEFAULT_MAX_HOST_BUF_COUNT, + 0, + HFI_PROP_BUFFER_HOST_MAX_COUNT, + CAP_FLAG_OUTPUT_PORT}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, 0x0, 0xff3fcff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_8BIT, + CAP_FLAG_INPUT_PORT}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, 0x0, 0x3fffffff, 1, + DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + V4L2_CID_MPEG_VIDEO_MUTE_YUV, + HFI_PROP_CONCEAL_COLOR_10BIT, + CAP_FLAG_INPUT_PORT}, + + {STAGE, DEC | ENC, CODECS_ALL, + MSM_VIDC_STAGE_1, + MSM_VIDC_STAGE_2, 1, + MSM_VIDC_STAGE_2, + 0, + HFI_PROP_STAGE}, + + {PIPE, DEC | ENC, CODECS_ALL, + MSM_VIDC_PIPE_1, + MSM_VIDC_PIPE_4, 1, + MSM_VIDC_PIPE_4, + 0, + HFI_PROP_PIPE}, + + {POC, DEC, H264, 0, 2, 1, 1, + 0, + HFI_PROP_PIC_ORDER_CNT_TYPE}, + + {QUALITY_MODE, ENC, CODECS_ALL, + MSM_VIDC_MAX_QUALITY_MODE, + MSM_VIDC_POWER_SAVE_MODE, 1, + MSM_VIDC_POWER_SAVE_MODE}, + + {CODED_FRAMES, DEC, H264 | HEVC, + CODED_FRAMES_PROGRESSIVE, CODED_FRAMES_INTERLACE, + 1, CODED_FRAMES_PROGRESSIVE, + 0, + HFI_PROP_CODED_FRAMES}, + + {BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8, + 0, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH}, + + {CODEC_CONFIG, DEC, H264 | HEVC, 0, 1, 1, 0, + 0, 0, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {BITSTREAM_SIZE_OVERWRITE, DEC, CODECS_ALL, 0, INT_MAX, 1, 0, + 0}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_THUMBNAIL_MODE, + CAP_FLAG_INPUT_PORT}, + + {DEFAULT_HEADER, DEC, CODECS_ALL, + 0, 1, 1, 0, + 0, + HFI_PROP_DEC_DEFAULT_HEADER}, + + {RAP_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_DEC_START_FROM_RAP_FRAME, + CAP_FLAG_INPUT_PORT}, + + {SEQ_CHANGE_AT_SYNC_FRAME, DEC, CODECS_ALL, + 0, 1, 1, 1, + 0, + HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME, + CAP_FLAG_INPUT_PORT | CAP_FLAG_DYNAMIC_ALLOWED}, + + {PRIORITY, DEC | ENC, CODECS_ALL, + 0, 4, 1, 4, + 0, + HFI_PROP_SESSION_PRIORITY, + CAP_FLAG_DYNAMIC_ALLOWED}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + 1, 1, 1, 1}, + + {ALL_INTRA, ENC, H264 | HEVC, + 0, 1, 1, 0, + 0, + 0, + CAP_FLAG_OUTPUT_PORT}, + + {COMPLEXITY, ENC, H264 | HEVC, + 0, 100, + 1, DEFAULT_COMPLEXITY, + 0}, +}; + +static struct msm_platform_inst_cap_dependency instance_cap_dependency_data_waipio[] = { + /* {cap, domain, codec, + * children, + * adjust, set} + */ + + {PIX_FMTS, ENC, H264, + {0}}, + + {PIX_FMTS, ENC, HEVC, + {PROFILE, MIN_FRAME_QP, MAX_FRAME_QP, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, MIN_QUALITY, BLUR_TYPES}}, + + {PIX_FMTS, DEC, HEVC, + {PROFILE}}, + + {FRAME_RATE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_q16}, + + {HFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {VFLIP, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_flip}, + + {ROTATION, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_rotation}, + + {SUPER_FRAME, ENC, H264 | HEVC, + {INPUT_BUF_HOST_MAX_COUNT, OUTPUT_BUF_HOST_MAX_COUNT}, + NULL, + NULL}, + + {HEADER_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_header_mode}, + + {WITHOUT_STARTCODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_nal_length}, + + {REQUEST_I_FRAME, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_req_sync_frame}, + + {BIT_RATE, ENC, H264 | HEVC, + {PEAK_BITRATE, L0_BR}, + msm_vidc_adjust_bitrate, + msm_vidc_set_bitrate}, + + {BITRATE_MODE, ENC, H264, + {LTR_COUNT, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, ENH_LAYER_COUNT, BIT_RATE, + MIN_QUALITY, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {BITRATE_MODE, ENC, HEVC, + {LTR_COUNT, I_FRAME_QP, P_FRAME_QP, + B_FRAME_QP, CONSTANT_QUALITY, ENH_LAYER_COUNT, + BIT_RATE, MIN_QUALITY, VBV_DELAY, + PEAK_BITRATE, SLICE_MODE, CONTENT_ADAPTIVE_CODING, + BLUR_TYPES, LOWLATENCY_MODE}, + msm_vidc_adjust_bitrate_mode, + msm_vidc_set_u32_enum}, + + {CONSTANT_QUALITY, ENC, HEVC, + {0}, + NULL, + msm_vidc_set_constant_quality}, + + {GOP_SIZE, ENC, CODECS_ALL, + {ALL_INTRA}, + msm_vidc_adjust_gop_size, + msm_vidc_set_gop_size}, + + {B_FRAME, ENC, H264 | HEVC, + {ALL_INTRA}, + msm_vidc_adjust_b_frame, + msm_vidc_set_u32}, + + {BLUR_TYPES, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_blur_type_iris2, + msm_vidc_set_u32_enum}, + + {LOWLATENCY_MODE, ENC, H264 | HEVC, + {STAGE, BIT_RATE}, + msm_vidc_adjust_enc_lowlatency_mode, + NULL}, + + {LOWLATENCY_MODE, DEC, H264 | HEVC | VP9, + {STAGE}, + msm_vidc_adjust_dec_lowlatency_mode, + NULL}, + + {LTR_COUNT, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_ltr_count, + msm_vidc_set_u32}, + + {USE_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_use_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {MARK_LTR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_mark_ltr, + msm_vidc_set_use_and_mark_ltr}, + + {AU_DELIMITER, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_u32}, + + {CONTENT_ADAPTIVE_CODING, ENC, H264 | HEVC, + {REQUEST_PREPROCESS}, + msm_vidc_adjust_brs, + msm_vidc_set_vbr_related_properties}, + + {REQUEST_PREPROCESS, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_preprocess, + msm_vidc_set_preprocess}, + + {MIN_QUALITY, ENC, H264, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {MIN_QUALITY, ENC, HEVC, + {BLUR_TYPES}, + msm_vidc_adjust_min_quality, + msm_vidc_set_u32}, + + {VBV_DELAY, ENC, H264 | HEVC, + {0}, + NULL, + msm_vidc_set_cbr_related_properties}, + + {PEAK_BITRATE, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_peak_bitrate, + msm_vidc_set_cbr_related_properties}, + + {MIN_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_min_qp}, + + {MIN_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_min_qp, + msm_vidc_set_min_qp}, + + {MAX_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_max_qp}, + + {MAX_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_max_qp, + msm_vidc_set_max_qp}, + + {I_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_i_frame_qp, + msm_vidc_set_frame_qp}, + + {I_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_p_frame_qp, + msm_vidc_set_frame_qp}, + + {P_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, HEVC, + {0}, + msm_vidc_adjust_hevc_b_frame_qp, + msm_vidc_set_frame_qp}, + + {B_FRAME_QP, ENC, H264, + {0}, + NULL, + msm_vidc_set_frame_qp}, + + {LAYER_TYPE, ENC, H264, + {CONTENT_ADAPTIVE_CODING}}, + + {LAYER_ENABLE, ENC, H264 | HEVC, + {CONTENT_ADAPTIVE_CODING}}, + + {ENH_LAYER_COUNT, ENC, H264 | HEVC, + {GOP_SIZE, B_FRAME, BIT_RATE, MIN_QUALITY, SLICE_MODE}, + msm_vidc_adjust_layer_count, + msm_vidc_set_layer_count_and_type}, + + {L0_BR, ENC, H264 | HEVC, + {L1_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L1_BR, ENC, H264 | HEVC, + {L2_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L2_BR, ENC, H264 | HEVC, + {L3_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L3_BR, ENC, H264 | HEVC, + {L4_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L4_BR, ENC, H264 | HEVC, + {L5_BR}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {L5_BR, ENC, H264 | HEVC, + {0}, + msm_vidc_adjust_layer_bitrate, + msm_vidc_set_layer_bitrate}, + + {ENTROPY_MODE, ENC, H264, + {BIT_RATE}, + msm_vidc_adjust_entropy_mode, + msm_vidc_set_u32}, + + {PROFILE, ENC, H264, + {ENTROPY_MODE, TRANSFORM_8X8}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, H264, + {ENTROPY_MODE}, + NULL, + msm_vidc_set_u32_enum}, + + {PROFILE, ENC | DEC, HEVC, + {0}, + msm_vidc_adjust_profile, + msm_vidc_set_u32_enum}, + + {PROFILE, DEC, VP9, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LEVEL, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_level}, + + {HEVC_TIER, ENC | DEC, HEVC, + {0}, + NULL, + msm_vidc_set_u32_enum}, + + {LF_MODE, ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_deblock_mode}, + + {SLICE_MODE, ENC, H264 | HEVC, + {STAGE}, + msm_vidc_adjust_slice_count, + msm_vidc_set_slice_count}, + + {TRANSFORM_8X8, ENC, H264, + {0}, + msm_vidc_adjust_transform_8x8, + msm_vidc_set_u32}, + + {CHROMA_QP_INDEX_OFFSET, ENC, HEVC, + {0}, + msm_vidc_adjust_chroma_qp_index_offset, + msm_vidc_set_chroma_qp_index_offset}, + + {DISPLAY_DELAY_ENABLE, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {DISPLAY_DELAY, DEC, H264 | HEVC | VP9, + {OUTPUT_ORDER}, + NULL, + NULL}, + + {OUTPUT_ORDER, DEC, H264 | HEVC | VP9, + {0}, + msm_vidc_adjust_output_order, + msm_vidc_set_u32}, + + {INPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_input_buf_host_max_count, + msm_vidc_set_u32}, + + {OUTPUT_BUF_HOST_MAX_COUNT, ENC | DEC, CODECS_ALL, + {0}, + msm_vidc_adjust_output_buf_host_max_count, + msm_vidc_set_u32}, + + {CONCEAL_COLOR_8BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {CONCEAL_COLOR_10BIT, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32_packed}, + + {STAGE, ENC | DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_stage}, + + {PIPE, DEC | ENC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_pipe}, + + {THUMBNAIL_MODE, DEC, CODECS_ALL, + {OUTPUT_ORDER}, + NULL, + msm_vidc_set_u32}, + + {RAP_FRAME, DEC, CODECS_ALL, + {0}, + NULL, + msm_vidc_set_u32}, + + {PRIORITY, DEC | ENC, CODECS_ALL, + {0}, + msm_vidc_adjust_session_priority, + msm_vidc_set_session_priority}, + + {FIRMWARE_PRIORITY_OFFSET, DEC | ENC, CODECS_ALL, + {0}, + NULL, + NULL}, + + {ALL_INTRA, ENC, H264 | HEVC, + {LTR_COUNT, SLICE_MODE, BIT_RATE}, + msm_vidc_adjust_all_intra, + NULL}, +}; + +/* Default UBWC config for LPDDR5 */ +static struct msm_vidc_ubwc_config_data ubwc_config_waipio[] = { + UBWC_CONFIG(8, 32, 16, 0, 1, 1, 1), +}; + +static struct msm_vidc_format_capability format_data_waipio = { + .codec_info = codec_data_waipio, + .codec_info_size = ARRAY_SIZE(codec_data_waipio), + .color_format_info = color_format_data_waipio, + .color_format_info_size = ARRAY_SIZE(color_format_data_waipio), + .color_prim_info = color_primaries_data_waipio, + .color_prim_info_size = ARRAY_SIZE(color_primaries_data_waipio), + .transfer_char_info = transfer_char_data_waipio, + .transfer_char_info_size = ARRAY_SIZE(transfer_char_data_waipio), + .matrix_coeff_info = matrix_coeff_data_waipio, + .matrix_coeff_info_size = ARRAY_SIZE(matrix_coeff_data_waipio), +}; + +/* name, min_kbps, max_kbps */ +static const struct bw_table waipio_bw_table[] = { + { "venus-cnoc", 1000, 1000 }, + { "venus-ddr", 1000, 15000000 }, +}; + +/* name */ +static const struct pd_table waipio_pd_table[] = { + { "iris-ctl" }, + { "vcodec" }, +}; + +/* name */ +static const char * const waipio_opp_table[] = { "mx", "mmcx", NULL }; + +/* name, clock id, scaling */ +static const struct clk_table waipio_clk_table[] = { + { "gcc_video_axi0", GCC_VIDEO_AXI0_CLK, 0 }, + { "core_clk", VIDEO_CC_MVS0C_CLK, 0 }, + { "vcodec_clk", VIDEO_CC_MVS0_CLK, 1 }, +}; + +/* name */ +static const struct clk_rst_table waipio_clk_reset_table[] = { + { "video_axi_reset" }, + { "video_core_reset" }, +}; + +/* name, start, size, secure, dma_coherant */ +const struct context_bank_table waipio_context_bank_table[] = { + {"qcom,vidc,cb-ns", 0x25800000, 0xba800000, 0, 1, MSM_VIDC_NON_SECURE, 0xe0000000 - 1}, + {"qcom,vidc,cb-sec-non-pxl", 0x01000000, 0x24800000, 1, 0, MSM_VIDC_SECURE_NONPIXEL, 0 }, +}; + +/* freq */ +static struct freq_table waipio_freq_table[] = { + {444000000}, {366000000}, {338000000}, {240000000} +}; + +/* register, value, mask */ +static const struct reg_preset_table waipio_reg_preset_table[] = { + { 0xB0088, 0x0, 0x11 }, +}; + +/* decoder properties */ +static const u32 waipio_vdec_psc_avc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_CODED_FRAMES, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PIC_ORDER_CNT_TYPE, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 waipio_vdec_psc_hevc[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, + HFI_PROP_TIER, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 waipio_vdec_psc_vp9[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_PROP_PROFILE, + HFI_PROP_LEVEL, +}; + +static const u32 waipio_vdec_input_properties_avc[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, +}; + +static const u32 waipio_vdec_input_properties_hevc[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, +}; + +static const u32 waipio_vdec_input_properties_vp9[] = { + HFI_PROP_NO_OUTPUT, + HFI_PROP_SUBFRAME_INPUT, +}; + +static const u32 waipio_vdec_output_properties_avc[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_DPB_LIST, + HFI_PROP_CABAC_SESSION, + HFI_PROP_FENCE, +}; + +static const u32 waipio_vdec_output_properties_hevc[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_DPB_LIST, + HFI_PROP_FENCE, +}; + +static const u32 waipio_vdec_output_properties_vp9[] = { + HFI_PROP_WORST_COMPRESSION_RATIO, + HFI_PROP_WORST_COMPLEXITY_FACTOR, + HFI_PROP_PICTURE_TYPE, + HFI_PROP_DPB_LIST, + HFI_PROP_FENCE, +}; + +static const u32 waipio_msm_vidc_ssr_type[] = { + HFI_SSR_TYPE_SW_ERR_FATAL, + HFI_SSR_TYPE_SW_DIV_BY_ZERO, + HFI_SSR_TYPE_CPU_WDOG_IRQ, + HFI_SSR_TYPE_NOC_ERROR, +}; + +static const struct msm_vidc_platform_data waipio_data = { + /* resources dependent on other module */ + .bw_tbl = waipio_bw_table, + .bw_tbl_size = ARRAY_SIZE(waipio_bw_table), + .clk_tbl = waipio_clk_table, + .clk_tbl_size = ARRAY_SIZE(waipio_clk_table), + .clk_rst_tbl = waipio_clk_reset_table, + .clk_rst_tbl_size = ARRAY_SIZE(waipio_clk_reset_table), + .subcache_tbl = NULL, + .subcache_tbl_size = 0, + + /* populate context bank */ + .context_bank_tbl = waipio_context_bank_table, + .context_bank_tbl_size = ARRAY_SIZE(waipio_context_bank_table), + + /* populate power domain and opp table */ + .pd_tbl = waipio_pd_table, + .pd_tbl_size = ARRAY_SIZE(waipio_pd_table), + .opp_tbl = waipio_opp_table, + .opp_tbl_size = ARRAY_SIZE(waipio_opp_table), + + /* platform specific resources */ + .freq_tbl = waipio_freq_table, + .freq_tbl_size = ARRAY_SIZE(waipio_freq_table), + .reg_prst_tbl = waipio_reg_preset_table, + .reg_prst_tbl_size = ARRAY_SIZE(waipio_reg_preset_table), + .fwname = "vpu20_4v", + .pas_id = 9, + .supports_mmrm = 0, + + /* caps related resorces */ + .core_data = core_data_waipio, + .core_data_size = ARRAY_SIZE(core_data_waipio), + .inst_cap_data = instance_cap_data_waipio, + .inst_cap_data_size = ARRAY_SIZE(instance_cap_data_waipio), + .inst_cap_dependency_data = instance_cap_dependency_data_waipio, + .inst_cap_dependency_data_size = ARRAY_SIZE(instance_cap_dependency_data_waipio), + .csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff, + .csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff, + .csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff, + .ubwc_config = ubwc_config_waipio, + .format_data = &format_data_waipio, + + /* decoder properties related*/ + .psc_avc_tbl = waipio_vdec_psc_avc, + .psc_avc_tbl_size = ARRAY_SIZE(waipio_vdec_psc_avc), + .psc_hevc_tbl = waipio_vdec_psc_hevc, + .psc_hevc_tbl_size = ARRAY_SIZE(waipio_vdec_psc_hevc), + .psc_vp9_tbl = waipio_vdec_psc_vp9, + .psc_vp9_tbl_size = ARRAY_SIZE(waipio_vdec_psc_vp9), + .dec_input_prop_avc = waipio_vdec_input_properties_avc, + .dec_input_prop_hevc = waipio_vdec_input_properties_hevc, + .dec_input_prop_vp9 = waipio_vdec_input_properties_vp9, + .dec_input_prop_size_avc = ARRAY_SIZE(waipio_vdec_input_properties_avc), + .dec_input_prop_size_hevc = ARRAY_SIZE(waipio_vdec_input_properties_hevc), + .dec_input_prop_size_vp9 = ARRAY_SIZE(waipio_vdec_input_properties_vp9), + .dec_output_prop_avc = waipio_vdec_output_properties_avc, + .dec_output_prop_hevc = waipio_vdec_output_properties_hevc, + .dec_output_prop_vp9 = waipio_vdec_output_properties_vp9, + .dec_output_prop_size_avc = ARRAY_SIZE(waipio_vdec_output_properties_avc), + .dec_output_prop_size_hevc = ARRAY_SIZE(waipio_vdec_output_properties_hevc), + .dec_output_prop_size_vp9 = ARRAY_SIZE(waipio_vdec_output_properties_vp9), + + .msm_vidc_ssr_type = waipio_msm_vidc_ssr_type, + .msm_vidc_ssr_type_size = ARRAY_SIZE(waipio_msm_vidc_ssr_type), +}; + +static int msm_vidc_init_data(struct msm_vidc_core *core) +{ + int rc = 0; + + d_vpr_h("%s: initialize waipio data\n", __func__); + + core->platform->data = waipio_data; + + return rc; +} + +int msm_vidc_init_platform_waipio(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = msm_vidc_init_data(core); + if (rc) + return rc; + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/variant/common/inc/msm_vidc_variant.h b/qcom/opensource/video-driver/driver/variant/common/inc/msm_vidc_variant.h new file mode 100644 index 0000000000..dee6df24c5 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/common/inc/msm_vidc_variant.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_VARIANT_H_ +#define _MSM_VIDC_VARIANT_H_ + +#include + +struct msm_vidc_core; + +int __write_register_masked(struct msm_vidc_core *core, u32 reg, u32 value, + u32 mask); +int __write_register(struct msm_vidc_core *core, u32 reg, u32 value); +int __read_register(struct msm_vidc_core *core, u32 reg, u32 *value); +int __read_register_with_poll_timeout(struct msm_vidc_core *core, u32 reg, + u32 mask, u32 exp_val, u32 sleep_us, u32 timeout_us); +int __set_registers(struct msm_vidc_core *core); + +#endif diff --git a/qcom/opensource/video-driver/driver/variant/common/src/msm_vidc_variant.c b/qcom/opensource/video-driver/driver/variant/common/src/msm_vidc_variant.c new file mode 100644 index 0000000000..70c23a1bca --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/common/src/msm_vidc_variant.c @@ -0,0 +1,161 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include + +#include "msm_vidc_core.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_state.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_variant.h" +#include "msm_vidc_platform.h" +#include "venus_hfi.h" + +int __write_register(struct msm_vidc_core *core, u32 reg, u32 value) +{ + u32 hwiosymaddr = reg; + u8 *base_addr; + int rc = 0; + + rc = __strict_check(core, __func__); + if (rc) + return rc; + + if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) { + d_vpr_e("HFI Write register failed : Power is OFF\n"); + return -EINVAL; + } + + base_addr = core->resource->register_base_addr; + d_vpr_l("regwrite(%pK + %#x) = %#x\n", base_addr, hwiosymaddr, value); + base_addr += hwiosymaddr; + writel_relaxed(value, base_addr); + + /* Memory barrier to make sure value is written into the register */ + wmb(); + + return rc; +} + +/* + * Argument mask is used to specify which bits to update. In case mask is 0x11, + * only bits 0 & 4 will be updated with corresponding bits from value. To update + * entire register with value, set mask = 0xFFFFFFFF. + */ +int __write_register_masked(struct msm_vidc_core *core, u32 reg, u32 value, + u32 mask) +{ + u32 prev_val, new_val; + u8 *base_addr; + int rc = 0; + + rc = __strict_check(core, __func__); + if (rc) + return rc; + + if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) { + d_vpr_e("%s: register write failed, power is off\n", + __func__); + return -EINVAL; + } + + base_addr = core->resource->register_base_addr; + base_addr += reg; + + prev_val = readl_relaxed(base_addr); + /* + * Memory barrier to ensure register read is correct + */ + rmb(); + + new_val = (prev_val & ~mask) | (value & mask); + d_vpr_l( + "Base addr: %pK, writing to: %#x, previous-value: %#x, value: %#x, mask: %#x, new-value: %#x...\n", + base_addr, reg, prev_val, value, mask, new_val); + writel_relaxed(new_val, base_addr); + /* + * Memory barrier to make sure value is written into the register. + */ + wmb(); + + return rc; +} + +int __read_register(struct msm_vidc_core *core, u32 reg, u32 *value) +{ + int rc = 0; + u8 *base_addr; + + if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) { + d_vpr_e("HFI Read register failed : Power is OFF\n"); + return -EINVAL; + } + + base_addr = core->resource->register_base_addr; + + *value = readl_relaxed(base_addr + reg); + /* + * Memory barrier to make sure value is read correctly from the + * register. + */ + rmb(); + d_vpr_l("regread(%pK + %#x) = %#x\n", base_addr, reg, *value); + + return rc; +} + +int __read_register_with_poll_timeout(struct msm_vidc_core *core, u32 reg, + u32 mask, u32 exp_val, u32 sleep_us, + u32 timeout_us) +{ + int rc = 0; + u32 val = 0; + u8 *addr; + + if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) { + d_vpr_e("%s failed: Power is OFF\n", __func__); + return -EINVAL; + } + + addr = (u8 *)core->resource->register_base_addr + reg; + + rc = readl_relaxed_poll_timeout(addr, val, ((val & mask) == exp_val), sleep_us, timeout_us); + /* + * Memory barrier to make sure value is read correctly from the + * register. + */ + rmb(); + d_vpr_l( + "regread(%pK + %#x) = %#x. rc %d, mask %#x, exp_val %#x, cond %u, sleep %u, timeout %u\n", + core->resource->register_base_addr, reg, val, rc, mask, exp_val, + ((val & mask) == exp_val), sleep_us, timeout_us); + + return rc; +} + +int __set_registers(struct msm_vidc_core *core) +{ + const struct reg_preset_table *reg_prst; + unsigned int prst_count; + int cnt, rc = 0; + + reg_prst = core->platform->data.reg_prst_tbl; + prst_count = core->platform->data.reg_prst_tbl_size; + + /* skip if there is no preset reg available */ + if (!reg_prst || !prst_count) + return 0; + + for (cnt = 0; cnt < prst_count; cnt++) { + rc = __write_register_masked(core, reg_prst[cnt].reg, + reg_prst[cnt].value, reg_prst[cnt].mask); + if (rc) + return rc; + } + + return rc; +} diff --git a/qcom/opensource/video-driver/driver/variant/iris2/inc/hfi_buffer_iris2.h b/qcom/opensource/video-driver/driver/variant/iris2/inc/hfi_buffer_iris2.h new file mode 100644 index 0000000000..5be5f720f7 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris2/inc/hfi_buffer_iris2.h @@ -0,0 +1,1458 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __HFI_BUFFER_IRIS2__ +#define __HFI_BUFFER_IRIS2__ + +#include +#include "hfi_property.h" + +typedef u8 HFI_U8; +typedef s8 HFI_S8; +typedef u16 HFI_U16; +typedef s16 HFI_S16; +typedef u32 HFI_U32; +typedef s32 HFI_S32; +typedef u64 HFI_U64; +typedef HFI_U32 HFI_BOOL; + +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#ifndef MAX +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#define HFI_ALIGNMENT_4096 (4096) + +#define BUF_SIZE_ALIGN_16 (16) +#define BUF_SIZE_ALIGN_32 (32) +#define BUF_SIZE_ALIGN_64 (64) +#define BUF_SIZE_ALIGN_128 (128) +#define BUF_SIZE_ALIGN_256 (256) +#define BUF_SIZE_ALIGN_512 (512) +#define BUF_SIZE_ALIGN_4096 (4096) + +#define HFI_ALIGN(a, b) (((b) & ((b) - 1)) ? (((a) + (b) - 1) / \ + (b) * (b)) : (((a) + (b) - 1) & (~((b) - 1)))) + +#define HFI_WORKMODE_1 1 +#define HFI_WORKMODE_2 2 + +#define HFI_DEFAULT_METADATA_STRIDE_MULTIPLE (64) +#define HFI_DEFAULT_METADATA_BUFFERHEIGHT_MULTIPLE (16) + +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT (8) +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH (32) +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT (8) +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH (16) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT (4) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH (48) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_HEIGHT (4) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_WIDTH (24) +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_HEIGHT (4) +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_WIDTH (16) + +#define HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width, stride_multiple)) + +#define HFI_NV12_IL_CALC_Y_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) (buf_height = HFI_ALIGN(frame_height, \ + min_buf_height_multiple)) + +#define HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width, stride_multiple)) + +#define HFI_NV12_IL_CALC_UV_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) (buf_height = HFI_ALIGN(((frame_height + 1) \ + >> 1), min_buf_height_multiple)) + +#define HFI_NV12_IL_CALC_BUF_SIZE(buf_size, y_bufSize, y_stride, y_buf_height, \ + uv_buf_size, uv_stride, uv_buf_height) \ + do { \ + y_bufSize = (y_stride * y_buf_height); \ + uv_buf_size = (uv_stride * uv_buf_height); \ + buf_size = HFI_ALIGN(y_bufSize + uv_buf_size, HFI_ALIGNMENT_4096); \ + } while (0) + +#define HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_bufSize, y_stride, y_buf_height) \ + (y_bufSize = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, \ + uv_stride, uv_buf_height) \ + (uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_NV12_UBWC_IL_CALC_BUF_SIZE_V2(buf_size,\ + frame_width, frame_height, y_stride_multiple,\ + y_buffer_height_multiple, uv_stride_multiple, \ + uv_buffer_height_multiple, y_metadata_stride_multiple, \ + y_metadata_buffer_height_multiple, \ + uv_metadata_stride_multiple, uv_metadata_buffer_height_multiple) \ + do { \ + HFI_U32 y_buf_size, uv_buf_size, y_meta_size, uv_meta_size; \ + HFI_U32 stride, _height; \ + HFI_U32 half_height = (frame_height + 1) >> 1; \ + HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width,\ + y_stride_multiple); \ + HFI_NV12_IL_CALC_Y_BUFHEIGHT(_height, half_height,\ + y_buffer_height_multiple); \ + HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_buf_size, stride, _height);\ + HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, \ + uv_stride_multiple); \ + HFI_NV12_IL_CALC_UV_BUFHEIGHT(_height, half_height, \ + uv_buffer_height_multiple); \ + HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, stride, _height);\ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(stride, frame_width,\ + y_metadata_stride_multiple, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH);\ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(_height, half_height, \ + y_metadata_buffer_height_multiple,\ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT);\ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_meta_size, stride, \ + _height); \ + HFI_UBWC_UV_METADATA_PLANE_STRIDE(stride, frame_width,\ + uv_metadata_stride_multiple, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH); \ + HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(_height, half_height,\ + uv_metadata_buffer_height_multiple,\ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT);\ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_meta_size, stride, \ + _height); \ + buf_size = (y_buf_size + uv_buf_size + y_meta_size + \ + uv_meta_size) << 1;\ + } while (0) + +#define HFI_YUV420_TP10_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \ + do { \ + stride = HFI_ALIGN(frame_width, 192); \ + stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \ + } while (0) + +#define HFI_YUV420_TP10_CALC_Y_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple)) + +#define HFI_YUV420_TP10_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \ + do { \ + stride = HFI_ALIGN(frame_width, 192); \ + stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \ + } while (0) + +#define HFI_YUV420_TP10_CALC_UV_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \ + min_buf_height_multiple)) + +#define HFI_YUV420_TP10_CALC_BUF_SIZE(buf_size, y_buf_size, y_stride,\ + y_buf_height, uv_buf_size, uv_stride, uv_buf_height) \ + do { \ + y_buf_size = (y_stride * y_buf_height); \ + uv_buf_size = (uv_stride * uv_buf_height); \ + buf_size = y_buf_size + uv_buf_size; \ + } while (0) + +#define HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_buf_size, y_stride, \ + y_buf_height) \ + (y_buf_size = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_buf_size, uv_stride, \ + uv_buf_height) \ + (uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_YUV420_TP10_UBWC_CALC_BUF_SIZE(buf_size, y_stride, y_buf_height, \ + uv_stride, uv_buf_height, y_md_stride, y_md_height, uv_md_stride, \ + uv_md_height)\ + do { \ + HFI_U32 y_data_size, uv_data_size, y_md_size, uv_md_size; \ + HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_data_size, y_stride,\ + y_buf_height); \ + HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_data_size, uv_stride, \ + uv_buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_md_size, y_md_stride, \ + y_md_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_md_size, uv_md_stride, \ + uv_md_height); \ + buf_size = y_data_size + uv_data_size + y_md_size + \ + uv_md_size; \ + } while (0) + +#define HFI_YUV420_P010_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width * 2, stride_multiple)) + +#define HFI_YUV420_P010_CALC_Y_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple)) + +#define HFI_YUV420_P010_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width * 2, stride_multiple)) + +#define HFI_YUV420_P010_CALC_UV_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \ + min_buf_height_multiple)) + +#define HFI_YUV420_P010_CALC_BUF_SIZE(buf_size, y_data_size, y_stride, \ + y_buf_height, uv_data_size, uv_stride, uv_buf_height) \ + do { \ + y_data_size = HFI_ALIGN(y_stride * y_buf_height, \ + HFI_ALIGNMENT_4096);\ + uv_data_size = HFI_ALIGN(uv_stride * uv_buf_height, \ + HFI_ALIGNMENT_4096); \ + buf_size = y_data_size + uv_data_size; \ + } while (0) + +#define HFI_RGB888_CALC_STRIDE(stride, frame_width, stride_multiple) \ + (stride = ((frame_width * 3) + stride_multiple - 1) & \ + (0xffffffff - (stride_multiple - 1))) + +#define HFI_RGB888_CALC_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = ((frame_height + min_buf_height_multiple - 1) & \ + (0xffffffff - (min_buf_height_multiple - 1)))) + +#define HFI_RGB888_CALC_BUF_SIZE(buf_size, stride, buf_height) \ + (buf_size = ((stride) * (buf_height))) + +#define HFI_RGBA8888_CALC_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN((frame_width << 2), stride_multiple)) + +#define HFI_RGBA8888_CALC_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple)) + +#define HFI_RGBA8888_CALC_BUF_SIZE(buf_size, stride, buf_height) \ + (buf_size = (stride) * (buf_height)) + +#define HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(buf_size, stride, \ + buf_height) \ + (buf_size = HFI_ALIGN((stride) * (buf_height), HFI_ALIGNMENT_4096)) + +#define HFI_RGBA8888_UBWC_BUF_SIZE(buf_size, data_buf_size, \ + metadata_buffer_size, stride, buf_height, _metadata_tride, \ + _metadata_buf_height) \ + do { \ + HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(data_buf_size, \ + stride, buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(metadata_buffer_size, \ + _metadata_tride, _metadata_buf_height); \ + buf_size = data_buf_size + metadata_buffer_size; \ + } while (0) + +#define HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, frame_width,\ + metadata_stride_multiple, tile_width_in_pels) \ + (metadata_stride = HFI_ALIGN(((frame_width + (tile_width_in_pels - 1)) /\ + tile_width_in_pels), metadata_stride_multiple)) + +#define HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, frame_height, \ + metadata_height_multiple, tile_height_in_pels) \ + (metadata_buf_height = HFI_ALIGN(((frame_height + \ + (tile_height_in_pels - 1)) / tile_height_in_pels), \ + metadata_height_multiple)) + +#define HFI_UBWC_UV_METADATA_PLANE_STRIDE(metadata_stride, frame_width, \ + metadata_stride_multiple, tile_width_in_pels) \ + (metadata_stride = HFI_ALIGN(((((frame_width + 1) >> 1) +\ + (tile_width_in_pels - 1)) / tile_width_in_pels), \ + metadata_stride_multiple)) + +#define HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, frame_height,\ + metadata_height_multiple, tile_height_in_pels) \ + (metadata_buf_height = HFI_ALIGN(((((frame_height + 1) >> 1) + \ + (tile_height_in_pels - 1)) / tile_height_in_pels), \ + metadata_height_multiple)) + +#define HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(buffer_size, _metadata_tride, \ + _metadata_buf_height) \ + (buffer_size = HFI_ALIGN(_metadata_tride * _metadata_buf_height, \ + HFI_ALIGNMENT_4096)) + +#define BUFFER_ALIGNMENT_512_BYTES 512 +#define BUFFER_ALIGNMENT_256_BYTES 256 +#define BUFFER_ALIGNMENT_128_BYTES 128 +#define BUFFER_ALIGNMENT_64_BYTES 64 +#define BUFFER_ALIGNMENT_32_BYTES 32 +#define BUFFER_ALIGNMENT_16_BYTES 16 +#define BUFFER_ALIGNMENT_8_BYTES 8 +#define BUFFER_ALIGNMENT_4_BYTES 4 + +#define VENUS_DMA_ALIGNMENT BUFFER_ALIGNMENT_256_BYTES + +#define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE 640 +#define MAX_FE_NBR_DATA_CB_LINE_BUFFER_SIZE 320 +#define MAX_FE_NBR_DATA_CR_LINE_BUFFER_SIZE 320 + +#define MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE (128 / 8) +#define MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE (128 / 8) +#define MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE (128 / 8) + +#define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE (64 * 2 * 3) +#define MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE (32 * 2 * 3) +#define MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE (16 * 2 * 3) + +#define MAX_TILE_COLUMNS 32 + +#define SIZE_VPSS_LB(Size, frame_width, frame_height, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_4tap_top_buffer_size, vpss_div2_top_buffer_size, \ + vpss_4tap_left_buffer_size, vpss_div2_left_buffer_size; \ + HFI_U32 opb_wr_top_line_luma_buffer_size, \ + opb_wr_top_line_chroma_buffer_size, \ + opb_lb_wr_llb_y_buffer_size,\ + opb_lb_wr_llb_uv_buffer_size; \ + HFI_U32 macrotiling_size; \ + vpss_4tap_top_buffer_size = vpss_div2_top_buffer_size = \ + vpss_4tap_left_buffer_size = vpss_div2_left_buffer_size = 0; \ + macrotiling_size = 32; \ + opb_wr_top_line_luma_buffer_size = HFI_ALIGN(frame_width, \ + macrotiling_size) / macrotiling_size * 256; \ + opb_wr_top_line_luma_buffer_size = \ + HFI_ALIGN(opb_wr_top_line_luma_buffer_size, \ + VENUS_DMA_ALIGNMENT) + (MAX_TILE_COLUMNS - 1) * 256; \ + opb_wr_top_line_luma_buffer_size = \ + MAX(opb_wr_top_line_luma_buffer_size, (32 * \ + HFI_ALIGN(frame_height, 8))); \ + opb_wr_top_line_chroma_buffer_size = \ + opb_wr_top_line_luma_buffer_size;\ + opb_lb_wr_llb_uv_buffer_size = opb_lb_wr_llb_y_buffer_size = \ + HFI_ALIGN((HFI_ALIGN(frame_height, 8) / (4 / 2)) * 64,\ + BUFFER_ALIGNMENT_32_BYTES); \ + Size = num_vpp_pipes * 2 * (vpss_4tap_top_buffer_size + \ + vpss_div2_top_buffer_size) + \ + 2 * (vpss_4tap_left_buffer_size + \ + vpss_div2_left_buffer_size) + \ + opb_wr_top_line_luma_buffer_size + \ + opb_wr_top_line_chroma_buffer_size + \ + opb_lb_wr_llb_uv_buffer_size + \ + opb_lb_wr_llb_y_buffer_size; \ + } while (0) + +#define VPP_CMD_MAX_SIZE (1 << 20) +#define NUM_HW_PIC_BUF 32 +#define BIN_BUFFER_THRESHOLD (1280 * 736) +#define H264D_MAX_SLICE 1800 +#define SIZE_H264D_BUFTAB_T (256) +#define SIZE_H264D_HW_PIC_T (1 << 11) +#define SIZE_H264D_BSE_CMD_PER_BUF (32 * 4) +#define SIZE_H264D_VPP_CMD_PER_BUF (512) + +#define SIZE_H264D_LB_FE_TOP_DATA(frame_width, frame_height) \ + (MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * HFI_ALIGN(frame_width, 16) * 3) + +#define SIZE_H264D_LB_FE_TOP_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_width + 15) >> 4)) + +#define SIZE_H264D_LB_FE_LEFT_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_height + 15) >> 4)) + +#define SIZE_H264D_LB_SE_TOP_CTRL(frame_width, frame_height) \ + (MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_width + 15) >> 4)) + +#define SIZE_H264D_LB_SE_LEFT_CTRL(frame_width, frame_height) \ + (MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_height + 15) >> 4)) + +#define SIZE_H264D_LB_PE_TOP_DATA(frame_width, frame_height) \ + (MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * ((frame_width + 15) >> 4)) + +#define SIZE_H264D_LB_VSP_TOP(frame_width, frame_height) \ + ((((frame_width + 15) >> 4) << 7)) + +#define SIZE_H264D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \ + (HFI_ALIGN(frame_height, 16) * 32) + +#define SIZE_H264D_QP(frame_width, frame_height) \ + (((frame_width + 63) >> 6) * ((frame_height + 63) >> 6) * 128) + +#define SIZE_HW_PIC(size_per_buf) \ + (NUM_HW_PIC_BUF * size_per_buf) + +#define SIZE_H264D_BSE_CMD_BUF(_size, frame_width, frame_height) \ + do { \ + HFI_U32 _height = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_32_BYTES); \ + _size = MIN((((_height + 15) >> 4) * 48), H264D_MAX_SLICE) *\ + SIZE_H264D_BSE_CMD_PER_BUF; \ + } while (0) + +#define SIZE_H264D_VPP_CMD_BUF(_size, frame_width, frame_height) \ + do { \ + HFI_U32 _height = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_32_BYTES); \ + _size = MIN((((_height + 15) >> 4) * 48), H264D_MAX_SLICE) * \ + SIZE_H264D_VPP_CMD_PER_BUF; \ + if (_size > VPP_CMD_MAX_SIZE) { \ + _size = VPP_CMD_MAX_SIZE; \ + } \ + } while (0) + +#define HFI_BUFFER_COMV_H264D(coMV_size, frame_width, \ + frame_height, _yuv_bufcount_min) \ + do { \ + HFI_U32 frame_width_in_mbs = ((frame_width + 15) >> 4); \ + HFI_U32 frame_height_in_mbs = ((frame_height + 15) >> 4); \ + HFI_U32 col_mv_aligned_width = (frame_width_in_mbs << 7); \ + HFI_U32 col_zero_aligned_width = (frame_width_in_mbs << 2); \ + HFI_U32 col_zero_size = 0, size_colloc = 0; \ + col_mv_aligned_width = HFI_ALIGN(col_mv_aligned_width, \ + BUFFER_ALIGNMENT_16_BYTES); \ + col_zero_aligned_width = HFI_ALIGN(col_zero_aligned_width, \ + BUFFER_ALIGNMENT_16_BYTES); \ + col_zero_size = col_zero_aligned_width * \ + ((frame_height_in_mbs + 1) >> 1); \ + col_zero_size = HFI_ALIGN(col_zero_size, \ + BUFFER_ALIGNMENT_64_BYTES); \ + col_zero_size <<= 1; \ + col_zero_size = HFI_ALIGN(col_zero_size, \ + BUFFER_ALIGNMENT_512_BYTES); \ + size_colloc = col_mv_aligned_width * ((frame_height_in_mbs + \ + 1) >> 1); \ + size_colloc = HFI_ALIGN(size_colloc, \ + BUFFER_ALIGNMENT_64_BYTES); \ + size_colloc <<= 1; \ + size_colloc = HFI_ALIGN(size_colloc, \ + BUFFER_ALIGNMENT_512_BYTES); \ + size_colloc += (col_zero_size + SIZE_H264D_BUFTAB_T * 2); \ + coMV_size = size_colloc * (_yuv_bufcount_min); \ + coMV_size += BUFFER_ALIGNMENT_512_BYTES; \ + } while (0) + +#define HFI_BUFFER_NON_COMV_H264D(_size, frame_width, frame_height, \ + num_vpp_pipes) \ + do { \ + HFI_U32 _size_bse, _size_vpp; \ + SIZE_H264D_BSE_CMD_BUF(_size_bse, frame_width, frame_height); \ + SIZE_H264D_VPP_CMD_BUF(_size_vpp, frame_width, frame_height); \ + _size = HFI_ALIGN(_size_bse, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(_size_vpp, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), \ + VENUS_DMA_ALIGNMENT); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define HFI_BUFFER_LINE_H264D(_size, frame_width, frame_height, \ + is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_lb_size = 0; \ + _size = HFI_ALIGN(SIZE_H264D_LB_FE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_FE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H264D_LB_SE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_SE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * \ + num_vpp_pipes + \ + HFI_ALIGN(SIZE_H264D_LB_PE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_VSP_TOP(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_RECON_DMA_METADATA_WR\ + (frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * 2 + HFI_ALIGN(SIZE_H264D_QP\ + (frame_width, frame_height), VENUS_DMA_ALIGNMENT); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \ + num_vpp_pipes); \ + } \ + _size = HFI_ALIGN((_size + vpss_lb_size), \ + VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define H264_CABAC_HDR_RATIO_HD_TOT 1 +#define H264_CABAC_RES_RATIO_HD_TOT 3 + +#define SIZE_H264D_HW_BIN_BUFFER(_size, frame_width, frame_height, \ + delay, num_vpp_pipes) \ + do { \ + HFI_U32 size_yuv, size_bin_hdr, size_bin_res; \ + size_yuv = ((frame_width * frame_height) <= \ + BIN_BUFFER_THRESHOLD) ?\ + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : \ + ((frame_width * frame_height * 3) >> 1); \ + size_bin_hdr = size_yuv * H264_CABAC_HDR_RATIO_HD_TOT; \ + size_bin_res = size_yuv * H264_CABAC_RES_RATIO_HD_TOT; \ + size_bin_hdr = size_bin_hdr * (((((HFI_U32)(delay)) & 31) /\ + 10) + 2) / 2; \ + size_bin_res = size_bin_res * (((((HFI_U32)(delay)) & 31) /\ + 10) + 2) / 2; \ + size_bin_hdr = HFI_ALIGN(size_bin_hdr / num_vpp_pipes,\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + size_bin_res = HFI_ALIGN(size_bin_res / num_vpp_pipes, \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + _size = size_bin_hdr + size_bin_res; \ + } while (0) + +#define HFI_BUFFER_BIN_H264D(_size, frame_width, frame_height, is_interlaced, \ + delay, num_vpp_pipes) \ + do { \ + HFI_U32 n_aligned_w = HFI_ALIGN(frame_width, \ + BUFFER_ALIGNMENT_16_BYTES);\ + HFI_U32 n_aligned_h = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_16_BYTES); \ + if (!is_interlaced) { \ + SIZE_H264D_HW_BIN_BUFFER(_size, n_aligned_w, \ + n_aligned_h, delay, num_vpp_pipes); \ + } else { \ + _size = 0; \ + } \ + } while (0) + +#define NUM_SLIST_BUF_H264 (256 + 32) +#define SIZE_SLIST_BUF_H264 (512) +#define SIZE_SEI_USERDATA (4096) +#define H264_NUM_FRM_INFO (66) +#define H264_DISPLAY_BUF_SIZE (3328) +#define SIZE_DOLBY_RPU_METADATA (41 * 1024) +#define HFI_BUFFER_PERSIST_H264D(_size, rpu_enabled) \ + (_size = HFI_ALIGN((SIZE_SLIST_BUF_H264 * NUM_SLIST_BUF_H264 + \ + H264_DISPLAY_BUF_SIZE * H264_NUM_FRM_INFO + \ + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA + \ + (rpu_enabled) * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA), \ + VENUS_DMA_ALIGNMENT)) + +#define LCU_MAX_SIZE_PELS 64 +#define LCU_MIN_SIZE_PELS 16 + +#define H265D_MAX_SLICE 1200 +#define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T +#define SIZE_H265D_BSE_CMD_PER_BUF (16 * sizeof(HFI_U32)) +#define SIZE_H265D_VPP_CMD_PER_BUF (256) + +#define SIZE_H265D_LB_FE_TOP_DATA(frame_width, frame_height) \ + (MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * \ + (HFI_ALIGN(frame_width, 64) + 8) * 2) + +#define SIZE_H265D_LB_FE_TOP_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + (HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_FE_LEFT_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + (HFI_ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_SE_TOP_CTRL(frame_width, frame_height) \ + ((LCU_MAX_SIZE_PELS / 8 * (128 / 8)) * ((frame_width + 15) >> 4)) + +#define SIZE_H265D_LB_SE_LEFT_CTRL(frame_width, frame_height) \ + (MAX(((frame_height + 16 - 1) / 8) * \ + MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, \ + MAX(((frame_height + 32 - 1) / 8) * \ + MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((frame_height + 64 - 1) / 8) * \ + MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE))) + +#define SIZE_H265D_LB_PE_TOP_DATA(frame_width, frame_height) \ + (MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * (HFI_ALIGN(frame_width, \ + LCU_MIN_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_VSP_TOP(frame_width, frame_height) \ + (((frame_width + 63) >> 6) * 128) + +#define SIZE_H265D_LB_VSP_LEFT(frame_width, frame_height) \ + (((frame_height + 63) >> 6) * 128) + +#define SIZE_H265D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \ + SIZE_H264D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) + +#define SIZE_H265D_QP(frame_width, frame_height) \ + SIZE_H264D_QP(frame_width, frame_height) + +#define SIZE_H265D_BSE_CMD_BUF(_size, frame_width, frame_height)\ + do { \ + _size = HFI_ALIGN(((HFI_ALIGN(frame_width, \ + LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * \ + (HFI_ALIGN(frame_height, LCU_MAX_SIZE_PELS) /\ + LCU_MIN_SIZE_PELS)) * NUM_HW_PIC_BUF, VENUS_DMA_ALIGNMENT); \ + _size = MIN(_size, H265D_MAX_SLICE + 1); \ + _size = 2 * _size * SIZE_H265D_BSE_CMD_PER_BUF; \ + } while (0) + +#define SIZE_H265D_VPP_CMD_BUF(_size, frame_width, frame_height) \ + do { \ + _size = HFI_ALIGN(((HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) /\ + LCU_MIN_SIZE_PELS) * (HFI_ALIGN(frame_height, \ + LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) * \ + NUM_HW_PIC_BUF, VENUS_DMA_ALIGNMENT); \ + _size = MIN(_size, H265D_MAX_SLICE + 1); \ + _size = HFI_ALIGN(_size, 4); \ + _size = 2 * _size * SIZE_H265D_VPP_CMD_PER_BUF; \ + if (_size > VPP_CMD_MAX_SIZE) { \ + _size = VPP_CMD_MAX_SIZE; \ + } \ + } while (0) + +#define HFI_BUFFER_COMV_H265D(_size, frame_width, frame_height, \ + _yuv_bufcount_min) \ + do { \ + _size = HFI_ALIGN(((((frame_width + 15) >> 4) * \ + ((frame_height + 15) >> 4)) << 8), \ + BUFFER_ALIGNMENT_512_BYTES); \ + _size *= _yuv_bufcount_min; \ + _size += BUFFER_ALIGNMENT_512_BYTES; \ + } while (0) + +#define HDR10_HIST_EXTRADATA_SIZE (4 * 1024) + +#define HFI_BUFFER_NON_COMV_H265D(_size, frame_width, frame_height, \ + num_vpp_pipes) \ + do { \ + HFI_U32 _size_bse, _size_vpp; \ + SIZE_H265D_BSE_CMD_BUF(_size_bse, frame_width, \ + frame_height); \ + SIZE_H265D_VPP_CMD_BUF(_size_vpp, frame_width, \ + frame_height); \ + _size = HFI_ALIGN(_size_bse, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(_size_vpp, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(NUM_HW_PIC_BUF * 20 * 22 * 4, \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(2 * sizeof(HFI_U16) * \ + (HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) / \ + LCU_MIN_SIZE_PELS) * (HFI_ALIGN(frame_height, \ + LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_HW_PIC(SIZE_H265D_HW_PIC_T), \ + VENUS_DMA_ALIGNMENT) + \ + HDR10_HIST_EXTRADATA_SIZE; \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define HFI_BUFFER_LINE_H265D(_size, frame_width, frame_height, \ + is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_lb_size = 0; \ + _size = HFI_ALIGN(SIZE_H265D_LB_FE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_FE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H265D_LB_SE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H265D_LB_SE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_PE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_VSP_TOP(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_VSP_LEFT(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H265D_LB_RECON_DMA_METADATA_WR\ + (frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * 4 + \ + HFI_ALIGN(SIZE_H265D_QP(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height,\ + num_vpp_pipes); \ + } \ + _size = HFI_ALIGN((_size + vpss_lb_size), \ + VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define H265_CABAC_HDR_RATIO_HD_TOT 2 +#define H265_CABAC_RES_RATIO_HD_TOT 2 + +#define SIZE_H265D_HW_BIN_BUFFER(_size, frame_width, frame_height, \ + delay, num_vpp_pipes) \ + do { \ + HFI_U32 size_yuv, size_bin_hdr, size_bin_res; \ + size_yuv = ((frame_width * frame_height) <= \ + BIN_BUFFER_THRESHOLD) ? \ + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : \ + ((frame_width * frame_height * 3) >> 1); \ + size_bin_hdr = size_yuv * H265_CABAC_HDR_RATIO_HD_TOT; \ + size_bin_res = size_yuv * H265_CABAC_RES_RATIO_HD_TOT; \ + size_bin_hdr = size_bin_hdr * \ + (((((HFI_U32)(delay)) & 31) / 10) + 2) / 2; \ + size_bin_res = size_bin_res * \ + (((((HFI_U32)(delay)) & 31) / 10) + 2) / 2; \ + size_bin_hdr = HFI_ALIGN(size_bin_hdr / \ + num_vpp_pipes, VENUS_DMA_ALIGNMENT) * \ + num_vpp_pipes; \ + size_bin_res = HFI_ALIGN(size_bin_res / num_vpp_pipes,\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + _size = size_bin_hdr + size_bin_res; \ + } while (0) + +#define HFI_BUFFER_BIN_H265D(_size, frame_width, frame_height, \ + is_interlaced, delay, num_vpp_pipes) \ + do { \ + HFI_U32 n_aligned_w = HFI_ALIGN(frame_width, \ + BUFFER_ALIGNMENT_16_BYTES); \ + HFI_U32 n_aligned_h = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_16_BYTES); \ + if (!is_interlaced) { \ + SIZE_H265D_HW_BIN_BUFFER(_size, n_aligned_w, \ + n_aligned_h, delay, num_vpp_pipes); \ + } else { \ + _size = 0; \ + } \ + } while (0) + +#define SIZE_SLIST_BUF_H265 (1 << 10) +#define NUM_SLIST_BUF_H265 (80 + 20) +#define H265_NUM_TILE_COL 32 +#define H265_NUM_TILE_ROW 128 +#define H265_NUM_TILE (H265_NUM_TILE_ROW * H265_NUM_TILE_COL + 1) +#define H265_NUM_FRM_INFO (48) +#define H265_DISPLAY_BUF_SIZE (3072) +#define HFI_BUFFER_PERSIST_H265D(_size, rpu_enabled) \ + (_size = HFI_ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 + \ + H265_NUM_FRM_INFO * H265_DISPLAY_BUF_SIZE + \ + H265_NUM_TILE * sizeof(HFI_U32) + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA + \ + (rpu_enabled) * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA),\ + VENUS_DMA_ALIGNMENT)) + +#define SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, frame_height) \ + MAX(((frame_height + 15) >> 4) * \ + MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, \ + MAX(((frame_height + 31) >> 5) * \ + MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((frame_height + 63) >> 6) * MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)) +#define SIZE_VPXD_LB_FE_TOP_CTRL(frame_width, frame_height) \ + (((HFI_ALIGN(frame_width, 64) + 8) * 10 * 2)) +#define SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height) \ + (((frame_width + 15) >> 4) * MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE) +#define SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height) \ + MAX(((frame_height + 15) >> 4) * \ + MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE,\ + MAX(((frame_height + 31) >> 5) * \ + MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((frame_height + 63) >> 6) * MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)) +#define SIZE_VPXD_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \ + HFI_ALIGN((HFI_ALIGN(frame_height, 8) / (4 / 2)) * 64,\ + BUFFER_ALIGNMENT_32_BYTES) +#define SIZE_MP2D_LB_FE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(frame_width, 16) + 8) * 10 * 2) +#define SIZE_VP9D_LB_FE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) + 8) * 10 * 2) +#define SIZE_MP2D_LB_PE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(frame_width, 16) >> 4) * 64) +#define SIZE_VP9D_LB_PE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) >> 6) * 176) +#define SIZE_MP2D_LB_VSP_TOP(frame_width, frame_height) \ + (((HFI_ALIGN(frame_width, 16) >> 4) * 64 / 2) + 256) +#define SIZE_VP9D_LB_VSP_TOP(frame_width, frame_height) \ + ((((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) >> 6) * 64 * 8) + 256)) + +#define HFI_IRIS2_VP9D_COMV_SIZE \ + ((((8192 + 63) >> 6) * ((4320 + 63) >> 6) * 8 * 8 * 2 * 8)) + +#define SIZE_VP9D_QP(frame_width, frame_height) \ + SIZE_H264D_QP(frame_width, frame_height) + +#define HFI_IRIS2_VP9D_LB_SIZE(_size, frame_width, frame_height, num_vpp_pipes)\ + do { \ + _size = HFI_ALIGN(SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_VP9D_LB_VSP_TOP(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VPXD_LB_FE_TOP_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + 2 * \ + HFI_ALIGN(SIZE_VPXD_LB_RECON_DMA_METADATA_WR \ + (frame_width, frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VP9D_LB_PE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VP9D_LB_FE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VP9D_QP(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define HFI_BUFFER_LINE_VP9D(_size, frame_width, frame_height, \ + _yuv_bufcount_min, is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 _lb_size = 0; \ + HFI_U32 vpss_lb_size = 0; \ + HFI_IRIS2_VP9D_LB_SIZE(_lb_size, frame_width, frame_height,\ + num_vpp_pipes); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \ + num_vpp_pipes); \ + } \ + _size = _lb_size + vpss_lb_size; \ + } while (0) + +#define VPX_DECODER_FRAME_CONCURENCY_LVL (2) +#define VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO 1 / 2 +#define VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO 3 / 2 + +#define HFI_BUFFER_BIN_VP9D(_size, frame_width, frame_height, \ + is_interlaced, num_vpp_pipes) \ + do { \ + HFI_U32 _size_yuv = HFI_ALIGN(frame_width, \ + BUFFER_ALIGNMENT_16_BYTES) *\ + HFI_ALIGN(frame_height, BUFFER_ALIGNMENT_16_BYTES) * 3 / 2; \ + if (!is_interlaced) { \ + _size = HFI_ALIGN(((MAX(_size_yuv, \ + ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * \ + VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO * \ + VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(((MAX(_size_yuv, \ + ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * \ + VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO * \ + VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), \ + VENUS_DMA_ALIGNMENT); \ + _size = _size * num_vpp_pipes; \ + } \ + else \ + _size = 0; \ + } while (0) + +#define VP9_NUM_FRAME_INFO_BUF 32 +#define VP9_NUM_PROBABILITY_TABLE_BUF (VP9_NUM_FRAME_INFO_BUF + 4) +#define VP9_PROB_TABLE_SIZE (3840) +#define VP9_FRAME_INFO_BUF_SIZE (6144) + +#define VP9_UDC_HEADER_BUF_SIZE (3 * 128) +#define MAX_SUPERFRAME_HEADER_LEN (34) +#define CCE_TILE_OFFSET_SIZE HFI_ALIGN(32 * 4 * 4, BUFFER_ALIGNMENT_32_BYTES) + +#define HFI_BUFFER_PERSIST_VP9D(_size) \ + (_size = HFI_ALIGN(VP9_NUM_PROBABILITY_TABLE_BUF * VP9_PROB_TABLE_SIZE, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(HFI_IRIS2_VP9D_COMV_SIZE, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(MAX_SUPERFRAME_HEADER_LEN, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(VP9_UDC_HEADER_BUF_SIZE, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(VP9_NUM_FRAME_INFO_BUF * \ + CCE_TILE_OFFSET_SIZE, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(VP9_NUM_FRAME_INFO_BUF * VP9_FRAME_INFO_BUF_SIZE, \ + VENUS_DMA_ALIGNMENT) + HDR10_HIST_EXTRADATA_SIZE) + +#define HFI_BUFFER_LINE_MP2D(_size, frame_width, frame_height, \ +_yuv_bufcount_min, is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_lb_size = 0; \ + _size = HFI_ALIGN(SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_MP2D_LB_VSP_TOP(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(SIZE_VPXD_LB_FE_TOP_CTRL\ + (frame_width, frame_height), VENUS_DMA_ALIGNMENT) + \ + 2 * HFI_ALIGN(SIZE_VPXD_LB_RECON_DMA_METADATA_WR(frame_width,\ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_MP2D_LB_PE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_MP2D_LB_FE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \ + num_vpp_pipes); \ + } \ + _size += vpss_lb_size; \ + } while (0) + +#define HFI_BUFFER_BIN_MP2D(_size, frame_width, frame_height, is_interlaced) 0 + +#define QMATRIX_SIZE (sizeof(HFI_U32) * 128 + 256) +#define MP2D_QPDUMP_SIZE 115200 +#define HFI_BUFFER_PERSIST_MP2D(_size) \ + (_size = QMATRIX_SIZE + MP2D_QPDUMP_SIZE;) + +#define HFI_BUFFER_BITSTREAM_ENC(size, frame_width, frame_height, \ + rc_type, is_ten_bit) \ + do { \ + HFI_U32 aligned_width, aligned_height, bitstream_size; \ + aligned_width = HFI_ALIGN(frame_width, 32); \ + aligned_height = HFI_ALIGN(frame_height, 32); \ + bitstream_size = aligned_width * aligned_height * 3; \ + if (aligned_width * aligned_height > (4096 * 2176)) { \ + bitstream_size = (bitstream_size >> 3); \ + } \ + else if (bitstream_size > (1280 * 720)) { \ + bitstream_size = (bitstream_size >> 2); \ + } else { \ + bitstream_size = (bitstream_size << 1);\ + } \ + if ((rc_type == HFI_RC_CQ) || (rc_type == HFI_RC_OFF)) { \ + bitstream_size = (bitstream_size << 1);\ + } \ + if (is_ten_bit) { \ + bitstream_size = (bitstream_size) + \ + (bitstream_size >> 2); \ + } \ + size = HFI_ALIGN(bitstream_size, HFI_ALIGNMENT_4096); \ + } while (0) + +#define SIZE_ROI_METADATA_ENC(size_roi, frame_width, frame_height, lcu_size)\ + do { \ + HFI_U32 width_in_lcus = 0, height_in_lcus = 0, n_shift = 0; \ + HFI_U32 n_lcu_size = lcu_size; \ + while (n_lcu_size && !(n_lcu_size & 0x1)) { \ + n_shift++; \ + n_lcu_size = n_lcu_size >> 1; \ + } \ + width_in_lcus = (frame_width + (lcu_size - 1)) >> n_shift; \ + height_in_lcus = (frame_height + (lcu_size - 1)) >> n_shift; \ + size_roi = (((width_in_lcus + 7) >> 3) << 3) * \ + height_in_lcus * 2 + 256; \ + } while (0) + +#define HFI_BUFFER_INPUT_METADATA_ENC(size, frame_width, frame_height, \ + is_roi_enabled, lcu_size) \ + do { \ + HFI_U32 roi_size = 0; \ + if (is_roi_enabled) { \ + SIZE_ROI_METADATA_ENC(roi_size, frame_width, \ + frame_height, lcu_size); \ + } \ + size = roi_size + 16384; \ + size = HFI_ALIGN(size, HFI_ALIGNMENT_4096); \ + } while (0) + +#define HFI_BUFFER_INPUT_METADATA_H264E(size_metadata, frame_width, \ + frame_height, is_roi_enabled) \ + do { \ + HFI_BUFFER_INPUT_METADATA_ENC(size_metadata, frame_width, \ + frame_height, is_roi_enabled, 16); \ + } while (0) + +#define HFI_BUFFER_INPUT_METADATA_H265E(size_metadata, frame_width, \ + frame_height, is_roi_enabled) \ + do { \ + HFI_BUFFER_INPUT_METADATA_ENC(size_metadata, frame_width, \ + frame_height, is_roi_enabled, 32); \ + } while (0) + +#define HFI_BUFFER_ARP_ENC(size) \ + do { \ + size = 204800; \ + } while (0) + +#define HFI_MAX_COL_FRAME 6 +#define HFI_VENUS_VENC_TRE_WB_BUFF_SIZE (65 << 4) // bytes +#define HFI_VENUS_VENC_DB_LINE_BUFF_PER_MB 512 +#define HFI_VENUS_VPPSG_MAX_REGISTERS 2048 +#define HFI_VENUS_WIDTH_ALIGNMENT 128 +#define HFI_VENUS_WIDTH_TEN_BIT_ALIGNMENT 192 +#define HFI_VENUS_HEIGHT_ALIGNMENT 32 +#define VENUS_METADATA_STRIDE_MULTIPLE 64 +#define VENUS_METADATA_HEIGHT_MULTIPLE 16 + +#ifndef SYSTEM_LAL_TILE10 +#define SYSTEM_LAL_TILE10 192 +#endif + +#define HFI_IRIS2_ENC_RECON_BUF_COUNT(num_recon, n_bframe, ltr_count, \ + _total_hp_layers, _total_hb_layers, hybrid_hp, codec_standard) \ + do { \ + HFI_U32 num_ref = 1; \ + if (n_bframe) \ + num_ref = 2; \ + if (_total_hp_layers > 1) { \ + if (hybrid_hp) \ + num_ref = (_total_hp_layers + 1) >> 1; \ + else if (codec_standard == HFI_CODEC_ENCODE_HEVC) \ + num_ref = (_total_hp_layers + 1) >> 1; \ + else if (codec_standard == HFI_CODEC_ENCODE_AVC && \ + _total_hp_layers < 4) \ + num_ref = (_total_hp_layers - 1); \ + else \ + num_ref = _total_hp_layers; \ + } \ + if (ltr_count) \ + num_ref = num_ref + ltr_count; \ + if (_total_hb_layers > 1) { \ + if (codec_standard == HFI_CODEC_ENCODE_HEVC) \ + num_ref = (_total_hb_layers); \ + else if (codec_standard == HFI_CODEC_ENCODE_AVC) \ + num_ref = (1 << (_total_hb_layers - 2)) + 1; \ + } \ + num_recon = num_ref + 1; \ + } while (0) + +#define SIZE_BIN_BITSTREAM_ENC(_size, rc_type, frame_width, frame_height, \ + work_mode, lcu_size) \ + do { \ + HFI_U32 size_aligned_width = 0, size_aligned_height = 0; \ + HFI_U32 bitstream_size_eval = 0; \ + size_aligned_width = HFI_ALIGN((frame_width), lcu_size); \ + size_aligned_height = HFI_ALIGN((frame_height), lcu_size); \ + if (work_mode == HFI_WORKMODE_2) { \ + if ((rc_type == HFI_RC_CQ) || (rc_type == HFI_RC_OFF)) { \ + bitstream_size_eval = (((size_aligned_width) * \ + (size_aligned_height) * 3) >> 1); \ + } \ + else { \ + bitstream_size_eval = ((size_aligned_width) * \ + (size_aligned_height) * 3); \ + if (rc_type == HFI_RC_LOSSLESS) { \ + bitstream_size_eval = (bitstream_size_eval * 3 >> 2); \ + } \ + else if ((size_aligned_width * size_aligned_height) > \ + (4096 * 2176)) { \ + bitstream_size_eval >>= 3; \ + } \ + else if ((size_aligned_width * size_aligned_height) > \ + (480 * 320)) { \ + bitstream_size_eval >>= 2; \ + } \ + if (lcu_size == 32) { \ + bitstream_size_eval = (bitstream_size_eval * 5 >> 2); \ + } \ + } \ + } else { \ + bitstream_size_eval = size_aligned_width * \ + size_aligned_height * 3; \ + } \ + _size = HFI_ALIGN(bitstream_size_eval, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_ENC_SINGLE_PIPE(size, rc_type, bitbin_size, num_vpp_pipes, \ + frame_width, frame_height, lcu_size) \ + do { \ + HFI_U32 size_single_pipe_eval = 0, sao_bin_buffer_size = 0, \ + _padded_bin_sz = 0; \ + HFI_U32 size_aligned_width = 0, size_aligned_height = 0; \ + size_aligned_width = HFI_ALIGN((frame_width), lcu_size); \ + size_aligned_height = HFI_ALIGN((frame_height), lcu_size); \ + if ((size_aligned_width * size_aligned_height) > \ + (3840 * 2160)) { \ + size_single_pipe_eval = (bitbin_size / num_vpp_pipes); \ + } \ + else if (num_vpp_pipes > 2) { \ + size_single_pipe_eval = bitbin_size / 2; \ + } else { \ + size_single_pipe_eval = bitbin_size; \ + } \ + if (rc_type == HFI_RC_LOSSLESS) { \ + size_single_pipe_eval = (size_single_pipe_eval << 1); \ + } \ + sao_bin_buffer_size = (64 * ((((frame_width) + \ + BUFFER_ALIGNMENT_32_BYTES) * ((frame_height) +\ + BUFFER_ALIGNMENT_32_BYTES)) >> 10)) + 384; \ + _padded_bin_sz = HFI_ALIGN(size_single_pipe_eval, \ + VENUS_DMA_ALIGNMENT);\ + size_single_pipe_eval = sao_bin_buffer_size + _padded_bin_sz; \ + size_single_pipe_eval = HFI_ALIGN(size_single_pipe_eval, \ + VENUS_DMA_ALIGNMENT); \ + size = size_single_pipe_eval; \ + } while (0) + +#define HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, lcu_size, \ + work_mode, num_vpp_pipes) \ + do { \ + HFI_U32 bitstream_size = 0, total_bitbin_buffers = 0, \ + size_single_pipe = 0, bitbin_size = 0; \ + SIZE_BIN_BITSTREAM_ENC(bitstream_size, rc_type, frame_width, \ + frame_height, work_mode, lcu_size); \ + if (work_mode == HFI_WORKMODE_2) { \ + total_bitbin_buffers = 3; \ + bitbin_size = bitstream_size * 17 / 10; \ + bitbin_size = HFI_ALIGN(bitbin_size, \ + VENUS_DMA_ALIGNMENT); \ + } \ + else if ((lcu_size == 16) || (num_vpp_pipes > 1)) { \ + total_bitbin_buffers = 1; \ + bitbin_size = bitstream_size; \ + } \ + if (total_bitbin_buffers > 0) { \ + SIZE_ENC_SINGLE_PIPE(size_single_pipe, rc_type, bitbin_size, \ + num_vpp_pipes, frame_width, frame_height, lcu_size); \ + bitbin_size = size_single_pipe * num_vpp_pipes; \ + _size = HFI_ALIGN(bitbin_size, VENUS_DMA_ALIGNMENT) * \ + total_bitbin_buffers + 512; \ + } else { \ + /* Avoid 512 Bytes allocation in case of 1Pipe HEVC Direct Mode*/ \ + _size = 0; \ + } \ + } while (0) + +#define HFI_BUFFER_BIN_H264E(_size, rc_type, frame_width, frame_height, \ + work_mode, num_vpp_pipes) \ + do { \ + HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, 16, \ + work_mode, num_vpp_pipes); \ + } while (0) + +#define HFI_BUFFER_BIN_H265E(_size, rc_type, frame_width, frame_height, \ + work_mode, num_vpp_pipes) \ + do { \ + HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, 32,\ + work_mode, num_vpp_pipes); \ + } while (0) + +#define SIZE_ENC_SLICE_INFO_BUF(num_lcu_in_frame) HFI_ALIGN((256 + \ + (num_lcu_in_frame << 4)), VENUS_DMA_ALIGNMENT) +#define SIZE_LINE_BUF_CTRL(frame_width_coded) \ + HFI_ALIGN(frame_width_coded, VENUS_DMA_ALIGNMENT) +#define SIZE_LINE_BUF_CTRL_ID2(frame_width_coded) \ + HFI_ALIGN(frame_width_coded, VENUS_DMA_ALIGNMENT) + +#define SIZE_LINEBUFF_DATA(_size, is_ten_bit, frame_width_coded) \ + do { \ + _size = is_ten_bit ? (((((10 * (frame_width_coded) +\ + 1024) + (VENUS_DMA_ALIGNMENT - 1)) & \ + (~(VENUS_DMA_ALIGNMENT - 1))) * 1) + \ + (((((10 * (frame_width_coded) + 1024) >> 1) + \ + (VENUS_DMA_ALIGNMENT - 1)) & (~(VENUS_DMA_ALIGNMENT - 1))) * \ + 2)) : (((((8 * (frame_width_coded) + 1024) + \ + (VENUS_DMA_ALIGNMENT - 1)) \ + & (~(VENUS_DMA_ALIGNMENT - 1))) * 1) + \ + (((((8 * (frame_width_coded) +\ + 1024) >> 1) + (VENUS_DMA_ALIGNMENT - 1)) & \ + (~(VENUS_DMA_ALIGNMENT - 1))) * 2)); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_CTRL(_size, standard, frame_height_coded, \ + num_vpp_pipes_enc) \ + do { \ + _size = (standard == HFI_CODEC_ENCODE_HEVC) ? \ + (((frame_height_coded) + \ + (BUF_SIZE_ALIGN_32)) / BUF_SIZE_ALIGN_32 * 4 * 16) : \ + (((frame_height_coded) + 15) / 16 * 5 * 16); \ + if ((num_vpp_pipes_enc) > 1) { \ + _size += BUFFER_ALIGNMENT_512_BYTES; \ + _size = HFI_ALIGN(_size, BUFFER_ALIGNMENT_512_BYTES) *\ + (num_vpp_pipes_enc); \ + } \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_RECON_PIX(_size, is_ten_bit, frame_height_coded, \ + num_vpp_pipes_enc) \ + do { \ + _size = (((is_ten_bit + 1) * 2 * (frame_height_coded) + \ + VENUS_DMA_ALIGNMENT) + \ + (VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1) & \ + (~((VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1)) * 1; \ + } while (0) + +#define SIZE_TOP_LINEBUFF_CTRL_FE(_size, frame_width_coded, standard) \ + do { \ + _size = (standard == HFI_CODEC_ENCODE_HEVC) ? (64 * \ + ((frame_width_coded) >> 5)) : (VENUS_DMA_ALIGNMENT + 16 * \ + ((frame_width_coded) >> 4)); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_CTRL_FE(frame_height_coded, num_vpp_pipes_enc) \ + ((((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) >> 4)) + \ + (VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1) & \ + (~((VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1)) * 1) * \ + num_vpp_pipes_enc) + +#define SIZE_LEFT_LINEBUFF_METADATA_RECON_Y(_size, frame_height_coded, \ + is_ten_bit, num_vpp_pipes_enc) \ + do { \ + _size = ((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) / \ + (8 * (is_ten_bit ? 4 : 8))))); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + _size = (_size * num_vpp_pipes_enc); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_METADATA_RECON_UV(_size, frame_height_coded, \ + is_ten_bit, num_vpp_pipes_enc) \ + do { \ + _size = ((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) / \ + (4 * (is_ten_bit ? 4 : 8))))); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + _size = (_size * num_vpp_pipes_enc); \ + } while (0) + +#define SIZE_LINEBUFF_RECON_PIX(_size, is_ten_bit, frame_width_coded) \ + do { \ + _size = ((is_ten_bit ? 3 : 2) * (frame_width_coded)); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_SLICE_CMD_BUFFER (HFI_ALIGN(20480, VENUS_DMA_ALIGNMENT)) +#define SIZE_SPS_PPS_SLICE_HDR (2048 + 4096) + +#define SIZE_FRAME_RC_BUF_SIZE(_size, standard, frame_height_coded, \ + num_vpp_pipes_enc) \ + do { \ + _size = (standard == HFI_CODEC_ENCODE_HEVC) ? (256 + 16 * \ + (14 + ((((frame_height_coded) >> 5) + 7) >> 3))) : \ + (256 + 16 * (14 + ((((frame_height_coded) >> 4) + 7) >> 3))); \ + _size *= 11; \ + if (num_vpp_pipes_enc > 1) { \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT) * \ + num_vpp_pipes_enc;\ + } \ + _size = HFI_ALIGN(_size, BUFFER_ALIGNMENT_512_BYTES) * \ + HFI_MAX_COL_FRAME; \ + } while (0) + +#define ENC_BITCNT_BUF_SIZE(num_lcu_in_frame) HFI_ALIGN((256 + \ + (4 * (num_lcu_in_frame))), VENUS_DMA_ALIGNMENT) +#define ENC_BITMAP_BUF_SIZE(num_lcu_in_frame) HFI_ALIGN((256 + \ + ((num_lcu_in_frame) >> 3)), VENUS_DMA_ALIGNMENT) +#define SIZE_LINE_BUF_SDE(frame_width_coded) HFI_ALIGN((256 + \ + (16 * ((frame_width_coded) >> 4))), VENUS_DMA_ALIGNMENT) + +#define SIZE_BSE_SLICE_CMD_BUF ((((8192 << 2) + 7) & (~7)) * 3) + +#define SIZE_LAMBDA_LUT (256 * 11) +#define SIZE_OVERRIDE_BUF(num_lcumb) (HFI_ALIGN(((16 * (((num_lcumb) + 7)\ + >> 3))), VENUS_DMA_ALIGNMENT) * 2) +#define SIZE_IR_BUF(num_lcu_in_frame) HFI_ALIGN((((((num_lcu_in_frame) << 1) + 7) &\ + (~7)) * 3), VENUS_DMA_ALIGNMENT) + +#define SIZE_VPSS_LINE_BUF(num_vpp_pipes_enc, frame_height_coded, \ + frame_width_coded) \ + (HFI_ALIGN(((((((8192) >> 2) << 5) * (num_vpp_pipes_enc)) + 64) + \ + (((((MAX((frame_width_coded), (frame_height_coded)) + 3) >> 2) << 5) +\ + 256) * 16)), VENUS_DMA_ALIGNMENT)) + +#define SIZE_TOP_LINE_BUF_FIRST_STG_SAO(frame_width_coded) \ + HFI_ALIGN((16 * ((frame_width_coded) >> 5)), VENUS_DMA_ALIGNMENT) + +#define HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, is_ten_bit, \ + num_vpp_pipes_enc, lcu_size, standard) \ + do { \ + HFI_U32 width_in_lcus = 0, height_in_lcus = 0, \ + frame_width_coded = 0, frame_height_coded = 0; \ + HFI_U32 line_buff_data_size = 0, left_line_buff_ctrl_size = 0, \ + left_line_buff_recon_pix_size = 0, \ + top_line_buff_ctrl_fe_size = 0; \ + HFI_U32 left_line_buff_metadata_recon__y__size = 0, \ + left_line_buff_metadata_recon__uv__size = 0, \ + line_buff_recon_pix_size = 0; \ + width_in_lcus = ((frame_width) + (lcu_size)-1) / (lcu_size); \ + height_in_lcus = ((frame_height) + (lcu_size)-1) / (lcu_size); \ + frame_width_coded = width_in_lcus * (lcu_size); \ + frame_height_coded = height_in_lcus * (lcu_size); \ + SIZE_LINEBUFF_DATA(line_buff_data_size, is_ten_bit, \ + frame_width_coded);\ + SIZE_LEFT_LINEBUFF_CTRL(left_line_buff_ctrl_size, standard, \ + frame_height_coded, num_vpp_pipes_enc); \ + SIZE_LEFT_LINEBUFF_RECON_PIX(left_line_buff_recon_pix_size, \ + is_ten_bit, frame_height_coded, num_vpp_pipes_enc); \ + SIZE_TOP_LINEBUFF_CTRL_FE(top_line_buff_ctrl_fe_size, \ + frame_width_coded, standard); \ + SIZE_LEFT_LINEBUFF_METADATA_RECON_Y\ + (left_line_buff_metadata_recon__y__size, \ + frame_height_coded, is_ten_bit, num_vpp_pipes_enc); \ + SIZE_LEFT_LINEBUFF_METADATA_RECON_UV\ + (left_line_buff_metadata_recon__uv__size, \ + frame_height_coded, is_ten_bit, num_vpp_pipes_enc); \ + SIZE_LINEBUFF_RECON_PIX(line_buff_recon_pix_size, is_ten_bit,\ + frame_width_coded); \ + _size = SIZE_LINE_BUF_CTRL(frame_width_coded) + \ + SIZE_LINE_BUF_CTRL_ID2(frame_width_coded) + \ + line_buff_data_size + \ + left_line_buff_ctrl_size + \ + left_line_buff_recon_pix_size + \ + top_line_buff_ctrl_fe_size + \ + left_line_buff_metadata_recon__y__size + \ + left_line_buff_metadata_recon__uv__size + \ + line_buff_recon_pix_size + \ + SIZE_LEFT_LINEBUFF_CTRL_FE(frame_height_coded, \ + num_vpp_pipes_enc) + SIZE_LINE_BUF_SDE(frame_width_coded) + \ + SIZE_VPSS_LINE_BUF(num_vpp_pipes_enc, frame_height_coded, \ + frame_width_coded) + \ + SIZE_TOP_LINE_BUF_FIRST_STG_SAO(frame_width_coded); \ + } while (0) + +#define HFI_BUFFER_LINE_H264E(_size, frame_width, frame_height, is_ten_bit, \ + num_vpp_pipes) \ + do { \ + HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, 0, \ + num_vpp_pipes, 16, HFI_CODEC_ENCODE_AVC); \ + } while (0) + +#define HFI_BUFFER_LINE_H265E(_size, frame_width, frame_height, is_ten_bit, \ + num_vpp_pipes) \ + do { \ + HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, \ + is_ten_bit, num_vpp_pipes, 32, HFI_CODEC_ENCODE_HEVC); \ + } while (0) + +#define HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, lcu_size, \ + num_recon, standard) \ + do { \ + HFI_U32 size_colloc_mv = 0, size_colloc_rc = 0; \ + HFI_U32 mb_width = ((frame_width) + 15) >> 4; \ + HFI_U32 mb_height = ((frame_height) + 15) >> 4; \ + HFI_U32 width_in_lcus = ((frame_width) + (lcu_size)-1) /\ + (lcu_size); \ + HFI_U32 height_in_lcus = ((frame_height) + (lcu_size)-1) / \ + (lcu_size); \ + HFI_U32 num_lcu_in_frame = width_in_lcus * height_in_lcus; \ + size_colloc_mv = (standard == HFI_CODEC_ENCODE_HEVC) ? \ + (16 * ((num_lcu_in_frame << 2) + BUFFER_ALIGNMENT_32_BYTES)) : \ + (3 * 16 * (width_in_lcus * height_in_lcus +\ + BUFFER_ALIGNMENT_32_BYTES)); \ + size_colloc_mv = HFI_ALIGN(size_colloc_mv, \ + VENUS_DMA_ALIGNMENT) * num_recon; \ + size_colloc_rc = (((mb_width + 7) >> 3) * 16 * 2 * mb_height); \ + size_colloc_rc = HFI_ALIGN(size_colloc_rc, \ + VENUS_DMA_ALIGNMENT) * HFI_MAX_COL_FRAME; \ + _size = size_colloc_mv + size_colloc_rc; \ + } while (0) + +#define HFI_BUFFER_COMV_H264E(_size, frame_width, frame_height, num_recon) \ + do { \ + HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, 16, \ + num_recon, HFI_CODEC_ENCODE_AVC); \ + } while (0) + +#define HFI_BUFFER_COMV_H265E(_size, frame_width, frame_height, num_recon) \ + do { \ + HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, 32,\ + num_recon, HFI_CODEC_ENCODE_HEVC); \ + } while (0) + +#define HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \ + num_vpp_pipes_enc, lcu_size, standard) \ + do { \ + HFI_U32 width_in_lcus = 0, height_in_lcus = 0, \ + frame_width_coded = 0, frame_height_coded = 0, \ + num_lcu_in_frame = 0, num_lcumb = 0; \ + HFI_U32 frame_rc_buf_size = 0; \ + width_in_lcus = ((frame_width) + (lcu_size)-1) / (lcu_size); \ + height_in_lcus = ((frame_height) + (lcu_size)-1) / (lcu_size); \ + num_lcu_in_frame = width_in_lcus * height_in_lcus; \ + frame_width_coded = width_in_lcus * (lcu_size); \ + frame_height_coded = height_in_lcus * (lcu_size); \ + num_lcumb = (frame_height_coded / lcu_size) * \ + ((frame_width_coded + lcu_size * 8) / lcu_size); \ + SIZE_FRAME_RC_BUF_SIZE(frame_rc_buf_size, standard, \ + frame_height_coded, num_vpp_pipes_enc); \ + _size = SIZE_ENC_SLICE_INFO_BUF(num_lcu_in_frame) + \ + SIZE_SLICE_CMD_BUFFER + \ + SIZE_SPS_PPS_SLICE_HDR + \ + frame_rc_buf_size + \ + ENC_BITCNT_BUF_SIZE(num_lcu_in_frame) + \ + ENC_BITMAP_BUF_SIZE(num_lcu_in_frame) + \ + SIZE_BSE_SLICE_CMD_BUF + \ + SIZE_LAMBDA_LUT + \ + SIZE_OVERRIDE_BUF(num_lcumb) + \ + SIZE_IR_BUF(num_lcu_in_frame); \ + } while (0) + +#define HFI_BUFFER_NON_COMV_H264E(_size, frame_width, frame_height, \ + num_vpp_pipes_enc) \ + do { \ + HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \ + num_vpp_pipes_enc, 16, HFI_CODEC_ENCODE_AVC); \ + } while (0) + +#define HFI_BUFFER_NON_COMV_H265E(_size, frame_width, frame_height, \ + num_vpp_pipes_enc) \ + do { \ + HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \ + num_vpp_pipes_enc, 32, HFI_CODEC_ENCODE_HEVC); \ + } while (0) + +#define SIZE_ENC_REF_BUFFER(size, frame_width, frame_height) \ + do { \ + HFI_U32 u_buffer_width = 0, u_buffer_height = 0, \ + u_chroma_buffer_height = 0; \ + u_buffer_height = HFI_ALIGN(frame_height, \ + HFI_VENUS_HEIGHT_ALIGNMENT); \ + u_chroma_buffer_height = frame_height >> 1; \ + u_chroma_buffer_height = HFI_ALIGN(u_chroma_buffer_height, \ + HFI_VENUS_HEIGHT_ALIGNMENT); \ + u_buffer_width = HFI_ALIGN(frame_width, \ + HFI_VENUS_WIDTH_ALIGNMENT); \ + size = (u_buffer_height + u_chroma_buffer_height) * \ + u_buffer_width; \ + } while (0) + +#define SIZE_ENC_TEN_BIT_REF_BUFFER(size, frame_width, frame_height) \ + do { \ + HFI_U32 ref_buf_height = 0, ref_luma_stride_in_bytes = 0, \ + u_ref_stride = 0, luma_size = 0, ref_chrm_height_in_bytes = 0, \ + chroma_size = 0, ref_buf_size = 0; \ + ref_buf_height = (frame_height + \ + (HFI_VENUS_HEIGHT_ALIGNMENT - 1)) \ + & (~(HFI_VENUS_HEIGHT_ALIGNMENT - 1)); \ + ref_luma_stride_in_bytes = ((frame_width + \ + SYSTEM_LAL_TILE10 - 1) / SYSTEM_LAL_TILE10) * \ + SYSTEM_LAL_TILE10; \ + u_ref_stride = 4 * (ref_luma_stride_in_bytes / 3); \ + u_ref_stride = (u_ref_stride + (BUF_SIZE_ALIGN_128 - 1)) &\ + (~(BUF_SIZE_ALIGN_128 - 1)); \ + luma_size = ref_buf_height * u_ref_stride; \ + ref_chrm_height_in_bytes = (((frame_height + 1) >> 1) + \ + (BUF_SIZE_ALIGN_32 - 1)) & (~(BUF_SIZE_ALIGN_32 - 1)); \ + chroma_size = u_ref_stride * ref_chrm_height_in_bytes; \ + luma_size = (luma_size + (BUF_SIZE_ALIGN_4096 - 1)) & \ + (~(BUF_SIZE_ALIGN_4096 - 1)); \ + chroma_size = (chroma_size + (BUF_SIZE_ALIGN_4096 - 1)) & \ + (~(BUF_SIZE_ALIGN_4096 - 1)); \ + ref_buf_size = luma_size + chroma_size; \ + size = ref_buf_size; \ + } while (0) + +#define HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, is_ten_bit) \ + do { \ + HFI_U32 metadata_stride, metadata_buf_height, meta_size_y, \ + meta_size_c; \ + HFI_U32 ten_bit_ref_buf_size = 0, ref_buf_size = 0; \ + if (!is_ten_bit) { \ + SIZE_ENC_REF_BUFFER(ref_buf_size, frame_width, \ + frame_height); \ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, \ + (frame_width), 64, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH); \ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, \ + (frame_height), 16, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_y, \ + metadata_stride, metadata_buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_c, \ + metadata_stride, metadata_buf_height); \ + _size = ref_buf_size + meta_size_y + meta_size_c; \ + } else { \ + SIZE_ENC_TEN_BIT_REF_BUFFER(ten_bit_ref_buf_size, \ + frame_width, frame_height); \ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, \ + frame_width, VENUS_METADATA_STRIDE_MULTIPLE, \ + HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH); \ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, \ + frame_height, VENUS_METADATA_HEIGHT_MULTIPLE, \ + HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_y, \ + metadata_stride, metadata_buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_c, \ + metadata_stride, metadata_buf_height); \ + _size = ten_bit_ref_buf_size + meta_size_y + \ + meta_size_c; \ + } \ + } while (0) + +#define HFI_BUFFER_DPB_H264E(_size, frame_width, frame_height) \ + do { \ + HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, 0); \ + } while (0) + +#define HFI_BUFFER_DPB_H265E(_size, frame_width, frame_height, is_ten_bit) \ + do { \ + HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, is_ten_bit); \ + } while (0) + +#define HFI_BUFFER_VPSS_ENC(vpss_size, dswidth, dsheight, ds_enable, blur, is_ten_bit) \ + do { \ + vpss_size = 0; \ + if (ds_enable || blur) { \ + HFI_BUFFER_DPB_ENC(vpss_size, dswidth, dsheight, is_ten_bit); \ + } \ + } while (0) + +#define HFI_IRIS2_ENC_MIN_INPUT_BUF_COUNT(numInput, TotalHBLayers) \ + do { \ + numInput = 3; \ + if (TotalHBLayers >= 2) { \ + numInput = (1 << (TotalHBLayers - 1)) + 2; \ + } \ + } while (0) + +#endif /* __HFI_BUFFER_IRIS2__ */ diff --git a/qcom/opensource/video-driver/driver/variant/iris2/inc/msm_vidc_buffer_iris2.h b/qcom/opensource/video-driver/driver/variant/iris2/inc/msm_vidc_buffer_iris2.h new file mode 100644 index 0000000000..459b6a9cd7 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris2/inc/msm_vidc_buffer_iris2.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __H_MSM_VIDC_BUFFER_IRIS2_H__ +#define __H_MSM_VIDC_BUFFER_IRIS2_H__ + +#include "msm_vidc_inst.h" + +int msm_buffer_size_iris2(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +int msm_buffer_min_count_iris2(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +int msm_buffer_extra_count_iris2(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); + +#endif // __H_MSM_VIDC_BUFFER_IRIS2_H__ diff --git a/qcom/opensource/video-driver/driver/variant/iris2/inc/msm_vidc_iris2.h b/qcom/opensource/video-driver/driver/variant/iris2/inc/msm_vidc_iris2.h new file mode 100644 index 0000000000..11b8008415 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris2/inc/msm_vidc_iris2.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_IRIS2_H_ +#define _MSM_VIDC_IRIS2_H_ + +#include "msm_vidc_core.h" + +#if defined(CONFIG_MSM_VIDC_VOLCANO) +int msm_vidc_init_iris2(struct msm_vidc_core *core); +int msm_vidc_adjust_blur_type_iris2(void *instance, struct v4l2_ctrl *ctrl); +#else +static inline int msm_vidc_init_iris2(struct msm_vidc_core *core) +{ + return -EINVAL; +} + +static inline int msm_vidc_adjust_blur_type_iris2(void *instance, struct v4l2_ctrl *ctrl) +{ + return -EINVAL; +} +#endif + +#endif // _MSM_VIDC_IRIS2_H_ diff --git a/qcom/opensource/video-driver/driver/variant/iris2/inc/msm_vidc_power_iris2.h b/qcom/opensource/video-driver/driver/variant/iris2/inc/msm_vidc_power_iris2.h new file mode 100644 index 0000000000..28c6ae3180 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris2/inc/msm_vidc_power_iris2.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __H_MSM_VIDC_POWER_IRIS2_H__ +#define __H_MSM_VIDC_POWER_IRIS2_H__ + +#include "msm_vidc_inst.h" +#include "msm_vidc_power.h" + +u64 msm_vidc_calc_freq_iris2(struct msm_vidc_inst *inst, u32 data_size); +int msm_vidc_calc_bw_iris2(struct msm_vidc_inst *inst, + struct vidc_bus_vote_data *vote_data); + +#endif diff --git a/qcom/opensource/video-driver/driver/variant/iris2/src/msm_vidc_buffer_iris2.c b/qcom/opensource/video-driver/driver/variant/iris2/src/msm_vidc_buffer_iris2.c new file mode 100644 index 0000000000..f54764c11e --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris2/src/msm_vidc_buffer_iris2.c @@ -0,0 +1,582 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "hfi_property.h" +#include "hfi_buffer_iris2.h" +#include "msm_vidc_buffer_iris2.h" +#include "msm_vidc_buffer.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" +#include "msm_vidc_driver.h" +#include "msm_media_info.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" + +static u32 msm_vidc_decoder_bin_size_iris2(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, num_vpp_pipes; + struct v4l2_format *f; + bool is_interlaced; + u32 vpp_delay; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + if (inst->decode_vpp_delay.enable) + vpp_delay = inst->decode_vpp_delay.size; + else + vpp_delay = DEFAULT_BSE_VPP_DELAY; + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_PROGRESSIVE) + is_interlaced = false; + else + is_interlaced = true; + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_BIN_H264D(size, width, height, + is_interlaced, vpp_delay, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_BIN_H265D(size, width, height, + 0, vpp_delay, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_VP9) + HFI_BUFFER_BIN_VP9D(size, width, height, + 0, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_comv_size_iris2(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, out_min_count, vpp_delay; + struct v4l2_format *f; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + if (inst->decode_vpp_delay.enable) + vpp_delay = inst->decode_vpp_delay.size; + else + vpp_delay = DEFAULT_BSE_VPP_DELAY; + out_min_count = inst->buffers.output.min_count; + out_min_count = max(vpp_delay + 1, out_min_count); + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_COMV_H264D(size, width, height, out_min_count); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_COMV_H265D(size, width, height, out_min_count); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_non_comv_size_iris2(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, num_vpp_pipes; + struct msm_vidc_core *core; + struct v4l2_format *f; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_NON_COMV_H264D(size, width, height, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_NON_COMV_H265D(size, width, height, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_line_size_iris2(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, out_min_count, num_vpp_pipes, vpp_delay; + struct v4l2_format *f; + bool is_opb; + u32 color_fmt; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + + color_fmt = v4l2_colorformat_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, __func__); + if (is_linear_colorformat(color_fmt)) + is_opb = true; + else + is_opb = false; + /* + * assume worst case, since color format is unknown at this + * time + */ + is_opb = true; + + if (inst->decode_vpp_delay.enable) + vpp_delay = inst->decode_vpp_delay.size; + else + vpp_delay = DEFAULT_BSE_VPP_DELAY; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + out_min_count = inst->buffers.output.min_count; + out_min_count = max(vpp_delay + 1, out_min_count); + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_LINE_H264D(size, width, height, is_opb, + num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_LINE_H265D(size, width, height, is_opb, + num_vpp_pipes); + else if (inst->codec == MSM_VIDC_VP9) + HFI_BUFFER_LINE_VP9D(size, width, height, out_min_count, + is_opb, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_persist_size_iris2(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 rpu_enabled = 0; + + if (inst->capabilities[META_DOLBY_RPU].value) + rpu_enabled = 1; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_PERSIST_H264D(size, rpu_enabled); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_PERSIST_H265D(size, rpu_enabled); + else if (inst->codec == MSM_VIDC_VP9) + HFI_BUFFER_PERSIST_VP9D(size); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_dpb_size_iris2(struct msm_vidc_inst *inst) +{ + + u32 color_fmt, width, height, size = 0; + struct v4l2_format *f; + + color_fmt = inst->capabilities[PIX_FMTS].value; + if (!is_linear_colorformat(color_fmt)) + return size; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (color_fmt == MSM_VIDC_FMT_NV12) { + color_fmt = MSM_VIDC_FMT_NV12C; + HFI_NV12_UBWC_IL_CALC_BUF_SIZE_V2(size, width, height, + video_y_stride_bytes(color_fmt, width), + video_y_scanlines(color_fmt, height), + video_uv_stride_bytes(color_fmt, width), + video_uv_scanlines(color_fmt, height), + video_y_meta_stride(color_fmt, width), + video_y_meta_scanlines(color_fmt, height), + video_uv_meta_stride(color_fmt, width), + video_uv_meta_scanlines(color_fmt, height)); + } else if (color_fmt == MSM_VIDC_FMT_P010) { + color_fmt = MSM_VIDC_FMT_TP10C; + HFI_YUV420_TP10_UBWC_CALC_BUF_SIZE(size, + video_y_stride_bytes(color_fmt, width), + video_y_scanlines(color_fmt, height), + video_uv_stride_bytes(color_fmt, width), + video_uv_scanlines(color_fmt, height), + video_y_meta_stride(color_fmt, width), + video_y_meta_scanlines(color_fmt, height), + video_uv_meta_stride(color_fmt, width), + video_uv_meta_scanlines(color_fmt, height)); + } + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +/* encoder internal buffers */ +static u32 msm_vidc_encoder_bin_size_iris2(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, num_vpp_pipes, stage; + struct v4l2_format *f; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + stage = inst->capabilities[STAGE].value; + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_BIN_H264E(size, inst->hfi_rc_type, width, + height, stage, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_BIN_H265E(size, inst->hfi_rc_type, width, + height, stage, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_get_recon_buf_count(struct msm_vidc_inst *inst) +{ + u32 num_buf_recon = 0; + s32 n_bframe, ltr_count, hp_layers = 0, hb_layers = 0; + bool is_hybrid_hp = false; + u32 hfi_codec = 0; + + n_bframe = inst->capabilities[B_FRAME].value; + ltr_count = inst->capabilities[LTR_COUNT].value; + + if (inst->hfi_layer_type == HFI_HIER_B) { + hb_layers = inst->capabilities[ENH_LAYER_COUNT].value + 1; + } else { + hp_layers = inst->capabilities[ENH_LAYER_COUNT].value + 1; + if (inst->hfi_layer_type == HFI_HIER_P_HYBRID_LTR) + is_hybrid_hp = true; + } + + if (inst->codec == MSM_VIDC_H264) + hfi_codec = HFI_CODEC_ENCODE_AVC; + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + hfi_codec = HFI_CODEC_ENCODE_HEVC; + + HFI_IRIS2_ENC_RECON_BUF_COUNT(num_buf_recon, n_bframe, ltr_count, + hp_layers, hb_layers, is_hybrid_hp, hfi_codec); + + return num_buf_recon; +} + +static u32 msm_vidc_encoder_comv_size_iris2(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, num_recon = 0; + struct v4l2_format *f; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + num_recon = msm_vidc_get_recon_buf_count(inst); + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_COMV_H264E(size, width, height, num_recon); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_COMV_H265E(size, width, height, num_recon); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_non_comv_size_iris2(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, num_vpp_pipes; + struct v4l2_format *f; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_NON_COMV_H264E(size, width, height, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_NON_COMV_H265E(size, width, height, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_line_size_iris2(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, pixfmt, num_vpp_pipes; + bool is_tenbit = false; + struct v4l2_format *f; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + pixfmt = inst->capabilities[PIX_FMTS].value; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + is_tenbit = (pixfmt == MSM_VIDC_FMT_P010 || pixfmt == MSM_VIDC_FMT_TP10C); + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_LINE_H264E(size, width, height, is_tenbit, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_LINE_H265E(size, width, height, is_tenbit, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_dpb_size_iris2(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, pixfmt; + struct v4l2_format *f; + bool is_tenbit; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + pixfmt = inst->capabilities[PIX_FMTS].value; + is_tenbit = (pixfmt == MSM_VIDC_FMT_P010 || pixfmt == MSM_VIDC_FMT_TP10C); + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_DPB_H264E(size, width, height); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_DPB_H265E(size, width, height, is_tenbit); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_arp_size_iris2(struct msm_vidc_inst *inst) +{ + u32 size = 0; + + HFI_BUFFER_ARP_ENC(size); + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_vpss_size_iris2(struct msm_vidc_inst *inst) +{ + u32 size = 0; + bool ds_enable = false, is_tenbit = false, blur = false; + u32 rotation_val = HFI_ROTATION_NONE; + u32 width, height, driver_colorfmt; + struct v4l2_format *f; + + ds_enable = is_scaling_enabled(inst); + msm_vidc_v4l2_to_hfi_enum(inst, ROTATION, &rotation_val); + + f = &inst->fmts[OUTPUT_PORT]; + if (is_rotation_90_or_270(inst)) { + /* + * output width and height are rotated, + * so unrotate them to use as arguments to + * HFI_BUFFER_VPSS_ENC. + */ + width = f->fmt.pix_mp.height; + height = f->fmt.pix_mp.width; + } else { + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + } + + f = &inst->fmts[INPUT_PORT]; + driver_colorfmt = v4l2_colorformat_to_driver(inst, + f->fmt.pix_mp.pixelformat, __func__); + is_tenbit = is_10bit_colorformat(driver_colorfmt); + if (inst->capabilities[BLUR_TYPES].value != MSM_VIDC_BLUR_NONE) + blur = true; + + HFI_BUFFER_VPSS_ENC(size, width, height, ds_enable, blur, is_tenbit); + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +struct msm_vidc_buf_type_handle { + enum msm_vidc_buffer_type type; + u32 (*handle)(struct msm_vidc_inst *inst); +}; + +int msm_buffer_size_iris2(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int i; + u32 size = 0, buf_type_handle_size = 0; + const struct msm_vidc_buf_type_handle *buf_type_handle_arr = NULL; + static const struct msm_vidc_buf_type_handle dec_buf_type_handle[] = { + {MSM_VIDC_BUF_INPUT, msm_vidc_decoder_input_size }, + {MSM_VIDC_BUF_OUTPUT, msm_vidc_decoder_output_size }, + {MSM_VIDC_BUF_INPUT_META, msm_vidc_decoder_input_meta_size }, + {MSM_VIDC_BUF_OUTPUT_META, msm_vidc_decoder_output_meta_size }, + {MSM_VIDC_BUF_BIN, msm_vidc_decoder_bin_size_iris2 }, + {MSM_VIDC_BUF_COMV, msm_vidc_decoder_comv_size_iris2 }, + {MSM_VIDC_BUF_NON_COMV, msm_vidc_decoder_non_comv_size_iris2 }, + {MSM_VIDC_BUF_LINE, msm_vidc_decoder_line_size_iris2 }, + {MSM_VIDC_BUF_PERSIST, msm_vidc_decoder_persist_size_iris2 }, + {MSM_VIDC_BUF_DPB, msm_vidc_decoder_dpb_size_iris2 }, + }; + static const struct msm_vidc_buf_type_handle enc_buf_type_handle[] = { + {MSM_VIDC_BUF_INPUT, msm_vidc_encoder_input_size }, + {MSM_VIDC_BUF_OUTPUT, msm_vidc_encoder_output_size }, + {MSM_VIDC_BUF_INPUT_META, msm_vidc_encoder_input_meta_size }, + {MSM_VIDC_BUF_OUTPUT_META, msm_vidc_encoder_output_meta_size }, + {MSM_VIDC_BUF_BIN, msm_vidc_encoder_bin_size_iris2 }, + {MSM_VIDC_BUF_COMV, msm_vidc_encoder_comv_size_iris2 }, + {MSM_VIDC_BUF_NON_COMV, msm_vidc_encoder_non_comv_size_iris2 }, + {MSM_VIDC_BUF_LINE, msm_vidc_encoder_line_size_iris2 }, + {MSM_VIDC_BUF_DPB, msm_vidc_encoder_dpb_size_iris2 }, + {MSM_VIDC_BUF_ARP, msm_vidc_encoder_arp_size_iris2 }, + {MSM_VIDC_BUF_VPSS, msm_vidc_encoder_vpss_size_iris2 }, + }; + + if (is_decode_session(inst)) { + buf_type_handle_size = ARRAY_SIZE(dec_buf_type_handle); + buf_type_handle_arr = dec_buf_type_handle; + } else if (is_encode_session(inst)) { + buf_type_handle_size = ARRAY_SIZE(enc_buf_type_handle); + buf_type_handle_arr = enc_buf_type_handle; + } + + /* handle invalid session */ + if (!buf_type_handle_arr || !buf_type_handle_size) { + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return size; + } + + /* fetch buffer size */ + for (i = 0; i < buf_type_handle_size; i++) { + if (buf_type_handle_arr[i].type == buffer_type) { + size = buf_type_handle_arr[i].handle(inst); + break; + } + } + + /* handle unknown buffer type */ + if (i == buf_type_handle_size) { + i_vpr_e(inst, "%s: unknown buffer type %#x\n", __func__, buffer_type); + goto exit; + } + + i_vpr_l(inst, "buffer_size: type: %11s, size: %9u\n", buf_name(buffer_type), size); + +exit: + return size; +} + +static int msm_vidc_input_min_count_iris2(struct msm_vidc_inst *inst) +{ + u32 input_min_count = 0; + u32 total_hb_layer = 0; + + if (is_decode_session(inst)) { + input_min_count = MIN_DEC_INPUT_BUFFERS; + } else if (is_encode_session(inst)) { + total_hb_layer = is_hierb_type_requested(inst) ? + inst->capabilities[ENH_LAYER_COUNT].value + 1 : 0; + if (inst->codec == MSM_VIDC_H264 && + !inst->capabilities[LAYER_ENABLE].value) { + total_hb_layer = 0; + } + HFI_IRIS2_ENC_MIN_INPUT_BUF_COUNT(input_min_count, + total_hb_layer); + } else { + i_vpr_e(inst, "%s: invalid domain %d\n", __func__, inst->domain); + return 0; + } + + if (is_thumbnail_session(inst) || is_image_session(inst)) + input_min_count = 1; + + return input_min_count; +} + +static int msm_buffer_dpb_count(struct msm_vidc_inst *inst) +{ + int count = 0; + u32 color_fmt; + + /* decoder dpb buffer count */ + if (is_decode_session(inst)) { + color_fmt = inst->capabilities[PIX_FMTS].value; + if (is_linear_colorformat(color_fmt)) { + count = inst->fw_min_count ? + inst->fw_min_count : inst->buffers.output.min_count; + } + return count; + } + + /* encoder dpb buffer count */ + return msm_vidc_get_recon_buf_count(inst); +} + +int msm_buffer_min_count_iris2(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int count = 0; + + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + case MSM_VIDC_BUF_INPUT_META: + count = msm_vidc_input_min_count_iris2(inst); + break; + case MSM_VIDC_BUF_OUTPUT: + case MSM_VIDC_BUF_OUTPUT_META: + count = msm_vidc_output_min_count(inst); + break; + case MSM_VIDC_BUF_BIN: + case MSM_VIDC_BUF_COMV: + case MSM_VIDC_BUF_NON_COMV: + case MSM_VIDC_BUF_LINE: + case MSM_VIDC_BUF_PERSIST: + case MSM_VIDC_BUF_ARP: + case MSM_VIDC_BUF_VPSS: + count = msm_vidc_internal_buffer_count(inst, buffer_type); + break; + case MSM_VIDC_BUF_DPB: + count = msm_buffer_dpb_count(inst); + break; + default: + break; + } + + i_vpr_l(inst, " min_count: type: %11s, count: %9u\n", buf_name(buffer_type), count); + return count; +} + +int msm_buffer_extra_count_iris2(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int count = 0; + + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + case MSM_VIDC_BUF_INPUT_META: + count = msm_vidc_input_extra_count(inst); + break; + case MSM_VIDC_BUF_OUTPUT: + case MSM_VIDC_BUF_OUTPUT_META: + count = msm_vidc_output_extra_count(inst); + break; + default: + break; + } + + i_vpr_l(inst, "extra_count: type: %11s, count: %9u\n", buf_name(buffer_type), count); + return count; +} diff --git a/qcom/opensource/video-driver/driver/variant/iris2/src/msm_vidc_iris2.c b/qcom/opensource/video-driver/driver/variant/iris2/src/msm_vidc_iris2.c new file mode 100644 index 0000000000..2743450641 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris2/src/msm_vidc_iris2.c @@ -0,0 +1,960 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include "msm_vidc_iris2.h" +#include "msm_vidc_buffer_iris2.h" +#include "msm_vidc_power_iris2.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_buffer.h" +#include "msm_vidc_state.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_variant.h" +#include "venus_hfi.h" + +#define VIDEO_ARCH_LX 1 + +#define VCODEC_BASE_OFFS_IRIS2 0x00000000 +#define AON_MVP_NOC_RESET 0x0001F000 +#define CPU_BASE_OFFS_IRIS2 0x000A0000 +#define AON_BASE_OFFS 0x000E0000 +#define CPU_CS_BASE_OFFS_IRIS2 (CPU_BASE_OFFS_IRIS2) +#define CPU_IC_BASE_OFFS_IRIS2 (CPU_BASE_OFFS_IRIS2) + +#define CPU_CS_A2HSOFTINTCLR_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x1C) +#define CPU_CS_VCICMD_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x20) +#define CPU_CS_VCICMDARG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x24) +#define CPU_CS_VCICMDARG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x28) +#define CPU_CS_VCICMDARG2_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x2C) +#define CPU_CS_VCICMDARG3_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x30) +#define CPU_CS_VMIMSG_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x34) +#define CPU_CS_VMIMSGAG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x38) +#define CPU_CS_VMIMSGAG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x3C) +#define CPU_CS_SCIACMD_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x48) +#define CPU_CS_H2XSOFTINTEN_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x148) + +/* HFI_CTRL_STATUS */ +#define CPU_CS_SCIACMDARG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x4C) +#define CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS2 0xfe +#define CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_IRIS2 0x100 +#define CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS2 0x40000000 + +/* HFI_QTBL_INFO */ +#define CPU_CS_SCIACMDARG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x50) + +/* HFI_QTBL_ADDR */ +#define CPU_CS_SCIACMDARG2_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x54) + +/* HFI_VERSION_INFO */ +#define CPU_CS_SCIACMDARG3_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x58) + +/* SFR_ADDR */ +#define CPU_CS_SCIBCMD_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x5C) + +/* MMAP_ADDR */ +#define CPU_CS_SCIBCMDARG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x60) + +/* UC_REGION_ADDR */ +#define CPU_CS_SCIBARG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x64) + +/* UC_REGION_ADDR */ +#define CPU_CS_SCIBARG2_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x68) + +#define CPU_CS_AHB_BRIDGE_SYNC_RESET (CPU_CS_BASE_OFFS_IRIS2 + 0x160) +#define CPU_CS_AHB_BRIDGE_SYNC_RESET_STATUS (CPU_CS_BASE_OFFS_IRIS2 + 0x164) + +/* FAL10 Feature Control */ +#define CPU_CS_X2RPMh_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x168) +#define CPU_CS_X2RPMh_MASK0_BMSK_IRIS2 0x1 +#define CPU_CS_X2RPMh_MASK0_SHFT_IRIS2 0x0 +#define CPU_CS_X2RPMh_MASK1_BMSK_IRIS2 0x2 +#define CPU_CS_X2RPMh_MASK1_SHFT_IRIS2 0x1 +#define CPU_CS_X2RPMh_SWOVERRIDE_BMSK_IRIS2 0x4 +#define CPU_CS_X2RPMh_SWOVERRIDE_SHFT_IRIS2 0x3 + +#define CPU_IC_SOFTINT_IRIS2 (CPU_IC_BASE_OFFS_IRIS2 + 0x150) +#define CPU_IC_SOFTINT_H2A_SHFT_IRIS2 0x0 + +/* + * -------------------------------------------------------------------------- + * MODULE: AON_MVP_NOC_RESET_REGISTERS + * -------------------------------------------------------------------------- + */ +#define AON_WRAPPER_MVP_NOC_RESET_REQ (AON_MVP_NOC_RESET + 0x000) +#define AON_WRAPPER_MVP_NOC_RESET_ACK (AON_MVP_NOC_RESET + 0x004) + +/* + * -------------------------------------------------------------------------- + * MODULE: wrapper + * -------------------------------------------------------------------------- + */ +#define WRAPPER_BASE_OFFS_IRIS2 0x000B0000 +#define WRAPPER_INTR_STATUS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x0C) +#define WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2 0x8 +#define WRAPPER_INTR_STATUS_A2H_BMSK_IRIS2 0x4 + +#define WRAPPER_INTR_MASK_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x10) +#define WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS2 0x8 +#define WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS2 0x4 + +#define WRAPPER_CPU_CLOCK_CONFIG_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x2000) +#define WRAPPER_CPU_CGC_DIS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x2010) +#define WRAPPER_CPU_STATUS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x2014) + +#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x54) +#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x58) +#define WRAPPER_CORE_CLOCK_CONFIG_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x88) + +/* + * -------------------------------------------------------------------------- + * MODULE: tz_wrapper + * -------------------------------------------------------------------------- + */ +#define WRAPPER_TZ_BASE_OFFS 0x000C0000 +#define WRAPPER_TZ_CPU_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS) +#define WRAPPER_TZ_CPU_STATUS (WRAPPER_TZ_BASE_OFFS + 0x10) + +#define CTRL_INIT_IRIS2 CPU_CS_SCIACMD_IRIS2 + +#define CTRL_STATUS_IRIS2 CPU_CS_SCIACMDARG0_IRIS2 +#define CTRL_ERROR_STATUS__M_IRIS2 \ + CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS2 +#define CTRL_INIT_IDLE_MSG_BMSK_IRIS2 \ + CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS2 +#define CTRL_STATUS_PC_READY_IRIS2 \ + CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_IRIS2 + + +#define QTBL_INFO_IRIS2 CPU_CS_SCIACMDARG1_IRIS2 + +#define QTBL_ADDR_IRIS2 CPU_CS_SCIACMDARG2_IRIS2 + +#define VERSION_INFO_IRIS2 CPU_CS_SCIACMDARG3_IRIS2 + +#define SFR_ADDR_IRIS2 CPU_CS_SCIBCMD_IRIS2 +#define MMAP_ADDR_IRIS2 CPU_CS_SCIBCMDARG0_IRIS2 +#define UC_REGION_ADDR_IRIS2 CPU_CS_SCIBARG1_IRIS2 +#define UC_REGION_SIZE_IRIS2 CPU_CS_SCIBARG2_IRIS2 + +#define AON_WRAPPER_MVP_NOC_LPI_CONTROL (AON_BASE_OFFS) +#define AON_WRAPPER_MVP_NOC_LPI_STATUS (AON_BASE_OFFS + 0x4) + +/* + * -------------------------------------------------------------------------- + * MODULE: VCODEC_SS registers + * -------------------------------------------------------------------------- + */ +#define VCODEC_SS_IDLE_STATUSn (VCODEC_BASE_OFFS_IRIS2 + 0x70) + +/* + * -------------------------------------------------------------------------- + * MODULE: vcodec noc error log registers (iris2) + * -------------------------------------------------------------------------- + */ +#define VCODEC_NOC_VIDEO_A_NOC_BASE_OFFS 0x00010000 +#define VCODEC_NOC_ERL_MAIN_SWID_LOW 0x00011200 +#define VCODEC_NOC_ERL_MAIN_SWID_HIGH 0x00011204 +#define VCODEC_NOC_ERL_MAIN_MAINCTL_LOW 0x00011208 +#define VCODEC_NOC_ERL_MAIN_ERRVLD_LOW 0x00011210 +#define VCODEC_NOC_ERL_MAIN_ERRCLR_LOW 0x00011218 +#define VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW 0x00011220 +#define VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH 0x00011224 +#define VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW 0x00011228 +#define VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH 0x0001122C +#define VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW 0x00011230 +#define VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH 0x00011234 +#define VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW 0x00011238 +#define VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH 0x0001123C + +static int __interrupt_init_iris2(struct msm_vidc_core *core) +{ + u32 mask_val = 0; + int rc = 0; + + /* All interrupts should be disabled initially 0x1F6 : Reset value */ + rc = __read_register(core, WRAPPER_INTR_MASK_IRIS2, &mask_val); + if (rc) + return rc; + + /* Write 0 to unmask CPU and WD interrupts */ + mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS2 | + WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS2); + rc = __write_register(core, WRAPPER_INTR_MASK_IRIS2, mask_val); + if (rc) + return rc; + + return 0; +} + +static int __setup_ucregion_memory_map_iris2(struct msm_vidc_core *core) +{ + u32 value; + int rc = 0; + + value = (u32)core->iface_q_table.align_device_addr; + rc = __write_register(core, UC_REGION_ADDR_IRIS2, value); + if (rc) + return rc; + + value = SHARED_QSIZE; + rc = __write_register(core, UC_REGION_SIZE_IRIS2, value); + if (rc) + return rc; + + value = (u32)core->iface_q_table.align_device_addr; + rc = __write_register(core, QTBL_ADDR_IRIS2, value); + if (rc) + return rc; + + rc = __write_register(core, QTBL_INFO_IRIS2, 0x01); + if (rc) + return rc; + + /* update queues vaddr for debug purpose */ + value = (u32)((u64)core->iface_q_table.align_virtual_addr); + rc = __write_register(core, CPU_CS_VCICMDARG0_IRIS2, value); + if (rc) + return rc; + + value = (u32)((u64)core->iface_q_table.align_virtual_addr >> 32); + rc = __write_register(core, CPU_CS_VCICMDARG1_IRIS2, value); + if (rc) + return rc; + + if (core->sfr.align_device_addr) { + value = (u32)core->sfr.align_device_addr + VIDEO_ARCH_LX; + rc = __write_register(core, SFR_ADDR_IRIS2, value); + if (rc) + return rc; + } + + return 0; +} + +static int __power_off_iris2_hardware(struct msm_vidc_core *core) +{ + int rc = 0, i; + u32 value = 0; + + if (is_core_sub_state(core, CORE_SUBSTATE_FW_PWR_CTRL)) { + d_vpr_h("%s: hardware power control enabled\n", __func__); + goto disable_power; + } + + /* + * check to make sure core clock branch enabled else + * we cannot read vcodec top idle register + */ + rc = __read_register(core, WRAPPER_CORE_CLOCK_CONFIG_IRIS2, &value); + if (rc) + return rc; + + if (value) { + d_vpr_h("%s: core clock config not enabled, enabling it to read vcodec registers\n", + __func__); + rc = __write_register(core, WRAPPER_CORE_CLOCK_CONFIG_IRIS2, 0); + if (rc) + return rc; + } + + /* + * add MNoC idle check before collapsing MVS0 per HPG update + * poll for NoC DMA idle -> HPG 6.1.1 + */ + for (i = 0; i < core->capabilities[NUM_VPP_PIPE].value; i++) { + rc = __read_register_with_poll_timeout(core, VCODEC_SS_IDLE_STATUSn + 4*i, + 0x400000, 0x400000, 2000, 20000); + if (rc) + d_vpr_h("%s: VCODEC_SS_IDLE_STATUSn (%d) is not idle (%#x)\n", + __func__, i, value); + } + + /* Apply partial reset on MSF interface and wait for ACK */ + rc = __write_register(core, AON_WRAPPER_MVP_NOC_RESET_REQ, 0x3); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_RESET_ACK, + 0x3, 0x3, 200, 2000); + if (rc) + d_vpr_h("%s: AON_WRAPPER_MVP_NOC_RESET assert failed\n", __func__); + + /* De-assert partial reset on MSF interface and wait for ACK */ + rc = __write_register(core, AON_WRAPPER_MVP_NOC_RESET_REQ, 0x0); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_RESET_ACK, + 0x3, 0x0, 200, 2000); + if (rc) + d_vpr_h("%s: AON_WRAPPER_MVP_NOC_RESET de-assert failed\n", __func__); + + /* + * Reset both sides of 2 ahb2ahb_bridges (TZ and non-TZ) + * do we need to check status register here? + */ + rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x3); + if (rc) + return rc; + rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x2); + if (rc) + return rc; + rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x0); + if (rc) + return rc; + +disable_power: + /* power down process */ + rc = call_res_op(core, gdsc_off, core, "vcodec"); + if (rc) { + d_vpr_e("%s: disable regulator vcodec failed\n", __func__); + rc = 0; + } + rc = call_res_op(core, clk_disable, core, "video_cc_mvs0_clk"); + if (rc) { + d_vpr_e("%s: disable unprepare video_cc_mvs0_clk failed\n", __func__); + rc = 0; + } + + return rc; +} + +static int __power_off_iris2_controller(struct msm_vidc_core *core) +{ + int rc = 0; + + /* + * mask fal10_veto QLPAC error since fal10_veto can go 1 + * when pwwait == 0 and clamped to 0 -> HPG 6.1.2 + */ + rc = __write_register(core, CPU_CS_X2RPMh_IRIS2, 0x3); + if (rc) + return rc; + + /* set MNoC to low power, set PD_NOC_QREQ (bit 0) */ + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL, + 0x1, BIT(0)); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_LPI_STATUS, + 0x1, 0x1, 200, 2000); + if (rc) + d_vpr_h("%s: AON_WRAPPER_MVP_NOC_LPI_CONTROL failed\n", __func__); + + /* Set Debug bridge Low power */ + rc = __write_register(core, WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS2, 0x7); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2, + 0x7, 0x7, 200, 2000); + if (rc) + d_vpr_h("%s: debug bridge low power failed\n", __func__); + + /* Debug bridge LPI release */ + rc = __write_register(core, WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS2, 0x0); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2, + 0xffffffff, 0x0, 200, 2000); + if (rc) + d_vpr_h("%s: debug bridge release failed\n", __func__); + + /* Turn off MVP MVS0C core clock */ + rc = call_res_op(core, clk_disable, core, "video_cc_mvs0c_clk"); + if (rc) { + d_vpr_e("%s: disable unprepare video_cc_mvs0c_clk failed\n", __func__); + rc = 0; + } + + /* Disable gcc_video_axi0_clk clock */ + rc = call_res_op(core, clk_disable, core, "gcc_video_axi0_clk"); + if (rc) { + d_vpr_e("%s: disable unprepare gcc_video_axi0_clk failed\n", __func__); + rc = 0; + } + + rc = call_res_op(core, reset_bridge, core); + if (rc) { + d_vpr_e("%s: reset bridge failed\n", __func__); + rc = 0; + } + + /* power down process */ + rc = call_res_op(core, gdsc_off, core, "iris-ctl"); + if (rc) { + d_vpr_e("%s: disable regulator iris-ctl failed\n", __func__); + rc = 0; + } + + return rc; +} + +static int __power_off_iris2(struct msm_vidc_core *core) +{ + int rc = 0; + + if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) + return 0; + + /** + * Reset video_cc_mvs0_clk_src value to resolve MMRM high video + * clock projection issue. + */ + rc = call_res_op(core, set_clks, core, 0); + if (rc) + d_vpr_e("%s: resetting clocks failed\n", __func__); + + if (__power_off_iris2_hardware(core)) + d_vpr_e("%s: failed to power off hardware\n", __func__); + + if (__power_off_iris2_controller(core)) + d_vpr_e("%s: failed to power off controller\n", __func__); + + rc = call_res_op(core, set_bw, core, 0, 0); + if (rc) + d_vpr_e("%s: failed to unvote buses\n", __func__); + + if (!call_venus_op(core, watchdog, core, core->intr_status)) + disable_irq_nosync(core->resource->irq); + + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__); + + return rc; +} + +static int __power_on_iris2_controller(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = call_res_op(core, gdsc_on, core, "iris-ctl"); + if (rc) + goto fail_regulator; + + rc = call_res_op(core, reset_bridge, core); + if (rc) + goto fail_reset_ahb2axi; + + rc = call_res_op(core, clk_enable, core, "gcc_video_axi0_clk"); + if (rc) + goto fail_clk_axi; + + rc = call_res_op(core, clk_enable, core, "video_cc_mvs0c_clk"); + if (rc) + goto fail_clk_controller; + + return 0; + +fail_clk_controller: + call_res_op(core, clk_disable, core, "gcc_video_axi0_clk"); +fail_clk_axi: +fail_reset_ahb2axi: + call_res_op(core, gdsc_off, core, "iris-ctl"); +fail_regulator: + return rc; +} + +static int __power_on_iris2_hardware(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = call_res_op(core, gdsc_on, core, "vcodec"); + if (rc) + goto fail_regulator; + + rc = call_res_op(core, clk_enable, core, "video_cc_mvs0_clk"); + if (rc) + goto fail_clk_controller; + + return 0; + +fail_clk_controller: + call_res_op(core, gdsc_off, core, "vcodec"); +fail_regulator: + return rc; +} + +static int __power_on_iris2(struct msm_vidc_core *core) +{ + struct frequency_table *freq_tbl; + u32 freq = 0; + int rc = 0; + + if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) + return 0; + + if (!core_in_valid_state(core)) { + d_vpr_e("%s: invalid core state %s\n", + __func__, core_state_name(core->state)); + return -EINVAL; + } + + /* Vote for all hardware resources */ + rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX); + if (rc) { + d_vpr_e("%s: failed to vote buses, rc %d\n", __func__, rc); + goto fail_vote_buses; + } + + rc = __power_on_iris2_controller(core); + if (rc) { + d_vpr_e("%s: failed to power on iris2 controller\n", __func__); + goto fail_power_on_controller; + } + + rc = __power_on_iris2_hardware(core); + if (rc) { + d_vpr_e("%s: failed to power on iris2 hardware\n", __func__); + goto fail_power_on_hardware; + } + /* video controller and hardware powered on successfully */ + rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_POWER_ENABLE, __func__); + if (rc) + goto fail_power_on_substate; + + freq_tbl = core->resource->freq_set.freq_tbl; + freq = core->power.clk_freq ? core->power.clk_freq : + freq_tbl[0].freq; + + rc = call_res_op(core, set_clks, core, freq); + if (rc) { + d_vpr_e("%s: failed to scale clocks\n", __func__); + rc = 0; + } + + core->power.clk_freq = freq; + + /* + * Re-program all of the registers that get reset as a result of + * regulator_disable() and _enable() + */ + __set_registers(core); + + __interrupt_init_iris2(core); + core->intr_status = 0; + enable_irq(core->resource->irq); + + return rc; + +fail_power_on_substate: + __power_off_iris2_hardware(core); +fail_power_on_hardware: + __power_off_iris2_controller(core); +fail_power_on_controller: + call_res_op(core, set_bw, core, 0, 0); +fail_vote_buses: + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__); + return rc; +} + +static int __prepare_pc_iris2(struct msm_vidc_core *core) +{ + int rc = 0; + u32 wfi_status = 0, idle_status = 0, pc_ready = 0; + u32 ctrl_status = 0; + + rc = __read_register(core, CTRL_STATUS_IRIS2, &ctrl_status); + if (rc) + return rc; + + pc_ready = ctrl_status & CTRL_STATUS_PC_READY_IRIS2; + idle_status = ctrl_status & BIT(30); + + if (pc_ready) { + d_vpr_h("Already in pc_ready state\n"); + return 0; + } + rc = __read_register(core, WRAPPER_TZ_CPU_STATUS, &wfi_status); + if (rc) + return rc; + + wfi_status &= BIT(0); + if (!wfi_status || !idle_status) { + d_vpr_e("Skipping PC, wfi status not set\n"); + goto skip_power_off; + } + + rc = __prepare_pc(core); + if (rc) { + d_vpr_e("Failed __prepare_pc %d\n", rc); + goto skip_power_off; + } + + rc = __read_register_with_poll_timeout(core, CTRL_STATUS_IRIS2, + CTRL_STATUS_PC_READY_IRIS2, CTRL_STATUS_PC_READY_IRIS2, 250, 2500); + if (rc) { + d_vpr_e("%s: Skip PC. Ctrl status not set\n", __func__); + goto skip_power_off; + } + + rc = __read_register_with_poll_timeout(core, WRAPPER_TZ_CPU_STATUS, + BIT(0), 0x1, 250, 2500); + if (rc) { + d_vpr_e("%s: Skip PC. Wfi status not set\n", __func__); + goto skip_power_off; + } + return rc; + +skip_power_off: + rc = __read_register(core, CTRL_STATUS_IRIS2, &ctrl_status); + if (rc) + return rc; + rc = __read_register(core, WRAPPER_TZ_CPU_STATUS, &wfi_status); + if (rc) + return rc; + wfi_status &= BIT(0); + d_vpr_e("Skip PC, wfi=%#x, idle=%#x, pcr=%#x, ctrl=%#x)\n", + wfi_status, idle_status, pc_ready, ctrl_status); + return -EAGAIN; +} + +static int __raise_interrupt_iris2(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = __write_register(core, CPU_IC_SOFTINT_IRIS2, 1 << CPU_IC_SOFTINT_H2A_SHFT_IRIS2); + if (rc) + return rc; + + return 0; +} + +static int __watchdog_iris2(struct msm_vidc_core *core, u32 intr_status) +{ + int rc = 0; + + if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2) { + d_vpr_e("%s: received watchdog interrupt\n", __func__); + rc = 1; + } + + return rc; +} + +static int __noc_error_info_iris2(struct msm_vidc_core *core) +{ + /* + * we are not supposed to access vcodec subsystem registers + * unless vcodec core clock WRAPPER_CORE_CLOCK_CONFIG_IRIS2 is enabled. + * core clock might have been disabled by video firmware as part of + * inter frame power collapse (power plane control feature). + */ + + /* + val = __read_register(core, VCODEC_NOC_ERL_MAIN_SWID_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_SWID_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_SWID_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_SWID_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_MAINCTL_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_MAINCTL_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRVLD_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRVLD_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRCLR_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRCLR_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH: %#x\n", val); + */ + + return 0; +} + +static int __clear_interrupt_iris2(struct msm_vidc_core *core) +{ + u32 intr_status = 0, mask = 0; + int rc = 0; + + rc = __read_register(core, WRAPPER_INTR_STATUS_IRIS2, &intr_status); + if (rc) + return rc; + + mask = (WRAPPER_INTR_STATUS_A2H_BMSK_IRIS2| + WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2| + CTRL_INIT_IDLE_MSG_BMSK_IRIS2); + + if (intr_status & mask) { + core->intr_status |= intr_status; + core->reg_count++; + d_vpr_l("INTERRUPT: times: %d interrupt_status: %d\n", + core->reg_count, intr_status); + } else { + core->spur_count++; + } + + rc = __write_register(core, CPU_CS_A2HSOFTINTCLR_IRIS2, 1); + if (rc) + return rc; + + return 0; +} + +static int __boot_firmware_iris2(struct msm_vidc_core *core) +{ + int rc = 0; + u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 1000; + + rc = __setup_ucregion_memory_map_iris2(core); + if (rc) + return rc; + + ctrl_init_val = BIT(0); + + rc = __write_register(core, CTRL_INIT_IRIS2, ctrl_init_val); + if (rc) + return rc; + + while (!ctrl_status && count < max_tries) { + rc = __read_register(core, CTRL_STATUS_IRIS2, &ctrl_status); + if (rc) + return rc; + + if ((ctrl_status & CTRL_ERROR_STATUS__M_IRIS2) == 0x4) { + d_vpr_e("invalid setting for UC_REGION\n"); + break; + } + + usleep_range(50, 100); + count++; + } + + if (count >= max_tries) { + d_vpr_e("Error booting up vidc firmware\n"); + return -ETIME; + } + + /* Enable interrupt before sending commands to venus */ + rc = __write_register(core, CPU_CS_H2XSOFTINTEN_IRIS2, 0x1); + if (rc) + return rc; + + rc = __write_register(core, CPU_CS_X2RPMh_IRIS2, 0x0); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_decide_work_mode_iris2(struct msm_vidc_inst *inst) +{ + u32 work_mode; + struct v4l2_format *inp_f; + u32 width, height; + bool res_ok = false; + + work_mode = MSM_VIDC_STAGE_2; + inp_f = &inst->fmts[INPUT_PORT]; + + if (is_image_decode_session(inst)) + work_mode = MSM_VIDC_STAGE_1; + + if (is_image_session(inst)) + goto exit; + + if (is_decode_session(inst)) { + height = inp_f->fmt.pix_mp.height; + width = inp_f->fmt.pix_mp.width; + res_ok = res_is_less_than(width, height, 1280, 720); + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_INTERLACE || + inst->capabilities[LOWLATENCY_MODE].value || + res_ok) { + work_mode = MSM_VIDC_STAGE_1; + } + } else if (is_encode_session(inst)) { + height = inst->crop.height; + width = inst->crop.width; + res_ok = !res_is_greater_than(width, height, 4096, 2160); + if (res_ok && + (inst->capabilities[LOWLATENCY_MODE].value)) { + work_mode = MSM_VIDC_STAGE_1; + } + if (inst->capabilities[SLICE_MODE].value == + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { + work_mode = MSM_VIDC_STAGE_1; + } + if (inst->capabilities[LOSSLESS].value) + work_mode = MSM_VIDC_STAGE_2; + + if (!inst->capabilities[GOP_SIZE].value) + work_mode = MSM_VIDC_STAGE_2; + } else { + i_vpr_e(inst, "%s: invalid session type\n", __func__); + return -EINVAL; + } + +exit: + i_vpr_h(inst, "Configuring work mode = %u low latency = %u, gop size = %u\n", + work_mode, inst->capabilities[LOWLATENCY_MODE].value, + inst->capabilities[GOP_SIZE].value); + msm_vidc_update_cap_value(inst, STAGE, work_mode, __func__); + + return 0; +} + +int msm_vidc_decide_work_route_iris2(struct msm_vidc_inst *inst) +{ + u32 work_route; + struct msm_vidc_core *core; + + core = inst->core; + work_route = core->capabilities[NUM_VPP_PIPE].value; + + if (is_image_session(inst)) + goto exit; + + if (is_decode_session(inst)) { + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_INTERLACE) + work_route = MSM_VIDC_PIPE_1; + } else if (is_encode_session(inst)) { + u32 slice_mode; + + slice_mode = inst->capabilities[SLICE_MODE].value; + + /*TODO Pipe=1 for legacy CBR*/ + if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) + work_route = MSM_VIDC_PIPE_1; + + } else { + i_vpr_e(inst, "%s: invalid session type\n", __func__); + return -EINVAL; + } + +exit: + i_vpr_h(inst, "Configuring work route = %u", work_route); + msm_vidc_update_cap_value(inst, PIPE, work_route, __func__); + + return 0; +} + +int msm_vidc_adjust_blur_type_iris2(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1, cac = -1; + s32 pix_fmts = -1, min_quality = -1; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[BLUR_TYPES].value; + + if (adjusted_value == MSM_VIDC_BLUR_NONE) + return 0; + + if (msm_vidc_get_parent_value(inst, BLUR_TYPES, BITRATE_MODE, + &rc_type, __func__) || + msm_vidc_get_parent_value(inst, BLUR_TYPES, + CONTENT_ADAPTIVE_CODING, &cac, __func__) || + msm_vidc_get_parent_value(inst, BLUR_TYPES, PIX_FMTS, + &pix_fmts, __func__) || + msm_vidc_get_parent_value(inst, BLUR_TYPES, MIN_QUALITY, + &min_quality, __func__)) + return -EINVAL; + + if (adjusted_value == MSM_VIDC_BLUR_EXTERNAL) { + if (is_scaling_enabled(inst) || min_quality) + adjusted_value = MSM_VIDC_BLUR_NONE; + } else if (adjusted_value == MSM_VIDC_BLUR_ADAPTIVE) { + if (is_scaling_enabled(inst) || min_quality || + (rc_type != HFI_RC_VBR_CFR) || + !cac || + is_10bit_colorformat(pix_fmts)) { + adjusted_value = MSM_VIDC_BLUR_NONE; + } + } + + msm_vidc_update_cap_value(inst, BLUR_TYPES, + adjusted_value, __func__); + + return 0; +} + +int msm_vidc_decide_quality_mode_iris2(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 mbpf, mbps, max_hq_mbpf, max_hq_mbps; + u32 mode = MSM_VIDC_POWER_SAVE_MODE; + + if (!is_encode_session(inst)) + return 0; + + /* image session always runs at quality mode */ + if (is_image_session(inst)) { + mode = MSM_VIDC_MAX_QUALITY_MODE; + goto exit; + } + + mbpf = msm_vidc_get_mbs_per_frame(inst); + mbps = mbpf * msm_vidc_get_fps(inst); + core = inst->core; + max_hq_mbpf = core->capabilities[MAX_MBPF_HQ].value;; + max_hq_mbps = core->capabilities[MAX_MBPS_HQ].value;; + + /* NRT session to have max quality unless client configures lesser complexity */ + if (!is_realtime_session(inst) && mbpf <= max_hq_mbpf) { + mode = MSM_VIDC_MAX_QUALITY_MODE; + if (inst->capabilities[COMPLEXITY].value < DEFAULT_COMPLEXITY) + mode = MSM_VIDC_POWER_SAVE_MODE; + goto exit; + } + + /* Power saving always disabled for CQ and LOSSLESS RC modes. */ + if (inst->capabilities[LOSSLESS].value || + (mbpf <= max_hq_mbpf && mbps <= max_hq_mbps)) + mode = MSM_VIDC_MAX_QUALITY_MODE; + +exit: + msm_vidc_update_cap_value(inst, QUALITY_MODE, mode, __func__); + + return 0; +} + +static struct msm_vidc_venus_ops iris2_ops = { + .boot_firmware = __boot_firmware_iris2, + .raise_interrupt = __raise_interrupt_iris2, + .clear_interrupt = __clear_interrupt_iris2, + .power_on = __power_on_iris2, + .power_off = __power_off_iris2, + .prepare_pc = __prepare_pc_iris2, + .watchdog = __watchdog_iris2, + .noc_error_info = __noc_error_info_iris2, +}; + +static struct msm_vidc_session_ops msm_session_ops = { + .buffer_size = msm_buffer_size_iris2, + .min_count = msm_buffer_min_count_iris2, + .extra_count = msm_buffer_extra_count_iris2, + .calc_freq = msm_vidc_calc_freq_iris2, + .calc_bw = msm_vidc_calc_bw_iris2, + .decide_work_route = msm_vidc_decide_work_route_iris2, + .decide_work_mode = msm_vidc_decide_work_mode_iris2, + .decide_quality_mode = msm_vidc_decide_quality_mode_iris2, +}; + +int msm_vidc_init_iris2(struct msm_vidc_core *core) +{ + d_vpr_h("%s()\n", __func__); + core->venus_ops = &iris2_ops; + core->session_ops = &msm_session_ops; + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/variant/iris2/src/msm_vidc_power_iris2.c b/qcom/opensource/video-driver/driver/variant/iris2/src/msm_vidc_power_iris2.c new file mode 100644 index 0000000000..61b3df9996 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris2/src/msm_vidc_power_iris2.c @@ -0,0 +1,706 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_power_iris2.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_core.h" +#include "msm_vidc_debug.h" + +u64 msm_vidc_calc_freq_iris2(struct msm_vidc_inst *inst, u32 data_size) +{ + u64 freq = 0; + struct msm_vidc_core *core; + u64 vsp_cycles = 0, vpp_cycles = 0, fw_cycles = 0; + u64 fw_vpp_cycles = 0, bitrate = 0; + u32 vpp_cycles_per_mb; + u32 mbs_per_second; + u32 operating_rate, vsp_factor_num = 1, vsp_factor_den = 1; + u32 base_cycles = 0; + u32 fps, mbpf; + + core = inst->core; + + mbpf = msm_vidc_get_mbs_per_frame(inst); + fps = inst->max_rate; + mbs_per_second = mbpf * fps; + + /* + * Calculate vpp, vsp, fw cycles separately for encoder and decoder. + * Even though, most part is common now, in future it may change + * between them. + */ + fw_cycles = fps * inst->capabilities[MB_CYCLES_FW].value; + fw_vpp_cycles = fps * inst->capabilities[MB_CYCLES_FW_VPP].value; + + if (is_encode_session(inst)) { + vpp_cycles_per_mb = is_low_power_session(inst) ? + inst->capabilities[MB_CYCLES_LP].value : + inst->capabilities[MB_CYCLES_VPP].value; + + vpp_cycles = mbs_per_second * vpp_cycles_per_mb / + inst->capabilities[PIPE].value; + + /* Factor 1.25 for IbP and 1.375 for I1B2b1P GOP structure */ + if (inst->capabilities[B_FRAME].value > 1) + vpp_cycles += (vpp_cycles / 4) + (vpp_cycles / 8); + else if (inst->capabilities[B_FRAME].value) + vpp_cycles += vpp_cycles / 4; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); + /* 1.01 is multi-pipe overhead */ + if (inst->capabilities[PIPE].value > 1) + vpp_cycles += div_u64(vpp_cycles, 100); + /* + * 1080p@480fps usecase needs exactly 338MHz + * without any margin left. Hence, adding 2 percent + * extra to bump it to next level (366MHz). + */ + if (fps == 480) + vpp_cycles += div_u64(vpp_cycles * 2, 100); + + /* + * Add 5 percent extra for 720p@960fps use case + * to bump it to next level (366MHz). + */ + if (fps == 960) + vpp_cycles += div_u64(vpp_cycles * 5, 100); + + /* VSP */ + /* bitrate is based on fps, scale it using operating rate */ + operating_rate = inst->capabilities[OPERATING_RATE].value >> 16; + if (operating_rate > + (inst->capabilities[FRAME_RATE].value >> 16) && + (inst->capabilities[FRAME_RATE].value >> 16)) { + vsp_factor_num = operating_rate; + vsp_factor_den = inst->capabilities[FRAME_RATE].value >> 16; + } + vsp_cycles = div_u64(((u64)inst->capabilities[BIT_RATE].value * + vsp_factor_num), vsp_factor_den); + + base_cycles = inst->capabilities[MB_CYCLES_VSP].value; + if (inst->codec == MSM_VIDC_VP9) { + vsp_cycles = div_u64(vsp_cycles * 170, 100); + } else if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) { + vsp_cycles = div_u64(vsp_cycles * 135, 100); + } else { + base_cycles = 0; + vsp_cycles = div_u64(vsp_cycles, 2); + } + /* VSP FW Overhead 1.05 */ + vsp_cycles = div_u64(vsp_cycles * 21, 20); + + if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_1) + vsp_cycles = vsp_cycles * 3; + + vsp_cycles += mbs_per_second * base_cycles; + + } else if (is_decode_session(inst)) { + /* VPP */ + vpp_cycles = mbs_per_second * inst->capabilities[MB_CYCLES_VPP].value / + inst->capabilities[PIPE].value; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); + /* 1.059 is multi-pipe overhead */ + if (inst->capabilities[PIPE].value > 1) + vpp_cycles += div_u64(vpp_cycles * 59, 1000); + + /* VSP */ + base_cycles = inst->has_bframe ? + 80 : inst->capabilities[MB_CYCLES_VSP].value; + bitrate = fps * data_size * 8; + vsp_cycles = bitrate; + + if (inst->codec == MSM_VIDC_VP9) { + vsp_cycles = div_u64(vsp_cycles * 170, 100); + } else if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) { + vsp_cycles = div_u64(vsp_cycles * 135, 100); + } else { + base_cycles = 0; + vsp_cycles = div_u64(vsp_cycles, 2); + } + /* VSP FW overhead 1.05 */ + vsp_cycles = div_u64(vsp_cycles * 21, 20); + + if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_1) + vsp_cycles = vsp_cycles * 3; + + vsp_cycles += mbs_per_second * base_cycles; + + /* Add 25 percent extra for 960fps use case */ + if (fps >= 960) + vsp_cycles += div_u64(vpp_cycles * 25, 100); + + if (inst->codec == MSM_VIDC_VP9 && + inst->capabilities[STAGE].value == + MSM_VIDC_STAGE_2 && + inst->capabilities[PIPE].value == 4 && + bitrate > 90000000) + vsp_cycles = msm_vidc_max_freq(inst); + } else { + i_vpr_e(inst, "%s: Unknown session type\n", __func__); + return msm_vidc_max_freq(inst); + } + + freq = max(vpp_cycles, vsp_cycles); + freq = max(freq, fw_cycles); + + i_vpr_p(inst, "%s: filled len %d, required freq %llu, fps %u, mbpf %u\n", + __func__, data_size, freq, fps, mbpf); + + return freq; +} + +static u64 __calculate_decoder(struct vidc_bus_vote_data *d) +{ + /* + * XXX: Don't fool around with any of the hardcoded numbers unless you + * know /exactly/ what you're doing. Many of these numbers are + * measured heuristics and hardcoded numbers taken from the firmware. + */ + /* Decoder parameters */ + int width, height, lcu_size, fps, dpb_bpp; + bool unified_dpb_opb, dpb_compression_enabled = true, + opb_compression_enabled = false, + llc_ref_read_l2_cache_enabled = false, + llc_top_line_buf_enabled = false; + fp_t dpb_read_compression_factor, dpb_opb_scaling_ratio, + dpb_write_compression_factor, opb_write_compression_factor, + qsmmu_bw_overhead_factor; + bool is_h264_category = true; + + /* Derived parameters */ + int lcu_per_frame, collocated_bytes_per_lcu, tnbr_per_lcu; + unsigned long bitrate; + unsigned int num_vpp_pipes; + + fp_t bins_to_bit_factor, vsp_read_factor, vsp_write_factor, + dpb_factor, dpb_write_factor, y_bw_no_ubwc_8bpp; + fp_t y_bw_no_ubwc_10bpp = 0, y_bw_10bpp_p010 = 0, + motion_vector_complexity = 0; + fp_t dpb_total = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + dpb_read, dpb_write, opb_read, opb_write, + line_buffer_read, line_buffer_write, + total; + } ddr = {0}; + + struct { + fp_t dpb_read, line_buffer_read, line_buffer_write, total; + } llc = {0}; + + unsigned long ret = 0; + unsigned int integer_part, frac_part; + + width = max(d->input_width, BASELINE_DIMENSIONS.width); + height = max(d->input_height, BASELINE_DIMENSIONS.height); + + fps = d->fps; + + lcu_size = d->lcu_size; + + dpb_bpp = __bpp(d->color_formats[0]); + + unified_dpb_opb = d->num_formats == 1; + + dpb_opb_scaling_ratio = fp_div(FP_INT(d->input_width * d->input_height), + FP_INT(d->output_width * d->output_height)); + + opb_compression_enabled = d->num_formats >= 2 && + __ubwc(d->color_formats[1]); + + integer_part = Q16_INT(d->compression_ratio); + frac_part = Q16_FRAC(d->compression_ratio); + dpb_read_compression_factor = FP(integer_part, frac_part, 100); + + integer_part = Q16_INT(d->complexity_factor); + frac_part = Q16_FRAC(d->complexity_factor); + motion_vector_complexity = FP(integer_part, frac_part, 100); + + dpb_write_compression_factor = dpb_read_compression_factor; + opb_write_compression_factor = opb_compression_enabled ? + dpb_write_compression_factor : FP_ONE; + + num_vpp_pipes = d->num_vpp_pipes; + + if (d->codec == MSM_VIDC_HEVC || + d->codec == MSM_VIDC_HEIC || + d->codec == MSM_VIDC_VP9) { + /* H264, VP8, MPEG2 use the same settings */ + /* HEVC, VP9 use the same setting */ + is_h264_category = false; + } + if (d->use_sys_cache) { + llc_ref_read_l2_cache_enabled = true; + if (is_h264_category) + llc_top_line_buf_enabled = true; + } + + /* Derived parameters setup */ + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + + bitrate = DIV_ROUND_UP(d->bitrate, 1000000); + + bins_to_bit_factor = FP_INT(4); + + vsp_write_factor = bins_to_bit_factor; + vsp_read_factor = bins_to_bit_factor + FP_INT(2); + + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + dpb_factor = FP(1, 50, 100); + dpb_write_factor = FP(1, 5, 100); + + /* This change is applicable for all IRIS2 targets, + * But currently being done only for IRIS2 with 2 pipe + * and 1 pipe due to timeline constraints. + */ + if (num_vpp_pipes != 4) + tnbr_per_lcu = lcu_size == 16 ? 64 : + lcu_size == 32 ? 64 : 128; + else + tnbr_per_lcu = lcu_size == 16 ? 128 : + lcu_size == 32 ? 64 : 128; + + /* .... For DDR & LLC ...... */ + ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate), + vsp_read_factor), FP_INT(8)); + ddr.vsp_write = fp_div(fp_mult(FP_INT(bitrate), + vsp_write_factor), FP_INT(8)); + + ddr.collocated_read = fp_div(FP_INT(lcu_per_frame * + collocated_bytes_per_lcu * fps), FP_INT(bps(1))); + ddr.collocated_write = ddr.collocated_read; + + y_bw_no_ubwc_8bpp = fp_div(FP_INT(width * height * fps), + FP_INT(1000 * 1000)); + + if (dpb_bpp != 8) { + y_bw_no_ubwc_10bpp = + fp_div(fp_mult(y_bw_no_ubwc_8bpp, FP_INT(256)), + FP_INT(192)); + y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2; + } + + ddr.dpb_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_read = fp_div(fp_mult(ddr.dpb_read, + fp_mult(dpb_factor, motion_vector_complexity)), + dpb_read_compression_factor); + + ddr.dpb_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_write = fp_div(fp_mult(ddr.dpb_write, + fp_mult(dpb_factor, dpb_write_factor)), + dpb_write_compression_factor); + + dpb_total = ddr.dpb_read + ddr.dpb_write; + + if (llc_ref_read_l2_cache_enabled) { + ddr.dpb_read = fp_div(ddr.dpb_read, is_h264_category ? + FP(1, 30, 100) : FP(1, 14, 100)); + llc.dpb_read = dpb_total - ddr.dpb_write - ddr.dpb_read; + } + + ddr.opb_read = FP_ZERO; + ddr.opb_write = unified_dpb_opb ? FP_ZERO : (dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : (opb_compression_enabled ? + y_bw_no_ubwc_10bpp : y_bw_10bpp_p010)); + ddr.opb_write = fp_div(fp_mult(dpb_factor, ddr.opb_write), + fp_mult(dpb_opb_scaling_ratio, opb_write_compression_factor)); + + ddr.line_buffer_read = + fp_div(FP_INT(tnbr_per_lcu * lcu_per_frame * fps), + FP_INT(bps(1))); + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer_read = ddr.line_buffer_read; + llc.line_buffer_write = ddr.line_buffer_write; + ddr.line_buffer_write = ddr.line_buffer_read = FP_ZERO; + } + + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.dpb_read + ddr.dpb_write + + ddr.opb_read + ddr.opb_write + + ddr.line_buffer_read + ddr.line_buffer_write; + + qsmmu_bw_overhead_factor = FP(1, 3, 100); + + ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); + llc.total = llc.dpb_read + llc.line_buffer_read + + llc.line_buffer_write + ddr.total; + + /* Add 25 percent extra for 960fps use case */ + if (fps >= 960) { + ddr.total += div_u64(ddr.total * 25, 100); + llc.total += div_u64(llc.total * 25, 100); + } + + /* Dump all the variables for easier debugging */ + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu size", "%d", lcu_size}, + {"dpb bitdepth", "%d", dpb_bpp}, + {"frame rate", "%d", fps}, + {"dpb/opb unified", "%d", unified_dpb_opb}, + {"dpb/opb downscaling ratio", DUMP_FP_FMT, + dpb_opb_scaling_ratio}, + {"dpb compression", "%d", dpb_compression_enabled}, + {"opb compression", "%d", opb_compression_enabled}, + {"dpb read compression factor", DUMP_FP_FMT, + dpb_read_compression_factor}, + {"dpb write compression factor", DUMP_FP_FMT, + dpb_write_compression_factor}, + {"frame width", "%d", width}, + {"frame height", "%d", height}, + {"llc ref read l2 cache enabled", "%d", + llc_ref_read_l2_cache_enabled}, + {"llc top line buf enabled", "%d", + llc_top_line_buf_enabled}, + + {"DERIVED PARAMETERS (1)", "", DUMP_HEADER_MAGIC}, + {"lcus/frame", "%d", lcu_per_frame}, + {"bitrate (Mbit/sec)", "%d", bitrate}, + {"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor}, + {"dpb write factor", DUMP_FP_FMT, dpb_write_factor}, + {"vsp read factor", DUMP_FP_FMT, vsp_read_factor}, + {"vsp write factor", DUMP_FP_FMT, vsp_write_factor}, + {"tnbr/lcu", "%d", tnbr_per_lcu}, + {"collocated bytes/LCU", "%d", collocated_bytes_per_lcu}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, + + {"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC}, + {"mv complexity", DUMP_FP_FMT, motion_vector_complexity}, + {"qsmmu_bw_overhead_factor", DUMP_FP_FMT, + qsmmu_bw_overhead_factor}, + + {"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, + {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, + {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, + {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, + {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, + {"opb read", DUMP_FP_FMT, ddr.opb_read}, + {"opb write", DUMP_FP_FMT, ddr.opb_write}, + {"dpb read", DUMP_FP_FMT, ddr.dpb_read}, + {"dpb write", DUMP_FP_FMT, ddr.dpb_write}, + {"dpb total", DUMP_FP_FMT, dpb_total}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc dpb read", DUMP_FP_FMT, llc.dpb_read}, + {"llc line buffer read", DUMP_FP_FMT, llc.line_buffer_read}, + {"llc line buffer write", DUMP_FP_FMT, llc.line_buffer_write}, + + }; + __dump(dump, ARRAY_SIZE(dump)); + } + + d->calc_bw_ddr = kbps(fp_round(ddr.total)); + d->calc_bw_llcc = kbps(fp_round(llc.total)); + + return ret; +} + +static u64 __calculate_encoder(struct vidc_bus_vote_data *d) +{ + /* + * XXX: Don't fool around with any of the hardcoded numbers unless you + * know /exactly/ what you're doing. Many of these numbers are + * measured heuristics and hardcoded numbers taken from the firmware. + */ + /* Encoder Parameters */ + int width, height, fps, lcu_size, bitrate, lcu_per_frame, + collocated_bytes_per_lcu, tnbr_per_lcu, dpb_bpp, + original_color_format, vertical_tile_width, rotation; + bool work_mode_1, original_compression_enabled, + low_power, cropping_or_scaling, + b_frames_enabled = false, + llc_ref_chroma_cache_enabled = false, + llc_top_line_buf_enabled = false, + llc_vpss_rot_line_buf_enabled = false; + + unsigned int bins_to_bit_factor; + fp_t dpb_compression_factor, + original_compression_factor, + original_compression_factor_y, + y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp = 0, y_bw_10bpp_p010 = 0, + input_compression_factor, + downscaling_ratio, + ref_y_read_bw_factor, ref_cbcr_read_bw_factor, + recon_write_bw_factor, + total_ref_read_crcb, + qsmmu_bw_overhead_factor; + fp_t integer_part, frac_part; + unsigned long ret = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + ref_read_y, ref_read_crcb, ref_write, + ref_write_overlap, orig_read, + line_buffer_read, line_buffer_write, + total; + } ddr = {0}; + + struct { + fp_t ref_read_crcb, line_buffer, total; + } llc = {0}; + + /* Encoder Parameters setup */ + rotation = d->rotation; + cropping_or_scaling = false; + vertical_tile_width = 960; + /* + * recon_write_bw_factor varies according to resolution and bit-depth, + * here use 1.08(1.075) for worst case. + * Similar for ref_y_read_bw_factor, it can reach 1.375 for worst case, + * here use 1.3 for average case, and can somewhat balance the + * worst case assumption for UBWC CR factors. + */ + recon_write_bw_factor = FP(1, 8, 100); + ref_y_read_bw_factor = FP(1, 30, 100); + ref_cbcr_read_bw_factor = FP(1, 50, 100); + + + /* Derived Parameters */ + fps = d->fps; + width = max(d->output_width, BASELINE_DIMENSIONS.width); + height = max(d->output_height, BASELINE_DIMENSIONS.height); + downscaling_ratio = fp_div(FP_INT(d->input_width * d->input_height), + FP_INT(d->output_width * d->output_height)); + downscaling_ratio = max(downscaling_ratio, FP_ONE); + bitrate = d->bitrate > 0 ? DIV_ROUND_UP(d->bitrate, 1000000) : + __lut(width, height, fps)->bitrate; + lcu_size = d->lcu_size; + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + tnbr_per_lcu = 16; + + dpb_bpp = __bpp(d->color_formats[0]); + + y_bw_no_ubwc_8bpp = fp_div(FP_INT(width * height * fps), + FP_INT(1000 * 1000)); + + if (dpb_bpp != 8) { + y_bw_no_ubwc_10bpp = fp_div(fp_mult(y_bw_no_ubwc_8bpp, + FP_INT(256)), FP_INT(192)); + y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2; + } + + b_frames_enabled = d->b_frames_enabled; + original_color_format = d->num_formats >= 1 ? + d->color_formats[0] : MSM_VIDC_FMT_NV12C; + + original_compression_enabled = __ubwc(original_color_format); + + work_mode_1 = d->work_mode == MSM_VIDC_STAGE_1; + low_power = d->power_mode == VIDC_POWER_LOW; + bins_to_bit_factor = 4; + + if (d->use_sys_cache) { + llc_ref_chroma_cache_enabled = true; + llc_top_line_buf_enabled = true, + llc_vpss_rot_line_buf_enabled = true; + } + + integer_part = Q16_INT(d->compression_ratio); + frac_part = Q16_FRAC(d->compression_ratio); + dpb_compression_factor = FP(integer_part, frac_part, 100); + + integer_part = Q16_INT(d->input_cr); + frac_part = Q16_FRAC(d->input_cr); + input_compression_factor = FP(integer_part, frac_part, 100); + + original_compression_factor = original_compression_factor_y = + !original_compression_enabled ? FP_ONE : + __compression_ratio(__lut(width, height, fps), dpb_bpp); + /* use input cr if it is valid (not 1), otherwise use lut */ + if (original_compression_enabled && + input_compression_factor != FP_ONE) { + original_compression_factor = input_compression_factor; + /* Luma usually has lower compression factor than Chroma, + * input cf is overall cf, add 1.08 factor for Luma cf + */ + original_compression_factor_y = + input_compression_factor > FP(1, 8, 100) ? + fp_div(input_compression_factor, FP(1, 8, 100)) : + input_compression_factor; + } + + ddr.vsp_read = fp_div(FP_INT(bitrate * bins_to_bit_factor), FP_INT(8)); + ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8)); + + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + ddr.collocated_read = fp_div(FP_INT(lcu_per_frame * + collocated_bytes_per_lcu * fps), FP_INT(bps(1))); + + ddr.collocated_write = ddr.collocated_read; + + ddr.ref_read_y = dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + if (b_frames_enabled) + ddr.ref_read_y = ddr.ref_read_y * 2; + ddr.ref_read_y = fp_div(ddr.ref_read_y, dpb_compression_factor); + + ddr.ref_read_crcb = fp_mult((ddr.ref_read_y / 2), + ref_cbcr_read_bw_factor); + + if (width > vertical_tile_width) { + ddr.ref_read_y = fp_mult(ddr.ref_read_y, + ref_y_read_bw_factor); + } + + if (llc_ref_chroma_cache_enabled) { + total_ref_read_crcb = ddr.ref_read_crcb; + ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb, + ref_cbcr_read_bw_factor); + llc.ref_read_crcb = total_ref_read_crcb - ddr.ref_read_crcb; + } + + ddr.ref_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.ref_write = fp_div(fp_mult(ddr.ref_write, FP(1, 50, 100)), + dpb_compression_factor); + + if (width > vertical_tile_width) { + ddr.ref_write_overlap = fp_mult(ddr.ref_write, + (recon_write_bw_factor - FP_ONE)); + ddr.ref_write = fp_mult(ddr.ref_write, recon_write_bw_factor); + } + + ddr.orig_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : + (original_compression_enabled ? y_bw_no_ubwc_10bpp : + y_bw_10bpp_p010); + ddr.orig_read = fp_div(fp_mult(fp_mult(ddr.orig_read, FP(1, 50, 100)), + downscaling_ratio), original_compression_factor); + if (rotation == 90 || rotation == 270) + ddr.orig_read *= lcu_size == 32 ? (dpb_bpp == 8 ? 1 : 3) : 2; + + ddr.line_buffer_read = + fp_div(FP_INT(tnbr_per_lcu * lcu_per_frame * fps), + FP_INT(bps(1))); + + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write; + ddr.line_buffer_read = ddr.line_buffer_write = FP_ZERO; + } + + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.ref_read_y + ddr.ref_read_crcb + + ddr.ref_write + ddr.ref_write_overlap + + ddr.orig_read + + ddr.line_buffer_read + ddr.line_buffer_write; + + qsmmu_bw_overhead_factor = FP(1, 3, 100); + ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); + llc.total = llc.ref_read_crcb + llc.line_buffer + ddr.total; + + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"width", "%d", width}, + {"height", "%d", height}, + {"fps", "%d", fps}, + {"dpb bitdepth", "%d", dpb_bpp}, + {"input downscaling ratio", DUMP_FP_FMT, downscaling_ratio}, + {"rotation", "%d", rotation}, + {"cropping or scaling", "%d", cropping_or_scaling}, + {"low power mode", "%d", low_power}, + {"work Mode", "%d", work_mode_1}, + {"B frame enabled", "%d", b_frames_enabled}, + {"original frame format", "%#x", original_color_format}, + {"original compression enabled", "%d", + original_compression_enabled}, + {"dpb compression factor", DUMP_FP_FMT, + dpb_compression_factor}, + {"input compression factor", DUMP_FP_FMT, + input_compression_factor}, + {"llc ref chroma cache enabled", DUMP_FP_FMT, + llc_ref_chroma_cache_enabled}, + {"llc top line buf enabled", DUMP_FP_FMT, + llc_top_line_buf_enabled}, + {"llc vpss rot line buf enabled ", DUMP_FP_FMT, + llc_vpss_rot_line_buf_enabled}, + + {"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu size", "%d", lcu_size}, + {"bitrate (Mbit/sec)", "%lu", bitrate}, + {"bins to bit factor", "%u", bins_to_bit_factor}, + {"original compression factor", DUMP_FP_FMT, + original_compression_factor}, + {"original compression factor y", DUMP_FP_FMT, + original_compression_factor_y}, + {"qsmmu_bw_overhead_factor", + DUMP_FP_FMT, qsmmu_bw_overhead_factor}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, + + {"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, + {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, + {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, + {"ref read y", DUMP_FP_FMT, ddr.ref_read_y}, + {"ref read crcb", DUMP_FP_FMT, ddr.ref_read_crcb}, + {"ref write", DUMP_FP_FMT, ddr.ref_write}, + {"ref write overlap", DUMP_FP_FMT, ddr.ref_write_overlap}, + {"original read", DUMP_FP_FMT, ddr.orig_read}, + {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, + {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc ref read crcb", DUMP_FP_FMT, llc.ref_read_crcb}, + {"llc line buffer", DUMP_FP_FMT, llc.line_buffer}, + }; + __dump(dump, ARRAY_SIZE(dump)); + } + + d->calc_bw_ddr = kbps(fp_round(ddr.total)); + d->calc_bw_llcc = kbps(fp_round(llc.total)); + + return ret; +} + +static u64 __calculate(struct msm_vidc_inst *inst, struct vidc_bus_vote_data *d) +{ + u64 value = 0; + + switch (d->domain) { + case MSM_VIDC_ENCODER: + value = __calculate_encoder(d); + break; + case MSM_VIDC_DECODER: + value = __calculate_decoder(d); + break; + default: + i_vpr_e(inst, "%s: Unknown Domain %#x", __func__, d->domain); + } + + return value; +} + +int msm_vidc_calc_bw_iris2(struct msm_vidc_inst *inst, + struct vidc_bus_vote_data *vidc_data) +{ + int value = 0; + + if (!vidc_data) + return value; + + value = __calculate(inst, vidc_data); + + return value; +} diff --git a/qcom/opensource/video-driver/driver/variant/iris3/inc/hfi_buffer_iris3.h b/qcom/opensource/video-driver/driver/variant/iris3/inc/hfi_buffer_iris3.h new file mode 100644 index 0000000000..dc233d9692 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris3/inc/hfi_buffer_iris3.h @@ -0,0 +1,1800 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __HFI_BUFFER_IRIS3__ +#define __HFI_BUFFER_IRIS3__ + +#include +#include "hfi_property.h" + +typedef u8 HFI_U8; +typedef s8 HFI_S8; +typedef u16 HFI_U16; +typedef s16 HFI_S16; +typedef u32 HFI_U32; +typedef s32 HFI_S32; +typedef u64 HFI_U64; +typedef HFI_U32 HFI_BOOL; + +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#ifndef MAX +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#define HFI_ALIGNMENT_4096 (4096) + +#define BUF_SIZE_ALIGN_16 (16) +#define BUF_SIZE_ALIGN_32 (32) +#define BUF_SIZE_ALIGN_64 (64) +#define BUF_SIZE_ALIGN_128 (128) +#define BUF_SIZE_ALIGN_256 (256) +#define BUF_SIZE_ALIGN_512 (512) +#define BUF_SIZE_ALIGN_4096 (4096) + +#define HFI_ALIGN(a, b) (((b) & ((b) - 1)) ? (((a) + (b) - 1) / \ + (b) * (b)) : (((a) + (b) - 1) & (~((b) - 1)))) + +#define HFI_WORKMODE_1 1 +#define HFI_WORKMODE_2 2 + +#define HFI_DEFAULT_METADATA_STRIDE_MULTIPLE (64) +#define HFI_DEFAULT_METADATA_BUFFERHEIGHT_MULTIPLE (16) + +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT (8) +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH (32) +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT (8) +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH (16) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT (4) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH (48) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_HEIGHT (4) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_WIDTH (24) +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_HEIGHT (4) +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_WIDTH (16) + +#define HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width, stride_multiple)) + +#define HFI_NV12_IL_CALC_Y_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) (buf_height = HFI_ALIGN(frame_height, \ + min_buf_height_multiple)) + +#define HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width, stride_multiple)) + +#define HFI_NV12_IL_CALC_UV_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) (buf_height = HFI_ALIGN(((frame_height + 1) \ + >> 1), min_buf_height_multiple)) + +#define HFI_NV12_IL_CALC_BUF_SIZE(buf_size, y_bufSize, y_stride, y_buf_height, \ + uv_buf_size, uv_stride, uv_buf_height) \ + do { \ + y_bufSize = (y_stride * y_buf_height); \ + uv_buf_size = (uv_stride * uv_buf_height); \ + buf_size = HFI_ALIGN(y_bufSize + uv_buf_size, HFI_ALIGNMENT_4096); \ + } while (0) + +#define HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_bufSize, y_stride, y_buf_height) \ + (y_bufSize = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, \ + uv_stride, uv_buf_height) \ + (uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_NV12_UBWC_IL_CALC_BUF_SIZE_V2(buf_size,\ + frame_width, frame_height, y_stride_multiple,\ + y_buffer_height_multiple, uv_stride_multiple, \ + uv_buffer_height_multiple, y_metadata_stride_multiple, \ + y_metadata_buffer_height_multiple, \ + uv_metadata_stride_multiple, uv_metadata_buffer_height_multiple) \ + do { \ + HFI_U32 y_buf_size, uv_buf_size, y_meta_size, uv_meta_size; \ + HFI_U32 stride, _height; \ + HFI_U32 half_height = (frame_height + 1) >> 1; \ + HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width,\ + y_stride_multiple); \ + HFI_NV12_IL_CALC_Y_BUFHEIGHT(_height, half_height,\ + y_buffer_height_multiple); \ + HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_buf_size, stride, _height);\ + HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, \ + uv_stride_multiple); \ + HFI_NV12_IL_CALC_UV_BUFHEIGHT(_height, half_height, \ + uv_buffer_height_multiple); \ + HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, stride, _height);\ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(stride, frame_width,\ + y_metadata_stride_multiple, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH);\ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(_height, half_height, \ + y_metadata_buffer_height_multiple,\ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT);\ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_meta_size, stride, \ + _height); \ + HFI_UBWC_UV_METADATA_PLANE_STRIDE(stride, frame_width,\ + uv_metadata_stride_multiple, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH); \ + HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(_height, half_height,\ + uv_metadata_buffer_height_multiple,\ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT);\ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_meta_size, stride, \ + _height); \ + buf_size = (y_buf_size + uv_buf_size + y_meta_size + \ + uv_meta_size) << 1;\ + } while (0) + +#define HFI_YUV420_TP10_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \ + do { \ + stride = HFI_ALIGN(frame_width, 192); \ + stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \ + } while (0) + +#define HFI_YUV420_TP10_CALC_Y_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple)) + +#define HFI_YUV420_TP10_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \ + do { \ + stride = HFI_ALIGN(frame_width, 192); \ + stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \ + } while (0) + +#define HFI_YUV420_TP10_CALC_UV_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \ + min_buf_height_multiple)) + +#define HFI_YUV420_TP10_CALC_BUF_SIZE(buf_size, y_buf_size, y_stride,\ + y_buf_height, uv_buf_size, uv_stride, uv_buf_height) \ + do { \ + y_buf_size = (y_stride * y_buf_height); \ + uv_buf_size = (uv_stride * uv_buf_height); \ + buf_size = y_buf_size + uv_buf_size; \ + } while (0) + +#define HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_buf_size, y_stride, \ + y_buf_height) \ + (y_buf_size = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_buf_size, uv_stride, \ + uv_buf_height) \ + (uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_YUV420_TP10_UBWC_CALC_BUF_SIZE(buf_size, y_stride, y_buf_height, \ + uv_stride, uv_buf_height, y_md_stride, y_md_height, uv_md_stride, \ + uv_md_height)\ + do { \ + HFI_U32 y_data_size, uv_data_size, y_md_size, uv_md_size; \ + HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_data_size, y_stride,\ + y_buf_height); \ + HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_data_size, uv_stride, \ + uv_buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_md_size, y_md_stride, \ + y_md_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_md_size, uv_md_stride, \ + uv_md_height); \ + buf_size = y_data_size + uv_data_size + y_md_size + \ + uv_md_size; \ + } while (0) + +#define HFI_YUV420_P010_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width * 2, stride_multiple)) + +#define HFI_YUV420_P010_CALC_Y_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple)) + +#define HFI_YUV420_P010_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width * 2, stride_multiple)) + +#define HFI_YUV420_P010_CALC_UV_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \ + min_buf_height_multiple)) + +#define HFI_YUV420_P010_CALC_BUF_SIZE(buf_size, y_data_size, y_stride, \ + y_buf_height, uv_data_size, uv_stride, uv_buf_height) \ + do { \ + y_data_size = HFI_ALIGN(y_stride * y_buf_height, \ + HFI_ALIGNMENT_4096);\ + uv_data_size = HFI_ALIGN(uv_stride * uv_buf_height, \ + HFI_ALIGNMENT_4096); \ + buf_size = y_data_size + uv_data_size; \ + } while (0) + +#define HFI_RGB888_CALC_STRIDE(stride, frame_width, stride_multiple) \ + (stride = ((frame_width * 3) + stride_multiple - 1) & \ + (0xffffffff - (stride_multiple - 1))) + +#define HFI_RGB888_CALC_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = ((frame_height + min_buf_height_multiple - 1) & \ + (0xffffffff - (min_buf_height_multiple - 1)))) + +#define HFI_RGB888_CALC_BUF_SIZE(buf_size, stride, buf_height) \ + (buf_size = ((stride) * (buf_height))) + +#define HFI_RGBA8888_CALC_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN((frame_width << 2), stride_multiple)) + +#define HFI_RGBA8888_CALC_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple)) + +#define HFI_RGBA8888_CALC_BUF_SIZE(buf_size, stride, buf_height) \ + (buf_size = (stride) * (buf_height)) + +#define HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(buf_size, stride, \ + buf_height) \ + (buf_size = HFI_ALIGN((stride) * (buf_height), HFI_ALIGNMENT_4096)) + +#define HFI_RGBA8888_UBWC_BUF_SIZE(buf_size, data_buf_size, \ + metadata_buffer_size, stride, buf_height, _metadata_tride, \ + _metadata_buf_height) \ + do { \ + HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(data_buf_size, \ + stride, buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(metadata_buffer_size, \ + _metadata_tride, _metadata_buf_height); \ + buf_size = data_buf_size + metadata_buffer_size; \ + } while (0) + +#define HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, frame_width,\ + metadata_stride_multiple, tile_width_in_pels) \ + ((metadata_stride = HFI_ALIGN(((frame_width + (tile_width_in_pels - 1)) /\ + tile_width_in_pels), metadata_stride_multiple))) + +#define HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, frame_height, \ + metadata_height_multiple, tile_height_in_pels) \ + ((metadata_buf_height = HFI_ALIGN(((frame_height + \ + (tile_height_in_pels - 1)) / tile_height_in_pels), \ + metadata_height_multiple))) + +#define HFI_UBWC_UV_METADATA_PLANE_STRIDE(metadata_stride, frame_width, \ + metadata_stride_multiple, tile_width_in_pels) \ + ((metadata_stride = HFI_ALIGN(((((frame_width + 1) >> 1) +\ + (tile_width_in_pels - 1)) / tile_width_in_pels), \ + metadata_stride_multiple))) + +#define HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, frame_height,\ + metadata_height_multiple, tile_height_in_pels) \ + (metadata_buf_height = HFI_ALIGN(((((frame_height + 1) >> 1) + \ + (tile_height_in_pels - 1)) / tile_height_in_pels), \ + metadata_height_multiple)) + +#define HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(buffer_size, _metadata_tride, \ + _metadata_buf_height) \ + ((buffer_size = HFI_ALIGN(_metadata_tride * _metadata_buf_height, \ + HFI_ALIGNMENT_4096))) + +#define BUFFER_ALIGNMENT_512_BYTES 512 +#define BUFFER_ALIGNMENT_256_BYTES 256 +#define BUFFER_ALIGNMENT_128_BYTES 128 +#define BUFFER_ALIGNMENT_64_BYTES 64 +#define BUFFER_ALIGNMENT_32_BYTES 32 +#define BUFFER_ALIGNMENT_16_BYTES 16 +#define BUFFER_ALIGNMENT_8_BYTES 8 +#define BUFFER_ALIGNMENT_4_BYTES 4 + +#define VENUS_DMA_ALIGNMENT BUFFER_ALIGNMENT_256_BYTES + +#define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE 640 +#define MAX_FE_NBR_DATA_CB_LINE_BUFFER_SIZE 320 +#define MAX_FE_NBR_DATA_CR_LINE_BUFFER_SIZE 320 + +#define MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE (128 / 8) +#define MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE (128 / 8) +#define MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE (128 / 8) + +#define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE (64 * 2 * 3) +#define MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE (32 * 2 * 3) +#define MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE (16 * 2 * 3) + +#define MAX_TILE_COLUMNS 32 + +#define SIZE_VPSS_LB(Size, frame_width, frame_height, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_4tap_top_buffer_size, vpss_div2_top_buffer_size, \ + vpss_4tap_left_buffer_size, vpss_div2_left_buffer_size; \ + HFI_U32 opb_wr_top_line_luma_buffer_size, \ + opb_wr_top_line_chroma_buffer_size, \ + opb_lb_wr_llb_y_buffer_size,\ + opb_lb_wr_llb_uv_buffer_size; \ + HFI_U32 macrotiling_size; \ + vpss_4tap_top_buffer_size = vpss_div2_top_buffer_size = \ + vpss_4tap_left_buffer_size = vpss_div2_left_buffer_size = 0; \ + macrotiling_size = 32; \ + opb_wr_top_line_luma_buffer_size = HFI_ALIGN(frame_width, \ + macrotiling_size) / macrotiling_size * 256; \ + opb_wr_top_line_luma_buffer_size = \ + HFI_ALIGN(opb_wr_top_line_luma_buffer_size, \ + VENUS_DMA_ALIGNMENT) + (MAX_TILE_COLUMNS - 1) * 256; \ + opb_wr_top_line_luma_buffer_size = \ + MAX(opb_wr_top_line_luma_buffer_size, (32 * \ + HFI_ALIGN(frame_height, 8))); \ + opb_wr_top_line_chroma_buffer_size = \ + opb_wr_top_line_luma_buffer_size;\ + opb_lb_wr_llb_uv_buffer_size = opb_lb_wr_llb_y_buffer_size = \ + HFI_ALIGN((HFI_ALIGN(frame_height, 8) / (4 / 2)) * 64,\ + BUFFER_ALIGNMENT_32_BYTES); \ + Size = num_vpp_pipes * 2 * (vpss_4tap_top_buffer_size + \ + vpss_div2_top_buffer_size) + \ + 2 * (vpss_4tap_left_buffer_size + \ + vpss_div2_left_buffer_size) + \ + opb_wr_top_line_luma_buffer_size + \ + opb_wr_top_line_chroma_buffer_size + \ + opb_lb_wr_llb_uv_buffer_size + \ + opb_lb_wr_llb_y_buffer_size; \ + } while (0) + +#define VPP_CMD_MAX_SIZE (1 << 20) +#define NUM_HW_PIC_BUF 32 +#define BIN_BUFFER_THRESHOLD (1280 * 736) +#define H264D_MAX_SLICE 1800 +#define SIZE_H264D_BUFTAB_T (256) +#define SIZE_H264D_HW_PIC_T (1 << 11) +#define SIZE_H264D_BSE_CMD_PER_BUF (32 * 4) +#define SIZE_H264D_VPP_CMD_PER_BUF (512) + +#define SIZE_H264D_LB_FE_TOP_DATA(frame_width, frame_height) \ + (MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * HFI_ALIGN(frame_width, 16) * 3) + +#define SIZE_H264D_LB_FE_TOP_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_width + 15) >> 4)) + +#define SIZE_H264D_LB_FE_LEFT_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_height + 15) >> 4)) + +#define SIZE_H264D_LB_SE_TOP_CTRL(frame_width, frame_height) \ + (MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_width + 15) >> 4)) + +#define SIZE_H264D_LB_SE_LEFT_CTRL(frame_width, frame_height) \ + (MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_height + 15) >> 4)) + +#define SIZE_H264D_LB_PE_TOP_DATA(frame_width, frame_height) \ + (MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * ((frame_width + 15) >> 4)) + +#define SIZE_H264D_LB_VSP_TOP(frame_width, frame_height) \ + ((((frame_width + 15) >> 4) << 7)) + +#define SIZE_H264D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \ + (HFI_ALIGN(frame_height, 16) * 32) + +#define SIZE_H264D_QP(frame_width, frame_height) \ + (((frame_width + 63) >> 6) * ((frame_height + 63) >> 6) * 128) + +#define SIZE_HW_PIC(size_per_buf) \ + (NUM_HW_PIC_BUF * size_per_buf) + +#define SIZE_H264D_BSE_CMD_BUF(_size, frame_width, frame_height) \ + do { \ + HFI_U32 _height = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_32_BYTES); \ + _size = MIN((((_height + 15) >> 4) * 48), H264D_MAX_SLICE) *\ + SIZE_H264D_BSE_CMD_PER_BUF; \ + } while (0) + +#define SIZE_H264D_VPP_CMD_BUF(_size, frame_width, frame_height) \ + do { \ + HFI_U32 _height = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_32_BYTES); \ + _size = MIN((((_height + 15) >> 4) * 48), H264D_MAX_SLICE) * \ + SIZE_H264D_VPP_CMD_PER_BUF; \ + if (_size > VPP_CMD_MAX_SIZE) { \ + _size = VPP_CMD_MAX_SIZE; \ + } \ + } while (0) + +#define HFI_BUFFER_COMV_H264D(coMV_size, frame_width, \ + frame_height, _comv_bufcount) \ + do { \ + HFI_U32 frame_width_in_mbs = ((frame_width + 15) >> 4); \ + HFI_U32 frame_height_in_mbs = ((frame_height + 15) >> 4); \ + HFI_U32 col_mv_aligned_width = (frame_width_in_mbs << 7); \ + HFI_U32 col_zero_aligned_width = (frame_width_in_mbs << 2); \ + HFI_U32 col_zero_size = 0, size_colloc = 0; \ + col_mv_aligned_width = HFI_ALIGN(col_mv_aligned_width, \ + BUFFER_ALIGNMENT_16_BYTES); \ + col_zero_aligned_width = HFI_ALIGN(col_zero_aligned_width, \ + BUFFER_ALIGNMENT_16_BYTES); \ + col_zero_size = col_zero_aligned_width * \ + ((frame_height_in_mbs + 1) >> 1); \ + col_zero_size = HFI_ALIGN(col_zero_size, \ + BUFFER_ALIGNMENT_64_BYTES); \ + col_zero_size <<= 1; \ + col_zero_size = HFI_ALIGN(col_zero_size, \ + BUFFER_ALIGNMENT_512_BYTES); \ + size_colloc = col_mv_aligned_width * ((frame_height_in_mbs + \ + 1) >> 1); \ + size_colloc = HFI_ALIGN(size_colloc, \ + BUFFER_ALIGNMENT_64_BYTES); \ + size_colloc <<= 1; \ + size_colloc = HFI_ALIGN(size_colloc, \ + BUFFER_ALIGNMENT_512_BYTES); \ + size_colloc += (col_zero_size + SIZE_H264D_BUFTAB_T * 2); \ + coMV_size = size_colloc * (_comv_bufcount); \ + coMV_size += BUFFER_ALIGNMENT_512_BYTES; \ + } while (0) + +#define HFI_BUFFER_NON_COMV_H264D(_size, frame_width, frame_height, \ + num_vpp_pipes) \ + do { \ + HFI_U32 _size_bse, _size_vpp; \ + SIZE_H264D_BSE_CMD_BUF(_size_bse, frame_width, frame_height); \ + SIZE_H264D_VPP_CMD_BUF(_size_vpp, frame_width, frame_height); \ + _size = HFI_ALIGN(_size_bse, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(_size_vpp, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), \ + VENUS_DMA_ALIGNMENT); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define HFI_BUFFER_LINE_H264D(_size, frame_width, frame_height, \ + is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_lb_size = 0; \ + _size = HFI_ALIGN(SIZE_H264D_LB_FE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_FE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H264D_LB_SE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_SE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * \ + num_vpp_pipes + \ + HFI_ALIGN(SIZE_H264D_LB_PE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_VSP_TOP(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_RECON_DMA_METADATA_WR\ + (frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * 2 + HFI_ALIGN(SIZE_H264D_QP\ + (frame_width, frame_height), VENUS_DMA_ALIGNMENT); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \ + num_vpp_pipes); \ + } \ + _size = HFI_ALIGN((_size + vpss_lb_size), \ + VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define H264_CABAC_HDR_RATIO_HD_TOT 1 +#define H264_CABAC_RES_RATIO_HD_TOT 3 + +#define SIZE_H264D_HW_BIN_BUFFER(_size, frame_width, frame_height, \ + delay, num_vpp_pipes) \ + do { \ + HFI_U32 size_yuv, size_bin_hdr, size_bin_res; \ + size_yuv = ((frame_width * frame_height) <= \ + BIN_BUFFER_THRESHOLD) ?\ + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : \ + ((frame_width * frame_height * 3) >> 1); \ + size_bin_hdr = size_yuv * H264_CABAC_HDR_RATIO_HD_TOT; \ + size_bin_res = size_yuv * H264_CABAC_RES_RATIO_HD_TOT; \ + size_bin_hdr = size_bin_hdr * (((((HFI_U32)(delay)) & 31) /\ + 10) + 2) / 2; \ + size_bin_res = size_bin_res * (((((HFI_U32)(delay)) & 31) /\ + 10) + 2) / 2; \ + size_bin_hdr = HFI_ALIGN(size_bin_hdr / num_vpp_pipes,\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + size_bin_res = HFI_ALIGN(size_bin_res / num_vpp_pipes, \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + _size = size_bin_hdr + size_bin_res; \ + } while (0) + +#define HFI_BUFFER_BIN_H264D(_size, frame_width, frame_height, is_interlaced, \ + delay, num_vpp_pipes) \ + do { \ + HFI_U32 n_aligned_w = HFI_ALIGN(frame_width, \ + BUFFER_ALIGNMENT_16_BYTES);\ + HFI_U32 n_aligned_h = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_16_BYTES); \ + if (!is_interlaced) { \ + SIZE_H264D_HW_BIN_BUFFER(_size, n_aligned_w, \ + n_aligned_h, delay, num_vpp_pipes); \ + } else { \ + _size = 0; \ + } \ + } while (0) + +#define NUM_SLIST_BUF_H264 (256 + 32) +#define SIZE_SLIST_BUF_H264 (512) +#define SIZE_SEI_USERDATA (4096) +#define H264_NUM_FRM_INFO (66) +#define H264_DISPLAY_BUF_SIZE (3328) +#define SIZE_DOLBY_RPU_METADATA (41 * 1024) +#define HFI_BUFFER_PERSIST_H264D(_size, rpu_enabled) \ + (_size = HFI_ALIGN((SIZE_SLIST_BUF_H264 * NUM_SLIST_BUF_H264 + \ + H264_DISPLAY_BUF_SIZE * H264_NUM_FRM_INFO + \ + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA + \ + rpu_enabled * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA), \ + VENUS_DMA_ALIGNMENT)) + +#define LCU_MAX_SIZE_PELS 64 +#define LCU_MIN_SIZE_PELS 16 + +#define H265D_MAX_SLICE 1200 +#define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T +#define SIZE_H265D_BSE_CMD_PER_BUF (16 * sizeof(HFI_U32)) +#define SIZE_H265D_VPP_CMD_PER_BUF (256) + +#define SIZE_H265D_LB_FE_TOP_DATA(frame_width, frame_height) \ + (MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * \ + (HFI_ALIGN(frame_width, 64) + 8) * 2) + +#define SIZE_H265D_LB_FE_TOP_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + (HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_FE_LEFT_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + (HFI_ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_SE_TOP_CTRL(frame_width, frame_height) \ + ((LCU_MAX_SIZE_PELS / 8 * (128 / 8)) * ((frame_width + 15) >> 4)) + +#define SIZE_H265D_LB_SE_LEFT_CTRL(frame_width, frame_height) \ + (MAX(((frame_height + 16 - 1) / 8) * \ + MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, \ + MAX(((frame_height + 32 - 1) / 8) * \ + MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((frame_height + 64 - 1) / 8) * \ + MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE))) + +#define SIZE_H265D_LB_PE_TOP_DATA(frame_width, frame_height) \ + (MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * (HFI_ALIGN(frame_width, \ + LCU_MIN_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_VSP_TOP(frame_width, frame_height) \ + (((frame_width + 63) >> 6) * 128) + +#define SIZE_H265D_LB_VSP_LEFT(frame_width, frame_height) \ + (((frame_height + 63) >> 6) * 128) + +#define SIZE_H265D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \ + SIZE_H264D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) + +#define SIZE_H265D_QP(frame_width, frame_height) \ + SIZE_H264D_QP(frame_width, frame_height) + +#define SIZE_H265D_BSE_CMD_BUF(_size, frame_width, frame_height)\ + do { \ + _size = HFI_ALIGN(((HFI_ALIGN(frame_width, \ + LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * \ + (HFI_ALIGN(frame_height, LCU_MAX_SIZE_PELS) /\ + LCU_MIN_SIZE_PELS)) * NUM_HW_PIC_BUF, VENUS_DMA_ALIGNMENT); \ + _size = MIN(_size, H265D_MAX_SLICE + 1); \ + _size = 2 * _size * SIZE_H265D_BSE_CMD_PER_BUF; \ + } while (0) + +#define SIZE_H265D_VPP_CMD_BUF(_size, frame_width, frame_height) \ + do { \ + _size = HFI_ALIGN(((HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) /\ + LCU_MIN_SIZE_PELS) * (HFI_ALIGN(frame_height, \ + LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) * \ + NUM_HW_PIC_BUF, VENUS_DMA_ALIGNMENT); \ + _size = MIN(_size, H265D_MAX_SLICE + 1); \ + _size = HFI_ALIGN(_size, 4); \ + _size = 2 * _size * SIZE_H265D_VPP_CMD_PER_BUF; \ + if (_size > VPP_CMD_MAX_SIZE) { \ + _size = VPP_CMD_MAX_SIZE; \ + } \ + } while (0) + +#define HFI_BUFFER_COMV_H265D(_size, frame_width, frame_height, \ + _comv_bufcount) \ + do { \ + _size = HFI_ALIGN(((((frame_width + 15) >> 4) * \ + ((frame_height + 15) >> 4)) << 8), \ + BUFFER_ALIGNMENT_512_BYTES); \ + _size *= _comv_bufcount; \ + _size += BUFFER_ALIGNMENT_512_BYTES; \ + } while (0) + +#define HDR10_HIST_EXTRADATA_SIZE (4 * 1024) + +#define HFI_BUFFER_NON_COMV_H265D(_size, frame_width, frame_height, \ + num_vpp_pipes) \ + do { \ + HFI_U32 _size_bse, _size_vpp; \ + SIZE_H265D_BSE_CMD_BUF(_size_bse, frame_width, \ + frame_height); \ + SIZE_H265D_VPP_CMD_BUF(_size_vpp, frame_width, \ + frame_height); \ + _size = HFI_ALIGN(_size_bse, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(_size_vpp, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(NUM_HW_PIC_BUF * 20 * 22 * 4, \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(2 * sizeof(HFI_U16) * \ + (HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) / \ + LCU_MIN_SIZE_PELS) * (HFI_ALIGN(frame_height, \ + LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_HW_PIC(SIZE_H265D_HW_PIC_T), \ + VENUS_DMA_ALIGNMENT) + \ + HDR10_HIST_EXTRADATA_SIZE; \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define HFI_BUFFER_LINE_H265D(_size, frame_width, frame_height, \ + is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_lb_size = 0; \ + _size = HFI_ALIGN(SIZE_H265D_LB_FE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_FE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H265D_LB_SE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H265D_LB_SE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_PE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_VSP_TOP(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_VSP_LEFT(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H265D_LB_RECON_DMA_METADATA_WR\ + (frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * 4 + \ + HFI_ALIGN(SIZE_H265D_QP(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height,\ + num_vpp_pipes); \ + } \ + _size = HFI_ALIGN((_size + vpss_lb_size), \ + VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define H265_CABAC_HDR_RATIO_HD_TOT 2 +#define H265_CABAC_RES_RATIO_HD_TOT 2 + +#define SIZE_H265D_HW_BIN_BUFFER(_size, frame_width, frame_height, \ + delay, num_vpp_pipes) \ + do { \ + HFI_U32 size_yuv, size_bin_hdr, size_bin_res; \ + size_yuv = ((frame_width * frame_height) <= \ + BIN_BUFFER_THRESHOLD) ? \ + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : \ + ((frame_width * frame_height * 3) >> 1); \ + size_bin_hdr = size_yuv * H265_CABAC_HDR_RATIO_HD_TOT; \ + size_bin_res = size_yuv * H265_CABAC_RES_RATIO_HD_TOT; \ + size_bin_hdr = size_bin_hdr * \ + (((((HFI_U32)(delay)) & 31) / 10) + 2) / 2; \ + size_bin_res = size_bin_res * \ + (((((HFI_U32)(delay)) & 31) / 10) + 2) / 2; \ + size_bin_hdr = HFI_ALIGN(size_bin_hdr / \ + num_vpp_pipes, VENUS_DMA_ALIGNMENT) * \ + num_vpp_pipes; \ + size_bin_res = HFI_ALIGN(size_bin_res / num_vpp_pipes,\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + _size = size_bin_hdr + size_bin_res; \ + } while (0) + +#define HFI_BUFFER_BIN_H265D(_size, frame_width, frame_height, \ + is_interlaced, delay, num_vpp_pipes) \ + do { \ + HFI_U32 n_aligned_w = HFI_ALIGN(frame_width, \ + BUFFER_ALIGNMENT_16_BYTES); \ + HFI_U32 n_aligned_h = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_16_BYTES); \ + if (!is_interlaced) { \ + SIZE_H265D_HW_BIN_BUFFER(_size, n_aligned_w, \ + n_aligned_h, delay, num_vpp_pipes); \ + } else { \ + _size = 0; \ + } \ + } while (0) + +#define SIZE_SLIST_BUF_H265 (1 << 10) +#define NUM_SLIST_BUF_H265 (80 + 20) +#define H265_NUM_TILE_COL 32 +#define H265_NUM_TILE_ROW 128 +#define H265_NUM_TILE (H265_NUM_TILE_ROW * H265_NUM_TILE_COL + 1) +#define H265_NUM_FRM_INFO (48) +#define H265_DISPLAY_BUF_SIZE (3072) +#define HFI_BUFFER_PERSIST_H265D(_size, rpu_enabled) \ + (_size = HFI_ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 + \ + H265_NUM_FRM_INFO * H265_DISPLAY_BUF_SIZE + \ + H265_NUM_TILE * sizeof(HFI_U32) + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA + \ + rpu_enabled * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA),\ + VENUS_DMA_ALIGNMENT)) + +#define SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, frame_height) \ + MAX(((frame_height + 15) >> 4) * \ + MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, \ + MAX(((frame_height + 31) >> 5) * \ + MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((frame_height + 63) >> 6) * MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)) +#define SIZE_VPXD_LB_FE_TOP_CTRL(frame_width, frame_height) \ + (((HFI_ALIGN(frame_width, 64) + 8) * 10 * 2)) +#define SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height) \ + (((frame_width + 15) >> 4) * MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE) +#define SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height) \ + MAX(((frame_height + 15) >> 4) * \ + MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE,\ + MAX(((frame_height + 31) >> 5) * \ + MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((frame_height + 63) >> 6) * MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)) +#define SIZE_VPXD_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \ + HFI_ALIGN((HFI_ALIGN(frame_height, 8) / (4 / 2)) * 64,\ + BUFFER_ALIGNMENT_32_BYTES) +#define SIZE_MP2D_LB_FE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(frame_width, 16) + 8) * 10 * 2) +#define SIZE_VP9D_LB_FE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) + 8) * 10 * 2) +#define SIZE_MP2D_LB_PE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(frame_width, 16) >> 4) * 64) +#define SIZE_VP9D_LB_PE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) >> 6) * 176) +#define SIZE_MP2D_LB_VSP_TOP(frame_width, frame_height) \ + (((HFI_ALIGN(frame_width, 16) >> 4) * 64 / 2) + 256) +#define SIZE_VP9D_LB_VSP_TOP(frame_width, frame_height) \ + ((((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) >> 6) * 64 * 8) + 256)) + +#define HFI_IRIS3_VP9D_COMV_SIZE \ + ((((8192 + 63) >> 6) * ((4320 + 63) >> 6) * 8 * 8 * 2 * 8)) + +#define SIZE_VP9D_QP(frame_width, frame_height) \ + SIZE_H264D_QP(frame_width, frame_height) + +#define HFI_IRIS3_VP9D_LB_SIZE(_size, frame_width, frame_height, num_vpp_pipes)\ + do { \ + _size = HFI_ALIGN(SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_VP9D_LB_VSP_TOP(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VPXD_LB_FE_TOP_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + 2 * \ + HFI_ALIGN(SIZE_VPXD_LB_RECON_DMA_METADATA_WR \ + (frame_width, frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VP9D_LB_PE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VP9D_LB_FE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VP9D_QP(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define HFI_BUFFER_LINE_VP9D(_size, frame_width, frame_height, \ + _yuv_bufcount_min, is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 _lb_size = 0; \ + HFI_U32 vpss_lb_size = 0; \ + HFI_IRIS3_VP9D_LB_SIZE(_lb_size, frame_width, frame_height,\ + num_vpp_pipes); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \ + num_vpp_pipes); \ + } \ + _size = _lb_size + vpss_lb_size; \ + } while (0) + +#define VPX_DECODER_FRAME_CONCURENCY_LVL (2) +#define VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO 1 / 2 +#define VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO 3 / 2 + +#define HFI_BUFFER_BIN_VP9D(_size, frame_width, frame_height, \ + is_interlaced, num_vpp_pipes) \ + do { \ + HFI_U32 _size_yuv = HFI_ALIGN(frame_width, \ + BUFFER_ALIGNMENT_16_BYTES) *\ + HFI_ALIGN(frame_height, BUFFER_ALIGNMENT_16_BYTES) * 3 / 2; \ + if (!is_interlaced) { \ + _size = HFI_ALIGN(((MAX(_size_yuv, \ + ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * \ + VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO * \ + VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(((MAX(_size_yuv, \ + ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * \ + VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO * \ + VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), \ + VENUS_DMA_ALIGNMENT); \ + _size = _size * num_vpp_pipes; \ + } \ + else \ + _size = 0; \ + } while (0) + +#define VP9_NUM_FRAME_INFO_BUF 32 +#define VP9_NUM_PROBABILITY_TABLE_BUF (VP9_NUM_FRAME_INFO_BUF + 4) +#define VP9_PROB_TABLE_SIZE (3840) +#define VP9_FRAME_INFO_BUF_SIZE (6144) + +#define VP9_UDC_HEADER_BUF_SIZE (3 * 128) +#define MAX_SUPERFRAME_HEADER_LEN (34) +#define CCE_TILE_OFFSET_SIZE HFI_ALIGN(32 * 4 * 4, BUFFER_ALIGNMENT_32_BYTES) + +#define HFI_BUFFER_PERSIST_VP9D(_size) \ + (_size = HFI_ALIGN(VP9_NUM_PROBABILITY_TABLE_BUF * VP9_PROB_TABLE_SIZE, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(HFI_IRIS3_VP9D_COMV_SIZE, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(MAX_SUPERFRAME_HEADER_LEN, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(VP9_UDC_HEADER_BUF_SIZE, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(VP9_NUM_FRAME_INFO_BUF * \ + CCE_TILE_OFFSET_SIZE, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(VP9_NUM_FRAME_INFO_BUF * VP9_FRAME_INFO_BUF_SIZE, \ + VENUS_DMA_ALIGNMENT) + HDR10_HIST_EXTRADATA_SIZE) + +#define HFI_BUFFER_LINE_MP2D(_size, frame_width, frame_height, \ +_yuv_bufcount_min, is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_lb_size = 0; \ + _size = HFI_ALIGN(SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_MP2D_LB_VSP_TOP(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(SIZE_VPXD_LB_FE_TOP_CTRL\ + (frame_width, frame_height), VENUS_DMA_ALIGNMENT) + \ + 2 * HFI_ALIGN(SIZE_VPXD_LB_RECON_DMA_METADATA_WR(frame_width,\ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_MP2D_LB_PE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_MP2D_LB_FE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \ + num_vpp_pipes); \ + } \ + _size += vpss_lb_size; \ + } while (0) + +#define HFI_BUFFER_BIN_MP2D(_size, frame_width, frame_height, is_interlaced) 0 + +#define QMATRIX_SIZE (sizeof(HFI_U32) * 128 + 256) +#define MP2D_QPDUMP_SIZE 115200 +#define HFI_BUFFER_PERSIST_MP2D(_size) \ + (_size = QMATRIX_SIZE + MP2D_QPDUMP_SIZE;) + +#define AV1D_LCU_MAX_SIZE_PELS 128 +#define AV1D_LCU_MIN_SIZE_PELS 64 +#define AV1D_MAX_TILE_COLS 64 + +#define HFI_BUFFER_COMV_AV1D(_size, frame_width, frame_height, \ + _comv_bufcount) \ + do { \ \ + _size = 2 * HFI_ALIGN(MAX(((frame_width + 63) / 64) * \ + ((frame_height + 63) / 64) * 512, \ + ((frame_width + 127) / 128) * \ + ((frame_height + 127) / 128) * 2816), \ + VENUS_DMA_ALIGNMENT); \ + _size *= _comv_bufcount; \ + } while (0) + +#define SIZE_AV1D_LB_FE_TOP_DATA(frame_width, frame_height) \ + (HFI_ALIGN(frame_width, AV1D_LCU_MAX_SIZE_PELS) * ((16 * 10) >> 3) + \ + HFI_ALIGN(frame_width, AV1D_LCU_MAX_SIZE_PELS) / 2 * ((16 * 6) >> 3) * 2) + +#define SIZE_AV1D_LB_FE_LEFT_DATA(frame_width, frame_height) \ + (32 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 16) + \ + 16 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 2 + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 8) * 2 + \ + 24 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 16) + \ + 24 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 2 + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 12) * 2 + \ + 24 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 16) + \ + 16 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 16) + \ + 16 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 2 + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 12) * 2) + +#define SIZE_AV1D_LB_FE_TOP_CTRL(frame_width, frame_height) \ + (10 * ((frame_width + AV1D_LCU_MIN_SIZE_PELS - 1) / \ + AV1D_LCU_MIN_SIZE_PELS) * 128 / 8) + +#define SIZE_AV1D_LB_FE_LEFT_CTRL(frame_width, frame_height) \ + (16 * ((HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 16) + \ + (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS)) + \ + 3 * 16 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS)) + +#define SIZE_AV1D_LB_SE_TOP_CTRL(frame_width, frame_height) \ + (((frame_width + 7) / 8) * 16) + +#define SIZE_AV1D_LB_SE_LEFT_CTRL(frame_width, frame_height) \ + (MAX(((frame_height + 15) / 16) * MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, \ + MAX(((frame_height + 31) / 32) * MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((frame_height + 63) / 64) * MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE))) + +#define SIZE_AV1D_LB_PE_TOP_DATA(frame_width, frame_height) \ + (MAX(((frame_width + 15) / 16) * MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE, \ + MAX(((frame_width + 31) / 32) * MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE, \ + ((frame_width + 63) / 64) * MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE))) + +#define SIZE_AV1D_LB_VSP_TOP(frame_width, frame_height) \ + (MAX(((frame_width + 63) / 64) * 1280, ((frame_width + 127) / 128) * 2304)) + +#define SIZE_AV1D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \ + ((HFI_ALIGN(frame_height, 8) / (4 / 2)) * 64) + +#define SIZE_AV1D_QP(frame_width, frame_height) \ + SIZE_H264D_QP(frame_width, frame_height) + +#define SIZE_AV1D_LB_OPB_WR1_NV12_UBWC(_size, frame_width, frame_height) \ + do { \ + HFI_U32 y_width, y_width_a = 128; \ + HFI_NV12_IL_CALC_Y_STRIDE(y_width, frame_width, y_width_a); \ + _size = (256 * ((y_width + 31) / 32 + (AV1D_MAX_TILE_COLS - 1))); \ + } while (0) + +#define SIZE_AV1D_LB_OPB_WR1_TP10_UBWC(_size, frame_width, frame_height) \ + do { \ + HFI_U32 y_width, y_width_a = 256; \ + HFI_YUV420_TP10_CALC_Y_STRIDE(y_width, frame_width, y_width_a); \ + _size = (256 * ((y_width + 47) / 48 + (AV1D_MAX_TILE_COLS - 1))); \ + } while (0) + +#define SIZE_AV1D_IBC_NV12_UBWC(_size, frame_width, frame_height) \ + do { \ + HFI_U32 y_width_a = 128, y_height_a = 32; \ + HFI_U32 uv_width_a = 128, uv_height_a = 32; \ + HFI_U32 yBufSize, uvBufSize, y_width, y_height, uv_width, uv_height; \ + HFI_U32 y_meta_width_a = 64, y_meta_height_a = 16; \ + HFI_U32 uv_meta_width_a = 64, uv_meta_height_a = 16; \ + HFI_U32 meta_height, meta_stride, meta_size; \ + HFI_U32 tile_width_y = HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH; \ + HFI_U32 tile_height_y = HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT; \ + HFI_U32 tile_width_uv = HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH; \ + HFI_U32 tile_height_uv = \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT; \ + HFI_NV12_IL_CALC_Y_STRIDE(y_width, frame_width, y_width_a); \ + HFI_NV12_IL_CALC_Y_BUFHEIGHT(y_height, frame_height, y_height_a); \ + HFI_NV12_IL_CALC_UV_STRIDE(uv_width, frame_width, uv_width_a); \ + HFI_NV12_IL_CALC_UV_BUFHEIGHT(uv_height, frame_height, uv_height_a); \ + HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(yBufSize, y_width, y_height); \ + HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uvBufSize, uv_width, uv_height); \ + _size = yBufSize + uvBufSize; \ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(meta_stride, frame_width, \ + y_meta_width_a, tile_width_y); \ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(meta_height, frame_height, \ + y_meta_height_a, tile_height_y); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size, \ + meta_stride, meta_height); \ + _size += meta_size; \ + HFI_UBWC_UV_METADATA_PLANE_STRIDE(meta_stride, frame_width, \ + uv_meta_width_a, tile_width_uv); \ + HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(meta_height, frame_height, \ + uv_meta_height_a, tile_height_uv); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size, \ + meta_stride, meta_height); \ + _size += meta_size; \ + } while (0) + +#define SIZE_AV1D_IBC_TP10_UBWC(_size, frame_width, frame_height) \ + do { \ + HFI_U32 y_width_a = 256, y_height_a = 16, \ + uv_width_a = 256, uv_height_a = 16; \ + HFI_U32 yBufSize, uvBufSize, y_width, y_height, uv_width, uv_height; \ + HFI_U32 y_meta_width_a = 64, y_meta_height_a = 16, \ + uv_meta_width_a = 64, uv_meta_height_a = 16; \ + HFI_U32 meta_height, meta_stride, meta_size; \ + HFI_U32 tile_width_y = HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH; \ + HFI_U32 tile_height_y = HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT; \ + HFI_U32 tile_width_uv = HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_WIDTH; \ + HFI_U32 tile_height_uv = \ + HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_HEIGHT; \ + HFI_YUV420_TP10_CALC_Y_STRIDE(y_width, frame_width, y_width_a); \ + HFI_YUV420_TP10_CALC_Y_BUFHEIGHT(y_height, frame_height, y_height_a); \ + HFI_YUV420_TP10_CALC_UV_STRIDE(uv_width, frame_width, uv_width_a); \ + HFI_YUV420_TP10_CALC_UV_BUFHEIGHT(uv_height, frame_height, \ + uv_height_a); \ + HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(yBufSize, y_width, y_height); \ + HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uvBufSize, uv_width, uv_height); \ + _size = yBufSize + uvBufSize; \ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(meta_stride, frame_width, \ + y_meta_width_a, tile_width_y); \ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(meta_height, frame_height, \ + y_meta_height_a, tile_height_y); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size, \ + meta_stride, meta_height); \ + _size += meta_size; \ + HFI_UBWC_UV_METADATA_PLANE_STRIDE(meta_stride, frame_width, \ + uv_meta_width_a, tile_width_uv); \ + HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(meta_height, frame_height, \ + uv_meta_height_a, tile_height_uv); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size, \ + meta_stride, meta_height); \ + _size += meta_size; \ + } while (0) + +#define HFI_BUFFER_LINE_AV1D(_size, frame_width, frame_height, isOPB, \ + num_vpp_pipes) \ + do { \ + HFI_U32 vpssLBSize, opbwr1BufSize, opbwr8, opbwr10; \ + _size = HFI_ALIGN(SIZE_AV1D_LB_FE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_AV1D_LB_FE_TOP_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_AV1D_LB_FE_LEFT_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_AV1D_LB_FE_LEFT_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_AV1D_LB_SE_LEFT_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_AV1D_LB_SE_TOP_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_AV1D_LB_PE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_AV1D_LB_VSP_TOP(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_AV1D_LB_RECON_DMA_METADATA_WR(frame_width, \ + frame_height), \ + VENUS_DMA_ALIGNMENT) * 2 + \ + HFI_ALIGN(SIZE_AV1D_QP(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT); \ + SIZE_AV1D_LB_OPB_WR1_NV12_UBWC(opbwr8, frame_width, frame_height); \ + SIZE_AV1D_LB_OPB_WR1_TP10_UBWC(opbwr10, frame_width, frame_height); \ + opbwr1BufSize = MAX(opbwr8, opbwr10); \ + _size = HFI_ALIGN((_size + opbwr1BufSize), VENUS_DMA_ALIGNMENT); \ + if (isOPB) { \ + SIZE_VPSS_LB(vpssLBSize, frame_width, frame_height, num_vpp_pipes); \ + _size = HFI_ALIGN((_size + vpssLBSize), VENUS_DMA_ALIGNMENT); \ + } \ + } while (0) + +#define HFI_BUFFER_IBC_AV1D(_size, frame_width, frame_height) \ + do { \ \ + HFI_U32 ibc8, ibc10; \ + SIZE_AV1D_IBC_NV12_UBWC(ibc8, frame_width, frame_height); \ + SIZE_AV1D_IBC_TP10_UBWC(ibc10, frame_width, frame_height); \ + _size = HFI_ALIGN(MAX(ibc8, ibc10), VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define AV1_CABAC_HDR_RATIO_HD_TOT 2 +#define AV1_CABAC_RES_RATIO_HD_TOT 2 +/* some content need more bin buffer, + * but limit buffer size for high resolution + */ +#define SIZE_AV1D_HW_BIN_BUFFER(_size, frame_width, frame_height, delay, \ + num_vpp_pipes) \ + do { \ + HFI_U32 size_yuv, size_bin_hdr, size_bin_res; \ + size_yuv = ((frame_width * frame_height) <= BIN_BUFFER_THRESHOLD) ? \ + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : \ + ((frame_width * frame_height * 3) >> 1); \ + size_bin_hdr = size_yuv * AV1_CABAC_HDR_RATIO_HD_TOT; \ + size_bin_res = size_yuv * AV1_CABAC_RES_RATIO_HD_TOT; \ + size_bin_hdr = size_bin_hdr * \ + (((((HFI_U32)(delay)) & 31) / 10) + 2) / 2; \ + size_bin_res = size_bin_res * \ + (((((HFI_U32)(delay)) & 31) / 10) + 2) / 2; \ + size_bin_hdr = HFI_ALIGN(size_bin_hdr / num_vpp_pipes, \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + size_bin_res = HFI_ALIGN(size_bin_res / num_vpp_pipes, \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + _size = size_bin_hdr + size_bin_res; \ + } while (0) + +#define HFI_BUFFER_BIN_AV1D(_size, frame_width, frame_height, isInterlaced, \ + delay, num_vpp_pipes) \ + do { \ + HFI_U32 nAlignedW = HFI_ALIGN(frame_width, BUFFER_ALIGNMENT_16_BYTES); \ + HFI_U32 nAlignedH = HFI_ALIGN(frame_height, BUFFER_ALIGNMENT_16_BYTES); \ + if (!isInterlaced) { \ + SIZE_AV1D_HW_BIN_BUFFER(_size, nAlignedW, nAlignedH, \ + delay, num_vpp_pipes); \ + } else { \ + _size = 0; \ + } \ + } while (0) + +#define AV1D_NUM_HW_PIC_BUF 16 +#define AV1D_NUM_FRAME_HEADERS 16 + +#define SIZE_AV1D_SEQUENCE_HEADER 768 +#define SIZE_AV1D_METADATA 512 +#define SIZE_AV1D_FRAME_HEADER 1280 +#define SIZE_AV1D_TILE_OFFSET 65536 +#define SIZE_AV1D_QM 3328 +#define SIZE_AV1D_PROB_TABLE 22784 + +#define AV1D_SIZE_BSE_COL_MV_64x64 512 +#define AV1D_SIZE_BSE_COL_MV_128x128 2816 +#define SIZE_AV1D_COL_MV MAX((((8192 + 63) / 64) * ((4352 + 63) / 64) * \ + AV1D_SIZE_BSE_COL_MV_64x64), \ + (((8192 + 127) / 128) * ((4352 + 127) / 128) * \ + AV1D_SIZE_BSE_COL_MV_128x128)) + +#define HFI_BUFFER_PERSIST_AV1D(_size, max_width, max_height, total_ref_count) \ + do { \ + HFI_U32 comv_size; \ + HFI_BUFFER_COMV_AV1D(comv_size, max_width, max_height, total_ref_count); \ + _size = \ + HFI_ALIGN((SIZE_AV1D_SEQUENCE_HEADER * 2 + \ + SIZE_AV1D_METADATA + \ + AV1D_NUM_HW_PIC_BUF * (SIZE_AV1D_TILE_OFFSET + SIZE_AV1D_QM) + \ + AV1D_NUM_FRAME_HEADERS * (SIZE_AV1D_FRAME_HEADER + \ + 2 * SIZE_AV1D_PROB_TABLE) + \ + comv_size + HDR10_HIST_EXTRADATA_SIZE + \ + SIZE_AV1D_METADATA * AV1D_NUM_HW_PIC_BUF), VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define HFI_BUFFER_BITSTREAM_ENC(size, frame_width, frame_height, \ + rc_type, is_ten_bit) \ + do { \ + HFI_U32 aligned_width, aligned_height, bitstream_size, yuv_size; \ + aligned_width = HFI_ALIGN(frame_width, 32); \ + aligned_height = HFI_ALIGN(frame_height, 32); \ + bitstream_size = aligned_width * aligned_height * 3; \ + yuv_size = (aligned_width * aligned_height * 3) >> 1; \ + if (aligned_width * aligned_height > (4096 * 2176)) { \ + /* bitstream_size = 0.25 * yuv_size; */ \ + bitstream_size = (bitstream_size >> 3); \ + } \ + else if (aligned_width * aligned_height > (1280 * 720)) { \ + /* bitstream_size = 0.5 * yuv_size; */ \ + bitstream_size = (bitstream_size >> 2); \ + } else { \ + /* bitstream_size = 2 * yuv_size; */ \ + } \ + if (((rc_type == HFI_RC_CQ) || (rc_type == HFI_RC_OFF)) \ + && (bitstream_size < yuv_size)) { \ + bitstream_size = (bitstream_size << 1);\ + } \ + if (is_ten_bit) { \ + bitstream_size = (bitstream_size) + \ + (bitstream_size >> 2); \ + } \ + size = HFI_ALIGN(bitstream_size, HFI_ALIGNMENT_4096); \ + } while (0) + +#define HFI_IRIS3_ENC_TILE_SIZE_INFO(tile_size, tile_count, last_tile_size, \ + frame_width_coded, codec_standard, num_vpp_pipes) \ + do { \ + HFI_U32 without_tile_enc_width, min_tile_size, fixed_tile_width; \ + if (num_vpp_pipes == 4) { \ + min_tile_size = 352; \ + fixed_tile_width = 960; \ + } \ + else if (num_vpp_pipes == 2) { \ + min_tile_size = 256; \ + fixed_tile_width = 768; \ + } \ + else { \ + min_tile_size = 256; \ + fixed_tile_width = 672; \ + } \ + without_tile_enc_width = min_tile_size + fixed_tile_width; \ + if ((codec_standard == HFI_CODEC_ENCODE_HEVC) && \ + (frame_width_coded > without_tile_enc_width)) { \ + tile_size = fixed_tile_width; \ + tile_count = (frame_width_coded + tile_size - 1) / tile_size; \ + last_tile_size = (frame_width_coded - (tile_size * (tile_count - 1))); \ + if (last_tile_size < min_tile_size) { \ + tile_count -= 1; \ + last_tile_size = (tile_size + min_tile_size); \ + } \ + } else { \ + tile_size = frame_width_coded; \ + tile_count = 1; \ + last_tile_size = 0; \ + } \ + } while (0) + +#define HFI_IRIS3_ENC_MB_BASED_MULTI_SLICE_COUNT(total_slice_count, frame_width, frame_height, \ + codec_standard, multi_slice_max_mb_count, num_vpp_pipes) \ + do { \ + HFI_U32 tile_size, tile_count, last_tile_size, \ + slice_count_per_tile, slice_count_in_last_tile; \ + HFI_U32 mbs_in_one_tile, mbs_in_last_tile; \ + HFI_U32 frame_width_coded, frame_height_coded, lcu_size; \ + lcu_size = (codec_standard == HFI_CODEC_ENCODE_HEVC) ? 32 : 16; \ + frame_width_coded = HFI_ALIGN(frame_width, lcu_size); \ + frame_height_coded = HFI_ALIGN(frame_height, lcu_size); \ + HFI_IRIS3_ENC_TILE_SIZE_INFO(tile_size, tile_count, last_tile_size, \ + frame_width_coded, codec_standard, num_vpp_pipes); \ + mbs_in_one_tile = (tile_size * frame_height_coded) / (lcu_size * lcu_size); \ + slice_count_per_tile = \ + (mbs_in_one_tile + multi_slice_max_mb_count - 1) / \ + (multi_slice_max_mb_count); \ + if (last_tile_size) { \ + mbs_in_last_tile = \ + (last_tile_size * frame_height_coded) / (lcu_size * lcu_size); \ + slice_count_in_last_tile = \ + (mbs_in_last_tile + multi_slice_max_mb_count - 1) / \ + (multi_slice_max_mb_count); \ + total_slice_count = \ + (slice_count_per_tile * (tile_count - 1)) + \ + slice_count_in_last_tile; \ + } else { \ + total_slice_count = (slice_count_per_tile * tile_count); \ + } \ + } while (0) + +#define SIZE_ROI_METADATA_ENC(size_roi, frame_width, frame_height, lcu_size)\ + do { \ + HFI_U32 width_in_lcus = 0, height_in_lcus = 0, n_shift = 0; \ + HFI_U32 n_lcu_size = lcu_size; \ + while (n_lcu_size && !(n_lcu_size & 0x1)) { \ + n_shift++; \ + n_lcu_size = n_lcu_size >> 1; \ + } \ + width_in_lcus = (frame_width + (lcu_size - 1)) >> n_shift; \ + height_in_lcus = (frame_height + (lcu_size - 1)) >> n_shift; \ + size_roi = (((width_in_lcus + 7) >> 3) << 3) * \ + height_in_lcus * 2 + 256; \ + } while (0) + +#define HFI_BUFFER_INPUT_METADATA_ENC(size, frame_width, frame_height, \ + is_roi_enabled, lcu_size) \ + do { \ + HFI_U32 roi_size = 0; \ + if (is_roi_enabled) { \ + SIZE_ROI_METADATA_ENC(roi_size, frame_width, \ + frame_height, lcu_size); \ + } \ + size = roi_size + 16384; \ + size = HFI_ALIGN(size, HFI_ALIGNMENT_4096); \ + } while (0) + +#define HFI_BUFFER_INPUT_METADATA_H264E(size_metadata, frame_width, \ + frame_height, is_roi_enabled) \ + do { \ + HFI_BUFFER_INPUT_METADATA_ENC(size_metadata, frame_width, \ + frame_height, is_roi_enabled, 16); \ + } while (0) + +#define HFI_BUFFER_INPUT_METADATA_H265E(size_metadata, frame_width, \ + frame_height, is_roi_enabled) \ + do { \ + HFI_BUFFER_INPUT_METADATA_ENC(size_metadata, frame_width, \ + frame_height, is_roi_enabled, 32); \ + } while (0) + +#define HFI_BUFFER_ARP_ENC(size) \ + do { \ + size = 204800; \ + } while (0) + +#define HFI_MAX_COL_FRAME 6 +#define HFI_VENUS_VENC_TRE_WB_BUFF_SIZE (65 << 4) // bytes +#define HFI_VENUS_VENC_DB_LINE_BUFF_PER_MB 512 +#define HFI_VENUS_VPPSG_MAX_REGISTERS 2048 +#define HFI_VENUS_WIDTH_ALIGNMENT 128 +#define HFI_VENUS_WIDTH_TEN_BIT_ALIGNMENT 192 +#define HFI_VENUS_HEIGHT_ALIGNMENT 32 +#define VENUS_METADATA_STRIDE_MULTIPLE 64 +#define VENUS_METADATA_HEIGHT_MULTIPLE 16 + +#ifndef SYSTEM_LAL_TILE10 +#define SYSTEM_LAL_TILE10 192 +#endif + +#define HFI_IRIS3_ENC_RECON_BUF_COUNT(num_recon, n_bframe, ltr_count, \ + _total_hp_layers, _total_hb_layers, hybrid_hp, codec_standard) \ + do { \ + HFI_U32 num_ref = 1; \ + if (n_bframe) \ + num_ref = 2; \ + if (_total_hp_layers > 1) { \ + if (hybrid_hp) \ + num_ref = (_total_hp_layers + 1) >> 1; \ + else if (codec_standard == HFI_CODEC_ENCODE_HEVC) \ + num_ref = (_total_hp_layers + 1) >> 1; \ + else if (codec_standard == HFI_CODEC_ENCODE_AVC && \ + _total_hp_layers < 4) \ + num_ref = (_total_hp_layers - 1); \ + else \ + num_ref = _total_hp_layers; \ + } \ + if (ltr_count) \ + num_ref = num_ref + ltr_count; \ + if (_total_hb_layers > 1) { \ + if (codec_standard == HFI_CODEC_ENCODE_HEVC) \ + num_ref = (_total_hb_layers); \ + else if (codec_standard == HFI_CODEC_ENCODE_AVC) \ + num_ref = (1 << (_total_hb_layers - 2)) + 1; \ + } \ + num_recon = num_ref + 1; \ + } while (0) + +#define SIZE_BIN_BITSTREAM_ENC(_size, rc_type, frame_width, frame_height, \ + work_mode, lcu_size, profile) \ + do { \ + HFI_U32 size_aligned_width = 0, size_aligned_height = 0; \ + HFI_U32 bitstream_size_eval = 0; \ + size_aligned_width = HFI_ALIGN((frame_width), lcu_size); \ + size_aligned_height = HFI_ALIGN((frame_height), lcu_size); \ + if (work_mode == HFI_WORKMODE_2) { \ + if ((rc_type == HFI_RC_CQ) || (rc_type == HFI_RC_OFF)) { \ + bitstream_size_eval = (((size_aligned_width) * \ + (size_aligned_height) * 3) >> 1); \ + } \ + else { \ + bitstream_size_eval = ((size_aligned_width) * \ + (size_aligned_height) * 3); \ + if (rc_type == HFI_RC_LOSSLESS) { \ + bitstream_size_eval = (bitstream_size_eval * 3 >> 2); \ + } \ + else if ((size_aligned_width * size_aligned_height) > \ + (4096 * 2176)) { \ + bitstream_size_eval >>= 3; \ + } \ + else if ((size_aligned_width * size_aligned_height) > \ + (480 * 320)) { \ + bitstream_size_eval >>= 2; \ + } \ + if (profile == HFI_H265_PROFILE_MAIN_10 || \ + profile == HFI_H265_PROFILE_MAIN_10_STILL_PICTURE) { \ + bitstream_size_eval = (bitstream_size_eval * 5 >> 2); \ + } \ + } \ + } else { \ + bitstream_size_eval = size_aligned_width * \ + size_aligned_height * 3; \ + } \ + _size = HFI_ALIGN(bitstream_size_eval, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_ENC_SINGLE_PIPE(size, rc_type, bitbin_size, num_vpp_pipes, \ + frame_width, frame_height, lcu_size) \ + do { \ + HFI_U32 size_single_pipe_eval = 0, sao_bin_buffer_size = 0, \ + _padded_bin_sz = 0; \ + HFI_U32 size_aligned_width = 0, size_aligned_height = 0; \ + size_aligned_width = HFI_ALIGN((frame_width), lcu_size); \ + size_aligned_height = HFI_ALIGN((frame_height), lcu_size); \ + if ((size_aligned_width * size_aligned_height) > \ + (3840 * 2160)) { \ + size_single_pipe_eval = (bitbin_size / num_vpp_pipes); \ + } \ + else if (num_vpp_pipes > 2) { \ + size_single_pipe_eval = bitbin_size / 2; \ + } else { \ + size_single_pipe_eval = bitbin_size; \ + } \ + if (rc_type == HFI_RC_LOSSLESS) { \ + size_single_pipe_eval = (size_single_pipe_eval << 1); \ + } \ + sao_bin_buffer_size = (64 * ((((frame_width) + \ + BUFFER_ALIGNMENT_32_BYTES) * ((frame_height) +\ + BUFFER_ALIGNMENT_32_BYTES)) >> 10)) + 384; \ + _padded_bin_sz = HFI_ALIGN(size_single_pipe_eval, \ + VENUS_DMA_ALIGNMENT);\ + size_single_pipe_eval = sao_bin_buffer_size + _padded_bin_sz; \ + size_single_pipe_eval = HFI_ALIGN(size_single_pipe_eval, \ + VENUS_DMA_ALIGNMENT); \ + size = size_single_pipe_eval; \ + } while (0) + +#define HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, lcu_size, \ + work_mode, num_vpp_pipes, profile) \ + do { \ + HFI_U32 bitstream_size = 0, total_bitbin_buffers = 0, \ + size_single_pipe = 0, bitbin_size = 0; \ + SIZE_BIN_BITSTREAM_ENC(bitstream_size, rc_type, frame_width, \ + frame_height, work_mode, lcu_size, profile); \ + if (work_mode == HFI_WORKMODE_2) { \ + total_bitbin_buffers = 3; \ + bitbin_size = bitstream_size * 12 / 10; \ + bitbin_size = HFI_ALIGN(bitbin_size, \ + VENUS_DMA_ALIGNMENT); \ + } \ + else if ((lcu_size == 16) || (num_vpp_pipes > 1)) { \ + total_bitbin_buffers = 1; \ + bitbin_size = bitstream_size; \ + } \ + if (total_bitbin_buffers > 0) { \ + SIZE_ENC_SINGLE_PIPE(size_single_pipe, rc_type, bitbin_size, \ + num_vpp_pipes, frame_width, frame_height, lcu_size); \ + bitbin_size = size_single_pipe * num_vpp_pipes; \ + _size = HFI_ALIGN(bitbin_size, VENUS_DMA_ALIGNMENT) * \ + total_bitbin_buffers + 512; \ + } \ + else \ + /* Avoid 512 Bytes allocation in case of 1Pipe HEVC Direct Mode*/ \ + _size = 0; \ + } while (0) + +#define HFI_BUFFER_BIN_H264E(_size, rc_type, frame_width, frame_height, \ + work_mode, num_vpp_pipes, profile) \ + do { \ + HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, 16, \ + work_mode, num_vpp_pipes, profile); \ + } while (0) + +#define HFI_BUFFER_BIN_H265E(_size, rc_type, frame_width, frame_height, \ + work_mode, num_vpp_pipes, profile) \ + do { \ + HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, 32,\ + work_mode, num_vpp_pipes, profile); \ + } while (0) + +#define SIZE_ENC_SLICE_INFO_BUF(num_lcu_in_frame) HFI_ALIGN((256 + \ + (num_lcu_in_frame << 4)), VENUS_DMA_ALIGNMENT) +#define SIZE_LINE_BUF_CTRL(frame_width_coded) \ + HFI_ALIGN(frame_width_coded, VENUS_DMA_ALIGNMENT) +#define SIZE_LINE_BUF_CTRL_ID2(frame_width_coded) \ + HFI_ALIGN(frame_width_coded, VENUS_DMA_ALIGNMENT) + +#define SIZE_LINEBUFF_DATA(_size, is_ten_bit, frame_width_coded) \ + do { \ + _size = is_ten_bit ? (((((10 * (frame_width_coded) +\ + 1024) + (VENUS_DMA_ALIGNMENT - 1)) & \ + (~(VENUS_DMA_ALIGNMENT - 1))) * 1) + \ + (((((10 * (frame_width_coded) + 1024) >> 1) + \ + (VENUS_DMA_ALIGNMENT - 1)) & (~(VENUS_DMA_ALIGNMENT - 1))) * \ + 2)) : (((((8 * (frame_width_coded) + 1024) + \ + (VENUS_DMA_ALIGNMENT - 1)) \ + & (~(VENUS_DMA_ALIGNMENT - 1))) * 1) + \ + (((((8 * (frame_width_coded) +\ + 1024) >> 1) + (VENUS_DMA_ALIGNMENT - 1)) & \ + (~(VENUS_DMA_ALIGNMENT - 1))) * 2)); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_CTRL(_size, standard, frame_height_coded, \ + num_vpp_pipes_enc) \ + do { \ + _size = (standard == HFI_CODEC_ENCODE_HEVC) ? \ + (((frame_height_coded) + \ + (BUF_SIZE_ALIGN_32)) / BUF_SIZE_ALIGN_32 * 4 * 16) : \ + (((frame_height_coded) + 15) / 16 * 5 * 16); \ + if ((num_vpp_pipes_enc) > 1) { \ + _size += BUFFER_ALIGNMENT_512_BYTES; \ + _size = HFI_ALIGN(_size, BUFFER_ALIGNMENT_512_BYTES) *\ + (num_vpp_pipes_enc); \ + } \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_RECON_PIX(_size, is_ten_bit, frame_height_coded, \ + num_vpp_pipes_enc) \ + do { \ + _size = (((is_ten_bit + 1) * 2 * (frame_height_coded) + \ + VENUS_DMA_ALIGNMENT) + \ + (VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1) & \ + (~((VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1)) * 1; \ + } while (0) + +#define SIZE_TOP_LINEBUFF_CTRL_FE(_size, frame_width_coded, standard) \ + do { \ + _size = (standard == HFI_CODEC_ENCODE_HEVC) ? (64 * \ + ((frame_width_coded) >> 5)) : (VENUS_DMA_ALIGNMENT + 16 * \ + ((frame_width_coded) >> 4)); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_CTRL_FE(frame_height_coded, num_vpp_pipes_enc) \ + ((((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) >> 4)) + \ + (VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1) & \ + (~((VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1)) * 1) * \ + num_vpp_pipes_enc) + +#define SIZE_LEFT_LINEBUFF_METADATA_RECON_Y(_size, frame_height_coded, \ + is_ten_bit, num_vpp_pipes_enc) \ + do { \ + _size = ((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) / \ + (8 * (is_ten_bit ? 4 : 8))))); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + _size = (_size * num_vpp_pipes_enc); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_METADATA_RECON_UV(_size, frame_height_coded, \ + is_ten_bit, num_vpp_pipes_enc) \ + do { \ + _size = ((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) / \ + (4 * (is_ten_bit ? 4 : 8))))); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + _size = (_size * num_vpp_pipes_enc); \ + } while (0) + +#define SIZE_LINEBUFF_RECON_PIX(_size, is_ten_bit, frame_width_coded) \ + do { \ + _size = ((is_ten_bit ? 3 : 2) * (frame_width_coded)); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_SLICE_CMD_BUFFER (HFI_ALIGN(20480, VENUS_DMA_ALIGNMENT)) +#define SIZE_SPS_PPS_SLICE_HDR (2048 + 4096) + +#define SIZE_FRAME_RC_BUF_SIZE(_size, standard, frame_height_coded, \ + num_vpp_pipes_enc) \ + do { \ + _size = (standard == HFI_CODEC_ENCODE_HEVC) ? (256 + 16 * \ + (14 + ((((frame_height_coded) >> 5) + 7) >> 3))) : \ + (256 + 16 * (14 + ((((frame_height_coded) >> 4) + 7) >> 3))); \ + _size *= 11; \ + if (num_vpp_pipes_enc > 1) { \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT) * \ + num_vpp_pipes_enc;\ + } \ + _size = HFI_ALIGN(_size, BUFFER_ALIGNMENT_512_BYTES) * \ + HFI_MAX_COL_FRAME; \ + } while (0) + +#define ENC_BITCNT_BUF_SIZE(num_lcu_in_frame) HFI_ALIGN((256 + \ + (4 * (num_lcu_in_frame))), VENUS_DMA_ALIGNMENT) +#define ENC_BITMAP_BUF_SIZE(num_lcu_in_frame) HFI_ALIGN((256 + \ + ((num_lcu_in_frame) >> 3)), VENUS_DMA_ALIGNMENT) +#define SIZE_LINE_BUF_SDE(frame_width_coded) HFI_ALIGN((256 + \ + (16 * ((frame_width_coded) >> 4))), VENUS_DMA_ALIGNMENT) + +#define SIZE_BSE_SLICE_CMD_BUF ((((8192 << 2) + 7) & (~7)) * 3) + +#define SIZE_LAMBDA_LUT (256 * 11) +#define SIZE_OVERRIDE_BUF(num_lcumb) (HFI_ALIGN(((16 * (((num_lcumb) + 7)\ + >> 3))), VENUS_DMA_ALIGNMENT) * 2) +#define SIZE_IR_BUF(num_lcu_in_frame) HFI_ALIGN((((((num_lcu_in_frame) << 1) + 7) &\ + (~7)) * 3), VENUS_DMA_ALIGNMENT) + +#define SIZE_VPSS_LINE_BUF(num_vpp_pipes_enc, frame_height_coded, \ + frame_width_coded) \ + (HFI_ALIGN(((((((8192) >> 2) << 5) * (num_vpp_pipes_enc)) + 64) + \ + (((((MAX((frame_width_coded), (frame_height_coded)) + 3) >> 2) << 5) +\ + 256) * 16)), VENUS_DMA_ALIGNMENT)) + +#define SIZE_TOP_LINE_BUF_FIRST_STG_SAO(frame_width_coded) \ + HFI_ALIGN((16 * ((frame_width_coded) >> 5)), VENUS_DMA_ALIGNMENT) + +#define HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, is_ten_bit, \ + num_vpp_pipes_enc, lcu_size, standard) \ + do { \ + HFI_U32 width_in_lcus = 0, height_in_lcus = 0, \ + frame_width_coded = 0, frame_height_coded = 0; \ + HFI_U32 line_buff_data_size = 0, left_line_buff_ctrl_size = 0, \ + left_line_buff_recon_pix_size = 0, \ + top_line_buff_ctrl_fe_size = 0; \ + HFI_U32 left_line_buff_metadata_recon__y__size = 0, \ + left_line_buff_metadata_recon__uv__size = 0, \ + line_buff_recon_pix_size = 0; \ + width_in_lcus = ((frame_width) + (lcu_size)-1) / (lcu_size); \ + height_in_lcus = ((frame_height) + (lcu_size)-1) / (lcu_size); \ + frame_width_coded = width_in_lcus * (lcu_size); \ + frame_height_coded = height_in_lcus * (lcu_size); \ + SIZE_LINEBUFF_DATA(line_buff_data_size, is_ten_bit, \ + frame_width_coded);\ + SIZE_LEFT_LINEBUFF_CTRL(left_line_buff_ctrl_size, standard, \ + frame_height_coded, num_vpp_pipes_enc); \ + SIZE_LEFT_LINEBUFF_RECON_PIX(left_line_buff_recon_pix_size, \ + is_ten_bit, frame_height_coded, num_vpp_pipes_enc); \ + SIZE_TOP_LINEBUFF_CTRL_FE(top_line_buff_ctrl_fe_size, \ + frame_width_coded, standard); \ + SIZE_LEFT_LINEBUFF_METADATA_RECON_Y\ + (left_line_buff_metadata_recon__y__size, \ + frame_height_coded, is_ten_bit, num_vpp_pipes_enc); \ + SIZE_LEFT_LINEBUFF_METADATA_RECON_UV\ + (left_line_buff_metadata_recon__uv__size, \ + frame_height_coded, is_ten_bit, num_vpp_pipes_enc); \ + SIZE_LINEBUFF_RECON_PIX(line_buff_recon_pix_size, is_ten_bit,\ + frame_width_coded); \ + _size = SIZE_LINE_BUF_CTRL(frame_width_coded) + \ + SIZE_LINE_BUF_CTRL_ID2(frame_width_coded) + \ + line_buff_data_size + \ + left_line_buff_ctrl_size + \ + left_line_buff_recon_pix_size + \ + top_line_buff_ctrl_fe_size + \ + left_line_buff_metadata_recon__y__size + \ + left_line_buff_metadata_recon__uv__size + \ + line_buff_recon_pix_size + \ + SIZE_LEFT_LINEBUFF_CTRL_FE(frame_height_coded, \ + num_vpp_pipes_enc) + SIZE_LINE_BUF_SDE(frame_width_coded) + \ + SIZE_VPSS_LINE_BUF(num_vpp_pipes_enc, frame_height_coded, \ + frame_width_coded) + \ + SIZE_TOP_LINE_BUF_FIRST_STG_SAO(frame_width_coded); \ + } while (0) + +#define HFI_BUFFER_LINE_H264E(_size, frame_width, frame_height, is_ten_bit, \ + num_vpp_pipes) \ + do { \ + HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, 0, \ + num_vpp_pipes, 16, HFI_CODEC_ENCODE_AVC); \ + } while (0) + +#define HFI_BUFFER_LINE_H265E(_size, frame_width, frame_height, is_ten_bit, \ + num_vpp_pipes) \ + do { \ + HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, \ + is_ten_bit, num_vpp_pipes, 32, HFI_CODEC_ENCODE_HEVC); \ + } while (0) + +#define HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, lcu_size, \ + num_recon, standard) \ + do { \ + HFI_U32 size_colloc_mv = 0, size_colloc_rc = 0; \ + HFI_U32 mb_width = ((frame_width) + 15) >> 4; \ + HFI_U32 mb_height = ((frame_height) + 15) >> 4; \ + HFI_U32 width_in_lcus = ((frame_width) + (lcu_size)-1) /\ + (lcu_size); \ + HFI_U32 height_in_lcus = ((frame_height) + (lcu_size)-1) / \ + (lcu_size); \ + HFI_U32 num_lcu_in_frame = width_in_lcus * height_in_lcus; \ + size_colloc_mv = (standard == HFI_CODEC_ENCODE_HEVC) ? \ + (16 * ((num_lcu_in_frame << 2) + BUFFER_ALIGNMENT_32_BYTES)) : \ + (3 * 16 * (width_in_lcus * height_in_lcus +\ + BUFFER_ALIGNMENT_32_BYTES)); \ + size_colloc_mv = HFI_ALIGN(size_colloc_mv, \ + VENUS_DMA_ALIGNMENT) * num_recon; \ + size_colloc_rc = (((mb_width + 7) >> 3) * 16 * 2 * mb_height); \ + size_colloc_rc = HFI_ALIGN(size_colloc_rc, \ + VENUS_DMA_ALIGNMENT) * HFI_MAX_COL_FRAME; \ + _size = size_colloc_mv + size_colloc_rc; \ + } while (0) + +#define HFI_BUFFER_COMV_H264E(_size, frame_width, frame_height, num_recon) \ + do { \ + HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, 16, \ + num_recon, HFI_CODEC_ENCODE_AVC); \ + } while (0) + +#define HFI_BUFFER_COMV_H265E(_size, frame_width, frame_height, num_recon) \ + do { \ + HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, 32,\ + num_recon, HFI_CODEC_ENCODE_HEVC); \ + } while (0) + +#define HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \ + num_vpp_pipes_enc, lcu_size, standard) \ + do { \ + HFI_U32 width_in_lcus = 0, height_in_lcus = 0, \ + frame_width_coded = 0, frame_height_coded = 0, \ + num_lcu_in_frame = 0, num_lcumb = 0; \ + HFI_U32 frame_rc_buf_size = 0; \ + width_in_lcus = ((frame_width) + (lcu_size)-1) / (lcu_size); \ + height_in_lcus = ((frame_height) + (lcu_size)-1) / (lcu_size); \ + num_lcu_in_frame = width_in_lcus * height_in_lcus; \ + frame_width_coded = width_in_lcus * (lcu_size); \ + frame_height_coded = height_in_lcus * (lcu_size); \ + num_lcumb = (frame_height_coded / lcu_size) * \ + ((frame_width_coded + lcu_size * 8) / lcu_size); \ + SIZE_FRAME_RC_BUF_SIZE(frame_rc_buf_size, standard, \ + frame_height_coded, num_vpp_pipes_enc); \ + _size = SIZE_ENC_SLICE_INFO_BUF(num_lcu_in_frame) + \ + SIZE_SLICE_CMD_BUFFER + \ + SIZE_SPS_PPS_SLICE_HDR + \ + frame_rc_buf_size + \ + ENC_BITCNT_BUF_SIZE(num_lcu_in_frame) + \ + ENC_BITMAP_BUF_SIZE(num_lcu_in_frame) + \ + SIZE_BSE_SLICE_CMD_BUF + \ + SIZE_LAMBDA_LUT + \ + SIZE_OVERRIDE_BUF(num_lcumb) + \ + SIZE_IR_BUF(num_lcu_in_frame); \ + } while (0) + +#define HFI_BUFFER_NON_COMV_H264E(_size, frame_width, frame_height, \ + num_vpp_pipes_enc) \ + do { \ + HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \ + num_vpp_pipes_enc, 16, HFI_CODEC_ENCODE_AVC); \ + } while (0) + +#define HFI_BUFFER_NON_COMV_H265E(_size, frame_width, frame_height, \ + num_vpp_pipes_enc) \ + do { \ + HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \ + num_vpp_pipes_enc, 32, HFI_CODEC_ENCODE_HEVC); \ + } while (0) + +#define SIZE_ENC_REF_BUFFER(size, frame_width, frame_height) \ + do { \ + HFI_U32 u_buffer_width = 0, u_buffer_height = 0, \ + u_chroma_buffer_height = 0; \ + u_buffer_height = HFI_ALIGN(frame_height, \ + HFI_VENUS_HEIGHT_ALIGNMENT); \ + u_chroma_buffer_height = frame_height >> 1; \ + u_chroma_buffer_height = HFI_ALIGN(u_chroma_buffer_height, \ + HFI_VENUS_HEIGHT_ALIGNMENT); \ + u_buffer_width = HFI_ALIGN(frame_width, \ + HFI_VENUS_WIDTH_ALIGNMENT); \ + size = (u_buffer_height + u_chroma_buffer_height) * \ + u_buffer_width; \ + } while (0) + +#define SIZE_ENC_TEN_BIT_REF_BUFFER(size, frame_width, frame_height) \ + do { \ + HFI_U32 ref_buf_height = 0, ref_luma_stride_in_bytes = 0, \ + u_ref_stride = 0, luma_size = 0, ref_chrm_height_in_bytes = 0, \ + chroma_size = 0, ref_buf_size = 0; \ + ref_buf_height = (frame_height + \ + (HFI_VENUS_HEIGHT_ALIGNMENT - 1)) \ + & (~(HFI_VENUS_HEIGHT_ALIGNMENT - 1)); \ + ref_luma_stride_in_bytes = ((frame_width + \ + SYSTEM_LAL_TILE10 - 1) / SYSTEM_LAL_TILE10) * \ + SYSTEM_LAL_TILE10; \ + u_ref_stride = 4 * (ref_luma_stride_in_bytes / 3); \ + u_ref_stride = (u_ref_stride + (BUF_SIZE_ALIGN_128 - 1)) &\ + (~(BUF_SIZE_ALIGN_128 - 1)); \ + luma_size = ref_buf_height * u_ref_stride; \ + ref_chrm_height_in_bytes = (((frame_height + 1) >> 1) + \ + (BUF_SIZE_ALIGN_32 - 1)) & (~(BUF_SIZE_ALIGN_32 - 1)); \ + chroma_size = u_ref_stride * ref_chrm_height_in_bytes; \ + luma_size = (luma_size + (BUF_SIZE_ALIGN_4096 - 1)) & \ + (~(BUF_SIZE_ALIGN_4096 - 1)); \ + chroma_size = (chroma_size + (BUF_SIZE_ALIGN_4096 - 1)) & \ + (~(BUF_SIZE_ALIGN_4096 - 1)); \ + ref_buf_size = luma_size + chroma_size; \ + size = ref_buf_size; \ + } while (0) + +#define HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, is_ten_bit) \ + do { \ + HFI_U32 metadata_stride, metadata_buf_height, meta_size_y, \ + meta_size_c; \ + HFI_U32 ten_bit_ref_buf_size = 0, ref_buf_size = 0; \ + if (!is_ten_bit) { \ + SIZE_ENC_REF_BUFFER(ref_buf_size, frame_width, \ + frame_height); \ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, \ + (frame_width), 64, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH); \ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, \ + (frame_height), 16, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_y, \ + metadata_stride, metadata_buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_c, \ + metadata_stride, metadata_buf_height); \ + _size = ref_buf_size + meta_size_y + meta_size_c; \ + } else { \ + SIZE_ENC_TEN_BIT_REF_BUFFER(ten_bit_ref_buf_size, \ + frame_width, frame_height); \ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, \ + frame_width, VENUS_METADATA_STRIDE_MULTIPLE, \ + HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH); \ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, \ + frame_height, VENUS_METADATA_HEIGHT_MULTIPLE, \ + HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_y, \ + metadata_stride, metadata_buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_c, \ + metadata_stride, metadata_buf_height); \ + _size = ten_bit_ref_buf_size + meta_size_y + \ + meta_size_c; \ + } \ + } while (0) + +#define HFI_BUFFER_DPB_H264E(_size, frame_width, frame_height) \ + do { \ + HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, 0); \ + } while (0) + +#define HFI_BUFFER_DPB_H265E(_size, frame_width, frame_height, is_ten_bit) \ + do { \ + HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, is_ten_bit); \ + } while (0) + +#define HFI_BUFFER_VPSS_ENC(vpss_size, dswidth, dsheight, ds_enable, blur, is_ten_bit) \ + do { \ + vpss_size = 0; \ + if (ds_enable || blur) { \ + HFI_BUFFER_DPB_ENC(vpss_size, dswidth, dsheight, is_ten_bit); \ + } \ + } while (0) + +#define HFI_IRIS3_ENC_MIN_INPUT_BUF_COUNT(numInput, TotalHBLayers) \ + do { \ + numInput = 3; \ + if (TotalHBLayers >= 2) { \ + numInput = (1 << (TotalHBLayers - 1)) + 2; \ + } \ + } while (0) + +#endif /* __HFI_BUFFER_IRIS3__ */ diff --git a/qcom/opensource/video-driver/driver/variant/iris3/inc/msm_vidc_buffer_iris3.h b/qcom/opensource/video-driver/driver/variant/iris3/inc/msm_vidc_buffer_iris3.h new file mode 100644 index 0000000000..7548a9f25f --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris3/inc/msm_vidc_buffer_iris3.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __H_MSM_VIDC_BUFFER_IRIS3_H__ +#define __H_MSM_VIDC_BUFFER_IRIS3_H__ + +#include "msm_vidc_inst.h" + +int msm_buffer_size_iris3(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +int msm_buffer_min_count_iris3(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +int msm_buffer_extra_count_iris3(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); + +#endif // __H_MSM_VIDC_BUFFER_IRIS3_H__ diff --git a/qcom/opensource/video-driver/driver/variant/iris3/inc/msm_vidc_iris3.h b/qcom/opensource/video-driver/driver/variant/iris3/inc/msm_vidc_iris3.h new file mode 100644 index 0000000000..75ba4decc3 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris3/inc/msm_vidc_iris3.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_IRIS3_H_ +#define _MSM_VIDC_IRIS3_H_ + +#include "msm_vidc_core.h" + +#if defined(CONFIG_MSM_VIDC_KALAMA) +int msm_vidc_init_iris3(struct msm_vidc_core *core); +int msm_vidc_adjust_bitrate_boost_iris3(void *instance, struct v4l2_ctrl *ctrl); +#else +static inline int msm_vidc_init_iris3(struct msm_vidc_core *core) +{ + return -EINVAL; +} + +static inline int msm_vidc_adjust_bitrate_boost_iris3(void *instance, struct v4l2_ctrl *ctrl) +{ + return -EINVAL; +} +#endif + +#endif // _MSM_VIDC_IRIS3_H_ diff --git a/qcom/opensource/video-driver/driver/variant/iris3/inc/msm_vidc_power_iris3.h b/qcom/opensource/video-driver/driver/variant/iris3/inc/msm_vidc_power_iris3.h new file mode 100644 index 0000000000..e0a5cbcd39 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris3/inc/msm_vidc_power_iris3.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __H_MSM_VIDC_POWER_IRIS3_H__ +#define __H_MSM_VIDC_POWER_IRIS3_H__ + +#include "msm_vidc_inst.h" +#include "msm_vidc_power.h" + +#define ENABLE_LEGACY_POWER_CALCULATIONS 0 + +u64 msm_vidc_calc_freq_iris3(struct msm_vidc_inst *inst, u32 data_size); +int msm_vidc_calc_bw_iris3(struct msm_vidc_inst *inst, + struct vidc_bus_vote_data *vote_data); + +#endif diff --git a/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_buffer_iris3.c b/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_buffer_iris3.c new file mode 100644 index 0000000000..f30050213d --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_buffer_iris3.c @@ -0,0 +1,736 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_buffer_iris3.h" +#include "msm_vidc_buffer.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_debug.h" +#include "msm_media_info.h" +#include "msm_vidc_platform.h" +#include "hfi_property.h" +#include "hfi_buffer_iris3.h" + +static u32 msm_vidc_decoder_bin_size_iris3(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, num_vpp_pipes; + struct v4l2_format *f; + bool is_interlaced; + u32 vpp_delay; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + if (inst->decode_vpp_delay.enable) + vpp_delay = inst->decode_vpp_delay.size; + else + vpp_delay = DEFAULT_BSE_VPP_DELAY; + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_PROGRESSIVE) + is_interlaced = false; + else + is_interlaced = true; + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_BIN_H264D(size, width, height, + is_interlaced, vpp_delay, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_BIN_H265D(size, width, height, + 0, vpp_delay, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_VP9) + HFI_BUFFER_BIN_VP9D(size, width, height, + 0, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_AV1) + HFI_BUFFER_BIN_AV1D(size, width, height, is_interlaced, + 0, num_vpp_pipes); + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_comv_size_iris3(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, num_comv, vpp_delay; + struct v4l2_format *f; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_AV1) { + /* + * AV1 requires larger COMV buffer size to meet performance + * for certain use cases. Increase the COMV buffer size by + * increasing COMV bufcount. Use lower count for 8k to + * achieve performance but save memory. + */ + if (res_is_greater_than(width, height, 4096, 2176)) + num_comv = inst->buffers.output.min_count + 3; + else + num_comv = inst->buffers.output.min_count + 7; + } else { + num_comv = inst->buffers.output.min_count; + } + msm_vidc_update_cap_value(inst, NUM_COMV, num_comv, __func__); + + if (inst->codec == MSM_VIDC_HEIC + && is_thumbnail_session(inst)) { + vpp_delay = 0; + } else { + if (inst->decode_vpp_delay.enable) + vpp_delay = inst->decode_vpp_delay.size; + else + vpp_delay = DEFAULT_BSE_VPP_DELAY; + } + + num_comv = max(vpp_delay + 1, num_comv); + if (inst->codec == MSM_VIDC_H264) { + HFI_BUFFER_COMV_H264D(size, width, height, num_comv); + } else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) { + HFI_BUFFER_COMV_H265D(size, width, height, num_comv); + } else if (inst->codec == MSM_VIDC_AV1) { + /* + * When DRAP is enabled, COMV buffer is part of PERSIST buffer and + * should not be allocated separately. + * When DRAP is disabled, COMV buffer must be allocated. + */ + if (inst->capabilities[DRAP].value) + size = 0; + else + HFI_BUFFER_COMV_AV1D(size, width, height, num_comv); + } + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_non_comv_size_iris3(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, num_vpp_pipes; + struct msm_vidc_core *core; + struct v4l2_format *f; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_NON_COMV_H264D(size, width, height, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_NON_COMV_H265D(size, width, height, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_line_size_iris3(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, out_min_count, num_vpp_pipes, vpp_delay; + struct v4l2_format *f; + bool is_opb; + u32 color_fmt; + + core = inst->core; + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + + color_fmt = v4l2_colorformat_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, __func__); + if (is_linear_colorformat(color_fmt)) + is_opb = true; + else + is_opb = false; + /* + * assume worst case, since color format is unknown at this + * time. + */ + is_opb = true; + + if (inst->decode_vpp_delay.enable) + vpp_delay = inst->decode_vpp_delay.size; + else + vpp_delay = DEFAULT_BSE_VPP_DELAY; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + out_min_count = inst->buffers.output.min_count; + out_min_count = max(vpp_delay + 1, out_min_count); + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_LINE_H264D(size, width, height, is_opb, + num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_LINE_H265D(size, width, height, is_opb, + num_vpp_pipes); + else if (inst->codec == MSM_VIDC_VP9) + HFI_BUFFER_LINE_VP9D(size, width, height, out_min_count, + is_opb, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_AV1) + HFI_BUFFER_LINE_AV1D(size, width, height, is_opb, + num_vpp_pipes); + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_partial_data_size_iris3(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height; + struct v4l2_format *f; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_AV1) + HFI_BUFFER_IBC_AV1D(size, width, height); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_persist_size_iris3(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 rpu_enabled = 0; + + if (inst->capabilities[META_DOLBY_RPU].value) + rpu_enabled = 1; + + if (inst->codec == MSM_VIDC_H264) { + HFI_BUFFER_PERSIST_H264D(size, rpu_enabled); + } else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) { + HFI_BUFFER_PERSIST_H265D(size, rpu_enabled); + } else if (inst->codec == MSM_VIDC_VP9) { + HFI_BUFFER_PERSIST_VP9D(size); + } else if (inst->codec == MSM_VIDC_AV1) { + /* + * When DRAP is enabled, COMV buffer is part of PERSIST buffer and + * should not be allocated separately. PERSIST buffer should include + * COMV buffer calculated with width, height, refcount. + * When DRAP is disabled, COMV buffer should not be included in PERSIST + * buffer. + */ + if (inst->capabilities[DRAP].value) + HFI_BUFFER_PERSIST_AV1D(size, + inst->capabilities[FRAME_WIDTH].max, + inst->capabilities[FRAME_HEIGHT].max, 16); + else + HFI_BUFFER_PERSIST_AV1D(size, 0, 0, 0); + } + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_dpb_size_iris3(struct msm_vidc_inst *inst) +{ + + u32 size = 0; + u32 color_fmt; + u32 width, height; + struct v4l2_format *f; + + /* + * For legacy codecs (non-AV1), DPB is calculated only + * for linear formats. For AV1, DPB is needed for film-grain + * enabled bitstreams (UBWC & linear). + */ + color_fmt = inst->capabilities[PIX_FMTS].value; + if (!is_linear_colorformat(color_fmt)) { + if (inst->codec != MSM_VIDC_AV1) + return size; + + if (inst->codec == MSM_VIDC_AV1 && + !inst->capabilities[FILM_GRAIN].value) + return size; + } + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (color_fmt == MSM_VIDC_FMT_NV12 || + color_fmt == MSM_VIDC_FMT_NV12C) { + color_fmt = MSM_VIDC_FMT_NV12C; + HFI_NV12_UBWC_IL_CALC_BUF_SIZE_V2(size, width, height, + video_y_stride_bytes(color_fmt, width), + video_y_scanlines(color_fmt, height), + video_uv_stride_bytes(color_fmt, width), + video_uv_scanlines(color_fmt, height), + video_y_meta_stride(color_fmt, width), + video_y_meta_scanlines(color_fmt, height), + video_uv_meta_stride(color_fmt, width), + video_uv_meta_scanlines(color_fmt, height)); + } else if (color_fmt == MSM_VIDC_FMT_P010 || + color_fmt == MSM_VIDC_FMT_TP10C) { + color_fmt = MSM_VIDC_FMT_TP10C; + HFI_YUV420_TP10_UBWC_CALC_BUF_SIZE(size, + video_y_stride_bytes(color_fmt, width), + video_y_scanlines(color_fmt, height), + video_uv_stride_bytes(color_fmt, width), + video_uv_scanlines(color_fmt, height), + video_y_meta_stride(color_fmt, width), + video_y_meta_scanlines(color_fmt, height), + video_uv_meta_stride(color_fmt, width), + video_uv_meta_scanlines(color_fmt, height)); + } + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +/* encoder internal buffers */ +static u32 msm_vidc_encoder_bin_size_iris3(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, num_vpp_pipes, stage, profile; + struct v4l2_format *f; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + stage = inst->capabilities[STAGE].value; + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + profile = inst->capabilities[PROFILE].value; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_BIN_H264E(size, inst->hfi_rc_type, width, + height, stage, num_vpp_pipes, profile); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_BIN_H265E(size, inst->hfi_rc_type, width, + height, stage, num_vpp_pipes, profile); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_get_recon_buf_count(struct msm_vidc_inst *inst) +{ + u32 num_buf_recon = 0; + s32 n_bframe, ltr_count, hp_layers = 0, hb_layers = 0; + bool is_hybrid_hp = false; + u32 hfi_codec = 0; + + n_bframe = inst->capabilities[B_FRAME].value; + ltr_count = inst->capabilities[LTR_COUNT].value; + + if (inst->hfi_layer_type == HFI_HIER_B) { + hb_layers = inst->capabilities[ENH_LAYER_COUNT].value + 1; + } else { + hp_layers = inst->capabilities[ENH_LAYER_COUNT].value + 1; + if (inst->hfi_layer_type == HFI_HIER_P_HYBRID_LTR) + is_hybrid_hp = true; + } + + if (inst->codec == MSM_VIDC_H264) + hfi_codec = HFI_CODEC_ENCODE_AVC; + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + hfi_codec = HFI_CODEC_ENCODE_HEVC; + + HFI_IRIS3_ENC_RECON_BUF_COUNT(num_buf_recon, n_bframe, ltr_count, + hp_layers, hb_layers, is_hybrid_hp, hfi_codec); + + return num_buf_recon; +} + +static u32 msm_vidc_encoder_comv_size_iris3(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, num_recon = 0; + struct v4l2_format *f; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + num_recon = msm_vidc_get_recon_buf_count(inst); + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_COMV_H264E(size, width, height, num_recon); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_COMV_H265E(size, width, height, num_recon); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_non_comv_size_iris3(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, num_vpp_pipes; + struct v4l2_format *f; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_NON_COMV_H264E(size, width, height, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_NON_COMV_H265E(size, width, height, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_line_size_iris3(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, pixfmt, num_vpp_pipes; + bool is_tenbit = false; + struct v4l2_format *f; + + core = inst->core; + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + pixfmt = inst->capabilities[PIX_FMTS].value; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + is_tenbit = (pixfmt == MSM_VIDC_FMT_P010 || pixfmt == MSM_VIDC_FMT_TP10C); + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_LINE_H264E(size, width, height, is_tenbit, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_LINE_H265E(size, width, height, is_tenbit, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_dpb_size_iris3(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, pixfmt; + struct v4l2_format *f; + bool is_tenbit; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + pixfmt = inst->capabilities[PIX_FMTS].value; + is_tenbit = (pixfmt == MSM_VIDC_FMT_P010 || pixfmt == MSM_VIDC_FMT_TP10C); + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_DPB_H264E(size, width, height); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_DPB_H265E(size, width, height, is_tenbit); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_arp_size_iris3(struct msm_vidc_inst *inst) +{ + u32 size = 0; + + HFI_BUFFER_ARP_ENC(size); + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_vpss_size_iris3(struct msm_vidc_inst *inst) +{ + u32 size = 0; + bool ds_enable = false, is_tenbit = false, blur = false; + u32 rotation_val = HFI_ROTATION_NONE; + u32 width, height, driver_colorfmt; + struct v4l2_format *f; + + ds_enable = is_scaling_enabled(inst); + msm_vidc_v4l2_to_hfi_enum(inst, ROTATION, &rotation_val); + + f = &inst->fmts[OUTPUT_PORT]; + if (is_rotation_90_or_270(inst)) { + /* + * output width and height are rotated, + * so unrotate them to use as arguments to + * HFI_BUFFER_VPSS_ENC. + */ + width = f->fmt.pix_mp.height; + height = f->fmt.pix_mp.width; + } else { + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + } + + f = &inst->fmts[INPUT_PORT]; + driver_colorfmt = v4l2_colorformat_to_driver(inst, + f->fmt.pix_mp.pixelformat, __func__); + is_tenbit = is_10bit_colorformat(driver_colorfmt); + if (inst->capabilities[BLUR_TYPES].value != MSM_VIDC_BLUR_NONE) + blur = true; + + HFI_BUFFER_VPSS_ENC(size, width, height, ds_enable, blur, is_tenbit); + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_output_size_iris3(struct msm_vidc_inst *inst) +{ + u32 frame_size; + struct v4l2_format *f; + bool is_ten_bit = false; + int bitrate_mode, frame_rc; + u32 hfi_rc_type = HFI_RC_VBR_CFR; + enum msm_vidc_codec_type codec; + + f = &inst->fmts[OUTPUT_PORT]; + codec = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__); + if (codec == MSM_VIDC_HEVC || codec == MSM_VIDC_HEIC) + is_ten_bit = true; + + bitrate_mode = inst->capabilities[BITRATE_MODE].value; + frame_rc = inst->capabilities[FRAME_RC_ENABLE].value; + if (!frame_rc && !is_image_session(inst)) + hfi_rc_type = HFI_RC_OFF; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + hfi_rc_type = HFI_RC_CQ; + + HFI_BUFFER_BITSTREAM_ENC(frame_size, f->fmt.pix_mp.width, + f->fmt.pix_mp.height, hfi_rc_type, is_ten_bit); + + frame_size = msm_vidc_enc_delivery_mode_based_output_buf_size(inst, frame_size); + + return frame_size; +} + +struct msm_vidc_buf_type_handle { + enum msm_vidc_buffer_type type; + u32 (*handle)(struct msm_vidc_inst *inst); +}; + +int msm_buffer_size_iris3(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int i; + u32 size = 0, buf_type_handle_size = 0; + const struct msm_vidc_buf_type_handle *buf_type_handle_arr = NULL; + static const struct msm_vidc_buf_type_handle dec_buf_type_handle[] = { + {MSM_VIDC_BUF_INPUT, msm_vidc_decoder_input_size }, + {MSM_VIDC_BUF_OUTPUT, msm_vidc_decoder_output_size }, + {MSM_VIDC_BUF_INPUT_META, msm_vidc_decoder_input_meta_size }, + {MSM_VIDC_BUF_OUTPUT_META, msm_vidc_decoder_output_meta_size }, + {MSM_VIDC_BUF_BIN, msm_vidc_decoder_bin_size_iris3 }, + {MSM_VIDC_BUF_COMV, msm_vidc_decoder_comv_size_iris3 }, + {MSM_VIDC_BUF_NON_COMV, msm_vidc_decoder_non_comv_size_iris3 }, + {MSM_VIDC_BUF_LINE, msm_vidc_decoder_line_size_iris3 }, + {MSM_VIDC_BUF_PERSIST, msm_vidc_decoder_persist_size_iris3 }, + {MSM_VIDC_BUF_DPB, msm_vidc_decoder_dpb_size_iris3 }, + {MSM_VIDC_BUF_PARTIAL_DATA, msm_vidc_decoder_partial_data_size_iris3 }, + }; + static const struct msm_vidc_buf_type_handle enc_buf_type_handle[] = { + {MSM_VIDC_BUF_INPUT, msm_vidc_encoder_input_size }, + {MSM_VIDC_BUF_OUTPUT, msm_vidc_encoder_output_size_iris3 }, + {MSM_VIDC_BUF_INPUT_META, msm_vidc_encoder_input_meta_size }, + {MSM_VIDC_BUF_OUTPUT_META, msm_vidc_encoder_output_meta_size }, + {MSM_VIDC_BUF_BIN, msm_vidc_encoder_bin_size_iris3 }, + {MSM_VIDC_BUF_COMV, msm_vidc_encoder_comv_size_iris3 }, + {MSM_VIDC_BUF_NON_COMV, msm_vidc_encoder_non_comv_size_iris3 }, + {MSM_VIDC_BUF_LINE, msm_vidc_encoder_line_size_iris3 }, + {MSM_VIDC_BUF_DPB, msm_vidc_encoder_dpb_size_iris3 }, + {MSM_VIDC_BUF_ARP, msm_vidc_encoder_arp_size_iris3 }, + {MSM_VIDC_BUF_VPSS, msm_vidc_encoder_vpss_size_iris3 }, + }; + + if (is_decode_session(inst)) { + buf_type_handle_size = ARRAY_SIZE(dec_buf_type_handle); + buf_type_handle_arr = dec_buf_type_handle; + } else if (is_encode_session(inst)) { + buf_type_handle_size = ARRAY_SIZE(enc_buf_type_handle); + buf_type_handle_arr = enc_buf_type_handle; + } + + /* handle invalid session */ + if (!buf_type_handle_arr || !buf_type_handle_size) { + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return size; + } + + /* fetch buffer size */ + for (i = 0; i < buf_type_handle_size; i++) { + if (buf_type_handle_arr[i].type == buffer_type) { + size = buf_type_handle_arr[i].handle(inst); + break; + } + } + + /* handle unknown buffer type */ + if (i == buf_type_handle_size) { + i_vpr_e(inst, "%s: unknown buffer type %#x\n", __func__, buffer_type); + goto exit; + } + + i_vpr_l(inst, "buffer_size: type: %11s, size: %9u\n", buf_name(buffer_type), size); + +exit: + return size; +} + +static int msm_vidc_input_min_count_iris3(struct msm_vidc_inst *inst) +{ + u32 input_min_count = 0; + u32 total_hb_layer = 0; + + if (is_decode_session(inst)) { + input_min_count = MIN_DEC_INPUT_BUFFERS; + } else if (is_encode_session(inst)) { + total_hb_layer = is_hierb_type_requested(inst) ? + inst->capabilities[ENH_LAYER_COUNT].value + 1 : 0; + if (inst->codec == MSM_VIDC_H264 && + !inst->capabilities[LAYER_ENABLE].value) { + total_hb_layer = 0; + } + HFI_IRIS3_ENC_MIN_INPUT_BUF_COUNT(input_min_count, + total_hb_layer); + } else { + i_vpr_e(inst, "%s: invalid domain %d\n", __func__, inst->domain); + return 0; + } + + if (is_thumbnail_session(inst) || is_image_session(inst)) + input_min_count = 1; + + return input_min_count; +} + +static int msm_buffer_dpb_count(struct msm_vidc_inst *inst) +{ + int count = 0; + u32 color_fmt; + + /* decoder dpb buffer count */ + if (is_decode_session(inst)) { + color_fmt = inst->capabilities[PIX_FMTS].value; + if (is_linear_colorformat(color_fmt) || + (inst->codec == MSM_VIDC_AV1 && + (inst->capabilities[FILM_GRAIN].value))) + count = inst->buffers.output.min_count; + + return count; + } + + /* encoder dpb buffer count */ + return msm_vidc_get_recon_buf_count(inst); +} + +static int msm_buffer_delivery_mode_based_min_count_iris3(struct msm_vidc_inst *inst, + uint32_t count) +{ + struct v4l2_format *f; + struct msm_vidc_core *core = NULL; + u32 width, height, total_num_slices = 1; + u32 hfi_codec = 0; + u32 max_mbs_per_slice = 0; + u32 slice_mode = 0; + u32 delivery_mode = 0; + u32 num_vpp_pipes; + + slice_mode = inst->capabilities[SLICE_MODE].value; + delivery_mode = inst->capabilities[DELIVERY_MODE].value; + + if (slice_mode != V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB || + (!delivery_mode)) + return count; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + max_mbs_per_slice = inst->capabilities[SLICE_MAX_MB].value; + + if (inst->codec == MSM_VIDC_H264) + hfi_codec = HFI_CODEC_ENCODE_AVC; + else if (inst->codec == MSM_VIDC_HEVC) + hfi_codec = HFI_CODEC_ENCODE_HEVC; + + core = inst->core; + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + + HFI_IRIS3_ENC_MB_BASED_MULTI_SLICE_COUNT(total_num_slices, width, height, + hfi_codec, max_mbs_per_slice, num_vpp_pipes); + + return (total_num_slices * count); +} + +int msm_buffer_min_count_iris3(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int count = 0; + + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + case MSM_VIDC_BUF_INPUT_META: + count = msm_vidc_input_min_count_iris3(inst); + break; + case MSM_VIDC_BUF_OUTPUT: + case MSM_VIDC_BUF_OUTPUT_META: + count = msm_vidc_output_min_count(inst); + count = msm_buffer_delivery_mode_based_min_count_iris3(inst, count); + break; + case MSM_VIDC_BUF_BIN: + case MSM_VIDC_BUF_COMV: + case MSM_VIDC_BUF_NON_COMV: + case MSM_VIDC_BUF_LINE: + case MSM_VIDC_BUF_PERSIST: + case MSM_VIDC_BUF_ARP: + case MSM_VIDC_BUF_VPSS: + case MSM_VIDC_BUF_PARTIAL_DATA: + count = msm_vidc_internal_buffer_count(inst, buffer_type); + break; + case MSM_VIDC_BUF_DPB: + count = msm_buffer_dpb_count(inst); + break; + default: + break; + } + + i_vpr_l(inst, " min_count: type: %11s, count: %9u\n", buf_name(buffer_type), count); + return count; +} + +int msm_buffer_extra_count_iris3(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int count = 0; + + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + case MSM_VIDC_BUF_INPUT_META: + count = msm_vidc_input_extra_count(inst); + break; + case MSM_VIDC_BUF_OUTPUT: + case MSM_VIDC_BUF_OUTPUT_META: + count = msm_vidc_output_extra_count(inst); + break; + default: + break; + } + + i_vpr_l(inst, "extra_count: type: %11s, count: %9u\n", buf_name(buffer_type), count); + return count; +} diff --git a/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_bus_iris3.c b/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_bus_iris3.c new file mode 100644 index 0000000000..ac7826c2b4 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_bus_iris3.c @@ -0,0 +1,928 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "kalama_technology.h" +#include "msm_vidc_debug.h" + +u32 calculate_number_lcus_kalama(u32 width, u32 height, u32 lcu_size) +{ + u32 mbs_width = (width % lcu_size) ? + (width / lcu_size + 1) : (width / lcu_size); + u32 mbs_height = (height % lcu_size) ? + (height / lcu_size + 1) : (height / lcu_size); + + return mbs_width * mbs_height; +} + +u32 calculate_number_ubwctiles_kalama( + u32 width, u32 height, u32 tile_w, u32 tile_h) +{ + u32 tiles_width = (width % tile_w) ? + (width / tile_w + 1) : (width / tile_w); + u32 tiles_height = (height % tile_h) ? + (height / tile_h + 1) : (height / tile_h); + + return tiles_width * tiles_height; +} + +struct compression_factors { + u32 dpb_cf_y; + u32 dpb_cf_cbcr; + u32 opb_cf_ycbcr; + u32 dpb_cr_y; + u32 ipb_cr_y; + u32 ipb_cr; +} compression_factor; + +u32 get_compression_factors(struct compression_factors *compression_factor, + struct api_calculation_input codec_input) +{ + u8 cr_index_entry, cr_index_y, cr_index_c, cr_index_uni; + u32 frame_width; + u32 frame_height; + + frame_width = codec_input.frame_width; + frame_height = codec_input.frame_height; + if (frame_width * frame_height <= 1920 * 1080) + cr_index_entry = 0; + else + cr_index_entry = 1; + + if (codec_input.bitdepth == CODEC_BITDEPTH_8) { + /* NOT PWC or average and power case */ + if (codec_input.complexity_setting != 0) { + cr_index_y = 0; + cr_index_c = 1; + cr_index_uni = 2; + } else { + cr_index_y = 3; + cr_index_c = 4; + cr_index_uni = 5; + } + } else { + /* NOT PWC or average and power case */ + if (codec_input.complexity_setting != 0) { + cr_index_y = 6; + cr_index_c = 7; + cr_index_uni = 8; + } else { + cr_index_y = 9; + cr_index_c = 10; + cr_index_uni = 11; + } + } + + if (codec_input.decoder_or_encoder == CODEC_DECODER) { + compression_factor->dpb_cf_y = + dpbopb_ubwc30_cr_table_cratio_kalama[cr_index_entry][cr_index_y]; + compression_factor->dpb_cf_cbcr = + dpbopb_ubwc30_cr_table_cratio_kalama[cr_index_entry][cr_index_c]; + compression_factor->opb_cf_ycbcr = + dpbopb_ubwc30_cr_table_cratio_kalama[cr_index_entry][cr_index_uni]; + + if ((codec_input.regression_mode == 3) && + /* input cr numbers from interface */ + ((codec_input.cr_dpb != 0) || (codec_input.cr_opb != 0))) { + compression_factor->dpb_cf_y = (u32)(codec_input.cr_dpb * 100); + compression_factor->dpb_cf_cbcr = (u32)(codec_input.cr_dpb * 100); + compression_factor->opb_cf_ycbcr = (u32)(codec_input.cr_opb * 100); + } + } else { /* encoder */ + /* + * IPB CR Table Choice; static sheet (if framewidth<3840, use lossless table) + * (else, use lossy table) + * stick to this choice for SW purpose (no change for SW) + */ + if (frame_width < 3840) { + compression_factor->ipb_cr = + ipblossless_ubwc30_cr_table_cratio_kalama[cr_index_entry] + [cr_index_uni]; + compression_factor->ipb_cr_y = + ipblossless_ubwc30_cr_table_cratio_kalama[cr_index_entry] + [cr_index_y]; + } else { + compression_factor->ipb_cr = + ipblossy_ubwc30_cr_table_cratio_kalama[cr_index_entry] + [cr_index_uni]; + compression_factor->ipb_cr_y = + ipblossy_ubwc30_cr_table_cratio_kalama[cr_index_entry] + [cr_index_y]; + } + + compression_factor->dpb_cf_y = + rpb_ubwc30_cr_table_cratio_kalama[cr_index_entry][cr_index_y]; + + compression_factor->dpb_cf_cbcr = + rpb_ubwc30_cr_table_cratio_kalama[cr_index_entry][cr_index_c]; + + if ((codec_input.regression_mode == 3) && + /* input cr from interface */ + ((codec_input.cr_ipb != 0) || (codec_input.cr_rpb != 0))) { + compression_factor->dpb_cf_y = (u32)(codec_input.cr_rpb * 100); + compression_factor->dpb_cf_cbcr = (u32)(codec_input.cr_rpb * 100); + compression_factor->ipb_cr_y = (u32)(codec_input.cr_ipb * 100); + } + } + + return 0; +} + +static int calculate_bandwidth_decoder_iris3( + struct api_calculation_input codec_input, + struct api_calculation_bw_output *codec_output) +{ + /* common control parameters */ + u32 frame_width; + u32 frame_height; + u32 frame_lcu_size = 16; /* initialized to h264 */ + u32 lcu_per_frame; + u32 target_bitrate; + u32 collocated_bytes_per_lcu = 16; /* initialized to h264 */ + u32 av1d_segment_read_per_lcu; + u32 av1d_fe_leftlinebuffer_perlcu_tileboudary; + + u32 frame420_y_bw_linear_8bpp; + u32 frame420_y_bw_no_ubwc_tile_10bpp; + u32 frame420_y_bw_linear_10bpp; + + u16 ubwc_tile_w; + u16 ubwc_tile_h; + + u32 dpb_compression_factor_y; + u32 dpb_compression_factor_cbcr; + + u32 reconstructed_write_bw_factor_rd; + u32 reference_y_read_bw_factor; + u32 reference_cbcr_read_bw_factor; + + /* decoder control parameters */ + u32 decoder_vsp_read_factor = 6; + u32 bins_to_bits_factor = 4; + + u32 dpb_to_opb_ratios_ds = 1; + + u8 llc_enabled_ref_y_rd = 1; + u8 llc_enable_ref_crcb_rd = 1; + u8 llc_enabled_bse_tlb = 1; + /* this is for 2pipe and 1pipe LLC */ + u8 llc_enable_probtable_av1d_21pipe = 0; + + u32 opb_compression_factor_ycbcr; + u32 dpb_ubwc_tile_width_pixels; + u32 dpb_ubwc_tile_height_pixels; + u32 decoder_frame_complexity_factor; + u32 llc_saving = 130; /* Initialized to H264 */ + + u16 av1_tile_numbers; + u32 av1_collated_seg_buffer_rd_wr; + /* need divide by 1M at later step; */ + u32 av1_probability_table_rdwr_bytesperframe = 22784; + u32 av1_fe_left_line_buffer_rdwr; + + u32 bse_tlb_byte_per_lcu = 0; + + u32 large_bw_calculation_fp = 0; + + llc_enabled_ref_y_rd = (codec_input.status_llc_onoff) ? 1 : 0; + llc_enable_ref_crcb_rd = (codec_input.status_llc_onoff) ? 1 : 0; + /* H265D BSE tlb in LLC will be pored in Kailua */ + llc_enabled_bse_tlb = (codec_input.status_llc_onoff) ? 1 : 0; + + frame_width = codec_input.frame_width; + frame_height = codec_input.frame_height; + if ((codec_input.codec == CODEC_H264) || + (codec_input.codec == CODEC_H264_CAVLC)) { + frame_lcu_size = 16; + collocated_bytes_per_lcu = 16; + llc_saving = 130; + } else if (codec_input.codec == CODEC_HEVC) { + if (codec_input.lcu_size == 32) { + frame_lcu_size = 32; + collocated_bytes_per_lcu = 64; + llc_saving = 114; + } else if (codec_input.lcu_size == 64) { + frame_lcu_size = 64; + collocated_bytes_per_lcu = 256; + llc_saving = 107; + } + } else if (codec_input.codec == CODEC_VP9) { + if (codec_input.lcu_size == 32) { + frame_lcu_size = 32; + collocated_bytes_per_lcu = 64; + llc_saving = 114; + } else if (codec_input.lcu_size == 64) { + frame_lcu_size = 64; + collocated_bytes_per_lcu = 256; + llc_saving = 107; + } + } else if (codec_input.codec == CODEC_AV1) { + u32 av1d_leftline_cdef = (2944 + 896 + 896); + u32 av1d_leftline_scaling = (2176 + 1408 + 1408); + u32 av1d_leftline_fg = (1280); + u32 av1d_leftline_lr = (1536 + 1024 + 1024); + + av1d_fe_leftlinebuffer_perlcu_tileboudary = + av1d_leftline_cdef + av1d_leftline_scaling + + av1d_leftline_fg + av1d_leftline_lr; + + if (codec_input.lcu_size == 128) { + frame_lcu_size = 128; + collocated_bytes_per_lcu = 4 * 512; + av1d_segment_read_per_lcu = 512; + llc_saving = 104; + } else if (codec_input.lcu_size == 32) { + frame_lcu_size = 32; + collocated_bytes_per_lcu = 4 * 512 / (128 * 128 / 32 / 32); + av1d_segment_read_per_lcu = 512 / (128 * 128 / 32 / 32); + av1d_fe_leftlinebuffer_perlcu_tileboudary = + av1d_fe_leftlinebuffer_perlcu_tileboudary / (128 * 128 / 32 / 32); + llc_saving = 114; + } else if (codec_input.lcu_size == 64) { + frame_lcu_size = 64; + collocated_bytes_per_lcu = 4 * 512 / (128 * 128 / 64 / 64); + av1d_segment_read_per_lcu = 512 / (128 * 128 / 64 / 64); + av1d_fe_leftlinebuffer_perlcu_tileboudary = + av1d_fe_leftlinebuffer_perlcu_tileboudary / (128 * 128 / 64 / 64); + llc_saving = 107; + } + } + + lcu_per_frame = + calculate_number_lcus_kalama(frame_width, frame_height, frame_lcu_size); + + target_bitrate = (u32)(codec_input.bitrate_mbps); /* Mbps */ + + ubwc_tile_w = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 32 : 48; + ubwc_tile_h = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 8 : 4; + + frame420_y_bw_linear_8bpp = + ((calculate_number_ubwctiles_kalama(frame_width, frame_height, 32, 8) * + 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + + frame420_y_bw_no_ubwc_tile_10bpp = + ((calculate_number_ubwctiles_kalama(frame_width, frame_height, 48, 4) * + 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + frame420_y_bw_linear_10bpp = ((frame_width * frame_height * + codec_input.frame_rate * 2 + 999) / 1000 + 999) / 1000; + + /* TODO Integrate Compression Ratio returned by FW */ + get_compression_factors(&compression_factor, codec_input); + dpb_compression_factor_y = compression_factor.dpb_cf_y; + dpb_compression_factor_cbcr = compression_factor.dpb_cf_cbcr; + opb_compression_factor_ycbcr = compression_factor.opb_cf_ycbcr; + + dpb_ubwc_tile_width_pixels = ubwc_tile_w; + + dpb_ubwc_tile_height_pixels = ubwc_tile_h; + + decoder_frame_complexity_factor = + (codec_input.complexity_setting == 0) ? + 400 : ((codec_input.complexity_setting == 1) ? 266 : 100); + + reconstructed_write_bw_factor_rd = (codec_input.complexity_setting == 0) ? + 105 : 100; + + reference_y_read_bw_factor = llc_saving; + + reference_cbcr_read_bw_factor = llc_saving; + + if (codec_input.codec == CODEC_AV1) { + u8 av1tile_index_entry, av1tile_complexity; + + if (frame_width * frame_height <= 1280 * 720) + av1tile_index_entry = 4; + else if (frame_width * frame_height <= 1920 * 1080) + av1tile_index_entry = 0; + else if (frame_width * frame_height <= 2560 * 1440) + av1tile_index_entry = 5; + else if (frame_width * frame_height <= 4096 * 2304) + av1tile_index_entry = 1; + else + av1tile_index_entry = 6; + + /* NOT PWC //or average and power case */ + if (codec_input.complexity_setting != 0) + av1tile_complexity = 1; + else + av1tile_complexity = 0; + + av1_tile_numbers = av1_num_tiles_kalama[av1tile_index_entry][av1tile_complexity]; + + /* these bw can be ignored */ + av1_collated_seg_buffer_rd_wr = + ((av1d_segment_read_per_lcu * lcu_per_frame * + codec_input.frame_rate + 999) / 1000 + 999) / 1000; + + av1_fe_left_line_buffer_rdwr = + (((av1d_fe_leftlinebuffer_perlcu_tileboudary * + frame_height * (av1_tile_numbers > 1 ? av1_tile_numbers / 2 : 0) + + 999) / 1000 + 999) / 1000 + (frame_lcu_size - 1)) / frame_lcu_size; + } + + if (codec_input.codec == CODEC_HEVC) { + if (codec_input.lcu_size == 32) + bse_tlb_byte_per_lcu = 64; + else if (codec_input.lcu_size == 16) + bse_tlb_byte_per_lcu = 32; + else + bse_tlb_byte_per_lcu = 128; + } else if ((codec_input.codec == CODEC_H264) || + (codec_input.codec == CODEC_H264_CAVLC)) { + bse_tlb_byte_per_lcu = 64; + } else if (codec_input.codec == CODEC_VP9) { + bse_tlb_byte_per_lcu = 304; + } else if (codec_input.codec == CODEC_AV1) { + if (codec_input.lcu_size == 128) + bse_tlb_byte_per_lcu = 2064; + else if (codec_input.lcu_size == 64) + bse_tlb_byte_per_lcu = 1056; + else if (codec_input.lcu_size == 32) + bse_tlb_byte_per_lcu = 2064 / (128 * 128 / 32 / 32); + } + + codec_output->noc_bw_rd = 0; + codec_output->noc_bw_wr = 0; + codec_output->ddr_bw_rd = 0; + codec_output->ddr_bw_wr = 0; + + large_bw_calculation_fp = 0; + large_bw_calculation_fp = ((target_bitrate * + decoder_vsp_read_factor + 7) / 8); + + codec_output->vsp_read_noc = large_bw_calculation_fp; + + codec_output->vsp_read_ddr = codec_output->vsp_read_noc; + + large_bw_calculation_fp = ((target_bitrate * + bins_to_bits_factor + 7) / 8); + + codec_output->vsp_write_noc = large_bw_calculation_fp; + codec_output->vsp_write_ddr = codec_output->vsp_write_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->vsp_read_noc; + codec_output->ddr_bw_rd += codec_output->vsp_read_ddr; + codec_output->noc_bw_wr += codec_output->vsp_write_noc; + codec_output->ddr_bw_wr += codec_output->vsp_write_ddr; + + large_bw_calculation_fp = 0; + large_bw_calculation_fp = ((collocated_bytes_per_lcu * + lcu_per_frame * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + codec_output->collocated_rd_noc = large_bw_calculation_fp; + codec_output->collocated_wr_noc = codec_output->collocated_rd_noc; + codec_output->collocated_rd_ddr = codec_output->collocated_rd_noc; + codec_output->collocated_wr_ddr = codec_output->collocated_wr_noc; + + codec_output->collocated_rd_wr_total_noc = + (u32)(codec_output->collocated_rd_noc + codec_output->collocated_wr_noc); + + codec_output->collocated_rd_wr_total_ddr = + codec_output->collocated_rd_wr_total_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->collocated_rd_noc; + codec_output->noc_bw_wr += codec_output->collocated_wr_noc; + codec_output->ddr_bw_rd += codec_output->collocated_rd_ddr; + codec_output->ddr_bw_wr += codec_output->collocated_wr_ddr; + + large_bw_calculation_fp = 0; + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : + frame420_y_bw_no_ubwc_tile_10bpp) * decoder_frame_complexity_factor; + + large_bw_calculation_fp = + (large_bw_calculation_fp + dpb_compression_factor_y - 1) / + dpb_compression_factor_y; + + codec_output->dpb_rd_y_noc = large_bw_calculation_fp; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) * + decoder_frame_complexity_factor; + + large_bw_calculation_fp = + (large_bw_calculation_fp + dpb_compression_factor_cbcr - 1) / + dpb_compression_factor_cbcr / 2; + + codec_output->dpb_rd_crcb_noc = large_bw_calculation_fp; + codec_output->dpb_rdwr_duetooverlap_noc = 0; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) * + reconstructed_write_bw_factor_rd; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) * + reconstructed_write_bw_factor_rd; + + large_bw_calculation_fp = large_bw_calculation_fp * + (dpb_compression_factor_y / 2 + dpb_compression_factor_cbcr); + + large_bw_calculation_fp = (large_bw_calculation_fp + dpb_compression_factor_y - 1) / + dpb_compression_factor_y; + + large_bw_calculation_fp = + (large_bw_calculation_fp + dpb_compression_factor_cbcr - 1) / + dpb_compression_factor_cbcr; + + codec_output->dpb_wr_noc = large_bw_calculation_fp; + + codec_output->dpb_rd_y_ddr = (llc_enabled_ref_y_rd) ? + ((codec_output->dpb_rd_y_noc * 100 + reference_y_read_bw_factor - 1) / + reference_y_read_bw_factor) : codec_output->dpb_rd_y_noc; + + codec_output->dpb_rd_crcb_ddr = (llc_enable_ref_crcb_rd) ? + ((codec_output->dpb_rd_crcb_noc * 100 + + reference_cbcr_read_bw_factor - 1) / + reference_cbcr_read_bw_factor) : codec_output->dpb_rd_crcb_noc; + + codec_output->dpb_rdwr_duetooverlap_ddr = 0; + codec_output->dpb_wr_ddr = codec_output->dpb_wr_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->dpb_rd_y_noc; + codec_output->noc_bw_rd += codec_output->dpb_rd_crcb_noc; + codec_output->noc_bw_rd += codec_output->dpb_rdwr_duetooverlap_noc; + codec_output->noc_bw_wr += codec_output->dpb_wr_noc; + codec_output->ddr_bw_rd += codec_output->dpb_rd_y_ddr; + codec_output->ddr_bw_rd += codec_output->dpb_rd_crcb_ddr; + codec_output->ddr_bw_rd += codec_output->dpb_rdwr_duetooverlap_ddr; + codec_output->ddr_bw_wr += codec_output->dpb_wr_ddr; + + if (codec_input.linear_opb || codec_input.split_opb) { + if (codec_input.linear_opb) { + if (codec_input.bitdepth == CODEC_BITDEPTH_8) { + large_bw_calculation_fp = ((frame420_y_bw_linear_8bpp) * + 3 / 2 / dpb_to_opb_ratios_ds); + + codec_output->opb_write_total_noc = large_bw_calculation_fp; + } else { + large_bw_calculation_fp = ((frame420_y_bw_linear_10bpp) * + 3 / 2 / dpb_to_opb_ratios_ds); + + codec_output->opb_write_total_noc = large_bw_calculation_fp; + } + } else { /* (CODEC_INPUT.split_opb) */ + if (codec_input.bitdepth == CODEC_BITDEPTH_8) { + large_bw_calculation_fp = + (frame420_y_bw_linear_8bpp * 3 / 2 / dpb_to_opb_ratios_ds * + 100 + opb_compression_factor_ycbcr - 1) / + opb_compression_factor_ycbcr; + + codec_output->opb_write_total_noc = large_bw_calculation_fp; + } else { + large_bw_calculation_fp = + (frame420_y_bw_no_ubwc_tile_10bpp * 3 / 2 / + dpb_to_opb_ratios_ds * 100 + + opb_compression_factor_ycbcr - 1) / + opb_compression_factor_ycbcr; + + codec_output->opb_write_total_noc = large_bw_calculation_fp; + } + } + } else { + codec_output->opb_write_total_noc = 0; + } + + codec_output->opb_write_total_ddr = codec_output->opb_write_total_noc; + + /* accumulation */ + codec_output->noc_bw_wr += codec_output->opb_write_total_noc; + codec_output->ddr_bw_wr += codec_output->opb_write_total_ddr; + + large_bw_calculation_fp = ((bse_tlb_byte_per_lcu * lcu_per_frame * + codec_input.frame_rate + 999) / 1000 + 999) / 1000; + + codec_output->bse_tlb_rd_noc = large_bw_calculation_fp; + + if (llc_enabled_bse_tlb) + codec_output->bse_tlb_rd_ddr = 0; + else + codec_output->bse_tlb_rd_ddr = codec_output->bse_tlb_rd_noc; + + codec_output->bse_tlb_wr_noc = codec_output->bse_tlb_rd_noc; + + if (llc_enabled_bse_tlb) + codec_output->bse_tlb_wr_ddr = 0; + else + codec_output->bse_tlb_wr_ddr = codec_output->bse_tlb_wr_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->bse_tlb_rd_noc; + codec_output->ddr_bw_rd += codec_output->bse_tlb_rd_ddr; + codec_output->noc_bw_wr += codec_output->bse_tlb_wr_noc; + codec_output->ddr_bw_wr += codec_output->bse_tlb_wr_ddr; + + if (codec_input.codec == CODEC_AV1) { + codec_output->statistics_rd_noc = (av1_collated_seg_buffer_rd_wr + + av1_probability_table_rdwr_bytesperframe * av1_tile_numbers / + 1000 / 1000 + av1_fe_left_line_buffer_rdwr); + + codec_output->statistics_wr_noc = (av1_collated_seg_buffer_rd_wr + + av1_probability_table_rdwr_bytesperframe * av1_tile_numbers / + 1000 / 1000 + av1_fe_left_line_buffer_rdwr); + + if (llc_enable_probtable_av1d_21pipe) { + /* assert(CODEC_INPUT.pipe_num != 4); */ + codec_output->statistics_rd_ddr = codec_output->statistics_rd_noc - + av1_probability_table_rdwr_bytesperframe * + av1_tile_numbers / 1000 / 1000; + + codec_output->statistics_wr_ddr = codec_output->statistics_wr_noc - + av1_probability_table_rdwr_bytesperframe * + av1_tile_numbers / 1000 / 1000; + } else { + codec_output->statistics_rd_ddr = codec_output->statistics_rd_noc; + codec_output->statistics_wr_ddr = codec_output->statistics_wr_noc; + } + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->statistics_rd_noc; + codec_output->ddr_bw_rd += codec_output->statistics_rd_ddr; + codec_output->noc_bw_wr += codec_output->statistics_wr_noc; + codec_output->ddr_bw_wr += codec_output->statistics_wr_ddr; + } + + + codec_output->mmu_rd_ddr = 0; + codec_output->mmu_rd_noc = 0; + /* accumulation */ + codec_output->noc_bw_rd += codec_output->mmu_rd_noc; + codec_output->ddr_bw_rd += codec_output->mmu_rd_ddr; + + return 0; +} + +static int calculate_bandwidth_encoder_iris3( + struct api_calculation_input codec_input, + struct api_calculation_bw_output *codec_output) +{ + /* common control parameters */ + u32 frame_width; + u32 frame_height; + u32 frame_lcu_size; + u32 lcu_per_frame; + u32 target_bitrate; + u32 collocated_bytes_per_lcu; + + u32 frame420_y_bw_linear_8bpp; + u32 frame420_y_bw_no_ubwc_tile_10bpp; + u32 frame420_y_bw_linear_10bpp; + + u16 ubwc_tile_w; + u16 ubwc_tile_h; + + u32 dpb_compression_factor_y; + u32 dpb_compression_factor_cbcr; + + u32 reconstructed_write_bw_factor_rd; + u32 reference_y_read_bw_factor; + u32 reference_crcb_read_bw_factor; + + /* encoder control parameters */ + u32 en_vertical_tiles_width = 960; + + u8 en_rotation_90_270 = 0; + /* TODO Can we use (codec_input.status_llc_onoff) for enc_llc_*? */ + u8 en_llc_enable_ref_rd_crcb = 0; + u8 en_llc_enable_rec_wr_uncompleted = 0; + u8 en_llc_enable_ref_rd_y_overlap = 0; + + u32 en_bins_to_bits_factor = 4; + u32 en_search_windows_size_horizontal = 96; + + u32 en_tile_number; + u32 ipb_compression_factor_y; + u32 ipb_compression_factor; + + u32 large_bw_calculation_fp = 0; + + /* TODO Are these really needed in Encoder? */ + u32 bse_tlb_byte_per_lcu = 0; + u8 llc_enabled_bse_tlb = 1; + + /*H265D BSE tlb in LLC will be pored in Kailua */ + llc_enabled_bse_tlb = (codec_input.status_llc_onoff) ? 1 : 0; + + frame_width = codec_input.frame_width; + frame_height = codec_input.frame_height; + if ((codec_input.codec == CODEC_H264) || + (codec_input.codec == CODEC_H264_CAVLC)) { + frame_lcu_size = 16; + collocated_bytes_per_lcu = 16; + } else if (codec_input.codec == CODEC_HEVC) { + frame_lcu_size = 32; + collocated_bytes_per_lcu = 64; + } else { + /* TODO What is the value for VP9, AV1? */ + frame_lcu_size = 16; + collocated_bytes_per_lcu = 16; /* TODO Fixes Uninitialized compilation error. */ + } + + lcu_per_frame = + calculate_number_lcus_kalama(frame_width, frame_height, frame_lcu_size); + + bse_tlb_byte_per_lcu = 16; /* TODO Should be in common declaration */ + + target_bitrate = (u32)(codec_input.bitrate_mbps); /* Mbps */ + + ubwc_tile_w = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 32 : 48; + ubwc_tile_h = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 8 : 4; + + /* yuv */ + if (codec_input.ipb_yuvrgb == 0) { + frame420_y_bw_linear_8bpp = + ((calculate_number_ubwctiles_kalama(frame_width, frame_height, + 32, 8) * 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + } else { /* RGBA */ + frame420_y_bw_linear_8bpp = + ((calculate_number_ubwctiles_kalama(frame_width, frame_height, + 6, 4) * 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + } + + frame420_y_bw_no_ubwc_tile_10bpp = + ((calculate_number_ubwctiles_kalama(frame_width, frame_height, 48, 4) * + 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + + frame420_y_bw_linear_10bpp = ((frame_width * frame_height * + codec_input.frame_rate * 2 + 999) / 1000 + 999) / 1000; + + /* TODO Integrate Compression Ratio returned by FW */ + get_compression_factors(&compression_factor, codec_input); + dpb_compression_factor_y = compression_factor.dpb_cf_y; + dpb_compression_factor_cbcr = compression_factor.dpb_cf_cbcr; + ipb_compression_factor_y = compression_factor.ipb_cr_y; + ipb_compression_factor = compression_factor.ipb_cr; + + en_tile_number = (frame_width % en_vertical_tiles_width) ? + ((frame_width / en_vertical_tiles_width) + 1) : + (frame_width / en_vertical_tiles_width); + + en_tile_number = en_tile_number * 100; + + /* ceil is same as excel roundup (float, 0); */ + reconstructed_write_bw_factor_rd = ((en_tile_number - 100) * 2 * + ((codec_input.lcu_size + ubwc_tile_w - 1) / ubwc_tile_w) * + ubwc_tile_w + (frame_width - 1)) / (frame_width)+100; + + reference_y_read_bw_factor = ((en_tile_number - 100) * 2 * + ((en_search_windows_size_horizontal + ubwc_tile_w - 1) / ubwc_tile_w) * + ubwc_tile_w + (frame_width - 1)) / frame_width + 100; + + reference_crcb_read_bw_factor = 150; + + codec_output->noc_bw_rd = 0; + codec_output->noc_bw_wr = 0; + codec_output->ddr_bw_rd = 0; + codec_output->ddr_bw_wr = 0; + + large_bw_calculation_fp = (target_bitrate * en_bins_to_bits_factor + 7) / 8; + codec_output->vsp_read_noc = large_bw_calculation_fp; + codec_output->vsp_read_ddr = codec_output->vsp_read_noc; + large_bw_calculation_fp = (target_bitrate + 7) / 8; + + codec_output->vsp_write_noc = codec_output->vsp_read_noc + + large_bw_calculation_fp; + + codec_output->vsp_write_ddr = codec_output->vsp_write_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->vsp_read_noc; + codec_output->ddr_bw_rd += codec_output->vsp_read_ddr; + codec_output->noc_bw_wr += codec_output->vsp_write_noc; + codec_output->ddr_bw_wr += codec_output->vsp_write_ddr; + + large_bw_calculation_fp = ((collocated_bytes_per_lcu * lcu_per_frame * + codec_input.frame_rate + 999) / 1000 + 999) / 1000; + + codec_output->collocated_rd_noc = large_bw_calculation_fp; + codec_output->collocated_wr_noc = codec_output->collocated_rd_noc; + codec_output->collocated_rd_ddr = codec_output->collocated_rd_noc; + codec_output->collocated_wr_ddr = codec_output->collocated_wr_noc; + + codec_output->collocated_rd_wr_total_noc = + (u32)(codec_output->collocated_rd_noc + codec_output->collocated_wr_noc); + codec_output->collocated_rd_wr_total_ddr = + codec_output->collocated_rd_wr_total_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->collocated_rd_noc; + codec_output->noc_bw_wr += codec_output->collocated_wr_noc; + codec_output->ddr_bw_rd += codec_output->collocated_rd_ddr; + codec_output->ddr_bw_wr += codec_output->collocated_wr_ddr; + + large_bw_calculation_fp = 0; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : + frame420_y_bw_no_ubwc_tile_10bpp) * reference_y_read_bw_factor; + + large_bw_calculation_fp = (large_bw_calculation_fp * + kalama_en_readfactor[codec_input.hierachical_layer]); + + large_bw_calculation_fp = (large_bw_calculation_fp + + dpb_compression_factor_y - 1) / dpb_compression_factor_y; + + large_bw_calculation_fp = (large_bw_calculation_fp + 999) / 1000; + + codec_output->dpb_rd_y_noc = large_bw_calculation_fp; + + large_bw_calculation_fp = 0; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : + frame420_y_bw_no_ubwc_tile_10bpp) * reference_crcb_read_bw_factor / 2; + + large_bw_calculation_fp = large_bw_calculation_fp * + kalama_en_readfactor[codec_input.hierachical_layer]; + + large_bw_calculation_fp = (large_bw_calculation_fp + + dpb_compression_factor_cbcr - 1) / dpb_compression_factor_cbcr; + + large_bw_calculation_fp = (large_bw_calculation_fp + 999) / 1000; + codec_output->dpb_rd_crcb_noc = large_bw_calculation_fp; + + large_bw_calculation_fp = 0; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) * + reconstructed_write_bw_factor_rd * + kalama_en_writefactor[codec_input.hierachical_layer] / + kalama_en_frame_num_parallel; + + large_bw_calculation_fp = (large_bw_calculation_fp + 999) / 1000; + + large_bw_calculation_fp = large_bw_calculation_fp * + (dpb_compression_factor_cbcr + dpb_compression_factor_y / 2); + + large_bw_calculation_fp = (large_bw_calculation_fp + + dpb_compression_factor_y - 1) / dpb_compression_factor_y; + + large_bw_calculation_fp = (large_bw_calculation_fp + + dpb_compression_factor_cbcr - 1) / dpb_compression_factor_cbcr; + + codec_output->dpb_wr_noc = large_bw_calculation_fp; + + /* + * Summary: + * by default (for both HFR and HSR cases) : + * -Any resolution and fps >= 120, enable layering. + * (120 -> 3, 240 -> 4, 480 -> 5) + * - (once we enable layering) : 50 per cent frames are Non - reference + * frames.recon write is disable by Venus firmware + * - Customer has ability to enable / disable layering. + * Hence, recon write savings would not be there if + * customer explicitly disables layer encoding. + */ + + /*HFR Cases use alternating rec write if not PWC*/ + if ((codec_input.frame_rate >= 120) && (codec_input.complexity_setting != 0)) + codec_output->dpb_wr_noc = codec_output->dpb_wr_noc / 2; + + /* for power cases with [B1] adaptive non-ref b frame */ + /* power caes IbP non reference b */ + if ((codec_input.hierachical_layer >= 1) && + (codec_input.hierachical_layer <= 3) && + (codec_input.complexity_setting != 0)) + codec_output->dpb_wr_noc = codec_output->dpb_wr_noc / 2; + + large_bw_calculation_fp = 0; + large_bw_calculation_fp = codec_output->dpb_wr_noc * + (reconstructed_write_bw_factor_rd - 100); + + large_bw_calculation_fp = (large_bw_calculation_fp + + reconstructed_write_bw_factor_rd - 1) / reconstructed_write_bw_factor_rd; + + codec_output->dpb_rdwr_duetooverlap_noc = large_bw_calculation_fp; + + codec_output->dpb_rd_y_ddr = (en_llc_enable_ref_rd_y_overlap) ? + (codec_output->dpb_rd_y_noc * 100 + reference_y_read_bw_factor - 1) / + reference_y_read_bw_factor : codec_output->dpb_rd_y_noc; + + codec_output->dpb_rd_crcb_ddr = (en_llc_enable_ref_rd_crcb) ? + (codec_output->dpb_rd_crcb_noc * 100 + reference_crcb_read_bw_factor - 1) / + reference_crcb_read_bw_factor : codec_output->dpb_rd_crcb_noc; + + codec_output->dpb_rdwr_duetooverlap_ddr = (en_llc_enable_rec_wr_uncompleted) ? + 0 : codec_output->dpb_rdwr_duetooverlap_noc; + + codec_output->dpb_wr_ddr = (en_llc_enable_rec_wr_uncompleted) ? + 0 : codec_output->dpb_wr_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->dpb_rd_y_noc; + codec_output->noc_bw_rd += codec_output->dpb_rd_crcb_noc; + codec_output->noc_bw_rd += codec_output->dpb_rdwr_duetooverlap_noc; + codec_output->noc_bw_wr += codec_output->dpb_wr_noc; + codec_output->ddr_bw_rd += codec_output->dpb_rd_y_ddr; + codec_output->ddr_bw_rd += codec_output->dpb_rd_crcb_ddr; + codec_output->ddr_bw_rd += codec_output->dpb_rdwr_duetooverlap_ddr; + codec_output->ddr_bw_wr += codec_output->dpb_wr_ddr; + + if (codec_input.bitdepth == CODEC_BITDEPTH_8) { + if (codec_input.ipb_yuvrgb == 0) { /* yuv */ + large_bw_calculation_fp = ((frame420_y_bw_linear_8bpp) * 3 / 2); + codec_output->ipb_rd_total_noc = large_bw_calculation_fp; + if (codec_input.linear_ipb == 0) { + codec_output->ipb_rd_total_noc = + (large_bw_calculation_fp * 100 + + ipb_compression_factor - 1) / ipb_compression_factor; + } + } else { /* rgb */ + large_bw_calculation_fp = frame420_y_bw_linear_8bpp; + codec_output->ipb_rd_total_noc = large_bw_calculation_fp; + if (codec_input.linear_ipb == 0) { + if (codec_input.complexity_setting == 0) /* pwc */ + codec_output->ipb_rd_total_noc = + (large_bw_calculation_fp * 100 + + en_original_compression_factor_rgba_pwd_kalama + - 1) / + en_original_compression_factor_rgba_pwd_kalama; + else + codec_output->ipb_rd_total_noc = + (large_bw_calculation_fp * 100 + + en_original_compression_factor_rgba_avg_kalama - 1) / + en_original_compression_factor_rgba_avg_kalama; + } + } + } else { + if (codec_input.linear_ipb == 1) { + large_bw_calculation_fp = (frame420_y_bw_linear_10bpp) * 3 / 2; + codec_output->ipb_rd_total_noc = large_bw_calculation_fp; + } else { + large_bw_calculation_fp = (frame420_y_bw_no_ubwc_tile_10bpp * + 300 / 2 + ipb_compression_factor - 1) / ipb_compression_factor; + codec_output->ipb_rd_total_noc = large_bw_calculation_fp; + } + } + + if (en_rotation_90_270) { + if (codec_input.codec == CODEC_HEVC) { + if ((codec_input.bitdepth == CODEC_BITDEPTH_8) && + (codec_input.ipb_yuvrgb == 0)) + codec_output->ipb_rd_total_noc = codec_output->ipb_rd_total_noc + * 1; + else + codec_output->ipb_rd_total_noc = codec_output->ipb_rd_total_noc + * 3; + } else { + codec_output->ipb_rd_total_noc = codec_output->ipb_rd_total_noc * 2; + } + } + + codec_output->ipb_rd_total_ddr = codec_output->ipb_rd_total_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->ipb_rd_total_noc; + codec_output->ddr_bw_rd += codec_output->ipb_rd_total_ddr; + + codec_output->bse_tlb_rd_noc = + ((bse_tlb_byte_per_lcu * lcu_per_frame * codec_input.frame_rate + 999) + / 1000 + 999) / 1000; + + if (llc_enabled_bse_tlb) /* TODO should be common declaration */ + codec_output->bse_tlb_rd_ddr = 0; + else + codec_output->bse_tlb_rd_ddr = codec_output->bse_tlb_rd_noc; + + codec_output->bse_tlb_wr_noc = codec_output->bse_tlb_rd_noc; + + if (llc_enabled_bse_tlb) + codec_output->bse_tlb_wr_ddr = 0; + else + codec_output->bse_tlb_wr_ddr = codec_output->bse_tlb_wr_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->bse_tlb_rd_noc; + codec_output->ddr_bw_rd += codec_output->bse_tlb_rd_ddr; + codec_output->noc_bw_wr += codec_output->bse_tlb_wr_noc; + codec_output->ddr_bw_wr += codec_output->bse_tlb_wr_ddr; + + codec_output->mmu_rd_ddr = 0; + codec_output->mmu_rd_noc = 0; + /* accumulation */ + codec_output->noc_bw_rd += codec_output->mmu_rd_noc; + codec_output->ddr_bw_rd += codec_output->mmu_rd_ddr; + + return 0; +} + +int msm_vidc_calculate_bandwidth(struct api_calculation_input codec_input, + struct api_calculation_bw_output *codec_output) +{ + int rc = 0; + + if (codec_input.decoder_or_encoder == CODEC_DECODER) { + rc = calculate_bandwidth_decoder_iris3(codec_input, codec_output); + } else if (codec_input.decoder_or_encoder == CODEC_ENCODER) { + rc = calculate_bandwidth_encoder_iris3(codec_input, codec_output); + } else { + d_vpr_e("%s: invalid codec\n", codec_input.decoder_or_encoder); + return -EINVAL; + } + + return rc; +} + diff --git a/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_clock_iris3.c b/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_clock_iris3.c new file mode 100644 index 0000000000..6c187a5967 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_clock_iris3.c @@ -0,0 +1,557 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "kalama_technology.h" +#include "msm_vidc_debug.h" + +static u32 calculate_number_mbs_kalama(u32 width, u32 height, u32 lcu_size) +{ + u32 mbs_width = (width % lcu_size) ? + (width / lcu_size + 1) : (width / lcu_size); + + u32 mbs_height = (height % lcu_size) ? + (height / lcu_size + 1) : (height / lcu_size); + + return mbs_width * mbs_height * (lcu_size / 16) * (lcu_size / 16); +} + +static int initialize_encoder_complexity_table(void) +{ + /* Beging Calculate Encoder GOP Complexity Table and HW Floor numbers */ + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] = 70000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY] = 10000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY] * 100); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY] - 1); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] / + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY]); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] = 30000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY] = 10000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY] * 100); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY] - 1); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] / + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY]); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] = 10000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY] = 10000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY] * 100); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY] - 1); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] / + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY]); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] = 0; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY] = 1; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY] * 100); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY] - 1); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] / + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY]); + + return 0; +} + +u32 get_bitrate_entry(u32 pixle_count) +{ + u32 bitrate_entry = 0; + + if (pixle_count >= fp_pixel_count_bar1) + bitrate_entry = 1; + else if (pixle_count >= fp_pixel_count_bar2) + bitrate_entry = 2; + else if (pixle_count >= fp_pixel_count_bar3) + bitrate_entry = 3; + else if (pixle_count >= fp_pixel_count_bar4) + bitrate_entry = 4; + else if (pixle_count >= fp_pixel_count_bar5) + bitrate_entry = 5; + else if (pixle_count >= fp_pixel_count_bar6) + bitrate_entry = 6; + else if (pixle_count >= fp_pixel_count_bar7) + bitrate_entry = 7; + else if (pixle_count >= fp_pixel_count_bar8) + bitrate_entry = 8; + else if (pixle_count >= fp_pixel_count_bar9) + bitrate_entry = 9; + else + bitrate_entry = 9; + + return bitrate_entry; +} + +static int calculate_vsp_min_freq(struct api_calculation_input codec_input, + struct api_calculation_freq_output *codec_output) +{ + /* + * VSP calculation + * different methodology from Lahaina + */ + u32 vsp_hw_min_frequency = 0; + /* UInt32 decoder_vsp_fw_overhead = 100 + 5; // amplified by 100x */ + u32 fw_sw_vsp_offset = 1000 + 55; /* amplified by 1000x */ + + /* + * Ignore fw_sw_vsp_offset, as this is baked into the reference bitrate tables. + * As a consequence remove x1000 multipler as well. + */ + u32 codec = codec_input.codec; + /* UInt32 *bitratetable; */ + u32 pixle_count = codec_input.frame_width * + codec_input.frame_height * codec_input.frame_rate; + + u8 bitrate_entry = get_bitrate_entry(pixle_count); /* TODO EXTRACT */ + + input_bitrate_fp = ((u32)(codec_input.bitrate_mbps * 100 + 99)) / 100; + vsp_hw_min_frequency = frequency_table_kalama[0][1] * input_bitrate_fp * 1000; + + /* 8KUHD60fps with B frame */ + if ((pixle_count >= fp_pixel_count_bar0) && + (codec_input.hierachical_layer != CODEC_GOP_IPP)) { + /* + * FORMULA: VSPfreq = NOMINAL * (InputBitrate / ReferenceBitrate); + * ReferenceBitrate = 0 for, + * - 1Stage TURBO, all Codecs. + * - 2Stage TURBO, H264 & H265. + * + * 8KUHD60fps with B frame + * - bitrate_entry = 0 + * - Clock=NOMINAL for H264 & 2Stage H265. Because bitrate + * table entry for TURBO is 0. + * + * TODO : Reduce these conditions by removing the zero entries from Bitrate table. + */ + vsp_hw_min_frequency = frequency_table_kalama[0][1] * + input_bitrate_fp * 1000; + + if (codec_input.codec == CODEC_AV1) + vsp_hw_min_frequency = frequency_table_kalama[0][0] * + input_bitrate_fp * 1000; + + if ((codec_input.codec == CODEC_H264) || + (codec_input.codec == CODEC_H264_CAVLC) || + ((codec_input.codec == CODEC_HEVC) && + (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_1S))) { + vsp_hw_min_frequency = + DIV_ROUND_UP(frequency_table_kalama[0][1], fw_sw_vsp_offset); + } else if (((codec_input.codec == CODEC_HEVC) && + (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S)) + || (codec_input.codec == CODEC_VP9) + || (codec_input.codec == CODEC_AV1)) { + if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) { + vsp_hw_min_frequency = DIV_ROUND_UP(vsp_hw_min_frequency, + (bitrate_table_kalama_2stage_fp[codec][0] * + fw_sw_vsp_offset)); + } else { + vsp_hw_min_frequency = DIV_ROUND_UP(vsp_hw_min_frequency, + (bitrate_table_kalama_1stage_fp[codec][0] * + fw_sw_vsp_offset)); + } + } + } else { + vsp_hw_min_frequency = frequency_table_kalama[0][1] * + input_bitrate_fp * 1000; + + if (codec_input.codec == CODEC_AV1 && bitrate_entry == 1) + vsp_hw_min_frequency = frequency_table_kalama[0][0] * + input_bitrate_fp * 1000; + + if ((codec_input.codec == CODEC_H264_CAVLC) && + (codec_input.entropy_coding_mode == CODEC_ENTROPY_CODING_CAVLC)) + codec = CODEC_H264_CAVLC; + else if ((codec_input.codec == CODEC_H264) && + (codec_input.entropy_coding_mode == CODEC_ENTROPY_CODING_CABAC)) + codec = CODEC_H264; + + if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) + vsp_hw_min_frequency = DIV_ROUND_UP(vsp_hw_min_frequency, + (bitrate_table_kalama_2stage_fp[codec][bitrate_entry]) * + fw_sw_vsp_offset); + else + vsp_hw_min_frequency = DIV_ROUND_UP(vsp_hw_min_frequency, + (bitrate_table_kalama_1stage_fp[codec][bitrate_entry]) * + fw_sw_vsp_offset); + } + + codec_output->vsp_min_freq = vsp_hw_min_frequency; + return 0; +} + +static u32 calculate_pipe_penalty(struct api_calculation_input codec_input) +{ + u32 pipe_penalty_codec = 0; + u8 avid_commercial_content = 0; + u32 pixel_count = 0; + + /* decoder */ + if (codec_input.decoder_or_encoder == CODEC_DECODER) { + pipe_penalty_codec = pipe_penalty_kalama[0][0]; + avid_commercial_content = codec_input.av1d_commer_tile_enable; + if (codec_input.codec == CODEC_AV1) { + pixel_count = codec_input.frame_width * codec_input.frame_height; + if (pixel_count <= 1920 * 1080) + pipe_penalty_codec = + pipe_penalty_kalama[avid_commercial_content + 1][0]; + else if (pixel_count < 3840 * 2160) + pipe_penalty_codec = + (pipe_penalty_kalama[avid_commercial_content + 1][0] + + pipe_penalty_kalama[avid_commercial_content + 1][1]) / 2; + else if ((pixel_count == 3840 * 2160) || + (pixel_count == 4096 * 2160) || (pixel_count == 4096 * 2304)) + pipe_penalty_codec = + pipe_penalty_kalama[avid_commercial_content + 1][1]; + else if (pixel_count < 7680 * 4320) + pipe_penalty_codec = + (pipe_penalty_kalama[avid_commercial_content + 1][1] + + pipe_penalty_kalama[avid_commercial_content + 1][2]) / 2; + else + pipe_penalty_codec = + pipe_penalty_kalama[avid_commercial_content + 1][2]; + } + } else { + pipe_penalty_codec = 101; + } + + return pipe_penalty_codec; +} + +static int calculate_vpp_min_freq(struct api_calculation_input codec_input, + struct api_calculation_freq_output *codec_output) +{ + u32 vpp_hw_min_frequency = 0; + u32 fmin = 0; + u32 tensilica_min_frequency = 0; + u32 decoder_vsp_fw_overhead = 100 + 5; /* amplified by 100x */ + /* UInt32 fw_sw_vsp_offset = 1000 + 55; amplified by 1000x */ + /* TODO from calculate_sw_vsp_min_freq */ + u32 vsp_hw_min_frequency = codec_output->vsp_min_freq; + u32 pipe_penalty_codec = 0; + u32 fmin_fwoverhead105 = 0; + u32 fmin_measured_fwoverhead = 0; + u32 lpmode_uhd_cycle_permb = 0; + u32 hqmode1080p_cycle_permb = 0; + u32 encoder_vpp_target_clk_per_mb = 0; + + codec_mbspersession_kalama = + calculate_number_mbs_kalama(codec_input.frame_width, + codec_input.frame_height, codec_input.lcu_size) * + codec_input.frame_rate; + + /* Section 2. 0 VPP/VSP calculation */ + if (codec_input.decoder_or_encoder == CODEC_DECODER) { /* decoder */ + vpp_hw_min_frequency = ((decoder_vpp_target_clk_per_mb_kalama) * + (codec_mbspersession_kalama) + codec_input.pipe_num - 1) / + (codec_input.pipe_num); + + vpp_hw_min_frequency = (vpp_hw_min_frequency + 99999) / 1000000; + + if (codec_input.pipe_num > 1) { + pipe_penalty_codec = calculate_pipe_penalty(codec_input); + vpp_hw_min_frequency = (vpp_hw_min_frequency * + pipe_penalty_codec + 999) / 1000; + } + + if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) { + /* FW overhead, convert FW cycles to impact to one pipe */ + u64 decoder_vpp_fw_overhead = 0; + + decoder_vpp_fw_overhead = + DIV_ROUND_UP((DECODER_VPP_FW_OVERHEAD_KALAMA * 10 * + codec_input.frame_rate), 15); + + decoder_vpp_fw_overhead = + DIV_ROUND_UP((decoder_vpp_fw_overhead * 1000), + (codec_mbspersession_kalama * + decoder_vpp_target_clk_per_mb_kalama / codec_input.pipe_num)); + + decoder_vpp_fw_overhead += 1000; + decoder_vpp_fw_overhead = (decoder_vpp_fw_overhead < 1050) ? + 1050 : decoder_vpp_fw_overhead; + + /* VPP HW + FW */ + if (codec_input.linear_opb == 1 && + codec_input.bitdepth == CODEC_BITDEPTH_10) + /* multiply by 1.20 for 10b case */ + decoder_vpp_fw_overhead = 1200 + decoder_vpp_fw_overhead - 1000; + + vpp_hw_min_frequency = (vpp_hw_min_frequency * + decoder_vpp_fw_overhead + 999) / 1000; + + /* VSP HW+FW */ + vsp_hw_min_frequency = + (vsp_hw_min_frequency * decoder_vsp_fw_overhead + 99) / 100; + + fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ? + vpp_hw_min_frequency : vsp_hw_min_frequency; + } else { + /* 1-stage need SW cycles + FW cycles + HW time */ + if (codec_input.linear_opb == 1 && + codec_input.bitdepth == CODEC_BITDEPTH_10) + /* multiply by 1.20 for 10b linear case */ + vpp_hw_min_frequency = + (vpp_hw_min_frequency * 1200 + 999) / 1000; + + /* + * HW time + * comment: 02/23/2021 SY: the bitrate is measured bitrate, + * the overlapping effect is already considered into bitrate. + * no need to add extra anymore + */ + fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ? + vpp_hw_min_frequency : vsp_hw_min_frequency; + + /* FW time */ + fmin_fwoverhead105 = (fmin * 105 + 99) / 100; + fmin_measured_fwoverhead = fmin + + (((DECODER_VPPVSP1STAGE_FW_OVERHEAD_KALAMA * + codec_input.frame_rate * 10 + 14) / 15 + 999) / 1000 + 999) / + 1000; + + fmin = (fmin_fwoverhead105 > fmin_measured_fwoverhead) ? + fmin_fwoverhead105 : fmin_measured_fwoverhead; + } + + tensilica_min_frequency = (DECODER_SW_OVERHEAD_KALAMA * 10 + 14) / 15; + tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000; + tensilica_min_frequency = tensilica_min_frequency * codec_input.frame_rate; + tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000; + fmin = (tensilica_min_frequency > fmin) ? tensilica_min_frequency : fmin; + } else { /* encoder */ + /* Decide LP/HQ */ + u8 hq_mode = 0; + + if (codec_input.pipe_num > 1) + if (codec_input.frame_width * codec_input.frame_height <= + 1920 * 1080) + if (codec_input.frame_width * codec_input.frame_height * + codec_input.frame_rate <= 1920 * 1080 * 60) + hq_mode = 1; + + codec_output->enc_hqmode = hq_mode; + + /* Section 1. 0 */ + /* TODO ONETIME call, should be in another place. */ + initialize_encoder_complexity_table(); + + /* End Calculate Encoder GOP Complexity Table */ + + /* VPP base cycle */ + lpmode_uhd_cycle_permb = (320 * + codec_encoder_gop_complexity_table_fp + [codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + 99) / 100; + + if ((codec_input.frame_width == 1920) && + ((codec_input.frame_height == 1080) || + (codec_input.frame_height == 1088)) && + (codec_input.frame_rate >= 480)) + lpmode_uhd_cycle_permb = (90 * 4 * + codec_encoder_gop_complexity_table_fp + [codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + 99) / 100; + + if ((codec_input.frame_width == 1280) && + ((codec_input.frame_height == 720) || + (codec_input.frame_height == 768)) && + (codec_input.frame_rate >= 960)) + lpmode_uhd_cycle_permb = (99 * 4 * + codec_encoder_gop_complexity_table_fp + [codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + 99) / 100; + + hqmode1080p_cycle_permb = (675 * + codec_encoder_gop_complexity_table_fp + [codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + 99) / 100; + + encoder_vpp_target_clk_per_mb = (hq_mode) ? + hqmode1080p_cycle_permb : lpmode_uhd_cycle_permb; + + vpp_hw_min_frequency = ((encoder_vpp_target_clk_per_mb) * + (codec_mbspersession_kalama) + codec_input.pipe_num - 1) / + (codec_input.pipe_num); + + vpp_hw_min_frequency = (vpp_hw_min_frequency + 99999) / 1000000; + + if (codec_input.pipe_num > 1) { + u32 pipe_penalty_codec = 101; + + vpp_hw_min_frequency = (vpp_hw_min_frequency * + pipe_penalty_codec + 99) / 100; + } + + if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) { + /* FW overhead, convert FW cycles to impact to one pipe */ + u64 encoder_vpp_fw_overhead = 0; + + encoder_vpp_fw_overhead = + DIV_ROUND_UP((ENCODER_VPP_FW_OVERHEAD_KALAMA * 10 * + codec_input.frame_rate), 15); + + encoder_vpp_fw_overhead = + DIV_ROUND_UP((encoder_vpp_fw_overhead * 1000), + (codec_mbspersession_kalama * encoder_vpp_target_clk_per_mb / + codec_input.pipe_num)); + + encoder_vpp_fw_overhead += 1000; + + encoder_vpp_fw_overhead = (encoder_vpp_fw_overhead < 1050) ? + 1050 : encoder_vpp_fw_overhead; + + /* VPP HW + FW */ + vpp_hw_min_frequency = (vpp_hw_min_frequency * + encoder_vpp_fw_overhead + 999) / 1000; + + /* TODO : decoder_vsp_fw_overhead? */ + vsp_hw_min_frequency = (vsp_hw_min_frequency * + decoder_vsp_fw_overhead + 99) / 100; + + fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ? + vpp_hw_min_frequency : vsp_hw_min_frequency; + } else { + /* HW time */ + fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ? + vpp_hw_min_frequency : vsp_hw_min_frequency; + + /* FW time */ + fmin_fwoverhead105 = (fmin * 105 + 99) / 100; + fmin_measured_fwoverhead = fmin + + (((DECODER_VPPVSP1STAGE_FW_OVERHEAD_KALAMA * + codec_input.frame_rate * 10 + 14) / 15 + 999) / + 1000 + 999) / 1000; + + fmin = (fmin_fwoverhead105 > fmin_measured_fwoverhead) ? + fmin_fwoverhead105 : fmin_measured_fwoverhead; + /* SW time */ + } + + tensilica_min_frequency = (ENCODER_SW_OVERHEAD_KALAMA * 10 + 14) / 15; + tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000; + + tensilica_min_frequency = tensilica_min_frequency * + codec_input.frame_rate; + + tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000; + + fmin = (tensilica_min_frequency > fmin) ? + tensilica_min_frequency : fmin; + } + + codec_output->vpp_min_freq = vpp_hw_min_frequency; + codec_output->vsp_min_freq = vsp_hw_min_frequency; + codec_output->tensilica_min_freq = tensilica_min_frequency; + codec_output->hw_min_freq = fmin; + + return 0; +} + +int msm_vidc_calculate_frequency(struct api_calculation_input codec_input, + struct api_calculation_freq_output *codec_output) +{ + int rc = 0; + + rc = calculate_vsp_min_freq(codec_input, codec_output); + if (rc) + return rc; + + rc = calculate_vpp_min_freq(codec_input, codec_output); + if (rc) + return rc; + + return rc; +} diff --git a/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_iris3.c b/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_iris3.c new file mode 100644 index 0000000000..edb503f13c --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_iris3.c @@ -0,0 +1,1038 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_iris3.h" +#include "msm_vidc_buffer_iris3.h" +#include "msm_vidc_power_iris3.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_buffer.h" +#include "msm_vidc_state.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_variant.h" +#include "venus_hfi.h" + +#define VIDEO_ARCH_LX 1 + +#define VCODEC_BASE_OFFS_IRIS3 0x00000000 +#define AON_MVP_NOC_RESET 0x0001F000 +#define CPU_BASE_OFFS_IRIS3 0x000A0000 +#define AON_BASE_OFFS 0x000E0000 +#define CPU_CS_BASE_OFFS_IRIS3 (CPU_BASE_OFFS_IRIS3) +#define CPU_IC_BASE_OFFS_IRIS3 (CPU_BASE_OFFS_IRIS3) + +#define CPU_CS_A2HSOFTINTCLR_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x1C) +#define CPU_CS_VCICMD_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x20) +#define CPU_CS_VCICMDARG0_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x24) +#define CPU_CS_VCICMDARG1_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x28) +#define CPU_CS_VCICMDARG2_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x2C) +#define CPU_CS_VCICMDARG3_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x30) +#define CPU_CS_VMIMSG_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x34) +#define CPU_CS_VMIMSGAG0_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x38) +#define CPU_CS_VMIMSGAG1_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x3C) +#define CPU_CS_SCIACMD_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x48) +#define CPU_CS_H2XSOFTINTEN_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x148) + +/* HFI_CTRL_STATUS */ +#define CPU_CS_SCIACMDARG0_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x4C) +#define CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS3 0xfe +#define CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_IRIS3 0x100 +#define CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS3 0x40000000 + +/* HFI_QTBL_INFO */ +#define CPU_CS_SCIACMDARG1_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x50) + +/* HFI_QTBL_ADDR */ +#define CPU_CS_SCIACMDARG2_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x54) + +/* HFI_VERSION_INFO */ +#define CPU_CS_SCIACMDARG3_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x58) + +/* SFR_ADDR */ +#define CPU_CS_SCIBCMD_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x5C) + +/* MMAP_ADDR */ +#define CPU_CS_SCIBCMDARG0_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x60) + +/* UC_REGION_ADDR */ +#define CPU_CS_SCIBARG1_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x64) + +/* UC_REGION_ADDR */ +#define CPU_CS_SCIBARG2_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x68) + +#define CPU_CS_AHB_BRIDGE_SYNC_RESET (CPU_CS_BASE_OFFS_IRIS3 + 0x160) +#define CPU_CS_AHB_BRIDGE_SYNC_RESET_STATUS (CPU_CS_BASE_OFFS_IRIS3 + 0x164) + +/* FAL10 Feature Control */ +#define CPU_CS_X2RPMh_IRIS3 (CPU_CS_BASE_OFFS_IRIS3 + 0x168) +#define CPU_CS_X2RPMh_MASK0_BMSK_IRIS3 0x1 +#define CPU_CS_X2RPMh_MASK0_SHFT_IRIS3 0x0 +#define CPU_CS_X2RPMh_MASK1_BMSK_IRIS3 0x2 +#define CPU_CS_X2RPMh_MASK1_SHFT_IRIS3 0x1 +#define CPU_CS_X2RPMh_SWOVERRIDE_BMSK_IRIS3 0x4 +#define CPU_CS_X2RPMh_SWOVERRIDE_SHFT_IRIS3 0x3 + +#define CPU_IC_SOFTINT_IRIS3 (CPU_IC_BASE_OFFS_IRIS3 + 0x150) +#define CPU_IC_SOFTINT_H2A_SHFT_IRIS3 0x0 + +/* + * -------------------------------------------------------------------------- + * MODULE: AON_MVP_NOC_RESET_REGISTERS + * -------------------------------------------------------------------------- + */ +#define AON_WRAPPER_MVP_NOC_RESET_REQ (AON_MVP_NOC_RESET + 0x000) +#define AON_WRAPPER_MVP_NOC_RESET_ACK (AON_MVP_NOC_RESET + 0x004) + +/* + * -------------------------------------------------------------------------- + * MODULE: wrapper + * -------------------------------------------------------------------------- + */ +#define WRAPPER_BASE_OFFS_IRIS3 0x000B0000 +#define WRAPPER_INTR_STATUS_IRIS3 (WRAPPER_BASE_OFFS_IRIS3 + 0x0C) +#define WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3 0x8 +#define WRAPPER_INTR_STATUS_A2H_BMSK_IRIS3 0x4 + +#define WRAPPER_INTR_MASK_IRIS3 (WRAPPER_BASE_OFFS_IRIS3 + 0x10) +#define WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS3 0x8 +#define WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS3 0x4 + +#define WRAPPER_CPU_CLOCK_CONFIG_IRIS3 (WRAPPER_BASE_OFFS_IRIS3 + 0x2000) +#define WRAPPER_CPU_CGC_DIS_IRIS3 (WRAPPER_BASE_OFFS_IRIS3 + 0x2010) +#define WRAPPER_CPU_STATUS_IRIS3 (WRAPPER_BASE_OFFS_IRIS3 + 0x2014) + +#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS3 (WRAPPER_BASE_OFFS_IRIS3 + 0x54) +#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS3 (WRAPPER_BASE_OFFS_IRIS3 + 0x58) +#define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL (WRAPPER_BASE_OFFS_IRIS3 + 0x5C) +#define WRAPPER_IRIS_CPU_NOC_LPI_STATUS (WRAPPER_BASE_OFFS_IRIS3 + 0x60) +#define WRAPPER_CORE_POWER_STATUS (WRAPPER_BASE_OFFS_IRIS3 + 0x80) +#define WRAPPER_CORE_CLOCK_CONFIG_IRIS3 (WRAPPER_BASE_OFFS_IRIS3 + 0x88) + +/* + * -------------------------------------------------------------------------- + * MODULE: tz_wrapper + * -------------------------------------------------------------------------- + */ +#define WRAPPER_TZ_BASE_OFFS 0x000C0000 +#define WRAPPER_TZ_CPU_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS) +#define WRAPPER_TZ_CPU_STATUS (WRAPPER_TZ_BASE_OFFS + 0x10) +#define WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS + 0x14) +#define WRAPPER_TZ_QNS4PDXFIFO_RESET (WRAPPER_TZ_BASE_OFFS + 0x18) + +#define CTRL_INIT_IRIS3 CPU_CS_SCIACMD_IRIS3 + +#define CTRL_STATUS_IRIS3 CPU_CS_SCIACMDARG0_IRIS3 +#define CTRL_ERROR_STATUS__M_IRIS3 \ + CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS3 +#define CTRL_INIT_IDLE_MSG_BMSK_IRIS3 \ + CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS3 +#define CTRL_STATUS_PC_READY_IRIS3 \ + CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_IRIS3 + + +#define QTBL_INFO_IRIS3 CPU_CS_SCIACMDARG1_IRIS3 + +#define QTBL_ADDR_IRIS3 CPU_CS_SCIACMDARG2_IRIS3 + +#define VERSION_INFO_IRIS3 CPU_CS_SCIACMDARG3_IRIS3 + +#define SFR_ADDR_IRIS3 CPU_CS_SCIBCMD_IRIS3 +#define MMAP_ADDR_IRIS3 CPU_CS_SCIBCMDARG0_IRIS3 +#define UC_REGION_ADDR_IRIS3 CPU_CS_SCIBARG1_IRIS3 +#define UC_REGION_SIZE_IRIS3 CPU_CS_SCIBARG2_IRIS3 + +#define AON_WRAPPER_MVP_NOC_LPI_CONTROL (AON_BASE_OFFS) +#define AON_WRAPPER_MVP_NOC_LPI_STATUS (AON_BASE_OFFS + 0x4) + +/* + * -------------------------------------------------------------------------- + * MODULE: VCODEC_SS registers + * -------------------------------------------------------------------------- + */ +#define VCODEC_SS_IDLE_STATUSn (VCODEC_BASE_OFFS_IRIS3 + 0x70) + +/* + * -------------------------------------------------------------------------- + * MODULE: vcodec noc error log registers (iris3) + * -------------------------------------------------------------------------- + */ +#define VCODEC_NOC_VIDEO_A_NOC_BASE_OFFS 0x00010000 +#define VCODEC_NOC_ERL_MAIN_SWID_LOW 0x00011200 +#define VCODEC_NOC_ERL_MAIN_SWID_HIGH 0x00011204 +#define VCODEC_NOC_ERL_MAIN_MAINCTL_LOW 0x00011208 +#define VCODEC_NOC_ERL_MAIN_ERRVLD_LOW 0x00011210 +#define VCODEC_NOC_ERL_MAIN_ERRCLR_LOW 0x00011218 +#define VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW 0x00011220 +#define VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH 0x00011224 +#define VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW 0x00011228 +#define VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH 0x0001122C +#define VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW 0x00011230 +#define VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH 0x00011234 +#define VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW 0x00011238 +#define VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH 0x0001123C + +static int __interrupt_init_iris3(struct msm_vidc_core *core) +{ + u32 mask_val = 0; + int rc = 0; + + /* All interrupts should be disabled initially 0x1F6 : Reset value */ + rc = __read_register(core, WRAPPER_INTR_MASK_IRIS3, &mask_val); + if (rc) + return rc; + + /* Write 0 to unmask CPU and WD interrupts */ + mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS3 | + WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS3); + rc = __write_register(core, WRAPPER_INTR_MASK_IRIS3, mask_val); + if (rc) + return rc; + + return 0; +} + +static int __setup_ucregion_memory_map_iris3(struct msm_vidc_core *core) +{ + u32 value; + int rc = 0; + + value = (u32)core->iface_q_table.align_device_addr; + rc = __write_register(core, UC_REGION_ADDR_IRIS3, value); + if (rc) + return rc; + + value = SHARED_QSIZE; + rc = __write_register(core, UC_REGION_SIZE_IRIS3, value); + if (rc) + return rc; + + value = (u32)core->iface_q_table.align_device_addr; + rc = __write_register(core, QTBL_ADDR_IRIS3, value); + if (rc) + return rc; + + rc = __write_register(core, QTBL_INFO_IRIS3, 0x01); + if (rc) + return rc; + + /* update queues vaddr for debug purpose */ + value = (u32)((u64)core->iface_q_table.align_virtual_addr); + rc = __write_register(core, CPU_CS_VCICMDARG0_IRIS3, value); + if (rc) + return rc; + + value = (u32)((u64)core->iface_q_table.align_virtual_addr >> 32); + rc = __write_register(core, CPU_CS_VCICMDARG1_IRIS3, value); + if (rc) + return rc; + + if (core->sfr.align_device_addr) { + value = (u32)core->sfr.align_device_addr + VIDEO_ARCH_LX; + rc = __write_register(core, SFR_ADDR_IRIS3, value); + if (rc) + return rc; + } + + return 0; +} + +static bool is_iris3_hw_power_collapsed(struct msm_vidc_core *core) +{ + int rc = 0; + u32 value = 0, pwr_status = 0; + + rc = __read_register(core, WRAPPER_CORE_POWER_STATUS, &value); + if (rc) + return false; + + /* if BIT(1) is 1 then video hw power is on else off */ + pwr_status = value & BIT(1); + return pwr_status ? false : true; +} + +static int __power_off_iris3_hardware(struct msm_vidc_core *core) +{ + int rc = 0, i; + u32 value = 0; + bool pwr_collapsed = false; + + /* + * Incase hw power control is enabled, for both CPU WD, video + * hw unresponsive cases, check for power status to decide on + * executing NOC reset sequence before disabling power. If there + * is no CPU WD and hw power control is enabled, fw is expected + * to power collapse video hw always. + */ + if (is_core_sub_state(core, CORE_SUBSTATE_FW_PWR_CTRL)) { + pwr_collapsed = is_iris3_hw_power_collapsed(core); + if (is_core_sub_state(core, CORE_SUBSTATE_CPU_WATCHDOG) || + is_core_sub_state(core, CORE_SUBSTATE_VIDEO_UNRESPONSIVE)) { + if (pwr_collapsed) { + d_vpr_e("%s: video hw power collapsed %s\n", + __func__, core->sub_state_name); + goto disable_power; + } else { + d_vpr_e("%s: video hw is power ON %s\n", + __func__, core->sub_state_name); + } + } else { + if (!pwr_collapsed) + d_vpr_e("%s: video hw is not power collapsed\n", __func__); + + d_vpr_h("%s: disabling hw power\n", __func__); + goto disable_power; + } + } + + /* + * check to make sure core clock branch enabled else + * we cannot read vcodec top idle register + */ + rc = __read_register(core, WRAPPER_CORE_CLOCK_CONFIG_IRIS3, &value); + if (rc) + return rc; + + if (value) { + d_vpr_h("%s: core clock config not enabled, enabling it to read vcodec registers\n", + __func__); + rc = __write_register(core, WRAPPER_CORE_CLOCK_CONFIG_IRIS3, 0); + if (rc) + return rc; + } + + /* + * add MNoC idle check before collapsing MVS0 per HPG update + * poll for NoC DMA idle -> HPG 6.1.1 + */ + for (i = 0; i < core->capabilities[NUM_VPP_PIPE].value; i++) { + rc = __read_register_with_poll_timeout(core, VCODEC_SS_IDLE_STATUSn + 4*i, + 0x400000, 0x400000, 2000, 20000); + if (rc) + d_vpr_h("%s: VCODEC_SS_IDLE_STATUSn (%d) is not idle (%#x)\n", + __func__, i, value); + } + + /* Apply partial reset on MSF interface and wait for ACK */ + rc = __write_register(core, AON_WRAPPER_MVP_NOC_RESET_REQ, 0x3); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_RESET_ACK, + 0x3, 0x3, 200, 2000); + if (rc) + d_vpr_h("%s: AON_WRAPPER_MVP_NOC_RESET assert failed\n", __func__); + + /* De-assert partial reset on MSF interface and wait for ACK */ + rc = __write_register(core, AON_WRAPPER_MVP_NOC_RESET_REQ, 0x0); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_RESET_ACK, + 0x3, 0x0, 200, 2000); + if (rc) + d_vpr_h("%s: AON_WRAPPER_MVP_NOC_RESET de-assert failed\n", __func__); + + /* + * Reset both sides of 2 ahb2ahb_bridges (TZ and non-TZ) + * do we need to check status register here? + */ + rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x3); + if (rc) + return rc; + rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x2); + if (rc) + return rc; + rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x0); + if (rc) + return rc; + +disable_power: + /* power down process */ + rc = call_res_op(core, gdsc_off, core, "vcodec"); + if (rc) { + d_vpr_e("%s: disable regulator vcodec failed\n", __func__); + rc = 0; + } + + rc = call_res_op(core, clk_disable, core, "vcodec_clk"); + if (rc) { + d_vpr_e("%s: disable unprepare vcodec_clk failed\n", __func__); + rc = 0; + } + + return rc; +} + +static int __power_off_iris3_controller(struct msm_vidc_core *core) +{ + int rc = 0; + + /* + * mask fal10_veto QLPAC error since fal10_veto can go 1 + * when pwwait == 0 and clamped to 0 -> HPG 6.1.2 + */ + rc = __write_register(core, CPU_CS_X2RPMh_IRIS3, 0x3); + if (rc) + return rc; + + /* set MNoC to low power, set PD_NOC_QREQ (bit 0) */ + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL, + 0x1, BIT(0)); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, AON_WRAPPER_MVP_NOC_LPI_STATUS, + 0x1, 0x1, 200, 2000); + if (rc) + d_vpr_h("%s: AON_WRAPPER_MVP_NOC_LPI_CONTROL failed\n", __func__); + + /* Set Iris CPU NoC to Low power */ + rc = __write_register_masked(core, WRAPPER_IRIS_CPU_NOC_LPI_CONTROL, + 0x1, BIT(0)); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, WRAPPER_IRIS_CPU_NOC_LPI_STATUS, + 0x1, 0x1, 200, 2000); + if (rc) + d_vpr_h("%s: WRAPPER_IRIS_CPU_NOC_LPI_CONTROL failed\n", __func__); + + /* Debug bridge LPI release */ + rc = __write_register(core, WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS3, 0x0); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS3, + 0xffffffff, 0x0, 200, 2000); + if (rc) + d_vpr_h("%s: debug bridge release failed\n", __func__); + + /* Reset MVP QNS4PDXFIFO */ + rc = __write_register(core, WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG, 0x3); + if (rc) + return rc; + + rc = __write_register(core, WRAPPER_TZ_QNS4PDXFIFO_RESET, 0x1); + if (rc) + return rc; + + rc = __write_register(core, WRAPPER_TZ_QNS4PDXFIFO_RESET, 0x0); + if (rc) + return rc; + + rc = __write_register(core, WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG, 0x0); + if (rc) + return rc; + + /* Turn off MVP MVS0C core clock */ + rc = call_res_op(core, clk_disable, core, "core_clk"); + if (rc) { + d_vpr_e("%s: disable unprepare core_clk failed\n", __func__); + rc = 0; + } + + /* power down process */ + rc = call_res_op(core, gdsc_off, core, "iris-ctl"); + if (rc) { + d_vpr_e("%s: disable regulator iris-ctl failed\n", __func__); + rc = 0; + } + + return rc; +} + +static int __power_off_iris3(struct msm_vidc_core *core) +{ + int rc = 0; + + if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) + return 0; + + /** + * Reset video_cc_mvs0_clk_src value to resolve MMRM high video + * clock projection issue. + */ + rc = call_res_op(core, set_clks, core, 0); + if (rc) + d_vpr_e("%s: resetting clocks failed\n", __func__); + + if (__power_off_iris3_hardware(core)) + d_vpr_e("%s: failed to power off hardware\n", __func__); + + if (__power_off_iris3_controller(core)) + d_vpr_e("%s: failed to power off controller\n", __func__); + + rc = call_res_op(core, set_bw, core, 0, 0); + if (rc) + d_vpr_e("%s: failed to unvote buses\n", __func__); + + if (!call_venus_op(core, watchdog, core, core->intr_status)) + disable_irq_nosync(core->resource->irq); + + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__); + + return rc; +} + +static int __power_on_iris3_controller(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = call_res_op(core, gdsc_on, core, "iris-ctl"); + if (rc) + goto fail_regulator; + + rc = call_res_op(core, reset_bridge, core); + if (rc) + goto fail_reset_ahb2axi; + + rc = call_res_op(core, clk_enable, core, "gcc_video_axi0"); + if (rc) + goto fail_clk_axi; + + rc = call_res_op(core, clk_enable, core, "core_clk"); + if (rc) + goto fail_clk_controller; + + return 0; + +fail_clk_controller: + call_res_op(core, clk_disable, core, "gcc_video_axi0"); +fail_clk_axi: +fail_reset_ahb2axi: + call_res_op(core, gdsc_off, core, "iris-ctl"); +fail_regulator: + return rc; +} + +static int __power_on_iris3_hardware(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = call_res_op(core, gdsc_on, core, "vcodec"); + if (rc) + goto fail_regulator; + + rc = call_res_op(core, clk_enable, core, "vcodec_clk"); + if (rc) + goto fail_clk_controller; + + return 0; + +fail_clk_controller: + call_res_op(core, gdsc_off, core, "vcodec"); +fail_regulator: + return rc; +} + +static int __power_on_iris3(struct msm_vidc_core *core) +{ + struct frequency_table *freq_tbl; + u32 freq = 0; + int rc = 0; + + if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) + return 0; + + if (!core_in_valid_state(core)) { + d_vpr_e("%s: invalid core state %s\n", + __func__, core_state_name(core->state)); + return -EINVAL; + } + + /* Vote for all hardware resources */ + rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX); + if (rc) { + d_vpr_e("%s: failed to vote buses, rc %d\n", __func__, rc); + goto fail_vote_buses; + } + + rc = __power_on_iris3_controller(core); + if (rc) { + d_vpr_e("%s: failed to power on iris3 controller\n", __func__); + goto fail_power_on_controller; + } + + rc = __power_on_iris3_hardware(core); + if (rc) { + d_vpr_e("%s: failed to power on iris3 hardware\n", __func__); + goto fail_power_on_hardware; + } + /* video controller and hardware powered on successfully */ + rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_POWER_ENABLE, __func__); + if (rc) + goto fail_power_on_substate; + + freq_tbl = core->resource->freq_set.freq_tbl; + freq = core->power.clk_freq ? core->power.clk_freq : + freq_tbl[0].freq; + + rc = call_res_op(core, set_clks, core, freq); + if (rc) { + d_vpr_e("%s: failed to scale clocks\n", __func__); + rc = 0; + } + /* + * Re-program all of the registers that get reset as a result of + * regulator_disable() and _enable() + */ + __set_registers(core); + + __interrupt_init_iris3(core); + core->intr_status = 0; + enable_irq(core->resource->irq); + + return rc; + +fail_power_on_substate: + __power_off_iris3_hardware(core); +fail_power_on_hardware: + __power_off_iris3_controller(core); +fail_power_on_controller: + call_res_op(core, set_bw, core, 0, 0); +fail_vote_buses: + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__); + return rc; +} + +static int __prepare_pc_iris3(struct msm_vidc_core *core) +{ + int rc = 0; + u32 wfi_status = 0, idle_status = 0, pc_ready = 0; + u32 ctrl_status = 0; + + rc = __read_register(core, CTRL_STATUS_IRIS3, &ctrl_status); + if (rc) + return rc; + + pc_ready = ctrl_status & CTRL_STATUS_PC_READY_IRIS3; + idle_status = ctrl_status & BIT(30); + + if (pc_ready) { + d_vpr_h("Already in pc_ready state\n"); + return 0; + } + rc = __read_register(core, WRAPPER_TZ_CPU_STATUS, &wfi_status); + if (rc) + return rc; + + wfi_status &= BIT(0); + if (!wfi_status || !idle_status) { + d_vpr_e("Skipping PC, wfi status not set\n"); + goto skip_power_off; + } + + rc = __prepare_pc(core); + if (rc) { + d_vpr_e("Failed __prepare_pc %d\n", rc); + goto skip_power_off; + } + + rc = __read_register_with_poll_timeout(core, CTRL_STATUS_IRIS3, + CTRL_STATUS_PC_READY_IRIS3, CTRL_STATUS_PC_READY_IRIS3, 250, 2500); + if (rc) { + d_vpr_e("%s: Skip PC. Ctrl status not set\n", __func__); + goto skip_power_off; + } + + rc = __read_register_with_poll_timeout(core, WRAPPER_TZ_CPU_STATUS, + BIT(0), 0x1, 250, 2500); + if (rc) { + d_vpr_e("%s: Skip PC. Wfi status not set\n", __func__); + goto skip_power_off; + } + return rc; + +skip_power_off: + rc = __read_register(core, CTRL_STATUS_IRIS3, &ctrl_status); + if (rc) + return rc; + rc = __read_register(core, WRAPPER_TZ_CPU_STATUS, &wfi_status); + if (rc) + return rc; + wfi_status &= BIT(0); + d_vpr_e("Skip PC, wfi=%#x, idle=%#x, pcr=%#x, ctrl=%#x)\n", + wfi_status, idle_status, pc_ready, ctrl_status); + return -EAGAIN; +} + +static int __raise_interrupt_iris3(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = __write_register(core, CPU_IC_SOFTINT_IRIS3, 1 << CPU_IC_SOFTINT_H2A_SHFT_IRIS3); + if (rc) + return rc; + + return 0; +} + +static int __watchdog_iris3(struct msm_vidc_core *core, u32 intr_status) +{ + int rc = 0; + + if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3) { + d_vpr_e("%s: received watchdog interrupt\n", __func__); + rc = 1; + } + + return rc; +} + +static int __noc_error_info_iris3(struct msm_vidc_core *core) +{ + /* + * we are not supposed to access vcodec subsystem registers + * unless vcodec core clock WRAPPER_CORE_CLOCK_CONFIG_IRIS3 is enabled. + * core clock might have been disabled by video firmware as part of + * inter frame power collapse (power plane control feature). + */ + + /* + val = __read_register(core, VCODEC_NOC_ERL_MAIN_SWID_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_SWID_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_SWID_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_SWID_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_MAINCTL_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_MAINCTL_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRVLD_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRVLD_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRCLR_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRCLR_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH: %#x\n", val); + */ + + return 0; +} + +static int __clear_interrupt_iris3(struct msm_vidc_core *core) +{ + u32 intr_status = 0, mask = 0; + int rc = 0; + + rc = __read_register(core, WRAPPER_INTR_STATUS_IRIS3, &intr_status); + if (rc) + return rc; + + mask = (WRAPPER_INTR_STATUS_A2H_BMSK_IRIS3| + WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS3| + CTRL_INIT_IDLE_MSG_BMSK_IRIS3); + + if (intr_status & mask) { + core->intr_status |= intr_status; + core->reg_count++; + d_vpr_l("INTERRUPT: times: %d interrupt_status: %d\n", + core->reg_count, intr_status); + } else { + core->spur_count++; + } + + rc = __write_register(core, CPU_CS_A2HSOFTINTCLR_IRIS3, 1); + if (rc) + return rc; + + return 0; +} + +static int __boot_firmware_iris3(struct msm_vidc_core *core) +{ + int rc = 0; + u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 1000; + + rc = __setup_ucregion_memory_map_iris3(core); + if (rc) + return rc; + + ctrl_init_val = BIT(0); + + rc = __write_register(core, CTRL_INIT_IRIS3, ctrl_init_val); + if (rc) + return rc; + + while (!ctrl_status && count < max_tries) { + rc = __read_register(core, CTRL_STATUS_IRIS3, &ctrl_status); + if (rc) + return rc; + + if ((ctrl_status & CTRL_ERROR_STATUS__M_IRIS3) == 0x4) { + d_vpr_e("invalid setting for UC_REGION\n"); + break; + } + + usleep_range(50, 100); + count++; + } + + if (count >= max_tries) { + d_vpr_e("Error booting up vidc firmware\n"); + return -ETIME; + } + + /* Enable interrupt before sending commands to venus */ + rc = __write_register(core, CPU_CS_H2XSOFTINTEN_IRIS3, 0x1); + if (rc) + return rc; + + rc = __write_register(core, CPU_CS_X2RPMh_IRIS3, 0x0); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_decide_work_mode_iris3(struct msm_vidc_inst *inst) +{ + u32 work_mode; + struct v4l2_format *inp_f; + u32 width, height; + bool res_ok = false; + + work_mode = MSM_VIDC_STAGE_2; + inp_f = &inst->fmts[INPUT_PORT]; + + if (is_image_decode_session(inst)) + work_mode = MSM_VIDC_STAGE_1; + + if (is_image_session(inst)) + goto exit; + + if (is_decode_session(inst)) { + height = inp_f->fmt.pix_mp.height; + width = inp_f->fmt.pix_mp.width; + res_ok = res_is_less_than(width, height, 1280, 720); + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_INTERLACE || + inst->capabilities[LOWLATENCY_MODE].value || + res_ok) { + work_mode = MSM_VIDC_STAGE_1; + } + } else if (is_encode_session(inst)) { + height = inst->crop.height; + width = inst->crop.width; + res_ok = !res_is_greater_than(width, height, 4096, 2160); + if (res_ok && + (inst->capabilities[LOWLATENCY_MODE].value)) { + work_mode = MSM_VIDC_STAGE_1; + } + if (inst->capabilities[SLICE_MODE].value == + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { + work_mode = MSM_VIDC_STAGE_1; + } + if (inst->capabilities[LOSSLESS].value) + work_mode = MSM_VIDC_STAGE_2; + + if (!inst->capabilities[GOP_SIZE].value) + work_mode = MSM_VIDC_STAGE_2; + } else { + i_vpr_e(inst, "%s: invalid session type\n", __func__); + return -EINVAL; + } + +exit: + i_vpr_h(inst, "Configuring work mode = %u low latency = %u, gop size = %u\n", + work_mode, inst->capabilities[LOWLATENCY_MODE].value, + inst->capabilities[GOP_SIZE].value); + msm_vidc_update_cap_value(inst, STAGE, work_mode, __func__); + + return 0; +} + +int msm_vidc_decide_work_route_iris3(struct msm_vidc_inst *inst) +{ + u32 work_route; + struct msm_vidc_core *core; + + core = inst->core; + work_route = core->capabilities[NUM_VPP_PIPE].value; + + if (is_image_session(inst)) + goto exit; + + if (is_decode_session(inst)) { + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_INTERLACE) + work_route = MSM_VIDC_PIPE_1; + } else if (is_encode_session(inst)) { + u32 slice_mode; + + slice_mode = inst->capabilities[SLICE_MODE].value; + + /*TODO Pipe=1 for legacy CBR*/ + if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) + work_route = MSM_VIDC_PIPE_1; + + } else { + i_vpr_e(inst, "%s: invalid session type\n", __func__); + return -EINVAL; + } + +exit: + i_vpr_h(inst, "Configuring work route = %u", work_route); + msm_vidc_update_cap_value(inst, PIPE, work_route, __func__); + + return 0; +} + +int msm_vidc_decide_quality_mode_iris3(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 mbpf, mbps, max_hq_mbpf, max_hq_mbps; + u32 mode = MSM_VIDC_POWER_SAVE_MODE; + + if (!is_encode_session(inst)) + return 0; + + /* image or lossless or all intra runs at quality mode */ + if (is_image_session(inst) || inst->capabilities[LOSSLESS].value || + inst->capabilities[ALL_INTRA].value) { + mode = MSM_VIDC_MAX_QUALITY_MODE; + goto decision_done; + } + + /* for lesser complexity, make LP for all resolution */ + if (inst->capabilities[COMPLEXITY].value < DEFAULT_COMPLEXITY) { + mode = MSM_VIDC_POWER_SAVE_MODE; + goto decision_done; + } + + mbpf = msm_vidc_get_mbs_per_frame(inst); + mbps = mbpf * msm_vidc_get_fps(inst); + core = inst->core; + max_hq_mbpf = core->capabilities[MAX_MBPF_HQ].value;; + max_hq_mbps = core->capabilities[MAX_MBPS_HQ].value;; + + if (!is_realtime_session(inst)) { + if (((inst->capabilities[COMPLEXITY].flags & CAP_FLAG_CLIENT_SET) && + (inst->capabilities[COMPLEXITY].value >= DEFAULT_COMPLEXITY)) || + mbpf <= max_hq_mbpf) { + mode = MSM_VIDC_MAX_QUALITY_MODE; + goto decision_done; + } + } + + if (mbpf <= max_hq_mbpf && mbps <= max_hq_mbps) + mode = MSM_VIDC_MAX_QUALITY_MODE; + +decision_done: + msm_vidc_update_cap_value(inst, QUALITY_MODE, mode, __func__); + + return 0; +} + +int msm_vidc_adjust_bitrate_boost_iris3(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1; + u32 width, height, frame_rate; + struct v4l2_format *f; + u32 max_bitrate = 0, bitrate = 0; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[BITRATE_BOOST].value; + + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) + return 0; + + if (msm_vidc_get_parent_value(inst, BITRATE_BOOST, + BITRATE_MODE, &rc_type, __func__)) + return -EINVAL; + + /* + * Bitrate Boost are supported only for VBR rc type. + * Hence, do not adjust or set to firmware for non VBR rc's + */ + if (rc_type != HFI_RC_VBR_CFR) { + adjusted_value = 0; + goto adjust; + } + + frame_rate = inst->capabilities[FRAME_RATE].value >> 16; + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + /* + * honor client set bitrate boost + * if client did not set, keep max bitrate boost upto 4k@60fps + * and remove bitrate boost after 4k@60fps + */ + if (inst->capabilities[BITRATE_BOOST].flags & CAP_FLAG_CLIENT_SET) { + /* accept client set bitrate boost value as is */ + } else { + if (res_is_less_than_or_equal_to(width, height, 4096, 2176) && + frame_rate <= 60) + adjusted_value = MAX_BITRATE_BOOST; + else + adjusted_value = 0; + } + + max_bitrate = msm_vidc_get_max_bitrate(inst); + bitrate = inst->capabilities[BIT_RATE].value; + if (adjusted_value) { + if ((bitrate + bitrate / (100 / adjusted_value)) > max_bitrate) { + i_vpr_h(inst, + "%s: bitrate %d is beyond max bitrate %d, remove bitrate boost\n", + __func__, max_bitrate, bitrate); + adjusted_value = 0; + } + } +adjust: + msm_vidc_update_cap_value(inst, BITRATE_BOOST, adjusted_value, __func__); + + return 0; +} + + + +static struct msm_vidc_venus_ops iris3_ops = { + .boot_firmware = __boot_firmware_iris3, + .raise_interrupt = __raise_interrupt_iris3, + .clear_interrupt = __clear_interrupt_iris3, + .power_on = __power_on_iris3, + .power_off = __power_off_iris3, + .prepare_pc = __prepare_pc_iris3, + .watchdog = __watchdog_iris3, + .noc_error_info = __noc_error_info_iris3, +}; + +static struct msm_vidc_session_ops msm_session_ops = { + .buffer_size = msm_buffer_size_iris3, + .min_count = msm_buffer_min_count_iris3, + .extra_count = msm_buffer_extra_count_iris3, + .calc_freq = msm_vidc_calc_freq_iris3, + .calc_bw = msm_vidc_calc_bw_iris3, + .decide_work_route = msm_vidc_decide_work_route_iris3, + .decide_work_mode = msm_vidc_decide_work_mode_iris3, + .decide_quality_mode = msm_vidc_decide_quality_mode_iris3, +}; + +int msm_vidc_init_iris3(struct msm_vidc_core *core) +{ + d_vpr_h("%s()\n", __func__); + core->venus_ops = &iris3_ops; + core->session_ops = &msm_session_ops; + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_power_iris3.c b/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_power_iris3.c new file mode 100644 index 0000000000..6ce3891b1d --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris3/src/msm_vidc_power_iris3.c @@ -0,0 +1,1160 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_power_iris3.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" +#include "msm_vidc_debug.h" +#include "perf_static_model.h" +#include "msm_vidc_power.h" + +static u64 __calculate_decoder(struct vidc_bus_vote_data *d); +static u64 __calculate_encoder(struct vidc_bus_vote_data *d); +static u64 __calculate(struct msm_vidc_inst *inst, struct vidc_bus_vote_data *d); +static u64 msm_vidc_calc_freq_iris3_legacy(struct msm_vidc_inst *inst, u32 data_size); + +static int msm_vidc_init_codec_input_freq(struct msm_vidc_inst *inst, u32 data_size, + struct api_calculation_input *codec_input) +{ + enum msm_vidc_port_type port; + u32 color_fmt; + + if (is_encode_session(inst)) { + codec_input->decoder_or_encoder = CODEC_ENCODER; + } else if (is_decode_session(inst)) { + codec_input->decoder_or_encoder = CODEC_DECODER; + } else { + d_vpr_e("%s: invalid domain %d\n", __func__, inst->domain); + return -EINVAL; + } + + codec_input->chipset_gen = MSM_KALAMA; + + if (inst->codec == MSM_VIDC_H264) { + codec_input->codec = CODEC_H264; + codec_input->lcu_size = 16; + if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) + codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CABAC; + else + codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CAVLC; + } else if (inst->codec == MSM_VIDC_HEVC) { + codec_input->codec = CODEC_HEVC; + codec_input->lcu_size = 32; + } else if (inst->codec == MSM_VIDC_VP9) { + codec_input->codec = CODEC_VP9; + codec_input->lcu_size = 16; + } else if (inst->codec == MSM_VIDC_AV1) { + codec_input->codec = CODEC_AV1; + codec_input->lcu_size = 32; + } else { + d_vpr_e("%s: invalid codec %d\n", __func__, inst->codec); + return -EINVAL; + } + + codec_input->pipe_num = inst->capabilities[PIPE].value; + codec_input->frame_rate = inst->max_rate; + + port = is_decode_session(inst) ? INPUT_PORT : OUTPUT_PORT; + codec_input->frame_width = inst->fmts[port].fmt.pix_mp.width; + codec_input->frame_height = inst->fmts[port].fmt.pix_mp.height; + + if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_1) { + codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_1S; + } else if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_2) { + codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_2S; + } else { + d_vpr_e("%s: invalid stage %d\n", __func__, + inst->capabilities[STAGE].value); + return -EINVAL; + } + + if (inst->capabilities[BIT_DEPTH].value == BIT_DEPTH_8) + codec_input->bitdepth = CODEC_BITDEPTH_8; + else + codec_input->bitdepth = CODEC_BITDEPTH_10; + + /* + * Used for calculating Encoder GOP Complexity + * hierachical_layer= 0..7 used as Array Index + * inst->capabilities[B_FRAME].value=[ 0 1 2] + * TODO how to map? + */ + + /* set as IPP */ + codec_input->hierachical_layer = 0; + + if (is_decode_session(inst)) + color_fmt = v4l2_colorformat_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, __func__); + else + color_fmt = v4l2_colorformat_to_driver(inst, + inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat, __func__); + + codec_input->linear_opb = is_linear_colorformat(color_fmt); + codec_input->bitrate_mbps = + (codec_input->frame_rate * data_size * 8) / 1000000; + + /* disable av1d commercial tile */ + codec_input->av1d_commer_tile_enable = 0; + /* set as sanity mode */ + codec_input->regression_mode = 1; + + return 0; +} + +static int msm_vidc_init_codec_input_bus(struct msm_vidc_inst *inst, struct vidc_bus_vote_data *d, + struct api_calculation_input *codec_input) +{ + u32 complexity_factor_int = 0, complexity_factor_frac = 0; + bool opb_compression_enabled = false; + + if (!d) + return -EINVAL; + + if (d->domain == MSM_VIDC_ENCODER) { + codec_input->decoder_or_encoder = CODEC_ENCODER; + } else if (d->domain == MSM_VIDC_DECODER) { + codec_input->decoder_or_encoder = CODEC_DECODER; + } else { + d_vpr_e("%s: invalid domain %d\n", __func__, d->domain); + return -EINVAL; + } + + codec_input->chipset_gen = MSM_KALAMA; + + if (d->codec == MSM_VIDC_H264) { + codec_input->codec = CODEC_H264; + } else if (d->codec == MSM_VIDC_HEVC) { + codec_input->codec = CODEC_HEVC; + } else if (d->codec == MSM_VIDC_VP9) { + codec_input->codec = CODEC_VP9; + } else if (d->codec == MSM_VIDC_AV1) { + codec_input->codec = CODEC_AV1; + } else { + d_vpr_e("%s: invalid codec %d\n", __func__, d->codec); + return -EINVAL; + } + + codec_input->lcu_size = d->lcu_size; + codec_input->pipe_num = d->num_vpp_pipes; + codec_input->frame_rate = d->fps; + codec_input->frame_width = d->input_width; + codec_input->frame_height = d->input_height; + + if (d->work_mode == MSM_VIDC_STAGE_1) { + codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_1S; + } else if (d->work_mode == MSM_VIDC_STAGE_2) { + codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_2S; + } else { + d_vpr_e("%s: invalid stage %d\n", __func__, d->work_mode); + return -EINVAL; + } + + if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) { + codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CABAC; + } else if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) { + codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CAVLC; + } else { + d_vpr_e("%s: invalid entropy %d\n", __func__, + inst->capabilities[ENTROPY_MODE].value); + return -EINVAL; + } + + /* + * Used for calculating Encoder GOP Complexity + * hierachical_layer= 0..7 used as Array Index + * TODO how to map? + */ + codec_input->hierachical_layer = 0; /* set as IPP */ + + /* + * If the calculated motion_vector_complexity is > 2 then set the + * complexity_setting and refframe_complexity to be pwc(performance worst case) + * values. If the motion_vector_complexity is < 2 then set the complexity_setting + * and refframe_complexity to be average case values. + */ + + complexity_factor_int = Q16_INT(d->complexity_factor); + complexity_factor_frac = Q16_FRAC(d->complexity_factor); + + if (complexity_factor_int < COMPLEXITY_THRESHOLD || + (complexity_factor_int == COMPLEXITY_THRESHOLD && + complexity_factor_frac == 0)) { + /* set as average case values */ + codec_input->complexity_setting = COMPLEXITY_SETTING_AVG; + codec_input->refframe_complexity = REFFRAME_COMPLEXITY_AVG; + } else { + /* set as pwc */ + codec_input->complexity_setting = COMPLEXITY_SETTING_PWC; + codec_input->refframe_complexity = REFFRAME_COMPLEXITY_PWC; + } + + codec_input->status_llc_onoff = d->use_sys_cache; + + if (__bpp(d->color_formats[0]) == 8) + codec_input->bitdepth = CODEC_BITDEPTH_8; + else + codec_input->bitdepth = CODEC_BITDEPTH_10; + + if (d->num_formats == 1) { + codec_input->split_opb = 0; + codec_input->linear_opb = !__ubwc(d->color_formats[0]); + } else if (d->num_formats == 2) { + codec_input->split_opb = 1; + codec_input->linear_opb = !__ubwc(d->color_formats[1]); + } else { + d_vpr_e("%s: invalid num_formats %d\n", + __func__, d->num_formats); + return -EINVAL; + } + + codec_input->linear_ipb = 0; /* set as ubwc ipb */ + + /* TODO Confirm if we always LOSSLESS mode ie lossy_ipb = 0*/ + codec_input->lossy_ipb = 0; /* set as lossless ipb */ + + /* TODO Confirm if no multiref */ + codec_input->encoder_multiref = 0; /* set as no multiref */ + codec_input->bitrate_mbps = (d->bitrate / 1000000); /* bps 10; set as 10mbps */ + + opb_compression_enabled = d->num_formats >= 2 && __ubwc(d->color_formats[1]); + + /* ANDROID CR is in Q16 format, StaticModel CR in x100 format */ + codec_input->cr_dpb = ((Q16_INT(d->compression_ratio)*100) + + Q16_FRAC(d->compression_ratio)); + + codec_input->cr_opb = opb_compression_enabled ? + codec_input->cr_dpb : FP_ONE; + + codec_input->cr_ipb = ((Q16_INT(d->input_cr)*100) + Q16_FRAC(d->input_cr)); + codec_input->cr_rpb = codec_input->cr_dpb; /* cr_rpb ony for encoder */ + + /* disable by default, only enable for aurora depth map session */ + codec_input->lumaonly_decode = 0; + /* TODO: disable av1d commercial tile */ + codec_input->av1d_commer_tile_enable = 0; + /* set as custom regression mode, as are using cr,cf values from FW */ + codec_input->regression_mode = REGRESSION_MODE_CUSTOM; + + + /* Dump all the variables for easier debugging */ + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"complexity_factor_int", "%d", complexity_factor_int}, + {"complexity_factor_frac", "%d", complexity_factor_frac}, + {"refframe_complexity", "%d", codec_input->refframe_complexity}, + {"complexity_setting", "%d", codec_input->complexity_setting}, + {"cr_dpb", "%d", codec_input->cr_dpb}, + {"cr_opb", "%d", codec_input->cr_opb}, + {"cr_ipb", "%d", codec_input->cr_ipb}, + {"cr_rpb", "%d", codec_input->cr_rpb}, + {"lcu size", "%d", codec_input->lcu_size}, + {"pipe number", "%d", codec_input->pipe_num}, + {"frame_rate", "%d", codec_input->frame_rate}, + {"frame_width", "%d", codec_input->frame_width}, + {"frame_height", "%d", codec_input->frame_height}, + {"work_mode", "%d", d->work_mode}, + {"encoder_or_decode", "%d", inst->domain}, + {"chipset_gen", "%d", codec_input->chipset_gen}, + {"codec_input", "%d", codec_input->codec}, + {"entropy_coding_mode", "%d", codec_input->entropy_coding_mode}, + {"hierachical_layer", "%d", codec_input->hierachical_layer}, + {"status_llc_onoff", "%d", codec_input->status_llc_onoff}, + {"bit_depth", "%d", codec_input->bitdepth}, + {"split_opb", "%d", codec_input->split_opb}, + {"linear_opb", "%d", codec_input->linear_opb}, + {"linear_ipb", "%d", codec_input->linear_ipb}, + {"lossy_ipb", "%d", codec_input->lossy_ipb}, + {"encoder_multiref", "%d", codec_input->encoder_multiref}, + {"bitrate_mbps", "%d", codec_input->bitrate_mbps}, + {"lumaonly_decode", "%d", codec_input->lumaonly_decode}, + {"av1d_commer_tile_enable", "%d", codec_input->av1d_commer_tile_enable}, + {"regression_mode", "%d", codec_input->regression_mode}, + }; + __dump(dump, ARRAY_SIZE(dump)); + } + + return 0; +} + +static u64 msm_vidc_calc_freq_iris3_new(struct msm_vidc_inst *inst, u32 data_size) +{ + u64 freq = 0; + struct msm_vidc_core *core; + int ret = 0; + struct api_calculation_input codec_input; + struct api_calculation_freq_output codec_output; + u32 fps, mbpf; + + core = inst->core; + + mbpf = msm_vidc_get_mbs_per_frame(inst); + fps = inst->max_rate; + + memset(&codec_input, 0, sizeof(struct api_calculation_input)); + memset(&codec_output, 0, sizeof(struct api_calculation_freq_output)); + ret = msm_vidc_init_codec_input_freq(inst, data_size, &codec_input); + if (ret) + return freq; + ret = msm_vidc_calculate_frequency(codec_input, &codec_output); + if (ret) + return freq; + freq = codec_output.hw_min_freq * 1000000; /* Convert to Hz */ + + i_vpr_p(inst, "%s: filled len %d, required freq %llu, fps %u, mbpf %u\n", + __func__, data_size, freq, fps, mbpf); + + if (inst->codec == MSM_VIDC_AV1 || + (inst->iframe && is_hevc_10bit_decode_session(inst))) { + /* + * for AV1 or HEVC 10bit and iframe case only allow TURBO and + * limit to NOM for all other cases + */ + } else { + /* limit to NOM, index 0 is TURBO, index 1 is NOM clock rate */ + if (core->resource->freq_set.count >= 2 && + freq > core->resource->freq_set.freq_tbl[1].freq) + freq = core->resource->freq_set.freq_tbl[1].freq; + } + + return freq; +} + +static int msm_vidc_calc_bw_iris3_new(struct msm_vidc_inst *inst, + struct vidc_bus_vote_data *vidc_data) +{ + u32 ret = 0; + struct api_calculation_input codec_input; + struct api_calculation_bw_output codec_output; + + memset(&codec_input, 0, sizeof(struct api_calculation_input)); + memset(&codec_output, 0, sizeof(struct api_calculation_bw_output)); + + ret = msm_vidc_init_codec_input_bus(inst, vidc_data, &codec_input); + if (ret) + return ret; + ret = msm_vidc_calculate_bandwidth(codec_input, &codec_output); + if (ret) + return ret; + + vidc_data->calc_bw_ddr = kbps(codec_output.ddr_bw_rd + codec_output.ddr_bw_wr); + vidc_data->calc_bw_llcc = kbps(codec_output.noc_bw_rd + codec_output.noc_bw_wr); + + i_vpr_l(inst, "%s: calc_bw_ddr %lu calc_bw_llcc %lu", + __func__, vidc_data->calc_bw_ddr, vidc_data->calc_bw_llcc); + + return ret; +} + +u64 msm_vidc_calc_freq_iris3(struct msm_vidc_inst *inst, u32 data_size) +{ + u64 freq = 0; + + if (ENABLE_LEGACY_POWER_CALCULATIONS) + freq = msm_vidc_calc_freq_iris3_legacy(inst, data_size); + else + freq = msm_vidc_calc_freq_iris3_new(inst, data_size); + + return freq; +} + +static u64 msm_vidc_calc_freq_iris3_legacy(struct msm_vidc_inst *inst, u32 data_size) +{ + u64 freq = 0; + struct msm_vidc_core *core; + u64 vsp_cycles = 0, vpp_cycles = 0, fw_cycles = 0; + u64 fw_vpp_cycles = 0, bitrate = 0; + u32 vpp_cycles_per_mb; + u32 mbs_per_second; + u32 operating_rate, vsp_factor_num = 1, vsp_factor_den = 1; + u32 base_cycles = 0; + u32 fps, mbpf; + + core = inst->core; + + if (!core->resource || !core->resource->freq_set.freq_tbl || + !core->resource->freq_set.count) { + d_vpr_e("%s: invalid params\n", __func__); + return freq; + } + + mbpf = msm_vidc_get_mbs_per_frame(inst); + fps = inst->max_rate; + mbs_per_second = mbpf * fps; + + /* + * Calculate vpp, vsp, fw cycles separately for encoder and decoder. + * Even though, most part is common now, in future it may change + * between them. + */ + fw_cycles = fps * inst->capabilities[MB_CYCLES_FW].value; + fw_vpp_cycles = fps * inst->capabilities[MB_CYCLES_FW_VPP].value; + + if (is_encode_session(inst)) { + vpp_cycles_per_mb = is_low_power_session(inst) ? + inst->capabilities[MB_CYCLES_LP].value : + inst->capabilities[MB_CYCLES_VPP].value; + + vpp_cycles = mbs_per_second * vpp_cycles_per_mb / + inst->capabilities[PIPE].value; + + /* Factor 1.25 for IbP and 1.375 for I1B2b1P GOP structure */ + if (inst->capabilities[B_FRAME].value > 1) + vpp_cycles += (vpp_cycles / 4) + (vpp_cycles / 8); + else if (inst->capabilities[B_FRAME].value) + vpp_cycles += vpp_cycles / 4; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); + /* 1.01 is multi-pipe overhead */ + if (inst->capabilities[PIPE].value > 1) + vpp_cycles += div_u64(vpp_cycles, 100); + /* + * 1080p@480fps usecase needs exactly 338MHz + * without any margin left. Hence, adding 2 percent + * extra to bump it to next level (366MHz). + */ + if (fps == 480) + vpp_cycles += div_u64(vpp_cycles * 2, 100); + + /* + * Add 5 percent extra for 720p@960fps use case + * to bump it to next level (366MHz). + */ + if (fps == 960) + vpp_cycles += div_u64(vpp_cycles * 5, 100); + + /* increase vpp_cycles by 50% for preprocessing */ + if (inst->capabilities[REQUEST_PREPROCESS].value) + vpp_cycles = vpp_cycles + vpp_cycles / 2; + + /* VSP */ + /* bitrate is based on fps, scale it using operating rate */ + operating_rate = inst->capabilities[OPERATING_RATE].value >> 16; + if (operating_rate > + (inst->capabilities[FRAME_RATE].value >> 16) && + (inst->capabilities[FRAME_RATE].value >> 16)) { + vsp_factor_num = operating_rate; + vsp_factor_den = inst->capabilities[FRAME_RATE].value >> 16; + } + vsp_cycles = div_u64(((u64)inst->capabilities[BIT_RATE].value * + vsp_factor_num), vsp_factor_den); + + base_cycles = inst->capabilities[MB_CYCLES_VSP].value; + if (inst->codec == MSM_VIDC_VP9) { + vsp_cycles = div_u64(vsp_cycles * 170, 100); + } else if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) { + vsp_cycles = div_u64(vsp_cycles * 135, 100); + } else { + base_cycles = 0; + vsp_cycles = div_u64(vsp_cycles, 2); + } + /* VSP FW Overhead 1.05 */ + vsp_cycles = div_u64(vsp_cycles * 21, 20); + + if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_1) + vsp_cycles = vsp_cycles * 3; + + vsp_cycles += mbs_per_second * base_cycles; + + } else if (is_decode_session(inst)) { + /* VPP */ + vpp_cycles = mbs_per_second * inst->capabilities[MB_CYCLES_VPP].value / + inst->capabilities[PIPE].value; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); + if (inst->capabilities[PIPE].value > 1) { + if (inst->codec == MSM_VIDC_AV1) { + /* + * Additional vpp_cycles are required for bitstreams with + * 128x128 superblock and non-recommended tile settings. + * recommended tiles: 1080P_V2XH1, UHD_V2X2, 8KUHD_V8X2 + * non-recommended tiles: 1080P_V4XH2_V4X1, UHD_V8X4_V8X1, + * 8KUHD_V8X8_V8X1 + */ + if (inst->capabilities[SUPER_BLOCK].value) + vpp_cycles += div_u64(vpp_cycles * 1464, 1000); + else + vpp_cycles += div_u64(vpp_cycles * 410, 1000); + } else { + /* 1.059 is multi-pipe overhead */ + vpp_cycles += div_u64(vpp_cycles * 59, 1000); + } + } + + /* VSP */ + if (inst->codec == MSM_VIDC_AV1) { + /* + * For AV1: Use VSP calculations from Kalama perf model. + * For legacy codecs, use vsp_cycles based on legacy MB_CYCLES_VSP. + */ + u32 decoder_vsp_fw_overhead = 105; + u32 fw_sw_vsp_offset = 1055; + u64 vsp_hw_min_frequency = 0; + u32 input_bitrate_mbps = 0; + u32 bitrate_2stage[2] = {130, 120}; + u32 bitrate_1stage = 100; + u32 width, height; + u32 bitrate_entry, freq_entry, freq_tbl_value; + struct frequency_table *freq_tbl; + struct v4l2_format *out_f = &inst->fmts[OUTPUT_PORT]; + + width = out_f->fmt.pix_mp.width; + height = out_f->fmt.pix_mp.height; + + bitrate_entry = 1; + /* 8KUHD60, UHD240, 1080p960 */ + if (width * height * fps >= 3840 * 2160 * 240) + bitrate_entry = 0; + + freq_entry = bitrate_entry; + + freq_tbl = core->resource->freq_set.freq_tbl; + freq_tbl_value = freq_tbl[freq_entry].freq / 1000000; + + input_bitrate_mbps = fps * data_size * 8 / (1024 * 1024); + vsp_hw_min_frequency = freq_tbl_value * 1000 * input_bitrate_mbps; + + if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_2) { + vsp_hw_min_frequency += + (bitrate_2stage[bitrate_entry] * fw_sw_vsp_offset - 1); + vsp_hw_min_frequency = div_u64(vsp_hw_min_frequency, + (bitrate_2stage[bitrate_entry] * fw_sw_vsp_offset)); + /* VSP fw overhead 1.05 */ + vsp_hw_min_frequency = div_u64(vsp_hw_min_frequency * + decoder_vsp_fw_overhead + 99, 100); + } else { + vsp_hw_min_frequency += (bitrate_1stage * fw_sw_vsp_offset - 1); + vsp_hw_min_frequency = div_u64(vsp_hw_min_frequency, + (bitrate_1stage * fw_sw_vsp_offset)); + } + + vsp_cycles = vsp_hw_min_frequency * 1000000; + } else { + base_cycles = inst->has_bframe ? + 80 : inst->capabilities[MB_CYCLES_VSP].value; + bitrate = fps * data_size * 8; + vsp_cycles = bitrate; + + if (inst->codec == MSM_VIDC_VP9) { + vsp_cycles = div_u64(vsp_cycles * 170, 100); + } else if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) { + vsp_cycles = div_u64(vsp_cycles * 135, 100); + } else { + base_cycles = 0; + vsp_cycles = div_u64(vsp_cycles, 2); + } + /* VSP FW overhead 1.05 */ + vsp_cycles = div_u64(vsp_cycles * 21, 20); + + if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_1) + vsp_cycles = vsp_cycles * 3; + + vsp_cycles += mbs_per_second * base_cycles; + + /* Add 25 percent extra for 960fps use case */ + if (fps >= 960) + vsp_cycles += div_u64(vpp_cycles * 25, 100); + + /* Add 25 percent extra for HEVC 10bit all intra use case */ + if (inst->iframe && is_hevc_10bit_decode_session(inst)) + vsp_cycles += div_u64(vsp_cycles * 25, 100); + + if (inst->codec == MSM_VIDC_VP9 && + inst->capabilities[STAGE].value == + MSM_VIDC_STAGE_2 && + inst->capabilities[PIPE].value == 4 && + bitrate > 90000000) + vsp_cycles = msm_vidc_max_freq(inst); + } + } else { + i_vpr_e(inst, "%s: Unknown session type\n", __func__); + return msm_vidc_max_freq(inst); + } + + freq = max(vpp_cycles, vsp_cycles); + freq = max(freq, fw_cycles); + + if (inst->codec == MSM_VIDC_AV1 || + (inst->iframe && is_hevc_10bit_decode_session(inst))) { + /* + * for AV1 or HEVC 10bit and iframe case only allow TURBO and + * limit to NOM for all other cases + */ + } else { + /* limit to NOM, index 0 is TURBO, index 1 is NOM clock rate */ + if (core->resource->freq_set.count >= 2 && + freq > core->resource->freq_set.freq_tbl[1].freq) + freq = core->resource->freq_set.freq_tbl[1].freq; + } + + i_vpr_p(inst, "%s: filled len %d, required freq %llu, fps %u, mbpf %u\n", + __func__, data_size, freq, fps, mbpf); + + return freq; +} + +static u64 __calculate_decoder(struct vidc_bus_vote_data *d) +{ + /* + * XXX: Don't fool around with any of the hardcoded numbers unless you + * know /exactly/ what you're doing. Many of these numbers are + * measured heuristics and hardcoded numbers taken from the firmware. + */ + /* Decoder parameters */ + int width, height, lcu_size, fps, dpb_bpp; + bool unified_dpb_opb, dpb_compression_enabled = true, + opb_compression_enabled = false, + llc_ref_read_l2_cache_enabled = false, + llc_top_line_buf_enabled = false; + fp_t dpb_read_compression_factor, dpb_opb_scaling_ratio, + dpb_write_compression_factor, opb_write_compression_factor, + qsmmu_bw_overhead_factor; + bool is_h264_category = (d->codec == MSM_VIDC_H264) ? true : false; + + /* Derived parameters */ + int lcu_per_frame, collocated_bytes_per_lcu, tnbr_per_lcu; + unsigned long bitrate; + + fp_t bins_to_bit_factor, vsp_read_factor, vsp_write_factor, + dpb_factor, dpb_write_factor, y_bw_no_ubwc_8bpp; + fp_t y_bw_no_ubwc_10bpp = 0, y_bw_10bpp_p010 = 0, + motion_vector_complexity = 0; + fp_t dpb_total = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + dpb_read, dpb_write, opb_read, opb_write, + line_buffer_read, line_buffer_write, + total; + } ddr = {0}; + + struct { + fp_t dpb_read, line_buffer_read, line_buffer_write, total; + } llc = {0}; + + unsigned long ret = 0; + unsigned int integer_part, frac_part; + + width = max(d->input_width, BASELINE_DIMENSIONS.width); + height = max(d->input_height, BASELINE_DIMENSIONS.height); + + fps = d->fps; + + lcu_size = d->lcu_size; + + dpb_bpp = __bpp(d->color_formats[0]); + + unified_dpb_opb = d->num_formats == 1; + + dpb_opb_scaling_ratio = fp_div(FP_INT(d->input_width * d->input_height), + FP_INT(d->output_width * d->output_height)); + + opb_compression_enabled = d->num_formats >= 2 && + __ubwc(d->color_formats[1]); + + integer_part = Q16_INT(d->compression_ratio); + frac_part = Q16_FRAC(d->compression_ratio); + dpb_read_compression_factor = FP(integer_part, frac_part, 100); + + integer_part = Q16_INT(d->complexity_factor); + frac_part = Q16_FRAC(d->complexity_factor); + motion_vector_complexity = FP(integer_part, frac_part, 100); + + dpb_write_compression_factor = dpb_read_compression_factor; + opb_write_compression_factor = opb_compression_enabled ? + dpb_write_compression_factor : FP_ONE; + + if (d->use_sys_cache) { + llc_ref_read_l2_cache_enabled = true; + if (is_h264_category) + llc_top_line_buf_enabled = true; + } + + /* Derived parameters setup */ + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + + bitrate = DIV_ROUND_UP(d->bitrate, 1000000); + + bins_to_bit_factor = FP_INT(4); + + vsp_write_factor = bins_to_bit_factor; + vsp_read_factor = bins_to_bit_factor + FP_INT(2); + + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + if (d->codec == MSM_VIDC_AV1) { + collocated_bytes_per_lcu = 4 * 512; /* lcu_size = 128 */ + if (lcu_size == 32) + collocated_bytes_per_lcu = 4 * 512 / (128 * 128 / 32 / 32); + else if (lcu_size == 64) + collocated_bytes_per_lcu = 4 * 512 / (128 * 128 / 64 / 64); + } + + dpb_factor = FP(1, 50, 100); + dpb_write_factor = FP(1, 5, 100); + + tnbr_per_lcu = lcu_size == 16 ? 128 : + lcu_size == 32 ? 64 : 128; + + /* .... For DDR & LLC ...... */ + ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate), + vsp_read_factor), FP_INT(8)); + ddr.vsp_write = fp_div(fp_mult(FP_INT(bitrate), + vsp_write_factor), FP_INT(8)); + + ddr.collocated_read = fp_div(FP_INT(lcu_per_frame * + collocated_bytes_per_lcu * fps), FP_INT(bps(1))); + ddr.collocated_write = ddr.collocated_read; + + y_bw_no_ubwc_8bpp = fp_div(FP_INT(width * height * fps), + FP_INT(1000 * 1000)); + + if (dpb_bpp != 8) { + y_bw_no_ubwc_10bpp = + fp_div(fp_mult(y_bw_no_ubwc_8bpp, FP_INT(256)), + FP_INT(192)); + y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2; + } + + ddr.dpb_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_read = fp_div(fp_mult(ddr.dpb_read, + fp_mult(dpb_factor, motion_vector_complexity)), + dpb_read_compression_factor); + + ddr.dpb_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_write = fp_div(fp_mult(ddr.dpb_write, + fp_mult(dpb_factor, dpb_write_factor)), + dpb_write_compression_factor); + + dpb_total = ddr.dpb_read + ddr.dpb_write; + + if (llc_ref_read_l2_cache_enabled) { + ddr.dpb_read = fp_div(ddr.dpb_read, is_h264_category ? + FP(1, 30, 100) : FP(1, 14, 100)); + llc.dpb_read = dpb_total - ddr.dpb_write - ddr.dpb_read; + } + + ddr.opb_read = FP_ZERO; + ddr.opb_write = unified_dpb_opb ? FP_ZERO : (dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : (opb_compression_enabled ? + y_bw_no_ubwc_10bpp : y_bw_10bpp_p010)); + ddr.opb_write = fp_div(fp_mult(dpb_factor, ddr.opb_write), + fp_mult(dpb_opb_scaling_ratio, opb_write_compression_factor)); + + ddr.line_buffer_read = + fp_div(FP_INT(tnbr_per_lcu * lcu_per_frame * fps), + FP_INT(bps(1))); + + if (is_h264_category) + ddr.line_buffer_write = fp_div(ddr.line_buffer_read, FP_INT(2)); + else + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer_read = ddr.line_buffer_read; + llc.line_buffer_write = ddr.line_buffer_write; + ddr.line_buffer_write = ddr.line_buffer_read = FP_ZERO; + } + + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.dpb_read + ddr.dpb_write + + ddr.opb_read + ddr.opb_write + + ddr.line_buffer_read + ddr.line_buffer_write; + + qsmmu_bw_overhead_factor = FP(1, 3, 100); + + ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); + llc.total = llc.dpb_read + llc.line_buffer_read + + llc.line_buffer_write + ddr.total; + + /* Add 25 percent extra for 960fps use case */ + if (fps >= 960) { + ddr.total += div_u64(ddr.total * 25, 100); + llc.total += div_u64(llc.total * 25, 100); + } + + /* Dump all the variables for easier debugging */ + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu size", "%d", lcu_size}, + {"dpb bitdepth", "%d", dpb_bpp}, + {"frame rate", "%d", fps}, + {"dpb/opb unified", "%d", unified_dpb_opb}, + {"dpb/opb downscaling ratio", DUMP_FP_FMT, + dpb_opb_scaling_ratio}, + {"dpb compression", "%d", dpb_compression_enabled}, + {"opb compression", "%d", opb_compression_enabled}, + {"dpb read compression factor", DUMP_FP_FMT, + dpb_read_compression_factor}, + {"dpb write compression factor", DUMP_FP_FMT, + dpb_write_compression_factor}, + {"frame width", "%d", width}, + {"frame height", "%d", height}, + {"llc ref read l2 cache enabled", "%d", + llc_ref_read_l2_cache_enabled}, + {"llc top line buf enabled", "%d", + llc_top_line_buf_enabled}, + + {"DERIVED PARAMETERS (1)", "", DUMP_HEADER_MAGIC}, + {"lcus/frame", "%d", lcu_per_frame}, + {"bitrate (Mbit/sec)", "%d", bitrate}, + {"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor}, + {"dpb write factor", DUMP_FP_FMT, dpb_write_factor}, + {"vsp read factor", DUMP_FP_FMT, vsp_read_factor}, + {"vsp write factor", DUMP_FP_FMT, vsp_write_factor}, + {"tnbr/lcu", "%d", tnbr_per_lcu}, + {"collocated bytes/LCU", "%d", collocated_bytes_per_lcu}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, + + {"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC}, + {"mv complexity", DUMP_FP_FMT, motion_vector_complexity}, + {"qsmmu_bw_overhead_factor", DUMP_FP_FMT, + qsmmu_bw_overhead_factor}, + + {"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, + {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, + {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, + {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, + {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, + {"opb read", DUMP_FP_FMT, ddr.opb_read}, + {"opb write", DUMP_FP_FMT, ddr.opb_write}, + {"dpb read", DUMP_FP_FMT, ddr.dpb_read}, + {"dpb write", DUMP_FP_FMT, ddr.dpb_write}, + {"dpb total", DUMP_FP_FMT, dpb_total}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc dpb read", DUMP_FP_FMT, llc.dpb_read}, + {"llc line buffer read", DUMP_FP_FMT, llc.line_buffer_read}, + {"llc line buffer write", DUMP_FP_FMT, llc.line_buffer_write}, + + }; + __dump(dump, ARRAY_SIZE(dump)); + } + + d->calc_bw_ddr = kbps(fp_round(ddr.total)); + d->calc_bw_llcc = kbps(fp_round(llc.total)); + + return ret; +} + +static u64 __calculate_encoder(struct vidc_bus_vote_data *d) +{ + /* + * XXX: Don't fool around with any of the hardcoded numbers unless you + * know /exactly/ what you're doing. Many of these numbers are + * measured heuristics and hardcoded numbers taken from the firmware. + */ + /* Encoder Parameters */ + int width, height, fps, lcu_size, bitrate, lcu_per_frame, + collocated_bytes_per_lcu, tnbr_per_lcu, dpb_bpp, + original_color_format, vertical_tile_width, rotation; + bool work_mode_1, original_compression_enabled, + low_power, cropping_or_scaling, + b_frames_enabled = false, + llc_ref_chroma_cache_enabled = false, + llc_top_line_buf_enabled = false, + llc_vpss_rot_line_buf_enabled = false, + vpss_preprocessing_enabled = false; + + unsigned int bins_to_bit_factor; + fp_t dpb_compression_factor, + original_compression_factor, + original_compression_factor_y, + y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp = 0, y_bw_10bpp_p010 = 0, + input_compression_factor, + downscaling_ratio, + ref_y_read_bw_factor, ref_cbcr_read_bw_factor, + recon_write_bw_factor, + total_ref_read_crcb, + qsmmu_bw_overhead_factor; + fp_t integer_part, frac_part; + unsigned long ret = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + ref_read_y, ref_read_crcb, ref_write, + ref_write_overlap, orig_read, + line_buffer_read, line_buffer_write, + total; + } ddr = {0}; + + struct { + fp_t ref_read_crcb, line_buffer, total; + } llc = {0}; + + /* Encoder Parameters setup */ + rotation = d->rotation; + cropping_or_scaling = false; + vertical_tile_width = 960; + /* + * recon_write_bw_factor varies according to resolution and bit-depth, + * here use 1.08(1.075) for worst case. + * Similar for ref_y_read_bw_factor, it can reach 1.375 for worst case, + * here use 1.3 for average case, and can somewhat balance the + * worst case assumption for UBWC CR factors. + */ + recon_write_bw_factor = FP(1, 8, 100); + ref_y_read_bw_factor = FP(1, 30, 100); + ref_cbcr_read_bw_factor = FP(1, 50, 100); + + + /* Derived Parameters */ + fps = d->fps; + width = max(d->output_width, BASELINE_DIMENSIONS.width); + height = max(d->output_height, BASELINE_DIMENSIONS.height); + downscaling_ratio = fp_div(FP_INT(d->input_width * d->input_height), + FP_INT(d->output_width * d->output_height)); + downscaling_ratio = max(downscaling_ratio, FP_ONE); + bitrate = d->bitrate > 0 ? DIV_ROUND_UP(d->bitrate, 1000000) : + __lut(width, height, fps)->bitrate; + lcu_size = d->lcu_size; + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + tnbr_per_lcu = 16; + + dpb_bpp = __bpp(d->color_formats[0]); + + y_bw_no_ubwc_8bpp = fp_div(FP_INT(width * height * fps), + FP_INT(1000 * 1000)); + + if (dpb_bpp != 8) { + y_bw_no_ubwc_10bpp = fp_div(fp_mult(y_bw_no_ubwc_8bpp, + FP_INT(256)), FP_INT(192)); + y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2; + } + + b_frames_enabled = d->b_frames_enabled; + original_color_format = d->num_formats >= 1 ? + d->color_formats[0] : MSM_VIDC_FMT_NV12C; + + original_compression_enabled = __ubwc(original_color_format); + + work_mode_1 = d->work_mode == MSM_VIDC_STAGE_1; + low_power = d->power_mode == VIDC_POWER_LOW; + bins_to_bit_factor = 4; + vpss_preprocessing_enabled = d->vpss_preprocessing_enabled; + + if (d->use_sys_cache) { + llc_ref_chroma_cache_enabled = true; + llc_top_line_buf_enabled = true, + llc_vpss_rot_line_buf_enabled = true; + } + + integer_part = Q16_INT(d->compression_ratio); + frac_part = Q16_FRAC(d->compression_ratio); + dpb_compression_factor = FP(integer_part, frac_part, 100); + + integer_part = Q16_INT(d->input_cr); + frac_part = Q16_FRAC(d->input_cr); + input_compression_factor = FP(integer_part, frac_part, 100); + + original_compression_factor = original_compression_factor_y = + !original_compression_enabled ? FP_ONE : + __compression_ratio(__lut(width, height, fps), dpb_bpp); + /* use input cr if it is valid (not 1), otherwise use lut */ + if (original_compression_enabled && + input_compression_factor != FP_ONE) { + original_compression_factor = input_compression_factor; + /* Luma usually has lower compression factor than Chroma, + * input cf is overall cf, add 1.08 factor for Luma cf + */ + original_compression_factor_y = + input_compression_factor > FP(1, 8, 100) ? + fp_div(input_compression_factor, FP(1, 8, 100)) : + input_compression_factor; + } + + ddr.vsp_read = fp_div(FP_INT(bitrate * bins_to_bit_factor), FP_INT(8)); + ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8)); + + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + ddr.collocated_read = fp_div(FP_INT(lcu_per_frame * + collocated_bytes_per_lcu * fps), FP_INT(bps(1))); + + ddr.collocated_write = ddr.collocated_read; + + ddr.ref_read_y = dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + if (b_frames_enabled) + ddr.ref_read_y = ddr.ref_read_y * 2; + ddr.ref_read_y = fp_div(ddr.ref_read_y, dpb_compression_factor); + + ddr.ref_read_crcb = fp_mult((ddr.ref_read_y / 2), + ref_cbcr_read_bw_factor); + + if (width > vertical_tile_width) { + ddr.ref_read_y = fp_mult(ddr.ref_read_y, + ref_y_read_bw_factor); + } + + if (llc_ref_chroma_cache_enabled) { + total_ref_read_crcb = ddr.ref_read_crcb; + ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb, + ref_cbcr_read_bw_factor); + llc.ref_read_crcb = total_ref_read_crcb - ddr.ref_read_crcb; + } + + ddr.ref_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.ref_write = fp_div(fp_mult(ddr.ref_write, FP(1, 50, 100)), + dpb_compression_factor); + + if (width > vertical_tile_width) { + ddr.ref_write_overlap = fp_mult(ddr.ref_write, + (recon_write_bw_factor - FP_ONE)); + ddr.ref_write = fp_mult(ddr.ref_write, recon_write_bw_factor); + } + + /* double ref_write */ + if (vpss_preprocessing_enabled) + ddr.ref_write = ddr.ref_write * 2; + + ddr.orig_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : + (original_compression_enabled ? y_bw_no_ubwc_10bpp : + y_bw_10bpp_p010); + ddr.orig_read = fp_div(fp_mult(fp_mult(ddr.orig_read, FP(1, 50, 100)), + downscaling_ratio), original_compression_factor); + if (rotation == 90 || rotation == 270) + ddr.orig_read *= lcu_size == 32 ? (dpb_bpp == 8 ? 1 : 3) : 2; + + /* double orig_read */ + if (vpss_preprocessing_enabled) + ddr.orig_read = ddr.orig_read * 2; + + ddr.line_buffer_read = + fp_div(FP_INT(tnbr_per_lcu * lcu_per_frame * fps), + FP_INT(bps(1))); + + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write; + ddr.line_buffer_read = ddr.line_buffer_write = FP_ZERO; + } + + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.ref_read_y + ddr.ref_read_crcb + + ddr.ref_write + ddr.ref_write_overlap + + ddr.orig_read + + ddr.line_buffer_read + ddr.line_buffer_write; + + qsmmu_bw_overhead_factor = FP(1, 3, 100); + ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); + llc.total = llc.ref_read_crcb + llc.line_buffer + ddr.total; + + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"width", "%d", width}, + {"height", "%d", height}, + {"fps", "%d", fps}, + {"dpb bitdepth", "%d", dpb_bpp}, + {"input downscaling ratio", DUMP_FP_FMT, downscaling_ratio}, + {"rotation", "%d", rotation}, + {"cropping or scaling", "%d", cropping_or_scaling}, + {"low power mode", "%d", low_power}, + {"work Mode", "%d", work_mode_1}, + {"B frame enabled", "%d", b_frames_enabled}, + {"original frame format", "%#x", original_color_format}, + {"VPSS preprocessing", "%d", vpss_preprocessing_enabled}, + {"original compression enabled", "%d", + original_compression_enabled}, + {"dpb compression factor", DUMP_FP_FMT, + dpb_compression_factor}, + {"input compression factor", DUMP_FP_FMT, + input_compression_factor}, + {"llc ref chroma cache enabled", DUMP_FP_FMT, + llc_ref_chroma_cache_enabled}, + {"llc top line buf enabled", DUMP_FP_FMT, + llc_top_line_buf_enabled}, + {"llc vpss rot line buf enabled ", DUMP_FP_FMT, + llc_vpss_rot_line_buf_enabled}, + + {"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu size", "%d", lcu_size}, + {"bitrate (Mbit/sec)", "%lu", bitrate}, + {"bins to bit factor", "%u", bins_to_bit_factor}, + {"original compression factor", DUMP_FP_FMT, + original_compression_factor}, + {"original compression factor y", DUMP_FP_FMT, + original_compression_factor_y}, + {"qsmmu_bw_overhead_factor", + DUMP_FP_FMT, qsmmu_bw_overhead_factor}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, + + {"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, + {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, + {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, + {"ref read y", DUMP_FP_FMT, ddr.ref_read_y}, + {"ref read crcb", DUMP_FP_FMT, ddr.ref_read_crcb}, + {"ref write", DUMP_FP_FMT, ddr.ref_write}, + {"ref write overlap", DUMP_FP_FMT, ddr.ref_write_overlap}, + {"original read", DUMP_FP_FMT, ddr.orig_read}, + {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, + {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc ref read crcb", DUMP_FP_FMT, llc.ref_read_crcb}, + {"llc line buffer", DUMP_FP_FMT, llc.line_buffer}, + }; + __dump(dump, ARRAY_SIZE(dump)); + } + + d->calc_bw_ddr = kbps(fp_round(ddr.total)); + d->calc_bw_llcc = kbps(fp_round(llc.total)); + + return ret; +} + +static u64 __calculate(struct msm_vidc_inst *inst, struct vidc_bus_vote_data *d) +{ + u64 value = 0; + + switch (d->domain) { + case MSM_VIDC_ENCODER: + value = __calculate_encoder(d); + break; + case MSM_VIDC_DECODER: + value = __calculate_decoder(d); + break; + default: + i_vpr_e(inst, "%s: Unknown Domain %#x", __func__, d->domain); + } + + return value; +} + +int msm_vidc_calc_bw_iris3(struct msm_vidc_inst *inst, + struct vidc_bus_vote_data *vidc_data) +{ + int value = 0; + + if (!vidc_data) + return value; + + if (ENABLE_LEGACY_POWER_CALCULATIONS) + value = __calculate(inst, vidc_data); + else + value = msm_vidc_calc_bw_iris3_new(inst, vidc_data); + + return value; +} \ No newline at end of file diff --git a/qcom/opensource/video-driver/driver/variant/iris33/inc/hfi_buffer_iris33.h b/qcom/opensource/video-driver/driver/variant/iris33/inc/hfi_buffer_iris33.h new file mode 100644 index 0000000000..3fb918bb7d --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris33/inc/hfi_buffer_iris33.h @@ -0,0 +1,1819 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __HFI_BUFFER_IRIS3_3__ +#define __HFI_BUFFER_IRIS3_3__ + +#include +#include "hfi_property.h" + +typedef u8 HFI_U8; +typedef s8 HFI_S8; +typedef u16 HFI_U16; +typedef s16 HFI_S16; +typedef u32 HFI_U32; +typedef s32 HFI_S32; +typedef u64 HFI_U64; +typedef HFI_U32 HFI_BOOL; + +#ifndef MIN +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#ifndef MAX +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#define HFI_ALIGNMENT_4096 (4096) + +#define BUF_SIZE_ALIGN_16 (16) +#define BUF_SIZE_ALIGN_32 (32) +#define BUF_SIZE_ALIGN_64 (64) +#define BUF_SIZE_ALIGN_128 (128) +#define BUF_SIZE_ALIGN_256 (256) +#define BUF_SIZE_ALIGN_512 (512) +#define BUF_SIZE_ALIGN_4096 (4096) + +#define HFI_ALIGN(a, b) (((b) & ((b) - 1)) ? (((a) + (b) - 1) / \ + (b) * (b)) : (((a) + (b) - 1) & (~((b) - 1)))) + +#define HFI_WORKMODE_1 1 +#define HFI_WORKMODE_2 2 + +#define HFI_DEFAULT_METADATA_STRIDE_MULTIPLE (64) +#define HFI_DEFAULT_METADATA_BUFFERHEIGHT_MULTIPLE (16) + +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT (8) +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH (32) +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT (8) +#define HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH (16) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT (4) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH (48) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_HEIGHT (4) +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_WIDTH (24) +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_HEIGHT (4) +#define HFI_COLOR_FORMAT_RGBA8888_UBWC_TILE_WIDTH (16) + +#define HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width, stride_multiple)) + +#define HFI_NV12_IL_CALC_Y_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) (buf_height = HFI_ALIGN(frame_height, \ + min_buf_height_multiple)) + +#define HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width, stride_multiple)) + +#define HFI_NV12_IL_CALC_UV_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) (buf_height = HFI_ALIGN(((frame_height + 1) \ + >> 1), min_buf_height_multiple)) + +#define HFI_NV12_IL_CALC_BUF_SIZE(buf_size, y_bufSize, y_stride, y_buf_height, \ + uv_buf_size, uv_stride, uv_buf_height) \ + do { \ + y_bufSize = (y_stride * y_buf_height); \ + uv_buf_size = (uv_stride * uv_buf_height); \ + buf_size = HFI_ALIGN(y_bufSize + uv_buf_size, HFI_ALIGNMENT_4096); \ + } while (0) + +#define HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_bufSize, y_stride, y_buf_height) \ + (y_bufSize = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, \ + uv_stride, uv_buf_height) \ + (uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_NV12_UBWC_IL_CALC_BUF_SIZE_V2(buf_size,\ + frame_width, frame_height, y_stride_multiple,\ + y_buffer_height_multiple, uv_stride_multiple, \ + uv_buffer_height_multiple, y_metadata_stride_multiple, \ + y_metadata_buffer_height_multiple, \ + uv_metadata_stride_multiple, uv_metadata_buffer_height_multiple, binterlace) \ + do { \ + HFI_U32 y_buf_size, uv_buf_size, y_meta_size, uv_meta_size; \ + HFI_U32 stride, _height; \ + HFI_U32 half_height = (frame_height + 1) >> 1; \ + HFI_NV12_IL_CALC_Y_STRIDE(stride, frame_width,\ + y_stride_multiple); \ + HFI_NV12_IL_CALC_Y_BUFHEIGHT(_height, half_height,\ + y_buffer_height_multiple); \ + HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(y_buf_size, stride, _height);\ + HFI_NV12_IL_CALC_UV_STRIDE(stride, frame_width, \ + uv_stride_multiple); \ + HFI_NV12_IL_CALC_UV_BUFHEIGHT(_height, half_height, \ + uv_buffer_height_multiple); \ + HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uv_buf_size, stride, _height);\ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(stride, frame_width,\ + y_metadata_stride_multiple, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH);\ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(_height, half_height, \ + y_metadata_buffer_height_multiple,\ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT);\ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_meta_size, stride, \ + _height); \ + HFI_UBWC_UV_METADATA_PLANE_STRIDE(stride, frame_width,\ + uv_metadata_stride_multiple, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH); \ + HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(_height, half_height,\ + uv_metadata_buffer_height_multiple,\ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT);\ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_meta_size, stride, \ + _height); \ + buf_size = (y_buf_size + uv_buf_size + y_meta_size + \ + uv_meta_size) << binterlace;\ + } while (0) + +#define HFI_YUV420_TP10_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \ + do { \ + stride = HFI_ALIGN(frame_width, 192); \ + stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \ + } while (0) + +#define HFI_YUV420_TP10_CALC_Y_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple)) + +#define HFI_YUV420_TP10_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \ + do { \ + stride = HFI_ALIGN(frame_width, 192); \ + stride = HFI_ALIGN(stride * 4 / 3, stride_multiple); \ + } while (0) + +#define HFI_YUV420_TP10_CALC_UV_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \ + min_buf_height_multiple)) + +#define HFI_YUV420_TP10_CALC_BUF_SIZE(buf_size, y_buf_size, y_stride,\ + y_buf_height, uv_buf_size, uv_stride, uv_buf_height) \ + do { \ + y_buf_size = (y_stride * y_buf_height); \ + uv_buf_size = (uv_stride * uv_buf_height); \ + buf_size = y_buf_size + uv_buf_size; \ + } while (0) + +#define HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_buf_size, y_stride, \ + y_buf_height) \ + (y_buf_size = HFI_ALIGN(y_stride * y_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_buf_size, uv_stride, \ + uv_buf_height) \ + (uv_buf_size = HFI_ALIGN(uv_stride * uv_buf_height, HFI_ALIGNMENT_4096)) + +#define HFI_YUV420_TP10_UBWC_CALC_BUF_SIZE(buf_size, y_stride, y_buf_height, \ + uv_stride, uv_buf_height, y_md_stride, y_md_height, uv_md_stride, \ + uv_md_height)\ + do { \ + HFI_U32 y_data_size, uv_data_size, y_md_size, uv_md_size; \ + HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(y_data_size, y_stride,\ + y_buf_height); \ + HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uv_data_size, uv_stride, \ + uv_buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(y_md_size, y_md_stride, \ + y_md_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(uv_md_size, uv_md_stride, \ + uv_md_height); \ + buf_size = y_data_size + uv_data_size + y_md_size + \ + uv_md_size; \ + } while (0) + +#define HFI_YUV420_P010_CALC_Y_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width * 2, stride_multiple)) + +#define HFI_YUV420_P010_CALC_Y_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple)) + +#define HFI_YUV420_P010_CALC_UV_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN(frame_width * 2, stride_multiple)) + +#define HFI_YUV420_P010_CALC_UV_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(((frame_height + 1) >> 1), \ + min_buf_height_multiple)) + +#define HFI_YUV420_P010_CALC_BUF_SIZE(buf_size, y_data_size, y_stride, \ + y_buf_height, uv_data_size, uv_stride, uv_buf_height) \ + do { \ + y_data_size = HFI_ALIGN(y_stride * y_buf_height, \ + HFI_ALIGNMENT_4096);\ + uv_data_size = HFI_ALIGN(uv_stride * uv_buf_height, \ + HFI_ALIGNMENT_4096); \ + buf_size = y_data_size + uv_data_size; \ + } while (0) + +#define HFI_RGB888_CALC_STRIDE(stride, frame_width, stride_multiple) \ + (stride = ((frame_width * 3) + stride_multiple - 1) & \ + (0xffffffff - (stride_multiple - 1))) + +#define HFI_RGB888_CALC_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = ((frame_height + min_buf_height_multiple - 1) & \ + (0xffffffff - (min_buf_height_multiple - 1)))) + +#define HFI_RGB888_CALC_BUF_SIZE(buf_size, stride, buf_height) \ + (buf_size = ((stride) * (buf_height))) + +#define HFI_RGBA8888_CALC_STRIDE(stride, frame_width, stride_multiple) \ + (stride = HFI_ALIGN((frame_width << 2), stride_multiple)) + +#define HFI_RGBA8888_CALC_BUFHEIGHT(buf_height, frame_height, \ + min_buf_height_multiple) \ + (buf_height = HFI_ALIGN(frame_height, min_buf_height_multiple)) + +#define HFI_RGBA8888_CALC_BUF_SIZE(buf_size, stride, buf_height) \ + (buf_size = (stride) * (buf_height)) + +#define HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(buf_size, stride, \ + buf_height) \ + (buf_size = HFI_ALIGN((stride) * (buf_height), HFI_ALIGNMENT_4096)) + +#define HFI_RGBA8888_UBWC_BUF_SIZE(buf_size, data_buf_size, \ + metadata_buffer_size, stride, buf_height, _metadata_tride, \ + _metadata_buf_height) \ + do { \ + HFI_RGBA8888_UBWC_CALC_DATA_PLANE_BUF_SIZE(data_buf_size, \ + stride, buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(metadata_buffer_size, \ + _metadata_tride, _metadata_buf_height); \ + buf_size = data_buf_size + metadata_buffer_size; \ + } while (0) + +#define HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, frame_width,\ + metadata_stride_multiple, tile_width_in_pels) \ + ((metadata_stride = HFI_ALIGN(((frame_width + (tile_width_in_pels - 1)) /\ + tile_width_in_pels), metadata_stride_multiple))) + +#define HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, frame_height, \ + metadata_height_multiple, tile_height_in_pels) \ + ((metadata_buf_height = HFI_ALIGN(((frame_height + \ + (tile_height_in_pels - 1)) / tile_height_in_pels), \ + metadata_height_multiple))) + +#define HFI_UBWC_UV_METADATA_PLANE_STRIDE(metadata_stride, frame_width, \ + metadata_stride_multiple, tile_width_in_pels) \ + ((metadata_stride = HFI_ALIGN(((((frame_width + 1) >> 1) +\ + (tile_width_in_pels - 1)) / tile_width_in_pels), \ + metadata_stride_multiple))) + +#define HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, frame_height,\ + metadata_height_multiple, tile_height_in_pels) \ + (metadata_buf_height = HFI_ALIGN(((((frame_height + 1) >> 1) + \ + (tile_height_in_pels - 1)) / tile_height_in_pels), \ + metadata_height_multiple)) + +#define HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(buffer_size, _metadata_tride, \ + _metadata_buf_height) \ + ((buffer_size = HFI_ALIGN(_metadata_tride * _metadata_buf_height, \ + HFI_ALIGNMENT_4096))) + +#define BUFFER_ALIGNMENT_512_BYTES 512 +#define BUFFER_ALIGNMENT_256_BYTES 256 +#define BUFFER_ALIGNMENT_128_BYTES 128 +#define BUFFER_ALIGNMENT_64_BYTES 64 +#define BUFFER_ALIGNMENT_32_BYTES 32 +#define BUFFER_ALIGNMENT_16_BYTES 16 +#define BUFFER_ALIGNMENT_8_BYTES 8 +#define BUFFER_ALIGNMENT_4_BYTES 4 + +#define VENUS_DMA_ALIGNMENT BUFFER_ALIGNMENT_256_BYTES + +#define MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE 64 +#define MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE 640 +#define MAX_FE_NBR_DATA_CB_LINE_BUFFER_SIZE 320 +#define MAX_FE_NBR_DATA_CR_LINE_BUFFER_SIZE 320 + +#define MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE (128 / 8) +#define MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE (128 / 8) +#define MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE (128 / 8) + +#define MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE (64 * 2 * 3) +#define MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE (32 * 2 * 3) +#define MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE (16 * 2 * 3) + +#define MAX_TILE_COLUMNS 32 + +#define SIZE_VPSS_LB(Size, frame_width, frame_height, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_4tap_top_buffer_size, vpss_div2_top_buffer_size, \ + vpss_4tap_left_buffer_size, vpss_div2_left_buffer_size; \ + HFI_U32 opb_wr_top_line_luma_buffer_size, \ + opb_wr_top_line_chroma_buffer_size, \ + opb_lb_wr_llb_y_buffer_size,\ + opb_lb_wr_llb_uv_buffer_size; \ + HFI_U32 macrotiling_size; \ + vpss_4tap_top_buffer_size = vpss_div2_top_buffer_size = \ + vpss_4tap_left_buffer_size = vpss_div2_left_buffer_size = 0; \ + macrotiling_size = 32; \ + opb_wr_top_line_luma_buffer_size = HFI_ALIGN(frame_width, \ + macrotiling_size) / macrotiling_size * 256; \ + opb_wr_top_line_luma_buffer_size = \ + HFI_ALIGN(opb_wr_top_line_luma_buffer_size, \ + VENUS_DMA_ALIGNMENT) + (MAX_TILE_COLUMNS - 1) * 256; \ + opb_wr_top_line_luma_buffer_size = \ + MAX(opb_wr_top_line_luma_buffer_size, (32 * \ + HFI_ALIGN(frame_height, 8))); \ + opb_wr_top_line_chroma_buffer_size = \ + opb_wr_top_line_luma_buffer_size;\ + opb_lb_wr_llb_uv_buffer_size = opb_lb_wr_llb_y_buffer_size = \ + HFI_ALIGN((HFI_ALIGN(frame_height, 8) / (4 / 2)) * 64,\ + BUFFER_ALIGNMENT_32_BYTES); \ + Size = num_vpp_pipes * 2 * (vpss_4tap_top_buffer_size + \ + vpss_div2_top_buffer_size) + \ + 2 * (vpss_4tap_left_buffer_size + \ + vpss_div2_left_buffer_size) + \ + opb_wr_top_line_luma_buffer_size + \ + opb_wr_top_line_chroma_buffer_size + \ + opb_lb_wr_llb_uv_buffer_size + \ + opb_lb_wr_llb_y_buffer_size; \ + } while (0) + +#define VPP_CMD_MAX_SIZE (1 << 20) +#define NUM_HW_PIC_BUF 32 +#define BIN_BUFFER_THRESHOLD (1280 * 736) +#define H264D_MAX_SLICE 1800 +#define SIZE_H264D_BUFTAB_T (256) +#define SIZE_H264D_HW_PIC_T (1 << 11) +#define SIZE_H264D_BSE_CMD_PER_BUF (32 * 4) +#define SIZE_H264D_VPP_CMD_PER_BUF (512) + +#define SIZE_H264D_LB_FE_TOP_DATA(frame_width, frame_height) \ + (MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * HFI_ALIGN(frame_width, 16) * 3) + +#define SIZE_H264D_LB_FE_TOP_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_width + 15) >> 4)) + +#define SIZE_H264D_LB_FE_LEFT_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_height + 15) >> 4)) + +#define SIZE_H264D_LB_SE_TOP_CTRL(frame_width, frame_height) \ + (MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_width + 15) >> 4)) + +#define SIZE_H264D_LB_SE_LEFT_CTRL(frame_width, frame_height) \ + (MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * ((frame_height + 15) >> 4)) + +#define SIZE_H264D_LB_PE_TOP_DATA(frame_width, frame_height) \ + (MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * ((frame_width + 15) >> 4)) + +#define SIZE_H264D_LB_VSP_TOP(frame_width, frame_height) \ + ((((frame_width + 15) >> 4) << 7)) + +#define SIZE_H264D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \ + (HFI_ALIGN(frame_height, 16) * 32) + +#define SIZE_H264D_QP(frame_width, frame_height) \ + (((frame_width + 63) >> 6) * ((frame_height + 63) >> 6) * 128) + +#define SIZE_HW_PIC(size_per_buf) \ + (NUM_HW_PIC_BUF * size_per_buf) + +#define SIZE_H264D_BSE_CMD_BUF(_size, frame_width, frame_height) \ + do { \ + HFI_U32 _height = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_32_BYTES); \ + _size = MIN((((_height + 15) >> 4) * 48), H264D_MAX_SLICE) *\ + SIZE_H264D_BSE_CMD_PER_BUF; \ + } while (0) + +#define SIZE_H264D_VPP_CMD_BUF(_size, frame_width, frame_height) \ + do { \ + HFI_U32 _height = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_32_BYTES); \ + _size = MIN((((_height + 15) >> 4) * 48), H264D_MAX_SLICE) * \ + SIZE_H264D_VPP_CMD_PER_BUF; \ + if (_size > VPP_CMD_MAX_SIZE) { \ + _size = VPP_CMD_MAX_SIZE; \ + } \ + } while (0) + +#define HFI_BUFFER_COMV_H264D(coMV_size, frame_width, \ + frame_height, _comv_bufcount) \ + do { \ + HFI_U32 frame_width_in_mbs = ((frame_width + 15) >> 4); \ + HFI_U32 frame_height_in_mbs = ((frame_height + 15) >> 4); \ + HFI_U32 col_mv_aligned_width = (frame_width_in_mbs << 7); \ + HFI_U32 col_zero_aligned_width = (frame_width_in_mbs << 2); \ + HFI_U32 col_zero_size = 0, size_colloc = 0; \ + col_mv_aligned_width = HFI_ALIGN(col_mv_aligned_width, \ + BUFFER_ALIGNMENT_16_BYTES); \ + col_zero_aligned_width = HFI_ALIGN(col_zero_aligned_width, \ + BUFFER_ALIGNMENT_16_BYTES); \ + col_zero_size = col_zero_aligned_width * \ + ((frame_height_in_mbs + 1) >> 1); \ + col_zero_size = HFI_ALIGN(col_zero_size, \ + BUFFER_ALIGNMENT_64_BYTES); \ + col_zero_size <<= 1; \ + col_zero_size = HFI_ALIGN(col_zero_size, \ + BUFFER_ALIGNMENT_512_BYTES); \ + size_colloc = col_mv_aligned_width * ((frame_height_in_mbs + \ + 1) >> 1); \ + size_colloc = HFI_ALIGN(size_colloc, \ + BUFFER_ALIGNMENT_64_BYTES); \ + size_colloc <<= 1; \ + size_colloc = HFI_ALIGN(size_colloc, \ + BUFFER_ALIGNMENT_512_BYTES); \ + size_colloc += (col_zero_size + SIZE_H264D_BUFTAB_T * 2); \ + coMV_size = size_colloc * (_comv_bufcount); \ + coMV_size += BUFFER_ALIGNMENT_512_BYTES; \ + } while (0) + +#define HFI_BUFFER_NON_COMV_H264D(_size, frame_width, frame_height, \ + num_vpp_pipes) \ + do { \ + HFI_U32 _size_bse, _size_vpp; \ + SIZE_H264D_BSE_CMD_BUF(_size_bse, frame_width, frame_height); \ + SIZE_H264D_VPP_CMD_BUF(_size_vpp, frame_width, frame_height); \ + _size = HFI_ALIGN(_size_bse, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(_size_vpp, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_HW_PIC(SIZE_H264D_HW_PIC_T), \ + VENUS_DMA_ALIGNMENT); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define HFI_BUFFER_LINE_H264D(_size, frame_width, frame_height, \ + is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_lb_size = 0; \ + _size = HFI_ALIGN(SIZE_H264D_LB_FE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_FE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H264D_LB_SE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_SE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * \ + num_vpp_pipes + \ + HFI_ALIGN(SIZE_H264D_LB_PE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_VSP_TOP(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H264D_LB_RECON_DMA_METADATA_WR\ + (frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * 2 + HFI_ALIGN(SIZE_H264D_QP\ + (frame_width, frame_height), VENUS_DMA_ALIGNMENT); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \ + num_vpp_pipes); \ + } \ + _size = HFI_ALIGN((_size + vpss_lb_size), \ + VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define H264_CABAC_HDR_RATIO_HD_TOT 1 +#define H264_CABAC_RES_RATIO_HD_TOT 3 + +#define SIZE_H264D_HW_BIN_BUFFER(_size, frame_width, frame_height, \ + delay, num_vpp_pipes) \ + do { \ + HFI_U32 size_yuv, size_bin_hdr, size_bin_res; \ + size_yuv = ((frame_width * frame_height) <= \ + BIN_BUFFER_THRESHOLD) ?\ + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : \ + ((frame_width * frame_height * 3) >> 1); \ + size_bin_hdr = size_yuv * H264_CABAC_HDR_RATIO_HD_TOT; \ + size_bin_res = size_yuv * H264_CABAC_RES_RATIO_HD_TOT; \ + size_bin_hdr = size_bin_hdr * (((((HFI_U32)(delay)) & 31) /\ + 10) + 2) / 2; \ + size_bin_res = size_bin_res * (((((HFI_U32)(delay)) & 31) /\ + 10) + 2) / 2; \ + size_bin_hdr = HFI_ALIGN(size_bin_hdr / num_vpp_pipes,\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + size_bin_res = HFI_ALIGN(size_bin_res / num_vpp_pipes, \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + _size = size_bin_hdr + size_bin_res; \ + } while (0) + +#define HFI_BUFFER_BIN_H264D(_size, frame_width, frame_height, is_interlaced, \ + delay, num_vpp_pipes) \ + do { \ + HFI_U32 n_aligned_w = HFI_ALIGN(frame_width, \ + BUFFER_ALIGNMENT_16_BYTES);\ + HFI_U32 n_aligned_h = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_16_BYTES); \ + if (!is_interlaced) { \ + SIZE_H264D_HW_BIN_BUFFER(_size, n_aligned_w, \ + n_aligned_h, delay, num_vpp_pipes); \ + } else { \ + _size = 0; \ + } \ + } while (0) + +#define NUM_SLIST_BUF_H264 (256 + 32) +#define SIZE_SLIST_BUF_H264 (512) +#define SIZE_SEI_USERDATA (4096) +#define H264_NUM_FRM_INFO (66) +#define H264_DISPLAY_BUF_SIZE (3328) +#define SIZE_DOLBY_RPU_METADATA (41 * 1024) +#define HFI_BUFFER_PERSIST_H264D(_size, rpu_enabled) \ + (_size = HFI_ALIGN((SIZE_SLIST_BUF_H264 * NUM_SLIST_BUF_H264 + \ + H264_DISPLAY_BUF_SIZE * H264_NUM_FRM_INFO + \ + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA + \ + rpu_enabled * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA), \ + VENUS_DMA_ALIGNMENT)) + +#define LCU_MAX_SIZE_PELS 64 +#define LCU_MIN_SIZE_PELS 16 + +#define H265D_MAX_SLICE 1200 +#define SIZE_H265D_HW_PIC_T SIZE_H264D_HW_PIC_T +#define SIZE_H265D_BSE_CMD_PER_BUF (16 * sizeof(HFI_U32)) +#define SIZE_H265D_VPP_CMD_PER_BUF (256) + +#define SIZE_H265D_LB_FE_TOP_DATA(frame_width, frame_height) \ + (MAX_FE_NBR_DATA_LUMA_LINE_BUFFER_SIZE * \ + (HFI_ALIGN(frame_width, 64) + 8) * 2) + +#define SIZE_H265D_LB_FE_TOP_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + (HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_FE_LEFT_CTRL(frame_width, frame_height) \ + (MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE * \ + (HFI_ALIGN(frame_height, LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_SE_TOP_CTRL(frame_width, frame_height) \ + ((LCU_MAX_SIZE_PELS / 8 * (128 / 8)) * ((frame_width + 15) >> 4)) + +#define SIZE_H265D_LB_SE_LEFT_CTRL(frame_width, frame_height) \ + (MAX(((frame_height + 16 - 1) / 8) * \ + MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, \ + MAX(((frame_height + 32 - 1) / 8) * \ + MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((frame_height + 64 - 1) / 8) * \ + MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE))) + +#define SIZE_H265D_LB_PE_TOP_DATA(frame_width, frame_height) \ + (MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE * (HFI_ALIGN(frame_width, \ + LCU_MIN_SIZE_PELS) / LCU_MIN_SIZE_PELS)) + +#define SIZE_H265D_LB_VSP_TOP(frame_width, frame_height) \ + (((frame_width + 63) >> 6) * 128) + +#define SIZE_H265D_LB_VSP_LEFT(frame_width, frame_height) \ + (((frame_height + 63) >> 6) * 128) + +#define SIZE_H265D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \ + SIZE_H264D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) + +#define SIZE_H265D_QP(frame_width, frame_height) \ + SIZE_H264D_QP(frame_width, frame_height) + +#define SIZE_H265D_BSE_CMD_BUF(_size, frame_width, frame_height)\ + do { \ + _size = HFI_ALIGN(((HFI_ALIGN(frame_width, \ + LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS) * \ + (HFI_ALIGN(frame_height, LCU_MAX_SIZE_PELS) /\ + LCU_MIN_SIZE_PELS)) * NUM_HW_PIC_BUF, VENUS_DMA_ALIGNMENT); \ + _size = MIN(_size, H265D_MAX_SLICE + 1); \ + _size = 2 * _size * SIZE_H265D_BSE_CMD_PER_BUF; \ + } while (0) + +#define SIZE_H265D_VPP_CMD_BUF(_size, frame_width, frame_height) \ + do { \ + _size = HFI_ALIGN(((HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) /\ + LCU_MIN_SIZE_PELS) * (HFI_ALIGN(frame_height, \ + LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS)) * \ + NUM_HW_PIC_BUF, VENUS_DMA_ALIGNMENT); \ + _size = MIN(_size, H265D_MAX_SLICE + 1); \ + _size = HFI_ALIGN(_size, 4); \ + _size = 2 * _size * SIZE_H265D_VPP_CMD_PER_BUF; \ + if (_size > VPP_CMD_MAX_SIZE) { \ + _size = VPP_CMD_MAX_SIZE; \ + } \ + } while (0) + +#define HFI_BUFFER_COMV_H265D(_size, frame_width, frame_height, \ + _comv_bufcount) \ + do { \ + _size = HFI_ALIGN(((((frame_width + 15) >> 4) * \ + ((frame_height + 15) >> 4)) << 8), \ + BUFFER_ALIGNMENT_512_BYTES); \ + _size *= _comv_bufcount; \ + _size += BUFFER_ALIGNMENT_512_BYTES; \ + } while (0) + +#define HDR10_HIST_EXTRADATA_SIZE (4 * 1024) + +#define HFI_BUFFER_NON_COMV_H265D(_size, frame_width, frame_height, \ + num_vpp_pipes) \ + do { \ + HFI_U32 _size_bse, _size_vpp; \ + SIZE_H265D_BSE_CMD_BUF(_size_bse, frame_width, \ + frame_height); \ + SIZE_H265D_VPP_CMD_BUF(_size_vpp, frame_width, \ + frame_height); \ + _size = HFI_ALIGN(_size_bse, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(_size_vpp, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(NUM_HW_PIC_BUF * 20 * 22 * 4, \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(2 * sizeof(HFI_U16) * \ + (HFI_ALIGN(frame_width, LCU_MAX_SIZE_PELS) / \ + LCU_MIN_SIZE_PELS) * (HFI_ALIGN(frame_height, \ + LCU_MAX_SIZE_PELS) / LCU_MIN_SIZE_PELS), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_HW_PIC(SIZE_H265D_HW_PIC_T), \ + VENUS_DMA_ALIGNMENT) + \ + HDR10_HIST_EXTRADATA_SIZE; \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define HFI_BUFFER_LINE_H265D(_size, frame_width, frame_height, \ + is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_lb_size = 0; \ + _size = HFI_ALIGN(SIZE_H265D_LB_FE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_FE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H265D_LB_SE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H265D_LB_SE_TOP_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_PE_TOP_DATA(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_VSP_TOP(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_H265D_LB_VSP_LEFT(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_H265D_LB_RECON_DMA_METADATA_WR\ + (frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * 4 + \ + HFI_ALIGN(SIZE_H265D_QP(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height,\ + num_vpp_pipes); \ + } \ + _size = HFI_ALIGN((_size + vpss_lb_size), \ + VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define H265_CABAC_HDR_RATIO_HD_TOT 2 +#define H265_CABAC_RES_RATIO_HD_TOT 2 + +#define SIZE_H265D_HW_BIN_BUFFER(_size, frame_width, frame_height, \ + delay, num_vpp_pipes) \ + do { \ + HFI_U32 size_yuv, size_bin_hdr, size_bin_res; \ + size_yuv = ((frame_width * frame_height) <= \ + BIN_BUFFER_THRESHOLD) ? \ + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : \ + ((frame_width * frame_height * 3) >> 1); \ + size_bin_hdr = size_yuv * H265_CABAC_HDR_RATIO_HD_TOT; \ + size_bin_res = size_yuv * H265_CABAC_RES_RATIO_HD_TOT; \ + size_bin_hdr = size_bin_hdr * \ + (((((HFI_U32)(delay)) & 31) / 10) + 2) / 2; \ + size_bin_res = size_bin_res * \ + (((((HFI_U32)(delay)) & 31) / 10) + 2) / 2; \ + size_bin_hdr = HFI_ALIGN(size_bin_hdr / \ + num_vpp_pipes, VENUS_DMA_ALIGNMENT) * \ + num_vpp_pipes; \ + size_bin_res = HFI_ALIGN(size_bin_res / num_vpp_pipes,\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + _size = size_bin_hdr + size_bin_res; \ + } while (0) + +#define HFI_BUFFER_BIN_H265D(_size, frame_width, frame_height, \ + is_interlaced, delay, num_vpp_pipes) \ + do { \ + HFI_U32 n_aligned_w = HFI_ALIGN(frame_width, \ + BUFFER_ALIGNMENT_16_BYTES); \ + HFI_U32 n_aligned_h = HFI_ALIGN(frame_height, \ + BUFFER_ALIGNMENT_16_BYTES); \ + if (!is_interlaced) { \ + SIZE_H265D_HW_BIN_BUFFER(_size, n_aligned_w, \ + n_aligned_h, delay, num_vpp_pipes); \ + } else { \ + _size = 0; \ + } \ + } while (0) + +#define SIZE_SLIST_BUF_H265 (1 << 10) +#define NUM_SLIST_BUF_H265 (80 + 20) +#define H265_NUM_TILE_COL 32 +#define H265_NUM_TILE_ROW 128 +#define H265_NUM_TILE (H265_NUM_TILE_ROW * H265_NUM_TILE_COL + 1) +#define H265_NUM_FRM_INFO (48) +#define H265_DISPLAY_BUF_SIZE (3072) +#define HFI_BUFFER_PERSIST_H265D(_size, rpu_enabled) \ + (_size = HFI_ALIGN((SIZE_SLIST_BUF_H265 * NUM_SLIST_BUF_H265 + \ + H265_NUM_FRM_INFO * H265_DISPLAY_BUF_SIZE + \ + H265_NUM_TILE * sizeof(HFI_U32) + NUM_HW_PIC_BUF * SIZE_SEI_USERDATA + \ + rpu_enabled * NUM_HW_PIC_BUF * SIZE_DOLBY_RPU_METADATA),\ + VENUS_DMA_ALIGNMENT)) + +#define SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, frame_height) \ + MAX(((frame_height + 15) >> 4) * \ + MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, \ + MAX(((frame_height + 31) >> 5) * \ + MAX_FE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((frame_height + 63) >> 6) * MAX_FE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)) +#define SIZE_VPXD_LB_FE_TOP_CTRL(frame_width, frame_height) \ + (((HFI_ALIGN(frame_width, 64) + 8) * 10 * 2)) +#define SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height) \ + (((frame_width + 15) >> 4) * MAX_FE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE) +#define SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height) \ + MAX(((frame_height + 15) >> 4) * \ + MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE,\ + MAX(((frame_height + 31) >> 5) * \ + MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((frame_height + 63) >> 6) * MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE)) +#define SIZE_VPXD_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \ + HFI_ALIGN((HFI_ALIGN(frame_height, 8) / (4 / 2)) * 64,\ + BUFFER_ALIGNMENT_32_BYTES) +#define SIZE_MP2D_LB_FE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(frame_width, 16) + 8) * 10 * 2) +#define SIZE_VP9D_LB_FE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) + 8) * 10 * 2) +#define SIZE_MP2D_LB_PE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(frame_width, 16) >> 4) * 64) +#define SIZE_VP9D_LB_PE_TOP_DATA(frame_width, frame_height) \ + ((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) >> 6) * 176) +#define SIZE_MP2D_LB_VSP_TOP(frame_width, frame_height) \ + (((HFI_ALIGN(frame_width, 16) >> 4) * 64 / 2) + 256) +#define SIZE_VP9D_LB_VSP_TOP(frame_width, frame_height) \ + ((((HFI_ALIGN(HFI_ALIGN(frame_width, 8), 64) >> 6) * 64 * 8) + 256)) + +#define HFI_IRIS3_VP9D_COMV_SIZE \ + ((((8192 + 63) >> 6) * ((4320 + 63) >> 6) * 8 * 8 * 2 * 8)) + +#define SIZE_VP9D_QP(frame_width, frame_height) \ + SIZE_H264D_QP(frame_width, frame_height) + +#define HFI_IRIS3_VP9D_LB_SIZE(_size, frame_width, frame_height, num_vpp_pipes)\ + do { \ + _size = HFI_ALIGN(SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_VP9D_LB_VSP_TOP(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VPXD_LB_FE_TOP_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + 2 * \ + HFI_ALIGN(SIZE_VPXD_LB_RECON_DMA_METADATA_WR \ + (frame_width, frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VP9D_LB_PE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VP9D_LB_FE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VP9D_QP(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define HFI_BUFFER_LINE_VP9D(_size, frame_width, frame_height, \ + _yuv_bufcount_min, is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 _lb_size = 0; \ + HFI_U32 vpss_lb_size = 0; \ + HFI_IRIS3_VP9D_LB_SIZE(_lb_size, frame_width, frame_height,\ + num_vpp_pipes); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \ + num_vpp_pipes); \ + } \ + _size = _lb_size + vpss_lb_size; \ + } while (0) + +#define VPX_DECODER_FRAME_CONCURENCY_LVL (2) +#define VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO 1 / 2 +#define VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO 3 / 2 + +#define HFI_BUFFER_BIN_VP9D(_size, frame_width, frame_height, \ + is_interlaced, num_vpp_pipes) \ + do { \ + HFI_U32 _size_yuv = HFI_ALIGN(frame_width, \ + BUFFER_ALIGNMENT_16_BYTES) *\ + HFI_ALIGN(frame_height, BUFFER_ALIGNMENT_16_BYTES) * 3 / 2; \ + if (!is_interlaced) { \ + _size = HFI_ALIGN(((MAX(_size_yuv, \ + ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * \ + VPX_DECODER_FRAME_BIN_HDR_BUDGET_RATIO * \ + VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(((MAX(_size_yuv, \ + ((BIN_BUFFER_THRESHOLD * 3) >> 1)) * \ + VPX_DECODER_FRAME_BIN_RES_BUDGET_RATIO * \ + VPX_DECODER_FRAME_CONCURENCY_LVL) / num_vpp_pipes), \ + VENUS_DMA_ALIGNMENT); \ + _size = _size * num_vpp_pipes; \ + } \ + else \ + _size = 0; \ + } while (0) + +#define VP9_NUM_FRAME_INFO_BUF 32 +#define VP9_NUM_PROBABILITY_TABLE_BUF (VP9_NUM_FRAME_INFO_BUF + 4) +#define VP9_PROB_TABLE_SIZE (3840) +#define VP9_FRAME_INFO_BUF_SIZE (6144) + +#define VP9_UDC_HEADER_BUF_SIZE (3 * 128) +#define MAX_SUPERFRAME_HEADER_LEN (34) +#define CCE_TILE_OFFSET_SIZE HFI_ALIGN(32 * 4 * 4, BUFFER_ALIGNMENT_32_BYTES) + +#define HFI_BUFFER_PERSIST_VP9D(_size) \ + (_size = HFI_ALIGN(VP9_NUM_PROBABILITY_TABLE_BUF * VP9_PROB_TABLE_SIZE, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(HFI_IRIS3_VP9D_COMV_SIZE, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(MAX_SUPERFRAME_HEADER_LEN, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(VP9_UDC_HEADER_BUF_SIZE, \ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(VP9_NUM_FRAME_INFO_BUF * \ + CCE_TILE_OFFSET_SIZE, VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(VP9_NUM_FRAME_INFO_BUF * VP9_FRAME_INFO_BUF_SIZE, \ + VENUS_DMA_ALIGNMENT) + HDR10_HIST_EXTRADATA_SIZE) + +#define HFI_BUFFER_LINE_MP2D(_size, frame_width, frame_height, \ +_yuv_bufcount_min, is_opb, num_vpp_pipes) \ + do { \ + HFI_U32 vpss_lb_size = 0; \ + _size = HFI_ALIGN(SIZE_VPXD_LB_FE_LEFT_CTRL(frame_width, \ + frame_height), VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_LEFT_CTRL(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_MP2D_LB_VSP_TOP(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) + HFI_ALIGN(SIZE_VPXD_LB_FE_TOP_CTRL\ + (frame_width, frame_height), VENUS_DMA_ALIGNMENT) + \ + 2 * HFI_ALIGN(SIZE_VPXD_LB_RECON_DMA_METADATA_WR(frame_width,\ + frame_height), VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_VPXD_LB_SE_TOP_CTRL(frame_width, frame_height),\ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_MP2D_LB_PE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_MP2D_LB_FE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT); \ + if (is_opb) { \ + SIZE_VPSS_LB(vpss_lb_size, frame_width, frame_height, \ + num_vpp_pipes); \ + } \ + _size += vpss_lb_size; \ + } while (0) + +#define HFI_BUFFER_BIN_MP2D(_size, frame_width, frame_height, is_interlaced) 0 + +#define QMATRIX_SIZE (sizeof(HFI_U32) * 128 + 256) +#define MP2D_QPDUMP_SIZE 115200 +#define HFI_BUFFER_PERSIST_MP2D(_size) \ + (_size = QMATRIX_SIZE + MP2D_QPDUMP_SIZE;) + +#define AV1D_LCU_MAX_SIZE_PELS 128 +#define AV1D_LCU_MIN_SIZE_PELS 64 +#define AV1D_MAX_TILE_COLS 64 + +#define HFI_BUFFER_COMV_AV1D(_size, frame_width, frame_height, \ + _comv_bufcount) \ + do { \ + _size = 2 * HFI_ALIGN(MAX(((frame_width + 63) / 64) * \ + ((frame_height + 63) / 64) * 512, \ + ((frame_width + 127) / 128) * \ + ((frame_height + 127) / 128) * 2816), \ + VENUS_DMA_ALIGNMENT); \ + _size *= _comv_bufcount; \ + } while (0) + +#define SIZE_AV1D_LB_FE_TOP_DATA(frame_width, frame_height) \ + (HFI_ALIGN(frame_width, AV1D_LCU_MAX_SIZE_PELS) * ((16 * 10) >> 3) + \ + HFI_ALIGN(frame_width, AV1D_LCU_MAX_SIZE_PELS) / 2 * ((16 * 6) >> 3) * 2) + +#define SIZE_AV1D_LB_FE_LEFT_DATA(frame_width, frame_height) \ + (32 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 16) + \ + 16 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 2 + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 8) * 2 + \ + 24 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 16) + \ + 24 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 2 + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 12) * 2 + \ + 24 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 16) + \ + 16 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 16) + \ + 16 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 2 + \ + HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS * 12) * 2) + +#define SIZE_AV1D_LB_FE_TOP_CTRL(frame_width, frame_height) \ + (10 * ((frame_width + AV1D_LCU_MIN_SIZE_PELS - 1) / \ + AV1D_LCU_MIN_SIZE_PELS) * 128 / 8) + +#define SIZE_AV1D_LB_FE_LEFT_CTRL(frame_width, frame_height) \ + (16 * ((HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / 16) + \ + (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS)) + \ + 3 * 16 * (HFI_ALIGN(frame_height, AV1D_LCU_MAX_SIZE_PELS) / \ + AV1D_LCU_MIN_SIZE_PELS)) + +#define SIZE_AV1D_LB_SE_TOP_CTRL(frame_width, frame_height) \ + (((frame_width + 7) / 8) * 16) + +#define SIZE_AV1D_LB_SE_LEFT_CTRL(frame_width, frame_height) \ + (MAX(((frame_height + 15) / 16) * MAX_SE_NBR_CTRL_LCU16_LINE_BUFFER_SIZE, \ + MAX(((frame_height + 31) / 32) * MAX_SE_NBR_CTRL_LCU32_LINE_BUFFER_SIZE, \ + ((frame_height + 63) / 64) * MAX_SE_NBR_CTRL_LCU64_LINE_BUFFER_SIZE))) + +#define SIZE_AV1D_LB_PE_TOP_DATA(frame_width, frame_height) \ + (MAX(((frame_width + 15) / 16) * MAX_PE_NBR_DATA_LCU16_LINE_BUFFER_SIZE, \ + MAX(((frame_width + 31) / 32) * MAX_PE_NBR_DATA_LCU32_LINE_BUFFER_SIZE, \ + ((frame_width + 63) / 64) * MAX_PE_NBR_DATA_LCU64_LINE_BUFFER_SIZE))) + +#define SIZE_AV1D_LB_VSP_TOP(frame_width, frame_height) \ + (MAX(((frame_width + 63) / 64) * 1280, ((frame_width + 127) / 128) * 2304)) + +#define SIZE_AV1D_LB_RECON_DMA_METADATA_WR(frame_width, frame_height) \ + ((HFI_ALIGN(frame_height, 8) / (4 / 2)) * 64) + +#define SIZE_AV1D_QP(frame_width, frame_height) \ + SIZE_H264D_QP(frame_width, frame_height) + +#define SIZE_AV1D_LB_OPB_WR1_NV12_UBWC(_size, frame_width, frame_height) \ + do { \ + HFI_U32 y_width, y_width_a = 128; \ + HFI_NV12_IL_CALC_Y_STRIDE(y_width, frame_width, y_width_a); \ + _size = (256 * ((y_width + 31) / 32 + (AV1D_MAX_TILE_COLS - 1))); \ + } while (0) + +#define SIZE_AV1D_LB_OPB_WR1_TP10_UBWC(_size, frame_width, frame_height) \ + do { \ + HFI_U32 y_width, y_width_a = 256; \ + HFI_YUV420_TP10_CALC_Y_STRIDE(y_width, frame_width, y_width_a); \ + _size = (256 * ((y_width + 47) / 48 + (AV1D_MAX_TILE_COLS - 1))); \ + } while (0) + +#define SIZE_AV1D_IBC_NV12_UBWC(_size, frame_width, frame_height) \ + do { \ + HFI_U32 y_width_a = 128, y_height_a = 32; \ + HFI_U32 uv_width_a = 128, uv_height_a = 32; \ + HFI_U32 yBufSize, uvBufSize, y_width, y_height, uv_width, uv_height; \ + HFI_U32 y_meta_width_a = 64, y_meta_height_a = 16; \ + HFI_U32 uv_meta_width_a = 64, uv_meta_height_a = 16; \ + HFI_U32 meta_height, meta_stride, meta_size; \ + HFI_U32 tile_width_y = HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH; \ + HFI_U32 tile_height_y = HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT; \ + HFI_U32 tile_width_uv = HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_WIDTH; \ + HFI_U32 tile_height_uv = \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_UV_TILE_HEIGHT; \ + HFI_NV12_IL_CALC_Y_STRIDE(y_width, frame_width, y_width_a); \ + HFI_NV12_IL_CALC_Y_BUFHEIGHT(y_height, frame_height, y_height_a); \ + HFI_NV12_IL_CALC_UV_STRIDE(uv_width, frame_width, uv_width_a); \ + HFI_NV12_IL_CALC_UV_BUFHEIGHT(uv_height, frame_height, uv_height_a); \ + HFI_NV12_UBWC_IL_CALC_Y_BUF_SIZE(yBufSize, y_width, y_height); \ + HFI_NV12_UBWC_IL_CALC_UV_BUF_SIZE(uvBufSize, uv_width, uv_height); \ + _size = yBufSize + uvBufSize; \ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(meta_stride, frame_width, \ + y_meta_width_a, tile_width_y); \ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(meta_height, frame_height, \ + y_meta_height_a, tile_height_y); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size, \ + meta_stride, meta_height); \ + _size += meta_size; \ + HFI_UBWC_UV_METADATA_PLANE_STRIDE(meta_stride, frame_width, \ + uv_meta_width_a, tile_width_uv); \ + HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(meta_height, frame_height, \ + uv_meta_height_a, tile_height_uv); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size, \ + meta_stride, meta_height); \ + _size += meta_size; \ + } while (0) + +#define SIZE_AV1D_IBC_TP10_UBWC(_size, frame_width, frame_height) \ + do { \ + HFI_U32 y_width_a = 256, y_height_a = 16, \ + uv_width_a = 256, uv_height_a = 16; \ + HFI_U32 yBufSize, uvBufSize, y_width, y_height, uv_width, uv_height; \ + HFI_U32 y_meta_width_a = 64, y_meta_height_a = 16, \ + uv_meta_width_a = 64, uv_meta_height_a = 16; \ + HFI_U32 meta_height, meta_stride, meta_size; \ + HFI_U32 tile_width_y = HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH; \ + HFI_U32 tile_height_y = HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT; \ + HFI_U32 tile_width_uv = HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_WIDTH; \ + HFI_U32 tile_height_uv = \ + HFI_COLOR_FORMAT_YUV420_TP10_UBWC_UV_TILE_HEIGHT; \ + HFI_YUV420_TP10_CALC_Y_STRIDE(y_width, frame_width, y_width_a); \ + HFI_YUV420_TP10_CALC_Y_BUFHEIGHT(y_height, frame_height, y_height_a); \ + HFI_YUV420_TP10_CALC_UV_STRIDE(uv_width, frame_width, uv_width_a); \ + HFI_YUV420_TP10_CALC_UV_BUFHEIGHT(uv_height, frame_height, \ + uv_height_a); \ + HFI_YUV420_TP10_UBWC_CALC_Y_BUF_SIZE(yBufSize, y_width, y_height); \ + HFI_YUV420_TP10_UBWC_CALC_UV_BUF_SIZE(uvBufSize, uv_width, uv_height); \ + _size = yBufSize + uvBufSize; \ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(meta_stride, frame_width, \ + y_meta_width_a, tile_width_y); \ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(meta_height, frame_height, \ + y_meta_height_a, tile_height_y); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size, \ + meta_stride, meta_height); \ + _size += meta_size; \ + HFI_UBWC_UV_METADATA_PLANE_STRIDE(meta_stride, frame_width, \ + uv_meta_width_a, tile_width_uv); \ + HFI_UBWC_UV_METADATA_PLANE_BUFHEIGHT(meta_height, frame_height, \ + uv_meta_height_a, tile_height_uv); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size, \ + meta_stride, meta_height); \ + _size += meta_size; \ + } while (0) + +#define HFI_BUFFER_LINE_AV1D(_size, frame_width, frame_height, isOPB, \ + num_vpp_pipes) \ + do { \ + HFI_U32 vpssLBSize, opbwr1BufSize, opbwr8, opbwr10; \ + _size = HFI_ALIGN(SIZE_AV1D_LB_FE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_AV1D_LB_FE_TOP_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_AV1D_LB_FE_LEFT_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_AV1D_LB_FE_LEFT_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_AV1D_LB_SE_LEFT_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes + \ + HFI_ALIGN(SIZE_AV1D_LB_SE_TOP_CTRL(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_AV1D_LB_PE_TOP_DATA(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_AV1D_LB_VSP_TOP(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT) + \ + HFI_ALIGN(SIZE_AV1D_LB_RECON_DMA_METADATA_WR(frame_width, \ + frame_height), \ + VENUS_DMA_ALIGNMENT) * 2 + \ + HFI_ALIGN(SIZE_AV1D_QP(frame_width, frame_height), \ + VENUS_DMA_ALIGNMENT); \ + SIZE_AV1D_LB_OPB_WR1_NV12_UBWC(opbwr8, frame_width, frame_height); \ + SIZE_AV1D_LB_OPB_WR1_TP10_UBWC(opbwr10, frame_width, frame_height); \ + opbwr1BufSize = MAX(opbwr8, opbwr10); \ + _size = HFI_ALIGN((_size + opbwr1BufSize), VENUS_DMA_ALIGNMENT); \ + if (isOPB) { \ + SIZE_VPSS_LB(vpssLBSize, frame_width, frame_height, num_vpp_pipes); \ + _size = HFI_ALIGN((_size + vpssLBSize), VENUS_DMA_ALIGNMENT); \ + } \ + } while (0) + +#define HFI_BUFFER_IBC_AV1D(_size, frame_width, frame_height) \ + do { \ + HFI_U32 ibc8, ibc10; \ + SIZE_AV1D_IBC_NV12_UBWC(ibc8, frame_width, frame_height); \ + SIZE_AV1D_IBC_TP10_UBWC(ibc10, frame_width, frame_height); \ + _size = HFI_ALIGN(MAX(ibc8, ibc10), VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define AV1_CABAC_HDR_RATIO_HD_TOT 2 +#define AV1_CABAC_RES_RATIO_HD_TOT 2 +/* some content need more bin buffer, + * but limit buffer size for high resolution + */ +#define SIZE_AV1D_HW_BIN_BUFFER(_size, frame_width, frame_height, delay, \ + num_vpp_pipes) \ + do { \ + HFI_U32 size_yuv, size_bin_hdr, size_bin_res; \ + size_yuv = ((frame_width * frame_height) <= BIN_BUFFER_THRESHOLD) ? \ + ((BIN_BUFFER_THRESHOLD * 3) >> 1) : \ + ((frame_width * frame_height * 3) >> 1); \ + size_bin_hdr = size_yuv * AV1_CABAC_HDR_RATIO_HD_TOT; \ + size_bin_res = size_yuv * AV1_CABAC_RES_RATIO_HD_TOT; \ + size_bin_hdr = size_bin_hdr * \ + (((((HFI_U32)(delay)) & 31) / 10) + 2) / 2; \ + size_bin_res = size_bin_res * \ + (((((HFI_U32)(delay)) & 31) / 10) + 2) / 2; \ + size_bin_hdr = HFI_ALIGN(size_bin_hdr / num_vpp_pipes, \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + size_bin_res = HFI_ALIGN(size_bin_res / num_vpp_pipes, \ + VENUS_DMA_ALIGNMENT) * num_vpp_pipes; \ + _size = size_bin_hdr + size_bin_res; \ + } while (0) + +#define HFI_BUFFER_BIN_AV1D(_size, frame_width, frame_height, isInterlaced, \ + delay, num_vpp_pipes) \ + do { \ + HFI_U32 nAlignedW = HFI_ALIGN(frame_width, BUFFER_ALIGNMENT_16_BYTES); \ + HFI_U32 nAlignedH = HFI_ALIGN(frame_height, BUFFER_ALIGNMENT_16_BYTES); \ + if (!isInterlaced) { \ + SIZE_AV1D_HW_BIN_BUFFER(_size, nAlignedW, nAlignedH, \ + delay, num_vpp_pipes); \ + } else { \ + _size = 0; \ + } \ + } while (0) + +#define AV1D_NUM_HW_PIC_BUF 16 +#define AV1D_NUM_FRAME_HEADERS 16 + +#define SIZE_AV1D_SEQUENCE_HEADER 768 +#define SIZE_AV1D_METADATA 512 +#define SIZE_AV1D_FRAME_HEADER 1280 +#define SIZE_AV1D_TILE_OFFSET 65536 +#define SIZE_AV1D_QM 3328 +#define SIZE_AV1D_PROB_TABLE 22784 + +#define AV1D_SIZE_BSE_COL_MV_64x64 512 +#define AV1D_SIZE_BSE_COL_MV_128x128 2816 +#define SIZE_AV1D_COL_MV MAX((((8192 + 63) / 64) * ((4352 + 63) / 64) * \ + AV1D_SIZE_BSE_COL_MV_64x64), \ + (((8192 + 127) / 128) * ((4352 + 127) / 128) * \ + AV1D_SIZE_BSE_COL_MV_128x128)) + +#define HFI_BUFFER_PERSIST_AV1D(_size, max_width, max_height, total_ref_count) \ + do { \ + HFI_U32 comv_size; \ + HFI_BUFFER_COMV_AV1D(comv_size, max_width, max_height, total_ref_count); \ + _size = \ + HFI_ALIGN((SIZE_AV1D_SEQUENCE_HEADER * 2 + \ + SIZE_AV1D_METADATA + \ + AV1D_NUM_HW_PIC_BUF * (SIZE_AV1D_TILE_OFFSET + SIZE_AV1D_QM) + \ + AV1D_NUM_FRAME_HEADERS * (SIZE_AV1D_FRAME_HEADER + \ + 2 * SIZE_AV1D_PROB_TABLE) + \ + comv_size + HDR10_HIST_EXTRADATA_SIZE + \ + SIZE_AV1D_METADATA * AV1D_NUM_HW_PIC_BUF), VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define HFI_BUFFER_BITSTREAM_ENC(size, frame_width, frame_height, \ + rc_type, is_ten_bit) \ + do { \ + HFI_U32 aligned_width, aligned_height, bitstream_size, yuv_size; \ + aligned_width = HFI_ALIGN(frame_width, 32); \ + aligned_height = HFI_ALIGN(frame_height, 32); \ + bitstream_size = aligned_width * aligned_height * 3; \ + yuv_size = (aligned_width * aligned_height * 3) >> 1; \ + if (aligned_width * aligned_height > (4096 * 2176)) { \ + /* bitstream_size = 0.25 * yuv_size; */ \ + bitstream_size = (bitstream_size >> 3); \ + } \ + else if (aligned_width * aligned_height > (1280 * 720)) { \ + /* bitstream_size = 0.5 * yuv_size; */ \ + bitstream_size = (bitstream_size >> 2); \ + } else { \ + /* bitstream_size = 2 * yuv_size; */ \ + } \ + if (((rc_type == HFI_RC_CQ) || (rc_type == HFI_RC_OFF)) \ + && (bitstream_size < yuv_size)) { \ + bitstream_size = (bitstream_size << 1);\ + } \ + if (is_ten_bit) { \ + bitstream_size = (bitstream_size) + \ + (bitstream_size >> 2); \ + } \ + size = HFI_ALIGN(bitstream_size, HFI_ALIGNMENT_4096); \ + } while (0) + +#define HFI_IRIS3_ENC_TILE_SIZE_INFO(tile_size, tile_count, last_tile_size, \ + frame_width_coded, codec_standard, num_vpp_pipes) \ + do { \ + HFI_U32 without_tile_enc_width, min_tile_size, fixed_tile_width; \ + if (num_vpp_pipes == 4) { \ + min_tile_size = 352; \ + fixed_tile_width = 960; \ + } \ + else if (num_vpp_pipes == 2) { \ + min_tile_size = 256; \ + fixed_tile_width = 768; \ + } \ + else { \ + min_tile_size = 256; \ + fixed_tile_width = 672; \ + } \ + without_tile_enc_width = min_tile_size + fixed_tile_width; \ + if ((codec_standard == HFI_CODEC_ENCODE_HEVC) && \ + (frame_width_coded > without_tile_enc_width)) { \ + tile_size = fixed_tile_width; \ + tile_count = (frame_width_coded + tile_size - 1) / tile_size; \ + last_tile_size = (frame_width_coded - (tile_size * (tile_count - 1))); \ + if (last_tile_size < min_tile_size) { \ + tile_count -= 1; \ + last_tile_size = (tile_size + min_tile_size); \ + } \ + } else { \ + tile_size = frame_width_coded; \ + tile_count = 1; \ + last_tile_size = 0; \ + } \ + } while (0) + +#define HFI_IRIS3_ENC_MB_BASED_MULTI_SLICE_COUNT(total_slice_count, frame_width, frame_height, \ + codec_standard, multi_slice_max_mb_count, num_vpp_pipes) \ + do { \ + HFI_U32 tile_size, tile_count, last_tile_size, \ + slice_count_per_tile, slice_count_in_last_tile; \ + HFI_U32 mbs_in_one_tile, mbs_in_last_tile; \ + HFI_U32 frame_width_coded, frame_height_coded, lcu_size; \ + lcu_size = (codec_standard == HFI_CODEC_ENCODE_HEVC) ? 32 : 16; \ + frame_width_coded = HFI_ALIGN(frame_width, lcu_size); \ + frame_height_coded = HFI_ALIGN(frame_height, lcu_size); \ + HFI_IRIS3_ENC_TILE_SIZE_INFO(tile_size, tile_count, last_tile_size, \ + frame_width_coded, codec_standard, num_vpp_pipes); \ + mbs_in_one_tile = (tile_size * frame_height_coded) / (lcu_size * lcu_size); \ + slice_count_per_tile = \ + (mbs_in_one_tile + multi_slice_max_mb_count - 1) / \ + (multi_slice_max_mb_count); \ + if (last_tile_size) { \ + mbs_in_last_tile = \ + (last_tile_size * frame_height_coded) / (lcu_size * lcu_size); \ + slice_count_in_last_tile = \ + (mbs_in_last_tile + multi_slice_max_mb_count - 1) / \ + (multi_slice_max_mb_count); \ + total_slice_count = \ + (slice_count_per_tile * (tile_count - 1)) + \ + slice_count_in_last_tile; \ + } else { \ + total_slice_count = (slice_count_per_tile * tile_count); \ + } \ + } while (0) + +#define SIZE_ROI_METADATA_ENC(size_roi, frame_width, frame_height, lcu_size)\ + do { \ + HFI_U32 width_in_lcus = 0, height_in_lcus = 0, n_shift = 0; \ + HFI_U32 n_lcu_size = lcu_size; \ + while (n_lcu_size && !(n_lcu_size & 0x1)) { \ + n_shift++; \ + n_lcu_size = n_lcu_size >> 1; \ + } \ + width_in_lcus = (frame_width + (lcu_size - 1)) >> n_shift; \ + height_in_lcus = (frame_height + (lcu_size - 1)) >> n_shift; \ + size_roi = (((width_in_lcus + 7) >> 3) << 3) * \ + height_in_lcus * 2 + 256; \ + } while (0) + +#define HFI_BUFFER_INPUT_METADATA_ENC(size, frame_width, frame_height, \ + is_roi_enabled, lcu_size) \ + do { \ + HFI_U32 roi_size = 0; \ + if (is_roi_enabled) { \ + SIZE_ROI_METADATA_ENC(roi_size, frame_width, \ + frame_height, lcu_size); \ + } \ + size = roi_size + 16384; \ + size = HFI_ALIGN(size, HFI_ALIGNMENT_4096); \ + } while (0) + +#define HFI_BUFFER_INPUT_METADATA_H264E(size_metadata, frame_width, \ + frame_height, is_roi_enabled) \ + do { \ + HFI_BUFFER_INPUT_METADATA_ENC(size_metadata, frame_width, \ + frame_height, is_roi_enabled, 16); \ + } while (0) + +#define HFI_BUFFER_INPUT_METADATA_H265E(size_metadata, frame_width, \ + frame_height, is_roi_enabled) \ + do { \ + HFI_BUFFER_INPUT_METADATA_ENC(size_metadata, frame_width, \ + frame_height, is_roi_enabled, 32); \ + } while (0) + +#define HFI_BUFFER_ARP_ENC(size) \ + do { \ + size = 204800; \ + } while (0) + +#define HFI_MAX_COL_FRAME 6 +#define HFI_VENUS_VENC_TRE_WB_BUFF_SIZE (65 << 4) // bytes +#define HFI_VENUS_VENC_DB_LINE_BUFF_PER_MB 512 +#define HFI_VENUS_VPPSG_MAX_REGISTERS 2048 +#define HFI_VENUS_WIDTH_ALIGNMENT 128 +#define HFI_VENUS_WIDTH_TEN_BIT_ALIGNMENT 192 +#define HFI_VENUS_HEIGHT_ALIGNMENT 32 +#define VENUS_METADATA_STRIDE_MULTIPLE 64 +#define VENUS_METADATA_HEIGHT_MULTIPLE 16 + +#ifndef SYSTEM_LAL_TILE10 +#define SYSTEM_LAL_TILE10 192 +#endif + +#define HFI_IRIS3_ENC_RECON_BUF_COUNT(num_recon, n_bframe, ltr_count, \ + _total_hp_layers, _total_hb_layers, hybrid_hp, codec_standard) \ + do { \ + HFI_U32 num_ref = 1; \ + if (n_bframe) \ + num_ref = 2; \ + if (_total_hp_layers > 1) { \ + if (hybrid_hp) \ + num_ref = (_total_hp_layers + 1) >> 1; \ + else if (codec_standard == HFI_CODEC_ENCODE_HEVC) \ + num_ref = (_total_hp_layers + 1) >> 1; \ + else if (codec_standard == HFI_CODEC_ENCODE_AVC && \ + _total_hp_layers < 4) \ + num_ref = (_total_hp_layers - 1); \ + else \ + num_ref = _total_hp_layers; \ + } \ + if (ltr_count) \ + num_ref = num_ref + ltr_count; \ + if (_total_hb_layers > 1) { \ + if (codec_standard == HFI_CODEC_ENCODE_HEVC) \ + num_ref = (_total_hb_layers); \ + else if (codec_standard == HFI_CODEC_ENCODE_AVC) \ + num_ref = (1 << (_total_hb_layers - 2)) + 1; \ + } \ + num_recon = num_ref + 1; \ + } while (0) + +#define SIZE_BIN_BITSTREAM_ENC(_size, rc_type, frame_width, frame_height, \ + work_mode, lcu_size, profile) \ + do { \ + HFI_U32 size_aligned_width = 0, size_aligned_height = 0; \ + HFI_U32 bitstream_size_eval = 0; \ + size_aligned_width = HFI_ALIGN((frame_width), lcu_size); \ + size_aligned_height = HFI_ALIGN((frame_height), lcu_size); \ + if (work_mode == HFI_WORKMODE_2) { \ + if ((rc_type == HFI_RC_CQ) || (rc_type == HFI_RC_OFF)) { \ + bitstream_size_eval = (((size_aligned_width) * \ + (size_aligned_height) * 3) >> 1); \ + } \ + else { \ + bitstream_size_eval = ((size_aligned_width) * \ + (size_aligned_height) * 3); \ + if (rc_type == HFI_RC_LOSSLESS) { \ + bitstream_size_eval = (bitstream_size_eval * 3 >> 2); \ + } \ + else if ((size_aligned_width * size_aligned_height) > \ + (4096 * 2176)) { \ + bitstream_size_eval >>= 3; \ + } \ + else if ((size_aligned_width * size_aligned_height) > \ + (480 * 320)) { \ + bitstream_size_eval >>= 2; \ + } \ + if (profile == HFI_H265_PROFILE_MAIN_10 || \ + profile == HFI_H265_PROFILE_MAIN_10_STILL_PICTURE) { \ + bitstream_size_eval = (bitstream_size_eval * 5 >> 2); \ + } \ + } \ + } else { \ + bitstream_size_eval = size_aligned_width * \ + size_aligned_height * 3; \ + } \ + _size = HFI_ALIGN(bitstream_size_eval, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_ENC_SINGLE_PIPE(size, rc_type, bitbin_size, num_vpp_pipes, \ + frame_width, frame_height, lcu_size) \ + do { \ + HFI_U32 size_single_pipe_eval = 0, sao_bin_buffer_size = 0, \ + _padded_bin_sz = 0; \ + HFI_U32 size_aligned_width = 0, size_aligned_height = 0; \ + size_aligned_width = HFI_ALIGN((frame_width), lcu_size); \ + size_aligned_height = HFI_ALIGN((frame_height), lcu_size); \ + if ((size_aligned_width * size_aligned_height) > \ + (3840 * 2160)) { \ + size_single_pipe_eval = (bitbin_size / num_vpp_pipes); \ + } \ + else if (num_vpp_pipes > 2) { \ + size_single_pipe_eval = bitbin_size / 2; \ + } else { \ + size_single_pipe_eval = bitbin_size; \ + } \ + if (rc_type == HFI_RC_LOSSLESS) { \ + size_single_pipe_eval = (size_single_pipe_eval << 1); \ + } \ + sao_bin_buffer_size = (64 * ((((frame_width) + \ + BUFFER_ALIGNMENT_32_BYTES) * ((frame_height) +\ + BUFFER_ALIGNMENT_32_BYTES)) >> 10)) + 384; \ + _padded_bin_sz = HFI_ALIGN(size_single_pipe_eval, \ + VENUS_DMA_ALIGNMENT);\ + size_single_pipe_eval = sao_bin_buffer_size + _padded_bin_sz; \ + size_single_pipe_eval = HFI_ALIGN(size_single_pipe_eval, \ + VENUS_DMA_ALIGNMENT); \ + size = size_single_pipe_eval; \ + } while (0) + +#define HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, lcu_size, \ + work_mode, num_vpp_pipes, profile, ring_buf_count) \ + do { \ + HFI_U32 bitstream_size = 0, total_bitbin_buffers = 0, \ + size_single_pipe = 0, bitbin_size = 0; \ + SIZE_BIN_BITSTREAM_ENC(bitstream_size, rc_type, frame_width, \ + frame_height, work_mode, lcu_size, profile); \ + if (work_mode == HFI_WORKMODE_2) { \ + total_bitbin_buffers = (ring_buf_count > 3) ? ring_buf_count : 3; \ + bitbin_size = bitstream_size * 17 / 10; \ + bitbin_size = HFI_ALIGN(bitbin_size, \ + VENUS_DMA_ALIGNMENT); \ + } \ + else if ((lcu_size == 16) || (num_vpp_pipes > 1)) { \ + total_bitbin_buffers = 1; \ + bitbin_size = bitstream_size; \ + } \ + if (total_bitbin_buffers > 0) { \ + SIZE_ENC_SINGLE_PIPE(size_single_pipe, rc_type, bitbin_size, \ + num_vpp_pipes, frame_width, frame_height, lcu_size); \ + bitbin_size = size_single_pipe * num_vpp_pipes; \ + _size = HFI_ALIGN(bitbin_size, VENUS_DMA_ALIGNMENT) * \ + total_bitbin_buffers + 512; \ + } \ + else \ + /* Avoid 512 Bytes allocation in case of 1Pipe HEVC Direct Mode*/ \ + _size = 0; \ + } while (0) + +#define HFI_BUFFER_BIN_H264E(_size, rc_type, frame_width, frame_height, \ + work_mode, num_vpp_pipes, profile, ring_buf_count) \ + do { \ + HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, 16, \ + work_mode, num_vpp_pipes, profile, ring_buf_count); \ + } while (0) + +#define HFI_BUFFER_BIN_H265E(_size, rc_type, frame_width, frame_height, \ + work_mode, num_vpp_pipes, profile, ring_buf_count) \ + do { \ + HFI_BUFFER_BIN_ENC(_size, rc_type, frame_width, frame_height, 32,\ + work_mode, num_vpp_pipes, profile, ring_buf_count); \ + } while (0) + +#define SIZE_ENC_SLICE_INFO_BUF(num_lcu_in_frame) HFI_ALIGN((256 + \ + (num_lcu_in_frame << 4)), VENUS_DMA_ALIGNMENT) +#define SIZE_LINE_BUF_CTRL(frame_width_coded) \ + HFI_ALIGN(frame_width_coded, VENUS_DMA_ALIGNMENT) +#define SIZE_LINE_BUF_CTRL_ID2(frame_width_coded) \ + HFI_ALIGN(frame_width_coded, VENUS_DMA_ALIGNMENT) + +#define SIZE_LINEBUFF_DATA(_size, is_ten_bit, frame_width_coded) \ + do { \ + _size = is_ten_bit ? (((((10 * (frame_width_coded) +\ + 1024) + (VENUS_DMA_ALIGNMENT - 1)) & \ + (~(VENUS_DMA_ALIGNMENT - 1))) * 1) + \ + (((((10 * (frame_width_coded) + 1024) >> 1) + \ + (VENUS_DMA_ALIGNMENT - 1)) & (~(VENUS_DMA_ALIGNMENT - 1))) * \ + 2)) : (((((8 * (frame_width_coded) + 1024) + \ + (VENUS_DMA_ALIGNMENT - 1)) \ + & (~(VENUS_DMA_ALIGNMENT - 1))) * 1) + \ + (((((8 * (frame_width_coded) +\ + 1024) >> 1) + (VENUS_DMA_ALIGNMENT - 1)) & \ + (~(VENUS_DMA_ALIGNMENT - 1))) * 2)); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_CTRL(_size, standard, frame_height_coded, \ + num_vpp_pipes_enc) \ + do { \ + _size = (standard == HFI_CODEC_ENCODE_HEVC) ? \ + (((frame_height_coded) + \ + (BUF_SIZE_ALIGN_32)) / BUF_SIZE_ALIGN_32 * 4 * 16) : \ + (((frame_height_coded) + 15) / 16 * 5 * 16); \ + if ((num_vpp_pipes_enc) > 1) { \ + _size += BUFFER_ALIGNMENT_512_BYTES; \ + _size = HFI_ALIGN(_size, BUFFER_ALIGNMENT_512_BYTES) *\ + (num_vpp_pipes_enc); \ + } \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_RECON_PIX(_size, is_ten_bit, frame_height_coded, \ + num_vpp_pipes_enc) \ + do { \ + _size = (((is_ten_bit + 1) * 2 * (frame_height_coded) + \ + VENUS_DMA_ALIGNMENT) + \ + (VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1) & \ + (~((VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1)) * 1; \ + } while (0) + +#define SIZE_TOP_LINEBUFF_CTRL_FE(_size, frame_width_coded, standard) \ + do { \ + _size = (standard == HFI_CODEC_ENCODE_HEVC) ? (64 * \ + ((frame_width_coded) >> 5)) : (VENUS_DMA_ALIGNMENT + 16 * \ + ((frame_width_coded) >> 4)); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_CTRL_FE(frame_height_coded, num_vpp_pipes_enc) \ + ((((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) >> 4)) + \ + (VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1) & \ + (~((VENUS_DMA_ALIGNMENT << (num_vpp_pipes_enc - 1)) - 1)) * 1) * \ + num_vpp_pipes_enc) + +#define SIZE_LEFT_LINEBUFF_METADATA_RECON_Y(_size, frame_height_coded, \ + is_ten_bit, num_vpp_pipes_enc) \ + do { \ + _size = ((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) / \ + (8 * (is_ten_bit ? 4 : 8))))); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + _size = (_size * num_vpp_pipes_enc); \ + } while (0) + +#define SIZE_LEFT_LINEBUFF_METADATA_RECON_UV(_size, frame_height_coded, \ + is_ten_bit, num_vpp_pipes_enc) \ + do { \ + _size = ((VENUS_DMA_ALIGNMENT + 64 * ((frame_height_coded) / \ + (4 * (is_ten_bit ? 4 : 8))))); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + _size = (_size * num_vpp_pipes_enc); \ + } while (0) + +#define SIZE_LINEBUFF_RECON_PIX(_size, is_ten_bit, frame_width_coded) \ + do { \ + _size = ((is_ten_bit ? 3 : 2) * (frame_width_coded)); \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT); \ + } while (0) + +#define SIZE_SLICE_CMD_BUFFER (HFI_ALIGN(20480, VENUS_DMA_ALIGNMENT)) +#define SIZE_SPS_PPS_SLICE_HDR (2048 + 4096) + +#define SIZE_FRAME_RC_BUF_SIZE(_size, standard, frame_height_coded, \ + num_vpp_pipes_enc) \ + do { \ + _size = (standard == HFI_CODEC_ENCODE_HEVC) ? (256 + 16 * \ + (14 + ((((frame_height_coded) >> 5) + 7) >> 3))) : \ + (256 + 16 * (14 + ((((frame_height_coded) >> 4) + 7) >> 3))); \ + _size *= 11; \ + if (num_vpp_pipes_enc > 1) { \ + _size = HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT) * \ + num_vpp_pipes_enc;\ + } \ + _size = HFI_ALIGN(_size, BUFFER_ALIGNMENT_512_BYTES) * \ + HFI_MAX_COL_FRAME; \ + } while (0) + +#define ENC_BITCNT_BUF_SIZE(num_lcu_in_frame) HFI_ALIGN((256 + \ + (4 * (num_lcu_in_frame))), VENUS_DMA_ALIGNMENT) +#define ENC_BITMAP_BUF_SIZE(num_lcu_in_frame) HFI_ALIGN((256 + \ + ((num_lcu_in_frame) >> 3)), VENUS_DMA_ALIGNMENT) +#define SIZE_LINE_BUF_SDE(frame_width_coded) HFI_ALIGN((256 + \ + (16 * ((frame_width_coded) >> 4))), VENUS_DMA_ALIGNMENT) + +#define SIZE_BSE_SLICE_CMD_BUF ((((8192 << 2) + 7) & (~7)) * 3) + +#define SIZE_LAMBDA_LUT (256 * 11) +#define SIZE_OVERRIDE_BUF(num_lcumb) (HFI_ALIGN(((16 * (((num_lcumb) + 7)\ + >> 3))), VENUS_DMA_ALIGNMENT) * 2) +#define SIZE_IR_BUF(num_lcu_in_frame) HFI_ALIGN((((((num_lcu_in_frame) << 1) + 7) &\ + (~7)) * 3), VENUS_DMA_ALIGNMENT) + +#define SIZE_VPSS_LINE_BUF(_size, num_vpp_pipes_enc, frame_height_coded, \ + frame_width_coded) \ + do { \ + HFI_U32 vpss_4tap_top = 0, vpss_4tap_left = 0, vpss_div2_top = 0, \ + vpss_div2_left = 0, vpss_top_lb = 0, vpss_left_lb = 0, \ + size_left = 0, size_top = 0, color_comp = 2; \ + vpss_4tap_top = (((((MAX((frame_width_coded), (frame_height_coded)) \ + * 2) + 3) >> 2) << 4) + 256); \ + vpss_4tap_left = ((((8192 + 3) >> 2) << 5) + 64);\ + vpss_div2_top = ((((MAX((frame_width_coded), (frame_height_coded)) \ + + 3) >> 2) << 4) + 256); \ + vpss_div2_left = (((((MAX((frame_width_coded), (frame_height_coded)) \ + * 2) + 3) >> 2) << 5) + 64); \ + vpss_top_lb = (((frame_width_coded) + 1) << 3); \ + vpss_left_lb = (((frame_height_coded) << 3) * (num_vpp_pipes_enc)); \ + size_left = (((vpss_4tap_left) + (vpss_div2_left)) * (color_comp) \ + * (num_vpp_pipes_enc)); \ + size_top = (((vpss_4tap_top) + (vpss_div2_top)) * (color_comp)); \ + _size = ((size_left) + (size_top) + (vpss_top_lb) + (vpss_left_lb)); \ + _size = (HFI_ALIGN(_size, VENUS_DMA_ALIGNMENT)); \ + } while (0) + +#define SIZE_TOP_LINE_BUF_FIRST_STG_SAO(frame_width_coded) \ + HFI_ALIGN((16 * ((frame_width_coded) >> 5)), VENUS_DMA_ALIGNMENT) + +#define HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, is_ten_bit, \ + num_vpp_pipes_enc, lcu_size, standard) \ + do { \ + HFI_U32 width_in_lcus = 0, height_in_lcus = 0, \ + frame_width_coded = 0, frame_height_coded = 0; \ + HFI_U32 line_buff_data_size = 0, left_line_buff_ctrl_size = 0, \ + left_line_buff_recon_pix_size = 0, \ + top_line_buff_ctrl_fe_size = 0; \ + HFI_U32 left_line_buff_metadata_recon__y__size = 0, \ + left_line_buff_metadata_recon__uv__size = 0, \ + line_buff_recon_pix_size = 0, vpss_line_buff_size = 0; \ + width_in_lcus = ((frame_width) + (lcu_size)-1) / (lcu_size); \ + height_in_lcus = ((frame_height) + (lcu_size)-1) / (lcu_size); \ + frame_width_coded = width_in_lcus * (lcu_size); \ + frame_height_coded = height_in_lcus * (lcu_size); \ + SIZE_LINEBUFF_DATA(line_buff_data_size, is_ten_bit, \ + frame_width_coded);\ + SIZE_LEFT_LINEBUFF_CTRL(left_line_buff_ctrl_size, standard, \ + frame_height_coded, num_vpp_pipes_enc); \ + SIZE_LEFT_LINEBUFF_RECON_PIX(left_line_buff_recon_pix_size, \ + is_ten_bit, frame_height_coded, num_vpp_pipes_enc); \ + SIZE_TOP_LINEBUFF_CTRL_FE(top_line_buff_ctrl_fe_size, \ + frame_width_coded, standard); \ + SIZE_LEFT_LINEBUFF_METADATA_RECON_Y\ + (left_line_buff_metadata_recon__y__size, \ + frame_height_coded, is_ten_bit, num_vpp_pipes_enc); \ + SIZE_LEFT_LINEBUFF_METADATA_RECON_UV\ + (left_line_buff_metadata_recon__uv__size, \ + frame_height_coded, is_ten_bit, num_vpp_pipes_enc); \ + SIZE_LINEBUFF_RECON_PIX(line_buff_recon_pix_size, is_ten_bit,\ + frame_width_coded); \ + SIZE_VPSS_LINE_BUF(vpss_line_buff_size, num_vpp_pipes_enc, \ + frame_height_coded, frame_width_coded); \ + _size = SIZE_LINE_BUF_CTRL(frame_width_coded) + \ + SIZE_LINE_BUF_CTRL_ID2(frame_width_coded) + \ + line_buff_data_size + \ + left_line_buff_ctrl_size + \ + left_line_buff_recon_pix_size + \ + top_line_buff_ctrl_fe_size + \ + left_line_buff_metadata_recon__y__size + \ + left_line_buff_metadata_recon__uv__size + \ + line_buff_recon_pix_size + \ + vpss_line_buff_size + \ + SIZE_LEFT_LINEBUFF_CTRL_FE(frame_height_coded, \ + num_vpp_pipes_enc) + SIZE_LINE_BUF_SDE(frame_width_coded) + \ + SIZE_TOP_LINE_BUF_FIRST_STG_SAO(frame_width_coded); \ + } while (0) + +#define HFI_BUFFER_LINE_H264E(_size, frame_width, frame_height, is_ten_bit, \ + num_vpp_pipes) \ + do { \ + HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, 0, \ + num_vpp_pipes, 16, HFI_CODEC_ENCODE_AVC); \ + } while (0) + +#define HFI_BUFFER_LINE_H265E(_size, frame_width, frame_height, is_ten_bit, \ + num_vpp_pipes) \ + do { \ + HFI_BUFFER_LINE_ENC(_size, frame_width, frame_height, \ + is_ten_bit, num_vpp_pipes, 32, HFI_CODEC_ENCODE_HEVC); \ + } while (0) + +#define HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, lcu_size, \ + num_recon, standard) \ + do { \ + HFI_U32 size_colloc_mv = 0, size_colloc_rc = 0; \ + HFI_U32 mb_width = ((frame_width) + 15) >> 4; \ + HFI_U32 mb_height = ((frame_height) + 15) >> 4; \ + HFI_U32 width_in_lcus = ((frame_width) + (lcu_size)-1) /\ + (lcu_size); \ + HFI_U32 height_in_lcus = ((frame_height) + (lcu_size)-1) / \ + (lcu_size); \ + HFI_U32 num_lcu_in_frame = width_in_lcus * height_in_lcus; \ + size_colloc_mv = (standard == HFI_CODEC_ENCODE_HEVC) ? \ + (16 * ((num_lcu_in_frame << 2) + BUFFER_ALIGNMENT_32_BYTES)) : \ + (3 * 16 * (width_in_lcus * height_in_lcus +\ + BUFFER_ALIGNMENT_32_BYTES)); \ + size_colloc_mv = HFI_ALIGN(size_colloc_mv, \ + VENUS_DMA_ALIGNMENT) * num_recon; \ + size_colloc_rc = (((mb_width + 7) >> 3) * 16 * 2 * mb_height); \ + size_colloc_rc = HFI_ALIGN(size_colloc_rc, \ + VENUS_DMA_ALIGNMENT) * HFI_MAX_COL_FRAME; \ + _size = size_colloc_mv + size_colloc_rc; \ + } while (0) + +#define HFI_BUFFER_COMV_H264E(_size, frame_width, frame_height, num_recon) \ + do { \ + HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, 16, \ + num_recon, HFI_CODEC_ENCODE_AVC); \ + } while (0) + +#define HFI_BUFFER_COMV_H265E(_size, frame_width, frame_height, num_recon) \ + do { \ + HFI_BUFFER_COMV_ENC(_size, frame_width, frame_height, 32,\ + num_recon, HFI_CODEC_ENCODE_HEVC); \ + } while (0) + +#define HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \ + num_vpp_pipes_enc, lcu_size, standard) \ + do { \ + HFI_U32 width_in_lcus = 0, height_in_lcus = 0, \ + frame_width_coded = 0, frame_height_coded = 0, \ + num_lcu_in_frame = 0, num_lcumb = 0; \ + HFI_U32 frame_rc_buf_size = 0; \ + width_in_lcus = ((frame_width) + (lcu_size)-1) / (lcu_size); \ + height_in_lcus = ((frame_height) + (lcu_size)-1) / (lcu_size); \ + num_lcu_in_frame = width_in_lcus * height_in_lcus; \ + frame_width_coded = width_in_lcus * (lcu_size); \ + frame_height_coded = height_in_lcus * (lcu_size); \ + num_lcumb = (frame_height_coded / lcu_size) * \ + ((frame_width_coded + lcu_size * 8) / lcu_size); \ + SIZE_FRAME_RC_BUF_SIZE(frame_rc_buf_size, standard, \ + frame_height_coded, num_vpp_pipes_enc); \ + _size = SIZE_ENC_SLICE_INFO_BUF(num_lcu_in_frame) + \ + SIZE_SLICE_CMD_BUFFER + \ + SIZE_SPS_PPS_SLICE_HDR + \ + frame_rc_buf_size + \ + ENC_BITCNT_BUF_SIZE(num_lcu_in_frame) + \ + ENC_BITMAP_BUF_SIZE(num_lcu_in_frame) + \ + SIZE_BSE_SLICE_CMD_BUF + \ + SIZE_LAMBDA_LUT + \ + SIZE_OVERRIDE_BUF(num_lcumb) + \ + SIZE_IR_BUF(num_lcu_in_frame); \ + } while (0) + +#define HFI_BUFFER_NON_COMV_H264E(_size, frame_width, frame_height, \ + num_vpp_pipes_enc) \ + do { \ + HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \ + num_vpp_pipes_enc, 16, HFI_CODEC_ENCODE_AVC); \ + } while (0) + +#define SIZE_ONE_SLICE_BUF 256 +#define HFI_BUFFER_NON_COMV_H265E(_size, frame_width, frame_height, \ + num_vpp_pipes_enc) \ + do { \ + HFI_BUFFER_NON_COMV_ENC(_size, frame_width, frame_height, \ + num_vpp_pipes_enc, 32, HFI_CODEC_ENCODE_HEVC); \ + _size += SIZE_ONE_SLICE_BUF; \ + } while (0) + +#define SIZE_ENC_REF_BUFFER(size, frame_width, frame_height) \ + do { \ + HFI_U32 u_buffer_width = 0, u_buffer_height = 0, \ + u_chroma_buffer_height = 0; \ + u_buffer_height = HFI_ALIGN(frame_height, \ + HFI_VENUS_HEIGHT_ALIGNMENT); \ + u_chroma_buffer_height = frame_height >> 1; \ + u_chroma_buffer_height = HFI_ALIGN(u_chroma_buffer_height, \ + HFI_VENUS_HEIGHT_ALIGNMENT); \ + u_buffer_width = HFI_ALIGN(frame_width, \ + HFI_VENUS_WIDTH_ALIGNMENT); \ + size = (u_buffer_height + u_chroma_buffer_height) * \ + u_buffer_width; \ + } while (0) + +#define SIZE_ENC_TEN_BIT_REF_BUFFER(size, frame_width, frame_height) \ + do { \ + HFI_U32 ref_buf_height = 0, ref_luma_stride_in_bytes = 0, \ + u_ref_stride = 0, luma_size = 0, ref_chrm_height_in_bytes = 0, \ + chroma_size = 0, ref_buf_size = 0; \ + ref_buf_height = (frame_height + \ + (HFI_VENUS_HEIGHT_ALIGNMENT - 1)) \ + & (~(HFI_VENUS_HEIGHT_ALIGNMENT - 1)); \ + ref_luma_stride_in_bytes = ((frame_width + \ + SYSTEM_LAL_TILE10 - 1) / SYSTEM_LAL_TILE10) * \ + SYSTEM_LAL_TILE10; \ + u_ref_stride = 4 * (ref_luma_stride_in_bytes / 3); \ + u_ref_stride = (u_ref_stride + (BUF_SIZE_ALIGN_128 - 1)) &\ + (~(BUF_SIZE_ALIGN_128 - 1)); \ + luma_size = ref_buf_height * u_ref_stride; \ + ref_chrm_height_in_bytes = (((frame_height + 1) >> 1) + \ + (BUF_SIZE_ALIGN_32 - 1)) & (~(BUF_SIZE_ALIGN_32 - 1)); \ + chroma_size = u_ref_stride * ref_chrm_height_in_bytes; \ + luma_size = (luma_size + (BUF_SIZE_ALIGN_4096 - 1)) & \ + (~(BUF_SIZE_ALIGN_4096 - 1)); \ + chroma_size = (chroma_size + (BUF_SIZE_ALIGN_4096 - 1)) & \ + (~(BUF_SIZE_ALIGN_4096 - 1)); \ + ref_buf_size = luma_size + chroma_size; \ + size = ref_buf_size; \ + } while (0) + +#define HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, is_ten_bit) \ + do { \ + HFI_U32 metadata_stride, metadata_buf_height, meta_size_y, \ + meta_size_c; \ + HFI_U32 ten_bit_ref_buf_size = 0, ref_buf_size = 0; \ + if (!is_ten_bit) { \ + SIZE_ENC_REF_BUFFER(ref_buf_size, frame_width, \ + frame_height); \ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, \ + (frame_width), 64, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_WIDTH); \ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, \ + (frame_height), 16, \ + HFI_COLOR_FORMAT_YUV420_NV12_UBWC_Y_TILE_HEIGHT); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_y, \ + metadata_stride, metadata_buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_c, \ + metadata_stride, metadata_buf_height); \ + _size = ref_buf_size + meta_size_y + meta_size_c; \ + } else { \ + SIZE_ENC_TEN_BIT_REF_BUFFER(ten_bit_ref_buf_size, \ + frame_width, frame_height); \ + HFI_UBWC_CALC_METADATA_PLANE_STRIDE(metadata_stride, \ + frame_width, VENUS_METADATA_STRIDE_MULTIPLE, \ + HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_WIDTH); \ + HFI_UBWC_METADATA_PLANE_BUFHEIGHT(metadata_buf_height, \ + frame_height, VENUS_METADATA_HEIGHT_MULTIPLE, \ + HFI_COLOR_FORMAT_YUV420_TP10_UBWC_Y_TILE_HEIGHT); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_y, \ + metadata_stride, metadata_buf_height); \ + HFI_UBWC_METADATA_PLANE_BUFFER_SIZE(meta_size_c, \ + metadata_stride, metadata_buf_height); \ + _size = ten_bit_ref_buf_size + meta_size_y + \ + meta_size_c; \ + } \ + } while (0) + +#define HFI_BUFFER_DPB_H264E(_size, frame_width, frame_height) \ + do { \ + HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, 0); \ + } while (0) + +#define HFI_BUFFER_DPB_H265E(_size, frame_width, frame_height, is_ten_bit) \ + do { \ + HFI_BUFFER_DPB_ENC(_size, frame_width, frame_height, is_ten_bit); \ + } while (0) + +#define HFI_BUFFER_VPSS_ENC(vpss_size, dswidth, dsheight, ds_enable, blur, is_ten_bit) \ + do { \ + vpss_size = 0; \ + if (ds_enable || blur) { \ + HFI_BUFFER_DPB_ENC(vpss_size, dswidth, dsheight, is_ten_bit); \ + } \ + } while (0) + +#define HFI_IRIS3_ENC_MIN_INPUT_BUF_COUNT(numInput, TotalHBLayers) \ + do { \ + numInput = 3; \ + if (TotalHBLayers >= 2) { \ + numInput = (1 << (TotalHBLayers - 1)) + 2; \ + } \ + } while (0) + +#endif /* __HFI_BUFFER_IRIS3_3__ */ diff --git a/qcom/opensource/video-driver/driver/variant/iris33/inc/msm_vidc_buffer_iris33.h b/qcom/opensource/video-driver/driver/variant/iris33/inc/msm_vidc_buffer_iris33.h new file mode 100644 index 0000000000..f5b4806a22 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris33/inc/msm_vidc_buffer_iris33.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __H_MSM_VIDC_BUFFER_IRIS3_3_H__ +#define __H_MSM_VIDC_BUFFER_IRIS3_3_H__ + +#include "msm_vidc_inst.h" + +int msm_buffer_size_iris33(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +int msm_buffer_min_count_iris33(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +int msm_buffer_extra_count_iris33(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); + +#endif // __H_MSM_VIDC_BUFFER_IRIS3_3_H__ diff --git a/qcom/opensource/video-driver/driver/variant/iris33/inc/msm_vidc_iris33.h b/qcom/opensource/video-driver/driver/variant/iris33/inc/msm_vidc_iris33.h new file mode 100644 index 0000000000..d4e37bc8a7 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris33/inc/msm_vidc_iris33.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_IRIS3_3_H_ +#define _MSM_VIDC_IRIS3_3_H_ + +#include "msm_vidc_core.h" + +#if defined(CONFIG_MSM_VIDC_PINEAPPLE) +int msm_vidc_init_iris33(struct msm_vidc_core *core); +int msm_vidc_adjust_bitrate_boost_iris33(void *instance, struct v4l2_ctrl *ctrl); +#else +static inline int msm_vidc_init_iris33(struct msm_vidc_core *core) +{ + return -EINVAL; +} + +static inline int msm_vidc_adjust_bitrate_boost_iris33(void *instance, struct v4l2_ctrl *ctrl) +{ + return -EINVAL; +} +#endif + +#endif // _MSM_VIDC_IRIS3_3_H_ diff --git a/qcom/opensource/video-driver/driver/variant/iris33/inc/msm_vidc_power_iris33.h b/qcom/opensource/video-driver/driver/variant/iris33/inc/msm_vidc_power_iris33.h new file mode 100644 index 0000000000..180a68e6c1 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris33/inc/msm_vidc_power_iris33.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __H_MSM_VIDC_POWER_IRIS3_3_H__ +#define __H_MSM_VIDC_POWER_IRIS3_3_H__ + +#include "msm_vidc_inst.h" +#include "msm_vidc_power.h" + +#define ENABLE_LEGACY_POWER_CALCULATIONS 0 + +int msm_vidc_ring_buf_count_iris33(struct msm_vidc_inst *inst, u32 data_size); +u64 msm_vidc_calc_freq_iris33(struct msm_vidc_inst *inst, u32 data_size); +int msm_vidc_calc_bw_iris33(struct msm_vidc_inst *inst, + struct vidc_bus_vote_data *vote_data); + +#endif diff --git a/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_buffer_iris33.c b/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_buffer_iris33.c new file mode 100644 index 0000000000..b3f8ca5b7f --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_buffer_iris33.c @@ -0,0 +1,743 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_buffer_iris33.h" +#include "msm_vidc_buffer.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_debug.h" +#include "msm_media_info.h" +#include "msm_vidc_platform.h" +#include "hfi_property.h" +#include "hfi_buffer_iris33.h" + +static u32 msm_vidc_decoder_bin_size_iris33(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, num_vpp_pipes; + struct v4l2_format *f; + bool is_interlaced; + u32 vpp_delay; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + if (inst->decode_vpp_delay.enable) + vpp_delay = inst->decode_vpp_delay.size; + else + vpp_delay = DEFAULT_BSE_VPP_DELAY; + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_PROGRESSIVE) + is_interlaced = false; + else + is_interlaced = true; + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_BIN_H264D(size, width, height, + is_interlaced, vpp_delay, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_BIN_H265D(size, width, height, + 0, vpp_delay, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_VP9) + HFI_BUFFER_BIN_VP9D(size, width, height, + 0, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_AV1) + HFI_BUFFER_BIN_AV1D(size, width, height, is_interlaced, + 0, num_vpp_pipes); + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_comv_size_iris33(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, num_comv, vpp_delay; + struct v4l2_format *f; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_AV1) { + /* + * AV1 requires larger COMV buffer size to meet performance + * for certain use cases. Increase the COMV buffer size by + * increasing COMV bufcount. Use lower count for 8k to + * achieve performance but save memory. + */ + if (res_is_greater_than(width, height, 4096, 2176)) + num_comv = inst->fw_min_count ? + inst->fw_min_count + 3 : inst->buffers.output.min_count + 3; + else + num_comv = inst->fw_min_count ? + inst->fw_min_count + 7 : inst->buffers.output.min_count + 7; + } else { + num_comv = inst->buffers.output.min_count; + } + msm_vidc_update_cap_value(inst, NUM_COMV, num_comv, __func__); + + if (inst->codec == MSM_VIDC_HEIC + && is_thumbnail_session(inst)) { + vpp_delay = 0; + } else { + if (inst->decode_vpp_delay.enable) + vpp_delay = inst->decode_vpp_delay.size; + else + vpp_delay = DEFAULT_BSE_VPP_DELAY; + } + + num_comv = max(vpp_delay + 1, num_comv); + if (inst->codec == MSM_VIDC_H264) { + HFI_BUFFER_COMV_H264D(size, width, height, num_comv); + } else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) { + HFI_BUFFER_COMV_H265D(size, width, height, num_comv); + } else if (inst->codec == MSM_VIDC_AV1) { + /* + * When DRAP is enabled, COMV buffer is part of PERSIST buffer and + * should not be allocated separately. + * When DRAP is disabled, COMV buffer must be allocated. + */ + if (inst->capabilities[DRAP].value) + size = 0; + else + HFI_BUFFER_COMV_AV1D(size, width, height, num_comv); + } + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_non_comv_size_iris33(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, num_vpp_pipes; + struct msm_vidc_core *core; + struct v4l2_format *f; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_NON_COMV_H264D(size, width, height, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_NON_COMV_H265D(size, width, height, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_line_size_iris33(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, out_min_count, num_vpp_pipes, vpp_delay; + struct v4l2_format *f; + bool is_opb; + u32 color_fmt; + + core = inst->core; + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + + color_fmt = v4l2_colorformat_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, __func__); + if (is_linear_colorformat(color_fmt)) + is_opb = true; + else + is_opb = false; + /* + * assume worst case, since color format is unknown at this + * time. + */ + is_opb = true; + + if (inst->decode_vpp_delay.enable) + vpp_delay = inst->decode_vpp_delay.size; + else + vpp_delay = DEFAULT_BSE_VPP_DELAY; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + out_min_count = inst->buffers.output.min_count; + out_min_count = max(vpp_delay + 1, out_min_count); + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_LINE_H264D(size, width, height, is_opb, + num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_LINE_H265D(size, width, height, is_opb, + num_vpp_pipes); + else if (inst->codec == MSM_VIDC_VP9) + HFI_BUFFER_LINE_VP9D(size, width, height, out_min_count, + is_opb, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_AV1) + HFI_BUFFER_LINE_AV1D(size, width, height, is_opb, + num_vpp_pipes); + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_partial_data_size_iris33(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height; + struct v4l2_format *f; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_AV1) + HFI_BUFFER_IBC_AV1D(size, width, height); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_persist_size_iris33(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 rpu_enabled = 0; + + if (inst->capabilities[META_DOLBY_RPU].value) + rpu_enabled = 1; + + if (inst->codec == MSM_VIDC_H264) { + HFI_BUFFER_PERSIST_H264D(size, rpu_enabled); + } else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) { + HFI_BUFFER_PERSIST_H265D(size, rpu_enabled); + } else if (inst->codec == MSM_VIDC_VP9) { + HFI_BUFFER_PERSIST_VP9D(size); + } else if (inst->codec == MSM_VIDC_AV1) { + /* + * When DRAP is enabled, COMV buffer is part of PERSIST buffer and + * should not be allocated separately. PERSIST buffer should include + * COMV buffer calculated with width, height, refcount. + * When DRAP is disabled, COMV buffer should not be included in PERSIST + * buffer. + */ + if (inst->capabilities[DRAP].value) + HFI_BUFFER_PERSIST_AV1D(size, + inst->capabilities[FRAME_WIDTH].max, + inst->capabilities[FRAME_HEIGHT].max, 16); + else + HFI_BUFFER_PERSIST_AV1D(size, 0, 0, 0); + } + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_decoder_dpb_size_iris33(struct msm_vidc_inst *inst) +{ + + u32 size = 0; + u32 color_fmt; + u32 width, height; + u32 interlace = 0; + struct v4l2_format *f; + + /* + * For legacy codecs (non-AV1), DPB is calculated only + * for linear formats. For AV1, DPB is needed for film-grain + * enabled bitstreams (UBWC & linear). + */ + color_fmt = inst->capabilities[PIX_FMTS].value; + if (!is_linear_colorformat(color_fmt)) { + if (inst->codec != MSM_VIDC_AV1) + return size; + + if (inst->codec == MSM_VIDC_AV1 && + !inst->capabilities[FILM_GRAIN].value) + return size; + } + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + + if (inst->codec == MSM_VIDC_H264 && + res_is_less_than_or_equal_to(width, height, 1920, 1088)) + interlace = 1; + + if (color_fmt == MSM_VIDC_FMT_NV12 || + color_fmt == MSM_VIDC_FMT_NV12C) { + color_fmt = MSM_VIDC_FMT_NV12C; + HFI_NV12_UBWC_IL_CALC_BUF_SIZE_V2(size, width, height, + video_y_stride_bytes(color_fmt, width), + video_y_scanlines(color_fmt, height), + video_uv_stride_bytes(color_fmt, width), + video_uv_scanlines(color_fmt, height), + video_y_meta_stride(color_fmt, width), + video_y_meta_scanlines(color_fmt, height), + video_uv_meta_stride(color_fmt, width), + video_uv_meta_scanlines(color_fmt, height), + interlace); + } else if (color_fmt == MSM_VIDC_FMT_P010 || + color_fmt == MSM_VIDC_FMT_TP10C) { + color_fmt = MSM_VIDC_FMT_TP10C; + HFI_YUV420_TP10_UBWC_CALC_BUF_SIZE(size, + video_y_stride_bytes(color_fmt, width), + video_y_scanlines(color_fmt, height), + video_uv_stride_bytes(color_fmt, width), + video_uv_scanlines(color_fmt, height), + video_y_meta_stride(color_fmt, width), + video_y_meta_scanlines(color_fmt, height), + video_uv_meta_stride(color_fmt, width), + video_uv_meta_scanlines(color_fmt, height)); + } + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +/* encoder internal buffers */ +static u32 msm_vidc_encoder_bin_size_iris33(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, num_vpp_pipes, stage, profile, ring_buf_count; + struct v4l2_format *f; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + stage = inst->capabilities[STAGE].value; + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + profile = inst->capabilities[PROFILE].value; + ring_buf_count = inst->capabilities[ENC_RING_BUFFER_COUNT].value; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_BIN_H264E(size, inst->hfi_rc_type, width, + height, stage, num_vpp_pipes, profile, ring_buf_count); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_BIN_H265E(size, inst->hfi_rc_type, width, + height, stage, num_vpp_pipes, profile, ring_buf_count); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_get_recon_buf_count(struct msm_vidc_inst *inst) +{ + u32 num_buf_recon = 0; + s32 n_bframe, ltr_count, hp_layers = 0, hb_layers = 0; + bool is_hybrid_hp = false; + u32 hfi_codec = 0; + + n_bframe = inst->capabilities[B_FRAME].value; + ltr_count = inst->capabilities[LTR_COUNT].value; + + if (inst->hfi_layer_type == HFI_HIER_B) { + hb_layers = inst->capabilities[ENH_LAYER_COUNT].value + 1; + } else { + hp_layers = inst->capabilities[ENH_LAYER_COUNT].value + 1; + if (inst->hfi_layer_type == HFI_HIER_P_HYBRID_LTR) + is_hybrid_hp = true; + } + + if (inst->codec == MSM_VIDC_H264) + hfi_codec = HFI_CODEC_ENCODE_AVC; + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + hfi_codec = HFI_CODEC_ENCODE_HEVC; + + HFI_IRIS3_ENC_RECON_BUF_COUNT(num_buf_recon, n_bframe, ltr_count, + hp_layers, hb_layers, is_hybrid_hp, hfi_codec); + + return num_buf_recon; +} + +static u32 msm_vidc_encoder_comv_size_iris33(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, num_recon = 0; + struct v4l2_format *f; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + num_recon = msm_vidc_get_recon_buf_count(inst); + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_COMV_H264E(size, width, height, num_recon); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_COMV_H265E(size, width, height, num_recon); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_non_comv_size_iris33(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, num_vpp_pipes; + struct v4l2_format *f; + + core = inst->core; + + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_NON_COMV_H264E(size, width, height, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_NON_COMV_H265E(size, width, height, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_line_size_iris33(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 size = 0; + u32 width, height, pixfmt, num_vpp_pipes; + bool is_tenbit = false; + struct v4l2_format *f; + + core = inst->core; + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + pixfmt = inst->capabilities[PIX_FMTS].value; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + is_tenbit = (pixfmt == MSM_VIDC_FMT_P010 || pixfmt == MSM_VIDC_FMT_TP10C); + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_LINE_H264E(size, width, height, is_tenbit, num_vpp_pipes); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_LINE_H265E(size, width, height, is_tenbit, num_vpp_pipes); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_dpb_size_iris33(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 width, height, pixfmt; + struct v4l2_format *f; + bool is_tenbit; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + pixfmt = inst->capabilities[PIX_FMTS].value; + is_tenbit = (pixfmt == MSM_VIDC_FMT_P010 || pixfmt == MSM_VIDC_FMT_TP10C); + + if (inst->codec == MSM_VIDC_H264) + HFI_BUFFER_DPB_H264E(size, width, height); + else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) + HFI_BUFFER_DPB_H265E(size, width, height, is_tenbit); + + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_arp_size_iris33(struct msm_vidc_inst *inst) +{ + u32 size = 0; + + HFI_BUFFER_ARP_ENC(size); + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_vpss_size_iris33(struct msm_vidc_inst *inst) +{ + u32 size = 0; + bool ds_enable = false, is_tenbit = false, blur = false; + u32 rotation_val = HFI_ROTATION_NONE; + u32 width, height, driver_colorfmt; + struct v4l2_format *f; + + ds_enable = is_scaling_enabled(inst); + msm_vidc_v4l2_to_hfi_enum(inst, ROTATION, &rotation_val); + + f = &inst->fmts[OUTPUT_PORT]; + if (is_rotation_90_or_270(inst)) { + /* + * output width and height are rotated, + * so unrotate them to use as arguments to + * HFI_BUFFER_VPSS_ENC. + */ + width = f->fmt.pix_mp.height; + height = f->fmt.pix_mp.width; + } else { + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + } + + f = &inst->fmts[INPUT_PORT]; + driver_colorfmt = v4l2_colorformat_to_driver(inst, + f->fmt.pix_mp.pixelformat, __func__); + is_tenbit = is_10bit_colorformat(driver_colorfmt); + if (inst->capabilities[BLUR_TYPES].value != MSM_VIDC_BLUR_NONE) + blur = true; + + HFI_BUFFER_VPSS_ENC(size, width, height, ds_enable, blur, is_tenbit); + i_vpr_l(inst, "%s: size %d\n", __func__, size); + return size; +} + +static u32 msm_vidc_encoder_output_size_iris33(struct msm_vidc_inst *inst) +{ + u32 frame_size; + struct v4l2_format *f; + bool is_ten_bit = false; + int bitrate_mode, frame_rc; + u32 hfi_rc_type = HFI_RC_VBR_CFR; + enum msm_vidc_codec_type codec; + + f = &inst->fmts[OUTPUT_PORT]; + codec = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__); + if (codec == MSM_VIDC_HEVC || codec == MSM_VIDC_HEIC) + is_ten_bit = true; + + bitrate_mode = inst->capabilities[BITRATE_MODE].value; + frame_rc = inst->capabilities[FRAME_RC_ENABLE].value; + if (!frame_rc && !is_image_session(inst)) + hfi_rc_type = HFI_RC_OFF; + else if (bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + hfi_rc_type = HFI_RC_CQ; + + HFI_BUFFER_BITSTREAM_ENC(frame_size, f->fmt.pix_mp.width, + f->fmt.pix_mp.height, hfi_rc_type, is_ten_bit); + + frame_size = msm_vidc_enc_delivery_mode_based_output_buf_size(inst, frame_size); + + return frame_size; +} + +struct msm_vidc_buf_type_handle { + enum msm_vidc_buffer_type type; + u32 (*handle)(struct msm_vidc_inst *inst); +}; + +int msm_buffer_size_iris33(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int i; + u32 size = 0, buf_type_handle_size = 0; + const struct msm_vidc_buf_type_handle *buf_type_handle_arr = NULL; + static const struct msm_vidc_buf_type_handle dec_buf_type_handle[] = { + {MSM_VIDC_BUF_INPUT, msm_vidc_decoder_input_size }, + {MSM_VIDC_BUF_OUTPUT, msm_vidc_decoder_output_size }, + {MSM_VIDC_BUF_INPUT_META, msm_vidc_decoder_input_meta_size }, + {MSM_VIDC_BUF_OUTPUT_META, msm_vidc_decoder_output_meta_size }, + {MSM_VIDC_BUF_BIN, msm_vidc_decoder_bin_size_iris33 }, + {MSM_VIDC_BUF_COMV, msm_vidc_decoder_comv_size_iris33 }, + {MSM_VIDC_BUF_NON_COMV, msm_vidc_decoder_non_comv_size_iris33 }, + {MSM_VIDC_BUF_LINE, msm_vidc_decoder_line_size_iris33 }, + {MSM_VIDC_BUF_PERSIST, msm_vidc_decoder_persist_size_iris33 }, + {MSM_VIDC_BUF_DPB, msm_vidc_decoder_dpb_size_iris33 }, + {MSM_VIDC_BUF_PARTIAL_DATA, msm_vidc_decoder_partial_data_size_iris33 }, + }; + static const struct msm_vidc_buf_type_handle enc_buf_type_handle[] = { + {MSM_VIDC_BUF_INPUT, msm_vidc_encoder_input_size }, + {MSM_VIDC_BUF_OUTPUT, msm_vidc_encoder_output_size_iris33 }, + {MSM_VIDC_BUF_INPUT_META, msm_vidc_encoder_input_meta_size }, + {MSM_VIDC_BUF_OUTPUT_META, msm_vidc_encoder_output_meta_size }, + {MSM_VIDC_BUF_BIN, msm_vidc_encoder_bin_size_iris33 }, + {MSM_VIDC_BUF_COMV, msm_vidc_encoder_comv_size_iris33 }, + {MSM_VIDC_BUF_NON_COMV, msm_vidc_encoder_non_comv_size_iris33 }, + {MSM_VIDC_BUF_LINE, msm_vidc_encoder_line_size_iris33 }, + {MSM_VIDC_BUF_DPB, msm_vidc_encoder_dpb_size_iris33 }, + {MSM_VIDC_BUF_ARP, msm_vidc_encoder_arp_size_iris33 }, + {MSM_VIDC_BUF_VPSS, msm_vidc_encoder_vpss_size_iris33 }, + }; + + if (is_decode_session(inst)) { + buf_type_handle_size = ARRAY_SIZE(dec_buf_type_handle); + buf_type_handle_arr = dec_buf_type_handle; + } else if (is_encode_session(inst)) { + buf_type_handle_size = ARRAY_SIZE(enc_buf_type_handle); + buf_type_handle_arr = enc_buf_type_handle; + } + + /* handle invalid session */ + if (!buf_type_handle_arr || !buf_type_handle_size) { + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return size; + } + + /* fetch buffer size */ + for (i = 0; i < buf_type_handle_size; i++) { + if (buf_type_handle_arr[i].type == buffer_type) { + size = buf_type_handle_arr[i].handle(inst); + break; + } + } + + /* handle unknown buffer type */ + if (i == buf_type_handle_size) { + i_vpr_e(inst, "%s: unknown buffer type %#x\n", __func__, buffer_type); + goto exit; + } + + i_vpr_l(inst, "buffer_size: type: %11s, size: %9u\n", buf_name(buffer_type), size); + +exit: + return size; +} + +static int msm_vidc_input_min_count_iris33(struct msm_vidc_inst *inst) +{ + u32 input_min_count = 0; + u32 total_hb_layer = 0; + + if (is_decode_session(inst)) { + input_min_count = MIN_DEC_INPUT_BUFFERS; + } else if (is_encode_session(inst)) { + total_hb_layer = is_hierb_type_requested(inst) ? + inst->capabilities[ENH_LAYER_COUNT].value + 1 : 0; + if (inst->codec == MSM_VIDC_H264 && + !inst->capabilities[LAYER_ENABLE].value) { + total_hb_layer = 0; + } + HFI_IRIS3_ENC_MIN_INPUT_BUF_COUNT(input_min_count, + total_hb_layer); + } else { + i_vpr_e(inst, "%s: invalid domain %d\n", __func__, inst->domain); + return 0; + } + + if (is_thumbnail_session(inst) || is_image_session(inst)) + input_min_count = 1; + + return input_min_count; +} + +static int msm_buffer_dpb_count(struct msm_vidc_inst *inst) +{ + int count = 0; + + /* encoder dpb buffer count */ + if (is_encode_session(inst)) + return msm_vidc_get_recon_buf_count(inst); + + /* decoder dpb buffer count */ + if (is_split_mode_enabled(inst)) { + count = inst->fw_min_count ? + inst->fw_min_count : inst->buffers.output.min_count; + } + + return count; +} + +static int msm_buffer_delivery_mode_based_min_count_iris33(struct msm_vidc_inst *inst, + uint32_t count) +{ + struct v4l2_format *f; + struct msm_vidc_core *core = NULL; + u32 width, height, total_num_slices = 1; + u32 hfi_codec = 0; + u32 max_mbs_per_slice = 0; + u32 slice_mode = 0; + u32 delivery_mode = 0; + u32 num_vpp_pipes; + + slice_mode = inst->capabilities[SLICE_MODE].value; + delivery_mode = inst->capabilities[DELIVERY_MODE].value; + + if (slice_mode != V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB || + (!delivery_mode)) + return count; + + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + max_mbs_per_slice = inst->capabilities[SLICE_MAX_MB].value; + + if (inst->codec == MSM_VIDC_H264) + hfi_codec = HFI_CODEC_ENCODE_AVC; + else if (inst->codec == MSM_VIDC_HEVC) + hfi_codec = HFI_CODEC_ENCODE_HEVC; + + core = inst->core; + num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + + HFI_IRIS3_ENC_MB_BASED_MULTI_SLICE_COUNT(total_num_slices, width, height, + hfi_codec, max_mbs_per_slice, num_vpp_pipes); + + return (total_num_slices * count); +} + +int msm_buffer_min_count_iris33(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int count = 0; + + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + case MSM_VIDC_BUF_INPUT_META: + count = msm_vidc_input_min_count_iris33(inst); + break; + case MSM_VIDC_BUF_OUTPUT: + case MSM_VIDC_BUF_OUTPUT_META: + count = msm_vidc_output_min_count(inst); + count = msm_buffer_delivery_mode_based_min_count_iris33(inst, count); + break; + case MSM_VIDC_BUF_BIN: + case MSM_VIDC_BUF_COMV: + case MSM_VIDC_BUF_NON_COMV: + case MSM_VIDC_BUF_LINE: + case MSM_VIDC_BUF_PERSIST: + case MSM_VIDC_BUF_ARP: + case MSM_VIDC_BUF_VPSS: + case MSM_VIDC_BUF_PARTIAL_DATA: + count = msm_vidc_internal_buffer_count(inst, buffer_type); + break; + case MSM_VIDC_BUF_DPB: + count = msm_buffer_dpb_count(inst); + break; + default: + break; + } + + i_vpr_l(inst, " min_count: type: %11s, count: %9u\n", buf_name(buffer_type), count); + return count; +} + +int msm_buffer_extra_count_iris33(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int count = 0; + + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + case MSM_VIDC_BUF_INPUT_META: + count = msm_vidc_input_extra_count(inst); + break; + case MSM_VIDC_BUF_OUTPUT: + case MSM_VIDC_BUF_OUTPUT_META: + count = msm_vidc_output_extra_count(inst); + break; + default: + break; + } + + i_vpr_l(inst, "extra_count: type: %11s, count: %9u\n", buf_name(buffer_type), count); + return count; +} diff --git a/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_bus_iris33.c b/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_bus_iris33.c new file mode 100644 index 0000000000..e62f4e033e --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_bus_iris33.c @@ -0,0 +1,1051 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "perf_static_model.h" +#include "msm_vidc_debug.h" + +/* 100x */ +static u32 dpbopb_ubwc30_cr_table_cratio_iris33[7][12] = { + {237, 399, 272, 137, 225, 158, 185, 259, 203, 138, 167, 152}, + {269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149}, + {269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149}, + {269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149}, + {237, 399, 272, 137, 225, 158, 185, 259, 203, 138, 167, 152}, + {269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149}, + {269, 404, 302, 202, 367, 238, 210, 299, 232, 134, 181, 149}, +}; + +/* 100x */ +static u32 rpb_ubwc30_cr_table_cratio_iris33[7][12] = { + {193, 294, 218, 135, 214, 155, 175, 241, 191, 139, 162, 149}, + {285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152}, + {285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152}, + {285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152}, + {193, 294, 218, 135, 214, 155, 175, 241, 191, 139, 162, 149}, + {285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152}, + {285, 406, 316, 207, 373, 243, 201, 280, 221, 139, 177, 152}, +}; + +/* 100x */ +static u32 ipblossy_ubwc30_cr_table_cratio_iris33[7][12] = { + {215, 215, 215, 174, 174, 174, 266, 266, 266, 231, 231, 231}, + {254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249}, + {254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249}, + {254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249}, + {215, 215, 215, 174, 174, 174, 266, 266, 266, 231, 231, 231}, + {254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249}, + {254, 254, 254, 219, 219, 219, 292, 292, 292, 249, 249, 249}, +}; + +/* 100x */ +static u32 ipblossless_ubwc30_cr_table_cratio_iris33[7][12] = { + {185, 215, 194, 147, 178, 159, 162, 181, 169, 138, 161, 146}, + {186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148}, + {186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148}, + {186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148}, + {185, 215, 194, 147, 178, 159, 162, 181, 169, 138, 161, 146}, + {186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148}, + {186, 217, 195, 151, 183, 161, 164, 182, 170, 140, 168, 148}, +}; + +/* 100x */ +static u32 en_original_compression_factor_rgba_pwd_iris33 = 243; +/* 100x */ +static u32 en_original_compression_factor_rgba_avg_iris33 = 454; + +static u32 av1_num_tiles_iris33[7][3] = { + {2, 1, 1}, + {4, 2, 2}, + {4, 2, 2}, + {4, 2, 2}, + {1, 1, 1}, + {2, 1, 1}, + {16, 4, 4}, +}; + +/* H I J K L M N O P + * TotalW Total R Frequency Write Read + * Name B b P B b P B b P + * I3B4b1P 0.5 1.875 3 4 1 1 0 1 2 2 1 + * I1B2b1P 0.5 1.75 1 2 1 1 0 1 2 2 1 + * IbP 0.5 1.5 0 1 1 1 0 1 2 2 1 + * IPP 1 1 0 0 1 1 0 1 2 2 1 + * P 1 1 0 0 1 1 0 1 2 2 1 + * smallB 0 2 0 1 0 1 0 1 2 2 1 + * bigB 1 2 1 0 0 1 0 1 2 2 1 + * + * Total W = SUMPRODUCT(H16:J16, K16 : M16) / SUM(H16:J16) + * Total R = SUMPRODUCT(H16:J16, N16 : P16) / SUM(H16:J16) + */ + +/* 1000x */ +static u32 pineapple_en_readfactor[8] = {1000, 1500, 1750, 1875, 1000, 2000, 2000, 1000}; +/* 1000x */ +static u32 pineapple_en_writefactor[8] = {1000, 500, 500, 500, 1000, 0, 1000, 1000}; +static u32 pineapple_en_frame_num_parallel = 1; + +u32 calculate_number_lcus_iris33(u32 width, u32 height, u32 lcu_size) +{ + u32 mbs_width = (width % lcu_size) ? + (width / lcu_size + 1) : (width / lcu_size); + u32 mbs_height = (height % lcu_size) ? + (height / lcu_size + 1) : (height / lcu_size); + + return mbs_width * mbs_height; +} + +u32 calculate_number_ubwctiles_iris33( + u32 width, u32 height, u32 tile_w, u32 tile_h) +{ + u32 tiles_width = (width % tile_w) ? + (width / tile_w + 1) : (width / tile_w); + u32 tiles_height = (height % tile_h) ? + (height / tile_h + 1) : (height / tile_h); + + return tiles_width * tiles_height; +} + +struct compression_factors { + u32 dpb_cf_y; + u32 dpb_cf_cbcr; + u32 opb_cf_ycbcr; + u32 dpb_cr_y; + u32 ipb_cr_y; + u32 ipb_cr; +} compression_factor; + +u32 get_compression_factors(struct compression_factors *compression_factor, + struct api_calculation_input codec_input) +{ + u8 cr_index_entry, cr_index_y, cr_index_c, cr_index_uni; + u32 frame_width; + u32 frame_height; + + frame_width = codec_input.frame_width; + frame_height = codec_input.frame_height; + if (frame_width * frame_height <= 1920 * 1080) + cr_index_entry = 0; + else + cr_index_entry = 1; + + if (codec_input.bitdepth == CODEC_BITDEPTH_8) { + /* NOT PWC or average and power case */ + if (codec_input.complexity_setting != 0) { + cr_index_y = 0; + cr_index_c = 1; + cr_index_uni = 2; + } else { + cr_index_y = 3; + cr_index_c = 4; + cr_index_uni = 5; + } + } else { + /* NOT PWC or average and power case */ + if (codec_input.complexity_setting != 0) { + cr_index_y = 6; + cr_index_c = 7; + cr_index_uni = 8; + } else { + cr_index_y = 9; + cr_index_c = 10; + cr_index_uni = 11; + } + } + + if (codec_input.decoder_or_encoder == CODEC_DECODER) { + compression_factor->dpb_cf_y = + dpbopb_ubwc30_cr_table_cratio_iris33[cr_index_entry][cr_index_y]; + compression_factor->dpb_cf_cbcr = + dpbopb_ubwc30_cr_table_cratio_iris33[cr_index_entry][cr_index_c]; + compression_factor->opb_cf_ycbcr = + dpbopb_ubwc30_cr_table_cratio_iris33[cr_index_entry][cr_index_uni]; + + if ((codec_input.regression_mode == 3) && + /* input cr numbers from interface */ + ((codec_input.cr_dpb != 0) || (codec_input.cr_opb != 0))) { + compression_factor->dpb_cf_y = codec_input.cr_dpb; + compression_factor->dpb_cf_cbcr = codec_input.cr_dpb; + compression_factor->opb_cf_ycbcr = codec_input.cr_opb; + } + } else { /* encoder */ + /* + * IPB CR Table Choice; static sheet (if framewidth<3840, use lossless table) + * (else, use lossy table) + * stick to this choice for SW purpose (no change for SW) + */ + if (frame_width < 3840) { + compression_factor->ipb_cr = + ipblossless_ubwc30_cr_table_cratio_iris33[cr_index_entry] + [cr_index_uni]; + compression_factor->ipb_cr_y = + ipblossless_ubwc30_cr_table_cratio_iris33[cr_index_entry] + [cr_index_y]; + } else { + compression_factor->ipb_cr = + ipblossy_ubwc30_cr_table_cratio_iris33[cr_index_entry] + [cr_index_uni]; + compression_factor->ipb_cr_y = + ipblossy_ubwc30_cr_table_cratio_iris33[cr_index_entry] + [cr_index_y]; + } + + compression_factor->dpb_cf_y = + rpb_ubwc30_cr_table_cratio_iris33[cr_index_entry][cr_index_y]; + + compression_factor->dpb_cf_cbcr = + rpb_ubwc30_cr_table_cratio_iris33[cr_index_entry][cr_index_c]; + + if ((codec_input.regression_mode == 3) && + /* input cr from interface */ + ((codec_input.cr_ipb != 0) || (codec_input.cr_rpb != 0))) { + compression_factor->dpb_cf_y = codec_input.cr_rpb; + compression_factor->dpb_cf_cbcr = codec_input.cr_rpb; + compression_factor->ipb_cr_y = codec_input.cr_ipb; + } + } + + return 0; +} + +static int calculate_bandwidth_decoder_iris33( + struct api_calculation_input codec_input, + struct api_calculation_bw_output *codec_output) +{ + /* common control parameters */ + u32 frame_width; + u32 frame_height; + u32 frame_lcu_size = 16; /* initialized to h264 */ + u32 lcu_per_frame; + u32 target_bitrate; + u32 collocated_bytes_per_lcu = 16; /* initialized to h264 */ + u32 av1d_segment_read_per_lcu; + u32 av1d_fe_leftlinebuffer_perlcu_tileboudary; + + u32 frame420_y_bw_linear_8bpp; + u32 frame420_y_bw_no_ubwc_tile_10bpp; + u32 frame420_y_bw_linear_10bpp; + + u16 ubwc_tile_w; + u16 ubwc_tile_h; + + u32 dpb_compression_factor_y; + u32 dpb_compression_factor_cbcr; + + u32 reconstructed_write_bw_factor_rd; + u32 reference_y_read_bw_factor; + u32 reference_cbcr_read_bw_factor; + + /* decoder control parameters */ + u32 decoder_vsp_read_factor = 6; + u32 bins_to_bits_factor = 4; + + u32 dpb_to_opb_ratios_ds = 1; + + u8 llc_enabled_ref_y_rd; + u8 llc_enable_ref_crcb_rd; + u8 llc_enabled_bse_tlb; + + /* this is for 2pipe and 1pipe LLC */ + u8 llc_enable_probtable_av1d_21pipe = 0; + + u32 opb_compression_factor_ycbcr; + u32 dpb_ubwc_tile_width_pixels; + u32 dpb_ubwc_tile_height_pixels; + u32 decoder_frame_complexity_factor; + u32 llc_saving = 130; /* Initialized to H264 */ + + u16 av1_tile_numbers; + u32 av1_collated_seg_buffer_rd_wr; + /* need divide by 1M at later step; */ + u32 av1_probability_table_rdwr_bytesperframe = 22784; + u32 av1_fe_left_line_buffer_rdwr; + + u32 bse_tlb_byte_per_lcu = 0; + + u32 large_bw_calculation_fp = 0; + + if (codec_input.pipe_num == 4) { + llc_enabled_ref_y_rd = 1; + llc_enable_ref_crcb_rd = 1; + llc_enabled_bse_tlb = 1; + } else if (codec_input.pipe_num == 2) { + llc_enabled_ref_y_rd = 0; // llc 128kb for palawan + llc_enable_ref_crcb_rd = 0; + llc_enabled_bse_tlb = (codec_input.status_llc_onoff == 1) ? 1 : 0; + } + + llc_enabled_ref_y_rd = (codec_input.status_llc_onoff) ? 1 : 0; + llc_enable_ref_crcb_rd = (codec_input.status_llc_onoff) ? 1 : 0; + /* H265D BSE tlb in LLC will be pored in Kailua */ + llc_enabled_bse_tlb = (codec_input.status_llc_onoff) ? 1 : 0; + + frame_width = codec_input.frame_width; + frame_height = codec_input.frame_height; + if ((codec_input.codec == CODEC_H264) || + (codec_input.codec == CODEC_H264_CAVLC)) { + frame_lcu_size = 16; + collocated_bytes_per_lcu = 16; + llc_saving = 130; + } else if (codec_input.codec == CODEC_HEVC) { + if (codec_input.lcu_size == 32) { + frame_lcu_size = 32; + collocated_bytes_per_lcu = 64; + llc_saving = 114; + } else if (codec_input.lcu_size == 64) { + frame_lcu_size = 64; + collocated_bytes_per_lcu = 256; + llc_saving = 107; + } + } else if (codec_input.codec == CODEC_VP9) { + if (codec_input.lcu_size == 32) { + frame_lcu_size = 32; + collocated_bytes_per_lcu = 64; + llc_saving = 114; + } else if (codec_input.lcu_size == 64) { + frame_lcu_size = 64; + collocated_bytes_per_lcu = 256; + llc_saving = 107; + } + } else if (codec_input.codec == CODEC_AV1) { + u32 av1d_leftline_cdef = (2944 + 896 + 896); + u32 av1d_leftline_scaling = (2176 + 1408 + 1408); + u32 av1d_leftline_fg = (1280); + u32 av1d_leftline_lr = (1536 + 1024 + 1024); + + av1d_fe_leftlinebuffer_perlcu_tileboudary = + av1d_leftline_cdef + av1d_leftline_scaling + + av1d_leftline_fg + av1d_leftline_lr; + + if (codec_input.lcu_size == 128) { + frame_lcu_size = 128; + collocated_bytes_per_lcu = 4 * 512; + av1d_segment_read_per_lcu = 512; + llc_saving = 104; + } else if (codec_input.lcu_size == 32) { + frame_lcu_size = 32; + collocated_bytes_per_lcu = 4 * 512 / (128 * 128 / 32 / 32); + av1d_segment_read_per_lcu = 512 / (128 * 128 / 32 / 32); + av1d_fe_leftlinebuffer_perlcu_tileboudary = + av1d_fe_leftlinebuffer_perlcu_tileboudary / (128 * 128 / 32 / 32); + llc_saving = 114; + } else if (codec_input.lcu_size == 64) { + frame_lcu_size = 64; + collocated_bytes_per_lcu = 4 * 512 / (128 * 128 / 64 / 64); + av1d_segment_read_per_lcu = 512 / (128 * 128 / 64 / 64); + av1d_fe_leftlinebuffer_perlcu_tileboudary = + av1d_fe_leftlinebuffer_perlcu_tileboudary / (128 * 128 / 64 / 64); + llc_saving = 107; + } + } + + lcu_per_frame = + calculate_number_lcus_iris33(frame_width, frame_height, frame_lcu_size); + + target_bitrate = (u32)(codec_input.bitrate_mbps); /* Mbps */ + + ubwc_tile_w = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 32 : 48; + ubwc_tile_h = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 8 : 4; + + frame420_y_bw_linear_8bpp = + ((calculate_number_ubwctiles_iris33(frame_width, frame_height, 32, 8) * + 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + + frame420_y_bw_no_ubwc_tile_10bpp = + ((calculate_number_ubwctiles_iris33(frame_width, frame_height, 48, 4) * + 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + frame420_y_bw_linear_10bpp = ((frame_width * frame_height * + codec_input.frame_rate * 2 + 999) / 1000 + 999) / 1000; + + /* TODO Integrate Compression Ratio returned by FW */ + get_compression_factors(&compression_factor, codec_input); + dpb_compression_factor_y = compression_factor.dpb_cf_y; + dpb_compression_factor_cbcr = compression_factor.dpb_cf_cbcr; + opb_compression_factor_ycbcr = compression_factor.opb_cf_ycbcr; + + dpb_ubwc_tile_width_pixels = ubwc_tile_w; + + dpb_ubwc_tile_height_pixels = ubwc_tile_h; + + decoder_frame_complexity_factor = + (codec_input.complexity_setting == 0) ? + 400 : ((codec_input.complexity_setting == 1) ? 266 : 100); + + reconstructed_write_bw_factor_rd = (codec_input.complexity_setting == 0) ? + 105 : 100; + + reference_y_read_bw_factor = llc_saving; + + reference_cbcr_read_bw_factor = llc_saving; + + if (codec_input.codec == CODEC_AV1) { + u8 av1tile_index_entry, av1tile_complexity; + + if (frame_width * frame_height <= 1280 * 720) + av1tile_index_entry = 4; + else if (frame_width * frame_height <= 1920 * 1080) + av1tile_index_entry = 0; + else if (frame_width * frame_height <= 2560 * 1440) + av1tile_index_entry = 5; + else if (frame_width * frame_height <= 4096 * 2304) + av1tile_index_entry = 1; + else + av1tile_index_entry = 6; + + /* NOT PWC or average and power case */ + if (codec_input.complexity_setting != 0) + av1tile_complexity = 1; + else + av1tile_complexity = 0; + + av1_tile_numbers = av1_num_tiles_iris33[av1tile_index_entry][av1tile_complexity]; + + /* these bw can be ignored */ + av1_collated_seg_buffer_rd_wr = + ((av1d_segment_read_per_lcu * lcu_per_frame * + codec_input.frame_rate + 999) / 1000 + 999) / 1000; + + av1_fe_left_line_buffer_rdwr = + (((av1d_fe_leftlinebuffer_perlcu_tileboudary * + frame_height * (av1_tile_numbers > 1 ? av1_tile_numbers / 2 : 0) + + 999) / 1000 + 999) / 1000 + (frame_lcu_size - 1)) / frame_lcu_size; + } + + if (codec_input.codec == CODEC_HEVC) { + if (codec_input.lcu_size == 32) + bse_tlb_byte_per_lcu = 64; + else if (codec_input.lcu_size == 16) + bse_tlb_byte_per_lcu = 32; + else + bse_tlb_byte_per_lcu = 128; + } else if ((codec_input.codec == CODEC_H264) || + (codec_input.codec == CODEC_H264_CAVLC)) { + bse_tlb_byte_per_lcu = 64; + } else if (codec_input.codec == CODEC_VP9) { + bse_tlb_byte_per_lcu = 304; + } else if (codec_input.codec == CODEC_AV1) { + if (codec_input.lcu_size == 128) + bse_tlb_byte_per_lcu = 2064; + else if (codec_input.lcu_size == 64) + bse_tlb_byte_per_lcu = 1056; + else if (codec_input.lcu_size == 32) + bse_tlb_byte_per_lcu = 2064 / (128 * 128 / 32 / 32); + } + + codec_output->noc_bw_rd = 0; + codec_output->noc_bw_wr = 0; + codec_output->ddr_bw_rd = 0; + codec_output->ddr_bw_wr = 0; + + large_bw_calculation_fp = 0; + large_bw_calculation_fp = ((target_bitrate * + decoder_vsp_read_factor + 7) / 8); + + codec_output->vsp_read_noc = large_bw_calculation_fp; + + codec_output->vsp_read_ddr = codec_output->vsp_read_noc; + + large_bw_calculation_fp = ((target_bitrate * + bins_to_bits_factor + 7) / 8); + + codec_output->vsp_write_noc = large_bw_calculation_fp; + codec_output->vsp_write_ddr = codec_output->vsp_write_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->vsp_read_noc; + codec_output->ddr_bw_rd += codec_output->vsp_read_ddr; + codec_output->noc_bw_wr += codec_output->vsp_write_noc; + codec_output->ddr_bw_wr += codec_output->vsp_write_ddr; + + large_bw_calculation_fp = 0; + large_bw_calculation_fp = ((collocated_bytes_per_lcu * + lcu_per_frame * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + codec_output->collocated_rd_noc = large_bw_calculation_fp; + codec_output->collocated_wr_noc = codec_output->collocated_rd_noc; + codec_output->collocated_rd_ddr = codec_output->collocated_rd_noc; + codec_output->collocated_wr_ddr = codec_output->collocated_wr_noc; + + codec_output->collocated_rd_wr_total_noc = + (u32)(codec_output->collocated_rd_noc + codec_output->collocated_wr_noc); + + codec_output->collocated_rd_wr_total_ddr = + codec_output->collocated_rd_wr_total_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->collocated_rd_noc; + codec_output->noc_bw_wr += codec_output->collocated_wr_noc; + codec_output->ddr_bw_rd += codec_output->collocated_rd_ddr; + codec_output->ddr_bw_wr += codec_output->collocated_wr_ddr; + + large_bw_calculation_fp = 0; + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : + frame420_y_bw_no_ubwc_tile_10bpp) * decoder_frame_complexity_factor; + + large_bw_calculation_fp = + (large_bw_calculation_fp + dpb_compression_factor_y - 1) / + dpb_compression_factor_y; + + codec_output->dpb_rd_y_noc = large_bw_calculation_fp; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) * + decoder_frame_complexity_factor; + + large_bw_calculation_fp = + (large_bw_calculation_fp + dpb_compression_factor_cbcr - 1) / + dpb_compression_factor_cbcr / 2; + + codec_output->dpb_rd_crcb_noc = large_bw_calculation_fp; + codec_output->dpb_rdwr_duetooverlap_noc = 0; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) * + reconstructed_write_bw_factor_rd; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) * + reconstructed_write_bw_factor_rd; + + large_bw_calculation_fp = large_bw_calculation_fp * + (dpb_compression_factor_y / 2 + dpb_compression_factor_cbcr); + + large_bw_calculation_fp = (large_bw_calculation_fp + dpb_compression_factor_y - 1) / + dpb_compression_factor_y; + + large_bw_calculation_fp = + (large_bw_calculation_fp + dpb_compression_factor_cbcr - 1) / + dpb_compression_factor_cbcr; + + codec_output->dpb_wr_noc = large_bw_calculation_fp; + + codec_output->dpb_rd_y_ddr = (llc_enabled_ref_y_rd) ? + ((codec_output->dpb_rd_y_noc * 100 + reference_y_read_bw_factor - 1) / + reference_y_read_bw_factor) : codec_output->dpb_rd_y_noc; + + codec_output->dpb_rd_crcb_ddr = (llc_enable_ref_crcb_rd) ? + ((codec_output->dpb_rd_crcb_noc * 100 + + reference_cbcr_read_bw_factor - 1) / + reference_cbcr_read_bw_factor) : codec_output->dpb_rd_crcb_noc; + + codec_output->dpb_rdwr_duetooverlap_ddr = 0; + codec_output->dpb_wr_ddr = codec_output->dpb_wr_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->dpb_rd_y_noc; + codec_output->noc_bw_rd += codec_output->dpb_rd_crcb_noc; + codec_output->noc_bw_rd += codec_output->dpb_rdwr_duetooverlap_noc; + codec_output->noc_bw_wr += codec_output->dpb_wr_noc; + codec_output->ddr_bw_rd += codec_output->dpb_rd_y_ddr; + codec_output->ddr_bw_rd += codec_output->dpb_rd_crcb_ddr; + codec_output->ddr_bw_rd += codec_output->dpb_rdwr_duetooverlap_ddr; + codec_output->ddr_bw_wr += codec_output->dpb_wr_ddr; + + if (codec_input.linear_opb || codec_input.split_opb) { + if (codec_input.linear_opb) { + if (codec_input.bitdepth == CODEC_BITDEPTH_8) { + large_bw_calculation_fp = ((frame420_y_bw_linear_8bpp) * + 3 / 2 / dpb_to_opb_ratios_ds); + + codec_output->opb_write_total_noc = large_bw_calculation_fp; + } else { + large_bw_calculation_fp = ((frame420_y_bw_linear_10bpp) * + 3 / 2 / dpb_to_opb_ratios_ds); + + codec_output->opb_write_total_noc = large_bw_calculation_fp; + } + } else { /* (CODEC_INPUT.split_opb) */ + if (codec_input.bitdepth == CODEC_BITDEPTH_8) { + large_bw_calculation_fp = + (frame420_y_bw_linear_8bpp * 3 / 2 / dpb_to_opb_ratios_ds * + 100 + opb_compression_factor_ycbcr - 1) / + opb_compression_factor_ycbcr; + + codec_output->opb_write_total_noc = large_bw_calculation_fp; + } else { + large_bw_calculation_fp = + (frame420_y_bw_no_ubwc_tile_10bpp * 3 / 2 / + dpb_to_opb_ratios_ds * 100 + + opb_compression_factor_ycbcr - 1) / + opb_compression_factor_ycbcr; + + codec_output->opb_write_total_noc = large_bw_calculation_fp; + } + } + } else { + codec_output->opb_write_total_noc = 0; + } + + codec_output->opb_write_total_ddr = codec_output->opb_write_total_noc; + + /* accumulation */ + codec_output->noc_bw_wr += codec_output->opb_write_total_noc; + codec_output->ddr_bw_wr += codec_output->opb_write_total_ddr; + + large_bw_calculation_fp = ((bse_tlb_byte_per_lcu * lcu_per_frame * + codec_input.frame_rate + 999) / 1000 + 999) / 1000; + + codec_output->bse_tlb_rd_noc = large_bw_calculation_fp; + + if (llc_enabled_bse_tlb) + codec_output->bse_tlb_rd_ddr = 0; + else + codec_output->bse_tlb_rd_ddr = codec_output->bse_tlb_rd_noc; + + codec_output->bse_tlb_wr_noc = codec_output->bse_tlb_rd_noc; + + if (llc_enabled_bse_tlb) + codec_output->bse_tlb_wr_ddr = 0; + else + codec_output->bse_tlb_wr_ddr = codec_output->bse_tlb_wr_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->bse_tlb_rd_noc; + codec_output->ddr_bw_rd += codec_output->bse_tlb_rd_ddr; + codec_output->noc_bw_wr += codec_output->bse_tlb_wr_noc; + codec_output->ddr_bw_wr += codec_output->bse_tlb_wr_ddr; + + if (codec_input.codec == CODEC_AV1) { + codec_output->statistics_rd_noc = (av1_collated_seg_buffer_rd_wr + + av1_probability_table_rdwr_bytesperframe * av1_tile_numbers / + 1000 / 1000 + av1_fe_left_line_buffer_rdwr); + + codec_output->statistics_wr_noc = (av1_collated_seg_buffer_rd_wr + + av1_probability_table_rdwr_bytesperframe * av1_tile_numbers / + 1000 / 1000 + av1_fe_left_line_buffer_rdwr); + + if (llc_enable_probtable_av1d_21pipe) { + /* assert(CODEC_INPUT.pipe_num != 4); */ + codec_output->statistics_rd_ddr = codec_output->statistics_rd_noc - + av1_probability_table_rdwr_bytesperframe * + av1_tile_numbers / 1000 / 1000; + + codec_output->statistics_wr_ddr = codec_output->statistics_wr_noc - + av1_probability_table_rdwr_bytesperframe * + av1_tile_numbers / 1000 / 1000; + } else { + codec_output->statistics_rd_ddr = codec_output->statistics_rd_noc; + codec_output->statistics_wr_ddr = codec_output->statistics_wr_noc; + } + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->statistics_rd_noc; + codec_output->ddr_bw_rd += codec_output->statistics_rd_ddr; + codec_output->noc_bw_wr += codec_output->statistics_wr_noc; + codec_output->ddr_bw_wr += codec_output->statistics_wr_ddr; + } + + + codec_output->mmu_rd_ddr = 0; + codec_output->mmu_rd_noc = 0; + /* accumulation */ + codec_output->noc_bw_rd += codec_output->mmu_rd_noc; + codec_output->ddr_bw_rd += codec_output->mmu_rd_ddr; + + return 0; +} + +static int calculate_bandwidth_encoder_iris33( + struct api_calculation_input codec_input, + struct api_calculation_bw_output *codec_output) +{ + /* common control parameters */ + u32 frame_width; + u32 frame_height; + u32 frame_lcu_size; + u32 lcu_per_frame; + u32 target_bitrate; + u32 collocated_bytes_per_lcu; + + u32 frame420_y_bw_linear_8bpp; + u32 frame420_y_bw_no_ubwc_tile_10bpp; + u32 frame420_y_bw_linear_10bpp; + + u16 ubwc_tile_w; + u16 ubwc_tile_h; + + u32 dpb_compression_factor_y; + u32 dpb_compression_factor_cbcr; + + u32 reconstructed_write_bw_factor_rd; + u32 reference_y_read_bw_factor; + u32 reference_crcb_read_bw_factor; + + u32 en_vertical_tiles_width = 960; + u32 en_search_windows_size_horizontal = 96; + + u8 en_rotation_90_270 = 0; + /* TODO Can we use (codec_input.status_llc_onoff) for enc_llc_*? */ + u8 en_llc_enable_ref_rd_crcb = 0; + u8 en_llc_enable_rec_wr_uncompleted = 0; + u8 en_llc_enable_ref_rd_y_overlap = 0; + + u32 en_bins_to_bits_factor = 4; + + u32 en_tile_number; + u32 ipb_compression_factor_y; + u32 ipb_compression_factor; + + u32 large_bw_calculation_fp = 0; + + /* TODO Are these really needed in Encoder? */ + u32 bse_tlb_byte_per_lcu = 0; + u8 llc_enabled_bse_tlb = 1; + + /*H265D BSE tlb in LLC will be pored in Kailua */ + llc_enabled_bse_tlb = (codec_input.status_llc_onoff) ? 1 : 0; + + /* encoder control parameters + * iris3 2pipe uses 768 vertical tile width for IPP GoP + */ + if (codec_input.pipe_num == 2) { + en_vertical_tiles_width = + (codec_input.hierachical_layer == CODEC_GOP_IPP) ? 768 : 576; + // search ranges for iris3 2pipe + en_search_windows_size_horizontal = + (codec_input.hierachical_layer == CODEC_GOP_IPP) ? 192 : 96; + } + + frame_width = codec_input.frame_width; + frame_height = codec_input.frame_height; + if ((codec_input.codec == CODEC_H264) || + (codec_input.codec == CODEC_H264_CAVLC)) { + frame_lcu_size = 16; + collocated_bytes_per_lcu = 16; + } else if (codec_input.codec == CODEC_HEVC) { + frame_lcu_size = 32; + collocated_bytes_per_lcu = 64; + } else { + /* TODO What is the value for VP9, AV1? */ + frame_lcu_size = 16; + collocated_bytes_per_lcu = 16; /* TODO Fixes Uninitialized compilation error. */ + } + + lcu_per_frame = + calculate_number_lcus_iris33(frame_width, frame_height, frame_lcu_size); + + bse_tlb_byte_per_lcu = 16; /* TODO Should be in common declaration */ + + target_bitrate = (u32)(codec_input.bitrate_mbps); /* Mbps */ + + ubwc_tile_w = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 32 : 48; + ubwc_tile_h = (codec_input.bitdepth == CODEC_BITDEPTH_8) ? 8 : 4; + + /* yuv */ + if (codec_input.ipb_yuvrgb == 0) { + frame420_y_bw_linear_8bpp = + ((calculate_number_ubwctiles_iris33(frame_width, frame_height, + 32, 8) * 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + } else { /* RGBA */ + frame420_y_bw_linear_8bpp = + ((calculate_number_ubwctiles_iris33(frame_width, frame_height, + 16, 4) * 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + } + + frame420_y_bw_no_ubwc_tile_10bpp = + ((calculate_number_ubwctiles_iris33(frame_width, frame_height, 48, 4) * + 256 * codec_input.frame_rate + 999) / 1000 + 999) / 1000; + + frame420_y_bw_linear_10bpp = ((frame_width * frame_height * + codec_input.frame_rate * 2 + 999) / 1000 + 999) / 1000; + + /* TODO Integrate Compression Ratio returned by FW */ + get_compression_factors(&compression_factor, codec_input); + dpb_compression_factor_y = compression_factor.dpb_cf_y; + dpb_compression_factor_cbcr = compression_factor.dpb_cf_cbcr; + ipb_compression_factor_y = compression_factor.ipb_cr_y; + ipb_compression_factor = compression_factor.ipb_cr; + + en_tile_number = (frame_width % en_vertical_tiles_width) ? + ((frame_width / en_vertical_tiles_width) + 1) : + (frame_width / en_vertical_tiles_width); + + en_tile_number = en_tile_number * 100; + + /* ceil is same as excel roundup (float, 0); */ + reconstructed_write_bw_factor_rd = ((en_tile_number - 100) * 2 * + ((codec_input.lcu_size + ubwc_tile_w - 1) / ubwc_tile_w) * + ubwc_tile_w + (frame_width - 1)) / (frame_width)+100; + + reference_y_read_bw_factor = ((en_tile_number - 100) * 2 * + ((en_search_windows_size_horizontal + ubwc_tile_w - 1) / ubwc_tile_w) * + ubwc_tile_w + (frame_width - 1)) / frame_width + 100; + + reference_crcb_read_bw_factor = 150; + + codec_output->noc_bw_rd = 0; + codec_output->noc_bw_wr = 0; + codec_output->ddr_bw_rd = 0; + codec_output->ddr_bw_wr = 0; + + large_bw_calculation_fp = (target_bitrate * en_bins_to_bits_factor + 7) / 8; + codec_output->vsp_read_noc = large_bw_calculation_fp; + codec_output->vsp_read_ddr = codec_output->vsp_read_noc; + large_bw_calculation_fp = (target_bitrate + 7) / 8; + + codec_output->vsp_write_noc = codec_output->vsp_read_noc + + large_bw_calculation_fp; + + codec_output->vsp_write_ddr = codec_output->vsp_write_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->vsp_read_noc; + codec_output->ddr_bw_rd += codec_output->vsp_read_ddr; + codec_output->noc_bw_wr += codec_output->vsp_write_noc; + codec_output->ddr_bw_wr += codec_output->vsp_write_ddr; + + large_bw_calculation_fp = ((collocated_bytes_per_lcu * lcu_per_frame * + codec_input.frame_rate + 999) / 1000 + 999) / 1000; + + codec_output->collocated_rd_noc = large_bw_calculation_fp; + codec_output->collocated_wr_noc = codec_output->collocated_rd_noc; + codec_output->collocated_rd_ddr = codec_output->collocated_rd_noc; + codec_output->collocated_wr_ddr = codec_output->collocated_wr_noc; + + codec_output->collocated_rd_wr_total_noc = + (u32)(codec_output->collocated_rd_noc + codec_output->collocated_wr_noc); + codec_output->collocated_rd_wr_total_ddr = + codec_output->collocated_rd_wr_total_noc; + + /* I frame only */ + if (codec_input.hierachical_layer == CODEC_GOP_IONLY) { + codec_output->collocated_rd_noc = 0; + codec_output->collocated_wr_noc = 0; + codec_output->collocated_rd_ddr = 0; + codec_output->collocated_wr_ddr = 0; + codec_output->collocated_rd_wr_total_noc = 0; + codec_output->collocated_rd_wr_total_ddr = 0; + } + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->collocated_rd_noc; + codec_output->noc_bw_wr += codec_output->collocated_wr_noc; + codec_output->ddr_bw_rd += codec_output->collocated_rd_ddr; + codec_output->ddr_bw_wr += codec_output->collocated_wr_ddr; + + large_bw_calculation_fp = 0; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : + frame420_y_bw_no_ubwc_tile_10bpp) * reference_y_read_bw_factor; + + large_bw_calculation_fp = (large_bw_calculation_fp * + pineapple_en_readfactor[codec_input.hierachical_layer]); + + large_bw_calculation_fp = (large_bw_calculation_fp + + dpb_compression_factor_y - 1) / dpb_compression_factor_y; + + large_bw_calculation_fp = (large_bw_calculation_fp + 999) / 1000; + + codec_output->dpb_rd_y_noc = large_bw_calculation_fp; + + large_bw_calculation_fp = 0; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : + frame420_y_bw_no_ubwc_tile_10bpp) * reference_crcb_read_bw_factor / 2; + + large_bw_calculation_fp = large_bw_calculation_fp * + pineapple_en_readfactor[codec_input.hierachical_layer]; + + large_bw_calculation_fp = (large_bw_calculation_fp + + dpb_compression_factor_cbcr - 1) / dpb_compression_factor_cbcr; + + large_bw_calculation_fp = (large_bw_calculation_fp + 999) / 1000; + codec_output->dpb_rd_crcb_noc = large_bw_calculation_fp; + + large_bw_calculation_fp = 0; + + large_bw_calculation_fp = ((codec_input.bitdepth == CODEC_BITDEPTH_8) ? + frame420_y_bw_linear_8bpp : frame420_y_bw_no_ubwc_tile_10bpp) * + reconstructed_write_bw_factor_rd * + pineapple_en_writefactor[codec_input.hierachical_layer] / + pineapple_en_frame_num_parallel; + + large_bw_calculation_fp = (large_bw_calculation_fp + 999) / 1000; + + large_bw_calculation_fp = large_bw_calculation_fp * + (dpb_compression_factor_cbcr + dpb_compression_factor_y / 2); + + large_bw_calculation_fp = (large_bw_calculation_fp + + dpb_compression_factor_y - 1) / dpb_compression_factor_y; + + large_bw_calculation_fp = (large_bw_calculation_fp + + dpb_compression_factor_cbcr - 1) / dpb_compression_factor_cbcr; + + codec_output->dpb_wr_noc = large_bw_calculation_fp; + + /* + * Summary: + * by default (for both HFR and HSR cases) : + * -Any resolution and fps >= 120, enable layering. + * (120 -> 3, 240 -> 4, 480 -> 5) + * - (once we enable layering) : 50 per cent frames are Non - reference + * frames.recon write is disable by Venus firmware + * - Customer has ability to enable / disable layering. + * Hence, recon write savings would not be there if + * customer explicitly disables layer encoding. + */ + + /*HFR Cases use alternating rec write if not PWC*/ + if ((codec_input.frame_rate >= 120) && (codec_input.complexity_setting != 0)) + codec_output->dpb_wr_noc = codec_output->dpb_wr_noc / 2; + + /* for power cases with [B1] adaptive non-ref b frame */ + /* power caes IbP non reference b */ + if ((codec_input.hierachical_layer >= 1) && + (codec_input.hierachical_layer <= 3) && + (codec_input.complexity_setting != 0)) + codec_output->dpb_wr_noc = codec_output->dpb_wr_noc / 2; + + large_bw_calculation_fp = 0; + large_bw_calculation_fp = codec_output->dpb_wr_noc * + (reconstructed_write_bw_factor_rd - 100); + + large_bw_calculation_fp = (large_bw_calculation_fp + + reconstructed_write_bw_factor_rd - 1) / reconstructed_write_bw_factor_rd; + + codec_output->dpb_rdwr_duetooverlap_noc = large_bw_calculation_fp; + + codec_output->dpb_rd_y_ddr = (en_llc_enable_ref_rd_y_overlap) ? + (codec_output->dpb_rd_y_noc * 100 + reference_y_read_bw_factor - 1) / + reference_y_read_bw_factor : codec_output->dpb_rd_y_noc; + + codec_output->dpb_rd_crcb_ddr = (en_llc_enable_ref_rd_crcb) ? + (codec_output->dpb_rd_crcb_noc * 100 + reference_crcb_read_bw_factor - 1) / + reference_crcb_read_bw_factor : codec_output->dpb_rd_crcb_noc; + + codec_output->dpb_rdwr_duetooverlap_ddr = (en_llc_enable_rec_wr_uncompleted) ? + 0 : codec_output->dpb_rdwr_duetooverlap_noc; + + codec_output->dpb_wr_ddr = (en_llc_enable_rec_wr_uncompleted) ? + 0 : codec_output->dpb_wr_noc; + + /* I frame only */ + if (codec_input.hierachical_layer == CODEC_GOP_IONLY) { + codec_output->dpb_rd_y_noc = 0; + codec_output->dpb_rd_crcb_noc = 0; + codec_output->dpb_rdwr_duetooverlap_noc = 0; + codec_output->dpb_wr_noc = 0; + codec_output->dpb_rd_y_ddr = 0; + codec_output->dpb_rd_crcb_ddr = 0; + codec_output->dpb_rdwr_duetooverlap_ddr = 0; + codec_output->dpb_wr_ddr = 0; + } + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->dpb_rd_y_noc; + codec_output->noc_bw_rd += codec_output->dpb_rd_crcb_noc; + codec_output->noc_bw_rd += codec_output->dpb_rdwr_duetooverlap_noc; + codec_output->noc_bw_wr += codec_output->dpb_wr_noc; + codec_output->ddr_bw_rd += codec_output->dpb_rd_y_ddr; + codec_output->ddr_bw_rd += codec_output->dpb_rd_crcb_ddr; + codec_output->ddr_bw_rd += codec_output->dpb_rdwr_duetooverlap_ddr; + codec_output->ddr_bw_wr += codec_output->dpb_wr_ddr; + + if (codec_input.bitdepth == CODEC_BITDEPTH_8) { + if (codec_input.ipb_yuvrgb == 0) { /* yuv */ + large_bw_calculation_fp = ((frame420_y_bw_linear_8bpp) * 3 / 2); + codec_output->ipb_rd_total_noc = large_bw_calculation_fp; + if (codec_input.linear_ipb == 0) { + codec_output->ipb_rd_total_noc = + (large_bw_calculation_fp * 100 + + ipb_compression_factor - 1) / + ipb_compression_factor; + } + } else { /* rgb */ + large_bw_calculation_fp = frame420_y_bw_linear_8bpp; + codec_output->ipb_rd_total_noc = large_bw_calculation_fp; + if (codec_input.linear_ipb == 0) { + if (codec_input.complexity_setting == 0) /* pwc */ + codec_output->ipb_rd_total_noc = + (large_bw_calculation_fp * 100 + + en_original_compression_factor_rgba_pwd_iris33 + - 1) / + en_original_compression_factor_rgba_pwd_iris33; + else + codec_output->ipb_rd_total_noc = + (large_bw_calculation_fp * 100 + + en_original_compression_factor_rgba_avg_iris33 - 1) / + en_original_compression_factor_rgba_avg_iris33; + } + } + } else { + if (codec_input.linear_ipb == 1) { + large_bw_calculation_fp = (frame420_y_bw_linear_10bpp) * 3 / 2; + codec_output->ipb_rd_total_noc = large_bw_calculation_fp; + } else { + large_bw_calculation_fp = (frame420_y_bw_no_ubwc_tile_10bpp * + 300 / 2 + ipb_compression_factor - 1) / ipb_compression_factor; + codec_output->ipb_rd_total_noc = large_bw_calculation_fp; + } + } + + if (en_rotation_90_270) { + if (codec_input.codec == CODEC_HEVC) { + if ((codec_input.bitdepth == CODEC_BITDEPTH_8) && + (codec_input.ipb_yuvrgb == 0)) + codec_output->ipb_rd_total_noc = codec_output->ipb_rd_total_noc + * 1; + else + codec_output->ipb_rd_total_noc = codec_output->ipb_rd_total_noc + * 3; + } else { + codec_output->ipb_rd_total_noc = codec_output->ipb_rd_total_noc * 2; + } + } + + codec_output->ipb_rd_total_ddr = codec_output->ipb_rd_total_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->ipb_rd_total_noc; + codec_output->ddr_bw_rd += codec_output->ipb_rd_total_ddr; + + codec_output->bse_tlb_rd_noc = + ((bse_tlb_byte_per_lcu * lcu_per_frame * codec_input.frame_rate + 999) + / 1000 + 999) / 1000; + + if (llc_enabled_bse_tlb) /* TODO should be common declaration */ + codec_output->bse_tlb_rd_ddr = 0; + else + codec_output->bse_tlb_rd_ddr = codec_output->bse_tlb_rd_noc; + + codec_output->bse_tlb_wr_noc = codec_output->bse_tlb_rd_noc; + + if (llc_enabled_bse_tlb) + codec_output->bse_tlb_wr_ddr = 0; + else + codec_output->bse_tlb_wr_ddr = codec_output->bse_tlb_wr_noc; + + /* accumulation */ + codec_output->noc_bw_rd += codec_output->bse_tlb_rd_noc; + codec_output->ddr_bw_rd += codec_output->bse_tlb_rd_ddr; + codec_output->noc_bw_wr += codec_output->bse_tlb_wr_noc; + codec_output->ddr_bw_wr += codec_output->bse_tlb_wr_ddr; + + codec_output->mmu_rd_ddr = 0; + codec_output->mmu_rd_noc = 0; + /* accumulation */ + codec_output->noc_bw_rd += codec_output->mmu_rd_noc; + codec_output->ddr_bw_rd += codec_output->mmu_rd_ddr; + + return 0; +} + +int msm_vidc_calculate_bandwidth(struct api_calculation_input codec_input, + struct api_calculation_bw_output *codec_output) +{ + int rc = 0; + + if (codec_input.decoder_or_encoder == CODEC_DECODER) { + rc = calculate_bandwidth_decoder_iris33(codec_input, codec_output); + } else if (codec_input.decoder_or_encoder == CODEC_ENCODER) { + rc = calculate_bandwidth_encoder_iris33(codec_input, codec_output); + } else { + d_vpr_e("%s: invalid codec\n", codec_input.decoder_or_encoder); + return -EINVAL; + } + + return rc; +} diff --git a/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_clock_iris33.c b/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_clock_iris33.c new file mode 100644 index 0000000000..3fc33309b5 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_clock_iris33.c @@ -0,0 +1,726 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "perf_static_model.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_platform.h" + +#define ENABLE_FINEBITRATE_SUBUHD60 0 + +static u32 codec_encoder_gop_complexity_table_fp[8][3]; +static u32 codec_mbspersession_iris33; +static u32 input_bitrate_fp; + +/* + * Chipset Generation Technology: SW/FW overhead profiling + * need update with new numbers + */ +static u32 frequency_table_iris33[2][6] = { + /* //make lowsvs_D1 as invalid; */ + {533, 480, 435, 380, 300, 196}, + {840, 720, 652, 570, 450, 294}, +}; + +static u32 frequency_table_iris33_2p[2][6] = { + /* //make lowsvs_D1 as invalid; */ + { 533, 444, 366, 338, 240, 192 }, + { 800, 666, 549, 507, 360, 288 }, +}; + + /* + * TODO Move to pineapple.c + * TODO Replace hardcoded values with + * ENCODER_VPP_TARGET_CLK_PER_MB_IRIS33 in CPP file. + */ + +/* Tensilica cycles profiled by FW team in lanai device Feb 2022 */ +#define DECODER_VPP_FW_OVERHEAD_IRIS33_AV1D ((80000*3)/2) +#define DECODER_VPP_FW_OVERHEAD_IRIS33_NONAV1D ((60000*3)/2) + + /* Tensilica cycles */ +#define DECODER_VPP_FW_OVERHEAD_IRIS33 (0) + +/* Tensilica cycles; this is measured in Lahaina 1stage with FW profiling */ +#define DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS33 (93000) + +#define DECODER_VSP_FW_OVERHEAD_IRIS33 \ + (DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS33 - DECODER_VPP_FW_OVERHEAD_IRIS33) + +/* Tensilica cycles; encoder has ARP register */ +#define ENCODER_VPP_FW_OVERHEAD_IRIS33 (69000*3/2) + +#define ENCODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS33 \ + (ENCODER_VPP_FW_OVERHEAD_IRIS33 + DECODER_VSP_FW_OVERHEAD_IRIS33) + +#define DECODER_SW_OVERHEAD_IRIS33 (489583) +#define ENCODER_SW_OVERHEAD_IRIS33 (489583) + +/* Video IP Core Technology: pipefloor and pipe penlaty */ +// static u32 encoder_vpp_target_clk_per_mb_iris33[2] = {320, 675}; +static u32 decoder_vpp_target_clk_per_mb_iris33 = 200; + +/* + * These pipe penalty numbers only applies to 4 pipe + * For 2pipe and 1pipe, these numbers need recalibrate + */ +static u32 pipe_penalty_iris33[3][3] = { + /* NON AV1 */ + {1059, 1059, 1059}, + /* AV1 RECOMMENDED TILE 1080P_V2XH1, UHD_V2X2, 8KUHD_V8X2 */ + {1410, 1248, 1226}, + /* AV1 YOUTUBE/NETFLIX TILE 1080P_V4XH2_V4X1, UHD_V8X4_V8X1, 8KUHD_V8X8_V8X1 */ + {2039, 2464, 1191}, +}; + +static u32 pipe_penalty_iris33_2p[3][3] = { + /* NON AV1 */ + { 1059, 1059, 1059 }, + /* AV1 RECOMMENDED TILE 1080P_V2XH1, UHD_V2X2, 8KUHD_V8X2 */ + { 1123, 1079, 1079 }, + /* AV1 YOUTUBE/NETFLIX TILE 1080P_V4XH2_V4X1, UHD_V8X4_V8X1, 8KUHD_V8X8_V8X1 */ + { 1197, 1287, 1051 }, +}; + +/* + * Video IP Core Technology: bitrate constraint + * HW limit bitrate table (these values are measured end to end fw/sw impacts are also considered) + * TODO Can we convert to Cycles/MB? This will remove DIVISION. + */ +static u32 bitrate_table_iris33_2stage_fp[5][10] = { + /* h264 cavlc */ + {0, 220, 220, 220, 220, 220, 220, 220, 220, 220}, + /* h264 cabac */ + {0, 140, 150, 160, 175, 190, 190, 190, 190, 190}, + /* h265 */ + {90, 140, 160, 180, 190, 200, 200, 200, 200, 200}, + /* vp9 */ + {90, 90, 90, 90, 90, 90, 90, 90, 90, 90}, + /* av1 */ + {130, 130, 120, 120, 120, 120, 120, 120, 120, 120}, +}; + +static u32 bitrate_table_iris33_2p_2stage_fp[5][10] = { + /* h264 cavlc */ + { 0, 220, 220, 220, 220, 220, 220, 220, 220, 220 }, + /* h264 cabac */ + { 0, 140, 150, 160, 160, 160, 160, 160, 160, 160 }, + /* h265 */ + { 90, 140, 160, 160, 160, 160, 160, 160, 160, 160 }, + /*vp9 */ + { 90, 90, 90, 90, 90, 90, 90, 90, 90, 90 }, + { 130, 130, 120, 120, 120, 120, 120, 120, 120, 120 }, +}; + +/* + * HW limit bitrate table (these values are measured + * end to end fw/sw impacts are also considered) + */ +static u32 bitrate_table_iris33_1stage_fp[5][10] = { /* 1-stage assume IPPP */ + /* h264 cavlc */ + {0, 220, 220, 220, 220, 220, 220, 220, 220, 220}, + /* h264 cabac */ + {0, 110, 150, 150, 150, 150, 150, 150, 150, 150}, + /* h265 */ + {0, 140, 150, 150, 150, 150, 150, 150, 150, 150}, + /* vp9 */ + {0, 70, 70, 70, 70, 70, 70, 70, 70, 70}, + /* av1 */ + {0, 100, 100, 100, 100, 100, 100, 100, 100, 100}, +}; + +/* 8KUHD60; UHD240; 1080p960 with B */ +static u32 fp_pixel_count_bar0 = 3840 * 2160 * 240; +/* 8KUHD60; UHD240; 1080p960 without B */ +static u32 fp_pixel_count_bar1 = 3840 * 2160 * 240; +/* 1080p720 */ +static u32 fp_pixel_count_bar2 = 3840 * 2160 * 180; +/* UHD120 */ +static u32 fp_pixel_count_bar3 = 3840 * 2160 * 120; +/* UHD90 */ +static u32 fp_pixel_count_bar4 = 3840 * 2160 * 90; +/* UHD60 */ +static u32 fp_pixel_count_bar5 = 3840 * 2160 * 60; +/* UHD30; FHD120; HD240 */ +static u32 fp_pixel_count_bar6 = 3840 * 2160 * 30; +/* FHD60 */ +static u32 fp_pixel_count_bar7 = 1920 * 1080 * 60; +/* FHD30 */ +static u32 fp_pixel_count_bar8 = 1920 * 1080 * 30; +/* HD30 */ +static u32 fp_pixel_count_bar9 = 1280 * 720 * 30; + +static u32 calculate_number_mbs_iris33(u32 width, u32 height, u32 lcu_size) +{ + u32 mbs_width = (width % lcu_size) ? + (width / lcu_size + 1) : (width / lcu_size); + + u32 mbs_height = (height % lcu_size) ? + (height / lcu_size + 1) : (height / lcu_size); + + return mbs_width * mbs_height * (lcu_size / 16) * (lcu_size / 16); +} + +static int initialize_encoder_complexity_table(void) +{ + /* Beging Calculate Encoder GOP Complexity Table and HW Floor numbers */ + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] = 70000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY] = 10000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY] * 100); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY] - 1); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] / + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I3B4b1P][CODEC_ENCODER_GOP_P_ENTRY]); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] = 30000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY] = 10000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY] * 100); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY] - 1); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_FACTORY_ENTRY] / + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_I1B2b1P][CODEC_ENCODER_GOP_P_ENTRY]); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] = 10000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY] = 10000; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY] * 100); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY] - 1); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_FACTORY_ENTRY] / + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IbP][CODEC_ENCODER_GOP_P_ENTRY]); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] = 0; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY] = 1; + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] * 150 + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY] * 100); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY] - 1); + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] = + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_FACTORY_ENTRY] / + (codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_Bb_ENTRY] + + codec_encoder_gop_complexity_table_fp + [CODEC_GOP_IPP][CODEC_ENCODER_GOP_P_ENTRY]); + + return 0; +} + +u32 get_bitrate_entry(u32 pixle_count) +{ + u32 bitrate_entry = 0; + + if (pixle_count >= fp_pixel_count_bar1) + bitrate_entry = 1; + else if (pixle_count >= fp_pixel_count_bar2) + bitrate_entry = 2; + else if (pixle_count >= fp_pixel_count_bar3) + bitrate_entry = 3; + else if (pixle_count >= fp_pixel_count_bar4) + bitrate_entry = 4; + else if (pixle_count >= fp_pixel_count_bar5) + bitrate_entry = 5; + else if (pixle_count >= fp_pixel_count_bar6) + bitrate_entry = 6; + else if (pixle_count >= fp_pixel_count_bar7) + bitrate_entry = 7; + else if (pixle_count >= fp_pixel_count_bar8) + bitrate_entry = 8; + else if (pixle_count >= fp_pixel_count_bar9) + bitrate_entry = 9; + else + bitrate_entry = 9; + + return bitrate_entry; +} + +static int calculate_vsp_min_freq(struct api_calculation_input codec_input, + struct api_calculation_freq_output *codec_output) +{ + u32 (*frequency_table_value)[6]; + u32 (*bitrate_table_2stage_value)[10]; + /* + * VSP calculation + * different methodology from Lahaina + */ + u32 vsp_hw_min_frequency = 0; + /* UInt32 decoder_vsp_fw_overhead = 100 + 5; // amplified by 100x */ + u32 fw_sw_vsp_offset = 1000 + 55; /* amplified by 1000x */ + + /* + * Ignore fw_sw_vsp_offset, as this is baked into the reference bitrate tables. + * As a consequence remove x1000 multipler as well. + */ + u32 codec = codec_input.codec; + /* UInt32 *bitratetable; */ + u32 pixle_count = codec_input.frame_width * + codec_input.frame_height * codec_input.frame_rate; + + u8 bitrate_entry = get_bitrate_entry(pixle_count); /* TODO EXTRACT */ + + input_bitrate_fp = ((u32)(codec_input.bitrate_mbps * 100 + 99)) / 100; + + if (codec_input.vpu_ver == VPU_VERSION_IRIS33) { + frequency_table_value = frequency_table_iris33; + bitrate_table_2stage_value = bitrate_table_iris33_2stage_fp; + } else if (codec_input.vpu_ver == VPU_VERSION_IRIS33_2P) { + frequency_table_value = frequency_table_iris33_2p; + bitrate_table_2stage_value = bitrate_table_iris33_2p_2stage_fp; + } + + /* 8KUHD60fps with B frame */ + if ((pixle_count >= fp_pixel_count_bar0) && + (codec_input.hierachical_layer != CODEC_GOP_IPP)) { + /* + * FORMULA: VSPfreq = NOMINAL * (InputBitrate / ReferenceBitrate); + * ReferenceBitrate = 0 for, + * - 1Stage TURBO, all Codecs. + * - 2Stage TURBO, H264 & H265. + * + * 8KUHD60fps with B frame + * - bitrate_entry = 0 + * - Clock=NOMINAL for H264 & 2Stage H265. Because bitrate + * table entry for TURBO is 0. + * + * TODO : Reduce these conditions by removing the zero entries from Bitrate table. + */ + + vsp_hw_min_frequency = frequency_table_value[0][2] * + input_bitrate_fp * 1000; + + if (codec_input.codec == CODEC_AV1) + vsp_hw_min_frequency = frequency_table_value[0][1] * + input_bitrate_fp * 1000; + + if ((codec_input.codec == CODEC_H264) || + (codec_input.codec == CODEC_H264_CAVLC)) { + vsp_hw_min_frequency = (frequency_table_value[0][2] * 1000 + + (fw_sw_vsp_offset - 1)); + vsp_hw_min_frequency = + DIV_ROUND_UP(vsp_hw_min_frequency, fw_sw_vsp_offset); + } else { + if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) { + vsp_hw_min_frequency = vsp_hw_min_frequency + + (bitrate_table_2stage_value[codec][0] * + fw_sw_vsp_offset - 1); + vsp_hw_min_frequency = DIV_ROUND_UP(vsp_hw_min_frequency, + (bitrate_table_2stage_value[codec][0]) * + fw_sw_vsp_offset); + } else { + vsp_hw_min_frequency = vsp_hw_min_frequency + + (bitrate_table_iris33_1stage_fp[codec][0] * + fw_sw_vsp_offset - 1); + vsp_hw_min_frequency = DIV_ROUND_UP(vsp_hw_min_frequency, + (bitrate_table_iris33_1stage_fp[codec][0]) * + fw_sw_vsp_offset); + } + } + } else { + vsp_hw_min_frequency = frequency_table_value[0][2] * + input_bitrate_fp * 1000; + + if (codec_input.codec == CODEC_AV1 && bitrate_entry == 1) + vsp_hw_min_frequency = frequency_table_value[0][1] * + input_bitrate_fp * 1000; + + if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) { + vsp_hw_min_frequency = vsp_hw_min_frequency + + (bitrate_table_2stage_value[codec][bitrate_entry] * + fw_sw_vsp_offset - 1); + vsp_hw_min_frequency = DIV_ROUND_UP(vsp_hw_min_frequency, + (bitrate_table_2stage_value[codec][bitrate_entry]) * + fw_sw_vsp_offset); + } else { + vsp_hw_min_frequency = vsp_hw_min_frequency + + (bitrate_table_iris33_1stage_fp[codec][bitrate_entry] * + fw_sw_vsp_offset - 1); + vsp_hw_min_frequency = DIV_ROUND_UP(vsp_hw_min_frequency, + (bitrate_table_iris33_1stage_fp[codec][bitrate_entry]) * + fw_sw_vsp_offset); + } + } + + codec_output->vsp_min_freq = vsp_hw_min_frequency; + return 0; +} + +static u32 calculate_pipe_penalty(struct api_calculation_input codec_input) +{ + u32 pipe_penalty_codec = 0; + u8 avid_commercial_content = 0; + u32 pixel_count = 0; + u32 (*pipe_penalty_value)[3]; + + if (codec_input.vpu_ver == VPU_VERSION_IRIS33) + pipe_penalty_value = pipe_penalty_iris33; + else if (codec_input.vpu_ver == VPU_VERSION_IRIS33_2P) + pipe_penalty_value = pipe_penalty_iris33_2p; + + /* decoder */ + if (codec_input.decoder_or_encoder == CODEC_DECODER) { + pipe_penalty_codec = pipe_penalty_value[0][0]; + avid_commercial_content = codec_input.av1d_commer_tile_enable; + if (codec_input.codec == CODEC_AV1) { + pixel_count = codec_input.frame_width * codec_input.frame_height; + if (pixel_count <= 1920 * 1080) + pipe_penalty_codec = + pipe_penalty_value[avid_commercial_content + 1][0]; + else if (pixel_count < 3840 * 2160) + pipe_penalty_codec = + (pipe_penalty_value[avid_commercial_content + 1][0] + + pipe_penalty_value[avid_commercial_content + 1][1]) / 2; + else if ((pixel_count == 3840 * 2160) || + (pixel_count == 4096 * 2160) || (pixel_count == 4096 * 2304)) + pipe_penalty_codec = + pipe_penalty_value[avid_commercial_content + 1][1]; + else if (pixel_count < 7680 * 4320) + pipe_penalty_codec = + (pipe_penalty_value[avid_commercial_content + 1][1] + + pipe_penalty_value[avid_commercial_content + 1][2]) / 2; + else + pipe_penalty_codec = + pipe_penalty_value[avid_commercial_content + 1][2]; + } + } else { + pipe_penalty_codec = 101; + } + + return pipe_penalty_codec; +} + +static int calculate_vpp_min_freq(struct api_calculation_input codec_input, + struct api_calculation_freq_output *codec_output) +{ + u32 vpp_hw_min_frequency = 0; + u32 fmin = 0; + u32 tensilica_min_frequency = 0; + u32 decoder_vsp_fw_overhead = 100 + 5; /* amplified by 100x */ + /* UInt32 fw_sw_vsp_offset = 1000 + 55; amplified by 1000x */ + /* TODO from calculate_sw_vsp_min_freq */ + u32 vsp_hw_min_frequency = codec_output->vsp_min_freq; + u32 pipe_penalty_codec = 0; + u32 fmin_fwoverhead105 = 0; + u32 fmin_measured_fwoverhead = 0; + u32 lpmode_uhd_cycle_permb = 0; + u32 hqmode1080p_cycle_permb = 0; + u32 encoder_vpp_target_clk_per_mb = 0; + u32 decoder_vpp_fw_overhead = DECODER_VPP_FW_OVERHEAD_IRIS33; + + codec_mbspersession_iris33 = + calculate_number_mbs_iris33(codec_input.frame_width, + codec_input.frame_height, codec_input.lcu_size) * + codec_input.frame_rate; + + /* Section 2. 0 VPP/VSP calculation */ + if (codec_input.decoder_or_encoder == CODEC_DECODER) { /* decoder */ + vpp_hw_min_frequency = ((decoder_vpp_target_clk_per_mb_iris33) * + (codec_mbspersession_iris33) + codec_input.pipe_num - 1) / + (codec_input.pipe_num); + + vpp_hw_min_frequency = (vpp_hw_min_frequency + 99999) / 1000000; + + if (codec_input.pipe_num > 1) { + pipe_penalty_codec = calculate_pipe_penalty(codec_input); + vpp_hw_min_frequency = (vpp_hw_min_frequency * + pipe_penalty_codec + 999) / 1000; + } + + if (codec_input.codec == CODEC_AV1) + decoder_vpp_fw_overhead = DECODER_VPP_FW_OVERHEAD_IRIS33_AV1D; + else + decoder_vpp_fw_overhead = DECODER_VPP_FW_OVERHEAD_IRIS33_NONAV1D; + + if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) { + /* FW overhead, convert FW cycles to impact to one pipe */ + + decoder_vpp_fw_overhead = + DIV_ROUND_UP((decoder_vpp_fw_overhead * 10 * + codec_input.frame_rate), 15); + + decoder_vpp_fw_overhead = + DIV_ROUND_UP((decoder_vpp_fw_overhead * 1000), + (codec_mbspersession_iris33 * + decoder_vpp_target_clk_per_mb_iris33 / codec_input.pipe_num)); + + decoder_vpp_fw_overhead += 1000; + decoder_vpp_fw_overhead = (decoder_vpp_fw_overhead < 1050) ? + 1050 : decoder_vpp_fw_overhead; + + /* VPP HW + FW */ + if (codec_input.linear_opb == 1 && + codec_input.bitdepth == CODEC_BITDEPTH_10) + /* multiply by 1.20 for 10b case */ + decoder_vpp_fw_overhead = 1200 + decoder_vpp_fw_overhead - 1000; + + vpp_hw_min_frequency = (vpp_hw_min_frequency * + decoder_vpp_fw_overhead + 999) / 1000; + + /* VSP HW+FW */ + vsp_hw_min_frequency = + (vsp_hw_min_frequency * decoder_vsp_fw_overhead + 99) / 100; + + fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ? + vpp_hw_min_frequency : vsp_hw_min_frequency; + } else { + /* 1-stage need SW cycles + FW cycles + HW time */ + if (codec_input.linear_opb == 1 && + codec_input.bitdepth == CODEC_BITDEPTH_10) + /* multiply by 1.20 for 10b linear case */ + vpp_hw_min_frequency = + (vpp_hw_min_frequency * 1200 + 999) / 1000; + + /* + * HW time + * comment: 02/23/2021 SY: the bitrate is measured bitrate, + * the overlapping effect is already considered into bitrate. + * no need to add extra anymore + */ + fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ? + vpp_hw_min_frequency : vsp_hw_min_frequency; + + /* FW time */ + fmin_fwoverhead105 = (fmin * 105 + 99) / 100; + fmin_measured_fwoverhead = fmin + + (((DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS33 * + codec_input.frame_rate * 10 + 14) / 15 + 999) / 1000 + 999) / + 1000; + + fmin = (fmin_fwoverhead105 > fmin_measured_fwoverhead) ? + fmin_fwoverhead105 : fmin_measured_fwoverhead; + } + + tensilica_min_frequency = (DECODER_SW_OVERHEAD_IRIS33 * 10 + 14) / 15; + tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000; + tensilica_min_frequency = tensilica_min_frequency * codec_input.frame_rate; + tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000; + fmin = (tensilica_min_frequency > fmin) ? tensilica_min_frequency : fmin; + } else { /* encoder */ + /* Decide LP/HQ */ + u8 hq_mode = 0; + + if (codec_input.pipe_num > 1) + if (codec_input.frame_width * codec_input.frame_height <= + 1920 * 1080) + if (codec_input.frame_width * codec_input.frame_height * + codec_input.frame_rate <= 1920 * 1080 * 60) + hq_mode = 1; + + codec_output->enc_hqmode = hq_mode; + + /* Section 1. 0 */ + /* TODO ONETIME call, should be in another place. */ + initialize_encoder_complexity_table(); + + /* End Calculate Encoder GOP Complexity Table */ + + /* VPP base cycle */ + lpmode_uhd_cycle_permb = (320 * + codec_encoder_gop_complexity_table_fp + [codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + 99) / 100; + + if ((codec_input.frame_width == 1920) && + ((codec_input.frame_height == 1080) || + (codec_input.frame_height == 1088)) && + (codec_input.frame_rate >= 480)) + lpmode_uhd_cycle_permb = (90 * 4 * + codec_encoder_gop_complexity_table_fp + [codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + 99) / 100; + + if ((codec_input.frame_width == 1280) && + ((codec_input.frame_height == 720) || + (codec_input.frame_height == 768)) && + (codec_input.frame_rate >= 960)) + lpmode_uhd_cycle_permb = (99 * 4 * + codec_encoder_gop_complexity_table_fp + [codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + 99) / 100; + + hqmode1080p_cycle_permb = (675 * + codec_encoder_gop_complexity_table_fp + [codec_input.hierachical_layer][CODEC_ENCODER_GOP_FACTORY_ENTRY] + + 99) / 100; + + encoder_vpp_target_clk_per_mb = (hq_mode) ? + hqmode1080p_cycle_permb : lpmode_uhd_cycle_permb; + + vpp_hw_min_frequency = ((encoder_vpp_target_clk_per_mb) * + (codec_mbspersession_iris33) + codec_input.pipe_num - 1) / + (codec_input.pipe_num); + + vpp_hw_min_frequency = (vpp_hw_min_frequency + 99999) / 1000000; + + if (codec_input.pipe_num > 1) { + u32 pipe_penalty_codec = 101; + + vpp_hw_min_frequency = (vpp_hw_min_frequency * + pipe_penalty_codec + 99) / 100; + } + + if (codec_input.vsp_vpp_mode == CODEC_VSPVPP_MODE_2S) { + /* FW overhead, convert FW cycles to impact to one pipe */ + u64 encoder_vpp_fw_overhead = 0; + + encoder_vpp_fw_overhead = + DIV_ROUND_UP((ENCODER_VPP_FW_OVERHEAD_IRIS33 * 10 * + codec_input.frame_rate), 15); + + encoder_vpp_fw_overhead = + DIV_ROUND_UP((encoder_vpp_fw_overhead * 1000), + (codec_mbspersession_iris33 * encoder_vpp_target_clk_per_mb / + codec_input.pipe_num)); + + encoder_vpp_fw_overhead += 1000; + + encoder_vpp_fw_overhead = (encoder_vpp_fw_overhead < 1050) ? + 1050 : encoder_vpp_fw_overhead; + + /* VPP HW + FW */ + vpp_hw_min_frequency = (vpp_hw_min_frequency * + encoder_vpp_fw_overhead + 999) / 1000; + + /* TODO : decoder_vsp_fw_overhead? */ + vsp_hw_min_frequency = (vsp_hw_min_frequency * + decoder_vsp_fw_overhead + 99) / 100; + + fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ? + vpp_hw_min_frequency : vsp_hw_min_frequency; + } else { + /* HW time */ + fmin = (vpp_hw_min_frequency > vsp_hw_min_frequency) ? + vpp_hw_min_frequency : vsp_hw_min_frequency; + + /* FW time */ + fmin_fwoverhead105 = (fmin * 105 + 99) / 100; + fmin_measured_fwoverhead = fmin + + (((DECODER_VPPVSP1STAGE_FW_OVERHEAD_IRIS33 * + codec_input.frame_rate * 10 + 14) / 15 + 999) / + 1000 + 999) / 1000; + + fmin = (fmin_fwoverhead105 > fmin_measured_fwoverhead) ? + fmin_fwoverhead105 : fmin_measured_fwoverhead; + /* SW time */ + } + + tensilica_min_frequency = (ENCODER_SW_OVERHEAD_IRIS33 * 10 + 14) / 15; + tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000; + + tensilica_min_frequency = tensilica_min_frequency * + codec_input.frame_rate; + + tensilica_min_frequency = (tensilica_min_frequency + 999) / 1000; + + fmin = (tensilica_min_frequency > fmin) ? + tensilica_min_frequency : fmin; + } + + codec_output->vpp_min_freq = vpp_hw_min_frequency; + codec_output->vsp_min_freq = vsp_hw_min_frequency; + codec_output->tensilica_min_freq = tensilica_min_frequency; + codec_output->hw_min_freq = fmin; + + return 0; +} + +int msm_vidc_calculate_frequency(struct api_calculation_input codec_input, + struct api_calculation_freq_output *codec_output) +{ + int rc = 0; + + rc = calculate_vsp_min_freq(codec_input, codec_output); + if (rc) + return rc; + + rc = calculate_vpp_min_freq(codec_input, codec_output); + if (rc) + return rc; + + return rc; +} diff --git a/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_iris33.c b/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_iris33.c new file mode 100644 index 0000000000..45450dba79 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_iris33.c @@ -0,0 +1,1614 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "msm_vidc_iris33.h" +#include "msm_vidc_buffer_iris33.h" +#include "msm_vidc_power_iris33.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_buffer.h" +#include "msm_vidc_state.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_variant.h" +#include "venus_hfi.h" + +#define VIDEO_ARCH_LX 1 + +#define VCODEC_BASE_OFFS_IRIS33 0x00000000 +#define VCODEC_CPU_CS_IRIS33 0x000A0000 +#define AON_BASE_OFFS 0x000E0000 + +#define VCODEC_VPU_CPU_CS_VCICMDARG0_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x24) +#define VCODEC_VPU_CPU_CS_VCICMDARG1_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x28) +#define VCODEC_VPU_CPU_CS_SCIACMD_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x48) +#define VCODEC_VPU_CPU_CS_SCIACMDARG0_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x4C) +#define VCODEC_VPU_CPU_CS_SCIACMDARG1_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x50) +#define VCODEC_VPU_CPU_CS_SCIACMDARG2_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x54) +#define VCODEC_VPU_CPU_CS_SCIBCMD_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x5C) +#define VCODEC_VPU_CPU_CS_SCIBCMDARG0_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x60) +#define VCODEC_VPU_CPU_CS_SCIBARG1_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x64) +#define VCODEC_VPU_CPU_CS_SCIBARG2_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x68) + +#define HFI_CTRL_INIT_IRIS33 VCODEC_VPU_CPU_CS_SCIACMD_IRIS33 +#define HFI_CTRL_STATUS_IRIS33 VCODEC_VPU_CPU_CS_SCIACMDARG0_IRIS33 +typedef enum { + HFI_CTRL_NOT_INIT = 0x0, + HFI_CTRL_READY = 0x1, + HFI_CTRL_ERROR_FATAL = 0x2, + HFI_CTRL_ERROR_UC_REGION_NOT_SET = 0x4, + HFI_CTRL_ERROR_HW_FENCE_QUEUE = 0x8, + HFI_CTRL_PC_READY = 0x100, + HFI_CTRL_VCODEC_IDLE = 0x40000000 +} hfi_ctrl_status_type; + +#define HFI_QTBL_INFO_IRIS33 VCODEC_VPU_CPU_CS_SCIACMDARG1_IRIS33 +typedef enum { + HFI_QTBL_DISABLED = 0x00, + HFI_QTBL_ENABLED = 0x01, +} hfi_qtbl_status_type; + +#define HFI_QTBL_ADDR_IRIS33 VCODEC_VPU_CPU_CS_SCIACMDARG2_IRIS33 +#define HFI_MMAP_ADDR_IRIS33 VCODEC_VPU_CPU_CS_SCIBCMDARG0_IRIS33 +#define HFI_UC_REGION_ADDR_IRIS33 VCODEC_VPU_CPU_CS_SCIBARG1_IRIS33 +#define HFI_UC_REGION_SIZE_IRIS33 VCODEC_VPU_CPU_CS_SCIBARG2_IRIS33 +#define HFI_DEVICE_REGION_ADDR_IRIS33 VCODEC_VPU_CPU_CS_VCICMDARG0_IRIS33 +#define HFI_DEVICE_REGION_SIZE_IRIS33 VCODEC_VPU_CPU_CS_VCICMDARG1_IRIS33 +#define HFI_SFR_ADDR_IRIS33 VCODEC_VPU_CPU_CS_SCIBCMD_IRIS33 + +#define CPU_CS_A2HSOFTINTCLR_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x1C) +#define CPU_CS_H2XSOFTINTEN_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x148) + +#define CPU_CS_AHB_BRIDGE_SYNC_RESET (VCODEC_CPU_CS_IRIS33 + 0x160) + +/* FAL10 Feature Control */ +#define CPU_CS_X2RPMh_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x168) + +#define CPU_IC_SOFTINT_IRIS33 (VCODEC_CPU_CS_IRIS33 + 0x150) +#define CPU_IC_SOFTINT_H2A_SHFT_IRIS33 0x0 + +/* + * -------------------------------------------------------------------------- + * MODULE: wrapper + * -------------------------------------------------------------------------- + */ +#define WRAPPER_BASE_OFFS_IRIS33 0x000B0000 +#define WRAPPER_INTR_STATUS_IRIS33 (WRAPPER_BASE_OFFS_IRIS33 + 0x0C) +#define WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS33 0x8 +#define WRAPPER_INTR_STATUS_A2H_BMSK_IRIS33 0x4 + +#define WRAPPER_INTR_MASK_IRIS33 (WRAPPER_BASE_OFFS_IRIS33 + 0x10) +#define WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS33 0x8 +#define WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS33 0x4 + +#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS33 (WRAPPER_BASE_OFFS_IRIS33 + 0x54) +#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS33 (WRAPPER_BASE_OFFS_IRIS33 + 0x58) +#define WRAPPER_IRIS_CPU_NOC_LPI_CONTROL (WRAPPER_BASE_OFFS_IRIS33 + 0x5C) +#define WRAPPER_IRIS_CPU_NOC_LPI_STATUS (WRAPPER_BASE_OFFS_IRIS33 + 0x60) +#define WRAPPER_CORE_POWER_STATUS (WRAPPER_BASE_OFFS_IRIS33 + 0x80) +#define WRAPPER_CORE_CLOCK_CONFIG_IRIS33 (WRAPPER_BASE_OFFS_IRIS33 + 0x88) + +/* + * -------------------------------------------------------------------------- + * MODULE: tz_wrapper + * -------------------------------------------------------------------------- + */ +#define WRAPPER_TZ_BASE_OFFS 0x000C0000 +#define WRAPPER_TZ_CPU_STATUS (WRAPPER_TZ_BASE_OFFS + 0x10) +#define WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS + 0x14) +#define WRAPPER_TZ_QNS4PDXFIFO_RESET (WRAPPER_TZ_BASE_OFFS + 0x18) + +#define AON_WRAPPER_MVP_NOC_LPI_CONTROL (AON_BASE_OFFS) +#define AON_WRAPPER_MVP_NOC_LPI_STATUS (AON_BASE_OFFS + 0x4) +#define AON_WRAPPER_MVP_NOC_CORE_SW_RESET (AON_BASE_OFFS + 0x18) +#define AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL (AON_BASE_OFFS + 0x20) +#define AON_WRAPPER_SPARE (AON_BASE_OFFS + 0x28) +/* + * -------------------------------------------------------------------------- + * MODULE: VCODEC_SS registers + * -------------------------------------------------------------------------- + */ +#define VCODEC_SS_IDLE_STATUSn (VCODEC_BASE_OFFS_IRIS33 + 0x70) + +/* + * -------------------------------------------------------------------------- + * MODULE: VCODEC_NOC + * -------------------------------------------------------------------------- + */ +#define NOC_BASE_OFFS 0x00010000 + +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_MAINCTL_LOW_IRIS33 (NOC_BASE_OFFS + 0xA008) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRCLR_LOW_IRIS33 (NOC_BASE_OFFS + 0xA018) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_LOW_IRIS33 (NOC_BASE_OFFS + 0xA020) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_HIGH_IRIS33 (NOC_BASE_OFFS + 0xA024) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_LOW_IRIS33 (NOC_BASE_OFFS + 0xA028) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_HIGH_IRIS33 (NOC_BASE_OFFS + 0xA02C) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_LOW_IRIS33 (NOC_BASE_OFFS + 0xA030) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_HIGH_IRIS33 (NOC_BASE_OFFS + 0xA034) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_LOW_IRIS33 (NOC_BASE_OFFS + 0xA038) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_HIGH_IRIS33 (NOC_BASE_OFFS + 0xA03C) +#define NOC_SIDEBANDMANAGER_MAIN_SIDEBANDMANAGER_FAULTINEN0_LOW_IRIS33 (NOC_BASE_OFFS + 0x7040) +#define VCODEC_NOC_SidebandManager_SenseIn0_Low (NOC_BASE_OFFS + 0x7100) +#define VCODEC_NOC_SIDEBANDMANAGER_SENSEIN0_HIGH (NOC_BASE_OFFS + 0x7104) +#define VCODEC_NOC_SIDEBANDMANAGER_SENSEIN1_HIGH (NOC_BASE_OFFS + 0x710C) +#define VCODEC_NOC_SIDEBANDMANAGER_SENSEIN2_LOW (NOC_BASE_OFFS + 0x7110) + +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_MAINCTL_LOW_IRIS33_2P (NOC_BASE_OFFS + 0x3508) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRCLR_LOW_IRIS33_2P (NOC_BASE_OFFS + 0x3518) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_LOW_IRIS33_2P (NOC_BASE_OFFS + 0x3520) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_HIGH_IRIS33_2P (NOC_BASE_OFFS + 0x3524) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_LOW_IRIS33_2P (NOC_BASE_OFFS + 0x3528) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_HIGH_IRIS33_2P (NOC_BASE_OFFS + 0x352C) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_LOW_IRIS33_2P (NOC_BASE_OFFS + 0x3530) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_HIGH_IRIS33_2P (NOC_BASE_OFFS + 0x3534) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_LOW_IRIS33_2P (NOC_BASE_OFFS + 0x3538) +#define NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_HIGH_IRIS33_2P (NOC_BASE_OFFS + 0x353C) +#define NOC_SIDEBANDMANAGER_MAIN_SIDEBANDMANAGER_FAULTINEN0_LOW_IRIS33_2P (NOC_BASE_OFFS + 0x3240) +#define VCODEC_NOC_SidebandManager_SenseIn0_Low_2P (NOC_BASE_OFFS + 0x3300) +#define VCODEC_NOC_SIDEBANDMANAGER_SENSEIN0_HIGH_2P (NOC_BASE_OFFS + 0x3304) +#define VCODEC_NOC_SIDEBANDMANAGER_SENSEIN1_HIGH_2P (NOC_BASE_OFFS + 0x330C) +#define VCODEC_NOC_SIDEBANDMANAGER_SENSEIN2_LOW_2P (NOC_BASE_OFFS + 0x3310) + +#define VCODEC_DMA_SPARE_3 0x87B8 + +static int __interrupt_init_iris33(struct msm_vidc_core *core) +{ + u32 mask_val = 0; + int rc = 0; + + /* All interrupts should be disabled initially 0x1F6 : Reset value */ + rc = __read_register(core, WRAPPER_INTR_MASK_IRIS33, &mask_val); + if (rc) + return rc; + + /* Write 0 to unmask CPU and WD interrupts */ + mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS33 | + WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS33); + rc = __write_register(core, WRAPPER_INTR_MASK_IRIS33, mask_val); + if (rc) + return rc; + + return 0; +} + +static int __get_device_region_info(struct msm_vidc_core *core, + u32 *min_dev_addr, u32 *dev_reg_size) +{ + struct device_region_set *dev_set; + u32 min_addr, max_addr, count = 0; + int rc = 0; + + dev_set = &core->resource->device_region_set; + + if (!dev_set->count) { + d_vpr_h("%s: device region not available\n", __func__); + return 0; + } + + min_addr = 0xFFFFFFFF; + max_addr = 0x0; + for (count = 0; count < dev_set->count; count++) { + if (dev_set->device_region_tbl[count].dev_addr > max_addr) + max_addr = dev_set->device_region_tbl[count].dev_addr + + dev_set->device_region_tbl[count].size; + if (dev_set->device_region_tbl[count].dev_addr < min_addr) + min_addr = dev_set->device_region_tbl[count].dev_addr; + } + if (min_addr == 0xFFFFFFFF || max_addr == 0x0) { + d_vpr_e("%s: invalid device region\n", __func__); + return -EINVAL; + } + + *min_dev_addr = min_addr; + *dev_reg_size = max_addr - min_addr; + + return rc; +} + +static int __program_bootup_registers_iris33(struct msm_vidc_core *core) +{ + u32 min_dev_reg_addr = 0, dev_reg_size = 0; + u32 value; + int rc = 0; + + value = (u32)core->iface_q_table.align_device_addr; + rc = __write_register(core, HFI_UC_REGION_ADDR_IRIS33, value); + if (rc) + return rc; + + value = SHARED_QSIZE; + rc = __write_register(core, HFI_UC_REGION_SIZE_IRIS33, value); + if (rc) + return rc; + + value = (u32)core->iface_q_table.align_device_addr; + rc = __write_register(core, HFI_QTBL_ADDR_IRIS33, value); + if (rc) + return rc; + + rc = __write_register(core, HFI_QTBL_INFO_IRIS33, HFI_QTBL_ENABLED); + if (rc) + return rc; + + if (core->mmap_buf.align_device_addr) { + value = (u32)core->mmap_buf.align_device_addr; + rc = __write_register(core, HFI_MMAP_ADDR_IRIS33, value); + if (rc) + return rc; + } else { + d_vpr_e("%s: skip mmap buffer programming\n", __func__); + /* ignore the error for now for backward compatibility */ + /* return -EINVAL; */ + } + + rc = __get_device_region_info(core, &min_dev_reg_addr, &dev_reg_size); + if (rc) + return rc; + + if (min_dev_reg_addr && dev_reg_size) { + rc = __write_register(core, HFI_DEVICE_REGION_ADDR_IRIS33, min_dev_reg_addr); + if (rc) + return rc; + + rc = __write_register(core, HFI_DEVICE_REGION_SIZE_IRIS33, dev_reg_size); + if (rc) + return rc; + } else { + d_vpr_e("%s: skip device region programming\n", __func__); + /* ignore the error for now for backward compatibility */ + /* return -EINVAL; */ + } + + if (core->sfr.align_device_addr) { + value = (u32)core->sfr.align_device_addr + VIDEO_ARCH_LX; + rc = __write_register(core, HFI_SFR_ADDR_IRIS33, value); + if (rc) + return rc; + } + + return 0; +} + +static bool is_iris33_hw_power_collapsed(struct msm_vidc_core *core) +{ + int rc = 0; + u32 value = 0, pwr_status = 0; + + rc = __read_register(core, WRAPPER_CORE_POWER_STATUS, &value); + if (rc) + return false; + + /* if BIT(1) is 1 then video hw power is on else off */ + pwr_status = value & BIT(1); + return pwr_status ? false : true; +} + +static int __power_off_iris33_hardware(struct msm_vidc_core *core) +{ + int rc = 0, i; + u32 value = 0, count = 0; + bool pwr_collapsed = false; + u32 sense0_low, sense0_high, sense1_high, sense2_low; + + /* + * Incase hw power control is enabled, for any error case + * CPU WD, video hw unresponsive cases, NOC error case etc, + * execute NOC reset sequence before disabling power. If there + * is no CPU WD and hw power control is enabled, fw is expected + * to power collapse video hw always. + */ + if (is_core_sub_state(core, CORE_SUBSTATE_FW_PWR_CTRL)) { + pwr_collapsed = is_iris33_hw_power_collapsed(core); + if (pwr_collapsed) { + d_vpr_h("%s: video hw power collapsed %s\n", + __func__, core->sub_state_name); + goto disable_power; + } else { + d_vpr_e("%s: video hw is power ON, try power collpase hw %s\n", + __func__, core->sub_state_name); + } + } + + rc = call_res_op(core, gdsc_sw_ctrl, core); + if (rc) + return rc; + + /* + * check to make sure core clock branch enabled else + * we cannot read vcodec top idle register + */ + rc = __read_register(core, WRAPPER_CORE_CLOCK_CONFIG_IRIS33, &value); + if (rc) + return rc; + + if (value) { + d_vpr_e("%s: core clock config not enabled, enabling it to read vcodec registers\n", + __func__); + rc = __write_register(core, WRAPPER_CORE_CLOCK_CONFIG_IRIS33, 0); + if (rc) + return rc; + } + + rc = __write_register_masked(core, VCODEC_DMA_SPARE_3, 0x1, BIT(0)); + if (rc) + return rc; + + /* + * add MNoC idle check before collapsing MVS0 per HPG update + * poll for NoC DMA idle -> HPG 6.1.1 + */ + for (i = 0; i < core->capabilities[NUM_VPP_PIPE].value; i++) { + rc = __read_register_with_poll_timeout(core, VCODEC_SS_IDLE_STATUSn + 4*i, + 0x400000, 0x400000, 2000, 20000); + if (rc) + d_vpr_e("%s: VCODEC_SS_IDLE_STATUSn (%d) is not idle (%#x)\n", + __func__, i, value); + } + + /* set MNoC to low power, set PD_NOC_QREQ (bit 0) */ + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL, + 0x1, BIT(0)); + if (rc) + return rc; + + rc = __read_register(core, AON_WRAPPER_MVP_NOC_LPI_STATUS, &value); + if (rc) + return rc; + + while ((!(value & BIT(0))) && (value & BIT(1) || value & BIT(2))) { + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL, + 0x0, BIT(0)); + if (rc) + return rc; + + usleep_range(10, 20); + + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL, + 0x1, BIT(0)); + if (rc) + return rc; + + usleep_range(10, 20); + + rc = __read_register(core, AON_WRAPPER_MVP_NOC_LPI_STATUS, &value); + if (rc) + return rc; + + ++count; + if (count >= 1000) { + d_vpr_e("%s: AON_WRAPPER_MVP_NOC_LPI_CONTROL failed\n", __func__); + break; + } + } + + if (count < 1000) { + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL, + 0x0, BIT(0)); + if (rc) + return rc; + } + + i = 0; + do { + value = 0; + + if (core->platform->data.vpu_ver == VPU_VERSION_IRIS33) { + __read_register(core, + VCODEC_NOC_SidebandManager_SenseIn0_Low, + &sense0_low); + __read_register(core, + VCODEC_NOC_SIDEBANDMANAGER_SENSEIN0_HIGH, + &sense0_high); + __read_register(core, + VCODEC_NOC_SIDEBANDMANAGER_SENSEIN1_HIGH, + &sense1_high); + __read_register(core, + VCODEC_NOC_SIDEBANDMANAGER_SENSEIN2_LOW, + &sense2_low); + } else if (core->platform->data.vpu_ver == VPU_VERSION_IRIS33_2P) { + __read_register(core, + VCODEC_NOC_SidebandManager_SenseIn0_Low_2P, + &sense0_low); + __read_register(core, + VCODEC_NOC_SIDEBANDMANAGER_SENSEIN0_HIGH_2P, + &sense0_high); + __read_register(core, + VCODEC_NOC_SIDEBANDMANAGER_SENSEIN1_HIGH_2P, + &sense1_high); + __read_register(core, + VCODEC_NOC_SIDEBANDMANAGER_SENSEIN2_LOW_2P, + &sense2_low); + } + + value = ((sense0_low & 0x00008000) || + (sense0_high & 0x00000800) || + (sense1_high & 0x00800000) || + (sense2_low & 0x00002000)); + usleep_range(10, 20); + i++; + } while ((value) && (i <= 100)); + + d_vpr_h("%s: sideband register value = %d\n", __func__, value); + + /* + * Reset both sides of 2 ahb2ahb_bridges (TZ and non-TZ) + * do we need to check status register here? + */ + rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x3); + if (rc) + return rc; + rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x2); + if (rc) + return rc; + rc = __write_register(core, CPU_CS_AHB_BRIDGE_SYNC_RESET, 0x0); + if (rc) + return rc; + +disable_power: + /* power down process */ + rc = call_res_op(core, gdsc_off, core, "vcodec"); + if (rc) { + d_vpr_e("%s: disable regulator vcodec failed\n", __func__); + rc = 0; + } + + return rc; +} + +static int __power_off_iris33_controller(struct msm_vidc_core *core) +{ + int noc_lpi_status = 0, count = 0; + int rc = 0, value = 0; + + /* + * mask fal10_veto QLPAC error since fal10_veto can go 1 + * when pwwait == 0 and clamped to 0 -> HPG 6.1.2 + */ + rc = __write_register(core, CPU_CS_X2RPMh_IRIS33, 0x3); + if (rc) + return rc; + + /* Set Iris CPU NoC to Low power */ + rc = __write_register_masked(core, WRAPPER_IRIS_CPU_NOC_LPI_CONTROL, + 0x1, BIT(0)); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, WRAPPER_IRIS_CPU_NOC_LPI_STATUS, + 0x1, 0x1, 200, 2000); + if (rc) + d_vpr_e("%s: WRAPPER_IRIS_CPU_NOC_LPI_CONTROL failed\n", __func__); + + /* Debug bridge LPI release */ + rc = __write_register(core, WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS33, 0x0); + if (rc) + return rc; + + rc = __read_register_with_poll_timeout(core, WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS33, + 0xffffffff, 0x0, 200, 2000); + if (rc) + d_vpr_e("%s: debug bridge release failed\n", __func__); + + /* Reset MVP QNS4PDXFIFO */ + rc = __write_register(core, WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG, 0x3); + if (rc) + return rc; + + rc = __write_register(core, WRAPPER_TZ_QNS4PDXFIFO_RESET, 0x1); + if (rc) + return rc; + + rc = __write_register(core, WRAPPER_TZ_QNS4PDXFIFO_RESET, 0x0); + if (rc) + return rc; + + rc = __write_register(core, WRAPPER_TZ_CTL_AXI_CLOCK_CONFIG, 0x0); + if (rc) + return rc; + + /* assert and deassert axi and mvs0c resets */ + rc = call_res_op(core, reset_control_assert, core, "video_axi_reset"); + if (rc) + d_vpr_e("%s: assert video_axi_reset failed\n", __func__); + + rc = call_res_op(core, reset_control_assert, core, "video_mvs0_reset"); + if (rc) + d_vpr_e("%s: assert video_mvs0_reset failed\n", __func__); + + /* set retain mem and peripheral before asset mvs0c reset */ + rc = call_res_op(core, clk_set_flag, core, + "video_cc_mvs0c_clk", MSM_VIDC_CLKFLAG_RETAIN_MEM); + if (rc) + d_vpr_e("%s: set retain mem failed\n", __func__); + rc = call_res_op(core, clk_set_flag, core, + "video_cc_mvs0c_clk", MSM_VIDC_CLKFLAG_RETAIN_PERIPH); + if (rc) + d_vpr_e("%s: set retain peripheral failed\n", __func__); + rc = call_res_op(core, reset_control_assert, core, "video_mvs0c_reset"); + if (rc) + d_vpr_e("%s: assert video_mvs0c_reset failed\n", __func__); + usleep_range(400, 500); + rc = call_res_op(core, reset_control_deassert, core, "video_mvs0_reset"); + if (rc) + d_vpr_e("%s: de-assert video_mvs0_reset failed\n", __func__); + rc = call_res_op(core, reset_control_deassert, core, "video_axi_reset"); + if (rc) + d_vpr_e("%s: de-assert video_axi_reset failed\n", __func__); + rc = call_res_op(core, reset_control_deassert, core, "video_mvs0c_reset"); + if (rc) + d_vpr_e("%s: de-assert video_mvs0c_reset failed\n", __func__); + + /* Disable MVP NoC clock */ + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL, + 0x1, BIT(0)); + if (rc) + return rc; + + /* enable MVP NoC reset */ + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_CORE_SW_RESET, + 0x1, BIT(0)); + if (rc) + return rc; + + /* + * need to acquire "video_xo_reset" before assert and release + * after de-assert "video_xo_reset" reset clock to avoid other + * drivers (eva driver) operating on this shared reset clock + * and AON_WRAPPER_SPARE register in parallel. + */ + rc = call_res_op(core, reset_control_acquire, core, "video_xo_reset"); + if (rc) { + d_vpr_e("%s: failed to acquire video_xo_reset control\n", __func__); + goto skip_video_xo_reset; + } + + /* poll AON spare register bit0 to become zero with 50ms timeout */ + rc = __read_register_with_poll_timeout(core, AON_WRAPPER_SPARE, + 0x1, 0x0, 1000, 50 * 1000); + if (rc) + d_vpr_e("%s: AON spare register is not zero\n", __func__); + + /* enable bit(1) to avoid cvp noc xo reset */ + rc = __write_register(core, AON_WRAPPER_SPARE, value | 0x2); + if (rc) + goto exit; + + /* assert video_cc XO reset */ + rc = call_res_op(core, reset_control_assert, core, "video_xo_reset"); + if (rc) + d_vpr_e("%s: assert video_xo_reset failed\n", __func__); + + /* De-assert MVP NoC reset */ + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_CORE_SW_RESET, + 0x0, BIT(0)); + if (rc) + d_vpr_e("%s: MVP_NOC_CORE_SW_RESET failed\n", __func__); + + /* De-assert video_cc XO reset */ + usleep_range(80, 100); + rc = call_res_op(core, reset_control_deassert, core, "video_xo_reset"); + if (rc) + d_vpr_e("%s: deassert video_xo_reset failed\n", __func__); + + /* reset AON spare register */ + rc = __write_register(core, AON_WRAPPER_SPARE, 0x0); + if (rc) + goto exit; + + /* release reset control for other consumers */ + rc = call_res_op(core, reset_control_release, core, "video_xo_reset"); + if (rc) + d_vpr_e("%s: failed to release video_xo_reset reset\n", __func__); + +skip_video_xo_reset: + /* Enable MVP NoC clock */ + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_CORE_CLK_CONTROL, + 0x0, BIT(0)); + if (rc) + return rc; + + rc = call_res_op(core, clk_disable, core, "video_cc_mvs0_clk"); + if (rc) { + d_vpr_e("%s: disable unprepare video_cc_mvs0_clk failed\n", __func__); + rc = 0; + } + + /* remove retain mem and retain peripheral */ + rc = call_res_op(core, clk_set_flag, core, + "video_cc_mvs0c_clk", MSM_VIDC_CLKFLAG_NORETAIN_PERIPH); + if (rc) + d_vpr_e("%s: set noretain peripheral failed\n", __func__); + + rc = call_res_op(core, clk_set_flag, core, + "video_cc_mvs0c_clk", MSM_VIDC_CLKFLAG_NORETAIN_MEM); + if (rc) + d_vpr_e("%s: set noretain mem failed\n", __func__); + + /* Turn off MVP MVS0C core clock */ + rc = call_res_op(core, clk_disable, core, "video_cc_mvs0c_clk"); + if (rc) { + d_vpr_e("%s: disable unprepare video_cc_mvs0c_clk failed\n", __func__); + rc = 0; + } + + if (!is_core_state(core, MSM_VIDC_CORE_ERROR)) + goto power_down; + + /* power cycle process to recover from NoC error */ + rc = call_res_op(core, gdsc_off, core, "iris-ctl"); + if (rc) { + d_vpr_e("%s: disable regulator iris-ctl failed\n", __func__); + rc = 0; + } + + call_res_op(core, gdsc_on, core, "iris-ctl"); + rc = call_res_op(core, clk_enable, core, "video_cc_mvs0c_clk"); + + /* assert and deassert axi and mvs0c resets */ + rc = call_res_op(core, reset_control_assert, core, "video_axi_reset"); + if (rc) + d_vpr_e("%s: assert video_axi_reset failed\n", __func__); + + /* set retain mem and peripheral before asset mvs0c reset */ + rc = call_res_op(core, clk_set_flag, core, + "video_cc_mvs0c_clk", MSM_VIDC_CLKFLAG_RETAIN_MEM); + if (rc) + d_vpr_e("%s: set retain mem failed\n", __func__); + rc = call_res_op(core, clk_set_flag, core, + "video_cc_mvs0c_clk", MSM_VIDC_CLKFLAG_RETAIN_PERIPH); + if (rc) + d_vpr_e("%s: set retain peripheral failed\n", __func__); + rc = call_res_op(core, reset_control_assert, core, "video_mvs0c_reset"); + if (rc) + d_vpr_e("%s: assert video_mvs0c_reset failed\n", __func__); + usleep_range(400, 500); + + rc = call_res_op(core, reset_control_deassert, core, "video_axi_reset"); + if (rc) + d_vpr_e("%s: de-assert video_axi_reset failed\n", __func__); + rc = call_res_op(core, reset_control_deassert, core, "video_mvs0c_reset"); + if (rc) + d_vpr_e("%s: de-assert video_mvs0c_reset failed\n", __func__); + + rc = call_res_op(core, gdsc_on, core, "vcodec"); + if (rc) + return rc; + + rc = call_res_op(core, clk_enable, core, "video_cc_mvs0_clk"); + if (rc) + return rc; + + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL, + 0x1, BIT(0)); + if (rc) + return rc; + + usleep_range(10, 20); + + rc = __read_register(core, AON_WRAPPER_MVP_NOC_LPI_STATUS, &noc_lpi_status); + if (rc) + return rc; + + while ((!(noc_lpi_status & BIT(0))) && + (noc_lpi_status & BIT(1) || noc_lpi_status & BIT(2))) { + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL, + 0x0, BIT(0)); + if (rc) + return rc; + + usleep_range(10, 20); + + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL, + 0x1, BIT(0)); + if (rc) + return rc; + + usleep_range(10, 20); + + rc = __read_register(core, AON_WRAPPER_MVP_NOC_LPI_STATUS, &noc_lpi_status); + if (rc) + return rc; + + ++count; + if (count >= 1000) { + d_vpr_e("%s: AON_WRAPPER_MVP_NOC_LPI_CONTROL failed\n", __func__); + break; + } + } + + if (count < 1000) { + rc = __write_register_masked(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL, + 0x0, BIT(0)); + if (rc) + return rc; + } + + rc = call_res_op(core, clk_disable, core, "video_cc_mvs0_clk"); + if (rc) { + d_vpr_e("%s: disable unprepare video_cc_mvs0_clk failed\n", __func__); + rc = 0; + } + + rc = call_res_op(core, gdsc_off, core, "vcodec"); + if (rc) { + d_vpr_e("%s: disable regulator vcodec failed\n", __func__); + rc = 0; + } + + /* remove retain mem and retain peripheral */ + rc = call_res_op(core, clk_set_flag, core, + "video_cc_mvs0c_clk", MSM_VIDC_CLKFLAG_NORETAIN_PERIPH); + if (rc) + d_vpr_e("%s: set noretain peripheral failed\n", __func__); + + rc = call_res_op(core, clk_set_flag, core, + "video_cc_mvs0c_clk", MSM_VIDC_CLKFLAG_NORETAIN_MEM); + if (rc) + d_vpr_e("%s: set noretain mem failed\n", __func__); + + /* Turn off MVP MVS0C core clock */ + rc = call_res_op(core, clk_disable, core, "video_cc_mvs0c_clk"); + if (rc) { + d_vpr_e("%s: disable unprepare video_cc_mvs0c_clk failed\n", __func__); + rc = 0; + } + +power_down: + /* power down process */ + rc = call_res_op(core, gdsc_off, core, "iris-ctl"); + if (rc) { + d_vpr_e("%s: disable regulator iris-ctl failed\n", __func__); + rc = 0; + } + + /* Turn off GCC AXI clock */ + rc = call_res_op(core, clk_disable, core, "gcc_video_axi0_clk"); + if (rc) { + d_vpr_e("%s: disable unprepare gcc_video_axi0_clk failed\n", __func__); + rc = 0; + } + + return rc; + +exit: + call_res_op(core, reset_control_release, core, "video_xo_reset"); + return rc; +} + +static int __power_off_iris33(struct msm_vidc_core *core) +{ + int rc = 0; + + if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) + return 0; + + /** + * Reset video_cc_mvs0_clk_src value to resolve MMRM high video + * clock projection issue. + */ + rc = call_res_op(core, set_clks, core, 0); + if (rc) + d_vpr_e("%s: resetting clocks failed\n", __func__); + + if (__power_off_iris33_hardware(core)) + d_vpr_e("%s: failed to power off hardware\n", __func__); + + if (__power_off_iris33_controller(core)) + d_vpr_e("%s: failed to power off controller\n", __func__); + + rc = call_res_op(core, set_bw, core, 0, 0); + if (rc) + d_vpr_e("%s: failed to unvote buses\n", __func__); + + if (!call_venus_op(core, watchdog, core, core->intr_status)) + disable_irq_nosync(core->resource->irq); + + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__); + + return rc; +} + +static int __power_on_iris33_controller(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = call_res_op(core, gdsc_on, core, "iris-ctl"); + if (rc) + goto fail_regulator; + + rc = call_res_op(core, reset_control_assert, core, "video_axi_reset"); + if (rc) + goto fail_reset_assert_axi; + rc = call_res_op(core, reset_control_assert, core, "video_mvs0c_reset"); + if (rc) + goto fail_reset_assert_mvs0c; + /* add usleep between assert and deassert */ + usleep_range(1000, 1100); + rc = call_res_op(core, reset_control_deassert, core, "video_axi_reset"); + if (rc) + goto fail_reset_deassert_axi; + rc = call_res_op(core, reset_control_deassert, core, "video_mvs0c_reset"); + if (rc) + goto fail_reset_deassert_mvs0c; + + rc = call_res_op(core, clk_enable, core, "gcc_video_axi0_clk"); + if (rc) + goto fail_clk_axi; + + rc = call_res_op(core, clk_enable, core, "video_cc_mvs0c_clk"); + if (rc) + goto fail_clk_controller; + + return 0; + +fail_clk_controller: + call_res_op(core, clk_disable, core, "gcc_video_axi0_clk"); +fail_clk_axi: +fail_reset_deassert_mvs0c: +fail_reset_deassert_axi: + call_res_op(core, reset_control_deassert, core, "video_mvs0c_reset"); +fail_reset_assert_mvs0c: + call_res_op(core, reset_control_deassert, core, "video_axi_reset"); +fail_reset_assert_axi: + call_res_op(core, gdsc_off, core, "iris-ctl"); +fail_regulator: + return rc; +} + +static int __power_on_iris33_hardware(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = call_res_op(core, gdsc_on, core, "vcodec"); + if (rc) + goto fail_regulator; + + rc = call_res_op(core, clk_enable, core, "video_cc_mvs0_clk"); + if (rc) + goto fail_clk_controller; + + return 0; + +fail_clk_controller: + call_res_op(core, gdsc_off, core, "vcodec"); +fail_regulator: + return rc; +} + +static int __power_on_iris33(struct msm_vidc_core *core) +{ + struct frequency_table *freq_tbl; + u32 freq = 0; + int rc = 0; + + if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) + return 0; + + if (!core_in_valid_state(core)) { + d_vpr_e("%s: invalid core state %s\n", + __func__, core_state_name(core->state)); + return -EINVAL; + } + + /* Vote for all hardware resources */ + rc = call_res_op(core, set_bw, core, INT_MAX, INT_MAX); + if (rc) { + d_vpr_e("%s: failed to vote buses, rc %d\n", __func__, rc); + goto fail_vote_buses; + } + + rc = __power_on_iris33_controller(core); + if (rc) { + d_vpr_e("%s: failed to power on iris33 controller\n", __func__); + goto fail_power_on_controller; + } + + rc = __power_on_iris33_hardware(core); + if (rc) { + d_vpr_e("%s: failed to power on iris33 hardware\n", __func__); + goto fail_power_on_hardware; + } + /* video controller and hardware powered on successfully */ + rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_POWER_ENABLE, __func__); + if (rc) + goto fail_power_on_substate; + + freq_tbl = core->resource->freq_set.freq_tbl; + freq = core->power.clk_freq ? core->power.clk_freq : + freq_tbl[0].freq; + + rc = call_res_op(core, set_clks, core, freq); + if (rc) { + d_vpr_e("%s: failed to scale clocks\n", __func__); + rc = 0; + } + /* + * Re-program all of the registers that get reset as a result of + * regulator_disable() and _enable() + * When video module writing to QOS registers EVA module is not + * supposed to do video_xo_reset operations else we will see register + * access failure, so acquire video_xo_reset to ensure EVA module is + * not doing assert or de-assert on video_xo_reset. + */ + rc = call_res_op(core, reset_control_acquire, core, "video_xo_reset"); + if (rc) { + d_vpr_e("%s: failed to acquire video_xo_reset control\n", __func__); + goto fail_assert_xo_reset; + } + + __set_registers(core); + + /* + * Programm NOC error registers before releasing xo reset + * Clear error logger registers and then enable StallEn + */ + if (core->platform->data.vpu_ver == VPU_VERSION_IRIS33) { + rc = __write_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRCLR_LOW_IRIS33, 0x1); + if (rc) { + d_vpr_e( + "%s: error clearing NOC_MAIN_ERRORLOGGER_ERRCLR_LOW\n", + __func__); + goto fail_program_noc_regs; + } + + rc = __write_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_MAINCTL_LOW_IRIS33, 0x3); + if (rc) { + d_vpr_e( + "%s: failed to set NOC_ERL_MAIN_ERRORLOGGER_MAINCTL_LOW\n", + __func__); + goto fail_program_noc_regs; + } + rc = __write_register(core, + NOC_SIDEBANDMANAGER_MAIN_SIDEBANDMANAGER_FAULTINEN0_LOW_IRIS33, + 0x1); + if (rc) { + d_vpr_e( + "%s: failed to set NOC_SIDEBANDMANAGER_FAULTINEN0_LOW\n", + __func__); + goto fail_program_noc_regs; + } + } else if (core->platform->data.vpu_ver == VPU_VERSION_IRIS33_2P) { + rc = __write_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRCLR_LOW_IRIS33_2P, 0x1); + if (rc) { + d_vpr_e( + "%s: error clearing NOC_MAIN_ERRORLOGGER_ERRCLR_LOW\n", + __func__); + goto fail_program_noc_regs; + } + + rc = __write_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_MAINCTL_LOW_IRIS33_2P, 0x3); + if (rc) { + d_vpr_e( + "%s: failed to set NOC_ERL_MAIN_ERRORLOGGER_MAINCTL_LOW\n", + __func__); + goto fail_program_noc_regs; + } + rc = __write_register(core, + NOC_SIDEBANDMANAGER_MAIN_SIDEBANDMANAGER_FAULTINEN0_LOW_IRIS33_2P, + 0x1); + if (rc) { + d_vpr_e( + "%s: failed to set NOC_SIDEBANDMANAGER_FAULTINEN0_LOW\n", + __func__); + goto fail_program_noc_regs; + } + } + + /* release reset control for other consumers */ + rc = call_res_op(core, reset_control_release, core, "video_xo_reset"); + if (rc) { + d_vpr_e("%s: failed to release video_xo_reset reset\n", __func__); + goto fail_deassert_xo_reset; + } + + __interrupt_init_iris33(core); + core->intr_status = 0; + enable_irq(core->resource->irq); + + return rc; + +fail_program_noc_regs: + call_res_op(core, reset_control_release, core, "video_xo_reset"); +fail_deassert_xo_reset: +fail_assert_xo_reset: +fail_power_on_substate: + __power_off_iris33_hardware(core); +fail_power_on_hardware: + __power_off_iris33_controller(core); +fail_power_on_controller: + call_res_op(core, set_bw, core, 0, 0); +fail_vote_buses: + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__); + + return rc; +} + +static int __prepare_pc_iris33(struct msm_vidc_core *core) +{ + int rc = 0; + u32 wfi_status = 0, idle_status = 0, pc_ready = 0; + u32 ctrl_status = 0; + + rc = __read_register(core, HFI_CTRL_STATUS_IRIS33, &ctrl_status); + if (rc) + return rc; + + pc_ready = ctrl_status & HFI_CTRL_PC_READY; + idle_status = ctrl_status & BIT(30); + + if (pc_ready) { + d_vpr_h("Already in pc_ready state\n"); + return 0; + } + rc = __read_register(core, WRAPPER_TZ_CPU_STATUS, &wfi_status); + if (rc) + return rc; + + wfi_status &= BIT(0); + if (!wfi_status || !idle_status) { + d_vpr_e("Skipping PC, wfi status not set\n"); + goto skip_power_off; + } + + rc = __prepare_pc(core); + if (rc) { + d_vpr_e("Failed __prepare_pc %d\n", rc); + goto skip_power_off; + } + + rc = __read_register_with_poll_timeout(core, HFI_CTRL_STATUS_IRIS33, + HFI_CTRL_PC_READY, HFI_CTRL_PC_READY, 250, 2500); + if (rc) { + d_vpr_e("%s: Skip PC. Ctrl status not set\n", __func__); + goto skip_power_off; + } + + rc = __read_register_with_poll_timeout(core, WRAPPER_TZ_CPU_STATUS, + BIT(0), 0x1, 250, 2500); + if (rc) { + d_vpr_e("%s: Skip PC. Wfi status not set\n", __func__); + goto skip_power_off; + } + return rc; + +skip_power_off: + rc = __read_register(core, HFI_CTRL_STATUS_IRIS33, &ctrl_status); + if (rc) + return rc; + rc = __read_register(core, WRAPPER_TZ_CPU_STATUS, &wfi_status); + if (rc) + return rc; + wfi_status &= BIT(0); + d_vpr_e("Skip PC, wfi=%#x, idle=%#x, pcr=%#x, ctrl=%#x)\n", + wfi_status, idle_status, pc_ready, ctrl_status); + return -EAGAIN; +} + +static int __raise_interrupt_iris33(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = __write_register(core, CPU_IC_SOFTINT_IRIS33, 1 << CPU_IC_SOFTINT_H2A_SHFT_IRIS33); + if (rc) + return rc; + + return 0; +} + +static int __watchdog_iris33(struct msm_vidc_core *core, u32 intr_status) +{ + int rc = 0; + + if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS33) { + d_vpr_e("%s: received watchdog interrupt\n", __func__); + rc = 1; + } + + return rc; +} + +static int __read_noc_err_register_iris33(struct msm_vidc_core *core) +{ + int rc = 0; + u32 value; + + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_LOW_IRIS33, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_LOW: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_HIGH_IRIS33, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_HIGH: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_LOW_IRIS33, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_LOW: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_HIGH_IRIS33, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_HIGH: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_LOW_IRIS33, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_LOW: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_HIGH_IRIS33, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_HIGH: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_LOW_IRIS33, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_LOW: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_HIGH_IRIS33, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_HIGH: %#x\n", + __func__, value); + + return rc; +} + +static int __read_noc_err_register_iris33_2p(struct msm_vidc_core *core) +{ + int rc = 0; + u32 value; + + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_LOW_IRIS33_2P, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_LOW: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_HIGH_IRIS33_2P, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG0_HIGH: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_LOW_IRIS33_2P, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_LOW: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_HIGH_IRIS33_2P, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG1_HIGH: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_LOW_IRIS33_2P, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_LOW: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_HIGH_IRIS33_2P, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG2_HIGH: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_LOW_IRIS33_2P, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_LOW: %#x\n", + __func__, value); + rc = __read_register(core, + NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_HIGH_IRIS33_2P, &value); + if (!rc) + d_vpr_e("%s: NOC_ERL_ERRORLOGGER_MAIN_ERRORLOGGER_ERRLOG3_HIGH: %#x\n", + __func__, value); + + return rc; +} + +static int __noc_error_info_iris33(struct msm_vidc_core *core) +{ + int rc = 0; + + /* + * we are not supposed to access vcodec subsystem registers + * unless vcodec core clock WRAPPER_CORE_CLOCK_CONFIG_IRIS33 is enabled. + * core clock might have been disabled by video firmware as part of + * inter frame power collapse (power plane control feature). + */ + + /* + val = __read_register(core, VCODEC_NOC_ERL_MAIN_SWID_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_SWID_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_SWID_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_SWID_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_MAINCTL_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_MAINCTL_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRVLD_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRVLD_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRCLR_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRCLR_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW: %#x\n", val); + val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH); + d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH: %#x\n", val); + */ + + if (is_iris33_hw_power_collapsed(core)) { + d_vpr_e("%s: video hardware already power collapsed\n", __func__); + return rc; + } + + /* + * Acquire video_xo_reset to ensure EVA module is + * not doing assert or de-assert on video_xo_reset + * while reading noc registers + */ + d_vpr_e("%s: read NOC ERR LOG registers\n", __func__); + rc = call_res_op(core, reset_control_acquire, core, "video_xo_reset"); + if (rc) { + d_vpr_e("%s: failed to acquire video_xo_reset control\n", __func__); + goto fail_assert_xo_reset; + } + + if (core->platform->data.vpu_ver == VPU_VERSION_IRIS33) + rc = __read_noc_err_register_iris33(core); + else if (core->platform->data.vpu_ver == VPU_VERSION_IRIS33_2P) + rc = __read_noc_err_register_iris33_2p(core); + + /* release reset control for other consumers */ + rc = call_res_op(core, reset_control_release, core, "video_xo_reset"); + if (rc) { + d_vpr_e("%s: failed to release video_xo_reset reset\n", __func__); + goto fail_deassert_xo_reset; + } + +fail_deassert_xo_reset: +fail_assert_xo_reset: + return rc; +} + +static int __clear_interrupt_iris33(struct msm_vidc_core *core) +{ + u32 intr_status = 0, mask = 0; + int rc = 0; + + rc = __read_register(core, WRAPPER_INTR_STATUS_IRIS33, &intr_status); + if (rc) + return rc; + + mask = (WRAPPER_INTR_STATUS_A2H_BMSK_IRIS33| + WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS33| + HFI_CTRL_VCODEC_IDLE); + + if (intr_status & mask) { + core->intr_status |= intr_status; + core->reg_count++; + d_vpr_l("INTERRUPT: times: %d interrupt_status: %d\n", + core->reg_count, intr_status); + } else { + core->spur_count++; + } + + rc = __write_register(core, CPU_CS_A2HSOFTINTCLR_IRIS33, 1); + if (rc) + return rc; + + return 0; +} + +static int __boot_firmware_iris33(struct msm_vidc_core *core) +{ + int rc = 0; + u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 1000; + + rc = __program_bootup_registers_iris33(core); + if (rc) + return rc; + + ctrl_init_val = BIT(0); + + rc = __write_register(core, HFI_CTRL_INIT_IRIS33, ctrl_init_val); + if (rc) + return rc; + + while (count < max_tries) { + rc = __read_register(core, HFI_CTRL_STATUS_IRIS33, &ctrl_status); + if (rc) + return rc; + + rc = __read_register(core, HFI_CTRL_INIT_IRIS33, &ctrl_init_val); + if (rc) + return rc; + + if ((ctrl_status & HFI_CTRL_ERROR_FATAL) || + (ctrl_status & HFI_CTRL_ERROR_UC_REGION_NOT_SET) || + (ctrl_status & HFI_CTRL_ERROR_HW_FENCE_QUEUE)) { + d_vpr_e("%s: boot firmware failed, ctrl status %#x\n", + __func__, ctrl_status); + return -EINVAL; + } else if (ctrl_status & HFI_CTRL_READY) { + d_vpr_h("%s: boot firmware is successful, ctrl status %#x\n", + __func__, ctrl_status); + break; + } + + usleep_range(50, 100); + count++; + } + + if (count >= max_tries) { + d_vpr_e(FMT_STRING_BOOT_FIRMWARE_ERROR, + ctrl_status, ctrl_init_val); + return -ETIME; + } + + /* Enable interrupt before sending commands to venus */ + rc = __write_register(core, CPU_CS_H2XSOFTINTEN_IRIS33, 0x1); + if (rc) + return rc; + + rc = __write_register(core, CPU_CS_X2RPMh_IRIS33, 0x0); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_decide_work_mode_iris33(struct msm_vidc_inst *inst) +{ + u32 work_mode; + struct v4l2_format *inp_f; + u32 width, height; + bool res_ok = false; + + work_mode = MSM_VIDC_STAGE_2; + inp_f = &inst->fmts[INPUT_PORT]; + + if (is_image_decode_session(inst)) + work_mode = MSM_VIDC_STAGE_1; + + if (is_image_session(inst)) + goto exit; + + if (is_decode_session(inst)) { + height = inp_f->fmt.pix_mp.height; + width = inp_f->fmt.pix_mp.width; + res_ok = res_is_less_than(width, height, 1280, 720); + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_INTERLACE || + inst->capabilities[LOWLATENCY_MODE].value || + res_ok) { + work_mode = MSM_VIDC_STAGE_1; + } + } else if (is_encode_session(inst)) { + height = inst->crop.height; + width = inst->crop.width; + res_ok = !res_is_greater_than(width, height, 4096, 2160); + if (res_ok && + (inst->capabilities[LOWLATENCY_MODE].value)) { + work_mode = MSM_VIDC_STAGE_1; + } + if (inst->capabilities[SLICE_MODE].value == + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { + work_mode = MSM_VIDC_STAGE_1; + } + if (inst->capabilities[LOSSLESS].value) + work_mode = MSM_VIDC_STAGE_2; + + if (!inst->capabilities[GOP_SIZE].value) + work_mode = MSM_VIDC_STAGE_2; + } else { + i_vpr_e(inst, "%s: invalid session type\n", __func__); + return -EINVAL; + } + +exit: + i_vpr_h(inst, "Configuring work mode = %u low latency = %u, gop size = %u\n", + work_mode, inst->capabilities[LOWLATENCY_MODE].value, + inst->capabilities[GOP_SIZE].value); + msm_vidc_update_cap_value(inst, STAGE, work_mode, __func__); + + return 0; +} + +int msm_vidc_decide_work_route_iris33(struct msm_vidc_inst *inst) +{ + u32 work_route; + struct msm_vidc_core *core; + + core = inst->core; + work_route = core->capabilities[NUM_VPP_PIPE].value; + + if (is_image_session(inst)) + goto exit; + + if (is_decode_session(inst)) { + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_INTERLACE) + work_route = MSM_VIDC_PIPE_1; + } else if (is_encode_session(inst)) { + u32 slice_mode; + + slice_mode = inst->capabilities[SLICE_MODE].value; + + /*TODO Pipe=1 for legacy CBR*/ + if (slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) + work_route = MSM_VIDC_PIPE_1; + + } else { + i_vpr_e(inst, "%s: invalid session type\n", __func__); + return -EINVAL; + } + +exit: + i_vpr_h(inst, "Configuring work route = %u", work_route); + msm_vidc_update_cap_value(inst, PIPE, work_route, __func__); + + return 0; +} + +int msm_vidc_decide_quality_mode_iris33(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 mbpf, mbps, max_hq_mbpf, max_hq_mbps; + u32 mode = MSM_VIDC_POWER_SAVE_MODE; + + if (!is_encode_session(inst)) + return 0; + + /* image or lossless or all intra runs at quality mode */ + if (is_image_session(inst) || inst->capabilities[LOSSLESS].value || + inst->capabilities[ALL_INTRA].value) { + mode = MSM_VIDC_MAX_QUALITY_MODE; + goto decision_done; + } + + /* for lesser complexity, make LP for all resolution */ + if (inst->capabilities[COMPLEXITY].value < DEFAULT_COMPLEXITY) { + mode = MSM_VIDC_POWER_SAVE_MODE; + goto decision_done; + } + + mbpf = msm_vidc_get_mbs_per_frame(inst); + mbps = mbpf * msm_vidc_get_fps(inst); + core = inst->core; + max_hq_mbpf = core->capabilities[MAX_MBPF_HQ].value;; + max_hq_mbps = core->capabilities[MAX_MBPS_HQ].value;; + + if (!is_realtime_session(inst)) { + if (((inst->capabilities[COMPLEXITY].flags & CAP_FLAG_CLIENT_SET) && + (inst->capabilities[COMPLEXITY].value >= DEFAULT_COMPLEXITY)) || + mbpf <= max_hq_mbpf) { + mode = MSM_VIDC_MAX_QUALITY_MODE; + goto decision_done; + } + } + + if (mbpf <= max_hq_mbpf && mbps <= max_hq_mbps) + mode = MSM_VIDC_MAX_QUALITY_MODE; + +decision_done: + msm_vidc_update_cap_value(inst, QUALITY_MODE, mode, __func__); + + return 0; +} + +int msm_vidc_adjust_bitrate_boost_iris33(void *instance, struct v4l2_ctrl *ctrl) +{ + s32 adjusted_value; + struct msm_vidc_inst *inst = (struct msm_vidc_inst *)instance; + s32 rc_type = -1; + u32 width, height, frame_rate; + struct v4l2_format *f; + u32 max_bitrate = 0, bitrate = 0; + + adjusted_value = ctrl ? ctrl->val : + inst->capabilities[BITRATE_BOOST].value; + + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) + return 0; + + if (msm_vidc_get_parent_value(inst, BITRATE_BOOST, + BITRATE_MODE, &rc_type, __func__)) + return -EINVAL; + + /* + * Bitrate Boost are supported only for VBR rc type. + * Hence, do not adjust or set to firmware for non VBR rc's + */ + if (rc_type != HFI_RC_VBR_CFR) { + adjusted_value = 0; + goto adjust; + } + + frame_rate = inst->capabilities[FRAME_RATE].value >> 16; + f = &inst->fmts[OUTPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + /* + * honor client set bitrate boost + * if client did not set, keep max bitrate boost upto 4k@60fps + * and remove bitrate boost after 4k@60fps + */ + if (inst->capabilities[BITRATE_BOOST].flags & CAP_FLAG_CLIENT_SET) { + /* accept client set bitrate boost value as is */ + } else { + if (res_is_less_than_or_equal_to(width, height, 4096, 2176) && + frame_rate <= 60) + adjusted_value = MAX_BITRATE_BOOST; + else + adjusted_value = 0; + } + + max_bitrate = msm_vidc_get_max_bitrate(inst); + bitrate = inst->capabilities[BIT_RATE].value; + if (adjusted_value) { + if ((bitrate + bitrate / (100 / adjusted_value)) > max_bitrate) { + i_vpr_h(inst, + "%s: bitrate %d is beyond max bitrate %d, remove bitrate boost\n", + __func__, max_bitrate, bitrate); + adjusted_value = 0; + } + } +adjust: + msm_vidc_update_cap_value(inst, BITRATE_BOOST, adjusted_value, __func__); + + return 0; +} + + + +static struct msm_vidc_venus_ops iris33_ops = { + .boot_firmware = __boot_firmware_iris33, + .raise_interrupt = __raise_interrupt_iris33, + .clear_interrupt = __clear_interrupt_iris33, + .power_on = __power_on_iris33, + .power_off = __power_off_iris33, + .prepare_pc = __prepare_pc_iris33, + .watchdog = __watchdog_iris33, + .noc_error_info = __noc_error_info_iris33, +}; + +static struct msm_vidc_session_ops msm_session_ops = { + .buffer_size = msm_buffer_size_iris33, + .min_count = msm_buffer_min_count_iris33, + .extra_count = msm_buffer_extra_count_iris33, + .ring_buf_count = msm_vidc_ring_buf_count_iris33, + .calc_freq = msm_vidc_calc_freq_iris33, + .calc_bw = msm_vidc_calc_bw_iris33, + .decide_work_route = msm_vidc_decide_work_route_iris33, + .decide_work_mode = msm_vidc_decide_work_mode_iris33, + .decide_quality_mode = msm_vidc_decide_quality_mode_iris33, +}; + +int msm_vidc_init_iris33(struct msm_vidc_core *core) +{ + d_vpr_h("%s()\n", __func__); + core->venus_ops = &iris33_ops; + core->session_ops = &msm_session_ops; + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_power_iris33.c b/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_power_iris33.c new file mode 100644 index 0000000000..7c6597d042 --- /dev/null +++ b/qcom/opensource/video-driver/driver/variant/iris33/src/msm_vidc_power_iris33.c @@ -0,0 +1,1366 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_power_iris33.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" +#include "perf_static_model.h" +#include "msm_vidc_power.h" + +#define VPP_MIN_FREQ_MARGIN_PERCENT 5 /* to be tuned */ + +static u64 __calculate_decoder(struct vidc_bus_vote_data *d); +static u64 __calculate_encoder(struct vidc_bus_vote_data *d); +static u64 __calculate(struct msm_vidc_inst *inst, struct vidc_bus_vote_data *d); +static u64 msm_vidc_calc_freq_iris33_legacy(struct msm_vidc_inst *inst, u32 data_size); + + +static int msm_vidc_get_hier_layer_val(struct msm_vidc_inst *inst) +{ + int hierachical_layer = CODEC_GOP_IPP; + + if (is_encode_session(inst)) { + if (inst->capabilities[ALL_INTRA].value) { + /* no P and B frames case */ + hierachical_layer = CODEC_GOP_IONLY; + } else if (inst->capabilities[B_FRAME].value == 0) { + /* no B frames case */ + hierachical_layer = CODEC_GOP_IPP; + } else { /* P and B frames enabled case */ + if (inst->capabilities[ENH_LAYER_COUNT].value == 0 || + inst->capabilities[ENH_LAYER_COUNT].value == 1) + hierachical_layer = CODEC_GOP_IbP; + else if (inst->capabilities[ENH_LAYER_COUNT].value == 2) + hierachical_layer = CODEC_GOP_I1B2b1P; + else + hierachical_layer = CODEC_GOP_I3B4b1P; + } + } + + return hierachical_layer; +} + +static int msm_vidc_init_codec_input_freq(struct msm_vidc_inst *inst, u32 data_size, + struct api_calculation_input *codec_input) +{ + enum msm_vidc_port_type port; + u32 color_fmt, tile_rows_columns = 0; + struct msm_vidc_core *core; + + if (is_encode_session(inst)) { + codec_input->decoder_or_encoder = CODEC_ENCODER; + } else if (is_decode_session(inst)) { + codec_input->decoder_or_encoder = CODEC_DECODER; + } else { + d_vpr_e("%s: invalid domain %d\n", __func__, inst->domain); + return -EINVAL; + } + + codec_input->chipset_gen = MSM_PINEAPPLE; + + if (inst->codec == MSM_VIDC_H264) { + codec_input->codec = CODEC_H264; + codec_input->lcu_size = 16; + if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) { + codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CABAC; + codec_input->codec = CODEC_H264; + } else { + codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CAVLC; + codec_input->codec = CODEC_H264_CAVLC; + } + } else if (inst->codec == MSM_VIDC_HEVC) { + codec_input->codec = CODEC_HEVC; + codec_input->lcu_size = 32; + } else if (inst->codec == MSM_VIDC_VP9) { + codec_input->codec = CODEC_VP9; + codec_input->lcu_size = 32; + } else if (inst->codec == MSM_VIDC_AV1) { + codec_input->codec = CODEC_AV1; + codec_input->lcu_size = + inst->capabilities[SUPER_BLOCK].value ? 128 : 64; + } else { + d_vpr_e("%s: invalid codec %d\n", __func__, inst->codec); + return -EINVAL; + } + + codec_input->pipe_num = inst->capabilities[PIPE].value; + codec_input->frame_rate = inst->max_rate; + + port = is_decode_session(inst) ? INPUT_PORT : OUTPUT_PORT; + codec_input->frame_width = inst->fmts[port].fmt.pix_mp.width; + codec_input->frame_height = inst->fmts[port].fmt.pix_mp.height; + + if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_1) { + codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_1S; + } else if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_2) { + codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_2S; + } else { + d_vpr_e("%s: invalid stage %d\n", __func__, + inst->capabilities[STAGE].value); + return -EINVAL; + } + + if (inst->capabilities[BIT_DEPTH].value == BIT_DEPTH_8) + codec_input->bitdepth = CODEC_BITDEPTH_8; + else + codec_input->bitdepth = CODEC_BITDEPTH_10; + + codec_input->hierachical_layer = + msm_vidc_get_hier_layer_val(inst); + + if (is_decode_session(inst)) + color_fmt = v4l2_colorformat_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, __func__); + else + color_fmt = v4l2_colorformat_to_driver(inst, + inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat, __func__); + + codec_input->linear_opb = is_linear_colorformat(color_fmt); + + if (is_decode_session(inst)) + codec_input->bitrate_mbps = + (codec_input->frame_rate * data_size * 8) / 1000000; + else + codec_input->bitrate_mbps = + inst->capabilities[BIT_RATE].value / 1000000; + + /* av1d commercial tile */ + if (inst->codec == MSM_VIDC_AV1 && codec_input->lcu_size == 128) { + tile_rows_columns = inst->power.fw_av1_tile_rows * + inst->power.fw_av1_tile_columns; + + /* check resolution and tile info */ + codec_input->av1d_commer_tile_enable = 1; + + if (res_is_less_than_or_equal_to(codec_input->frame_width, + codec_input->frame_height, 1920, 1088)) { + if (tile_rows_columns <= 2) + codec_input->av1d_commer_tile_enable = 0; + } else if (res_is_less_than_or_equal_to(codec_input->frame_width, + codec_input->frame_height, 4096, 2172)) { + if (tile_rows_columns <= 4) + codec_input->av1d_commer_tile_enable = 0; + } else if (res_is_less_than_or_equal_to(codec_input->frame_width, + codec_input->frame_height, 8192, 4320)) { + if (tile_rows_columns <= 16) + codec_input->av1d_commer_tile_enable = 0; + } + } else { + codec_input->av1d_commer_tile_enable = 0; + } + + /* set as sanity mode, this regression mode has no effect on power calculations */ + codec_input->regression_mode = REGRESSION_MODE_SANITY; + + core = inst->core; + codec_input->vpu_ver = core->platform->data.vpu_ver; + + return 0; +} + +static int msm_vidc_init_codec_input_bus(struct msm_vidc_inst *inst, struct vidc_bus_vote_data *d, + struct api_calculation_input *codec_input) +{ + u32 complexity_factor_int = 0, complexity_factor_frac = 0, tile_rows_columns = 0; + bool opb_compression_enabled = false; + struct msm_vidc_core *core; + + if (!d) + return -EINVAL; + + if (d->domain == MSM_VIDC_ENCODER) { + codec_input->decoder_or_encoder = CODEC_ENCODER; + } else if (d->domain == MSM_VIDC_DECODER) { + codec_input->decoder_or_encoder = CODEC_DECODER; + } else { + d_vpr_e("%s: invalid domain %d\n", __func__, d->domain); + return -EINVAL; + } + + codec_input->chipset_gen = MSM_PINEAPPLE; + + if (d->codec == MSM_VIDC_H264) { + if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) { + codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CABAC; + codec_input->codec = CODEC_H264; + } else if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) { + codec_input->entropy_coding_mode = CODEC_ENTROPY_CODING_CAVLC; + codec_input->codec = CODEC_H264_CAVLC; + } else { + d_vpr_e("%s: invalid entropy %d\n", __func__, + inst->capabilities[ENTROPY_MODE].value); + return -EINVAL; + } + } else if (d->codec == MSM_VIDC_HEVC) { + codec_input->codec = CODEC_HEVC; + } else if (d->codec == MSM_VIDC_VP9) { + codec_input->codec = CODEC_VP9; + } else if (d->codec == MSM_VIDC_AV1) { + codec_input->codec = CODEC_AV1; + } else { + d_vpr_e("%s: invalid codec %d\n", __func__, d->codec); + return -EINVAL; + } + + codec_input->lcu_size = d->lcu_size; + codec_input->pipe_num = d->num_vpp_pipes; + codec_input->frame_rate = d->fps; + codec_input->frame_width = d->input_width; + codec_input->frame_height = d->input_height; + + if (d->work_mode == MSM_VIDC_STAGE_1) { + codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_1S; + } else if (d->work_mode == MSM_VIDC_STAGE_2) { + codec_input->vsp_vpp_mode = CODEC_VSPVPP_MODE_2S; + } else { + d_vpr_e("%s: invalid stage %d\n", __func__, d->work_mode); + return -EINVAL; + } + + codec_input->hierachical_layer = + msm_vidc_get_hier_layer_val(inst); + + /* + * If the calculated motion_vector_complexity is > 2 then set the + * complexity_setting and refframe_complexity to be pwc(performance worst case) + * values. If the motion_vector_complexity is < 2 then set the complexity_setting + * and refframe_complexity to be average case values. + */ + + complexity_factor_int = Q16_INT(d->complexity_factor); + complexity_factor_frac = Q16_FRAC(d->complexity_factor); + + if (complexity_factor_int < COMPLEXITY_THRESHOLD || + (complexity_factor_int == COMPLEXITY_THRESHOLD && + complexity_factor_frac == 0)) { + /* set as average case values */ + codec_input->complexity_setting = COMPLEXITY_SETTING_AVG; + codec_input->refframe_complexity = REFFRAME_COMPLEXITY_AVG; + } else { + /* set as pwc */ + codec_input->complexity_setting = COMPLEXITY_SETTING_PWC; + codec_input->refframe_complexity = REFFRAME_COMPLEXITY_PWC; + } + + codec_input->status_llc_onoff = d->use_sys_cache; + + if (__bpp(d->color_formats[0]) == 8) + codec_input->bitdepth = CODEC_BITDEPTH_8; + else + codec_input->bitdepth = CODEC_BITDEPTH_10; + + if (d->num_formats == 1) { + codec_input->split_opb = 0; + codec_input->linear_opb = !__ubwc(d->color_formats[0]); + } else if (d->num_formats == 2) { + codec_input->split_opb = 1; + codec_input->linear_opb = !__ubwc(d->color_formats[1]); + } else { + d_vpr_e("%s: invalid num_formats %d\n", + __func__, d->num_formats); + return -EINVAL; + } + + codec_input->linear_ipb = 0; /* set as ubwc ipb */ + + /* TODO Confirm if we always LOSSLESS mode ie lossy_ipb = 0*/ + codec_input->lossy_ipb = 0; /* set as lossless ipb */ + + /* TODO Confirm if no multiref */ + codec_input->encoder_multiref = 0; /* set as no multiref */ + codec_input->bitrate_mbps = (d->bitrate / 1000000); + + opb_compression_enabled = d->num_formats >= 2 && __ubwc(d->color_formats[1]); + + /* video driver CR is in Q16 format, StaticModel CR in x100 format */ + if (d->domain == MSM_VIDC_DECODER) { + codec_input->cr_dpb = ((Q16_INT(d->compression_ratio)*100) + + Q16_FRAC(d->compression_ratio)); + codec_input->cr_opb = codec_input->cr_dpb; + if (codec_input->split_opb == 1) { + /* need to check the value if linear opb, currently set min cr */ + codec_input->cr_opb = 100; + } + } else { + codec_input->cr_ipb = ((Q16_INT(d->input_cr)*100) + Q16_FRAC(d->input_cr)); + codec_input->cr_rpb = ((Q16_INT(d->compression_ratio)*100) + + Q16_FRAC(d->compression_ratio)); + } + + /* disable by default, only enable for aurora depth map session */ + codec_input->lumaonly_decode = 0; + + /* set as custom regression mode, as are using cr,cf values from FW */ + codec_input->regression_mode = REGRESSION_MODE_CUSTOM; + + /* av1d commercial tile */ + if (inst->codec == MSM_VIDC_AV1 && codec_input->lcu_size == 128) { + tile_rows_columns = inst->power.fw_av1_tile_rows * + inst->power.fw_av1_tile_columns; + + /* check resolution and tile info */ + codec_input->av1d_commer_tile_enable = 1; + + if (res_is_less_than_or_equal_to(codec_input->frame_width, + codec_input->frame_height, 1920, 1088)) { + if (tile_rows_columns <= 2) + codec_input->av1d_commer_tile_enable = 0; + } else if (res_is_less_than_or_equal_to(codec_input->frame_width, + codec_input->frame_height, 4096, 2172)) { + if (tile_rows_columns <= 4) + codec_input->av1d_commer_tile_enable = 0; + } else if (res_is_less_than_or_equal_to(codec_input->frame_width, + codec_input->frame_height, 8192, 4320)) { + if (tile_rows_columns <= 16) + codec_input->av1d_commer_tile_enable = 0; + } + } else { + codec_input->av1d_commer_tile_enable = 0; + } + + core = inst->core; + codec_input->vpu_ver = core->platform->data.vpu_ver; + + /* Dump all the variables for easier debugging */ + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"complexity_factor_int", "%d", complexity_factor_int}, + {"complexity_factor_frac", "%d", complexity_factor_frac}, + {"refframe_complexity", "%d", codec_input->refframe_complexity}, + {"complexity_setting", "%d", codec_input->complexity_setting}, + {"cr_dpb", "%d", codec_input->cr_dpb}, + {"cr_opb", "%d", codec_input->cr_opb}, + {"cr_ipb", "%d", codec_input->cr_ipb}, + {"cr_rpb", "%d", codec_input->cr_rpb}, + {"lcu size", "%d", codec_input->lcu_size}, + {"pipe number", "%d", codec_input->pipe_num}, + {"frame_rate", "%d", codec_input->frame_rate}, + {"frame_width", "%d", codec_input->frame_width}, + {"frame_height", "%d", codec_input->frame_height}, + {"work_mode", "%d", d->work_mode}, + {"encoder_or_decode", "%d", inst->domain}, + {"chipset_gen", "%d", codec_input->chipset_gen}, + {"codec_input", "%d", codec_input->codec}, + {"entropy_coding_mode", "%d", codec_input->entropy_coding_mode}, + {"hierachical_layer", "%d", codec_input->hierachical_layer}, + {"status_llc_onoff", "%d", codec_input->status_llc_onoff}, + {"bit_depth", "%d", codec_input->bitdepth}, + {"split_opb", "%d", codec_input->split_opb}, + {"linear_opb", "%d", codec_input->linear_opb}, + {"linear_ipb", "%d", codec_input->linear_ipb}, + {"lossy_ipb", "%d", codec_input->lossy_ipb}, + {"encoder_multiref", "%d", codec_input->encoder_multiref}, + {"bitrate_mbps", "%d", codec_input->bitrate_mbps}, + {"lumaonly_decode", "%d", codec_input->lumaonly_decode}, + {"av1d_commer_tile_enable", "%d", codec_input->av1d_commer_tile_enable}, + {"regression_mode", "%d", codec_input->regression_mode}, + {"vpu_ver", "%d", codec_input->vpu_ver}, + }; + __dump(dump, ARRAY_SIZE(dump)); + } + + return 0; +} + +static bool is_vpp_cycles_close_to_freq_corner(struct msm_vidc_core *core, + u64 vpp_min_freq) +{ + u64 margin_freq = 0; + u64 closest_freq_upper_corner = 0; + u32 margin_percent = 0; + int i = 0; + + if (!core || !core->resource || !core->resource->freq_set.freq_tbl || + !core->resource->freq_set.count) { + d_vpr_e("%s: invalid params\n", __func__); + return false; + } + + vpp_min_freq = vpp_min_freq * 1000000; /* convert to hz */ + + closest_freq_upper_corner = + core->resource->freq_set.freq_tbl[0].freq; + + /* return true if vpp_min_freq is more than max frequency */ + if (vpp_min_freq > closest_freq_upper_corner) + return true; + + /* get the closest freq corner for vpp_min_freq */ + for (i = 0; i < core->resource->freq_set.count; i++) { + if (vpp_min_freq <= + core->resource->freq_set.freq_tbl[i].freq) { + closest_freq_upper_corner = + core->resource->freq_set.freq_tbl[i].freq; + } else { + break; + } + } + + margin_freq = closest_freq_upper_corner - vpp_min_freq; + margin_percent = div_u64((margin_freq * 100), closest_freq_upper_corner); + + /* check if margin is less than cutoff */ + if (margin_percent < VPP_MIN_FREQ_MARGIN_PERCENT) + return true; + + return false; +} + +static u64 msm_vidc_calc_freq_iris33_new(struct msm_vidc_inst *inst, u32 data_size) +{ + u64 freq = 0; + struct msm_vidc_core *core; + int ret = 0; + struct api_calculation_input codec_input; + struct api_calculation_freq_output codec_output; + u32 fps, mbpf; + + core = inst->core; + + mbpf = msm_vidc_get_mbs_per_frame(inst); + fps = inst->max_rate; + + memset(&codec_input, 0, sizeof(struct api_calculation_input)); + memset(&codec_output, 0, sizeof(struct api_calculation_freq_output)); + ret = msm_vidc_init_codec_input_freq(inst, data_size, &codec_input); + if (ret) + return freq; + ret = msm_vidc_calculate_frequency(codec_input, &codec_output); + if (ret) + return freq; + + if (is_encode_session(inst)) { + if (!inst->capabilities[ENC_RING_BUFFER_COUNT].value && + is_vpp_cycles_close_to_freq_corner(core, + codec_output.vpp_min_freq)) { + /* + * if ring buffer not enabled and required vpp cycles + * is too close to the frequency corner then increase + * the vpp cycles by VPP_MIN_FREQ_MARGIN_PERCENT + */ + codec_output.vpp_min_freq += div_u64( + codec_output.vpp_min_freq * + VPP_MIN_FREQ_MARGIN_PERCENT, 100); + codec_output.hw_min_freq = max( + codec_output.hw_min_freq, + codec_output.vpp_min_freq); + } + } + + freq = (u64)codec_output.hw_min_freq * 1000000; /* Convert to Hz */ + + i_vpr_p(inst, + "%s: filled len %d, required freq %llu, vpp %u, vsp %u, tensilica %u, hw_freq %u, fps %u, mbpf %u\n", + __func__, data_size, freq, codec_output.vpp_min_freq, + codec_output.vsp_min_freq, codec_output.tensilica_min_freq, + codec_output.hw_min_freq, fps, mbpf); + + if (!is_realtime_session(inst) || + inst->codec == MSM_VIDC_AV1 || + is_lowlatency_session(inst) || + (inst->iframe && is_hevc_10bit_decode_session(inst))) { + /* + * TURBO is only allowed for: + * - NRT decoding/encoding session + * - AV1 decoding session + * - Low latency session + * - 10-bit I-Frame decoding session + * limit to NOM for all other cases + */ + } else { + /* limit to NOM, index 0 is TURBO, index 1 is NOM clock rate */ + if (core->resource->freq_set.count >= 2 && + freq > core->resource->freq_set.freq_tbl[1].freq) + freq = core->resource->freq_set.freq_tbl[1].freq; + } + + return freq; +} + +static int msm_vidc_calc_bw_iris33_new(struct msm_vidc_inst *inst, + struct vidc_bus_vote_data *vidc_data) +{ + u32 ret = 0; + struct api_calculation_input codec_input; + struct api_calculation_bw_output codec_output; + + memset(&codec_input, 0, sizeof(struct api_calculation_input)); + memset(&codec_output, 0, sizeof(struct api_calculation_bw_output)); + + ret = msm_vidc_init_codec_input_bus(inst, vidc_data, &codec_input); + if (ret) + return ret; + ret = msm_vidc_calculate_bandwidth(codec_input, &codec_output); + if (ret) + return ret; + + vidc_data->calc_bw_ddr = kbps(codec_output.ddr_bw_rd + codec_output.ddr_bw_wr); + vidc_data->calc_bw_llcc = kbps(codec_output.noc_bw_rd + codec_output.noc_bw_wr); + + i_vpr_l(inst, "%s: calc_bw_ddr %lu calc_bw_llcc %lu", + __func__, vidc_data->calc_bw_ddr, vidc_data->calc_bw_llcc); + + return ret; +} + +u64 msm_vidc_calc_freq_iris33(struct msm_vidc_inst *inst, u32 data_size) +{ + u64 freq = 0; + + if (ENABLE_LEGACY_POWER_CALCULATIONS) + freq = msm_vidc_calc_freq_iris33_legacy(inst, data_size); + else + freq = msm_vidc_calc_freq_iris33_new(inst, data_size); + + return freq; +} + +u64 msm_vidc_calc_freq_iris33_legacy(struct msm_vidc_inst *inst, u32 data_size) +{ + u64 freq = 0; + struct msm_vidc_core *core; + u64 vsp_cycles = 0, vpp_cycles = 0, fw_cycles = 0; + u64 fw_vpp_cycles = 0, bitrate = 0; + u32 vpp_cycles_per_mb; + u32 mbs_per_second; + u32 operating_rate, vsp_factor_num = 1, vsp_factor_den = 1; + u32 base_cycles = 0; + u32 fps, mbpf; + + core = inst->core; + + if (!core->resource || !core->resource->freq_set.freq_tbl || + !core->resource->freq_set.count) { + d_vpr_e("%s: invalid params\n", __func__); + return freq; + } + + mbpf = msm_vidc_get_mbs_per_frame(inst); + fps = inst->max_rate; + mbs_per_second = mbpf * fps; + + /* + * Calculate vpp, vsp, fw cycles separately for encoder and decoder. + * Even though, most part is common now, in future it may change + * between them. + */ + fw_cycles = fps * inst->capabilities[MB_CYCLES_FW].value; + fw_vpp_cycles = fps * inst->capabilities[MB_CYCLES_FW_VPP].value; + + if (is_encode_session(inst)) { + vpp_cycles_per_mb = is_low_power_session(inst) ? + inst->capabilities[MB_CYCLES_LP].value : + inst->capabilities[MB_CYCLES_VPP].value; + + vpp_cycles = mbs_per_second * vpp_cycles_per_mb / + inst->capabilities[PIPE].value; + + /* Factor 1.25 for IbP and 1.375 for I1B2b1P GOP structure */ + if (inst->capabilities[B_FRAME].value > 1) + vpp_cycles += (vpp_cycles / 4) + (vpp_cycles / 8); + else if (inst->capabilities[B_FRAME].value) + vpp_cycles += vpp_cycles / 4; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(div_u64(vpp_cycles, 20), fw_vpp_cycles); + /* 1.01 is multi-pipe overhead */ + if (inst->capabilities[PIPE].value > 1) + vpp_cycles += div_u64(vpp_cycles, 100); + /* + * 1080p@480fps usecase needs exactly 338MHz + * without any margin left. Hence, adding 2 percent + * extra to bump it to next level (366MHz). + */ + if (fps == 480) + vpp_cycles += div_u64(vpp_cycles * 2, 100); + + /* + * Add 5 percent extra for 720p@960fps use case + * to bump it to next level (366MHz). + */ + if (fps == 960) + vpp_cycles += div_u64(vpp_cycles * 5, 100); + + /* increase vpp_cycles by 50% for preprocessing */ + if (inst->capabilities[REQUEST_PREPROCESS].value) + vpp_cycles = vpp_cycles + vpp_cycles / 2; + + /* VSP */ + /* bitrate is based on fps, scale it using operating rate */ + operating_rate = inst->capabilities[OPERATING_RATE].value >> 16; + if (operating_rate > + (inst->capabilities[FRAME_RATE].value >> 16) && + (inst->capabilities[FRAME_RATE].value >> 16)) { + vsp_factor_num = operating_rate; + vsp_factor_den = inst->capabilities[FRAME_RATE].value >> 16; + } + vsp_cycles = div_u64(((u64)inst->capabilities[BIT_RATE].value * + vsp_factor_num), vsp_factor_den); + + base_cycles = inst->capabilities[MB_CYCLES_VSP].value; + if (inst->codec == MSM_VIDC_VP9) { + vsp_cycles = div_u64(vsp_cycles * 170, 100); + } else if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) { + vsp_cycles = div_u64(vsp_cycles * 135, 100); + } else { + base_cycles = 0; + vsp_cycles = div_u64(vsp_cycles, 2); + } + /* VSP FW Overhead 1.05 */ + vsp_cycles = div_u64(vsp_cycles * 21, 20); + + if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_1) + vsp_cycles = vsp_cycles * 3; + + vsp_cycles += mbs_per_second * base_cycles; + + } else if (is_decode_session(inst)) { + /* VPP */ + vpp_cycles = mbs_per_second * inst->capabilities[MB_CYCLES_VPP].value / + inst->capabilities[PIPE].value; + /* 21 / 20 is minimum overhead factor */ + vpp_cycles += max(vpp_cycles / 20, fw_vpp_cycles); + if (inst->capabilities[PIPE].value > 1) { + if (inst->codec == MSM_VIDC_AV1) { + /* + * Additional vpp_cycles are required for bitstreams with + * 128x128 superblock and non-recommended tile settings. + * recommended tiles: 1080P_V2XH1, UHD_V2X2, 8KUHD_V8X2 + * non-recommended tiles: 1080P_V4XH2_V4X1, UHD_V8X4_V8X1, + * 8KUHD_V8X8_V8X1 + */ + if (inst->capabilities[SUPER_BLOCK].value) + vpp_cycles += div_u64(vpp_cycles * 1464, 1000); + else + vpp_cycles += div_u64(vpp_cycles * 410, 1000); + } else { + /* 1.059 is multi-pipe overhead */ + vpp_cycles += div_u64(vpp_cycles * 59, 1000); + } + } + + /* VSP */ + if (inst->codec == MSM_VIDC_AV1) { + /* + * For AV1: Use VSP calculations from Lanai perf model. + * For legacy codecs, use vsp_cycles based on legacy MB_CYCLES_VSP. + */ + u32 decoder_vsp_fw_overhead = 105; + u32 fw_sw_vsp_offset = 1055; + u64 vsp_hw_min_frequency = 0; + u32 input_bitrate_mbps = 0; + u32 bitrate_2stage[2] = {130, 120}; + u32 bitrate_1stage = 100; + u32 width, height; + u32 bitrate_entry, freq_entry, freq_tbl_value; + struct frequency_table *freq_tbl; + struct v4l2_format *out_f = &inst->fmts[OUTPUT_PORT]; + + width = out_f->fmt.pix_mp.width; + height = out_f->fmt.pix_mp.height; + + bitrate_entry = 1; + /* 8KUHD60, UHD240, 1080p960 */ + if (width * height * fps >= 3840 * 2160 * 240) + bitrate_entry = 0; + + freq_entry = bitrate_entry; + + freq_tbl = core->resource->freq_set.freq_tbl; + freq_tbl_value = freq_tbl[freq_entry].freq / 1000000; + + input_bitrate_mbps = fps * data_size * 8 / (1024 * 1024); + vsp_hw_min_frequency = freq_tbl_value * 1000 * input_bitrate_mbps; + + if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_2) { + vsp_hw_min_frequency += + (bitrate_2stage[bitrate_entry] * fw_sw_vsp_offset - 1); + vsp_hw_min_frequency = div_u64(vsp_hw_min_frequency, + (bitrate_2stage[bitrate_entry] * fw_sw_vsp_offset)); + /* VSP fw overhead 1.05 */ + vsp_hw_min_frequency = div_u64(vsp_hw_min_frequency * + decoder_vsp_fw_overhead + 99, 100); + } else { + vsp_hw_min_frequency += (bitrate_1stage * fw_sw_vsp_offset - 1); + vsp_hw_min_frequency = div_u64(vsp_hw_min_frequency, + (bitrate_1stage * fw_sw_vsp_offset)); + } + + vsp_cycles = vsp_hw_min_frequency * 1000000; + } else { + base_cycles = inst->has_bframe ? + 80 : inst->capabilities[MB_CYCLES_VSP].value; + bitrate = fps * data_size * 8; + vsp_cycles = bitrate; + + if (inst->codec == MSM_VIDC_VP9) { + vsp_cycles = div_u64(vsp_cycles * 170, 100); + } else if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC) { + vsp_cycles = div_u64(vsp_cycles * 135, 100); + } else { + base_cycles = 0; + vsp_cycles = div_u64(vsp_cycles, 2); + } + /* VSP FW overhead 1.05 */ + vsp_cycles = div_u64(vsp_cycles * 21, 20); + + if (inst->capabilities[STAGE].value == MSM_VIDC_STAGE_1) + vsp_cycles = vsp_cycles * 3; + + vsp_cycles += mbs_per_second * base_cycles; + + /* Add 25 percent extra for 960fps use case */ + if (fps >= 960) + vsp_cycles += div_u64(vpp_cycles * 25, 100); + + /* Add 25 percent extra for HEVC 10bit all intra use case */ + if (inst->iframe && is_hevc_10bit_decode_session(inst)) + vsp_cycles += div_u64(vsp_cycles * 25, 100); + + if (inst->codec == MSM_VIDC_VP9 && + inst->capabilities[STAGE].value == + MSM_VIDC_STAGE_2 && + inst->capabilities[PIPE].value == 4 && + bitrate > 90000000) + vsp_cycles = msm_vidc_max_freq(inst); + } + } else { + i_vpr_e(inst, "%s: Unknown session type\n", __func__); + return msm_vidc_max_freq(inst); + } + + freq = max(vpp_cycles, vsp_cycles); + freq = max(freq, fw_cycles); + + i_vpr_p(inst, + "%s: filled len %d, required freq %llu, vpp %llu, vsp %llu, fw_cycles %llu, fps %u, mbpf %u\n", + __func__, data_size, freq, + vpp_cycles, vsp_cycles, fw_cycles, fps, mbpf); + + if (inst->codec == MSM_VIDC_AV1 || (inst->iframe && is_hevc_10bit_decode_session(inst)) || + (!is_realtime_session(inst))) { + /* + * TURBO is only allowed for: + * 1. AV1 decoding session + * 2. 10-bit I-Frame decoding session + * 3. NRT decoding/encoding session + * limit to NOM for all other cases + */ + } else { + /* limit to NOM, index 0 is TURBO, index 1 is NOM clock rate */ + if (core->resource->freq_set.count >= 2 && + freq > core->resource->freq_set.freq_tbl[1].freq) + freq = core->resource->freq_set.freq_tbl[1].freq; + } + + return freq; +} + +static u64 __calculate_decoder(struct vidc_bus_vote_data *d) +{ + /* + * XXX: Don't fool around with any of the hardcoded numbers unless you + * know /exactly/ what you're doing. Many of these numbers are + * measured heuristics and hardcoded numbers taken from the firmware. + */ + /* Decoder parameters */ + int width, height, lcu_size, fps, dpb_bpp; + bool unified_dpb_opb, dpb_compression_enabled = true, + opb_compression_enabled = false, + llc_ref_read_l2_cache_enabled = false, + llc_top_line_buf_enabled = false; + fp_t dpb_read_compression_factor, dpb_opb_scaling_ratio, + dpb_write_compression_factor, opb_write_compression_factor, + qsmmu_bw_overhead_factor; + bool is_h264_category = (d->codec == MSM_VIDC_H264) ? true : false; + + /* Derived parameters */ + int lcu_per_frame, collocated_bytes_per_lcu, tnbr_per_lcu; + unsigned long bitrate; + + fp_t bins_to_bit_factor, vsp_read_factor, vsp_write_factor, + dpb_factor, dpb_write_factor, y_bw_no_ubwc_8bpp; + fp_t y_bw_no_ubwc_10bpp = 0, y_bw_10bpp_p010 = 0, + motion_vector_complexity = 0; + fp_t dpb_total = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + dpb_read, dpb_write, opb_read, opb_write, + line_buffer_read, line_buffer_write, + total; + } ddr = {0}; + + struct { + fp_t dpb_read, line_buffer_read, line_buffer_write, total; + } llc = {0}; + + unsigned long ret = 0; + unsigned int integer_part, frac_part; + + width = max(d->input_width, BASELINE_DIMENSIONS.width); + height = max(d->input_height, BASELINE_DIMENSIONS.height); + + fps = d->fps; + + lcu_size = d->lcu_size; + + dpb_bpp = __bpp(d->color_formats[0]); + + unified_dpb_opb = d->num_formats == 1; + + dpb_opb_scaling_ratio = fp_div(FP_INT(d->input_width * d->input_height), + FP_INT(d->output_width * d->output_height)); + + opb_compression_enabled = d->num_formats >= 2 && + __ubwc(d->color_formats[1]); + + integer_part = Q16_INT(d->compression_ratio); + frac_part = Q16_FRAC(d->compression_ratio); + dpb_read_compression_factor = FP(integer_part, frac_part, 100); + + integer_part = Q16_INT(d->complexity_factor); + frac_part = Q16_FRAC(d->complexity_factor); + motion_vector_complexity = FP(integer_part, frac_part, 100); + + dpb_write_compression_factor = dpb_read_compression_factor; + opb_write_compression_factor = opb_compression_enabled ? + dpb_write_compression_factor : FP_ONE; + + if (d->use_sys_cache) { + llc_ref_read_l2_cache_enabled = true; + if (is_h264_category) + llc_top_line_buf_enabled = true; + } + + /* Derived parameters setup */ + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + + bitrate = DIV_ROUND_UP(d->bitrate, 1000000); + + bins_to_bit_factor = FP_INT(4); + + vsp_write_factor = bins_to_bit_factor; + vsp_read_factor = bins_to_bit_factor + FP_INT(2); + + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + if (d->codec == MSM_VIDC_AV1) { + collocated_bytes_per_lcu = 4 * 512; /* lcu_size = 128 */ + if (lcu_size == 32) + collocated_bytes_per_lcu = 4 * 512 / (128 * 128 / 32 / 32); + else if (lcu_size == 64) + collocated_bytes_per_lcu = 4 * 512 / (128 * 128 / 64 / 64); + } + + dpb_factor = FP(1, 50, 100); + dpb_write_factor = FP(1, 5, 100); + + tnbr_per_lcu = lcu_size == 16 ? 128 : + lcu_size == 32 ? 64 : 128; + + /* .... For DDR & LLC ...... */ + ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate), + vsp_read_factor), FP_INT(8)); + ddr.vsp_write = fp_div(fp_mult(FP_INT(bitrate), + vsp_write_factor), FP_INT(8)); + + ddr.collocated_read = fp_div(FP_INT(lcu_per_frame * + collocated_bytes_per_lcu * fps), FP_INT(bps(1))); + ddr.collocated_write = ddr.collocated_read; + + y_bw_no_ubwc_8bpp = fp_div(FP_INT(width * height * fps), + FP_INT(1000 * 1000)); + + if (dpb_bpp != 8) { + y_bw_no_ubwc_10bpp = + fp_div(fp_mult(y_bw_no_ubwc_8bpp, FP_INT(256)), + FP_INT(192)); + y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2; + } + + ddr.dpb_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_read = fp_div(fp_mult(ddr.dpb_read, + fp_mult(dpb_factor, motion_vector_complexity)), + dpb_read_compression_factor); + + ddr.dpb_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.dpb_write = fp_div(fp_mult(ddr.dpb_write, + fp_mult(dpb_factor, dpb_write_factor)), + dpb_write_compression_factor); + + dpb_total = ddr.dpb_read + ddr.dpb_write; + + if (llc_ref_read_l2_cache_enabled) { + ddr.dpb_read = fp_div(ddr.dpb_read, is_h264_category ? + FP(1, 30, 100) : FP(1, 14, 100)); + llc.dpb_read = dpb_total - ddr.dpb_write - ddr.dpb_read; + } + + ddr.opb_read = FP_ZERO; + ddr.opb_write = unified_dpb_opb ? FP_ZERO : (dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : (opb_compression_enabled ? + y_bw_no_ubwc_10bpp : y_bw_10bpp_p010)); + ddr.opb_write = fp_div(fp_mult(dpb_factor, ddr.opb_write), + fp_mult(dpb_opb_scaling_ratio, opb_write_compression_factor)); + + ddr.line_buffer_read = + fp_div(FP_INT(tnbr_per_lcu * lcu_per_frame * fps), + FP_INT(bps(1))); + + if (is_h264_category) + ddr.line_buffer_write = fp_div(ddr.line_buffer_read, FP_INT(2)); + else + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer_read = ddr.line_buffer_read; + llc.line_buffer_write = ddr.line_buffer_write; + ddr.line_buffer_write = ddr.line_buffer_read = FP_ZERO; + } + + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.dpb_read + ddr.dpb_write + + ddr.opb_read + ddr.opb_write + + ddr.line_buffer_read + ddr.line_buffer_write; + + qsmmu_bw_overhead_factor = FP(1, 3, 100); + + ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); + llc.total = llc.dpb_read + llc.line_buffer_read + + llc.line_buffer_write + ddr.total; + + /* Add 25 percent extra for 960fps use case */ + if (fps >= 960) { + ddr.total += div_u64(ddr.total * 25, 100); + llc.total += div_u64(llc.total * 25, 100); + } + + /* Dump all the variables for easier debugging */ + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu size", "%d", lcu_size}, + {"dpb bitdepth", "%d", dpb_bpp}, + {"frame rate", "%d", fps}, + {"dpb/opb unified", "%d", unified_dpb_opb}, + {"dpb/opb downscaling ratio", DUMP_FP_FMT, + dpb_opb_scaling_ratio}, + {"dpb compression", "%d", dpb_compression_enabled}, + {"opb compression", "%d", opb_compression_enabled}, + {"dpb read compression factor", DUMP_FP_FMT, + dpb_read_compression_factor}, + {"dpb write compression factor", DUMP_FP_FMT, + dpb_write_compression_factor}, + {"frame width", "%d", width}, + {"frame height", "%d", height}, + {"llc ref read l2 cache enabled", "%d", + llc_ref_read_l2_cache_enabled}, + {"llc top line buf enabled", "%d", + llc_top_line_buf_enabled}, + + {"DERIVED PARAMETERS (1)", "", DUMP_HEADER_MAGIC}, + {"lcus/frame", "%d", lcu_per_frame}, + {"bitrate (Mbit/sec)", "%d", bitrate}, + {"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor}, + {"dpb write factor", DUMP_FP_FMT, dpb_write_factor}, + {"vsp read factor", DUMP_FP_FMT, vsp_read_factor}, + {"vsp write factor", DUMP_FP_FMT, vsp_write_factor}, + {"tnbr/lcu", "%d", tnbr_per_lcu}, + {"collocated bytes/LCU", "%d", collocated_bytes_per_lcu}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, + + {"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC}, + {"mv complexity", DUMP_FP_FMT, motion_vector_complexity}, + {"qsmmu_bw_overhead_factor", DUMP_FP_FMT, + qsmmu_bw_overhead_factor}, + + {"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, + {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, + {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, + {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, + {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, + {"opb read", DUMP_FP_FMT, ddr.opb_read}, + {"opb write", DUMP_FP_FMT, ddr.opb_write}, + {"dpb read", DUMP_FP_FMT, ddr.dpb_read}, + {"dpb write", DUMP_FP_FMT, ddr.dpb_write}, + {"dpb total", DUMP_FP_FMT, dpb_total}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc dpb read", DUMP_FP_FMT, llc.dpb_read}, + {"llc line buffer read", DUMP_FP_FMT, llc.line_buffer_read}, + {"llc line buffer write", DUMP_FP_FMT, llc.line_buffer_write}, + + }; + __dump(dump, ARRAY_SIZE(dump)); + } + + d->calc_bw_ddr = kbps(fp_round(ddr.total)); + d->calc_bw_llcc = kbps(fp_round(llc.total)); + + return ret; +} + +static u64 __calculate_encoder(struct vidc_bus_vote_data *d) +{ + /* + * XXX: Don't fool around with any of the hardcoded numbers unless you + * know /exactly/ what you're doing. Many of these numbers are + * measured heuristics and hardcoded numbers taken from the firmware. + */ + /* Encoder Parameters */ + int width, height, fps, lcu_size, bitrate, lcu_per_frame, + collocated_bytes_per_lcu, tnbr_per_lcu, dpb_bpp, + original_color_format, vertical_tile_width, rotation; + bool work_mode_1, original_compression_enabled, + low_power, cropping_or_scaling, + b_frames_enabled = false, + llc_ref_chroma_cache_enabled = false, + llc_top_line_buf_enabled = false, + llc_vpss_rot_line_buf_enabled = false, + vpss_preprocessing_enabled = false; + + unsigned int bins_to_bit_factor; + fp_t dpb_compression_factor, + original_compression_factor, + original_compression_factor_y, + y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp = 0, y_bw_10bpp_p010 = 0, + input_compression_factor, + downscaling_ratio, + ref_y_read_bw_factor, ref_cbcr_read_bw_factor, + recon_write_bw_factor, + total_ref_read_crcb, + qsmmu_bw_overhead_factor; + fp_t integer_part, frac_part; + unsigned long ret = 0; + + /* Output parameters */ + struct { + fp_t vsp_read, vsp_write, collocated_read, collocated_write, + ref_read_y, ref_read_crcb, ref_write, + ref_write_overlap, orig_read, + line_buffer_read, line_buffer_write, + total; + } ddr = {0}; + + struct { + fp_t ref_read_crcb, line_buffer, total; + } llc = {0}; + + /* Encoder Parameters setup */ + rotation = d->rotation; + cropping_or_scaling = false; + vertical_tile_width = 960; + /* + * recon_write_bw_factor varies according to resolution and bit-depth, + * here use 1.08(1.075) for worst case. + * Similar for ref_y_read_bw_factor, it can reach 1.375 for worst case, + * here use 1.3 for average case, and can somewhat balance the + * worst case assumption for UBWC CR factors. + */ + recon_write_bw_factor = FP(1, 8, 100); + ref_y_read_bw_factor = FP(1, 30, 100); + ref_cbcr_read_bw_factor = FP(1, 50, 100); + + + /* Derived Parameters */ + fps = d->fps; + width = max(d->output_width, BASELINE_DIMENSIONS.width); + height = max(d->output_height, BASELINE_DIMENSIONS.height); + downscaling_ratio = fp_div(FP_INT(d->input_width * d->input_height), + FP_INT(d->output_width * d->output_height)); + downscaling_ratio = max(downscaling_ratio, FP_ONE); + bitrate = d->bitrate > 0 ? DIV_ROUND_UP(d->bitrate, 1000000) : + __lut(width, height, fps)->bitrate; + lcu_size = d->lcu_size; + lcu_per_frame = DIV_ROUND_UP(width, lcu_size) * + DIV_ROUND_UP(height, lcu_size); + tnbr_per_lcu = 16; + + dpb_bpp = __bpp(d->color_formats[0]); + + y_bw_no_ubwc_8bpp = fp_div(FP_INT(width * height * fps), + FP_INT(1000 * 1000)); + + if (dpb_bpp != 8) { + y_bw_no_ubwc_10bpp = fp_div(fp_mult(y_bw_no_ubwc_8bpp, + FP_INT(256)), FP_INT(192)); + y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2; + } + + b_frames_enabled = d->b_frames_enabled; + original_color_format = d->num_formats >= 1 ? + d->color_formats[0] : MSM_VIDC_FMT_NV12C; + + original_compression_enabled = __ubwc(original_color_format); + + work_mode_1 = d->work_mode == MSM_VIDC_STAGE_1; + low_power = d->power_mode == VIDC_POWER_LOW; + bins_to_bit_factor = 4; + vpss_preprocessing_enabled = d->vpss_preprocessing_enabled; + + if (d->use_sys_cache) { + llc_ref_chroma_cache_enabled = true; + llc_top_line_buf_enabled = true, + llc_vpss_rot_line_buf_enabled = true; + } + + integer_part = Q16_INT(d->compression_ratio); + frac_part = Q16_FRAC(d->compression_ratio); + dpb_compression_factor = FP(integer_part, frac_part, 100); + + integer_part = Q16_INT(d->input_cr); + frac_part = Q16_FRAC(d->input_cr); + input_compression_factor = FP(integer_part, frac_part, 100); + + original_compression_factor = original_compression_factor_y = + !original_compression_enabled ? FP_ONE : + __compression_ratio(__lut(width, height, fps), dpb_bpp); + /* use input cr if it is valid (not 1), otherwise use lut */ + if (original_compression_enabled && + input_compression_factor != FP_ONE) { + original_compression_factor = input_compression_factor; + /* Luma usually has lower compression factor than Chroma, + * input cf is overall cf, add 1.08 factor for Luma cf + */ + original_compression_factor_y = + input_compression_factor > FP(1, 8, 100) ? + fp_div(input_compression_factor, FP(1, 8, 100)) : + input_compression_factor; + } + + ddr.vsp_read = fp_div(FP_INT(bitrate * bins_to_bit_factor), FP_INT(8)); + ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8)); + + collocated_bytes_per_lcu = lcu_size == 16 ? 16 : + lcu_size == 32 ? 64 : 256; + + ddr.collocated_read = fp_div(FP_INT(lcu_per_frame * + collocated_bytes_per_lcu * fps), FP_INT(bps(1))); + + ddr.collocated_write = ddr.collocated_read; + + ddr.ref_read_y = dpb_bpp == 8 ? + y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + if (b_frames_enabled) + ddr.ref_read_y = ddr.ref_read_y * 2; + ddr.ref_read_y = fp_div(ddr.ref_read_y, dpb_compression_factor); + + ddr.ref_read_crcb = fp_mult((ddr.ref_read_y / 2), + ref_cbcr_read_bw_factor); + + if (width > vertical_tile_width) { + ddr.ref_read_y = fp_mult(ddr.ref_read_y, + ref_y_read_bw_factor); + } + + if (llc_ref_chroma_cache_enabled) { + total_ref_read_crcb = ddr.ref_read_crcb; + ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb, + ref_cbcr_read_bw_factor); + llc.ref_read_crcb = total_ref_read_crcb - ddr.ref_read_crcb; + } + + ddr.ref_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp; + ddr.ref_write = fp_div(fp_mult(ddr.ref_write, FP(1, 50, 100)), + dpb_compression_factor); + + if (width > vertical_tile_width) { + ddr.ref_write_overlap = fp_mult(ddr.ref_write, + (recon_write_bw_factor - FP_ONE)); + ddr.ref_write = fp_mult(ddr.ref_write, recon_write_bw_factor); + } + + /* double ref_write */ + if (vpss_preprocessing_enabled) + ddr.ref_write = ddr.ref_write * 2; + + ddr.orig_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : + (original_compression_enabled ? y_bw_no_ubwc_10bpp : + y_bw_10bpp_p010); + ddr.orig_read = fp_div(fp_mult(fp_mult(ddr.orig_read, FP(1, 50, 100)), + downscaling_ratio), original_compression_factor); + if (rotation == 90 || rotation == 270) + ddr.orig_read *= lcu_size == 32 ? (dpb_bpp == 8 ? 1 : 3) : 2; + + /* double orig_read */ + if (vpss_preprocessing_enabled) + ddr.orig_read = ddr.orig_read * 2; + + ddr.line_buffer_read = + fp_div(FP_INT(tnbr_per_lcu * lcu_per_frame * fps), + FP_INT(bps(1))); + + ddr.line_buffer_write = ddr.line_buffer_read; + if (llc_top_line_buf_enabled) { + llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write; + ddr.line_buffer_read = ddr.line_buffer_write = FP_ZERO; + } + + ddr.total = ddr.vsp_read + ddr.vsp_write + + ddr.collocated_read + ddr.collocated_write + + ddr.ref_read_y + ddr.ref_read_crcb + + ddr.ref_write + ddr.ref_write_overlap + + ddr.orig_read + + ddr.line_buffer_read + ddr.line_buffer_write; + + qsmmu_bw_overhead_factor = FP(1, 3, 100); + ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor); + llc.total = llc.ref_read_crcb + llc.line_buffer + ddr.total; + + if (msm_vidc_debug & VIDC_BUS) { + struct dump dump[] = { + {"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"width", "%d", width}, + {"height", "%d", height}, + {"fps", "%d", fps}, + {"dpb bitdepth", "%d", dpb_bpp}, + {"input downscaling ratio", DUMP_FP_FMT, downscaling_ratio}, + {"rotation", "%d", rotation}, + {"cropping or scaling", "%d", cropping_or_scaling}, + {"low power mode", "%d", low_power}, + {"work Mode", "%d", work_mode_1}, + {"B frame enabled", "%d", b_frames_enabled}, + {"original frame format", "%#x", original_color_format}, + {"VPSS preprocessing", "%d", vpss_preprocessing_enabled}, + {"original compression enabled", "%d", + original_compression_enabled}, + {"dpb compression factor", DUMP_FP_FMT, + dpb_compression_factor}, + {"input compression factor", DUMP_FP_FMT, + input_compression_factor}, + {"llc ref chroma cache enabled", DUMP_FP_FMT, + llc_ref_chroma_cache_enabled}, + {"llc top line buf enabled", DUMP_FP_FMT, + llc_top_line_buf_enabled}, + {"llc vpss rot line buf enabled ", DUMP_FP_FMT, + llc_vpss_rot_line_buf_enabled}, + + {"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC}, + {"lcu size", "%d", lcu_size}, + {"bitrate (Mbit/sec)", "%lu", bitrate}, + {"bins to bit factor", "%u", bins_to_bit_factor}, + {"original compression factor", DUMP_FP_FMT, + original_compression_factor}, + {"original compression factor y", DUMP_FP_FMT, + original_compression_factor_y}, + {"qsmmu_bw_overhead_factor", + DUMP_FP_FMT, qsmmu_bw_overhead_factor}, + {"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp}, + {"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp}, + + {"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC}, + {"vsp read", DUMP_FP_FMT, ddr.vsp_read}, + {"vsp write", DUMP_FP_FMT, ddr.vsp_write}, + {"collocated read", DUMP_FP_FMT, ddr.collocated_read}, + {"collocated write", DUMP_FP_FMT, ddr.collocated_write}, + {"ref read y", DUMP_FP_FMT, ddr.ref_read_y}, + {"ref read crcb", DUMP_FP_FMT, ddr.ref_read_crcb}, + {"ref write", DUMP_FP_FMT, ddr.ref_write}, + {"ref write overlap", DUMP_FP_FMT, ddr.ref_write_overlap}, + {"original read", DUMP_FP_FMT, ddr.orig_read}, + {"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read}, + {"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write}, + {"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC}, + {"llc ref read crcb", DUMP_FP_FMT, llc.ref_read_crcb}, + {"llc line buffer", DUMP_FP_FMT, llc.line_buffer}, + }; + __dump(dump, ARRAY_SIZE(dump)); + } + + d->calc_bw_ddr = kbps(fp_round(ddr.total)); + d->calc_bw_llcc = kbps(fp_round(llc.total)); + + return ret; +} + +static u64 __calculate(struct msm_vidc_inst *inst, struct vidc_bus_vote_data *d) +{ + u64 value = 0; + + switch (d->domain) { + case MSM_VIDC_ENCODER: + value = __calculate_encoder(d); + break; + case MSM_VIDC_DECODER: + value = __calculate_decoder(d); + break; + default: + i_vpr_e(inst, "%s: Unknown Domain %#x", __func__, d->domain); + } + + return value; +} + +int msm_vidc_calc_bw_iris33(struct msm_vidc_inst *inst, + struct vidc_bus_vote_data *vidc_data) +{ + int value = 0; + + if (!vidc_data) + return value; + + if (ENABLE_LEGACY_POWER_CALCULATIONS) + value = __calculate(inst, vidc_data); + else + value = msm_vidc_calc_bw_iris33_new(inst, vidc_data); + + return value; +} + +int msm_vidc_ring_buf_count_iris33(struct msm_vidc_inst *inst, u32 data_size) +{ + int rc = 0; + struct msm_vidc_core *core; + struct api_calculation_input codec_input; + struct api_calculation_freq_output codec_output; + + core = inst->core; + + if (!core->resource || !core->resource->freq_set.freq_tbl || + !core->resource->freq_set.count) { + i_vpr_e(inst, "%s: invalid frequency table\n", __func__); + return -EINVAL; + } + + if (ENABLE_LEGACY_POWER_CALCULATIONS) + return 0; + + memset(&codec_input, 0, sizeof(struct api_calculation_input)); + memset(&codec_output, 0, sizeof(struct api_calculation_freq_output)); + rc = msm_vidc_init_codec_input_freq(inst, data_size, &codec_input); + if (rc) + return rc; + rc = msm_vidc_calculate_frequency(codec_input, &codec_output); + if (rc) + return rc; + + /* check if vpp_min_freq is exceeding closest freq corner margin */ + if (is_vpp_cycles_close_to_freq_corner(core, + codec_output.vpp_min_freq)) { + /* enable ring buffer */ + i_vpr_h(inst, + "%s: vpp_min_freq %d, ring_buffer_count %d\n", + __func__, codec_output.vpp_min_freq, MAX_ENC_RING_BUF_COUNT); + inst->capabilities[ENC_RING_BUFFER_COUNT].value = + MAX_ENC_RING_BUF_COUNT; + } else { + inst->capabilities[ENC_RING_BUFFER_COUNT].value = 0; + } + return 0; +} diff --git a/qcom/opensource/video-driver/driver/vidc/inc/firmware.h b/qcom/opensource/video-driver/driver/vidc/inc/firmware.h new file mode 100644 index 0000000000..bd521802a4 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/firmware.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_FIRMWARE_H_ +#define _MSM_VIDC_FIRMWARE_H_ + +struct msm_vidc_core; + +int fw_load(struct msm_vidc_core *core); +int fw_unload(struct msm_vidc_core *core); +int fw_suspend(struct msm_vidc_core *core); +int fw_resume(struct msm_vidc_core *core); +void fw_coredump(struct msm_vidc_core *core); + +#endif diff --git a/qcom/opensource/video-driver/driver/vidc/inc/fixedpoint.h b/qcom/opensource/video-driver/driver/vidc/inc/fixedpoint.h new file mode 100644 index 0000000000..1929fa6d05 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/fixedpoint.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifdef _FIXP_ARITH_H +#error "This implementation is meant to override fixp-arith.h, don't use both" +#endif + +#ifndef _FIXEDPOINT_H_ +#define _FIXEDPOINT_H_ + +#include +#include + +/* + * Normally would typedef'ed, but checkpatch doesn't like typedef. + * Also should be normally typedef'ed to intmax_t but that doesn't seem to be + * available in the kernel + */ +#define fp_t size_t + +/* (Arbitrarily) make the first 25% of the bits to be the fractional bits */ +#define FP_FRACTIONAL_BITS ((sizeof(fp_t) * 8) / 4) + +#define FP(__i, __f_n, __f_d) \ + ((((fp_t)(__i)) << FP_FRACTIONAL_BITS) + \ + (((__f_n) << FP_FRACTIONAL_BITS) / (__f_d))) + +#define FP_INT(__i) FP(__i, 0, 1) +#define FP_ONE FP_INT(1) +#define FP_ZERO FP_INT(0) + +static inline size_t fp_frac_base(void) +{ + return GENMASK(FP_FRACTIONAL_BITS - 1, 0); +} + +static inline size_t fp_frac(fp_t a) +{ + return a & GENMASK(FP_FRACTIONAL_BITS - 1, 0); +} + +static inline size_t fp_int(fp_t a) +{ + return a >> FP_FRACTIONAL_BITS; +} + +static inline size_t fp_round(fp_t a) +{ + /* is the fractional part >= frac_max / 2? */ + bool round_up = fp_frac(a) >= fp_frac_base() / 2; + + return fp_int(a) + round_up; +} + +static inline fp_t fp_mult(fp_t a, fp_t b) +{ + return (a * b) >> FP_FRACTIONAL_BITS; +} + +static inline fp_t fp_div(fp_t a, fp_t b) +{ + return (a << FP_FRACTIONAL_BITS) / b; +} + +#endif diff --git a/qcom/opensource/video-driver/driver/vidc/inc/hfi_command.h b/qcom/opensource/video-driver/driver/vidc/inc/hfi_command.h new file mode 100644 index 0000000000..2f7f984965 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/hfi_command.h @@ -0,0 +1,190 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __H_HFI_COMMAND_H__ +#define __H_HFI_COMMAND_H__ + +//todo: DP: remove below headers +#include +#include + +#define HFI_VIDEO_ARCH_LX 0x1 + +struct hfi_header { + u32 size; + u32 session_id; + u32 header_id; + u32 reserved[4]; + u32 num_packets; +}; + +struct hfi_packet { + u32 size; + u32 type; + u32 flags; + u32 payload_info; + u32 port; + u32 packet_id; + u32 reserved[2]; +}; + +struct hfi_buffer { + u32 type; + u32 index; + u64 base_address; + u32 addr_offset; + u32 buffer_size; + u32 data_offset; + u32 data_size; + u64 timestamp; + u32 flags; + u32 reserved[5]; +}; + +enum hfi_packet_host_flags { + HFI_HOST_FLAGS_NONE = 0x00000000, + HFI_HOST_FLAGS_INTR_REQUIRED = 0x00000001, + HFI_HOST_FLAGS_RESPONSE_REQUIRED = 0x00000002, + HFI_HOST_FLAGS_NON_DISCARDABLE = 0x00000004, + HFI_HOST_FLAGS_GET_PROPERTY = 0x00000008, +}; + +enum hfi_packet_firmware_flags { + HFI_FW_FLAGS_NONE = 0x00000000, + HFI_FW_FLAGS_SUCCESS = 0x00000001, + HFI_FW_FLAGS_INFORMATION = 0x00000002, + HFI_FW_FLAGS_SESSION_ERROR = 0x00000004, + HFI_FW_FLAGS_SYSTEM_ERROR = 0x00000008, +}; + +enum hfi_packet_payload_info { + HFI_PAYLOAD_NONE = 0x00000000, + HFI_PAYLOAD_U32 = 0x00000001, + HFI_PAYLOAD_S32 = 0x00000002, + HFI_PAYLOAD_U64 = 0x00000003, + HFI_PAYLOAD_S64 = 0x00000004, + HFI_PAYLOAD_STRUCTURE = 0x00000005, + HFI_PAYLOAD_BLOB = 0x00000006, + HFI_PAYLOAD_STRING = 0x00000007, + HFI_PAYLOAD_Q16 = 0x00000008, + HFI_PAYLOAD_U32_ENUM = 0x00000009, + HFI_PAYLOAD_32_PACKED = 0x0000000a, + HFI_PAYLOAD_U32_ARRAY = 0x0000000b, + HFI_PAYLOAD_S32_ARRAY = 0x0000000c, + HFI_PAYLOAD_64_PACKED = 0x0000000d, +}; + +enum hfi_packet_port_type { + HFI_PORT_NONE = 0x00000000, + HFI_PORT_BITSTREAM = 0x00000001, + HFI_PORT_RAW = 0x00000002, +}; + +enum hfi_buffer_type { + HFI_BUFFER_BITSTREAM = 0x00000001, + HFI_BUFFER_RAW = 0x00000002, + HFI_BUFFER_METADATA = 0x00000003, + HFI_BUFFER_SUBCACHE = 0x00000004, + HFI_BUFFER_PARTIAL_DATA = 0x00000005, + HFI_BUFFER_DPB = 0x00000006, + HFI_BUFFER_BIN = 0x00000007, + HFI_BUFFER_LINE = 0x00000008, + HFI_BUFFER_ARP = 0x00000009, + HFI_BUFFER_COMV = 0x0000000A, + HFI_BUFFER_NON_COMV = 0x0000000B, + HFI_BUFFER_PERSIST = 0x0000000C, + HFI_BUFFER_VPSS = 0x0000000D, +}; + +enum hfi_buffer_host_flags { + HFI_BUF_HOST_FLAG_NONE = 0x00000000, + HFI_BUF_HOST_FLAG_RELEASE = 0x00000001, + HFI_BUF_HOST_FLAG_READONLY = 0x00000010, + HFI_BUF_HOST_FLAG_CODEC_CONFIG = 0x00000100, + HFI_BUF_HOST_FLAGS_CB_NON_SECURE = 0x00000200, + HFI_BUF_HOST_FLAGS_CB_SECURE_PIXEL = 0x00000400, + HFI_BUF_HOST_FLAGS_CB_SECURE_BITSTREAM = 0x00000800, + HFI_BUF_HOST_FLAGS_CB_SECURE_NON_PIXEL = 0x00001000, + HFI_BUF_HOST_FLAGS_CB_NON_SECURE_PIXEL = 0x00002000, +}; + +enum hfi_buffer_firmware_flags { + HFI_BUF_FW_FLAG_NONE = 0x00000000, + HFI_BUF_FW_FLAG_RELEASE_DONE = 0x00000001, + HFI_BUF_FW_FLAG_READONLY = 0x00000010, + HFI_BUF_FW_FLAG_CODEC_CONFIG = 0x00000100, + HFI_BUF_FW_FLAG_LAST = 0x10000000, + HFI_BUF_FW_FLAG_PSC_LAST = 0x20000000, +}; + +enum hfi_metapayload_header_flags { + HFI_METADATA_FLAGS_NONE = 0x00000000, + HFI_METADATA_FLAGS_TOP_FIELD = 0x00000001, + HFI_METADATA_FLAGS_BOTTOM_FIELD = 0x00000002, +}; + +struct metabuf_header { + u32 count; + u32 size; + u32 version; + u32 reserved[5]; +}; + +struct metapayload_header { + u32 type; + u32 size; + u32 version; + u32 offset; + u32 flags; + u32 reserved[3]; +}; + +enum hfi_property_mode_type { + HFI_MODE_NONE = 0x00000000, + HFI_MODE_PORT_SETTINGS_CHANGE = 0x00000001, + HFI_MODE_PROPERTY = 0x00000002, + HFI_MODE_METADATA = 0x00000004, + HFI_MODE_DYNAMIC_METADATA = 0x00000005, +}; + +enum hfi_reserve_type { + HFI_RESERVE_START = 0x1, + HFI_RESERVE_STOP = 0x2, +}; + +#define HFI_CMD_BEGIN 0x01000000 +#define HFI_CMD_INIT 0x01000001 +#define HFI_CMD_POWER_COLLAPSE 0x01000002 +#define HFI_CMD_OPEN 0x01000003 +#define HFI_CMD_CLOSE 0x01000004 +#define HFI_CMD_START 0x01000005 +#define HFI_CMD_STOP 0x01000006 +#define HFI_CMD_DRAIN 0x01000007 +#define HFI_CMD_RESUME 0x01000008 +#define HFI_CMD_BUFFER 0x01000009 +#define HFI_CMD_DELIVERY_MODE 0x0100000A +#define HFI_CMD_SUBSCRIBE_MODE 0x0100000B +#define HFI_CMD_SETTINGS_CHANGE 0x0100000C + +#define HFI_SSR_TYPE_SW_ERR_FATAL 0x1 +#define HFI_SSR_TYPE_SW_DIV_BY_ZERO 0x2 +#define HFI_SSR_TYPE_CPU_WDOG_IRQ 0x3 +#define HFI_SSR_TYPE_NOC_ERROR 0x4 +#define HFI_BITMASK_HW_CLIENT_ID 0x000000f0 +#define HFI_BITMASK_SSR_TYPE 0x0000000f +#define HFI_CMD_SSR 0x0100000D + +#define HFI_STABILITY_TYPE_VCODEC_HUNG 0x1 +#define HFI_STABILITY_TYPE_ENC_BUFFER_FULL 0x2 +#define HFI_BITMASK_STABILITY_TYPE 0x0000000f +#define HFI_CMD_STABILITY 0x0100000E + +#define HFI_CMD_RESERVE 0x0100000F +#define HFI_CMD_FLUSH 0x01000010 +#define HFI_CMD_PAUSE 0x01000011 +#define HFI_CMD_END 0x01FFFFFF + +#endif //__H_HFI_COMMAND_H__ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/hfi_packet.h b/qcom/opensource/video-driver/driver/vidc/inc/hfi_packet.h new file mode 100644 index 0000000000..0a69c4bc7c --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/hfi_packet.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _HFI_PACKET_H_ +#define _HFI_PACKET_H_ + +#include "msm_vidc_internal.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" +#include "hfi_command.h" +#include "hfi_property.h" + +u32 get_hfi_port(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port); +u32 get_hfi_port_from_buffer_type(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +u32 hfi_buf_type_from_driver(enum msm_vidc_domain_type domain, + enum msm_vidc_buffer_type buffer_type); +u32 hfi_buf_type_to_driver(enum msm_vidc_domain_type domain, + enum hfi_buffer_type buffer_type, + enum hfi_packet_port_type port_type); +u32 get_hfi_codec(struct msm_vidc_inst *inst); +u32 get_hfi_colorformat(struct msm_vidc_inst *inst, + enum msm_vidc_colorformat_type colorformat); +int get_hfi_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer, + struct hfi_buffer *buf); +int hfi_create_header(u8 *packet, u32 packet_size, + u32 session_id, u32 header_id); +int hfi_create_packet(u8 *packet, u32 packet_size, + u32 pkt_type, u32 pkt_flags, + u32 payload_type, u32 port, + u32 packet_id, void *payload, + u32 payload_size); +int hfi_create_buffer(u8 *packet, u32 packet_size, u32 *offset, + enum msm_vidc_domain_type domain, + struct msm_vidc_buffer *data); +int hfi_packet_sys_init(struct msm_vidc_core *core, + u8 *pkt, u32 pkt_size); +int hfi_packet_image_version(struct msm_vidc_core *core, + u8 *pkt, u32 pkt_size); +int hfi_packet_sys_pc_prep(struct msm_vidc_core *core, + u8 *pkt, u32 pkt_size); +int hfi_packet_sys_debug_config(struct msm_vidc_core *core, + u8 *pkt, u32 pkt_size, + u32 debug_config); +int hfi_packet_session_command(struct msm_vidc_inst *inst, + u32 pkt_type, u32 flags, + u32 port, u32 session_id, + u32 payload_type, void *payload, + u32 payload_size); +int hfi_packet_sys_intraframe_powercollapse(struct msm_vidc_core *core, + u8 *pkt, u32 pkt_size, + u32 enable); + +#endif // _HFI_PACKET_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/hfi_property.h b/qcom/opensource/video-driver/driver/vidc/inc/hfi_property.h new file mode 100644 index 0000000000..3fb6601af9 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/hfi_property.h @@ -0,0 +1,666 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __H_HFI_PROPERTY_H__ +#define __H_HFI_PROPERTY_H__ + +//todo: DP: remove below header +#include + +#define HFI_PROP_BEGIN 0x03000000 +#define HFI_PROP_IMAGE_VERSION 0x03000001 +#define HFI_PROP_INTRA_FRAME_POWER_COLLAPSE 0x03000002 +#define HFI_PROP_UBWC_MAX_CHANNELS 0x03000003 +#define HFI_PROP_UBWC_MAL_LENGTH 0x03000004 +#define HFI_PROP_UBWC_HBB 0x03000005 +#define HFI_PROP_UBWC_BANK_SWZL_LEVEL1 0x03000006 +#define HFI_PROP_UBWC_BANK_SWZL_LEVEL2 0x03000007 +#define HFI_PROP_UBWC_BANK_SWZL_LEVEL3 0x03000008 +#define HFI_PROP_UBWC_BANK_SPREADING 0x03000009 + +enum hfi_debug_config { + HFI_DEBUG_CONFIG_DEFAULT = 0x00000000, + HFI_DEBUG_CONFIG_CLRDBGQ = 0x00000001, + HFI_DEBUG_CONFIG_WFI = 0x00000002, + HFI_DEBUG_CONFIG_ARM9WD = 0x00000004, +}; + +#define HFI_PROP_DEBUG_CONFIG 0x0300000a + +enum hfi_debug_log_level { + HFI_DEBUG_LOG_NONE = 0x00000000, + HFI_DEBUG_LOG_ERROR = 0x00000001, + HFI_DEBUG_LOG_FATAL = 0x00000002, + HFI_DEBUG_LOG_PERF = 0x00000004, + HFI_DEBUG_LOG_HIGH = 0x00000008, + HFI_DEBUG_LOG_MEDIUM = 0x00000010, + HFI_DEBUG_LOG_LOW = 0x00000020, +}; + +struct hfi_debug_header { + u32 size; + u32 debug_level; + u32 reserved[2]; +}; + +#define HFI_PROP_DEBUG_LOG_LEVEL 0x0300000b + +#define HFI_PROP_FENCE_CLIENT_DATA 0x0300000d + +enum hfi_codec_type { + HFI_CODEC_DECODE_AVC = 1, + HFI_CODEC_ENCODE_AVC = 2, + HFI_CODEC_DECODE_HEVC = 3, + HFI_CODEC_ENCODE_HEVC = 4, + HFI_CODEC_DECODE_VP9 = 5, + HFI_CODEC_DECODE_MPEG2 = 6, + HFI_CODEC_DECODE_AV1 = 7, +}; + +#define HFI_PROP_CODEC 0x03000100 + +enum hfi_color_format { + HFI_COLOR_FMT_OPAQUE = 0, + HFI_COLOR_FMT_NV12 = 1, + HFI_COLOR_FMT_NV12_UBWC = 2, + HFI_COLOR_FMT_P010 = 3, + HFI_COLOR_FMT_TP10_UBWC = 4, + HFI_COLOR_FMT_RGBA8888 = 5, + HFI_COLOR_FMT_RGBA8888_UBWC = 6, + HFI_COLOR_FMT_NV21 = 7, +}; + +#define HFI_PROP_COLOR_FORMAT 0x03000101 + +#define HFI_PROP_SECURE 0x03000102 + +#define HFI_BITMASK_BITSTREAM_WIDTH 0xffff0000 +#define HFI_BITMASK_BITSTREAM_HEIGHT 0x0000ffff +#define HFI_PROP_BITSTREAM_RESOLUTION 0x03000103 + +#define HFI_BITMASK_LINEAR_STRIDE 0xffff0000 +#define HFI_BITMASK_LINEAR_SCANLINE 0x0000ffff +#define HFI_PROP_LINEAR_STRIDE_SCANLINE 0x03000104 + +#define HFI_BITMASK_CROP_RIGHT_OFFSET 0xffff0000 +#define HFI_BITMASK_CROP_BOTTOM_OFFSET 0x0000ffff +#define HFI_BITMASK_CROP_LEFT_OFFSET 0xffff0000 +#define HFI_BITMASK_CROP_TOP_OFFSET 0x0000ffff +#define HFI_PROP_CROP_OFFSETS 0x03000105 + +#define HFI_PROP_SESSION_PRIORITY 0x03000106 + +enum hfi_avc_profile_type { + HFI_AVC_PROFILE_BASELINE = 0, + HFI_AVC_PROFILE_CONSTRAINED_BASELINE = 1, + HFI_AVC_PROFILE_MAIN = 2, + HFI_AVC_PROFILE_HIGH = 4, + HFI_AVC_PROFILE_CONSTRAINED_HIGH = 17 +}; + +enum hfi_hevc_profile_type { + HFI_H265_PROFILE_MAIN = 0, + HFI_H265_PROFILE_MAIN_STILL_PICTURE = 1, + HFI_H265_PROFILE_MAIN_10 = 2, + HFI_H265_PROFILE_MAIN_10_STILL_PICTURE = 3, +}; + +enum hfi_vp9_profile_type { + HFI_VP9_PROFILE_0 = 0, + HFI_VP9_PROFILE_1 = 1, + HFI_VP9_PROFILE_2 = 2, + HFI_VP9_PROFILE_3 = 3, +}; + +enum hfi_mpeg2_profile_type { + HFI_MP2_PROFILE_SIMPLE = 0, + HFI_MP2_PROFILE_MAIN = 1, +}; + +enum hfi_av1_profile_type { + HFI_AV1_PROFILE_MAIN = 0, + HFI_AV1_PROFILE_HIGH = 1, + HFI_AV1_PROFILE_PROF = 2, +}; + +#define HFI_PROP_PROFILE 0x03000107 + +enum hfi_avc_level_type { + HFI_AVC_LEVEL_1_0 = 0, + HFI_AVC_LEVEL_1B = 1, + HFI_AVC_LEVEL_1_1 = 2, + HFI_AVC_LEVEL_1_2 = 3, + HFI_AVC_LEVEL_1_3 = 4, + HFI_AVC_LEVEL_2_0 = 5, + HFI_AVC_LEVEL_2_1 = 6, + HFI_AVC_LEVEL_2_2 = 7, + HFI_AVC_LEVEL_3_0 = 8, + HFI_AVC_LEVEL_3_1 = 9, + HFI_AVC_LEVEL_3_2 = 10, + HFI_AVC_LEVEL_4_0 = 11, + HFI_AVC_LEVEL_4_1 = 12, + HFI_AVC_LEVEL_4_2 = 13, + HFI_AVC_LEVEL_5_0 = 14, + HFI_AVC_LEVEL_5_1 = 15, + HFI_AVC_LEVEL_5_2 = 16, + HFI_AVC_LEVEL_6_0 = 17, + HFI_AVC_LEVEL_6_1 = 18, + HFI_AVC_LEVEL_6_2 = 19, +}; + +enum hfi_hevc_level_type { + HFI_H265_LEVEL_1 = 0, + HFI_H265_LEVEL_2 = 1, + HFI_H265_LEVEL_2_1 = 2, + HFI_H265_LEVEL_3 = 3, + HFI_H265_LEVEL_3_1 = 4, + HFI_H265_LEVEL_4 = 5, + HFI_H265_LEVEL_4_1 = 6, + HFI_H265_LEVEL_5 = 7, + HFI_H265_LEVEL_5_1 = 8, + HFI_H265_LEVEL_5_2 = 9, + HFI_H265_LEVEL_6 = 10, + HFI_H265_LEVEL_6_1 = 11, + HFI_H265_LEVEL_6_2 = 12, +}; + +enum hfi_vp9_level_type { + HFI_VP9_LEVEL_1_0 = 0, + HFI_VP9_LEVEL_1_1 = 1, + HFI_VP9_LEVEL_2_0 = 2, + HFI_VP9_LEVEL_2_1 = 3, + HFI_VP9_LEVEL_3_0 = 4, + HFI_VP9_LEVEL_3_1 = 5, + HFI_VP9_LEVEL_4_0 = 6, + HFI_VP9_LEVEL_4_1 = 7, + HFI_VP9_LEVEL_5_0 = 8, + HFI_VP9_LEVEL_5_1 = 9, + HFI_VP9_LEVEL_6_0 = 10, + HFI_VP9_LEVEL_6_1 = 11, +}; + +enum hfi_mpeg2_level_type { + HFI_MP2_LEVEL_LOW = 0, + HFI_MP2_LEVEL_MAIN = 1, + HFI_MP2_LEVEL_HIGH_1440 = 2, + HFI_MP2_LEVEL_HIGH = 3, +}; + +enum hfi_av1_level_type { + HFI_AV1_LEVEL_2_0 = 0, + HFI_AV1_LEVEL_2_1 = 1, + HFI_AV1_LEVEL_2_2 = 2, + HFI_AV1_LEVEL_2_3 = 3, + HFI_AV1_LEVEL_3_0 = 4, + HFI_AV1_LEVEL_3_1 = 5, + HFI_AV1_LEVEL_3_2 = 6, + HFI_AV1_LEVEL_3_3 = 7, + HFI_AV1_LEVEL_4_0 = 8, + HFI_AV1_LEVEL_4_1 = 9, + HFI_AV1_LEVEL_4_2 = 10, + HFI_AV1_LEVEL_4_3 = 11, + HFI_AV1_LEVEL_5_0 = 12, + HFI_AV1_LEVEL_5_1 = 13, + HFI_AV1_LEVEL_5_2 = 14, + HFI_AV1_LEVEL_5_3 = 15, + HFI_AV1_LEVEL_6_0 = 16, + HFI_AV1_LEVEL_6_1 = 17, + HFI_AV1_LEVEL_6_2 = 18, + HFI_AV1_LEVEL_6_3 = 19, + HFI_AV1_LEVEL_7_0 = 20, + HFI_AV1_LEVEL_7_1 = 21, + HFI_AV1_LEVEL_7_2 = 22, + HFI_AV1_LEVEL_7_3 = 23, + HFI_AV1_LEVEL_MAX = 31, +}; + +enum hfi_codec_level_type { + HFI_LEVEL_NONE = 0xFFFFFFFF, +}; + +#define HFI_PROP_LEVEL 0x03000108 + +enum hfi_hevc_tier_type { + HFI_H265_TIER_MAIN = 0, + HFI_H265_TIER_HIGH = 1, +}; + +enum hfi_av1_tier_type { + HFI_AV1_TIER_MAIN = 0, + HFI_AV1_TIER_HIGH = 1, +}; + +#define HFI_PROP_TIER 0x03000109 + +#define HFI_PROP_STAGE 0x0300010a + +#define HFI_PROP_PIPE 0x0300010b + +#define HFI_PROP_FRAME_RATE 0x0300010c + +#define HFI_BITMASK_CONCEAL_LUMA 0x000003ff +#define HFI_BITMASK_CONCEAL_CB 0x000ffC00 +#define HFI_BITMASK_CONCEAL_CR 0x3ff00000 +#define HFI_PROP_CONCEAL_COLOR_8BIT 0x0300010d + +#define HFI_BITMASK_CONCEAL_LUMA 0x000003ff +#define HFI_BITMASK_CONCEAL_CB 0x000ffC00 +#define HFI_BITMASK_CONCEAL_CR 0x3ff00000 +#define HFI_PROP_CONCEAL_COLOR_10BIT 0x0300010e + +#define HFI_BITMASK_LUMA_BIT_DEPTH 0xffff0000 +#define HFI_BITMASK_CHROMA_BIT_DEPTH 0x0000ffff +#define HFI_PROP_LUMA_CHROMA_BIT_DEPTH 0x0300010f + +#define HFI_BITMASK_FRAME_MBS_ONLY_FLAG 0x00000001 +#define HFI_BITMASK_MB_ADAPTIVE_FRAME_FIELD_FLAG 0x00000002 +#define HFI_PROP_CODED_FRAMES 0x03000120 + +#define HFI_PROP_CABAC_SESSION 0x03000121 + +#define HFI_PROP_8X8_TRANSFORM 0x03000122 + +#define HFI_PROP_BUFFER_HOST_MAX_COUNT 0x03000123 + +#define HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT 0x03000124 + +#define HFI_PROP_BUFFER_MAXDPB_COUNT 0x03000125 + +#define HFI_PROP_BUFFER_MAX_NUM_REFERENCE 0x03000126 + +#define HFI_PROP_MAX_NUM_REORDER_FRAMES 0x03000127 + +#define HFI_PROP_PIC_ORDER_CNT_TYPE 0x03000128 + +enum hfi_deblock_mode { + HFI_DEBLOCK_ALL_BOUNDARY = 0x0, + HFI_DEBLOCK_DISABLE = 0x1, + HFI_DEBLOCK_DISABLE_AT_SLICE_BOUNDARY = 0x2, +}; + +#define HFI_PROP_DEBLOCKING_MODE 0x03000129 + +enum hfi_rate_control { + HFI_RC_VBR_CFR = 0x00000000, + HFI_RC_CBR_CFR = 0x00000001, + HFI_RC_CQ = 0x00000002, + HFI_RC_OFF = 0x00000003, + HFI_RC_CBR_VFR = 0x00000004, + HFI_RC_LOSSLESS = 0x00000005, +}; + +#define HFI_PROP_RATE_CONTROL 0x0300012a + +#define HFI_PROP_TIME_DELTA_BASED_RATE_CONTROL 0x0300012b + +#define HFI_PROP_CONTENT_ADAPTIVE_CODING 0x0300012c + +#define HFI_PROP_BITRATE_BOOST 0x0300012d + +#define HFI_BITMASK_QP_I 0x000000ff +#define HFI_BITMASK_QP_P 0x0000ff00 +#define HFI_BITMASK_QP_B 0x00ff0000 +#define HFI_BITMASK_QP_ENABLE 0x0f000000 +#define HFI_BITMASK_QP_LAYERS 0xf0000000 +#define HFI_PROP_QP_PACKED 0x0300012e + +#define HFI_PROP_MIN_QP_PACKED 0x0300012f + +#define HFI_PROP_MAX_QP_PACKED 0x03000130 + +#define HFI_PROP_IR_RANDOM_PERIOD 0x03000131 + +#define HFI_PROP_MULTI_SLICE_MB_COUNT 0x03000132 + +#define HFI_PROP_MULTI_SLICE_BYTES_COUNT 0x03000133 + +#define HFI_PROP_LTR_COUNT 0x03000134 + +#define HFI_PROP_LTR_MARK 0x03000135 + +#define HFI_PROP_LTR_USE 0x03000136 + +#define HFI_PROP_LTR_MARK_USE_DETAILS 0x03000137 + +enum hfi_layer_encoding_type { + HFI_HIER_P_SLIDING_WINDOW = 0x1, + HFI_HIER_P_HYBRID_LTR = 0x2, + HFI_HIER_B = 0x3, +}; + +#define HFI_PROP_LAYER_ENCODING_TYPE 0x03000138 + +#define HFI_PROP_LAYER_COUNT 0x03000139 + +enum hfi_chromaqp_offset_mode { + HFI_ADAPTIVE_CHROMAQP_OFFSET = 0x0, + HFI_FIXED_CHROMAQP_OFFSET = 0x1, +}; + +#define HFI_BITMASK_CHROMA_CB_OFFSET 0x0000ffff +#define HFI_BITMASK_CHROMA_CR_OFFSET 0xffff0000 +#define HFI_PROP_CHROMA_QP_OFFSET 0x0300013a + +#define HFI_PROP_TOTAL_BITRATE 0x0300013b + +#define HFI_PROP_BITRATE_LAYER1 0x0300013c + +#define HFI_PROP_BITRATE_LAYER2 0x0300013d + +#define HFI_PROP_BITRATE_LAYER3 0x0300013e + +#define HFI_PROP_BITRATE_LAYER4 0x0300013f + +#define HFI_PROP_BITRATE_LAYER5 0x03000140 + +#define HFI_PROP_BITRATE_LAYER6 0x03000141 + +#define HFI_PROP_BASELAYER_PRIORITYID 0x03000142 + +#define HFI_PROP_CONSTANT_QUALITY 0x03000143 + +#define HFI_PROP_HEIC_GRID_ENABLE 0x03000144 + +enum hfi_syncframe_request_mode { + HFI_SYNC_FRAME_REQUEST_WITHOUT_SEQ_HDR = 0x00000001, + HFI_SYNC_FRAME_REQUEST_WITH_PREFIX_SEQ_HDR = 0x00000002, +}; + +#define HFI_PROP_REQUEST_SYNC_FRAME 0x03000145 + +#define HFI_PROP_MAX_GOP_FRAMES 0x03000146 + +#define HFI_PROP_MAX_B_FRAMES 0x03000147 + +enum hfi_quality_mode { + HFI_MODE_MAX_QUALITY = 0x1, + HFI_MODE_POWER_SAVE = 0x2, +}; + +#define HFI_PROP_QUALITY_MODE 0x03000148 + +enum hfi_seq_header_mode { + HFI_SEQ_HEADER_SEPERATE_FRAME = 0x00000001, + HFI_SEQ_HEADER_JOINED_WITH_1ST_FRAME = 0x00000002, + HFI_SEQ_HEADER_PREFIX_WITH_SYNC_FRAME = 0x00000004, + HFI_SEQ_HEADER_METADATA = 0x00000008, +}; + +#define HFI_PROP_SEQ_HEADER_MODE 0x03000149 + +#define HFI_PROP_METADATA_SEQ_HEADER_NAL 0x0300014a + +enum hfi_rotation { + HFI_ROTATION_NONE = 0x00000000, + HFI_ROTATION_90 = 0x00000001, + HFI_ROTATION_180 = 0x00000002, + HFI_ROTATION_270 = 0x00000003, +}; + +#define HFI_PROP_ROTATION 0x0300014b + +enum hfi_flip { + HFI_DISABLE_FLIP = 0x00000000, + HFI_HORIZONTAL_FLIP = 0x00000001, + HFI_VERTICAL_FLIP = 0x00000002, +}; + +#define HFI_PROP_FLIP 0x0300014c + +#define HFI_PROP_SCALAR 0x0300014d + +enum hfi_blur_types { + HFI_BLUR_NONE = 0x00000000, + HFI_BLUR_EXTERNAL = 0x00000001, + HFI_BLUR_ADAPTIVE = 0x00000002, +}; + +#define HFI_PROP_BLUR_TYPES 0x0300014e + +#define HFI_BITMASK_BLUR_WIDTH 0xffff0000 +#define HFI_BITMASK_BLUR_HEIGHT 0x0000ffff +#define HFI_PROP_BLUR_RESOLUTION 0x0300014f + +#define HFI_BITMASK_SPS_ID 0x000000ff +#define HFI_BITMASK_PPS_ID 0x0000ff00 +#define HFI_BITMASK_VPS_ID 0x00ff0000 +#define HFI_PROP_SEQUENCE_HEADER_IDS 0x03000150 + +#define HFI_PROP_AUD 0x03000151 + +#define HFI_PROP_DPB_LUMA_CHROMA_MISR 0x03000153 + +#define HFI_PROP_OPB_LUMA_CHROMA_MISR 0x03000154 + +#define HFI_BITMASK_QP_I 0x000000ff +#define HFI_BITMASK_QP_P 0x0000ff00 +#define HFI_BITMASK_QP_B 0x00ff0000 +#define HFI_BITMASK_QP_ENABLE 0x0f000000 +#define HFI_BITMASK_QP_LAYERS 0xf0000000 +#define HFI_PROP_SIGNAL_COLOR_INFO 0x03000155 + +enum hfi_interlace_info { + HFI_INTERLACE_INFO_NONE = 0x00000000, + HFI_FRAME_PROGRESSIVE = 0x00000001, + HFI_FRAME_MBAFF = 0x00000002, + HFI_FRAME_INTERLEAVE_TOPFIELD_FIRST = 0x00000004, + HFI_FRAME_INTERLEAVE_BOTTOMFIELD_FIRST = 0x00000008, + HFI_FRAME_INTERLACE_TOPFIELD_FIRST = 0x00000010, + HFI_FRAME_INTERLACE_BOTTOMFIELD_FIRST = 0x00000020, +}; + +#define HFI_PROP_INTERLACE_INFO 0x03000156 + +#define HFI_PROP_CSC 0x03000157 + +#define HFI_PROP_CSC_MATRIX 0x03000158 + +#define HFI_PROP_CSC_BIAS 0x03000159 + +#define HFI_PROP_CSC_LIMIT 0x0300015a + +#define HFI_PROP_DECODE_ORDER_OUTPUT 0x0300015b + +#define HFI_PROP_TIMESTAMP 0x0300015c + +#define HFI_PROP_FRAMERATE_FROM_BITSTREAM 0x0300015d + +#define HFI_PROP_SEI_RECOVERY_POINT 0x0300015e + +#define HFI_PROP_CONEALED_MB_COUNT 0x0300015f + +#define HFI_BITMASK_SAR_WIDTH 0xffff0000 +#define HFI_BITMASK_SAR_HEIGHT 0x0000ffff +#define HFI_PROP_SAR_RESOLUTION 0x03000160 + +#define HFI_PROP_HISTOGRAM_INFO 0x03000161 + +enum hfi_picture_type { + HFI_PICTURE_IDR = 0x00000001, + HFI_PICTURE_P = 0x00000002, + HFI_PICTURE_B = 0x00000004, + HFI_PICTURE_I = 0x00000008, + HFI_PICTURE_CRA = 0x00000010, + HFI_PICTURE_BLA = 0x00000020, + HFI_PICTURE_NOSHOW = 0x00000040, +}; + +#define HFI_PROP_PICTURE_TYPE 0x03000162 + +#define HFI_PROP_SEI_MASTERING_DISPLAY_COLOUR 0x03000163 + +#define HFI_PROP_SEI_CONTENT_LIGHT_LEVEL 0x03000164 + +#define HFI_PROP_SEI_HDR10PLUS_USERDATA 0x03000165 + +#define HFI_PROP_SEI_STREAM_USERDATA 0x03000166 + +#define HFI_PROP_EVA_STAT_INFO 0x03000167 + +#define HFI_PROP_DEC_DEFAULT_HEADER 0x03000168 + +#define HFI_PROP_DEC_START_FROM_RAP_FRAME 0x03000169 + +#define HFI_PROP_NO_OUTPUT 0x0300016a + +#define HFI_PROP_BUFFER_TAG 0x0300016b + +#define HFI_PROP_BUFFER_MARK 0x0300016c + +#define HFI_PROP_SUBFRAME_OUTPUT 0x0300016d + +#define HFI_PROP_ENC_QP_METADATA 0x0300016e + +#define HFI_PROP_DEC_QP_METADATA 0x0300016f + +#define HFI_PROP_SEI_FRAME_PACKING_ARRANGEMENT 0x03000170 + +#define HFI_PROP_SEI_PAN_SCAN_RECT 0x03000171 + +#define HFI_PROP_THUMBNAIL_MODE 0x03000172 + +#define HFI_PROP_ROI_INFO 0x03000173 + +#define HFI_PROP_WORST_COMPRESSION_RATIO 0x03000174 + +#define HFI_PROP_WORST_COMPLEXITY_FACTOR 0x03000175 + +#define HFI_PROP_VBV_DELAY 0x03000176 + +#define HFI_PROP_SEQ_CHANGE_AT_SYNC_FRAME 0x03000177 + +#define HFI_BITMASK_RAW_WIDTH 0xffff0000 +#define HFI_BITMASK_RAW_HEIGHT 0x0000ffff +#define HFI_PROP_RAW_RESOLUTION 0x03000178 + +#define HFI_PROP_DPB_TAG_LIST 0x03000179 + +#define HFI_PROP_DPB_LIST 0x0300017A + +enum hfi_nal_length_field_type { + HFI_NAL_LENGTH_STARTCODES = 0, + HFI_NAL_LENGTH_SIZE_4 = 4, +}; + +#define HFI_PROP_NAL_LENGTH_FIELD 0x0300017B + +#define HFI_PROP_TOTAL_PEAK_BITRATE 0x0300017C + +#define HFI_PROP_MAINTAIN_MIN_QUALITY 0x0300017D + +#define HFI_PROP_IR_CYCLIC_PERIOD 0x0300017E + +#define HFI_PROP_ENABLE_SLICE_DELIVERY 0x0300017F + +#define HFI_PROP_AV1_FILM_GRAIN_PRESENT 0x03000180 + +#define HFI_PROP_AV1_SUPER_BLOCK_ENABLED 0x03000181 + +#define HFI_PROP_AV1_OP_POINT 0x03000182 + +#define HFI_PROP_SUBFRAME_INPUT 0x03000183 + +#define HFI_PROP_OPB_ENABLE 0x03000184 + +#define HFI_PROP_AV1_TILE_ROWS_COLUMNS 0x03000187 + +#define HFI_PROP_AV1_DRAP_CONFIG 0x03000189 + +enum hfi_saliency_type { + HFI_SALIENCY_NONE, + HFI_SALIENCY_TYPE0, +}; + +#define HFI_PROP_ROI_AS_SALIENCY_INFO 0x0300018A + +#define HFI_PROP_FENCE 0x0300018B + +#define HFI_PROP_REQUEST_PREPROCESS 0x0300018E + +#define HFI_PROP_UBWC_STRIDE_SCANLINE 0x03000190 + +#define HFI_PROP_TRANSCODING_STAT_INFO 0x03000191 + +#define HFI_PROP_DOLBY_RPU_METADATA 0x03000192 + +#define HFI_PROP_COMV_BUFFER_COUNT 0x03000193 + +#define HFI_PROP_DISABLE_VUI_TIMING_INFO 0x03000194 + +#define HFI_PROP_SLICE_DECODE 0x03000196 + +#define HFI_PROP_AV1_UNIFORM_TILE_SPACING 0x03000197 + +#define HFI_PROP_ENC_RING_BIN_BUF 0x0300019C + +/* u32 */ +enum hfi_fence_type { + HFI_SW_FENCE = 0x00000001, + HFI_SYNX_V2_FENCE = 0x00000002, +}; + +#define HFI_PROP_FENCE_TYPE 0x0300019D + +enum hfi_fence_direction_type { + HFI_FENCE_TX_ENABLE = 0x00000001, + HFI_FENCE_RX_ENABLE = 0x00000002, +}; + +#define HFI_PROP_FENCE_DIRECTION 0x0300019E + +#define HFI_PROP_FENCE_ERROR_DATA_CORRUPT 0x0300019F + +#define HFI_PROP_END 0x03FFFFFF + +#define HFI_SESSION_ERROR_BEGIN 0x04000000 + +#define HFI_ERROR_UNKNOWN_SESSION 0x04000001 + +#define HFI_ERROR_MAX_SESSIONS 0x04000002 + +#define HFI_ERROR_FATAL 0x04000003 + +#define HFI_ERROR_INVALID_STATE 0x04000004 + +#define HFI_ERROR_INSUFFICIENT_RESOURCES 0x04000005 + +#define HFI_ERROR_BUFFER_NOT_SET 0x04000006 + +#define HFI_ERROR_DRAP_CONFIG_EXCEED 0x04000007 + +#define HFI_SESSION_ERROR_END 0x04FFFFFF + +#define HFI_SYSTEM_ERROR_BEGIN 0x05000000 + +#define HFI_SYS_ERROR_WD_TIMEOUT 0x05000001 + +#define HFI_SYS_ERROR_NOC 0x05000002 + +#define HFI_SYS_ERROR_FATAL 0x05000003 + +#define HFI_SYSTEM_ERROR_END 0x05FFFFFF + +#define HFI_INFORMATION_BEGIN 0x06000000 + +#define HFI_INFO_UNSUPPORTED 0x06000001 + +#define HFI_INFO_DATA_CORRUPT 0x06000002 + +#define HFI_INFO_NEGATIVE_TIMESTAMP 0x06000003 + +#define HFI_INFO_BUFFER_OVERFLOW 0x06000004 + +#define HFI_INFO_VCODEC_RESET 0x06000005 + +#define HFI_INFO_HFI_FLAG_DRAIN_LAST 0x06000006 + +#define HFI_INFO_HFI_FLAG_PSC_LAST 0x06000007 + +#define HFI_INFO_FENCE_SIGNAL_ERROR 0x06000008 + +#define HFI_INFORMATION_END 0x06FFFFFF + +#endif //__H_HFI_PROPERTY_H__ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_media_info.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_media_info.h new file mode 100644 index 0000000000..95cb05fd1b --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_media_info.h @@ -0,0 +1,612 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __MSM_MEDIA_INFO_H__ +#define __MSM_MEDIA_INFO_H__ + +#include "msm_vidc_internal.h" + +/* Width and Height should be multiple of 16 */ +#define INTERLACE_WIDTH_MAX 1920 +#define INTERLACE_HEIGHT_MAX 1920 +#define INTERLACE_MB_PER_FRAME_MAX ((1920 * 1088) / 256) + +#ifndef MSM_MEDIA_ALIGN +#define MSM_MEDIA_ALIGN(__sz, __align) (((__align) & ((__align) - 1)) ?\ + ((((__sz) + (__align) - 1) / (__align)) * (__align)) :\ + (((__sz) + (__align) - 1) & (~((__align) - 1)))) +#endif + +#ifndef MSM_MEDIA_ROUNDUP +#define MSM_MEDIA_ROUNDUP(__sz, __r) (((__sz) + ((__r) - 1)) / (__r)) +#endif + +/* + * Function arguments: + * @v4l2_fmt + * @width + * Progressive: width + * Interlaced: width + */ +static inline unsigned int video_y_stride_bytes(unsigned int colorformat, + unsigned int width) +{ + unsigned int alignment, stride = 0; + + if (!width) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_NV12: + case MSM_VIDC_FMT_NV21: + case MSM_VIDC_FMT_NV12C: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width, alignment); + break; + case MSM_VIDC_FMT_TP10C: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width, 192); + stride = MSM_MEDIA_ALIGN(stride * 4 / 3, alignment); + break; + case MSM_VIDC_FMT_P010: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width * 2, alignment); + break; + default: + break; + } +invalid_input: + return stride; +} + +/* + * Function arguments: + * @v4l2_fmt + * @width + * Progressive: width + * Interlaced: width + */ +static inline unsigned int video_y_stride_pix(unsigned int colorformat, + unsigned int width) +{ + unsigned int alignment, stride = 0; + + if (!width) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_NV12: + case MSM_VIDC_FMT_NV21: + case MSM_VIDC_FMT_NV12C: + case MSM_VIDC_FMT_P010: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width, alignment); + break; + case MSM_VIDC_FMT_TP10C: + alignment = 192; + stride = MSM_MEDIA_ALIGN(width, alignment); + break; + default: + break; + } + +invalid_input: + return stride; +} + +/* + * Function arguments: + * @v4l2_fmt + * @width + * Progressive: width + * Interlaced: width + */ +static inline unsigned int video_uv_stride_bytes(unsigned int colorformat, + unsigned int width) +{ + unsigned int alignment, stride = 0; + + if (!width) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_NV21: + case MSM_VIDC_FMT_NV12: + case MSM_VIDC_FMT_NV12C: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width, alignment); + break; + case MSM_VIDC_FMT_TP10C: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width, 192); + stride = MSM_MEDIA_ALIGN(stride * 4 / 3, alignment); + break; + case MSM_VIDC_FMT_P010: + alignment = 256; + stride = MSM_MEDIA_ALIGN(width * 2, alignment); + break; + default: + break; + } +invalid_input: + return stride; +} + +/* + * Function arguments: + * @v4l2_fmt + * @width + * Progressive: width + * Interlaced: width + */ +static inline unsigned int video_uv_stride_pix(unsigned int colorformat, + unsigned int width) +{ + unsigned int alignment, stride = 0; + + if (!width) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_NV21: + case MSM_VIDC_FMT_NV12: + case MSM_VIDC_FMT_NV12C: + case MSM_VIDC_FMT_P010: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width, alignment); + break; + case MSM_VIDC_FMT_TP10C: + alignment = 192; + stride = MSM_MEDIA_ALIGN(width, alignment); + break; + default: + break; + } +invalid_input: + return stride; +} + +/* + * Function arguments: + * @v4l2_fmt + * @height + * Progressive: height + * Interlaced: (height+1)>>1 + */ +static inline unsigned int video_y_scanlines(unsigned int colorformat, + unsigned int height) +{ + unsigned int alignment, sclines = 0; + + if (!height) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_NV12: + case MSM_VIDC_FMT_NV21: + case MSM_VIDC_FMT_NV12C: + case MSM_VIDC_FMT_P010: + alignment = 32; + break; + case MSM_VIDC_FMT_TP10C: + alignment = 16; + break; + default: + return 0; + } + sclines = MSM_MEDIA_ALIGN(height, alignment); +invalid_input: + return sclines; +} + +/* + * Function arguments: + * @v4l2_fmt + * @height + * Progressive: height + * Interlaced: (height+1)>>1 + */ +static inline unsigned int video_uv_scanlines(unsigned int colorformat, + unsigned int height) +{ + unsigned int alignment, sclines = 0; + + if (!height) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_NV21: + case MSM_VIDC_FMT_NV12: + case MSM_VIDC_FMT_TP10C: + case MSM_VIDC_FMT_P010: + alignment = 16; + break; + case MSM_VIDC_FMT_NV12C: + alignment = 32; + break; + default: + goto invalid_input; + } + + sclines = MSM_MEDIA_ALIGN((height + 1) >> 1, alignment); + +invalid_input: + return sclines; +} + +/* + * Function arguments: + * @v4l2_fmt + * @width + * Progressive: width + * Interlaced: width + */ +static inline unsigned int video_y_meta_stride(unsigned int colorformat, + unsigned int width) +{ + int y_tile_width = 0, y_meta_stride = 0; + + if (!width) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_NV12C: + y_tile_width = 32; + break; + case MSM_VIDC_FMT_TP10C: + y_tile_width = 48; + break; + default: + goto invalid_input; + } + + y_meta_stride = MSM_MEDIA_ROUNDUP(width, y_tile_width); + y_meta_stride = MSM_MEDIA_ALIGN(y_meta_stride, 64); + +invalid_input: + return y_meta_stride; +} + +/* + * Function arguments: + * @v4l2_fmt + * @height + * Progressive: height + * Interlaced: (height+1)>>1 + */ +static inline unsigned int video_y_meta_scanlines(unsigned int colorformat, + unsigned int height) +{ + int y_tile_height = 0, y_meta_scanlines = 0; + + if (!height) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_NV12C: + y_tile_height = 8; + break; + case MSM_VIDC_FMT_TP10C: + y_tile_height = 4; + break; + default: + goto invalid_input; + } + + y_meta_scanlines = MSM_MEDIA_ROUNDUP(height, y_tile_height); + y_meta_scanlines = MSM_MEDIA_ALIGN(y_meta_scanlines, 16); + +invalid_input: + return y_meta_scanlines; +} + +/* + * Function arguments: + * @v4l2_fmt + * @width + * Progressive: width + * Interlaced: width + */ +static inline unsigned int video_uv_meta_stride(unsigned int colorformat, + unsigned int width) +{ + int uv_tile_width = 0, uv_meta_stride = 0; + + if (!width) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_NV12C: + uv_tile_width = 16; + break; + case MSM_VIDC_FMT_TP10C: + uv_tile_width = 24; + break; + default: + goto invalid_input; + } + + uv_meta_stride = MSM_MEDIA_ROUNDUP((width + 1) >> 1, uv_tile_width); + uv_meta_stride = MSM_MEDIA_ALIGN(uv_meta_stride, 64); + +invalid_input: + return uv_meta_stride; +} + +/* + * Function arguments: + * @v4l2_fmt + * @height + * Progressive: height + * Interlaced: (height+1)>>1 + */ +static inline unsigned int video_uv_meta_scanlines(unsigned int colorformat, + unsigned int height) +{ + int uv_tile_height = 0, uv_meta_scanlines = 0; + + if (!height) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_NV12C: + uv_tile_height = 8; + break; + case MSM_VIDC_FMT_TP10C: + uv_tile_height = 4; + break; + default: + goto invalid_input; + } + + uv_meta_scanlines = MSM_MEDIA_ROUNDUP((height + 1) >> 1, uv_tile_height); + uv_meta_scanlines = MSM_MEDIA_ALIGN(uv_meta_scanlines, 16); + +invalid_input: + return uv_meta_scanlines; +} + +static inline unsigned int video_rgb_stride_bytes(unsigned int colorformat, + unsigned int width) +{ + unsigned int alignment = 0, stride = 0, bpp = 4; + + if (!width) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_RGBA8888C: + case MSM_VIDC_FMT_RGBA8888: + alignment = 256; + break; + default: + goto invalid_input; + } + + stride = MSM_MEDIA_ALIGN(width * bpp, alignment); + +invalid_input: + return stride; +} + +static inline unsigned int video_rgb_stride_pix(unsigned int colorformat, + unsigned int width) +{ + unsigned int bpp = 4; + + return video_rgb_stride_bytes(colorformat, width) / bpp; +} + +static inline unsigned int video_rgb_scanlines(unsigned int colorformat, + unsigned int height) +{ + unsigned int alignment = 0, scanlines = 0; + + if (!height) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_RGBA8888C: + alignment = 16; + break; + case MSM_VIDC_FMT_RGBA8888: + alignment = 32; + break; + default: + goto invalid_input; + } + + scanlines = MSM_MEDIA_ALIGN(height, alignment); + +invalid_input: + return scanlines; +} + +static inline unsigned int video_rgb_meta_stride(unsigned int colorformat, + unsigned int width) +{ + int rgb_tile_width = 0, rgb_meta_stride = 0; + + if (!width) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_RGBA8888C: + case MSM_VIDC_FMT_RGBA8888: + rgb_tile_width = 16; + break; + default: + goto invalid_input; + } + + rgb_meta_stride = MSM_MEDIA_ROUNDUP(width, rgb_tile_width); + rgb_meta_stride = MSM_MEDIA_ALIGN(rgb_meta_stride, 64); + +invalid_input: + return rgb_meta_stride; +} + +static inline unsigned int video_rgb_meta_scanlines(unsigned int colorformat, + unsigned int height) +{ + int rgb_tile_height = 0, rgb_meta_scanlines = 0; + + if (!height) + goto invalid_input; + + switch (colorformat) { + case MSM_VIDC_FMT_RGBA8888C: + case MSM_VIDC_FMT_RGBA8888: + rgb_tile_height = 4; + break; + default: + goto invalid_input; + } + + rgb_meta_scanlines = MSM_MEDIA_ROUNDUP(height, rgb_tile_height); + rgb_meta_scanlines = MSM_MEDIA_ALIGN(rgb_meta_scanlines, 16); + +invalid_input: + return rgb_meta_scanlines; +} + +static inline unsigned int video_buffer_size(unsigned int colorformat, + unsigned int pix_width, + unsigned int pix_height, + unsigned int interlace) +{ + unsigned int size = 0; + unsigned int y_plane, uv_plane, y_stride, + uv_stride, y_sclines, uv_sclines; + unsigned int y_ubwc_plane = 0, uv_ubwc_plane = 0; + unsigned int y_meta_stride = 0, y_meta_scanlines = 0; + unsigned int uv_meta_stride = 0, uv_meta_scanlines = 0; + unsigned int y_meta_plane = 0, uv_meta_plane = 0; + unsigned int rgb_stride = 0, rgb_scanlines = 0; + unsigned int rgb_plane = 0, rgb_ubwc_plane = 0, rgb_meta_plane = 0; + unsigned int rgb_meta_stride = 0, rgb_meta_scanlines = 0; + + if (!pix_width || !pix_height) + goto invalid_input; + + y_stride = video_y_stride_bytes(colorformat, pix_width); + uv_stride = video_uv_stride_bytes(colorformat, pix_width); + y_sclines = video_y_scanlines(colorformat, pix_height); + uv_sclines = video_uv_scanlines(colorformat, pix_height); + rgb_stride = video_rgb_stride_bytes(colorformat, pix_width); + rgb_scanlines = video_rgb_scanlines(colorformat, pix_height); + + switch (colorformat) { + case MSM_VIDC_FMT_NV21: + case MSM_VIDC_FMT_NV12: + case MSM_VIDC_FMT_P010: + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines; + size = y_plane + uv_plane; + break; + case MSM_VIDC_FMT_NV12C: + y_meta_stride = video_y_meta_stride(colorformat, pix_width); + uv_meta_stride = video_uv_meta_stride(colorformat, pix_width); + if (!interlace && colorformat == MSM_VIDC_FMT_NV12C) { + y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); + uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); + y_meta_scanlines = + video_y_meta_scanlines(colorformat, pix_height); + y_meta_plane = MSM_MEDIA_ALIGN(y_meta_stride * + y_meta_scanlines, 4096); + uv_meta_scanlines = + video_uv_meta_scanlines(colorformat, pix_height); + uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride * + uv_meta_scanlines, + 4096); + size = (y_ubwc_plane + uv_ubwc_plane + y_meta_plane + + uv_meta_plane); + } else { + if (pix_width <= INTERLACE_WIDTH_MAX && + pix_height <= INTERLACE_HEIGHT_MAX && + (pix_height * pix_width) / 256 <= INTERLACE_MB_PER_FRAME_MAX) { + y_sclines = + video_y_scanlines(colorformat, (pix_height + 1) >> 1); + y_ubwc_plane = + MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); + uv_sclines = + video_uv_scanlines(colorformat, (pix_height + 1) >> 1); + uv_ubwc_plane = + MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); + y_meta_scanlines = + video_y_meta_scanlines(colorformat, (pix_height + 1) >> 1); + y_meta_plane = MSM_MEDIA_ALIGN(y_meta_stride * + y_meta_scanlines, + 4096); + uv_meta_scanlines = + video_uv_meta_scanlines(colorformat, (pix_height + 1) >> 1); + uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride * + uv_meta_scanlines, + 4096); + size = (y_ubwc_plane + uv_ubwc_plane + y_meta_plane + + uv_meta_plane)*2; + } else { + y_sclines = video_y_scanlines(colorformat, pix_height); + y_ubwc_plane = + MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); + uv_sclines = video_uv_scanlines(colorformat, pix_height); + uv_ubwc_plane = + MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); + y_meta_scanlines = + video_y_meta_scanlines(colorformat, pix_height); + y_meta_plane = MSM_MEDIA_ALIGN(y_meta_stride * + y_meta_scanlines, + 4096); + uv_meta_scanlines = + video_uv_meta_scanlines(colorformat, pix_height); + uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride * + uv_meta_scanlines, + 4096); + size = (y_ubwc_plane + uv_ubwc_plane + y_meta_plane + + uv_meta_plane); + } + } + break; + case MSM_VIDC_FMT_TP10C: + y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); + uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); + y_meta_stride = video_y_meta_stride(colorformat, pix_width); + y_meta_scanlines = video_y_meta_scanlines(colorformat, pix_height); + y_meta_plane = MSM_MEDIA_ALIGN(y_meta_stride * + y_meta_scanlines, 4096); + uv_meta_stride = video_uv_meta_stride(colorformat, pix_width); + uv_meta_scanlines = video_uv_meta_scanlines(colorformat, pix_height); + uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride * + uv_meta_scanlines, + 4096); + + size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + + uv_meta_plane; + break; + case MSM_VIDC_FMT_RGBA8888C: + rgb_ubwc_plane = MSM_MEDIA_ALIGN(rgb_stride * rgb_scanlines, + 4096); + rgb_meta_stride = video_rgb_meta_stride(colorformat, pix_width); + rgb_meta_scanlines = video_rgb_meta_scanlines(colorformat, + pix_height); + rgb_meta_plane = MSM_MEDIA_ALIGN(rgb_meta_stride * + rgb_meta_scanlines, 4096); + size = rgb_ubwc_plane + rgb_meta_plane; + break; + case MSM_VIDC_FMT_RGBA8888: + rgb_plane = MSM_MEDIA_ALIGN(rgb_stride * rgb_scanlines, 4096); + size = rgb_plane; + break; + default: + break; + } + +invalid_input: + size = MSM_MEDIA_ALIGN(size, 4096); + return size; +} + +#endif diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vdec.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vdec.h new file mode 100644 index 0000000000..107d9d574f --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vdec.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VDEC_H_ +#define _MSM_VDEC_H_ + +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" + +int msm_vdec_streamoff_input(struct msm_vidc_inst *inst); +int msm_vdec_streamon_input(struct msm_vidc_inst *inst); +int msm_vdec_streamoff_output(struct msm_vidc_inst *inst); +int msm_vdec_streamon_output(struct msm_vidc_inst *inst); +int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2); +int msm_vdec_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f); +int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f); +int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f); +int msm_vdec_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s); +int msm_vdec_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s); +int msm_vdec_subscribe_event(struct msm_vidc_inst *inst, + const struct v4l2_event_subscription *sub); +int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f); +int msm_vdec_inst_init(struct msm_vidc_inst *inst); +int msm_vdec_inst_deinit(struct msm_vidc_inst *inst); +int msm_vdec_init_input_subcr_params(struct msm_vidc_inst *inst); +int msm_vdec_input_port_settings_change(struct msm_vidc_inst *inst); +int msm_vdec_output_port_settings_change(struct msm_vidc_inst *inst); +int msm_vdec_stop_cmd(struct msm_vidc_inst *inst); +int msm_vdec_start_cmd(struct msm_vidc_inst *inst); +int msm_vdec_handle_release_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf); +int msm_vdec_set_num_comv(struct msm_vidc_inst *inst); +int msm_vdec_subscribe_metadata(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port); +int msm_vdec_get_input_internal_buffers(struct msm_vidc_inst *inst); +int msm_vdec_create_input_internal_buffers(struct msm_vidc_inst *inst); +int msm_vdec_queue_input_internal_buffers(struct msm_vidc_inst *inst); +int msm_vdec_release_input_internal_buffers(struct msm_vidc_inst *inst); + +#endif // _MSM_VDEC_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_venc.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_venc.h new file mode 100644 index 0000000000..397834a06c --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_venc.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VENC_H_ +#define _MSM_VENC_H_ + +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" + +int msm_venc_streamoff_input(struct msm_vidc_inst *inst); +int msm_venc_streamon_input(struct msm_vidc_inst *inst); +int msm_venc_streamoff_output(struct msm_vidc_inst *inst); +int msm_venc_streamon_output(struct msm_vidc_inst *inst); +int msm_venc_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2); +int msm_venc_stop_cmd(struct msm_vidc_inst *inst); +int msm_venc_start_cmd(struct msm_vidc_inst *inst); +int msm_venc_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f); +int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f); +int msm_venc_s_fmt_output(struct msm_vidc_inst *inst, struct v4l2_format *f); +int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f); +int msm_venc_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s); +int msm_venc_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s); +int msm_venc_s_param(struct msm_vidc_inst *inst, + struct v4l2_streamparm *s_parm); +int msm_venc_g_param(struct msm_vidc_inst *inst, + struct v4l2_streamparm *s_parm); +int msm_venc_subscribe_event(struct msm_vidc_inst *inst, + const struct v4l2_event_subscription *sub); +int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f); +int msm_venc_inst_init(struct msm_vidc_inst *inst); +int msm_venc_inst_deinit(struct msm_vidc_inst *inst); + +#endif // _MSM_VENC_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc.h new file mode 100644 index 0000000000..c89b04e243 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_H_ +#define _MSM_VIDC_H_ + +#include +#include + +union msm_v4l2_cmd { + struct v4l2_decoder_cmd dec; + struct v4l2_encoder_cmd enc; +}; + +void *msm_vidc_open(struct msm_vidc_core *core, u32 session_type); +int msm_vidc_close(struct msm_vidc_inst *inst); +int msm_vidc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap); +int msm_vidc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f); +int msm_vidc_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f); +int msm_vidc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f); +int msm_vidc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f); +int msm_vidc_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s); +int msm_vidc_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s); +int msm_vidc_s_param(struct msm_vidc_inst *inst, struct v4l2_streamparm *sp); +int msm_vidc_g_param(struct msm_vidc_inst *inst, struct v4l2_streamparm *sp); +int msm_vidc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b); +int msm_vidc_querybuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b); +int msm_vidc_create_bufs(struct msm_vidc_inst *inst, struct v4l2_create_buffers *b); +int msm_vidc_prepare_buf(struct msm_vidc_inst *inst, struct media_device *mdev, + struct v4l2_buffer *b); +int msm_vidc_release_buffer(struct msm_vidc_inst *inst, int buffer_type, + unsigned int buffer_index); +int msm_vidc_qbuf(struct msm_vidc_inst *inst, struct media_device *mdev, + struct v4l2_buffer *b); +int msm_vidc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b); +int msm_vidc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type i); +int msm_vidc_query_ctrl(struct msm_vidc_inst *inst, struct v4l2_queryctrl *ctrl); +int msm_vidc_query_menu(struct msm_vidc_inst *inst, struct v4l2_querymenu *qmenu); +int msm_vidc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type i); +int msm_vidc_try_cmd(struct msm_vidc_inst *inst, union msm_v4l2_cmd *cmd); +int msm_vidc_start_cmd(struct msm_vidc_inst *inst); +int msm_vidc_stop_cmd(struct msm_vidc_inst *inst); +int msm_vidc_poll(struct msm_vidc_inst *inst, struct file *filp, + struct poll_table_struct *pt); +int msm_vidc_subscribe_event(struct msm_vidc_inst *inst, + const struct v4l2_event_subscription *sub); +int msm_vidc_unsubscribe_event(struct msm_vidc_inst *inst, + const struct v4l2_event_subscription *sub); +int msm_vidc_dqevent(struct msm_vidc_inst *inst, struct v4l2_event *event); +int msm_vidc_g_crop(struct msm_vidc_inst *inst, struct v4l2_crop *a); +int msm_vidc_enum_framesizes(struct msm_vidc_inst *inst, struct v4l2_frmsizeenum *fsize); +int msm_vidc_enum_frameintervals(struct msm_vidc_inst *inst, struct v4l2_frmivalenum *fival); + +#endif diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_buffer.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_buffer.h new file mode 100644 index 0000000000..7e24547db6 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_buffer.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __H_MSM_VIDC_BUFFER_H__ +#define __H_MSM_VIDC_BUFFER_H__ + +#include "msm_vidc_inst.h" + +#define MIN_DEC_INPUT_BUFFERS 4 +#define MIN_DEC_OUTPUT_BUFFERS 4 + +#define MIN_ENC_INPUT_BUFFERS 4 +#define MIN_ENC_OUTPUT_BUFFERS 4 + +#define DCVS_ENC_EXTRA_INPUT_BUFFERS 4 +#define DCVS_DEC_EXTRA_OUTPUT_BUFFERS 4 + +u32 msm_vidc_input_min_count(struct msm_vidc_inst *inst); +u32 msm_vidc_output_min_count(struct msm_vidc_inst *inst); +u32 msm_vidc_input_extra_count(struct msm_vidc_inst *inst); +u32 msm_vidc_output_extra_count(struct msm_vidc_inst *inst); +u32 msm_vidc_internal_buffer_count(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +u32 msm_vidc_decoder_input_size(struct msm_vidc_inst *inst); +u32 msm_vidc_decoder_output_size(struct msm_vidc_inst *inst); +u32 msm_vidc_decoder_input_meta_size(struct msm_vidc_inst *inst); +u32 msm_vidc_decoder_output_meta_size(struct msm_vidc_inst *inst); +u32 msm_vidc_encoder_input_size(struct msm_vidc_inst *inst); +u32 msm_vidc_encoder_output_size(struct msm_vidc_inst *inst); +u32 msm_vidc_encoder_input_meta_size(struct msm_vidc_inst *inst); +u32 msm_vidc_encoder_output_meta_size(struct msm_vidc_inst *inst); +u32 msm_vidc_enc_delivery_mode_based_output_buf_size(struct msm_vidc_inst *inst, + u32 frame_size); + +#endif // __H_MSM_VIDC_BUFFER_H__ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_control.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_control.h new file mode 100644 index 0000000000..8f46a920a1 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_control.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_CONTROL_H_ +#define _MSM_VIDC_CONTROL_H_ + +#include "msm_vidc_internal.h" +#include "msm_vidc_inst.h" + +int msm_vidc_ctrl_handler_init(struct msm_vidc_inst *inst, bool init); +int msm_vidc_ctrl_handler_deinit(struct msm_vidc_inst *inst); +int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl); +int msm_v4l2_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl); +int msm_vidc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl); +int msm_vidc_prepare_dependency_list(struct msm_vidc_inst *inst); +int msm_vidc_adjust_v4l2_properties(struct msm_vidc_inst *inst); +int msm_vidc_set_v4l2_properties(struct msm_vidc_inst *inst); +bool is_valid_cap_id(enum msm_vidc_inst_capability_type cap_id); +bool is_valid_cap(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id); +enum msm_vidc_inst_capability_type + msm_vidc_get_cap_id(struct msm_vidc_inst *inst, u32 id); +#endif diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_core.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_core.h new file mode 100644 index 0000000000..d5345c7e2f --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_core.h @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_CORE_H_ +#define _MSM_VIDC_CORE_H_ + +#include + +#include "msm_vidc_internal.h" +#include "msm_vidc_state.h" +#include "venus_hfi_queue.h" +#include "resources.h" + +struct msm_vidc_core; + +#define MAX_EVENTS 30 + +#define call_venus_op(d, op, ...) \ + (((d) && (d)->venus_ops && (d)->venus_ops->op) ? \ + ((d)->venus_ops->op(__VA_ARGS__)) : 0) + +struct msm_vidc_venus_ops { + int (*boot_firmware)(struct msm_vidc_core *core); + int (*raise_interrupt)(struct msm_vidc_core *core); + int (*clear_interrupt)(struct msm_vidc_core *core); + int (*prepare_pc)(struct msm_vidc_core *core); + int (*power_on)(struct msm_vidc_core *core); + int (*power_off)(struct msm_vidc_core *core); + int (*watchdog)(struct msm_vidc_core *core, u32 intr_status); + int (*noc_error_info)(struct msm_vidc_core *core); +}; + +struct msm_vidc_synx_fence_data { + u32 client_id; + void *session; + u32 client_flags; /* not used */ + struct msm_vidc_mem queue; +}; + +struct msm_vidc_mem_addr { + u32 align_device_addr; + u8 *align_virtual_addr; + u32 mem_size; + struct msm_vidc_mem mem; +}; + +struct msm_vidc_iface_q_info { + void *q_hdr; + struct msm_vidc_mem_addr q_array; +}; + +struct msm_video_device { + enum msm_vidc_domain_type type; + struct video_device vdev; + struct v4l2_m2m_dev *m2m_dev; +}; + +struct msm_vidc_core_power { + u64 clk_freq; + u64 bw_ddr; + u64 bw_llcc; +}; + +struct msm_vidc_core { + struct platform_device *pdev; + struct msm_video_device vdev[2]; + struct v4l2_device v4l2_dev; + struct media_device media_dev; + struct list_head instances; + struct list_head dangling_instances; + struct dentry *debugfs_parent; + struct dentry *debugfs_root; + char fw_version[MAX_NAME_LENGTH]; + enum msm_vidc_core_state state; + int (*state_handle)(struct msm_vidc_core *core, + enum msm_vidc_core_event_type type, + struct msm_vidc_event_data *data); + enum msm_vidc_core_sub_state sub_state; + char sub_state_name[MAX_NAME_LENGTH]; + struct mutex lock; + struct msm_vidc_resource *resource; + struct msm_vidc_platform *platform; + u32 intr_status; + u32 spur_count; + u32 reg_count; + u32 enc_codecs_count; + u32 dec_codecs_count; + struct msm_vidc_core_capability capabilities[CORE_CAP_MAX + 1]; + struct msm_vidc_inst_capability *inst_caps; + struct msm_vidc_mem_addr sfr; + struct msm_vidc_mem_addr iface_q_table; + struct msm_vidc_mem_addr mmap_buf; + struct msm_vidc_mem_addr aon_reg; + struct msm_vidc_mem_addr fence_reg; + struct msm_vidc_mem_addr qtimer_reg; + struct msm_vidc_iface_q_info iface_queues[VIDC_IFACEQ_NUMQ]; + struct delayed_work pm_work; + struct workqueue_struct *pm_workq; + struct workqueue_struct *batch_workq; + struct delayed_work fw_unload_work; + struct work_struct ssr_work; + struct msm_vidc_core_power power; + struct msm_vidc_ssr ssr; + u32 skip_pc_count; + u32 last_packet_type; + u8 *packet; + u32 packet_size; + u8 *response_packet; + struct v4l2_file_operations *v4l2_file_ops; + struct v4l2_ioctl_ops *v4l2_ioctl_ops_enc; + struct v4l2_ioctl_ops *v4l2_ioctl_ops_dec; + struct v4l2_ctrl_ops *v4l2_ctrl_ops; + struct vb2_ops *vb2_ops; + struct vb2_mem_ops *vb2_mem_ops; + struct v4l2_m2m_ops *v4l2_m2m_ops; + struct msm_vidc_venus_ops *venus_ops; + const struct msm_vidc_resources_ops *res_ops; + struct msm_vidc_session_ops *session_ops; + const struct msm_vidc_memory_ops *mem_ops; + struct media_device_ops *media_device_ops; + const struct msm_vidc_fence_ops *fence_ops; + u32 header_id; + u32 packet_id; + u32 sys_init_id; + struct msm_vidc_synx_fence_data synx_fence_data; +}; + +#endif // _MSM_VIDC_CORE_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_debug.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_debug.h new file mode 100644 index 0000000000..ea82fa6f85 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_debug.h @@ -0,0 +1,206 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __MSM_VIDC_DEBUG__ +#define __MSM_VIDC_DEBUG__ + +#include +#include +#include +#include +#include +#include + +struct msm_vidc_core; +struct msm_vidc_inst; + +#ifndef VIDC_DBG_LABEL +#define VIDC_DBG_LABEL "msm_vidc" +#endif + +/* Allow only 6 prints/sec */ +#define VIDC_DBG_SESSION_RATELIMIT_INTERVAL (1 * HZ) +#define VIDC_DBG_SESSION_RATELIMIT_BURST 6 + +#define VIDC_DBG_TAG_INST VIDC_DBG_LABEL ": %4s: %s: " +#define VIDC_DBG_TAG_CORE VIDC_DBG_LABEL ": %4s: %08x: %s: " +#define FW_DBG_TAG VIDC_DBG_LABEL ": %6s: " +#define DEFAULT_SID ((u32)-1) + +#ifndef MSM_VIDC_EMPTY_BRACE +#define MSM_VIDC_EMPTY_BRACE {}, +#endif + +extern unsigned int msm_vidc_debug; +extern unsigned int msm_fw_debug; +extern bool msm_vidc_lossless_encode; +extern bool msm_vidc_syscache_disable; +extern int msm_vidc_clock_voting; +extern int msm_vidc_ddr_bw; +extern int msm_vidc_llc_bw; +extern bool msm_vidc_fw_dump; +extern unsigned int msm_vidc_enable_bugon; +extern bool msm_vidc_synx_fence_enable; + +/* do not modify the log message as it is used in test scripts */ +#define FMT_STRING_SET_CTRL \ + "%s: state %s, name %s, id 0x%x value %d\n" +#define FMT_STRING_STATE_CHANGE \ + "%s: state changed to %s from %s\n" +#define FMT_STRING_MSG_SFR \ + "SFR Message from FW: %s\n" +#define FMT_STRING_FAULT_HANDLER \ + "%s: faulting address: %lx\n" +#define FMT_STRING_SET_CAP \ + "set cap: name: %24s, cap value: %#10x, hfi: %#10llx\n" +#define FMT_STRING_SYSTEM_ERROR \ + "%s: system error received\n" +#define FMT_STRING_BOOT_FIRMWARE_ERROR \ + "Error booting up vidc firmware, ctrl status %#x, ctrl init %#x\n" + +/* To enable messages OR these values and + * echo the result to debugfs file. + * + * To enable all messages set msm_vidc_debug = 0x101F + */ + +enum vidc_msg_prio_drv { + VIDC_ERR = 0x00000001, + VIDC_HIGH = 0x00000002, + VIDC_LOW = 0x00000004, + VIDC_PERF = 0x00000008, + VIDC_PKT = 0x00000010, + VIDC_BUS = 0x00000020, + VIDC_STAT = 0x00000040, + VIDC_ENCODER = 0x00000100, + VIDC_DECODER = 0x00000200, + VIDC_PRINTK = 0x10000000, + VIDC_FTRACE = 0x20000000, +}; + +enum vidc_msg_prio_fw { + FW_LOW = 0x00000001, + FW_MED = 0x00000002, + FW_HIGH = 0x00000004, + FW_ERROR = 0x00000008, + FW_FATAL = 0x00000010, + FW_PERF = 0x00000020, + FW_CACHE_LOW = 0x00000100, + FW_CACHE_MED = 0x00000200, + FW_CACHE_HIGH = 0x00000400, + FW_CACHE_ERROR = 0x00000800, + FW_CACHE_FATAL = 0x00001000, + FW_CACHE_PERF = 0x00002000, + FW_PRINTK = 0x10000000, + FW_FTRACE = 0x20000000, +}; + +#define DRV_LOG (VIDC_ERR | VIDC_PRINTK) +#define DRV_LOGSHIFT (0) +#define DRV_LOGMASK (0x0FFFFFFF) + +#define FW_LOG (FW_ERROR | FW_FATAL | FW_PRINTK) +#define FW_LOGSHIFT (0) +#define FW_LOGMASK (0x0FFFFFFF) + +#define dprintk_inst(__level, __level_str, inst, __fmt, ...) \ + do { \ + if (inst && (msm_vidc_debug & (__level))) { \ + pr_info(VIDC_DBG_TAG_INST __fmt, \ + __level_str, \ + inst->debug_str, \ + ##__VA_ARGS__); \ + } \ + } while (0) + +#define i_vpr_e(inst, __fmt, ...) dprintk_inst(VIDC_ERR, "err ", inst, __fmt, ##__VA_ARGS__) +#define i_vpr_i(inst, __fmt, ...) dprintk_inst(VIDC_HIGH, "high", inst, __fmt, ##__VA_ARGS__) +#define i_vpr_h(inst, __fmt, ...) dprintk_inst(VIDC_HIGH, "high", inst, __fmt, ##__VA_ARGS__) +#define i_vpr_l(inst, __fmt, ...) dprintk_inst(VIDC_LOW, "low ", inst, __fmt, ##__VA_ARGS__) +#define i_vpr_p(inst, __fmt, ...) dprintk_inst(VIDC_PERF, "perf", inst, __fmt, ##__VA_ARGS__) +#define i_vpr_t(inst, __fmt, ...) dprintk_inst(VIDC_PKT, "pkt ", inst, __fmt, ##__VA_ARGS__) +#define i_vpr_b(inst, __fmt, ...) dprintk_inst(VIDC_BUS, "bus ", inst, __fmt, ##__VA_ARGS__) +#define i_vpr_s(inst, __fmt, ...) dprintk_inst(VIDC_STAT, "stat", inst, __fmt, ##__VA_ARGS__) + +#define i_vpr_hp(inst, __fmt, ...) \ + dprintk_inst(VIDC_HIGH | VIDC_PERF, "high", inst, __fmt, ##__VA_ARGS__) +#define i_vpr_hs(inst, __fmt, ...) \ + dprintk_inst(VIDC_HIGH | VIDC_STAT, "stat", inst, __fmt, ##__VA_ARGS__) + +#define dprintk_core(__level, __level_str, __fmt, ...) \ + do { \ + if (msm_vidc_debug & (__level)) { \ + pr_info(VIDC_DBG_TAG_CORE __fmt, \ + __level_str, \ + DEFAULT_SID, \ + "codec", \ + ##__VA_ARGS__); \ + } \ + } while (0) + +#define d_vpr_e(__fmt, ...) dprintk_core(VIDC_ERR, "err ", __fmt, ##__VA_ARGS__) +#define d_vpr_h(__fmt, ...) dprintk_core(VIDC_HIGH, "high", __fmt, ##__VA_ARGS__) +#define d_vpr_l(__fmt, ...) dprintk_core(VIDC_LOW, "low ", __fmt, ##__VA_ARGS__) +#define d_vpr_p(__fmt, ...) dprintk_core(VIDC_PERF, "perf", __fmt, ##__VA_ARGS__) +#define d_vpr_t(__fmt, ...) dprintk_core(VIDC_PKT, "pkt ", __fmt, ##__VA_ARGS__) +#define d_vpr_b(__fmt, ...) dprintk_core(VIDC_BUS, "bus ", __fmt, ##__VA_ARGS__) +#define d_vpr_s(__fmt, ...) dprintk_core(VIDC_STAT, "stat", __fmt, ##__VA_ARGS__) +#define d_vpr_hs(__fmt, ...) \ + dprintk_core(VIDC_HIGH | VIDC_STAT, "high", __fmt, ##__VA_ARGS__) + +#define dprintk_ratelimit(__level, __level_str, __fmt, ...) \ + do { \ + if (msm_vidc_check_ratelimit()) { \ + dprintk_core(__level, __level_str, __fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +#define dprintk_firmware(__level, __fmt, ...) \ + do { \ + if ((msm_fw_debug & (__level)) & FW_PRINTK) { \ + pr_info(FW_DBG_TAG __fmt, \ + "fw", \ + ##__VA_ARGS__); \ + } \ + } while (0) + +#define MSM_VIDC_FATAL(value) \ + do { \ + if (value) { \ + d_vpr_e("bug on\n"); \ + BUG_ON(value); \ + } \ + } while (0) + +enum msm_vidc_debugfs_event { + MSM_VIDC_DEBUGFS_EVENT_ETB, + MSM_VIDC_DEBUGFS_EVENT_EBD, + MSM_VIDC_DEBUGFS_EVENT_FTB, + MSM_VIDC_DEBUGFS_EVENT_FBD, +}; + +enum msm_vidc_bug_on_error { + MSM_VIDC_BUG_ON_FATAL = BIT(0), + MSM_VIDC_BUG_ON_NOC = BIT(1), + MSM_VIDC_BUG_ON_WD_TIMEOUT = BIT(2), +}; + +struct dentry *msm_vidc_debugfs_init_drv(void); +struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core); +struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst, + struct dentry *parent); +void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst); +void msm_vidc_debugfs_update(struct msm_vidc_inst *inst, + enum msm_vidc_debugfs_event e); +int msm_vidc_check_ratelimit(void); +void msm_vidc_show_stats(struct msm_vidc_inst *inst); + +static inline bool is_stats_enabled(void) +{ + return !!(msm_vidc_debug & VIDC_STAT); +} + +#endif diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_driver.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_driver.h new file mode 100644 index 0000000000..e8a6ef494e --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_driver.h @@ -0,0 +1,630 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_DRIVER_H_ +#define _MSM_VIDC_DRIVER_H_ + +#include +#include +#include "msm_vidc_internal.h" +#include "msm_vidc_core.h" +#include "msm_vidc_inst.h" + +#define MSM_VIDC_SESSION_INACTIVE_THRESHOLD_MS 1000 + +enum msm_vidc_debugfs_event; + +static inline bool is_decode_session(struct msm_vidc_inst *inst) +{ + return inst->domain == MSM_VIDC_DECODER; +} + +static inline bool is_encode_session(struct msm_vidc_inst *inst) +{ + return inst->domain == MSM_VIDC_ENCODER; +} + +static inline bool is_image_encode_session(struct msm_vidc_inst *inst) +{ + return inst->codec == MSM_VIDC_HEIC && inst->domain == MSM_VIDC_ENCODER; +} + +static inline bool is_image_decode_session(struct msm_vidc_inst *inst) +{ + return inst->codec == MSM_VIDC_HEIC && inst->domain == MSM_VIDC_DECODER; +} + +static inline bool is_image_session(struct msm_vidc_inst *inst) +{ + return inst->codec == MSM_VIDC_HEIC; +} + +static inline bool is_secure_session(struct msm_vidc_inst *inst) +{ + return !!(inst->capabilities[SECURE_MODE].value); +} + +static inline bool is_input_buffer(enum msm_vidc_buffer_type buffer_type) +{ + return buffer_type == MSM_VIDC_BUF_INPUT; +} + +static inline bool is_output_buffer(enum msm_vidc_buffer_type buffer_type) +{ + return buffer_type == MSM_VIDC_BUF_OUTPUT; +} + +static inline bool is_input_meta_buffer(enum msm_vidc_buffer_type buffer_type) +{ + return buffer_type == MSM_VIDC_BUF_INPUT_META; +} + +static inline bool is_output_meta_buffer(enum msm_vidc_buffer_type buffer_type) +{ + return buffer_type == MSM_VIDC_BUF_OUTPUT_META; +} + +static inline bool is_ts_reorder_allowed(struct msm_vidc_inst *inst) +{ + return !!(inst->capabilities[TS_REORDER].value && + is_decode_session(inst) && !is_image_session(inst)); +} + +static inline bool is_scaling_enabled(struct msm_vidc_inst *inst) +{ + return inst->crop.left != inst->compose.left || + inst->crop.top != inst->compose.top || + inst->crop.width != inst->compose.width || + inst->crop.height != inst->compose.height; +} + +static inline bool is_rotation_90_or_270(struct msm_vidc_inst *inst) +{ + return inst->capabilities[ROTATION].value == 90 || + inst->capabilities[ROTATION].value == 270; +} + +static inline bool is_internal_buffer(enum msm_vidc_buffer_type buffer_type) +{ + return buffer_type == MSM_VIDC_BUF_BIN || + buffer_type == MSM_VIDC_BUF_ARP || + buffer_type == MSM_VIDC_BUF_COMV || + buffer_type == MSM_VIDC_BUF_NON_COMV || + buffer_type == MSM_VIDC_BUF_LINE || + buffer_type == MSM_VIDC_BUF_DPB || + buffer_type == MSM_VIDC_BUF_PERSIST || + buffer_type == MSM_VIDC_BUF_VPSS || + buffer_type == MSM_VIDC_BUF_PARTIAL_DATA; +} + +static inline bool is_meta_cap(struct msm_vidc_inst *inst, u32 cap) +{ + if (inst->capabilities[cap].flags & CAP_FLAG_META) + return true; + + return false; +} + +static inline bool is_meta_rx_inp_enabled(struct msm_vidc_inst *inst, u32 cap) +{ + bool enabled = false; + + if (!is_meta_cap(inst, cap)) + return false; + + if (inst->capabilities[cap].value & MSM_VIDC_META_ENABLE && + inst->capabilities[cap].value & MSM_VIDC_META_RX_INPUT) + enabled = true; + + return enabled; +} + +static inline bool is_meta_rx_out_enabled(struct msm_vidc_inst *inst, u32 cap) +{ + bool enabled = false; + + if (!is_meta_cap(inst, cap)) + return false; + + if (inst->capabilities[cap].value & MSM_VIDC_META_ENABLE && + inst->capabilities[cap].value & MSM_VIDC_META_RX_OUTPUT) + enabled = true; + + return enabled; +} + +static inline bool is_meta_tx_inp_enabled(struct msm_vidc_inst *inst, u32 cap) +{ + bool enabled = false; + + if (!is_meta_cap(inst, cap)) + return false; + + if (inst->capabilities[cap].value & MSM_VIDC_META_ENABLE && + inst->capabilities[cap].value & MSM_VIDC_META_TX_INPUT) + enabled = true; + + return enabled; +} + +static inline bool is_dyn_meta_tx_inp_enabled(struct msm_vidc_inst *inst, u32 cap) +{ + bool enabled = false; + + if (!is_meta_cap(inst, cap)) + return false; + + if (inst->capabilities[cap].value & MSM_VIDC_META_DYN_ENABLE && + inst->capabilities[cap].value & MSM_VIDC_META_TX_INPUT) + enabled = true; + + return enabled; +} + +static inline bool is_meta_tx_out_enabled(struct msm_vidc_inst *inst, u32 cap) +{ + bool enabled = false; + + if (!is_meta_cap(inst, cap)) + return false; + + if (inst->capabilities[cap].value & MSM_VIDC_META_ENABLE && + inst->capabilities[cap].value & MSM_VIDC_META_TX_OUTPUT) + enabled = true; + + return enabled; +} + +static inline bool is_dyn_meta_tx_out_enabled(struct msm_vidc_inst *inst, u32 cap) +{ + bool enabled = false; + + if (!is_meta_cap(inst, cap)) + return false; + + if (inst->capabilities[cap].value & MSM_VIDC_META_DYN_ENABLE && + inst->capabilities[cap].value & MSM_VIDC_META_TX_OUTPUT) + enabled = true; + + return enabled; +} + +static inline bool is_any_meta_tx_out_enabled(struct msm_vidc_inst *inst) +{ + bool enabled = false; + u32 i; + + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_tx_out_enabled(inst, i) || + is_dyn_meta_tx_out_enabled(inst, i)) { + enabled = true; + break; + } + } + + return enabled; +} + +static inline bool is_any_meta_tx_inp_enabled(struct msm_vidc_inst *inst) +{ + bool enabled = false; + u32 i; + + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_tx_inp_enabled(inst, i) || + is_dyn_meta_tx_inp_enabled(inst, i)) { + enabled = true; + break; + } + } + + return enabled; +} + +static inline bool is_input_meta_enabled(struct msm_vidc_inst *inst) +{ + bool enabled = false; + u32 i; + + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_tx_inp_enabled(inst, i) || + is_dyn_meta_tx_inp_enabled(inst, i) || + is_meta_rx_inp_enabled(inst, i)) { + enabled = true; + break; + } + } + + return enabled; +} + +static inline bool is_output_meta_enabled(struct msm_vidc_inst *inst) +{ + bool enabled = false; + u32 i; + + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_tx_out_enabled(inst, i) || + is_dyn_meta_tx_out_enabled(inst, i) || + is_meta_rx_out_enabled(inst, i)) { + enabled = true; + break; + } + } + + return enabled; +} + +static inline bool is_meta_enabled(struct msm_vidc_inst *inst, unsigned int type) +{ + bool enabled = false; + + if (type == MSM_VIDC_BUF_INPUT) + enabled = is_input_meta_enabled(inst); + else if (type == MSM_VIDC_BUF_OUTPUT) + enabled = is_output_meta_enabled(inst); + + return enabled; +} + +static inline bool is_outbuf_fence_enabled(struct msm_vidc_inst *inst) +{ + return is_meta_rx_inp_enabled(inst, META_OUTBUF_FENCE); +} + +static inline bool is_linear_yuv_colorformat(enum msm_vidc_colorformat_type colorformat) +{ + return colorformat == MSM_VIDC_FMT_NV12 || + colorformat == MSM_VIDC_FMT_NV21 || + colorformat == MSM_VIDC_FMT_P010; +} + +static inline bool is_linear_rgba_colorformat(enum msm_vidc_colorformat_type colorformat) +{ + return colorformat == MSM_VIDC_FMT_RGBA8888; +} + +static inline bool is_linear_colorformat(enum msm_vidc_colorformat_type colorformat) +{ + return is_linear_yuv_colorformat(colorformat) || is_linear_rgba_colorformat(colorformat); +} + +static inline bool is_ubwc_colorformat(enum msm_vidc_colorformat_type colorformat) +{ + return colorformat == MSM_VIDC_FMT_NV12C || + colorformat == MSM_VIDC_FMT_TP10C || + colorformat == MSM_VIDC_FMT_RGBA8888C; +} + +static inline bool is_10bit_colorformat(enum msm_vidc_colorformat_type colorformat) +{ + return colorformat == MSM_VIDC_FMT_P010 || + colorformat == MSM_VIDC_FMT_TP10C; +} + +static inline bool is_8bit_colorformat(enum msm_vidc_colorformat_type colorformat) +{ + return colorformat == MSM_VIDC_FMT_NV12 || + colorformat == MSM_VIDC_FMT_NV12C || + colorformat == MSM_VIDC_FMT_NV21 || + colorformat == MSM_VIDC_FMT_RGBA8888 || + colorformat == MSM_VIDC_FMT_RGBA8888C; +} + +static inline bool is_rgba_colorformat(enum msm_vidc_colorformat_type colorformat) +{ + return colorformat == MSM_VIDC_FMT_RGBA8888 || + colorformat == MSM_VIDC_FMT_RGBA8888C; +} + +static inline bool is_split_mode_enabled(struct msm_vidc_inst *inst) +{ + if (!is_decode_session(inst)) + return false; + + if (is_linear_colorformat(inst->capabilities[PIX_FMTS].value) || + (inst->codec == MSM_VIDC_AV1 && + inst->capabilities[FILM_GRAIN].value)) + return true; + + return false; +} + +static inline bool is_thumbnail_session(struct msm_vidc_inst *inst) +{ + return !!(inst->capabilities[THUMBNAIL_MODE].value); +} + +static inline bool is_low_power_session(struct msm_vidc_inst *inst) +{ + return (inst->capabilities[QUALITY_MODE].value == + MSM_VIDC_POWER_SAVE_MODE); +} + +static inline bool is_realtime_session(struct msm_vidc_inst *inst) +{ + return inst->capabilities[PRIORITY].value == 0 ? true : false; +} + +static inline bool is_critical_priority_session(struct msm_vidc_inst *inst) +{ + return !!(inst->capabilities[CRITICAL_PRIORITY].value); +} + +static inline bool is_lowlatency_session(struct msm_vidc_inst *inst) +{ + return !!(inst->capabilities[LOWLATENCY_MODE].value); +} + +static inline bool is_hierb_type_requested(struct msm_vidc_inst *inst) +{ + return (inst->codec == MSM_VIDC_H264 && + inst->capabilities[LAYER_TYPE].value == + V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_B) || + (inst->codec == MSM_VIDC_HEVC && + inst->capabilities[LAYER_TYPE].value == + V4L2_MPEG_VIDEO_HEVC_HIERARCHICAL_CODING_B); +} + +static inline bool is_active_session(u64 prev, u64 curr) +{ + u64 ts_delta; + + if (!prev || !curr) + return true; + + ts_delta = (prev < curr) ? curr - prev : prev - curr; + + return ((ts_delta / NSEC_PER_MSEC) <= + MSM_VIDC_SESSION_INACTIVE_THRESHOLD_MS); +} + +static inline bool is_session_error(struct msm_vidc_inst *inst) +{ + return inst->state == MSM_VIDC_ERROR; +} + +static inline bool is_secure_region(enum msm_vidc_buffer_region region) +{ + return !(region == MSM_VIDC_NON_SECURE || + region == MSM_VIDC_NON_SECURE_PIXEL); +} + +static inline bool is_enc_slice_delivery_mode(struct msm_vidc_inst *inst) +{ + if (is_decode_session(inst)) + return false; + + return (inst->capabilities[SLICE_MODE].value == + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB && + inst->capabilities[DELIVERY_MODE].value); +} + +const char *cap_name(enum msm_vidc_inst_capability_type cap_id); +const char *v4l2_pixelfmt_name(struct msm_vidc_inst *inst, u32 pixelfmt); +const char *v4l2_type_name(u32 port); +void print_vidc_buffer(u32 tag, const char *tag_str, const char *str, + struct msm_vidc_inst *inst, struct msm_vidc_buffer *vbuf); +void print_vb2_buffer(const char *str, struct msm_vidc_inst *inst, + struct vb2_buffer *vb2); +enum msm_vidc_codec_type v4l2_codec_to_driver(struct msm_vidc_inst *inst, + u32 v4l2_codec, const char *func); +u32 v4l2_codec_from_driver(struct msm_vidc_inst *inst, enum msm_vidc_codec_type codec, + const char *func); +enum msm_vidc_colorformat_type v4l2_colorformat_to_driver(struct msm_vidc_inst *inst, + u32 colorformat, const char *func); +u32 v4l2_colorformat_from_driver(struct msm_vidc_inst *inst, + enum msm_vidc_colorformat_type colorformat, + const char *func); +u32 v4l2_color_primaries_to_driver(struct msm_vidc_inst *inst, + u32 v4l2_primaries, const char *func); +u32 v4l2_color_primaries_from_driver(struct msm_vidc_inst *inst, + u32 vidc_color_primaries, const char *func); +u32 v4l2_transfer_char_to_driver(struct msm_vidc_inst *inst, + u32 v4l2_transfer_char, const char *func); +u32 v4l2_transfer_char_from_driver(struct msm_vidc_inst *inst, + u32 vidc_transfer_char, const char *func); +u32 v4l2_matrix_coeff_to_driver(struct msm_vidc_inst *inst, + u32 v4l2_matrix_coeff, const char *func); +u32 v4l2_matrix_coeff_from_driver(struct msm_vidc_inst *inst, + u32 vidc_matrix_coeff, const char *func); +int v4l2_type_to_driver_port(struct msm_vidc_inst *inst, u32 type, + const char *func); +const char *allow_name(enum msm_vidc_allow allow); +int msm_vidc_create_internal_buffer(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type, u32 index); +int msm_vidc_get_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +int msm_vidc_create_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +int msm_vidc_queue_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +int msm_vidc_alloc_and_queue_session_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +int msm_vidc_release_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); +int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf); +int msm_vidc_remove_dangling_session(struct msm_vidc_inst *inst); +int msm_vidc_remove_session(struct msm_vidc_inst *inst); +int msm_vidc_add_session(struct msm_vidc_inst *inst); +int msm_vidc_session_open(struct msm_vidc_inst *inst); +int msm_vidc_session_set_codec(struct msm_vidc_inst *inst); +int msm_vidc_session_set_secure_mode(struct msm_vidc_inst *inst); +int msm_vidc_session_set_default_header(struct msm_vidc_inst *inst); +int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port); +int msm_vidc_session_close(struct msm_vidc_inst *inst); +int msm_vidc_kill_session(struct msm_vidc_inst *inst); +int msm_vidc_get_inst_capability(struct msm_vidc_inst *inst); +int msm_vidc_change_core_state(struct msm_vidc_core *core, + enum msm_vidc_core_state request_state, + const char *func); +int msm_vidc_change_core_sub_state(struct msm_vidc_core *core, + enum msm_vidc_core_sub_state clear_sub_states, + enum msm_vidc_core_sub_state set_sub_states, + const char *func); +int msm_vidc_core_init(struct msm_vidc_core *core); +int msm_vidc_core_init_wait(struct msm_vidc_core *core); +int msm_vidc_core_deinit(struct msm_vidc_core *core, bool force); +int msm_vidc_print_residency_stats(struct msm_vidc_core *core); +int msm_vidc_reset_residency_stats(struct msm_vidc_core *core); +int msm_vidc_core_deinit_locked(struct msm_vidc_core *core, bool force); +int msm_vidc_inst_timeout(struct msm_vidc_inst *inst); +int msm_vidc_print_buffer_info(struct msm_vidc_inst *inst); +int msm_vidc_print_inst_info(struct msm_vidc_inst *inst); +void msm_vidc_print_core_info(struct msm_vidc_core *core); +int msm_vidc_smmu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long iova, + int flags, void *data); +int msm_vidc_trigger_ssr(struct msm_vidc_core *core, + u64 trigger_ssr_val); +void msm_vidc_ssr_handler(struct work_struct *work); +int msm_vidc_trigger_stability(struct msm_vidc_core *core, + u64 trigger_stability_val); +void msm_vidc_stability_handler(struct work_struct *work); +int cancel_stability_work_sync(struct msm_vidc_inst *inst); +void msm_vidc_fw_unload_handler(struct work_struct *work); +int msm_vidc_suspend(struct msm_vidc_core *core); +void msm_vidc_batch_handler(struct work_struct *work); +int msm_vidc_v4l2_fh_init(struct msm_vidc_inst *inst); +int msm_vidc_v4l2_fh_deinit(struct msm_vidc_inst *inst); +int msm_vidc_vb2_queue_init(struct msm_vidc_inst *inst); +int msm_vidc_vb2_queue_deinit(struct msm_vidc_inst *inst); +int msm_vidc_get_control(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl); +struct msm_vidc_buffers *msm_vidc_get_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type, + const char *func); +struct msm_vidc_mem_list *msm_vidc_get_mem_info(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type, + const char *func); +struct msm_vidc_buffer *msm_vidc_get_driver_buf(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2); +int msm_vidc_allocate_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buf_type, u32 num_buffers); +int msm_vidc_free_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buf_type); +void msm_vidc_update_stats(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf, + enum msm_vidc_debugfs_event etype); +void msm_vidc_stats_handler(struct work_struct *work); +int schedule_stats_work(struct msm_vidc_inst *inst); +int cancel_stats_work_sync(struct msm_vidc_inst *inst); +void msm_vidc_print_stats(struct msm_vidc_inst *inst); +void msm_vidc_print_memory_stats(struct msm_vidc_inst *inst); +enum msm_vidc_buffer_type v4l2_type_to_driver(u32 type, const char *func); +int msm_vidc_buf_queue(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf); +int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2); +int msm_vidc_queue_deferred_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buf_type); +int msm_vidc_destroy_internal_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer); +void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst); +int msm_vidc_flush_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type type); +int msm_vidc_flush_read_only_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type type); +struct msm_vidc_buffer *get_meta_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *vbuf); +struct msm_vidc_inst *get_inst_ref(struct msm_vidc_core *core, + struct msm_vidc_inst *instance); +struct msm_vidc_inst *get_inst(struct msm_vidc_core *core, + u32 session_id); +void put_inst(struct msm_vidc_inst *inst); +bool msm_vidc_allow_metadata_delivery(struct msm_vidc_inst *inst, + u32 cap_id, u32 port); +bool msm_vidc_allow_metadata_subscription(struct msm_vidc_inst *inst, + u32 cap_id, u32 port); +bool msm_vidc_allow_property(struct msm_vidc_inst *inst, u32 hfi_id); +enum msm_vidc_allow msm_vidc_allow_input_psc(struct msm_vidc_inst *inst); +bool msm_vidc_allow_drain_last_flag(struct msm_vidc_inst *inst); +bool msm_vidc_allow_psc_last_flag(struct msm_vidc_inst *inst); +enum msm_vidc_allow msm_vidc_allow_pm_suspend(struct msm_vidc_core *core); +int msm_vidc_state_change_streamon(struct msm_vidc_inst *inst, u32 type); +int msm_vidc_state_change_streamoff(struct msm_vidc_inst *inst, u32 type); +int msm_vidc_state_change_input_psc(struct msm_vidc_inst *inst); +int msm_vidc_state_change_drain_last_flag(struct msm_vidc_inst *inst); +int msm_vidc_state_change_psc_last_flag(struct msm_vidc_inst *inst); +int msm_vidc_process_drain(struct msm_vidc_inst *inst); +int msm_vidc_process_resume(struct msm_vidc_inst *inst); +int msm_vidc_process_streamon_input(struct msm_vidc_inst *inst); +int msm_vidc_process_streamon_output(struct msm_vidc_inst *inst); +int msm_vidc_process_stop_done(struct msm_vidc_inst *inst, + enum signal_session_response signal_type); +int msm_vidc_process_drain_done(struct msm_vidc_inst *inst); +int msm_vidc_process_drain_last_flag(struct msm_vidc_inst *inst); +int msm_vidc_process_psc_last_flag(struct msm_vidc_inst *inst); +int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst); +u32 msm_vidc_get_max_bitrate(struct msm_vidc_inst *inst); +int msm_vidc_get_fps(struct msm_vidc_inst *inst); +int msm_vidc_num_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type type, + enum msm_vidc_buffer_attributes attr); +void core_lock(struct msm_vidc_core *core, const char *function); +void core_unlock(struct msm_vidc_core *core, const char *function); +void inst_lock(struct msm_vidc_inst *inst, const char *function); +void inst_unlock(struct msm_vidc_inst *inst, const char *function); +void client_lock(struct msm_vidc_inst *inst, const char *function); +void client_unlock(struct msm_vidc_inst *inst, const char *function); +int msm_vidc_update_bitstream_buffer_size(struct msm_vidc_inst *inst); +int msm_vidc_update_meta_port_settings(struct msm_vidc_inst *inst); +int msm_vidc_update_buffer_count(struct msm_vidc_inst *inst, u32 port); +void msm_vidc_schedule_core_deinit(struct msm_vidc_core *core); +bool msm_vidc_is_super_buffer(struct msm_vidc_inst *inst); +int msm_vidc_init_core_caps(struct msm_vidc_core *core); +int msm_vidc_init_instance_caps(struct msm_vidc_core *core); +int msm_vidc_deinit_core_caps(struct msm_vidc_core *core); +int msm_vidc_update_debug_str(struct msm_vidc_inst *inst); +void msm_vidc_allow_dcvs(struct msm_vidc_inst *inst); +bool msm_vidc_allow_decode_batch(struct msm_vidc_inst *inst); +int msm_vidc_check_session_supported(struct msm_vidc_inst *inst); +int msm_vidc_check_core_mbps(struct msm_vidc_inst *inst); +int msm_vidc_check_core_mbpf(struct msm_vidc_inst *inst); +int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst); +int msm_vidc_update_timestamp_rate(struct msm_vidc_inst *inst, u64 timestamp); +int msm_vidc_set_auto_framerate(struct msm_vidc_inst *inst, u64 timestamp); +int msm_vidc_get_timestamp_rate(struct msm_vidc_inst *inst); +int msm_vidc_flush_ts(struct msm_vidc_inst *inst); +int msm_vidc_ts_reorder_insert_timestamp(struct msm_vidc_inst *inst, u64 timestamp); +int msm_vidc_ts_reorder_remove_timestamp(struct msm_vidc_inst *inst, u64 timestamp); +int msm_vidc_ts_reorder_get_first_timestamp(struct msm_vidc_inst *inst, u64 *timestamp); +int msm_vidc_ts_reorder_flush(struct msm_vidc_inst *inst); +const char *buf_name(enum msm_vidc_buffer_type type); +bool res_is_greater_than(u32 width, u32 height, + u32 ref_width, u32 ref_height); +bool res_is_greater_than_or_equal_to(u32 width, u32 height, + u32 ref_width, u32 ref_height); +bool res_is_less_than(u32 width, u32 height, + u32 ref_width, u32 ref_height); +bool res_is_less_than_or_equal_to(u32 width, u32 height, + u32 ref_width, u32 ref_height); +bool is_hevc_10bit_decode_session(struct msm_vidc_inst *inst); +int signal_session_msg_receipt(struct msm_vidc_inst *inst, + enum signal_session_response cmd); +int msm_vidc_get_properties(struct msm_vidc_inst *inst); +int msm_vidc_update_input_rate(struct msm_vidc_inst *inst, u64 time_us); +int msm_vidc_add_buffer_stats(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf, u64 timestamp); +int msm_vidc_remove_buffer_stats(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf, u64 timestamp); +int msm_vidc_flush_buffer_stats(struct msm_vidc_inst *inst); +int msm_vidc_get_input_rate(struct msm_vidc_inst *inst); +int msm_vidc_get_frame_rate(struct msm_vidc_inst *inst); +int msm_vidc_get_operating_rate(struct msm_vidc_inst *inst); +int msm_vidc_alloc_and_queue_input_internal_buffers(struct msm_vidc_inst *inst); +int vb2_buffer_to_driver(struct vb2_buffer *vb2, struct msm_vidc_buffer *buf); +bool is_ssr_type_allowed(struct msm_vidc_core *core, u32 type); +struct msm_vidc_buffer *msm_vidc_fetch_buffer(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2); +struct context_bank_info + *msm_vidc_get_context_bank_for_region(struct msm_vidc_core *core, + enum msm_vidc_buffer_region region); +struct context_bank_info + *msm_vidc_get_context_bank_for_device(struct msm_vidc_core *core, struct device *dev); + +#endif // _MSM_VIDC_DRIVER_H_ + diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_events.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_events.h new file mode 100644 index 0000000000..248dda606d --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_events.h @@ -0,0 +1,300 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#if !defined(_TRACE_MSM_VIDC_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_MSM_VIDC_H + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM msm_vidc_events +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_FILE msm_vidc_events + +#include + +#include "msm_vidc_inst.h" + +DECLARE_EVENT_CLASS(msm_v4l2_vidc_inst, + + TP_PROTO(char *dummy, struct msm_vidc_inst *inst), + + TP_ARGS(dummy, inst), + + TP_STRUCT__entry( + __field(char *, dummy) + __field(const char *, debug_str) + ), + + TP_fast_assign( + __entry->dummy = dummy; + __entry->debug_str = inst ? inst->debug_str : (u8 *)""; + ), + + TP_printk("%s: %s\n", __entry->dummy, __entry->debug_str) +); + +DEFINE_EVENT(msm_v4l2_vidc_inst, msm_v4l2_vidc_open, + + TP_PROTO(char *dummy, struct msm_vidc_inst *inst), + + TP_ARGS(dummy, inst) +); + +DEFINE_EVENT(msm_v4l2_vidc_inst, msm_v4l2_vidc_close, + + TP_PROTO(char *dummy, struct msm_vidc_inst *inst), + + TP_ARGS(dummy, inst) +); + +DECLARE_EVENT_CLASS(msm_v4l2_vidc_fw_load, + + TP_PROTO(char *dummy), + + TP_ARGS(dummy), + + TP_STRUCT__entry( + __field(char *, dummy) + ), + + TP_fast_assign( + __entry->dummy = dummy; + ), + + TP_printk("%s\n", __entry->dummy) +); + +DEFINE_EVENT(msm_v4l2_vidc_fw_load, msm_v4l2_vidc_fw_load, + + TP_PROTO(char *dummy), + + TP_ARGS(dummy) +); + +DECLARE_EVENT_CLASS(msm_vidc_driver, + + TP_PROTO(struct msm_vidc_inst *inst, const char *func, + const char *old_state, const char *new_state), + + TP_ARGS(inst, func, old_state, new_state), + + TP_STRUCT__entry( + __field(const char *, debug_str) + __field(const char *, func) + __field(const char *, old_state) + __field(const char *, new_state) + ), + + TP_fast_assign( + __entry->debug_str = inst ? inst->debug_str : (u8 *)""; + __entry->func = func; + __entry->old_state = old_state; + __entry->new_state = new_state; + ), + + TP_printk("%s: %s: state changed to %s from %s\n", + __entry->debug_str, + __entry->func, + __entry->new_state, + __entry->old_state) +); + +DEFINE_EVENT(msm_vidc_driver, msm_vidc_common_state_change, + + TP_PROTO(struct msm_vidc_inst *inst, const char *func, + const char *old_state, const char *new_state), + + TP_ARGS(inst, func, old_state, new_state) +); + +DECLARE_EVENT_CLASS(venus_hfi_var, + + TP_PROTO(u32 cp_start, u32 cp_size, + u32 cp_nonpixel_start, u32 cp_nonpixel_size), + + TP_ARGS(cp_start, cp_size, cp_nonpixel_start, cp_nonpixel_size), + + TP_STRUCT__entry( + __field(u32, cp_start) + __field(u32, cp_size) + __field(u32, cp_nonpixel_start) + __field(u32, cp_nonpixel_size) + ), + + TP_fast_assign( + __entry->cp_start = cp_start; + __entry->cp_size = cp_size; + __entry->cp_nonpixel_start = cp_nonpixel_start; + __entry->cp_nonpixel_size = cp_nonpixel_size; + ), + + TP_printk( + "TZBSP_MEM_PROTECT_VIDEO_VAR done, cp_start : 0x%x, cp_size : 0x%x, cp_nonpixel_start : 0x%x, cp_nonpixel_size : 0x%x\n", + __entry->cp_start, + __entry->cp_size, + __entry->cp_nonpixel_start, + __entry->cp_nonpixel_size) +); + +DEFINE_EVENT(venus_hfi_var, venus_hfi_var_done, + + TP_PROTO(u32 cp_start, u32 cp_size, + u32 cp_nonpixel_start, u32 cp_nonpixel_size), + + TP_ARGS(cp_start, cp_size, cp_nonpixel_start, cp_nonpixel_size) +); + +DECLARE_EVENT_CLASS(msm_v4l2_vidc_buffer_events, + + TP_PROTO(struct msm_vidc_inst *inst, const char *str, const char *buf_type, + struct msm_vidc_buffer *vbuf, unsigned long inode, long ref_count), + + TP_ARGS(inst, str, buf_type, vbuf, inode, ref_count), + + TP_STRUCT__entry( + __field(u8 *, debug_str) + __field(const char *, str) + __field(const char *, buf_type) + __field(u32, index) + __field(int, fd) + __field(u32, data_offset) + __field(u64, device_addr) + __field(unsigned long, inode) + __field(long, ref_count) + __field(u32, buffer_size) + __field(u32, data_size) + __field(u32, flags) + __field(u64, timestamp) + __field(int, attr) + __field(u64, etb) + __field(u64, ebd) + __field(u64, ftb) + __field(u64, fbd) + ), + + TP_fast_assign( + __entry->debug_str = inst ? inst->debug_str : (u8 *)""; + __entry->str = str; + __entry->buf_type = buf_type; + __entry->index = vbuf ? vbuf->index : -1; + __entry->fd = vbuf ? vbuf->fd : 0; + __entry->data_offset = vbuf ? vbuf->data_offset : 0; + __entry->device_addr = vbuf ? vbuf->device_addr : 0; + __entry->inode = inode; + __entry->ref_count = ref_count; + __entry->buffer_size = vbuf ? vbuf->buffer_size : 0; + __entry->data_size = vbuf ? vbuf->data_size : 0; + __entry->flags = vbuf ? vbuf->flags : 0; + __entry->timestamp = vbuf ? vbuf->timestamp : 0; + __entry->attr = vbuf ? vbuf->attr : 0; + __entry->etb = inst ? inst->debug_count.etb : 0; + __entry->ebd = inst ? inst->debug_count.ebd : 0; + __entry->ftb = inst ? inst->debug_count.ftb : 0; + __entry->fbd = inst ? inst->debug_count.fbd : 0; + ), + + TP_printk( + "%s: %s: %s: idx %2d fd %3d off %d daddr %#llx inode %8lu ref %2ld size %8d filled %8d flags %#x ts %8lld attr %#x counts(etb ebd ftb fbd) %4llu %4llu %4llu %4llu\n", + __entry->debug_str, __entry->str, __entry->buf_type, __entry->index, __entry->fd, + __entry->data_offset, __entry->device_addr, __entry->inode, __entry->ref_count, + __entry->buffer_size, __entry->data_size, __entry->flags, __entry->timestamp, + __entry->attr, __entry->etb, __entry->ebd, __entry->ftb, __entry->fbd) +); + +DEFINE_EVENT(msm_v4l2_vidc_buffer_events, msm_v4l2_vidc_buffer_event_log, + + TP_PROTO(struct msm_vidc_inst *inst, const char *str, const char *buf_type, + struct msm_vidc_buffer *vbuf, unsigned long inode, long ref_count), + + TP_ARGS(inst, str, buf_type, vbuf, inode, ref_count) +); + +DECLARE_EVENT_CLASS(msm_vidc_perf, + + TP_PROTO(struct msm_vidc_inst *inst, u64 clk_freq, u64 bw_ddr, u64 bw_llcc), + + TP_ARGS(inst, clk_freq, bw_ddr, bw_llcc), + + TP_STRUCT__entry( + __field(u8 *, debug_str) + __field(u64, curr_freq) + __field(u32, ddr_bw) + __field(u32, sys_cache_bw) + __field(u32, dcvs_flags) + __field(u64, clk_freq) + __field(u64, bw_ddr) + __field(u64, bw_llcc) + ), + + TP_fast_assign( + __entry->debug_str = inst ? inst->debug_str : (u8 *)""; + __entry->curr_freq = inst ? inst->power.curr_freq : 0; + __entry->ddr_bw = inst ? inst->power.ddr_bw : 0; + __entry->sys_cache_bw = inst ? inst->power.sys_cache_bw : 0; + __entry->dcvs_flags = inst ? inst->power.dcvs_flags : 0; + __entry->clk_freq = clk_freq; + __entry->bw_ddr = bw_ddr; + __entry->bw_llcc = bw_llcc; + ), + + TP_printk("%s: power: inst: clk %lld ddr %d llcc %d dcvs flags %#x, core: clk %lld ddr %lld llcc %lld\n", + __entry->debug_str, __entry->curr_freq, __entry->ddr_bw, __entry->sys_cache_bw, + __entry->dcvs_flags, __entry->clk_freq, __entry->bw_ddr, __entry->bw_llcc) +); + +DEFINE_EVENT(msm_vidc_perf, msm_vidc_perf_power_scale, + + TP_PROTO(struct msm_vidc_inst *inst, u64 clk_freq, u64 bw_ddr, u64 bw_llcc), + + TP_ARGS(inst, clk_freq, bw_ddr, bw_llcc) +); + +DECLARE_EVENT_CLASS(msm_vidc_buffer_dma_ops, + + TP_PROTO(const char *buffer_op, void *dmabuf, u8 size, void *kvaddr, + const char *buf_name, u8 secure, u32 region), + + TP_ARGS(buffer_op, dmabuf, size, kvaddr, buf_name, secure, region), + + TP_STRUCT__entry( + __field(const char *, buffer_op) + __field(void *, dmabuf) + __field(u8, size) + __field(void *, kvaddr) + __field(const char *, buf_name) + __field(u8, secure) + __field(u32, region) + ), + + TP_fast_assign( + __entry->buffer_op = buffer_op; + __entry->dmabuf = dmabuf; + __entry->size = size; + __entry->kvaddr = kvaddr; + __entry->buf_name = buf_name; + __entry->secure = secure; + __entry->region = region; + ), + + TP_printk( + "%s: dmabuf %pK, size %d, kvaddr %pK, buffer_type %s, secure %d, region %d\n", + __entry->buffer_op, __entry->dmabuf, __entry->size, __entry->kvaddr, + __entry->buf_name, __entry->secure, __entry->region) +); + +DEFINE_EVENT(msm_vidc_buffer_dma_ops, msm_vidc_dma_buffer, + + TP_PROTO(const char *buffer_op, void *dmabuf, u8 size, void *kvaddr, + const char *buf_name, u8 secure, u32 region), + + TP_ARGS(buffer_op, dmabuf, size, kvaddr, buf_name, secure, region) +); + +#endif + +/* This part must be outside protection */ +#include diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_fence.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_fence.h new file mode 100644 index 0000000000..9e375695ab --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_fence.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __H_MSM_VIDC_FENCE_H__ +#define __H_MSM_VIDC_FENCE_H__ + +#include "msm_vidc_inst.h" +#include "msm_vidc_buffer.h" + +int msm_vidc_fence_init(struct msm_vidc_inst *inst); +void msm_vidc_fence_deinit(struct msm_vidc_inst *inst); + +#define call_fence_op(c, op, ...) \ + (((c) && (c)->fence_ops && (c)->fence_ops->op) ? \ + ((c)->fence_ops->op(__VA_ARGS__)) : 0) + +struct msm_vidc_fence_ops { + int (*fence_register)(struct msm_vidc_core *core); + int (*fence_deregister)(struct msm_vidc_core *core); + struct msm_vidc_fence *(*fence_create)(struct msm_vidc_inst *inst); + int (*fence_create_fd)(struct msm_vidc_inst *inst, + struct msm_vidc_fence *fence); + void (*fence_destroy)(struct msm_vidc_inst *inst, + u64 fence_id); + int (*fence_signal)(struct msm_vidc_inst *inst, + u64 fence_id); + void (*fence_recover)(struct msm_vidc_core *core); +}; + +const struct msm_vidc_fence_ops *get_dma_fence_ops(void); + +#endif // __H_MSM_VIDC_FENCE_H__ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_inst.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_inst.h new file mode 100644 index 0000000000..ec303c8d0b --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_inst.h @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_INST_H_ +#define _MSM_VIDC_INST_H_ + +#include "msm_vidc_internal.h" +#include "msm_vidc_memory.h" +#include "msm_vidc_state.h" +#include "hfi_property.h" + +struct msm_vidc_inst; + +#define call_session_op(c, op, ...) \ + (((c) && (c)->session_ops && (c)->session_ops->op) ? \ + ((c)->session_ops->op(__VA_ARGS__)) : 0) + +struct msm_vidc_session_ops { + u64 (*calc_freq)(struct msm_vidc_inst *inst, u32 data_size); + int (*calc_bw)(struct msm_vidc_inst *inst, + struct vidc_bus_vote_data *vote_data); + int (*decide_work_route)(struct msm_vidc_inst *inst); + int (*decide_work_mode)(struct msm_vidc_inst *inst); + int (*decide_quality_mode)(struct msm_vidc_inst *inst); + int (*buffer_size)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type); + int (*min_count)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type); + int (*extra_count)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type); + int (*ring_buf_count)(struct msm_vidc_inst *inst, u32 data_size); +}; + +struct msm_vidc_mem_list_info { + struct msm_vidc_mem_list bin; + struct msm_vidc_mem_list arp; + struct msm_vidc_mem_list comv; + struct msm_vidc_mem_list non_comv; + struct msm_vidc_mem_list line; + struct msm_vidc_mem_list dpb; + struct msm_vidc_mem_list persist; + struct msm_vidc_mem_list vpss; + struct msm_vidc_mem_list partial_data; +}; + +struct msm_vidc_buffers_info { + struct msm_vidc_buffers input; + struct msm_vidc_buffers output; + struct msm_vidc_buffers read_only; + struct msm_vidc_buffers input_meta; + struct msm_vidc_buffers output_meta; + struct msm_vidc_buffers bin; + struct msm_vidc_buffers arp; + struct msm_vidc_buffers comv; + struct msm_vidc_buffers non_comv; + struct msm_vidc_buffers line; + struct msm_vidc_buffers dpb; + struct msm_vidc_buffers persist; + struct msm_vidc_buffers vpss; + struct msm_vidc_buffers partial_data; +}; + +struct buf_queue { + struct vb2_queue *vb2q; +}; + +struct msm_vidc_inst { + struct list_head list; + struct mutex lock; + struct mutex ctx_q_lock; + struct mutex client_lock; + enum msm_vidc_state state; + int (*event_handle)(struct msm_vidc_inst *inst, + enum msm_vidc_event event, + void *data); + enum msm_vidc_sub_state sub_state; + char sub_state_name[MAX_NAME_LENGTH]; + enum msm_vidc_domain_type domain; + enum msm_vidc_codec_type codec; + void *core; + struct kref kref; + u32 session_id; + u8 debug_str[24]; + void *packet; + u32 packet_size; + struct v4l2_format fmts[MAX_PORT]; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_fh fh; + struct v4l2_m2m_dev *m2m_dev; + struct v4l2_m2m_ctx *m2m_ctx; + u32 num_ctrls; + enum hfi_rate_control hfi_rc_type; + enum hfi_layer_encoding_type hfi_layer_type; + bool request; + struct buf_queue bufq[MAX_PORT]; + struct msm_vidc_rectangle crop; + struct msm_vidc_rectangle compose; + struct msm_vidc_power power; + struct vidc_bus_vote_data bus_data; + struct msm_memory_pool pool[MSM_MEM_POOL_MAX]; + struct msm_vidc_buffers_info buffers; + struct msm_vidc_mem_list_info mem_info; + struct msm_vidc_timestamps timestamps; + struct msm_vidc_timestamps ts_reorder; /* struct msm_vidc_timestamp */ + struct msm_vidc_subscription_params subcr_params[MAX_PORT]; + struct msm_vidc_hfi_frame_info hfi_frame_info; + struct msm_vidc_decode_batch decode_batch; + struct msm_vidc_decode_vpp_delay decode_vpp_delay; + struct msm_vidc_session_idle session_idle; + struct delayed_work stats_work; + struct work_struct stability_work; + struct msm_vidc_stability stability; + struct workqueue_struct *workq; + struct list_head enc_input_crs; + struct list_head dmabuf_tracker; /* struct msm_memory_dmabuf */ + struct list_head input_timer_list; /* struct msm_vidc_input_timer */ + struct list_head caps_list; + struct list_head children_list; /* struct msm_vidc_inst_cap_entry */ + struct list_head firmware_list; /* struct msm_vidc_inst_cap_entry */ + struct list_head pending_pkts; /* struct hfi_pending_packet */ + struct list_head fence_list; /* struct msm_vidc_fence */ + struct list_head buffer_stats_list; /* struct msm_vidc_buffer_stats */ + bool once_per_session_set; + bool ipsc_properties_set; + bool opsc_properties_set; + bool caps_list_prepared; + struct dentry *debugfs_root; + struct msm_vidc_debug debug; + struct debug_buf_count debug_count; + struct msm_vidc_statistics stats; + struct msm_vidc_inst_cap capabilities[INST_CAP_MAX + 1]; + struct completion completions[MAX_SIGNAL]; + struct msm_vidc_fence_context fence_context; + bool active; + u64 last_qbuf_time_ns; + u64 initial_time_us; + u32 max_input_data_size; + u32 dpb_list_payload[MAX_DPB_LIST_ARRAY_SIZE]; + bool input_dpb_list_enabled; + bool output_dpb_list_enabled; + u32 auto_framerate; + u32 max_rate; + bool has_bframe; + bool ir_enabled; + u32 adjust_priority; + bool iframe; + u32 fw_min_count; +}; + +#endif // _MSM_VIDC_INST_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_internal.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_internal.h new file mode 100644 index 0000000000..e59a5de452 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_internal.h @@ -0,0 +1,1058 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_INTERNAL_H_ +#define _MSM_VIDC_INTERNAL_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct msm_vidc_inst; + +/* start of vidc specific colorspace definitions */ +/* + * V4L2_COLORSPACE_VIDC_START, V4L2_XFER_FUNC_VIDC_START + * and V4L2_YCBCR_VIDC_START are introduced because + * V4L2_COLORSPACE_LAST, V4L2_XFER_FUNC_LAST, and + * V4L2_YCBCR_ENC_LAST respectively are not accessible + * in userspace. These values are needed in userspace + * to check if the colorspace info is private. + */ +#define V4L2_COLORSPACE_VIDC_START 100 +#define V4L2_COLORSPACE_VIDC_GENERIC_FILM 101 +#define V4L2_COLORSPACE_VIDC_EG431 102 +#define V4L2_COLORSPACE_VIDC_EBU_TECH 103 + +#define V4L2_XFER_FUNC_VIDC_START 200 +#define V4L2_XFER_FUNC_VIDC_BT470_SYSTEM_M 201 +#define V4L2_XFER_FUNC_VIDC_BT470_SYSTEM_BG 202 +#define V4L2_XFER_FUNC_VIDC_BT601_525_OR_625 203 +#define V4L2_XFER_FUNC_VIDC_LINEAR 204 +#define V4L2_XFER_FUNC_VIDC_XVYCC 205 +#define V4L2_XFER_FUNC_VIDC_BT1361 206 +#define V4L2_XFER_FUNC_VIDC_BT2020 207 +#define V4L2_XFER_FUNC_VIDC_ST428 208 +#define V4L2_XFER_FUNC_VIDC_HLG 209 + +/* should be 255 or below due to u8 limitation */ +#define V4L2_YCBCR_VIDC_START 240 +#define V4L2_YCBCR_VIDC_SRGB_OR_SMPTE_ST428 241 +#define V4L2_YCBCR_VIDC_FCC47_73_682 242 +/* end of vidc specific colorspace definitions */ + +/* TODO : remove once available in mainline kernel */ +#ifndef V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE +#define V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE (3) +#endif + +enum msm_vidc_blur_types { + MSM_VIDC_BLUR_NONE = 0x0, + MSM_VIDC_BLUR_EXTERNAL = 0x1, + MSM_VIDC_BLUR_ADAPTIVE = 0x2, +}; + +/* various Metadata - encoder & decoder */ +enum msm_vidc_metadata_bits { + MSM_VIDC_META_DISABLE = 0x0, + MSM_VIDC_META_ENABLE = 0x1, + MSM_VIDC_META_TX_INPUT = 0x2, + MSM_VIDC_META_TX_OUTPUT = 0x4, + MSM_VIDC_META_RX_INPUT = 0x8, + MSM_VIDC_META_RX_OUTPUT = 0x10, + MSM_VIDC_META_DYN_ENABLE = 0x20, + MSM_VIDC_META_MAX = 0x40, +}; + +#define MSM_VIDC_METADATA_SIZE (4 * 4096) /* 16 KB */ +#define ENCODE_INPUT_METADATA_SIZE (512 * 4096) /* 2 MB */ +#define DECODE_INPUT_METADATA_SIZE MSM_VIDC_METADATA_SIZE +#define MSM_VIDC_METADATA_DOLBY_RPU_SIZE (41 * 1024) /* 41 KB */ + +#define MAX_NAME_LENGTH 128 +#define VENUS_VERSION_LENGTH 128 +#define MAX_MATRIX_COEFFS 9 +#define MAX_BIAS_COEFFS 3 +#define MAX_LIMIT_COEFFS 6 +#define MAX_DEBUGFS_NAME 50 +#define DEFAULT_HEIGHT 240 +#define DEFAULT_WIDTH 320 +#define DEFAULT_FPS 30 +#define MAXIMUM_VP9_FPS 60 +#define NRT_PRIORITY_OFFSET 2 +#define RT_DEC_DOWN_PRORITY_OFFSET 1 +#define MAX_SUPPORTED_INSTANCES 16 +#define DEFAULT_BSE_VPP_DELAY 2 +#define MAX_CAP_PARENTS 20 +#define MAX_CAP_CHILDREN 20 +#define DEFAULT_MAX_HOST_BUF_COUNT 64 +#define DEFAULT_MAX_HOST_BURST_BUF_COUNT 256 +#define BIT_DEPTH_8 (8 << 16 | 8) +#define BIT_DEPTH_10 (10 << 16 | 10) +#define CODED_FRAMES_PROGRESSIVE 0x0 +#define CODED_FRAMES_INTERLACE 0x1 +#define MAX_VP9D_INST_COUNT 6 +/* TODO: move below macros to waipio.c */ +#define MAX_ENH_LAYER_HB 3 +#define MAX_HEVC_VBR_ENH_LAYER_SLIDING_WINDOW 5 +#define MAX_HEVC_NON_VBR_ENH_LAYER_SLIDING_WINDOW 3 +#define MAX_AVC_ENH_LAYER_SLIDING_WINDOW 3 +#define MAX_AVC_ENH_LAYER_HYBRID_HP 5 +#define INVALID_DEFAULT_MARK_OR_USE_LTR -1 +#define MAX_SLICES_PER_FRAME 10 +#define MAX_SLICES_FRAME_RATE 60 +#define MAX_MB_SLICE_WIDTH 4096 +#define MAX_MB_SLICE_HEIGHT 2160 +#define MAX_BYTES_SLICE_WIDTH 1920 +#define MAX_BYTES_SLICE_HEIGHT 1088 +#define MIN_HEVC_SLICE_WIDTH 384 +#define MIN_AVC_SLICE_WIDTH 192 +#define MIN_SLICE_HEIGHT 128 +#define MAX_BITRATE_BOOST 25 +#define MAX_SUPPORTED_MIN_QUALITY 70 +#define MIN_CHROMA_QP_OFFSET -12 +#define MAX_CHROMA_QP_OFFSET 0 +#define MIN_QP_10BIT -11 +#define MIN_QP_8BIT 1 +#define INVALID_FD -1 +#define INVALID_CLIENT_ID -1 +#define MAX_ENCODING_REFERNCE_FRAMES 7 +#define MAX_LTR_FRAME_COUNT_5 5 +#define MAX_LTR_FRAME_COUNT_2 2 +#define MAX_ENC_RING_BUF_COUNT 5 /* to be tuned */ +#define MAX_TRANSCODING_STATS_FRAME_RATE 60 +#define MAX_TRANSCODING_STATS_WIDTH 4096 +#define MAX_TRANSCODING_STATS_HEIGHT 2304 +#define HEIC_GRID_WIDTH 512 + +#define DCVS_WINDOW 16 +#define ENC_FPS_WINDOW 3 +#define DEC_FPS_WINDOW 10 +#define INPUT_TIMER_LIST_SIZE 30 + +#define DEFAULT_COMPLEXITY 50 + +#define INPUT_MPLANE V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE +#define OUTPUT_MPLANE V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE +#define INPUT_META_PLANE V4L2_BUF_TYPE_META_OUTPUT +#define OUTPUT_META_PLANE V4L2_BUF_TYPE_META_CAPTURE + +#define VIDC_IFACEQ_MAX_PKT_SIZE 1024 +#define VIDC_IFACEQ_MED_PKT_SIZE 768 +#define VIDC_IFACEQ_MIN_PKT_SIZE 8 +#define VIDC_IFACEQ_VAR_SMALL_PKT_SIZE 100 +#define VIDC_IFACEQ_VAR_LARGE_PKT_SIZE 512 +#define VIDC_IFACEQ_VAR_HUGE_PKT_SIZE (1024 * 4) + +#define NUM_MBS_PER_SEC(__height, __width, __fps) \ + (NUM_MBS_PER_FRAME(__height, __width) * __fps) + +#define NUM_MBS_PER_FRAME(__height, __width) \ + ((ALIGN(__height, 16) / 16) * (ALIGN(__width, 16) / 16)) + +#ifdef V4L2_CTRL_CLASS_CODEC +#define IS_PRIV_CTRL(idx) ( \ + (V4L2_CTRL_ID2WHICH(idx) == V4L2_CTRL_CLASS_CODEC) && \ + V4L2_CTRL_DRIVER_PRIV(idx)) +#else +#define IS_PRIV_CTRL(idx) ( \ + (V4L2_CTRL_ID2WHICH(idx) == V4L2_CTRL_CLASS_MPEG) && \ + V4L2_CTRL_DRIVER_PRIV(idx)) +#endif + +#define BUFFER_ALIGNMENT_SIZE(x) x +#define NUM_MBS_360P (((480 + 15) >> 4) * ((360 + 15) >> 4)) +#define NUM_MBS_720P (((1280 + 15) >> 4) * ((720 + 15) >> 4)) +#define NUM_MBS_4k (((4096 + 15) >> 4) * ((2304 + 15) >> 4)) +#define MB_SIZE_IN_PIXEL (16 * 16) + +#define DB_H264_DISABLE_SLICE_BOUNDARY \ + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY + +#define DB_HEVC_DISABLE_SLICE_BOUNDARY \ + V4L2_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY + +/* + * Convert Q16 number into Integer and Fractional part upto 2 places. + * Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752; + * Integer part = 105752 / 65536 = 1; + * Reminder = 105752 * 0xFFFF = 40216; Last 16 bits. + * Fractional part = 40216 * 100 / 65536 = 61; + * Now convert to FP(1, 61, 100). + */ +#define Q16_INT(q) ((q) >> 16) +#define Q16_FRAC(q) ((((q) & 0xFFFF) * 100) >> 16) + +/* define timeout values */ +#define HW_RESPONSE_TIMEOUT_VALUE (1000) +#define SW_PC_DELAY_VALUE (HW_RESPONSE_TIMEOUT_VALUE + 500) +#define FW_UNLOAD_DELAY_VALUE (SW_PC_DELAY_VALUE + 1500) + +#define MAX_DPB_COUNT 32 + /* + * max dpb count in firmware = 16 + * each dpb: 4 words - + * dpb list array size = 16 * 4 + * dpb payload size = 16 * 4 * 4 + */ +#define MAX_DPB_LIST_ARRAY_SIZE (16 * 4) +#define MAX_DPB_LIST_PAYLOAD_SIZE (16 * 4 * 4) + +#define GENERATE_ENUM(ENUM) ENUM, +#define GENERATE_STRING(STRING) (#STRING), + +/* append MSM_VIDC_ to prepare enum */ +#define GENERATE_MSM_VIDC_ENUM(ENUM) MSM_VIDC_##ENUM, + +/* append MSM_VIDC_BUF_ to prepare enum */ +#define GENERATE_MSM_VIDC_BUF_ENUM(ENUM) MSM_VIDC_BUF_##ENUM, + +/** + * msm_vidc_prepare_dependency_list() api will prepare caps_list by looping over + * enums(msm_vidc_inst_capability_type) from 0 to INST_CAP_MAX and arranges the + * node in such a way that parents willbe at the front and dependent children + * in the back. + * + * caps_list preparation may become CPU intensive task, so to save CPU cycles, + * organize enum in proper order(leaf caps at the beginning and dependent parent caps + * at back), so that during caps_list preparation num CPU cycles spent will reduce. + * + * Note: It will work, if enum kept at different places, but not efficient. + * + * - place all metadata cap(META_*) af the front. + * - place all leaf(no child) enums before PROFILE cap. + * - place all intermittent(having both parent and child) enums before FRAME_WIDTH cap. + * - place all root(no parent) enums before INST_CAP_MAX cap. + */ +#define FOREACH_CAP(CAP) { \ + CAP(INST_CAP_NONE) \ + CAP(META_SEQ_HDR_NAL) \ + CAP(META_BITSTREAM_RESOLUTION) \ + CAP(META_CROP_OFFSETS) \ + CAP(META_DPB_MISR) \ + CAP(META_OPB_MISR) \ + CAP(META_INTERLACE) \ + CAP(META_OUTBUF_FENCE) \ + CAP(META_LTR_MARK_USE) \ + CAP(META_TIMESTAMP) \ + CAP(META_CONCEALED_MB_CNT) \ + CAP(META_HIST_INFO) \ + CAP(META_PICTURE_TYPE) \ + CAP(META_SEI_MASTERING_DISP) \ + CAP(META_SEI_CLL) \ + CAP(META_HDR10PLUS) \ + CAP(META_BUF_TAG) \ + CAP(META_DPB_TAG_LIST) \ + CAP(META_SUBFRAME_OUTPUT) \ + CAP(META_ENC_QP_METADATA) \ + CAP(META_DEC_QP_METADATA) \ + CAP(META_MAX_NUM_REORDER_FRAMES) \ + CAP(META_EVA_STATS) \ + CAP(META_ROI_INFO) \ + CAP(META_SALIENCY_INFO) \ + CAP(META_TRANSCODING_STAT_INFO) \ + CAP(META_DOLBY_RPU) \ + CAP(DRV_VERSION) \ + CAP(MIN_FRAME_QP) \ + CAP(MAX_FRAME_QP) \ + CAP(I_FRAME_QP) \ + CAP(P_FRAME_QP) \ + CAP(B_FRAME_QP) \ + CAP(TIME_DELTA_BASED_RC) \ + CAP(CONSTANT_QUALITY) \ + CAP(VBV_DELAY) \ + CAP(PEAK_BITRATE) \ + CAP(ENTROPY_MODE) \ + CAP(TRANSFORM_8X8) \ + CAP(STAGE) \ + CAP(LTR_COUNT) \ + CAP(IR_PERIOD) \ + CAP(BITRATE_BOOST) \ + CAP(BLUR_RESOLUTION) \ + CAP(OUTPUT_ORDER) \ + CAP(INPUT_BUF_HOST_MAX_COUNT) \ + CAP(OUTPUT_BUF_HOST_MAX_COUNT) \ + CAP(DELIVERY_MODE) \ + CAP(VUI_TIMING_INFO) \ + CAP(SLICE_DECODE) \ + CAP(INBUF_FENCE_TYPE) \ + CAP(OUTBUF_FENCE_TYPE) \ + CAP(INBUF_FENCE_DIRECTION) \ + CAP(OUTBUF_FENCE_DIRECTION) \ + CAP(PROFILE) \ + CAP(ENH_LAYER_COUNT) \ + CAP(BIT_RATE) \ + CAP(LOWLATENCY_MODE) \ + CAP(GOP_SIZE) \ + CAP(B_FRAME) \ + CAP(ALL_INTRA) \ + CAP(MIN_QUALITY) \ + CAP(CONTENT_ADAPTIVE_CODING) \ + CAP(BLUR_TYPES) \ + CAP(REQUEST_PREPROCESS) \ + CAP(SLICE_MODE) \ + CAP(FRAME_WIDTH) \ + CAP(LOSSLESS_FRAME_WIDTH) \ + CAP(SECURE_FRAME_WIDTH) \ + CAP(FRAME_HEIGHT) \ + CAP(LOSSLESS_FRAME_HEIGHT) \ + CAP(SECURE_FRAME_HEIGHT) \ + CAP(PIX_FMTS) \ + CAP(MIN_BUFFERS_INPUT) \ + CAP(MIN_BUFFERS_OUTPUT) \ + CAP(MBPF) \ + CAP(BATCH_MBPF) \ + CAP(BATCH_FPS) \ + CAP(LOSSLESS_MBPF) \ + CAP(SECURE_MBPF) \ + CAP(FRAME_RATE) \ + CAP(OPERATING_RATE) \ + CAP(INPUT_RATE) \ + CAP(TIMESTAMP_RATE) \ + CAP(SCALE_FACTOR) \ + CAP(MB_CYCLES_VSP) \ + CAP(MB_CYCLES_VPP) \ + CAP(MB_CYCLES_LP) \ + CAP(MB_CYCLES_FW) \ + CAP(MB_CYCLES_FW_VPP) \ + CAP(ENC_RING_BUFFER_COUNT) \ + CAP(CLIENT_ID) \ + CAP(SECURE_MODE) \ + CAP(FENCE_ID) \ + CAP(FENCE_FD) \ + CAP(FENCE_ERROR_DATA_CORRUPT) \ + CAP(TS_REORDER) \ + CAP(HFLIP) \ + CAP(VFLIP) \ + CAP(ROTATION) \ + CAP(SUPER_FRAME) \ + CAP(HEADER_MODE) \ + CAP(PREPEND_SPSPPS_TO_IDR) \ + CAP(WITHOUT_STARTCODE) \ + CAP(NAL_LENGTH_FIELD) \ + CAP(REQUEST_I_FRAME) \ + CAP(BITRATE_MODE) \ + CAP(LOSSLESS) \ + CAP(FRAME_SKIP_MODE) \ + CAP(FRAME_RC_ENABLE) \ + CAP(GOP_CLOSURE) \ + CAP(CSC) \ + CAP(CSC_CUSTOM_MATRIX) \ + CAP(USE_LTR) \ + CAP(MARK_LTR) \ + CAP(BASELAYER_PRIORITY) \ + CAP(IR_TYPE) \ + CAP(AU_DELIMITER) \ + CAP(GRID_ENABLE) \ + CAP(GRID_SIZE) \ + CAP(I_FRAME_MIN_QP) \ + CAP(P_FRAME_MIN_QP) \ + CAP(B_FRAME_MIN_QP) \ + CAP(I_FRAME_MAX_QP) \ + CAP(P_FRAME_MAX_QP) \ + CAP(B_FRAME_MAX_QP) \ + CAP(LAYER_TYPE) \ + CAP(LAYER_ENABLE) \ + CAP(L0_BR) \ + CAP(L1_BR) \ + CAP(L2_BR) \ + CAP(L3_BR) \ + CAP(L4_BR) \ + CAP(L5_BR) \ + CAP(LEVEL) \ + CAP(HEVC_TIER) \ + CAP(AV1_TIER) \ + CAP(DISPLAY_DELAY_ENABLE) \ + CAP(DISPLAY_DELAY) \ + CAP(CONCEAL_COLOR_8BIT) \ + CAP(CONCEAL_COLOR_10BIT) \ + CAP(LF_MODE) \ + CAP(LF_ALPHA) \ + CAP(LF_BETA) \ + CAP(SLICE_MAX_BYTES) \ + CAP(SLICE_MAX_MB) \ + CAP(MB_RC) \ + CAP(CHROMA_QP_INDEX_OFFSET) \ + CAP(PIPE) \ + CAP(POC) \ + CAP(MAX_NUM_REORDER_FRAMES) \ + CAP(CODED_FRAMES) \ + CAP(BIT_DEPTH) \ + CAP(CODEC_CONFIG) \ + CAP(BITSTREAM_SIZE_OVERWRITE) \ + CAP(THUMBNAIL_MODE) \ + CAP(DEFAULT_HEADER) \ + CAP(RAP_FRAME) \ + CAP(SEQ_CHANGE_AT_SYNC_FRAME) \ + CAP(QUALITY_MODE) \ + CAP(PRIORITY) \ + CAP(FIRMWARE_PRIORITY_OFFSET) \ + CAP(CRITICAL_PRIORITY) \ + CAP(RESERVE_DURATION) \ + CAP(FILM_GRAIN) \ + CAP(SUPER_BLOCK) \ + CAP(DRAP) \ + CAP(ENC_IP_CR) \ + CAP(COMPLEXITY) \ + CAP(CABAC_MAX_BITRATE) \ + CAP(CAVLC_MAX_BITRATE) \ + CAP(ALLINTRA_MAX_BITRATE) \ + CAP(LOWLATENCY_MAX_BITRATE) \ + CAP(LAST_FLAG_EVENT_ENABLE) \ + CAP(NUM_COMV) \ + CAP(SIGNAL_COLOR_INFO) \ + CAP(INST_CAP_MAX) \ +} + +#define FOREACH_BUF_TYPE(BUF_TYPE) { \ + BUF_TYPE(NONE) \ + BUF_TYPE(INPUT) \ + BUF_TYPE(OUTPUT) \ + BUF_TYPE(INPUT_META) \ + BUF_TYPE(OUTPUT_META) \ + BUF_TYPE(READ_ONLY) \ + BUF_TYPE(INTERFACE_QUEUE) \ + BUF_TYPE(BIN) \ + BUF_TYPE(ARP) \ + BUF_TYPE(COMV) \ + BUF_TYPE(NON_COMV) \ + BUF_TYPE(LINE) \ + BUF_TYPE(DPB) \ + BUF_TYPE(PERSIST) \ + BUF_TYPE(VPSS) \ + BUF_TYPE(PARTIAL_DATA) \ +} + +#define FOREACH_ALLOW(ALLOW) { \ + ALLOW(MSM_VIDC_DISALLOW) \ + ALLOW(MSM_VIDC_ALLOW) \ + ALLOW(MSM_VIDC_DEFER) \ + ALLOW(MSM_VIDC_DISCARD) \ + ALLOW(MSM_VIDC_IGNORE) \ +} + +enum msm_vidc_domain_type { + MSM_VIDC_ENCODER = BIT(0), + MSM_VIDC_DECODER = BIT(1), +}; + +enum msm_vidc_codec_type { + MSM_VIDC_H264 = BIT(0), + MSM_VIDC_HEVC = BIT(1), + MSM_VIDC_VP9 = BIT(2), + MSM_VIDC_HEIC = BIT(3), + MSM_VIDC_AV1 = BIT(4), +}; + +enum msm_vidc_colorformat_type { + MSM_VIDC_FMT_NONE = 0, + MSM_VIDC_FMT_NV12C = BIT(0), + MSM_VIDC_FMT_NV12 = BIT(1), + MSM_VIDC_FMT_NV21 = BIT(2), + MSM_VIDC_FMT_TP10C = BIT(3), + MSM_VIDC_FMT_P010 = BIT(4), + MSM_VIDC_FMT_RGBA8888C = BIT(5), + MSM_VIDC_FMT_RGBA8888 = BIT(6), + MSM_VIDC_FMT_META = BIT(31), +}; + +enum msm_vidc_buffer_type FOREACH_BUF_TYPE(GENERATE_MSM_VIDC_BUF_ENUM); + +/* always match with v4l2 flags V4L2_BUF_FLAG_* */ +enum msm_vidc_buffer_flags { + MSM_VIDC_BUF_FLAG_KEYFRAME = 0x00000008, + MSM_VIDC_BUF_FLAG_PFRAME = 0x00000010, + MSM_VIDC_BUF_FLAG_BFRAME = 0x00000020, + MSM_VIDC_BUF_FLAG_ERROR = 0x00000040, + MSM_VIDC_BUF_FLAG_LAST = 0x00100000, + /* codec config is a vendor specific flag */ + MSM_VIDC_BUF_FLAG_CODECCONFIG = 0x01000000, + /* sub frame is a vendor specific flag */ + MSM_VIDC_BUF_FLAG_SUBFRAME = 0x02000000, +}; + +enum msm_vidc_buffer_attributes { + MSM_VIDC_ATTR_DEFERRED = BIT(0), + MSM_VIDC_ATTR_READ_ONLY = BIT(1), + MSM_VIDC_ATTR_PENDING_RELEASE = BIT(2), + MSM_VIDC_ATTR_QUEUED = BIT(3), + MSM_VIDC_ATTR_DEQUEUED = BIT(4), + MSM_VIDC_ATTR_BUFFER_DONE = BIT(5), + MSM_VIDC_ATTR_RELEASE_ELIGIBLE = BIT(6), +}; + +enum msm_vidc_buffer_region { + MSM_VIDC_REGION_NONE = 0, + MSM_VIDC_NON_SECURE, + MSM_VIDC_NON_SECURE_PIXEL, + MSM_VIDC_SECURE_PIXEL, + MSM_VIDC_SECURE_NONPIXEL, + MSM_VIDC_SECURE_BITSTREAM, + MSM_VIDC_REGION_MAX, +}; + +enum msm_vidc_device_region { + MSM_VIDC_DEVICE_REGION_NONE = 0, + MSM_VIDC_AON, + MSM_VIDC_PROTOCOL_FENCE_CLIENT_VPU, + MSM_VIDC_QTIMER, + MSM_VIDC_DEVICE_REGION_MAX, +}; + +enum msm_vidc_port_type { + INPUT_PORT = 0, + OUTPUT_PORT, + INPUT_META_PORT, + OUTPUT_META_PORT, + PORT_NONE, + MAX_PORT, +}; + +enum msm_vidc_stage_type { + MSM_VIDC_STAGE_NONE = 0, + MSM_VIDC_STAGE_1 = 1, + MSM_VIDC_STAGE_2 = 2, +}; + +enum msm_vidc_pipe_type { + MSM_VIDC_PIPE_NONE = 0, + MSM_VIDC_PIPE_1 = 1, + MSM_VIDC_PIPE_2 = 2, + MSM_VIDC_PIPE_4 = 4, +}; + +enum msm_vidc_quality_mode { + MSM_VIDC_MAX_QUALITY_MODE = 0x1, + MSM_VIDC_POWER_SAVE_MODE = 0x2, +}; + +enum msm_vidc_color_primaries { + MSM_VIDC_PRIMARIES_RESERVED = 0, + MSM_VIDC_PRIMARIES_BT709 = 1, + MSM_VIDC_PRIMARIES_UNSPECIFIED = 2, + MSM_VIDC_PRIMARIES_BT470_SYSTEM_M = 4, + MSM_VIDC_PRIMARIES_BT470_SYSTEM_BG = 5, + MSM_VIDC_PRIMARIES_BT601_525 = 6, + MSM_VIDC_PRIMARIES_SMPTE_ST240M = 7, + MSM_VIDC_PRIMARIES_GENERIC_FILM = 8, + MSM_VIDC_PRIMARIES_BT2020 = 9, + MSM_VIDC_PRIMARIES_SMPTE_ST428_1 = 10, + MSM_VIDC_PRIMARIES_SMPTE_RP431_2 = 11, + MSM_VIDC_PRIMARIES_SMPTE_EG431_1 = 12, + MSM_VIDC_PRIMARIES_SMPTE_EBU_TECH = 22, +}; + +enum msm_vidc_transfer_characteristics { + MSM_VIDC_TRANSFER_RESERVED = 0, + MSM_VIDC_TRANSFER_BT709 = 1, + MSM_VIDC_TRANSFER_UNSPECIFIED = 2, + MSM_VIDC_TRANSFER_BT470_SYSTEM_M = 4, + MSM_VIDC_TRANSFER_BT470_SYSTEM_BG = 5, + MSM_VIDC_TRANSFER_BT601_525_OR_625 = 6, + MSM_VIDC_TRANSFER_SMPTE_ST240M = 7, + MSM_VIDC_TRANSFER_LINEAR = 8, + MSM_VIDC_TRANSFER_LOG_100_1 = 9, + MSM_VIDC_TRANSFER_LOG_SQRT = 10, + MSM_VIDC_TRANSFER_XVYCC = 11, + MSM_VIDC_TRANSFER_BT1361_0 = 12, + MSM_VIDC_TRANSFER_SRGB_SYCC = 13, + MSM_VIDC_TRANSFER_BT2020_14 = 14, + MSM_VIDC_TRANSFER_BT2020_15 = 15, + MSM_VIDC_TRANSFER_SMPTE_ST2084_PQ = 16, + MSM_VIDC_TRANSFER_SMPTE_ST428_1 = 17, + MSM_VIDC_TRANSFER_BT2100_2_HLG = 18, +}; + +enum msm_vidc_matrix_coefficients { + MSM_VIDC_MATRIX_COEFF_SRGB_SMPTE_ST428_1 = 0, + MSM_VIDC_MATRIX_COEFF_BT709 = 1, + MSM_VIDC_MATRIX_COEFF_UNSPECIFIED = 2, + MSM_VIDC_MATRIX_COEFF_RESERVED = 3, + MSM_VIDC_MATRIX_COEFF_FCC_TITLE_47 = 4, + MSM_VIDC_MATRIX_COEFF_BT470_SYS_BG_OR_BT601_625 = 5, + MSM_VIDC_MATRIX_COEFF_BT601_525_BT1358_525_OR_625 = 6, + MSM_VIDC_MATRIX_COEFF_SMPTE_ST240 = 7, + MSM_VIDC_MATRIX_COEFF_YCGCO = 8, + MSM_VIDC_MATRIX_COEFF_BT2020_NON_CONSTANT = 9, + MSM_VIDC_MATRIX_COEFF_BT2020_CONSTANT = 10, + MSM_VIDC_MATRIX_COEFF_SMPTE_ST2085 = 11, + MSM_VIDC_MATRIX_COEFF_SMPTE_CHROM_DERV_NON_CONSTANT = 12, + MSM_VIDC_MATRIX_COEFF_SMPTE_CHROM_DERV_CONSTANT = 13, + MSM_VIDC_MATRIX_COEFF_BT2100 = 14, +}; + +enum msm_vidc_preprocess_type { + MSM_VIDC_PREPROCESS_NONE = BIT(0), + MSM_VIDC_PREPROCESS_TYPE0 = BIT(1), +}; + +enum msm_vidc_core_capability_type { + CORE_CAP_NONE = 0, + ENC_CODECS, + DEC_CODECS, + MAX_SESSION_COUNT, + MAX_NUM_720P_SESSIONS, + MAX_NUM_1080P_SESSIONS, + MAX_NUM_4K_SESSIONS, + MAX_NUM_8K_SESSIONS, + MAX_SECURE_SESSION_COUNT, + MAX_LOAD, + MAX_RT_MBPF, + MAX_MBPF, + MAX_MBPS, + MAX_IMAGE_MBPF, + MAX_MBPF_HQ, + MAX_MBPS_HQ, + MAX_MBPF_B_FRAME, + MAX_MBPS_B_FRAME, + MAX_MBPS_ALL_INTRA, + MAX_ENH_LAYER_COUNT, + NUM_VPP_PIPE, + SW_PC, + SW_PC_DELAY, + FW_UNLOAD, + FW_UNLOAD_DELAY, + HW_RESPONSE_TIMEOUT, + PREFIX_BUF_COUNT_PIX, + PREFIX_BUF_SIZE_PIX, + PREFIX_BUF_COUNT_NON_PIX, + PREFIX_BUF_SIZE_NON_PIX, + PAGEFAULT_NON_FATAL, + PAGETABLE_CACHING, + DCVS, + DECODE_BATCH, + DECODE_BATCH_TIMEOUT, + STATS_TIMEOUT_MS, + AV_SYNC_WINDOW_SIZE, + CLK_FREQ_THRESHOLD, + NON_FATAL_FAULTS, + ENC_AUTO_FRAMERATE, + DEVICE_CAPS, + SUPPORTS_REQUESTS, + SUPPORTS_SYNX_FENCE, + SSR_TYPE, + CORE_CAP_MAX, +}; + +enum msm_vidc_inst_capability_type FOREACH_CAP(GENERATE_ENUM); + +enum msm_vidc_inst_capability_flags { + CAP_FLAG_NONE = 0, + CAP_FLAG_DYNAMIC_ALLOWED = BIT(0), + CAP_FLAG_MENU = BIT(1), + CAP_FLAG_INPUT_PORT = BIT(2), + CAP_FLAG_OUTPUT_PORT = BIT(3), + CAP_FLAG_CLIENT_SET = BIT(4), + CAP_FLAG_BITMASK = BIT(5), + CAP_FLAG_VOLATILE = BIT(6), + CAP_FLAG_META = BIT(7), +}; + +struct msm_vidc_inst_cap { + enum msm_vidc_inst_capability_type cap_id; + s32 min; + s32 max; + u32 step_or_mask; + s32 value; + u32 v4l2_id; + u32 hfi_id; + enum msm_vidc_inst_capability_flags flags; + enum msm_vidc_inst_capability_type children[MAX_CAP_CHILDREN]; + int (*adjust)(void *inst, + struct v4l2_ctrl *ctrl); + int (*set)(void *inst, + enum msm_vidc_inst_capability_type cap_id); +}; + +struct msm_vidc_inst_capability { + enum msm_vidc_domain_type domain; + enum msm_vidc_codec_type codec; + struct msm_vidc_inst_cap cap[INST_CAP_MAX + 1]; +}; + +struct msm_vidc_core_capability { + enum msm_vidc_core_capability_type type; + u32 value; +}; + +struct msm_vidc_inst_cap_entry { + /* list of struct msm_vidc_inst_cap_entry */ + struct list_head list; + enum msm_vidc_inst_capability_type cap_id; +}; + +struct msm_vidc_event_data { + union { + bool bval; + u32 uval; + u64 uval64; + s32 val; + s64 val64; + void *ptr; + } edata; +}; + +struct debug_buf_count { + u64 etb; + u64 ftb; + u64 fbd; + u64 ebd; +}; + +struct msm_vidc_statistics { + struct debug_buf_count count; + u64 data_size; + u64 time_ms; + u32 avg_bw_llcc; + u32 avg_bw_ddr; +}; + +enum efuse_purpose { + SKU_VERSION = 0, +}; + +enum sku_version { + SKU_VERSION_0 = 0, + SKU_VERSION_1, + SKU_VERSION_2, +}; + +enum msm_vidc_ssr_trigger_type { + SSR_ERR_FATAL = 1, + SSR_SW_DIV_BY_ZERO, + SSR_HW_WDOG_IRQ, +}; + +enum msm_vidc_stability_trigger_type { + STABILITY_VCODEC_HUNG = 1, + STABILITY_ENC_BUFFER_FULL, +}; + +enum msm_vidc_cache_op { + MSM_VIDC_CACHE_CLEAN, + MSM_VIDC_CACHE_INVALIDATE, + MSM_VIDC_CACHE_CLEAN_INVALIDATE, +}; + +enum msm_vidc_dcvs_flags { + MSM_VIDC_DCVS_INCR = BIT(0), + MSM_VIDC_DCVS_DECR = BIT(1), +}; + +enum msm_vidc_clock_properties { + CLOCK_PROP_HAS_SCALING = BIT(0), + CLOCK_PROP_HAS_MEM_RETENTION = BIT(1), +}; + +enum profiling_points { + FRAME_PROCESSING = 0, + MAX_PROFILING_POINTS, +}; + +enum signal_session_response { + SIGNAL_CMD_STOP_INPUT = 0, + SIGNAL_CMD_STOP_OUTPUT, + SIGNAL_CMD_CLOSE, + MAX_SIGNAL, +}; + +struct profile_data { + u64 start; + u64 stop; + u64 cumulative; + char name[64]; + u32 sampling; + u64 average; +}; + +struct msm_vidc_debug { + struct profile_data pdata[MAX_PROFILING_POINTS]; + u32 profile; + u32 samples; +}; + +struct msm_vidc_input_cr_data { + struct list_head list; + u32 index; + u32 input_cr; +}; + +struct msm_vidc_session_idle { + bool idle; + u64 last_activity_time_ns; +}; + +struct msm_vidc_color_info { + u32 colorspace; + u32 ycbcr_enc; + u32 xfer_func; + u32 quantization; +}; + +struct msm_vidc_rectangle { + u32 left; + u32 top; + u32 width; + u32 height; +}; + +struct msm_vidc_subscription_params { + u32 bitstream_resolution; + u32 crop_offsets[2]; + u32 bit_depth; + u32 coded_frames; + u32 fw_min_count; + u32 pic_order_cnt; + u32 color_info; + u32 profile; + u32 level; + u32 tier; + u32 av1_film_grain_present; + u32 av1_super_block_enabled; + u32 max_num_reorder_frames; +}; + +struct msm_vidc_hfi_frame_info { + u32 picture_type; + u32 no_output; + u32 subframe_input; + u32 cr; + u32 cf; + u32 data_corrupt; + u32 overflow; + u32 fence_id; + u32 fence_error; + u32 av1_tile_rows_columns; + bool av1_non_uniform_tile_spacing; +}; + +struct msm_vidc_decode_vpp_delay { + bool enable; + u32 size; +}; + +struct msm_vidc_decode_batch { + bool enable; + u32 size; + struct delayed_work work; +}; + +enum msm_vidc_power_mode { + VIDC_POWER_NORMAL = 0, + VIDC_POWER_LOW, + VIDC_POWER_TURBO, +}; + +struct vidc_bus_vote_data { + enum msm_vidc_domain_type domain; + enum msm_vidc_codec_type codec; + enum msm_vidc_power_mode power_mode; + u32 color_formats[2]; + int num_formats; /* 1 = DPB-OPB unified; 2 = split */ + int input_height, input_width, bitrate; + int output_height, output_width; + int rotation; + int compression_ratio; + int complexity_factor; + int input_cr; + u32 lcu_size; + u32 fps; + u32 work_mode; + bool use_sys_cache; + bool b_frames_enabled; + u64 calc_bw_ddr; + u64 calc_bw_llcc; + u32 num_vpp_pipes; + bool vpss_preprocessing_enabled; +}; + +struct msm_vidc_power { + enum msm_vidc_power_mode power_mode; + u32 buffer_counter; + u32 min_threshold; + u32 nom_threshold; + u32 max_threshold; + bool dcvs_mode; + u32 dcvs_window; + u64 min_freq; + u64 curr_freq; + u32 ddr_bw; + u32 sys_cache_bw; + u32 dcvs_flags; + u32 fw_cr; + u32 fw_cf; + u32 fw_av1_tile_rows; + u32 fw_av1_tile_columns; +}; + +enum msm_vidc_fence_type { + MSM_VIDC_FENCE_NONE = 0, + MSM_VIDC_SW_FENCE = 1, + MSM_VIDC_SYNX_V2_FENCE = 2, +}; + +enum msm_vidc_fence_direction { + MSM_VIDC_FENCE_DIR_NONE = 0, + MSM_VIDC_FENCE_DIR_TX = 1, + MSM_VIDC_FENCE_DIR_RX = 2, +}; + +struct msm_vidc_fence_context { + char name[MAX_NAME_LENGTH]; + u64 ctx_num; + u64 seq_num; +}; + +struct msm_vidc_fence { + struct list_head list; + struct dma_fence dma_fence; + char name[MAX_NAME_LENGTH]; + spinlock_t lock; + struct sync_file *sync_file; + int fd; + u64 fence_id; + void *session; +}; + +struct msm_vidc_mem { + struct list_head list; + enum msm_vidc_buffer_type type; + enum msm_vidc_buffer_region region; + u32 size; + u8 secure:1; + u8 map_kernel:1; + struct dma_buf *dmabuf; + /* + * Kalama uses Kernel Version 5.15.x, + * Pineapple uses Kernel version 5.18.x + */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) + struct iosys_map dmabuf_map; +#elif (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)) + struct dma_buf_map dmabuf_map; +#endif + void *kvaddr; + dma_addr_t device_addr; + unsigned long attrs; + u32 refcount; + struct sg_table *table; + struct dma_buf_attachment *attach; + phys_addr_t phys_addr; + enum dma_data_direction direction; +}; + +struct msm_vidc_mem_list { + struct list_head list; // list of "struct msm_vidc_mem" +}; + +struct msm_vidc_buffer { + struct list_head list; + struct msm_vidc_inst *inst; + enum msm_vidc_buffer_type type; + enum msm_vidc_buffer_region region; + u32 index; + int fd; + u32 buffer_size; + u32 data_offset; + u32 data_size; + u64 device_addr; + u32 flags; + u64 timestamp; + enum msm_vidc_buffer_attributes attr; + void *dmabuf; + struct sg_table *sg_table; + struct dma_buf_attachment *attach; + u32 dbuf_get:1; + u64 fence_id; + u32 start_time_ms; + u32 end_time_ms; +}; + +struct msm_vidc_buffers { + struct list_head list; // list of "struct msm_vidc_buffer" + u32 min_count; + u32 extra_count; + u32 actual_count; + u32 size; + bool reuse; +}; + +struct msm_vidc_buffer_stats { + struct list_head list; + u32 frame_num; + u64 timestamp; + u32 etb_time_ms; + u32 ebd_time_ms; + u32 ftb_time_ms; + u32 fbd_time_ms; + u32 data_size; + u32 flags; + u32 ts_offset; +}; + +enum msm_vidc_buffer_stats_flag { + MSM_VIDC_STATS_FLAG_CORRUPT = BIT(0), + MSM_VIDC_STATS_FLAG_OVERFLOW = BIT(1), + MSM_VIDC_STATS_FLAG_NO_OUTPUT = BIT(2), + MSM_VIDC_STATS_FLAG_SUBFRAME_INPUT = BIT(3), +}; + +struct msm_vidc_sort { + struct list_head list; + s64 val; +}; + +struct msm_vidc_timestamp { + struct msm_vidc_sort sort; + u64 rank; +}; + +struct msm_vidc_timestamps { + struct list_head list; + u32 count; + u64 rank; +}; + +struct msm_vidc_input_timer { + struct list_head list; + u64 time_us; +}; + +enum msm_vidc_allow FOREACH_ALLOW(GENERATE_ENUM); + +struct msm_vidc_ssr { + enum msm_vidc_ssr_trigger_type ssr_type; + u32 sub_client_id; + u32 test_addr; +}; + +struct msm_vidc_stability { + enum msm_vidc_stability_trigger_type stability_type; + u32 sub_client_id; + u32 value; +}; + +struct msm_vidc_sfr { + u32 buf_size; + u8 rg_data[1]; +}; + +struct msm_vidc_ctrl_data { + bool skip_s_ctrl; +}; + +#endif // _MSM_VIDC_INTERNAL_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_memory.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_memory.h new file mode 100644 index 0000000000..508d166375 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_memory.h @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_MEMORY_H_ +#define _MSM_VIDC_MEMORY_H_ + +#include "msm_vidc_internal.h" + +struct msm_vidc_core; +struct msm_vidc_inst; + +#define MSM_MEM_POOL_PACKET_SIZE 1024 + +struct msm_memory_dmabuf { + struct list_head list; + struct dma_buf *dmabuf; + u32 refcount; +}; + +enum msm_memory_pool_type { + MSM_MEM_POOL_BUFFER = 0, + MSM_MEM_POOL_ALLOC_MAP, + MSM_MEM_POOL_TIMESTAMP, + MSM_MEM_POOL_DMABUF, + MSM_MEM_POOL_PACKET, + MSM_MEM_POOL_BUF_TIMER, + MSM_MEM_POOL_BUF_STATS, + MSM_MEM_POOL_MAX, +}; + +struct msm_memory_alloc_header { + struct list_head list; + u32 type; + bool busy; + void *buf; +}; + +struct msm_memory_pool { + u32 size; + char *name; + struct list_head free_pool; /* list of struct msm_memory_alloc_header */ + struct list_head busy_pool; /* list of struct msm_memory_alloc_header */ +}; + +void *msm_vidc_pool_alloc(struct msm_vidc_inst *inst, + enum msm_memory_pool_type type); +void msm_vidc_pool_free(struct msm_vidc_inst *inst, void *vidc_buf); +int msm_vidc_pools_init(struct msm_vidc_inst *inst); +void msm_vidc_pools_deinit(struct msm_vidc_inst *inst); + +#define call_mem_op(c, op, ...) \ + (((c) && (c)->mem_ops && (c)->mem_ops->op) ? \ + ((c)->mem_ops->op(__VA_ARGS__)) : 0) + +struct msm_vidc_memory_ops { + struct dma_buf *(*dma_buf_get)(struct msm_vidc_inst *inst, + int fd); + void (*dma_buf_put)(struct msm_vidc_inst *inst, + struct dma_buf *dmabuf); + void (*dma_buf_put_completely)(struct msm_vidc_inst *inst, + struct msm_memory_dmabuf *buf); + struct dma_buf_attachment *(*dma_buf_attach)(struct msm_vidc_core *core, + struct dma_buf *dbuf, struct device *dev); + int (*dma_buf_detach)(struct msm_vidc_core *core, struct dma_buf *dbuf, + struct dma_buf_attachment *attach); + struct sg_table + *(*dma_buf_map_attachment)(struct msm_vidc_core *core, + struct dma_buf_attachment *attach); + int (*dma_buf_unmap_attachment)(struct msm_vidc_core *core, + struct dma_buf_attachment *attach, + struct sg_table *table); + int (*memory_alloc_map)(struct msm_vidc_core *core, + struct msm_vidc_mem *mem); + int (*memory_unmap_free)(struct msm_vidc_core *core, + struct msm_vidc_mem *mem); + int (*mem_dma_map_page)(struct msm_vidc_core *core, + struct msm_vidc_mem *mem); + int (*mem_dma_unmap_page)(struct msm_vidc_core *core, + struct msm_vidc_mem *mem); + u32 (*buffer_region)(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type); + int (*iommu_map)(struct msm_vidc_core *core, + struct msm_vidc_mem *mem); + int (*iommu_unmap)(struct msm_vidc_core *core, + struct msm_vidc_mem *mem); +}; + +const struct msm_vidc_memory_ops *get_mem_ops(void); + +#endif // _MSM_VIDC_MEMORY_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_memory_ext.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_memory_ext.h new file mode 100644 index 0000000000..de4f9d0d0a --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_memory_ext.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_MEMORY_EXT_H_ +#define _MSM_VIDC_MEMORY_EXT_H_ + +#include "msm_vidc_memory.h" + +const struct msm_vidc_memory_ops *get_mem_ops_ext(void); + +#endif // _MSM_VIDC_MEMORY_EXT_H_ \ No newline at end of file diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_power.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_power.h new file mode 100644 index 0000000000..b408a6b8df --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_power.h @@ -0,0 +1,257 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_POWER_H_ +#define _MSM_VIDC_POWER_H_ + +#include "fixedpoint.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_inst.h" + +#define COMPRESSION_RATIO_MAX 5 + +/* TODO: Move to dtsi OR use source clock instead of branch clock.*/ +#define MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO 3 + +enum vidc_bus_type { + PERF, + DDR, + LLCC, +}; + +/* + * Minimum dimensions for which to calculate bandwidth. + * This means that anything bandwidth(0, 0) == + * bandwidth(BASELINE_DIMENSIONS.width, BASELINE_DIMENSIONS.height) + */ +static const struct { + int height, width; +} BASELINE_DIMENSIONS = { + .width = 1280, + .height = 720, +}; + +/* converts Mbps to bps (the "b" part can be bits or bytes based on context) */ +#define kbps(__mbps) ((__mbps) * 1000) +#define bps(__mbps) (kbps(__mbps) * 1000) + +#define GENERATE_COMPRESSION_PROFILE(__bpp, __worst) { \ + .bpp = __bpp, \ + .ratio = __worst, \ +} + +/* + * The below table is a structural representation of the following table: + * Resolution | Bitrate | Compression Ratio | + * ............|............|.........................................| + * Width Height|Average High|Avg_8bpc Worst_8bpc Avg_10bpc Worst_10bpc| + * 1280 720| 7 14| 1.69 1.28 1.49 1.23| + * 1920 1080| 20 40| 1.69 1.28 1.49 1.23| + * 2560 1440| 32 64| 2.2 1.26 1.97 1.22| + * 3840 2160| 42 84| 2.2 1.26 1.97 1.22| + * 4096 2160| 44 88| 2.2 1.26 1.97 1.22| + * 4096 2304| 48 96| 2.2 1.26 1.97 1.22| + */ +static struct lut { + int frame_size; /* width x height */ + int frame_rate; + unsigned long bitrate; + struct { + int bpp; + fp_t ratio; + } compression_ratio[COMPRESSION_RATIO_MAX]; +} const LUT[] = { + { + .frame_size = 1280 * 720, + .frame_rate = 30, + .bitrate = 14, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 28, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 23, 100)), + } + }, + { + .frame_size = 1280 * 720, + .frame_rate = 60, + .bitrate = 22, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 28, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 23, 100)), + } + }, + { + .frame_size = 1920 * 1088, + .frame_rate = 30, + .bitrate = 40, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 28, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 23, 100)), + } + }, + { + .frame_size = 1920 * 1088, + .frame_rate = 60, + .bitrate = 64, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 28, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 23, 100)), + } + }, + { + .frame_size = 2560 * 1440, + .frame_rate = 30, + .bitrate = 64, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 2560 * 1440, + .frame_rate = 60, + .bitrate = 102, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 3840 * 2160, + .frame_rate = 30, + .bitrate = 84, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 3840 * 2160, + .frame_rate = 60, + .bitrate = 134, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 4096 * 2160, + .frame_rate = 30, + .bitrate = 88, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 4096 * 2160, + .frame_rate = 60, + .bitrate = 141, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 4096 * 2304, + .frame_rate = 30, + .bitrate = 96, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, + { + .frame_size = 4096 * 2304, + .frame_rate = 60, + .bitrate = 154, + .compression_ratio = { + GENERATE_COMPRESSION_PROFILE(8, + FP(1, 26, 100)), + GENERATE_COMPRESSION_PROFILE(10, + FP(1, 22, 100)), + } + }, +}; + +static inline u32 get_type_frm_name(const char *name) +{ + if (!strcmp(name, "venus-llcc")) + return LLCC; + else if (!strcmp(name, "venus-ddr")) + return DDR; + else + return PERF; +} + +#define DUMP_HEADER_MAGIC 0xdeadbeef +#define DUMP_FP_FMT "%FP" /* special format for fp_t */ + +struct dump { + char *key; + char *format; + size_t val; +}; + +struct lut const *__lut(int width, int height, int fps); +fp_t __compression_ratio(struct lut const *entry, int bpp); +void __dump(struct dump dump[], int len); + +static inline bool __ubwc(enum msm_vidc_colorformat_type f) +{ + switch (f) { + case MSM_VIDC_FMT_NV12C: + case MSM_VIDC_FMT_TP10C: + return true; + default: + return false; + } +} + +static inline int __bpp(enum msm_vidc_colorformat_type f) +{ + switch (f) { + case MSM_VIDC_FMT_NV12: + case MSM_VIDC_FMT_NV21: + case MSM_VIDC_FMT_NV12C: + case MSM_VIDC_FMT_RGBA8888C: + return 8; + case MSM_VIDC_FMT_P010: + case MSM_VIDC_FMT_TP10C: + return 10; + default: + d_vpr_e("Unsupported colorformat (%x)", f); + return INT_MAX; + } +} + +u64 msm_vidc_max_freq(struct msm_vidc_inst *inst); +int msm_vidc_scale_power(struct msm_vidc_inst *inst, bool scale_buses); +void msm_vidc_power_data_reset(struct msm_vidc_inst *inst); + +#endif diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_state.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_state.h new file mode 100644 index 0000000000..a382a6c7aa --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_state.h @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_STATE_H_ +#define _MSM_VIDC_STATE_H_ + +#include "msm_vidc_internal.h" + +struct msm_vidc_core; + +#define FOREACH_CORE_STATE(CORE_STATE) { \ + CORE_STATE(CORE_DEINIT) \ + CORE_STATE(CORE_INIT_WAIT) \ + CORE_STATE(CORE_INIT) \ + CORE_STATE(CORE_ERROR) \ +} + +#define FOREACH_EVENT(EVENT) { \ + EVENT(TRY_FMT) \ + EVENT(S_FMT) \ + EVENT(REQBUFS) \ + EVENT(S_CTRL) \ + EVENT(STREAMON) \ + EVENT(STREAMOFF) \ + EVENT(CMD_START) \ + EVENT(CMD_STOP) \ + EVENT(BUF_QUEUE) \ +} + +enum msm_vidc_core_state FOREACH_CORE_STATE(GENERATE_MSM_VIDC_ENUM); + +enum msm_vidc_core_sub_state { + CORE_SUBSTATE_NONE = 0x0, + CORE_SUBSTATE_POWER_ENABLE = BIT(0), + CORE_SUBSTATE_GDSC_HANDOFF = BIT(1), + CORE_SUBSTATE_PM_SUSPEND = BIT(2), + CORE_SUBSTATE_FW_PWR_CTRL = BIT(3), + CORE_SUBSTATE_PAGE_FAULT = BIT(4), + CORE_SUBSTATE_CPU_WATCHDOG = BIT(5), + CORE_SUBSTATE_VIDEO_UNRESPONSIVE = BIT(6), + CORE_SUBSTATE_MAX = BIT(7), +}; + +enum msm_vidc_core_event_type { + CORE_EVENT_NONE = BIT(0), + CORE_EVENT_UPDATE_SUB_STATE = BIT(1), +}; + +#define FOREACH_STATE(STATE) { \ + STATE(OPEN) \ + STATE(INPUT_STREAMING) \ + STATE(OUTPUT_STREAMING) \ + STATE(STREAMING) \ + STATE(CLOSE) \ + STATE(ERROR) \ +} + +enum msm_vidc_state FOREACH_STATE(GENERATE_MSM_VIDC_ENUM); + +#define MSM_VIDC_SUB_STATE_NONE 0 +#define MSM_VIDC_MAX_SUB_STATES 7 +/* + * max value of inst->sub_state if all + * the 6 valid bits are set i.e 111111==>63 + */ +#define MSM_VIDC_MAX_SUB_STATE_VALUE ((1 << MSM_VIDC_MAX_SUB_STATES) - 1) + +enum msm_vidc_sub_state { + MSM_VIDC_DRAIN = BIT(0), + MSM_VIDC_DRC = BIT(1), + MSM_VIDC_DRAIN_LAST_BUFFER = BIT(2), + MSM_VIDC_DRC_LAST_BUFFER = BIT(3), + MSM_VIDC_INPUT_PAUSE = BIT(4), + MSM_VIDC_OUTPUT_PAUSE = BIT(5), + MSM_VIDC_FIRST_IPSC = BIT(6), +}; + +enum msm_vidc_event FOREACH_EVENT(GENERATE_MSM_VIDC_ENUM); + +/* core statemachine functions */ +enum msm_vidc_allow + msm_vidc_allow_core_state_change(struct msm_vidc_core *core, + enum msm_vidc_core_state req_state); +int msm_vidc_update_core_state(struct msm_vidc_core *core, + enum msm_vidc_core_state request_state, + const char *func); +bool core_in_valid_state(struct msm_vidc_core *core); +bool is_core_state(struct msm_vidc_core *core, enum msm_vidc_core_state state); +bool is_core_sub_state(struct msm_vidc_core *core, + enum msm_vidc_core_sub_state sub_state); +const char *core_state_name(enum msm_vidc_core_state state); +const char *core_sub_state_name(enum msm_vidc_core_sub_state sub_state); + +/* inst statemachine functions */ +bool is_drc_pending(struct msm_vidc_inst *inst); +bool is_drain_pending(struct msm_vidc_inst *inst); +int msm_vidc_update_state(struct msm_vidc_inst *inst, + enum msm_vidc_state request_state, + const char *func); +int msm_vidc_change_state(struct msm_vidc_inst *inst, + enum msm_vidc_state request_state, + const char *func); +int msm_vidc_change_sub_state(struct msm_vidc_inst *inst, + enum msm_vidc_sub_state clear_sub_state, + enum msm_vidc_sub_state set_sub_state, + const char *func); +const char *state_name(enum msm_vidc_state state); +const char *sub_state_name(enum msm_vidc_sub_state sub_state); +bool is_state(struct msm_vidc_inst *inst, enum msm_vidc_state state); +bool is_sub_state(struct msm_vidc_inst *inst, + enum msm_vidc_sub_state sub_state); + +#endif // _MSM_VIDC_STATE_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_synx.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_synx.h new file mode 100644 index 0000000000..75e1705cac --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_synx.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _H_MSM_VIDC_SYNX_H_ +#define _H_MSM_VIDC_SYNX_H_ + +#include "msm_vidc_fence.h" + +const struct msm_vidc_fence_ops *get_synx_fence_ops(void); + +#endif //_H_MSM_VIDC_SYNX_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_v4l2.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_v4l2.h new file mode 100644 index 0000000000..fb86ed6b7c --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_v4l2.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_V4L2_H_ +#define _MSM_VIDC_V4L2_H_ + +#include +#include +#include +#include +#include + +int msm_v4l2_open(struct file *filp); +int msm_v4l2_close(struct file *filp); +int msm_v4l2_querycap(struct file *filp, void *fh, + struct v4l2_capability *cap); +int msm_v4l2_enum_fmt(struct file *file, void *fh, + struct v4l2_fmtdesc *f); +int msm_v4l2_try_fmt(struct file *file, void *fh, + struct v4l2_format *f); +int msm_v4l2_s_fmt(struct file *file, void *fh, + struct v4l2_format *f); +int msm_v4l2_g_fmt(struct file *file, void *fh, + struct v4l2_format *f); +int msm_v4l2_s_selection(struct file *file, void *fh, + struct v4l2_selection *s); +int msm_v4l2_g_selection(struct file *file, void *fh, + struct v4l2_selection *s); +int msm_v4l2_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *a); +int msm_v4l2_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *a); +int msm_v4l2_reqbufs(struct file *file, void *fh, + struct v4l2_requestbuffers *b); +int msm_v4l2_querybuf(struct file *file, void *fh, + struct v4l2_buffer *b); +int msm_v4l2_create_bufs(struct file *filp, void *fh, + struct v4l2_create_buffers *b); +int msm_v4l2_prepare_buf(struct file *filp, void *fh, + struct v4l2_buffer *b); +int msm_v4l2_qbuf(struct file *file, void *fh, + struct v4l2_buffer *b); +int msm_v4l2_dqbuf(struct file *file, void *fh, + struct v4l2_buffer *b); +int msm_v4l2_streamon(struct file *file, void *fh, + enum v4l2_buf_type i); +int msm_v4l2_streamoff(struct file *file, void *fh, + enum v4l2_buf_type i); +int msm_v4l2_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub); +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub); +int msm_v4l2_try_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *enc); +int msm_v4l2_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *dec); +int msm_v4l2_try_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *enc); +int msm_v4l2_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *enc); +int msm_v4l2_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize); +int msm_v4l2_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *fival); +int msm_v4l2_queryctrl(struct file *file, void *fh, + struct v4l2_queryctrl *ctrl); +int msm_v4l2_querymenu(struct file *file, void *fh, + struct v4l2_querymenu *qmenu); +unsigned int msm_v4l2_poll(struct file *filp, + struct poll_table_struct *pt); +int msm_v4l2_request_validate(struct media_request *req); +void msm_v4l2_request_queue(struct media_request *req); +void msm_v4l2_m2m_device_run(void *priv); +void msm_v4l2_m2m_job_abort(void *priv); + +#endif // _MSM_VIDC_V4L2_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_vb2.h b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_vb2.h new file mode 100644 index 0000000000..e162bb1c87 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/msm_vidc_vb2.h @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_VB2_H_ +#define _MSM_VIDC_VB2_H_ + +#include +#include +#include "msm_vidc_inst.h" + +struct vb2_queue *msm_vidc_get_vb2q(struct msm_vidc_inst *inst, + u32 type, const char *func); + +/* vb2_mem_ops */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) +void *msm_vb2_alloc(struct device *dev, unsigned long attrs, + unsigned long size, enum dma_data_direction dma_dir, + gfp_t gfp_flags); +void *msm_vb2_attach_dmabuf(struct device *dev, + struct dma_buf *dbuf, + unsigned long size, + enum dma_data_direction dma_dir); +#else +void *msm_vb2_alloc(struct vb2_buffer *vb, struct device *dev, + unsigned long size); +void *msm_vb2_attach_dmabuf(struct vb2_buffer *vb, struct device *dev, + struct dma_buf *dbuf, unsigned long size); +#endif + +void msm_vb2_put(void *buf_priv); +int msm_vb2_mmap(void *buf_priv, struct vm_area_struct *vma); +void msm_vb2_detach_dmabuf(void *buf_priv); +int msm_vb2_map_dmabuf(void *buf_priv); +void msm_vb2_unmap_dmabuf(void *buf_priv); + +/* vb2_ops */ +int msm_vb2_queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]); +int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q); +int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q); +int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count); +void msm_vb2_stop_streaming(struct vb2_queue *q); +void msm_vb2_buf_queue(struct vb2_buffer *vb2); +int msm_vb2_buf_out_validate(struct vb2_buffer *vb); +void msm_vb2_request_complete(struct vb2_buffer *vb); +#endif // _MSM_VIDC_VB2_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/resources.h b/qcom/opensource/video-driver/driver/vidc/inc/resources.h new file mode 100644 index 0000000000..e461742f5d --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/resources.h @@ -0,0 +1,293 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _MSM_VIDC_RESOURCES_H_ +#define _MSM_VIDC_RESOURCES_H_ + +struct icc_path; +struct regulator; +struct clk; +struct reset_control; +struct llcc_slice_desc; +struct iommu_domain; +struct device; +struct msm_vidc_core; + +/* + * These are helper macros to iterate over various lists within + * msm_vidc_core->resource. The intention is to cut down on a lot + * of boiler-plate code + */ + +/* Read as "for each 'thing' in a set of 'thingies'" */ +#define venus_hfi_for_each_thing(__device, __thing, __thingy) \ + venus_hfi_for_each_thing_continue(__device, __thing, __thingy, 0) + +#define venus_hfi_for_each_thing_reverse(__device, __thing, __thingy) \ + venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \ + (__device)->resource->__thingy##_set.count - 1) + +/* TODO: the __from parameter technically not required since we can figure it + * out with some pointer magic (i.e. __thing - __thing##_tbl[0]). If this macro + * sees extensive use, probably worth cleaning it up but for now omitting it + * since it introduces unnecessary complexity. + */ +#define venus_hfi_for_each_thing_continue(__device, __thing, __thingy, __from) \ + for (__thing = &(__device)->resource->\ + __thingy##_set.__thingy##_tbl[__from]; \ + __thing < &(__device)->resource->__thingy##_set.__thingy##_tbl[0] + \ + ((__device)->resource->__thingy##_set.count - __from); \ + ++__thing) + +#define venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \ + __from) \ + for (__thing = &(__device)->resource->\ + __thingy##_set.__thingy##_tbl[__from]; \ + __thing >= &(__device)->resource->__thingy##_set.__thingy##_tbl[0]; \ + --__thing) + +/* Bus set helpers */ +#define venus_hfi_for_each_bus(__device, __binfo) \ + venus_hfi_for_each_thing(__device, __binfo, bus) +#define venus_hfi_for_each_bus_reverse(__device, __binfo) \ + venus_hfi_for_each_thing_reverse(__device, __binfo, bus) + +/* Regular set helpers */ +#define venus_hfi_for_each_regulator(__device, __rinfo) \ + venus_hfi_for_each_thing(__device, __rinfo, regulator) +#define venus_hfi_for_each_regulator_reverse(__device, __rinfo) \ + venus_hfi_for_each_thing_reverse(__device, __rinfo, regulator) +#define venus_hfi_for_each_regulator_reverse_continue(__device, __rinfo, \ + __from) \ + venus_hfi_for_each_thing_reverse_continue(__device, __rinfo, \ + regulator, __from) + +/* Power domain set helpers */ +#define venus_hfi_for_each_power_domain(__device, __pdinfo) \ + venus_hfi_for_each_thing(__device, __pdinfo, power_domain) + +/* Clock set helpers */ +#define venus_hfi_for_each_clock(__device, __cinfo) \ + venus_hfi_for_each_thing(__device, __cinfo, clock) +#define venus_hfi_for_each_clock_reverse(__device, __cinfo) \ + venus_hfi_for_each_thing_reverse(__device, __cinfo, clock) + +/* Reset clock set helpers */ +#define venus_hfi_for_each_reset_clock(__device, __rcinfo) \ + venus_hfi_for_each_thing(__device, __rcinfo, reset) +#define venus_hfi_for_each_reset_clock_reverse(__device, __rcinfo) \ + venus_hfi_for_each_thing_reverse(__device, __rcinfo, reset) +#define venus_hfi_for_each_reset_clock_reverse_continue(__device, __rinfo, \ + __from) \ + venus_hfi_for_each_thing_reverse_continue(__device, __rinfo, \ + reset, __from) + +/* Subcache set helpers */ +#define venus_hfi_for_each_subcache(__device, __sinfo) \ + venus_hfi_for_each_thing(__device, __sinfo, subcache) +#define venus_hfi_for_each_subcache_reverse(__device, __sinfo) \ + venus_hfi_for_each_thing_reverse(__device, __sinfo, subcache) + +/* Contextbank set helpers */ +#define venus_hfi_for_each_context_bank(__device, __sinfo) \ + venus_hfi_for_each_thing(__device, __sinfo, context_bank) +#define venus_hfi_for_each_context_bank_reverse(__device, __sinfo) \ + venus_hfi_for_each_thing_reverse(__device, __sinfo, context_bank) + +/* Device region set helper */ +#define venus_hfi_for_each_device_region(__device, __sinfo) \ + venus_hfi_for_each_thing(__device, __sinfo, device_region) + +enum msm_vidc_branch_mem_flags { + MSM_VIDC_CLKFLAG_RETAIN_PERIPH, + MSM_VIDC_CLKFLAG_NORETAIN_PERIPH, + MSM_VIDC_CLKFLAG_RETAIN_MEM, + MSM_VIDC_CLKFLAG_NORETAIN_MEM, + MSM_VIDC_CLKFLAG_PERIPH_OFF_SET, + MSM_VIDC_CLKFLAG_PERIPH_OFF_CLEAR, +}; + +struct bus_info { + struct icc_path *icc; + const char *name; + u32 min_kbps; + u32 max_kbps; +}; + +struct bus_set { + struct bus_info *bus_tbl; + u32 count; +}; + +struct regulator_info { + struct regulator *regulator; + const char *name; + bool hw_power_collapse; +}; + +struct regulator_set { + struct regulator_info *regulator_tbl; + u32 count; +}; + +struct power_domain_info { + struct device *genpd_dev; + const char *name; +}; + +struct power_domain_set { + struct power_domain_info *power_domain_tbl; + u32 count; +}; + +struct clock_residency { + struct list_head list; + u64 rate; + u64 start_time_us; + u64 total_time_us; +}; + +struct clock_info { + struct clk *clk; + const char *name; + u32 clk_id; + bool has_scaling; + u64 prev; +#ifdef CONFIG_MSM_MMRM + struct mmrm_client *mmrm_client; +#endif + struct list_head residency_list; /* list of struct clock_residency */ +}; + +struct clock_set { + struct clock_info *clock_tbl; + u32 count; +}; + +struct reset_info { + struct reset_control *rst; + const char *name; + bool exclusive_release; +}; + +struct reset_set { + struct reset_info *reset_tbl; + u32 count; +}; + +struct subcache_info { + struct llcc_slice_desc *subcache; + const char *name; + u32 llcc_id; + bool isactive; +}; + +struct subcache_set { + struct subcache_info *subcache_tbl; + u32 count; + bool set_to_fw; +}; + +struct addr_range { + u32 start; + u32 size; +}; + +struct context_bank_info { + const char *name; + struct addr_range addr_range; + bool secure; + bool dma_coherant; + struct device *dev; + struct iommu_domain *domain; + u32 region; + u64 dma_mask; +}; + +struct context_bank_set { + struct context_bank_info *context_bank_tbl; + u32 count; +}; + +struct frequency_table { + unsigned long freq; +}; + +struct freq_set { + struct frequency_table *freq_tbl; + u32 count; +}; + +struct device_region_info { + const char *name; + phys_addr_t phy_addr; + u32 size; + u32 dev_addr; + u32 region; +}; + +struct device_region_set { + struct device_region_info *device_region_tbl; + u32 count; +}; + +struct msm_vidc_resource { + u8 __iomem *register_base_addr; + u32 irq; + struct bus_set bus_set; + struct regulator_set regulator_set; + struct power_domain_set power_domain_set; + struct clock_set clock_set; + struct reset_set reset_set; + struct subcache_set subcache_set; + struct context_bank_set context_bank_set; + struct freq_set freq_set; + struct device_region_set device_region_set; + int fw_cookie; +}; + +#define call_res_op(c, op, ...) \ + (((c) && (c)->res_ops && (c)->res_ops->op) ? \ + ((c)->res_ops->op(__VA_ARGS__)) : 0) + +struct msm_vidc_resources_ops { + int (*init)(struct msm_vidc_core *core); + + int (*reset_bridge)(struct msm_vidc_core *core); + int (*reset_control_acquire)(struct msm_vidc_core *core, + const char *name); + int (*reset_control_release)(struct msm_vidc_core *core, + const char *name); + int (*reset_control_assert)(struct msm_vidc_core *core, + const char *name); + int (*reset_control_deassert)(struct msm_vidc_core *core, + const char *name); + + int (*gdsc_init)(struct msm_vidc_core *core); + int (*gdsc_on)(struct msm_vidc_core *core, const char *name); + int (*gdsc_off)(struct msm_vidc_core *core, const char *name); + int (*gdsc_hw_ctrl)(struct msm_vidc_core *core); + int (*gdsc_sw_ctrl)(struct msm_vidc_core *core); + + int (*llcc)(struct msm_vidc_core *core, bool enable); + int (*set_bw)(struct msm_vidc_core *core, unsigned long bw_ddr, + unsigned long bw_llcc); + int (*set_clks)(struct msm_vidc_core *core, u64 rate); + + int (*clk_disable)(struct msm_vidc_core *core, const char *name); + int (*clk_enable)(struct msm_vidc_core *core, const char *name); + int (*clk_set_flag)(struct msm_vidc_core *core, + const char *name, + enum msm_vidc_branch_mem_flags flag); + int (*clk_print_residency_stats)(struct msm_vidc_core *core); + int (*clk_reset_residency_stats)(struct msm_vidc_core *core); + int (*clk_update_residency_stats)(struct msm_vidc_core *core, + struct clock_info *cl, u64 rate); +}; + +const struct msm_vidc_resources_ops *get_resources_ops(void); + +#endif diff --git a/qcom/opensource/video-driver/driver/vidc/inc/resources_ext.h b/qcom/opensource/video-driver/driver/vidc/inc/resources_ext.h new file mode 100644 index 0000000000..30644b9796 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/resources_ext.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _RESOURCES_EXT_H_ +#define _RESOURCES_EXT_H_ + +struct msm_vidc_resources_ops; + +const struct msm_vidc_resources_ops *get_res_ops_ext(void); + +#endif // _RESOURCES_EXT_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/venus_hfi.h b/qcom/opensource/video-driver/driver/vidc/inc/venus_hfi.h new file mode 100644 index 0000000000..46a8f87b2f --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/venus_hfi.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _VENUS_HFI_H_ +#define _VENUS_HFI_H_ + +#include +#include +#include +#include + +#include "msm_vidc_internal.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" + +#define VIDC_MAX_PC_SKIP_COUNT 10 + +struct vidc_buffer_addr_info { + enum msm_vidc_buffer_type buffer_type; + u32 buffer_size; + u32 num_buffers; + u32 align_device_addr; + u32 extradata_addr; + u32 extradata_size; + u32 response_required; +}; + +struct hfi_pending_packet { + struct list_head list; + void *data; +}; + +int __strict_check(struct msm_vidc_core *core, + const char *function); +int venus_hfi_session_property(struct msm_vidc_inst *inst, + u32 pkt_type, u32 flags, u32 port, + u32 payload_type, void *payload, + u32 payload_size); +int venus_hfi_session_command(struct msm_vidc_inst *inst, + u32 cmd, enum msm_vidc_port_type port, + u32 payload_type, + void *payload, u32 payload_size); +int venus_hfi_queue_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer, + struct msm_vidc_buffer *metabuf); +int venus_hfi_queue_super_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer, + struct msm_vidc_buffer *metabuf); +int venus_hfi_release_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer); +int venus_hfi_start(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); +int venus_hfi_stop(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); +int venus_hfi_session_close(struct msm_vidc_inst *inst); +int venus_hfi_session_open(struct msm_vidc_inst *inst); +int venus_hfi_session_pause(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); +int venus_hfi_session_resume(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port, u32 payload); +int venus_hfi_session_drain(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); +int venus_hfi_session_set_codec(struct msm_vidc_inst *inst); +int venus_hfi_session_set_secure_mode(struct msm_vidc_inst *inst); +int venus_hfi_core_init(struct msm_vidc_core *core); +int venus_hfi_core_deinit(struct msm_vidc_core *core, bool force); +int venus_hfi_noc_error_info(struct msm_vidc_core *core); +int venus_hfi_suspend(struct msm_vidc_core *core); +int venus_hfi_trigger_ssr(struct msm_vidc_core *core, u32 type, + u32 client_id, u32 addr); +int venus_hfi_trigger_stability(struct msm_vidc_inst *inst, u32 type, + u32 client_id, u32 val); +int venus_hfi_reserve_hardware(struct msm_vidc_inst *inst, u32 duration); +int venus_hfi_scale_clocks(struct msm_vidc_inst *inst, u64 freq); +int venus_hfi_scale_buses(struct msm_vidc_inst *inst, u64 bw_ddr, u64 bw_llcc); +int venus_hfi_set_ir_period(struct msm_vidc_inst *inst, u32 ir_type, + enum msm_vidc_inst_capability_type cap_id); +void venus_hfi_pm_work_handler(struct work_struct *work); +irqreturn_t venus_hfi_isr(int irq, void *data); +irqreturn_t venus_hfi_isr_handler(int irq, void *data); +int __prepare_pc(struct msm_vidc_core *core); +struct device_region_info + *venus_hfi_get_device_region_info(struct msm_vidc_core *core, + enum msm_vidc_device_region region); + +#endif // _VENUS_HFI_H_ diff --git a/qcom/opensource/video-driver/driver/vidc/inc/venus_hfi_queue.h b/qcom/opensource/video-driver/driver/vidc/inc/venus_hfi_queue.h new file mode 100644 index 0000000000..83237c201a --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/venus_hfi_queue.h @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef _VENUS_HFI_QUEUE_H_ +#define _VENUS_HFI_QUEUE_H_ + +#include + +#include "msm_vidc_internal.h" + +#define HFI_MASK_QHDR_TX_TYPE 0xff000000 +#define HFI_MASK_QHDR_RX_TYPE 0x00ff0000 +#define HFI_MASK_QHDR_PRI_TYPE 0x0000ff00 +#define HFI_MASK_QHDR_Q_ID_TYPE 0x000000ff +#define HFI_Q_ID_HOST_TO_CTRL_CMD_Q 0 +#define HFI_Q_ID_CTRL_TO_HOST_MSG_Q 1 +#define HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q 2 +#define HFI_MASK_QHDR_STATUS 0x000000ff + +#define VIDC_IFACEQ_NUMQ 3 +#define VIDC_IFACEQ_CMDQ_IDX 0 +#define VIDC_IFACEQ_MSGQ_IDX 1 +#define VIDC_IFACEQ_DBGQ_IDX 2 +#define VIDC_IFACEQ_MAX_BUF_COUNT 50 +#define VIDC_IFACE_MAX_PARALLEL_CLNTS 16 +#define VIDC_IFACEQ_DFLT_QHDR 0x01010000 + +struct hfi_queue_table_header { + u32 qtbl_version; + u32 qtbl_size; + u32 qtbl_qhdr0_offset; + u32 qtbl_qhdr_size; + u32 qtbl_num_q; + u32 qtbl_num_active_q; + void *device_addr; + char name[256]; +}; + +struct hfi_queue_header { + u32 qhdr_status; + u32 qhdr_start_addr; + u32 qhdr_type; + u32 qhdr_q_size; + u32 qhdr_pkt_size; + u32 qhdr_pkt_drop_cnt; + u32 qhdr_rx_wm; + u32 qhdr_tx_wm; + u32 qhdr_rx_req; + u32 qhdr_tx_req; + u32 qhdr_rx_irq_status; + u32 qhdr_tx_irq_status; + u32 qhdr_read_idx; + u32 qhdr_write_idx; +}; + +#define VIDC_IFACEQ_TABLE_SIZE (sizeof(struct hfi_queue_table_header) + \ + sizeof(struct hfi_queue_header) * VIDC_IFACEQ_NUMQ) + +#define VIDC_IFACEQ_QUEUE_SIZE (VIDC_IFACEQ_MAX_PKT_SIZE * \ + VIDC_IFACEQ_MAX_BUF_COUNT * VIDC_IFACE_MAX_PARALLEL_CLNTS) + +#define VIDC_IFACEQ_GET_QHDR_START_ADDR(ptr, i) \ + ((void *)((ptr + sizeof(struct hfi_queue_table_header)) + \ + (i * sizeof(struct hfi_queue_header)))) + +#define QDSS_SIZE 4096 +#define SFR_SIZE 4096 +#define MMAP_BUF_SIZE 4096 + +#define QUEUE_SIZE (VIDC_IFACEQ_TABLE_SIZE + \ + (VIDC_IFACEQ_QUEUE_SIZE * VIDC_IFACEQ_NUMQ)) + +#define ALIGNED_QDSS_SIZE ALIGN(QDSS_SIZE, SZ_4K) +#define ALIGNED_SFR_SIZE ALIGN(SFR_SIZE, SZ_4K) +#define ALIGNED_MMAP_BUF_SIZE ALIGN(MMAP_BUF_SIZE, SZ_4K) +#define ALIGNED_QUEUE_SIZE ALIGN(QUEUE_SIZE, SZ_4K) +#define SHARED_QSIZE ALIGN(ALIGNED_SFR_SIZE + ALIGNED_QUEUE_SIZE + \ + ALIGNED_QDSS_SIZE + ALIGNED_MMAP_BUF_SIZE, SZ_1M) +#define TOTAL_QSIZE (SHARED_QSIZE - ALIGNED_SFR_SIZE - ALIGNED_QDSS_SIZE - \ + ALIGNED_MMAP_BUF_SIZE) + +struct msm_vidc_core; + +int venus_hfi_queue_cmd_write(struct msm_vidc_core *core, void *pkt); +int venus_hfi_queue_cmd_write_intr(struct msm_vidc_core *core, void *pkt, + bool allow_intr); +int venus_hfi_queue_msg_read(struct msm_vidc_core *core, void *pkt); +int venus_hfi_queue_dbg_read(struct msm_vidc_core *core, void *pkt); +void venus_hfi_queue_deinit(struct msm_vidc_core *core); +int venus_hfi_queue_init(struct msm_vidc_core *core); +int venus_hfi_reset_queue_header(struct msm_vidc_core *core); + +#endif diff --git a/qcom/opensource/video-driver/driver/vidc/inc/venus_hfi_response.h b/qcom/opensource/video-driver/driver/vidc/inc/venus_hfi_response.h new file mode 100644 index 0000000000..457059ed97 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/inc/venus_hfi_response.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __VENUS_HFI_RESPONSE_H__ +#define __VENUS_HFI_RESPONSE_H__ + +#include "hfi_packet.h" + +int handle_response(struct msm_vidc_core *core, + void *response); +int validate_packet(u8 *response_pkt, u8 *core_resp_pkt, + u32 core_resp_pkt_size, const char *func); +bool is_valid_port(struct msm_vidc_inst *inst, u32 port, + const char *func); +bool is_valid_hfi_buffer_type(struct msm_vidc_inst *inst, + u32 buffer_type, const char *func); +int handle_system_error(struct msm_vidc_core *core, + struct hfi_packet *pkt); +int handle_release_output_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer); + +#endif // __VENUS_HFI_RESPONSE_H__ diff --git a/qcom/opensource/video-driver/driver/vidc/src/firmware.c b/qcom/opensource/video-driver/driver/vidc/src/firmware.c new file mode 100644 index 0000000000..c11eb55a92 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/firmware.c @@ -0,0 +1,294 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_vidc_core.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_events.h" +#include "msm_vidc_platform.h" +#include "firmware.h" + +#define MAX_FIRMWARE_NAME_SIZE 128 + +struct tzbsp_memprot { + u32 cp_start; + u32 cp_size; + u32 cp_nonpixel_start; + u32 cp_nonpixel_size; +}; + +enum tzbsp_video_state { + TZBSP_VIDEO_STATE_SUSPEND = 0, + TZBSP_VIDEO_STATE_RESUME = 1, + TZBSP_VIDEO_STATE_RESTORE_THRESHOLD = 2, +}; + +static int protect_cp_mem(struct msm_vidc_core *core) +{ + struct tzbsp_memprot memprot; + int rc = 0; + struct context_bank_info *cb; + + memprot.cp_start = 0x0; + memprot.cp_size = 0x0; + memprot.cp_nonpixel_start = 0x0; + memprot.cp_nonpixel_size = 0x0; + + venus_hfi_for_each_context_bank(core, cb) { + if (cb->region == MSM_VIDC_NON_SECURE) { + memprot.cp_size = cb->addr_range.start; + + d_vpr_h("%s: memprot.cp_size: %#x\n", + __func__, memprot.cp_size); + } + + if (cb->region == MSM_VIDC_SECURE_NONPIXEL) { + memprot.cp_nonpixel_start = cb->addr_range.start; + memprot.cp_nonpixel_size = cb->addr_range.size; + + d_vpr_h("%s: cp_nonpixel_start: %#x size: %#x\n", + __func__, memprot.cp_nonpixel_start, + memprot.cp_nonpixel_size); + } + } + + rc = qcom_scm_mem_protect_video_var(memprot.cp_start, memprot.cp_size, + memprot.cp_nonpixel_start, memprot.cp_nonpixel_size); + if (rc) + d_vpr_e("Failed to protect memory(%d)\n", rc); + + trace_venus_hfi_var_done(memprot.cp_start, memprot.cp_size, + memprot.cp_nonpixel_start, memprot.cp_nonpixel_size); + + return rc; +} + +static int __load_fw_to_memory(struct platform_device *pdev, + const char *fw_name) +{ + int rc = 0; + const struct firmware *firmware = NULL; + struct msm_vidc_core *core; + char firmware_name[MAX_FIRMWARE_NAME_SIZE] = { 0 }; + struct device_node *node = NULL; + struct resource res = { 0 }; + phys_addr_t phys = 0; + size_t res_size = 0; + ssize_t fw_size = 0; + void *virt = NULL; + int pas_id = 0; + + if (!fw_name || !(*fw_name) || !pdev) { + d_vpr_e("%s: Invalid inputs\n", __func__); + return -EINVAL; + } + if (strlen(fw_name) >= MAX_FIRMWARE_NAME_SIZE - 4) { + d_vpr_e("%s: Invalid fw name\n", __func__); + return -EINVAL; + } + + core = dev_get_drvdata(&pdev->dev); + if (!core) { + d_vpr_e("%s: core not found in device %s", + __func__, dev_name(&pdev->dev)); + return -EINVAL; + } + scnprintf(firmware_name, ARRAY_SIZE(firmware_name), "%s.mbn", fw_name); + + pas_id = core->platform->data.pas_id; + + node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0); + if (!node) { + d_vpr_e("%s: failed to read \"memory-region\"\n", + __func__); + return -EINVAL; + } + + rc = of_address_to_resource(node, 0, &res); + if (rc) { + d_vpr_e("%s: failed to read \"memory-region\", error %d\n", + __func__, rc); + goto exit; + } + phys = res.start; + res_size = (size_t)resource_size(&res); + + rc = request_firmware(&firmware, firmware_name, &pdev->dev); + if (rc) { + d_vpr_e("%s: failed to request fw \"%s\", error %d\n", + __func__, firmware_name, rc); + goto exit; + } + + fw_size = qcom_mdt_get_size(firmware); + if (fw_size < 0 || res_size < (size_t)fw_size) { + rc = -EINVAL; + d_vpr_e("%s: out of bound fw image fw size: %ld, res_size: %lu", + __func__, fw_size, res_size); + goto exit; + } + + virt = memremap(phys, res_size, MEMREMAP_WC); + if (!virt) { + d_vpr_e("%s: failed to remap fw memory phys %pa[p]\n", + __func__, &phys); + return -ENOMEM; + } + + /* prevent system suspend during fw_load */ + pm_stay_awake(pdev->dev.parent); + rc = qcom_mdt_load(&pdev->dev, firmware, firmware_name, + pas_id, virt, phys, res_size, NULL); + pm_relax(pdev->dev.parent); + if (rc) { + d_vpr_e("%s: error %d loading fw \"%s\"\n", + __func__, rc, firmware_name); + goto exit; + } + rc = qcom_scm_pas_auth_and_reset(pas_id); + if (rc) { + d_vpr_e("%s: error %d authenticating fw \"%s\"\n", + __func__, rc, firmware_name); + goto exit; + } + + memunmap(virt); + release_firmware(firmware); + d_vpr_h("%s: firmware \"%s\" loaded successfully\n", + __func__, firmware_name); + + return pas_id; + +exit: + if (virt) + memunmap(virt); + if (firmware) + release_firmware(firmware); + + return rc; +} + +int fw_load(struct msm_vidc_core *core) +{ + int rc; + + if (!core->resource->fw_cookie) { + core->resource->fw_cookie = __load_fw_to_memory(core->pdev, + core->platform->data.fwname); + if (core->resource->fw_cookie <= 0) { + d_vpr_e("%s: firmware download failed %d\n", + __func__, core->resource->fw_cookie); + core->resource->fw_cookie = 0; + return -ENOMEM; + } + } + + rc = protect_cp_mem(core); + if (rc) { + d_vpr_e("%s: protect memory failed\n", __func__); + goto fail_protect_mem; + } + + return rc; + +fail_protect_mem: + if (core->resource->fw_cookie) + qcom_scm_pas_shutdown(core->resource->fw_cookie); + core->resource->fw_cookie = 0; + return rc; +} + +int fw_unload(struct msm_vidc_core *core) +{ + int ret; + + if (!core->resource->fw_cookie) + return -EINVAL; + + ret = qcom_scm_pas_shutdown(core->resource->fw_cookie); + if (ret) + d_vpr_e("Firmware unload failed rc=%d\n", ret); + + core->resource->fw_cookie = 0; + + return ret; +} + +int fw_suspend(struct msm_vidc_core *core) +{ + return qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_SUSPEND, 0); +} + +int fw_resume(struct msm_vidc_core *core) +{ + return qcom_scm_set_remote_state(TZBSP_VIDEO_STATE_RESUME, 0); +} + +void fw_coredump(struct msm_vidc_core *core) +{ + int rc = 0; + struct platform_device *pdev; + struct device_node *node = NULL; + struct resource res = {0}; + phys_addr_t mem_phys = 0; + size_t res_size = 0; + void *mem_va = NULL; + char *data = NULL, *dump = NULL; + u64 total_size; + + pdev = core->pdev; + + node = of_parse_phandle(pdev->dev.of_node, "memory-region", 0); + if (!node) { + d_vpr_e("%s: DT error getting \"memory-region\" property\n", + __func__); + return; + } + + rc = of_address_to_resource(node, 0, &res); + if (rc) { + d_vpr_e("%s: error %d while getting \"memory-region\" resource\n", + __func__, rc); + return; + } + + mem_phys = res.start; + res_size = (size_t)resource_size(&res); + + mem_va = memremap(mem_phys, res_size, MEMREMAP_WC); + if (!mem_va) { + d_vpr_e("%s: unable to remap firmware memory\n", __func__); + return; + } + total_size = res_size + TOTAL_QSIZE + ALIGNED_SFR_SIZE; + + data = vmalloc(total_size); + if (!data) { + memunmap(mem_va); + return; + } + dump = data; + + /* copy firmware dump */ + memcpy(data, mem_va, res_size); + memunmap(mem_va); + + /* copy queues(cmd, msg, dbg) dump(along with headers) */ + data += res_size; + memcpy(data, (char *)core->iface_q_table.align_virtual_addr, TOTAL_QSIZE); + + /* copy sfr dump */ + data += TOTAL_QSIZE; + memcpy(data, (char *)core->sfr.align_virtual_addr, ALIGNED_SFR_SIZE); + + dev_coredumpv(&pdev->dev, dump, total_size, GFP_KERNEL); +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/hfi_packet.c b/qcom/opensource/video-driver/driver/vidc/src/hfi_packet.c new file mode 100644 index 0000000000..72576ae18b --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/hfi_packet.c @@ -0,0 +1,708 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "hfi_packet.h" +#include "msm_vidc_core.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" + +u32 get_hfi_port(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + u32 hfi_port = HFI_PORT_NONE; + + if (is_decode_session(inst)) { + switch (port) { + case INPUT_PORT: + case INPUT_META_PORT: + hfi_port = HFI_PORT_BITSTREAM; + break; + case OUTPUT_PORT: + case OUTPUT_META_PORT: + hfi_port = HFI_PORT_RAW; + break; + default: + i_vpr_e(inst, "%s: invalid port type %d\n", + __func__, port); + break; + } + } else if (is_encode_session(inst)) { + switch (port) { + case INPUT_PORT: + case INPUT_META_PORT: + hfi_port = HFI_PORT_RAW; + break; + case OUTPUT_PORT: + case OUTPUT_META_PORT: + hfi_port = HFI_PORT_BITSTREAM; + break; + default: + i_vpr_e(inst, "%s: invalid port type %d\n", + __func__, port); + break; + } + } else { + i_vpr_e(inst, "%s: invalid domain %#x\n", + __func__, inst->domain); + } + + return hfi_port; +} + +u32 get_hfi_port_from_buffer_type(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + u32 hfi_port = HFI_PORT_NONE; + + if (is_decode_session(inst)) { + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + case MSM_VIDC_BUF_INPUT_META: + case MSM_VIDC_BUF_BIN: + case MSM_VIDC_BUF_COMV: + case MSM_VIDC_BUF_NON_COMV: + case MSM_VIDC_BUF_LINE: + case MSM_VIDC_BUF_PARTIAL_DATA: + hfi_port = HFI_PORT_BITSTREAM; + break; + case MSM_VIDC_BUF_OUTPUT: + case MSM_VIDC_BUF_OUTPUT_META: + case MSM_VIDC_BUF_DPB: + hfi_port = HFI_PORT_RAW; + break; + case MSM_VIDC_BUF_PERSIST: + hfi_port = HFI_PORT_NONE; + break; + default: + i_vpr_e(inst, "%s: invalid buffer type %d\n", + __func__, buffer_type); + break; + } + } else if (is_encode_session(inst)) { + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + case MSM_VIDC_BUF_INPUT_META: + case MSM_VIDC_BUF_VPSS: + hfi_port = HFI_PORT_RAW; + break; + case MSM_VIDC_BUF_OUTPUT: + case MSM_VIDC_BUF_OUTPUT_META: + case MSM_VIDC_BUF_BIN: + case MSM_VIDC_BUF_COMV: + case MSM_VIDC_BUF_NON_COMV: + case MSM_VIDC_BUF_LINE: + case MSM_VIDC_BUF_DPB: + hfi_port = HFI_PORT_BITSTREAM; + break; + case MSM_VIDC_BUF_ARP: + hfi_port = HFI_PORT_NONE; + break; + default: + i_vpr_e(inst, "%s: invalid buffer type %d\n", + __func__, buffer_type); + break; + } + } else { + i_vpr_e(inst, "%s: invalid domain %#x\n", + __func__, inst->domain); + } + + return hfi_port; +} + +u32 hfi_buf_type_from_driver(enum msm_vidc_domain_type domain, + enum msm_vidc_buffer_type buffer_type) +{ + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + if (domain == MSM_VIDC_DECODER) + return HFI_BUFFER_BITSTREAM; + else + return HFI_BUFFER_RAW; + case MSM_VIDC_BUF_OUTPUT: + if (domain == MSM_VIDC_DECODER) + return HFI_BUFFER_RAW; + else + return HFI_BUFFER_BITSTREAM; + case MSM_VIDC_BUF_INPUT_META: + case MSM_VIDC_BUF_OUTPUT_META: + return HFI_BUFFER_METADATA; + case MSM_VIDC_BUF_BIN: + return HFI_BUFFER_BIN; + case MSM_VIDC_BUF_ARP: + return HFI_BUFFER_ARP; + case MSM_VIDC_BUF_COMV: + return HFI_BUFFER_COMV; + case MSM_VIDC_BUF_NON_COMV: + return HFI_BUFFER_NON_COMV; + case MSM_VIDC_BUF_LINE: + return HFI_BUFFER_LINE; + case MSM_VIDC_BUF_DPB: + return HFI_BUFFER_DPB; + case MSM_VIDC_BUF_PERSIST: + return HFI_BUFFER_PERSIST; + case MSM_VIDC_BUF_VPSS: + return HFI_BUFFER_VPSS; + case MSM_VIDC_BUF_PARTIAL_DATA: + return HFI_BUFFER_PARTIAL_DATA; + default: + d_vpr_e("invalid buffer type %d\n", + buffer_type); + return 0; + } +} + +u32 hfi_buf_type_to_driver(enum msm_vidc_domain_type domain, + enum hfi_buffer_type buffer_type, enum hfi_packet_port_type port_type) +{ + switch (buffer_type) { + case HFI_BUFFER_BITSTREAM: + if (domain == MSM_VIDC_DECODER) + return MSM_VIDC_BUF_INPUT; + else + return MSM_VIDC_BUF_OUTPUT; + case HFI_BUFFER_RAW: + if (domain == MSM_VIDC_DECODER) + return MSM_VIDC_BUF_OUTPUT; + else + return MSM_VIDC_BUF_INPUT; + case HFI_BUFFER_METADATA: + if (domain == MSM_VIDC_DECODER) + if (port_type == HFI_PORT_BITSTREAM) + return MSM_VIDC_BUF_INPUT_META; + else + return MSM_VIDC_BUF_OUTPUT_META; + else + if (port_type == HFI_PORT_BITSTREAM) + return MSM_VIDC_BUF_OUTPUT_META; + else + return MSM_VIDC_BUF_INPUT_META; + case HFI_BUFFER_BIN: + return MSM_VIDC_BUF_BIN; + case HFI_BUFFER_ARP: + return MSM_VIDC_BUF_ARP; + case HFI_BUFFER_COMV: + return MSM_VIDC_BUF_COMV; + case HFI_BUFFER_NON_COMV: + return MSM_VIDC_BUF_NON_COMV; + case HFI_BUFFER_LINE: + return MSM_VIDC_BUF_LINE; + case HFI_BUFFER_DPB: + return MSM_VIDC_BUF_DPB; + case HFI_BUFFER_PERSIST: + return MSM_VIDC_BUF_PERSIST; + case HFI_BUFFER_VPSS: + return MSM_VIDC_BUF_VPSS; + case HFI_BUFFER_PARTIAL_DATA: + return MSM_VIDC_BUF_PARTIAL_DATA; + default: + d_vpr_e("invalid buffer type %d\n", + buffer_type); + return 0; + } +} + +u32 get_hfi_codec(struct msm_vidc_inst *inst) +{ + switch (inst->codec) { + case MSM_VIDC_H264: + if (is_encode_session(inst)) + return HFI_CODEC_ENCODE_AVC; + else + return HFI_CODEC_DECODE_AVC; + case MSM_VIDC_HEVC: + case MSM_VIDC_HEIC: + if (is_encode_session(inst)) + return HFI_CODEC_ENCODE_HEVC; + else + return HFI_CODEC_DECODE_HEVC; + case MSM_VIDC_VP9: + return HFI_CODEC_DECODE_VP9; + case MSM_VIDC_AV1: + return HFI_CODEC_DECODE_AV1; + default: + i_vpr_e(inst, "invalid codec %d, domain %d\n", + inst->codec, inst->domain); + return 0; + } +} + +u32 get_hfi_colorformat(struct msm_vidc_inst *inst, + enum msm_vidc_colorformat_type colorformat) +{ + u32 hfi_colorformat = HFI_COLOR_FMT_NV12_UBWC; + + switch (colorformat) { + case MSM_VIDC_FMT_NV12: + hfi_colorformat = HFI_COLOR_FMT_NV12; + break; + case MSM_VIDC_FMT_NV12C: + hfi_colorformat = HFI_COLOR_FMT_NV12_UBWC; + break; + case MSM_VIDC_FMT_P010: + hfi_colorformat = HFI_COLOR_FMT_P010; + break; + case MSM_VIDC_FMT_TP10C: + hfi_colorformat = HFI_COLOR_FMT_TP10_UBWC; + break; + case MSM_VIDC_FMT_RGBA8888: + hfi_colorformat = HFI_COLOR_FMT_RGBA8888; + break; + case MSM_VIDC_FMT_RGBA8888C: + hfi_colorformat = HFI_COLOR_FMT_RGBA8888_UBWC; + break; + case MSM_VIDC_FMT_NV21: + hfi_colorformat = HFI_COLOR_FMT_NV21; + break; + default: + i_vpr_e(inst, "%s: invalid colorformat %d\n", + __func__, colorformat); + break; + } + + return hfi_colorformat; +} + +static u32 get_hfi_region_flag(enum msm_vidc_buffer_region region) +{ + switch (region) { + case MSM_VIDC_NON_SECURE: + return HFI_BUF_HOST_FLAGS_CB_NON_SECURE; + case MSM_VIDC_NON_SECURE_PIXEL: + return HFI_BUF_HOST_FLAGS_CB_NON_SECURE_PIXEL; + case MSM_VIDC_SECURE_PIXEL: + return HFI_BUF_HOST_FLAGS_CB_SECURE_PIXEL; + case MSM_VIDC_SECURE_NONPIXEL: + return HFI_BUF_HOST_FLAGS_CB_SECURE_NON_PIXEL; + case MSM_VIDC_SECURE_BITSTREAM: + return HFI_BUF_HOST_FLAGS_CB_SECURE_BITSTREAM; + case MSM_VIDC_REGION_MAX: + case MSM_VIDC_REGION_NONE: + default: + return HFI_BUF_HOST_FLAG_NONE; + } +} + +int get_hfi_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer, struct hfi_buffer *buf) +{ + memset(buf, 0, sizeof(struct hfi_buffer)); + buf->type = hfi_buf_type_from_driver(inst->domain, buffer->type); + buf->index = buffer->index; + buf->base_address = buffer->device_addr; + buf->addr_offset = 0; + buf->buffer_size = buffer->buffer_size; + /* + * for decoder input buffers, firmware (BSE HW) needs 256 aligned + * buffer size otherwise it will truncate or ignore the data after 256 + * aligned size which may lead to error concealment + */ + if (is_decode_session(inst) && is_input_buffer(buffer->type)) + buf->buffer_size = ALIGN(buffer->buffer_size, 256); + buf->data_offset = buffer->data_offset; + buf->data_size = buffer->data_size; + if (buffer->attr & MSM_VIDC_ATTR_READ_ONLY) + buf->flags |= HFI_BUF_HOST_FLAG_READONLY; + if (buffer->attr & MSM_VIDC_ATTR_PENDING_RELEASE) + buf->flags |= HFI_BUF_HOST_FLAG_RELEASE; + if (buffer->flags & MSM_VIDC_BUF_FLAG_CODECCONFIG) + buf->flags |= HFI_BUF_HOST_FLAG_CODEC_CONFIG; + buf->flags |= get_hfi_region_flag(buffer->region); + buf->timestamp = buffer->timestamp; + + return 0; +} + +int hfi_create_header(u8 *packet, u32 packet_size, u32 session_id, + u32 header_id) +{ + struct hfi_header *hdr = (struct hfi_header *)packet; + + if (!packet || packet_size < sizeof(struct hfi_header)) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + memset(hdr, 0, sizeof(struct hfi_header)); + + hdr->size = sizeof(struct hfi_header); + hdr->session_id = session_id; + hdr->header_id = header_id; + hdr->num_packets = 0; + return 0; +} + +int hfi_create_packet(u8 *packet, u32 packet_size, + u32 pkt_type, u32 pkt_flags, u32 payload_type, u32 port, + u32 packet_id, void *payload, u32 payload_size) +{ + struct hfi_header *hdr; + struct hfi_packet *pkt; + u32 pkt_size; + + if (!packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + hdr = (struct hfi_header *)packet; + if (hdr->size < sizeof(struct hfi_header)) { + d_vpr_e("%s: invalid hdr size %d\n", __func__, hdr->size); + return -EINVAL; + } + pkt = (struct hfi_packet *)(packet + hdr->size); + pkt_size = sizeof(struct hfi_packet) + payload_size; + if (packet_size < hdr->size + pkt_size) { + d_vpr_e("%s: invalid packet_size %d, %d %d\n", + __func__, packet_size, hdr->size, pkt_size); + return -EINVAL; + } + memset(pkt, 0, pkt_size); + pkt->size = pkt_size; + pkt->type = pkt_type; + pkt->flags = pkt_flags; + pkt->payload_info = payload_type; + pkt->port = port; + pkt->packet_id = packet_id; + if (payload_size) + memcpy((u8 *)pkt + sizeof(struct hfi_packet), + payload, payload_size); + + hdr->num_packets++; + hdr->size += pkt->size; + return 0; +} + +int hfi_packet_sys_init(struct msm_vidc_core *core, + u8 *pkt, u32 pkt_size) +{ + int rc = 0; + u32 payload = 0; + u32 synx_client_data[2]; + + rc = hfi_create_header(pkt, pkt_size, + 0 /*session_id*/, + core->header_id++); + if (rc) + goto err_sys_init; + + /* HFI_CMD_SYSTEM_INIT */ + payload = HFI_VIDEO_ARCH_LX; + d_vpr_h("%s: arch %d\n", __func__, payload); + core->sys_init_id = core->packet_id++; + rc = hfi_create_packet(pkt, pkt_size, + HFI_CMD_INIT, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED | + HFI_HOST_FLAGS_NON_DISCARDABLE), + HFI_PAYLOAD_U32, + HFI_PORT_NONE, + core->sys_init_id, + &payload, + sizeof(u32)); + if (rc) + goto err_sys_init; + + /* HFI_PROP_UBWC_MAX_CHANNELS */ + payload = core->platform->data.ubwc_config->max_channels; + d_vpr_h("%s: ubwc max channels %d\n", __func__, payload); + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_UBWC_MAX_CHANNELS, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); + if (rc) + goto err_sys_init; + + /* HFI_PROP_UBWC_MAL_LENGTH */ + payload = core->platform->data.ubwc_config->mal_length; + d_vpr_h("%s: ubwc mal length %d\n", __func__, payload); + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_UBWC_MAL_LENGTH, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); + if (rc) + goto err_sys_init; + + /* HFI_PROP_UBWC_HBB */ + payload = core->platform->data.ubwc_config->highest_bank_bit; + d_vpr_h("%s: ubwc hbb %d\n", __func__, payload); + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_UBWC_HBB, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); + if (rc) + goto err_sys_init; + + /* HFI_PROP_UBWC_BANK_SWZL_LEVEL1 */ + payload = core->platform->data.ubwc_config->bank_swzl_level; + d_vpr_h("%s: ubwc swzl1 %d\n", __func__, payload); + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_UBWC_BANK_SWZL_LEVEL1, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); + if (rc) + goto err_sys_init; + + /* HFI_PROP_UBWC_BANK_SWZL_LEVEL2 */ + payload = core->platform->data.ubwc_config->bank_swz2_level; + d_vpr_h("%s: ubwc swzl2 %d\n", __func__, payload); + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_UBWC_BANK_SWZL_LEVEL2, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); + if (rc) + goto err_sys_init; + + /* HFI_PROP_UBWC_BANK_SWZL_LEVEL3 */ + payload = core->platform->data.ubwc_config->bank_swz3_level; + d_vpr_h("%s: ubwc swzl3 %d\n", __func__, payload); + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_UBWC_BANK_SWZL_LEVEL3, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); + if (rc) + goto err_sys_init; + + /* HFI_PROP_UBWC_BANK_SPREADING */ + payload = core->platform->data.ubwc_config->bank_spreading; + d_vpr_h("%s: ubwc bank spreading %d\n", __func__, payload); + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_UBWC_BANK_SPREADING, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); + if (rc) + goto err_sys_init; + + /* HFI_PROP_FENCE_CLIENT_DATA */ + if (core->capabilities[SUPPORTS_SYNX_FENCE].value) { + synx_client_data[0] = core->synx_fence_data.client_id; + synx_client_data[1] = core->synx_fence_data.client_flags; + d_vpr_h("%s: synx fence client id: %u client flags: %u\n", + __func__, synx_client_data[0], synx_client_data[1]); + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_FENCE_CLIENT_DATA, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32_ARRAY, + HFI_PORT_NONE, + core->packet_id++, + synx_client_data, + sizeof(u32) * 2); + if (rc) + goto err_sys_init; + } + + d_vpr_h("System init packet created\n"); + return rc; + +err_sys_init: + d_vpr_e("%s: create packet failed\n", __func__); + return rc; +} + +int hfi_packet_image_version(struct msm_vidc_core *core, + u8 *pkt, u32 pkt_size) +{ + int rc = 0; + + rc = hfi_create_header(pkt, pkt_size, + 0 /*session_id*/, + core->header_id++); + if (rc) + goto err_img_version; + + /* HFI_PROP_IMAGE_VERSION */ + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_IMAGE_VERSION, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED | + HFI_HOST_FLAGS_GET_PROPERTY), + HFI_PAYLOAD_NONE, + HFI_PORT_NONE, + core->packet_id++, + NULL, 0); + if (rc) + goto err_img_version; + + d_vpr_h("Image version packet created\n"); + return rc; + +err_img_version: + d_vpr_e("%s: create packet failed\n", __func__); + return rc; +} + +int hfi_packet_sys_pc_prep(struct msm_vidc_core *core, + u8 *pkt, u32 pkt_size) +{ + int rc = 0; + + rc = hfi_create_header(pkt, pkt_size, + 0 /*session_id*/, + core->header_id++); + if (rc) + goto err_sys_pc; + + /* HFI_CMD_POWER_COLLAPSE */ + rc = hfi_create_packet(pkt, pkt_size, + HFI_CMD_POWER_COLLAPSE, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_NONE, + HFI_PORT_NONE, + core->packet_id++, + NULL, 0); + if (rc) + goto err_sys_pc; + + d_vpr_h("Power collapse packet created\n"); + return rc; + +err_sys_pc: + d_vpr_e("%s: create packet failed\n", __func__); + return rc; +} + +int hfi_packet_sys_debug_config(struct msm_vidc_core *core, + u8 *pkt, u32 pkt_size, u32 debug_config) +{ + int rc = 0; + u32 payload = 0; + + rc = hfi_create_header(pkt, pkt_size, + 0 /*session_id*/, + core->header_id++); + if (rc) + goto err_debug; + + /* HFI_PROP_DEBUG_CONFIG */ + payload = 0; /*TODO:Change later*/ + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_DEBUG_CONFIG, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32_ENUM, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); + if (rc) + goto err_debug; + + /* HFI_PROP_DEBUG_LOG_LEVEL */ + payload = debug_config; /*TODO:Change later*/ + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_DEBUG_LOG_LEVEL, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32_ENUM, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); + if (rc) + goto err_debug; + +err_debug: + if (rc) + d_vpr_e("%s: create packet failed\n", __func__); + + return rc; +} + +int hfi_packet_session_command(struct msm_vidc_inst *inst, + u32 pkt_type, u32 flags, u32 port, u32 session_id, + u32 payload_type, void *payload, u32 payload_size) +{ + int rc = 0; + struct msm_vidc_core *core; + + core = inst->core; + + rc = hfi_create_header(inst->packet, inst->packet_size, + session_id, + core->header_id++); + if (rc) + goto err_cmd; + + rc = hfi_create_packet(inst->packet, + inst->packet_size, + pkt_type, + flags, + payload_type, + port, + core->packet_id++, + payload, + payload_size); + if (rc) + goto err_cmd; + + i_vpr_h(inst, "Command packet 0x%x created\n", pkt_type); + return rc; + +err_cmd: + i_vpr_e(inst, "%s: create packet failed\n", __func__); + return rc; +} + +int hfi_packet_sys_intraframe_powercollapse(struct msm_vidc_core *core, + u8 *pkt, u32 pkt_size, u32 enable) +{ + int rc = 0; + u32 payload = 0; + + rc = hfi_create_header(pkt, pkt_size, + 0 /*session_id*/, + core->header_id++); + if (rc) + goto err; + + /* HFI_PROP_INTRA_FRAME_POWER_COLLAPSE */ + payload = enable; + d_vpr_h("%s: intra frame power collapse %d\n", __func__, payload); + rc = hfi_create_packet(pkt, pkt_size, + HFI_PROP_INTRA_FRAME_POWER_COLLAPSE, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32, + HFI_PORT_NONE, + core->packet_id++, + &payload, + sizeof(u32)); + if (rc) + goto err; + + d_vpr_h("IFPC packet created\n"); + return rc; + +err: + d_vpr_e("%s: create packet failed\n", __func__); + return rc; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vdec.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vdec.c new file mode 100644 index 0000000000..77e40e2b6f --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vdec.c @@ -0,0 +1,2704 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_media_info.h" +#include + +#include "msm_vdec.h" +#include "msm_vidc_core.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_control.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_power.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_memory.h" +#include "venus_hfi.h" +#include "hfi_packet.h" + +/* TODO: update based on clips */ +#define MAX_DEC_BATCH_SIZE 6 +#define SKIP_BATCH_WINDOW 100 + +static const u32 msm_vdec_internal_buffer_type[] = { + MSM_VIDC_BUF_BIN, + MSM_VIDC_BUF_COMV, + MSM_VIDC_BUF_NON_COMV, + MSM_VIDC_BUF_LINE, + MSM_VIDC_BUF_PARTIAL_DATA, +}; + +static const u32 msm_vdec_output_internal_buffer_type[] = { + MSM_VIDC_BUF_DPB, +}; + +struct msm_vdec_prop_type_handle { + u32 type; + int (*handle)(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); +}; + +static int msm_vdec_codec_change(struct msm_vidc_inst *inst, u32 v4l2_codec) +{ + int rc = 0; + bool session_init = false; + + if (!inst->codec) + session_init = true; + + if (inst->codec && inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat == v4l2_codec) + return 0; + + i_vpr_h(inst, "%s: codec changed from %s to %s\n", + __func__, v4l2_pixelfmt_name(inst, inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat), + v4l2_pixelfmt_name(inst, v4l2_codec)); + + inst->codec = v4l2_codec_to_driver(inst, v4l2_codec, __func__); + if (!inst->codec) { + i_vpr_e(inst, "%s: invalid codec %#x\n", __func__, v4l2_codec); + rc = -EINVAL; + goto exit; + } + + inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat = v4l2_codec; + rc = msm_vidc_update_debug_str(inst); + if (rc) + goto exit; + + rc = msm_vidc_get_inst_capability(inst); + if (rc) + goto exit; + + rc = msm_vidc_ctrl_handler_init(inst, session_init); + if (rc) + goto exit; + + rc = msm_vidc_update_buffer_count(inst, INPUT_PORT); + if (rc) + goto exit; + + rc = msm_vidc_update_buffer_count(inst, OUTPUT_PORT); + if (rc) + goto exit; + +exit: + return rc; +} + +static int msm_vdec_set_bitstream_resolution(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 resolution; + + resolution = inst->fmts[INPUT_PORT].fmt.pix_mp.width << 16 | + inst->fmts[INPUT_PORT].fmt.pix_mp.height; + i_vpr_h(inst, "%s: width: %d height: %d\n", __func__, + inst->fmts[INPUT_PORT].fmt.pix_mp.width, + inst->fmts[INPUT_PORT].fmt.pix_mp.height); + inst->subcr_params[port].bitstream_resolution = resolution; + rc = venus_hfi_session_property(inst, + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32, + &resolution, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_linear_stride_scanline(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 stride_y, scanline_y, stride_uv, scanline_uv; + u32 payload[2]; + enum msm_vidc_colorformat_type colorformat; + + colorformat = v4l2_colorformat_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, + __func__); + + if (!is_linear_yuv_colorformat(colorformat)) + return 0; + + stride_y = inst->fmts[OUTPUT_PORT].fmt.pix_mp.width; + scanline_y = inst->fmts[OUTPUT_PORT].fmt.pix_mp.height; + stride_uv = stride_y; + scanline_uv = scanline_y / 2; + + payload[0] = stride_y << 16 | scanline_y; + payload[1] = stride_uv << 16 | scanline_uv; + i_vpr_h(inst, "%s: stride_y: %d scanline_y: %d " + "stride_uv: %d, scanline_uv: %d", __func__, + stride_y, scanline_y, stride_uv, scanline_uv); + rc = venus_hfi_session_property(inst, + HFI_PROP_LINEAR_STRIDE_SCANLINE, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, OUTPUT_PORT), + HFI_PAYLOAD_U64, + &payload, + sizeof(u64)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_ubwc_stride_scanline(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 stride_y, scanline_y, stride_uv, scanline_uv; + u32 meta_stride_y, meta_scanline_y, meta_stride_uv, meta_scanline_uv; + u32 payload[4]; + struct v4l2_format *f; + u32 pix_fmt, width, height, colorformat; + + f = &inst->fmts[OUTPUT_PORT]; + pix_fmt = f->fmt.pix_mp.pixelformat; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + colorformat = v4l2_colorformat_to_driver(inst, pix_fmt, __func__); + + if (inst->codec != MSM_VIDC_AV1 || + (!is_ubwc_colorformat(colorformat))) + return 0; + + stride_y = video_y_stride_bytes(colorformat, width); + scanline_y = video_y_scanlines(colorformat, height); + stride_uv = video_uv_stride_bytes(colorformat, width); + scanline_uv = video_uv_scanlines(colorformat, height); + + meta_stride_y = video_y_meta_stride(colorformat, width); + meta_scanline_y = video_y_meta_scanlines(colorformat, height); + meta_stride_uv = video_uv_meta_stride(colorformat, width); + meta_scanline_uv = video_uv_meta_scanlines(colorformat, height); + + payload[0] = stride_y << 16 | scanline_y; + payload[1] = stride_uv << 16 | scanline_uv; + payload[2] = meta_stride_y << 16 | meta_scanline_y; + payload[3] = meta_stride_uv << 16 | meta_scanline_uv; + + i_vpr_h(inst, "%s: stride_y: %d scanline_y: %d " + "stride_uv: %d scanline_uv: %d " + "meta_stride_y: %d meta_scanline_y: %d " + "meta_stride_uv: %d, meta_scanline_uv: %d", + __func__, + stride_y, scanline_y, stride_uv, scanline_uv, + meta_stride_y, meta_scanline_y, + meta_stride_uv, meta_scanline_uv); + rc = venus_hfi_session_property(inst, + HFI_PROP_UBWC_STRIDE_SCANLINE, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, OUTPUT_PORT), + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + sizeof(u32) * 4); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_crop_offsets(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 left_offset, top_offset, right_offset, bottom_offset; + u32 payload[2] = {0}; + + left_offset = inst->crop.left; + top_offset = inst->crop.top; + right_offset = (inst->fmts[INPUT_PORT].fmt.pix_mp.width - + inst->crop.width); + bottom_offset = (inst->fmts[INPUT_PORT].fmt.pix_mp.height - + inst->crop.height); + + payload[0] = left_offset << 16 | top_offset; + payload[1] = right_offset << 16 | bottom_offset; + i_vpr_h(inst, "%s: left_offset: %d top_offset: %d " + "right_offset: %d bottom_offset: %d", __func__, + left_offset, top_offset, right_offset, bottom_offset); + inst->subcr_params[port].crop_offsets[0] = payload[0]; + inst->subcr_params[port].crop_offsets[1] = payload[1]; + rc = venus_hfi_session_property(inst, + HFI_PROP_CROP_OFFSETS, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_64_PACKED, + &payload, + sizeof(u64)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_bit_depth(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 pix_fmt; + u32 bitdepth = 8 << 16 | 8; + enum msm_vidc_colorformat_type colorformat; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + pix_fmt = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat; + colorformat = v4l2_colorformat_to_driver(inst, pix_fmt, __func__); + if (is_10bit_colorformat(colorformat)) + bitdepth = 10 << 16 | 10; + + inst->subcr_params[port].bit_depth = bitdepth; + msm_vidc_update_cap_value(inst, BIT_DEPTH, bitdepth, __func__); + i_vpr_h(inst, "%s: bit depth: %#x", __func__, bitdepth); + rc = venus_hfi_session_property(inst, + HFI_PROP_LUMA_CHROMA_BIT_DEPTH, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32, + &bitdepth, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +//todo: enable when needed +/* +static int msm_vdec_set_cabac(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 cabac = 0; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + cabac = inst->capabilities[ENTROPY_MODE].value; + inst->subcr_params[port].cabac = cabac; + i_vpr_h(inst, "%s: entropy mode: %d", __func__, cabac); + rc = venus_hfi_session_property(inst, + HFI_PROP_CABAC_SESSION, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32, + &cabac, + sizeof(u32)); + if (rc) + i_vpr_e(inst, "%s: set property failed\n", __func__); + + return rc; +} + */ +static int msm_vdec_set_coded_frames(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 coded_frames = 0; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_PROGRESSIVE) + coded_frames = HFI_BITMASK_FRAME_MBS_ONLY_FLAG; + inst->subcr_params[port].coded_frames = coded_frames; + i_vpr_h(inst, "%s: coded frames: %d", __func__, coded_frames); + rc = venus_hfi_session_property(inst, + HFI_PROP_CODED_FRAMES, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32, + &coded_frames, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_min_output_count(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 min_output; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + min_output = inst->buffers.output.min_count; + inst->subcr_params[port].fw_min_count = min_output; + i_vpr_h(inst, "%s: firmware min output count: %d", + __func__, min_output); + rc = venus_hfi_session_property(inst, + HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32, + &min_output, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + return rc; +} + +static int msm_vdec_set_picture_order_count(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 poc = 0; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + inst->subcr_params[port].pic_order_cnt = poc; + i_vpr_h(inst, "%s: picture order count: %d", __func__, poc); + rc = venus_hfi_session_property(inst, + HFI_PROP_PIC_ORDER_CNT_TYPE, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32, + &poc, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_max_num_reorder_frames(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 reorder_frames = 0; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + reorder_frames = inst->subcr_params[port].max_num_reorder_frames; + i_vpr_h(inst, "%s: max reorder frames count: %d", __func__, reorder_frames); + rc = venus_hfi_session_property(inst, + HFI_PROP_MAX_NUM_REORDER_FRAMES, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32, + &reorder_frames, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_colorspace(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 primaries = MSM_VIDC_PRIMARIES_RESERVED; + u32 matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED; + u32 transfer_char = MSM_VIDC_TRANSFER_RESERVED; + u32 full_range = V4L2_QUANTIZATION_DEFAULT; + u32 colour_description_present_flag = 0; + u32 video_signal_type_present_flag = 0, color_info = 0; + /* Unspecified video format */ + u32 video_format = 5; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + if (inst->codec == MSM_VIDC_VP9) + return 0; + + if (inst->fmts[port].fmt.pix_mp.colorspace != V4L2_COLORSPACE_DEFAULT || + inst->fmts[port].fmt.pix_mp.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT || + inst->fmts[port].fmt.pix_mp.xfer_func != V4L2_XFER_FUNC_DEFAULT) { + colour_description_present_flag = 1; + video_signal_type_present_flag = 1; + primaries = v4l2_color_primaries_to_driver(inst, + inst->fmts[port].fmt.pix_mp.colorspace, __func__); + matrix_coeff = v4l2_matrix_coeff_to_driver(inst, + inst->fmts[port].fmt.pix_mp.ycbcr_enc, __func__); + transfer_char = v4l2_transfer_char_to_driver(inst, + inst->fmts[port].fmt.pix_mp.xfer_func, __func__); + } + + if (inst->fmts[port].fmt.pix_mp.quantization != + V4L2_QUANTIZATION_DEFAULT) { + video_signal_type_present_flag = 1; + full_range = inst->fmts[port].fmt.pix_mp.quantization == + V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0; + } + + color_info = (matrix_coeff & 0xFF) | + ((transfer_char << 8) & 0xFF00) | + ((primaries << 16) & 0xFF0000) | + ((colour_description_present_flag << 24) & 0x1000000) | + ((full_range << 25) & 0x2000000) | + ((video_format << 26) & 0x1C000000) | + ((video_signal_type_present_flag << 29) & 0x20000000); + + inst->subcr_params[port].color_info = color_info; + i_vpr_h(inst, "%s: color info: %#x\n", __func__, color_info); + rc = venus_hfi_session_property(inst, + HFI_PROP_SIGNAL_COLOR_INFO, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_32_PACKED, + &color_info, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_profile(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 profile; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + profile = inst->capabilities[PROFILE].value; + inst->subcr_params[port].profile = profile; + i_vpr_h(inst, "%s: profile: %d", __func__, profile); + rc = venus_hfi_session_property(inst, + HFI_PROP_PROFILE, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32_ENUM, + &profile, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_level(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 level; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + level = inst->capabilities[LEVEL].value; + inst->subcr_params[port].level = level; + i_vpr_h(inst, "%s: level: %d", __func__, level); + rc = venus_hfi_session_property(inst, + HFI_PROP_LEVEL, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32_ENUM, + &level, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_tier(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 tier; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + tier = inst->capabilities[HEVC_TIER].value; + inst->subcr_params[port].tier = tier; + i_vpr_h(inst, "%s: tier: %d", __func__, tier); + rc = venus_hfi_session_property(inst, + HFI_PROP_TIER, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32_ENUM, + &tier, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_av1_film_grain_present(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 fg_present; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + inst->subcr_params[port].av1_film_grain_present = + inst->capabilities[FILM_GRAIN].value; + fg_present = inst->subcr_params[port].av1_film_grain_present; + i_vpr_h(inst, "%s: film grain present: %d", __func__, fg_present); + rc = venus_hfi_session_property(inst, + HFI_PROP_AV1_FILM_GRAIN_PRESENT, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32_ENUM, + &fg_present, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_av1_superblock_enabled(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 sb_enabled; + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + inst->subcr_params[port].av1_super_block_enabled = + inst->capabilities[SUPER_BLOCK].value; + sb_enabled = inst->subcr_params[port].av1_super_block_enabled; + i_vpr_h(inst, "%s: super block enabled: %d", __func__, sb_enabled); + rc = venus_hfi_session_property(inst, + HFI_PROP_AV1_SUPER_BLOCK_ENABLED, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32_ENUM, + &sb_enabled, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_opb_enable(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 opb_enable = 0; + + if (inst->codec != MSM_VIDC_AV1) + return 0; + + if (is_split_mode_enabled(inst)) + opb_enable = 1; + + i_vpr_h(inst, "%s: OPB enable: %d", __func__, opb_enable); + rc = venus_hfi_session_property(inst, + HFI_PROP_OPB_ENABLE, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, OUTPUT_PORT), + HFI_PAYLOAD_U32, + &opb_enable, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_colorformat(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 pixelformat; + enum msm_vidc_colorformat_type colorformat; + u32 hfi_colorformat; + + pixelformat = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat; + colorformat = v4l2_colorformat_to_driver(inst, pixelformat, __func__); + hfi_colorformat = get_hfi_colorformat(inst, colorformat); + i_vpr_h(inst, "%s: hfi colorformat: %d", + __func__, hfi_colorformat); + rc = venus_hfi_session_property(inst, + HFI_PROP_COLOR_FORMAT, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, OUTPUT_PORT), + HFI_PAYLOAD_U32, + &hfi_colorformat, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_set_output_properties(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = msm_vdec_set_opb_enable(inst); + if (rc) + return rc; + + rc = msm_vdec_set_colorformat(inst); + if (rc) + return rc; + + rc = msm_vdec_set_linear_stride_scanline(inst); + if (rc) + return rc; + + rc = msm_vdec_set_ubwc_stride_scanline(inst); + if (rc) + return rc; + + rc = msm_vidc_set_session_priority(inst, PRIORITY); + if (rc) + return rc; + + return rc; +} + +static bool msm_vdec_check_outbuf_fence_allowed(struct msm_vidc_inst *inst) +{ + u32 reorder_count = inst->capabilities[MAX_NUM_REORDER_FRAMES].value >> 16; + + /* no need of checking for reordering/interlace for vp9/av1 */ + if (inst->codec == MSM_VIDC_VP9 || inst->codec == MSM_VIDC_AV1) + return true; + + if (inst->capabilities[CODED_FRAMES].value == CODED_FRAMES_INTERLACE || + (!inst->capabilities[OUTPUT_ORDER].value && reorder_count)) { + i_vpr_e(inst, + "%s: outbuf tx fence is unsupported for coded frames %d or output order %d and reorder frames %d\n", + __func__, inst->capabilities[CODED_FRAMES].value, + inst->capabilities[OUTPUT_ORDER].value, + (inst->capabilities[MAX_NUM_REORDER_FRAMES].value >> 16)); + return false; + } + + return true; +} + +int msm_vdec_get_input_internal_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 i = 0; + + for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) { + rc = msm_vidc_get_internal_buffers(inst, msm_vdec_internal_buffer_type[i]); + if (rc) + return rc; + } + + return rc; +} + +static int msm_vdec_get_output_internal_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = msm_vidc_get_internal_buffers(inst, MSM_VIDC_BUF_DPB); + if (rc) + return rc; + + return rc; +} + +static int msm_vdec_destroy_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf, *dummy; + const u32 *internal_buf_type; + u32 i, len; + + if (port == INPUT_PORT) { + internal_buf_type = msm_vdec_internal_buffer_type; + len = ARRAY_SIZE(msm_vdec_internal_buffer_type); + } else { + internal_buf_type = msm_vdec_output_internal_buffer_type; + len = ARRAY_SIZE(msm_vdec_output_internal_buffer_type); + } + + for (i = 0; i < len; i++) { + buffers = msm_vidc_get_buffers(inst, internal_buf_type[i], __func__); + if (!buffers) + return -EINVAL; + + if (buffers->reuse) { + i_vpr_l(inst, "%s: reuse enabled for %s\n", __func__, + buf_name(internal_buf_type[i])); + continue; + } + + list_for_each_entry_safe(buf, dummy, &buffers->list, list) { + /* + * do not destroy internal buffer (DPB buffer) if firmware + * did not return it, so skip if QUEUED flag is present + */ + if (buf->attr & MSM_VIDC_ATTR_QUEUED) + continue; + + i_vpr_h(inst, + "%s: destroying internal buffer: type %d idx %d fd %d addr %#llx size %d\n", + __func__, buf->type, buf->index, buf->fd, + buf->device_addr, buf->buffer_size); + + rc = msm_vidc_destroy_internal_buffer(inst, buf); + if (rc) + return rc; + } + } + + return 0; +} + +int msm_vdec_create_input_internal_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 i = 0; + + for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) { + rc = msm_vidc_create_internal_buffers(inst, msm_vdec_internal_buffer_type[i]); + if (rc) + return rc; + } + + return 0; +} + +static int msm_vdec_create_output_internal_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = msm_vidc_create_internal_buffers(inst, MSM_VIDC_BUF_DPB); + if (rc) + return rc; + + return 0; +} + +int msm_vdec_queue_input_internal_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 i = 0; + + for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) { + rc = msm_vidc_queue_internal_buffers(inst, msm_vdec_internal_buffer_type[i]); + if (rc) + return rc; + } + + return 0; +} + +static int msm_vdec_queue_output_internal_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_DPB); + if (rc) + return rc; + + return 0; +} + +int msm_vdec_release_input_internal_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 i = 0; + + i_vpr_h(inst, "%s()\n", __func__); + + for (i = 0; i < ARRAY_SIZE(msm_vdec_internal_buffer_type); i++) { + rc = msm_vidc_release_internal_buffers(inst, msm_vdec_internal_buffer_type[i]); + if (rc) + return rc; + } + + return 0; +} + +static int msm_vdec_subscribe_input_port_settings_change(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + struct msm_vidc_core *core; + u32 payload[32] = {0}; + u32 i, j; + u32 subscribe_psc_size; + const u32 *psc; + static const struct msm_vdec_prop_type_handle prop_type_handle_arr[] = { + {HFI_PROP_BITSTREAM_RESOLUTION, msm_vdec_set_bitstream_resolution }, + {HFI_PROP_CROP_OFFSETS, msm_vdec_set_crop_offsets }, + {HFI_PROP_LUMA_CHROMA_BIT_DEPTH, msm_vdec_set_bit_depth }, + {HFI_PROP_CODED_FRAMES, msm_vdec_set_coded_frames }, + {HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT, msm_vdec_set_min_output_count }, + {HFI_PROP_PIC_ORDER_CNT_TYPE, msm_vdec_set_picture_order_count }, + {HFI_PROP_MAX_NUM_REORDER_FRAMES, msm_vdec_set_max_num_reorder_frames }, + {HFI_PROP_SIGNAL_COLOR_INFO, msm_vdec_set_colorspace }, + {HFI_PROP_PROFILE, msm_vdec_set_profile }, + {HFI_PROP_LEVEL, msm_vdec_set_level }, + {HFI_PROP_TIER, msm_vdec_set_tier }, + {HFI_PROP_AV1_FILM_GRAIN_PRESENT, msm_vdec_set_av1_film_grain_present }, + {HFI_PROP_AV1_SUPER_BLOCK_ENABLED, msm_vdec_set_av1_superblock_enabled }, + }; + + i_vpr_h(inst, "%s()\n", __func__); + + core = inst->core; + payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE; + if (inst->codec == MSM_VIDC_H264) { + subscribe_psc_size = core->platform->data.psc_avc_tbl_size; + psc = core->platform->data.psc_avc_tbl; + } else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) { + subscribe_psc_size = core->platform->data.psc_hevc_tbl_size; + psc = core->platform->data.psc_hevc_tbl; + } else if (inst->codec == MSM_VIDC_VP9) { + subscribe_psc_size = core->platform->data.psc_vp9_tbl_size; + psc = core->platform->data.psc_vp9_tbl; + } else if (inst->codec == MSM_VIDC_AV1) { + subscribe_psc_size = core->platform->data.psc_av1_tbl_size; + psc = core->platform->data.psc_av1_tbl; + } else { + i_vpr_e(inst, "%s: unsupported codec: %d\n", __func__, inst->codec); + psc = NULL; + return -EINVAL; + } + + if (!psc || !subscribe_psc_size) { + i_vpr_e(inst, "%s: invalid params\n", __func__); + return -EINVAL; + } + + payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE; + for (i = 0; i < subscribe_psc_size; i++) + payload[i + 1] = psc[i]; + rc = venus_hfi_session_command(inst, + HFI_CMD_SUBSCRIBE_MODE, + port, + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + ((subscribe_psc_size + 1) * + sizeof(u32))); + + for (i = 0; i < subscribe_psc_size; i++) { + /* set session properties */ + for (j = 0; j < ARRAY_SIZE(prop_type_handle_arr); j++) { + if (prop_type_handle_arr[j].type == psc[i]) { + rc = prop_type_handle_arr[j].handle(inst, port); + if (rc) + goto exit; + break; + } + } + + /* is property type unknown ? */ + if (j == ARRAY_SIZE(prop_type_handle_arr)) + i_vpr_e(inst, "%s: unknown property %#x\n", __func__, psc[i]); + } + +exit: + return rc; +} + +static int msm_vdec_subscribe_property(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 payload[32] = {0}; + u32 i, count = 0; + bool allow = false; + struct msm_vidc_core *core; + u32 subscribe_prop_size; + const u32 *subcribe_prop; + + core = inst->core; + i_vpr_h(inst, "%s()\n", __func__); + + payload[0] = HFI_MODE_PROPERTY; + + if (port == INPUT_PORT) { + if (inst->codec == MSM_VIDC_H264) { + subscribe_prop_size = core->platform->data.dec_input_prop_size_avc; + subcribe_prop = core->platform->data.dec_input_prop_avc; + } else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) { + subscribe_prop_size = core->platform->data.dec_input_prop_size_hevc; + subcribe_prop = core->platform->data.dec_input_prop_hevc; + } else if (inst->codec == MSM_VIDC_VP9) { + subscribe_prop_size = core->platform->data.dec_input_prop_size_vp9; + subcribe_prop = core->platform->data.dec_input_prop_vp9; + } else if (inst->codec == MSM_VIDC_AV1) { + subscribe_prop_size = core->platform->data.dec_input_prop_size_av1; + subcribe_prop = core->platform->data.dec_input_prop_av1; + } else { + i_vpr_e(inst, "%s: unsupported codec: %d\n", __func__, inst->codec); + subcribe_prop = NULL; + return -EINVAL; + } + + for (i = 0; i < subscribe_prop_size; i++) { + allow = msm_vidc_allow_property(inst, + subcribe_prop[i]); + if (allow) { + payload[count + 1] = subcribe_prop[i]; + count++; + } + + if (subcribe_prop[i] == HFI_PROP_DPB_LIST) { + inst->input_dpb_list_enabled = true; + i_vpr_h(inst, "%s: DPB_LIST suscribed on input port", __func__); + } + } + } else if (port == OUTPUT_PORT) { + if (inst->codec == MSM_VIDC_H264) { + subscribe_prop_size = core->platform->data.dec_output_prop_size_avc; + subcribe_prop = core->platform->data.dec_output_prop_avc; + } else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) { + subscribe_prop_size = core->platform->data.dec_output_prop_size_hevc; + subcribe_prop = core->platform->data.dec_output_prop_hevc; + } else if (inst->codec == MSM_VIDC_VP9) { + subscribe_prop_size = core->platform->data.dec_output_prop_size_vp9; + subcribe_prop = core->platform->data.dec_output_prop_vp9; + } else if (inst->codec == MSM_VIDC_AV1) { + subscribe_prop_size = core->platform->data.dec_output_prop_size_av1; + subcribe_prop = core->platform->data.dec_output_prop_av1; + } else { + i_vpr_e(inst, "%s: unsupported codec: %d\n", __func__, inst->codec); + subcribe_prop = NULL; + return -EINVAL; + } + for (i = 0; i < subscribe_prop_size; i++) { + allow = msm_vidc_allow_property(inst, + subcribe_prop[i]); + if (allow) { + payload[count + 1] = subcribe_prop[i]; + count++; + } + + if (subcribe_prop[i] == HFI_PROP_DPB_LIST) { + inst->output_dpb_list_enabled = true; + i_vpr_h(inst, "%s: DPB_LIST suscribed on output port", __func__); + } + } + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port); + return -EINVAL; + } + + rc = venus_hfi_session_command(inst, + HFI_CMD_SUBSCRIBE_MODE, + port, + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + (count + 1) * sizeof(u32)); + if (rc) + return rc; + + return rc; +} + +int msm_vdec_subscribe_metadata(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 payload[32] = {0}; + u32 i, count = 0; + + i_vpr_h(inst, "%s() port %d\n", __func__, port); + + payload[0] = HFI_MODE_METADATA; + if (port == INPUT_PORT) { + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_rx_inp_enabled(inst, i) && + msm_vidc_allow_metadata_subscription( + inst, i, port)) { + if (count + 1 >= sizeof(payload) / sizeof(u32)) { + i_vpr_e(inst, + "%s: input metadatas (%d) exceeded limit (%d)\n", + __func__, count, sizeof(payload) / sizeof(u32)); + return -EINVAL; + } + payload[count + 1] = inst->capabilities[i].hfi_id; + count++; + } + } + } else if (port == OUTPUT_PORT) { + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_rx_out_enabled(inst, i) && + msm_vidc_allow_metadata_subscription( + inst, i, port)) { + if (count + 1 >= sizeof(payload) / sizeof(u32)) { + i_vpr_e(inst, + "%s: input metadatas (%d) exceeded limit (%d)\n", + __func__, count, sizeof(payload) / sizeof(u32)); + return -EINVAL; + } + payload[count + 1] = inst->capabilities[i].hfi_id; + count++; + } + } + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port); + return -EINVAL; + } + + rc = venus_hfi_session_command(inst, + HFI_CMD_SUBSCRIBE_MODE, + port, + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + (count + 1) * sizeof(u32)); + if (rc) + return rc; + + return rc; +} + +static int msm_vdec_set_delivery_mode_metadata(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 payload[32] = {0}; + u32 i, count = 0; + + i_vpr_h(inst, "%s()\n", __func__); + + payload[0] = HFI_MODE_METADATA; + + if (port == INPUT_PORT) { + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_tx_inp_enabled(inst, i)) { + if (count + 1 >= sizeof(payload) / sizeof(u32)) { + i_vpr_e(inst, + "%s: input metadatas (%d) exceeded limit (%d)\n", + __func__, count, sizeof(payload) / sizeof(u32)); + return -EINVAL; + } + payload[count + 1] = inst->capabilities[i].hfi_id; + count++; + } + } + } else if (port == OUTPUT_PORT) { + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_tx_out_enabled(inst, i) && + msm_vidc_allow_metadata_delivery( + inst, i, port)) { + if (count + 1 >= sizeof(payload) / sizeof(u32)) { + i_vpr_e(inst, + "%s: input metadatas (%d) exceeded limit (%d)\n", + __func__, count, sizeof(payload) / sizeof(u32)); + return -EINVAL; + } + payload[count + 1] = inst->capabilities[i].hfi_id; + count++; + } + } + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port); + return -EINVAL; + } + + rc = venus_hfi_session_command(inst, + HFI_CMD_DELIVERY_MODE, + port, + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + (count + 1) * sizeof(u32)); + if (rc) + return rc; + + return rc; +} + +static int msm_vdec_set_delivery_mode_property(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 payload[32] = {0}; + u32 i, count = 0; + static const u32 property_output_list[] = { + META_OUTBUF_FENCE, + }; + static const u32 property_input_list[] = {}; + + i_vpr_h(inst, "%s() port %d\n", __func__, port); + + payload[0] = HFI_MODE_PROPERTY; + + if (port == INPUT_PORT) { + for (i = 0; i < ARRAY_SIZE(property_input_list); i++) { + if (inst->capabilities[property_input_list[i]].value) { + payload[count + 1] = + inst->capabilities[property_input_list[i]].hfi_id; + count++; + } + } + } else if (port == OUTPUT_PORT) { + for (i = 0; i < ARRAY_SIZE(property_output_list); i++) { + if (property_output_list[i] == META_OUTBUF_FENCE) { + if (is_meta_rx_inp_enabled(inst, + META_OUTBUF_FENCE)) { + /* + * if output buffer fence enabled via + * META_OUTBUF_FENCE, then driver will send + * fence id via HFI_PROP_FENCE to firmware. + * So enable HFI_PROP_FENCE property as + * delivery mode property. + */ + payload[++count] = + inst->capabilities[property_output_list[i]].hfi_id; + } + continue; + } + if (inst->capabilities[property_output_list[i]].value) { + payload[count + 1] = + inst->capabilities[property_output_list[i]].hfi_id; + count++; + } + } + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port); + return -EINVAL; + } + + rc = venus_hfi_session_command(inst, + HFI_CMD_DELIVERY_MODE, + port, + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + (count + 1) * sizeof(u32)); + if (rc) + return rc; + + return rc; +} + +int msm_vdec_init_input_subcr_params(struct msm_vidc_inst *inst) +{ + struct msm_vidc_subscription_params *subsc_params; + u32 left_offset, top_offset, right_offset, bottom_offset; + u32 primaries, matrix_coeff, transfer_char; + u32 full_range = 0, video_format = 0; + u32 colour_description_present_flag = 0; + u32 video_signal_type_present_flag = 0; + + subsc_params = &inst->subcr_params[INPUT_PORT]; + + subsc_params->bitstream_resolution = + inst->fmts[INPUT_PORT].fmt.pix_mp.width << 16 | + inst->fmts[INPUT_PORT].fmt.pix_mp.height; + + left_offset = inst->crop.left; + top_offset = inst->crop.top; + right_offset = (inst->fmts[INPUT_PORT].fmt.pix_mp.width - + inst->crop.width); + bottom_offset = (inst->fmts[INPUT_PORT].fmt.pix_mp.height - + inst->crop.height); + subsc_params->crop_offsets[0] = + left_offset << 16 | top_offset; + subsc_params->crop_offsets[1] = + right_offset << 16 | bottom_offset; + + subsc_params->fw_min_count = inst->buffers.output.min_count; + + primaries = v4l2_color_primaries_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.colorspace, __func__); + matrix_coeff = v4l2_matrix_coeff_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.ycbcr_enc, __func__); + transfer_char = v4l2_transfer_char_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.xfer_func, __func__); + full_range = inst->fmts[OUTPUT_PORT].fmt.pix_mp.quantization == + V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0; + subsc_params->color_info = + (matrix_coeff & 0xFF) | + ((transfer_char << 8) & 0xFF00) | + ((primaries << 16) & 0xFF0000) | + ((colour_description_present_flag << 24) & 0x1000000) | + ((full_range << 25) & 0x2000000) | + ((video_format << 26) & 0x1C000000) | + ((video_signal_type_present_flag << 29) & 0x20000000); + + subsc_params->profile = inst->capabilities[PROFILE].value; + subsc_params->level = inst->capabilities[LEVEL].value; + subsc_params->tier = inst->capabilities[HEVC_TIER].value; + subsc_params->pic_order_cnt = inst->capabilities[POC].value; + subsc_params->max_num_reorder_frames = inst->capabilities[MAX_NUM_REORDER_FRAMES].value; + subsc_params->bit_depth = inst->capabilities[BIT_DEPTH].value; + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_PROGRESSIVE) + subsc_params->coded_frames = HFI_BITMASK_FRAME_MBS_ONLY_FLAG; + else + subsc_params->coded_frames = 0; + + return 0; +} + +int msm_vdec_set_num_comv(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 num_comv = 0; + + num_comv = inst->capabilities[NUM_COMV].value; + i_vpr_h(inst, "%s: num COMV: %d", __func__, num_comv); + rc = venus_hfi_session_property(inst, + HFI_PROP_COMV_BUFFER_COUNT, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, INPUT_PORT), + HFI_PAYLOAD_U32, + &num_comv, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; + } + + return rc; +} + +static int msm_vdec_read_input_subcr_params(struct msm_vidc_inst *inst) +{ + struct msm_vidc_subscription_params subsc_params; + struct msm_vidc_core *core; + u32 width, height; + u32 primaries, matrix_coeff, transfer_char; + u32 full_range = 0; + u32 colour_description_present_flag = 0; + u32 video_signal_type_present_flag = 0; + enum msm_vidc_colorformat_type output_fmt; + + core = inst->core; + + subsc_params = inst->subcr_params[INPUT_PORT]; + width = (subsc_params.bitstream_resolution & + HFI_BITMASK_BITSTREAM_WIDTH) >> 16; + height = subsc_params.bitstream_resolution & + HFI_BITMASK_BITSTREAM_HEIGHT; + + inst->fmts[INPUT_PORT].fmt.pix_mp.width = width; + inst->fmts[INPUT_PORT].fmt.pix_mp.height = height; + + output_fmt = v4l2_colorformat_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, __func__); + + inst->fmts[OUTPUT_PORT].fmt.pix_mp.width = video_y_stride_pix( + output_fmt, width); + inst->fmts[OUTPUT_PORT].fmt.pix_mp.height = video_y_scanlines( + output_fmt, height); + inst->fmts[OUTPUT_PORT].fmt.pix_mp.plane_fmt[0].bytesperline = + video_y_stride_bytes(output_fmt, width); + inst->fmts[OUTPUT_PORT].fmt.pix_mp.plane_fmt[0].sizeimage = + call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_OUTPUT); + //inst->buffers.output.size = inst->fmts[OUTPUT_PORT].fmt.pix_mp.plane_fmt[0].sizeimage; + + matrix_coeff = subsc_params.color_info & 0xFF; + transfer_char = (subsc_params.color_info & 0xFF00) >> 8; + primaries = (subsc_params.color_info & 0xFF0000) >> 16; + colour_description_present_flag = + (subsc_params.color_info & 0x1000000) >> 24; + full_range = (subsc_params.color_info & 0x2000000) >> 25; + video_signal_type_present_flag = + (subsc_params.color_info & 0x20000000) >> 29; + + inst->fmts[OUTPUT_PORT].fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; + inst->fmts[OUTPUT_PORT].fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; + inst->fmts[OUTPUT_PORT].fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + inst->fmts[OUTPUT_PORT].fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; + + if (video_signal_type_present_flag) { + inst->fmts[OUTPUT_PORT].fmt.pix_mp.quantization = + full_range ? + V4L2_QUANTIZATION_FULL_RANGE : + V4L2_QUANTIZATION_LIM_RANGE; + if (colour_description_present_flag) { + inst->fmts[OUTPUT_PORT].fmt.pix_mp.colorspace = + v4l2_color_primaries_from_driver(inst, primaries, __func__); + inst->fmts[OUTPUT_PORT].fmt.pix_mp.xfer_func = + v4l2_transfer_char_from_driver(inst, transfer_char, __func__); + inst->fmts[OUTPUT_PORT].fmt.pix_mp.ycbcr_enc = + v4l2_matrix_coeff_from_driver(inst, matrix_coeff, __func__); + } else { + i_vpr_h(inst, + "%s: color description flag is not present\n", + __func__); + } + } else { + i_vpr_h(inst, "%s: video_signal type is not present\n", + __func__); + } + + /* align input port color info with output port */ + inst->fmts[INPUT_PORT].fmt.pix_mp.colorspace = + inst->fmts[OUTPUT_PORT].fmt.pix_mp.colorspace; + inst->fmts[INPUT_PORT].fmt.pix_mp.xfer_func = + inst->fmts[OUTPUT_PORT].fmt.pix_mp.xfer_func; + inst->fmts[INPUT_PORT].fmt.pix_mp.ycbcr_enc = + inst->fmts[OUTPUT_PORT].fmt.pix_mp.ycbcr_enc; + inst->fmts[INPUT_PORT].fmt.pix_mp.quantization = + inst->fmts[OUTPUT_PORT].fmt.pix_mp.quantization; + + inst->crop.top = subsc_params.crop_offsets[0] & 0xFFFF; + inst->crop.left = (subsc_params.crop_offsets[0] >> 16) & 0xFFFF; + inst->crop.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height - + (subsc_params.crop_offsets[1] & 0xFFFF) - inst->crop.top; + inst->crop.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width - + ((subsc_params.crop_offsets[1] >> 16) & 0xFFFF) - inst->crop.left; + + msm_vidc_update_cap_value(inst, PROFILE, subsc_params.profile, __func__); + msm_vidc_update_cap_value(inst, LEVEL, subsc_params.level, __func__); + msm_vidc_update_cap_value(inst, HEVC_TIER, subsc_params.tier, __func__); + msm_vidc_update_cap_value(inst, POC, subsc_params.pic_order_cnt, __func__); + msm_vidc_update_cap_value(inst, MAX_NUM_REORDER_FRAMES, + subsc_params.max_num_reorder_frames, __func__); + if (subsc_params.bit_depth == BIT_DEPTH_8) + msm_vidc_update_cap_value(inst, BIT_DEPTH, BIT_DEPTH_8, __func__); + else + msm_vidc_update_cap_value(inst, BIT_DEPTH, BIT_DEPTH_10, __func__); + if (subsc_params.coded_frames & HFI_BITMASK_FRAME_MBS_ONLY_FLAG) + msm_vidc_update_cap_value(inst, CODED_FRAMES, CODED_FRAMES_PROGRESSIVE, __func__); + else + msm_vidc_update_cap_value(inst, CODED_FRAMES, CODED_FRAMES_INTERLACE, __func__); + if (inst->codec == MSM_VIDC_AV1) { + msm_vidc_update_cap_value(inst, FILM_GRAIN, + subsc_params.av1_film_grain_present, __func__); + msm_vidc_update_cap_value(inst, SUPER_BLOCK, + subsc_params.av1_super_block_enabled, __func__); + } + + inst->fw_min_count = subsc_params.fw_min_count; + inst->buffers.output.min_count = call_session_op(core, + min_count, inst, MSM_VIDC_BUF_OUTPUT); + inst->buffers.output.extra_count = call_session_op(core, + extra_count, inst, MSM_VIDC_BUF_OUTPUT); + inst->buffers.output_meta.min_count = inst->buffers.output.min_count; + inst->buffers.output_meta.extra_count = inst->buffers.output.extra_count; + if (is_thumbnail_session(inst) && inst->codec != MSM_VIDC_VP9) { + if (inst->buffers.output.min_count != 1) { + i_vpr_e(inst, "%s: invalid min count %d in thumbnail case\n", + __func__, inst->buffers.output.min_count); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + } + + return 0; +} + +int msm_vdec_input_port_settings_change(struct msm_vidc_inst *inst) +{ + u32 rc = 0; + struct v4l2_event event = {0}; + + if (!inst->bufq[INPUT_PORT].vb2q->streaming) { + i_vpr_e(inst, "%s: input port not streaming\n", + __func__); + return 0; + } + + rc = msm_vdec_read_input_subcr_params(inst); + if (rc) + return rc; + + event.type = V4L2_EVENT_SOURCE_CHANGE; + event.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION; + v4l2_event_queue_fh(&inst->fh, &event); + + return rc; +} + +int msm_vdec_output_port_settings_change(struct msm_vidc_inst *inst) +{ + return 0; +} + +int msm_vdec_streamoff_input(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = msm_vidc_session_streamoff(inst, INPUT_PORT); + if (rc) + return rc; + + return 0; +} + +int msm_vdec_streamon_input(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (is_input_meta_enabled(inst) && + !inst->bufq[INPUT_META_PORT].vb2q->streaming) { + i_vpr_e(inst, + "%s: Meta port must be streamed on before data port\n", + __func__); + return -EINVAL; + } + + rc = msm_vidc_check_session_supported(inst); + if (rc) + goto error; + + rc = msm_vidc_set_v4l2_properties(inst); + if (rc) + goto error; + + /* Decide bse vpp delay after work mode */ + //msm_vidc_set_bse_vpp_delay(inst); + + rc = msm_vdec_get_input_internal_buffers(inst); + if (rc) + goto error; + /* check for memory after all buffers calculation */ + //rc = msm_vidc_check_memory_supported(inst); + if (rc) + goto error; + + rc = msm_vdec_destroy_internal_buffers(inst, INPUT_PORT); + if (rc) + goto error; + + rc = msm_vdec_create_input_internal_buffers(inst); + if (rc) + goto error; + + rc = msm_vdec_queue_input_internal_buffers(inst); + if (rc) + goto error; + + if (!inst->ipsc_properties_set) { + rc = msm_vdec_subscribe_input_port_settings_change( + inst, INPUT_PORT); + if (rc) + goto error; + inst->ipsc_properties_set = true; + } + + rc = msm_vdec_subscribe_property(inst, INPUT_PORT); + if (rc) + goto error; + + rc = msm_vdec_subscribe_metadata(inst, INPUT_PORT); + if (rc) + goto error; + + /* + * Subscribe output metadatas in input port sequence as well so that + * metadatas detected in bitstream before output port is started + * are not missed. + * Example: AV1 HDR metadata which can be part of + * first ETB (sequence header OBU + metadata OBU) + */ + rc = msm_vdec_subscribe_metadata(inst, OUTPUT_PORT); + if (rc) + goto error; + + rc = msm_vdec_set_delivery_mode_metadata(inst, INPUT_PORT); + if (rc) + goto error; + + rc = msm_vidc_process_streamon_input(inst); + if (rc) + goto error; + + rc = msm_vidc_flush_ts(inst); + if (rc) + goto error; + + rc = msm_vidc_ts_reorder_flush(inst); + if (rc) + goto error; + + return 0; + +error: + i_vpr_e(inst, "%s: failed\n", __func__); + return rc; +} + +static int schedule_batch_work(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + mod_delayed_work(core->batch_workq, &inst->decode_batch.work, + msecs_to_jiffies(core->capabilities[DECODE_BATCH_TIMEOUT].value)); + + return 0; +} + +static int cancel_batch_work(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + cancel_delayed_work(&inst->decode_batch.work); + + return 0; +} + +int msm_vdec_streamoff_output(struct msm_vidc_inst *inst) +{ + int rc = 0; + + /* cancel pending batch work */ + cancel_batch_work(inst); + rc = msm_vidc_session_streamoff(inst, OUTPUT_PORT); + if (rc) + return rc; + + return 0; +} + +static int msm_vdec_subscribe_output_port_settings_change(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + struct msm_vidc_core *core; + u32 payload[32] = {0}; + u32 prop_type, payload_size, payload_type; + u32 i; + struct msm_vidc_subscription_params subsc_params; + u32 subscribe_psc_size = 0; + const u32 *psc = NULL; + + i_vpr_h(inst, "%s()\n", __func__); + + core = inst->core; + + payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE; + if (inst->codec == MSM_VIDC_H264) { + subscribe_psc_size = core->platform->data.psc_avc_tbl_size; + psc = core->platform->data.psc_avc_tbl; + } else if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) { + subscribe_psc_size = core->platform->data.psc_hevc_tbl_size; + psc = core->platform->data.psc_hevc_tbl; + } else if (inst->codec == MSM_VIDC_VP9) { + subscribe_psc_size = core->platform->data.psc_vp9_tbl_size; + psc = core->platform->data.psc_vp9_tbl; + } else if (inst->codec == MSM_VIDC_AV1) { + subscribe_psc_size = core->platform->data.psc_av1_tbl_size; + psc = core->platform->data.psc_av1_tbl; + } else { + i_vpr_e(inst, "%s: unsupported codec: %d\n", __func__, inst->codec); + psc = NULL; + return -EINVAL; + } + + if (!psc || !subscribe_psc_size) { + i_vpr_e(inst, "%s: invalid params\n", __func__); + return -EINVAL; + } + + payload[0] = HFI_MODE_PORT_SETTINGS_CHANGE; + for (i = 0; i < subscribe_psc_size; i++) + payload[i + 1] = psc[i]; + + rc = venus_hfi_session_command(inst, + HFI_CMD_SUBSCRIBE_MODE, + port, + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + ((subscribe_psc_size + 1) * + sizeof(u32))); + + subsc_params = inst->subcr_params[port]; + for (i = 0; i < subscribe_psc_size; i++) { + payload[0] = 0; + payload[1] = 0; + payload_size = 0; + payload_type = 0; + prop_type = psc[i]; + switch (prop_type) { + case HFI_PROP_BITSTREAM_RESOLUTION: + payload[0] = subsc_params.bitstream_resolution; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + case HFI_PROP_CROP_OFFSETS: + payload[0] = subsc_params.crop_offsets[0]; + payload[1] = subsc_params.crop_offsets[1]; + payload_size = sizeof(u64); + payload_type = HFI_PAYLOAD_64_PACKED; + break; + case HFI_PROP_LUMA_CHROMA_BIT_DEPTH: + payload[0] = subsc_params.bit_depth; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + case HFI_PROP_CODED_FRAMES: + payload[0] = subsc_params.coded_frames; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT: + payload[0] = subsc_params.fw_min_count; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + case HFI_PROP_PIC_ORDER_CNT_TYPE: + payload[0] = subsc_params.pic_order_cnt; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + case HFI_PROP_SIGNAL_COLOR_INFO: + payload[0] = subsc_params.color_info; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + case HFI_PROP_PROFILE: + payload[0] = subsc_params.profile; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + case HFI_PROP_LEVEL: + payload[0] = subsc_params.level; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + case HFI_PROP_TIER: + payload[0] = subsc_params.tier; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + case HFI_PROP_AV1_FILM_GRAIN_PRESENT: + payload[0] = subsc_params.av1_film_grain_present; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + case HFI_PROP_AV1_SUPER_BLOCK_ENABLED: + payload[0] = subsc_params.av1_super_block_enabled; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + case HFI_PROP_MAX_NUM_REORDER_FRAMES: + payload[0] = subsc_params.max_num_reorder_frames; + payload_size = sizeof(u32); + payload_type = HFI_PAYLOAD_U32; + break; + default: + i_vpr_e(inst, "%s: unknown property %#x\n", __func__, + prop_type); + prop_type = 0; + rc = -EINVAL; + break; + } + if (prop_type) { + rc = venus_hfi_session_property(inst, + prop_type, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + payload_type, + &payload, + payload_size); + if (rc) + return rc; + } + } + + return rc; +} + +int msm_vdec_streamon_output(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (is_output_meta_enabled(inst) && + !inst->bufq[OUTPUT_META_PORT].vb2q->streaming) { + i_vpr_e(inst, + "%s: Meta port must be streamed on before data port\n", + __func__); + return -EINVAL; + } + + if (inst->capabilities[CODED_FRAMES].value == CODED_FRAMES_INTERLACE && + !is_ubwc_colorformat(inst->capabilities[PIX_FMTS].value)) { + i_vpr_e(inst, + "%s: interlace with non-ubwc color format is unsupported\n", + __func__); + return -EINVAL; + } + + rc = msm_vidc_check_session_supported(inst); + if (rc) + goto error; + + rc = msm_vdec_set_output_properties(inst); + if (rc) + goto error; + + if (is_meta_rx_inp_enabled(inst, META_OUTBUF_FENCE)) { + if (!msm_vdec_check_outbuf_fence_allowed(inst)) { + rc = -EINVAL; + goto error; + } + } + + if (!inst->opsc_properties_set) { + memcpy(&inst->subcr_params[OUTPUT_PORT], + &inst->subcr_params[INPUT_PORT], + sizeof(inst->subcr_params[INPUT_PORT])); + rc = msm_vdec_subscribe_output_port_settings_change(inst, OUTPUT_PORT); + if (rc) + goto error; + inst->opsc_properties_set = true; + } + + rc = msm_vdec_subscribe_property(inst, OUTPUT_PORT); + if (rc) + goto error; + + rc = msm_vdec_subscribe_metadata(inst, OUTPUT_PORT); + if (rc) + goto error; + + rc = msm_vdec_set_delivery_mode_property(inst, OUTPUT_PORT); + if (rc) + goto error; + + rc = msm_vdec_set_delivery_mode_metadata(inst, OUTPUT_PORT); + if (rc) + goto error; + + rc = msm_vdec_get_output_internal_buffers(inst); + if (rc) + goto error; + + rc = msm_vdec_destroy_internal_buffers(inst, OUTPUT_PORT); + if (rc) + goto error; + + rc = msm_vdec_create_output_internal_buffers(inst); + if (rc) + goto error; + + rc = msm_vidc_process_streamon_output(inst); + if (rc) + goto error; + + rc = msm_vdec_queue_output_internal_buffers(inst); + if (rc) + goto error; + + return 0; + +error: + i_vpr_e(inst, "%s: failed\n", __func__); + msm_vdec_streamoff_output(inst); + return rc; +} + +static inline enum msm_vidc_allow msm_vdec_allow_queue_deferred_buffers( + struct msm_vidc_inst *inst) +{ + int count; + + /* do not defer buffers initially to avoid latency issues */ + if (inst->power.buffer_counter <= SKIP_BATCH_WINDOW) + return MSM_VIDC_ALLOW; + + /* defer qbuf, if pending buffers count less than batch size */ + count = msm_vidc_num_buffers(inst, MSM_VIDC_BUF_OUTPUT, MSM_VIDC_ATTR_DEFERRED); + if (count < inst->decode_batch.size) + return MSM_VIDC_DEFER; + + return MSM_VIDC_ALLOW; +} + +static int msm_vdec_qbuf_batch(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + struct msm_vidc_buffer *buf = NULL; + enum msm_vidc_allow allow; + int rc; + + if (!inst->decode_batch.size) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + buf = msm_vidc_get_driver_buf(inst, vb2); + if (!buf) + return -EINVAL; + + if (is_state(inst, MSM_VIDC_OPEN) || + is_state(inst, MSM_VIDC_INPUT_STREAMING)) { + print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf); + return 0; + } + + allow = msm_vdec_allow_queue_deferred_buffers(inst); + if (allow == MSM_VIDC_DISALLOW) { + i_vpr_e(inst, "%s: queue deferred buffers not allowed\n", __func__); + return -EINVAL; + } else if (allow == MSM_VIDC_DEFER) { + print_vidc_buffer(VIDC_LOW, "low ", "batch-qbuf deferred", inst, buf); + schedule_batch_work(inst); + return 0; + } + + cancel_batch_work(inst); + rc = msm_vidc_queue_deferred_buffers(inst, MSM_VIDC_BUF_OUTPUT); + if (rc) + return rc; + + return rc; +} + +static int msm_vdec_release_eligible_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_buffer *ro_buf; + + list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) { + /* release only release eligible read-only buffers */ + if (!(ro_buf->attr & MSM_VIDC_ATTR_RELEASE_ELIGIBLE)) + continue; + /* skip releasing buffers for which release cmd was already sent */ + if (ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE) + continue; + rc = venus_hfi_release_buffer(inst, ro_buf); + if (rc) + return rc; + ro_buf->attr |= MSM_VIDC_ATTR_PENDING_RELEASE; + ro_buf->attr &= ~MSM_VIDC_ATTR_RELEASE_ELIGIBLE; + print_vidc_buffer(VIDC_LOW, "low ", "release buf", inst, ro_buf); + } + + return rc; +} + +static int msm_vdec_release_nonref_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 fw_ro_count = 0, nonref_ro_count = 0; + struct msm_vidc_buffer *ro_buf; + int i = 0; + bool found = false; + + /* count read_only buffers which are not pending release in read_only list */ + list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) { + if (!(ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY)) + continue; + if (ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE) + continue; + fw_ro_count++; + } + + if (fw_ro_count <= MAX_DPB_COUNT) + return 0; + + /* + * Mark those read only buffers present in read_only list as + * non-reference if that buffer is not part of dpb_list_payload. + * count such non-ref read only buffers as nonref_ro_count. + * dpb_list_payload details: + * payload[0-1] : 64 bits base_address of DPB-1 + * payload[2] : 32 bits addr_offset of DPB-1 + * payload[3] : 32 bits data_offset of DPB-1 + */ + list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) { + found = false; + if (!(ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY)) + continue; + if (ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE) + continue; + for (i = 0; (i + 3) < MAX_DPB_LIST_ARRAY_SIZE; i = i + 4) { + if (ro_buf->device_addr == inst->dpb_list_payload[i] && + ro_buf->data_offset == inst->dpb_list_payload[i + 3]) { + found = true; + break; + } + } + if (!found) + nonref_ro_count++; + } + + + if (nonref_ro_count <= inst->buffers.output.min_count) + return 0; + + i_vpr_l(inst, "%s: fw ro buf count %d, non-ref ro count %d\n", + __func__, fw_ro_count, nonref_ro_count); + + /* release the eligible buffers as per above condition */ + list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) { + found = false; + if (!(ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY)) + continue; + if (ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE) + continue; + for (i = 0; (i + 3) < MAX_DPB_LIST_ARRAY_SIZE; i = i + 4) { + if (ro_buf->device_addr == inst->dpb_list_payload[i] && + ro_buf->data_offset == inst->dpb_list_payload[i + 3]) { + found = true; + break; + } + } + if (!found) { + ro_buf->attr |= MSM_VIDC_ATTR_PENDING_RELEASE; + print_vidc_buffer(VIDC_LOW, "low ", "release buf", inst, ro_buf); + rc = venus_hfi_release_buffer(inst, ro_buf); + if (rc) + return rc; + } + } + + return rc; +} + +int msm_vdec_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) +{ + int rc = 0; + + if (inst->adjust_priority) { + s32 priority = inst->capabilities[PRIORITY].value; + + priority += inst->adjust_priority; + inst->adjust_priority = 0; + msm_vidc_update_cap_value(inst, PRIORITY, priority, __func__); + msm_vidc_set_session_priority(inst, PRIORITY); + } + + /* batch decoder output & meta buffer only */ + if (inst->decode_batch.enable && vb2->type == OUTPUT_MPLANE) + rc = msm_vdec_qbuf_batch(inst, vb2); + else + rc = msm_vidc_queue_buffer_single(inst, vb2); + if (rc) + return rc; + + /* + * if DPB_LIST property is subscribed on output port, then + * driver needs to hold at least MAX_BPB_COUNT of read only + * buffers. So call msm_vdec_release_nonref_buffers() to handle + * the same. + */ + if (vb2->type == OUTPUT_MPLANE) { + if (inst->input_dpb_list_enabled) + rc = msm_vdec_release_eligible_buffers(inst); + else if (inst->output_dpb_list_enabled) + rc = msm_vdec_release_nonref_buffers(inst); + if (rc) + return rc; + } + + return rc; +} + +static int msm_vdec_alloc_and_queue_additional_dpb_buffers(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buffer = NULL; + int i, cur_min_count = 0, rc = 0; + + /* get latest min_count and size */ + rc = msm_vidc_get_internal_buffers(inst, MSM_VIDC_BUF_DPB); + if (rc) + return rc; + + buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_DPB, __func__); + if (!buffers) + return -EINVAL; + + /* get current min_count */ + list_for_each_entry(buffer, &buffers->list, list) + cur_min_count++; + + /* skip alloc and queue */ + if (cur_min_count >= buffers->min_count) + return 0; + + i_vpr_h(inst, "%s: dpb buffer count increased from %u -> %u\n", + __func__, cur_min_count, buffers->min_count); + + /* allocate additional DPB buffers */ + for (i = cur_min_count; i < buffers->min_count; i++) { + rc = msm_vidc_create_internal_buffer(inst, MSM_VIDC_BUF_DPB, i); + if (rc) + return rc; + } + + /* queue additional DPB buffers */ + rc = msm_vidc_queue_internal_buffers(inst, MSM_VIDC_BUF_DPB); + if (rc) + return rc; + + return 0; +} + +int msm_vdec_stop_cmd(struct msm_vidc_inst *inst) +{ + int rc = 0; + + i_vpr_h(inst, "received cmd: drain\n"); + rc = msm_vidc_process_drain(inst); + if (rc) + return rc; + + return rc; +} + +int msm_vdec_start_cmd(struct msm_vidc_inst *inst) +{ + int rc = 0; + + i_vpr_h(inst, "received cmd: resume\n"); + vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_META_PORT].vb2q); + vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q); + + if (inst->capabilities[CODED_FRAMES].value == CODED_FRAMES_INTERLACE && + !is_ubwc_colorformat(inst->capabilities[PIX_FMTS].value)) { + i_vpr_e(inst, + "%s: interlace with non-ubwc color format is unsupported\n", + __func__); + return -EINVAL; + } + + /* tune power features */ + inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst); + msm_vidc_allow_dcvs(inst); + msm_vidc_power_data_reset(inst); + + /* + * client is completing partial port reconfiguration, + * hence reallocate input internal buffers before input port + * is resumed. + */ + if (is_sub_state(inst, MSM_VIDC_DRC) && + is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER) && + is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + i_vpr_h(inst, "%s: alloc and queue input internal buffers\n", + __func__); + rc = msm_vidc_alloc_and_queue_input_internal_buffers(inst); + if (rc) + return rc; + + rc = msm_vidc_set_stage(inst, STAGE); + if (rc) + return rc; + + rc = msm_vidc_set_pipe(inst, PIPE); + if (rc) + return rc; + } + + /* allocate and queue extra dpb buffers */ + rc = msm_vdec_alloc_and_queue_additional_dpb_buffers(inst); + if (rc) + return rc; + + /* queue pending deferred buffers */ + rc = msm_vidc_queue_deferred_buffers(inst, MSM_VIDC_BUF_OUTPUT); + if (rc) + return rc; + + /* print final buffer counts & size details */ + msm_vidc_print_buffer_info(inst); + + /* print internal buffer memory usage stats */ + msm_vidc_print_memory_stats(inst); + + rc = msm_vidc_process_resume(inst); + if (rc) + return rc; + + return rc; +} + +int msm_vdec_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + u32 pix_fmt; + + memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); + if (f->type == INPUT_MPLANE) { + pix_fmt = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__); + if (!pix_fmt) { + i_vpr_e(inst, "%s: unsupported codec, set current params\n", __func__); + f->fmt.pix_mp.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width; + f->fmt.pix_mp.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height; + f->fmt.pix_mp.pixelformat = inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat; + pix_fmt = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__); + } + } else if (f->type == OUTPUT_MPLANE) { + pix_fmt = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__); + if (!pix_fmt) { + i_vpr_e(inst, "%s: unsupported format, set current params\n", __func__); + f->fmt.pix_mp.pixelformat = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat; + f->fmt.pix_mp.width = inst->fmts[OUTPUT_PORT].fmt.pix_mp.width; + f->fmt.pix_mp.height = inst->fmts[OUTPUT_PORT].fmt.pix_mp.height; + } + if (inst->bufq[INPUT_PORT].vb2q->streaming) { + f->fmt.pix_mp.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height; + f->fmt.pix_mp.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width; + } + } else if (f->type == INPUT_META_PLANE) { + f->fmt.meta.dataformat = inst->fmts[INPUT_META_PORT].fmt.meta.dataformat; + f->fmt.meta.buffersize = inst->fmts[INPUT_META_PORT].fmt.meta.buffersize; + } else if (f->type == OUTPUT_META_PLANE) { + f->fmt.meta.dataformat = inst->fmts[OUTPUT_META_PORT].fmt.meta.dataformat; + f->fmt.meta.buffersize = inst->fmts[OUTPUT_META_PORT].fmt.meta.buffersize; + } else { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, f->type); + return -EINVAL; + } + + if (pixmp->field == V4L2_FIELD_ANY) + pixmp->field = V4L2_FIELD_NONE; + + pixmp->num_planes = 1; + return rc; +} + +static bool msm_vidc_check_max_sessions_vp9d(struct msm_vidc_core *core) +{ + u32 vp9d_instance_count = 0; + struct msm_vidc_inst *inst = NULL; + + core_lock(core, __func__); + list_for_each_entry(inst, &core->instances, list) { + if (is_decode_session(inst) && + inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat == + V4L2_PIX_FMT_VP9) + vp9d_instance_count++; + } + core_unlock(core, __func__); + + if (vp9d_instance_count > MAX_VP9D_INST_COUNT) + return true; + return false; +} + +int msm_vdec_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + struct msm_vidc_core *core; + struct v4l2_format *fmt, *output_fmt; + u32 codec_align; + enum msm_vidc_colorformat_type colorformat; + + core = inst->core; + msm_vdec_try_fmt(inst, f); + + if (f->type == INPUT_MPLANE) { + if (inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat != + f->fmt.pix_mp.pixelformat) { + rc = msm_vdec_codec_change(inst, f->fmt.pix_mp.pixelformat); + if (rc) + goto err_invalid_fmt; + } + + if (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_VP9) { + if (msm_vidc_check_max_sessions_vp9d(inst->core)) { + i_vpr_e(inst, + "%s: vp9d sessions exceeded max limit %d\n", + __func__, MAX_VP9D_INST_COUNT); + rc = -ENOMEM; + goto err_invalid_fmt; + } + } + + fmt = &inst->fmts[INPUT_PORT]; + fmt->type = INPUT_MPLANE; + + codec_align = inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat == + V4L2_PIX_FMT_HEVC ? 32 : 16; + fmt->fmt.pix_mp.width = ALIGN(f->fmt.pix_mp.width, codec_align); + fmt->fmt.pix_mp.height = ALIGN(f->fmt.pix_mp.height, codec_align); + fmt->fmt.pix_mp.num_planes = 1; + fmt->fmt.pix_mp.plane_fmt[0].bytesperline = 0; + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_INPUT); + inst->buffers.input.min_count = call_session_op(core, + min_count, inst, MSM_VIDC_BUF_INPUT); + inst->buffers.input.extra_count = call_session_op(core, + extra_count, inst, MSM_VIDC_BUF_INPUT); + if (inst->buffers.input.actual_count < + inst->buffers.input.min_count + + inst->buffers.input.extra_count) { + inst->buffers.input.actual_count = + inst->buffers.input.min_count + + inst->buffers.input.extra_count; + } + inst->buffers.input.size = + fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + /* update input port color info */ + fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; + fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; + fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + /* update output port color info */ + output_fmt = &inst->fmts[OUTPUT_PORT]; + output_fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; + output_fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; + output_fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + output_fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + + /* update crop dimensions */ + inst->crop.left = inst->crop.top = 0; + inst->crop.width = f->fmt.pix_mp.width; + inst->crop.height = f->fmt.pix_mp.height; + i_vpr_h(inst, + "%s: type: INPUT, codec %s width %d height %d size %u min_count %d extra_count %d\n", + __func__, v4l2_pixelfmt_name(inst, f->fmt.pix_mp.pixelformat), + f->fmt.pix_mp.width, f->fmt.pix_mp.height, + fmt->fmt.pix_mp.plane_fmt[0].sizeimage, + inst->buffers.input.min_count, + inst->buffers.input.extra_count); + } else if (f->type == INPUT_META_PLANE) { + fmt = &inst->fmts[INPUT_META_PORT]; + fmt->type = INPUT_META_PLANE; + fmt->fmt.meta.dataformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__); + fmt->fmt.meta.buffersize = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_INPUT_META); + inst->buffers.input_meta.min_count = + inst->buffers.input.min_count; + inst->buffers.input_meta.extra_count = + inst->buffers.input.extra_count; + inst->buffers.input_meta.actual_count = + inst->buffers.input.actual_count; + inst->buffers.input_meta.size = fmt->fmt.meta.buffersize; + i_vpr_h(inst, + "%s: type: INPUT_META, size %u min_count %d extra_count %d\n", + __func__, fmt->fmt.meta.buffersize, + inst->buffers.input_meta.min_count, + inst->buffers.input_meta.extra_count); + } else if (f->type == OUTPUT_MPLANE) { + fmt = &inst->fmts[OUTPUT_PORT]; + fmt->type = OUTPUT_MPLANE; + if (inst->bufq[INPUT_PORT].vb2q->streaming) { + f->fmt.pix_mp.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height; + f->fmt.pix_mp.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width; + } + fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; + colorformat = v4l2_colorformat_to_driver(inst, fmt->fmt.pix_mp.pixelformat, + __func__); + fmt->fmt.pix_mp.width = video_y_stride_pix( + colorformat, f->fmt.pix_mp.width); + fmt->fmt.pix_mp.height = video_y_scanlines( + colorformat, f->fmt.pix_mp.height); + fmt->fmt.pix_mp.num_planes = 1; + fmt->fmt.pix_mp.plane_fmt[0].bytesperline = + video_y_stride_bytes( + colorformat, f->fmt.pix_mp.width); + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_OUTPUT); + + if (!inst->bufq[INPUT_PORT].vb2q->streaming) + inst->buffers.output.min_count = call_session_op(core, + min_count, inst, MSM_VIDC_BUF_OUTPUT); + inst->buffers.output.extra_count = call_session_op(core, + extra_count, inst, MSM_VIDC_BUF_OUTPUT); + if (inst->buffers.output.actual_count < + inst->buffers.output.min_count + + inst->buffers.output.extra_count) { + inst->buffers.output.actual_count = + inst->buffers.output.min_count + + inst->buffers.output.extra_count; + } + inst->buffers.output.size = + fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + msm_vidc_update_cap_value(inst, PIX_FMTS, colorformat, __func__); + + /* update crop while input port is not streaming */ + if (!inst->bufq[INPUT_PORT].vb2q->streaming) { + inst->crop.top = 0; + inst->crop.left = 0; + inst->crop.width = f->fmt.pix_mp.width; + inst->crop.height = f->fmt.pix_mp.height; + } + i_vpr_h(inst, + "%s: type: OUTPUT, format %s width %d height %d size %u min_count %d extra_count %d\n", + __func__, v4l2_pixelfmt_name(inst, fmt->fmt.pix_mp.pixelformat), + fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height, + fmt->fmt.pix_mp.plane_fmt[0].sizeimage, + inst->buffers.output.min_count, + inst->buffers.output.extra_count); + } else if (f->type == OUTPUT_META_PLANE) { + fmt = &inst->fmts[OUTPUT_META_PORT]; + fmt->type = OUTPUT_META_PLANE; + fmt->fmt.meta.dataformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__); + fmt->fmt.meta.buffersize = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_OUTPUT_META); + inst->buffers.output_meta.min_count = + inst->buffers.output.min_count; + inst->buffers.output_meta.extra_count = + inst->buffers.output.extra_count; + inst->buffers.output_meta.actual_count = + inst->buffers.output.actual_count; + inst->buffers.output_meta.size = fmt->fmt.meta.buffersize; + i_vpr_h(inst, + "%s: type: OUTPUT_META, size %u min_count %d extra_count %d\n", + __func__, fmt->fmt.meta.buffersize, + inst->buffers.output_meta.min_count, + inst->buffers.output_meta.extra_count); + } else { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, f->type); + goto err_invalid_fmt; + } + memcpy(f, fmt, sizeof(struct v4l2_format)); + +err_invalid_fmt: + return rc; +} + +int msm_vdec_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + int port; + + port = v4l2_type_to_driver_port(inst, f->type, __func__); + if (port < 0) + return -EINVAL; + + memcpy(f, &inst->fmts[port], sizeof(struct v4l2_format)); + + return rc; +} + +int msm_vdec_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s) +{ + i_vpr_e(inst, "%s: unsupported\n", __func__); + return -EINVAL; +} + +int msm_vdec_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s) +{ + if (s->type != OUTPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, s->type); + return -EINVAL; + } + + switch (s->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE: + s->r.left = inst->crop.left; + s->r.top = inst->crop.top; + s->r.width = inst->crop.width; + s->r.height = inst->crop.height; + break; + default: + i_vpr_e(inst, "%s: invalid target %d\n", + __func__, s->target); + return -EINVAL; + } + i_vpr_h(inst, "%s: target %d, r [%d, %d, %d, %d]\n", + __func__, s->target, s->r.top, s->r.left, + s->r.width, s->r.height); + return 0; +} + +int msm_vdec_subscribe_event(struct msm_vidc_inst *inst, + const struct v4l2_event_subscription *sub) +{ + int rc = 0; + + switch (sub->type) { + case V4L2_EVENT_EOS: + rc = v4l2_event_subscribe(&inst->fh, sub, MAX_EVENTS, NULL); + break; + case V4L2_EVENT_SOURCE_CHANGE: + rc = v4l2_src_change_event_subscribe(&inst->fh, sub); + break; + case V4L2_EVENT_CTRL: + rc = v4l2_ctrl_subscribe_event(&inst->fh, sub); + break; + default: + i_vpr_e(inst, "%s: invalid type %d id %d\n", __func__, sub->type, sub->id); + return -EINVAL; + } + + if (rc) + i_vpr_e(inst, "%s: failed, type %d id %d\n", + __func__, sub->type, sub->id); + return rc; +} + +static int msm_vdec_check_colorformat_supported(struct msm_vidc_inst *inst, + enum msm_vidc_colorformat_type colorformat) +{ + bool supported = true; + + /* do not reject coloformats before streamon */ + if (!inst->bufq[INPUT_PORT].vb2q->streaming) + return true; + + /* + * bit_depth 8 bit supports 8 bit colorformats only + * bit_depth 10 bit supports 10 bit colorformats only + * interlace supports ubwc colorformats only + */ + if (inst->capabilities[BIT_DEPTH].value == BIT_DEPTH_8 && + !is_8bit_colorformat(colorformat)) + supported = false; + if (inst->capabilities[BIT_DEPTH].value == BIT_DEPTH_10 && + !is_10bit_colorformat(colorformat)) + supported = false; + if (inst->capabilities[CODED_FRAMES].value == + CODED_FRAMES_INTERLACE && + !is_ubwc_colorformat(colorformat)) + supported = false; + + return supported; +} + +int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f) +{ + int rc = 0; + struct msm_vidc_core *core; + u32 array[32] = {0}; + u32 i = 0; + + if (f->index >= ARRAY_SIZE(array)) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + + if (f->type == INPUT_MPLANE) { + u32 codecs = core->capabilities[DEC_CODECS].value; + u32 idx = 0; + + for (i = 0; i <= 31; i++) { + if (codecs & BIT(i)) { + if (idx >= ARRAY_SIZE(array)) + break; + array[idx] = codecs & BIT(i); + idx++; + } + } + if (!array[f->index]) + return -EINVAL; + f->pixelformat = v4l2_codec_from_driver(inst, array[f->index], + __func__); + if (!f->pixelformat) + return -EINVAL; + f->flags = V4L2_FMT_FLAG_COMPRESSED; + strlcpy(f->description, "codec", sizeof(f->description)); + } else if (f->type == OUTPUT_MPLANE) { + u32 formats = inst->capabilities[PIX_FMTS].step_or_mask; + u32 idx = 0; + + for (i = 0; i <= 31; i++) { + if (formats & BIT(i)) { + if (idx >= ARRAY_SIZE(array)) + break; + if (msm_vdec_check_colorformat_supported(inst, + formats & BIT(i))) { + array[idx] = formats & BIT(i); + idx++; + } + } + } + if (!array[f->index]) + return -EINVAL; + f->pixelformat = v4l2_colorformat_from_driver(inst, array[f->index], + __func__); + if (!f->pixelformat) + return -EINVAL; + strlcpy(f->description, "colorformat", sizeof(f->description)); + } else if (f->type == INPUT_META_PLANE || f->type == OUTPUT_META_PLANE) { + if (!f->index) { + f->pixelformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__); + strlcpy(f->description, "metadata", sizeof(f->description)); + } else { + return -EINVAL; + } + } + memset(f->reserved, 0, sizeof(f->reserved)); + + i_vpr_h(inst, "%s: index %d, %s: %s, flags %#x\n", + __func__, f->index, f->description, + v4l2_pixelfmt_name(inst, f->pixelformat), f->flags); + return rc; +} + +int msm_vdec_inst_init(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + struct v4l2_format *f; + enum msm_vidc_colorformat_type colorformat; + + core = inst->core; + + INIT_DELAYED_WORK(&inst->decode_batch.work, msm_vidc_batch_handler); + if (core->capabilities[DECODE_BATCH].value) { + inst->decode_batch.enable = true; + inst->decode_batch.size = MAX_DEC_BATCH_SIZE; + } + if (core->capabilities[DCVS].value) + inst->power.dcvs_mode = true; + + f = &inst->fmts[INPUT_PORT]; + f->type = INPUT_MPLANE; + f->fmt.pix_mp.width = DEFAULT_WIDTH; + f->fmt.pix_mp.height = DEFAULT_HEIGHT; + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; + f->fmt.pix_mp.num_planes = 1; + f->fmt.pix_mp.plane_fmt[0].bytesperline = 0; + f->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_INPUT); + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + inst->buffers.input.min_count = call_session_op(core, + min_count, inst, MSM_VIDC_BUF_INPUT); + inst->buffers.input.extra_count = call_session_op(core, + extra_count, inst, MSM_VIDC_BUF_INPUT); + inst->buffers.input.actual_count = + inst->buffers.input.min_count + + inst->buffers.input.extra_count; + inst->buffers.input.size = f->fmt.pix_mp.plane_fmt[0].sizeimage; + + inst->crop.left = inst->crop.top = 0; + inst->crop.width = f->fmt.pix_mp.width; + inst->crop.height = f->fmt.pix_mp.height; + + f = &inst->fmts[INPUT_META_PORT]; + f->type = INPUT_META_PLANE; + f->fmt.meta.dataformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__);; + f->fmt.meta.buffersize = MSM_VIDC_METADATA_SIZE; + inst->buffers.input_meta.min_count = 0; + inst->buffers.input_meta.extra_count = 0; + inst->buffers.input_meta.actual_count = 0; + inst->buffers.input_meta.size = 0; + + f = &inst->fmts[OUTPUT_PORT]; + f->type = OUTPUT_MPLANE; + f->fmt.pix_mp.pixelformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_NV12C, __func__); + colorformat = v4l2_colorformat_to_driver(inst, + f->fmt.pix_mp.pixelformat, __func__); + f->fmt.pix_mp.width = video_y_stride_pix(colorformat, DEFAULT_WIDTH); + f->fmt.pix_mp.height = video_y_scanlines(colorformat, DEFAULT_HEIGHT); + f->fmt.pix_mp.num_planes = 1; + f->fmt.pix_mp.plane_fmt[0].bytesperline = + video_y_stride_bytes(colorformat, DEFAULT_WIDTH); + f->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_OUTPUT); + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; + inst->buffers.output.min_count = call_session_op(core, + min_count, inst, MSM_VIDC_BUF_OUTPUT); + inst->buffers.output.extra_count = call_session_op(core, + extra_count, inst, MSM_VIDC_BUF_OUTPUT); + inst->buffers.output.actual_count = + inst->buffers.output.min_count + + inst->buffers.output.extra_count; + inst->buffers.output.size = f->fmt.pix_mp.plane_fmt[0].sizeimage; + inst->fw_min_count = 0; + + f = &inst->fmts[OUTPUT_META_PORT]; + f->type = OUTPUT_META_PLANE; + f->fmt.meta.dataformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__); + f->fmt.meta.buffersize = MSM_VIDC_METADATA_SIZE; + inst->buffers.output_meta.min_count = 0; + inst->buffers.output_meta.extra_count = 0; + inst->buffers.output_meta.actual_count = 0; + inst->buffers.output_meta.size = 0; + inst->input_dpb_list_enabled = false; + inst->output_dpb_list_enabled = false; + + rc = msm_vdec_codec_change(inst, + inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat); + if (rc) + return rc; + + return rc; +} + +int msm_vdec_inst_deinit(struct msm_vidc_inst *inst) +{ + int rc = 0; + + /* cancel pending batch work */ + cancel_batch_work(inst); + rc = msm_vidc_ctrl_handler_deinit(inst); + if (rc) + return rc; + + return rc; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_venc.c b/qcom/opensource/video-driver/driver/vidc/src/msm_venc.c new file mode 100644 index 0000000000..aba0777f85 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_venc.c @@ -0,0 +1,1874 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_media_info.h" + +#include "msm_venc.h" +#include "msm_vidc_core.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_control.h" +#include "msm_vidc_power.h" +#include "msm_vidc_debug.h" +#include "venus_hfi.h" +#include "hfi_packet.h" +#include "msm_vidc_platform.h" + +static const u32 msm_venc_input_set_prop[] = { + HFI_PROP_COLOR_FORMAT, + HFI_PROP_RAW_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_LINEAR_STRIDE_SCANLINE, + HFI_PROP_SIGNAL_COLOR_INFO, +}; + +static const u32 msm_venc_output_set_prop[] = { + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_PROP_CROP_OFFSETS, + HFI_PROP_CSC, +}; + +static const u32 msm_venc_input_subscribe_for_properties[] = { + HFI_PROP_NO_OUTPUT, +}; + +static const u32 msm_venc_output_subscribe_for_properties[] = { + HFI_PROP_PICTURE_TYPE, + HFI_PROP_BUFFER_MARK, + HFI_PROP_WORST_COMPRESSION_RATIO, +}; + +static const u32 msm_venc_output_internal_buffer_type[] = { + MSM_VIDC_BUF_BIN, + MSM_VIDC_BUF_COMV, + MSM_VIDC_BUF_NON_COMV, + MSM_VIDC_BUF_LINE, + MSM_VIDC_BUF_DPB, +}; + +static const u32 msm_venc_input_internal_buffer_type[] = { + MSM_VIDC_BUF_VPSS, +}; + +struct msm_venc_prop_type_handle { + u32 type; + int (*handle)(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); +}; + +static int msm_venc_codec_change(struct msm_vidc_inst *inst, u32 v4l2_codec) +{ + int rc = 0; + bool session_init = false; + + if (!inst->codec) + session_init = true; + + if (inst->codec && inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat == v4l2_codec) + return 0; + + i_vpr_h(inst, "%s: codec changed from %s to %s\n", + __func__, v4l2_pixelfmt_name(inst, inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat), + v4l2_pixelfmt_name(inst, v4l2_codec)); + + inst->codec = v4l2_codec_to_driver(inst, v4l2_codec, __func__); + if (!inst->codec) { + i_vpr_e(inst, "%s: invalid codec %#x\n", __func__, v4l2_codec); + rc = -EINVAL; + goto exit; + } + + inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat = v4l2_codec; + rc = msm_vidc_update_debug_str(inst); + if (rc) + goto exit; + + rc = msm_vidc_get_inst_capability(inst); + if (rc) + goto exit; + + rc = msm_vidc_ctrl_handler_init(inst, session_init); + if (rc) + goto exit; + + rc = msm_vidc_update_buffer_count(inst, INPUT_PORT); + if (rc) + goto exit; + + rc = msm_vidc_update_buffer_count(inst, OUTPUT_PORT); + if (rc) + goto exit; + +exit: + return rc; +} + +/* todo: add logs for each property once finalised */ +static int msm_venc_set_colorformat(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 pixelformat; + enum msm_vidc_colorformat_type colorformat; + u32 hfi_colorformat; + + if (port != INPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + pixelformat = inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat; + colorformat = v4l2_colorformat_to_driver(inst, pixelformat, __func__); + if (!(colorformat & inst->capabilities[PIX_FMTS].step_or_mask)) { + i_vpr_e(inst, "%s: invalid pixelformat %s\n", + __func__, v4l2_pixelfmt_name(inst, pixelformat)); + return -EINVAL; + } + + hfi_colorformat = get_hfi_colorformat(inst, colorformat); + i_vpr_h(inst, "%s: hfi colorformat: %#x", __func__, + hfi_colorformat); + rc = venus_hfi_session_property(inst, + HFI_PROP_COLOR_FORMAT, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32_ENUM, + &hfi_colorformat, + sizeof(u32)); + if (rc) + return rc; + return 0; +} + +static int msm_venc_set_stride_scanline(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 color_format, stride_y, scanline_y; + u32 stride_uv = 0, scanline_uv = 0; + u32 payload[2]; + u32 grid_size; + + if (port != INPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + color_format = inst->capabilities[PIX_FMTS].value; + if (!is_linear_colorformat(color_format)) { + i_vpr_h(inst, + "%s: not a linear color fmt, property is not set\n", + __func__); + return 0; + } + + if (is_image_session(inst)) { + grid_size = inst->capabilities[GRID_SIZE].value; + stride_y = ALIGN(inst->fmts[INPUT_PORT].fmt.pix_mp.width, grid_size); + scanline_y = ALIGN(inst->fmts[INPUT_PORT].fmt.pix_mp.height, grid_size); + } else if (is_rgba_colorformat(color_format)) { + stride_y = video_rgb_stride_pix(color_format, + inst->fmts[INPUT_PORT].fmt.pix_mp.width); + scanline_y = video_rgb_scanlines(color_format, + inst->fmts[INPUT_PORT].fmt.pix_mp.height); + } else { + stride_y = video_y_stride_pix(color_format, + inst->fmts[INPUT_PORT].fmt.pix_mp.width); + scanline_y = video_y_scanlines(color_format, + inst->fmts[INPUT_PORT].fmt.pix_mp.height); + } + if (color_format == MSM_VIDC_FMT_NV12 || + color_format == MSM_VIDC_FMT_P010 || + color_format == MSM_VIDC_FMT_NV21) { + stride_uv = stride_y; + scanline_uv = scanline_y / 2; + } + + payload[0] = stride_y << 16 | scanline_y; + payload[1] = stride_uv << 16 | scanline_uv; + i_vpr_h(inst, "%s: stride_y: %d scanline_y: %d " + "stride_uv: %d, scanline_uv: %d", __func__, + stride_y, scanline_y, stride_uv, scanline_uv); + rc = venus_hfi_session_property(inst, + HFI_PROP_LINEAR_STRIDE_SCANLINE, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_64_PACKED, + &payload, + sizeof(u64)); + if (rc) + return rc; + + return 0; +} + +static int msm_venc_set_raw_resolution(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 resolution; + + if (port != INPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + resolution = (inst->fmts[port].fmt.pix_mp.width << 16) | + inst->fmts[port].fmt.pix_mp.height; + i_vpr_h(inst, "%s: width: %d height: %d\n", __func__, + inst->fmts[port].fmt.pix_mp.width, inst->fmts[port].fmt.pix_mp.height); + rc = venus_hfi_session_property(inst, + HFI_PROP_RAW_RESOLUTION, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_32_PACKED, + &resolution, + sizeof(u32)); + if (rc) + return rc; + return 0; +} + +static int msm_venc_set_bitstream_resolution(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 resolution; + + if (port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + resolution = (inst->fmts[port].fmt.pix_mp.width << 16) | + inst->fmts[port].fmt.pix_mp.height; + i_vpr_h(inst, "%s: width: %d height: %d\n", __func__, + inst->fmts[port].fmt.pix_mp.width, + inst->fmts[port].fmt.pix_mp.height); + rc = venus_hfi_session_property(inst, + HFI_PROP_BITSTREAM_RESOLUTION, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_32_PACKED, + &resolution, + sizeof(u32)); + if (rc) + return rc; + return 0; +} + +static int msm_venc_set_crop_offsets(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 left_offset, top_offset, right_offset, bottom_offset; + u32 crop[2] = {0}; + u32 width, height; + + if (port != OUTPUT_PORT && port != INPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + if (port == INPUT_PORT) { + left_offset = inst->crop.left; + top_offset = inst->crop.top; + width = inst->crop.width; + height = inst->crop.height; + } else { + left_offset = inst->compose.left; + top_offset = inst->compose.top; + width = inst->compose.width; + height = inst->compose.height; + if (is_rotation_90_or_270(inst)) { + width = inst->compose.height; + height = inst->compose.width; + } + } + + right_offset = (inst->fmts[port].fmt.pix_mp.width - width); + bottom_offset = (inst->fmts[port].fmt.pix_mp.height - height); + + if (is_image_session(inst)) + right_offset = bottom_offset = 0; + + crop[0] = left_offset << 16 | top_offset; + crop[1] = right_offset << 16 | bottom_offset; + i_vpr_h(inst, "%s: left_offset: %d top_offset: %d " + "right_offset: %d bottom_offset: %d", __func__, + left_offset, top_offset, right_offset, bottom_offset); + + rc = venus_hfi_session_property(inst, + HFI_PROP_CROP_OFFSETS, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_64_PACKED, + &crop, + sizeof(u64)); + if (rc) + return rc; + return 0; +} + +static int msm_venc_set_colorspace(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 primaries = MSM_VIDC_PRIMARIES_RESERVED; + u32 matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED; + u32 transfer_char = MSM_VIDC_TRANSFER_RESERVED; + u32 full_range = 0; + u32 colour_description_present_flag = 0; + u32 video_signal_type_present_flag = 0, payload = 0; + /* Unspecified video format */ + u32 video_format = 5; + struct v4l2_format *input_fmt; + u32 pix_fmt; + + if (port != INPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + if (inst->capabilities[SIGNAL_COLOR_INFO].flags & CAP_FLAG_CLIENT_SET) { + i_vpr_h(inst, "%s: client configured colorspace via control\n", __func__); + return 0; + } + + input_fmt = &inst->fmts[INPUT_PORT]; + pix_fmt = v4l2_colorformat_to_driver(inst, + input_fmt->fmt.pix_mp.pixelformat, __func__); + if (inst->fmts[port].fmt.pix_mp.colorspace != V4L2_COLORSPACE_DEFAULT || + inst->fmts[port].fmt.pix_mp.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT || + inst->fmts[port].fmt.pix_mp.xfer_func != V4L2_XFER_FUNC_DEFAULT) { + colour_description_present_flag = 1; + video_signal_type_present_flag = 1; + primaries = v4l2_color_primaries_to_driver(inst, + inst->fmts[port].fmt.pix_mp.colorspace, __func__); + matrix_coeff = v4l2_matrix_coeff_to_driver(inst, + inst->fmts[port].fmt.pix_mp.ycbcr_enc, __func__); + transfer_char = v4l2_transfer_char_to_driver(inst, + inst->fmts[port].fmt.pix_mp.xfer_func, __func__); + } else if (is_rgba_colorformat(pix_fmt)) { + colour_description_present_flag = 1; + video_signal_type_present_flag = 1; + primaries = MSM_VIDC_PRIMARIES_BT709; + matrix_coeff = MSM_VIDC_MATRIX_COEFF_BT709; + transfer_char = MSM_VIDC_TRANSFER_BT709; + full_range = 0; + } + + if (inst->fmts[port].fmt.pix_mp.quantization != + V4L2_QUANTIZATION_DEFAULT) { + video_signal_type_present_flag = 1; + full_range = inst->fmts[port].fmt.pix_mp.quantization == + V4L2_QUANTIZATION_FULL_RANGE ? 1 : 0; + } + + payload = (matrix_coeff & 0xFF) | + ((transfer_char << 8) & 0xFF00) | + ((primaries << 16) & 0xFF0000) | + ((colour_description_present_flag << 24) & 0x1000000) | + ((full_range << 25) & 0x2000000) | + ((video_format << 26) & 0x1C000000) | + ((video_signal_type_present_flag << 29) & 0x20000000); + i_vpr_h(inst, "%s: color info: %#x\n", __func__, payload); + rc = venus_hfi_session_property(inst, + HFI_PROP_SIGNAL_COLOR_INFO, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_32_PACKED, + &payload, + sizeof(u32)); + if (rc) + return rc; + return 0; +} + +static int msm_venc_set_csc(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 csc = 0; + + if (port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + return -EINVAL; + } + + csc = inst->capabilities[CSC].value; + i_vpr_h(inst, "%s: csc: %u\n", __func__, csc); + rc = venus_hfi_session_property(inst, + HFI_PROP_CSC, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, port), + HFI_PAYLOAD_U32, + &csc, + sizeof(u32)); + if (rc) + return rc; + + return 0; +} + +static int msm_venc_set_quality_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core = inst->core; + u32 mode; + + rc = call_session_op(core, decide_quality_mode, inst); + if (rc) { + i_vpr_e(inst, "%s: decide_work_route failed\n", + __func__); + return -EINVAL; + } + + mode = inst->capabilities[QUALITY_MODE].value; + i_vpr_h(inst, "%s: quality_mode: %u\n", __func__, mode); + rc = venus_hfi_session_property(inst, + HFI_PROP_QUALITY_MODE, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_U32_ENUM, + &mode, + sizeof(u32)); + if (rc) + return rc; + return 0; +} + +static int msm_venc_set_ring_buffer_count(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_inst_cap *cap; + + cap = &inst->capabilities[ENC_RING_BUFFER_COUNT]; + + if (!cap->set) + return 0; + + rc = cap->set(inst, ENC_RING_BUFFER_COUNT); + if (rc) { + i_vpr_e(inst, "%s: set cap failed\n", __func__); + return rc; + } + + return 0; +} + +static int msm_venc_set_input_properties(struct msm_vidc_inst *inst) +{ + int i, j, rc = 0; + static const struct msm_venc_prop_type_handle prop_type_handle_arr[] = { + {HFI_PROP_COLOR_FORMAT, msm_venc_set_colorformat }, + {HFI_PROP_RAW_RESOLUTION, msm_venc_set_raw_resolution }, + {HFI_PROP_CROP_OFFSETS, msm_venc_set_crop_offsets }, + {HFI_PROP_LINEAR_STRIDE_SCANLINE, msm_venc_set_stride_scanline }, + {HFI_PROP_SIGNAL_COLOR_INFO, msm_venc_set_colorspace }, + }; + + i_vpr_h(inst, "%s()\n", __func__); + for (i = 0; i < ARRAY_SIZE(msm_venc_input_set_prop); i++) { + /* set session input properties */ + for (j = 0; j < ARRAY_SIZE(prop_type_handle_arr); j++) { + if (prop_type_handle_arr[j].type == msm_venc_input_set_prop[i]) { + rc = prop_type_handle_arr[j].handle(inst, INPUT_PORT); + if (rc) + goto exit; + break; + } + } + + /* is property type unknown ? */ + if (j == ARRAY_SIZE(prop_type_handle_arr)) + i_vpr_e(inst, "%s: unknown property %#x\n", __func__, + msm_venc_input_set_prop[i]); + } + +exit: + return rc; +} + +static int msm_venc_set_output_properties(struct msm_vidc_inst *inst) +{ + int i, j, rc = 0; + static const struct msm_venc_prop_type_handle prop_type_handle_arr[] = { + {HFI_PROP_BITSTREAM_RESOLUTION, msm_venc_set_bitstream_resolution }, + {HFI_PROP_CROP_OFFSETS, msm_venc_set_crop_offsets }, + {HFI_PROP_CSC, msm_venc_set_csc }, + }; + + i_vpr_h(inst, "%s()\n", __func__); + for (i = 0; i < ARRAY_SIZE(msm_venc_output_set_prop); i++) { + /* set session output properties */ + for (j = 0; j < ARRAY_SIZE(prop_type_handle_arr); j++) { + if (prop_type_handle_arr[j].type == msm_venc_output_set_prop[i]) { + rc = prop_type_handle_arr[j].handle(inst, OUTPUT_PORT); + if (rc) + goto exit; + break; + } + } + + /* is property type unknown ? */ + if (j == ARRAY_SIZE(prop_type_handle_arr)) + i_vpr_e(inst, "%s: unknown property %#x\n", __func__, + msm_venc_output_set_prop[i]); + } + +exit: + return rc; +} + +static int msm_venc_set_internal_properties(struct msm_vidc_inst *inst) +{ + int rc = 0; + + i_vpr_h(inst, "%s()\n", __func__); + + rc = msm_venc_set_quality_mode(inst); + if (rc) + return rc; + + rc = msm_venc_set_ring_buffer_count(inst); + if (rc) + return rc; + + return rc; +} + +static int msm_venc_get_input_internal_buffers(struct msm_vidc_inst *inst) +{ + int i, rc = 0; + + for (i = 0; i < ARRAY_SIZE(msm_venc_input_internal_buffer_type); i++) { + rc = msm_vidc_get_internal_buffers(inst, + msm_venc_input_internal_buffer_type[i]); + if (rc) + return rc; + } + + return rc; +} + +static int msm_venc_destroy_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf, *dummy; + const u32 *internal_buf_type; + u32 i, len; + + if (port == INPUT_PORT) { + internal_buf_type = msm_venc_input_internal_buffer_type; + len = ARRAY_SIZE(msm_venc_input_internal_buffer_type); + } else { + internal_buf_type = msm_venc_output_internal_buffer_type; + len = ARRAY_SIZE(msm_venc_output_internal_buffer_type); + } + + for (i = 0; i < len; i++) { + buffers = msm_vidc_get_buffers(inst, internal_buf_type[i], __func__); + if (!buffers) + return -EINVAL; + + if (buffers->reuse) { + i_vpr_l(inst, "%s: reuse enabled for %s\n", __func__, + buf_name(internal_buf_type[i])); + continue; + } + + list_for_each_entry_safe(buf, dummy, &buffers->list, list) { + i_vpr_h(inst, + "%s: destroying internal buffer: type %d idx %d fd %d addr %#llx size %d\n", + __func__, buf->type, buf->index, buf->fd, + buf->device_addr, buf->buffer_size); + + rc = msm_vidc_destroy_internal_buffer(inst, buf); + if (rc) + return rc; + } + } + + return 0; +} + +static int msm_venc_create_input_internal_buffers(struct msm_vidc_inst *inst) +{ + int i, rc = 0; + + for (i = 0; i < ARRAY_SIZE(msm_venc_input_internal_buffer_type); i++) { + rc = msm_vidc_create_internal_buffers(inst, + msm_venc_input_internal_buffer_type[i]); + if (rc) + return rc; + } + + return rc; +} + +static int msm_venc_queue_input_internal_buffers(struct msm_vidc_inst *inst) +{ + int i, rc = 0; + + for (i = 0; i < ARRAY_SIZE(msm_venc_input_internal_buffer_type); i++) { + rc = msm_vidc_queue_internal_buffers(inst, + msm_venc_input_internal_buffer_type[i]); + if (rc) + return rc; + } + + return rc; +} + +static int msm_venc_get_output_internal_buffers(struct msm_vidc_inst *inst) +{ + int i, rc = 0; + + for (i = 0; i < ARRAY_SIZE(msm_venc_output_internal_buffer_type); i++) { + rc = msm_vidc_get_internal_buffers(inst, + msm_venc_output_internal_buffer_type[i]); + if (rc) + return rc; + } + + return rc; +} + +static int msm_venc_create_output_internal_buffers(struct msm_vidc_inst *inst) +{ + int i, rc = 0; + + for (i = 0; i < ARRAY_SIZE(msm_venc_output_internal_buffer_type); i++) { + rc = msm_vidc_create_internal_buffers(inst, + msm_venc_output_internal_buffer_type[i]); + if (rc) + return rc; + } + + return 0; +} + +static int msm_venc_queue_output_internal_buffers(struct msm_vidc_inst *inst) +{ + int i, rc = 0; + + for (i = 0; i < ARRAY_SIZE(msm_venc_output_internal_buffer_type); i++) { + rc = msm_vidc_queue_internal_buffers(inst, + msm_venc_output_internal_buffer_type[i]); + if (rc) + return rc; + } + + return 0; +} + +static int msm_venc_property_subscription(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 payload[32] = {0}; + u32 i; + u32 payload_size = 0; + + i_vpr_h(inst, "%s()\n", __func__); + + payload[0] = HFI_MODE_PROPERTY; + if (port == INPUT_PORT) { + for (i = 0; i < ARRAY_SIZE(msm_venc_input_subscribe_for_properties); i++) + payload[i + 1] = msm_venc_input_subscribe_for_properties[i]; + payload_size = (ARRAY_SIZE(msm_venc_input_subscribe_for_properties) + 1) * + sizeof(u32); + } else if (port == OUTPUT_PORT) { + for (i = 0; i < ARRAY_SIZE(msm_venc_output_subscribe_for_properties); i++) + payload[i + 1] = msm_venc_output_subscribe_for_properties[i]; + payload_size = (ARRAY_SIZE(msm_venc_output_subscribe_for_properties) + 1) * + sizeof(u32); + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port); + return -EINVAL; + } + + rc = venus_hfi_session_command(inst, + HFI_CMD_SUBSCRIBE_MODE, + port, + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + payload_size); + if (rc) + return rc; + + return rc; +} + +static int msm_venc_metadata_delivery(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 payload[32] = {0}; + u32 i, count = 0; + + i_vpr_h(inst, "%s()\n", __func__); + + payload[0] = HFI_MODE_METADATA; + + if (port == INPUT_PORT) { + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_tx_inp_enabled(inst, i)) { + if (count + 1 >= sizeof(payload) / sizeof(u32)) { + i_vpr_e(inst, + "%s: input metadatas (%d) exceeded limit (%d)\n", + __func__, count, sizeof(payload) / sizeof(u32)); + return -EINVAL; + } + payload[count + 1] = inst->capabilities[i].hfi_id; + count++; + } + } + } else if (port == OUTPUT_PORT) { + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_tx_out_enabled(inst, i)) { + if (count + 1 >= sizeof(payload) / sizeof(u32)) { + i_vpr_e(inst, + "%s: input metadatas (%d) exceeded limit (%d)\n", + __func__, count, sizeof(payload) / sizeof(u32)); + return -EINVAL; + } + payload[count + 1] = inst->capabilities[i].hfi_id; + count++; + } + } + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port); + return -EINVAL; + } + + rc = venus_hfi_session_command(inst, + HFI_CMD_DELIVERY_MODE, + port, + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + (count + 1) * sizeof(u32)); + if (rc) + return rc; + + return rc; +} + +static int msm_venc_dynamic_metadata_delivery(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 payload[32] = {0}; + u32 i, count = 0; + + i_vpr_h(inst, "%s()\n", __func__); + + payload[0] = HFI_MODE_DYNAMIC_METADATA; + + if (port != INPUT_PORT) { + i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port); + return -EINVAL; + } + + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_dyn_meta_tx_inp_enabled(inst, i)) { + if (count + 1 >= sizeof(payload) / sizeof(u32)) { + i_vpr_e(inst, + "%s: dynamic input metadatas (%d) exceeded limit (%d)\n", + __func__, count, sizeof(payload) / sizeof(u32)); + return -EINVAL; + } + payload[count + 1] = inst->capabilities[i].hfi_id; + count++; + } + } + + rc = venus_hfi_session_command(inst, + HFI_CMD_DELIVERY_MODE, + port, + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + (count + 1) * sizeof(u32)); + if (rc) + return rc; + + return rc; +} + +static int msm_venc_metadata_subscription(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + u32 payload[32] = {0}; + u32 i, count = 0; + + i_vpr_h(inst, "%s()\n", __func__); + + payload[0] = HFI_MODE_METADATA; + + if (port == INPUT_PORT) { + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_rx_inp_enabled(inst, i)) { + if (count + 1 >= sizeof(payload) / sizeof(u32)) { + i_vpr_e(inst, + "%s: input metadatas (%d) exceeded limit (%d)\n", + __func__, count, sizeof(payload) / sizeof(u32)); + return -EINVAL; + } + payload[count + 1] = inst->capabilities[i].hfi_id; + count++; + } + } + } else if (port == OUTPUT_PORT) { + for (i = INST_CAP_NONE + 1; i < INST_CAP_MAX; i++) { + if (is_meta_rx_out_enabled(inst, i)) { + if (count + 1 >= sizeof(payload) / sizeof(u32)) { + i_vpr_e(inst, + "%s: input metadatas (%d) exceeded limit (%d)\n", + __func__, count, sizeof(payload) / sizeof(u32)); + return -EINVAL; + } + payload[count + 1] = inst->capabilities[i].hfi_id; + count++; + } + } + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port); + return -EINVAL; + } + + rc = venus_hfi_session_command(inst, + HFI_CMD_SUBSCRIBE_MODE, + port, + HFI_PAYLOAD_U32_ARRAY, + &payload[0], + (count + 1) * sizeof(u32)); + if (rc) + return rc; + + return rc; +} + +int msm_venc_streamoff_input(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = msm_vidc_session_streamoff(inst, INPUT_PORT); + if (rc) + return rc; + + return 0; +} + +int msm_venc_streamon_input(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (is_input_meta_enabled(inst) && + !inst->bufq[INPUT_META_PORT].vb2q->streaming) { + i_vpr_e(inst, + "%s: Meta port must be streamed on before data port\n", + __func__); + return -EINVAL; + } + + rc = msm_vidc_check_session_supported(inst); + if (rc) + goto error; + + rc = msm_vidc_check_scaling_supported(inst); + if (rc) + goto error; + + rc = msm_venc_set_input_properties(inst); + if (rc) + goto error; + + /* Decide bse vpp delay after work mode */ + //msm_vidc_set_bse_vpp_delay(inst); + + rc = msm_venc_get_input_internal_buffers(inst); + if (rc) + goto error; + + rc = msm_venc_destroy_internal_buffers(inst, INPUT_PORT); + if (rc) + goto error; + + rc = msm_venc_create_input_internal_buffers(inst); + if (rc) + goto error; + + rc = msm_venc_queue_input_internal_buffers(inst); + if (rc) + goto error; + + rc = msm_venc_property_subscription(inst, INPUT_PORT); + if (rc) + goto error; + + rc = msm_venc_metadata_delivery(inst, INPUT_PORT); + if (rc) + goto error; + + rc = msm_venc_dynamic_metadata_delivery(inst, INPUT_PORT); + if (rc) + goto error; + + rc = msm_vidc_process_streamon_input(inst); + if (rc) + goto error; + + return 0; + +error: + i_vpr_e(inst, "%s: failed\n", __func__); + return rc; +} + +int msm_venc_qbuf(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) +{ + int rc = 0; + + rc = msm_vidc_queue_buffer_single(inst, vb2); + if (rc) + return rc; + + return rc; +} + +int msm_venc_stop_cmd(struct msm_vidc_inst *inst) +{ + int rc = 0; + + i_vpr_h(inst, "received cmd: drain\n"); + rc = msm_vidc_process_drain(inst); + if (rc) + return rc; + + return rc; +} + +int msm_venc_start_cmd(struct msm_vidc_inst *inst) +{ + int rc = 0; + + i_vpr_h(inst, "received cmd: resume\n"); + + vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_META_PORT].vb2q); + vb2_clear_last_buffer_dequeued(inst->bufq[OUTPUT_PORT].vb2q); + + /* tune power features */ + msm_vidc_allow_dcvs(inst); + msm_vidc_power_data_reset(inst); + + /* print final buffer counts & size details */ + msm_vidc_print_buffer_info(inst); + + /* print internal buffer memory usage stats */ + msm_vidc_print_memory_stats(inst); + + rc = msm_vidc_process_resume(inst); + if (rc) + return rc; + + return rc; +} + +int msm_venc_streamoff_output(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + + core = inst->core; + + /* restore LAYER_COUNT max allowed value */ + inst->capabilities[ENH_LAYER_COUNT].max = + core->capabilities[MAX_ENH_LAYER_COUNT].value; + + rc = msm_vidc_session_streamoff(inst, OUTPUT_PORT); + if (rc) + return rc; + + return 0; +} + +int msm_venc_streamon_output(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (is_output_meta_enabled(inst) && + !inst->bufq[OUTPUT_META_PORT].vb2q->streaming) { + i_vpr_e(inst, + "%s: Meta port must be streamed on before data port\n", + __func__); + return -EINVAL; + } + + rc = msm_venc_set_output_properties(inst); + if (rc) + goto error; + + rc = msm_vidc_set_v4l2_properties(inst); + if (rc) + goto error; + + rc = msm_venc_set_internal_properties(inst); + if (rc) + goto error; + + rc = msm_venc_get_output_internal_buffers(inst); + if (rc) + goto error; + + rc = msm_venc_destroy_internal_buffers(inst, OUTPUT_PORT); + if (rc) + goto error; + + rc = msm_venc_create_output_internal_buffers(inst); + if (rc) + goto error; + + rc = msm_venc_queue_output_internal_buffers(inst); + if (rc) + goto error; + + rc = msm_venc_property_subscription(inst, OUTPUT_PORT); + if (rc) + goto error; + + rc = msm_venc_metadata_subscription(inst, OUTPUT_PORT); + if (rc) + goto error; + + rc = msm_vidc_process_streamon_output(inst); + if (rc) + goto error; + + return 0; + +error: + i_vpr_e(inst, "%s: failed\n", __func__); + msm_venc_streamoff_output(inst); + return rc; +} + +int msm_venc_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + u32 pix_fmt; + + memset(pixmp->reserved, 0, sizeof(pixmp->reserved)); + + if (f->type == INPUT_MPLANE) { + pix_fmt = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__); + if (!pix_fmt) { + i_vpr_e(inst, "%s: unsupported format, set current params\n", __func__); + f->fmt.pix_mp.pixelformat = inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat; + f->fmt.pix_mp.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width; + f->fmt.pix_mp.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height; + pix_fmt = v4l2_colorformat_to_driver(inst, + f->fmt.pix_mp.pixelformat, __func__); + } + } else if (f->type == OUTPUT_MPLANE) { + pix_fmt = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__); + if (!pix_fmt) { + i_vpr_e(inst, "%s: unsupported codec, set current params\n", __func__); + f->fmt.pix_mp.width = inst->fmts[OUTPUT_PORT].fmt.pix_mp.width; + f->fmt.pix_mp.height = inst->fmts[OUTPUT_PORT].fmt.pix_mp.height; + f->fmt.pix_mp.pixelformat = inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat; + } + } else if (f->type == INPUT_META_PLANE) { + f->fmt.meta.dataformat = inst->fmts[INPUT_META_PORT].fmt.meta.dataformat; + f->fmt.meta.buffersize = inst->fmts[INPUT_META_PORT].fmt.meta.buffersize; + } else if (f->type == OUTPUT_META_PLANE) { + f->fmt.meta.dataformat = inst->fmts[OUTPUT_META_PORT].fmt.meta.dataformat; + f->fmt.meta.buffersize = inst->fmts[OUTPUT_META_PORT].fmt.meta.buffersize; + } else { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, f->type); + return -EINVAL; + } + + if (pixmp->field == V4L2_FIELD_ANY) + pixmp->field = V4L2_FIELD_NONE; + pixmp->num_planes = 1; + + return rc; +} + +int msm_venc_s_fmt_output(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + struct v4l2_format *fmt; + struct msm_vidc_core *core; + u32 codec_align; + u32 width, height; + enum msm_vidc_codec_type codec; + + core = inst->core; + msm_venc_try_fmt(inst, f); + + fmt = &inst->fmts[OUTPUT_PORT]; + if (fmt->fmt.pix_mp.pixelformat != f->fmt.pix_mp.pixelformat) { + rc = msm_venc_codec_change(inst, f->fmt.pix_mp.pixelformat); + if (rc) + return rc; + } + fmt->type = OUTPUT_MPLANE; + + codec = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__); + + codec_align = (codec == MSM_VIDC_HEVC || + codec == MSM_VIDC_HEIC) ? 32 : 16; + /* use rotated width height if rotation is enabled */ + width = inst->compose.width; + height = inst->compose.height; + if (is_rotation_90_or_270(inst)) { + width = inst->compose.height; + height = inst->compose.width; + } + /* width, height is readonly for client */ + fmt->fmt.pix_mp.width = ALIGN(width, codec_align); + fmt->fmt.pix_mp.height = ALIGN(height, codec_align); + /* use grid dimension for image session */ + if (is_image_session(inst)) + fmt->fmt.pix_mp.width = fmt->fmt.pix_mp.height = + inst->capabilities[GRID_SIZE].value; + fmt->fmt.pix_mp.num_planes = 1; + fmt->fmt.pix_mp.plane_fmt[0].bytesperline = 0; + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_OUTPUT); + /* video hw supports conversion to V4L2_COLORSPACE_REC709 only */ + if (f->fmt.pix_mp.colorspace != V4L2_COLORSPACE_DEFAULT && + f->fmt.pix_mp.colorspace != V4L2_COLORSPACE_REC709) + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; + fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; + fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; + fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + inst->buffers.output.min_count = call_session_op(core, + min_count, inst, MSM_VIDC_BUF_OUTPUT); + inst->buffers.output.extra_count = call_session_op(core, + extra_count, inst, MSM_VIDC_BUF_OUTPUT); + if (inst->buffers.output.actual_count < + inst->buffers.output.min_count + + inst->buffers.output.extra_count) { + inst->buffers.output.actual_count = + inst->buffers.output.min_count + + inst->buffers.output.extra_count; + } + inst->buffers.output.size = + fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + + /* reset metadata buffer size with updated resolution*/ + msm_vidc_update_meta_port_settings(inst); + + i_vpr_h(inst, + "%s: type: OUTPUT, codec %s width %d height %d size %u min_count %d extra_count %d\n", + __func__, v4l2_pixelfmt_name(inst, fmt->fmt.pix_mp.pixelformat), + fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height, + fmt->fmt.pix_mp.plane_fmt[0].sizeimage, + inst->buffers.output.min_count, + inst->buffers.output.extra_count); + + /* finally update client format */ + memcpy(f, fmt, sizeof(struct v4l2_format)); + return rc; +} + +static int msm_venc_s_fmt_output_meta(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + struct v4l2_format *fmt; + struct msm_vidc_core *core; + + core = inst->core; + + fmt = &inst->fmts[OUTPUT_META_PORT]; + fmt->type = OUTPUT_META_PLANE; + fmt->fmt.meta.dataformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__); + fmt->fmt.meta.buffersize = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_OUTPUT_META); + inst->buffers.output_meta.min_count = + inst->buffers.output.min_count; + inst->buffers.output_meta.extra_count = + inst->buffers.output.extra_count; + inst->buffers.output_meta.actual_count = + inst->buffers.output.actual_count; + inst->buffers.output_meta.size = fmt->fmt.meta.buffersize; + + memcpy(f, fmt, sizeof(struct v4l2_format)); + + i_vpr_h(inst, "%s: type: OUTPUT_META, size %u min_count %d extra_count %d\n", + __func__, fmt->fmt.meta.buffersize, + inst->buffers.output_meta.min_count, + inst->buffers.output_meta.extra_count); + + return rc; +} + +static int msm_venc_s_fmt_input(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + struct v4l2_format *fmt, *output_fmt; + struct msm_vidc_core *core; + u32 pix_fmt, width, height, size, bytesperline; + + core = inst->core; + msm_venc_try_fmt(inst, f); + + pix_fmt = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__); + msm_vidc_update_cap_value(inst, PIX_FMTS, pix_fmt, __func__); + + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + + if (is_image_session(inst)) { + bytesperline = ALIGN(f->fmt.pix_mp.width, + inst->capabilities[GRID_SIZE].value) * + (is_10bit_colorformat(pix_fmt) ? 2 : 1); + } else if (is_rgba_colorformat(pix_fmt)) { + bytesperline = video_rgb_stride_bytes(pix_fmt, f->fmt.pix_mp.width); + } else { + bytesperline = video_y_stride_bytes(pix_fmt, f->fmt.pix_mp.width); + } + + fmt = &inst->fmts[INPUT_PORT]; + fmt->type = INPUT_MPLANE; + fmt->fmt.pix_mp.width = width; + fmt->fmt.pix_mp.height = height; + fmt->fmt.pix_mp.num_planes = 1; + fmt->fmt.pix_mp.pixelformat = f->fmt.pix_mp.pixelformat; + fmt->fmt.pix_mp.plane_fmt[0].bytesperline = bytesperline; + size = call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT); + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = size; + /* update input port colorspace info */ + fmt->fmt.pix_mp.colorspace = f->fmt.pix_mp.colorspace; + fmt->fmt.pix_mp.xfer_func = f->fmt.pix_mp.xfer_func; + fmt->fmt.pix_mp.ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + fmt->fmt.pix_mp.quantization = f->fmt.pix_mp.quantization; + /* + * Update output port colorspace info. + * NOTE: If client needs CSC, then client needs to ensure setting + * output port color after setting input color info. + */ + output_fmt = &inst->fmts[OUTPUT_PORT]; + output_fmt->fmt.pix_mp.colorspace = fmt->fmt.pix_mp.colorspace; + output_fmt->fmt.pix_mp.xfer_func = fmt->fmt.pix_mp.xfer_func; + output_fmt->fmt.pix_mp.ycbcr_enc = fmt->fmt.pix_mp.ycbcr_enc; + output_fmt->fmt.pix_mp.quantization = fmt->fmt.pix_mp.quantization; + + inst->buffers.input.min_count = call_session_op(core, + min_count, inst, MSM_VIDC_BUF_INPUT); + inst->buffers.input.extra_count = call_session_op(core, + extra_count, inst, MSM_VIDC_BUF_INPUT); + if (inst->buffers.input.actual_count < + inst->buffers.input.min_count + + inst->buffers.input.extra_count) { + inst->buffers.input.actual_count = + inst->buffers.input.min_count + + inst->buffers.input.extra_count; + } + inst->buffers.input.size = size; + + if (f->fmt.pix_mp.width != inst->crop.width || + f->fmt.pix_mp.height != inst->crop.height) { + + /* reset crop dimensions with updated resolution */ + inst->crop.top = inst->crop.left = 0; + inst->crop.width = f->fmt.pix_mp.width; + inst->crop.height = f->fmt.pix_mp.height; + + /* reset compose dimensions with updated resolution */ + inst->compose.top = inst->compose.left = 0; + inst->compose.width = f->fmt.pix_mp.width; + inst->compose.height = f->fmt.pix_mp.height; + + /* update output format */ + rc = msm_venc_s_fmt_output(inst, output_fmt); + if (rc) + return rc; + } + + /* reset metadata buffer size with updated resolution*/ + msm_vidc_update_meta_port_settings(inst); + + i_vpr_h(inst, + "%s: type: INPUT, format %s width %d height %d size %u min_count %d extra_count %d\n", + __func__, v4l2_pixelfmt_name(inst, fmt->fmt.pix_mp.pixelformat), + fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height, + fmt->fmt.pix_mp.plane_fmt[0].sizeimage, + inst->buffers.input.min_count, + inst->buffers.input.extra_count); + + /* finally update client format */ + memcpy(f, fmt, sizeof(struct v4l2_format)); + + return rc; +} + +static int msm_venc_s_fmt_input_meta(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + struct v4l2_format *fmt; + struct msm_vidc_core *core; + + core = inst->core; + + fmt = &inst->fmts[INPUT_META_PORT]; + fmt->type = INPUT_META_PLANE; + fmt->fmt.meta.dataformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__); + fmt->fmt.meta.buffersize = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_INPUT_META); + inst->buffers.input_meta.min_count = + inst->buffers.input.min_count; + inst->buffers.input_meta.extra_count = + inst->buffers.input.extra_count; + inst->buffers.input_meta.actual_count = + inst->buffers.input.actual_count; + inst->buffers.input_meta.size = fmt->fmt.meta.buffersize; + + memcpy(f, fmt, sizeof(struct v4l2_format)); + + i_vpr_h(inst, "%s: type: INPUT_META, size %u min_count %d extra_count %d\n", + __func__, fmt->fmt.meta.buffersize, + inst->buffers.input_meta.min_count, + inst->buffers.input_meta.extra_count); + + return rc; +} + +int msm_venc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + + if (f->type == INPUT_MPLANE) { + rc = msm_venc_s_fmt_input(inst, f); + if (rc) + goto exit; + } else if (f->type == INPUT_META_PLANE) { + rc = msm_venc_s_fmt_input_meta(inst, f); + if (rc) + goto exit; + } else if (f->type == OUTPUT_MPLANE) { + rc = msm_venc_s_fmt_output(inst, f); + if (rc) + goto exit; + } else if (f->type == OUTPUT_META_PLANE) { + rc = msm_venc_s_fmt_output_meta(inst, f); + if (rc) + goto exit; + } else { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, f->type); + rc = -EINVAL; + goto exit; + } + +exit: + if (rc) + i_vpr_e(inst, "%s: failed\n", __func__); + + return rc; +} + +int msm_venc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + int port; + + port = v4l2_type_to_driver_port(inst, f->type, __func__); + if (port < 0) + return -EINVAL; + + memcpy(f, &inst->fmts[port], sizeof(struct v4l2_format)); + + return rc; +} + +int msm_venc_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s) +{ + int rc = 0; + struct v4l2_format *output_fmt; + + if (s->type != INPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, s->type); + return -EINVAL; + } + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + if (s->r.left || s->r.top) { + i_vpr_h(inst, "%s: unsupported top %d or left %d\n", + __func__, s->r.left, s->r.top); + s->r.left = s->r.top = 0; + } + if (s->r.width > inst->fmts[INPUT_PORT].fmt.pix_mp.width) { + i_vpr_h(inst, "%s: unsupported width %d, fmt width %d\n", + __func__, s->r.width, + inst->fmts[INPUT_PORT].fmt.pix_mp.width); + s->r.width = inst->fmts[INPUT_PORT].fmt.pix_mp.width; + } + if (s->r.height > inst->fmts[INPUT_PORT].fmt.pix_mp.height) { + i_vpr_h(inst, "%s: unsupported height %d, fmt height %d\n", + __func__, s->r.height, + inst->fmts[INPUT_PORT].fmt.pix_mp.height); + s->r.height = inst->fmts[INPUT_PORT].fmt.pix_mp.height; + } + + inst->crop.left = s->r.left; + inst->crop.top = s->r.top; + inst->crop.width = s->r.width; + inst->crop.height = s->r.height; + /* adjust compose such that it is within crop */ + inst->compose.left = inst->crop.left; + inst->compose.top = inst->crop.top; + inst->compose.width = inst->crop.width; + inst->compose.height = inst->crop.height; + /* update output format based on new crop dimensions */ + output_fmt = &inst->fmts[OUTPUT_PORT]; + rc = msm_venc_s_fmt_output(inst, output_fmt); + if (rc) + return rc; + break; + case V4L2_SEL_TGT_COMPOSE: + if (s->r.left < inst->crop.left) { + i_vpr_e(inst, + "%s: compose left (%d) less than crop left (%d)\n", + __func__, s->r.left, inst->crop.left); + s->r.left = inst->crop.left; + } + if (s->r.top < inst->crop.top) { + i_vpr_e(inst, + "%s: compose top (%d) less than crop top (%d)\n", + __func__, s->r.top, inst->crop.top); + s->r.top = inst->crop.top; + } + if (s->r.width > inst->crop.width) { + i_vpr_e(inst, + "%s: compose width (%d) greate than crop width (%d)\n", + __func__, s->r.width, inst->crop.width); + s->r.width = inst->crop.width; + } + if (s->r.height > inst->crop.height) { + i_vpr_e(inst, + "%s: compose height (%d) greate than crop height (%d)\n", + __func__, s->r.height, inst->crop.height); + s->r.height = inst->crop.height; + } + inst->compose.left = s->r.left; + inst->compose.top = s->r.top; + inst->compose.width = s->r.width; + inst->compose.height = s->r.height; + + if (is_scaling_enabled(inst)) { + i_vpr_h(inst, + "%s: scaling enabled, crop: l %d t %d w %d h %d compose: l %d t %d w %d h %d\n", + __func__, inst->crop.left, inst->crop.top, + inst->crop.width, inst->crop.height, + inst->compose.left, inst->compose.top, + inst->compose.width, inst->compose.height); + } + + /* update output format based on new compose dimensions */ + output_fmt = &inst->fmts[OUTPUT_PORT]; + rc = msm_venc_s_fmt_output(inst, output_fmt); + if (rc) + return rc; + break; + default: + i_vpr_e(inst, "%s: invalid target %d\n", + __func__, s->target); + rc = -EINVAL; + break; + } + if (!rc) + i_vpr_h(inst, "%s: target %d, r [%d, %d, %d, %d]\n", + __func__, s->target, s->r.top, s->r.left, + s->r.width, s->r.height); + return rc; +} + +int msm_venc_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s) +{ + int rc = 0; + + if (s->type != INPUT_MPLANE && s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, s->type); + return -EINVAL; + } + + switch (s->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP: + s->r.left = inst->crop.left; + s->r.top = inst->crop.top; + s->r.width = inst->crop.width; + s->r.height = inst->crop.height; + break; + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_PADDED: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE: + s->r.left = inst->compose.left; + s->r.top = inst->compose.top; + s->r.width = inst->compose.width; + s->r.height = inst->compose.height; + break; + default: + i_vpr_e(inst, "%s: invalid target %d\n", + __func__, s->target); + rc = -EINVAL; + break; + } + if (!rc) + i_vpr_h(inst, "%s: target %d, r [%d, %d, %d, %d]\n", + __func__, s->target, s->r.top, s->r.left, + s->r.width, s->r.height); + return rc; +} + +int msm_venc_s_param(struct msm_vidc_inst *inst, + struct v4l2_streamparm *s_parm) +{ + int rc = 0; + struct v4l2_fract *timeperframe = NULL; + u32 input_rate_q16, max_rate_q16; + u32 input_rate, default_rate; + bool is_frame_rate = false; + + if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* operating rate */ + timeperframe = &s_parm->parm.output.timeperframe; + max_rate_q16 = inst->capabilities[OPERATING_RATE].max; + default_rate = inst->capabilities[OPERATING_RATE].value >> 16; + s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + } else { + /* frame rate */ + timeperframe = &s_parm->parm.capture.timeperframe; + is_frame_rate = true; + max_rate_q16 = inst->capabilities[FRAME_RATE].max; + default_rate = inst->capabilities[FRAME_RATE].value >> 16; + s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + } + + if (!timeperframe->denominator || !timeperframe->numerator) { + i_vpr_e(inst, "%s: type %s, invalid rate, update with default\n", + __func__, v4l2_type_name(s_parm->type)); + if (!timeperframe->numerator) + timeperframe->numerator = 1; + if (!timeperframe->denominator) + timeperframe->denominator = default_rate; + } + + input_rate = (timeperframe->denominator / timeperframe->numerator); + if (input_rate > (max_rate_q16 >> 16)) { + input_rate_q16 = max_rate_q16; + i_vpr_h(inst, "%s: type %s, %s value %u limited to %u\n", + __func__, v4l2_type_name(s_parm->type), + is_frame_rate ? "frame rate" : "operating rate", + input_rate_q16, max_rate_q16); + } else { + input_rate_q16 = input_rate << 16; + input_rate_q16 |= + (timeperframe->denominator % timeperframe->numerator); + } + + i_vpr_h(inst, "%s: type %s, %s value %u.%u\n", + __func__, v4l2_type_name(s_parm->type), + is_frame_rate ? "frame rate" : "operating rate", + input_rate_q16 >> 16, input_rate_q16 & 0xffff); + + msm_vidc_update_cap_value(inst, is_frame_rate ? FRAME_RATE : OPERATING_RATE, + input_rate_q16, __func__); + if (is_realtime_session(inst) && + ((s_parm->type == INPUT_MPLANE && inst->bufq[INPUT_PORT].vb2q->streaming) || + (s_parm->type == OUTPUT_MPLANE && inst->bufq[OUTPUT_PORT].vb2q->streaming))) { + rc = msm_vidc_check_core_mbps(inst); + if (rc) { + i_vpr_e(inst, "%s: unsupported load\n", __func__); + goto reset_rate; + } + } + + if (is_frame_rate) + inst->capabilities[FRAME_RATE].flags |= CAP_FLAG_CLIENT_SET; + else + inst->capabilities[OPERATING_RATE].flags |= CAP_FLAG_CLIENT_SET; + /* + * In static case, frame rate is set via + * inst database set function mentioned in + * FRAME_RATE cap id. + * In dynamic case, frame rate is set like below. + */ + if (inst->bufq[OUTPUT_PORT].vb2q->streaming) { + rc = venus_hfi_session_property(inst, + HFI_PROP_FRAME_RATE, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_Q16, + &input_rate_q16, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, + "%s: failed to set frame rate to fw\n", __func__); + goto exit; + } + inst->auto_framerate = input_rate_q16; + } + + return 0; + +reset_rate: + if (rc) { + i_vpr_e(inst, "%s: setting rate %u failed, reset to %u\n", __func__, + input_rate_q16 >> 16, default_rate); + msm_vidc_update_cap_value(inst, is_frame_rate ? FRAME_RATE : OPERATING_RATE, + default_rate << 16, __func__); + } +exit: + return rc; +} + +int msm_venc_g_param(struct msm_vidc_inst *inst, + struct v4l2_streamparm *s_parm) +{ + struct v4l2_fract *timeperframe = NULL; + + if (s_parm->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + timeperframe = &s_parm->parm.output.timeperframe; + timeperframe->numerator = 1; + timeperframe->denominator = + inst->capabilities[OPERATING_RATE].value >> 16; + s_parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + } else { + timeperframe = &s_parm->parm.capture.timeperframe; + timeperframe->numerator = 1; + timeperframe->denominator = + inst->capabilities[FRAME_RATE].value >> 16; + s_parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + } + + i_vpr_h(inst, "%s: type %s, num %u denom %u\n", + __func__, v4l2_type_name(s_parm->type), timeperframe->numerator, + timeperframe->denominator); + return 0; +} + +int msm_venc_subscribe_event(struct msm_vidc_inst *inst, + const struct v4l2_event_subscription *sub) +{ + int rc = 0; + + switch (sub->type) { + case V4L2_EVENT_EOS: + rc = v4l2_event_subscribe(&inst->fh, sub, MAX_EVENTS, NULL); + break; + case V4L2_EVENT_CTRL: + rc = v4l2_ctrl_subscribe_event(&inst->fh, sub); + break; + default: + i_vpr_e(inst, "%s: invalid type %d id %d\n", __func__, sub->type, sub->id); + return -EINVAL; + } + + if (rc) + i_vpr_e(inst, "%s: failed, type %d id %d\n", + __func__, sub->type, sub->id); + return rc; +} + +int msm_venc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f) +{ + int rc = 0; + struct msm_vidc_core *core; + u32 array[32] = {0}; + u32 i = 0; + + if (f->index >= ARRAY_SIZE(array)) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + + if (f->type == OUTPUT_MPLANE) { + u32 codecs = core->capabilities[ENC_CODECS].value; + u32 idx = 0; + + for (i = 0; i <= 31; i++) { + if (codecs & BIT(i)) { + if (idx >= ARRAY_SIZE(array)) + break; + /* v4l2-compliance does not support private codecs */ + if ((codecs & BIT(i)) == MSM_VIDC_HEIC) + continue; + array[idx] = codecs & BIT(i); + idx++; + } + } + if (!array[f->index]) + return -EINVAL; + f->pixelformat = v4l2_codec_from_driver(inst, array[f->index], + __func__); + if (!f->pixelformat) + return -EINVAL; + f->flags = V4L2_FMT_FLAG_COMPRESSED; + strlcpy(f->description, "codec", sizeof(f->description)); + } else if (f->type == INPUT_MPLANE) { + u32 formats = inst->capabilities[PIX_FMTS].step_or_mask; + u32 idx = 0; + + for (i = 0; i <= 31; i++) { + if (formats & BIT(i)) { + if (idx >= ARRAY_SIZE(array)) + break; + array[idx] = formats & BIT(i); + idx++; + } + } + if (!array[f->index]) + return -EINVAL; + f->pixelformat = v4l2_colorformat_from_driver(inst, array[f->index], + __func__); + if (!f->pixelformat) + return -EINVAL; + strlcpy(f->description, "colorformat", sizeof(f->description)); + } else if (f->type == INPUT_META_PLANE || f->type == OUTPUT_META_PLANE) { + if (!f->index) { + f->pixelformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__); + strlcpy(f->description, "metadata", sizeof(f->description)); + } else { + return -EINVAL; + } + } + memset(f->reserved, 0, sizeof(f->reserved)); + + i_vpr_h(inst, "%s: index %d, %s: %s, flags %#x\n", + __func__, f->index, f->description, + v4l2_pixelfmt_name(inst, f->pixelformat), f->flags); + return rc; +} + +int msm_venc_inst_init(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + struct v4l2_format *f; + enum msm_vidc_colorformat_type colorformat; + + i_vpr_h(inst, "%s()\n", __func__); + + core = inst->core; + + if (core->capabilities[DCVS].value) + inst->power.dcvs_mode = true; + + f = &inst->fmts[OUTPUT_PORT]; + f->type = OUTPUT_MPLANE; + f->fmt.pix_mp.width = DEFAULT_WIDTH; + f->fmt.pix_mp.height = DEFAULT_HEIGHT; + f->fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264; + f->fmt.pix_mp.num_planes = 1; + f->fmt.pix_mp.plane_fmt[0].bytesperline = 0; + f->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_OUTPUT); + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; + inst->buffers.output.min_count = call_session_op(core, + min_count, inst, MSM_VIDC_BUF_OUTPUT); + inst->buffers.output.extra_count = call_session_op(core, + extra_count, inst, MSM_VIDC_BUF_OUTPUT); + inst->buffers.output.actual_count = + inst->buffers.output.min_count + + inst->buffers.output.extra_count; + inst->buffers.output.size = f->fmt.pix_mp.plane_fmt[0].sizeimage; + + inst->crop.left = inst->crop.top = 0; + inst->crop.width = f->fmt.pix_mp.width; + inst->crop.height = f->fmt.pix_mp.height; + + inst->compose.left = inst->compose.top = 0; + inst->compose.width = f->fmt.pix_mp.width; + inst->compose.height = f->fmt.pix_mp.height; + + f = &inst->fmts[OUTPUT_META_PORT]; + f->type = OUTPUT_META_PLANE; + f->fmt.meta.dataformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__); + f->fmt.meta.buffersize = MSM_VIDC_METADATA_SIZE; + inst->buffers.output_meta.min_count = 0; + inst->buffers.output_meta.extra_count = 0; + inst->buffers.output_meta.actual_count = 0; + inst->buffers.output_meta.size = 0; + + f = &inst->fmts[INPUT_PORT]; + f->type = INPUT_MPLANE; + f->fmt.pix_mp.pixelformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_NV12C, __func__); + f->fmt.pix_mp.width = DEFAULT_WIDTH; + f->fmt.pix_mp.height = DEFAULT_HEIGHT; + f->fmt.pix_mp.num_planes = 1; + colorformat = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat, + __func__); + f->fmt.pix_mp.plane_fmt[0].bytesperline = + video_y_stride_bytes(colorformat, DEFAULT_WIDTH); + f->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_INPUT); + f->fmt.pix_mp.field = V4L2_FIELD_NONE; + f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_DEFAULT; + f->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_DEFAULT; + f->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + f->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; + inst->buffers.input.min_count = call_session_op(core, + min_count, inst, MSM_VIDC_BUF_INPUT); + inst->buffers.input.extra_count = call_session_op(core, + extra_count, inst, MSM_VIDC_BUF_INPUT); + inst->buffers.input.actual_count = + inst->buffers.input.min_count + + inst->buffers.input.extra_count; + inst->buffers.input.size = f->fmt.pix_mp.plane_fmt[0].sizeimage; + + f = &inst->fmts[INPUT_META_PORT]; + f->type = INPUT_META_PLANE; + f->fmt.meta.dataformat = + v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__); + f->fmt.meta.buffersize = MSM_VIDC_METADATA_SIZE; + inst->buffers.input_meta.min_count = 0; + inst->buffers.input_meta.extra_count = 0; + inst->buffers.input_meta.actual_count = 0; + inst->buffers.input_meta.size = 0; + + inst->hfi_rc_type = HFI_RC_VBR_CFR; + inst->hfi_layer_type = HFI_HIER_P_SLIDING_WINDOW; + + rc = msm_venc_codec_change(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat); + if (rc) + return rc; + + return rc; +} + +int msm_venc_inst_deinit(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = msm_vidc_ctrl_handler_deinit(inst); + if (rc) + return rc; + + return rc; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc.c new file mode 100644 index 0000000000..d8709f6f7d --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc.c @@ -0,0 +1,890 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include + +#include "msm_vidc_core.h" +#include "msm_vidc_inst.h" +#include "msm_vdec.h" +#include "msm_venc.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_vb2.h" +#include "msm_vidc_v4l2.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_control.h" +#include "msm_vidc_power.h" +#include "msm_vidc_fence.h" +#include "msm_vidc_memory.h" +#include "venus_hfi_response.h" +#include "msm_vidc.h" + +extern const char video_banner[]; + +#define MSM_VIDC_DRV_NAME "msm_vidc_driver" +#define MSM_VIDC_BUS_NAME "platform:msm_vidc_bus" + +/* kernel/msm-4.19 */ +#define MSM_VIDC_VERSION ((5 << 16) + (10 << 8) + 0) + +static inline bool valid_v4l2_buffer(struct v4l2_buffer *b, + struct msm_vidc_inst *inst) +{ + if (b->type == INPUT_MPLANE || b->type == OUTPUT_MPLANE) + return b->length > 0; + else if (b->type == INPUT_META_PLANE || b->type == OUTPUT_META_PLANE) + return true; + + return false; +} + +static int get_poll_flags(struct msm_vidc_inst *inst, u32 port) +{ + int poll = 0; + struct vb2_queue *q = NULL; + struct vb2_buffer *vb = NULL; + unsigned long flags = 0; + + if (port >= MAX_PORT) { + d_vpr_e("%s: invalid params, inst %pK, port %d\n", + __func__, inst, port); + return poll; + } + q = inst->bufq[port].vb2q; + + spin_lock_irqsave(&q->done_lock, flags); + if (!list_empty(&q->done_list)) + vb = list_first_entry(&q->done_list, struct vb2_buffer, + done_entry); + if (vb && (vb->state == VB2_BUF_STATE_DONE || + vb->state == VB2_BUF_STATE_ERROR)) { + if (port == OUTPUT_PORT || port == OUTPUT_META_PORT) + poll |= POLLIN | POLLRDNORM; + else if (port == INPUT_PORT || port == INPUT_META_PORT) + poll |= POLLOUT | POLLWRNORM; + } + spin_unlock_irqrestore(&q->done_lock, flags); + + return poll; +} + +int msm_vidc_poll(struct msm_vidc_inst *inst, struct file *filp, + struct poll_table_struct *wait) +{ + int poll = 0; + + poll_wait(filp, &inst->fh.wait, wait); + poll_wait(filp, &inst->bufq[INPUT_META_PORT].vb2q->done_wq, wait); + poll_wait(filp, &inst->bufq[OUTPUT_META_PORT].vb2q->done_wq, wait); + poll_wait(filp, &inst->bufq[INPUT_PORT].vb2q->done_wq, wait); + poll_wait(filp, &inst->bufq[OUTPUT_PORT].vb2q->done_wq, wait); + + if (v4l2_event_pending(&inst->fh)) + poll |= POLLPRI; + + poll |= get_poll_flags(inst, INPUT_META_PORT); + poll |= get_poll_flags(inst, OUTPUT_META_PORT); + poll |= get_poll_flags(inst, INPUT_PORT); + poll |= get_poll_flags(inst, OUTPUT_PORT); + + return poll; +} + +int msm_vidc_querycap(struct msm_vidc_inst *inst, struct v4l2_capability *cap) +{ + strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver)); + strlcpy(cap->bus_info, MSM_VIDC_BUS_NAME, sizeof(cap->bus_info)); + cap->version = MSM_VIDC_VERSION; + + memset(cap->reserved, 0, sizeof(cap->reserved)); + + if (is_decode_session(inst)) + strlcpy(cap->card, "msm_vidc_decoder", sizeof(cap->card)); + else if (is_encode_session(inst)) + strlcpy(cap->card, "msm_vidc_encoder", sizeof(cap->card)); + else + return -EINVAL; + + return 0; +} + +int msm_vidc_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f) +{ + if (is_decode_session(inst)) + return msm_vdec_enum_fmt(inst, f); + if (is_encode_session(inst)) + return msm_venc_enum_fmt(inst, f); + + return -EINVAL; +} + +int msm_vidc_query_ctrl(struct msm_vidc_inst *inst, struct v4l2_queryctrl *q_ctrl) +{ + int rc = 0; + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, q_ctrl->id); + if (!ctrl) { + i_vpr_e(inst, "%s: get_ctrl failed for id %d\n", + __func__, q_ctrl->id); + return -EINVAL; + } + q_ctrl->minimum = ctrl->minimum; + q_ctrl->maximum = ctrl->maximum; + q_ctrl->default_value = ctrl->default_value; + q_ctrl->flags = 0; + q_ctrl->step = ctrl->step; + i_vpr_h(inst, + "query ctrl: %s: min %d, max %d, default %d step %d flags %#x\n", + ctrl->name, q_ctrl->minimum, q_ctrl->maximum, + q_ctrl->default_value, q_ctrl->step, q_ctrl->flags); + return rc; +} + +int msm_vidc_query_menu(struct msm_vidc_inst *inst, struct v4l2_querymenu *qmenu) +{ + int rc = 0; + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, qmenu->id); + if (!ctrl) { + i_vpr_e(inst, "%s: get_ctrl failed for id %d\n", + __func__, qmenu->id); + return -EINVAL; + } + if (ctrl->type != V4L2_CTRL_TYPE_MENU) { + i_vpr_e(inst, "%s: ctrl: %s: type (%d) is not MENU type\n", + __func__, ctrl->name, ctrl->type); + return -EINVAL; + } + if (qmenu->index < ctrl->minimum || qmenu->index > ctrl->maximum) + return -EINVAL; + + if (ctrl->menu_skip_mask & (1 << qmenu->index)) + rc = -EINVAL; + + i_vpr_h(inst, + "%s: ctrl: %s: min %lld, max %lld, menu_skip_mask %lld, qmenu: id %u, index %d, %s\n", + __func__, ctrl->name, ctrl->minimum, ctrl->maximum, + ctrl->menu_skip_mask, qmenu->id, qmenu->index, + rc ? "not supported" : "supported"); + return rc; +} + +int msm_vidc_try_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + + if (is_decode_session(inst)) + rc = msm_vdec_try_fmt(inst, f); + if (is_encode_session(inst)) + rc = msm_venc_try_fmt(inst, f); + + if (rc) + i_vpr_e(inst, "%s: try_fmt(%d) failed %d\n", + __func__, f->type, rc); + return rc; +} + +int msm_vidc_s_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + + if (is_decode_session(inst)) + rc = msm_vdec_s_fmt(inst, f); + if (is_encode_session(inst)) + rc = msm_venc_s_fmt(inst, f); + + if (rc) + i_vpr_e(inst, "%s: s_fmt(%d) failed %d\n", + __func__, f->type, rc); + return rc; +} + +int msm_vidc_g_fmt(struct msm_vidc_inst *inst, struct v4l2_format *f) +{ + int rc = 0; + + if (is_decode_session(inst)) + rc = msm_vdec_g_fmt(inst, f); + if (is_encode_session(inst)) + rc = msm_venc_g_fmt(inst, f); + if (rc) + return rc; + + if (f->type == INPUT_MPLANE || f->type == OUTPUT_MPLANE) + i_vpr_h(inst, "%s: type %s format %s width %d height %d size %d\n", + __func__, v4l2_type_name(f->type), + v4l2_pixelfmt_name(inst, f->fmt.pix_mp.pixelformat), + f->fmt.pix_mp.width, f->fmt.pix_mp.height, + f->fmt.pix_mp.plane_fmt[0].sizeimage); + else if (f->type == INPUT_META_PLANE || f->type == OUTPUT_META_PLANE) + i_vpr_h(inst, "%s: type %s size %d\n", + __func__, v4l2_type_name(f->type), f->fmt.meta.buffersize); + + return 0; +} + +int msm_vidc_s_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s) +{ + int rc = 0; + + if (is_decode_session(inst)) + rc = msm_vdec_s_selection(inst, s); + if (is_encode_session(inst)) + rc = msm_venc_s_selection(inst, s); + + return rc; +} + +int msm_vidc_g_selection(struct msm_vidc_inst *inst, struct v4l2_selection *s) +{ + int rc = 0; + + if (is_decode_session(inst)) + rc = msm_vdec_g_selection(inst, s); + if (is_encode_session(inst)) + rc = msm_venc_g_selection(inst, s); + + return rc; +} + +int msm_vidc_s_param(struct msm_vidc_inst *inst, struct v4l2_streamparm *param) +{ + int rc = 0; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + param->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + if (is_encode_session(inst)) { + rc = msm_venc_s_param(inst, param); + } else { + i_vpr_e(inst, "%s: invalid domain %#x\n", + __func__, inst->domain); + return -EINVAL; + } + + return rc; +} + +int msm_vidc_g_param(struct msm_vidc_inst *inst, struct v4l2_streamparm *param) +{ + int rc = 0; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE && + param->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return -EINVAL; + + if (is_encode_session(inst)) { + rc = msm_venc_g_param(inst, param); + } else { + i_vpr_e(inst, "%s: invalid domain %#x\n", + __func__, inst->domain); + return -EINVAL; + } + + return rc; +} + +int msm_vidc_reqbufs(struct msm_vidc_inst *inst, struct v4l2_requestbuffers *b) +{ + int rc = 0; + int port; + + port = v4l2_type_to_driver_port(inst, b->type, __func__); + if (port < 0) { + rc = -EINVAL; + goto exit; + } + + rc = vb2_reqbufs(inst->bufq[port].vb2q, b); + if (rc) { + i_vpr_e(inst, "%s: vb2_reqbufs(%d) failed, %d\n", + __func__, b->type, rc); + goto exit; + } + +exit: + return rc; +} + +int msm_vidc_querybuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) +{ + int rc = 0; + int port; + + port = v4l2_type_to_driver_port(inst, b->type, __func__); + if (port < 0) { + rc = -EINVAL; + goto exit; + } + + rc = vb2_querybuf(inst->bufq[port].vb2q, b); + if (rc) { + i_vpr_e(inst, "%s: vb2_querybuf(%d) failed, %d\n", + __func__, b->type, rc); + goto exit; + } + +exit: + return rc; +} + +int msm_vidc_create_bufs(struct msm_vidc_inst *inst, struct v4l2_create_buffers *b) +{ + int rc = 0; + int port; + struct v4l2_format *f; + + f = &b->format; + port = v4l2_type_to_driver_port(inst, f->type, __func__); + if (port < 0) { + rc = -EINVAL; + goto exit; + } + + rc = vb2_create_bufs(inst->bufq[port].vb2q, b); + if (rc) { + i_vpr_e(inst, "%s: vb2_create_bufs(%d) failed, %d\n", + __func__, f->type, rc); + goto exit; + } + +exit: + return rc; +} + +int msm_vidc_prepare_buf(struct msm_vidc_inst *inst, struct media_device *mdev, + struct v4l2_buffer *b) +{ + int rc = 0; + struct vb2_queue *q; + + if (!valid_v4l2_buffer(b, inst)) { + d_vpr_e("%s: invalid params %pK %pK\n", __func__, inst, b); + return -EINVAL; + } + + q = msm_vidc_get_vb2q(inst, b->type, __func__); + if (!q) { + rc = -EINVAL; + goto exit; + } + + rc = vb2_prepare_buf(q, mdev, b); + if (rc) { + i_vpr_e(inst, "%s: failed with %d\n", __func__, rc); + goto exit; + } + +exit: + return rc; +} + +int msm_vidc_qbuf(struct msm_vidc_inst *inst, struct media_device *mdev, + struct v4l2_buffer *b) +{ + int rc = 0; + struct vb2_queue *q; + + if (!valid_v4l2_buffer(b, inst)) { + d_vpr_e("%s: invalid params %pK %pK\n", __func__, inst, b); + return -EINVAL; + } + + q = msm_vidc_get_vb2q(inst, b->type, __func__); + if (!q) { + rc = -EINVAL; + goto exit; + } + + rc = vb2_qbuf(q, mdev, b); + if (rc) + i_vpr_e(inst, "%s: failed with %d\n", __func__, rc); + +exit: + return rc; +} + +int msm_vidc_dqbuf(struct msm_vidc_inst *inst, struct v4l2_buffer *b) +{ + int rc = 0; + struct vb2_queue *q; + + if (!valid_v4l2_buffer(b, inst)) { + d_vpr_e("%s: invalid params %pK %pK\n", __func__, inst, b); + return -EINVAL; + } + + q = msm_vidc_get_vb2q(inst, b->type, __func__); + if (!q) { + rc = -EINVAL; + goto exit; + } + + rc = vb2_dqbuf(q, b, true); + if (rc == -EAGAIN) { + goto exit; + } else if (rc) { + i_vpr_l(inst, "%s: failed with %d\n", __func__, rc); + goto exit; + } + +exit: + return rc; +} + +int msm_vidc_streamon(struct msm_vidc_inst *inst, enum v4l2_buf_type type) +{ + int rc = 0; + int port; + + port = v4l2_type_to_driver_port(inst, type, __func__); + if (port < 0) { + rc = -EINVAL; + goto exit; + } + + rc = vb2_streamon(inst->bufq[port].vb2q, type); + if (rc) { + i_vpr_e(inst, "%s: vb2_streamon(%d) failed, %d\n", + __func__, type, rc); + goto exit; + } + +exit: + return rc; +} + +int msm_vidc_streamoff(struct msm_vidc_inst *inst, enum v4l2_buf_type type) +{ + int rc = 0; + int port; + + port = v4l2_type_to_driver_port(inst, type, __func__); + if (port < 0) { + rc = -EINVAL; + goto exit; + } + + rc = vb2_streamoff(inst->bufq[port].vb2q, type); + if (rc) { + i_vpr_e(inst, "%s: vb2_streamoff(%d) failed, %d\n", + __func__, type, rc); + goto exit; + } + +exit: + return rc; +} + +int msm_vidc_try_cmd(struct msm_vidc_inst *inst, union msm_v4l2_cmd *cmd) +{ + int rc = 0; + struct v4l2_decoder_cmd *dec = NULL; + struct v4l2_encoder_cmd *enc = NULL; + + if (is_decode_session(inst)) { + dec = (struct v4l2_decoder_cmd *)cmd; + i_vpr_h(inst, "%s: cmd %d\n", __func__, dec->cmd); + if (dec->cmd != V4L2_DEC_CMD_STOP && dec->cmd != V4L2_DEC_CMD_START) + return -EINVAL; + dec->flags = 0; + if (dec->cmd == V4L2_DEC_CMD_STOP) { + dec->stop.pts = 0; + } else if (dec->cmd == V4L2_DEC_CMD_START) { + dec->start.speed = 0; + dec->start.format = V4L2_DEC_START_FMT_NONE; + } + } else if (is_encode_session(inst)) { + enc = (struct v4l2_encoder_cmd *)cmd; + i_vpr_h(inst, "%s: cmd %d\n", __func__, enc->cmd); + if (enc->cmd != V4L2_ENC_CMD_STOP && enc->cmd != V4L2_ENC_CMD_START) + return -EINVAL; + enc->flags = 0; + } + + return rc; +} + +int msm_vidc_start_cmd(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!is_decode_session(inst) && !is_encode_session(inst)) { + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return -EINVAL; + } + + if (is_decode_session(inst)) { + rc = msm_vdec_start_cmd(inst); + if (rc) + return rc; + } else if (is_encode_session(inst)) { + rc = msm_venc_start_cmd(inst); + if (rc) + return rc; + } + + return rc; +} + +int msm_vidc_stop_cmd(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!is_decode_session(inst) && !is_encode_session(inst)) { + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return -EINVAL; + } + + if (is_decode_session(inst)) { + rc = msm_vdec_stop_cmd(inst); + if (rc) + return rc; + } else if (is_encode_session(inst)) { + rc = msm_venc_stop_cmd(inst); + if (rc) + return rc; + } + + return rc; +} + +int msm_vidc_enum_framesizes(struct msm_vidc_inst *inst, struct v4l2_frmsizeenum *fsize) +{ + enum msm_vidc_colorformat_type colorfmt; + enum msm_vidc_codec_type codec; + u32 meta_fmt; + + /* only index 0 allowed as per v4l2 spec */ + if (fsize->index) + return -EINVAL; + + meta_fmt = v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__); + if (fsize->pixel_format != meta_fmt) { + /* validate pixel format */ + codec = v4l2_codec_to_driver(inst, fsize->pixel_format, __func__); + if (!codec) { + colorfmt = v4l2_colorformat_to_driver(inst, fsize->pixel_format, + __func__); + if (colorfmt == MSM_VIDC_FMT_NONE) { + i_vpr_e(inst, "%s: unsupported pix fmt %#x\n", + __func__, fsize->pixel_format); + return -EINVAL; + } + } + } + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = inst->capabilities[FRAME_WIDTH].min; + fsize->stepwise.max_width = inst->capabilities[FRAME_WIDTH].max; + fsize->stepwise.step_width = + inst->capabilities[FRAME_WIDTH].step_or_mask; + fsize->stepwise.min_height = inst->capabilities[FRAME_HEIGHT].min; + fsize->stepwise.max_height = inst->capabilities[FRAME_HEIGHT].max; + fsize->stepwise.step_height = + inst->capabilities[FRAME_HEIGHT].step_or_mask; + + return 0; +} + +int msm_vidc_enum_frameintervals(struct msm_vidc_inst *inst, struct v4l2_frmivalenum *fival) +{ + struct msm_vidc_core *core; + enum msm_vidc_colorformat_type colorfmt; + u32 fps, mbpf; + u32 meta_fmt; + + if (is_decode_session(inst)) { + i_vpr_e(inst, "%s: not supported by decoder\n", __func__); + return -ENOTTY; + } + + core = inst->core; + + + /* only index 0 allowed as per v4l2 spec */ + if (fival->index) + return -EINVAL; + + meta_fmt = v4l2_colorformat_from_driver(inst, MSM_VIDC_FMT_META, __func__); + if (fival->pixel_format != meta_fmt) { + /* validate pixel format */ + colorfmt = v4l2_colorformat_to_driver(inst, fival->pixel_format, __func__); + if (colorfmt == MSM_VIDC_FMT_NONE) { + i_vpr_e(inst, "%s: unsupported pix fmt %#x\n", + __func__, fival->pixel_format); + return -EINVAL; + } + } + + /* validate resolution */ + if (fival->width > inst->capabilities[FRAME_WIDTH].max || + fival->width < inst->capabilities[FRAME_WIDTH].min || + fival->height > inst->capabilities[FRAME_HEIGHT].max || + fival->height < inst->capabilities[FRAME_HEIGHT].min) { + i_vpr_e(inst, "%s: unsupported resolution %u x %u\n", __func__, + fival->width, fival->height); + return -EINVAL; + } + + /* calculate max supported fps for a given resolution */ + mbpf = NUM_MBS_PER_FRAME(fival->height, fival->width); + fps = core->capabilities[MAX_MBPS].value / mbpf; + + fival->type = V4L2_FRMIVAL_TYPE_STEPWISE; + fival->stepwise.min.numerator = 1; + fival->stepwise.min.denominator = + min_t(u32, fps, inst->capabilities[FRAME_RATE].max); + fival->stepwise.max.numerator = 1; + fival->stepwise.max.denominator = 1; + fival->stepwise.step.numerator = 1; + fival->stepwise.step.denominator = inst->capabilities[FRAME_RATE].max; + + return 0; +} + +int msm_vidc_subscribe_event(struct msm_vidc_inst *inst, + const struct v4l2_event_subscription *sub) +{ + int rc = 0; + + i_vpr_h(inst, "%s: type %d id %d\n", __func__, sub->type, sub->id); + + if (is_decode_session(inst)) + rc = msm_vdec_subscribe_event(inst, sub); + if (is_encode_session(inst)) + rc = msm_venc_subscribe_event(inst, sub); + + return rc; +} + +int msm_vidc_unsubscribe_event(struct msm_vidc_inst *inst, + const struct v4l2_event_subscription *sub) +{ + int rc = 0; + + i_vpr_h(inst, "%s: type %d id %d\n", __func__, sub->type, sub->id); + rc = v4l2_event_unsubscribe(&inst->fh, sub); + if (rc) + i_vpr_e(inst, "%s: failed, type %d id %d\n", + __func__, sub->type, sub->id); + return rc; +} + +int msm_vidc_dqevent(struct msm_vidc_inst *inst, struct v4l2_event *event) +{ + int rc = 0; + + rc = v4l2_event_dequeue(&inst->fh, event, false); + if (rc) + i_vpr_e(inst, "%s: fialed\n", __func__); + return rc; +} + +void *msm_vidc_open(struct msm_vidc_core *core, u32 session_type) +{ + int rc = 0; + struct msm_vidc_inst *inst = NULL; + int i = 0; + + d_vpr_h("%s: %s\n", __func__, video_banner); + + if (session_type != MSM_VIDC_DECODER && + session_type != MSM_VIDC_ENCODER) { + d_vpr_e("%s: invalid session_type %d\n", + __func__, session_type); + return NULL; + } + + rc = msm_vidc_core_init(core); + if (rc) + return NULL; + + rc = msm_vidc_core_init_wait(core); + if (rc) + return NULL; + + inst = vzalloc(sizeof(*inst)); + if (!inst) { + d_vpr_e("%s: allocation failed\n", __func__); + return NULL; + } + + inst->core = core; + inst->domain = session_type; + inst->session_id = hash32_ptr(inst); + msm_vidc_update_state(inst, MSM_VIDC_OPEN, __func__); + inst->sub_state = MSM_VIDC_SUB_STATE_NONE; + strlcpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name)); + inst->active = true; + inst->request = false; + inst->ipsc_properties_set = false; + inst->opsc_properties_set = false; + inst->caps_list_prepared = false; + inst->has_bframe = false; + inst->iframe = false; + inst->auto_framerate = DEFAULT_FPS << 16; + inst->initial_time_us = ktime_get_ns() / 1000; + kref_init(&inst->kref); + mutex_init(&inst->lock); + mutex_init(&inst->ctx_q_lock); + mutex_init(&inst->client_lock); + msm_vidc_update_debug_str(inst); + i_vpr_h(inst, "Opening video instance: %d\n", session_type); + + rc = msm_vidc_add_session(inst); + if (rc) { + i_vpr_e(inst, "%s: failed to add session\n", __func__); + goto fail_add_session; + } + + rc = msm_vidc_pools_init(inst); + if (rc) { + i_vpr_e(inst, "%s: failed to init pool buffers\n", __func__); + goto fail_pools_init; + } + INIT_LIST_HEAD(&inst->caps_list); + INIT_LIST_HEAD(&inst->timestamps.list); + INIT_LIST_HEAD(&inst->ts_reorder.list); + INIT_LIST_HEAD(&inst->buffers.input.list); + INIT_LIST_HEAD(&inst->buffers.input_meta.list); + INIT_LIST_HEAD(&inst->buffers.output.list); + INIT_LIST_HEAD(&inst->buffers.output_meta.list); + INIT_LIST_HEAD(&inst->buffers.read_only.list); + INIT_LIST_HEAD(&inst->buffers.bin.list); + INIT_LIST_HEAD(&inst->buffers.arp.list); + INIT_LIST_HEAD(&inst->buffers.comv.list); + INIT_LIST_HEAD(&inst->buffers.non_comv.list); + INIT_LIST_HEAD(&inst->buffers.line.list); + INIT_LIST_HEAD(&inst->buffers.dpb.list); + INIT_LIST_HEAD(&inst->buffers.persist.list); + INIT_LIST_HEAD(&inst->buffers.vpss.list); + INIT_LIST_HEAD(&inst->buffers.partial_data.list); + INIT_LIST_HEAD(&inst->mem_info.bin.list); + INIT_LIST_HEAD(&inst->mem_info.arp.list); + INIT_LIST_HEAD(&inst->mem_info.comv.list); + INIT_LIST_HEAD(&inst->mem_info.non_comv.list); + INIT_LIST_HEAD(&inst->mem_info.line.list); + INIT_LIST_HEAD(&inst->mem_info.dpb.list); + INIT_LIST_HEAD(&inst->mem_info.persist.list); + INIT_LIST_HEAD(&inst->mem_info.vpss.list); + INIT_LIST_HEAD(&inst->mem_info.partial_data.list); + INIT_LIST_HEAD(&inst->children_list); + INIT_LIST_HEAD(&inst->firmware_list); + INIT_LIST_HEAD(&inst->enc_input_crs); + INIT_LIST_HEAD(&inst->dmabuf_tracker); + INIT_LIST_HEAD(&inst->input_timer_list); + INIT_LIST_HEAD(&inst->pending_pkts); + INIT_LIST_HEAD(&inst->fence_list); + INIT_LIST_HEAD(&inst->buffer_stats_list); + for (i = 0; i < MAX_SIGNAL; i++) + init_completion(&inst->completions[i]); + + inst->workq = create_singlethread_workqueue("workq"); + if (!inst->workq) { + i_vpr_e(inst, "%s: create workq failed\n", __func__); + goto fail_create_workq; + } + + INIT_DELAYED_WORK(&inst->stats_work, msm_vidc_stats_handler); + INIT_WORK(&inst->stability_work, msm_vidc_stability_handler); + + rc = msm_vidc_v4l2_fh_init(inst); + if (rc) + goto fail_eventq_init; + + rc = msm_vidc_vb2_queue_init(inst); + if (rc) + goto fail_vb2q_init; + + if (is_decode_session(inst)) + rc = msm_vdec_inst_init(inst); + else if (is_encode_session(inst)) + rc = msm_venc_inst_init(inst); + if (rc) + goto fail_inst_init; + + rc = msm_vidc_fence_init(inst); + if (rc) + goto fail_fence_init; + + /* reset clock residency stats */ + msm_vidc_reset_residency_stats(core); + + msm_vidc_scale_power(inst, true); + + rc = msm_vidc_session_open(inst); + if (rc) { + msm_vidc_core_deinit(core, true); + goto fail_session_open; + } + + inst->debugfs_root = + msm_vidc_debugfs_init_inst(inst, core->debugfs_root); + if (!inst->debugfs_root) + i_vpr_h(inst, "%s: debugfs not available\n", __func__); + + return inst; + +fail_session_open: + msm_vidc_fence_deinit(inst); +fail_fence_init: + if (is_decode_session(inst)) + msm_vdec_inst_deinit(inst); + else if (is_encode_session(inst)) + msm_venc_inst_deinit(inst); +fail_inst_init: + msm_vidc_vb2_queue_deinit(inst); +fail_vb2q_init: + msm_vidc_v4l2_fh_deinit(inst); +fail_eventq_init: + destroy_workqueue(inst->workq); +fail_create_workq: + msm_vidc_pools_deinit(inst); +fail_pools_init: + msm_vidc_remove_session(inst); + msm_vidc_remove_dangling_session(inst); +fail_add_session: + mutex_destroy(&inst->client_lock); + mutex_destroy(&inst->ctx_q_lock); + mutex_destroy(&inst->lock); + vfree(inst); + return NULL; +} + +int msm_vidc_close(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + + core = inst->core; + + i_vpr_h(inst, "%s()\n", __func__); + client_lock(inst, __func__); + inst_lock(inst, __func__); + /* print final stats */ + msm_vidc_print_stats(inst); + /* print internal buffer memory usage stats */ + msm_vidc_print_memory_stats(inst); + msm_vidc_print_residency_stats(core); + msm_vidc_session_close(inst); + msm_vidc_change_state(inst, MSM_VIDC_CLOSE, __func__); + inst->sub_state = MSM_VIDC_SUB_STATE_NONE; + strscpy(inst->sub_state_name, "SUB_STATE_NONE", sizeof(inst->sub_state_name)); + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + cancel_stability_work_sync(inst); + cancel_stats_work_sync(inst); + msm_vidc_show_stats(inst); + put_inst(inst); + msm_vidc_schedule_core_deinit(core); + + return rc; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_buffer.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_buffer.c new file mode 100644 index 0000000000..65ae24e4c2 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_buffer.c @@ -0,0 +1,453 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_media_info.h" +#include "msm_vidc_buffer.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_debug.h" + +/* Generic function for all targets. Not being used for iris2 */ +u32 msm_vidc_input_min_count(struct msm_vidc_inst *inst) +{ + u32 input_min_count = 0; + u32 hb_enh_layer = 0; + + if (is_decode_session(inst)) { + input_min_count = MIN_DEC_INPUT_BUFFERS; + } else if (is_encode_session(inst)) { + input_min_count = MIN_ENC_INPUT_BUFFERS; + if (is_hierb_type_requested(inst)) { + hb_enh_layer = + inst->capabilities[ENH_LAYER_COUNT].value; + if (inst->codec == MSM_VIDC_H264 && + !inst->capabilities[LAYER_ENABLE].value) { + hb_enh_layer = 0; + } + if (hb_enh_layer) + input_min_count = (1 << hb_enh_layer) + 2; + } + } else { + i_vpr_e(inst, "%s: invalid domain %d\n", + __func__, inst->domain); + return 0; + } + + if (is_thumbnail_session(inst) || is_image_session(inst)) + input_min_count = 1; + + return input_min_count; +} + +u32 msm_vidc_output_min_count(struct msm_vidc_inst *inst) +{ + u32 output_min_count; + + if (!is_decode_session(inst) && !is_encode_session(inst)) + return 0; + + if (is_thumbnail_session(inst)) + return 1; + + if (is_encode_session(inst)) + return MIN_ENC_OUTPUT_BUFFERS; + + /* decoder handling below */ + /* fw_min_count > 0 indicates reconfig event has already arrived */ + if (inst->fw_min_count) { + /* TODO: need to update condition to include AVC/HEVC as well */ + if (is_split_mode_enabled(inst) && + (inst->codec == MSM_VIDC_AV1 || + inst->codec == MSM_VIDC_VP9)) { + /* + * return opb min buffer count as min(4, fw_min_count) + * fw min count is used for dpb min count + */ + return min_t(u32, 4, inst->fw_min_count); + } else { + return inst->fw_min_count; + } + } + + /* initial handling before reconfig event arrived */ + switch (inst->codec) { + case MSM_VIDC_H264: + case MSM_VIDC_HEVC: + output_min_count = 4; + break; + case MSM_VIDC_VP9: + output_min_count = 9; + break; + case MSM_VIDC_AV1: + output_min_count = 11; + break; + case MSM_VIDC_HEIC: + output_min_count = 3; + break; + default: + output_min_count = 4; + break; + } + + return output_min_count; +} + +u32 msm_vidc_input_extra_count(struct msm_vidc_inst *inst) +{ + u32 count = 0; + struct msm_vidc_core *core; + + core = inst->core; + + /* + * no extra buffers for thumbnail session because + * neither dcvs nor batching will be enabled + */ + if (is_thumbnail_session(inst) || is_image_session(inst)) + return 0; + + if (is_decode_session(inst)) { + /* + * if decode batching enabled, ensure minimum batch size + * count of input buffers present on input port + */ + if (core->capabilities[DECODE_BATCH].value && + inst->decode_batch.enable) { + if (inst->buffers.input.min_count < inst->decode_batch.size) { + count = inst->decode_batch.size - + inst->buffers.input.min_count; + } + } + } else if (is_encode_session(inst)) { + /* add dcvs buffers, if platform supports dcvs */ + if (core->capabilities[DCVS].value) + count = DCVS_ENC_EXTRA_INPUT_BUFFERS; + } + + return count; +} + +u32 msm_vidc_output_extra_count(struct msm_vidc_inst *inst) +{ + u32 count = 0; + struct msm_vidc_core *core; + + core = inst->core; + + /* + * no extra buffers for thumbnail session because + * neither dcvs nor batching will be enabled + */ + if (is_thumbnail_session(inst) || is_image_session(inst)) + return 0; + + if (is_decode_session(inst)) { + /* add dcvs buffers, if platform supports dcvs */ + if (core->capabilities[DCVS].value) + count = DCVS_DEC_EXTRA_OUTPUT_BUFFERS; + /* + * if decode batching enabled, ensure minimum batch size + * count of extra output buffers added on output port + */ + if (core->capabilities[DECODE_BATCH].value && + inst->decode_batch.enable && + count < inst->decode_batch.size) + count = inst->decode_batch.size; + + } + + return count; +} + +u32 msm_vidc_internal_buffer_count(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + u32 count = 0; + + if (is_encode_session(inst)) + return 1; + + if (is_decode_session(inst)) { + if (buffer_type == MSM_VIDC_BUF_BIN || + buffer_type == MSM_VIDC_BUF_LINE || + buffer_type == MSM_VIDC_BUF_PERSIST || + buffer_type == MSM_VIDC_BUF_PARTIAL_DATA) { + count = 1; + } else if (buffer_type == MSM_VIDC_BUF_COMV || + buffer_type == MSM_VIDC_BUF_NON_COMV) { + if (inst->codec == MSM_VIDC_H264 || + inst->codec == MSM_VIDC_HEVC || + inst->codec == MSM_VIDC_HEIC || + inst->codec == MSM_VIDC_AV1) + count = 1; + else + count = 0; + } else { + i_vpr_e(inst, "%s: unsupported buffer type %s\n", + __func__, buf_name(buffer_type)); + count = 0; + } + } + + return count; +} + +u32 msm_vidc_decoder_input_size(struct msm_vidc_inst *inst) +{ + u32 frame_size, num_mbs; + u32 div_factor = 1; + u32 base_res_mbs = NUM_MBS_4k; + struct v4l2_format *f; + u32 bitstream_size_overwrite = 0; + enum msm_vidc_codec_type codec; + + bitstream_size_overwrite = + inst->capabilities[BITSTREAM_SIZE_OVERWRITE].value; + if (bitstream_size_overwrite) { + frame_size = bitstream_size_overwrite; + i_vpr_h(inst, "client configured bitstream buffer size %d\n", + frame_size); + return frame_size; + } + + /* + * Decoder input size calculation: + * For 8k resolution, buffer size is calculated as 8k mbs / 4 and + * for 8k cases we expect width/height to be set always. + * In all other cases, buffer size is calculated as + * 4k mbs for VP8/VP9 and 4k / 2 for remaining codecs. + */ + f = &inst->fmts[INPUT_PORT]; + codec = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__); + num_mbs = msm_vidc_get_mbs_per_frame(inst); + if (num_mbs > NUM_MBS_4k) { + div_factor = 4; + base_res_mbs = inst->capabilities[MBPF].value; + } else { + base_res_mbs = NUM_MBS_4k; + if (codec == MSM_VIDC_VP9) + div_factor = 1; + else + div_factor = 2; + } + + if (is_secure_session(inst)) + div_factor = div_factor << 1; + + /* For image session, use the actual resolution to calc buffer size */ + if (is_image_session(inst)) { + base_res_mbs = num_mbs; + div_factor = 1; + } + + frame_size = base_res_mbs * MB_SIZE_IN_PIXEL * 3 / 2 / div_factor; + + /* multiply by 10/8 (1.25) to get size for 10 bit case */ + if (codec == MSM_VIDC_VP9 || codec == MSM_VIDC_AV1 || + codec == MSM_VIDC_HEVC || codec == MSM_VIDC_HEIC) + frame_size = frame_size + (frame_size >> 2); + + i_vpr_h(inst, "set input buffer size to %d\n", frame_size); + + return ALIGN(frame_size, SZ_4K); +} + +u32 msm_vidc_decoder_output_size(struct msm_vidc_inst *inst) +{ + u32 size; + struct v4l2_format *f; + enum msm_vidc_colorformat_type colorformat; + + f = &inst->fmts[OUTPUT_PORT]; + colorformat = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat, + __func__); + size = video_buffer_size(colorformat, f->fmt.pix_mp.width, + f->fmt.pix_mp.height, true); + return size; +} + +u32 msm_vidc_decoder_input_meta_size(struct msm_vidc_inst *inst) +{ + return MSM_VIDC_METADATA_SIZE; +} + +u32 msm_vidc_decoder_output_meta_size(struct msm_vidc_inst *inst) +{ + u32 size = MSM_VIDC_METADATA_SIZE; + + if (inst->capabilities[META_DOLBY_RPU].value) + size += MSM_VIDC_METADATA_DOLBY_RPU_SIZE; + + return ALIGN(size, SZ_4K); +} + +u32 msm_vidc_encoder_input_size(struct msm_vidc_inst *inst) +{ + u32 size; + struct v4l2_format *f; + u32 width, height; + enum msm_vidc_colorformat_type colorformat; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + colorformat = v4l2_colorformat_to_driver(inst, f->fmt.pix_mp.pixelformat, + __func__); + if (is_image_session(inst)) { + width = ALIGN(width, inst->capabilities[GRID_SIZE].value); + height = ALIGN(height, inst->capabilities[GRID_SIZE].value); + } + size = video_buffer_size(colorformat, width, height, true); + return size; +} + +u32 msm_vidc_enc_delivery_mode_based_output_buf_size(struct msm_vidc_inst *inst, + u32 frame_size) +{ + u32 slice_size; + u32 width, height; + u32 width_in_lcus, height_in_lcus, lcu_size; + u32 total_mb_count; + struct v4l2_format *f; + + f = &inst->fmts[OUTPUT_PORT]; + + if (f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_HEVC && + f->fmt.pix_mp.pixelformat != V4L2_PIX_FMT_H264) + return frame_size; + + if (inst->capabilities[SLICE_MODE].value != V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) + return frame_size; + + if (!is_enc_slice_delivery_mode(inst)) + return frame_size; + + lcu_size = (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_HEVC) ? 32 : 16; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + width_in_lcus = (width + lcu_size - 1) / lcu_size; + height_in_lcus = (height + lcu_size - 1) / lcu_size; + total_mb_count = width_in_lcus * height_in_lcus; + + slice_size = ((frame_size * inst->capabilities[SLICE_MAX_MB].value) + + total_mb_count - 1) / total_mb_count; + + slice_size = ALIGN(slice_size, SZ_4K); + return slice_size; +} + +u32 msm_vidc_encoder_output_size(struct msm_vidc_inst *inst) +{ + u32 frame_size; + u32 mbs_per_frame; + u32 width, height; + struct v4l2_format *f; + enum msm_vidc_codec_type codec; + + f = &inst->fmts[OUTPUT_PORT]; + codec = v4l2_codec_to_driver(inst, f->fmt.pix_mp.pixelformat, __func__); + /* + * Encoder output size calculation: 32 Align width/height + * For heic session : YUVsize * 2 + * For resolution <= 480x360p : YUVsize * 2 + * For resolution > 360p & <= 4K : YUVsize / 2 + * For resolution > 4k : YUVsize / 4 + * Initially frame_size = YUVsize * 2; + */ + + width = ALIGN(f->fmt.pix_mp.width, BUFFER_ALIGNMENT_SIZE(32)); + height = ALIGN(f->fmt.pix_mp.height, BUFFER_ALIGNMENT_SIZE(32)); + mbs_per_frame = NUM_MBS_PER_FRAME(width, height); + frame_size = (width * height * 3); + + /* Image session: 2 x yuv size */ + if (is_image_session(inst) || + inst->capabilities[BITRATE_MODE].value == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ) + goto skip_calc; + + if (mbs_per_frame <= NUM_MBS_360P) + (void)frame_size; /* Default frame_size = YUVsize * 2 */ + else if (mbs_per_frame <= NUM_MBS_4k) + frame_size = frame_size >> 2; + else + frame_size = frame_size >> 3; + + /*if ((inst->rc_type == RATE_CONTROL_OFF) || + (inst->rc_type == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)) + frame_size = frame_size << 1; + + if (inst->rc_type == RATE_CONTROL_LOSSLESS) + frame_size = (width * height * 9) >> 2; + */ + +skip_calc: + /* multiply by 10/8 (1.25) to get size for 10 bit case + */ + if (codec == MSM_VIDC_HEVC || codec == MSM_VIDC_HEIC) + frame_size = frame_size + (frame_size >> 2); + + frame_size = ALIGN(frame_size, SZ_4K); + frame_size = msm_vidc_enc_delivery_mode_based_output_buf_size(inst, frame_size); + + return frame_size; +} + +static inline u32 ROI_METADATA_SIZE( + u32 width, u32 height, u32 lcu_size) { + u32 lcu_width = 0; + u32 lcu_height = 0; + u32 n_shift = 0; + + while (lcu_size && !(lcu_size & 0x1)) { + n_shift++; + lcu_size = lcu_size >> 1; + } + lcu_width = (width + (lcu_size - 1)) >> n_shift; + lcu_height = (height + (lcu_size - 1)) >> n_shift; + + return (((lcu_width + 7) >> 3) << 3) * lcu_height * 2; +} + +u32 msm_vidc_encoder_input_meta_size(struct msm_vidc_inst *inst) +{ + u32 size = 0; + u32 lcu_size = 0; + struct v4l2_format *f; + u32 width, height; + + size = MSM_VIDC_METADATA_SIZE; + + if (inst->capabilities[META_ROI_INFO].value) { + lcu_size = 16; + + f = &inst->fmts[OUTPUT_PORT]; + if (f->fmt.pix_mp.pixelformat == V4L2_PIX_FMT_HEVC) + lcu_size = 32; + + f = &inst->fmts[INPUT_PORT]; + width = f->fmt.pix_mp.width; + height = f->fmt.pix_mp.height; + if (is_image_session(inst)) { + width = ALIGN(width, inst->capabilities[GRID_SIZE].value); + height = ALIGN(height, inst->capabilities[GRID_SIZE].value); + } + size += ROI_METADATA_SIZE(width, height, lcu_size); + size = ALIGN(size, SZ_4K); + } + + if (inst->capabilities[META_DOLBY_RPU].value) { + size += MSM_VIDC_METADATA_DOLBY_RPU_SIZE; + size = ALIGN(size, SZ_4K); + } + return size; +} + +u32 msm_vidc_encoder_output_meta_size(struct msm_vidc_inst *inst) +{ + return MSM_VIDC_METADATA_SIZE; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_control.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_control.c new file mode 100644 index 0000000000..7dadc33bef --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_control.c @@ -0,0 +1,1078 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_internal.h" +#include "msm_vidc_driver.h" +#include "msm_venc.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_debug.h" + +extern struct msm_vidc_core *g_core; + +static bool is_priv_ctrl(u32 id) +{ + bool private = false; + + if (IS_PRIV_CTRL(id)) + return true; + + /* + * Treat below standard controls as private because + * we have added custom values to the controls + */ + switch (id) { + /* + * TODO: V4L2_CID_MPEG_VIDEO_HEVC_PROFILE is std ctrl. But + * V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE support is not + * available yet. Hence, make this as private ctrl for time being + */ + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + private = true; + break; + default: + private = false; + break; + } + + return private; +} + +static const char *const mpeg_video_blur_types[] = { + "Blur None", + "Blur External", + "Blur Adaptive", + NULL, +}; + +static const char *const mpeg_video_hevc_profile[] = { + "Main", + "Main Still Picture", + "Main 10", + "Main 10 Still Picture", + NULL, +}; + +static const char * const av1_profile[] = { + "Main", + "High", + "Professional", + NULL, +}; + +static const char * const av1_level[] = { + "2.0", + "2.1", + "2.2", + "2.3", + "3.0", + "3.1", + "3.2", + "3.3", + "4.0", + "4.1", + "4.2", + "4.3", + "5.0", + "5.1", + "5.2", + "5.3", + "6.0", + "6.1", + "6.2", + "6.3", + "7.0", + "7.1", + "7.2", + "7.3", + NULL, +}; + +static const char * const av1_tier[] = { + "Main", + "High", + NULL, +}; + +static const char *const mpeg_video_vidc_ir_type[] = { + "Random", + "Cyclic", + NULL, +}; + +static const char * const *msm_vidc_get_qmenu_type( + struct msm_vidc_inst *inst, u32 cap_id) +{ + switch (cap_id) { + case BLUR_TYPES: + return mpeg_video_blur_types; + case PROFILE: + if (inst->codec == MSM_VIDC_HEVC || inst->codec == MSM_VIDC_HEIC) { + return mpeg_video_hevc_profile; + } else if (inst->codec == MSM_VIDC_AV1) { + return av1_profile; + } else { + i_vpr_e(inst, "%s: invalid codec type %d for cap id %d\n", + __func__, inst->codec, cap_id); + return NULL; + } + case LEVEL: + if (inst->codec == MSM_VIDC_AV1) { + return av1_level; + } else { + i_vpr_e(inst, "%s: invalid codec type %d for cap id %d\n", + __func__, inst->codec, cap_id); + return NULL; + } + case AV1_TIER: + return av1_tier; + case IR_TYPE: + return mpeg_video_vidc_ir_type; + default: + i_vpr_e(inst, "%s: No available qmenu for cap id %d\n", + __func__, cap_id); + return NULL; + } +} + +static inline bool has_children(struct msm_vidc_inst_cap *cap) +{ + return !!cap->children[0]; +} + +static inline bool is_leaf(struct msm_vidc_inst_cap *cap) +{ + return !has_children(cap); +} + +bool is_valid_cap_id(enum msm_vidc_inst_capability_type cap_id) +{ + return cap_id > INST_CAP_NONE && cap_id < INST_CAP_MAX; +} + +bool is_valid_cap(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id) +{ + if (cap_id <= INST_CAP_NONE || cap_id >= INST_CAP_MAX) + return false; + + return !!inst->capabilities[cap_id].cap_id; +} + +static inline bool is_all_childrens_visited( + struct msm_vidc_inst_cap *cap, bool lookup[INST_CAP_MAX]) { + bool found = true; + int i; + + for (i = 0; i < MAX_CAP_CHILDREN; i++) { + if (cap->children[i] == INST_CAP_NONE) + continue; + + if (!lookup[cap->children[i]]) { + found = false; + break; + } + } + return found; +} + +static int add_node_list(struct list_head *list, enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_inst_cap_entry *entry = NULL; + + entry = vzalloc(sizeof(*entry)); + if (!entry) { + d_vpr_e("%s: allocation failed\n", __func__); + return -ENOMEM; + } + + INIT_LIST_HEAD(&entry->list); + entry->cap_id = cap_id; + list_add(&entry->list, list); + + return rc; +} + +static int add_node( + struct list_head *list, struct msm_vidc_inst_cap *lcap, bool lookup[INST_CAP_MAX]) +{ + int rc = 0; + + if (lookup[lcap->cap_id]) + return 0; + + rc = add_node_list(list, lcap->cap_id); + if (rc) + return rc; + + lookup[lcap->cap_id] = true; + return 0; +} + + + +static int msm_vidc_add_capid_to_fw_list(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id) +{ + struct msm_vidc_inst_cap_entry *entry = NULL; + int rc = 0; + + /* skip adding if cap_id already present in firmware list */ + list_for_each_entry(entry, &inst->firmware_list, list) { + if (entry->cap_id == cap_id) { + i_vpr_l(inst, + "%s: cap[%d] %s already present in fw list\n", + __func__, cap_id, cap_name(cap_id)); + return 0; + } + } + + rc = add_node_list(&inst->firmware_list, cap_id); + if (rc) + return rc; + + return 0; +} + +static int msm_vidc_add_children(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id) +{ + struct msm_vidc_inst_cap *cap; + int i, rc = 0; + + cap = &inst->capabilities[cap_id]; + + for (i = 0; i < MAX_CAP_CHILDREN; i++) { + if (!cap->children[i]) + break; + + if (!is_valid_cap_id(cap->children[i])) + continue; + + rc = add_node_list(&inst->children_list, cap->children[i]); + if (rc) + return rc; + } + + return rc; +} + +static int msm_vidc_adjust_cap(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id, + struct v4l2_ctrl *ctrl, const char *func) +{ + struct msm_vidc_inst_cap *cap; + int rc = 0; + + /* validate cap_id */ + if (!is_valid_cap_id(cap_id)) + return 0; + + /* validate cap */ + cap = &inst->capabilities[cap_id]; + if (!is_valid_cap(inst, cap->cap_id)) + return 0; + + /* check if adjust supported */ + if (!cap->adjust) { + if (ctrl) + msm_vidc_update_cap_value(inst, cap_id, ctrl->val, func); + return 0; + } + + /* call adjust */ + rc = cap->adjust(inst, ctrl); + if (rc) { + i_vpr_e(inst, "%s: adjust cap failed for %s\n", func, cap_name(cap_id)); + return rc; + } + + return rc; +} + +static int msm_vidc_set_cap(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id, + const char *func) +{ + struct msm_vidc_inst_cap *cap; + int rc = 0; + + /* validate cap_id */ + if (!is_valid_cap_id(cap_id)) + return 0; + + /* validate cap */ + cap = &inst->capabilities[cap_id]; + if (!is_valid_cap(inst, cap->cap_id)) + return 0; + + /* check if set supported */ + if (!cap->set) + return 0; + + /* call set */ + rc = cap->set(inst, cap_id); + if (rc) { + i_vpr_e(inst, "%s: set cap failed for %s\n", func, cap_name(cap_id)); + return rc; + } + + return rc; +} + +static int msm_vidc_adjust_dynamic_property(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id, struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst_cap_entry *entry = NULL, *temp = NULL; + struct msm_vidc_inst_cap *cap; + s32 prev_value; + int rc = 0; + + cap = &inst->capabilities[0]; + + /* sanitize cap_id */ + if (!is_valid_cap_id(cap_id)) { + i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id); + return -EINVAL; + } + + if (!(cap[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) { + i_vpr_h(inst, + "%s: dynamic setting of cap[%d] %s is not allowed\n", + __func__, cap_id, cap_name(cap_id)); + return -EBUSY; + } + i_vpr_h(inst, "%s: cap[%d] %s\n", __func__, cap_id, cap_name(cap_id)); + + prev_value = cap[cap_id].value; + rc = msm_vidc_adjust_cap(inst, cap_id, ctrl, __func__); + if (rc) + return rc; + + if (cap[cap_id].value == prev_value && cap_id == GOP_SIZE) { + /* + * Ignore setting same GOP size value to firmware to avoid + * unnecessary generation of IDR frame. + */ + return 0; + } + + /* add cap_id to firmware list always */ + rc = msm_vidc_add_capid_to_fw_list(inst, cap_id); + if (rc) + goto error; + + /* add children only if cap value modified */ + if (cap[cap_id].value == prev_value) + return 0; + + rc = msm_vidc_add_children(inst, cap_id); + if (rc) + goto error; + + list_for_each_entry_safe(entry, temp, &inst->children_list, list) { + if (!is_valid_cap_id(entry->cap_id)) { + rc = -EINVAL; + goto error; + } + + if (!cap[entry->cap_id].adjust) { + i_vpr_e(inst, "%s: child cap must have ajdust function %s\n", + __func__, cap_name(entry->cap_id)); + rc = -EINVAL; + goto error; + } + + prev_value = cap[entry->cap_id].value; + rc = msm_vidc_adjust_cap(inst, entry->cap_id, NULL, __func__); + if (rc) + goto error; + + /* add children if cap value modified */ + if (cap[entry->cap_id].value != prev_value) { + /* add cap_id to firmware list always */ + rc = msm_vidc_add_capid_to_fw_list(inst, entry->cap_id); + if (rc) + goto error; + + rc = msm_vidc_add_children(inst, entry->cap_id); + if (rc) + goto error; + } + + list_del_init(&entry->list); + vfree(entry); + } + + /* expecting children_list to be empty */ + if (!list_empty(&inst->children_list)) { + i_vpr_e(inst, "%s: child_list is not empty\n", __func__); + rc = -EINVAL; + goto error; + } + + return 0; +error: + list_for_each_entry_safe(entry, temp, &inst->children_list, list) { + i_vpr_e(inst, "%s: child list: %s\n", __func__, cap_name(entry->cap_id)); + list_del_init(&entry->list); + vfree(entry); + } + list_for_each_entry_safe(entry, temp, &inst->firmware_list, list) { + i_vpr_e(inst, "%s: fw list: %s\n", __func__, cap_name(entry->cap_id)); + list_del_init(&entry->list); + vfree(entry); + } + + return rc; +} + +static int msm_vidc_set_dynamic_property(struct msm_vidc_inst *inst) +{ + struct msm_vidc_inst_cap_entry *entry = NULL, *temp = NULL; + int rc = 0; + + i_vpr_h(inst, "%s()\n", __func__); + + list_for_each_entry_safe(entry, temp, &inst->firmware_list, list) { + rc = msm_vidc_set_cap(inst, entry->cap_id, __func__); + if (rc) + goto error; + + list_del_init(&entry->list); + vfree(entry); + } + + return 0; +error: + list_for_each_entry_safe(entry, temp, &inst->firmware_list, list) { + i_vpr_e(inst, "%s: fw list: %s\n", __func__, cap_name(entry->cap_id)); + list_del_init(&entry->list); + vfree(entry); + } + + return rc; +} + +int msm_vidc_ctrl_handler_deinit(struct msm_vidc_inst *inst) +{ + i_vpr_h(inst, "%s(): num ctrls %d\n", __func__, inst->num_ctrls); + v4l2_ctrl_handler_free(&inst->ctrl_handler); + memset(&inst->ctrl_handler, 0, sizeof(struct v4l2_ctrl_handler)); + + return 0; +} + +int msm_vidc_ctrl_handler_init(struct msm_vidc_inst *inst, bool init) +{ + int rc = 0; + struct msm_vidc_inst_cap *cap; + struct msm_vidc_core *core; + int idx = 0; + struct v4l2_ctrl_config ctrl_cfg = {0}; + int num_ctrls = 0, ctrl_idx = 0; + u64 codecs_count, step_or_mask; + + core = inst->core; + cap = &inst->capabilities[0]; + + if (!core->v4l2_ctrl_ops) { + i_vpr_e(inst, "%s: no control ops\n", __func__); + return -EINVAL; + } + + for (idx = 0; idx < INST_CAP_MAX; idx++) { + if (cap[idx].v4l2_id) + num_ctrls++; + } + if (!num_ctrls) { + i_vpr_e(inst, "%s: no ctrls available in cap database\n", + __func__); + return -EINVAL; + } + + if (init) { + codecs_count = is_encode_session(inst) ? + core->enc_codecs_count : + core->dec_codecs_count; + rc = v4l2_ctrl_handler_init(&inst->ctrl_handler, + INST_CAP_MAX * codecs_count); + if (rc) { + i_vpr_e(inst, "control handler init failed, %d\n", + inst->ctrl_handler.error); + goto error; + } + } + + for (idx = 0; idx < INST_CAP_MAX; idx++) { + struct v4l2_ctrl *ctrl; + + if (!cap[idx].v4l2_id) + continue; + + if (ctrl_idx >= num_ctrls) { + i_vpr_e(inst, + "%s: invalid ctrl %#x, max allowed %d\n", + __func__, cap[idx].v4l2_id, + num_ctrls); + rc = -EINVAL; + goto error; + } + i_vpr_l(inst, + "%s: cap[%d] %24s, value %d min %d max %d step_or_mask %#x flags %#x v4l2_id %#x hfi_id %#x\n", + __func__, idx, cap_name(idx), + cap[idx].value, + cap[idx].min, + cap[idx].max, + cap[idx].step_or_mask, + cap[idx].flags, + cap[idx].v4l2_id, + cap[idx].hfi_id); + + memset(&ctrl_cfg, 0, sizeof(struct v4l2_ctrl_config)); + + /* + * few controls might have been already initialized in instance initialization, + * so modify the range values for them instead of initializing them again + */ + if (!init) { + struct msm_vidc_ctrl_data ctrl_priv_data; + + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, cap[idx].v4l2_id); + if (ctrl) { + step_or_mask = (cap[idx].flags & CAP_FLAG_MENU) ? + ~(cap[idx].step_or_mask) : + cap[idx].step_or_mask; + memset(&ctrl_priv_data, 0, sizeof(struct msm_vidc_ctrl_data)); + ctrl_priv_data.skip_s_ctrl = true; + ctrl->priv = &ctrl_priv_data; + v4l2_ctrl_modify_range(ctrl, + cap[idx].min, + cap[idx].max, + step_or_mask, + cap[idx].value); + /* reset private data to null to ensure s_ctrl not skipped */ + ctrl->priv = NULL; + continue; + } + } + + if (is_priv_ctrl(cap[idx].v4l2_id)) { + /* add private control */ + ctrl_cfg.def = cap[idx].value; + ctrl_cfg.flags = 0; + ctrl_cfg.id = cap[idx].v4l2_id; + ctrl_cfg.max = cap[idx].max; + ctrl_cfg.min = cap[idx].min; + ctrl_cfg.ops = core->v4l2_ctrl_ops; + if (cap[idx].flags & CAP_FLAG_MENU) + ctrl_cfg.type = V4L2_CTRL_TYPE_MENU; + else if (cap[idx].flags & CAP_FLAG_BITMASK) + ctrl_cfg.type = V4L2_CTRL_TYPE_BITMASK; + else + ctrl_cfg.type = V4L2_CTRL_TYPE_INTEGER; + if (is_meta_cap(inst, idx)) { + /* bitmask is expected to be enabled for meta controls */ + if (ctrl_cfg.type != V4L2_CTRL_TYPE_BITMASK) { + i_vpr_e(inst, + "%s: missing bitmask for cap %s\n", + __func__, cap_name(idx)); + rc = -EINVAL; + goto error; + } + } + if (ctrl_cfg.type == V4L2_CTRL_TYPE_MENU) { + ctrl_cfg.menu_skip_mask = + ~(cap[idx].step_or_mask); + ctrl_cfg.qmenu = msm_vidc_get_qmenu_type(inst, + cap[idx].cap_id); + } else { + ctrl_cfg.step = + cap[idx].step_or_mask; + } + ctrl_cfg.name = cap_name(cap[idx].cap_id); + if (!ctrl_cfg.name) { + i_vpr_e(inst, "%s: %#x ctrl name is null\n", + __func__, ctrl_cfg.id); + rc = -EINVAL; + goto error; + } + ctrl = v4l2_ctrl_new_custom(&inst->ctrl_handler, + &ctrl_cfg, NULL); + } else { + if (cap[idx].flags & CAP_FLAG_MENU) { + ctrl = v4l2_ctrl_new_std_menu( + &inst->ctrl_handler, + core->v4l2_ctrl_ops, + cap[idx].v4l2_id, + cap[idx].max, + ~(cap[idx].step_or_mask), + cap[idx].value); + } else { + ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, + core->v4l2_ctrl_ops, + cap[idx].v4l2_id, + cap[idx].min, + cap[idx].max, + cap[idx].step_or_mask, + cap[idx].value); + } + } + if (!ctrl) { + i_vpr_e(inst, "%s: invalid ctrl %#x cap %24s\n", __func__, + cap[idx].v4l2_id, cap_name(idx)); + rc = -EINVAL; + goto error; + } + + rc = inst->ctrl_handler.error; + if (rc) { + i_vpr_e(inst, + "error adding ctrl (%#x) to ctrl handle, %d\n", + cap[idx].v4l2_id, + inst->ctrl_handler.error); + goto error; + } + + if (cap[idx].flags & CAP_FLAG_VOLATILE) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + + ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + ctrl_idx++; + } + inst->num_ctrls = num_ctrls; + i_vpr_h(inst, "%s(): num ctrls %d\n", __func__, inst->num_ctrls); + + return 0; +error: + msm_vidc_ctrl_handler_deinit(inst); + + return rc; +} + +static int msm_vidc_update_buffer_count_if_needed(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + bool update_input_port = false, update_output_port = false; + + switch (cap_id) { + case LAYER_TYPE: + case ENH_LAYER_COUNT: + case LAYER_ENABLE: + update_input_port = true; + break; + case THUMBNAIL_MODE: + case PRIORITY: + update_input_port = true; + update_output_port = true; + break; + default: + update_input_port = false; + update_output_port = false; + break; + } + + if (update_input_port) { + rc = msm_vidc_update_buffer_count(inst, INPUT_PORT); + if (rc) + return rc; + } + if (update_output_port) { + rc = msm_vidc_update_buffer_count(inst, OUTPUT_PORT); + if (rc) + return rc; + } + + return rc; +} + +static int msm_vidc_allow_secure_session(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_inst *i; + struct msm_vidc_core *core; + u32 count = 0; + + core = inst->core; + + core_lock(core, __func__); + list_for_each_entry(i, &core->instances, list) { + if (i->capabilities[SECURE_MODE].value) + count++; + } + + if (count > core->capabilities[MAX_SECURE_SESSION_COUNT].value) { + i_vpr_e(inst, + "%s: total secure sessions %d exceeded max limit %d\n", + __func__, count, + core->capabilities[MAX_SECURE_SESSION_COUNT].value); + rc = -EINVAL; + } + core_unlock(core, __func__); + + return rc; +} + +int msm_v4l2_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + int rc = 0; + struct msm_vidc_inst *inst; + + if (!ctrl) { + d_vpr_e("%s: invalid ctrl parameter\n", __func__); + return -EINVAL; + } + + inst = container_of(ctrl->handler, + struct msm_vidc_inst, ctrl_handler); + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: could not find inst for ctrl %s id %#x\n", + __func__, ctrl->name, ctrl->id); + return -EINVAL; + } + client_lock(inst, __func__); + inst_lock(inst, __func__); + + rc = msm_vidc_get_control(inst, ctrl); + if (rc) { + i_vpr_e(inst, "%s: failed for ctrl %s id %#x\n", + __func__, ctrl->name, ctrl->id); + goto unlock; + } else { + i_vpr_h(inst, "%s: ctrl %s id %#x, value %d\n", + __func__, ctrl->name, ctrl->id, ctrl->val); + } + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + return rc; +} + +static int msm_vidc_update_static_property(struct msm_vidc_inst *inst, + enum msm_vidc_inst_capability_type cap_id, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + + if (cap_id == DRV_VERSION) { + i_vpr_h(inst, "%s: driver version update not allowed\n", + __func__); + return 0; + } + + /* update value to db */ + msm_vidc_update_cap_value(inst, cap_id, ctrl->val, __func__); + + if (cap_id == CLIENT_ID) { + rc = msm_vidc_update_debug_str(inst); + if (rc) + return rc; + } + + if (cap_id == SECURE_MODE) { + if (ctrl->val) { + rc = msm_vidc_allow_secure_session(inst); + if (rc) + return rc; + } + } + + if (cap_id == ROTATION) { + struct v4l2_format *output_fmt; + + output_fmt = &inst->fmts[OUTPUT_PORT]; + rc = msm_venc_s_fmt_output(inst, output_fmt); + if (rc) + return rc; + } + + if (cap_id == DELIVERY_MODE) { + struct v4l2_format *output_fmt; + + output_fmt = &inst->fmts[OUTPUT_PORT]; + rc = msm_venc_s_fmt_output(inst, output_fmt); + if (rc) + return rc; + } + + if (cap_id == BITSTREAM_SIZE_OVERWRITE) { + rc = msm_vidc_update_bitstream_buffer_size(inst); + if (rc) + return rc; + } + + /* call this explicitly to adjust client priority */ + if (cap_id == PRIORITY) { + rc = msm_vidc_adjust_session_priority(inst, ctrl); + if (rc) + return rc; + } + + if (cap_id == CRITICAL_PRIORITY) + msm_vidc_update_cap_value(inst, PRIORITY, 0, __func__); + + if (cap_id == ENH_LAYER_COUNT && inst->codec == MSM_VIDC_HEVC) { + u32 enable; + + /* enable LAYER_ENABLE cap if HEVC_HIER enh layers > 0 */ + if (ctrl->val > 0) + enable = 1; + else + enable = 0; + + msm_vidc_update_cap_value(inst, LAYER_ENABLE, enable, __func__); + } + if (is_meta_cap(inst, cap_id)) { + rc = msm_vidc_update_meta_port_settings(inst); + if (rc) + return rc; + } + + rc = msm_vidc_update_buffer_count_if_needed(inst, cap_id); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) +{ + enum msm_vidc_inst_capability_type cap_id; + struct msm_vidc_inst_cap *cap; + int rc = 0; + u32 port; + + cap = &inst->capabilities[0]; + + i_vpr_h(inst, FMT_STRING_SET_CTRL, + __func__, state_name(inst->state), ctrl->name, ctrl->id, ctrl->val); + + cap_id = msm_vidc_get_cap_id(inst, ctrl->id); + if (!is_valid_cap_id(cap_id)) { + i_vpr_e(inst, "%s: invalid cap_id for ctrl %s\n", __func__, ctrl->name); + return -EINVAL; + } + + /* mark client set flag */ + cap[cap_id].flags |= CAP_FLAG_CLIENT_SET; + + port = is_encode_session(inst) ? OUTPUT_PORT : INPUT_PORT; + if (!inst->bufq[port].vb2q->streaming) { + /* static case */ + rc = msm_vidc_update_static_property(inst, cap_id, ctrl); + if (rc) + return rc; + } else { + /* dynamic case */ + rc = msm_vidc_adjust_dynamic_property(inst, cap_id, ctrl); + if (rc) + return rc; + + rc = msm_vidc_set_dynamic_property(inst); + if (rc) + return rc; + } + + return rc; +} + +int msm_v4l2_op_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct msm_vidc_inst *inst; + struct msm_vidc_ctrl_data *priv_ctrl_data; + int rc = 0; + + if (!ctrl) { + d_vpr_e("%s: invalid ctrl parameter\n", __func__); + return -EINVAL; + } + + /* + * v4l2_ctrl_modify_range may internally call s_ctrl + * which will again try to acquire lock leading to deadlock, + * Add check to avoid such scenario. + */ + priv_ctrl_data = ctrl->priv ? ctrl->priv : NULL; + if (priv_ctrl_data && priv_ctrl_data->skip_s_ctrl) { + d_vpr_l("%s: skip s_ctrl (%s)\n", __func__, ctrl->name); + return 0; + } + + inst = container_of(ctrl->handler, struct msm_vidc_inst, ctrl_handler); + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + rc = inst->event_handle(inst, MSM_VIDC_S_CTRL, ctrl); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + return rc; +} + +int msm_vidc_prepare_dependency_list(struct msm_vidc_inst *inst) +{ + struct list_head leaf_list, opt_list; + struct msm_vidc_inst_cap *cap, *lcap, *temp_cap; + struct msm_vidc_inst_cap_entry *entry = NULL, *temp = NULL; + bool leaf_visited[INST_CAP_MAX]; + bool opt_visited[INST_CAP_MAX]; + int tmp_count_total, tmp_count, num_nodes = 0; + int i, rc = 0; + + cap = &inst->capabilities[0]; + + if (!list_empty(&inst->caps_list)) { + i_vpr_h(inst, "%s: dependency list already prepared\n", __func__); + return 0; + } + + /* init local list and lookup table entries */ + INIT_LIST_HEAD(&leaf_list); + INIT_LIST_HEAD(&opt_list); + memset(&leaf_visited, 0, sizeof(leaf_visited)); + memset(&opt_visited, 0, sizeof(opt_visited)); + + /* populate leaf nodes first */ + for (i = 1; i < INST_CAP_MAX; i++) { + lcap = &cap[i]; + if (!is_valid_cap(inst, lcap->cap_id)) + continue; + + /* sanitize cap value */ + if (i != lcap->cap_id) { + i_vpr_e(inst, "%s: cap id mismatch. expected %s, actual %s\n", + __func__, cap_name(i), cap_name(lcap->cap_id)); + rc = -EINVAL; + goto error; + } + + /* add all leaf nodes */ + if (is_leaf(lcap)) { + rc = add_node(&leaf_list, lcap, leaf_visited); + if (rc) + goto error; + } else { + rc = add_node(&opt_list, lcap, opt_visited); + if (rc) + goto error; + } + } + + /* find total optional list entries */ + list_for_each_entry(entry, &opt_list, list) + num_nodes++; + + /* used for loop detection */ + tmp_count_total = num_nodes; + tmp_count = num_nodes; + + /* sort final outstanding nodes */ + list_for_each_entry_safe(entry, temp, &opt_list, list) { + /* initially remove entry from opt list */ + list_del_init(&entry->list); + opt_visited[entry->cap_id] = false; + tmp_count--; + temp_cap = &cap[entry->cap_id]; + + /** + * if all child are visited then add this entry to + * leaf list else add it to the end of optional list. + */ + if (is_all_childrens_visited(temp_cap, leaf_visited)) { + list_add(&entry->list, &leaf_list); + leaf_visited[entry->cap_id] = true; + tmp_count_total--; + } else { + list_add_tail(&entry->list, &opt_list); + opt_visited[entry->cap_id] = true; + } + + /* detect loop */ + if (!tmp_count) { + if (num_nodes == tmp_count_total) { + i_vpr_e(inst, "%s: loop detected in subgraph %d\n", + __func__, num_nodes); + rc = -EINVAL; + goto error; + } + num_nodes = tmp_count_total; + tmp_count = tmp_count_total; + } + } + + /* expecting opt_list to be empty */ + if (!list_empty(&opt_list)) { + i_vpr_e(inst, "%s: opt_list is not empty\n", __func__); + rc = -EINVAL; + goto error; + } + + /* move elements to &inst->caps_list from local */ + list_replace_init(&leaf_list, &inst->caps_list); + + return 0; +error: + list_for_each_entry_safe(entry, temp, &opt_list, list) { + i_vpr_e(inst, "%s: opt_list: %s\n", __func__, cap_name(entry->cap_id)); + list_del_init(&entry->list); + vfree(entry); + } + list_for_each_entry_safe(entry, temp, &leaf_list, list) { + i_vpr_e(inst, "%s: leaf_list: %s\n", __func__, cap_name(entry->cap_id)); + list_del_init(&entry->list); + vfree(entry); + } + return rc; +} + +int msm_vidc_adjust_v4l2_properties(struct msm_vidc_inst *inst) +{ + struct msm_vidc_inst_cap_entry *entry = NULL, *temp = NULL; + int rc = 0; + + i_vpr_h(inst, "%s()\n", __func__); + + /* adjust all possible caps from caps_list */ + list_for_each_entry_safe(entry, temp, &inst->caps_list, list) { + i_vpr_l(inst, "%s: cap: id %3u, name %s\n", __func__, + entry->cap_id, cap_name(entry->cap_id)); + + rc = msm_vidc_adjust_cap(inst, entry->cap_id, NULL, __func__); + if (rc) + return rc; + } + + return rc; +} + +int msm_vidc_set_v4l2_properties(struct msm_vidc_inst *inst) +{ + struct msm_vidc_inst_cap_entry *entry = NULL, *temp = NULL; + int rc = 0; + + i_vpr_h(inst, "%s()\n", __func__); + + /* set all caps from caps_list */ + list_for_each_entry_safe(entry, temp, &inst->caps_list, list) { + rc = msm_vidc_set_cap(inst, entry->cap_id, __func__); + if (rc) + return rc; + } + + return rc; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_debug.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_debug.c new file mode 100644 index 0000000000..9be5f0ee0f --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_debug.c @@ -0,0 +1,816 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#define CREATE_TRACE_POINTS +#include "msm_vidc_debug.h" +#include "msm_vidc_driver.h" +#include "msm_vidc.h" +#include "msm_vidc_core.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_events.h" + +extern struct msm_vidc_core *g_core; + +#define MAX_SSR_STRING_LEN 64 +#define MAX_STABILITY_STRING_LEN 64 +#define MAX_DEBUG_LEVEL_STRING_LEN 15 +#define MSM_VIDC_MIN_STATS_DELAY_MS 200 +#define MSM_VIDC_MAX_STATS_DELAY_MS 10000 + +unsigned int msm_vidc_debug = DRV_LOG; +unsigned int msm_fw_debug = FW_LOG; + +/* disabled synx fence by default temporarily */ +bool msm_vidc_synx_fence_enable = false; + +static int debug_level_set_drv(const char *val, + const struct kernel_param *kp) +{ + struct msm_vidc_core *core = NULL; + unsigned int dvalue; + int ret; + + if (!kp || !kp->arg || !val) { + d_vpr_e("%s: Invalid params\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(val, 0, &dvalue); + if (ret) + return ret; + + msm_vidc_debug = dvalue; + + core = *(struct msm_vidc_core **)kp->arg; + + if (!core) { + d_vpr_e("%s: Invalid core/capabilities\n", __func__); + return 0; + } + + /* check if driver is more than default level */ + if ((dvalue & DRV_LOGMASK) & ~(DRV_LOG)) { + core->capabilities[HW_RESPONSE_TIMEOUT].value = 4 * HW_RESPONSE_TIMEOUT_VALUE; + core->capabilities[SW_PC_DELAY].value = 4 * SW_PC_DELAY_VALUE; + core->capabilities[FW_UNLOAD_DELAY].value = 4 * FW_UNLOAD_DELAY_VALUE; + } else { + /* reset timeout values, if user reduces the logging */ + core->capabilities[HW_RESPONSE_TIMEOUT].value = HW_RESPONSE_TIMEOUT_VALUE; + core->capabilities[SW_PC_DELAY].value = SW_PC_DELAY_VALUE; + core->capabilities[FW_UNLOAD_DELAY].value = FW_UNLOAD_DELAY_VALUE; + } + + d_vpr_h( + "timeout updated for driver: hw_response %u, sw_pc %u, fw_unload %u, debug_level %#x\n", + core->capabilities[HW_RESPONSE_TIMEOUT].value, + core->capabilities[SW_PC_DELAY].value, + core->capabilities[FW_UNLOAD_DELAY].value, + msm_vidc_debug); + + return 0; +} + +static int debug_level_set_fw(const char *val, + const struct kernel_param *kp) +{ + struct msm_vidc_core *core = NULL; + unsigned int dvalue; + int ret; + + if (!kp || !kp->arg || !val) { + d_vpr_e("%s: Invalid params\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(val, 0, &dvalue); + if (ret) + return ret; + + msm_fw_debug = dvalue; + + core = *(struct msm_vidc_core **)kp->arg; + + if (!core) { + d_vpr_e("%s: Invalid core/capabilities\n", __func__); + return 0; + } + + /* check if firmware is more than default level */ + if ((dvalue & FW_LOGMASK) & ~(FW_LOG)) { + core->capabilities[HW_RESPONSE_TIMEOUT].value = 4 * HW_RESPONSE_TIMEOUT_VALUE; + core->capabilities[SW_PC_DELAY].value = 4 * SW_PC_DELAY_VALUE; + core->capabilities[FW_UNLOAD_DELAY].value = 4 * FW_UNLOAD_DELAY_VALUE; + } else { + /* reset timeout values, if user reduces the logging */ + core->capabilities[HW_RESPONSE_TIMEOUT].value = HW_RESPONSE_TIMEOUT_VALUE; + core->capabilities[SW_PC_DELAY].value = SW_PC_DELAY_VALUE; + core->capabilities[FW_UNLOAD_DELAY].value = FW_UNLOAD_DELAY_VALUE; + } + + d_vpr_h( + "timeout updated for firmware: hw_response %u, sw_pc %u, fw_unload %u, debug_level %#x\n", + core->capabilities[HW_RESPONSE_TIMEOUT].value, + core->capabilities[SW_PC_DELAY].value, + core->capabilities[FW_UNLOAD_DELAY].value, + msm_fw_debug); + + return 0; +} + +static int debug_level_get_drv(char *buffer, const struct kernel_param *kp) +{ + return scnprintf(buffer, PAGE_SIZE, "%#x", msm_vidc_debug); +} + +static int debug_level_get_fw(char *buffer, const struct kernel_param *kp) +{ + return scnprintf(buffer, PAGE_SIZE, "%#x", msm_fw_debug); +} + +static const struct kernel_param_ops msm_vidc_debug_fops = { + .set = debug_level_set_drv, + .get = debug_level_get_drv, +}; + +static const struct kernel_param_ops msm_fw_debug_fops = { + .set = debug_level_set_fw, + .get = debug_level_get_fw, +}; + +static int fw_dump_set(const char *val, + const struct kernel_param *kp) +{ + unsigned int dvalue; + int ret; + + if (!kp || !kp->arg || !val) { + d_vpr_e("%s: Invalid params\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(val, 0, &dvalue); + if (ret) + return ret; + + msm_vidc_fw_dump = dvalue; + + d_vpr_h("fw dump %s\n", msm_vidc_fw_dump ? "Enabled" : "Disabled"); + + return 0; +} + +static int fw_dump_get(char *buffer, const struct kernel_param *kp) +{ + return scnprintf(buffer, PAGE_SIZE, "%#x", msm_vidc_fw_dump); +} + +static const struct kernel_param_ops msm_vidc_fw_dump_fops = { + .set = fw_dump_set, + .get = fw_dump_get, +}; + +static int synx_fence_set(const char *val, + const struct kernel_param *kp) +{ + unsigned int dvalue; + int ret; + + if (!kp || !kp->arg || !val) { + d_vpr_e("%s: Invalid params\n", __func__); + return -EINVAL; + } + + ret = kstrtouint(val, 0, &dvalue); + if (ret) + return ret; + + msm_vidc_synx_fence_enable = dvalue; + + return 0; +} + +static int synx_fence_get(char *buffer, const struct kernel_param *kp) +{ + return scnprintf(buffer, PAGE_SIZE, "%#x", msm_vidc_synx_fence_enable); +} + +static const struct kernel_param_ops msm_vidc_synx_fence_debug_fops = { + .set = synx_fence_set, + .get = synx_fence_get, +}; + +module_param_cb(msm_vidc_debug, &msm_vidc_debug_fops, &g_core, 0644); +module_param_cb(msm_fw_debug, &msm_fw_debug_fops, &g_core, 0644); +module_param_cb(msm_vidc_fw_dump, &msm_vidc_fw_dump_fops, &g_core, 0644); +module_param_cb(msm_vidc_synx_fence_enable, + &msm_vidc_synx_fence_debug_fops, &g_core, 0644); + +bool msm_vidc_lossless_encode = !true; +EXPORT_SYMBOL(msm_vidc_lossless_encode); + +bool msm_vidc_syscache_disable = !true; +EXPORT_SYMBOL(msm_vidc_syscache_disable); + +int msm_vidc_clock_voting = !1; +int msm_vidc_ddr_bw = !1; +int msm_vidc_llc_bw = !1; + +bool msm_vidc_fw_dump = !true; +EXPORT_SYMBOL(msm_vidc_fw_dump); + +unsigned int msm_vidc_enable_bugon = !1; +EXPORT_SYMBOL(msm_vidc_enable_bugon); + +#define MAX_DBG_BUF_SIZE 4096 + +struct core_inst_pair { + struct msm_vidc_core *core; + struct msm_vidc_inst *inst; +}; + +/* debug fs support */ +static inline void tic(struct msm_vidc_inst *inst, enum profiling_points p, + char *b) +{ + if (!inst->debug.pdata[p].name[0]) + memcpy(inst->debug.pdata[p].name, b, 64); + if (inst->debug.pdata[p].sampling) { + inst->debug.pdata[p].start = ktime_get_ns() / 1000 / 1000; + inst->debug.pdata[p].sampling = false; + } +} + +static inline void toc(struct msm_vidc_inst *inst, enum profiling_points p) +{ + if (!inst->debug.pdata[p].sampling) { + inst->debug.pdata[p].stop = ktime_get_ns() / 1000 / 1000; + inst->debug.pdata[p].cumulative += inst->debug.pdata[p].stop - + inst->debug.pdata[p].start; + inst->debug.pdata[p].sampling = true; + } +} + +void msm_vidc_show_stats(struct msm_vidc_inst *inst) +{ + int x; + + for (x = 0; x < MAX_PROFILING_POINTS; x++) { + if (inst->debug.pdata[x].name[0]) { + if (inst->debug.samples) { + i_vpr_p(inst, "%s averaged %llu ms/sample\n", + inst->debug.pdata[x].name, + inst->debug.pdata[x].cumulative / + inst->debug.samples); + } + + i_vpr_p(inst, "%s Samples: %d\n", + inst->debug.pdata[x].name, inst->debug.samples); + } + } +} + +static u32 write_str(char *buffer, + size_t size, const char *fmt, ...) +{ + va_list args; + u32 len; + + va_start(args, fmt); + len = vscnprintf(buffer, size, fmt, args); + va_end(args); + return len; +} + +static ssize_t core_info_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct msm_vidc_core *core = file->private_data; + char *cur, *end, *dbuf = NULL; + ssize_t len = 0; + + if (!core) { + d_vpr_e("%s: invalid params %pK\n", __func__, core); + return 0; + } + + dbuf = vzalloc(MAX_DBG_BUF_SIZE); + if (!dbuf) { + d_vpr_e("%s: allocation failed\n", __func__); + return -ENOMEM; + } + + cur = dbuf; + end = cur + MAX_DBG_BUF_SIZE; + + cur += write_str(cur, end - cur, "Core state: %d\n", core->state); + + cur += write_str(cur, end - cur, + "FW version : %s\n", core->fw_version); + cur += write_str(cur, end - cur, + "register_base: 0x%x\n", core->resource->register_base_addr); + cur += write_str(cur, end - cur, "irq: %u\n", core->resource->irq); + + len = simple_read_from_buffer(buf, count, ppos, + dbuf, cur - dbuf); + + vfree(dbuf); + return len; +} + +static const struct file_operations core_info_fops = { + .open = simple_open, + .read = core_info_read, +}; + +static ssize_t stats_delay_write_ms(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + int rc = 0; + struct msm_vidc_core *core = filp->private_data; + char kbuf[MAX_DEBUG_LEVEL_STRING_LEN] = {0}; + u32 delay_ms = 0; + + if (!core) { + d_vpr_e("%s: invalid params %pK\n", __func__, core); + return 0; + } + + /* filter partial writes and invalid commands */ + if (*ppos != 0 || count >= sizeof(kbuf) || count == 0) { + d_vpr_e("returning error - pos %lld, count %lu\n", *ppos, count); + rc = -EINVAL; + } + + rc = simple_write_to_buffer(kbuf, sizeof(kbuf) - 1, ppos, buf, count); + if (rc < 0) { + d_vpr_e("%s: User memory fault\n", __func__); + rc = -EFAULT; + goto exit; + } + + rc = kstrtoint(kbuf, 0, &delay_ms); + if (rc) { + d_vpr_e("returning error err %d\n", rc); + rc = -EINVAL; + goto exit; + } + delay_ms = clamp_t(u32, delay_ms, MSM_VIDC_MIN_STATS_DELAY_MS, MSM_VIDC_MAX_STATS_DELAY_MS); + core->capabilities[STATS_TIMEOUT_MS].value = delay_ms; + d_vpr_h("Stats delay is updated to - %d ms\n", delay_ms); + +exit: + return rc; +} + +static ssize_t stats_delay_read_ms(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + size_t len; + char kbuf[MAX_DEBUG_LEVEL_STRING_LEN]; + struct msm_vidc_core *core = file->private_data; + + if (!core) { + d_vpr_e("%s: invalid params %pK\n", __func__, core); + return 0; + } + + len = scnprintf(kbuf, sizeof(kbuf), "%u\n", core->capabilities[STATS_TIMEOUT_MS].value); + return simple_read_from_buffer(buf, count, ppos, kbuf, len); +} + +static const struct file_operations stats_delay_fops = { + .open = simple_open, + .write = stats_delay_write_ms, + .read = stats_delay_read_ms, +}; + +static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long ssr_trigger_val = 0; + int rc = 0; + struct msm_vidc_core *core = filp->private_data; + size_t size = MAX_SSR_STRING_LEN; + char kbuf[MAX_SSR_STRING_LEN + 1] = { 0 }; + + if (!core) { + d_vpr_e("%s: invalid params %pK\n", __func__, core); + return 0; + } + + if (!buf) + return -EINVAL; + + if (!count) + goto exit; + + if (count < size) + size = count; + + if (copy_from_user(kbuf, buf, size)) { + d_vpr_e("%s: User memory fault\n", __func__); + rc = -EFAULT; + goto exit; + } + + rc = kstrtoul(kbuf, 0, &ssr_trigger_val); + if (rc) { + d_vpr_e("returning error err %d\n", rc); + rc = -EINVAL; + } else { + msm_vidc_trigger_ssr(core, ssr_trigger_val); + rc = count; + } +exit: + return rc; +} + +static const struct file_operations ssr_fops = { + .open = simple_open, + .write = trigger_ssr_write, +}; + +static ssize_t trigger_stability_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long stability_trigger_val = 0; + int rc = 0; + struct msm_vidc_core *core = filp->private_data; + size_t size = MAX_STABILITY_STRING_LEN; + char kbuf[MAX_STABILITY_STRING_LEN + 1] = { 0 }; + + if (!core) { + d_vpr_e("%s: invalid params %pK\n", __func__, core); + return 0; + } + + if (!buf) + return -EINVAL; + + if (!count) + goto exit; + + if (count < size) + size = count; + + if (copy_from_user(kbuf, buf, size)) { + d_vpr_e("%s: User memory fault\n", __func__); + rc = -EFAULT; + goto exit; + } + + rc = kstrtoul(kbuf, 0, &stability_trigger_val); + if (rc) { + d_vpr_e("%s: returning error err %d\n", __func__, rc); + rc = -EINVAL; + } else { + msm_vidc_trigger_stability(core, stability_trigger_val); + rc = count; + } +exit: + return rc; +} + +static const struct file_operations stability_fops = { + .open = simple_open, + .write = trigger_stability_write, +}; + +struct dentry *msm_vidc_debugfs_init_drv(void) +{ + struct dentry *dir = NULL; + + dir = debugfs_create_dir("msm_vidc", NULL); + if (IS_ERR_OR_NULL(dir)) { + dir = NULL; + goto failed_create_dir; + } + + debugfs_create_u32("core_clock_voting", 0644, dir, + &msm_vidc_clock_voting); + debugfs_create_u32("ddr_bw_kbps", 0644, dir, + &msm_vidc_ddr_bw); + debugfs_create_u32("llc_bw_kbps", 0644, dir, + &msm_vidc_llc_bw); + debugfs_create_bool("disable_video_syscache", 0644, dir, + &msm_vidc_syscache_disable); + debugfs_create_bool("lossless_encoding", 0644, dir, + &msm_vidc_lossless_encode); + debugfs_create_u32("enable_bugon", 0644, dir, + &msm_vidc_enable_bugon); + + return dir; + +failed_create_dir: + if (dir) + debugfs_remove_recursive(dir); + + return NULL; +} + +struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core) +{ + struct dentry *dir = NULL; + char debugfs_name[MAX_DEBUGFS_NAME]; + struct dentry *parent; + + if (!core->debugfs_parent) { + d_vpr_e("%s: invalid params\n", __func__); + goto failed_create_dir; + } + parent = core->debugfs_parent; + + snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core"); + dir = debugfs_create_dir(debugfs_name, parent); + if (IS_ERR_OR_NULL(dir)) { + dir = NULL; + d_vpr_e("Failed to create debugfs for msm_vidc\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("info", 0444, dir, core, &core_info_fops)) { + d_vpr_e("debugfs_create_file: fail\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("trigger_ssr", 0200, + dir, core, &ssr_fops)) { + d_vpr_e("debugfs_create_file: fail\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("trigger_stability", 0200, dir, core, &stability_fops)) { + d_vpr_e("trigger_stability debugfs_create_file: fail\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("stats_delay_ms", 0644, dir, core, &stats_delay_fops)) { + d_vpr_e("debugfs_create_file: fail\n"); + goto failed_create_dir; + } +failed_create_dir: + return dir; +} + +static int inst_info_open(struct inode *inode, struct file *file) +{ + d_vpr_l("Open inode ptr: %pK\n", inode->i_private); + file->private_data = inode->i_private; + return 0; +} + +static int publish_unreleased_reference(struct msm_vidc_inst *inst, + char **dbuf, char *end) +{ + return 0; +} + +static ssize_t inst_info_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct core_inst_pair *idata = file->private_data; + struct msm_vidc_core *core; + struct msm_vidc_inst *inst; + char *cur, *end, *dbuf = NULL; + int i, j; + ssize_t len = 0; + struct v4l2_format *f; + + if (!idata || !idata->core || !idata->inst) { + d_vpr_e("%s: invalid params %pK\n", __func__, idata); + return 0; + } + + core = idata->core; + inst = idata->inst; + + inst = get_inst(core, inst->session_id); + if (!inst) { + d_vpr_h("%s: instance has become obsolete", __func__); + return 0; + } + + dbuf = vzalloc(MAX_DBG_BUF_SIZE); + if (!dbuf) { + i_vpr_e(inst, "%s: allocation failed\n", __func__); + len = -ENOMEM; + goto failed_alloc; + } + + cur = dbuf; + end = cur + MAX_DBG_BUF_SIZE; + + f = &inst->fmts[OUTPUT_PORT]; + cur += write_str(cur, end - cur, "==============================\n"); + cur += write_str(cur, end - cur, "INSTANCE: %pK (%s)\n", inst, + is_encode_session(inst) ? "Encoder" : "Decoder"); + cur += write_str(cur, end - cur, "==============================\n"); + cur += write_str(cur, end - cur, "core: %pK\n", inst->core); + cur += write_str(cur, end - cur, "height: %d\n", f->fmt.pix_mp.height); + cur += write_str(cur, end - cur, "width: %d\n", f->fmt.pix_mp.width); + cur += write_str(cur, end - cur, "fps: %d\n", + inst->capabilities[FRAME_RATE].value >> 16); + cur += write_str(cur, end - cur, "state: %d\n", inst->state); + cur += write_str(cur, end - cur, "secure: %d\n", + is_secure_session(inst)); + cur += write_str(cur, end - cur, "-----------Formats-------------\n"); + for (i = 0; i < MAX_PORT; i++) { + if (i != INPUT_PORT && i != OUTPUT_PORT) + continue; + f = &inst->fmts[i]; + cur += write_str(cur, end - cur, "capability: %s\n", + i == INPUT_PORT ? "Output" : "Capture"); + cur += write_str(cur, end - cur, "planes : %d\n", + f->fmt.pix_mp.num_planes); + cur += write_str(cur, end - cur, + "type: %s\n", i == INPUT_PORT ? + "Output" : "Capture"); + cur += write_str(cur, end - cur, "count: %u\n", + inst->bufq[i].vb2q->num_buffers); + + for (j = 0; j < f->fmt.pix_mp.num_planes; j++) + cur += write_str(cur, end - cur, + "size for plane %d: %u\n", + j, f->fmt.pix_mp.plane_fmt[j].sizeimage); + + cur += write_str(cur, end - cur, "\n"); + } + cur += write_str(cur, end - cur, "-------------------------------\n"); + cur += write_str(cur, end - cur, "ETB Count: %d\n", + inst->debug_count.etb); + cur += write_str(cur, end - cur, "EBD Count: %d\n", + inst->debug_count.ebd); + cur += write_str(cur, end - cur, "FTB Count: %d\n", + inst->debug_count.ftb); + cur += write_str(cur, end - cur, "FBD Count: %d\n", + inst->debug_count.fbd); + + publish_unreleased_reference(inst, &cur, end); + len = simple_read_from_buffer(buf, count, ppos, + dbuf, cur - dbuf); + + vfree(dbuf); +failed_alloc: + put_inst(inst); + return len; +} + +static int inst_info_release(struct inode *inode, struct file *file) +{ + d_vpr_l("Release inode ptr: %pK\n", inode->i_private); + file->private_data = NULL; + return 0; +} + +static const struct file_operations inst_info_fops = { + .open = inst_info_open, + .read = inst_info_read, + .release = inst_info_release, +}; + +struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst, struct dentry *parent) +{ + struct dentry *dir = NULL, *info = NULL; + char debugfs_name[MAX_DEBUGFS_NAME]; + struct core_inst_pair *idata = NULL; + + snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%d", inst->session_id); + + idata = vzalloc(sizeof(*idata)); + if (!idata) { + i_vpr_e(inst, "%s: allocation failed\n", __func__); + goto exit; + } + + idata->core = inst->core; + idata->inst = inst; + + dir = debugfs_create_dir(debugfs_name, parent); + if (IS_ERR_OR_NULL(dir)) { + dir = NULL; + i_vpr_e(inst, + "%s: Failed to create debugfs for msm_vidc\n", + __func__); + goto failed_create_dir; + } + + info = debugfs_create_file("info", 0444, dir, + idata, &inst_info_fops); + if (IS_ERR_OR_NULL(info)) { + i_vpr_e(inst, "%s: debugfs_create_file: fail\n", + __func__); + goto failed_create_file; + } + + dir->d_inode->i_private = info->d_inode->i_private; + inst->debug.pdata[FRAME_PROCESSING].sampling = true; + return dir; + +failed_create_file: + debugfs_remove_recursive(dir); + dir = NULL; +failed_create_dir: + vfree(idata); +exit: + return dir; +} + +void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst) +{ + struct dentry *dentry = NULL; + + if (!inst->debugfs_root) + return; + + dentry = inst->debugfs_root; + if (dentry->d_inode) { + i_vpr_l(inst, "%s: Destroy %pK\n", + __func__, dentry->d_inode->i_private); + vfree(dentry->d_inode->i_private); + dentry->d_inode->i_private = NULL; + } + debugfs_remove_recursive(dentry); + inst->debugfs_root = NULL; +} + +void msm_vidc_debugfs_update(struct msm_vidc_inst *inst, + enum msm_vidc_debugfs_event e) +{ + struct msm_vidc_debug *d; + char a[64] = "Frame processing"; + + d = &inst->debug; + + switch (e) { + case MSM_VIDC_DEBUGFS_EVENT_ETB: + inst->debug_count.etb++; + if (inst->debug_count.ebd && + inst->debug_count.ftb > inst->debug_count.fbd) { + d->pdata[FRAME_PROCESSING].name[0] = '\0'; + tic(inst, FRAME_PROCESSING, a); + } + break; + case MSM_VIDC_DEBUGFS_EVENT_EBD: + inst->debug_count.ebd++; + /* + * Host needs to ensure FW atleast have 2 buffers available always + * one for HW processing and another for fw processing in parallel + * to avoid FW starving for buffers + */ + if (inst->debug_count.etb < (inst->debug_count.ebd + 2)) { + toc(inst, FRAME_PROCESSING); + i_vpr_p(inst, + "EBD: FW needs input buffers. Processed etb %llu ebd %llu ftb %llu fbd %llu\n", + inst->debug_count.etb, inst->debug_count.ebd, + inst->debug_count.ftb, inst->debug_count.fbd); + } + if (inst->debug_count.fbd && + inst->debug_count.ftb < (inst->debug_count.fbd + 2)) + i_vpr_p(inst, + "EBD: FW needs output buffers. Processed etb %llu ebd %llu ftb %llu fbd %llu\n", + inst->debug_count.etb, inst->debug_count.ebd, + inst->debug_count.ftb, inst->debug_count.fbd); + break; + case MSM_VIDC_DEBUGFS_EVENT_FTB: + inst->debug_count.ftb++; + if (inst->debug_count.ebd && + inst->debug_count.etb > inst->debug_count.ebd) { + d->pdata[FRAME_PROCESSING].name[0] = '\0'; + tic(inst, FRAME_PROCESSING, a); + } + break; + case MSM_VIDC_DEBUGFS_EVENT_FBD: + inst->debug_count.fbd++; + inst->debug.samples++; + /* + * Host needs to ensure FW atleast have 2 buffers available always + * one for HW processing and another for fw processing in parallel + * to avoid FW starving for buffers + */ + if (inst->debug_count.ftb < (inst->debug_count.fbd + 2)) { + toc(inst, FRAME_PROCESSING); + i_vpr_p(inst, + "FBD: FW needs output buffers. Processed etb %llu ebd %llu ftb %llu fbd %llu\n", + inst->debug_count.etb, inst->debug_count.ebd, + inst->debug_count.ftb, inst->debug_count.fbd); + } + if (inst->debug_count.ebd && + inst->debug_count.etb < (inst->debug_count.ebd + 2)) + i_vpr_p(inst, + "FBD: FW needs input buffers. Processed etb %llu ebd %llu ftb %llu fbd %llu\n", + inst->debug_count.etb, inst->debug_count.ebd, + inst->debug_count.ftb, inst->debug_count.fbd); + break; + default: + i_vpr_e(inst, "invalid event in debugfs: %d\n", e); + break; + } +} + +int msm_vidc_check_ratelimit(void) +{ + static DEFINE_RATELIMIT_STATE(_rs, + VIDC_DBG_SESSION_RATELIMIT_INTERVAL, + VIDC_DBG_SESSION_RATELIMIT_BURST); + return __ratelimit(&_rs); +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_driver.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_driver.c new file mode 100644 index 0000000000..1fe57b2faa --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_driver.c @@ -0,0 +1,5487 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include "msm_media_info.h" + +#include "msm_vidc_driver.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_control.h" +#include "msm_vidc_memory.h" +#include "msm_vidc_state.h" +#include "msm_vidc_power.h" +#include "msm_vidc_debug.h" +#include "msm_vidc.h" +#include "msm_vdec.h" +#include "msm_venc.h" +#include "msm_vidc_fence.h" +#include "venus_hfi.h" +#include "venus_hfi_response.h" +#include "hfi_packet.h" +#include "msm_vidc_events.h" + +extern struct msm_vidc_core *g_core; + +#define is_odd(val) ((val) % 2 == 1) +#define in_range(val, min, max) (((min) <= (val)) && ((val) <= (max))) +#define COUNT_BITS(a, out) { \ + while ((a) >= 1) { \ + (out) += (a) & (1); \ + (a) >>= (1); \ + } \ +} + +#define SSR_TYPE 0x0000000F +#define SSR_TYPE_SHIFT 0 +#define SSR_SUB_CLIENT_ID 0x000000F0 +#define SSR_SUB_CLIENT_ID_SHIFT 4 +#define SSR_ADDR_ID 0xFFFFFFFF00000000 +#define SSR_ADDR_SHIFT 32 + +#define STABILITY_TYPE 0x0000000F +#define STABILITY_TYPE_SHIFT 0 +#define STABILITY_SUB_CLIENT_ID 0x000000F0 +#define STABILITY_SUB_CLIENT_ID_SHIFT 4 +#define STABILITY_PAYLOAD_ID 0xFFFFFFFF00000000 +#define STABILITY_PAYLOAD_SHIFT 32 + +/* do not modify the cap names as it is used in test scripts */ +static const char * const cap_name_arr[] = + FOREACH_CAP(GENERATE_STRING); + +const char *cap_name(enum msm_vidc_inst_capability_type cap_id) +{ + const char *name = "UNKNOWN CAP"; + + if (cap_id >= ARRAY_SIZE(cap_name_arr)) + goto exit; + + name = cap_name_arr[cap_id]; + +exit: + return name; +} + +static const char * const buf_type_name_arr[] = + FOREACH_BUF_TYPE(GENERATE_STRING); + +const char *buf_name(enum msm_vidc_buffer_type type) +{ + const char *name = "UNKNOWN BUF"; + + if (type >= ARRAY_SIZE(buf_type_name_arr)) + goto exit; + + name = buf_type_name_arr[type]; + +exit: + return name; +} + +static const char * const inst_allow_name_arr[] = + FOREACH_ALLOW(GENERATE_STRING); + +const char *allow_name(enum msm_vidc_allow allow) +{ + const char *name = "UNKNOWN"; + + if (allow >= ARRAY_SIZE(inst_allow_name_arr)) + goto exit; + + name = inst_allow_name_arr[allow]; + +exit: + return name; +} + +const char *v4l2_type_name(u32 port) +{ + switch (port) { + case INPUT_MPLANE: return "INPUT"; + case OUTPUT_MPLANE: return "OUTPUT"; + case INPUT_META_PLANE: return "INPUT_META"; + case OUTPUT_META_PLANE: return "OUTPUT_META"; + } + + return "UNKNOWN"; +} + +const char *v4l2_pixelfmt_name(struct msm_vidc_inst *inst, u32 pixfmt) +{ + struct msm_vidc_core *core; + const struct codec_info *codec_info; + const struct color_format_info *color_format_info; + u32 i, size; + + core = inst->core; + codec_info = core->platform->data.format_data->codec_info; + size = core->platform->data.format_data->codec_info_size; + + for (i = 0; i < size; i++) { + if (codec_info[i].v4l2_codec == pixfmt) + return codec_info[i].pixfmt_name; + } + + color_format_info = core->platform->data.format_data->color_format_info; + size = core->platform->data.format_data->color_format_info_size; + + for (i = 0; i < size; i++) { + if (color_format_info[i].v4l2_color_format == pixfmt) + return color_format_info[i].pixfmt_name; + } + + return "UNKNOWN"; +} + +void print_vidc_buffer(u32 tag, const char *tag_str, const char *str, struct msm_vidc_inst *inst, + struct msm_vidc_buffer *vbuf) +{ + struct dma_buf *dbuf; + struct inode *f_inode; + unsigned long inode_num = 0; + long ref_count = -1; + + if (!vbuf || !tag_str || !str) + return; + + dbuf = (struct dma_buf *)vbuf->dmabuf; + if (dbuf && dbuf->file) { + f_inode = file_inode(dbuf->file); + if (f_inode) { + inode_num = f_inode->i_ino; + ref_count = file_count(dbuf->file); + } + } + + dprintk_inst(tag, tag_str, inst, + "%s: %s: idx %2d fd %3d off %d daddr %#llx inode %8lu ref %2ld size %8d filled %8d flags %#x ts %8lld attr %#x dbuf_get %d attach %d map %d counts(etb ebd ftb fbd) %4llu %4llu %4llu %4llu\n", + str, buf_name(vbuf->type), + vbuf->index, vbuf->fd, vbuf->data_offset, + vbuf->device_addr, inode_num, ref_count, vbuf->buffer_size, + vbuf->data_size, vbuf->flags, vbuf->timestamp, vbuf->attr, + vbuf->dbuf_get, vbuf->attach ? 1 : 0, vbuf->sg_table ? 1 : 0, + inst->debug_count.etb, inst->debug_count.ebd, + inst->debug_count.ftb, inst->debug_count.fbd); + + trace_msm_v4l2_vidc_buffer_event_log(inst, str, buf_name(vbuf->type), vbuf, + inode_num, ref_count); +} + +void print_vb2_buffer(const char *str, struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + if (vb2->type == INPUT_MPLANE || vb2->type == OUTPUT_MPLANE) { + i_vpr_e(inst, + "%s: %s: idx %2d fd %d off %d size %d filled %d\n", + str, vb2->type == INPUT_MPLANE ? "INPUT" : "OUTPUT", + vb2->index, vb2->planes[0].m.fd, + vb2->planes[0].data_offset, vb2->planes[0].length, + vb2->planes[0].bytesused); + } else if (vb2->type == INPUT_META_PLANE || vb2->type == OUTPUT_META_PLANE) { + i_vpr_e(inst, + "%s: %s: idx %2d fd %d off %d size %d filled %d\n", + str, vb2->type == INPUT_MPLANE ? "INPUT_META" : "OUTPUT_META", + vb2->index, vb2->planes[0].m.fd, + vb2->planes[0].data_offset, vb2->planes[0].length, + vb2->planes[0].bytesused); + } +} + +static void print_buffer_stats(u32 tag, const char *tag_str, struct msm_vidc_inst *inst, + struct msm_vidc_buffer_stats *stats) +{ + if (!tag_str || !stats) + return; + + /* skip flushed buffer stats */ + if (!stats->etb_time_ms || !stats->ebd_time_ms || + !stats->ftb_time_ms || !stats->fbd_time_ms) + return; + + dprintk_inst(tag, tag_str, inst, + "f.no %4u ts %16llu (etb ebd ftb fbd)ms %6u %6u %6u %6u (ebd-etb fbd-etb etb-ftb)ms %4d %4d %4d size %8u attr %#x\n", + stats->frame_num, stats->timestamp, stats->etb_time_ms, stats->ebd_time_ms, + stats->ftb_time_ms, stats->fbd_time_ms, stats->ebd_time_ms - stats->etb_time_ms, + stats->fbd_time_ms - stats->etb_time_ms, stats->etb_time_ms - stats->ftb_time_ms, + stats->data_size, stats->flags); +} + +static u32 msm_vidc_get_buffer_stats_flag(struct msm_vidc_inst *inst) +{ + u32 flags = 0; + + if (inst->hfi_frame_info.data_corrupt) + flags |= MSM_VIDC_STATS_FLAG_CORRUPT; + + if (inst->hfi_frame_info.overflow) + flags |= MSM_VIDC_STATS_FLAG_OVERFLOW; + + if (inst->hfi_frame_info.no_output) + flags |= MSM_VIDC_STATS_FLAG_NO_OUTPUT; + + if (inst->hfi_frame_info.subframe_input) + flags |= MSM_VIDC_STATS_FLAG_SUBFRAME_INPUT; + + return flags; +} + +int msm_vidc_suspend(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = venus_hfi_suspend(core); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_add_buffer_stats(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf, u64 timestamp) +{ + struct msm_vidc_buffer_stats *stats = NULL; + + if (!(msm_vidc_debug & VIDC_LOW)) + return 0; + + /* stats applicable only to input & output buffers */ + if (!is_input_buffer(buf->type) && !is_output_buffer(buf->type)) + return -EINVAL; + + /* update start timestamp */ + buf->start_time_ms = (ktime_get_ns() / 1000 - inst->initial_time_us) / 1000; + + /* add buffer stats only in ETB path */ + if (!is_input_buffer(buf->type)) + return 0; + + stats = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_BUF_STATS); + if (!stats) + return -ENOMEM; + INIT_LIST_HEAD(&stats->list); + list_add_tail(&stats->list, &inst->buffer_stats_list); + + stats->frame_num = inst->debug_count.etb; + stats->timestamp = timestamp; + stats->ts_offset = 0; + stats->etb_time_ms = buf->start_time_ms; + if (is_decode_session(inst)) + stats->data_size = buf->data_size; + + return 0; +} + +int msm_vidc_remove_buffer_stats(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf, u64 timestamp) +{ + struct msm_vidc_buffer_stats *stats = NULL, *dummy_stats = NULL; + struct msm_vidc_buffer_stats *prev_stats = NULL; + bool remove_stat = false, is_first_stat = false;; + + if (!(msm_vidc_debug & VIDC_LOW)) + return 0; + + /* stats applicable only to input & output buffers */ + if (!is_input_buffer(buf->type) && !is_output_buffer(buf->type)) + return -EINVAL; + + /* update end timestamp */ + buf->end_time_ms = (ktime_get_ns() / 1000 - inst->initial_time_us) / 1000; + + list_for_each_entry_safe(stats, dummy_stats, &inst->buffer_stats_list, list) { + if (stats->timestamp - stats->ts_offset != timestamp) + continue; + + remove_stat = false; + if (is_input_buffer(buf->type)) { + /* skip - ebd already updated(multiple input - single output case) */ + if (stats->ebd_time_ms) + continue; + + /* ebd: update end ts and return */ + stats->ebd_time_ms = buf->end_time_ms; + stats->flags |= msm_vidc_get_buffer_stats_flag(inst); + + /* multi in - single out (interlace/slice decoding case) */ + is_first_stat = list_is_first(&stats->list, &inst->buffer_stats_list); + if (!is_first_stat) { + prev_stats = list_prev_entry(stats, list); + + /* add offset if FW requires more etb's to process output */ + if (prev_stats->flags & MSM_VIDC_STATS_FLAG_SUBFRAME_INPUT) + stats->ts_offset = stats->timestamp - prev_stats->timestamp; + } + + /* remove entry - no output attached */ + remove_stat = !!(stats->flags & MSM_VIDC_STATS_FLAG_NO_OUTPUT); + remove_stat |= stats->ebd_time_ms && stats->fbd_time_ms; + } else if (is_output_buffer(buf->type)) { + /* skip - ebd already updated(encoder superframe case) */ + if (stats->fbd_time_ms) + continue; + + /* fbd: update end ts */ + stats->ftb_time_ms = buf->start_time_ms; + stats->fbd_time_ms = buf->end_time_ms; + stats->flags |= msm_vidc_get_buffer_stats_flag(inst); + if (is_encode_session(inst)) + stats->data_size = buf->data_size; + + remove_stat |= stats->ebd_time_ms && stats->fbd_time_ms; + } + /* remove stats node */ + if (remove_stat) { + list_del_init(&stats->list); + print_buffer_stats(VIDC_LOW, "low ", inst, stats); + msm_vidc_pool_free(inst, stats); + } + } + + return 0; +} + +int msm_vidc_flush_buffer_stats(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buffer_stats *stats, *dummy_stats; + + i_vpr_l(inst, "%s: flush buffer_stats list\n", __func__); + list_for_each_entry_safe(stats, dummy_stats, &inst->buffer_stats_list, list) { + list_del_init(&stats->list); + msm_vidc_pool_free(inst, stats); + } + + /* reset initial ts as well to avoid huge delta */ + inst->initial_time_us = ktime_get_ns() / 1000; + + return 0; +} + +enum msm_vidc_buffer_type v4l2_type_to_driver(u32 type, const char *func) +{ + enum msm_vidc_buffer_type buffer_type = 0; + + switch (type) { + case INPUT_MPLANE: + buffer_type = MSM_VIDC_BUF_INPUT; + break; + case OUTPUT_MPLANE: + buffer_type = MSM_VIDC_BUF_OUTPUT; + break; + case INPUT_META_PLANE: + buffer_type = MSM_VIDC_BUF_INPUT_META; + break; + case OUTPUT_META_PLANE: + buffer_type = MSM_VIDC_BUF_OUTPUT_META; + break; + default: + d_vpr_e("%s: invalid v4l2 buffer type %#x\n", func, type); + break; + } + return buffer_type; +} + +u32 v4l2_type_from_driver(enum msm_vidc_buffer_type buffer_type, + const char *func) +{ + u32 type = 0; + + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + type = INPUT_MPLANE; + break; + case MSM_VIDC_BUF_OUTPUT: + type = OUTPUT_MPLANE; + break; + case MSM_VIDC_BUF_INPUT_META: + type = INPUT_META_PLANE; + break; + case MSM_VIDC_BUF_OUTPUT_META: + type = OUTPUT_META_PLANE; + break; + default: + d_vpr_e("%s: invalid driver buffer type %d\n", + func, buffer_type); + break; + } + return type; +} + +enum msm_vidc_codec_type v4l2_codec_to_driver(struct msm_vidc_inst *inst, + u32 v4l2_codec, const char *func) +{ + struct msm_vidc_core *core; + const struct codec_info *codec_info; + u32 i, size; + enum msm_vidc_codec_type codec = 0; + + core = inst->core; + codec_info = core->platform->data.format_data->codec_info; + size = core->platform->data.format_data->codec_info_size; + + for (i = 0; i < size; i++) { + if (codec_info[i].v4l2_codec == v4l2_codec) + return codec_info[i].vidc_codec; + } + + d_vpr_h("%s: invalid v4l2 codec %#x\n", func, v4l2_codec); + return codec; +} + +u32 v4l2_codec_from_driver(struct msm_vidc_inst *inst, + enum msm_vidc_codec_type codec, const char *func) +{ + struct msm_vidc_core *core; + const struct codec_info *codec_info; + u32 i, size; + u32 v4l2_codec = 0; + + core = inst->core; + codec_info = core->platform->data.format_data->codec_info; + size = core->platform->data.format_data->codec_info_size; + + for (i = 0; i < size; i++) { + if (codec_info[i].vidc_codec == codec) + return codec_info[i].v4l2_codec; + } + + d_vpr_e("%s: invalid driver codec %#x\n", func, codec); + return v4l2_codec; +} + +enum msm_vidc_colorformat_type v4l2_colorformat_to_driver( + struct msm_vidc_inst *inst, + u32 v4l2_colorformat, const char *func) +{ + struct msm_vidc_core *core; + const struct color_format_info *color_format_info; + u32 i, size; + enum msm_vidc_colorformat_type colorformat = 0; + + core = inst->core; + color_format_info = core->platform->data.format_data->color_format_info; + size = core->platform->data.format_data->color_format_info_size; + + for (i = 0; i < size; i++) { + if (color_format_info[i].v4l2_color_format == v4l2_colorformat) + return color_format_info[i].vidc_color_format; + } + + d_vpr_e("%s: invalid v4l2 color format %#x\n", func, v4l2_colorformat); + return colorformat; +} + +u32 v4l2_colorformat_from_driver(struct msm_vidc_inst *inst, + enum msm_vidc_colorformat_type colorformat, + const char *func) +{ + struct msm_vidc_core *core; + const struct color_format_info *color_format_info; + u32 i, size; + u32 v4l2_colorformat = 0; + + core = inst->core; + color_format_info = core->platform->data.format_data->color_format_info; + size = core->platform->data.format_data->color_format_info_size; + + for (i = 0; i < size; i++) { + if (color_format_info[i].vidc_color_format == colorformat) + return color_format_info[i].v4l2_color_format; + } + + d_vpr_e("%s: invalid driver color format %#x\n", func, colorformat); + return v4l2_colorformat; +} + +u32 v4l2_color_primaries_to_driver(struct msm_vidc_inst *inst, + u32 v4l2_primaries, const char *func) +{ + struct msm_vidc_core *core; + const struct color_primaries_info *color_prim_info; + u32 i, size; + u32 vidc_color_primaries = MSM_VIDC_PRIMARIES_RESERVED; + + core = inst->core; + color_prim_info = core->platform->data.format_data->color_prim_info; + size = core->platform->data.format_data->color_prim_info_size; + + for (i = 0; i < size; i++) { + if (color_prim_info[i].v4l2_color_primaries == v4l2_primaries) + return color_prim_info[i].vidc_color_primaries; + } + + i_vpr_e(inst, "%s: invalid v4l2 color primaries %d\n", + func, v4l2_primaries); + + return vidc_color_primaries; +} + +u32 v4l2_color_primaries_from_driver(struct msm_vidc_inst *inst, + u32 vidc_color_primaries, const char *func) +{ + struct msm_vidc_core *core; + const struct color_primaries_info *color_prim_info; + u32 i, size; + u32 v4l2_primaries = V4L2_COLORSPACE_DEFAULT; + + core = inst->core; + color_prim_info = core->platform->data.format_data->color_prim_info; + size = core->platform->data.format_data->color_prim_info_size; + + for (i = 0; i < size; i++) { + if (color_prim_info[i].vidc_color_primaries == vidc_color_primaries) + return color_prim_info[i].v4l2_color_primaries; + } + + i_vpr_e(inst, "%s: invalid hfi color primaries %d\n", + func, vidc_color_primaries); + + return v4l2_primaries; +} + +u32 v4l2_transfer_char_to_driver(struct msm_vidc_inst *inst, + u32 v4l2_transfer_char, const char *func) +{ + struct msm_vidc_core *core; + const struct transfer_char_info *transfer_char_info; + u32 i, size; + u32 vidc_transfer_char = MSM_VIDC_TRANSFER_RESERVED; + + core = inst->core; + transfer_char_info = core->platform->data.format_data->transfer_char_info; + size = core->platform->data.format_data->transfer_char_info_size; + + for (i = 0; i < size; i++) { + if (transfer_char_info[i].v4l2_transfer_char == v4l2_transfer_char) + return transfer_char_info[i].vidc_transfer_char; + } + + i_vpr_e(inst, "%s: invalid v4l2 transfer char %d\n", + func, v4l2_transfer_char); + + return vidc_transfer_char; +} + +u32 v4l2_transfer_char_from_driver(struct msm_vidc_inst *inst, + u32 vidc_transfer_char, const char *func) +{ + struct msm_vidc_core *core; + const struct transfer_char_info *transfer_char_info; + u32 i, size; + u32 v4l2_transfer_char = V4L2_XFER_FUNC_DEFAULT; + + core = inst->core; + transfer_char_info = core->platform->data.format_data->transfer_char_info; + size = core->platform->data.format_data->transfer_char_info_size; + + for (i = 0; i < size; i++) { + if (transfer_char_info[i].vidc_transfer_char == vidc_transfer_char) + return transfer_char_info[i].v4l2_transfer_char; + } + + i_vpr_e(inst, "%s: invalid hfi transfer char %d\n", + func, vidc_transfer_char); + + return v4l2_transfer_char; +} + +u32 v4l2_matrix_coeff_to_driver(struct msm_vidc_inst *inst, + u32 v4l2_matrix_coeff, const char *func) +{ + struct msm_vidc_core *core; + const struct matrix_coeff_info *matrix_coeff_info; + u32 i, size; + u32 vidc_matrix_coeff = MSM_VIDC_MATRIX_COEFF_RESERVED; + + core = inst->core; + matrix_coeff_info = core->platform->data.format_data->matrix_coeff_info; + size = core->platform->data.format_data->matrix_coeff_info_size; + + for (i = 0; i < size; i++) { + if (matrix_coeff_info[i].v4l2_matrix_coeff == v4l2_matrix_coeff) + return matrix_coeff_info[i].vidc_matrix_coeff; + } + + i_vpr_e(inst, "%s: invalid v4l2 matrix coeff %d\n", + func, v4l2_matrix_coeff); + + return vidc_matrix_coeff; +} + +u32 v4l2_matrix_coeff_from_driver(struct msm_vidc_inst *inst, + u32 vidc_matrix_coeff, const char *func) +{ + struct msm_vidc_core *core; + const struct matrix_coeff_info *matrix_coeff_info; + u32 i, size; + u32 v4l2_matrix_coeff = V4L2_YCBCR_ENC_DEFAULT; + + core = inst->core; + matrix_coeff_info = core->platform->data.format_data->matrix_coeff_info; + size = core->platform->data.format_data->matrix_coeff_info_size; + + for (i = 0; i < size; i++) { + if (matrix_coeff_info[i].vidc_matrix_coeff == vidc_matrix_coeff) + return matrix_coeff_info[i].v4l2_matrix_coeff; + } + + i_vpr_e(inst, "%s: invalid hfi matrix coeff %d\n", + func, vidc_matrix_coeff); + + return v4l2_matrix_coeff; +} + +int v4l2_type_to_driver_port(struct msm_vidc_inst *inst, u32 type, + const char *func) +{ + int port; + + if (type == INPUT_MPLANE) { + port = INPUT_PORT; + } else if (type == INPUT_META_PLANE) { + port = INPUT_META_PORT; + } else if (type == OUTPUT_MPLANE) { + port = OUTPUT_PORT; + } else if (type == OUTPUT_META_PLANE) { + port = OUTPUT_META_PORT; + } else { + i_vpr_e(inst, "%s: port not found for v4l2 type %d\n", + func, type); + port = -EINVAL; + } + + return port; +} + +struct msm_vidc_buffers *msm_vidc_get_buffers( + struct msm_vidc_inst *inst, enum msm_vidc_buffer_type buffer_type, + const char *func) +{ + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + return &inst->buffers.input; + case MSM_VIDC_BUF_INPUT_META: + return &inst->buffers.input_meta; + case MSM_VIDC_BUF_OUTPUT: + return &inst->buffers.output; + case MSM_VIDC_BUF_OUTPUT_META: + return &inst->buffers.output_meta; + case MSM_VIDC_BUF_READ_ONLY: + return &inst->buffers.read_only; + case MSM_VIDC_BUF_BIN: + return &inst->buffers.bin; + case MSM_VIDC_BUF_ARP: + return &inst->buffers.arp; + case MSM_VIDC_BUF_COMV: + return &inst->buffers.comv; + case MSM_VIDC_BUF_NON_COMV: + return &inst->buffers.non_comv; + case MSM_VIDC_BUF_LINE: + return &inst->buffers.line; + case MSM_VIDC_BUF_DPB: + return &inst->buffers.dpb; + case MSM_VIDC_BUF_PERSIST: + return &inst->buffers.persist; + case MSM_VIDC_BUF_VPSS: + return &inst->buffers.vpss; + case MSM_VIDC_BUF_PARTIAL_DATA: + return &inst->buffers.partial_data; + case MSM_VIDC_BUF_INTERFACE_QUEUE: + return NULL; + default: + i_vpr_e(inst, "%s: invalid driver buffer type %d\n", + func, buffer_type); + return NULL; + } +} + +struct msm_vidc_mem_list *msm_vidc_get_mem_info( + struct msm_vidc_inst *inst, enum msm_vidc_buffer_type buffer_type, + const char *func) +{ + switch (buffer_type) { + case MSM_VIDC_BUF_BIN: + return &inst->mem_info.bin; + case MSM_VIDC_BUF_ARP: + return &inst->mem_info.arp; + case MSM_VIDC_BUF_COMV: + return &inst->mem_info.comv; + case MSM_VIDC_BUF_NON_COMV: + return &inst->mem_info.non_comv; + case MSM_VIDC_BUF_LINE: + return &inst->mem_info.line; + case MSM_VIDC_BUF_DPB: + return &inst->mem_info.dpb; + case MSM_VIDC_BUF_PERSIST: + return &inst->mem_info.persist; + case MSM_VIDC_BUF_VPSS: + return &inst->mem_info.vpss; + case MSM_VIDC_BUF_PARTIAL_DATA: + return &inst->mem_info.partial_data; + default: + i_vpr_e(inst, "%s: invalid driver buffer type %d\n", + func, buffer_type); + return NULL; + } +} + +bool res_is_greater_than(u32 width, u32 height, + u32 ref_width, u32 ref_height) +{ + u32 num_mbs = NUM_MBS_PER_FRAME(height, width); + u32 max_side = max(ref_width, ref_height); + + if (num_mbs > NUM_MBS_PER_FRAME(ref_height, ref_width) || + width > max_side || + height > max_side) + return true; + else + return false; +} + +bool res_is_greater_than_or_equal_to(u32 width, u32 height, + u32 ref_width, u32 ref_height) +{ + u32 num_mbs = NUM_MBS_PER_FRAME(height, width); + u32 max_side = max(ref_width, ref_height); + + if (num_mbs >= NUM_MBS_PER_FRAME(ref_height, ref_width) || + width >= max_side || + height >= max_side) + return true; + else + return false; +} + +bool res_is_less_than(u32 width, u32 height, + u32 ref_width, u32 ref_height) +{ + u32 num_mbs = NUM_MBS_PER_FRAME(height, width); + u32 max_side = max(ref_width, ref_height); + + if (num_mbs < NUM_MBS_PER_FRAME(ref_height, ref_width) && + width < max_side && + height < max_side) + return true; + else + return false; +} + +bool res_is_less_than_or_equal_to(u32 width, u32 height, + u32 ref_width, u32 ref_height) +{ + u32 num_mbs = NUM_MBS_PER_FRAME(height, width); + u32 max_side = max(ref_width, ref_height); + + if (num_mbs <= NUM_MBS_PER_FRAME(ref_height, ref_width) && + width <= max_side && + height <= max_side) + return true; + else + return false; +} + +int signal_session_msg_receipt(struct msm_vidc_inst *inst, + enum signal_session_response cmd) +{ + if (cmd < MAX_SIGNAL) + complete(&inst->completions[cmd]); + return 0; +} + +bool msm_vidc_allow_metadata_delivery(struct msm_vidc_inst *inst, u32 cap_id, + u32 port) +{ + return true; +} + +bool msm_vidc_allow_metadata_subscription(struct msm_vidc_inst *inst, u32 cap_id, + u32 port) +{ + bool is_allowed = true; + + if (port == INPUT_PORT) { + switch (cap_id) { + case META_BUF_TAG: + case META_BITSTREAM_RESOLUTION: + case META_CROP_OFFSETS: + case META_SEI_MASTERING_DISP: + case META_SEI_CLL: + case META_HDR10PLUS: + if (!is_meta_rx_inp_enabled(inst, META_OUTBUF_FENCE)) { + i_vpr_h(inst, + "%s: cap: %24s not allowed as output buffer fence is disabled\n", + __func__, cap_name(cap_id)); + is_allowed = false; + } + break; + case META_DPB_TAG_LIST: + if (!is_ubwc_colorformat(inst->capabilities[PIX_FMTS].value)) { + i_vpr_h(inst, + "%s: cap: %24s not allowed for split mode\n", + __func__, cap_name(cap_id)); + is_allowed = false; + } + break; + default: + is_allowed = true; + break; + } + } else if (port == OUTPUT_PORT) { + is_allowed = true; + } else { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + is_allowed = false; + } + + return is_allowed; +} + +bool msm_vidc_allow_property(struct msm_vidc_inst *inst, u32 hfi_id) +{ + bool is_allowed = true; + + switch (hfi_id) { + case HFI_PROP_AV1_TILE_ROWS_COLUMNS: + case HFI_PROP_AV1_UNIFORM_TILE_SPACING: + if (inst->codec == MSM_VIDC_AV1) + is_allowed = true; + else + is_allowed = false; + break; + case HFI_PROP_FENCE: + if (!is_meta_rx_inp_enabled(inst, META_OUTBUF_FENCE)) { + i_vpr_h(inst, + "%s: cap: %24s not enabled, hence not allowed to subscribe\n", + __func__, cap_name(META_OUTBUF_FENCE)); + is_allowed = false; + } + break; + default: + is_allowed = true; + break; + } + + return is_allowed; +} + +enum msm_vidc_allow msm_vidc_allow_input_psc(struct msm_vidc_inst *inst) +{ + enum msm_vidc_allow allow = MSM_VIDC_ALLOW; + + /* + * if drc sequence is not completed by client, fw is not + * expected to raise another ipsc + */ + if (is_sub_state(inst, MSM_VIDC_DRC)) { + i_vpr_e(inst, "%s: not allowed in sub state %s\n", + __func__, inst->sub_state_name); + return MSM_VIDC_DISALLOW; + } + + return allow; +} + +bool msm_vidc_allow_drain_last_flag(struct msm_vidc_inst *inst) +{ + /* + * drain last flag is expected only when DRAIN, INPUT_PAUSE + * is set and DRAIN_LAST_BUFFER is not set + */ + if (is_sub_state(inst, MSM_VIDC_DRAIN) && + is_sub_state(inst, MSM_VIDC_INPUT_PAUSE) && + !is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER)) + return true; + + i_vpr_e(inst, "%s: not allowed in sub state %s\n", + __func__, inst->sub_state_name); + return false; +} + +bool msm_vidc_allow_psc_last_flag(struct msm_vidc_inst *inst) +{ + /* + * drc last flag is expected only when DRC, INPUT_PAUSE + * is set and DRC_LAST_BUFFER is not set + */ + if (is_sub_state(inst, MSM_VIDC_DRC) && + is_sub_state(inst, MSM_VIDC_INPUT_PAUSE) && + !is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) + return true; + + i_vpr_e(inst, "%s: not allowed in sub state %s\n", + __func__, inst->sub_state_name); + + return false; +} + +enum msm_vidc_allow msm_vidc_allow_pm_suspend(struct msm_vidc_core *core) +{ + /* core must be in valid state to do pm_suspend */ + if (!core_in_valid_state(core)) { + d_vpr_e("%s: invalid core state %s\n", + __func__, core_state_name(core->state)); + return MSM_VIDC_DISALLOW; + } + + /* check if power is enabled */ + if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) { + d_vpr_h("%s: Power already disabled\n", __func__); + return MSM_VIDC_IGNORE; + } + + return MSM_VIDC_ALLOW; +} + +bool is_hevc_10bit_decode_session(struct msm_vidc_inst *inst) +{ + bool is10bit = false; + enum msm_vidc_colorformat_type colorformat; + + /* in case of decoder session return false */ + if (!is_decode_session(inst)) + return false; + + colorformat = v4l2_colorformat_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, __func__); + + if (colorformat == MSM_VIDC_FMT_TP10C || colorformat == MSM_VIDC_FMT_P010) + is10bit = true; + + return is_decode_session(inst) && + inst->codec == MSM_VIDC_HEVC && + is10bit; +} + +int msm_vidc_state_change_streamon(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + enum msm_vidc_state new_state = MSM_VIDC_ERROR; + + if (port == INPUT_META_PORT || port == OUTPUT_META_PORT) + return 0; + + if (port == INPUT_PORT) { + if (is_state(inst, MSM_VIDC_OPEN)) + new_state = MSM_VIDC_INPUT_STREAMING; + else if (is_state(inst, MSM_VIDC_OUTPUT_STREAMING)) + new_state = MSM_VIDC_STREAMING; + } else if (port == OUTPUT_PORT) { + if (is_state(inst, MSM_VIDC_OPEN)) + new_state = MSM_VIDC_OUTPUT_STREAMING; + else if (is_state(inst, MSM_VIDC_INPUT_STREAMING)) + new_state = MSM_VIDC_STREAMING; + } + + rc = msm_vidc_change_state(inst, new_state, __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_state_change_streamoff(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + enum msm_vidc_state new_state = MSM_VIDC_ERROR; + + if (port == INPUT_META_PORT || port == OUTPUT_META_PORT) + return 0; + + if (port == INPUT_PORT) { + if (is_state(inst, MSM_VIDC_INPUT_STREAMING)) + new_state = MSM_VIDC_OPEN; + else if (is_state(inst, MSM_VIDC_STREAMING)) + new_state = MSM_VIDC_OUTPUT_STREAMING; + } else if (port == OUTPUT_PORT) { + if (is_state(inst, MSM_VIDC_OUTPUT_STREAMING)) + new_state = MSM_VIDC_OPEN; + else if (is_state(inst, MSM_VIDC_STREAMING)) + new_state = MSM_VIDC_INPUT_STREAMING; + } + rc = msm_vidc_change_state(inst, new_state, __func__); + if (rc) + goto exit; + +exit: + return rc; +} + +int msm_vidc_process_drain(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = venus_hfi_session_drain(inst, INPUT_PORT); + if (rc) + return rc; + rc = msm_vidc_change_sub_state(inst, 0, MSM_VIDC_DRAIN, __func__); + if (rc) + return rc; + + msm_vidc_scale_power(inst, true); + + return rc; +} + +int msm_vidc_process_resume(struct msm_vidc_inst *inst) +{ + int rc = 0; + enum msm_vidc_sub_state clear_sub_state = MSM_VIDC_SUB_STATE_NONE; + bool drain_pending = false; + + msm_vidc_scale_power(inst, true); + + /* first check DRC pending else check drain pending */ + if (is_sub_state(inst, MSM_VIDC_DRC) && + is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) { + clear_sub_state = MSM_VIDC_DRC | MSM_VIDC_DRC_LAST_BUFFER; + /* + * if drain sequence is not completed then do not resume here. + * client will eventually complete drain sequence in which ports + * will be resumed. + */ + drain_pending = is_sub_state(inst, MSM_VIDC_DRAIN) && + is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER); + if (!drain_pending) { + if (is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + rc = venus_hfi_session_resume(inst, INPUT_PORT, + HFI_CMD_SETTINGS_CHANGE); + if (rc) + return rc; + clear_sub_state |= MSM_VIDC_INPUT_PAUSE; + } + if (is_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE) && + !is_encode_session(inst)) { + rc = venus_hfi_session_resume(inst, OUTPUT_PORT, + HFI_CMD_SETTINGS_CHANGE); + if (rc) + return rc; + clear_sub_state |= MSM_VIDC_OUTPUT_PAUSE; + } + } + } else if (is_sub_state(inst, MSM_VIDC_DRAIN) && + is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER)) { + clear_sub_state = MSM_VIDC_DRAIN | MSM_VIDC_DRAIN_LAST_BUFFER; + if (is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + rc = venus_hfi_session_resume(inst, INPUT_PORT, HFI_CMD_DRAIN); + if (rc) + return rc; + clear_sub_state |= MSM_VIDC_INPUT_PAUSE; + } + if (is_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE) && + !is_encode_session(inst)) { + rc = venus_hfi_session_resume(inst, OUTPUT_PORT, HFI_CMD_DRAIN); + if (rc) + return rc; + clear_sub_state |= MSM_VIDC_OUTPUT_PAUSE; + } + } + + rc = msm_vidc_change_sub_state(inst, clear_sub_state, 0, __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_process_streamon_input(struct msm_vidc_inst *inst) +{ + int rc = 0; + enum msm_vidc_sub_state clear_sub_state = MSM_VIDC_SUB_STATE_NONE; + enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE; + + msm_vidc_scale_power(inst, true); + + rc = venus_hfi_start(inst, INPUT_PORT); + if (rc) + return rc; + + /* clear input pause substate immediately */ + if (is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + rc = msm_vidc_change_sub_state(inst, MSM_VIDC_INPUT_PAUSE, 0, __func__); + if (rc) + return rc; + } + + /* + * if DRC sequence is not completed by the client then PAUSE + * firmware input port to avoid firmware raising IPSC again. + * When client completes DRC or DRAIN sequences, firmware + * input port will be resumed. + */ + if (is_sub_state(inst, MSM_VIDC_DRC) || + is_sub_state(inst, MSM_VIDC_DRAIN) || + is_sub_state(inst, MSM_VIDC_FIRST_IPSC)) { + if (!is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + rc = venus_hfi_session_pause(inst, INPUT_PORT); + if (rc) + return rc; + set_sub_state = MSM_VIDC_INPUT_PAUSE; + } + } + + rc = msm_vidc_state_change_streamon(inst, INPUT_PORT); + if (rc) + return rc; + + rc = msm_vidc_change_sub_state(inst, clear_sub_state, set_sub_state, __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_process_streamon_output(struct msm_vidc_inst *inst) +{ + int rc = 0; + enum msm_vidc_sub_state clear_sub_state = MSM_VIDC_SUB_STATE_NONE; + enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE; + bool drain_pending = false; + + msm_vidc_scale_power(inst, true); + + /* + * client completed drc sequence, reset DRC and + * MSM_VIDC_DRC_LAST_BUFFER substates + */ + if (is_sub_state(inst, MSM_VIDC_DRC) && + is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) { + clear_sub_state = MSM_VIDC_DRC | MSM_VIDC_DRC_LAST_BUFFER; + } + /* + * Client is completing port reconfiguration, hence reallocate + * input internal buffers before input port is resumed. + * Drc sub-state cannot be checked because DRC sub-state will + * not be set during initial port reconfiguration. + */ + if (is_decode_session(inst) && + is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + rc = msm_vidc_alloc_and_queue_input_internal_buffers(inst); + if (rc) + return rc; + rc = msm_vidc_set_stage(inst, STAGE); + if (rc) + return rc; + rc = msm_vidc_set_pipe(inst, PIPE); + if (rc) + return rc; + /* + * Input port subscription for metadata may be changed. + * For eg: due to IPSC, driver may have disabled tx + * type output fence, hence fence related metadatas + * to recieve on input port will be disabled by HAL. + * Hence, update metadata subscription properties + * on INPUT port before sending RESUME command to FW. + */ + i_vpr_l(inst, "%s: reset input port subscribe metadata\n", + __func__); + rc = msm_vdec_subscribe_metadata(inst, INPUT_PORT); + if (rc) + return rc; + } + + /* + * fw input port is paused due to ipsc. now that client + * completed drc sequence, resume fw input port provided + * drain is not pending and input port is streaming. + */ + drain_pending = is_sub_state(inst, MSM_VIDC_DRAIN) && + is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER); + if (!drain_pending && is_state(inst, MSM_VIDC_INPUT_STREAMING)) { + if (is_sub_state(inst, MSM_VIDC_INPUT_PAUSE)) { + i_vpr_h(inst, "%s: resume input port\n", __func__); + rc = venus_hfi_session_resume(inst, INPUT_PORT, + HFI_CMD_SETTINGS_CHANGE); + if (rc) + return rc; + clear_sub_state |= MSM_VIDC_INPUT_PAUSE; + } + } + + if (is_sub_state(inst, MSM_VIDC_FIRST_IPSC)) + clear_sub_state |= MSM_VIDC_FIRST_IPSC; + + rc = venus_hfi_start(inst, OUTPUT_PORT); + if (rc) + return rc; + + /* clear output pause substate immediately */ + if (is_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE)) { + rc = msm_vidc_change_sub_state(inst, MSM_VIDC_OUTPUT_PAUSE, 0, __func__); + if (rc) + return rc; + } + + rc = msm_vidc_state_change_streamon(inst, OUTPUT_PORT); + if (rc) + return rc; + + rc = msm_vidc_change_sub_state(inst, clear_sub_state, set_sub_state, __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_process_stop_done(struct msm_vidc_inst *inst, + enum signal_session_response signal_type) +{ + int rc = 0; + enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE; + + if (signal_type == SIGNAL_CMD_STOP_INPUT) { + set_sub_state = MSM_VIDC_INPUT_PAUSE; + /* + * FW is expected to return DRC LAST flag before input + * stop done if DRC sequence is pending + */ + if (is_sub_state(inst, MSM_VIDC_DRC) && + !is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER)) { + i_vpr_e(inst, "%s: drc last flag pkt not received\n", __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + /* + * for a decode session, FW is expected to return + * DRAIN LAST flag before input stop done if + * DRAIN sequence is pending + */ + if (is_decode_session(inst) && + is_sub_state(inst, MSM_VIDC_DRAIN) && + !is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER)) { + i_vpr_e(inst, "%s: drain last flag pkt not received\n", __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + } else if (signal_type == SIGNAL_CMD_STOP_OUTPUT) { + set_sub_state = MSM_VIDC_OUTPUT_PAUSE; + } + + rc = msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__); + if (rc) + return rc; + + signal_session_msg_receipt(inst, signal_type); + return rc; +} + +int msm_vidc_process_drain_done(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (is_sub_state(inst, MSM_VIDC_DRAIN)) { + rc = msm_vidc_change_sub_state(inst, 0, MSM_VIDC_INPUT_PAUSE, __func__); + if (rc) + return rc; + } else { + i_vpr_e(inst, "%s: unexpected drain done\n", __func__); + } + + return rc; +} + +int msm_vidc_process_drain_last_flag(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct v4l2_event event = {0}; + + rc = msm_vidc_state_change_drain_last_flag(inst); + if (rc) + return rc; + + if (!inst->capabilities[LAST_FLAG_EVENT_ENABLE].value) { + i_vpr_h(inst, "%s: last flag event not enabled\n", __func__); + return 0; + } + + event.type = V4L2_EVENT_EOS; + v4l2_event_queue_fh(&inst->fh, &event); + + return rc; +} + +int msm_vidc_process_psc_last_flag(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct v4l2_event event = {0}; + + rc = msm_vidc_state_change_psc_last_flag(inst); + if (rc) + return rc; + + if (!inst->capabilities[LAST_FLAG_EVENT_ENABLE].value) { + i_vpr_h(inst, "%s: last flag event not enabled\n", __func__); + return 0; + } + + event.type = V4L2_EVENT_EOS; + v4l2_event_queue_fh(&inst->fh, &event); + + return rc; +} + +int msm_vidc_state_change_input_psc(struct msm_vidc_inst *inst) +{ + int rc = 0; + enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE; + + /* + * if output port is not streaming, then do not set DRC substate + * because DRC_LAST_FLAG is not going to be received. Update + * INPUT_PAUSE substate only + */ + if (is_state(inst, MSM_VIDC_INPUT_STREAMING) || + is_state(inst, MSM_VIDC_OPEN)) + set_sub_state = MSM_VIDC_INPUT_PAUSE | MSM_VIDC_FIRST_IPSC; + else + set_sub_state = MSM_VIDC_DRC | MSM_VIDC_INPUT_PAUSE; + + rc = msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_state_change_drain_last_flag(struct msm_vidc_inst *inst) +{ + int rc = 0; + enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE; + + set_sub_state = MSM_VIDC_DRAIN_LAST_BUFFER | MSM_VIDC_OUTPUT_PAUSE; + rc = msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_state_change_psc_last_flag(struct msm_vidc_inst *inst) +{ + int rc = 0; + enum msm_vidc_sub_state set_sub_state = MSM_VIDC_SUB_STATE_NONE; + + set_sub_state = MSM_VIDC_DRC_LAST_BUFFER | MSM_VIDC_OUTPUT_PAUSE; + rc = msm_vidc_change_sub_state(inst, 0, set_sub_state, __func__); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_get_fence_fd(struct msm_vidc_inst *inst, int *fence_fd) +{ + int rc = 0; + struct msm_vidc_fence *fence, *dummy_fence; + struct msm_vidc_core *core; + bool found = false; + + *fence_fd = INVALID_FD; + core = inst->core; + + list_for_each_entry_safe(fence, dummy_fence, &inst->fence_list, list) { + if (fence->fence_id == + (u64)inst->capabilities[FENCE_ID].value) { + found = true; + break; + } + } + + if (!found) { + i_vpr_h(inst, "%s: could not find matching fence for fence id: %d\n", + __func__, inst->capabilities[FENCE_ID].value); + goto exit; + } + + if (fence->fd == INVALID_FD) { + rc = call_fence_op(core, fence_create_fd, inst, fence); + if (rc) + goto exit; + } + + *fence_fd = fence->fd; + +exit: + return rc; +} + +int msm_vidc_get_control(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl) +{ + int rc = 0; + enum msm_vidc_inst_capability_type cap_id; + + cap_id = msm_vidc_get_cap_id(inst, ctrl->id); + if (!is_valid_cap_id(cap_id)) { + i_vpr_e(inst, "%s: could not find cap_id for ctrl %s\n", + __func__, ctrl->name); + return -EINVAL; + } + + switch (cap_id) { + case MIN_BUFFERS_OUTPUT: + ctrl->val = inst->buffers.output.min_count + + inst->buffers.output.extra_count; + i_vpr_h(inst, "g_min: output buffers %d\n", ctrl->val); + break; + case MIN_BUFFERS_INPUT: + ctrl->val = inst->buffers.input.min_count + + inst->buffers.input.extra_count; + i_vpr_h(inst, "g_min: input buffers %d\n", ctrl->val); + break; + case FILM_GRAIN: + ctrl->val = inst->capabilities[FILM_GRAIN].value; + i_vpr_h(inst, "%s: film grain present: %d\n", + __func__, ctrl->val); + break; + case FENCE_FD: + rc = msm_vidc_get_fence_fd(inst, &ctrl->val); + if (!rc) + i_vpr_l(inst, "%s: fence fd: %d\n", + __func__, ctrl->val); + break; + case MAX_NUM_REORDER_FRAMES: + ctrl->val = inst->capabilities[MAX_NUM_REORDER_FRAMES].value; + i_vpr_h(inst, "%s: max num reorder frames: %d\n", + __func__, ctrl->val); + break; + case CODED_FRAMES: + ctrl->val = inst->capabilities[CODED_FRAMES].value; + i_vpr_h(inst, "%s: coded frames: %d\n", __func__, ctrl->val); + break; + default: + i_vpr_e(inst, "invalid ctrl %s id %d\n", + ctrl->name, ctrl->id); + return -EINVAL; + } + + return rc; +} + +int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst) +{ + int height = 0, width = 0; + struct v4l2_format *inp_f; + + if (is_decode_session(inst)) { + inp_f = &inst->fmts[INPUT_PORT]; + width = max(inp_f->fmt.pix_mp.width, inst->crop.width); + height = max(inp_f->fmt.pix_mp.height, inst->crop.height); + } else if (is_encode_session(inst)) { + width = inst->crop.width; + height = inst->crop.height; + } + + return NUM_MBS_PER_FRAME(height, width); +} + +int msm_vidc_get_fps(struct msm_vidc_inst *inst) +{ + int fps; + u32 frame_rate, operating_rate; + + frame_rate = msm_vidc_get_frame_rate(inst); + operating_rate = msm_vidc_get_operating_rate(inst); + + if (operating_rate > frame_rate) + fps = operating_rate ? operating_rate : 1; + else + fps = frame_rate; + + return fps; +} + +int msm_vidc_num_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type type, enum msm_vidc_buffer_attributes attr) +{ + int count = 0; + struct msm_vidc_buffer *vbuf; + struct msm_vidc_buffers *buffers; + + if (is_output_buffer(type)) { + buffers = &inst->buffers.output; + } else if (is_input_buffer(type)) { + buffers = &inst->buffers.input; + } else { + i_vpr_e(inst, "%s: invalid buffer type %#x\n", + __func__, type); + return count; + } + + list_for_each_entry(vbuf, &buffers->list, list) { + if (vbuf->type != type) + continue; + if (!(vbuf->attr & attr)) + continue; + count++; + } + + return count; +} + +int vb2_buffer_to_driver(struct vb2_buffer *vb2, + struct msm_vidc_buffer *buf) +{ + int rc = 0; + struct vb2_v4l2_buffer *vbuf; + + if (!vb2 || !buf) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + vbuf = to_vb2_v4l2_buffer(vb2); + + buf->fd = vb2->planes[0].m.fd; + buf->data_offset = vb2->planes[0].data_offset; + buf->data_size = vb2->planes[0].bytesused - vb2->planes[0].data_offset; + buf->buffer_size = vb2->planes[0].length; + buf->timestamp = vb2->timestamp; + buf->flags = vbuf->flags; + buf->attr = 0; + buf->fence_id = 0; + + return rc; +} + +int msm_vidc_process_readonly_buffers(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + int rc = 0; + struct msm_vidc_buffer *ro_buf, *dummy; + struct msm_vidc_core *core; + + core = inst->core; + + if (!is_decode_session(inst) || !is_output_buffer(buf->type)) + return 0; + + /* + * check if read_only buffer is present in read_only list + * if present: add ro flag to buf provided buffer is not + * pending release + */ + list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) { + if (ro_buf->device_addr != buf->device_addr) + continue; + if (ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY && + !(ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE)) { + /* add READ_ONLY to the buffer going to the firmware */ + buf->attr |= MSM_VIDC_ATTR_READ_ONLY; + /* + * remove READ_ONLY on the read_only list buffer so that + * it will get removed from the read_only list below + */ + ro_buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY; + break; + } + } + + /* remove ro buffers if not required anymore */ + list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) { + /* if read only buffer do not remove */ + if (ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY) + continue; + + print_vidc_buffer(VIDC_LOW, "low ", "ro buf removed", inst, ro_buf); + /* unmap the buffer if driver holds mapping */ + if (ro_buf->sg_table && ro_buf->attach) { + call_mem_op(core, dma_buf_unmap_attachment, core, + ro_buf->attach, ro_buf->sg_table); + call_mem_op(core, dma_buf_detach, core, + ro_buf->dmabuf, ro_buf->attach); + ro_buf->sg_table = NULL; + ro_buf->attach = NULL; + } + if (ro_buf->dbuf_get) { + call_mem_op(core, dma_buf_put, inst, ro_buf->dmabuf); + ro_buf->dmabuf = NULL; + ro_buf->dbuf_get = 0; + } + + list_del_init(&ro_buf->list); + msm_vidc_pool_free(inst, ro_buf); + } + + return rc; +} + +int msm_vidc_set_auto_framerate(struct msm_vidc_inst *inst, u64 timestamp) +{ + struct msm_vidc_core *core; + struct msm_vidc_timestamp *ts; + struct msm_vidc_timestamp *prev = NULL; + u32 counter = 0, prev_fr = 0, curr_fr = 0; + u64 time_us = 0; + int rc = 0; + + core = inst->core; + if (!core->capabilities[ENC_AUTO_FRAMERATE].value || + is_image_session(inst) || msm_vidc_is_super_buffer(inst) || + !inst->capabilities[TIME_DELTA_BASED_RC].value) + goto exit; + + rc = msm_vidc_update_timestamp_rate(inst, timestamp); + if (rc) + goto exit; + + list_for_each_entry(ts, &inst->timestamps.list, sort.list) { + if (prev) { + time_us = ts->sort.val - prev->sort.val; + prev_fr = curr_fr; + curr_fr = time_us ? DIV64_U64_ROUND_CLOSEST(USEC_PER_SEC, time_us) << 16 : + inst->auto_framerate; + if (curr_fr > inst->capabilities[FRAME_RATE].max) + curr_fr = inst->capabilities[FRAME_RATE].max; + } + prev = ts; + counter++; + } + + if (counter < ENC_FPS_WINDOW) + goto exit; + + if (curr_fr > inst->capabilities[FRAME_RATE].value) { + i_vpr_l(inst, "%s: fps: %u limitted to client fps.\n", __func__, curr_fr >> 16); + curr_fr = inst->capabilities[FRAME_RATE].value; + } + + /* if framerate changed and stable for 2 frames, set to firmware */ + if (curr_fr == prev_fr && curr_fr != inst->auto_framerate) { + i_vpr_l(inst, "%s: updated fps: %u -> %u\n", __func__, + inst->auto_framerate >> 16, curr_fr >> 16); + rc = venus_hfi_session_property(inst, + HFI_PROP_FRAME_RATE, + HFI_HOST_FLAGS_NONE, + HFI_PORT_BITSTREAM, + HFI_PAYLOAD_Q16, + &curr_fr, + sizeof(u32)); + if (rc) { + i_vpr_e(inst, "%s: set auto frame rate failed\n", + __func__); + goto exit; + } + inst->auto_framerate = curr_fr; + } +exit: + return rc; +} + +int msm_vidc_update_input_rate(struct msm_vidc_inst *inst, u64 time_us) +{ + struct msm_vidc_input_timer *input_timer; + struct msm_vidc_input_timer *prev_timer = NULL; + struct msm_vidc_core *core; + u64 counter = 0; + u64 input_timer_sum_us = 0; + + core = inst->core; + + input_timer = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_BUF_TIMER); + if (!input_timer) + return -ENOMEM; + + input_timer->time_us = time_us; + INIT_LIST_HEAD(&input_timer->list); + list_add_tail(&input_timer->list, &inst->input_timer_list); + list_for_each_entry(input_timer, &inst->input_timer_list, list) { + if (prev_timer) { + input_timer_sum_us += input_timer->time_us - prev_timer->time_us; + counter++; + } + prev_timer = input_timer; + } + + if (input_timer_sum_us && counter >= INPUT_TIMER_LIST_SIZE) + inst->capabilities[INPUT_RATE].value = + (s32)(DIV64_U64_ROUND_CLOSEST(counter * 1000000, + input_timer_sum_us) << 16); + + /* delete the first entry once counter >= INPUT_TIMER_LIST_SIZE */ + if (counter >= INPUT_TIMER_LIST_SIZE) { + input_timer = list_first_entry(&inst->input_timer_list, + struct msm_vidc_input_timer, list); + list_del_init(&input_timer->list); + msm_vidc_pool_free(inst, input_timer); + } + + return 0; +} + +int msm_vidc_flush_input_timer(struct msm_vidc_inst *inst) +{ + struct msm_vidc_input_timer *input_timer, *dummy_timer; + struct msm_vidc_core *core; + + core = inst->core; + + i_vpr_l(inst, "%s: flush input_timer list\n", __func__); + list_for_each_entry_safe(input_timer, dummy_timer, &inst->input_timer_list, list) { + list_del_init(&input_timer->list); + msm_vidc_pool_free(inst, input_timer); + } + return 0; +} + +int msm_vidc_get_input_rate(struct msm_vidc_inst *inst) +{ + return inst->capabilities[INPUT_RATE].value >> 16; +} + +int msm_vidc_get_timestamp_rate(struct msm_vidc_inst *inst) +{ + return inst->capabilities[TIMESTAMP_RATE].value >> 16; +} + +int msm_vidc_get_frame_rate(struct msm_vidc_inst *inst) +{ + return inst->capabilities[FRAME_RATE].value >> 16; +} + +int msm_vidc_get_operating_rate(struct msm_vidc_inst *inst) +{ + return inst->capabilities[OPERATING_RATE].value >> 16; +} + +static int msm_vidc_insert_sort(struct list_head *head, + struct msm_vidc_sort *entry) +{ + struct msm_vidc_sort *first, *node; + struct msm_vidc_sort *prev = NULL; + bool is_inserted = false; + + if (!head || !entry) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (list_empty(head)) { + list_add(&entry->list, head); + return 0; + } + + first = list_first_entry(head, struct msm_vidc_sort, list); + if (entry->val < first->val) { + list_add(&entry->list, head); + return 0; + } + + list_for_each_entry(node, head, list) { + if (prev && + entry->val >= prev->val && entry->val <= node->val) { + list_add(&entry->list, &prev->list); + is_inserted = true; + break; + } + prev = node; + } + + if (!is_inserted && prev) + list_add(&entry->list, &prev->list); + + return 0; +} + +static struct msm_vidc_timestamp *msm_vidc_get_least_rank_ts(struct msm_vidc_inst *inst) +{ + struct msm_vidc_timestamp *ts, *final = NULL; + u64 least_rank = INT_MAX; + + list_for_each_entry(ts, &inst->timestamps.list, sort.list) { + if (ts->rank < least_rank) { + least_rank = ts->rank; + final = ts; + } + } + + return final; +} + +int msm_vidc_flush_ts(struct msm_vidc_inst *inst) +{ + struct msm_vidc_timestamp *temp, *ts = NULL; + struct msm_vidc_core *core; + + core = inst->core; + + list_for_each_entry_safe(ts, temp, &inst->timestamps.list, sort.list) { + i_vpr_l(inst, "%s: flushing ts: val %llu, rank %llu\n", + __func__, ts->sort.val, ts->rank); + list_del(&ts->sort.list); + msm_vidc_pool_free(inst, ts); + } + inst->timestamps.count = 0; + inst->timestamps.rank = 0; + + return 0; +} + +int msm_vidc_update_timestamp_rate(struct msm_vidc_inst *inst, u64 timestamp) +{ + struct msm_vidc_timestamp *ts, *prev = NULL; + struct msm_vidc_core *core; + int rc = 0; + u32 window_size = 0; + u32 timestamp_rate = 0; + u64 ts_ms = 0; + u32 counter = 0; + + core = inst->core; + + ts = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_TIMESTAMP); + if (!ts) { + i_vpr_e(inst, "%s: ts alloc failed\n", __func__); + return -ENOMEM; + } + + INIT_LIST_HEAD(&ts->sort.list); + ts->sort.val = timestamp; + ts->rank = inst->timestamps.rank++; + rc = msm_vidc_insert_sort(&inst->timestamps.list, &ts->sort); + if (rc) + return rc; + inst->timestamps.count++; + + if (is_encode_session(inst)) + window_size = ENC_FPS_WINDOW; + else + window_size = DEC_FPS_WINDOW; + + /* keep sliding window */ + if (inst->timestamps.count > window_size) { + ts = msm_vidc_get_least_rank_ts(inst); + if (!ts) { + i_vpr_e(inst, "%s: least rank ts is NULL\n", __func__); + return -EINVAL; + } + inst->timestamps.count--; + list_del(&ts->sort.list); + msm_vidc_pool_free(inst, ts); + } + + /* Calculate timestamp rate */ + list_for_each_entry(ts, &inst->timestamps.list, sort.list) { + if (prev) { + if (ts->sort.val == prev->sort.val) + continue; + ts_ms += div_u64(ts->sort.val - prev->sort.val, 1000000); + counter++; + } + prev = ts; + } + if (ts_ms) + timestamp_rate = (u32)div_u64((u64)counter * 1000, ts_ms); + + msm_vidc_update_cap_value(inst, TIMESTAMP_RATE, timestamp_rate << 16, __func__); + + return 0; +} + +int msm_vidc_ts_reorder_insert_timestamp(struct msm_vidc_inst *inst, u64 timestamp) +{ + struct msm_vidc_timestamp *ts; + struct msm_vidc_core *core; + int rc = 0; + + core = inst->core; + + /* allocate ts from pool */ + ts = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_TIMESTAMP); + if (!ts) { + i_vpr_e(inst, "%s: ts alloc failed\n", __func__); + return -ENOMEM; + } + + /* initialize ts node */ + INIT_LIST_HEAD(&ts->sort.list); + ts->sort.val = timestamp; + rc = msm_vidc_insert_sort(&inst->ts_reorder.list, &ts->sort); + if (rc) + return rc; + inst->ts_reorder.count++; + + return 0; +} + +int msm_vidc_ts_reorder_remove_timestamp(struct msm_vidc_inst *inst, u64 timestamp) +{ + struct msm_vidc_timestamp *ts, *temp; + struct msm_vidc_core *core; + + core = inst->core; + + /* remove matching node */ + list_for_each_entry_safe(ts, temp, &inst->ts_reorder.list, sort.list) { + if (ts->sort.val == timestamp) { + list_del_init(&ts->sort.list); + inst->ts_reorder.count--; + msm_vidc_pool_free(inst, ts); + break; + } + } + + return 0; +} + +int msm_vidc_ts_reorder_get_first_timestamp(struct msm_vidc_inst *inst, u64 *timestamp) +{ + struct msm_vidc_timestamp *ts; + struct msm_vidc_core *core; + + core = inst->core; + + /* check if list empty */ + if (list_empty(&inst->ts_reorder.list)) { + i_vpr_e(inst, "%s: list empty. ts %lld\n", __func__, *timestamp); + return -EINVAL; + } + + /* get 1st node from reorder list */ + ts = list_first_entry(&inst->ts_reorder.list, + struct msm_vidc_timestamp, sort.list); + list_del_init(&ts->sort.list); + + /* copy timestamp */ + *timestamp = ts->sort.val; + + inst->ts_reorder.count--; + msm_vidc_pool_free(inst, ts); + + return 0; +} + +int msm_vidc_ts_reorder_flush(struct msm_vidc_inst *inst) +{ + struct msm_vidc_timestamp *temp, *ts = NULL; + struct msm_vidc_core *core; + + core = inst->core; + + /* flush all entries */ + list_for_each_entry_safe(ts, temp, &inst->ts_reorder.list, sort.list) { + i_vpr_l(inst, "%s: flushing ts: val %lld\n", __func__, ts->sort.val); + list_del(&ts->sort.list); + msm_vidc_pool_free(inst, ts); + } + inst->ts_reorder.count = 0; + + return 0; +} + +struct msm_vidc_buffer *msm_vidc_get_driver_buf(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + int rc = 0; + struct msm_vidc_buffer *buf; + struct msm_vidc_core *core; + + core = inst->core; + + buf = msm_vidc_fetch_buffer(inst, vb2); + if (!buf) { + i_vpr_e(inst, "%s: failed to fetch buffer\n", __func__); + return NULL; + } + + rc = vb2_buffer_to_driver(vb2, buf); + if (rc) + return NULL; + + /* treat every buffer as deferred buffer initially */ + buf->attr |= MSM_VIDC_ATTR_DEFERRED; + + if (is_decode_session(inst) && is_output_buffer(buf->type)) { + /* get a reference */ + if (!buf->dbuf_get) { + buf->dmabuf = call_mem_op(core, dma_buf_get, inst, buf->fd); + if (!buf->dmabuf) + return NULL; + buf->dbuf_get = 1; + } + } + + return buf; +} + +int msm_vidc_allocate_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buf_type, u32 num_buffers) +{ + int rc = 0; + int idx = 0; + struct msm_vidc_buffer *buf = NULL; + struct msm_vidc_buffers *buffers; + struct msm_vidc_core *core; + + core = inst->core; + + buffers = msm_vidc_get_buffers(inst, buf_type, __func__); + if (!buffers) + return -EINVAL; + + for (idx = 0; idx < num_buffers; idx++) { + buf = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_BUFFER); + if (!buf) { + i_vpr_e(inst, "%s: alloc failed\n", __func__); + return -EINVAL; + } + INIT_LIST_HEAD(&buf->list); + list_add_tail(&buf->list, &buffers->list); + buf->type = buf_type; + buf->index = idx; + buf->region = call_mem_op(core, buffer_region, inst, buf_type); + } + i_vpr_h(inst, "%s: allocated %d buffers for type %s\n", + __func__, num_buffers, buf_name(buf_type)); + + return rc; +} + +int msm_vidc_free_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buf_type) +{ + int rc = 0; + int buf_count = 0; + struct msm_vidc_buffer *buf, *dummy; + struct msm_vidc_buffers *buffers; + struct msm_vidc_core *core; + + core = inst->core; + + buffers = msm_vidc_get_buffers(inst, buf_type, __func__); + if (!buffers) + return -EINVAL; + + list_for_each_entry_safe(buf, dummy, &buffers->list, list) { + buf_count++; + print_vidc_buffer(VIDC_LOW, "low ", "free buffer", inst, buf); + list_del_init(&buf->list); + msm_vidc_pool_free(inst, buf); + } + i_vpr_h(inst, "%s: freed %d buffers for type %s\n", + __func__, buf_count, buf_name(buf_type)); + + return rc; +} + +struct msm_vidc_buffer *msm_vidc_fetch_buffer(struct msm_vidc_inst *inst, + struct vb2_buffer *vb2) +{ + struct msm_vidc_buffer *buf = NULL; + struct msm_vidc_buffers *buffers; + enum msm_vidc_buffer_type buf_type; + bool found = false; + + buf_type = v4l2_type_to_driver(vb2->type, __func__); + if (!buf_type) + return NULL; + + buffers = msm_vidc_get_buffers(inst, buf_type, __func__); + if (!buffers) + return NULL; + + list_for_each_entry(buf, &buffers->list, list) { + if (buf->index == vb2->index) { + found = true; + break; + } + } + + if (!found) { + i_vpr_e(inst, "%s: buffer not found for index %d for vb2 buffer type %s\n", + __func__, vb2->index, v4l2_type_name(vb2->type)); + return NULL; + } + + return buf; +} + +struct msm_vidc_buffer *get_meta_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + struct msm_vidc_buffer *mbuf; + struct msm_vidc_buffers *buffers; + bool found = false; + + if (is_input_buffer(buf->type)) { + buffers = &inst->buffers.input_meta; + } else if (is_output_buffer(buf->type)) { + buffers = &inst->buffers.output_meta; + } else { + i_vpr_e(inst, "%s: invalid buffer type %d\n", + __func__, buf->type); + return NULL; + } + list_for_each_entry(mbuf, &buffers->list, list) { + if (mbuf->index == buf->index) { + found = true; + break; + } + } + if (!found) + return NULL; + + return mbuf; +} + +bool msm_vidc_is_super_buffer(struct msm_vidc_inst *inst) +{ + return !!inst->capabilities[SUPER_FRAME].value; +} + +static bool is_single_session(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + u32 count = 0; + + core = inst->core; + + core_lock(core, __func__); + list_for_each_entry(inst, &core->instances, list) + count++; + core_unlock(core, __func__); + + return count == 1; +} + +void msm_vidc_allow_dcvs(struct msm_vidc_inst *inst) +{ + bool allow = false; + struct msm_vidc_core *core; + u32 fps; + + core = inst->core; + + allow = !msm_vidc_clock_voting; + if (!allow) { + i_vpr_h(inst, "%s: core_clock_voting is set\n", __func__); + goto exit; + } + + allow = core->capabilities[DCVS].value; + if (!allow) { + i_vpr_h(inst, "%s: core doesn't support dcvs\n", __func__); + goto exit; + } + + allow = !inst->decode_batch.enable; + if (!allow) { + i_vpr_h(inst, "%s: decode_batching enabled\n", __func__); + goto exit; + } + + allow = !msm_vidc_is_super_buffer(inst); + if (!allow) { + i_vpr_h(inst, "%s: encode_batching(super_buffer) enabled\n", __func__); + goto exit; + } + + allow = !is_thumbnail_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: thumbnail session\n", __func__); + goto exit; + } + + allow = !is_critical_priority_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: critical priority session\n", __func__); + goto exit; + } + + allow = !is_image_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: image session\n", __func__); + goto exit; + } + + allow = !is_lowlatency_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: lowlatency session\n", __func__); + goto exit; + } + + fps = msm_vidc_get_fps(inst); + if (is_decode_session(inst) && + fps >= inst->capabilities[FRAME_RATE].max) { + allow = false; + i_vpr_h(inst, "%s: unsupported fps %d\n", __func__, fps); + goto exit; + } + +exit: + i_vpr_hp(inst, "%s: dcvs: %s\n", __func__, allow ? "enabled" : "disabled"); + + inst->power.dcvs_flags = 0; + inst->power.dcvs_mode = allow; +} + +bool msm_vidc_allow_decode_batch(struct msm_vidc_inst *inst) +{ + struct msm_vidc_inst_cap *cap; + struct msm_vidc_core *core; + bool allow = false; + u32 value = 0; + + core = inst->core; + cap = &inst->capabilities[0]; + + allow = inst->decode_batch.enable; + if (!allow) { + i_vpr_h(inst, "%s: batching already disabled\n", __func__); + goto exit; + } + + allow = core->capabilities[DECODE_BATCH].value; + if (!allow) { + i_vpr_h(inst, "%s: core doesn't support batching\n", __func__); + goto exit; + } + + allow = is_single_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: multiple sessions running\n", __func__); + goto exit; + } + + allow = is_decode_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: not a decoder session\n", __func__); + goto exit; + } + + allow = !is_thumbnail_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: thumbnail session\n", __func__); + goto exit; + } + + allow = !is_image_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: image session\n", __func__); + goto exit; + } + + allow = is_realtime_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: non-realtime session\n", __func__); + goto exit; + } + + allow = !is_lowlatency_session(inst); + if (!allow) { + i_vpr_h(inst, "%s: lowlatency session\n", __func__); + goto exit; + } + + value = msm_vidc_get_fps(inst); + allow = value < cap[BATCH_FPS].value; + if (!allow) { + i_vpr_h(inst, "%s: unsupported fps %u, max %u\n", __func__, + value, cap[BATCH_FPS].value); + goto exit; + } + + value = msm_vidc_get_mbs_per_frame(inst); + allow = value < cap[BATCH_MBPF].value; + if (!allow) { + i_vpr_h(inst, "%s: unsupported mbpf %u, max %u\n", __func__, + value, cap[BATCH_MBPF].value); + goto exit; + } + +exit: + i_vpr_hp(inst, "%s: batching: %s\n", __func__, allow ? "enabled" : "disabled"); + + return allow; +} + +static void msm_vidc_update_input_cr(struct msm_vidc_inst *inst, u32 idx, u32 cr) +{ + struct msm_vidc_input_cr_data *temp = NULL, *next = NULL; + bool found = false; + + list_for_each_entry_safe(temp, next, &inst->enc_input_crs, list) { + if (temp->index == idx) { + temp->input_cr = cr; + found = true; + break; + } + } + if (!found) { + temp = NULL; + temp = vzalloc(sizeof(*temp)); + if (!temp) { + i_vpr_e(inst, "%s: allocation failed\n", __func__); + return; + } + temp->index = idx; + temp->input_cr = cr; + list_add_tail(&temp->list, &inst->enc_input_crs); + } +} + +void msm_vidc_update_stats(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf, enum msm_vidc_debugfs_event etype) +{ + if ((is_decode_session(inst) && etype == MSM_VIDC_DEBUGFS_EVENT_ETB) || + (is_encode_session(inst) && etype == MSM_VIDC_DEBUGFS_EVENT_FBD)) + inst->stats.data_size += buf->data_size; + + msm_vidc_debugfs_update(inst, etype); +} + +void msm_vidc_print_stats(struct msm_vidc_inst *inst) +{ + u32 frame_rate, operating_rate, achieved_fps, priority, etb, ebd, ftb, fbd, dt_ms; + u64 bitrate_kbps = 0, time_ms = ktime_get_ns() / 1000 / 1000; + + etb = inst->debug_count.etb - inst->stats.count.etb; + ebd = inst->debug_count.ebd - inst->stats.count.ebd; + ftb = inst->debug_count.ftb - inst->stats.count.ftb; + fbd = inst->debug_count.fbd - inst->stats.count.fbd; + frame_rate = inst->capabilities[FRAME_RATE].value >> 16; + operating_rate = inst->capabilities[OPERATING_RATE].value >> 16; + priority = inst->capabilities[PRIORITY].value; + + dt_ms = time_ms - inst->stats.time_ms; + achieved_fps = (fbd * 1000) / dt_ms; + bitrate_kbps = (inst->stats.data_size * 8 * 1000) / (dt_ms * 1024); + + i_vpr_hs(inst, + "counts (etb,ebd,ftb,fbd): %u %u %u %u (total %llu %llu %llu %llu), achieved bitrate %lldKbps fps %u/s, frame rate %u, operating rate %u, priority %u, avg bw llcc %ukhz, avb bw ddr %ukhz, dt %ums\n", + etb, ebd, ftb, fbd, inst->debug_count.etb, inst->debug_count.ebd, + inst->debug_count.ftb, inst->debug_count.fbd, bitrate_kbps, + achieved_fps, frame_rate, operating_rate, priority, + inst->stats.avg_bw_llcc, inst->stats.avg_bw_ddr, dt_ms); + + inst->stats.count = inst->debug_count; + inst->stats.data_size = 0; + inst->stats.avg_bw_llcc = 0; + inst->stats.avg_bw_ddr = 0; + inst->stats.time_ms = time_ms; +} + +void msm_vidc_print_memory_stats(struct msm_vidc_inst *inst) +{ + static enum msm_vidc_buffer_type buf_type_arr[9] = { + MSM_VIDC_BUF_BIN, + MSM_VIDC_BUF_ARP, + MSM_VIDC_BUF_COMV, + MSM_VIDC_BUF_NON_COMV, + MSM_VIDC_BUF_LINE, + MSM_VIDC_BUF_DPB, + MSM_VIDC_BUF_PERSIST, + MSM_VIDC_BUF_VPSS, + MSM_VIDC_BUF_PARTIAL_DATA, + }; + u32 count_arr[9]; + u32 size_arr[9]; + u32 size_kb_arr[9]; + u64 total_size = 0; + struct msm_vidc_buffers *buffers; + int cnt; + + /* reset array values */ + memset(&count_arr, 0, sizeof(count_arr)); + memset(&size_arr, 0, sizeof(size_arr)); + memset(&size_kb_arr, 0, sizeof(size_kb_arr)); + + /* populate buffer details */ + for (cnt = 0; cnt < 9; cnt++) { + buffers = msm_vidc_get_buffers(inst, buf_type_arr[cnt], __func__); + if (!buffers) + continue; + + size_arr[cnt] = buffers->size; + count_arr[cnt] = buffers->min_count; + size_kb_arr[cnt] = (size_arr[cnt] * count_arr[cnt]) / 1024; + total_size += size_arr[cnt] * count_arr[cnt]; + } + + /* print internal memory stats */ + i_vpr_hs(inst, + "%s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) %s %u kb(%ux%d) total %llu kb\n", + buf_name(buf_type_arr[0]), size_kb_arr[0], size_arr[0], count_arr[0], + buf_name(buf_type_arr[1]), size_kb_arr[1], size_arr[1], count_arr[1], + buf_name(buf_type_arr[2]), size_kb_arr[2], size_arr[2], count_arr[2], + buf_name(buf_type_arr[3]), size_kb_arr[3], size_arr[3], count_arr[3], + buf_name(buf_type_arr[4]), size_kb_arr[4], size_arr[4], count_arr[4], + buf_name(buf_type_arr[5]), size_kb_arr[5], size_arr[5], count_arr[5], + buf_name(buf_type_arr[6]), size_kb_arr[6], size_arr[6], count_arr[6], + buf_name(buf_type_arr[7]), size_kb_arr[7], size_arr[7], count_arr[7], + buf_name(buf_type_arr[8]), size_kb_arr[8], size_arr[8], count_arr[8], + (total_size / 1024)); +} + +int schedule_stats_work(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (!is_stats_enabled()) { + i_vpr_h(inst, "%s: stats not enabled. Skip scheduling\n", __func__); + return 0; + } + + /** + * Hfi session is already closed and inst also going to be + * closed soon. So skip scheduling new stats_work to avoid + * use-after-free issues with close sequence. + */ + if (!inst->packet) { + i_vpr_e(inst, "skip scheduling stats_work\n"); + return 0; + } + core = inst->core; + mod_delayed_work(inst->workq, &inst->stats_work, + msecs_to_jiffies(core->capabilities[STATS_TIMEOUT_MS].value)); + + return 0; +} + +int cancel_stats_work_sync(struct msm_vidc_inst *inst) +{ + cancel_delayed_work_sync(&inst->stats_work); + + return 0; +} + +void msm_vidc_stats_handler(struct work_struct *work) +{ + struct msm_vidc_inst *inst; + + inst = container_of(work, struct msm_vidc_inst, stats_work.work); + inst = get_inst_ref(g_core, inst); + if (!inst || !inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + inst_lock(inst, __func__); + msm_vidc_print_stats(inst); + schedule_stats_work(inst); + inst_unlock(inst, __func__); + + put_inst(inst); +} + +static int msm_vidc_queue_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf) +{ + struct msm_vidc_buffer *meta; + enum msm_vidc_debugfs_event etype; + int rc = 0; + u32 cr = 0; + + if (is_encode_session(inst) && is_input_buffer(buf->type)) { + cr = inst->capabilities[ENC_IP_CR].value; + msm_vidc_update_input_cr(inst, buf->index, cr); + msm_vidc_update_cap_value(inst, ENC_IP_CR, 0, __func__); + } + + if (is_decode_session(inst) && is_input_buffer(buf->type) && + inst->capabilities[CODEC_CONFIG].value) { + buf->flags |= MSM_VIDC_BUF_FLAG_CODECCONFIG; + msm_vidc_update_cap_value(inst, CODEC_CONFIG, 0, __func__); + } + + if (is_decode_session(inst) && is_output_buffer(buf->type)) { + rc = msm_vidc_process_readonly_buffers(inst, buf); + if (rc) + return rc; + } + + print_vidc_buffer(VIDC_HIGH, "high", "qbuf", inst, buf); + meta = get_meta_buffer(inst, buf); + if (meta && meta->attr & MSM_VIDC_ATTR_DEFERRED) + print_vidc_buffer(VIDC_LOW, "low ", "qbuf", inst, meta); + else + meta = NULL; + + if (!meta && is_meta_enabled(inst, buf->type)) { + print_vidc_buffer(VIDC_ERR, "err ", "missing meta for", inst, buf); + return -EINVAL; + } + + if (msm_vidc_is_super_buffer(inst) && is_input_buffer(buf->type)) + rc = venus_hfi_queue_super_buffer(inst, buf, meta); + else + rc = venus_hfi_queue_buffer(inst, buf, meta); + if (rc) + return rc; + + buf->attr &= ~MSM_VIDC_ATTR_DEFERRED; + buf->attr |= MSM_VIDC_ATTR_QUEUED; + if (meta) { + meta->attr &= ~MSM_VIDC_ATTR_DEFERRED; + meta->attr |= MSM_VIDC_ATTR_QUEUED; + } + + /* insert timestamp for ts_reorder enable case */ + if (is_ts_reorder_allowed(inst) && is_input_buffer(buf->type)) { + rc = msm_vidc_ts_reorder_insert_timestamp(inst, buf->timestamp); + if (rc) + i_vpr_e(inst, "%s: insert timestamp failed\n", __func__); + } + + if (is_input_buffer(buf->type)) + inst->power.buffer_counter++; + + if (is_input_buffer(buf->type)) + etype = MSM_VIDC_DEBUGFS_EVENT_ETB; + else + etype = MSM_VIDC_DEBUGFS_EVENT_FTB; + + msm_vidc_update_stats(inst, buf, etype); + + return 0; +} + +int msm_vidc_alloc_and_queue_input_internal_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = msm_vdec_get_input_internal_buffers(inst); + if (rc) + return rc; + + rc = msm_vdec_release_input_internal_buffers(inst); + if (rc) + return rc; + + rc = msm_vdec_create_input_internal_buffers(inst); + if (rc) + return rc; + + rc = msm_vdec_queue_input_internal_buffers(inst); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_queue_deferred_buffers(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type buf_type) +{ + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf; + int rc = 0; + + buffers = msm_vidc_get_buffers(inst, buf_type, __func__); + if (!buffers) + return -EINVAL; + + msm_vidc_scale_power(inst, true); + + list_for_each_entry(buf, &buffers->list, list) { + if (!(buf->attr & MSM_VIDC_ATTR_DEFERRED)) + continue; + rc = msm_vidc_queue_buffer(inst, buf); + if (rc) + return rc; + } + + return 0; +} + +int msm_vidc_buf_queue(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buf) +{ + int rc = 0; + + msm_vidc_scale_power(inst, is_input_buffer(buf->type)); + + rc = msm_vidc_queue_buffer(inst, buf); + if (rc) + return rc; + + return rc; +} + +int msm_vidc_queue_buffer_single(struct msm_vidc_inst *inst, struct vb2_buffer *vb2) +{ + int rc = 0; + struct msm_vidc_buffer *buf = NULL; + struct msm_vidc_fence *fence = NULL; + struct msm_vidc_core *core = NULL; + + core = inst->core; + + buf = msm_vidc_get_driver_buf(inst, vb2); + if (!buf) + return -EINVAL; + + if (is_meta_rx_inp_enabled(inst, META_OUTBUF_FENCE) && + is_output_buffer(buf->type)) { + fence = call_fence_op(core, fence_create, inst); + if (!fence) + return -EINVAL; + buf->fence_id = fence->fence_id; + } + + rc = inst->event_handle(inst, MSM_VIDC_BUF_QUEUE, buf); + if (rc) + goto exit; + +exit: + if (rc) { + i_vpr_e(inst, "%s: qbuf failed\n", __func__); + if (fence) + call_fence_op(core, fence_destroy, inst, fence->fence_id); + } + return rc; +} + +int msm_vidc_destroy_internal_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer) +{ + struct msm_vidc_buffers *buffers; + struct msm_vidc_mem_list *mem_list; + struct msm_vidc_mem *mem, *mem_dummy; + struct msm_vidc_buffer *buf, *dummy; + struct msm_vidc_core *core; + + core = inst->core; + + if (!is_internal_buffer(buffer->type)) { + i_vpr_e(inst, "%s: type: %s is not internal\n", + __func__, buf_name(buffer->type)); + return 0; + } + + i_vpr_h(inst, "%s: destroy: type: %8s, size: %9u, device_addr %#llx\n", __func__, + buf_name(buffer->type), buffer->buffer_size, buffer->device_addr); + + buffers = msm_vidc_get_buffers(inst, buffer->type, __func__); + if (!buffers) + return -EINVAL; + mem_list = msm_vidc_get_mem_info(inst, buffer->type, __func__); + if (!mem_list) + return -EINVAL; + + list_for_each_entry_safe(mem, mem_dummy, &mem_list->list, list) { + if (mem->dmabuf == buffer->dmabuf) { + call_mem_op(core, memory_unmap_free, core, mem); + list_del(&mem->list); + msm_vidc_pool_free(inst, mem); + break; + } + } + + list_for_each_entry_safe(buf, dummy, &buffers->list, list) { + if (buf->dmabuf == buffer->dmabuf) { + list_del(&buf->list); + msm_vidc_pool_free(inst, buf); + break; + } + } + + return 0; +} + +int msm_vidc_get_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + u32 buf_size; + u32 buf_count; + struct msm_vidc_core *core; + struct msm_vidc_buffers *buffers; + + core = inst->core; + + buf_size = call_session_op(core, buffer_size, + inst, buffer_type); + + buf_count = call_session_op(core, min_count, + inst, buffer_type); + + buffers = msm_vidc_get_buffers(inst, buffer_type, __func__); + if (!buffers) + return -EINVAL; + + /* + * In a usecase when film grain is initially present, dpb buffers + * are allocated and in the middle of the session, if film grain + * is disabled, then dpb internal buffers should be destroyed. + * When film grain is disabled, buffer_size op call returns 0. + * To ensure buffers->reuse is set to false, add check to detect + * if buf_size has become zero. Do the same for buf_count as well. + */ + if (is_split_mode_enabled(inst) && is_sub_state(inst, MSM_VIDC_FIRST_IPSC)) { + buffers->reuse = false; + buffers->size = buf_size; + buffers->min_count = buf_count; + } else if (buf_size && buf_size <= buffers->size && + buf_count && buf_count <= buffers->min_count) { + buffers->reuse = true; + } else { + buffers->reuse = false; + buffers->size = buf_size; + buffers->min_count = buf_count; + } + return 0; +} + +int msm_vidc_create_internal_buffer(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type, u32 index) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + struct msm_vidc_mem_list *mem_list; + struct msm_vidc_buffer *buffer; + struct msm_vidc_mem *mem; + struct msm_vidc_core *core; + + core = inst->core; + + if (!is_internal_buffer(buffer_type)) { + i_vpr_e(inst, "%s: type %s is not internal\n", + __func__, buf_name(buffer_type)); + return 0; + } + + buffers = msm_vidc_get_buffers(inst, buffer_type, __func__); + if (!buffers) + return -EINVAL; + mem_list = msm_vidc_get_mem_info(inst, buffer_type, __func__); + if (!mem_list) + return -EINVAL; + + if (!buffers->size) + return 0; + + buffer = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_BUFFER); + if (!buffer) { + i_vpr_e(inst, "%s: buf alloc failed\n", __func__); + return -ENOMEM; + } + INIT_LIST_HEAD(&buffer->list); + buffer->type = buffer_type; + buffer->index = index; + buffer->buffer_size = buffers->size; + list_add_tail(&buffer->list, &buffers->list); + + mem = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_ALLOC_MAP); + if (!mem) { + i_vpr_e(inst, "%s: mem poo alloc failed\n", __func__); + return -ENOMEM; + } + INIT_LIST_HEAD(&mem->list); + mem->type = buffer_type; + mem->region = call_mem_op(core, buffer_region, inst, buffer_type); + mem->size = buffer->buffer_size; + mem->secure = is_secure_region(mem->region); + rc = call_mem_op(core, memory_alloc_map, core, mem); + if (rc) + return -ENOMEM; + list_add_tail(&mem->list, &mem_list->list); + + buffer->dmabuf = mem->dmabuf; + buffer->device_addr = mem->device_addr; + buffer->region = mem->region; + i_vpr_h(inst, "%s: create: type: %8s, size: %9u, device_addr %#llx\n", __func__, + buf_name(buffer_type), buffers->size, buffer->device_addr); + + return 0; +} + +int msm_vidc_create_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + int i; + + buffers = msm_vidc_get_buffers(inst, buffer_type, __func__); + if (!buffers) + return -EINVAL; + + if (buffers->reuse) { + i_vpr_l(inst, "%s: reuse enabled for %s\n", __func__, buf_name(buffer_type)); + return 0; + } + + for (i = 0; i < buffers->min_count; i++) { + rc = msm_vidc_create_internal_buffer(inst, buffer_type, i); + if (rc) + return rc; + } + + return rc; +} + +int msm_vidc_queue_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buffer, *dummy; + + if (!is_internal_buffer(buffer_type)) { + i_vpr_e(inst, "%s: %s is not internal\n", __func__, buf_name(buffer_type)); + return 0; + } + + /* + * Set HFI_PROP_COMV_BUFFER_COUNT to firmware even if COMV buffer + * is reused. + */ + if (is_decode_session(inst) && buffer_type == MSM_VIDC_BUF_COMV) { + rc = msm_vdec_set_num_comv(inst); + if (rc) + return rc; + } + + buffers = msm_vidc_get_buffers(inst, buffer_type, __func__); + if (!buffers) + return -EINVAL; + + list_for_each_entry_safe(buffer, dummy, &buffers->list, list) { + /* do not queue pending release buffers */ + if (buffer->attr & MSM_VIDC_ATTR_PENDING_RELEASE) + continue; + /* do not queue already queued buffers */ + if (buffer->attr & MSM_VIDC_ATTR_QUEUED) + continue; + rc = venus_hfi_queue_buffer(inst, buffer, NULL); + if (rc) + return rc; + /* mark queued */ + buffer->attr |= MSM_VIDC_ATTR_QUEUED; + + i_vpr_h(inst, "%s: queue: type: %8s, size: %9u, device_addr %#llx\n", __func__, + buf_name(buffer->type), buffer->buffer_size, buffer->device_addr); + } + + return 0; +} + +int msm_vidc_alloc_and_queue_session_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int rc = 0; + + if (buffer_type != MSM_VIDC_BUF_ARP && + buffer_type != MSM_VIDC_BUF_PERSIST) { + i_vpr_e(inst, "%s: invalid buffer type: %s\n", + __func__, buf_name(buffer_type)); + rc = -EINVAL; + goto exit; + } + + rc = msm_vidc_get_internal_buffers(inst, buffer_type); + if (rc) + goto exit; + + rc = msm_vidc_create_internal_buffers(inst, buffer_type); + if (rc) + goto exit; + + rc = msm_vidc_queue_internal_buffers(inst, buffer_type); + if (rc) + goto exit; + +exit: + return rc; +} + +int msm_vidc_release_internal_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buffer, *dummy; + if (!is_internal_buffer(buffer_type)) { + i_vpr_e(inst, "%s: %s is not internal\n", + __func__, buf_name(buffer_type)); + return 0; + } + + buffers = msm_vidc_get_buffers(inst, buffer_type, __func__); + if (!buffers) + return -EINVAL; + + if (buffers->reuse) { + i_vpr_l(inst, "%s: reuse enabled for %s buf\n", + __func__, buf_name(buffer_type)); + return 0; + } + + list_for_each_entry_safe(buffer, dummy, &buffers->list, list) { + /* do not release already pending release buffers */ + if (buffer->attr & MSM_VIDC_ATTR_PENDING_RELEASE) + continue; + /* release only queued buffers */ + if (!(buffer->attr & MSM_VIDC_ATTR_QUEUED)) + continue; + rc = venus_hfi_release_buffer(inst, buffer); + if (rc) + return rc; + /* mark pending release */ + buffer->attr |= MSM_VIDC_ATTR_PENDING_RELEASE; + + i_vpr_h(inst, "%s: release: type: %8s, size: %9u, device_addr %#llx\n", __func__, + buf_name(buffer->type), buffer->buffer_size, buffer->device_addr); + } + + return 0; +} + +int msm_vidc_vb2_buffer_done(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + int type, port, state; + struct vb2_queue *q; + struct vb2_buffer *vb2; + struct vb2_v4l2_buffer *vbuf; + bool found; + + type = v4l2_type_from_driver(buf->type, __func__); + if (!type) + return -EINVAL; + port = v4l2_type_to_driver_port(inst, type, __func__); + if (port < 0) + return -EINVAL; + + q = inst->bufq[port].vb2q; + if (!q->streaming) { + i_vpr_e(inst, "%s: port %d is not streaming\n", + __func__, port); + return -EINVAL; + } + + found = false; + list_for_each_entry(vb2, &q->queued_list, queued_entry) { + if (vb2->state != VB2_BUF_STATE_ACTIVE) + continue; + if (vb2->index == buf->index) { + found = true; + break; + } + } + if (!found) { + print_vidc_buffer(VIDC_ERR, "err ", "vb2 not found for", inst, buf); + return -EINVAL; + } + /** + * v4l2 clears buffer state related flags. For driver errors + * send state as error to avoid skipping V4L2_BUF_FLAG_ERROR + * flag at v4l2 side. + */ + if (buf->flags & MSM_VIDC_BUF_FLAG_ERROR) + state = VB2_BUF_STATE_ERROR; + else + state = VB2_BUF_STATE_DONE; + + vbuf = to_vb2_v4l2_buffer(vb2); + vbuf->flags = buf->flags; + vb2->timestamp = buf->timestamp; + vb2->planes[0].bytesused = buf->data_size + vb2->planes[0].data_offset; + vb2_buffer_done(vb2, state); + + return 0; +} + +int msm_vidc_v4l2_fh_init(struct msm_vidc_inst *inst) +{ + int rc = 0; + int index; + struct msm_vidc_core *core; + + core = inst->core; + + /* do not init, if already inited */ + if (inst->fh.vdev) { + i_vpr_e(inst, "%s: already inited\n", __func__); + return -EINVAL; + } + + if (is_decode_session(inst)) + index = 0; + else if (is_encode_session(inst)) + index = 1; + else + return -EINVAL; + + v4l2_fh_init(&inst->fh, &core->vdev[index].vdev); + inst->fh.ctrl_handler = &inst->ctrl_handler; + v4l2_fh_add(&inst->fh); + + return rc; +} + +int msm_vidc_v4l2_fh_deinit(struct msm_vidc_inst *inst) +{ + int rc = 0; + + /* do not deinit, if not already inited */ + if (!inst->fh.vdev) { + i_vpr_h(inst, "%s: already not inited\n", __func__); + return 0; + } + + v4l2_fh_del(&inst->fh); + inst->fh.ctrl_handler = NULL; + v4l2_fh_exit(&inst->fh); + + return rc; +} + +static int vb2q_init(struct msm_vidc_inst *inst, + struct vb2_queue *q, enum v4l2_buf_type type) +{ + int rc = 0; + struct msm_vidc_core *core; + + core = inst->core; + + q->type = type; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + q->ops = core->vb2_ops; + q->mem_ops = core->vb2_mem_ops; + q->drv_priv = inst; + q->copy_timestamp = 1; + rc = vb2_queue_init(q); + if (rc) + i_vpr_e(inst, "%s: vb2_queue_init failed for type %d\n", + __func__, type); + return rc; +} + +static int m2m_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + int rc = 0; + struct msm_vidc_inst *inst = priv; + struct msm_vidc_core *core; + + if (!inst || !inst->core || !src_vq || !dst_vq) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + + src_vq->supports_requests = core->capabilities[SUPPORTS_REQUESTS].value; + src_vq->lock = &inst->ctx_q_lock; + src_vq->dev = &core->pdev->dev; + rc = vb2q_init(inst, src_vq, INPUT_MPLANE); + if (rc) + goto fail_input_vb2q_init; + inst->bufq[INPUT_PORT].vb2q = src_vq; + + dst_vq->lock = src_vq->lock; + dst_vq->dev = &core->pdev->dev; + rc = vb2q_init(inst, dst_vq, OUTPUT_MPLANE); + if (rc) + goto fail_out_vb2q_init; + inst->bufq[OUTPUT_PORT].vb2q = dst_vq; + return rc; + +fail_out_vb2q_init: + vb2_queue_release(inst->bufq[INPUT_PORT].vb2q); +fail_input_vb2q_init: + return rc; +} + +int msm_vidc_vb2_queue_init(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + + core = inst->core; + + if (inst->m2m_dev) { + i_vpr_e(inst, "%s: vb2q already inited\n", __func__); + return -EINVAL; + } + + inst->m2m_dev = v4l2_m2m_init(core->v4l2_m2m_ops); + if (IS_ERR(inst->m2m_dev)) { + i_vpr_e(inst, "%s: failed to initialize v4l2 m2m device\n", __func__); + rc = PTR_ERR(inst->m2m_dev); + goto fail_m2m_init; + } + + /* v4l2_m2m_ctx_init will do input & output queues initialization */ + inst->m2m_ctx = v4l2_m2m_ctx_init(inst->m2m_dev, inst, m2m_queue_init); + if (!inst->m2m_ctx) { + rc = -EINVAL; + i_vpr_e(inst, "%s: v4l2_m2m_ctx_init failed\n", __func__); + goto fail_m2m_ctx_init; + } + inst->fh.m2m_ctx = inst->m2m_ctx; + + inst->bufq[INPUT_META_PORT].vb2q = vzalloc(sizeof(*inst->bufq[INPUT_META_PORT].vb2q)); + if (!inst->bufq[INPUT_META_PORT].vb2q) { + i_vpr_e(inst, "%s: allocation failed\n", __func__); + rc = -ENOMEM; + goto fail_in_meta_alloc; + } + + /* do input meta port queues initialization */ + rc = vb2q_init(inst, inst->bufq[INPUT_META_PORT].vb2q, INPUT_META_PLANE); + if (rc) + goto fail_in_meta_vb2q_init; + + inst->bufq[OUTPUT_META_PORT].vb2q = vzalloc(sizeof(*inst->bufq[OUTPUT_META_PORT].vb2q)); + if (!inst->bufq[OUTPUT_META_PORT].vb2q) { + i_vpr_e(inst, "%s: allocation failed\n", __func__); + rc = -ENOMEM; + goto fail_out_meta_alloc; + } + + /* do output meta port queues initialization */ + rc = vb2q_init(inst, inst->bufq[OUTPUT_META_PORT].vb2q, OUTPUT_META_PLANE); + if (rc) + goto fail_out_meta_vb2q_init; + + return 0; + +fail_out_meta_vb2q_init: + vfree(inst->bufq[OUTPUT_META_PORT].vb2q); + inst->bufq[OUTPUT_META_PORT].vb2q = NULL; +fail_out_meta_alloc: + vb2_queue_release(inst->bufq[INPUT_META_PORT].vb2q); +fail_in_meta_vb2q_init: + vfree(inst->bufq[INPUT_META_PORT].vb2q); + inst->bufq[INPUT_META_PORT].vb2q = NULL; +fail_in_meta_alloc: + v4l2_m2m_ctx_release(inst->m2m_ctx); + inst->m2m_ctx = NULL; + inst->fh.m2m_ctx = NULL; + inst->bufq[OUTPUT_PORT].vb2q = NULL; + inst->bufq[INPUT_PORT].vb2q = NULL; +fail_m2m_ctx_init: + v4l2_m2m_release(inst->m2m_dev); + inst->m2m_dev = NULL; +fail_m2m_init: + return rc; +} + +int msm_vidc_vb2_queue_deinit(struct msm_vidc_inst *inst) +{ + int rc = 0; + + if (!inst->m2m_dev) { + i_vpr_h(inst, "%s: vb2q already deinited\n", __func__); + return 0; + } + + /* + * vb2_queue_release() for input and output queues + * is called from v4l2_m2m_ctx_release() + */ + v4l2_m2m_ctx_release(inst->m2m_ctx); + inst->m2m_ctx = NULL; + inst->bufq[OUTPUT_PORT].vb2q = NULL; + inst->bufq[INPUT_PORT].vb2q = NULL; + v4l2_m2m_release(inst->m2m_dev); + inst->m2m_dev = NULL; + + vb2_queue_release(inst->bufq[OUTPUT_META_PORT].vb2q); + vfree(inst->bufq[OUTPUT_META_PORT].vb2q); + inst->bufq[OUTPUT_META_PORT].vb2q = NULL; + vb2_queue_release(inst->bufq[INPUT_META_PORT].vb2q); + vfree(inst->bufq[INPUT_META_PORT].vb2q); + inst->bufq[INPUT_META_PORT].vb2q = NULL; + + return rc; +} + +int msm_vidc_add_session(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_inst *i; + struct msm_vidc_core *core; + u32 count = 0; + + core = inst->core; + + core_lock(core, __func__); + if (core->state != MSM_VIDC_CORE_INIT) { + i_vpr_e(inst, "%s: invalid state %s\n", + __func__, core_state_name(core->state)); + rc = -EINVAL; + goto unlock; + } + list_for_each_entry(i, &core->instances, list) + count++; + + if (count < core->capabilities[MAX_SESSION_COUNT].value) { + list_add_tail(&inst->list, &core->instances); + } else { + i_vpr_e(inst, "%s: max limit %d already running %d sessions\n", + __func__, core->capabilities[MAX_SESSION_COUNT].value, count); + rc = -EAGAIN; + } +unlock: + core_unlock(core, __func__); + + return rc; +} + +int msm_vidc_remove_session(struct msm_vidc_inst *inst) +{ + struct msm_vidc_inst *i, *temp; + struct msm_vidc_core *core; + u32 count = 0; + + core = inst->core; + + core_lock(core, __func__); + list_for_each_entry_safe(i, temp, &core->instances, list) { + if (i->session_id == inst->session_id) { + list_move_tail(&i->list, &core->dangling_instances); + i_vpr_h(inst, "%s: removed session %#x\n", + __func__, i->session_id); + } + } + list_for_each_entry(i, &core->instances, list) + count++; + i_vpr_h(inst, "%s: remaining sessions %d\n", __func__, count); + core_unlock(core, __func__); + + return 0; +} + +int msm_vidc_remove_dangling_session(struct msm_vidc_inst *inst) +{ + struct msm_vidc_inst *i, *temp; + struct msm_vidc_core *core; + u32 count = 0, dcount = 0; + + core = inst->core; + + core_lock(core, __func__); + list_for_each_entry_safe(i, temp, &core->dangling_instances, list) { + if (i->session_id == inst->session_id) { + list_del_init(&i->list); + i_vpr_h(inst, "%s: removed dangling session %#x\n", + __func__, i->session_id); + break; + } + } + list_for_each_entry(i, &core->instances, list) + count++; + list_for_each_entry(i, &core->dangling_instances, list) + dcount++; + i_vpr_h(inst, "%s: remaining sessions. active %d, dangling %d\n", + __func__, count, dcount); + core_unlock(core, __func__); + + return 0; +} + +int msm_vidc_session_open(struct msm_vidc_inst *inst) +{ + int rc = 0; + + inst->packet_size = 4096; + inst->packet = vzalloc(inst->packet_size); + if (!inst->packet) { + i_vpr_e(inst, "%s: allocation failed\n", __func__); + return -ENOMEM; + } + + rc = venus_hfi_session_open(inst); + if (rc) + goto error; + + return 0; +error: + i_vpr_e(inst, "%s(): session open failed\n", __func__); + vfree(inst->packet); + inst->packet = NULL; + return rc; +} + +int msm_vidc_session_set_codec(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = venus_hfi_session_set_codec(inst); + if (rc) + return rc; + + return 0; +} + +int msm_vidc_session_set_secure_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + + rc = venus_hfi_session_set_secure_mode(inst); + if (rc) + return rc; + + return 0; +} + +int msm_vidc_session_set_default_header(struct msm_vidc_inst *inst) +{ + int rc = 0; + u32 default_header = false; + + default_header = inst->capabilities[DEFAULT_HEADER].value; + i_vpr_h(inst, "%s: default header: %d", __func__, default_header); + rc = venus_hfi_session_property(inst, + HFI_PROP_DEC_DEFAULT_HEADER, + HFI_HOST_FLAGS_NONE, + get_hfi_port(inst, INPUT_PORT), + HFI_PAYLOAD_U32, + &default_header, + sizeof(u32)); + if (rc) + i_vpr_e(inst, "%s: set property failed\n", __func__); + return rc; +} + +int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port) +{ + int rc = 0; + int count = 0; + struct msm_vidc_core *core; + enum signal_session_response signal_type; + enum msm_vidc_buffer_type buffer_type; + + if (port == INPUT_PORT) { + signal_type = SIGNAL_CMD_STOP_INPUT; + buffer_type = MSM_VIDC_BUF_INPUT; + } else if (port == OUTPUT_PORT) { + signal_type = SIGNAL_CMD_STOP_OUTPUT; + buffer_type = MSM_VIDC_BUF_OUTPUT; + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", __func__, port); + return -EINVAL; + } + + rc = venus_hfi_stop(inst, port); + if (rc) + goto error; + + core = inst->core; + i_vpr_h(inst, "%s: wait on port: %d for time: %d ms\n", + __func__, port, core->capabilities[HW_RESPONSE_TIMEOUT].value); + inst_unlock(inst, __func__); + rc = wait_for_completion_timeout( + &inst->completions[signal_type], + msecs_to_jiffies( + core->capabilities[HW_RESPONSE_TIMEOUT].value)); + if (!rc) { + i_vpr_e(inst, "%s: session stop timed out for port: %d\n", + __func__, port); + rc = -ETIMEDOUT; + msm_vidc_inst_timeout(inst); + } else { + rc = 0; + } + inst_lock(inst, __func__); + + if (rc) + goto error; + + if (port == INPUT_PORT) { + /* flush input timer list */ + msm_vidc_flush_input_timer(inst); + } + + /* no more queued buffers after streamoff */ + count = msm_vidc_num_buffers(inst, buffer_type, MSM_VIDC_ATTR_QUEUED); + if (!count) { + i_vpr_h(inst, "%s: stop successful on port: %d\n", + __func__, port); + } else { + i_vpr_e(inst, + "%s: %d buffers pending with firmware on port: %d\n", + __func__, count, port); + rc = -EINVAL; + goto error; + } + + rc = msm_vidc_state_change_streamoff(inst, port); + if (rc) + goto error; + + /* flush deferred buffers */ + msm_vidc_flush_buffers(inst, buffer_type); + msm_vidc_flush_read_only_buffers(inst, buffer_type); + return 0; + +error: + msm_vidc_kill_session(inst); + msm_vidc_flush_buffers(inst, buffer_type); + msm_vidc_flush_read_only_buffers(inst, buffer_type); + return rc; +} + +int msm_vidc_session_close(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + bool wait_for_response; + + core = inst->core; + + wait_for_response = true; + rc = venus_hfi_session_close(inst); + if (rc) { + i_vpr_e(inst, "%s: session close cmd failed\n", __func__); + wait_for_response = false; + } + + /* we are not supposed to send any more commands after close */ + i_vpr_h(inst, "%s: free session packet data\n", __func__); + vfree(inst->packet); + inst->packet = NULL; + + if (wait_for_response) { + i_vpr_h(inst, "%s: wait on close for time: %d ms\n", + __func__, core->capabilities[HW_RESPONSE_TIMEOUT].value); + inst_unlock(inst, __func__); + rc = wait_for_completion_timeout( + &inst->completions[SIGNAL_CMD_CLOSE], + msecs_to_jiffies( + core->capabilities[HW_RESPONSE_TIMEOUT].value)); + if (!rc) { + i_vpr_e(inst, "%s: session close timed out\n", __func__); + rc = -ETIMEDOUT; + msm_vidc_inst_timeout(inst); + } else { + rc = 0; + i_vpr_h(inst, "%s: close successful\n", __func__); + } + inst_lock(inst, __func__); + } + + return rc; +} + +int msm_vidc_kill_session(struct msm_vidc_inst *inst) +{ + if (!inst->session_id) { + i_vpr_e(inst, "%s: already killed\n", __func__); + return 0; + } + + i_vpr_e(inst, "%s: killing session\n", __func__); + msm_vidc_session_close(inst); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + + return 0; +} + +int msm_vidc_get_inst_capability(struct msm_vidc_inst *inst) +{ + int rc = 0; + int i; + u32 codecs_count = 0; + struct msm_vidc_core *core; + + core = inst->core; + + codecs_count = core->enc_codecs_count + core->dec_codecs_count; + + for (i = 0; i < codecs_count; i++) { + if (core->inst_caps[i].domain == inst->domain && + core->inst_caps[i].codec == inst->codec) { + i_vpr_h(inst, + "%s: copied capabilities with %#x codec, %#x domain\n", + __func__, inst->codec, inst->domain); + memcpy(&inst->capabilities[0], &core->inst_caps[i].cap[0], + (INST_CAP_MAX + 1) * sizeof(struct msm_vidc_inst_cap)); + } + } + + return rc; +} + +int msm_vidc_init_core_caps(struct msm_vidc_core *core) +{ + int rc = 0; + int i, num_platform_caps; + struct msm_platform_core_capability *platform_data; + + platform_data = core->platform->data.core_data; + if (!platform_data) { + d_vpr_e("%s: platform core data is NULL\n", + __func__); + rc = -EINVAL; + goto exit; + } + + num_platform_caps = core->platform->data.core_data_size; + + /* loop over platform caps */ + for (i = 0; i < num_platform_caps && i < CORE_CAP_MAX; i++) { + core->capabilities[platform_data[i].type].type = platform_data[i].type; + core->capabilities[platform_data[i].type].value = platform_data[i].value; + } + +exit: + return rc; +} + +static int update_inst_capability(struct msm_platform_inst_capability *in, + struct msm_vidc_inst_capability *capability) +{ + if (!in || !capability) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, in, capability); + return -EINVAL; + } + if (in->cap_id >= INST_CAP_MAX) { + d_vpr_e("%s: invalid cap id %d\n", __func__, in->cap_id); + return -EINVAL; + } + + capability->cap[in->cap_id].cap_id = in->cap_id; + capability->cap[in->cap_id].min = in->min; + capability->cap[in->cap_id].max = in->max; + capability->cap[in->cap_id].step_or_mask = in->step_or_mask; + capability->cap[in->cap_id].value = in->value; + capability->cap[in->cap_id].flags = in->flags; + capability->cap[in->cap_id].v4l2_id = in->v4l2_id; + capability->cap[in->cap_id].hfi_id = in->hfi_id; + + return 0; +} + +static int update_inst_cap_dependency( + struct msm_platform_inst_cap_dependency *in, + struct msm_vidc_inst_capability *capability) +{ + if (!in || !capability) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, in, capability); + return -EINVAL; + } + if (in->cap_id >= INST_CAP_MAX) { + d_vpr_e("%s: invalid cap id %d\n", __func__, in->cap_id); + return -EINVAL; + } + + if (capability->cap[in->cap_id].cap_id != in->cap_id) { + d_vpr_e("%s: invalid cap id %d\n", __func__, in->cap_id); + return -EINVAL; + } + + memcpy(capability->cap[in->cap_id].children, in->children, + sizeof(capability->cap[in->cap_id].children)); + capability->cap[in->cap_id].adjust = in->adjust; + capability->cap[in->cap_id].set = in->set; + + return 0; +} + +int msm_vidc_init_instance_caps(struct msm_vidc_core *core) +{ + int rc = 0; + u8 enc_valid_codecs, dec_valid_codecs; + u8 count_bits, codecs_count = 0; + u8 enc_codecs_count = 0, dec_codecs_count = 0; + int i, j, check_bit; + int num_platform_cap_data, num_platform_cap_dependency_data; + struct msm_platform_inst_capability *platform_cap_data = NULL; + struct msm_platform_inst_cap_dependency *platform_cap_dependency_data = NULL; + + platform_cap_data = core->platform->data.inst_cap_data; + if (!platform_cap_data) { + d_vpr_e("%s: platform instance cap data is NULL\n", + __func__); + rc = -EINVAL; + goto error; + } + + platform_cap_dependency_data = core->platform->data.inst_cap_dependency_data; + if (!platform_cap_dependency_data) { + d_vpr_e("%s: platform instance cap dependency data is NULL\n", + __func__); + rc = -EINVAL; + goto error; + } + + enc_valid_codecs = core->capabilities[ENC_CODECS].value; + count_bits = enc_valid_codecs; + COUNT_BITS(count_bits, enc_codecs_count); + core->enc_codecs_count = enc_codecs_count; + + dec_valid_codecs = core->capabilities[DEC_CODECS].value; + count_bits = dec_valid_codecs; + COUNT_BITS(count_bits, dec_codecs_count); + core->dec_codecs_count = dec_codecs_count; + + codecs_count = enc_codecs_count + dec_codecs_count; + core->inst_caps = devm_kzalloc(&core->pdev->dev, + codecs_count * sizeof(struct msm_vidc_inst_capability), GFP_KERNEL); + if (!core->inst_caps) { + d_vpr_e("%s: failed to alloc memory for instance caps\n", __func__); + rc = -ENOMEM; + goto error; + } + + check_bit = 0; + /* determine codecs for enc domain */ + for (i = 0; i < enc_codecs_count; i++) { + while (check_bit < (sizeof(enc_valid_codecs) * 8)) { + if (enc_valid_codecs & BIT(check_bit)) { + core->inst_caps[i].domain = MSM_VIDC_ENCODER; + core->inst_caps[i].codec = enc_valid_codecs & + BIT(check_bit); + check_bit++; + break; + } + check_bit++; + } + } + + /* reset checkbit to check from 0th bit of decoder codecs set bits*/ + check_bit = 0; + /* determine codecs for dec domain */ + for (; i < codecs_count; i++) { + while (check_bit < (sizeof(dec_valid_codecs) * 8)) { + if (dec_valid_codecs & BIT(check_bit)) { + core->inst_caps[i].domain = MSM_VIDC_DECODER; + core->inst_caps[i].codec = dec_valid_codecs & + BIT(check_bit); + check_bit++; + break; + } + check_bit++; + } + } + + num_platform_cap_data = core->platform->data.inst_cap_data_size; + num_platform_cap_dependency_data = core->platform->data.inst_cap_dependency_data_size; + d_vpr_h("%s: num caps %d, dependency %d\n", __func__, + num_platform_cap_data, num_platform_cap_dependency_data); + + /* loop over each platform capability */ + for (i = 0; i < num_platform_cap_data; i++) { + /* select matching core codec and update it */ + for (j = 0; j < codecs_count; j++) { + if ((platform_cap_data[i].domain & + core->inst_caps[j].domain) && + (platform_cap_data[i].codec & + core->inst_caps[j].codec)) { + /* update core capability */ + rc = update_inst_capability(&platform_cap_data[i], + &core->inst_caps[j]); + if (rc) + return rc; + } + } + } + + /* loop over each platform dependency capability */ + for (i = 0; i < num_platform_cap_dependency_data; i++) { + /* select matching core codec and update it */ + for (j = 0; j < codecs_count; j++) { + if ((platform_cap_dependency_data[i].domain & + core->inst_caps[j].domain) && + (platform_cap_dependency_data[i].codec & + core->inst_caps[j].codec)) { + /* update core dependency capability */ + rc = update_inst_cap_dependency( + &platform_cap_dependency_data[i], + &core->inst_caps[j]); + if (rc) + return rc; + } + } + } + +error: + return rc; +} + +int msm_vidc_core_deinit_locked(struct msm_vidc_core *core, bool force) +{ + int rc = 0; + struct msm_vidc_inst *inst, *dummy; + enum msm_vidc_allow allow; + + rc = __strict_check(core, __func__); + if (rc) { + d_vpr_e("%s(): core was not locked\n", __func__); + return rc; + } + + if (is_core_state(core, MSM_VIDC_CORE_DEINIT)) + return 0; + + /* print error for state change not allowed case */ + allow = msm_vidc_allow_core_state_change(core, MSM_VIDC_CORE_DEINIT); + if (allow != MSM_VIDC_ALLOW) + d_vpr_e("%s: %s core state change %s -> %s\n", __func__, + allow_name(allow), core_state_name(core->state), + core_state_name(MSM_VIDC_CORE_DEINIT)); + + if (force) { + d_vpr_e("%s(): force deinit core\n", __func__); + } else { + /* in normal case, deinit core only if no session present */ + if (!list_empty(&core->instances)) { + d_vpr_h("%s(): skip deinit\n", __func__); + return 0; + } else { + d_vpr_h("%s(): deinit core\n", __func__); + } + } + + venus_hfi_core_deinit(core, force); + + /* unlink all sessions from core, if any */ + list_for_each_entry_safe(inst, dummy, &core->instances, list) { + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + list_move_tail(&inst->list, &core->dangling_instances); + } + msm_vidc_change_core_state(core, MSM_VIDC_CORE_DEINIT, __func__); + + return rc; +} + +int msm_vidc_core_deinit(struct msm_vidc_core *core, bool force) +{ + int rc = 0; + + core_lock(core, __func__); + rc = msm_vidc_core_deinit_locked(core, force); + core_unlock(core, __func__); + + return rc; +} + +int msm_vidc_core_init_wait(struct msm_vidc_core *core) +{ + const int interval = 10; + int max_tries, count = 0, rc = 0; + + core_lock(core, __func__); + if (is_core_state(core, MSM_VIDC_CORE_INIT)) { + rc = 0; + goto unlock; + } else if (is_core_state(core, MSM_VIDC_CORE_DEINIT) || + is_core_state(core, MSM_VIDC_CORE_ERROR)) { + d_vpr_e("%s: invalid core state %s\n", + __func__, core_state_name(core->state)); + rc = -EINVAL; + goto unlock; + } + + d_vpr_h("%s(): waiting for state change\n", __func__); + max_tries = core->capabilities[HW_RESPONSE_TIMEOUT].value / interval; + while (count < max_tries) { + if (core->state != MSM_VIDC_CORE_INIT_WAIT) + break; + + core_unlock(core, __func__); + msleep_interruptible(interval); + core_lock(core, __func__); + count++; + } + d_vpr_h("%s: state %s, interval %u, count %u, max_tries %u\n", __func__, + core_state_name(core->state), interval, count, max_tries); + + if (is_core_state(core, MSM_VIDC_CORE_INIT)) { + d_vpr_h("%s: sys init successful\n", __func__); + rc = 0; + goto unlock; + } else if (is_core_state(core, MSM_VIDC_CORE_INIT_WAIT)) { + d_vpr_h("%s: sys init wait timedout. state %s\n", + __func__, core_state_name(core->state)); + msm_vidc_change_core_state(core, MSM_VIDC_CORE_ERROR, __func__); + /* mark video hw unresponsive */ + msm_vidc_change_core_sub_state(core, + 0, CORE_SUBSTATE_VIDEO_UNRESPONSIVE, __func__); + /* core deinit to handle error */ + msm_vidc_core_deinit_locked(core, true); + rc = -EINVAL; + goto unlock; + } else { + d_vpr_e("%s: invalid core state %s\n", + __func__, core_state_name(core->state)); + rc = -EINVAL; + goto unlock; + } +unlock: + core_unlock(core, __func__); + return rc; +} + +int msm_vidc_core_init(struct msm_vidc_core *core) +{ + enum msm_vidc_allow allow; + int rc = 0; + + core_lock(core, __func__); + if (core_in_valid_state(core)) { + goto unlock; + } else if (is_core_state(core, MSM_VIDC_CORE_ERROR)) { + d_vpr_e("%s: invalid core state %s\n", + __func__, core_state_name(core->state)); + rc = -EINVAL; + goto unlock; + } + + /* print error for state change not allowed case */ + allow = msm_vidc_allow_core_state_change(core, MSM_VIDC_CORE_INIT_WAIT); + if (allow != MSM_VIDC_ALLOW) + d_vpr_e("%s: %s core state change %s -> %s\n", __func__, + allow_name(allow), core_state_name(core->state), + core_state_name(MSM_VIDC_CORE_INIT_WAIT)); + + msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT_WAIT, __func__); + /* clear PM suspend from core sub_state */ + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND, 0, __func__); + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PAGE_FAULT, 0, __func__); + + rc = venus_hfi_core_init(core); + if (rc) { + msm_vidc_change_core_state(core, MSM_VIDC_CORE_ERROR, __func__); + d_vpr_e("%s: core init failed\n", __func__); + /* do core deinit to handle error */ + msm_vidc_core_deinit_locked(core, true); + goto unlock; + } + +unlock: + core_unlock(core, __func__); + return rc; +} + +int msm_vidc_print_residency_stats(struct msm_vidc_core *core) +{ + int rc = 0; + + core_lock(core, __func__); + rc = call_res_op(core, clk_print_residency_stats, core); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int msm_vidc_reset_residency_stats(struct msm_vidc_core *core) +{ + int rc = 0; + + core_lock(core, __func__); + rc = call_res_op(core, clk_reset_residency_stats, core); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int msm_vidc_inst_timeout(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + struct msm_vidc_inst *instance; + bool found; + + core = inst->core; + + core_lock(core, __func__); + /* + * All sessions will be removed from core list in core deinit, + * do not deinit core from a session which is not present in + * core list. + */ + found = false; + list_for_each_entry(instance, &core->instances, list) { + if (instance == inst) { + found = true; + break; + } + } + if (!found) { + i_vpr_e(inst, + "%s: session not available in core list\n", __func__); + rc = -EINVAL; + goto unlock; + } + /* mark video hw unresponsive */ + msm_vidc_change_core_state(core, MSM_VIDC_CORE_ERROR, __func__); + msm_vidc_change_core_sub_state(core, + 0, CORE_SUBSTATE_VIDEO_UNRESPONSIVE, __func__); + + /* call core deinit for a valid instance timeout case */ + msm_vidc_core_deinit_locked(core, true); + +unlock: + core_unlock(core, __func__); + + return rc; +} + +int msm_vidc_print_buffer_info(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buffers *buffers; + int i; + + /* Print buffer details */ + for (i = 1; i < ARRAY_SIZE(buf_type_name_arr); i++) { + buffers = msm_vidc_get_buffers(inst, i, __func__); + if (!buffers) + continue; + + i_vpr_h(inst, + "buf: type: %15s, min %2d, extra %2d, actual %2d, size %9u, reuse %d\n", + buf_name(i), buffers->min_count, + buffers->extra_count, buffers->actual_count, + buffers->size, buffers->reuse); + } + + return 0; +} + +int msm_vidc_print_inst_info(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf; + enum msm_vidc_port_type port; + bool is_secure, is_decode; + u32 bit_depth, bit_rate, frame_rate, width, height; + struct dma_buf *dbuf; + struct inode *f_inode; + unsigned long inode_num = 0; + long ref_count = -1; + int i = 0; + + is_secure = is_secure_session(inst); + is_decode = is_decode_session(inst); + port = is_decode ? INPUT_PORT : OUTPUT_PORT; + width = inst->fmts[port].fmt.pix_mp.width; + height = inst->fmts[port].fmt.pix_mp.height; + bit_depth = inst->capabilities[BIT_DEPTH].value & 0xFFFF; + bit_rate = inst->capabilities[BIT_RATE].value; + frame_rate = inst->capabilities[FRAME_RATE].value >> 16; + + i_vpr_e(inst, "%s %s session, HxW: %d x %d, fps: %d, bitrate: %d, bit-depth: %d\n", + is_secure ? "Secure" : "Non-Secure", + is_decode ? "Decode" : "Encode", + height, width, + frame_rate, bit_rate, bit_depth); + + /* Print buffer details */ + for (i = 1; i < ARRAY_SIZE(buf_type_name_arr); i++) { + buffers = msm_vidc_get_buffers(inst, i, __func__); + if (!buffers) + continue; + + i_vpr_e(inst, "count: type: %11s, min: %2d, extra: %2d, actual: %2d\n", + buf_name(i), buffers->min_count, + buffers->extra_count, buffers->actual_count); + + list_for_each_entry(buf, &buffers->list, list) { + if (!buf->dmabuf) + continue; + dbuf = (struct dma_buf *)buf->dmabuf; + if (dbuf && dbuf->file) { + f_inode = file_inode(dbuf->file); + if (f_inode) { + inode_num = f_inode->i_ino; + ref_count = file_count(dbuf->file); + } + } + i_vpr_e(inst, + "buf: type: %11s, index: %2d, fd: %4d, size: %9u, off: %8u, filled: %9u, daddr: %#llx, inode: %8lu, ref: %2ld, flags: %8x, ts: %16lld, attr: %8x\n", + buf_name(i), buf->index, buf->fd, buf->buffer_size, + buf->data_offset, buf->data_size, buf->device_addr, + inode_num, ref_count, buf->flags, buf->timestamp, buf->attr); + } + } + + return 0; +} + +void msm_vidc_print_core_info(struct msm_vidc_core *core) +{ + struct msm_vidc_inst *inst = NULL; + struct msm_vidc_inst *instances[MAX_SUPPORTED_INSTANCES]; + s32 num_instances = 0; + + core_lock(core, __func__); + list_for_each_entry(inst, &core->instances, list) + instances[num_instances++] = inst; + core_unlock(core, __func__); + + while (num_instances--) { + inst = instances[num_instances]; + inst = get_inst_ref(core, inst); + if (!inst) + continue; + inst_lock(inst, __func__); + msm_vidc_print_inst_info(inst); + inst_unlock(inst, __func__); + put_inst(inst); + } +} + +int msm_vidc_smmu_fault_handler(struct iommu_domain *domain, + struct device *dev, unsigned long iova, int flags, void *data) +{ + struct msm_vidc_core *core = data; + + if (is_core_sub_state(core, CORE_SUBSTATE_PAGE_FAULT)) { + if (core->capabilities[NON_FATAL_FAULTS].value) { + dprintk_ratelimit(VIDC_ERR, "err ", + "%s: non-fatal pagefault address: %lx\n", + __func__, iova); + return 0; + } + } + + d_vpr_e(FMT_STRING_FAULT_HANDLER, __func__, iova); + + /* mark smmu fault as handled */ + core_lock(core, __func__); + msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PAGE_FAULT, __func__); + core_unlock(core, __func__); + + msm_vidc_print_core_info(core); + /* + * Return -ENOSYS to elicit the default behaviour of smmu driver. + * If we return -ENOSYS, then smmu driver assumes page fault handler + * is not installed and prints a list of useful debug information like + * FAR, SID etc. This information is not printed if we return 0. + */ + return -ENOSYS; +} + +bool is_ssr_type_allowed(struct msm_vidc_core *core, u32 type) +{ + u32 i; + const u32 *ssr_type = core->platform->data.msm_vidc_ssr_type; + u32 ssr_type_size = core->platform->data.msm_vidc_ssr_type_size; + + for (i = 0; i < ssr_type_size; i++) { + if (type == ssr_type[i]) + return true; + } + return false; +} + +int msm_vidc_trigger_ssr(struct msm_vidc_core *core, + u64 trigger_ssr_val) +{ + struct msm_vidc_ssr *ssr; + + ssr = &core->ssr; + /* + * + * ssr_type: 0-3 bits + * sub_client_id: 4-7 bits + * reserved: 8-31 bits + * test_addr: 32-63 bits + */ + d_vpr_e("%s: trigger ssr is called. trigger ssr val: %#llx\n", + __func__, trigger_ssr_val); + + ssr->ssr_type = (trigger_ssr_val & + (unsigned long)SSR_TYPE) >> SSR_TYPE_SHIFT; + + if (!is_ssr_type_allowed(core, ssr->ssr_type)) { + d_vpr_h("SSR Type %#llx is not allowed\n", ssr->ssr_type); + return 0; + } + + ssr->sub_client_id = (trigger_ssr_val & + (unsigned long)SSR_SUB_CLIENT_ID) >> SSR_SUB_CLIENT_ID_SHIFT; + ssr->test_addr = (trigger_ssr_val & + (unsigned long)SSR_ADDR_ID) >> SSR_ADDR_SHIFT; + schedule_work(&core->ssr_work); + return 0; +} + +void msm_vidc_ssr_handler(struct work_struct *work) +{ + int rc; + struct msm_vidc_core *core; + struct msm_vidc_ssr *ssr; + + core = container_of(work, struct msm_vidc_core, ssr_work); + if (!core) { + d_vpr_e("%s: invalid params %pK\n", __func__, core); + return; + } + ssr = &core->ssr; + + d_vpr_e("%s: ssr handler is called, core state: %s\n", + __func__, core_state_name(core->state)); + core_lock(core, __func__); + if (is_core_state(core, MSM_VIDC_CORE_INIT)) { + /* + * In current implementation, user-initiated SSR triggers + * a fatal error from hardware. However, there is no way + * to know if fatal error is due to SSR or not. Handle + * user SSR as non-fatal. + */ + rc = venus_hfi_trigger_ssr(core, ssr->ssr_type, + ssr->sub_client_id, ssr->test_addr); + if (rc) + d_vpr_e("%s: trigger_ssr failed\n", __func__); + } else { + d_vpr_e("%s: video core not initialized\n", __func__); + } + core_unlock(core, __func__); +} + +int msm_vidc_trigger_stability(struct msm_vidc_core *core, + u64 trigger_stability_val) +{ + struct msm_vidc_inst *inst = NULL; + struct msm_vidc_stability stability; + + /* + * + * stability_type: 0-3 bits + * sub_client_id: 4-7 bits + * reserved: 8-31 bits + * payload: 32-63 bits + */ + memset(&stability, 0, sizeof(struct msm_vidc_stability)); + stability.stability_type = (trigger_stability_val & + (unsigned long)STABILITY_TYPE) >> STABILITY_TYPE_SHIFT; + stability.sub_client_id = (trigger_stability_val & + (unsigned long)STABILITY_SUB_CLIENT_ID) >> STABILITY_SUB_CLIENT_ID_SHIFT; + stability.value = (trigger_stability_val & + (unsigned long)STABILITY_PAYLOAD_ID) >> STABILITY_PAYLOAD_SHIFT; + + core_lock(core, __func__); + list_for_each_entry(inst, &core->instances, list) { + memcpy(&inst->stability, &stability, sizeof(struct msm_vidc_stability)); + schedule_work(&inst->stability_work); + } + core_unlock(core, __func__); + + return 0; +} + +void msm_vidc_stability_handler(struct work_struct *work) +{ + int rc; + struct msm_vidc_inst *inst; + struct msm_vidc_stability *stability; + + inst = container_of(work, struct msm_vidc_inst, stability_work); + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + inst_lock(inst, __func__); + stability = &inst->stability; + rc = venus_hfi_trigger_stability(inst, stability->stability_type, + stability->sub_client_id, stability->value); + if (rc) + i_vpr_e(inst, "%s: trigger_stability failed\n", __func__); + inst_unlock(inst, __func__); + + put_inst(inst); +} + +int cancel_stability_work_sync(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + cancel_work_sync(&inst->stability_work); + + return 0; +} + +void msm_vidc_fw_unload_handler(struct work_struct *work) +{ + struct msm_vidc_core *core = NULL; + int rc = 0; + + core = container_of(work, struct msm_vidc_core, fw_unload_work.work); + if (!core) { + d_vpr_e("%s: invalid work or core handle\n", __func__); + return; + } + + d_vpr_h("%s: deinitializing video core\n", __func__); + rc = msm_vidc_core_deinit(core, false); + if (rc) + d_vpr_e("%s: Failed to deinit core\n", __func__); + +} + +void msm_vidc_batch_handler(struct work_struct *work) +{ + struct msm_vidc_inst *inst; + struct msm_vidc_core *core; + int rc = 0; + + inst = container_of(work, struct msm_vidc_inst, decode_batch.work.work); + inst = get_inst_ref(g_core, inst); + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + core = inst->core; + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: failled. Session error\n", __func__); + goto exit; + } + + if (is_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND)) { + i_vpr_h(inst, "%s: device in pm suspend state\n", __func__); + goto exit; + } + + if (is_state(inst, MSM_VIDC_OPEN) || + is_state(inst, MSM_VIDC_INPUT_STREAMING)) { + i_vpr_e(inst, "%s: not allowed in state: %s\n", __func__, + state_name(inst->state)); + goto exit; + } + + i_vpr_h(inst, "%s: queue pending batch buffers\n", __func__); + rc = msm_vidc_queue_deferred_buffers(inst, MSM_VIDC_BUF_OUTPUT); + if (rc) { + i_vpr_e(inst, "%s: batch qbufs failed\n", __func__); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + +exit: + inst_unlock(inst, __func__); + put_inst(inst); +} + +int msm_vidc_flush_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type type) +{ + int rc = 0; + struct msm_vidc_core *core; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf, *dummy; + enum msm_vidc_buffer_type buffer_type[2]; + int i; + + core = inst->core; + + if (is_input_buffer(type)) { + buffer_type[0] = MSM_VIDC_BUF_INPUT_META; + buffer_type[1] = MSM_VIDC_BUF_INPUT; + } else if (is_output_buffer(type)) { + buffer_type[0] = MSM_VIDC_BUF_OUTPUT_META; + buffer_type[1] = MSM_VIDC_BUF_OUTPUT; + } else { + i_vpr_h(inst, "%s: invalid buffer type %d\n", + __func__, type); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(buffer_type); i++) { + buffers = msm_vidc_get_buffers(inst, buffer_type[i], __func__); + if (!buffers) + return -EINVAL; + + list_for_each_entry_safe(buf, dummy, &buffers->list, list) { + if (buf->attr & MSM_VIDC_ATTR_QUEUED || + buf->attr & MSM_VIDC_ATTR_DEFERRED) { + print_vidc_buffer(VIDC_HIGH, "high", "flushing buffer", inst, buf); + if (!(buf->attr & MSM_VIDC_ATTR_BUFFER_DONE)) { + if (is_decode_session(inst) && + is_output_buffer(buf->type)) { + if (buf->dbuf_get) { + call_mem_op(core, dma_buf_put, + inst, buf->dmabuf); + buf->dbuf_get = 0; + } + } + buf->data_size = 0; + msm_vidc_vb2_buffer_done(inst, buf); + } + } + } + } + + return rc; +} + +int msm_vidc_flush_read_only_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type type) +{ + int rc = 0; + struct msm_vidc_buffer *ro_buf, *dummy; + struct msm_vidc_core *core; + + core = inst->core; + + if (!is_decode_session(inst) || !is_output_buffer(type)) + return 0; + + list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) { + if (ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY) + continue; + print_vidc_buffer(VIDC_ERR, "high", "flush ro buf", inst, ro_buf); + if (ro_buf->attach && ro_buf->sg_table) + call_mem_op(core, dma_buf_unmap_attachment, core, + ro_buf->attach, ro_buf->sg_table); + if (ro_buf->attach && ro_buf->dmabuf) + call_mem_op(core, dma_buf_detach, core, + ro_buf->dmabuf, ro_buf->attach); + if (ro_buf->dbuf_get) + call_mem_op(core, dma_buf_put, inst, ro_buf->dmabuf); + ro_buf->attach = NULL; + ro_buf->sg_table = NULL; + ro_buf->dmabuf = NULL; + ro_buf->dbuf_get = 0; + ro_buf->device_addr = 0x0; + list_del_init(&ro_buf->list); + msm_vidc_pool_free(inst, ro_buf); + } + + return rc; +} + +void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst) +{ + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf, *dummy; + struct msm_vidc_timestamp *ts, *dummy_ts; + struct msm_memory_dmabuf *dbuf, *dummy_dbuf; + struct msm_vidc_input_timer *timer, *dummy_timer; + struct msm_vidc_buffer_stats *stats, *dummy_stats; + struct msm_vidc_inst_cap_entry *entry, *dummy_entry; + struct msm_vidc_input_cr_data *cr, *dummy_cr; + struct msm_vidc_fence *fence, *dummy_fence; + struct msm_vidc_core *core; + + static const enum msm_vidc_buffer_type ext_buf_types[] = { + MSM_VIDC_BUF_INPUT, + MSM_VIDC_BUF_OUTPUT, + MSM_VIDC_BUF_INPUT_META, + MSM_VIDC_BUF_OUTPUT_META, + }; + static const enum msm_vidc_buffer_type internal_buf_types[] = { + MSM_VIDC_BUF_BIN, + MSM_VIDC_BUF_ARP, + MSM_VIDC_BUF_COMV, + MSM_VIDC_BUF_NON_COMV, + MSM_VIDC_BUF_LINE, + MSM_VIDC_BUF_DPB, + MSM_VIDC_BUF_PERSIST, + MSM_VIDC_BUF_VPSS, + MSM_VIDC_BUF_PARTIAL_DATA, + }; + int i; + + core = inst->core; + + for (i = 0; i < ARRAY_SIZE(internal_buf_types); i++) { + buffers = msm_vidc_get_buffers(inst, internal_buf_types[i], __func__); + if (!buffers) + continue; + list_for_each_entry_safe(buf, dummy, &buffers->list, list) { + i_vpr_h(inst, + "destroying internal buffer: type %d idx %d fd %d addr %#llx size %d\n", + buf->type, buf->index, buf->fd, buf->device_addr, buf->buffer_size); + msm_vidc_destroy_internal_buffer(inst, buf); + } + } + + /* + * read_only list does not take dma ref_count using dma_buf_get(). + * dma_buf ptr will be obselete when its ref_count reaches zero. + * Hence printthe dma_buf info before releasing the ref count. + */ + list_for_each_entry_safe(buf, dummy, &inst->buffers.read_only.list, list) { + print_vidc_buffer(VIDC_ERR, "err ", "destroying ro buf", inst, buf); + if (buf->attach && buf->sg_table) + call_mem_op(core, dma_buf_unmap_attachment, core, + buf->attach, buf->sg_table); + if (buf->attach && buf->dmabuf) + call_mem_op(core, dma_buf_detach, core, buf->dmabuf, buf->attach); + if (buf->dbuf_get) + call_mem_op(core, dma_buf_put, inst, buf->dmabuf); + list_del_init(&buf->list); + msm_vidc_pool_free(inst, buf); + } + + for (i = 0; i < ARRAY_SIZE(ext_buf_types); i++) { + buffers = msm_vidc_get_buffers(inst, ext_buf_types[i], __func__); + if (!buffers) + continue; + + list_for_each_entry_safe(buf, dummy, &buffers->list, list) { + if (buf->attach && buf->sg_table) + call_mem_op(core, dma_buf_unmap_attachment, core, + buf->attach, buf->sg_table); + if (buf->attach && buf->dmabuf) + call_mem_op(core, dma_buf_detach, core, buf->dmabuf, buf->attach); + if (buf->dbuf_get) { + print_vidc_buffer(VIDC_ERR, "err ", "destroying: put dmabuf", + inst, buf); + call_mem_op(core, dma_buf_put, inst, buf->dmabuf); + } + list_del_init(&buf->list); + msm_vidc_pool_free(inst, buf); + } + } + + list_for_each_entry_safe(ts, dummy_ts, &inst->timestamps.list, sort.list) { + i_vpr_e(inst, "%s: removing ts: val %lld, rank %lld\n", + __func__, ts->sort.val, ts->rank); + list_del(&ts->sort.list); + msm_vidc_pool_free(inst, ts); + } + + list_for_each_entry_safe(ts, dummy_ts, &inst->ts_reorder.list, sort.list) { + i_vpr_e(inst, "%s: removing reorder ts: val %lld\n", + __func__, ts->sort.val); + list_del(&ts->sort.list); + msm_vidc_pool_free(inst, ts); + } + + list_for_each_entry_safe(timer, dummy_timer, &inst->input_timer_list, list) { + i_vpr_e(inst, "%s: removing input_timer %lld\n", + __func__, timer->time_us); + list_del(&timer->list); + msm_vidc_pool_free(inst, timer); + } + + list_for_each_entry_safe(stats, dummy_stats, &inst->buffer_stats_list, list) { + print_buffer_stats(VIDC_ERR, "err ", inst, stats); + list_del(&stats->list); + msm_vidc_pool_free(inst, stats); + } + + list_for_each_entry_safe(dbuf, dummy_dbuf, &inst->dmabuf_tracker, list) { + struct dma_buf *dmabuf; + struct inode *f_inode; + unsigned long inode_num = 0; + + dmabuf = dbuf->dmabuf; + if (dmabuf && dmabuf->file) { + f_inode = file_inode(dmabuf->file); + if (f_inode) + inode_num = f_inode->i_ino; + } + i_vpr_e(inst, "%s: removing dma_buf %p, inode %lu, refcount %u\n", + __func__, dbuf->dmabuf, inode_num, dbuf->refcount); + call_mem_op(core, dma_buf_put_completely, inst, dbuf); + } + + list_for_each_entry_safe(entry, dummy_entry, &inst->firmware_list, list) { + i_vpr_e(inst, "%s: fw list: %s\n", __func__, cap_name(entry->cap_id)); + list_del(&entry->list); + vfree(entry); + } + + list_for_each_entry_safe(entry, dummy_entry, &inst->children_list, list) { + i_vpr_e(inst, "%s: child list: %s\n", __func__, cap_name(entry->cap_id)); + list_del(&entry->list); + vfree(entry); + } + + list_for_each_entry_safe(entry, dummy_entry, &inst->caps_list, list) { + list_del(&entry->list); + vfree(entry); + } + + list_for_each_entry_safe(cr, dummy_cr, &inst->enc_input_crs, list) { + list_del(&cr->list); + vfree(cr); + } + + list_for_each_entry_safe(fence, dummy_fence, &inst->fence_list, list) { + i_vpr_e(inst, "%s: destroying fence %s\n", __func__, fence->name); + call_fence_op(core, fence_destroy, inst, fence->fence_id); + } + + /* destroy buffers from pool */ + msm_vidc_pools_deinit(inst); +} + +static void msm_vidc_close_helper(struct kref *kref) +{ + struct msm_vidc_inst *inst = container_of(kref, + struct msm_vidc_inst, kref); + struct msm_vidc_core *core; + + core = inst->core; + + i_vpr_h(inst, "%s()\n", __func__); + msm_vidc_debugfs_deinit_inst(inst); + msm_vidc_fence_deinit(inst); + if (is_decode_session(inst)) + msm_vdec_inst_deinit(inst); + else if (is_encode_session(inst)) + msm_venc_inst_deinit(inst); + /** + * Lock is not necessay here, but in force close case, + * vb2q_deinit() will attempt to call stop_streaming() + * vb2 callback and i.e expecting inst lock to be taken. + * So acquire lock before calling vb2q_deinit. + */ + inst_lock(inst, __func__); + msm_vidc_vb2_queue_deinit(inst); + msm_vidc_v4l2_fh_deinit(inst); + inst_unlock(inst, __func__); + destroy_workqueue(inst->workq); + msm_vidc_destroy_buffers(inst); + msm_vidc_remove_session(inst); + msm_vidc_remove_dangling_session(inst); + mutex_destroy(&inst->client_lock); + mutex_destroy(&inst->ctx_q_lock); + mutex_destroy(&inst->lock); + vfree(inst); +} + +struct msm_vidc_inst *get_inst_ref(struct msm_vidc_core *core, + struct msm_vidc_inst *instance) +{ + struct msm_vidc_inst *inst = NULL; + bool matches = false; + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + if (inst == instance) { + matches = true; + break; + } + } + inst = (matches && kref_get_unless_zero(&inst->kref)) ? inst : NULL; + mutex_unlock(&core->lock); + return inst; +} + +struct msm_vidc_inst *get_inst(struct msm_vidc_core *core, + u32 session_id) +{ + struct msm_vidc_inst *inst = NULL; + bool matches = false; + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + if (inst->session_id == session_id) { + matches = true; + break; + } + } + inst = (matches && kref_get_unless_zero(&inst->kref)) ? inst : NULL; + mutex_unlock(&core->lock); + return inst; +} + +void put_inst(struct msm_vidc_inst *inst) +{ + kref_put(&inst->kref, msm_vidc_close_helper); +} + +void core_lock(struct msm_vidc_core *core, const char *function) +{ + mutex_lock(&core->lock); +} + +void core_unlock(struct msm_vidc_core *core, const char *function) +{ + mutex_unlock(&core->lock); +} + +void inst_lock(struct msm_vidc_inst *inst, const char *function) +{ + mutex_lock(&inst->lock); +} + +void inst_unlock(struct msm_vidc_inst *inst, const char *function) +{ + mutex_unlock(&inst->lock); +} + +void client_lock(struct msm_vidc_inst *inst, const char *function) +{ + mutex_lock(&inst->client_lock); +} + +void client_unlock(struct msm_vidc_inst *inst, const char *function) +{ + mutex_unlock(&inst->client_lock); +} + +int msm_vidc_update_bitstream_buffer_size(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + struct v4l2_format *fmt; + + core = inst->core; + + if (is_decode_session(inst)) { + fmt = &inst->fmts[INPUT_PORT]; + fmt->fmt.pix_mp.plane_fmt[0].sizeimage = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_INPUT); + } + + return 0; +} + +int msm_vidc_update_meta_port_settings(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + struct v4l2_format *fmt; + + core = inst->core; + + fmt = &inst->fmts[INPUT_META_PORT]; + fmt->fmt.meta.buffersize = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_INPUT_META); + inst->buffers.input_meta.min_count = + inst->buffers.input.min_count; + inst->buffers.input_meta.extra_count = + inst->buffers.input.extra_count; + inst->buffers.input_meta.actual_count = + inst->buffers.input.actual_count; + inst->buffers.input_meta.size = fmt->fmt.meta.buffersize; + + fmt = &inst->fmts[OUTPUT_META_PORT]; + fmt->fmt.meta.buffersize = call_session_op(core, + buffer_size, inst, MSM_VIDC_BUF_OUTPUT_META); + inst->buffers.output_meta.min_count = + inst->buffers.output.min_count; + inst->buffers.output_meta.extra_count = + inst->buffers.output.extra_count; + inst->buffers.output_meta.actual_count = + inst->buffers.output.actual_count; + inst->buffers.output_meta.size = fmt->fmt.meta.buffersize; + return 0; +} + +int msm_vidc_update_buffer_count(struct msm_vidc_inst *inst, u32 port) +{ + struct msm_vidc_core *core; + + core = inst->core; + + switch (port) { + case INPUT_PORT: + inst->buffers.input.min_count = call_session_op(core, + min_count, inst, MSM_VIDC_BUF_INPUT); + inst->buffers.input.extra_count = call_session_op(core, + extra_count, inst, MSM_VIDC_BUF_INPUT); + if (inst->buffers.input.actual_count < + inst->buffers.input.min_count + + inst->buffers.input.extra_count) { + inst->buffers.input.actual_count = + inst->buffers.input.min_count + + inst->buffers.input.extra_count; + } + if (is_input_meta_enabled(inst)) { + inst->buffers.input_meta.min_count = + inst->buffers.input.min_count; + inst->buffers.input_meta.extra_count = + inst->buffers.input.extra_count; + inst->buffers.input_meta.actual_count = + inst->buffers.input.actual_count; + } else { + inst->buffers.input_meta.min_count = 0; + inst->buffers.input_meta.extra_count = 0; + inst->buffers.input_meta.actual_count = 0; + } + i_vpr_h(inst, "%s: type: INPUT, count: min %u, extra %u, actual %u\n", __func__, + inst->buffers.input.min_count, + inst->buffers.input.extra_count, + inst->buffers.input.actual_count); + break; + case OUTPUT_PORT: + if (!inst->bufq[INPUT_PORT].vb2q->streaming) + inst->buffers.output.min_count = call_session_op(core, + min_count, inst, MSM_VIDC_BUF_OUTPUT); + inst->buffers.output.extra_count = call_session_op(core, + extra_count, inst, MSM_VIDC_BUF_OUTPUT); + if (inst->buffers.output.actual_count < + inst->buffers.output.min_count + + inst->buffers.output.extra_count) { + inst->buffers.output.actual_count = + inst->buffers.output.min_count + + inst->buffers.output.extra_count; + } + if (is_output_meta_enabled(inst)) { + inst->buffers.output_meta.min_count = + inst->buffers.output.min_count; + inst->buffers.output_meta.extra_count = + inst->buffers.output.extra_count; + inst->buffers.output_meta.actual_count = + inst->buffers.output.actual_count; + } else { + inst->buffers.output_meta.min_count = 0; + inst->buffers.output_meta.extra_count = 0; + inst->buffers.output_meta.actual_count = 0; + } + i_vpr_h(inst, "%s: type: OUTPUT, count: min %u, extra %u, actual %u\n", __func__, + inst->buffers.output.min_count, + inst->buffers.output.extra_count, + inst->buffers.output.actual_count); + break; + default: + d_vpr_e("%s unknown port %d\n", __func__, port); + return -EINVAL; + } + + return 0; +} + +void msm_vidc_schedule_core_deinit(struct msm_vidc_core *core) +{ + if (!core->capabilities[FW_UNLOAD].value) + return; + + cancel_delayed_work(&core->fw_unload_work); + + schedule_delayed_work(&core->fw_unload_work, + msecs_to_jiffies(core->capabilities[FW_UNLOAD_DELAY].value)); + + d_vpr_h("firmware unload delayed by %u ms\n", + core->capabilities[FW_UNLOAD_DELAY].value); + + return; +} + +static const char *get_codec_str(enum msm_vidc_codec_type type) +{ + switch (type) { + case MSM_VIDC_H264: return " avc"; + case MSM_VIDC_HEVC: return "hevc"; + case MSM_VIDC_VP9: return " vp9"; + case MSM_VIDC_AV1: return " av1"; + case MSM_VIDC_HEIC: return "heic"; + } + + return "...."; +} + +static const char *get_domain_str(enum msm_vidc_domain_type type) +{ + switch (type) { + case MSM_VIDC_ENCODER: return "E"; + case MSM_VIDC_DECODER: return "D"; + } + + return "."; +} + +int msm_vidc_update_debug_str(struct msm_vidc_inst *inst) +{ + u32 sid; + int client_id = INVALID_CLIENT_ID; + const char *codec; + const char *domain; + + if (!inst) { + d_vpr_e("%s: Invalid params\n", __func__); + return -EINVAL; + } + + client_id = inst->capabilities[CLIENT_ID].value; + + sid = inst->session_id; + codec = get_codec_str(inst->codec); + domain = get_domain_str(inst->domain); + if (client_id != INVALID_CLIENT_ID) { + snprintf(inst->debug_str, sizeof(inst->debug_str), "%08x: %s%s_%d", + sid, codec, domain, client_id); + } else { + snprintf(inst->debug_str, sizeof(inst->debug_str), "%08x: %s%s", + sid, codec, domain); + } + d_vpr_h("%s: sid: %08x, codec: %s, domain: %s, final: %s\n", + __func__, sid, codec, domain, inst->debug_str); + + return 0; +} + +static int msm_vidc_print_running_instances_info(struct msm_vidc_core *core) +{ + struct msm_vidc_inst *inst; + u32 height, width, fps, orate; + struct msm_vidc_inst_cap *cap; + struct v4l2_format *out_f; + struct v4l2_format *inp_f; + char prop[64]; + + d_vpr_e("Print all running instances\n"); + d_vpr_e("%6s | %6s | %5s | %5s | %5s\n", "width", "height", "fps", "orate", "prop"); + + core_lock(core, __func__); + list_for_each_entry(inst, &core->instances, list) { + out_f = &inst->fmts[OUTPUT_PORT]; + inp_f = &inst->fmts[INPUT_PORT]; + cap = &inst->capabilities[0]; + memset(&prop, 0, sizeof(prop)); + + width = max(out_f->fmt.pix_mp.width, inp_f->fmt.pix_mp.width); + height = max(out_f->fmt.pix_mp.height, inp_f->fmt.pix_mp.height); + fps = cap[FRAME_RATE].value >> 16; + orate = cap[OPERATING_RATE].value >> 16; + + if (is_realtime_session(inst)) + strlcat(prop, "RT ", sizeof(prop)); + else + strlcat(prop, "NRT", sizeof(prop)); + + if (is_thumbnail_session(inst)) + strlcat(prop, "+THUMB", sizeof(prop)); + + if (is_image_session(inst)) + strlcat(prop, "+IMAGE", sizeof(prop)); + + i_vpr_e(inst, "%6u | %6u | %5u | %5u | %5s\n", width, height, fps, orate, prop); + } + core_unlock(core, __func__); + + return 0; +} + +static int msm_vidc_get_inst_load(struct msm_vidc_inst *inst) +{ + u32 mbpf, fps; + u32 input_rate, timestamp_rate, operating_rate; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + /* + * Encoder: consider frame rate + * Decoder: consider max(frame rate, operating rate, + * timestamp rate, input queue rate) + */ + mbpf = msm_vidc_get_mbs_per_frame(inst); + fps = msm_vidc_get_frame_rate(inst); + + if (is_decode_session(inst)) { + input_rate = msm_vidc_get_input_rate(inst); + timestamp_rate = msm_vidc_get_timestamp_rate(inst); + operating_rate = msm_vidc_get_operating_rate(inst); + fps = max(fps, operating_rate); + fps = max(fps, input_rate); + fps = max(fps, timestamp_rate); + } + + return mbpf * fps; +} + +static bool msm_vidc_ignore_session_load(struct msm_vidc_inst *inst) +{ + if (!is_realtime_session(inst) || is_thumbnail_session(inst) || + is_image_session(inst) || is_session_error(inst)) + return true; + + return false; +} + +int msm_vidc_check_core_mbps(struct msm_vidc_inst *inst) +{ + u64 mbps = 0, total_mbps = 0, enc_mbps = 0, critical_mbps = 0; + struct msm_vidc_core *core; + struct msm_vidc_inst *instance; + + core = inst->core; + + /* skip mbps check for non-realtime, thumnail, image sessions */ + if (msm_vidc_ignore_session_load(inst)) { + i_vpr_h(inst, + "%s: skip mbps check due to NRT %d, TH %d, IMG %d, error session %d\n", + __func__, !is_realtime_session(inst), is_thumbnail_session(inst), + is_image_session(inst), is_session_error(inst)); + return 0; + } + + core_lock(core, __func__); + list_for_each_entry(instance, &core->instances, list) { + if (is_critical_priority_session(instance)) + critical_mbps += msm_vidc_get_inst_load(instance); + } + core_unlock(core, __func__); + + if (critical_mbps > core->capabilities[MAX_MBPS].value) { + i_vpr_e(inst, "%s: Hardware overloaded with critical sessions. needed %u, max %u", + __func__, critical_mbps, core->capabilities[MAX_MBPS].value); + return -ENOMEM; + } + + core_lock(core, __func__); + list_for_each_entry(instance, &core->instances, list) { + + /* ignore thumbnail, image, non realtime, error sessions */ + if (msm_vidc_ignore_session_load(instance)) + continue; + + mbps = msm_vidc_get_inst_load(instance); + total_mbps += mbps; + if (is_encode_session(instance)) + enc_mbps += mbps; + } + core_unlock(core, __func__); + + if (is_encode_session(inst)) { + /* reject encoder if all encoders mbps is greater than MAX_MBPS */ + if (enc_mbps > core->capabilities[MAX_MBPS].value) { + i_vpr_e(inst, "%s: Hardware overloaded. needed %u, max %u", __func__, + mbps, core->capabilities[MAX_MBPS].value); + return -ENOMEM; + } + /* + * if total_mbps is greater than max_mbps then reduce all decoders + * priority by 1 to allow this encoder + */ + if (total_mbps > core->capabilities[MAX_MBPS].value) { + core_lock(core, __func__); + list_for_each_entry(instance, &core->instances, list) { + /* reduce realtime decode sessions priority */ + if (is_decode_session(instance) && is_realtime_session(instance)) { + instance->adjust_priority = RT_DEC_DOWN_PRORITY_OFFSET; + i_vpr_h(inst, "%s: pending adjust priority by %d\n", + __func__, instance->adjust_priority); + } + } + core_unlock(core, __func__); + } + } else if (is_decode_session(inst)) { + /* + * if total_mbps is greater than max_mbps then allow this + * decoder by reducing its piority (moving it to NRT) + */ + if (total_mbps > core->capabilities[MAX_MBPS].value) { + inst->adjust_priority = RT_DEC_DOWN_PRORITY_OFFSET; + i_vpr_h(inst, "%s: pending adjust priority by %d\n", + __func__, inst->adjust_priority); + } + } + + i_vpr_h(inst, "%s: HW load needed %u is within max %u", __func__, + total_mbps, core->capabilities[MAX_MBPS].value); + + return 0; +} + +int msm_vidc_check_core_mbpf(struct msm_vidc_inst *inst) +{ + u32 video_mbpf = 0, image_mbpf = 0, video_rt_mbpf = 0; + u32 critical_mbpf = 0; + struct msm_vidc_core *core; + struct msm_vidc_inst *instance; + + core = inst->core; + + core_lock(core, __func__); + list_for_each_entry(instance, &core->instances, list) { + if (is_critical_priority_session(instance)) + critical_mbpf += msm_vidc_get_mbs_per_frame(instance); + } + core_unlock(core, __func__); + + if (critical_mbpf > core->capabilities[MAX_MBPF].value) { + i_vpr_e(inst, "%s: Hardware overloaded with critical sessions. needed %u, max %u", + __func__, critical_mbpf, core->capabilities[MAX_MBPF].value); + return -ENOMEM; + } + + core_lock(core, __func__); + list_for_each_entry(instance, &core->instances, list) { + /* ignore thumbnail session */ + if (is_thumbnail_session(instance)) + continue; + + if (is_image_session(instance)) + image_mbpf += msm_vidc_get_mbs_per_frame(instance); + else + video_mbpf += msm_vidc_get_mbs_per_frame(instance); + } + core_unlock(core, __func__); + + if (video_mbpf > core->capabilities[MAX_MBPF].value) { + i_vpr_e(inst, "%s: video overloaded. needed %u, max %u", __func__, + video_mbpf, core->capabilities[MAX_MBPF].value); + return -ENOMEM; + } + + if (image_mbpf > core->capabilities[MAX_IMAGE_MBPF].value) { + i_vpr_e(inst, "%s: image overloaded. needed %u, max %u", __func__, + image_mbpf, core->capabilities[MAX_IMAGE_MBPF].value); + return -ENOMEM; + } + + core_lock(core, __func__); + /* check real-time video sessions max limit */ + list_for_each_entry(instance, &core->instances, list) { + if (msm_vidc_ignore_session_load(instance)) + continue; + + video_rt_mbpf += msm_vidc_get_mbs_per_frame(instance); + } + core_unlock(core, __func__); + + if (video_rt_mbpf > core->capabilities[MAX_RT_MBPF].value) { + i_vpr_e(inst, "%s: real-time video overloaded. needed %u, max %u", + __func__, video_rt_mbpf, core->capabilities[MAX_RT_MBPF].value); + return -ENOMEM; + } + + return 0; +} + +static int msm_vidc_check_inst_mbpf(struct msm_vidc_inst *inst) +{ + u32 mbpf = 0, max_mbpf = 0; + struct msm_vidc_inst_cap *cap; + + cap = &inst->capabilities[0]; + + if (is_secure_session(inst)) + max_mbpf = cap[SECURE_MBPF].max; + else if (is_encode_session(inst) && cap[LOSSLESS].value) + max_mbpf = cap[LOSSLESS_MBPF].max; + else + max_mbpf = cap[MBPF].max; + + /* check current session mbpf */ + mbpf = msm_vidc_get_mbs_per_frame(inst); + if (mbpf > max_mbpf) { + i_vpr_e(inst, "%s: session overloaded. needed %u, max %u", __func__, + mbpf, max_mbpf); + return -ENOMEM; + } + + return 0; +} + +u32 msm_vidc_get_max_bitrate(struct msm_vidc_inst *inst) +{ + u32 max_bitrate = 0x7fffffff; + + if (inst->capabilities[LOWLATENCY_MODE].value) + max_bitrate = min(max_bitrate, + (u32)inst->capabilities[LOWLATENCY_MAX_BITRATE].max); + + if (inst->capabilities[ALL_INTRA].value) + max_bitrate = min(max_bitrate, + (u32)inst->capabilities[ALLINTRA_MAX_BITRATE].max); + + if (inst->codec == MSM_VIDC_HEVC) { + max_bitrate = min(max_bitrate, + (u32)inst->capabilities[CABAC_MAX_BITRATE].max); + } else if (inst->codec == MSM_VIDC_H264) { + if (inst->capabilities[ENTROPY_MODE].value == + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) + max_bitrate = min(max_bitrate, + (u32)inst->capabilities[CAVLC_MAX_BITRATE].max); + else + max_bitrate = min(max_bitrate, + (u32)inst->capabilities[CABAC_MAX_BITRATE].max); + } + if (max_bitrate == 0x7fffffff || !max_bitrate) + max_bitrate = min(max_bitrate, (u32)inst->capabilities[BIT_RATE].max); + + return max_bitrate; +} + +static bool msm_vidc_allow_image_encode_session(struct msm_vidc_inst *inst) +{ + struct msm_vidc_inst_cap *cap; + struct v4l2_format *fmt; + u32 min_width, min_height, max_width, max_height, pix_fmt, profile; + bool allow = false; + + cap = &inst->capabilities[0]; + + if (!is_image_encode_session(inst)) { + i_vpr_e(inst, "%s: not an image encode session\n", __func__); + return false; + } + + pix_fmt = cap[PIX_FMTS].value; + profile = cap[PROFILE].value; + + /* is input with & height is in allowed range */ + min_width = cap[FRAME_WIDTH].min; + max_width = cap[FRAME_WIDTH].max; + min_height = cap[FRAME_HEIGHT].min; + max_height = cap[FRAME_HEIGHT].max; + fmt = &inst->fmts[INPUT_PORT]; + if (!in_range(fmt->fmt.pix_mp.width, min_width, max_width) || + !in_range(fmt->fmt.pix_mp.height, min_height, max_height)) { + i_vpr_e(inst, "unsupported wxh [%u x %u], allowed [%u x %u] to [%u x %u]\n", + fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height, + min_width, min_height, max_width, max_height); + allow = false; + goto exit; + } + + /* is linear yuv color fmt */ + allow = is_linear_yuv_colorformat(pix_fmt); + if (!allow) { + i_vpr_e(inst, "%s: compressed fmt: %#x\n", __func__, pix_fmt); + goto exit; + } + + /* is output grid dimension */ + fmt = &inst->fmts[OUTPUT_PORT]; + allow = fmt->fmt.pix_mp.width == cap[GRID_SIZE].value; + allow &= fmt->fmt.pix_mp.height == cap[GRID_SIZE].value; + if (!allow) { + i_vpr_e(inst, "%s: output is not a grid dimension: %u x %u\n", __func__, + fmt->fmt.pix_mp.width, fmt->fmt.pix_mp.height); + goto exit; + } + + /* is bitrate mode CQ */ + allow = cap[BITRATE_MODE].value == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ; + if (!allow) { + i_vpr_e(inst, "%s: bitrate mode is not CQ: %#x\n", __func__, + cap[BITRATE_MODE].value); + goto exit; + } + + /* is all intra */ + allow = !cap[GOP_SIZE].value; + allow &= !cap[B_FRAME].value; + if (!allow) { + i_vpr_e(inst, "%s: not all intra: gop: %u, bframe: %u\n", __func__, + cap[GOP_SIZE].value, cap[B_FRAME].value); + goto exit; + } + + /* is time delta based rc disabled */ + allow = !cap[TIME_DELTA_BASED_RC].value; + if (!allow) { + i_vpr_e(inst, "%s: time delta based rc not disabled: %#x\n", __func__, + cap[TIME_DELTA_BASED_RC].value); + goto exit; + } + + /* is frame skip mode disabled */ + allow = !cap[FRAME_SKIP_MODE].value; + if (!allow) { + i_vpr_e(inst, "%s: frame skip mode not disabled: %#x\n", __func__, + cap[FRAME_SKIP_MODE].value); + goto exit; + } + +exit: + if (!allow) + i_vpr_e(inst, "%s: current session not allowed\n", __func__); + + return allow; +} + +static int msm_vidc_check_resolution_supported(struct msm_vidc_inst *inst) +{ + struct msm_vidc_inst_cap *cap; + u32 width = 0, height = 0, min_width, min_height, + max_width, max_height; + bool is_interlaced = false; + + cap = &inst->capabilities[0]; + + if (is_decode_session(inst)) { + width = inst->fmts[INPUT_PORT].fmt.pix_mp.width; + height = inst->fmts[INPUT_PORT].fmt.pix_mp.height; + } else if (is_encode_session(inst)) { + width = inst->crop.width; + height = inst->crop.height; + } + + if (is_secure_session(inst)) { + min_width = cap[SECURE_FRAME_WIDTH].min; + max_width = cap[SECURE_FRAME_WIDTH].max; + min_height = cap[SECURE_FRAME_HEIGHT].min; + max_height = cap[SECURE_FRAME_HEIGHT].max; + } else if (is_encode_session(inst) && cap[LOSSLESS].value) { + min_width = cap[LOSSLESS_FRAME_WIDTH].min; + max_width = cap[LOSSLESS_FRAME_WIDTH].max; + min_height = cap[LOSSLESS_FRAME_HEIGHT].min; + max_height = cap[LOSSLESS_FRAME_HEIGHT].max; + } else { + min_width = cap[FRAME_WIDTH].min; + max_width = cap[FRAME_WIDTH].max; + min_height = cap[FRAME_HEIGHT].min; + max_height = cap[FRAME_HEIGHT].max; + } + + /* check if input width and height is in supported range */ + if (is_decode_session(inst) || is_encode_session(inst)) { + if (!in_range(width, min_width, max_width) || + !in_range(height, min_height, max_height)) { + i_vpr_e(inst, + "%s: unsupported input wxh [%u x %u], allowed range: [%u x %u] to [%u x %u]\n", + __func__, width, height, min_width, + min_height, max_width, max_height); + return -EINVAL; + } + } + + /* check interlace supported resolution */ + is_interlaced = cap[CODED_FRAMES].value == CODED_FRAMES_INTERLACE; + if (is_interlaced && (width > INTERLACE_WIDTH_MAX || height > INTERLACE_HEIGHT_MAX || + NUM_MBS_PER_FRAME(width, height) > INTERLACE_MB_PER_FRAME_MAX)) { + i_vpr_e(inst, "%s: unsupported interlace wxh [%u x %u], max [%u x %u]\n", + __func__, width, height, INTERLACE_WIDTH_MAX, INTERLACE_HEIGHT_MAX); + return -EINVAL; + } + + return 0; +} + +static int msm_vidc_check_max_sessions(struct msm_vidc_inst *inst) +{ + u32 width = 0, height = 0; + u32 num_1080p_sessions = 0, num_4k_sessions = 0, num_8k_sessions = 0; + struct msm_vidc_inst *i; + struct msm_vidc_core *core; + + core = inst->core; + + core_lock(core, __func__); + list_for_each_entry(i, &core->instances, list) { + /* skip image sessions count */ + if (is_image_session(i)) + continue; + + if (is_decode_session(i)) { + width = i->fmts[INPUT_PORT].fmt.pix_mp.width; + height = i->fmts[INPUT_PORT].fmt.pix_mp.height; + } else if (is_encode_session(i)) { + width = i->crop.width; + height = i->crop.height; + } + + /* + * one 8k session equals to 64 720p sessions in reality. + * So for one 8k session the number of 720p sessions will + * exceed max supported session count(16), hence one 8k session + * will be rejected as well. + * Therefore, treat one 8k session equal to two 4k sessions and + * one 4k session equal to two 1080p sessions and + * one 1080p session equal to two 720p sessions. This equation + * will make one 8k session equal to eight 720p sessions + * which looks good. + * + * Do not treat resolutions above 4k as 8k session instead + * treat (4K + half 4k) above as 8k session + */ + if (res_is_greater_than(width, height, 4096 + (4096 >> 1), 2176 + (2176 >> 1))) { + num_8k_sessions += 1; + num_4k_sessions += 2; + num_1080p_sessions += 4; + } else if (res_is_greater_than(width, height, 1920 + (1920 >> 1), + 1088 + (1088 >> 1))) { + num_4k_sessions += 1; + num_1080p_sessions += 2; + } else if (res_is_greater_than(width, height, 1280 + (1280 >> 1), + 736 + (736 >> 1))) { + num_1080p_sessions += 1; + } + } + core_unlock(core, __func__); + + if (num_8k_sessions > core->capabilities[MAX_NUM_8K_SESSIONS].value) { + i_vpr_e(inst, "%s: total 8k sessions %d, exceeded max limit %d\n", + __func__, num_8k_sessions, + core->capabilities[MAX_NUM_8K_SESSIONS].value); + return -ENOMEM; + } + + if (num_4k_sessions > core->capabilities[MAX_NUM_4K_SESSIONS].value) { + i_vpr_e(inst, "%s: total 4K sessions %d, exceeded max limit %d\n", + __func__, num_4k_sessions, + core->capabilities[MAX_NUM_4K_SESSIONS].value); + return -ENOMEM; + } + + if (num_1080p_sessions > core->capabilities[MAX_NUM_1080P_SESSIONS].value) { + i_vpr_e(inst, "%s: total 1080p sessions %d, exceeded max limit %d\n", + __func__, num_1080p_sessions, + core->capabilities[MAX_NUM_1080P_SESSIONS].value); + return -ENOMEM; + } + + return 0; +} + +int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) +{ + bool allow = false; + int rc = 0; + + if (is_image_session(inst) && is_secure_session(inst)) { + i_vpr_e(inst, "%s: secure image session not supported\n", __func__); + rc = -EINVAL; + goto exit; + } + + rc = msm_vidc_check_core_mbps(inst); + if (rc) + goto exit; + + rc = msm_vidc_check_core_mbpf(inst); + if (rc) + goto exit; + + rc = msm_vidc_check_inst_mbpf(inst); + if (rc) + goto exit; + + rc = msm_vidc_check_resolution_supported(inst); + if (rc) + goto exit; + + /* check image capabilities */ + if (is_image_encode_session(inst)) { + allow = msm_vidc_allow_image_encode_session(inst); + if (!allow) { + rc = -EINVAL; + goto exit; + } + } + + rc = msm_vidc_check_max_sessions(inst); + if (rc) + goto exit; + +exit: + if (rc) { + i_vpr_e(inst, "%s: current session not supported\n", __func__); + msm_vidc_print_running_instances_info(inst->core); + } + + return rc; +} + +int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst) +{ + u32 iwidth, owidth, iheight, oheight, ds_factor; + + if (is_image_session(inst) || is_decode_session(inst)) { + i_vpr_h(inst, "%s: Scaling is supported for encode session only\n", __func__); + return 0; + } + + if (!is_scaling_enabled(inst)) { + i_vpr_h(inst, "%s: Scaling not enabled. skip scaling check\n", __func__); + return 0; + } + + iwidth = inst->crop.width; + iheight = inst->crop.height; + owidth = inst->compose.width; + oheight = inst->compose.height; + ds_factor = inst->capabilities[SCALE_FACTOR].value; + + /* upscaling: encoder doesnot support upscaling */ + if (owidth > iwidth || oheight > iheight) { + i_vpr_e(inst, "%s: upscale not supported: input [%u x %u], output [%u x %u]\n", + __func__, iwidth, iheight, owidth, oheight); + return -EINVAL; + } + + /* downscaling: only supported upto 1/8 of width & 1/8 of height */ + if (iwidth > owidth * ds_factor || iheight > oheight * ds_factor) { + i_vpr_e(inst, + "%s: unsupported ratio: input [%u x %u], output [%u x %u], ratio %u\n", + __func__, iwidth, iheight, owidth, oheight, ds_factor); + return -EINVAL; + } + + return 0; +} + +struct msm_vidc_fw_query_params { + u32 hfi_prop_name; + u32 port; +}; + +int msm_vidc_get_properties(struct msm_vidc_inst *inst) +{ + int rc = 0; + int i; + + static const struct msm_vidc_fw_query_params fw_query_params[] = { + {HFI_PROP_STAGE, HFI_PORT_NONE}, + {HFI_PROP_PIPE, HFI_PORT_NONE}, + {HFI_PROP_QUALITY_MODE, HFI_PORT_BITSTREAM} + }; + + for (i = 0; i < ARRAY_SIZE(fw_query_params); i++) { + + if (is_decode_session(inst)) { + if (fw_query_params[i].hfi_prop_name == HFI_PROP_QUALITY_MODE) + continue; + } + + i_vpr_l(inst, "%s: querying fw for property %#x\n", __func__, + fw_query_params[i].hfi_prop_name); + + rc = venus_hfi_session_property(inst, + fw_query_params[i].hfi_prop_name, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED | + HFI_HOST_FLAGS_GET_PROPERTY), + fw_query_params[i].port, + HFI_PAYLOAD_NONE, + NULL, + 0); + if (rc) + return rc; + } + + return 0; +} + +struct context_bank_info *msm_vidc_get_context_bank_for_region( + struct msm_vidc_core *core, enum msm_vidc_buffer_region region) +{ + struct context_bank_info *cb = NULL, *match = NULL; + + if (!region || region >= MSM_VIDC_REGION_MAX) { + d_vpr_e("Invalid region %#x\n", region); + return NULL; + } + + venus_hfi_for_each_context_bank(core, cb) { + if (cb->region == region) { + match = cb; + break; + } + } + if (!match) + d_vpr_e("cb not found for region %#x\n", region); + + return match; +} + +struct context_bank_info *msm_vidc_get_context_bank_for_device( + struct msm_vidc_core *core, struct device *dev) +{ + struct context_bank_info *cb = NULL, *match = NULL; + + venus_hfi_for_each_context_bank(core, cb) { + if (of_device_is_compatible(dev->of_node, cb->name)) { + match = cb; + break; + } + } + if (!match) + d_vpr_e("cb not found for dev %s\n", dev_name(dev)); + + return match; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_fence.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_fence.c new file mode 100644 index 0000000000..0bdcca92bc --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_fence.c @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_fence.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_debug.h" + +static const char *msm_vidc_dma_fence_get_driver_name(struct dma_fence *df) +{ + struct msm_vidc_fence *fence; + + if (df) { + fence = container_of(df, struct msm_vidc_fence, dma_fence); + return fence->name; + } + return "msm_vidc_dma_fence_get_driver_name: invalid fence"; +} + +static const char *msm_vidc_dma_fence_get_timeline_name(struct dma_fence *df) +{ + struct msm_vidc_fence *fence; + + if (df) { + fence = container_of(df, struct msm_vidc_fence, dma_fence); + return fence->name; + } + return "msm_vidc_dma_fence_get_timeline_name: invalid fence"; +} + +static void msm_vidc_dma_fence_release(struct dma_fence *df) +{ + struct msm_vidc_fence *fence; + + if (df) { + fence = container_of(df, struct msm_vidc_fence, dma_fence); + d_vpr_l("%s: name %s\n", __func__, fence->name); + vfree(fence); + } else { + d_vpr_e("%s: invalid fence\n", __func__); + } +} + +static const struct dma_fence_ops msm_vidc_dma_fence_ops = { + .get_driver_name = msm_vidc_dma_fence_get_driver_name, + .get_timeline_name = msm_vidc_dma_fence_get_timeline_name, + .release = msm_vidc_dma_fence_release, +}; + +struct msm_vidc_fence *msm_vidc_fence_create(struct msm_vidc_inst *inst) +{ + struct msm_vidc_fence *fence = NULL; + + fence = vzalloc(sizeof(*fence)); + if (!fence) { + i_vpr_e(inst, "%s: allocation failed\n", __func__); + return NULL; + } + + fence->fd = INVALID_FD; + spin_lock_init(&fence->lock); + dma_fence_init(&fence->dma_fence, &msm_vidc_dma_fence_ops, + &fence->lock, inst->fence_context.ctx_num, + ++inst->fence_context.seq_num); + snprintf(fence->name, sizeof(fence->name), "%s: %llu", + inst->fence_context.name, inst->fence_context.seq_num); + + /* reset seqno to avoid going beyond INT_MAX */ + if (inst->fence_context.seq_num >= INT_MAX) + inst->fence_context.seq_num = 0; + + fence->fence_id = fence->dma_fence.seqno; + + INIT_LIST_HEAD(&fence->list); + list_add_tail(&fence->list, &inst->fence_list); + i_vpr_l(inst, "%s: created %s\n", __func__, fence->name); + + return fence; +} + +int msm_vidc_dma_fence_create_fd(struct msm_vidc_inst *inst, + struct msm_vidc_fence *fence) +{ + int rc = 0; + + fence->fd = get_unused_fd_flags(0); + if (fence->fd < 0) { + i_vpr_e(inst, "%s: getting fd (%d) failed\n", __func__, + fence->fd); + rc = -EINVAL; + goto err_fd; + } + fence->sync_file = sync_file_create(&fence->dma_fence); + if (!fence->sync_file) { + i_vpr_e(inst, "%s: sync_file_create failed\n", __func__); + rc = -EINVAL; + goto err_sync_file; + } + fd_install(fence->fd, fence->sync_file->file); + + i_vpr_l(inst, "%s: created fd %d for fence %s\n", __func__, + fence->fd, fence->name); + + return 0; + +err_sync_file: + put_unused_fd(fence->fd); +err_fd: + return rc; +} + +static struct msm_vidc_fence *msm_vidc_get_dma_fence_from_id( + struct msm_vidc_inst *inst, u64 fence_id) +{ + struct msm_vidc_fence *fence, *dummy_fence; + bool found = false; + + list_for_each_entry_safe(fence, dummy_fence, &inst->fence_list, list) { + if (fence->fence_id == fence_id) { + found = true; + break; + } + } + + if (!found) { + i_vpr_l(inst, "%s: no fence available for id: %u\n", + __func__, fence_id); + return NULL; + } + + return fence; +} + +static int msm_vidc_fence_signal(struct msm_vidc_inst *inst, u64 fence_id) +{ + int rc = 0; + struct msm_vidc_fence *fence; + + fence = msm_vidc_get_dma_fence_from_id(inst, fence_id); + if (!fence) { + i_vpr_e(inst, "%s: no fence available to signal with id: %u\n", + __func__, fence_id); + rc = -EINVAL; + goto exit; + } + + i_vpr_l(inst, "%s: fence %s\n", __func__, fence->name); + list_del_init(&fence->list); + + dma_fence_signal(&fence->dma_fence); + dma_fence_put(&fence->dma_fence); + +exit: + return rc; +} + + +static void msm_vidc_fence_destroy(struct msm_vidc_inst *inst, u64 fence_id) +{ + struct msm_vidc_fence *fence; + + fence = msm_vidc_get_dma_fence_from_id(inst, fence_id); + if (!fence) + return; + + i_vpr_l(inst, "%s: fence %s\n", __func__, fence->name); + list_del_init(&fence->list); + dma_fence_set_error(&fence->dma_fence, -EINVAL); + dma_fence_signal(&fence->dma_fence); + dma_fence_put(&fence->dma_fence); +} + +int msm_vidc_fence_init(struct msm_vidc_inst *inst) +{ + int rc = 0; + + inst->fence_context.ctx_num = dma_fence_context_alloc(1); + snprintf(inst->fence_context.name, sizeof(inst->fence_context.name), + "msm_vidc_fence: %s: %llu", inst->debug_str, + inst->fence_context.ctx_num); + i_vpr_h(inst, "%s: %s\n", __func__, inst->fence_context.name); + + return rc; +} + +void msm_vidc_fence_deinit(struct msm_vidc_inst *inst) +{ + i_vpr_h(inst, "%s: %s\n", __func__, inst->fence_context.name); + inst->fence_context.ctx_num = 0; + snprintf(inst->fence_context.name, sizeof(inst->fence_context.name), + "%s", ""); +} + +static const struct msm_vidc_fence_ops msm_dma_fence_ops = { + .fence_create = msm_vidc_fence_create, + .fence_destroy = msm_vidc_fence_destroy, + .fence_signal = msm_vidc_fence_signal, + .fence_create_fd = msm_vidc_dma_fence_create_fd, +}; + +const struct msm_vidc_fence_ops *get_dma_fence_ops(void) +{ + return &msm_dma_fence_ops; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_memory.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_memory.c new file mode 100644 index 0000000000..576ea0ff09 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_memory.c @@ -0,0 +1,616 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include + +#include "msm_vidc_memory.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_core.h" +#include "msm_vidc_events.h" +#include "msm_vidc_platform.h" +#include "venus_hfi.h" + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) + MODULE_IMPORT_NS(DMA_BUF); +#endif + +struct msm_vidc_type_size_name { + enum msm_memory_pool_type type; + u32 size; + char *name; +}; + +static const struct msm_vidc_type_size_name buftype_size_name_arr[] = { + {MSM_MEM_POOL_BUFFER, sizeof(struct msm_vidc_buffer), "MSM_MEM_POOL_BUFFER" }, + {MSM_MEM_POOL_ALLOC_MAP, sizeof(struct msm_vidc_mem), "MSM_MEM_POOL_ALLOC_MAP" }, + {MSM_MEM_POOL_TIMESTAMP, sizeof(struct msm_vidc_timestamp), "MSM_MEM_POOL_TIMESTAMP" }, + {MSM_MEM_POOL_DMABUF, sizeof(struct msm_memory_dmabuf), "MSM_MEM_POOL_DMABUF" }, + {MSM_MEM_POOL_PACKET, sizeof(struct hfi_pending_packet) + MSM_MEM_POOL_PACKET_SIZE, + "MSM_MEM_POOL_PACKET"}, + {MSM_MEM_POOL_BUF_TIMER, sizeof(struct msm_vidc_input_timer), "MSM_MEM_POOL_BUF_TIMER" }, + {MSM_MEM_POOL_BUF_STATS, sizeof(struct msm_vidc_buffer_stats), "MSM_MEM_POOL_BUF_STATS"}, +}; + +void *msm_vidc_pool_alloc(struct msm_vidc_inst *inst, enum msm_memory_pool_type type) +{ + struct msm_memory_alloc_header *hdr = NULL; + struct msm_memory_pool *pool; + + if (type < 0 || type >= MSM_MEM_POOL_MAX) { + d_vpr_e("%s: Invalid params\n", __func__); + return NULL; + } + pool = &inst->pool[type]; + + if (!list_empty(&pool->free_pool)) { + /* get 1st node from free pool */ + hdr = list_first_entry(&pool->free_pool, + struct msm_memory_alloc_header, list); + + /* move node from free pool to busy pool */ + list_move_tail(&hdr->list, &pool->busy_pool); + + /* reset existing data */ + memset((char *)hdr->buf, 0, pool->size); + + /* set busy flag to true. This is to catch double free request */ + hdr->busy = true; + + return hdr->buf; + } + + hdr = vzalloc(pool->size + sizeof(struct msm_memory_alloc_header)); + if (!hdr) { + i_vpr_e(inst, "%s: allocation failed\n", __func__); + return NULL; + } + + INIT_LIST_HEAD(&hdr->list); + hdr->type = type; + hdr->busy = true; + hdr->buf = (void *)(hdr + 1); + list_add_tail(&hdr->list, &pool->busy_pool); + + return hdr->buf; +} + +void msm_vidc_pool_free(struct msm_vidc_inst *inst, void *vidc_buf) +{ + struct msm_memory_alloc_header *hdr; + struct msm_memory_pool *pool; + + if (!vidc_buf) { + d_vpr_e("%s: Invalid params\n", __func__); + return; + } + hdr = (struct msm_memory_alloc_header *)vidc_buf - 1; + + /* sanitize buffer addr */ + if (hdr->buf != vidc_buf) { + i_vpr_e(inst, "%s: invalid buf addr %p\n", __func__, vidc_buf); + return; + } + + /* sanitize pool type */ + if (hdr->type < 0 || hdr->type >= MSM_MEM_POOL_MAX) { + i_vpr_e(inst, "%s: invalid pool type %#x\n", __func__, hdr->type); + return; + } + pool = &inst->pool[hdr->type]; + + /* catch double-free request */ + if (!hdr->busy) { + i_vpr_e(inst, "%s: double free request. type %s, addr %p\n", __func__, + pool->name, vidc_buf); + return; + } + hdr->busy = false; + + /* move node from busy pool to free pool */ + list_move_tail(&hdr->list, &pool->free_pool); +} + +static void msm_vidc_destroy_pool_buffers(struct msm_vidc_inst *inst, + enum msm_memory_pool_type type) +{ + struct msm_memory_alloc_header *hdr, *dummy; + struct msm_memory_pool *pool; + u32 fcount = 0, bcount = 0; + + if (type < 0 || type >= MSM_MEM_POOL_MAX) { + d_vpr_e("%s: Invalid params\n", __func__); + return; + } + pool = &inst->pool[type]; + + /* detect memleak: busy pool is expected to be empty here */ + if (!list_empty(&pool->busy_pool)) + i_vpr_e(inst, "%s: destroy request on active buffer. type %s\n", + __func__, pool->name); + + /* destroy all free buffers */ + list_for_each_entry_safe(hdr, dummy, &pool->free_pool, list) { + list_del(&hdr->list); + vfree(hdr); + fcount++; + } + + /* destroy all busy buffers */ + list_for_each_entry_safe(hdr, dummy, &pool->busy_pool, list) { + list_del(&hdr->list); + vfree(hdr); + bcount++; + } + + i_vpr_h(inst, "%s: type: %23s, count: free %2u, busy %2u\n", + __func__, pool->name, fcount, bcount); +} + +int msm_vidc_pools_init(struct msm_vidc_inst *inst) +{ + u32 i; + + if (ARRAY_SIZE(buftype_size_name_arr) != MSM_MEM_POOL_MAX) { + i_vpr_e(inst, "%s: num elements mismatch %lu %u\n", __func__, + ARRAY_SIZE(buftype_size_name_arr), MSM_MEM_POOL_MAX); + return -EINVAL; + } + + for (i = 0; i < MSM_MEM_POOL_MAX; i++) { + if (i != buftype_size_name_arr[i].type) { + i_vpr_e(inst, "%s: type mismatch %u %u\n", __func__, + i, buftype_size_name_arr[i].type); + return -EINVAL; + } + inst->pool[i].size = buftype_size_name_arr[i].size; + inst->pool[i].name = buftype_size_name_arr[i].name; + INIT_LIST_HEAD(&inst->pool[i].free_pool); + INIT_LIST_HEAD(&inst->pool[i].busy_pool); + } + + return 0; +} + +void msm_vidc_pools_deinit(struct msm_vidc_inst *inst) +{ + u32 i = 0; + + /* destroy all buffers from all pool types */ + for (i = 0; i < MSM_MEM_POOL_MAX; i++) + msm_vidc_destroy_pool_buffers(inst, i); +} + +static struct dma_buf *msm_vidc_dma_buf_get(struct msm_vidc_inst *inst, int fd) +{ + struct msm_memory_dmabuf *buf = NULL; + struct dma_buf *dmabuf = NULL; + bool found = false; + + /* get local dmabuf ref for tracking */ + dmabuf = dma_buf_get(fd); + if (IS_ERR_OR_NULL(dmabuf)) { + d_vpr_e("Failed to get dmabuf for %d, error %ld\n", + fd, PTR_ERR(dmabuf)); + return NULL; + } + + /* track dmabuf - inc refcount if already present */ + list_for_each_entry(buf, &inst->dmabuf_tracker, list) { + if (buf->dmabuf == dmabuf) { + buf->refcount++; + found = true; + break; + } + } + if (found) { + /* put local dmabuf ref */ + dma_buf_put(dmabuf); + return dmabuf; + } + + /* get tracker instance from pool */ + buf = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_DMABUF); + if (!buf) { + i_vpr_e(inst, "%s: dmabuf alloc failed\n", __func__); + dma_buf_put(dmabuf); + return NULL; + } + /* hold dmabuf strong ref in tracker */ + buf->dmabuf = dmabuf; + buf->refcount = 1; + INIT_LIST_HEAD(&buf->list); + + /* add new dmabuf entry to tracker */ + list_add_tail(&buf->list, &inst->dmabuf_tracker); + + return dmabuf; +} + +static void msm_vidc_dma_buf_put(struct msm_vidc_inst *inst, struct dma_buf *dmabuf) +{ + struct msm_memory_dmabuf *buf = NULL; + bool found = false; + + if (!dmabuf) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + /* track dmabuf - dec refcount if already present */ + list_for_each_entry(buf, &inst->dmabuf_tracker, list) { + if (buf->dmabuf == dmabuf) { + buf->refcount--; + found = true; + break; + } + } + if (!found) { + i_vpr_e(inst, "%s: invalid dmabuf %p\n", __func__, dmabuf); + return; + } + + /* non-zero refcount - do nothing */ + if (buf->refcount) + return; + + /* remove dmabuf entry from tracker */ + list_del(&buf->list); + + /* release dmabuf strong ref from tracker */ + dma_buf_put(buf->dmabuf); + + /* put tracker instance back to pool */ + msm_vidc_pool_free(inst, buf); +} + +static void msm_vidc_dma_buf_put_completely(struct msm_vidc_inst *inst, + struct msm_memory_dmabuf *buf) +{ + if (!buf) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + while (buf->refcount) { + buf->refcount--; + if (!buf->refcount) { + /* remove dmabuf entry from tracker */ + list_del(&buf->list); + + /* release dmabuf strong ref from tracker */ + dma_buf_put(buf->dmabuf); + + /* put tracker instance back to pool */ + msm_vidc_pool_free(inst, buf); + break; + } + } +} + +static struct dma_buf_attachment *msm_vidc_dma_buf_attach(struct msm_vidc_core *core, + struct dma_buf *dbuf, struct device *dev) +{ + int rc = 0; + struct dma_buf_attachment *attach = NULL; + + if (!dbuf || !dev) { + d_vpr_e("%s: invalid params\n", __func__); + return NULL; + } + + attach = dma_buf_attach(dbuf, dev); + if (IS_ERR_OR_NULL(attach)) { + rc = PTR_ERR(attach) ? PTR_ERR(attach) : -1; + d_vpr_e("Failed to attach dmabuf, error %d\n", rc); + return NULL; + } + + return attach; +} + +static int msm_vidc_dma_buf_detach(struct msm_vidc_core *core, + struct dma_buf *dbuf, struct dma_buf_attachment *attach) +{ + int rc = 0; + + if (!dbuf || !attach) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + dma_buf_detach(dbuf, attach); + + return rc; +} + +static int msm_vidc_dma_buf_unmap_attachment(struct msm_vidc_core *core, + struct dma_buf_attachment *attach, struct sg_table *table) +{ + int rc = 0; + + if (!attach || !table) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL); + + return rc; +} + +static struct sg_table *msm_vidc_dma_buf_map_attachment( + struct msm_vidc_core *core, struct dma_buf_attachment *attach) +{ + int rc = 0; + struct sg_table *table = NULL; + + if (!attach) { + d_vpr_e("%s: invalid params\n", __func__); + return NULL; + } + + table = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); + if (IS_ERR_OR_NULL(table)) { + rc = PTR_ERR(table) ? PTR_ERR(table) : -1; + d_vpr_e("Failed to map table, error %d\n", rc); + return NULL; + } + if (!table->sgl) { + d_vpr_e("%s: sgl is NULL\n", __func__); + msm_vidc_dma_buf_unmap_attachment(core, attach, table); + return NULL; + } + + return table; +} + +static int msm_vidc_memory_alloc_map(struct msm_vidc_core *core, struct msm_vidc_mem *mem) +{ + int size = 0; + struct context_bank_info *cb = NULL; + + if (!mem) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + size = ALIGN(mem->size, SZ_4K); + mem->attrs = DMA_ATTR_WRITE_COMBINE; + + cb = msm_vidc_get_context_bank_for_region(core, mem->region); + if (!cb) { + d_vpr_e("%s: failed to get context bank device\n", __func__); + return -EIO; + } + + mem->kvaddr = dma_alloc_attrs(cb->dev, size, &mem->device_addr, GFP_KERNEL, + mem->attrs); + if (!mem->kvaddr) { + d_vpr_e("%s: dma_alloc_attrs returned NULL\n", __func__); + return -ENOMEM; + } + + d_vpr_h( + "%s: dmabuf %pK, size %d, buffer_type %s, secure %d, region %d\n", + __func__, mem->kvaddr, mem->size, buf_name(mem->type), + mem->secure, mem->region); + + return 0; +} + +static int msm_vidc_memory_unmap_free(struct msm_vidc_core *core, struct msm_vidc_mem *mem) +{ + int rc = 0; + struct context_bank_info *cb = NULL; + + if (!mem || !mem->device_addr || !mem->kvaddr) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + d_vpr_h( + "%s: dmabuf %pK, size %d, kvaddr %pK, buffer_type %s, secure %d, region %d\n", + __func__, mem->device_addr, mem->size, mem->kvaddr, + buf_name(mem->type), mem->secure, mem->region); + + cb = msm_vidc_get_context_bank_for_region(core, mem->region); + if (!cb) { + d_vpr_e("%s: failed to get context bank device\n", __func__); + return -EIO; + } + + dma_free_attrs(cb->dev, mem->size, mem->kvaddr, mem->device_addr, + mem->attrs); + + mem->kvaddr = NULL; + mem->device_addr = 0; + + return rc; +} + +static int msm_vidc_dma_map_page(struct msm_vidc_core *core, + struct msm_vidc_mem *mem) +{ + int rc = 0; + struct context_bank_info *cb = NULL; + dma_addr_t dma_addr; + + if (!mem) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (mem->refcount) { + mem->refcount++; + goto exit; + } + + cb = msm_vidc_get_context_bank_for_region(core, mem->region); + if (!cb) { + d_vpr_e("%s: Failed to get context bank device\n", + __func__); + rc = -EIO; + goto error; + } + + /* map and obtain dma address for physically contiguous memory */ + dma_addr = dma_map_page(cb->dev, phys_to_page(mem->phys_addr), + 0, (size_t)mem->size, mem->direction); + + rc = dma_mapping_error(cb->dev, dma_addr); + if (rc) { + d_vpr_e("%s: Failed to map memory\n", __func__); + goto error; + } + + mem->device_addr = dma_addr; + mem->refcount++; + +exit: + d_vpr_l( + "%s: type %11s, device_addr %#llx, size %u region %d, refcount %d\n", + __func__, buf_name(mem->type), mem->device_addr, + mem->size, mem->region, mem->refcount); + + return 0; + +error: + return rc; +} + +static int msm_vidc_dma_unmap_page(struct msm_vidc_core *core, + struct msm_vidc_mem *mem) +{ + int rc = 0; + struct context_bank_info *cb = NULL; + + if (!mem) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (mem->refcount) { + mem->refcount--; + } else { + d_vpr_e("unmap called while refcount is zero already\n"); + return -EINVAL; + } + + cb = msm_vidc_get_context_bank_for_region(core, mem->region); + if (!cb) { + d_vpr_e("%s: Failed to get context bank device\n", + __func__); + rc = -EIO; + goto exit; + } + + d_vpr_l( + "%s: type %11s, device_addr %#x, refcount %d, region %d\n", + __func__, buf_name(mem->type), mem->device_addr, + mem->refcount, mem->region); + + if (mem->refcount) + goto exit; + + dma_unmap_page(cb->dev, (dma_addr_t)(mem->device_addr), + mem->size, mem->direction); + + mem->device_addr = 0x0; + +exit: + return rc; +} + +static u32 msm_vidc_buffer_region(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + return MSM_VIDC_NON_SECURE; +} + +static int msm_vidc_iommu_map(struct msm_vidc_core *core, struct msm_vidc_mem *mem) +{ + int rc = 0; + struct context_bank_info *cb = NULL; + + if (!mem) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + cb = msm_vidc_get_context_bank_for_region(core, mem->region); + if (!cb) { + d_vpr_e("%s: failed to get context bank device for region: %d\n", + __func__, mem->region); + return -EIO; + } + + rc = iommu_map(cb->domain, mem->device_addr, mem->phys_addr, + mem->size, IOMMU_READ | IOMMU_WRITE | IOMMU_MMIO); + if (rc) { + d_vpr_e("iommu_map failed for device_addr 0x%x, size %d, rc:%d\n", + mem->device_addr, mem->size, rc); + return rc; + } + + d_vpr_h("%s: phys_addr %#x size %#x device_addr %#x, mem_region %d\n", + __func__, mem->phys_addr, mem->size, mem->device_addr, mem->region); + + return rc; +} + +static int msm_vidc_iommu_unmap(struct msm_vidc_core *core, struct msm_vidc_mem *mem) +{ + int rc = 0; + struct context_bank_info *cb = NULL; + + if (!mem) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + cb = msm_vidc_get_context_bank_for_region(core, mem->region); + if (!cb) { + d_vpr_e("%s: failed to get context bank device for region: %d\n", + __func__, mem->region); + return -EIO; + } + + d_vpr_h("%s: phys_addr %#x size %#x device_addr %#x, mem_region %d\n", + __func__, mem->phys_addr, mem->size, mem->device_addr, mem->region); + + iommu_unmap(cb->domain, mem->device_addr, mem->size); + mem->device_addr = 0x0; + mem->phys_addr = 0x0; + mem->size = 0; + + return rc; +} + +static const struct msm_vidc_memory_ops msm_mem_ops = { + .dma_buf_get = msm_vidc_dma_buf_get, + .dma_buf_put = msm_vidc_dma_buf_put, + .dma_buf_put_completely = msm_vidc_dma_buf_put_completely, + .dma_buf_attach = msm_vidc_dma_buf_attach, + .dma_buf_detach = msm_vidc_dma_buf_detach, + .dma_buf_map_attachment = msm_vidc_dma_buf_map_attachment, + .dma_buf_unmap_attachment = msm_vidc_dma_buf_unmap_attachment, + .memory_alloc_map = msm_vidc_memory_alloc_map, + .memory_unmap_free = msm_vidc_memory_unmap_free, + .mem_dma_map_page = msm_vidc_dma_map_page, + .mem_dma_unmap_page = msm_vidc_dma_unmap_page, + .buffer_region = msm_vidc_buffer_region, + .iommu_map = msm_vidc_iommu_map, + .iommu_unmap = msm_vidc_iommu_unmap, +}; + +const struct msm_vidc_memory_ops *get_mem_ops(void) +{ + return &msm_mem_ops; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_memory_ext.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_memory_ext.c new file mode 100644 index 0000000000..3eeb85d7ff --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_memory_ext.c @@ -0,0 +1,472 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "msm_vidc_core.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_events.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_memory.h" + +static bool is_non_secure_buffer(struct dma_buf *dmabuf) +{ + return mem_buf_dma_buf_exclusive_owner(dmabuf); +} + +static struct dma_buf_attachment *msm_vidc_dma_buf_attach_ext(struct msm_vidc_core *core, + struct dma_buf *dbuf, struct device *dev) +{ + int rc = 0; + struct dma_buf_attachment *attach = NULL; + struct context_bank_info *cb = NULL; + + if (!dbuf || !dev) { + d_vpr_e("%s: invalid params\n", __func__); + return NULL; + } + + cb = msm_vidc_get_context_bank_for_device(core, dev); + if (!cb) { + d_vpr_e("%s: Failed to get context bank device for %s\n", + __func__, dev_name(dev)); + return NULL; + } + + /* reject non-secure mapping request for a secure buffer(or vice versa) */ + if (cb->region == MSM_VIDC_NON_SECURE || cb->region == MSM_VIDC_NON_SECURE_PIXEL) { + if (!is_non_secure_buffer(dbuf)) { + d_vpr_e("%s: secure buffer mapping to non-secure region %d not allowed\n", + __func__, cb->region); + return NULL; + } + } else { + if (is_non_secure_buffer(dbuf)) { + d_vpr_e("%s: non-secure buffer mapping to secure region %d not allowed\n", + __func__, cb->region); + return NULL; + } + } + + attach = dma_buf_attach(dbuf, dev); + if (IS_ERR_OR_NULL(attach)) { + rc = PTR_ERR(attach) ? PTR_ERR(attach) : -1; + d_vpr_e("Failed to attach dmabuf, error %d\n", rc); + return NULL;; + } + + /* + * We do not need dma_map function to perform cache operations + * on the whole buffer size and hence pass skip sync flag. + */ + attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC; + /* + * Get the scatterlist for the given attachment + * Mapping of sg is taken care by map attachment + */ + attach->dma_map_attrs |= DMA_ATTR_DELAYED_UNMAP; + if (is_sys_cache_present(core)) + attach->dma_map_attrs |= DMA_ATTR_IOMMU_USE_UPSTREAM_HINT; + + return attach; +} + +static int msm_vidc_memory_free_ext(struct msm_vidc_core *core, struct msm_vidc_mem *mem) +{ + int rc = 0; + + if (!mem || !mem->dmabuf) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + d_vpr_h( + "%s: dmabuf %pK, size %d, kvaddr %pK, buffer_type %s, secure %d, region %d\n", + __func__, mem->dmabuf, mem->size, mem->kvaddr, buf_name(mem->type), + mem->secure, mem->region); + + trace_msm_vidc_dma_buffer("FREE", mem->dmabuf, mem->size, mem->kvaddr, + buf_name(mem->type), mem->secure, mem->region); + + if (mem->kvaddr) { +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) + dma_buf_vunmap(mem->dmabuf, mem->kvaddr); +#else + dma_buf_vunmap(mem->dmabuf, &mem->dmabuf_map); +#endif + mem->kvaddr = NULL; + dma_buf_end_cpu_access(mem->dmabuf, DMA_BIDIRECTIONAL); + } + + if (mem->dmabuf) { + dma_heap_buffer_free(mem->dmabuf); + mem->dmabuf = NULL; + } + + return rc; +} + +static int msm_vidc_memory_alloc_ext(struct msm_vidc_core *core, struct msm_vidc_mem *mem) +{ + int rc = 0; + int size = 0; + struct dma_heap *heap; + char *heap_name = NULL; + struct mem_buf_lend_kernel_arg lend_arg; + int vmids[1]; + int perms[1]; + + if (!mem) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + size = ALIGN(mem->size, SZ_4K); + + if (mem->secure) { + switch (mem->region) { + case MSM_VIDC_SECURE_PIXEL: + heap_name = "qcom,secure-pixel"; + break; + case MSM_VIDC_SECURE_NONPIXEL: + heap_name = "qcom,secure-non-pixel"; + break; + case MSM_VIDC_SECURE_BITSTREAM: + heap_name = "qcom,system"; + break; + default: + d_vpr_e("invalid secure region : %#x\n", mem->region); + return -EINVAL; + } + } else { + heap_name = "qcom,system"; + } + + heap = dma_heap_find(heap_name); + if (IS_ERR_OR_NULL(heap)) { + d_vpr_e("%s: dma heap %s find failed\n", __func__, heap_name); + heap = NULL; + rc = -ENOMEM; + goto error; + } + mem->dmabuf = dma_heap_buffer_alloc(heap, size, 0, 0); + if (IS_ERR_OR_NULL(mem->dmabuf)) { + d_vpr_e("%s: dma heap %s alloc failed\n", __func__, heap_name); + mem->dmabuf = NULL; + rc = -ENOMEM; + goto error; + } + + if (mem->secure && mem->type == MSM_VIDC_BUF_BIN) { + vmids[0] = VMID_CP_BITSTREAM; + perms[0] = PERM_READ | PERM_WRITE; + + lend_arg.nr_acl_entries = ARRAY_SIZE(vmids); + lend_arg.vmids = vmids; + lend_arg.perms = perms; + + rc = mem_buf_lend(mem->dmabuf, &lend_arg); + if (rc) { + d_vpr_e("%s: BIN dmabuf %pK LEND failed, rc %d heap %s\n", + __func__, mem->dmabuf, rc, heap_name); + goto error; + } + } + + if (mem->map_kernel) { + dma_buf_begin_cpu_access(mem->dmabuf, DMA_BIDIRECTIONAL); + + /* + * Waipio uses Kernel version 5.10.x, + * Kalama uses Kernel Version 5.15.x, + * Pineapple uses Kernel Version 5.18.x + */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) + mem->kvaddr = dma_buf_vmap(mem->dmabuf); + if (!mem->kvaddr) { + d_vpr_e("%s: kernel map failed\n", __func__); + rc = -EIO; + goto error; + } +#elif (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)) + rc = dma_buf_vmap(mem->dmabuf, &mem->dmabuf_map); + if (rc) { + d_vpr_e("%s: kernel map failed\n", __func__); + rc = -EIO; + goto error; + } + mem->kvaddr = mem->dmabuf_map.vaddr; +#else + rc = dma_buf_vmap(mem->dmabuf, &mem->dmabuf_map); + if (rc) { + d_vpr_e("%s: kernel map failed\n", __func__); + rc = -EIO; + goto error; + } + mem->kvaddr = mem->dmabuf_map.vaddr; +#endif + } + + d_vpr_h( + "%s: dmabuf %pK, size %d, kvaddr %pK, buffer_type %s, secure %d, region %d\n", + __func__, mem->dmabuf, mem->size, mem->kvaddr, buf_name(mem->type), + mem->secure, mem->region); + trace_msm_vidc_dma_buffer("ALLOC", mem->dmabuf, mem->size, mem->kvaddr, + buf_name(mem->type), mem->secure, mem->region); + + return 0; + +error: + msm_vidc_memory_free_ext(core, mem); + return rc; +} + +static int msm_vidc_memory_map_ext(struct msm_vidc_core *core, struct msm_vidc_mem *mem) +{ + int rc = 0; + struct dma_buf_attachment *attach = NULL; + struct sg_table *table = NULL; + struct context_bank_info *cb = NULL; + + if (!mem) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (mem->refcount) { + mem->refcount++; + goto exit; + } + + /* reject non-secure mapping request for a secure buffer(or vice versa) */ + if (mem->region == MSM_VIDC_NON_SECURE || mem->region == MSM_VIDC_NON_SECURE_PIXEL) { + if (!is_non_secure_buffer(mem->dmabuf)) { + d_vpr_e("%s: secure buffer mapping to non-secure region %d not allowed\n", + __func__, mem->region); + return -EINVAL; + } + } else { + if (is_non_secure_buffer(mem->dmabuf)) { + d_vpr_e("%s: non-secure buffer mapping to secure region %d not allowed\n", + __func__, mem->region); + return -EINVAL; + } + } + + cb = msm_vidc_get_context_bank_for_region(core, mem->region); + if (!cb || !cb->dev) { + d_vpr_e("%s: Failed to get context bank device\n", + __func__); + rc = -EIO; + goto error_cb; + } + + /* Prepare a dma buf for dma on the given device */ + attach = msm_vidc_dma_buf_attach_ext(core, mem->dmabuf, cb->dev); + if (IS_ERR_OR_NULL(attach)) { + rc = PTR_ERR(attach) ? PTR_ERR(attach) : -ENOMEM; + d_vpr_e("Failed to attach dmabuf\n"); + goto error_attach; + } + + table = call_mem_op(core, dma_buf_map_attachment, core, attach); + if (IS_ERR_OR_NULL(table)) { + rc = PTR_ERR(table) ? PTR_ERR(table) : -ENOMEM; + d_vpr_e("Failed to map table\n"); + goto error_table; + } + + mem->device_addr = sg_dma_address(table->sgl); + mem->table = table; + mem->attach = attach; + mem->refcount++; + +exit: + d_vpr_l("%s: type %11s, device_addr %#llx, refcount %d, region %d\n", + __func__, buf_name(mem->type), mem->device_addr, mem->refcount, mem->region); + + return 0; + +error_table: + call_mem_op(core, dma_buf_detach, core, mem->dmabuf, attach); +error_attach: +error_cb: + return rc; +} + +static int msm_vidc_memory_unmap_ext(struct msm_vidc_core *core, + struct msm_vidc_mem *mem) +{ + int rc = 0; + + if (!mem) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (mem->refcount) { + mem->refcount--; + } else { + d_vpr_e("unmap called while refcount is zero already\n"); + return -EINVAL; + } + + d_vpr_l( + "%s: type %11s, device_addr %#llx, refcount %d, region %d\n", + __func__, buf_name(mem->type), mem->device_addr, mem->refcount, mem->region); + + if (mem->refcount) + goto exit; + + call_mem_op(core, dma_buf_unmap_attachment, core, mem->attach, mem->table); + call_mem_op(core, dma_buf_detach, core, mem->dmabuf, mem->attach); + + mem->device_addr = 0x0; + mem->attach = NULL; + mem->table = NULL; + +exit: + return rc; +} + +static u32 msm_vidc_buffer_region_ext(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type buffer_type) +{ + u32 region = MSM_VIDC_NON_SECURE; + + if (!is_secure_session(inst)) { + switch (buffer_type) { + case MSM_VIDC_BUF_ARP: + region = MSM_VIDC_NON_SECURE; + break; + case MSM_VIDC_BUF_INPUT: + if (is_encode_session(inst)) + region = MSM_VIDC_NON_SECURE_PIXEL; + else + region = MSM_VIDC_NON_SECURE; + break; + case MSM_VIDC_BUF_OUTPUT: + if (is_encode_session(inst)) + region = MSM_VIDC_NON_SECURE; + else + region = MSM_VIDC_NON_SECURE_PIXEL; + break; + case MSM_VIDC_BUF_DPB: + case MSM_VIDC_BUF_VPSS: + case MSM_VIDC_BUF_PARTIAL_DATA: + region = MSM_VIDC_NON_SECURE_PIXEL; + break; + case MSM_VIDC_BUF_INPUT_META: + case MSM_VIDC_BUF_OUTPUT_META: + case MSM_VIDC_BUF_BIN: + case MSM_VIDC_BUF_COMV: + case MSM_VIDC_BUF_NON_COMV: + case MSM_VIDC_BUF_LINE: + case MSM_VIDC_BUF_PERSIST: + region = MSM_VIDC_NON_SECURE; + break; + default: + i_vpr_e(inst, "%s: invalid driver buffer type %d\n", + __func__, buffer_type); + } + } else { + switch (buffer_type) { + case MSM_VIDC_BUF_INPUT: + if (is_encode_session(inst)) + region = MSM_VIDC_SECURE_PIXEL; + else + region = MSM_VIDC_SECURE_BITSTREAM; + break; + case MSM_VIDC_BUF_OUTPUT: + if (is_encode_session(inst)) + region = MSM_VIDC_SECURE_BITSTREAM; + else + region = MSM_VIDC_SECURE_PIXEL; + break; + case MSM_VIDC_BUF_INPUT_META: + case MSM_VIDC_BUF_OUTPUT_META: + region = MSM_VIDC_NON_SECURE; + break; + case MSM_VIDC_BUF_DPB: + case MSM_VIDC_BUF_VPSS: + case MSM_VIDC_BUF_PARTIAL_DATA: + region = MSM_VIDC_SECURE_PIXEL; + break; + case MSM_VIDC_BUF_BIN: + region = MSM_VIDC_SECURE_BITSTREAM; + break; + case MSM_VIDC_BUF_ARP: + case MSM_VIDC_BUF_COMV: + case MSM_VIDC_BUF_NON_COMV: + case MSM_VIDC_BUF_LINE: + case MSM_VIDC_BUF_PERSIST: + region = MSM_VIDC_SECURE_NONPIXEL; + break; + default: + i_vpr_e(inst, "%s: invalid driver buffer type %d\n", + __func__, buffer_type); + } + } + + return region; +} + +static int msm_vidc_memory_alloc_map_ext(struct msm_vidc_core *core, struct msm_vidc_mem *mem) +{ + int rc = 0; + + rc = msm_vidc_memory_alloc_ext(core, mem); + if (rc) { + d_vpr_e("%s: memory_alloc failed\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_memory_map_ext(core, mem); + if (rc) { + d_vpr_e("%s: memory_map failed\n", __func__); + return -EINVAL; + } + + return rc; +} + +static int msm_vidc_memory_unmap_free_ext(struct msm_vidc_core *core, struct msm_vidc_mem *mem) +{ + int rc = 0; + + rc = msm_vidc_memory_unmap_ext(core, mem); + if (rc) { + d_vpr_e("%s: memory_unmap failed\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_memory_free_ext(core, mem); + if (rc) { + d_vpr_e("%s: memory_free failed\n", __func__); + return -EINVAL; + } + + return rc; +} + +const struct msm_vidc_memory_ops *get_mem_ops_ext(void) +{ + const struct msm_vidc_memory_ops *mem_ops = get_mem_ops(); + static struct msm_vidc_memory_ops mem_ops_ext; + + memcpy(&mem_ops_ext, mem_ops, sizeof(struct msm_vidc_memory_ops)); + mem_ops_ext.dma_buf_attach = msm_vidc_dma_buf_attach_ext; + mem_ops_ext.memory_alloc_map = msm_vidc_memory_alloc_map_ext; + mem_ops_ext.memory_unmap_free = msm_vidc_memory_unmap_free_ext; + mem_ops_ext.buffer_region = msm_vidc_buffer_region_ext; + + return &mem_ops_ext; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_power.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_power.c new file mode 100644 index 0000000000..938828de78 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_power.c @@ -0,0 +1,660 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_power.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_core.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_buffer.h" +#include "venus_hfi.h" +#include "msm_vidc_events.h" + +/* Q16 Format */ +#define MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR (1 << 16) +#define MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR (4 << 16) +#define MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO (1 << 16) +#define MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO (5 << 16) +#define PASSIVE_VOTE 1000 + +/** + * Utility function to enforce some of our assumptions. Spam calls to this + * in hotspots in code to double check some of the assumptions that we hold. + */ +struct lut const *__lut(int width, int height, int fps) +{ + int frame_size = height * width, c = 0; + + do { + if (LUT[c].frame_size >= frame_size && LUT[c].frame_rate >= fps) + return &LUT[c]; + } while (++c < ARRAY_SIZE(LUT)); + + return &LUT[ARRAY_SIZE(LUT) - 1]; +} + +fp_t __compression_ratio(struct lut const *entry, int bpp) +{ + int c = 0; + + for (c = 0; c < COMPRESSION_RATIO_MAX; ++c) { + if (entry->compression_ratio[c].bpp == bpp) + return entry->compression_ratio[c].ratio; + } + + WARN(true, "Shouldn't be here, LUT possibly corrupted?\n"); + return FP_ZERO; /* impossible */ +} + + +void __dump(struct dump dump[], int len) +{ + int c = 0; + + for (c = 0; c < len; ++c) { + char format_line[128] = "", formatted_line[128] = ""; + + if (dump[c].val == DUMP_HEADER_MAGIC) { + snprintf(formatted_line, sizeof(formatted_line), "%s\n", + dump[c].key); + } else { + bool fp_format = !strcmp(dump[c].format, DUMP_FP_FMT); + + if (!fp_format) { + snprintf(format_line, sizeof(format_line), + " %-35s: %s\n", dump[c].key, + dump[c].format); + snprintf(formatted_line, sizeof(formatted_line), + format_line, dump[c].val); + } else { + size_t integer_part, fractional_part; + + integer_part = fp_int(dump[c].val); + fractional_part = fp_frac(dump[c].val); + snprintf(formatted_line, sizeof(formatted_line), + " %-35s: %zd + %zd/%zd\n", + dump[c].key, integer_part, + fractional_part, + fp_frac_base()); + + + } + } + d_vpr_b("%s", formatted_line); + } +} + +u64 msm_vidc_max_freq(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + struct frequency_table *freq_tbl; + u64 freq = 0; + + core = inst->core; + + if (!core->resource || !core->resource->freq_set.freq_tbl || + !core->resource->freq_set.count) { + i_vpr_e(inst, "%s: invalid frequency table\n", __func__); + return freq; + } + freq_tbl = core->resource->freq_set.freq_tbl; + freq = freq_tbl[0].freq; + + i_vpr_l(inst, "%s: rate = %llu\n", __func__, freq); + return freq; +} + +static int fill_dynamic_stats(struct msm_vidc_inst *inst, + struct vidc_bus_vote_data *vote_data) +{ + struct msm_vidc_input_cr_data *temp, *next; + u32 cf = MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR; + u32 cr = MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO; + u32 input_cr = MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO; + u32 frame_size; + + if (inst->power.fw_cr) + cr = inst->power.fw_cr; + + if (inst->power.fw_cf) { + cf = inst->power.fw_cf; + frame_size = (msm_vidc_get_mbs_per_frame(inst) / (32 * 8) * 3) / 2; + if (frame_size) + cf = cf / frame_size; + } + + list_for_each_entry_safe(temp, next, &inst->enc_input_crs, list) + input_cr = min(input_cr, temp->input_cr); + + vote_data->compression_ratio = cr; + vote_data->complexity_factor = cf; + vote_data->input_cr = input_cr; + + /* Sanitize CF values from HW */ + cf = clamp_t(u32, cf, MSM_VIDC_MIN_UBWC_COMPLEXITY_FACTOR, + MSM_VIDC_MAX_UBWC_COMPLEXITY_FACTOR); + cr = clamp_t(u32, cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO, + MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO); + input_cr = clamp_t(u32, input_cr, MSM_VIDC_MIN_UBWC_COMPRESSION_RATIO, + MSM_VIDC_MAX_UBWC_COMPRESSION_RATIO); + + vote_data->compression_ratio = cr; + vote_data->complexity_factor = cf; + vote_data->input_cr = input_cr; + + i_vpr_l(inst, + "Input CR = %d Recon CR = %d Complexity Factor = %d\n", + vote_data->input_cr, vote_data->compression_ratio, + vote_data->complexity_factor); + + return 0; +} + +static int msm_vidc_set_buses(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + struct msm_vidc_inst *temp; + u64 total_bw_ddr = 0, total_bw_llcc = 0; + u64 curr_time_ns; + + core = inst->core; + + mutex_lock(&core->lock); + curr_time_ns = ktime_get_ns(); + list_for_each_entry(temp, &core->instances, list) { + /* skip for session where no input is there to process */ + if (!temp->max_input_data_size) + continue; + + /* skip inactive session bus bandwidth */ + if (!is_active_session(temp->last_qbuf_time_ns, curr_time_ns)) { + temp->active = false; + continue; + } + + if (temp->power.power_mode == VIDC_POWER_TURBO) { + total_bw_ddr = total_bw_llcc = INT_MAX; + break; + } + + total_bw_ddr += temp->power.ddr_bw; + total_bw_llcc += temp->power.sys_cache_bw; + } + mutex_unlock(&core->lock); + + /* Incase of no video frames to process ensure min passive voting for Tensilica */ + if (!total_bw_ddr) + total_bw_ddr = PASSIVE_VOTE; + + if (msm_vidc_ddr_bw) { + d_vpr_l("msm_vidc_ddr_bw %d\n", msm_vidc_ddr_bw); + total_bw_ddr = msm_vidc_ddr_bw; + } + + if (msm_vidc_llc_bw) { + d_vpr_l("msm_vidc_llc_bw %d\n", msm_vidc_llc_bw); + total_bw_llcc = msm_vidc_llc_bw; + } + + rc = venus_hfi_scale_buses(inst, total_bw_ddr, total_bw_llcc); + if (rc) + return rc; + + return 0; +} + +int msm_vidc_scale_buses(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + struct vidc_bus_vote_data *vote_data; + struct v4l2_format *out_f; + struct v4l2_format *inp_f; + u32 operating_rate, frame_rate; + + core = inst->core; + if (!core->resource) { + i_vpr_e(inst, "%s: invalid resource params\n", __func__); + return -EINVAL; + } + vote_data = &inst->bus_data; + + vote_data->power_mode = VIDC_POWER_NORMAL; + if (inst->power.buffer_counter < DCVS_WINDOW || is_image_session(inst)) + vote_data->power_mode = VIDC_POWER_TURBO; + + if (vote_data->power_mode == VIDC_POWER_TURBO) + goto set_buses; + + out_f = &inst->fmts[OUTPUT_PORT]; + inp_f = &inst->fmts[INPUT_PORT]; + + vote_data->codec = inst->codec; + vote_data->input_width = inp_f->fmt.pix_mp.width; + vote_data->input_height = inp_f->fmt.pix_mp.height; + vote_data->output_width = out_f->fmt.pix_mp.width; + vote_data->output_height = out_f->fmt.pix_mp.height; + vote_data->lcu_size = (inst->codec == MSM_VIDC_HEVC || + inst->codec == MSM_VIDC_VP9) ? 32 : 16; + if (inst->codec == MSM_VIDC_AV1) + vote_data->lcu_size = + inst->capabilities[SUPER_BLOCK].value ? 128 : 64; + vote_data->fps = inst->max_rate; + + if (is_encode_session(inst)) { + vote_data->domain = MSM_VIDC_ENCODER; + vote_data->bitrate = inst->capabilities[BIT_RATE].value; + vote_data->rotation = inst->capabilities[ROTATION].value; + vote_data->b_frames_enabled = + inst->capabilities[B_FRAME].value > 0; + + /* scale bitrate if operating rate is larger than frame rate */ + frame_rate = msm_vidc_get_frame_rate(inst); + operating_rate = inst->max_rate; + if (frame_rate && operating_rate && operating_rate > frame_rate) + vote_data->bitrate = (vote_data->bitrate / frame_rate) * operating_rate; + + vote_data->num_formats = 1; + vote_data->color_formats[0] = v4l2_colorformat_to_driver(inst, + inst->fmts[INPUT_PORT].fmt.pix_mp.pixelformat, __func__); + vote_data->vpss_preprocessing_enabled = + inst->capabilities[REQUEST_PREPROCESS].value; + } else if (is_decode_session(inst)) { + u32 color_format; + + vote_data->domain = MSM_VIDC_DECODER; + vote_data->bitrate = inst->max_input_data_size * vote_data->fps * 8; + color_format = v4l2_colorformat_to_driver(inst, + inst->fmts[OUTPUT_PORT].fmt.pix_mp.pixelformat, __func__); + if (is_linear_colorformat(color_format)) { + vote_data->num_formats = 2; + /* + * 0 index - dpb colorformat + * 1 index - opb colorformat + */ + if (is_10bit_colorformat(color_format)) + vote_data->color_formats[0] = MSM_VIDC_FMT_TP10C; + else + vote_data->color_formats[0] = MSM_VIDC_FMT_NV12; + + vote_data->color_formats[1] = color_format; + } else if (inst->codec == MSM_VIDC_AV1 && + inst->capabilities[FILM_GRAIN].value) { + /* + * UBWC formats with AV1 film grain requires dpb-opb + * split mode + */ + vote_data->num_formats = 2; + vote_data->color_formats[0] = + vote_data->color_formats[1] = color_format; + } else { + vote_data->num_formats = 1; + vote_data->color_formats[0] = color_format; + } + } + vote_data->work_mode = inst->capabilities[STAGE].value; + if (core->resource->subcache_set.set_to_fw) + vote_data->use_sys_cache = true; + vote_data->num_vpp_pipes = core->capabilities[NUM_VPP_PIPE].value; + fill_dynamic_stats(inst, vote_data); + + call_session_op(core, calc_bw, inst, vote_data); + + inst->power.ddr_bw = vote_data->calc_bw_ddr; + inst->power.sys_cache_bw = vote_data->calc_bw_llcc; + + if (!inst->stats.avg_bw_llcc) + inst->stats.avg_bw_llcc = inst->power.sys_cache_bw; + else + inst->stats.avg_bw_llcc = + (inst->stats.avg_bw_llcc + inst->power.sys_cache_bw) / 2; + + if (!inst->stats.avg_bw_ddr) + inst->stats.avg_bw_ddr = inst->power.ddr_bw; + else + inst->stats.avg_bw_ddr = + (inst->stats.avg_bw_ddr + inst->power.ddr_bw) / 2; + +set_buses: + inst->power.power_mode = vote_data->power_mode; + rc = msm_vidc_set_buses(inst); + if (rc) + return rc; + + return 0; +} + +int msm_vidc_set_clocks(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + struct msm_vidc_inst *temp; + u64 freq; + u64 rate = 0; + bool increment, decrement; + u64 curr_time_ns; + int i = 0; + + core = inst->core; + + if (!core->resource || !core->resource->freq_set.freq_tbl || + !core->resource->freq_set.count) { + d_vpr_e("%s: invalid frequency table\n", __func__); + return -EINVAL; + } + + mutex_lock(&core->lock); + increment = false; + decrement = true; + freq = 0; + curr_time_ns = ktime_get_ns(); + list_for_each_entry(temp, &core->instances, list) { + /* skip for session where no input is there to process */ + if (!temp->max_input_data_size) + continue; + + /* skip inactive session clock rate */ + if (!is_active_session(temp->last_qbuf_time_ns, curr_time_ns)) { + temp->active = false; + continue; + } + freq += temp->power.min_freq; + + if (msm_vidc_clock_voting) { + d_vpr_l("msm_vidc_clock_voting %d\n", msm_vidc_clock_voting); + freq = msm_vidc_clock_voting; + decrement = false; + break; + } + /* increment even if one session requested for it */ + if (temp->power.dcvs_flags & MSM_VIDC_DCVS_INCR) + increment = true; + /* decrement only if all sessions requested for it */ + if (!(temp->power.dcvs_flags & MSM_VIDC_DCVS_DECR)) + decrement = false; + } + + /* + * keep checking from lowest to highest rate until + * table rate >= requested rate + */ + for (i = core->resource->freq_set.count - 1; i >= 0; i--) { + rate = core->resource->freq_set.freq_tbl[i].freq; + if (rate >= freq) + break; + } + if (i < 0) + i = 0; + if (increment) { + if (i > 0) + rate = core->resource->freq_set.freq_tbl[i - 1].freq; + } else if (decrement) { + if (i < (int)(core->platform->data.freq_tbl_size - 1)) + rate = core->resource->freq_set.freq_tbl[i + 1].freq; + } + core->power.clk_freq = (u32)rate; + + i_vpr_p(inst, "%s: clock rate %llu requested %llu increment %d decrement %d\n", + __func__, rate, freq, increment, decrement); + mutex_unlock(&core->lock); + + rc = venus_hfi_scale_clocks(inst, rate); + if (rc) + return rc; + + return 0; +} + +static int msm_vidc_apply_dcvs(struct msm_vidc_inst *inst) +{ + int rc = 0; + int bufs_with_fw = 0; + struct msm_vidc_power *power; + + /* skip dcvs */ + if (!inst->power.dcvs_mode) + return 0; + + power = &inst->power; + + if (is_decode_session(inst)) { + bufs_with_fw = msm_vidc_num_buffers(inst, + MSM_VIDC_BUF_OUTPUT, MSM_VIDC_ATTR_QUEUED); + } else { + bufs_with_fw = msm_vidc_num_buffers(inst, + MSM_VIDC_BUF_INPUT, MSM_VIDC_ATTR_QUEUED); + } + + /* +1 as one buffer is going to be queued after the function */ + bufs_with_fw += 1; + + /* + * DCVS decides clock level based on below algorithm + * + * Limits : + * min_threshold : Buffers required for reference by FW. + * nom_threshold : Midpoint of Min and Max thresholds + * max_threshold : Min Threshold + DCVS extra buffers, allocated + * for smooth flow. + * 1) When buffers outside FW are reaching client's extra buffers, + * FW is slow and will impact pipeline, Increase clock. + * 2) When pending buffers with FW are less than FW requested, + * pipeline has cushion to absorb FW slowness, Decrease clocks. + * 3) When DCVS has engaged(Inc or Dec): + * For decode: + * - Pending buffers with FW transitions past the nom_threshold, + * switch to calculated load, this smoothens the clock transitions. + * For encode: + * - Always switch to calculated load. + * 4) Otherwise maintain previous Load config. + */ + if (bufs_with_fw >= power->max_threshold) { + power->dcvs_flags = MSM_VIDC_DCVS_INCR; + goto exit; + } else if (bufs_with_fw < power->min_threshold) { + power->dcvs_flags = MSM_VIDC_DCVS_DECR; + goto exit; + } + + /* encoder: dcvs window handling */ + if (is_encode_session(inst)) { + power->dcvs_flags = 0; + goto exit; + } + + /* decoder: dcvs window handling */ + if ((power->dcvs_flags & MSM_VIDC_DCVS_DECR && bufs_with_fw >= power->nom_threshold) || + (power->dcvs_flags & MSM_VIDC_DCVS_INCR && bufs_with_fw <= power->nom_threshold)) { + power->dcvs_flags = 0; + } + +exit: + i_vpr_p(inst, "dcvs: bufs_with_fw %d th[%d %d %d] flags %#x\n", + bufs_with_fw, power->min_threshold, + power->nom_threshold, power->max_threshold, + power->dcvs_flags); + + return rc; +} + +int msm_vidc_scale_clocks(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + + core = inst->core; + + if (inst->power.buffer_counter < DCVS_WINDOW || + is_image_session(inst) || + is_sub_state(inst, MSM_VIDC_DRC) || + is_sub_state(inst, MSM_VIDC_DRAIN)) { + inst->power.min_freq = msm_vidc_max_freq(inst); + inst->power.dcvs_flags = 0; + } else if (msm_vidc_clock_voting) { + inst->power.min_freq = msm_vidc_clock_voting; + inst->power.dcvs_flags = 0; + } else { + inst->power.min_freq = + call_session_op(core, calc_freq, inst, inst->max_input_data_size); + msm_vidc_apply_dcvs(inst); + } + inst->power.curr_freq = inst->power.min_freq; + msm_vidc_set_clocks(inst); + + return 0; +} + +int msm_vidc_scale_power(struct msm_vidc_inst *inst, bool scale_buses) +{ + struct msm_vidc_core *core; + struct msm_vidc_buffer *vbuf; + u32 data_size = 0; + u32 cnt = 0; + u32 fps; + u32 frame_rate, operating_rate; + u32 timestamp_rate = 0, input_rate = 0; + + core = inst->core; + + if (!inst->active) { + /* scale buses for inactive -> active session */ + scale_buses = true; + inst->active = true; + } + + /* + * consider avg. filled length in decode batching case + * to avoid overvoting for the entire batch due to single + * frame with huge filled length + */ + if (inst->decode_batch.enable) { + list_for_each_entry(vbuf, &inst->buffers.input.list, list) { + if (vbuf->attr & MSM_VIDC_ATTR_DEFERRED || + vbuf->attr & MSM_VIDC_ATTR_QUEUED) { + data_size += vbuf->data_size; + cnt++; + } + } + if (cnt) + data_size /= cnt; + } else { + list_for_each_entry(vbuf, &inst->buffers.input.list, list) + data_size = max(data_size, vbuf->data_size); + } + inst->max_input_data_size = data_size; + + frame_rate = msm_vidc_get_frame_rate(inst); + operating_rate = msm_vidc_get_operating_rate(inst); + fps = max(frame_rate, operating_rate); + /* + * Consider input queuing rate power scaling in below scenarios + * decoder: non-realtime and realtime as well because client + * may not set the frame rate / operating rate and + * we need to rely on input queue rate + * encoder: non-realtime only, for realtime client is expected to + * queue input buffers at the set frame rate / operating rate + */ + if (is_decode_session(inst) || + (is_encode_session(inst) && !is_realtime_session(inst))) { + /* + * when buffer detected fps is more than client set value by 12.5%, + * utilize buffer detected fps to scale clock. + */ + timestamp_rate = msm_vidc_get_timestamp_rate(inst); + input_rate = msm_vidc_get_input_rate(inst); + if (timestamp_rate > (fps + fps / 8)) + fps = timestamp_rate; + + if (input_rate > fps) { + fps = input_rate; + /* + * add 6.25% more fps for NRT session to increase power to make + * firmware processing little faster than client queuing rate + */ + if (!is_realtime_session(inst)) + fps = fps + fps / 16; + } + } + inst->max_rate = fps; + + /* no pending inputs - skip scale power */ + if (!inst->max_input_data_size) + return 0; + + if (msm_vidc_scale_clocks(inst)) + i_vpr_e(inst, "failed to scale clock\n"); + + if (scale_buses) { + if (msm_vidc_scale_buses(inst)) + i_vpr_e(inst, "failed to scale bus\n"); + } + + i_vpr_hp(inst, + "power: inst: clk %lld ddr %d llcc %d dcvs flags %#x fps %u (%u %u %u %u) core: clk %lld ddr %lld llcc %lld\n", + inst->power.curr_freq, inst->power.ddr_bw, + inst->power.sys_cache_bw, inst->power.dcvs_flags, + inst->max_rate, frame_rate, operating_rate, timestamp_rate, + input_rate, core->power.clk_freq, core->power.bw_ddr, + core->power.bw_llcc); + + trace_msm_vidc_perf_power_scale(inst, core->power.clk_freq, + core->power.bw_ddr, core->power.bw_llcc); + + return 0; +} + +void msm_vidc_dcvs_data_reset(struct msm_vidc_inst *inst) +{ + struct msm_vidc_power *dcvs; + u32 min_count, actual_count, max_count; + + dcvs = &inst->power; + if (is_encode_session(inst)) { + min_count = inst->buffers.input.min_count; + actual_count = inst->buffers.input.actual_count; + max_count = min((min_count + DCVS_ENC_EXTRA_INPUT_BUFFERS), actual_count); + } else if (is_decode_session(inst)) { + min_count = inst->buffers.output.min_count; + actual_count = inst->buffers.output.actual_count; + max_count = min((min_count + DCVS_DEC_EXTRA_OUTPUT_BUFFERS), actual_count); + } else { + i_vpr_e(inst, "%s: invalid domain type %d\n", + __func__, inst->domain); + return; + } + + dcvs->min_threshold = min_count; + dcvs->max_threshold = max_count; + dcvs->dcvs_window = min_count < max_count ? max_count - min_count : 0; + dcvs->nom_threshold = dcvs->min_threshold + (dcvs->dcvs_window / 2); + dcvs->dcvs_flags = 0; + + i_vpr_p(inst, "%s: dcvs: thresholds [%d %d %d] flags %#x\n", + __func__, dcvs->min_threshold, + dcvs->nom_threshold, dcvs->max_threshold, + dcvs->dcvs_flags); +} + +void msm_vidc_power_data_reset(struct msm_vidc_inst *inst) +{ + int rc = 0; + + i_vpr_hp(inst, "%s\n", __func__); + + msm_vidc_dcvs_data_reset(inst); + + inst->power.buffer_counter = 0; + inst->power.fw_cr = 0; + inst->power.fw_cf = INT_MAX; + inst->power.fw_av1_tile_rows = 1; + inst->power.fw_av1_tile_columns = 1; + + rc = msm_vidc_scale_power(inst, true); + if (rc) + i_vpr_e(inst, "%s: failed to scale power\n", __func__); +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_probe.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_probe.c new file mode 100644 index 0000000000..a3577e7ab7 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_probe.c @@ -0,0 +1,1028 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2022, The Linux Foundation. All rights reserved. + * Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)) +#include +#endif +#ifdef CONFIG_MSM_MMRM +#include +#endif + +#include "msm_vidc_internal.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_state.h" +#include "msm_vidc_fence.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_core.h" +#include "msm_vidc_memory.h" +#include "venus_hfi.h" + +#define BASE_DEVICE_NUMBER 32 + +struct msm_vidc_core *g_core; + +const char video_banner[] = "Video-Banner: (" __stringify(VIDEO_COMPILE_BY) "@" + __stringify(VIDEO_COMPILE_HOST) ") (" __stringify(VIDEO_COMPILE_TIME) ")"; + +static inline bool is_video_device(struct device *dev) +{ + return !!(of_device_is_compatible(dev->of_node, "qcom,sm8450-vidc") || + of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc") || + of_device_is_compatible(dev->of_node, "qcom,sm8550-vidc-v2") || + of_device_is_compatible(dev->of_node, "qcom,sm8650-vidc") || + of_device_is_compatible(dev->of_node, "qcom,sm8650-vidc-v2") || + of_device_is_compatible(dev->of_node, "qcom,cliffs-vidc") || + of_device_is_compatible(dev->of_node, "qcom,volcano-vidc")); +} + +static inline bool is_video_context_bank_device_node(struct device_node *of_node) +{ + return !!(of_device_is_compatible(of_node, "qcom,vidc,cb-sec-pxl") || + of_device_is_compatible(of_node, "qcom,vidc,cb-sec-bitstream") || + of_device_is_compatible(of_node, "qcom,vidc,cb-sec-non-pxl") || + of_device_is_compatible(of_node, "qcom,vidc,cb-ns") || + of_device_is_compatible(of_node, "qcom,vidc,cb-ns-pxl")); +} + +static inline bool is_video_context_bank_device(struct device *dev) +{ + return is_video_context_bank_device_node(dev->of_node); +} + +static int msm_vidc_init_resources(struct msm_vidc_core *core) +{ + struct msm_vidc_resource *res = NULL; + int rc = 0; + + res = devm_kzalloc(&core->pdev->dev, sizeof(*res), GFP_KERNEL); + if (!res) { + d_vpr_e("%s: failed to alloc memory for resource\n", __func__); + return -ENOMEM; + } + core->resource = res; + + rc = call_res_op(core, init, core); + if (rc) { + d_vpr_e("%s: Failed to init resources: %d\n", __func__, rc); + return rc; + } + + return 0; +} + +static ssize_t sku_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct msm_vidc_core *core; + + /* + * Default sku version: 0 + * driver possibly not probed yet or not the main device. + */ + if (!dev || !dev->driver) + return 0; + + core = dev_get_drvdata(dev); + if (!core || !core->platform) { + d_vpr_e("%s: invalid core\n", __func__); + return 0; + } + + return scnprintf(buf, PAGE_SIZE, "%d", + core->platform->data.sku_version); +} + +static DEVICE_ATTR_RO(sku_version); + +static struct attribute *msm_vidc_core_attrs[] = { + &dev_attr_sku_version.attr, + NULL +}; + +static struct attribute_group msm_vidc_core_attr_group = { + .attrs = msm_vidc_core_attrs, +}; + +static const struct of_device_id msm_vidc_dt_match[] = { + {.compatible = "qcom,sm8450-vidc"}, + {.compatible = "qcom,sm8550-vidc"}, + {.compatible = "qcom,sm8550-vidc-v2"}, + {.compatible = "qcom,sm8650-vidc"}, + {.compatible = "qcom,sm8650-vidc-v2"}, + {.compatible = "qcom,cliffs-vidc"}, + {.compatible = "qcom,volcano-vidc"}, + {.compatible = "qcom,vidc,cb-ns-pxl"}, + {.compatible = "qcom,vidc,cb-ns"}, + {.compatible = "qcom,vidc,cb-sec-non-pxl"}, + {.compatible = "qcom,vidc,cb-sec-bitstream"}, + {.compatible = "qcom,vidc,cb-sec-pxl"}, + MSM_VIDC_EMPTY_BRACE +}; +MODULE_DEVICE_TABLE(of, msm_vidc_dt_match); + +static void msm_vidc_release_video_device(struct video_device *vdev) +{ + d_vpr_e("%s:\n", __func__); +} + +static void msm_vidc_unregister_video_device(struct msm_vidc_core *core, + enum msm_vidc_domain_type type) +{ + int index; + + d_vpr_h("%s: domain %d\n", __func__, type); + + if (type == MSM_VIDC_DECODER) + index = 0; + else if (type == MSM_VIDC_ENCODER) + index = 1; + else + return; + + +#ifdef CONFIG_MEDIA_CONTROLLER + v4l2_m2m_unregister_media_controller(core->vdev[index].m2m_dev); + v4l2_m2m_release(core->vdev[index].m2m_dev); +#endif + //rc = device_create_file(&core->vdev[index].vdev.dev, &dev_attr_link_name); + video_set_drvdata(&core->vdev[index].vdev, NULL); + video_unregister_device(&core->vdev[index].vdev); + //memset vdev to 0 +} + +static int msm_vidc_register_video_device(struct msm_vidc_core *core, + enum msm_vidc_domain_type type, int nr) +{ + int rc = 0; + int index, media_index; + + d_vpr_h("%s: domain %d\n", __func__, type); + + if (type == MSM_VIDC_DECODER) { + index = 0; + media_index = MEDIA_ENT_F_PROC_VIDEO_DECODER; + } else if (type == MSM_VIDC_ENCODER) { + index = 1; + media_index = MEDIA_ENT_F_PROC_VIDEO_ENCODER; + } else { + return -EINVAL; + } + + core->vdev[index].vdev.release = + msm_vidc_release_video_device; + core->vdev[index].vdev.fops = core->v4l2_file_ops; + if (type == MSM_VIDC_DECODER) + core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_dec; + else + core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops_enc; + core->vdev[index].vdev.vfl_dir = VFL_DIR_M2M; + core->vdev[index].type = type; + core->vdev[index].vdev.v4l2_dev = &core->v4l2_dev; + core->vdev[index].vdev.device_caps = core->capabilities[DEVICE_CAPS].value; + rc = video_register_device(&core->vdev[index].vdev, + VFL_TYPE_VIDEO, nr); + if (rc) { + d_vpr_e("Failed to register the video device\n"); + return rc; + } + video_set_drvdata(&core->vdev[index].vdev, core); + //rc = device_create_file(&core->vdev[index].vdev.dev, &dev_attr_link_name); + if (rc) { + d_vpr_e("Failed to create video device file\n"); + goto video_reg_failed; + } +#ifdef CONFIG_MEDIA_CONTROLLER + core->vdev[index].m2m_dev = v4l2_m2m_init(core->v4l2_m2m_ops); + if (IS_ERR(core->vdev[index].m2m_dev)) { + d_vpr_e("Failed to initialize V4L2 M2M device\n"); + rc = PTR_ERR(core->vdev[index].m2m_dev); + goto m2m_init_failed; + } + rc = v4l2_m2m_register_media_controller(core->vdev[index].m2m_dev, + &core->vdev[index].vdev, media_index); + if (rc) { + d_vpr_e("%s: m2m_dev controller register failed for session type %d\n", + __func__, index); + goto m2m_mc_failed; + } +#endif + + return 0; +#ifdef CONFIG_MEDIA_CONTROLLER +m2m_mc_failed: + v4l2_m2m_release(core->vdev[index].m2m_dev); +m2m_init_failed: +#endif +video_reg_failed: + video_unregister_device(&core->vdev[index].vdev); + + return rc; +} + +static int msm_vidc_initialize_media(struct msm_vidc_core *core) +{ + int rc = 0, nr = BASE_DEVICE_NUMBER; + + rc = v4l2_device_register(&core->pdev->dev, &core->v4l2_dev); + if (rc) { + d_vpr_e("Failed to register v4l2 device\n"); + return -EINVAL; + } + +#ifdef CONFIG_MEDIA_CONTROLLER + core->media_dev.dev = &core->pdev->dev; + strscpy(core->media_dev.model, "msm_vidc_media", sizeof(core->media_dev.model)); + media_device_init(&core->media_dev); + core->media_dev.ops = core->media_device_ops; + core->v4l2_dev.mdev = &core->media_dev; +#endif + + /* setup the decoder device */ + rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr); + if (rc) { + d_vpr_e("Failed to register video decoder\n"); + goto dec_reg_failed; + } + + /* setup the encoder device */ + rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1); + if (rc) { + d_vpr_e("Failed to register video encoder\n"); + goto enc_reg_failed; + } +#ifdef CONFIG_MEDIA_CONTROLLER + rc = media_device_register(&core->media_dev); + if (rc) { + d_vpr_e("%s: media_device_register failed with %d\n", __func__, rc); + goto media_reg_failed; + } +#endif + + return rc; +#ifdef CONFIG_MEDIA_CONTROLLER +media_reg_failed: +#endif + msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER); +enc_reg_failed: + msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER); +dec_reg_failed: +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_cleanup(&core->media_dev); +#endif + v4l2_device_unregister(&core->v4l2_dev); + + return rc; +} + +static int msm_vidc_deinitialize_media(struct msm_vidc_core *core) +{ + int rc = 0; + +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_unregister(&core->media_dev); +#endif + msm_vidc_unregister_video_device(core, MSM_VIDC_ENCODER); + msm_vidc_unregister_video_device(core, MSM_VIDC_DECODER); +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_cleanup(&core->media_dev); +#endif + v4l2_device_unregister(&core->v4l2_dev); + + return rc; +} + +#ifdef CONFIG_MSM_MMRM +static int msm_vidc_check_mmrm_support(struct msm_vidc_core *core) +{ + int rc = 0; + + if (!is_mmrm_supported(core)) + goto exit; + + if (!mmrm_client_check_scaling_supported(MMRM_CLIENT_CLOCK, 0)) { + d_vpr_e("%s: MMRM not supported\n", __func__); + core->platform->data.supports_mmrm = 0; + } + +exit: + d_vpr_h("%s: %d\n", __func__, is_mmrm_supported(core)); + return rc; +} +#else +static int msm_vidc_check_mmrm_support(struct msm_vidc_core *core) +{ + core->platform->data.supports_mmrm = 0; + + return 0; +} +#endif + +static int msm_vidc_deinitialize_core(struct msm_vidc_core *core) +{ + int rc = 0; + + if (!core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + d_vpr_h("%s()\n", __func__); + + mutex_destroy(&core->lock); + msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__); + + if (core->batch_workq) + destroy_workqueue(core->batch_workq); + + if (core->pm_workq) + destroy_workqueue(core->pm_workq); + + core->batch_workq = NULL; + core->pm_workq = NULL; + + return rc; +} + +static int msm_vidc_initialize_core(struct msm_vidc_core *core) +{ + int rc = 0; + + d_vpr_h("%s()\n", __func__); + + msm_vidc_update_core_state(core, MSM_VIDC_CORE_DEINIT, __func__); + + core->pm_workq = create_singlethread_workqueue("pm_workq"); + if (!core->pm_workq) { + d_vpr_e("%s: create pm workq failed\n", __func__); + rc = -EINVAL; + goto exit; + } + + core->batch_workq = create_singlethread_workqueue("batch_workq"); + if (!core->batch_workq) { + d_vpr_e("%s: create batch workq failed\n", __func__); + rc = -EINVAL; + goto exit; + } + + core->packet_size = VIDC_IFACEQ_VAR_HUGE_PKT_SIZE; + core->packet = devm_kzalloc(&core->pdev->dev, core->packet_size, GFP_KERNEL); + if (!core->packet) { + d_vpr_e("%s: failed to alloc core packet\n", __func__); + rc = -ENOMEM; + goto exit; + } + + core->response_packet = devm_kzalloc(&core->pdev->dev, core->packet_size, GFP_KERNEL); + if (!core->packet) { + d_vpr_e("%s: failed to alloc core response packet\n", __func__); + rc = -ENOMEM; + goto exit; + } + + mutex_init(&core->lock); + INIT_LIST_HEAD(&core->instances); + INIT_LIST_HEAD(&core->dangling_instances); + + INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler); + INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler); + INIT_WORK(&core->ssr_work, msm_vidc_ssr_handler); + + return 0; +exit: + if (core->batch_workq) + destroy_workqueue(core->batch_workq); + if (core->pm_workq) + destroy_workqueue(core->pm_workq); + core->batch_workq = NULL; + core->pm_workq = NULL; + + return rc; +} + +static void msm_vidc_devm_deinit_core(void *res) +{ + struct msm_vidc_core *core = res; + + d_vpr_h("%s()\n", __func__); + msm_vidc_deinitialize_core(core); +} + +static int msm_vidc_devm_init_core(struct device *dev, struct msm_vidc_core *core) +{ + int rc = 0; + + if (!dev || !core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + rc = msm_vidc_initialize_core(core); + if (rc) { + d_vpr_e("%s: init failed with %d\n", __func__, rc); + return rc; + } + + rc = devm_add_action_or_reset(dev, msm_vidc_devm_deinit_core, (void *)core); + if (rc) + return -EINVAL; + + return rc; +} + +static void msm_vidc_devm_debugfs_put(void *res) +{ + struct dentry *parent = res; + + d_vpr_h("%s()\n", __func__); + debugfs_remove_recursive(parent); +} + +static struct dentry *msm_vidc_devm_debugfs_get(struct device *dev) +{ + struct dentry *parent = NULL; + int rc = 0; + + if (!dev) { + d_vpr_e("%s: invalid params\n", __func__); + return NULL; + } + + parent = msm_vidc_debugfs_init_drv(); + if (!parent) + return NULL; + + rc = devm_add_action_or_reset(dev, msm_vidc_devm_debugfs_put, (void *)parent); + if (rc) + return NULL; + + return parent; +} + +static int msm_vidc_setup_context_bank(struct msm_vidc_core *core, + struct device *dev) +{ + struct context_bank_info *cb = NULL; + int rc = 0; + + cb = msm_vidc_get_context_bank_for_device(core, dev); + if (!cb) { + d_vpr_e("%s: Failed to get context bank device for %s\n", + __func__, dev_name(dev)); + return -EIO; + } + + /* populate dev & domain field */ + cb->dev = dev; + cb->domain = iommu_get_domain_for_dev(cb->dev); + if (!cb->domain) { + d_vpr_e("%s: Failed to get iommu domain for %s\n", __func__, dev_name(dev)); + return -EIO; + } + + if (cb->dma_mask) { + rc = dma_set_mask_and_coherent(cb->dev, cb->dma_mask); + if (rc) { + d_vpr_e("%s: dma_set_mask_and_coherent failed\n", __func__); + return rc; + } + } + + /* + * When memory is fragmented, below configuration increases the + * possibility to get a mapping for buffer in the configured CB. + */ + + /* remove kernel version condition once below api is whitelisted in pineapple */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)) + iommu_dma_enable_best_fit_algo(cb->dev); +#endif + + /* + * configure device segment size and segment boundary to ensure + * iommu mapping returns one mapping (which is required for partial + * cache operations) + */ + if (!dev->dma_parms) + dev->dma_parms = + devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); + dma_set_max_seg_size(dev, (unsigned int)DMA_BIT_MASK(32)); + dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64)); + + iommu_set_fault_handler(cb->domain, + msm_vidc_smmu_fault_handler, (void *)core); + + d_vpr_h( + "%s: name %s addr start %x size %x secure %d dma_coherant %d " + "region %d dev_name %s domain %pK dma_mask %llu\n", + __func__, cb->name, cb->addr_range.start, + cb->addr_range.size, cb->secure, cb->dma_coherant, + cb->region, dev_name(cb->dev), cb->domain, cb->dma_mask); + + return rc; +} + +static int msm_vidc_component_compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static void msm_vidc_component_release_of(struct device *dev, void *data) +{ + d_vpr_h("%s(): %s\n", __func__, of_node_full_name(data)); + of_node_put(data); +} + +static int msm_vidc_component_bind(struct device *dev, + struct device *parent, void *data) +{ + struct msm_vidc_core *core; + int rc = 0; + + if (!dev || !parent || !data) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = (struct msm_vidc_core *)data; + + if (!dev->parent || dev->parent != parent) { + d_vpr_e("%s: failed to find a parent for %s\n", + __func__, dev_name(dev)); + return -ENODEV; + } + + rc = msm_vidc_setup_context_bank(core, dev); + if (rc) { + d_vpr_e("%s: Failed to probe context bank - %s\n", + __func__, dev_name(dev)); + return rc; + } + + d_vpr_h("%s: Successfully probed context bank - %s\n", + __func__, dev_name(dev)); + + return rc; +} + +static void msm_vidc_component_unbind(struct device *dev, + struct device *parent, void *data) +{ + d_vpr_h("%s(): %s\n", __func__, dev_name(dev)); +} + +static int msm_vidc_component_master_bind(struct device *dev) +{ + struct msm_vidc_core *core = dev_get_drvdata(dev); + int rc = 0; + + d_vpr_h("%s(): %s\n", __func__, dev_name(dev)); + + rc = component_bind_all(dev, core); + if (rc) { + d_vpr_e("%s: sub-device bind failed. rc %d\n", __func__, rc); + return rc; + } + + if (core->capabilities[SUPPORTS_SYNX_FENCE].value) { + if (msm_vidc_synx_fence_enable) { + /* register for synx fence */ + rc = call_fence_op(core, fence_register, core); + if (rc) { + d_vpr_e("%s: failed to register synx fence\n", + __func__); + core->capabilities[SUPPORTS_SYNX_FENCE].value = 0; + return rc; + } + } else { + /* override synx fence ops with dma fence ops */ + core->fence_ops = get_dma_fence_ops(); + if (!core->fence_ops) { + d_vpr_e("%s: invalid dma fence ops\n", __func__); + return -EINVAL; + } + core->capabilities[SUPPORTS_SYNX_FENCE].value = 0; + } + } + + rc = msm_vidc_initialize_media(core); + if (rc) { + d_vpr_e("%s: media initialization failed\n", __func__); + return rc; + } + + rc = venus_hfi_queue_init(core); + if (rc) { + d_vpr_e("%s: interface queues init failed\n", __func__); + goto queues_deinit; + } + + rc = msm_vidc_core_init(core); + if (rc) { + d_vpr_e("%s: sys init failed\n", __func__); + goto queues_deinit; + } + + d_vpr_h("%s(): succssful\n", __func__); + + return 0; + +queues_deinit: + venus_hfi_queue_deinit(core); + /** + * queues and core can be inited again during session_open. + * So don't declare as probe failure. + */ + return 0; +} + +static void msm_vidc_component_master_unbind(struct device *dev) +{ + struct msm_vidc_core *core = dev_get_drvdata(dev); + + d_vpr_h("%s(): %s\n", __func__, dev_name(dev)); + + msm_vidc_core_deinit(core, true); + venus_hfi_queue_deinit(core); + msm_vidc_deinitialize_media(core); + call_fence_op(core, fence_deregister, core); + component_unbind_all(dev, core); + + d_vpr_h("%s(): succssful\n", __func__); +} + +static const struct component_ops msm_vidc_component_ops = { + .bind = msm_vidc_component_bind, + .unbind = msm_vidc_component_unbind, +}; + +static const struct component_master_ops msm_vidc_component_master_ops = { + .bind = msm_vidc_component_master_bind, + .unbind = msm_vidc_component_master_unbind, +}; + +static int msm_vidc_remove_video_device(struct platform_device *pdev) +{ + struct msm_vidc_core *core; + + if (!pdev) { + d_vpr_e("%s: invalid input %pK", __func__, pdev); + return -EINVAL; + } + + core = dev_get_drvdata(&pdev->dev); + if (!core) { + d_vpr_e("%s: invalid core\n", __func__); + return -EINVAL; + } + + d_vpr_h("%s()\n", __func__); + + /* destroy component master and deallocate match data */ + component_master_del(&pdev->dev, &msm_vidc_component_master_ops); + + d_vpr_h("depopulating sub devices\n"); + /* + * Trigger remove for each sub-device i.e. qcom,context-bank,xxxx + * When msm_vidc_remove is called for each sub-device, destroy + * context-bank mappings. + */ + of_platform_depopulate(&pdev->dev); + + sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); + + dev_set_drvdata(&pdev->dev, NULL); + g_core = NULL; + d_vpr_h("%s(): succssful\n", __func__); + + return 0; +} + +static int msm_vidc_remove_context_bank(struct platform_device *pdev) +{ + d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev)); + + component_del(&pdev->dev, &msm_vidc_component_ops); + + return 0; +} + +static int msm_vidc_remove(struct platform_device *pdev) +{ + /* + * Sub devices remove will be triggered by of_platform_depopulate() + * after core_deinit(). It return immediately after completing + * sub-device remove. + */ + if (is_video_device(&pdev->dev)) + return msm_vidc_remove_video_device(pdev); + else if (is_video_context_bank_device(&pdev->dev)) + return msm_vidc_remove_context_bank(pdev); + + /* How did we end up here? */ + WARN_ON(1); + return -EINVAL; +} + +static int msm_vidc_probe_video_device(struct platform_device *pdev) +{ + int rc = 0; + struct component_match *match = NULL; + struct msm_vidc_core *core = NULL; + struct device_node *child = NULL; + int cb_count = 0; + + d_vpr_h("%s: %s\n", __func__, dev_name(&pdev->dev)); + + core = devm_kzalloc(&pdev->dev, sizeof(struct msm_vidc_core), GFP_KERNEL); + if (!core) { + d_vpr_e("%s: failed to alloc memory for core\n", __func__); + return -ENOMEM; + } + g_core = core; + + core->pdev = pdev; + dev_set_drvdata(&pdev->dev, core); + + core->debugfs_parent = msm_vidc_devm_debugfs_get(&pdev->dev); + if (!core->debugfs_parent) + d_vpr_h("Failed to create debugfs for msm_vidc\n"); + + rc = msm_vidc_devm_init_core(&pdev->dev, core); + if (rc) { + d_vpr_e("%s: init core failed with %d\n", __func__, rc); + goto init_core_failed; + } + + rc = msm_vidc_init_platform(core); + if (rc) { + d_vpr_e("%s: init platform failed with %d\n", __func__, rc); + rc = -EINVAL; + goto init_plat_failed; + } + + rc = msm_vidc_init_resources(core); + if (rc) { + d_vpr_e("%s: init resource failed with %d\n", __func__, rc); + goto init_res_failed; + } + + rc = msm_vidc_init_core_caps(core); + if (rc) { + d_vpr_e("%s: init core caps failed with %d\n", __func__, rc); + goto init_res_failed; + } + + rc = msm_vidc_init_instance_caps(core); + if (rc) { + d_vpr_e("%s: init inst cap failed with %d\n", __func__, rc); + goto init_inst_caps_fail; + } + + rc = sysfs_create_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); + if (rc) { + d_vpr_e("Failed to create attributes\n"); + goto init_group_failed; + } + + rc = msm_vidc_check_mmrm_support(core); + if (rc) { + d_vpr_e("Failed to check MMRM scaling support\n"); + rc = 0; /* Ignore error */ + } + + core->debugfs_root = msm_vidc_debugfs_init_core(core); + if (!core->debugfs_root) + d_vpr_h("Failed to init debugfs core\n"); + + /* registering sub-device with component model framework */ + for_each_available_child_of_node(pdev->dev.of_node, child) { + /* consider only context bank devices */ + if (!is_video_context_bank_device_node(child)) + continue; + + /* take refcount on device node */ + of_node_get(child); + + /* add entry into component_match array */ + component_match_add_release(&pdev->dev, &match, msm_vidc_component_release_of, + msm_vidc_component_compare_of, child); + if (IS_ERR(match)) { + of_node_put(child); + rc = PTR_ERR(match) ? PTR_ERR(match) : -ENOMEM; + d_vpr_e("%s: component match add release failed\n", __func__); + goto sub_dev_failed; + } + + /* count context bank devices */ + cb_count++; + } + + d_vpr_h("populating sub devices. count %d\n", cb_count); + /* + * Trigger probe for each sub-device i.e. qcom,msm-vidc,context-bank. + * When msm_vidc_probe is called for each sub-device, parse the + * context-bank details. + */ + rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL, + &pdev->dev); + if (rc) { + d_vpr_e("Failed to trigger probe for sub-devices\n"); + goto sub_dev_failed; + } + + /** + * create and try to bring up aggregate device for master. + * match is a component_match_array and acts as a placeholder for + * components added via component_add(). + */ + rc = component_master_add_with_match(&pdev->dev, &msm_vidc_component_master_ops, match); + if (rc) { + d_vpr_e("%s: component master add with match failed\n", __func__); + goto master_add_failed; + } + + d_vpr_h("%s(): succssful\n", __func__); + + return rc; + +master_add_failed: + of_platform_depopulate(&pdev->dev); +sub_dev_failed: + sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); +init_group_failed: +init_inst_caps_fail: +init_res_failed: +init_plat_failed: +init_core_failed: + dev_set_drvdata(&pdev->dev, NULL); + g_core = NULL; + + return rc; +} + +static int msm_vidc_probe_context_bank(struct platform_device *pdev) +{ + d_vpr_h("%s(): %s\n", __func__, dev_name(&pdev->dev)); + + return component_add(&pdev->dev, &msm_vidc_component_ops); +} + +static int msm_vidc_probe(struct platform_device *pdev) +{ + d_vpr_h("%s()\n", __func__); + + if (!pdev) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + /* + * Sub devices probe will be triggered by of_platform_populate() towards + * the end of the probe function after msm-vidc device probe is + * completed. Return immediately after completing sub-device probe. + */ + if (is_video_device(&pdev->dev)) + return msm_vidc_probe_video_device(pdev); + else if (is_video_context_bank_device(&pdev->dev)) + return msm_vidc_probe_context_bank(pdev); + + /* How did we end up here? */ + WARN_ON(1); + return -EINVAL; +} + +static int msm_vidc_pm_suspend(struct device *dev) +{ + int rc = 0; + struct msm_vidc_core *core; + enum msm_vidc_allow allow = MSM_VIDC_DISALLOW; + + /* + * Bail out if + * - driver possibly not probed yet + * - not the main device. We don't support power management on + * subdevices (e.g. context banks) + */ + if (!dev || !dev->driver || !is_video_device(dev)) + return 0; + + core = dev_get_drvdata(dev); + if (!core) { + d_vpr_e("%s: invalid core\n", __func__); + return -EINVAL; + } + + core_lock(core, __func__); + allow = msm_vidc_allow_pm_suspend(core); + + if (allow == MSM_VIDC_IGNORE) { + d_vpr_h("%s: pm already suspended\n", __func__); + msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__); + rc = 0; + goto unlock; + } else if (allow != MSM_VIDC_ALLOW) { + d_vpr_h("%s: pm suspend not allowed\n", __func__); + rc = 0; + goto unlock; + } + + d_vpr_h("%s\n", __func__); + rc = msm_vidc_suspend(core); + if (rc == -ENOTSUPP) + rc = 0; + else if (rc) + d_vpr_e("Failed to suspend: %d\n", rc); + else + msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_PM_SUSPEND, __func__); + +unlock: + core_unlock(core, __func__); + return rc; +} + +static int msm_vidc_pm_resume(struct device *dev) +{ + struct msm_vidc_core *core; + + /* + * Bail out if + * - driver possibly not probed yet + * - not the main device. We don't support power management on + * subdevices (e.g. context banks) + */ + if (!dev || !dev->driver || !is_video_device(dev)) + return 0; + + core = dev_get_drvdata(dev); + if (!core) { + d_vpr_e("%s: invalid core\n", __func__); + return -EINVAL; + } + + d_vpr_h("%s\n", __func__); + + /* remove PM suspend from core sub_state */ + core_lock(core, __func__); + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_PM_SUSPEND, 0, __func__); + core_unlock(core, __func__); + + return 0; +} + +static const struct dev_pm_ops msm_vidc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(msm_vidc_pm_suspend, msm_vidc_pm_resume) +}; + +struct platform_driver msm_vidc_driver = { + .probe = msm_vidc_probe, + .remove = msm_vidc_remove, + .driver = { + .name = "msm_vidc_v4l2", + .of_match_table = msm_vidc_dt_match, + .pm = &msm_vidc_pm_ops, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; + +static int __init msm_vidc_init(void) +{ + int rc = 0; + + d_vpr_h("%s: %s\n", __func__, video_banner); + + rc = platform_driver_register(&msm_vidc_driver); + if (rc) { + d_vpr_e("Failed to register platform driver\n"); + return rc; + } + d_vpr_h("%s(): succssful\n", __func__); + + return 0; +} + +static void __exit msm_vidc_exit(void) +{ + d_vpr_h("%s()\n", __func__); + + platform_driver_unregister(&msm_vidc_driver); + d_vpr_h("%s(): succssful\n", __func__); +} + +module_init(msm_vidc_init); +module_exit(msm_vidc_exit); + +MODULE_SOFTDEP("pre: subsys-pil-tz msm-mmrm"); +MODULE_LICENSE("GPL v2"); diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_state.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_state.c new file mode 100644 index 0000000000..78c55765c3 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_state.c @@ -0,0 +1,1559 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_control.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_state.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_core.h" +#include "msm_vidc_vb2.h" +#include "msm_vidc.h" +#include "msm_vidc_events.h" +#include "venus_hfi.h" + +bool core_in_valid_state(struct msm_vidc_core *core) +{ + return (core->state == MSM_VIDC_CORE_INIT || + core->state == MSM_VIDC_CORE_INIT_WAIT); +} + +bool is_core_state(struct msm_vidc_core *core, enum msm_vidc_core_state state) +{ + return core->state == state; +} + +bool is_drc_pending(struct msm_vidc_inst *inst) +{ + return is_sub_state(inst, MSM_VIDC_DRC) && + is_sub_state(inst, MSM_VIDC_DRC_LAST_BUFFER); +} + +bool is_drain_pending(struct msm_vidc_inst *inst) +{ + return is_sub_state(inst, MSM_VIDC_DRAIN) && + is_sub_state(inst, MSM_VIDC_DRAIN_LAST_BUFFER); +} + +static const char * const core_state_name_arr[] = + FOREACH_CORE_STATE(GENERATE_STRING); + +const char *core_state_name(enum msm_vidc_core_state state) +{ + const char *name = "UNKNOWN STATE"; + + if (state >= ARRAY_SIZE(core_state_name_arr)) + goto exit; + + name = core_state_name_arr[state]; + +exit: + return name; +} + +static const char * const event_name_arr[] = + FOREACH_EVENT(GENERATE_STRING); + +static const char *event_name(enum msm_vidc_event event) +{ + const char *name = "UNKNOWN EVENT"; + + if (event >= ARRAY_SIZE(event_name_arr)) + goto exit; + + name = event_name_arr[event]; + +exit: + return name; +} + +static int __strict_inst_check(struct msm_vidc_inst *inst, const char *function) +{ + bool fatal = !mutex_is_locked(&inst->lock); + + WARN_ON(fatal); + + return fatal ? -EINVAL : 0; +} + +static int msm_vidc_core_deinit_state(struct msm_vidc_core *core, + enum msm_vidc_core_event_type type, + struct msm_vidc_event_data *data) +{ + int rc = 0; + + switch (type) { + case CORE_EVENT_UPDATE_SUB_STATE: + { + u32 req_sub_state; + u32 allow_mask = -1; + + req_sub_state = data->edata.uval; + + /* none of the requested substate supported */ + if (!(req_sub_state & allow_mask)) { + d_vpr_e("%s: invalid substate update request %#x\n", + __func__, req_sub_state); + return -EINVAL; + } + + /* update core substate */ + core->sub_state |= req_sub_state & allow_mask; + return rc; + } + default: { + d_vpr_e("%s: unexpected core event type %u\n", + __func__, type); + return -EINVAL; + } + } + + return rc; +} + +static int msm_vidc_core_init_wait_state(struct msm_vidc_core *core, + enum msm_vidc_core_event_type type, + struct msm_vidc_event_data *data) +{ + int rc = 0; + + switch (type) { + case CORE_EVENT_UPDATE_SUB_STATE: + { + u32 req_sub_state; + u32 allow_mask = -1; + + req_sub_state = data->edata.uval; + + /* none of the requested substate supported */ + if (!(req_sub_state & allow_mask)) { + d_vpr_e("%s: invalid substate update request %#x\n", + __func__, req_sub_state); + return -EINVAL; + } + + /* update core substate */ + core->sub_state |= req_sub_state & allow_mask; + return rc; + } + default: { + d_vpr_e("%s: unexpected core event type %u\n", + __func__, type); + return -EINVAL; + } + } + + return rc; +} + +static int msm_vidc_core_init_state(struct msm_vidc_core *core, + enum msm_vidc_core_event_type type, + struct msm_vidc_event_data *data) +{ + int rc = 0; + + switch (type) { + case CORE_EVENT_UPDATE_SUB_STATE: + { + u32 req_sub_state; + u32 allow_mask = -1; + + req_sub_state = data->edata.uval; + + /* none of the requested substate supported */ + if (!(req_sub_state & allow_mask)) { + d_vpr_e("%s: invalid substate update request %#x\n", + __func__, req_sub_state); + return -EINVAL; + } + + /* update core substate */ + core->sub_state |= req_sub_state & allow_mask; + return rc; + } + default: { + d_vpr_e("%s: unexpected core event type %u\n", + __func__, type); + return -EINVAL; + } + } + + return rc; +} + +static int msm_vidc_core_error_state(struct msm_vidc_core *core, + enum msm_vidc_core_event_type type, + struct msm_vidc_event_data *data) +{ + int rc = 0; + + switch (type) { + case CORE_EVENT_UPDATE_SUB_STATE: + { + u32 req_sub_state; + u32 allow_mask = -1; + + req_sub_state = data->edata.uval; + + /* none of the requested substate supported */ + if (!(req_sub_state & allow_mask)) { + d_vpr_e("%s: invalid substate update request %#x\n", + __func__, req_sub_state); + return -EINVAL; + } + + /* update core substate */ + core->sub_state |= req_sub_state & allow_mask; + return rc; + } + default: { + d_vpr_e("%s: unexpected core event type %u\n", + __func__, type); + return -EINVAL; + } + } + + return rc; +} + +struct msm_vidc_core_state_handle { + enum msm_vidc_core_state state; + int (*handle)(struct msm_vidc_core *core, + enum msm_vidc_core_event_type type, + struct msm_vidc_event_data *data); +}; + +static struct msm_vidc_core_state_handle *msm_vidc_get_core_state_handle( + enum msm_vidc_core_state req_state) +{ + int cnt; + struct msm_vidc_core_state_handle *core_state_handle = NULL; + static struct msm_vidc_core_state_handle state_handle[] = { + {MSM_VIDC_CORE_DEINIT, msm_vidc_core_deinit_state }, + {MSM_VIDC_CORE_INIT_WAIT, msm_vidc_core_init_wait_state }, + {MSM_VIDC_CORE_INIT, msm_vidc_core_init_state }, + {MSM_VIDC_CORE_ERROR, msm_vidc_core_error_state }, + }; + + for (cnt = 0; cnt < ARRAY_SIZE(state_handle); cnt++) { + if (state_handle[cnt].state == req_state) { + core_state_handle = &state_handle[cnt]; + break; + } + } + + /* if req_state does not exist in the table */ + if (cnt == ARRAY_SIZE(state_handle)) { + d_vpr_e("%s: invalid core state \"%s\" requested\n", + __func__, core_state_name(req_state)); + return core_state_handle; + } + + return core_state_handle; +} + +int msm_vidc_update_core_state(struct msm_vidc_core *core, + enum msm_vidc_core_state request_state, const char *func) +{ + struct msm_vidc_core_state_handle *state_handle = NULL; + int rc = 0; + + /* get core state handler for requested state */ + state_handle = msm_vidc_get_core_state_handle(request_state); + if (!state_handle) + return -EINVAL; + + d_vpr_h("%s: core state changed to %s from %s\n", func, + core_state_name(state_handle->state), core_state_name(core->state)); + + /* finally update core state and handler */ + core->state = state_handle->state; + core->state_handle = state_handle->handle; + + return rc; +} + +struct msm_vidc_core_state_allow { + enum msm_vidc_core_state from; + enum msm_vidc_core_state to; + enum msm_vidc_allow allow; +}; + +enum msm_vidc_allow msm_vidc_allow_core_state_change( + struct msm_vidc_core *core, + enum msm_vidc_core_state req_state) +{ + int cnt; + enum msm_vidc_allow allow = MSM_VIDC_DISALLOW; + static struct msm_vidc_core_state_allow state[] = { + /* from, to, allow */ + {MSM_VIDC_CORE_DEINIT, MSM_VIDC_CORE_DEINIT, MSM_VIDC_IGNORE }, + {MSM_VIDC_CORE_DEINIT, MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_ALLOW }, + {MSM_VIDC_CORE_DEINIT, MSM_VIDC_CORE_INIT, MSM_VIDC_DISALLOW }, + {MSM_VIDC_CORE_DEINIT, MSM_VIDC_CORE_ERROR, MSM_VIDC_IGNORE }, + {MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_CORE_DEINIT, MSM_VIDC_DISALLOW }, + {MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_IGNORE }, + {MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_CORE_INIT, MSM_VIDC_ALLOW }, + {MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_CORE_ERROR, MSM_VIDC_ALLOW }, + {MSM_VIDC_CORE_INIT, MSM_VIDC_CORE_DEINIT, MSM_VIDC_ALLOW }, + {MSM_VIDC_CORE_INIT, MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_DISALLOW }, + {MSM_VIDC_CORE_INIT, MSM_VIDC_CORE_INIT, MSM_VIDC_IGNORE }, + {MSM_VIDC_CORE_INIT, MSM_VIDC_CORE_ERROR, MSM_VIDC_ALLOW }, + {MSM_VIDC_CORE_ERROR, MSM_VIDC_CORE_DEINIT, MSM_VIDC_ALLOW }, + {MSM_VIDC_CORE_ERROR, MSM_VIDC_CORE_INIT_WAIT, MSM_VIDC_IGNORE }, + {MSM_VIDC_CORE_ERROR, MSM_VIDC_CORE_INIT, MSM_VIDC_IGNORE }, + {MSM_VIDC_CORE_ERROR, MSM_VIDC_CORE_ERROR, MSM_VIDC_IGNORE }, + }; + + for (cnt = 0; cnt < ARRAY_SIZE(state); cnt++) { + if (state[cnt].from == core->state && state[cnt].to == req_state) { + allow = state[cnt].allow; + break; + } + } + + return allow; +} + +int msm_vidc_change_core_state(struct msm_vidc_core *core, + enum msm_vidc_core_state request_state, const char *func) +{ + enum msm_vidc_allow allow; + int rc = 0; + + /* core must be locked */ + rc = __strict_check(core, func); + if (rc) { + d_vpr_e("%s(): core was not locked\n", func); + return rc; + } + + /* current and requested state is same */ + if (core->state == request_state) + return 0; + + /* check if requested state movement is allowed */ + allow = msm_vidc_allow_core_state_change(core, request_state); + if (allow == MSM_VIDC_IGNORE) { + d_vpr_h("%s: %s core state change %s -> %s\n", func, + allow_name(allow), core_state_name(core->state), + core_state_name(request_state)); + return 0; + } else if (allow == MSM_VIDC_DISALLOW) { + d_vpr_e("%s: %s core state change %s -> %s\n", func, + allow_name(allow), core_state_name(core->state), + core_state_name(request_state)); + return -EINVAL; + } + + /* go ahead and update core state */ + rc = msm_vidc_update_core_state(core, request_state, func); + if (rc) + return rc; + + return rc; +} + +bool is_core_sub_state(struct msm_vidc_core *core, + enum msm_vidc_core_sub_state sub_state) +{ + return !!(core->sub_state & sub_state); +} + +const char *core_sub_state_name(enum msm_vidc_core_sub_state sub_state) +{ + switch (sub_state) { + case CORE_SUBSTATE_NONE: return "NONE "; + case CORE_SUBSTATE_GDSC_HANDOFF: return "GDSC_HANDOFF "; + case CORE_SUBSTATE_PM_SUSPEND: return "PM_SUSPEND "; + case CORE_SUBSTATE_FW_PWR_CTRL: return "FW_PWR_CTRL "; + case CORE_SUBSTATE_POWER_ENABLE: return "POWER_ENABLE "; + case CORE_SUBSTATE_PAGE_FAULT: return "PAGE_FAULT "; + case CORE_SUBSTATE_CPU_WATCHDOG: return "CPU_WATCHDOG "; + case CORE_SUBSTATE_VIDEO_UNRESPONSIVE: return "VIDEO_UNRESPONSIVE "; + case CORE_SUBSTATE_MAX: return "MAX "; + } + + return "UNKNOWN "; +} + +static int prepare_core_sub_state_name(enum msm_vidc_core_sub_state sub_state, + char *buf, u32 size) +{ + int i = 0; + + if (!buf || !size) + return -EINVAL; + + strscpy(buf, "\0", size); + if (sub_state == CORE_SUBSTATE_NONE) { + strscpy(buf, "CORE_SUBSTATE_NONE", size); + return 0; + } + + for (i = 0; BIT(i) < CORE_SUBSTATE_MAX; i++) { + if (sub_state & BIT(i)) + strlcat(buf, core_sub_state_name(BIT(i)), size); + } + + return 0; +} + +static int msm_vidc_update_core_sub_state(struct msm_vidc_core *core, + enum msm_vidc_core_sub_state sub_state, const char *func) +{ + struct msm_vidc_event_data data; + char sub_state_name[MAX_NAME_LENGTH]; + int ret = 0, rc = 0; + + /* no substate update */ + if (!sub_state) + return 0; + + /* invoke update core substate event */ + memset(&data, 0, sizeof(struct msm_vidc_event_data)); + data.edata.uval = sub_state; + rc = core->state_handle(core, CORE_EVENT_UPDATE_SUB_STATE, &data); + if (rc) { + ret = prepare_core_sub_state_name(sub_state, + sub_state_name, sizeof(sub_state_name) - 1); + if (!ret) + d_vpr_e("%s: state %s, requested invalid core substate %s\n", + func, core_state_name(core->state), sub_state_name); + return rc; + } + + return rc; +} + +int msm_vidc_change_core_sub_state(struct msm_vidc_core *core, + enum msm_vidc_core_sub_state clear_sub_state, + enum msm_vidc_core_sub_state set_sub_state, const char *func) +{ + int rc = 0; + enum msm_vidc_core_sub_state prev_sub_state; + + /* core must be locked */ + rc = __strict_check(core, func); + if (rc) { + d_vpr_e("%s(): core was not locked\n", func); + return rc; + } + + /* sanitize core state handler */ + if (!core->state_handle) { + d_vpr_e("%s: invalid core state handle\n", __func__); + return -EINVAL; + } + + /* final value will not change */ + if (clear_sub_state == set_sub_state) + return 0; + + /* sanitize clear & set value */ + if (set_sub_state > CORE_SUBSTATE_MAX || + clear_sub_state > CORE_SUBSTATE_MAX) { + d_vpr_e("%s: invalid sub states. clear %#x or set %#x\n", + func, clear_sub_state, set_sub_state); + return -EINVAL; + } + + prev_sub_state = core->sub_state; + + /* set sub state */ + rc = msm_vidc_update_core_sub_state(core, set_sub_state, func); + if (rc) + return rc; + + /* check if all core substates updated */ + if ((core->sub_state & set_sub_state) != set_sub_state) + d_vpr_e("%s: all substates not updated %#x, expected %#x\n", + func, core->sub_state & set_sub_state, set_sub_state); + + /* clear sub state */ + core->sub_state &= ~clear_sub_state; + + /* print substates only when there is a change */ + if (core->sub_state != prev_sub_state) { + rc = prepare_core_sub_state_name(core->sub_state, core->sub_state_name, + sizeof(core->sub_state_name) - 1); + if (!rc) + d_vpr_h("%s: core sub state changed to %s\n", func, core->sub_state_name); + } + + return 0; +} + +/* do not modify the state names as it is used in test scripts */ +static const char * const state_name_arr[] = + FOREACH_STATE(GENERATE_STRING); + +const char *state_name(enum msm_vidc_state state) +{ + const char *name = "UNKNOWN STATE"; + + if (state >= ARRAY_SIZE(state_name_arr)) + goto exit; + + name = state_name_arr[state]; + +exit: + return name; +} + +bool is_state(struct msm_vidc_inst *inst, enum msm_vidc_state state) +{ + return inst->state == state; +} + +bool is_sub_state(struct msm_vidc_inst *inst, enum msm_vidc_sub_state sub_state) +{ + return (inst->sub_state & sub_state); +} + +const char *sub_state_name(enum msm_vidc_sub_state sub_state) +{ + switch (sub_state) { + case MSM_VIDC_DRAIN: return "DRAIN "; + case MSM_VIDC_DRC: return "DRC "; + case MSM_VIDC_DRAIN_LAST_BUFFER: return "DRAIN_LAST_BUFFER "; + case MSM_VIDC_DRC_LAST_BUFFER: return "DRC_LAST_BUFFER "; + case MSM_VIDC_INPUT_PAUSE: return "INPUT_PAUSE "; + case MSM_VIDC_OUTPUT_PAUSE: return "OUTPUT_PAUSE "; + case MSM_VIDC_FIRST_IPSC: return "FIRST_IPSC "; + } + + return "SUB_STATE_NONE"; +} + +static int prepare_sub_state_name(enum msm_vidc_sub_state sub_state, + char *buf, u32 size) +{ + int i = 0; + + if (!buf || !size) + return -EINVAL; + + strscpy(buf, "\0", size); + if (sub_state == MSM_VIDC_SUB_STATE_NONE) { + strscpy(buf, "SUB_STATE_NONE", size); + return 0; + } + + for (i = 0; i < MSM_VIDC_MAX_SUB_STATES; i++) { + if (sub_state & BIT(i)) + strlcat(buf, sub_state_name(BIT(i)), size); + } + + return 0; +} + +struct msm_vidc_state_allow { + enum msm_vidc_state from; + enum msm_vidc_state to; + enum msm_vidc_allow allow; +}; + +static enum msm_vidc_allow msm_vidc_allow_state_change( + struct msm_vidc_inst *inst, + enum msm_vidc_state req_state) +{ + int cnt; + enum msm_vidc_allow allow = MSM_VIDC_DISALLOW; + static struct msm_vidc_state_allow state[] = { + /* from, to, allow */ + {MSM_VIDC_OPEN, MSM_VIDC_OPEN, MSM_VIDC_IGNORE }, + {MSM_VIDC_OPEN, MSM_VIDC_INPUT_STREAMING, MSM_VIDC_ALLOW }, + {MSM_VIDC_OPEN, MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_ALLOW }, + {MSM_VIDC_OPEN, MSM_VIDC_STREAMING, MSM_VIDC_DISALLOW }, + {MSM_VIDC_OPEN, MSM_VIDC_CLOSE, MSM_VIDC_ALLOW }, + {MSM_VIDC_OPEN, MSM_VIDC_ERROR, MSM_VIDC_ALLOW }, + + {MSM_VIDC_INPUT_STREAMING, MSM_VIDC_OPEN, MSM_VIDC_ALLOW }, + {MSM_VIDC_INPUT_STREAMING, MSM_VIDC_INPUT_STREAMING, MSM_VIDC_IGNORE }, + {MSM_VIDC_INPUT_STREAMING, MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_DISALLOW }, + {MSM_VIDC_INPUT_STREAMING, MSM_VIDC_STREAMING, MSM_VIDC_ALLOW }, + {MSM_VIDC_INPUT_STREAMING, MSM_VIDC_CLOSE, MSM_VIDC_ALLOW }, + {MSM_VIDC_INPUT_STREAMING, MSM_VIDC_ERROR, MSM_VIDC_ALLOW }, + + {MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_OPEN, MSM_VIDC_ALLOW }, + {MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_INPUT_STREAMING, MSM_VIDC_DISALLOW }, + {MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_IGNORE }, + {MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_STREAMING, MSM_VIDC_ALLOW }, + {MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_CLOSE, MSM_VIDC_ALLOW }, + {MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_ERROR, MSM_VIDC_ALLOW }, + + {MSM_VIDC_STREAMING, MSM_VIDC_OPEN, MSM_VIDC_DISALLOW }, + {MSM_VIDC_STREAMING, MSM_VIDC_INPUT_STREAMING, MSM_VIDC_ALLOW }, + {MSM_VIDC_STREAMING, MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_ALLOW }, + {MSM_VIDC_STREAMING, MSM_VIDC_STREAMING, MSM_VIDC_IGNORE }, + {MSM_VIDC_STREAMING, MSM_VIDC_CLOSE, MSM_VIDC_ALLOW }, + {MSM_VIDC_STREAMING, MSM_VIDC_ERROR, MSM_VIDC_ALLOW }, + + {MSM_VIDC_CLOSE, MSM_VIDC_OPEN, MSM_VIDC_DISALLOW }, + {MSM_VIDC_CLOSE, MSM_VIDC_INPUT_STREAMING, MSM_VIDC_DISALLOW }, + {MSM_VIDC_CLOSE, MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_DISALLOW }, + {MSM_VIDC_CLOSE, MSM_VIDC_STREAMING, MSM_VIDC_DISALLOW }, + {MSM_VIDC_CLOSE, MSM_VIDC_CLOSE, MSM_VIDC_IGNORE }, + {MSM_VIDC_CLOSE, MSM_VIDC_ERROR, MSM_VIDC_IGNORE }, + + {MSM_VIDC_ERROR, MSM_VIDC_OPEN, MSM_VIDC_IGNORE }, + {MSM_VIDC_ERROR, MSM_VIDC_INPUT_STREAMING, MSM_VIDC_IGNORE }, + {MSM_VIDC_ERROR, MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_IGNORE }, + {MSM_VIDC_ERROR, MSM_VIDC_STREAMING, MSM_VIDC_IGNORE }, + {MSM_VIDC_ERROR, MSM_VIDC_CLOSE, MSM_VIDC_IGNORE }, + {MSM_VIDC_ERROR, MSM_VIDC_ERROR, MSM_VIDC_IGNORE }, + }; + + for (cnt = 0; cnt < ARRAY_SIZE(state); cnt++) { + if (state[cnt].from == inst->state && state[cnt].to == req_state) { + allow = state[cnt].allow; + break; + } + } + + return allow; +} + +static int msm_vidc_open_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + switch (event) { + case MSM_VIDC_TRY_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)data; + + /* allow try_fmt request in open state */ + rc = msm_vidc_try_fmt(inst, f); + if (rc) + return rc; + break; + } + case MSM_VIDC_S_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)data; + + /* allow s_fmt request in open state */ + rc = msm_vidc_s_fmt(inst, f); + if (rc) + return rc; + break; + } + case MSM_VIDC_S_CTRL: + { + struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data; + + /* allow set_control request in open state */ + rc = msm_vidc_s_ctrl(inst, ctrl); + if (rc) + return rc; + break; + } + case MSM_VIDC_REQBUFS: + { + struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data; + + /* allow reqbufs request in open state */ + rc = msm_vidc_reqbufs(inst, b); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMON: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + /* allow streamon request in open state */ + rc = msm_vidc_start_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMOFF: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + /* ignore streamoff request in open state */ + i_vpr_h(inst, "%s: streamoff of (%s) ignored in state (%s)\n", + __func__, v4l2_type_name(q->type), state_name(inst->state)); + break; + } + case MSM_VIDC_CMD_START: + { + /* disallow start cmd request in open state */ + i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n", + __func__, event_name(event), inst->sub_state_name); + + return -EBUSY; + } + case MSM_VIDC_CMD_STOP: + { + /* ignore stop cmd request in open state */ + i_vpr_h(inst, "%s: (%s) ignored, sub_state (%s)\n", + __func__, event_name(event), inst->sub_state_name); + break; + } + case MSM_VIDC_BUF_QUEUE: + { + struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data; + + /* defer qbuf request in open state */ + print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf); + break; + } + default: + { + i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event)); + return -EINVAL; + } + } + + return rc; +} + +static int msm_vidc_input_streaming_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + switch (event) { + case MSM_VIDC_BUF_QUEUE: + { + struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data; + + /* defer meta port */ + if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) { + print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf); + return 0; + } + + /* disallow */ + if (!is_input_buffer(buf->type) && !is_output_buffer(buf->type)) { + i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type); + return -EINVAL; + } + + /* defer output port */ + if (is_output_buffer(buf->type)) { + print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf); + return 0; + } + + rc = msm_vidc_buf_queue(inst, buf); + if (rc) + return rc; + break; + } + case MSM_VIDC_TRY_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)data; + + /* disallow */ + if (f->type == INPUT_MPLANE || f->type == INPUT_META_PLANE) { + i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n", + __func__, event_name(event), v4l2_type_name(f->type)); + return -EBUSY; + } + + rc = msm_vidc_try_fmt(inst, f); + if (rc) + return rc; + break; + } + case MSM_VIDC_S_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)data; + + /* disallow */ + if (f->type == INPUT_MPLANE || f->type == INPUT_META_PLANE) { + i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n", + __func__, event_name(event), v4l2_type_name(f->type)); + return -EBUSY; + } + + rc = msm_vidc_s_fmt(inst, f); + if (rc) + return rc; + break; + } + case MSM_VIDC_S_CTRL: + { + struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data; + u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id); + + if (cap_id == INST_CAP_NONE) { + i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id); + return -EINVAL; + } + + /* disallow */ + if (is_decode_session(inst)) { + /* check dynamic allowed if master port is streaming */ + if (!(inst->capabilities[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) { + i_vpr_e(inst, "%s: cap_id %#x (%s) not allowed in state %s\n", + __func__, cap_id, cap_name(cap_id), + state_name(inst->state)); + return -EINVAL; + } + } + + rc = msm_vidc_s_ctrl(inst, ctrl); + if (rc) + return rc; + break; + } + case MSM_VIDC_REQBUFS: + { + struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data; + + /* disallow */ + if (b->type == INPUT_MPLANE || b->type == INPUT_META_PLANE) { + i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n", + __func__, event_name(event), v4l2_type_name(b->type)); + return -EBUSY; + } + + rc = msm_vidc_reqbufs(inst, b); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMON: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + /* disallow */ + if (q->type == INPUT_MPLANE || q->type == INPUT_META_PLANE) { + i_vpr_e(inst, "%s: (%s) not allowed for (%s) type\n", + __func__, event_name(event), v4l2_type_name(q->type)); + return -EBUSY; + } + + rc = msm_vidc_start_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMOFF: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + /* ignore */ + if (q->type == OUTPUT_MPLANE || q->type == OUTPUT_META_PLANE) { + i_vpr_h(inst, "%s: streamoff of (%s) ignored in state (%s)\n", + __func__, v4l2_type_name(q->type), state_name(inst->state)); + return 0; + } + + /* disallow */ + if (q->type == INPUT_META_PLANE) { + i_vpr_e(inst, "%s: streamoff of (%s) not allowed in state (%s)\n", + __func__, v4l2_type_name(q->type), state_name(inst->state)); + return -EINVAL; + } + + /* sanitize type field */ + if (q->type != INPUT_MPLANE) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); + return -EINVAL; + } + + rc = msm_vidc_stop_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_START: + { + /* disallow if START called for non DRC/drain cases */ + if (!is_drc_pending(inst) && !is_drain_pending(inst)) { + i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n", + __func__, event_name(event), inst->sub_state_name); + return -EBUSY; + } + + /* client would call start(resume) to complete DRC/drain sequence */ + rc = msm_vidc_start_cmd(inst); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_STOP: + { + /* back to back drain not allowed */ + if (is_sub_state(inst, MSM_VIDC_DRAIN)) { + i_vpr_e(inst, "%s: drain (%s) not allowed, sub_state (%s)\n\n", + __func__, event_name(event), inst->sub_state_name); + return -EBUSY; + } + + rc = msm_vidc_stop_cmd(inst); + if (rc) + return rc; + break; + } + default: + { + i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event)); + return -EINVAL; + } + } + + return rc; +} + +static int msm_vidc_output_streaming_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + switch (event) { + case MSM_VIDC_BUF_QUEUE: + { + struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data; + + /* defer meta port */ + if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) { + print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf); + return 0; + } + + /* disallow */ + if (!is_input_buffer(buf->type) && !is_output_buffer(buf->type)) { + i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type); + return -EINVAL; + } + + /* defer input port */ + if (is_input_buffer(buf->type)) { + print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf); + return 0; + } + + rc = msm_vidc_buf_queue(inst, buf); + if (rc) + return rc; + break; + } + case MSM_VIDC_TRY_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)data; + + /* disallow */ + if (f->type == OUTPUT_MPLANE || f->type == OUTPUT_META_PLANE) { + i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n", + __func__, event_name(event), v4l2_type_name(f->type)); + return -EBUSY; + } + + rc = msm_vidc_try_fmt(inst, f); + if (rc) + return rc; + break; + } + case MSM_VIDC_S_FMT: + { + struct v4l2_format *f = (struct v4l2_format *)data; + + /* disallow */ + if (f->type == OUTPUT_MPLANE || f->type == OUTPUT_META_PLANE) { + i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n", + __func__, event_name(event), v4l2_type_name(f->type)); + return -EBUSY; + } + + rc = msm_vidc_s_fmt(inst, f); + if (rc) + return rc; + break; + } + case MSM_VIDC_S_CTRL: + { + struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data; + u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id); + + if (cap_id == INST_CAP_NONE) { + i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id); + return -EINVAL; + } + + /* disallow */ + if (is_encode_session(inst)) { + /* check dynamic allowed if master port is streaming */ + if (!(inst->capabilities[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) { + i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n", + __func__, cap_id, state_name(inst->state)); + return -EINVAL; + } + } + + rc = msm_vidc_s_ctrl(inst, ctrl); + if (rc) + return rc; + break; + } + case MSM_VIDC_REQBUFS: + { + struct v4l2_requestbuffers *b = (struct v4l2_requestbuffers *)data; + + /* disallow */ + if (b->type == OUTPUT_MPLANE || b->type == OUTPUT_META_PLANE) { + i_vpr_e(inst, "%s: (%s) not allowed for (%s) port\n", + __func__, event_name(event), v4l2_type_name(b->type)); + return -EBUSY; + } + + rc = msm_vidc_reqbufs(inst, b); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMON: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + /* disallow */ + if (q->type == OUTPUT_MPLANE || q->type == OUTPUT_META_PLANE) { + i_vpr_e(inst, "%s: (%s) not allowed for (%s) type\n", + __func__, event_name(event), v4l2_type_name(q->type)); + return -EBUSY; + } + + rc = msm_vidc_start_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMOFF: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + /* ignore */ + if (q->type == INPUT_MPLANE || q->type == INPUT_META_PLANE) { + i_vpr_h(inst, "%s: streamoff of (%s) ignored in state (%s)\n", + __func__, v4l2_type_name(q->type), state_name(inst->state)); + return 0; + } + + /* disallow */ + if (q->type == OUTPUT_META_PLANE) { + i_vpr_e(inst, "%s: streamoff of (%s) not allowed in state (%s)\n", + __func__, v4l2_type_name(q->type), state_name(inst->state)); + return -EINVAL; + } + + /* sanitize type field */ + if (q->type != OUTPUT_MPLANE) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); + return -EINVAL; + } + + rc = msm_vidc_stop_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_START: + { + /* disallow if START called for non DRC/drain cases */ + if (!is_drc_pending(inst) && !is_drain_pending(inst)) { + i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n", + __func__, event_name(event), inst->sub_state_name); + return -EBUSY; + } + + /* client would call start(resume) to complete DRC/drain sequence */ + rc = msm_vidc_start_cmd(inst); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_STOP: + { + /* drain not allowed as input is not streaming */ + i_vpr_e(inst, "%s: drain (%s) not allowed, sub state %s\n", + __func__, event_name(event), inst->sub_state_name); + return -EBUSY; + } + default: { + i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event)); + return -EINVAL; + } + } + + return rc; +} + +static int msm_vidc_streaming_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + switch (event) { + case MSM_VIDC_BUF_QUEUE: + { + struct msm_vidc_buffer *buf = (struct msm_vidc_buffer *)data; + + /* defer meta port */ + if (buf->type == MSM_VIDC_BUF_INPUT_META || buf->type == MSM_VIDC_BUF_OUTPUT_META) { + print_vidc_buffer(VIDC_LOW, "low ", "qbuf deferred", inst, buf); + return 0; + } + + /* disallow */ + if (!is_input_buffer(buf->type) && !is_output_buffer(buf->type)) { + i_vpr_e(inst, "%s: invalid buf type %u\n", __func__, buf->type); + return -EINVAL; + } + + rc = msm_vidc_buf_queue(inst, buf); + if (rc) + return rc; + break; + } + case MSM_VIDC_S_CTRL: + { + struct v4l2_ctrl *ctrl = (struct v4l2_ctrl *)data; + u32 cap_id = msm_vidc_get_cap_id(inst, ctrl->id); + + if (cap_id == INST_CAP_NONE) { + i_vpr_e(inst, "%s: invalid cap_id %u\n", __func__, cap_id); + return -EINVAL; + } + + /* disallow */ + if (!(inst->capabilities[cap_id].flags & CAP_FLAG_DYNAMIC_ALLOWED)) { + i_vpr_e(inst, "%s: cap_id %#x not allowed in state %s\n", + __func__, cap_id, state_name(inst->state)); + return -EINVAL; + } + + rc = msm_vidc_s_ctrl(inst, ctrl); + if (rc) + return rc; + break; + } + case MSM_VIDC_STREAMOFF: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + /* disallow */ + if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) { + i_vpr_e(inst, "%s: streamoff of (%s) not allowed in state (%s)\n", + __func__, v4l2_type_name(q->type), state_name(inst->state)); + return -EINVAL; + } + + /* sanitize type field */ + if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); + return -EINVAL; + } + + rc = msm_vidc_stop_streaming(inst, q); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_START: + { + /* disallow if START called for non DRC/drain cases */ + if (!is_drc_pending(inst) && !is_drain_pending(inst)) { + i_vpr_e(inst, "%s: (%s) not allowed, sub_state (%s)\n", + __func__, event_name(event), inst->sub_state_name); + return -EBUSY; + } + + /* client would call start(resume) to complete DRC/drain sequence */ + rc = msm_vidc_start_cmd(inst); + if (rc) + return rc; + break; + } + case MSM_VIDC_CMD_STOP: + { + /* back to back drain not allowed */ + if (is_sub_state(inst, MSM_VIDC_DRAIN)) { + i_vpr_e(inst, "%s: drain (%s) not allowed, sub_state (%s)\n\n", + __func__, event_name(event), inst->sub_state_name); + return -EBUSY; + } + + rc = msm_vidc_stop_cmd(inst); + if (rc) + return rc; + break; + } + default: { + i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event)); + return -EINVAL; + } + } + + return rc; +} + +static int msm_vidc_close_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + switch (event) { + case MSM_VIDC_STREAMOFF: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + rc = msm_vidc_stop_streaming(inst, q); + if (rc) + return rc; + break; + } + default: { + i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event)); + return -EINVAL; + } + } + + return rc; +} + +static int msm_vidc_error_state(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data) +{ + int rc = 0; + + /* inst must be locked */ + rc = __strict_inst_check(inst, __func__); + if (rc) { + i_vpr_e(inst, "%s(): inst was not locked\n", __func__); + return -EINVAL; + } + + switch (event) { + case MSM_VIDC_STREAMOFF: + { + struct vb2_queue *q = (struct vb2_queue *)data; + + rc = msm_vidc_stop_streaming(inst, q); + if (rc) + return rc; + break; + } + default: { + i_vpr_e(inst, "%s: unexpected event %s\n", __func__, event_name(event)); + return -EINVAL; + } + } + + return rc; +} + +struct msm_vidc_state_handle { + enum msm_vidc_state state; + int (*handle)(struct msm_vidc_inst *inst, + enum msm_vidc_event event, void *data); +}; + +static struct msm_vidc_state_handle *msm_vidc_get_state_handle( + struct msm_vidc_inst *inst, + enum msm_vidc_state req_state) +{ + int cnt; + struct msm_vidc_state_handle *inst_state_handle = NULL; + static struct msm_vidc_state_handle state_handle[] = { + {MSM_VIDC_OPEN, msm_vidc_open_state }, + {MSM_VIDC_INPUT_STREAMING, msm_vidc_input_streaming_state }, + {MSM_VIDC_OUTPUT_STREAMING, msm_vidc_output_streaming_state }, + {MSM_VIDC_STREAMING, msm_vidc_streaming_state }, + {MSM_VIDC_CLOSE, msm_vidc_close_state }, + {MSM_VIDC_ERROR, msm_vidc_error_state }, + }; + + for (cnt = 0; cnt < ARRAY_SIZE(state_handle); cnt++) { + if (state_handle[cnt].state == req_state) { + inst_state_handle = &state_handle[cnt]; + break; + } + } + + /* check if req_state does not exist in the table */ + if (cnt == ARRAY_SIZE(state_handle)) { + i_vpr_e(inst, "%s: invalid state %s\n", __func__, state_name(req_state)); + return inst_state_handle; + } + + return inst_state_handle; +} + +int msm_vidc_update_state(struct msm_vidc_inst *inst, + enum msm_vidc_state request_state, const char *func) +{ + struct msm_vidc_state_handle *state_handle = NULL; + int rc = 0; + + /* get inst state handler for requested state */ + state_handle = msm_vidc_get_state_handle(inst, request_state); + if (!state_handle) + return -EINVAL; + + if (request_state == MSM_VIDC_ERROR) + i_vpr_e(inst, FMT_STRING_STATE_CHANGE, + func, state_name(request_state), state_name(inst->state)); + else + i_vpr_h(inst, FMT_STRING_STATE_CHANGE, + func, state_name(request_state), state_name(inst->state)); + + trace_msm_vidc_common_state_change(inst, func, state_name(inst->state), + state_name(request_state)); + + /* finally update inst state and handler */ + inst->state = state_handle->state; + inst->event_handle = state_handle->handle; + + return rc; +} + +int msm_vidc_change_state(struct msm_vidc_inst *inst, + enum msm_vidc_state request_state, const char *func) +{ + enum msm_vidc_allow allow; + int rc; + + if (is_session_error(inst)) { + i_vpr_h(inst, + "%s: inst is in bad state, can not change state to %s\n", + func, state_name(request_state)); + return 0; + } + + /* current and requested state is same */ + if (inst->state == request_state) + return 0; + + /* check if requested state movement is allowed */ + allow = msm_vidc_allow_state_change(inst, request_state); + if (allow != MSM_VIDC_ALLOW) { + i_vpr_e(inst, "%s: %s state change %s -> %s\n", func, + allow_name(allow), state_name(inst->state), + state_name(request_state)); + return (allow == MSM_VIDC_DISALLOW ? -EINVAL : 0); + } + + /* go ahead and update inst state */ + rc = msm_vidc_update_state(inst, request_state, func); + if (rc) + return rc; + + return 0; +} + +struct msm_vidc_sub_state_allow { + enum msm_vidc_state state; + enum msm_vidc_allow allow; + u32 sub_state_mask; +}; + +static int msm_vidc_set_sub_state(struct msm_vidc_inst *inst, + enum msm_vidc_sub_state sub_state, const char *func) +{ + char sub_state_name[MAX_NAME_LENGTH]; + int cnt, rc = 0; + static struct msm_vidc_sub_state_allow sub_state_allow[] = { + /* state, allow, sub_state */ + {MSM_VIDC_OPEN, MSM_VIDC_DISALLOW, MSM_VIDC_DRC | + MSM_VIDC_DRAIN | + MSM_VIDC_DRC_LAST_BUFFER | + MSM_VIDC_DRAIN_LAST_BUFFER | + MSM_VIDC_INPUT_PAUSE | + MSM_VIDC_OUTPUT_PAUSE }, + + {MSM_VIDC_INPUT_STREAMING, MSM_VIDC_DISALLOW, MSM_VIDC_DRC_LAST_BUFFER | + MSM_VIDC_DRAIN_LAST_BUFFER | + MSM_VIDC_OUTPUT_PAUSE }, + {MSM_VIDC_INPUT_STREAMING, MSM_VIDC_ALLOW, MSM_VIDC_DRC | + MSM_VIDC_DRAIN | + MSM_VIDC_INPUT_PAUSE | + MSM_VIDC_FIRST_IPSC }, + + {MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_DISALLOW, MSM_VIDC_DRC | + MSM_VIDC_DRAIN | + MSM_VIDC_INPUT_PAUSE }, + {MSM_VIDC_OUTPUT_STREAMING, MSM_VIDC_ALLOW, MSM_VIDC_DRC_LAST_BUFFER | + MSM_VIDC_DRAIN_LAST_BUFFER | + MSM_VIDC_OUTPUT_PAUSE }, + + {MSM_VIDC_STREAMING, MSM_VIDC_ALLOW, MSM_VIDC_DRC | + MSM_VIDC_DRAIN | + MSM_VIDC_DRC_LAST_BUFFER | + MSM_VIDC_DRAIN_LAST_BUFFER | + MSM_VIDC_INPUT_PAUSE | + MSM_VIDC_OUTPUT_PAUSE }, + + {MSM_VIDC_CLOSE, MSM_VIDC_ALLOW, MSM_VIDC_DRC | + MSM_VIDC_DRAIN | + MSM_VIDC_DRC_LAST_BUFFER | + MSM_VIDC_DRAIN_LAST_BUFFER | + MSM_VIDC_INPUT_PAUSE | + MSM_VIDC_OUTPUT_PAUSE }, + + {MSM_VIDC_ERROR, MSM_VIDC_ALLOW, MSM_VIDC_DRC | + MSM_VIDC_DRAIN | + MSM_VIDC_DRC_LAST_BUFFER | + MSM_VIDC_DRAIN_LAST_BUFFER | + MSM_VIDC_INPUT_PAUSE | + MSM_VIDC_OUTPUT_PAUSE }, + }; + + /* no substate to update */ + if (!sub_state) + return 0; + + /* check if any substate is disallowed */ + for (cnt = 0; cnt < ARRAY_SIZE(sub_state_allow); cnt++) { + /* skip other states */ + if (sub_state_allow[cnt].state != inst->state) + continue; + + /* continue if not disallowed */ + if (sub_state_allow[cnt].allow != MSM_VIDC_DISALLOW) + continue; + + if (sub_state_allow[cnt].sub_state_mask & sub_state) { + prepare_sub_state_name(sub_state, sub_state_name, sizeof(sub_state_name)); + i_vpr_e(inst, "%s: state (%s), disallow substate (%s)\n", + func, state_name(inst->state), sub_state_name); + return -EINVAL; + } + } + + /* remove ignorable substates from a given substate */ + for (cnt = 0; cnt < ARRAY_SIZE(sub_state_allow); cnt++) { + /* skip other states */ + if (sub_state_allow[cnt].state != inst->state) + continue; + + /* continue if not ignored */ + if (sub_state_allow[cnt].allow != MSM_VIDC_IGNORE) + continue; + + if (sub_state_allow[cnt].sub_state_mask & sub_state) { + prepare_sub_state_name(sub_state, sub_state_name, sizeof(sub_state_name)); + i_vpr_h(inst, "%s: state (%s), ignore substate (%s)\n", + func, state_name(inst->state), sub_state_name); + + /* remove ignorable substate bits from actual */ + sub_state &= ~(sub_state_allow[cnt].sub_state_mask & sub_state); + break; + } + } + + /* check if all substate bits are allowed */ + for (cnt = 0; cnt < ARRAY_SIZE(sub_state_allow); cnt++) { + /* skip other states */ + if (sub_state_allow[cnt].state != inst->state) + continue; + + /* continue if not allowed */ + if (sub_state_allow[cnt].allow != MSM_VIDC_ALLOW) + continue; + + if ((sub_state_allow[cnt].sub_state_mask & sub_state) != sub_state) { + prepare_sub_state_name(sub_state, sub_state_name, sizeof(sub_state_name)); + i_vpr_e(inst, "%s: state (%s), not all substates allowed (%s)\n", + func, state_name(inst->state), sub_state_name); + return -EINVAL; + } + } + + /* update substate */ + inst->sub_state |= sub_state; + + return rc; +} + +int msm_vidc_change_sub_state(struct msm_vidc_inst *inst, + enum msm_vidc_sub_state clear_sub_state, + enum msm_vidc_sub_state set_sub_state, const char *func) +{ + enum msm_vidc_sub_state prev_sub_state; + int rc = 0; + + if (is_session_error(inst)) { + i_vpr_h(inst, + "%s: inst is in bad state, can not change sub state\n", func); + return 0; + } + + /* final value will not change */ + if (!clear_sub_state && !set_sub_state) + return 0; + + /* sanitize clear & set value */ + if ((clear_sub_state & set_sub_state) || + (set_sub_state > MSM_VIDC_MAX_SUB_STATE_VALUE) || + (clear_sub_state > MSM_VIDC_MAX_SUB_STATE_VALUE)) { + i_vpr_e(inst, "%s: invalid sub states to clear %#x or set %#x\n", + func, clear_sub_state, set_sub_state); + return -EINVAL; + } + + prev_sub_state = inst->sub_state; + + /* set sub state */ + rc = msm_vidc_set_sub_state(inst, set_sub_state, __func__); + if (rc) + return rc; + + /* clear sub state */ + inst->sub_state &= ~clear_sub_state; + + /* print substates only when there is a change */ + if (inst->sub_state != prev_sub_state) { + rc = prepare_sub_state_name(inst->sub_state, inst->sub_state_name, + sizeof(inst->sub_state_name)); + if (!rc) + i_vpr_h(inst, "%s: state %s and sub state changed to %s\n", + func, state_name(inst->state), inst->sub_state_name); + } + + return 0; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_synx.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_synx.c new file mode 100644 index 0000000000..313a8edc11 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_synx.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include "msm_vidc_core.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_fence.h" +#include "msm_vidc_debug.h" +#include + +#define MSM_VIDC_SYNX_FENCE_CLIENT_ID SYNX_CLIENT_HW_FENCE_VID_CTX0 +#define MSM_VIDC_SYNX_CREATE_DMA_FENCE SYNX_CREATE_DMA_FENCE +#define MAX_SYNX_FENCE_SESSION_NAME 64 + +static const char *msm_vidc_synx_dma_fence_get_driver_name(struct dma_fence *df) +{ + struct msm_vidc_fence *fence; + + if (df) { + fence = container_of(df, struct msm_vidc_fence, dma_fence); + return fence->name; + } + return "msm_vidc_synx_dma_fence_get_driver_name: invalid fence"; +} + +static const char *msm_vidc_synx_dma_fence_get_timeline_name(struct dma_fence *df) +{ + struct msm_vidc_fence *fence; + + if (df) { + fence = container_of(df, struct msm_vidc_fence, dma_fence); + return fence->name; + } + return "msm_vidc_synx_dma_fence_get_timeline_name: invalid fence"; +} + +static void msm_vidc_synx_fence_release(struct dma_fence *df) +{ + struct msm_vidc_fence *fence; + int rc = 0; + + if (!df) { + d_vpr_e("%s: invalid dma fence\n", __func__); + return; + } + + fence = container_of(df, struct msm_vidc_fence, dma_fence); + if (!fence) { + d_vpr_e("%s: invalid fence\n", __func__); + return; + } + d_vpr_l("%s: name %s\n", __func__, fence->name); + + /* destroy associated synx fence */ + if (fence->session) { + rc = synx_hwfence_release((struct synx_session *)fence->session, + (u32)fence->fence_id); + if (rc) + d_vpr_e("%s: failed to destroy synx fence for %s\n", + __func__, fence->name); + } + + vfree(fence); + return; +} + +static const struct dma_fence_ops msm_vidc_synx_dma_fence_ops = { + .get_driver_name = msm_vidc_synx_dma_fence_get_driver_name, + .get_timeline_name = msm_vidc_synx_dma_fence_get_timeline_name, + .release = msm_vidc_synx_fence_release, +}; + +static struct msm_vidc_fence *msm_vidc_get_synx_fence_from_id( + struct msm_vidc_inst *inst, u64 fence_id) +{ + struct msm_vidc_fence *fence, *dummy_fence; + bool found = false; + + list_for_each_entry_safe(fence, dummy_fence, &inst->fence_list, list) { + if (fence->fence_id == fence_id) { + found = true; + break; + } + } + + if (!found) { + i_vpr_l(inst, "%s: no fence available for id: %u\n", + __func__, fence_id); + return NULL; + } + + return fence; +} + +static void msm_vidc_synx_fence_destroy(struct msm_vidc_inst *inst, u64 fence_id) +{ + struct msm_vidc_fence *fence; + + fence = msm_vidc_get_synx_fence_from_id(inst, fence_id); + if (!fence) + return; + + i_vpr_e(inst, "%s: fence %s\n", __func__, fence->name); + list_del_init(&fence->list); + + dma_fence_set_error(&fence->dma_fence, -EINVAL); + dma_fence_signal(&fence->dma_fence); + dma_fence_put(&fence->dma_fence); +} + +static int msm_vidc_synx_fence_register(struct msm_vidc_core *core) +{ + struct synx_initialization_params params; + struct synx_session *session = NULL; + char synx_session_name[MAX_SYNX_FENCE_SESSION_NAME]; + struct synx_queue_desc queue_desc; + + if (!core->capabilities[SUPPORTS_SYNX_FENCE].value) + return 0; + + /* fill synx_initialization_params */ + memset(¶ms, 0, sizeof(struct synx_initialization_params)); + memset(&queue_desc, 0, sizeof(struct synx_queue_desc)); + + params.id = (enum synx_client_id)MSM_VIDC_SYNX_FENCE_CLIENT_ID; + snprintf(synx_session_name, MAX_SYNX_FENCE_SESSION_NAME, + "video synx fence"); + params.name = synx_session_name; + params.ptr = &queue_desc; + params.flags = SYNX_INIT_MAX; /* unused */ + + session = + (struct synx_session *)synx_hwfence_initialize(¶ms); + if (IS_ERR_OR_NULL(session)) { + d_vpr_e("%s: invalid synx fence session\n", __func__); + return -EINVAL; + } + + /* fill core synx fence data */ + core->synx_fence_data.client_id = (u32)params.id; + core->synx_fence_data.client_flags = (u32)params.flags; + core->synx_fence_data.session = (void *)session; + core->synx_fence_data.queue.size = (u32)queue_desc.size; + core->synx_fence_data.queue.kvaddr = queue_desc.vaddr; + core->synx_fence_data.queue.phys_addr = (phys_addr_t)queue_desc.dev_addr; + + core->synx_fence_data.queue.type = MSM_VIDC_BUF_INTERFACE_QUEUE; + core->synx_fence_data.queue.region = MSM_VIDC_NON_SECURE; + core->synx_fence_data.queue.direction = DMA_BIDIRECTIONAL; + + d_vpr_h("%s: successfully registered synx fence\n", __func__); + return 0; +} + +static int msm_vidc_synx_fence_deregister(struct msm_vidc_core *core) +{ + int rc = 0; + + if (!core->capabilities[SUPPORTS_SYNX_FENCE].value) + return 0; + + rc = synx_hwfence_uninitialize( + (struct synx_session *)core->synx_fence_data.session); + if (rc) { + d_vpr_e("%s: failed to deregister synx fence\n", __func__); + /* ignore error */ + rc = 0; + } else { + d_vpr_l("%s: successfully deregistered synx fence\n", __func__); + } + + return rc; +} + +static struct msm_vidc_fence *msm_vidc_synx_dma_fence_create(struct msm_vidc_inst *inst) +{ + struct msm_vidc_fence *fence = NULL; + + fence = vzalloc(sizeof(*fence)); + if (!fence) { + i_vpr_e(inst, "%s: allocation failed\n", __func__); + return NULL; + } + + fence->fd = INVALID_FD; + spin_lock_init(&fence->lock); + dma_fence_init(&fence->dma_fence, &msm_vidc_synx_dma_fence_ops, + &fence->lock, inst->fence_context.ctx_num, + ++inst->fence_context.seq_num); + snprintf(fence->name, sizeof(fence->name), "synx %s: %llu", + inst->fence_context.name, inst->fence_context.seq_num); + + fence->fence_id = fence->dma_fence.seqno; + + INIT_LIST_HEAD(&fence->list); + list_add_tail(&fence->list, &inst->fence_list); + i_vpr_l(inst, "%s: created %s\n", __func__, fence->name); + + return fence; +} + +static struct msm_vidc_fence *msm_vidc_synx_fence_create(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_fence *fence = NULL; + struct msm_vidc_core *core = NULL; + struct synx_create_params params; + u32 fence_id = 0; + + core = inst->core; + + /* return if synx fence is not supported */ + if (!core->capabilities[SUPPORTS_SYNX_FENCE].value) + return NULL; + + /* create dma fence */ + fence = msm_vidc_synx_dma_fence_create(inst); + if (!fence) { + i_vpr_e(inst, "%s: failed to create dma fence\n", __func__); + return NULL; + } + + if (!core->synx_fence_data.session) { + i_vpr_e(inst, "%s: invalid synx fence session\n", __func__); + goto destroy_dma_fence; + } + + /* fill synx fence params structure */ + memset(¶ms, 0, sizeof(struct synx_create_params)); + params.name = fence->name; + params.fence = (void *)&fence->dma_fence; + params.h_synx = &fence_id; + params.flags = MSM_VIDC_SYNX_CREATE_DMA_FENCE; + + /* create hw fence */ + rc = synx_hwfence_create( + (struct synx_session *)core->synx_fence_data.session, + ¶ms); + if (rc) { + i_vpr_e(inst, "%s: failed to create hw fence for %s", + __func__, fence->name); + goto destroy_dma_fence; + } + + fence->fence_id = (u64)(*(params.h_synx)); + /* this copy of hw fence client handle is req. to destroy synx fence */ + fence->session = core->synx_fence_data.session; + i_vpr_l(inst, "%s: successfully created synx fence with id: %llu", + __func__, fence->fence_id); + + return fence; + +destroy_dma_fence: + msm_vidc_synx_fence_destroy(inst, fence->fence_id); + return NULL; +} + +int msm_vidc_synx_fence_create_fd(struct msm_vidc_inst *inst, + struct msm_vidc_fence *fence) +{ + int rc = 0; + + fence->fd = get_unused_fd_flags(0); + if (fence->fd < 0) { + i_vpr_e(inst, "%s: getting fd (%d) failed\n", __func__, + fence->fd); + rc = -EINVAL; + goto err_fd; + } + fence->sync_file = sync_file_create(&fence->dma_fence); + if (!fence->sync_file) { + i_vpr_e(inst, "%s: sync_file_create failed\n", __func__); + rc = -EINVAL; + goto err_sync_file; + } + fd_install(fence->fd, fence->sync_file->file); + + i_vpr_l(inst, "%s: created fd %d for fence %s\n", __func__, + fence->fd, fence->name); + + return 0; + +err_sync_file: + put_unused_fd(fence->fd); +err_fd: + return rc; +} + +static int msm_vidc_synx_fence_signal(struct msm_vidc_inst *inst, u64 fence_id) +{ + int rc = 0; + struct msm_vidc_fence *fence; + struct msm_vidc_core *core; + + core = inst->core; + + fence = msm_vidc_get_synx_fence_from_id(inst, fence_id); + if (!fence) { + i_vpr_e(inst, "%s: no fence available to signal with id: %u\n", + __func__, fence_id); + rc = -EINVAL; + goto exit; + } + + i_vpr_l(inst, "%s: fence %s\n", __func__, fence->name); + list_del_init(&fence->list); + + dma_fence_signal(&fence->dma_fence); + dma_fence_put(&fence->dma_fence); + +exit: + return rc; +} + +static void msm_vidc_synx_fence_recover(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = synx_hwfence_recover( + (enum synx_client_id)core->synx_fence_data.client_id); + if (rc) + d_vpr_e("%s: failed to recover synx fences for client id: %d", + __func__, + (enum synx_client_id)core->synx_fence_data.client_id); + + return; +} + +const struct msm_vidc_fence_ops *get_synx_fence_ops(void) +{ + static struct msm_vidc_fence_ops synx_ops; + + synx_ops.fence_register = msm_vidc_synx_fence_register; + synx_ops.fence_deregister = msm_vidc_synx_fence_deregister; + synx_ops.fence_create = msm_vidc_synx_fence_create; + synx_ops.fence_create_fd = msm_vidc_synx_fence_create_fd; + synx_ops.fence_destroy = msm_vidc_synx_fence_destroy; + synx_ops.fence_signal = msm_vidc_synx_fence_signal; + synx_ops.fence_recover = msm_vidc_synx_fence_recover; + + return &synx_ops; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_v4l2.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_v4l2.c new file mode 100644 index 0000000000..feeeb97fc7 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_v4l2.c @@ -0,0 +1,985 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_v4l2.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_core.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_debug.h" +#include "msm_vidc.h" +#include "msm_vidc_events.h" + +extern struct msm_vidc_core *g_core; + +static struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh) +{ + if (!filp || !filp->private_data) + return NULL; + return container_of(filp->private_data, + struct msm_vidc_inst, fh); +} + +unsigned int msm_v4l2_poll(struct file *filp, struct poll_table_struct *pt) +{ + int poll = 0; + struct msm_vidc_inst *inst = get_vidc_inst(filp, NULL); + + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: invalid instance\n", __func__); + return POLLERR; + } + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + poll = POLLERR; + goto exit; + } + poll = msm_vidc_poll((void *)inst, filp, pt); + if (poll) + goto exit; + +exit: + put_inst(inst); + return poll; +} + +int msm_v4l2_open(struct file *filp) +{ + struct video_device *vdev = video_devdata(filp); + struct msm_video_device *vid_dev = + container_of(vdev, struct msm_video_device, vdev); + struct msm_vidc_core *core = video_drvdata(filp); + struct msm_vidc_inst *inst; + + trace_msm_v4l2_vidc_open("START", NULL); + inst = msm_vidc_open(core, vid_dev->type); + if (!inst) { + d_vpr_e("Failed to create instance, type = %d\n", + vid_dev->type); + trace_msm_v4l2_vidc_open("END", NULL); + return -ENOMEM; + } + filp->private_data = &(inst->fh); + trace_msm_v4l2_vidc_open("END", inst); + return 0; +} + +int msm_v4l2_close(struct file *filp) +{ + int rc = 0; + struct msm_vidc_inst *inst; + + inst = get_vidc_inst(filp, NULL); + if (!inst) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + trace_msm_v4l2_vidc_close("START", inst); + + rc = msm_vidc_close(inst); + filp->private_data = NULL; + trace_msm_v4l2_vidc_close("END", NULL); + return rc; +} + +int msm_v4l2_querycap(struct file *filp, void *fh, + struct v4l2_capability *cap) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !cap) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_querycap((void *)inst, cap); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_enum_fmt(struct file *filp, void *fh, + struct v4l2_fmtdesc *f) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !f) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_enum_fmt((void *)inst, f); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_try_fmt(struct file *filp, void *fh, struct v4l2_format *f) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !f) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = inst->event_handle(inst, MSM_VIDC_TRY_FMT, f); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_s_fmt(struct file *filp, void *fh, + struct v4l2_format *f) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !f) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = inst->event_handle(inst, MSM_VIDC_S_FMT, f); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_g_fmt(struct file *filp, void *fh, + struct v4l2_format *f) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !f) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_g_fmt((void *)inst, f); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_s_selection(struct file *filp, void *fh, + struct v4l2_selection *s) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !s) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_s_selection((void *)inst, s); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_g_selection(struct file *filp, void *fh, + struct v4l2_selection *s) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !s) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_g_selection((void *)inst, s); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_s_parm(struct file *filp, void *fh, + struct v4l2_streamparm *a) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !a) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_s_param((void *)inst, a); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_g_parm(struct file *filp, void *fh, + struct v4l2_streamparm *a) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !a) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_g_param((void *)inst, a); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_reqbufs(struct file *filp, void *fh, + struct v4l2_requestbuffers *b) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !b) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = inst->event_handle(inst, MSM_VIDC_REQBUFS, b); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_querybuf(struct file *filp, void *fh, + struct v4l2_buffer *b) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !b) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_querybuf((void *)inst, b); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_create_bufs(struct file *filp, void *fh, + struct v4l2_create_buffers *b) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !b) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_create_bufs((void *)inst, b); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_prepare_buf(struct file *filp, void *fh, + struct v4l2_buffer *b) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + struct video_device *vdev = video_devdata(filp); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !b) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_prepare_buf((void *)inst, vdev->v4l2_dev->mdev, b); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_qbuf(struct file *filp, void *fh, + struct v4l2_buffer *b) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + struct video_device *vdev = video_devdata(filp); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !b) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + /* + * [1] If request_fd enabled, msm_vb2_buf_queue() is not called from here. + * instead it's called as part of msm_v4l2_request_queue(). + * Hence inst lock should be acquired in common function i.e + * msm_vb2_buf_queue, to handle both requests and non-request + * scenarios. + * [2] If request_fd is disabled, inst_lock can be acquired here. + * Acquiring inst_lock from here will ensure RO list insertion + * and deletion i.e. attach/map will happen under lock. + * Currently, request_fd is disabled. Therefore, acquire inst_lock + * from this function to ensure RO list insertion/updation is under + * lock to avoid stability usecase. + */ + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EINVAL; + goto exit; + } + + rc = msm_vidc_qbuf(inst, vdev->v4l2_dev->mdev, b); + if (rc) + goto exit; + +exit: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_dqbuf(struct file *filp, void *fh, + struct v4l2_buffer *b) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !b) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + rc = msm_vidc_dqbuf(inst, b); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_streamon(struct file *filp, void *fh, + enum v4l2_buf_type i) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto exit; + } + + rc = msm_vidc_streamon((void *)inst, i); + if (rc) + goto exit; + +exit: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_streamoff(struct file *filp, void *fh, + enum v4l2_buf_type i) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + rc = msm_vidc_streamoff((void *)inst, i); + if (rc) + i_vpr_e(inst, "%s: msm_vidc_stramoff failed\n", __func__); + + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + struct msm_vidc_inst *inst; + int rc = 0; + + inst = container_of(fh, struct msm_vidc_inst, fh); + inst = get_inst_ref(g_core, inst); + if (!inst || !sub) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_subscribe_event((void *)inst, sub); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + struct msm_vidc_inst *inst; + int rc = 0; + + inst = container_of(fh, struct msm_vidc_inst, fh); + inst = get_inst_ref(g_core, inst); + if (!inst || !sub) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + rc = msm_vidc_unsubscribe_event((void *)inst, sub); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_try_decoder_cmd(struct file *filp, void *fh, + struct v4l2_decoder_cmd *dec) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !dec) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)dec); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_decoder_cmd(struct file *filp, void *fh, + struct v4l2_decoder_cmd *dec) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + enum msm_vidc_event event; + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + if (!dec) { + i_vpr_e(inst, "%s: invalid params\n", __func__); + rc = -EINVAL; + goto unlock; + } + if (dec->cmd != V4L2_DEC_CMD_START && + dec->cmd != V4L2_DEC_CMD_STOP) { + i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, dec->cmd); + rc = -EINVAL; + goto unlock; + } + event = (dec->cmd == V4L2_DEC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP); + rc = inst->event_handle(inst, event, NULL); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_try_encoder_cmd(struct file *filp, void *fh, + struct v4l2_encoder_cmd *enc) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !enc) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_try_cmd(inst, (union msm_v4l2_cmd *)enc); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_encoder_cmd(struct file *filp, void *fh, + struct v4l2_encoder_cmd *enc) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + enum msm_vidc_event event; + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + if (!enc) { + i_vpr_e(inst, "%s: invalid params\n", __func__); + rc = -EINVAL; + goto unlock; + } + if (enc->cmd != V4L2_ENC_CMD_START && + enc->cmd != V4L2_ENC_CMD_STOP) { + i_vpr_e(inst, "%s: invalid cmd %#x\n", __func__, enc->cmd); + rc = -EINVAL; + goto unlock; + } + event = (enc->cmd == V4L2_ENC_CMD_START ? MSM_VIDC_CMD_START : MSM_VIDC_CMD_STOP); + rc = inst->event_handle(inst, event, NULL); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_enum_framesizes(struct file *filp, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !fsize) { + d_vpr_e("%s: invalid params: %pK %pK\n", + __func__, inst, fsize); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_enum_framesizes((void *)inst, fsize); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_enum_frameintervals(struct file *filp, void *fh, + struct v4l2_frmivalenum *fival) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !fival) { + d_vpr_e("%s: invalid params: %pK %pK\n", + __func__, inst, fival); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_enum_frameintervals((void *)inst, fival); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_queryctrl(struct file *filp, void *fh, + struct v4l2_queryctrl *ctrl) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !ctrl) { + d_vpr_e("%s: invalid instance\n", __func__); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_query_ctrl((void *)inst, ctrl); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_querymenu(struct file *filp, void *fh, + struct v4l2_querymenu *qmenu) +{ + struct msm_vidc_inst *inst = get_vidc_inst(filp, fh); + int rc = 0; + + inst = get_inst_ref(g_core, inst); + if (!inst || !qmenu) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, inst, qmenu); + return -EINVAL; + } + + client_lock(inst, __func__); + inst_lock(inst, __func__); + if (is_session_error(inst)) { + i_vpr_e(inst, "%s: inst in error state\n", __func__); + rc = -EBUSY; + goto unlock; + } + rc = msm_vidc_query_menu((void *)inst, qmenu); + if (rc) + goto unlock; + +unlock: + inst_unlock(inst, __func__); + client_unlock(inst, __func__); + put_inst(inst); + + return rc; +} + +int msm_v4l2_request_validate(struct media_request *req) +{ + d_vpr_l("%s()\n", __func__); + return vb2_request_validate(req); +} + +void msm_v4l2_request_queue(struct media_request *req) +{ + d_vpr_l("%s()\n", __func__); + v4l2_m2m_request_queue(req); +} + +void msm_v4l2_m2m_device_run(void *priv) +{ + d_vpr_l("%s()\n", __func__); +} + +void msm_v4l2_m2m_job_abort(void *priv) +{ + struct msm_vidc_inst *inst = priv; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + i_vpr_h(inst, "%s: m2m job aborted\n", __func__); + v4l2_m2m_job_finish(inst->m2m_dev, inst->m2m_ctx); +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_vb2.c b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_vb2.c new file mode 100644 index 0000000000..8b02303a6d --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/msm_vidc_vb2.c @@ -0,0 +1,694 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "msm_vidc_vb2.h" +#include "msm_vidc_core.h" +#include "msm_vidc_inst.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_power.h" +#include "msm_vidc_debug.h" +#include "msm_vdec.h" +#include "msm_venc.h" +#include "msm_vidc_control.h" +#include "msm_vidc_platform.h" + +extern struct msm_vidc_core *g_core; + +struct vb2_queue *msm_vidc_get_vb2q(struct msm_vidc_inst *inst, + u32 type, const char *func) +{ + struct vb2_queue *q = NULL; + + if (type == INPUT_MPLANE) { + q = inst->bufq[INPUT_PORT].vb2q; + } else if (type == OUTPUT_MPLANE) { + q = inst->bufq[OUTPUT_PORT].vb2q; + } else if (type == INPUT_META_PLANE) { + q = inst->bufq[INPUT_META_PORT].vb2q; + } else if (type == OUTPUT_META_PLANE) { + q = inst->bufq[OUTPUT_META_PORT].vb2q; + } else { + i_vpr_e(inst, "%s: invalid buffer type %d\n", + __func__, type); + } + return q; +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 15, 0)) +void *msm_vb2_alloc(struct device *dev, unsigned long attrs, + unsigned long size, enum dma_data_direction dma_dir, + gfp_t gfp_flags) +{ + return (void *)0xdeadbeef; +} + +void *msm_vb2_attach_dmabuf(struct device *dev, struct dma_buf *dbuf, + unsigned long size, enum dma_data_direction dma_dir) +{ + return (void *)0xdeadbeef; +} + +#else +void *msm_vb2_alloc(struct vb2_buffer *vb, struct device *dev, + unsigned long size) +{ + return (void *)0xdeadbeef; +} + +void *msm_vb2_attach_dmabuf(struct vb2_buffer *vb, struct device *dev, + struct dma_buf *dbuf, unsigned long size) +{ + struct msm_vidc_inst *inst; + struct msm_vidc_core *core; + struct msm_vidc_buffer *buf = NULL; + + if (!vb || !dev || !dbuf || !vb->vb2_queue) { + d_vpr_e("%s: invalid params\n", __func__); + return NULL; + } + inst = vb->vb2_queue->drv_priv; + inst = get_inst_ref(g_core, inst); + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return NULL; + } + core = inst->core; + + buf = msm_vidc_fetch_buffer(inst, vb); + if (!buf) { + i_vpr_e(inst, "%s: failed to fetch buffer\n", __func__); + buf = NULL; + goto exit; + } + buf->inst = inst; + + buf->attach = call_mem_op(core, dma_buf_attach, core, dbuf, dev); + if (!buf->attach) { + buf->attach = NULL; + buf = NULL; + goto exit; + } + buf->dmabuf = dbuf; + print_vidc_buffer(VIDC_LOW, "low ", "attach", inst, buf); + +exit: + if (!buf) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + put_inst(inst); + return buf; +} +#endif + +void msm_vb2_put(void *buf_priv) +{ +} + +int msm_vb2_mmap(void *buf_priv, struct vm_area_struct *vma) +{ + return 0; +} + +void msm_vb2_detach_dmabuf(void *buf_priv) +{ + struct msm_vidc_buffer *vbuf = buf_priv; + struct msm_vidc_buffer *ro_buf, *dummy; + struct msm_vidc_core *core; + struct msm_vidc_inst *inst; + + if (!vbuf || !vbuf->inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + inst = vbuf->inst; + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return; + } + core = inst->core; + + if (is_decode_session(inst) && is_output_buffer(vbuf->type)) { + list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) { + if (ro_buf->dmabuf == vbuf->dmabuf) { + print_vidc_buffer(VIDC_LOW, "low ", "detach: found ro buf", + inst, ro_buf); + ro_buf->attach = vbuf->attach; + vbuf->attach = NULL; + goto exit; + } + } + } + + print_vidc_buffer(VIDC_LOW, "low ", "detach", inst, vbuf); + if (vbuf->attach && vbuf->dmabuf) { + call_mem_op(core, dma_buf_detach, core, vbuf->dmabuf, vbuf->attach); + vbuf->attach = NULL; + vbuf->dmabuf = NULL; + vbuf->inst = NULL; + } + vbuf->inst = NULL; + +exit: + return; +} + +int msm_vb2_map_dmabuf(void *buf_priv) +{ + int rc = 0; + struct msm_vidc_buffer *buf = buf_priv; + struct msm_vidc_core *core; + struct msm_vidc_inst *inst; + + if (!buf || !buf->inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + inst = buf->inst; + inst = get_inst_ref(g_core, inst); + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + + buf->sg_table = call_mem_op(core, dma_buf_map_attachment, core, buf->attach); + if (!buf->sg_table || !buf->sg_table->sgl) { + buf->sg_table = NULL; + rc = -ENOMEM; + goto exit; + } + buf->device_addr = sg_dma_address(buf->sg_table->sgl); + print_vidc_buffer(VIDC_HIGH, "high", "map", inst, buf); + +exit: + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + put_inst(inst); + return rc; +} + +void msm_vb2_unmap_dmabuf(void *buf_priv) +{ + struct msm_vidc_buffer *vbuf = buf_priv; + struct msm_vidc_buffer *ro_buf, *dummy; + struct msm_vidc_core *core; + struct msm_vidc_inst *inst; + + if (!vbuf || !vbuf->inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + inst = vbuf->inst; + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return; + } + core = inst->core; + + if (is_decode_session(inst) && is_output_buffer(vbuf->type)) { + list_for_each_entry_safe(ro_buf, dummy, &inst->buffers.read_only.list, list) { + if (ro_buf->dmabuf == vbuf->dmabuf) { + print_vidc_buffer(VIDC_LOW, "low ", "unmap: found ro buf", + inst, ro_buf); + ro_buf->sg_table = vbuf->sg_table; + ro_buf->attach = vbuf->attach; + vbuf->sg_table = NULL; + vbuf->device_addr = 0x0; + goto exit; + } + } + } + + print_vidc_buffer(VIDC_HIGH, "high", "unmap", inst, vbuf); + if (vbuf->attach && vbuf->sg_table) { + call_mem_op(core, dma_buf_unmap_attachment, core, vbuf->attach, vbuf->sg_table); + vbuf->sg_table = NULL; + vbuf->device_addr = 0x0; + } + +exit: + return; +} + +int msm_vb2_queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + int rc = 0; + struct msm_vidc_inst *inst; + struct msm_vidc_core *core; + int port; + struct v4l2_format *f; + enum msm_vidc_buffer_type buffer_type = 0; + enum msm_vidc_buffer_region region = MSM_VIDC_REGION_NONE; + struct context_bank_info *cb = NULL; + struct msm_vidc_buffers *buffers; + + if (!q || !num_buffers || !num_planes + || !sizes || !q->drv_priv) { + d_vpr_e("%s: invalid params, q = %pK, %pK, %pK\n", + __func__, q, num_buffers, num_planes); + return -EINVAL; + } + inst = q->drv_priv; + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params %pK\n", __func__, inst); + return -EINVAL; + } + core = inst->core; + + if (is_state(inst, MSM_VIDC_STREAMING)) { + i_vpr_e(inst, "%s: invalid state %d\n", __func__, inst->state); + return -EINVAL; + } + + port = v4l2_type_to_driver_port(inst, q->type, __func__); + if (port < 0) + return -EINVAL; + + /* prepare dependency list once per session */ + if (!inst->caps_list_prepared) { + rc = msm_vidc_prepare_dependency_list(inst); + if (rc) + return rc; + inst->caps_list_prepared = true; + } + + /* adjust v4l2 properties for master port */ + if ((is_encode_session(inst) && port == OUTPUT_PORT) || + (is_decode_session(inst) && port == INPUT_PORT)) { + rc = msm_vidc_adjust_v4l2_properties(inst); + if (rc) { + i_vpr_e(inst, "%s: failed to adjust properties\n", __func__); + return rc; + } + } + + if (*num_planes && (port == INPUT_PORT || port == OUTPUT_PORT)) { + f = &inst->fmts[port]; + if (*num_planes != f->fmt.pix_mp.num_planes) { + i_vpr_e(inst, "%s: requested num_planes %d not supported %d\n", + __func__, *num_planes, f->fmt.pix_mp.num_planes); + return -EINVAL; + } + if (sizes[0] < inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage) { + i_vpr_e(inst, "%s: requested size %d not acceptable\n", + __func__, sizes[0]); + return -EINVAL; + } + } + + buffer_type = v4l2_type_to_driver(q->type, __func__); + if (!buffer_type) + return -EINVAL; + + rc = msm_vidc_free_buffers(inst, buffer_type); + if (rc) { + i_vpr_e(inst, "%s: failed to free buffers, type %s\n", + __func__, v4l2_type_name(q->type)); + return rc; + } + + buffers = msm_vidc_get_buffers(inst, buffer_type, __func__); + if (!buffers) + return -EINVAL; + + buffers->min_count = call_session_op(core, min_count, inst, buffer_type); + buffers->extra_count = call_session_op(core, extra_count, inst, buffer_type); + if (*num_buffers < buffers->min_count + buffers->extra_count) + *num_buffers = buffers->min_count + buffers->extra_count; + buffers->actual_count = *num_buffers; + *num_planes = 1; + + buffers->size = call_session_op(core, buffer_size, inst, buffer_type); + if (port == INPUT_PORT || port == OUTPUT_PORT) { + inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage = buffers->size; + sizes[0] = inst->fmts[port].fmt.pix_mp.plane_fmt[0].sizeimage; + } else if (port == OUTPUT_META_PORT) { + inst->fmts[port].fmt.meta.buffersize = buffers->size; + sizes[0] = inst->fmts[port].fmt.meta.buffersize; + } else if (port == INPUT_META_PORT) { + inst->fmts[port].fmt.meta.buffersize = buffers->size; + if (inst->capabilities[SUPER_FRAME].value) + sizes[0] = inst->capabilities[SUPER_FRAME].value * + inst->fmts[port].fmt.meta.buffersize; + else + sizes[0] = inst->fmts[port].fmt.meta.buffersize; + } + + rc = msm_vidc_allocate_buffers(inst, buffer_type, *num_buffers); + if (rc) { + i_vpr_e(inst, "%s: failed to allocate buffers, type %s\n", + __func__, v4l2_type_name(q->type)); + return rc; + } + + region = call_mem_op(core, buffer_region, inst, buffer_type); + cb = msm_vidc_get_context_bank_for_region(core, region); + if (!cb) { + d_vpr_e("%s: Failed to get context bank device\n", + __func__); + return -EIO; + } + q->dev = cb->dev; + + i_vpr_h(inst, + "queue_setup: type %s num_buffers %d sizes[0] %d cb %s\n", + v4l2_type_name(q->type), *num_buffers, sizes[0], cb->name); + return rc; +} + +int msm_vb2_start_streaming(struct vb2_queue *q, unsigned int count) +{ + int rc = 0; + struct msm_vidc_inst *inst; + + if (!q || !q->drv_priv) { + d_vpr_e("%s: invalid input, q = %pK\n", __func__, q); + return -EINVAL; + } + inst = q->drv_priv; + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + rc = inst->event_handle(inst, MSM_VIDC_STREAMON, q); + if (rc) { + i_vpr_e(inst, "Streamon: %s failed\n", v4l2_type_name(q->type)); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + goto exit; + } + +exit: + return rc; +} + +int msm_vidc_start_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q) +{ + enum msm_vidc_buffer_type buf_type; + int rc = 0; + + if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) { + i_vpr_h(inst, "%s: nothing to start on %s\n", + __func__, v4l2_type_name(q->type)); + return 0; + } + if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); + return -EINVAL; + } + if (!is_decode_session(inst) && !is_encode_session(inst)) { + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return -EINVAL; + } + i_vpr_h(inst, "Streamon: %s\n", v4l2_type_name(q->type)); + + if (!inst->once_per_session_set) { + inst->once_per_session_set = true; + rc = msm_vidc_session_set_codec(inst); + if (rc) + return rc; + + rc = msm_vidc_session_set_secure_mode(inst); + if (rc) + return rc; + + if (is_encode_session(inst)) { + rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst, + MSM_VIDC_BUF_ARP); + if (rc) + return rc; + } else if (is_decode_session(inst)) { + rc = msm_vidc_session_set_default_header(inst); + if (rc) + return rc; + + rc = msm_vidc_alloc_and_queue_session_internal_buffers(inst, + MSM_VIDC_BUF_PERSIST); + if (rc) + return rc; + } + } + + if (is_decode_session(inst)) + inst->decode_batch.enable = msm_vidc_allow_decode_batch(inst); + + msm_vidc_allow_dcvs(inst); + msm_vidc_power_data_reset(inst); + + if (q->type == INPUT_MPLANE) { + if (is_decode_session(inst)) + rc = msm_vdec_streamon_input(inst); + else if (is_encode_session(inst)) + rc = msm_venc_streamon_input(inst); + } else if (q->type == OUTPUT_MPLANE) { + if (is_decode_session(inst)) + rc = msm_vdec_streamon_output(inst); + else if (is_encode_session(inst)) + rc = msm_venc_streamon_output(inst); + } + if (rc) + return rc; + + /* print final buffer counts & size details */ + msm_vidc_print_buffer_info(inst); + + /* print internal buffer memory usage stats */ + msm_vidc_print_memory_stats(inst); + + buf_type = v4l2_type_to_driver(q->type, __func__); + if (!buf_type) + return -EINVAL; + + /* queue pending buffers */ + rc = msm_vidc_queue_deferred_buffers(inst, buf_type); + if (rc) + return rc; + + /* initialize statistics timer(one time) */ + if (!inst->stats.time_ms) + inst->stats.time_ms = ktime_get_ns() / 1000 / 1000; + + /* schedule to print buffer statistics */ + rc = schedule_stats_work(inst); + if (rc) + return rc; + + if ((q->type == INPUT_MPLANE && inst->bufq[OUTPUT_PORT].vb2q->streaming) || + (q->type == OUTPUT_MPLANE && inst->bufq[INPUT_PORT].vb2q->streaming)) { + rc = msm_vidc_get_properties(inst); + if (rc) + return rc; + } + + i_vpr_h(inst, "Streamon: %s successful\n", v4l2_type_name(q->type)); + return rc; +} + +int msm_vidc_stop_streaming(struct msm_vidc_inst *inst, struct vb2_queue *q) +{ + int rc = 0; + + if (q->type == INPUT_META_PLANE || q->type == OUTPUT_META_PLANE) { + i_vpr_h(inst, "%s: nothing to stop on %s\n", + __func__, v4l2_type_name(q->type)); + return 0; + } + if (q->type != INPUT_MPLANE && q->type != OUTPUT_MPLANE) { + i_vpr_e(inst, "%s: invalid type %d\n", __func__, q->type); + return -EINVAL; + } + if (!is_decode_session(inst) && !is_encode_session(inst)) { + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return -EINVAL; + } + i_vpr_h(inst, "Streamoff: %s\n", v4l2_type_name(q->type)); + + if (q->type == INPUT_MPLANE) { + if (is_decode_session(inst)) + rc = msm_vdec_streamoff_input(inst); + else if (is_encode_session(inst)) + rc = msm_venc_streamoff_input(inst); + } else if (q->type == OUTPUT_MPLANE) { + if (is_decode_session(inst)) + rc = msm_vdec_streamoff_output(inst); + else if (is_encode_session(inst)) + rc = msm_venc_streamoff_output(inst); + } + if (rc) + return rc; + + /* Input port streamoff */ + if (q->type == INPUT_MPLANE) { + /* flush timestamps list */ + msm_vidc_flush_ts(inst); + + /* flush buffer_stats list */ + msm_vidc_flush_buffer_stats(inst); + } + + /* print internal buffer memory usage stats */ + msm_vidc_print_memory_stats(inst); + + i_vpr_h(inst, "Streamoff: %s successful\n", v4l2_type_name(q->type)); + return rc; +} + +void msm_vb2_stop_streaming(struct vb2_queue *q) +{ + struct msm_vidc_inst *inst; + int rc = 0; + + if (!q || !q->drv_priv) { + d_vpr_e("%s: invalid input, q = %pK\n", __func__, q); + return; + } + inst = q->drv_priv; + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + rc = inst->event_handle(inst, MSM_VIDC_STREAMOFF, q); + if (rc) { + i_vpr_e(inst, "Streamoff: %s failed\n", v4l2_type_name(q->type)); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + + return; +} + +void msm_vb2_buf_queue(struct vb2_buffer *vb2) +{ + int rc = 0; + struct msm_vidc_inst *inst; + struct msm_vidc_core *core; + u64 timestamp_us = 0; + u64 ktime_ns = ktime_get_ns(); + + if (!vb2) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + inst = vb2_get_drv_priv(vb2->vb2_queue); + if (!inst || !inst->core) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + core = inst->core; + + /* + * As part of every qbuf initalise request to true. + * If there are any dynamic controls associated with qbuf, + * they will set as part s_ctrl() from v4l2_ctrl_request_setup(). + * Once v4l2_ctrl_request_setup() is done, reset request variable. + * If the buffer does not have any requests with it, then + * v4l2_ctrl_request_setup() will return 0. + */ + if (core->capabilities[SUPPORTS_REQUESTS].value) { + /* + * If Request API is enabled: + * Call request_setup and request_complete without acquiring lock + * to avoid deadlock issues because request_setup or request_complete + * would call .s_ctrl and .g_volatile_ctrl respectively which acquire + * lock too. + */ + inst->request = true; + rc = v4l2_ctrl_request_setup(vb2->req_obj.req, + &inst->ctrl_handler); + inst->request = false; + v4l2_ctrl_request_complete(vb2->req_obj.req, &inst->ctrl_handler); + if (rc) { + i_vpr_e(inst, "%s: request setup failed, error %d\n", + __func__, rc); + goto exit; + } + } + + if (!vb2->planes[0].bytesused) { + if (vb2->type == INPUT_MPLANE) { + /* Expecting non-zero filledlen on INPUT port */ + i_vpr_e(inst, + "%s: zero bytesused input buffer not supported\n", __func__); + rc = -EINVAL; + goto exit; + } + if ((vb2->type == OUTPUT_META_PLANE && is_any_meta_tx_out_enabled(inst)) || + (vb2->type == INPUT_META_PLANE && is_any_meta_tx_inp_enabled(inst))) { + /* + * vb2 is not allowing client to pass data in output meta plane. + * adjust the bytesused as client will send buffer tag metadata + * in output meta plane if DPB_TAG_LIST, or OUTBUF_FENCE metadata + * is enabled. + */ + vb2->planes[0].bytesused = vb2->planes[0].length; + } + } + + if (is_encode_session(inst) && vb2->type == INPUT_MPLANE) { + timestamp_us = div_u64(vb2->timestamp, 1000); + msm_vidc_set_auto_framerate(inst, timestamp_us); + } + inst->last_qbuf_time_ns = ktime_ns; + + if (vb2->type == INPUT_MPLANE) { + rc = msm_vidc_update_input_rate(inst, div_u64(ktime_ns, 1000)); + if (rc) + goto exit; + } + + if (is_decode_session(inst)) + rc = msm_vdec_qbuf(inst, vb2); + else if (is_encode_session(inst)) + rc = msm_venc_qbuf(inst, vb2); + else + rc = -EINVAL; + if (rc) { + print_vb2_buffer("failed vb2-qbuf", inst, vb2); + goto exit; + } + +exit: + if (rc) { + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + vb2_buffer_done(vb2, VB2_BUF_STATE_ERROR); + } +} + +int msm_vb2_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf; + + if (!vb) { + d_vpr_e("%s: invalid vb\n", __func__); + return -EINVAL; + } + + vbuf = to_vb2_v4l2_buffer(vb); + vbuf->field = V4L2_FIELD_NONE; + return 0; +} + +void msm_vb2_request_complete(struct vb2_buffer *vb) +{ + struct msm_vidc_inst *inst; + + if (!vb) { + d_vpr_e("%s: invalid vb\n", __func__); + return; + } + inst = vb2_get_drv_priv(vb->vb2_queue); + if (!inst) { + d_vpr_e("%s: invalid inst\n", __func__); + return; + } + + i_vpr_l(inst, "%s: vb type %d, index %d\n", + __func__, vb->type, vb->index); + v4l2_ctrl_request_complete(vb->req_obj.req, &inst->ctrl_handler); +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/resources.c b/qcom/opensource/video-driver/driver/vidc/src/resources.c new file mode 100644 index 0000000000..79a49a0828 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/resources.c @@ -0,0 +1,1736 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MSM_MMRM +#include +#endif + +#include "msm_vidc_core.h" +#include "msm_vidc_power.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_platform.h" +#include "venus_hfi.h" + +/* Less than 50MBps is treated as trivial BW change */ +#define TRIVIAL_BW_THRESHOLD 50000 +#define TRIVIAL_BW_CHANGE(a, b) \ + ((a) > (b) ? (a) - (b) < TRIVIAL_BW_THRESHOLD : \ + (b) - (a) < TRIVIAL_BW_THRESHOLD) + +static struct clock_residency *get_residency_stats(struct clock_info *cl, u64 rate); +static int __update_residency_stats(struct msm_vidc_core *core, + struct clock_info *cl, u64 rate); +enum reset_state { + INIT = 1, + ASSERT, + DEASSERT, +}; + +/* A comparator to compare loads (needed later on) */ +static inline int cmp(const void *a, const void *b) +{ + /* want to sort in reverse so flip the comparison */ + return ((struct freq_table *)b)->freq - + ((struct freq_table *)a)->freq; +} + +static void __fatal_error(bool fatal) +{ + WARN_ON(fatal); +} + +static void devm_llcc_release(void *res) +{ + d_vpr_h("%s()\n", __func__); + llcc_slice_putd((struct llcc_slice_desc *)res); +} + +static struct llcc_slice_desc *devm_llcc_get(struct device *dev, u32 id) +{ + struct llcc_slice_desc *llcc = NULL; + int rc = 0; + + llcc = llcc_slice_getd(id); + if (!llcc) + return NULL; + + /** + * register release callback with devm, so that when device goes + * out of scope(during remove sequence), devm will take care of + * de-register part by invoking release callback. + */ + rc = devm_add_action_or_reset(dev, devm_llcc_release, (void *)llcc); + if (rc) + return NULL; + + return llcc; +} + +#ifdef CONFIG_MSM_MMRM +static void devm_mmrm_release(void *res) +{ + d_vpr_h("%s()\n", __func__); + mmrm_client_deregister((struct mmrm_client *)res); +} + +static struct mmrm_client *devm_mmrm_get(struct device *dev, struct mmrm_client_desc *desc) +{ + struct mmrm_client *mmrm = NULL; + int rc = 0; + + mmrm = mmrm_client_register(desc); + if (!mmrm) + return NULL; + + /** + * register release callback with devm, so that when device goes + * out of scope(during remove sequence), devm will take care of + * de-register part by invoking release callback. + */ + rc = devm_add_action_or_reset(dev, devm_mmrm_release, (void *)mmrm); + if (rc) + return NULL; + + return mmrm; +} +#endif + +static void devm_pd_release(void *res) +{ + struct device *pd = (struct device *)res; + + d_vpr_h("%s(): %s\n", __func__, dev_name(pd)); + dev_pm_domain_detach(pd, true); +} + +static struct device *devm_pd_get(struct device *dev, const char *name) +{ + struct device *pd = NULL; + int rc = 0; + + pd = dev_pm_domain_attach_by_name(dev, name); + if (!pd) { + d_vpr_e("%s: pm domain attach failed %s\n", __func__, name); + return NULL; + } + + rc = devm_add_action_or_reset(dev, devm_pd_release, (void *)pd); + if (rc) { + d_vpr_e("%s: add action or reset failed %s\n", __func__, name); + return NULL; + } + + return pd; +} + +static void devm_opp_dl_release(void *res) +{ + struct device_link *link = (struct device_link *)res; + + d_vpr_h("%s(): %s\n", __func__, dev_name(&link->link_dev)); + device_link_del(link); +} + +static int devm_opp_dl_get(struct device *dev, struct device *supplier) +{ + u32 flag = DL_FLAG_RPM_ACTIVE | DL_FLAG_PM_RUNTIME | DL_FLAG_STATELESS; + struct device_link *link = NULL; + int rc = 0; + + link = device_link_add(dev, supplier, flag); + if (!link) { + d_vpr_e("%s: device link add failed\n", __func__); + return -EINVAL; + } + + rc = devm_add_action_or_reset(dev, devm_opp_dl_release, (void *)link); + if (rc) { + d_vpr_e("%s: add action or reset failed\n", __func__); + return rc; + } + + return rc; +} + +static void devm_pm_runtime_put_sync(void *res) +{ + struct device *dev = (struct device *)res; + + d_vpr_h("%s(): %s\n", __func__, dev_name(dev)); + pm_runtime_put_sync(dev); +} + +static int devm_pm_runtime_get_sync(struct device *dev) +{ + int rc = 0; + + rc = pm_runtime_get_sync(dev); + if (rc < 0) { + d_vpr_e("%s: pm domain get sync failed\n", __func__); + return rc; + } + + rc = devm_add_action_or_reset(dev, devm_pm_runtime_put_sync, (void *)dev); + if (rc) { + d_vpr_e("%s: add action or reset failed\n", __func__); + return rc; + } + + return rc; +} + +static int __opp_set_rate(struct msm_vidc_core *core, u64 freq) +{ + unsigned long opp_freq = 0; + struct dev_pm_opp *opp; + int rc = 0; + + opp_freq = freq; + + /* find max(ceil) freq from opp table */ + opp = dev_pm_opp_find_freq_ceil(&core->pdev->dev, &opp_freq); + if (IS_ERR(opp)) { + opp = dev_pm_opp_find_freq_floor(&core->pdev->dev, &opp_freq); + if (IS_ERR(opp)) { + d_vpr_e("%s: unable to find freq %lld in opp table\n", __func__, freq); + return -EINVAL; + } + } + dev_pm_opp_put(opp); + + /* print freq value */ + d_vpr_h("%s: set rate %lld (requested %lld)\n", + __func__, opp_freq, freq); + + /* scale freq to power up mxc & mmcx */ + rc = dev_pm_opp_set_rate(&core->pdev->dev, opp_freq); + if (rc) { + d_vpr_e("%s: failed to set rate\n", __func__); + return rc; + } + + return rc; +} + +static int __init_register_base(struct msm_vidc_core *core) +{ + struct msm_vidc_resource *res; + + res = core->resource; + + res->register_base_addr = devm_platform_ioremap_resource(core->pdev, 0); + if (IS_ERR(res->register_base_addr)) { + d_vpr_e("%s: map reg addr failed %ld\n", + __func__, PTR_ERR(res->register_base_addr)); + return -EINVAL; + } + d_vpr_h("%s: reg_base %#x\n", __func__, res->register_base_addr); + + return 0; +} + +static int __init_irq(struct msm_vidc_core *core) +{ + struct msm_vidc_resource *res; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 16, 0)) + struct resource *kres; +#endif + int rc = 0; + + res = core->resource; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0)) + res->irq = platform_get_irq(core->pdev, 0); +#else + kres = platform_get_resource(core->pdev, IORESOURCE_IRQ, 0); + res->irq = kres ? kres->start : -1; +#endif + if (res->irq < 0) + d_vpr_e("%s: get irq failed, %d\n", __func__, res->irq); + + d_vpr_h("%s: irq %d\n", __func__, res->irq); + + rc = devm_request_threaded_irq(&core->pdev->dev, res->irq, venus_hfi_isr, + venus_hfi_isr_handler, IRQF_TRIGGER_HIGH, "msm-vidc", core); + if (rc) { + d_vpr_e("%s: Failed to allocate venus IRQ\n", __func__); + return rc; + } + disable_irq_nosync(res->irq); + + return rc; +} + +static int __init_bus(struct msm_vidc_core *core) +{ + const struct bw_table *bus_tbl; + struct bus_set *interconnects; + struct bus_info *binfo = NULL; + u32 bus_count = 0, cnt = 0; + int rc = 0; + + interconnects = &core->resource->bus_set; + + bus_tbl = core->platform->data.bw_tbl; + bus_count = core->platform->data.bw_tbl_size; + + if (!bus_tbl || !bus_count) { + d_vpr_e("%s: invalid bus tbl %#x or count %d\n", + __func__, bus_tbl, bus_count); + return -EINVAL; + } + + /* allocate bus_set */ + interconnects->bus_tbl = devm_kzalloc(&core->pdev->dev, + sizeof(*interconnects->bus_tbl) * bus_count, GFP_KERNEL); + if (!interconnects->bus_tbl) { + d_vpr_e("%s: failed to alloc memory for bus table\n", __func__); + return -ENOMEM; + } + interconnects->count = bus_count; + + /* populate bus field from platform data */ + for (cnt = 0; cnt < interconnects->count; cnt++) { + interconnects->bus_tbl[cnt].name = bus_tbl[cnt].name; + interconnects->bus_tbl[cnt].min_kbps = bus_tbl[cnt].min_kbps; + interconnects->bus_tbl[cnt].max_kbps = bus_tbl[cnt].max_kbps; + } + + /* print bus fields */ + venus_hfi_for_each_bus(core, binfo) { + d_vpr_h("%s: name %s min_kbps %u max_kbps %u\n", + __func__, binfo->name, binfo->min_kbps, binfo->max_kbps); + } + + /* get interconnect handle */ + venus_hfi_for_each_bus(core, binfo) { + if (!strcmp(binfo->name, "venus-llcc")) { + if (msm_vidc_syscache_disable) { + d_vpr_h("%s: skipping LLC bus init: %s\n", __func__, + binfo->name); + continue; + } + } + binfo->icc = devm_of_icc_get(&core->pdev->dev, binfo->name); + if (IS_ERR_OR_NULL(binfo->icc)) { + d_vpr_e("%s: failed to get bus: %s\n", __func__, binfo->name); + rc = PTR_ERR(binfo->icc) ? + PTR_ERR(binfo->icc) : -EBADHANDLE; + binfo->icc = NULL; + return rc; + } + } + + return rc; +} + +static int __init_power_domains(struct msm_vidc_core *core) +{ + struct power_domain_info *pdinfo = NULL; + const struct pd_table *pd_tbl; + struct power_domain_set *pds; + struct device **opp_vdevs = NULL; + const char * const *opp_tbl; + u32 pd_count = 0, opp_count = 0, cnt = 0; + int rc = 0; + + pds = &core->resource->power_domain_set; + + pd_tbl = core->platform->data.pd_tbl; + pd_count = core->platform->data.pd_tbl_size; + + /* skip init if power domain not supported */ + if (!pd_count) { + d_vpr_h("%s: power domain entries not available in db\n", __func__); + return 0; + } + + /* sanitize power domain table */ + if (!pd_tbl) { + d_vpr_e("%s: invalid power domain tbl\n", __func__); + return -EINVAL; + } + + /* allocate power_domain_set */ + pds->power_domain_tbl = devm_kzalloc(&core->pdev->dev, + sizeof(*pds->power_domain_tbl) * pd_count, GFP_KERNEL); + if (!pds->power_domain_tbl) { + d_vpr_e("%s: failed to alloc memory for pd table\n", __func__); + return -ENOMEM; + } + pds->count = pd_count; + + /* populate power domain fields */ + for (cnt = 0; cnt < pds->count; cnt++) + pds->power_domain_tbl[cnt].name = pd_tbl[cnt].name; + + /* print power domain fields */ + venus_hfi_for_each_power_domain(core, pdinfo) + d_vpr_h("%s: pd name %s\n", __func__, pdinfo->name); + + /* get power domain handle */ + venus_hfi_for_each_power_domain(core, pdinfo) { + pdinfo->genpd_dev = devm_pd_get(&core->pdev->dev, pdinfo->name); + if (IS_ERR_OR_NULL(pdinfo->genpd_dev)) { + rc = PTR_ERR(pdinfo->genpd_dev) ? + PTR_ERR(pdinfo->genpd_dev) : -EBADHANDLE; + d_vpr_e("%s: failed to get pd: %s\n", __func__, pdinfo->name); + pdinfo->genpd_dev = NULL; + return rc; + } + } + + opp_tbl = core->platform->data.opp_tbl; + opp_count = core->platform->data.opp_tbl_size; + + /* skip init if opp not supported */ + if (opp_count < 2) { + d_vpr_h("%s: opp entries not available\n", __func__); + return 0; + } + + /* sanitize opp table */ + if (!opp_tbl) { + d_vpr_e("%s: invalid opp table\n", __func__); + return -EINVAL; + } + + /* ignore NULL entry at the end of table */ + opp_count -= 1; + + /* print opp table entries */ + for (cnt = 0; cnt < opp_count; cnt++) + d_vpr_h("%s: opp name %s\n", __func__, opp_tbl[cnt]); + + /* populate opp power domains(for rails) */ + //rc = devm_pm_opp_attach_genpd(&core->pdev->dev, opp_tbl, &opp_vdevs); + rc = -EINVAL; + if (rc) + return rc; + + /* create device_links b/w consumer(dev) and multiple suppliers(mx, mmcx) */ + for (cnt = 0; cnt < opp_count; cnt++) { + rc = devm_opp_dl_get(&core->pdev->dev, opp_vdevs[cnt]); + if (rc) { + d_vpr_e("%s: failed to create dl: %s\n", + __func__, dev_name(opp_vdevs[cnt])); + return rc; + } + } + + /* initialize opp table from device tree */ + rc = devm_pm_opp_of_add_table(&core->pdev->dev); + if (rc) { + d_vpr_e("%s: failed to add opp table\n", __func__); + return rc; + } + + /** + * 1. power up mx & mmcx supply for RCG(mvs0_clk_src) + * 2. power up gdsc0c for mvs0c branch clk + * 3. power up gdsc0 for mvs0 branch clk + */ + + /** + * power up mxc, mmcx rails to enable supply for + * RCG(video_cc_mvs0_clk_src) + */ + /* enable runtime pm */ + rc = devm_pm_runtime_enable(&core->pdev->dev); + if (rc) { + d_vpr_e("%s: failed to enable runtime pm\n", __func__); + return rc; + } + /* power up rails(mxc & mmcx) */ + rc = devm_pm_runtime_get_sync(&core->pdev->dev); + if (rc) { + d_vpr_e("%s: failed to get sync runtime pm\n", __func__); + return rc; + } + + return rc; +} + +static int __init_clocks(struct msm_vidc_core *core) +{ + struct clock_residency *residency = NULL; + const struct clk_table *clk_tbl; + struct freq_table *freq_tbl; + struct clock_set *clocks; + struct clock_info *cinfo = NULL; + u32 clk_count = 0, freq_count = 0; + int fcnt = 0, cnt = 0, rc = 0; + + clocks = &core->resource->clock_set; + + clk_tbl = core->platform->data.clk_tbl; + clk_count = core->platform->data.clk_tbl_size; + + if (!clk_tbl || !clk_count) { + d_vpr_e("%s: invalid clock tbl %#x or count %d\n", + __func__, clk_tbl, clk_count); + return -EINVAL; + } + + /* allocate clock_set */ + clocks->clock_tbl = devm_kzalloc(&core->pdev->dev, + sizeof(*clocks->clock_tbl) * clk_count, GFP_KERNEL); + if (!clocks->clock_tbl) { + d_vpr_e("%s: failed to alloc memory for clock table\n", __func__); + return -ENOMEM; + } + clocks->count = clk_count; + + /* populate clock field from platform data */ + for (cnt = 0; cnt < clocks->count; cnt++) { + clocks->clock_tbl[cnt].name = clk_tbl[cnt].name; + clocks->clock_tbl[cnt].clk_id = clk_tbl[cnt].clk_id; + clocks->clock_tbl[cnt].has_scaling = clk_tbl[cnt].scaling; + } + + freq_tbl = core->platform->data.freq_tbl; + freq_count = core->platform->data.freq_tbl_size; + + /* populate clk residency stats table */ + for (cnt = 0; cnt < clocks->count; cnt++) { + /* initialize residency_list */ + INIT_LIST_HEAD(&clocks->clock_tbl[cnt].residency_list); + + /* skip if scaling not supported */ + if (!clocks->clock_tbl[cnt].has_scaling) + continue; + + for (fcnt = 0; fcnt < freq_count; fcnt++) { + residency = devm_kzalloc(&core->pdev->dev, + sizeof(struct clock_residency), GFP_KERNEL); + if (!residency) { + d_vpr_e("%s: failed to alloc clk residency stat node\n", __func__); + return -ENOMEM; + } + + if (!freq_tbl) { + d_vpr_e("%s: invalid freq tbl %#x\n", __func__, freq_tbl); + return -EINVAL; + } + + /* update residency node */ + residency->rate = freq_tbl[fcnt].freq; + residency->start_time_us = 0; + residency->total_time_us = 0; + INIT_LIST_HEAD(&residency->list); + + /* add entry into residency_list */ + list_add_tail(&residency->list, &clocks->clock_tbl[cnt].residency_list); + } + } + + /* print clock fields */ + venus_hfi_for_each_clock(core, cinfo) { + d_vpr_h("%s: clock name %s clock id %#x scaling %d\n", + __func__, cinfo->name, cinfo->clk_id, cinfo->has_scaling); + } + + /* get clock handle */ + venus_hfi_for_each_clock(core, cinfo) { + cinfo->clk = devm_clk_get(&core->pdev->dev, cinfo->name); + if (IS_ERR_OR_NULL(cinfo->clk)) { + d_vpr_e("%s: failed to get clock: %s\n", __func__, cinfo->name); + rc = PTR_ERR(cinfo->clk) ? + PTR_ERR(cinfo->clk) : -EINVAL; + cinfo->clk = NULL; + return rc; + } + } + + return rc; +} + +static int __init_reset_clocks(struct msm_vidc_core *core) +{ + const struct clk_rst_table *rst_tbl; + struct reset_set *rsts; + struct reset_info *rinfo = NULL; + u32 rst_count = 0, cnt = 0; + int rc = 0; + + rsts = &core->resource->reset_set; + + rst_tbl = core->platform->data.clk_rst_tbl; + rst_count = core->platform->data.clk_rst_tbl_size; + + if (!rst_tbl || !rst_count) { + d_vpr_e("%s: invalid reset tbl %#x or count %d\n", + __func__, rst_tbl, rst_count); + return -EINVAL; + } + + /* allocate reset_set */ + rsts->reset_tbl = devm_kzalloc(&core->pdev->dev, + sizeof(*rsts->reset_tbl) * rst_count, GFP_KERNEL); + if (!rsts->reset_tbl) { + d_vpr_e("%s: failed to alloc memory for reset table\n", __func__); + return -ENOMEM; + } + rsts->count = rst_count; + + /* populate clock field from platform data */ + for (cnt = 0; cnt < rsts->count; cnt++) { + rsts->reset_tbl[cnt].name = rst_tbl[cnt].name; + rsts->reset_tbl[cnt].exclusive_release = rst_tbl[cnt].exclusive_release; + } + + /* print reset clock fields */ + venus_hfi_for_each_reset_clock(core, rinfo) { + d_vpr_h("%s: reset clk %s, exclusive %d\n", + __func__, rinfo->name, rinfo->exclusive_release); + } + + /* get reset clock handle */ + venus_hfi_for_each_reset_clock(core, rinfo) { + if (rinfo->exclusive_release) + rinfo->rst = devm_reset_control_get_exclusive_released( + &core->pdev->dev, rinfo->name); + else + rinfo->rst = devm_reset_control_get(&core->pdev->dev, rinfo->name); + if (IS_ERR_OR_NULL(rinfo->rst)) { + d_vpr_e("%s: failed to get reset clock: %s\n", __func__, rinfo->name); + rc = PTR_ERR(rinfo->rst) ? + PTR_ERR(rinfo->rst) : -EINVAL; + rinfo->rst = NULL; + return rc; + } + } + + return rc; +} + +static int __init_subcaches(struct msm_vidc_core *core) +{ + const struct subcache_table *llcc_tbl; + struct subcache_set *caches; + struct subcache_info *sinfo = NULL; + u32 llcc_count = 0, cnt = 0; + int rc = 0; + + caches = &core->resource->subcache_set; + + /* skip init if subcache not available */ + if (!is_sys_cache_present(core)) + return 0; + + llcc_tbl = core->platform->data.subcache_tbl; + llcc_count = core->platform->data.subcache_tbl_size; + + if (!llcc_tbl || !llcc_count) { + d_vpr_e("%s: invalid llcc tbl %#x or count %d\n", + __func__, llcc_tbl, llcc_count); + return -EINVAL; + } + + /* allocate clock_set */ + caches->subcache_tbl = devm_kzalloc(&core->pdev->dev, + sizeof(*caches->subcache_tbl) * llcc_count, GFP_KERNEL); + if (!caches->subcache_tbl) { + d_vpr_e("%s: failed to alloc memory for subcache table\n", __func__); + return -ENOMEM; + } + caches->count = llcc_count; + + /* populate subcache fields from platform data */ + for (cnt = 0; cnt < caches->count; cnt++) { + caches->subcache_tbl[cnt].name = llcc_tbl[cnt].name; + caches->subcache_tbl[cnt].llcc_id = llcc_tbl[cnt].llcc_id; + } + + /* print subcache fields */ + venus_hfi_for_each_subcache(core, sinfo) { + d_vpr_h("%s: name %s subcache id %d\n", + __func__, sinfo->name, sinfo->llcc_id); + } + + /* get subcache/llcc handle */ + venus_hfi_for_each_subcache(core, sinfo) { + sinfo->subcache = devm_llcc_get(&core->pdev->dev, sinfo->llcc_id); + if (IS_ERR_OR_NULL(sinfo->subcache)) { + d_vpr_e("%s: failed to get subcache: %d\n", __func__, sinfo->llcc_id); + rc = PTR_ERR(sinfo->subcache) ? + PTR_ERR(sinfo->subcache) : -EBADHANDLE; + sinfo->subcache = NULL; + return rc; + } + } + + return rc; +} + +static int __init_freq_table(struct msm_vidc_core *core) +{ + struct freq_table *freq_tbl; + struct freq_set *clks; + u32 freq_count = 0, cnt = 0; + int rc = 0; + + clks = &core->resource->freq_set; + + freq_tbl = core->platform->data.freq_tbl; + freq_count = core->platform->data.freq_tbl_size; + + if (!freq_tbl || !freq_count) { + d_vpr_e("%s: invalid freq tbl %#x or count %d\n", + __func__, freq_tbl, freq_count); + return -EINVAL; + } + + /* allocate freq_set */ + clks->freq_tbl = devm_kzalloc(&core->pdev->dev, + sizeof(*clks->freq_tbl) * freq_count, GFP_KERNEL); + if (!clks->freq_tbl) { + d_vpr_e("%s: failed to alloc memory for freq table\n", __func__); + return -ENOMEM; + } + clks->count = freq_count; + + /* populate freq field from platform data */ + for (cnt = 0; cnt < clks->count; cnt++) + clks->freq_tbl[cnt].freq = freq_tbl[cnt].freq; + + /* sort freq table */ + sort(clks->freq_tbl, clks->count, sizeof(*clks->freq_tbl), cmp, NULL); + + /* print freq field freq_set */ + d_vpr_h("%s: updated freq table\n", __func__); + for (cnt = 0; cnt < clks->count; cnt++) + d_vpr_h("%s:\t %lu\n", __func__, clks->freq_tbl[cnt].freq); + + return rc; +} + +static int __init_context_banks(struct msm_vidc_core *core) +{ + const struct context_bank_table *cb_tbl; + struct context_bank_set *cbs; + struct context_bank_info *cbinfo = NULL; + u32 cb_count = 0, cnt = 0; + int rc = 0; + + cbs = &core->resource->context_bank_set; + + cb_tbl = core->platform->data.context_bank_tbl; + cb_count = core->platform->data.context_bank_tbl_size; + + if (!cb_tbl || !cb_count) { + d_vpr_e("%s: invalid context bank tbl %#x or count %d\n", + __func__, cb_tbl, cb_count); + return -EINVAL; + } + + /* allocate context_bank table */ + cbs->context_bank_tbl = devm_kzalloc(&core->pdev->dev, + sizeof(*cbs->context_bank_tbl) * cb_count, GFP_KERNEL); + if (!cbs->context_bank_tbl) { + d_vpr_e("%s: failed to alloc memory for context_bank table\n", __func__); + return -ENOMEM; + } + cbs->count = cb_count; + + /** + * populate context bank field from platform data except + * dev & domain which are assigned as part of context bank + * probe sequence + */ + for (cnt = 0; cnt < cbs->count; cnt++) { + cbs->context_bank_tbl[cnt].name = cb_tbl[cnt].name; + cbs->context_bank_tbl[cnt].addr_range.start = cb_tbl[cnt].start; + cbs->context_bank_tbl[cnt].addr_range.size = cb_tbl[cnt].size; + cbs->context_bank_tbl[cnt].secure = cb_tbl[cnt].secure; + cbs->context_bank_tbl[cnt].dma_coherant = cb_tbl[cnt].dma_coherant; + cbs->context_bank_tbl[cnt].region = cb_tbl[cnt].region; + cbs->context_bank_tbl[cnt].dma_mask = cb_tbl[cnt].dma_mask; + } + + /* print context_bank fiels */ + venus_hfi_for_each_context_bank(core, cbinfo) { + d_vpr_h("%s: name %s addr start %#x size %#x secure %d " + "coherant %d region %d dma_mask %llu\n", + __func__, cbinfo->name, cbinfo->addr_range.start, + cbinfo->addr_range.size, cbinfo->secure, + cbinfo->dma_coherant, cbinfo->region, cbinfo->dma_mask); + } + + return rc; +} + +static int __init_device_region(struct msm_vidc_core *core) +{ + const struct device_region_table *dev_reg_tbl; + struct device_region_set *dev_set; + struct device_region_info *dev_reg_info; + u32 dev_reg_count = 0, cnt = 0; + int rc = 0; + + dev_set = &core->resource->device_region_set; + + dev_reg_tbl = core->platform->data.dev_reg_tbl; + dev_reg_count = core->platform->data.dev_reg_tbl_size; + + if (!dev_reg_tbl || !dev_reg_count) { + d_vpr_h("%s: device regions not available\n", __func__); + return 0; + } + + /* allocate device region table */ + dev_set->device_region_tbl = devm_kzalloc(&core->pdev->dev, + sizeof(*dev_set->device_region_tbl) * dev_reg_count, GFP_KERNEL); + if (!dev_set->device_region_tbl) { + d_vpr_e("%s: failed to alloc memory for device region table\n", __func__); + return -ENOMEM; + } + dev_set->count = dev_reg_count; + + /* populate device region fields from platform data */ + for (cnt = 0; cnt < dev_set->count; cnt++) { + dev_set->device_region_tbl[cnt].name = dev_reg_tbl[cnt].name; + dev_set->device_region_tbl[cnt].phy_addr = dev_reg_tbl[cnt].phy_addr; + dev_set->device_region_tbl[cnt].size = dev_reg_tbl[cnt].size; + dev_set->device_region_tbl[cnt].dev_addr = dev_reg_tbl[cnt].dev_addr; + dev_set->device_region_tbl[cnt].region = dev_reg_tbl[cnt].region; + } + + /* print device region fields */ + venus_hfi_for_each_device_region(core, dev_reg_info) { + d_vpr_h("%s: name %s phy_addr %#x size %#x dev_addr %#x dev_region %d\n", + __func__, dev_reg_info->name, dev_reg_info->phy_addr, dev_reg_info->size, + dev_reg_info->dev_addr, dev_reg_info->region); + } + + return rc; +} + +#ifdef CONFIG_MSM_MMRM +static int __register_mmrm(struct msm_vidc_core *core) +{ + int rc = 0; + struct clock_info *cl; + + /* skip if platform does not support mmrm */ + if (!is_mmrm_supported(core)) { + d_vpr_h("%s: MMRM not supported\n", __func__); + return 0; + } + + /* get mmrm handle for each clock sources */ + venus_hfi_for_each_clock(core, cl) { + struct mmrm_client_desc desc; + char *name = (char *)desc.client_info.desc.name; + + // TODO: set notifier data vals + struct mmrm_client_notifier_data notifier_data = { + MMRM_CLIENT_RESOURCE_VALUE_CHANGE, + {{0, 0}}, + NULL}; + + // TODO: add callback fn + desc.notifier_callback_fn = NULL; + + if (!cl->has_scaling) + continue; + + if (IS_ERR_OR_NULL(cl->clk)) { + d_vpr_e("%s: Invalid clock: %s\n", __func__, cl->name); + return PTR_ERR(cl->clk) ? PTR_ERR(cl->clk) : -EINVAL; + } + + desc.client_type = MMRM_CLIENT_CLOCK; + desc.client_info.desc.client_domain = MMRM_CLIENT_DOMAIN_VIDEO; + desc.client_info.desc.client_id = cl->clk_id; + strscpy(name, cl->name, sizeof(desc.client_info.desc.name)); + desc.client_info.desc.clk = cl->clk; + desc.priority = MMRM_CLIENT_PRIOR_LOW; + desc.pvt_data = notifier_data.pvt_data; + + d_vpr_h("%s: domain(%d) cid(%d) name(%s) clk(%pK)\n", + __func__, + desc.client_info.desc.client_domain, + desc.client_info.desc.client_id, + desc.client_info.desc.name, + desc.client_info.desc.clk); + + d_vpr_h("%s: type(%d) pri(%d) pvt(%pK) notifier(%pK)\n", + __func__, + desc.client_type, + desc.priority, + desc.pvt_data, + desc.notifier_callback_fn); + + cl->mmrm_client = devm_mmrm_get(&core->pdev->dev, &desc); + if (!cl->mmrm_client) { + d_vpr_e("%s: Failed to register clk(%s): %d\n", + __func__, cl->name, rc); + return -EINVAL; + } + } + + return rc; +} +#else +static int __register_mmrm(struct msm_vidc_core *core) +{ + return 0; +} +#endif + +static int __enable_power_domains(struct msm_vidc_core *core, const char *name) +{ + struct power_domain_info *pdinfo = NULL; + int rc = 0; + + /* power up rails(mxc & mmcx) to enable RCG(video_cc_mvs0_clk_src) */ + rc = __opp_set_rate(core, ULONG_MAX); + if (rc) { + d_vpr_e("%s: opp setrate failed\n", __func__); + return rc; + } + + /* power up (gdsc0/gdsc0c) to enable (mvs0/mvs0c) branch clock */ + venus_hfi_for_each_power_domain(core, pdinfo) { + if (strcmp(pdinfo->name, name)) + continue; + + rc = pm_runtime_get_sync(pdinfo->genpd_dev); + if (rc < 0) { + d_vpr_e("%s: failed to get sync: %s\n", __func__, pdinfo->name); + return rc; + } + d_vpr_h("%s: enabled power doamin %s\n", __func__, pdinfo->name); + } + + return rc; +} + +static int __disable_power_domains(struct msm_vidc_core *core, const char *name) +{ + struct power_domain_info *pdinfo = NULL; + int rc = 0; + + /* power down (gdsc0/gdsc0c) to disable (mvs0/mvs0c) branch clock */ + venus_hfi_for_each_power_domain(core, pdinfo) { + if (strcmp(pdinfo->name, name)) + continue; + + rc = pm_runtime_put_sync(pdinfo->genpd_dev); + if (rc) { + d_vpr_e("%s: failed to put sync: %s\n", __func__, pdinfo->name); + return rc; + } + d_vpr_h("%s: disabled power doamin %s\n", __func__, pdinfo->name); + } + + /* power down rails(mxc & mmcx) to disable RCG(video_cc_mvs0_clk_src) */ + rc = __opp_set_rate(core, 0); + if (rc) { + d_vpr_e("%s: opp setrate failed\n", __func__); + return rc; + } + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__); + + return rc; +} + +static int __hand_off_power_domains(struct msm_vidc_core *core) +{ + msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_GDSC_HANDOFF, __func__); + + return 0; +} + +static int __acquire_power_domains(struct msm_vidc_core *core) +{ + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__); + + return 0; +} + +static int __disable_subcaches(struct msm_vidc_core *core) +{ + struct subcache_info *sinfo; + int rc = 0; + + if (msm_vidc_syscache_disable || !is_sys_cache_present(core)) + return 0; + + /* De-activate subcaches */ + venus_hfi_for_each_subcache_reverse(core, sinfo) { + if (!sinfo->isactive) + continue; + + d_vpr_h("%s: De-activate subcache %s\n", __func__, sinfo->name); + rc = llcc_slice_deactivate(sinfo->subcache); + if (rc) { + d_vpr_e("Failed to de-activate %s: %d\n", + sinfo->name, rc); + } + sinfo->isactive = false; + } + + return 0; +} + +static int __enable_subcaches(struct msm_vidc_core *core) +{ + int rc = 0; + u32 c = 0; + struct subcache_info *sinfo; + + if (msm_vidc_syscache_disable || !is_sys_cache_present(core)) + return 0; + + /* Activate subcaches */ + venus_hfi_for_each_subcache(core, sinfo) { + rc = llcc_slice_activate(sinfo->subcache); + if (rc) { + d_vpr_e("Failed to activate %s: %d\n", sinfo->name, rc); + __fatal_error(true); + goto err_activate_fail; + } + sinfo->isactive = true; + d_vpr_h("Activated subcache %s\n", sinfo->name); + c++; + } + + d_vpr_h("Activated %d Subcaches to Venus\n", c); + + return 0; + +err_activate_fail: + __disable_subcaches(core); + return rc; +} + +static int llcc_enable(struct msm_vidc_core *core, bool enable) +{ + int ret; + + if (enable) + ret = __enable_subcaches(core); + else + ret = __disable_subcaches(core); + + return ret; +} + +static int __vote_bandwidth(struct bus_info *bus, unsigned long bw_kbps) +{ + int rc = 0; + + if (!bus->icc) { + d_vpr_e("%s: invalid bus\n", __func__); + return -EINVAL; + } + + d_vpr_p("Voting bus %s to ab %lu kBps\n", bus->name, bw_kbps); + + rc = icc_set_bw(bus->icc, bw_kbps, 0); + if (rc) + d_vpr_e("Failed voting bus %s to ab %lu, rc=%d\n", + bus->name, bw_kbps, rc); + + return rc; +} + +static int __unvote_buses(struct msm_vidc_core *core) +{ + int rc = 0; + struct bus_info *bus = NULL; + + core->power.bw_ddr = 0; + core->power.bw_llcc = 0; + + venus_hfi_for_each_bus(core, bus) { + rc = __vote_bandwidth(bus, 0); + if (rc) + goto err_unknown_device; + } + +err_unknown_device: + return rc; +} + +static int __vote_buses(struct msm_vidc_core *core, + unsigned long bw_ddr, unsigned long bw_llcc) +{ + int rc = 0; + struct bus_info *bus = NULL; + unsigned long bw_kbps = 0, bw_prev = 0; + enum vidc_bus_type type; + + venus_hfi_for_each_bus(core, bus) { + if (bus && bus->icc) { + type = get_type_frm_name(bus->name); + + if (type == DDR) { + bw_kbps = bw_ddr; + bw_prev = core->power.bw_ddr; + } else if (type == LLCC) { + bw_kbps = bw_llcc; + bw_prev = core->power.bw_llcc; + } else { + bw_kbps = bus->max_kbps; + bw_prev = core->power.bw_ddr ? + bw_kbps : 0; + } + + /* ensure freq is within limits */ + bw_kbps = clamp_t(typeof(bw_kbps), bw_kbps, + bus->min_kbps, bus->max_kbps); + + if (TRIVIAL_BW_CHANGE(bw_kbps, bw_prev) && bw_prev) { + d_vpr_l("Skip voting bus %s to %lu kBps\n", + bus->name, bw_kbps); + continue; + } + + rc = __vote_bandwidth(bus, bw_kbps); + + if (type == DDR) + core->power.bw_ddr = bw_kbps; + else if (type == LLCC) + core->power.bw_llcc = bw_kbps; + } else { + d_vpr_e("No BUS to Vote\n"); + } + } + + return rc; +} + +static int set_bw(struct msm_vidc_core *core, unsigned long bw_ddr, + unsigned long bw_llcc) +{ + if (!bw_ddr && !bw_llcc) + return __unvote_buses(core); + + return __vote_buses(core, bw_ddr, bw_llcc); +} + +static int print_residency_stats(struct msm_vidc_core *core, struct clock_info *cl) +{ + struct clock_residency *residency = NULL; + u64 total_time_us = 0; + int rc = 0; + + /* skip if scaling not supported */ + if (!cl->has_scaling) + return 0; + + /* grand total residency time */ + list_for_each_entry(residency, &cl->residency_list, list) + total_time_us += residency->total_time_us; + + /* sanity check to avoid divide by 0 */ + total_time_us = (total_time_us > 0) ? total_time_us : 1; + + /* print residency percent for each clock */ + list_for_each_entry(residency, &cl->residency_list, list) { + d_vpr_hs("%s: %s clock rate [%d] total %lluus residency %u%%\n", + __func__, cl->name, residency->rate, residency->total_time_us, + (residency->total_time_us * 100 + total_time_us / 2) / total_time_us); + } + + return rc; +} + +static int reset_residency_stats(struct msm_vidc_core *core, struct clock_info *cl) +{ + struct clock_residency *residency = NULL; + int rc = 0; + + /* skip if scaling not supported */ + if (!cl->has_scaling) + return 0; + + d_vpr_h("%s: reset %s residency stats\n", __func__, cl->name); + + /* reset clock residency stats */ + list_for_each_entry(residency, &cl->residency_list, list) { + residency->start_time_us = 0; + residency->total_time_us = 0; + } + /* + * During the reset make sure to update start time of the clk prev freq, + * because the prev clk freq might not be 0 so when the next seesion start + * voting from that freq, then those resideny print will not come in stats + */ + residency = get_residency_stats(cl, cl->prev); + if (residency) + residency->start_time_us = ktime_get_ns() / 1000; + return rc; +} + +static struct clock_residency *get_residency_stats(struct clock_info *cl, u64 rate) +{ + struct clock_residency *residency = NULL; + bool found = false; + + if (!cl) { + d_vpr_e("%s: invalid params\n", __func__); + return NULL; + } + + list_for_each_entry(residency, &cl->residency_list, list) { + if (residency->rate == rate) { + found = true; + break; + } + } + + return found ? residency : NULL; +} + +static int __update_residency_stats(struct msm_vidc_core *core, + struct clock_info *cl, u64 rate) +{ + struct clock_residency *cur_residency = NULL, *prev_residency = NULL; + u64 cur_time_us = 0; + int rc = 0; + + /* skip update if high or stats logs not enabled */ + if (!(msm_vidc_debug & (VIDC_HIGH | VIDC_STAT))) + return 0; + + /* skip update if scaling not supported */ + if (!cl->has_scaling) + return 0; + + /* skip update if rate not changed */ + if (rate == cl->prev) + return 0; + + /* get current time in ns */ + cur_time_us = ktime_get_ns() / 1000; + + /* update previous rate residency end or total time */ + prev_residency = get_residency_stats(cl, cl->prev); + if (prev_residency) { + if (prev_residency->start_time_us) + prev_residency->total_time_us += cur_time_us - + prev_residency->start_time_us; + + /* reset start time us */ + prev_residency->start_time_us = 0; + } + + /* clk disable case - no need to update new entry */ + if (rate == 0) + return 0; + + /* check if rate entry is present */ + cur_residency = get_residency_stats(cl, rate); + if (!cur_residency) { + d_vpr_e("%s: entry not found. rate %llu\n", __func__, rate); + return -EINVAL; + } + + /* update residency start time for current rate/freq */ + cur_residency->start_time_us = cur_time_us; + + return rc; +} + +static int __set_clk_rate(struct msm_vidc_core *core, struct clock_info *cl, + u64 rate) +{ + int rc = 0; + + /* update clock residency stats */ + __update_residency_stats(core, cl, rate); + + /* bail early if requested clk rate is not changed */ + if (rate == cl->prev) + return 0; + + d_vpr_p("Scaling clock %s to %llu, prev %llu\n", + cl->name, rate, cl->prev); + + rc = clk_set_rate(cl->clk, rate); + if (rc) { + d_vpr_e("%s: Failed to set clock rate %llu %s: %d\n", + __func__, rate, cl->name, rc); + return rc; + } + + cl->prev = rate; + + return rc; +} + +static int __set_clocks(struct msm_vidc_core *core, u64 freq) +{ + struct clock_info *cl; + int rc = 0; + + /* scale mxc & mmcx rails */ + rc = __opp_set_rate(core, freq); + if (rc) { + d_vpr_e("%s: opp setrate failed %lld\n", __func__, freq); + return rc; + } + + venus_hfi_for_each_clock(core, cl) { + if (cl->has_scaling) { + rc = __set_clk_rate(core, cl, freq); + if (rc) + return rc; + } + } + + return 0; +} + +static int __disable_unprepare_clock(struct msm_vidc_core *core, + const char *clk_name) +{ + int rc = 0; + struct clock_info *cl; + bool found; + + found = false; + venus_hfi_for_each_clock(core, cl) { + if (!cl->clk) { + d_vpr_e("%s: invalid clock %s\n", __func__, cl->name); + return -EINVAL; + } + if (strcmp(cl->name, clk_name)) + continue; + found = true; + clk_disable_unprepare(cl->clk); + if (cl->has_scaling) + __set_clk_rate(core, cl, 0); + cl->prev = 0; + d_vpr_h("%s: clock %s disable unprepared\n", __func__, cl->name); + break; + } + if (!found) { + d_vpr_e("%s: clock %s not found\n", __func__, clk_name); + return -EINVAL; + } + + return rc; +} + +static int __prepare_enable_clock(struct msm_vidc_core *core, + const char *clk_name) +{ + int rc = 0; + struct clock_info *cl; + bool found; + u64 rate = 0; + + found = false; + venus_hfi_for_each_clock(core, cl) { + if (!cl->clk) { + d_vpr_e("%s: invalid clock\n", __func__); + return -EINVAL; + } + if (strcmp(cl->name, clk_name)) + continue; + found = true; + /* + * For the clocks we control, set the rate prior to preparing + * them. Since we don't really have a load at this point, scale + * it to the lowest frequency possible + */ + if (cl->has_scaling) { + /* reset clk residency stats */ + reset_residency_stats(core, cl); + + rate = clk_round_rate(cl->clk, 0); + /** + * source clock is already multipled with scaling ratio and __set_clk_rate + * attempts to multiply again. So divide scaling ratio before calling + * __set_clk_rate. + */ + rate = rate / MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO; + __set_clk_rate(core, cl, rate); + } + + rc = clk_prepare_enable(cl->clk); + if (rc) { + d_vpr_e("%s: failed to enable clock %s\n", + __func__, cl->name); + return rc; + } + if (!__clk_is_enabled(cl->clk)) { + d_vpr_e("%s: clock %s not enabled\n", + __func__, cl->name); + clk_disable_unprepare(cl->clk); + if (cl->has_scaling) + __set_clk_rate(core, cl, 0); + return -EINVAL; + } + d_vpr_h("%s: clock %s prepare enabled\n", __func__, cl->name); + break; + } + if (!found) { + d_vpr_e("%s: clock %s not found\n", __func__, clk_name); + return -EINVAL; + } + + return rc; +} + +static int __init_resources(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = __init_register_base(core); + if (rc) + return rc; + + rc = __init_irq(core); + if (rc) + return rc; + + rc = __init_bus(core); + if (rc) + return rc; + + rc = call_res_op(core, gdsc_init, core); + if (rc) + return rc; + + rc = __init_clocks(core); + if (rc) + return rc; + + rc = __init_reset_clocks(core); + if (rc) + return rc; + + rc = __init_subcaches(core); + if (rc) + return rc; + + rc = __init_freq_table(core); + if (rc) + return rc; + + rc = __init_context_banks(core); + if (rc) + return rc; + + rc = __init_device_region(core); + if (rc) + return rc; + + rc = __register_mmrm(core); + if (rc) + return rc; + + return rc; +} + +static int __reset_control_acquire_name(struct msm_vidc_core *core, + const char *name) +{ + struct reset_info *rcinfo = NULL; + int rc = 0, count = 0; + bool found = false; + + venus_hfi_for_each_reset_clock(core, rcinfo) { + if (strcmp(rcinfo->name, name)) + continue; + + /* this function is valid only for exclusive_release reset clocks*/ + if (!rcinfo->exclusive_release) { + d_vpr_e("%s: unsupported reset control (%s), exclusive %d\n", + __func__, name, rcinfo->exclusive_release); + return -EINVAL; + } + + found = true; + /* reset_control_acquire is exposed in kernel version 6 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + do { + rc = reset_control_acquire(rcinfo->rst); + if (!rc) + break; + + d_vpr_e("%s: failed to acquire video_xo_reset control, count %d\n", + __func__, count); + count++; + usleep_range(1000, 1500); + } while (count < 1000); + + if (count >= 1000) { + d_vpr_e("%s: timeout acquiring video_xo_reset\n", __func__); + rc = -EINVAL; + MSM_VIDC_FATAL(true); + } +#else + rc = -EINVAL; +#endif + if (rc) + d_vpr_e("%s: failed to acquire reset control (%s), rc = %d\n", + __func__, rcinfo->name, rc); + else + d_vpr_h("%s: acquire reset control (%s)\n", + __func__, rcinfo->name); + break; + } + /* Faced this issue for volcano which doesn't support xo_reset + * skip this check and return success + */ + if (!found) { + d_vpr_h("%s: reset control (%s) not found but returning success\n", + __func__, name); + rc = 0; + } + + return rc; +} + +static int __reset_control_release_name(struct msm_vidc_core *core, + const char *name) +{ + struct reset_info *rcinfo = NULL; + int rc = 0; + bool found = false; + + venus_hfi_for_each_reset_clock(core, rcinfo) { + if (strcmp(rcinfo->name, name)) + continue; + + /* this function is valid only for exclusive_release reset clocks*/ + if (!rcinfo->exclusive_release) { + d_vpr_e("%s: unsupported reset control (%s), exclusive %d\n", + __func__, name, rcinfo->exclusive_release); + return -EINVAL; + } + + found = true; + /* reset_control_release exposed in kernel version 6 */ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(6, 0, 0)) + reset_control_release(rcinfo->rst); +#else + rc = -EINVAL; +#endif + if (rc) + d_vpr_e("%s: release reset control (%s) failed\n", + __func__, rcinfo->name); + else + d_vpr_h("%s: release reset control (%s) done\n", + __func__, rcinfo->name); + break; + } + /* Faced this issue for volcano which doesn't support xo_reset + * skip this check and return success + */ + if (!found) { + d_vpr_h("%s: reset control (%s) not found but returning success\n", + __func__, name); + rc = 0; + } + + return rc; +} + +static int __reset_control_assert_name(struct msm_vidc_core *core, + const char *name) +{ + struct reset_info *rcinfo = NULL; + int rc = 0; + bool found = false; + + venus_hfi_for_each_reset_clock(core, rcinfo) { + if (strcmp(rcinfo->name, name)) + continue; + + found = true; + rc = reset_control_assert(rcinfo->rst); + if (rc) + d_vpr_e("%s: failed to assert reset control (%s), rc = %d\n", + __func__, rcinfo->name, rc); + else + d_vpr_h("%s: assert reset control (%s)\n", + __func__, rcinfo->name); + break; + } + if (!found) { + d_vpr_e("%s: reset control (%s) not found\n", __func__, name); + rc = -EINVAL; + } + + return rc; +} + +static int __reset_control_deassert_name(struct msm_vidc_core *core, + const char *name) +{ + struct reset_info *rcinfo = NULL; + int rc = 0; + bool found = false; + + venus_hfi_for_each_reset_clock(core, rcinfo) { + if (strcmp(rcinfo->name, name)) + continue; + found = true; + rc = reset_control_deassert(rcinfo->rst); + if (rc) + d_vpr_e("%s: deassert reset control for (%s) failed, rc %d\n", + __func__, rcinfo->name, rc); + else + d_vpr_h("%s: deassert reset control (%s)\n", + __func__, rcinfo->name); + break; + } + if (!found) { + d_vpr_e("%s: reset control (%s) not found\n", __func__, name); + rc = -EINVAL; + } + + return rc; +} + +static int __reset_control_deassert(struct msm_vidc_core *core) +{ + struct reset_info *rcinfo = NULL; + int rc = 0; + + venus_hfi_for_each_reset_clock(core, rcinfo) { + rc = reset_control_deassert(rcinfo->rst); + if (rc) { + d_vpr_e("%s: deassert reset control failed. rc = %d\n", __func__, rc); + continue; + } + d_vpr_h("%s: deassert reset control %s\n", __func__, rcinfo->name); + } + + return rc; +} + +static int __reset_control_assert(struct msm_vidc_core *core) +{ + struct reset_info *rcinfo = NULL; + int rc = 0, cnt = 0; + + venus_hfi_for_each_reset_clock(core, rcinfo) { + if (!rcinfo->rst) { + d_vpr_e("%s: invalid reset clock %s\n", + __func__, rcinfo->name); + return -EINVAL; + } + rc = reset_control_assert(rcinfo->rst); + if (rc) { + d_vpr_e("%s: failed to assert reset control %s, rc = %d\n", + __func__, rcinfo->name, rc); + goto deassert_reset_control; + } + cnt++; + d_vpr_h("%s: assert reset control %s, count %d\n", __func__, rcinfo->name, cnt); + + usleep_range(1000, 1100); + } + + return rc; +deassert_reset_control: + venus_hfi_for_each_reset_clock_reverse_continue(core, rcinfo, cnt) { + d_vpr_e("%s: deassert reset control %s\n", __func__, rcinfo->name); + reset_control_deassert(rcinfo->rst); + } + + return rc; +} + +static int __reset_ahb2axi_bridge(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = __reset_control_assert(core); + if (rc) + return rc; + + rc = __reset_control_deassert(core); + if (rc) + return rc; + + return rc; +} + +static int __print_clock_residency_stats(struct msm_vidc_core *core) +{ + struct clock_info *cl; + int rc = 0; + + venus_hfi_for_each_clock(core, cl) { + /* skip if scaling not supported */ + if (!cl->has_scaling) + continue; + + /* + * residency for the last clk corner entry will be updated in stats + * only if we call update residency with rate 0 + */ + __update_residency_stats(core, cl, 0); + + /* print clock residency stats */ + print_residency_stats(core, cl); + } + + return rc; +} + +static int __reset_clock_residency_stats(struct msm_vidc_core *core) +{ + struct clock_info *cl; + int rc = 0; + + venus_hfi_for_each_clock(core, cl) { + /* skip if scaling not supported */ + if (!cl->has_scaling) + continue; + + /* reset clock residency stats */ + reset_residency_stats(core, cl); + } + + return rc; +} + +static const struct msm_vidc_resources_ops res_ops = { + .init = __init_resources, + .reset_bridge = __reset_ahb2axi_bridge, + .reset_control_acquire = __reset_control_acquire_name, + .reset_control_release = __reset_control_release_name, + .reset_control_assert = __reset_control_assert_name, + .reset_control_deassert = __reset_control_deassert_name, + .gdsc_init = __init_power_domains, + .gdsc_on = __enable_power_domains, + .gdsc_off = __disable_power_domains, + .gdsc_hw_ctrl = __hand_off_power_domains, + .gdsc_sw_ctrl = __acquire_power_domains, + .llcc = llcc_enable, + .set_bw = set_bw, + .set_clks = __set_clocks, + .clk_enable = __prepare_enable_clock, + .clk_disable = __disable_unprepare_clock, + .clk_print_residency_stats = __print_clock_residency_stats, + .clk_reset_residency_stats = __reset_clock_residency_stats, + .clk_update_residency_stats = __update_residency_stats, +}; + +const struct msm_vidc_resources_ops *get_resources_ops(void) +{ + return &res_ops; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/resources_ext.c b/qcom/opensource/video-driver/driver/vidc/src/resources_ext.c new file mode 100644 index 0000000000..9ce52a54cd --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/resources_ext.c @@ -0,0 +1,529 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include + +#ifdef CONFIG_MSM_MMRM +#include +#endif + +#include "resources.h" +#include "msm_vidc_core.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_power.h" +#include "msm_vidc_driver.h" +#include "msm_vidc_platform.h" + +static void __fatal_error(bool fatal) +{ + WARN_ON(fatal); +} + +static int __init_regulators(struct msm_vidc_core *core) +{ + const struct regulator_table *regulator_tbl; + struct regulator_set *regulators; + struct regulator_info *rinfo = NULL; + u32 regulator_count = 0, cnt = 0; + int rc = 0; + + regulators = &core->resource->regulator_set; + + regulator_tbl = core->platform->data.regulator_tbl; + regulator_count = core->platform->data.regulator_tbl_size; + + /* skip init if regulators not supported */ + if (!regulator_count) { + d_vpr_h("%s: regulators are not available in database\n", __func__); + return 0; + } + + /* sanitize regulator table */ + if (!regulator_tbl) { + d_vpr_e("%s: invalid regulator tbl\n", __func__); + return -EINVAL; + } + + /* allocate regulator_set */ + regulators->regulator_tbl = devm_kzalloc(&core->pdev->dev, + sizeof(*regulators->regulator_tbl) * regulator_count, GFP_KERNEL); + if (!regulators->regulator_tbl) { + d_vpr_e("%s: failed to alloc memory for regulator table\n", __func__); + return -ENOMEM; + } + regulators->count = regulator_count; + + /* populate regulator fields */ + for (cnt = 0; cnt < regulators->count; cnt++) { + regulators->regulator_tbl[cnt].name = regulator_tbl[cnt].name; + regulators->regulator_tbl[cnt].hw_power_collapse = regulator_tbl[cnt].hw_trigger; + } + + /* print regulator fields */ + venus_hfi_for_each_regulator(core, rinfo) { + d_vpr_h("%s: name %s hw_power_collapse %d\n", + __func__, rinfo->name, rinfo->hw_power_collapse); + } + + /* get regulator handle */ + venus_hfi_for_each_regulator(core, rinfo) { + rinfo->regulator = devm_regulator_get(&core->pdev->dev, rinfo->name); + if (IS_ERR_OR_NULL(rinfo->regulator)) { + rc = PTR_ERR(rinfo->regulator) ? + PTR_ERR(rinfo->regulator) : -EBADHANDLE; + d_vpr_e("%s: failed to get regulator: %s\n", __func__, rinfo->name); + rinfo->regulator = NULL; + return rc; + } + } + + return rc; +} + +static int __acquire_regulator(struct msm_vidc_core *core, + struct regulator_info *rinfo) +{ + int rc = 0; + + rc = call_res_op(core, reset_control_acquire, core, "video_xo_reset"); + if (rc) { + d_vpr_e("%s: failed to acquire video_xo_reset control\n", __func__); + goto fail_assert_xo_reset; + } + + if (rinfo->hw_power_collapse) { + if (!rinfo->regulator) { + d_vpr_e("%s: invalid regulator\n", __func__); + rc = -EINVAL; + goto exit; + } + + if (regulator_get_mode(rinfo->regulator) == + REGULATOR_MODE_NORMAL) { + /* clear handoff from core sub_state */ + msm_vidc_change_core_sub_state(core, + CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__); + d_vpr_h("Skip acquire regulator %s\n", rinfo->name); + goto exit; + } + + rc = regulator_set_mode(rinfo->regulator, + REGULATOR_MODE_NORMAL); + if (rc) { + /* + * This is somewhat fatal, but nothing we can do + * about it. We can't disable the regulator w/o + * getting it back under s/w control + */ + d_vpr_e("Failed to acquire regulator control: %s\n", + rinfo->name); + goto exit; + } else { + /* reset handoff from core sub_state */ + msm_vidc_change_core_sub_state(core, + CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__); + d_vpr_h("Acquired regulator control from HW: %s\n", + rinfo->name); + + } + + if (!regulator_is_enabled(rinfo->regulator)) { + d_vpr_e("%s: Regulator is not enabled %s\n", + __func__, rinfo->name); + __fatal_error(true); + } + } + +exit: + rc = call_res_op(core, reset_control_release, core, "video_xo_reset"); + if (rc) + d_vpr_e("%s: failed to release video_xo_reset reset\n", __func__); +fail_assert_xo_reset: + return rc; +} + +static int __hand_off_regulator(struct msm_vidc_core *core, + struct regulator_info *rinfo) +{ + int rc = 0; + + rc = call_res_op(core, reset_control_acquire, core, "video_xo_reset"); + if (rc) { + d_vpr_e("%s: failed to acquire video_xo_reset control\n", __func__); + goto fail_assert_xo_reset; + } + + if (rinfo->hw_power_collapse) { + if (!rinfo->regulator) { + d_vpr_e("%s: invalid regulator\n", __func__); + goto exit; + } + + rc = regulator_set_mode(rinfo->regulator, + REGULATOR_MODE_FAST); + if (rc) { + d_vpr_e("Failed to hand off regulator control: %s\n", + rinfo->name); + goto exit; + } else { + /* set handoff done in core sub_state */ + msm_vidc_change_core_sub_state(core, + 0, CORE_SUBSTATE_GDSC_HANDOFF, __func__); + d_vpr_h("Hand off regulator control to HW: %s\n", + rinfo->name); + } + + if (!regulator_is_enabled(rinfo->regulator)) { + d_vpr_e("%s: Regulator is not enabled %s\n", + __func__, rinfo->name); + __fatal_error(true); + } + } + +exit: + rc = call_res_op(core, reset_control_release, core, "video_xo_reset"); + if (rc) + d_vpr_e("%s: failed to release video_xo_reset reset\n", __func__); +fail_assert_xo_reset: + return rc; +} + +static int __enable_regulator(struct msm_vidc_core *core, const char *reg_name) +{ + int rc = 0; + struct regulator_info *rinfo; + bool found; + + found = false; + venus_hfi_for_each_regulator(core, rinfo) { + if (!rinfo->regulator) { + d_vpr_e("%s: invalid regulator %s\n", + __func__, rinfo->name); + return -EINVAL; + } + if (strcmp(rinfo->name, reg_name)) + continue; + found = true; + + rc = call_res_op(core, reset_control_acquire, core, "video_xo_reset"); + if (rc) { + d_vpr_e("%s: failed to acquire video_xo_reset control\n", __func__); + goto fail_assert_xo_reset; + } + + rc = regulator_enable(rinfo->regulator); + if (rc) { + d_vpr_e("%s: failed to enable %s, rc = %d\n", + __func__, rinfo->name, rc); + goto fail_regulator_enable; + } + if (!regulator_is_enabled(rinfo->regulator)) { + d_vpr_e("%s: regulator %s not enabled\n", + __func__, rinfo->name); + regulator_disable(rinfo->regulator); + rc = -EINVAL; + goto fail_regulator_enable; + } + + rc = call_res_op(core, reset_control_release, core, "video_xo_reset"); + if (rc) + d_vpr_e("%s: failed to release video_xo_reset reset\n", __func__); + + d_vpr_h("%s: enabled regulator %s\n", __func__, rinfo->name); + break; + } + if (!found) { + d_vpr_e("%s: regulator %s not found\n", __func__, reg_name); + return -EINVAL; + } + + return rc; + +fail_regulator_enable: + call_res_op(core, reset_control_release, core, "video_xo_reset"); +fail_assert_xo_reset: + return rc; +} + +static int __disable_regulator(struct msm_vidc_core *core, const char *reg_name) +{ + int rc = 0; + struct regulator_info *rinfo; + bool found; + + found = false; + venus_hfi_for_each_regulator(core, rinfo) { + if (!rinfo->regulator) { + d_vpr_e("%s: invalid regulator %s\n", + __func__, rinfo->name); + return -EINVAL; + } + if (strcmp(rinfo->name, reg_name)) + continue; + found = true; + + rc = __acquire_regulator(core, rinfo); + if (rc) { + d_vpr_e("%s: failed to acquire %s, rc = %d\n", + __func__, rinfo->name, rc); + /* Bring attention to this issue */ + WARN_ON(true); + return rc; + } + /* reset handoff done from core sub_state */ + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__); + + rc = call_res_op(core, reset_control_acquire, core, "video_xo_reset"); + if (rc) { + d_vpr_e("%s: failed to acquire video_xo_reset control\n", __func__); + goto fail_assert_xo_reset; + } + + rc = regulator_disable(rinfo->regulator); + if (rc) { + d_vpr_e("%s: failed to disable %s, rc = %d\n", + __func__, rinfo->name, rc); + goto fail_regulator_disable; + } + + rc = call_res_op(core, reset_control_release, core, "video_xo_reset"); + if (rc) + d_vpr_e("%s: failed to release video_xo_reset reset\n", __func__); + + d_vpr_h("%s: disabled regulator %s\n", __func__, rinfo->name); + break; + } + if (!found) { + d_vpr_e("%s: regulator %s not found\n", __func__, reg_name); + return -EINVAL; + } + + return rc; + +fail_regulator_disable: + call_res_op(core, reset_control_release, core, "video_xo_reset"); +fail_assert_xo_reset: + return rc; +} + +static int __hand_off_regulators(struct msm_vidc_core *core) +{ + struct regulator_info *rinfo; + int rc = 0, c = 0; + + venus_hfi_for_each_regulator(core, rinfo) { + rc = __hand_off_regulator(core, rinfo); + /* + * If one regulator hand off failed, driver should take + * the control for other regulators back. + */ + if (rc) + goto err_reg_handoff_failed; + c++; + } + + return rc; +err_reg_handoff_failed: + venus_hfi_for_each_regulator_reverse_continue(core, rinfo, c) + __acquire_regulator(core, rinfo); + + return rc; +} + +static int __acquire_regulators(struct msm_vidc_core *core) +{ + int rc = 0; + struct regulator_info *rinfo; + + venus_hfi_for_each_regulator(core, rinfo) + __acquire_regulator(core, rinfo); + + return rc; +} + +#ifdef CONFIG_MSM_MMRM +static int __set_clk_rate(struct msm_vidc_core *core, struct clock_info *cl, + u64 rate) +{ + int rc = 0; + struct mmrm_client_data client_data; + struct mmrm_client *client; + u64 srate; + + if (is_mmrm_supported(core) && !cl->mmrm_client) { + d_vpr_e("%s: invalid mmrm client\n", __func__); + return -EINVAL; + } + + /* update clock residency stats */ + call_res_op(core, clk_update_residency_stats, core, cl, rate); + + /* + * This conversion is necessary since we are scaling clock values based on + * the branch clock. However, mmrm driver expects source clock to be registered + * and used for scaling. + * TODO: Remove this scaling if using source clock instead of branch clock. + */ + srate = rate * MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO; + + /* bail early if requested clk rate is not changed */ + if (rate == cl->prev) + return 0; + + d_vpr_p("Scaling clock %s to %llu, prev %llu\n", + cl->name, srate, cl->prev * MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO); + + if (is_mmrm_supported(core)) { + /* set clock rate to mmrm driver */ + client = cl->mmrm_client; + memset(&client_data, 0, sizeof(client_data)); + client_data.num_hw_blocks = 1; + rc = mmrm_client_set_value(client, &client_data, srate); + if (rc) { + d_vpr_e("%s: Failed to set mmrm clock rate %llu %s: %d\n", + __func__, srate, cl->name, rc); + return rc; + } + } else { + /* set clock rate to clock driver */ + rc = clk_set_rate(cl->clk, srate); + if (rc) { + d_vpr_e("%s: Failed to set clock rate %llu %s: %d\n", + __func__, srate, cl->name, rc); + return rc; + } + } + cl->prev = rate; + return rc; +} +#else +static int __set_clk_rate(struct msm_vidc_core *core, struct clock_info *cl, + u64 rate) +{ + u64 srate; + int rc = 0; + + /* update clock residency stats */ + call_res_op(core, clk_update_residency_stats, core, cl, rate); + + /* + * This conversion is necessary since we are scaling clock values based on + * the branch clock. However, mmrm driver expects source clock to be registered + * and used for scaling. + * TODO: Remove this scaling if using source clock instead of branch clock. + */ + srate = rate * MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO; + + /* bail early if requested clk rate is not changed */ + if (rate == cl->prev) + return 0; + + d_vpr_p("Scaling clock %s to %llu, prev %llu\n", + cl->name, srate, cl->prev * MSM_VIDC_CLOCK_SOURCE_SCALING_RATIO); + + rc = clk_set_rate(cl->clk, srate); + if (rc) { + d_vpr_e("%s: Failed to set clock rate %llu %s: %d\n", + __func__, srate, cl->name, rc); + return rc; + } + + cl->prev = rate; + + return rc; +} +#endif + +static int __set_clocks_ext(struct msm_vidc_core *core, u64 freq) +{ + int rc = 0; + struct clock_info *cl; + + venus_hfi_for_each_clock(core, cl) { + if (cl->has_scaling) { + rc = __set_clk_rate(core, cl, freq); + if (rc) + return rc; + } + } + + return 0; +} + +static int qcom_clk_get_branch_flag(enum msm_vidc_branch_mem_flags vidc_flag, + enum branch_mem_flags *clk_flag) +{ + switch (vidc_flag) { + case MSM_VIDC_CLKFLAG_RETAIN_PERIPH: + *clk_flag = CLKFLAG_RETAIN_PERIPH; + break; + case MSM_VIDC_CLKFLAG_NORETAIN_PERIPH: + *clk_flag = CLKFLAG_NORETAIN_PERIPH; + break; + case MSM_VIDC_CLKFLAG_RETAIN_MEM: + *clk_flag = CLKFLAG_RETAIN_MEM; + break; + case MSM_VIDC_CLKFLAG_NORETAIN_MEM: + *clk_flag = CLKFLAG_NORETAIN_MEM; + break; + case MSM_VIDC_CLKFLAG_PERIPH_OFF_SET: + *clk_flag = CLKFLAG_PERIPH_OFF_SET; + break; + case MSM_VIDC_CLKFLAG_PERIPH_OFF_CLEAR: + *clk_flag = CLKFLAG_PERIPH_OFF_CLEAR; + break; + default: + d_vpr_e("%s: invalid clk flag: %d\n", __func__, vidc_flag); + return -EINVAL; + } + return 0; +} + +static int __clock_set_flag_ext(struct msm_vidc_core *core, + const char *name, enum msm_vidc_branch_mem_flags flag) +{ + int rc = 0; + struct clock_info *cinfo = NULL; + bool found = false; + enum branch_mem_flags mem_flag; + + /* get clock handle */ + venus_hfi_for_each_clock(core, cinfo) { + if (strcmp(cinfo->name, name)) + continue; + found = true; + rc = qcom_clk_get_branch_flag(flag, &mem_flag); + if (rc) + return rc; + + qcom_clk_set_flags(cinfo->clk, mem_flag); + d_vpr_h("%s: set flag %d on clock %s\n", __func__, mem_flag, name); + break; + } + if (!found) { + d_vpr_e("%s: failed to find clock: %s\n", __func__, name); + return -EINVAL; + } + return 0; +} + +const struct msm_vidc_resources_ops *get_res_ops_ext(void) +{ + const struct msm_vidc_resources_ops *res_ops = get_resources_ops(); + static struct msm_vidc_resources_ops res_ops_ext; + + memcpy(&res_ops_ext, res_ops, sizeof(struct msm_vidc_resources_ops)); + res_ops_ext.gdsc_init = __init_regulators; + res_ops_ext.gdsc_on = __enable_regulator; + res_ops_ext.gdsc_off = __disable_regulator; + res_ops_ext.gdsc_hw_ctrl = __hand_off_regulators; + res_ops_ext.gdsc_sw_ctrl = __acquire_regulators; + res_ops_ext.set_clks = __set_clocks_ext; + res_ops_ext.clk_set_flag = __clock_set_flag_ext; + + return &res_ops_ext; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/venus_hfi.c b/qcom/opensource/video-driver/driver/vidc/src/venus_hfi.c new file mode 100644 index 0000000000..7b05acd36f --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/venus_hfi.c @@ -0,0 +1,2023 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "venus_hfi.h" +#include "msm_vidc_core.h" +#include "msm_vidc_control.h" +#include "msm_vidc_power.h" +#include "msm_vidc_platform.h" +#include "msm_vidc_memory.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_driver.h" +#include "hfi_packet.h" +#include "venus_hfi_response.h" +#include "venus_hfi_queue.h" +#include "msm_vidc_events.h" +#include "msm_vidc_state.h" +#include "firmware.h" + +#define update_offset(offset, val) ((offset) += (val)) +#define update_timestamp(ts, val) \ + do { \ + do_div((ts), NSEC_PER_USEC); \ + (ts) += (val); \ + (ts) *= NSEC_PER_USEC; \ + } while (0) + +extern struct msm_vidc_core *g_core; + +static int __resume(struct msm_vidc_core *core); +static int __suspend(struct msm_vidc_core *core); + +static void __fatal_error(bool fatal) +{ + WARN_ON(fatal); +} + +int __strict_check(struct msm_vidc_core *core, const char *function) +{ + bool fatal = !mutex_is_locked(&core->lock); + + __fatal_error(fatal); + + if (fatal) + d_vpr_e("%s: strict check failed\n", function); + + return fatal ? -EINVAL : 0; +} + +static bool __valdiate_session(struct msm_vidc_core *core, + struct msm_vidc_inst *inst, const char *func) +{ + bool valid = false; + struct msm_vidc_inst *temp; + int rc = 0; + + rc = __strict_check(core, __func__); + if (rc) + return false; + + list_for_each_entry(temp, &core->instances, list) { + if (temp == inst) { + valid = true; + break; + } + } + if (!valid) + i_vpr_e(inst, "%s: invalid session\n", func); + + return valid; +} + +static void __schedule_power_collapse_work(struct msm_vidc_core *core) +{ + if (!core->capabilities[SW_PC].value) { + d_vpr_l("software power collapse not enabled\n"); + return; + } + + if (!mod_delayed_work(core->pm_workq, &core->pm_work, + msecs_to_jiffies(core->capabilities[SW_PC_DELAY].value))) { + d_vpr_h("power collapse already scheduled\n"); + } else { + d_vpr_l("power collapse scheduled for %d ms\n", + core->capabilities[SW_PC_DELAY].value); + } +} + +static void __cancel_power_collapse_work(struct msm_vidc_core *core) +{ + if (!core->capabilities[SW_PC].value) + return; + + cancel_delayed_work(&core->pm_work); +} + +static void __flush_debug_queue(struct msm_vidc_core *core, + u8 *packet, u32 packet_size) +{ + u8 *log; + struct hfi_debug_header *pkt; + bool local_packet = false; + enum vidc_msg_prio_fw log_level_fw = msm_fw_debug; + + if (!packet || !packet_size) { + packet = vzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE); + if (!packet) { + d_vpr_e("%s: allocation failed\n", __func__); + return; + } + packet_size = VIDC_IFACEQ_VAR_HUGE_PKT_SIZE; + + local_packet = true; + + /* + * Local packet is used when error occurred. + * It is good to print these logs to printk as well. + */ + log_level_fw |= FW_PRINTK; + } + + while (!venus_hfi_queue_dbg_read(core, packet)) { + pkt = (struct hfi_debug_header *)packet; + + if (pkt->size < sizeof(struct hfi_debug_header)) { + d_vpr_e("%s: invalid pkt size %d\n", + __func__, pkt->size); + continue; + } + if (pkt->size >= packet_size) { + d_vpr_e("%s: pkt size[%d] >= packet_size[%d]\n", + __func__, pkt->size, packet_size); + continue; + } + + packet[pkt->size] = '\0'; + /* + * All fw messages starts with new line character. This + * causes dprintk to print this message in two lines + * in the kernel log. Ignoring the first character + * from the message fixes this to print it in a single + * line. + */ + log = (u8 *)packet + sizeof(struct hfi_debug_header) + 1; + dprintk_firmware(log_level_fw, "%s", log); + } + + if (local_packet) + vfree(packet); +} + +static int __cmdq_write(struct msm_vidc_core *core, void *pkt) +{ + int rc; + + rc = __resume(core); + if (rc) + return rc; + + rc = venus_hfi_queue_cmd_write(core, pkt); + if (!rc) + __schedule_power_collapse_work(core); + + return rc; +} + +static int __cmdq_write_intr(struct msm_vidc_core *core, void *pkt, bool allow_intr) +{ + int rc; + + rc = __resume(core); + if (rc) + return rc; + + rc = venus_hfi_queue_cmd_write_intr(core, pkt, allow_intr); + if (!rc) + __schedule_power_collapse_work(core); + + return rc; +} + +static int __sys_set_debug(struct msm_vidc_core *core, u32 debug) +{ + int rc = 0; + + rc = hfi_packet_sys_debug_config(core, core->packet, + core->packet_size, debug); + if (rc) + goto exit; + + rc = __cmdq_write(core, core->packet); + if (rc) + goto exit; + +exit: + if (rc) + d_vpr_e("Debug mode setting to FW failed\n"); + + return rc; +} + +static int __sys_set_power_control(struct msm_vidc_core *core, bool enable) +{ + int rc = 0; + + if (!is_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF)) { + d_vpr_e("%s: skipping as power control hanfoff was not done\n", + __func__); + return rc; + } + + if (!core_in_valid_state(core)) { + d_vpr_e("%s: invalid core state %s\n", + __func__, core_state_name(core->state)); + return rc; + } + + rc = hfi_packet_sys_intraframe_powercollapse(core, + core->packet, core->packet_size, enable); + if (rc) + return rc; + + rc = __cmdq_write(core, core->packet); + if (rc) + return rc; + + rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_FW_PWR_CTRL, __func__); + if (rc) + return rc; + + d_vpr_h("%s: set hardware power control successful\n", __func__); + + return rc; +} + +int __prepare_pc(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = hfi_packet_sys_pc_prep(core, core->packet, core->packet_size); + if (rc) { + d_vpr_e("Failed to create sys pc prep pkt\n"); + goto err_pc_prep; + } + + if (__cmdq_write(core, core->packet)) + rc = -ENOTEMPTY; + if (rc) + d_vpr_e("Failed to prepare venus for power off"); +err_pc_prep: + return rc; +} + +static int __power_collapse(struct msm_vidc_core *core, bool force) +{ + int rc = 0; + + if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) { + d_vpr_h("%s: Power already disabled\n", __func__); + goto exit; + } + + if (!core_in_valid_state(core)) { + d_vpr_e("%s: Core not in init state\n", __func__); + return -EINVAL; + } + + __flush_debug_queue(core, (!force ? core->packet : NULL), core->packet_size); + + rc = call_venus_op(core, prepare_pc, core); + if (rc) + goto skip_power_off; + + rc = __suspend(core); + if (rc) + d_vpr_e("Failed __suspend\n"); + +exit: + return rc; + +skip_power_off: + d_vpr_e("%s: skipped\n", __func__); + return -EAGAIN; +} + +static int __release_subcaches(struct msm_vidc_core *core) +{ + int rc = 0; + struct subcache_info *sinfo; + struct hfi_buffer buf; + + if (msm_vidc_syscache_disable || !is_sys_cache_present(core)) + return 0; + + if (!core->resource->subcache_set.set_to_fw) { + d_vpr_h("Subcaches not set to Venus\n"); + return 0; + } + + rc = hfi_create_header(core->packet, core->packet_size, + 0, core->header_id++); + if (rc) + return rc; + + memset(&buf, 0, sizeof(struct hfi_buffer)); + buf.type = HFI_BUFFER_SUBCACHE; + buf.flags = HFI_BUF_HOST_FLAG_RELEASE; + + venus_hfi_for_each_subcache_reverse(core, sinfo) { + if (!sinfo->isactive) + continue; + + buf.index = sinfo->subcache->slice_id; + buf.buffer_size = sinfo->subcache->slice_size; + + rc = hfi_create_packet(core->packet, + core->packet_size, + HFI_CMD_BUFFER, + HFI_BUF_HOST_FLAG_NONE, + HFI_PAYLOAD_STRUCTURE, + HFI_PORT_NONE, + core->packet_id++, + &buf, + sizeof(buf)); + if (rc) + return rc; + } + + /* Set resource to Venus for activated subcaches */ + rc = __cmdq_write(core, core->packet); + if (rc) + return rc; + + venus_hfi_for_each_subcache_reverse(core, sinfo) { + if (!sinfo->isactive) + continue; + + d_vpr_h("%s: release Subcache id %d size %lu done\n", + __func__, sinfo->subcache->slice_id, + sinfo->subcache->slice_size); + } + core->resource->subcache_set.set_to_fw = false; + + return 0; +} + +static int __set_subcaches(struct msm_vidc_core *core) +{ + int rc = 0; + struct subcache_info *sinfo; + struct hfi_buffer buf; + + if (msm_vidc_syscache_disable || + !is_sys_cache_present(core)) { + return 0; + } + + if (core->resource->subcache_set.set_to_fw) { + d_vpr_h("Subcaches already set to Venus\n"); + return 0; + } + + rc = hfi_create_header(core->packet, core->packet_size, + 0, core->header_id++); + if (rc) + goto err_fail_set_subacaches; + + memset(&buf, 0, sizeof(struct hfi_buffer)); + buf.type = HFI_BUFFER_SUBCACHE; + buf.flags = HFI_BUF_HOST_FLAG_NONE; + + venus_hfi_for_each_subcache(core, sinfo) { + if (!sinfo->isactive) + continue; + buf.index = sinfo->subcache->slice_id; + buf.buffer_size = sinfo->subcache->slice_size; + + rc = hfi_create_packet(core->packet, + core->packet_size, + HFI_CMD_BUFFER, + HFI_BUF_HOST_FLAG_NONE, + HFI_PAYLOAD_STRUCTURE, + HFI_PORT_NONE, + core->packet_id++, + &buf, + sizeof(buf)); + if (rc) + goto err_fail_set_subacaches; + } + + /* Set resource to Venus for activated subcaches */ + rc = __cmdq_write(core, core->packet); + if (rc) + goto err_fail_set_subacaches; + + venus_hfi_for_each_subcache(core, sinfo) { + if (!sinfo->isactive) + continue; + d_vpr_h("%s: set Subcache id %d size %lu done\n", + __func__, sinfo->subcache->slice_id, + sinfo->subcache->slice_size); + } + core->resource->subcache_set.set_to_fw = true; + + return 0; + +err_fail_set_subacaches: + call_res_op(core, llcc, core, false); + return rc; +} + +static int __venus_power_off(struct msm_vidc_core *core) +{ + int rc = 0; + + if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) + return 0; + + rc = call_venus_op(core, power_off, core); + if (rc) { + d_vpr_e("Failed to power off, err: %d\n", rc); + return rc; + } + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE, 0, __func__); + + return rc; +} + +static int __venus_power_on(struct msm_vidc_core *core) +{ + int rc = 0; + + if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) + return 0; + + rc = call_venus_op(core, power_on, core); + if (rc) { + d_vpr_e("Failed to power on, err: %d\n", rc); + return rc; + } + + rc = msm_vidc_change_core_sub_state(core, 0, CORE_SUBSTATE_POWER_ENABLE, __func__); + if (rc) + return rc; + + return rc; +} + +static int __suspend(struct msm_vidc_core *core) +{ + int rc = 0; + + if (!is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) { + d_vpr_h("Power already disabled\n"); + return 0; + } + + rc = __strict_check(core, __func__); + if (rc) + return rc; + + d_vpr_h("Entering suspend\n"); + + rc = fw_suspend(core); + if (rc) { + d_vpr_e("Failed to suspend video core %d\n", rc); + goto err_tzbsp_suspend; + } + + call_res_op(core, llcc, core, false); + + __venus_power_off(core); + d_vpr_h("Venus power off\n"); + return rc; + +err_tzbsp_suspend: + return rc; +} + +static int __resume(struct msm_vidc_core *core) +{ + int rc = 0; + + if (is_core_sub_state(core, CORE_SUBSTATE_POWER_ENABLE)) { + goto exit; + } else if (!core_in_valid_state(core)) { + d_vpr_e("%s: core not in valid state\n", __func__); + return -EINVAL; + } + + rc = __strict_check(core, __func__); + if (rc) + return rc; + + d_vpr_h("Resuming from power collapse\n"); + /* reset handoff done from core sub_state */ + rc = msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_GDSC_HANDOFF, 0, __func__); + if (rc) + return rc; + /* reset hw pwr ctrl from core sub_state */ + rc = msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_FW_PWR_CTRL, 0, __func__); + if (rc) + return rc; + + rc = __venus_power_on(core); + if (rc) { + d_vpr_e("Failed to power on venus\n"); + goto err_venus_power_on; + } + + /* Reboot the firmware */ + rc = fw_resume(core); + if (rc) { + d_vpr_e("Failed to resume video core %d\n", rc); + goto err_set_video_state; + } + + /* + * Hand off control of regulators to h/w _after_ loading fw. + * Note that the GDSC will turn off when switching from normal + * (s/w triggered) to fast (HW triggered) unless the h/w vote is + * present. + */ + call_res_op(core, gdsc_hw_ctrl, core); + + /* Wait for boot completion */ + rc = call_venus_op(core, boot_firmware, core); + if (rc) { + d_vpr_e("Failed to reset venus core\n"); + goto err_reset_core; + } + + __sys_set_debug(core, (msm_fw_debug & FW_LOGMASK) >> FW_LOGSHIFT); + + rc = call_res_op(core, llcc, core, true); + if (rc) { + d_vpr_e("Failed to activate subcache\n"); + goto err_reset_core; + } + __set_subcaches(core); + + rc = __sys_set_power_control(core, true); + if (rc) { + d_vpr_e("%s: set power control failed\n", __func__); + call_res_op(core, gdsc_sw_ctrl, core); + rc = 0; + } + + d_vpr_h("Resumed from power collapse\n"); +exit: + /* Don't reset skip_pc_count for SYS_PC_PREP cmd */ + //if (core->last_packet_type != HFI_CMD_SYS_PC_PREP) + // core->skip_pc_count = 0; + return rc; +err_reset_core: + fw_suspend(core); +err_set_video_state: + __venus_power_off(core); +err_venus_power_on: + d_vpr_e("Failed to resume from power collapse\n"); + return rc; +} + +int __load_fw(struct msm_vidc_core *core) +{ + int rc = 0; + + d_vpr_h("%s: loading video firmware\n", __func__); + + /* clear all substates */ + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_MAX - 1, 0, __func__); + + trace_msm_v4l2_vidc_fw_load("START"); + rc = __venus_power_on(core); + if (rc) { + d_vpr_e("%s: power on failed\n", __func__); + goto fail_power; + } + + rc = fw_load(core); + if (rc) + goto fail_load_fw; + + /* + * Hand off control of regulators to h/w _after_ loading fw. + * Note that the GDSC will turn off when switching from normal + * (s/w triggered) to fast (HW triggered) unless the h/w vote is + * present. + */ + call_res_op(core, gdsc_hw_ctrl, core); + trace_msm_v4l2_vidc_fw_load("END"); + + return rc; +fail_load_fw: + __venus_power_off(core); +fail_power: + trace_msm_v4l2_vidc_fw_load("END"); + return rc; +} + +void __unload_fw(struct msm_vidc_core *core) +{ + if (!core->resource->fw_cookie) + return; + + cancel_delayed_work(&core->pm_work); + fw_unload(core); + __venus_power_off(core); + + /* clear all substates */ + msm_vidc_change_core_sub_state(core, CORE_SUBSTATE_MAX - 1, 0, __func__); + + d_vpr_h("%s unloaded video firmware\n", __func__); +} + +static int __response_handler(struct msm_vidc_core *core) +{ + int rc = 0; + + if (call_venus_op(core, watchdog, core, core->intr_status)) { + struct hfi_packet pkt = {.type = HFI_SYS_ERROR_WD_TIMEOUT}; + + core_lock(core, __func__); + msm_vidc_change_core_state(core, MSM_VIDC_CORE_ERROR, __func__); + /* mark cpu watchdog error */ + msm_vidc_change_core_sub_state(core, + 0, CORE_SUBSTATE_CPU_WATCHDOG, __func__); + d_vpr_e("%s: CPU WD error received\n", __func__); + core_unlock(core, __func__); + + return handle_system_error(core, &pkt); + } + + memset(core->response_packet, 0, core->packet_size); + while (!venus_hfi_queue_msg_read(core, core->response_packet)) { + rc = handle_response(core, core->response_packet); + if (rc) + continue; + /* check for system error */ + if (core->state != MSM_VIDC_CORE_INIT) + break; + memset(core->response_packet, 0, core->packet_size); + } + + __schedule_power_collapse_work(core); + __flush_debug_queue(core, core->response_packet, core->packet_size); + + return rc; +} + +irqreturn_t venus_hfi_isr(int irq, void *data) +{ + disable_irq_nosync(irq); + return IRQ_WAKE_THREAD; +} + +irqreturn_t venus_hfi_isr_handler(int irq, void *data) +{ + struct msm_vidc_core *core = data; + int num_responses = 0, rc = 0; + + d_vpr_l("%s: received interrupt from hardware\n", __func__); + + if (!core) { + d_vpr_e("%s: invalid params\n", __func__); + return IRQ_NONE; + } + + core_lock(core, __func__); + rc = __resume(core); + if (rc) { + d_vpr_e("%s: Power on failed\n", __func__); + core_unlock(core, __func__); + goto exit; + } + call_venus_op(core, clear_interrupt, core); + core_unlock(core, __func__); + + num_responses = __response_handler(core); + +exit: + if (!call_venus_op(core, watchdog, core, core->intr_status)) + enable_irq(irq); + + return IRQ_HANDLED; +} + +void venus_hfi_pm_work_handler(struct work_struct *work) +{ + int rc = 0; + struct msm_vidc_core *core; + + core = container_of(work, struct msm_vidc_core, pm_work.work); + + core_lock(core, __func__); + d_vpr_h("%s: try power collapse\n", __func__); + /* + * It is ok to check this variable outside the lock since + * it is being updated in this context only + */ + if (core->skip_pc_count >= VIDC_MAX_PC_SKIP_COUNT) { + d_vpr_e("Failed to PC for %d times\n", + core->skip_pc_count); + core->skip_pc_count = 0; + msm_vidc_change_core_state(core, MSM_VIDC_CORE_ERROR, __func__); + /* mark video hw unresponsive */ + msm_vidc_change_core_sub_state(core, + 0, CORE_SUBSTATE_VIDEO_UNRESPONSIVE, __func__); + /* do core deinit to handle error */ + msm_vidc_core_deinit_locked(core, true); + goto unlock; + } + + /* core already deinited - skip power collapse */ + if (is_core_state(core, MSM_VIDC_CORE_DEINIT)) { + d_vpr_e("%s: invalid core state %s\n", + __func__, core_state_name(core->state)); + goto unlock; + } + + rc = __power_collapse(core, false); + switch (rc) { + case 0: + core->skip_pc_count = 0; + /* Cancel pending delayed works if any */ + __cancel_power_collapse_work(core); + d_vpr_h("%s: power collapse successful!\n", __func__); + break; + case -EBUSY: + core->skip_pc_count = 0; + d_vpr_h("%s: retry PC as dsp is busy\n", __func__); + __schedule_power_collapse_work(core); + break; + case -EAGAIN: + core->skip_pc_count++; + d_vpr_e("%s: retry power collapse (count %d)\n", + __func__, core->skip_pc_count); + __schedule_power_collapse_work(core); + break; + default: + d_vpr_e("%s: power collapse failed\n", __func__); + break; + } +unlock: + core_unlock(core, __func__); +} + +static int __sys_init(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = hfi_packet_sys_init(core, core->packet, core->packet_size); + if (rc) + return rc; + + rc = __cmdq_write(core, core->packet); + if (rc) + return rc; + + return 0; +} + +static int __sys_image_version(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = hfi_packet_image_version(core, core->packet, core->packet_size); + if (rc) + return rc; + + rc = __cmdq_write(core, core->packet); + if (rc) + return rc; + + return 0; +} + +int venus_hfi_core_init(struct msm_vidc_core *core) +{ + int rc = 0; + + d_vpr_h("%s(): core %pK\n", __func__, core); + + rc = __strict_check(core, __func__); + if (rc) + return rc; + + rc = venus_hfi_queue_init(core); + if (rc) + goto error; + + rc = __load_fw(core); + if (rc) + goto error; + + rc = call_venus_op(core, boot_firmware, core); + if (rc) + goto error; + + rc = call_res_op(core, llcc, core, true); + if (rc) + goto error; + + rc = __sys_init(core); + if (rc) + goto error; + + rc = __sys_image_version(core); + if (rc) + goto error; + + rc = __sys_set_debug(core, (msm_fw_debug & FW_LOGMASK) >> FW_LOGSHIFT); + if (rc) + goto error; + + rc = __set_subcaches(core); + if (rc) + goto error; + + rc = __sys_set_power_control(core, true); + if (rc) { + d_vpr_e("%s: set power control failed\n", __func__); + call_res_op(core, gdsc_sw_ctrl, core); + rc = 0; + } + + d_vpr_h("%s(): successful\n", __func__); + return 0; + +error: + d_vpr_e("%s(): failed\n", __func__); + return rc; +} + +int venus_hfi_core_deinit(struct msm_vidc_core *core, bool force) +{ + int rc = 0; + + d_vpr_h("%s(): core %pK\n", __func__, core); + rc = __strict_check(core, __func__); + if (rc) + return rc; + + if (is_core_state(core, MSM_VIDC_CORE_DEINIT)) + return 0; + __resume(core); + __flush_debug_queue(core, (!force ? core->packet : NULL), core->packet_size); + __release_subcaches(core); + call_res_op(core, llcc, core, false); + __unload_fw(core); + /** + * coredump need to be called after firmware unload, coredump also + * copying queues memory. So need to be called before queues deinit. + */ + if (msm_vidc_fw_dump) + fw_coredump(core); + + return 0; +} + +int venus_hfi_noc_error_info(struct msm_vidc_core *core) +{ + int rc = 0; + + if (!core->capabilities[NON_FATAL_FAULTS].value) + return 0; + + core_lock(core, __func__); + if (is_core_state(core, MSM_VIDC_CORE_DEINIT)) + goto unlock; + + /* resume venus before accessing noc registers */ + rc = __resume(core); + if (rc) { + d_vpr_e("%s: Power on failed\n", __func__); + goto unlock; + } + + call_venus_op(core, noc_error_info, core); + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_suspend(struct msm_vidc_core *core) +{ + int rc = 0; + + rc = __strict_check(core, __func__); + if (rc) + return rc; + + if (!core->capabilities[SW_PC].value) { + d_vpr_h("Skip suspending venus\n"); + return 0; + } + + d_vpr_h("Suspending Venus\n"); + rc = __power_collapse(core, true); + if (!rc) { + /* Cancel pending delayed works if any */ + __cancel_power_collapse_work(core); + } else { + d_vpr_e("%s: Venus is busy\n", __func__); + rc = -EBUSY; + } + + return rc; +} + +int venus_hfi_trigger_ssr(struct msm_vidc_core *core, u32 type, + u32 client_id, u32 addr) +{ + int rc = 0; + u32 payload[2]; + + /* + * call resume before preparing ssr hfi packet in core->packet + * otherwise ssr hfi packet in core->packet will be overwritten + * by __resume() call (inside __cmdq_write) which is preparing + * ifpc hfi packets in core->packet + */ + rc = __resume(core); + if (rc) + return rc; + + payload[0] = client_id << 4 | type; + payload[1] = addr; + + rc = hfi_create_header(core->packet, core->packet_size, + 0 /*session_id*/, + core->header_id++); + if (rc) + goto exit; + + /* HFI_CMD_SSR */ + rc = hfi_create_packet(core->packet, core->packet_size, + HFI_CMD_SSR, + HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED, + HFI_PAYLOAD_U64, + HFI_PORT_NONE, + core->packet_id++, + &payload, sizeof(u64)); + if (rc) + goto exit; + + rc = __cmdq_write(core, core->packet); + if (rc) + goto exit; + +exit: + if (rc) + d_vpr_e("%s(): failed\n", __func__); + + return rc; +} + +int venus_hfi_trigger_stability(struct msm_vidc_inst *inst, u32 type, + u32 client_id, u32 val) +{ + struct msm_vidc_core *core; + u32 payload[2]; + int rc = 0; + + if (!inst->packet) { + d_vpr_e("%s: Invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + payload[0] = client_id << 4 | type; + payload[1] = val; + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, core->header_id++); + if (rc) + goto unlock; + + /* HFI_CMD_STABILITY */ + rc = hfi_create_packet(inst->packet, inst->packet_size, + HFI_CMD_STABILITY, + HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED, + HFI_PAYLOAD_U64, + HFI_PORT_NONE, + core->packet_id++, + &payload, sizeof(u64)); + if (rc) + goto unlock; + + rc = __cmdq_write(core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_reserve_hardware(struct msm_vidc_inst *inst, u32 duration) +{ + struct msm_vidc_core *core; + enum hfi_reserve_type payload; + int rc = 0; + + if (!inst->packet) { + d_vpr_e("%s: Invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + if (duration) + payload = HFI_RESERVE_START; + else + payload = HFI_RESERVE_STOP; + + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, core->header_id++); + if (rc) + goto unlock; + + rc = hfi_create_packet(inst->packet, inst->packet_size, + HFI_CMD_RESERVE, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32_ENUM, + HFI_PORT_NONE, + core->packet_id++, + &payload, sizeof(u32)); + if (rc) + goto unlock; + + rc = __cmdq_write(core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_session_open(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + __sys_set_debug(core, (msm_fw_debug & FW_LOGMASK) >> FW_LOGSHIFT); + + rc = hfi_packet_session_command(inst, + HFI_CMD_OPEN, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED), + HFI_PORT_NONE, + 0, /* session_id */ + HFI_PAYLOAD_U32, + &inst->session_id, /* payload */ + sizeof(u32)); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_session_set_codec(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + u32 codec; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, core->header_id++); + if (rc) + goto unlock; + + codec = get_hfi_codec(inst); + rc = hfi_create_packet(inst->packet, inst->packet_size, + HFI_PROP_CODEC, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32_ENUM, + HFI_PORT_NONE, + core->packet_id++, + &codec, + sizeof(u32)); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_session_set_secure_mode(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + u32 secure_mode; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, core->header_id++); + if (rc) + goto unlock; + + secure_mode = inst->capabilities[SECURE_MODE].value; + rc = hfi_create_packet(inst->packet, inst->packet_size, + HFI_PROP_SECURE, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32, + HFI_PORT_NONE, + core->packet_id++, + &secure_mode, + sizeof(u32)); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +static int venus_hfi_cache_packet(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct hfi_header *hdr; + struct hfi_pending_packet *packet; + struct msm_vidc_core *core; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + + hdr = (struct hfi_header *)inst->packet; + if (hdr->size < sizeof(struct hfi_header)) { + d_vpr_e("%s: invalid hdr size %d\n", __func__, hdr->size); + return -EINVAL; + } + + packet = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_PACKET); + if (!packet) { + i_vpr_e(inst, "%s: failed to allocate pending packet\n", __func__); + return -ENOMEM; + } + + INIT_LIST_HEAD(&packet->list); + list_add_tail(&packet->list, &inst->pending_pkts); + packet->data = (u8 *)packet + sizeof(struct hfi_pending_packet); + + if (hdr->size > MSM_MEM_POOL_PACKET_SIZE) { + i_vpr_e(inst, "%s: header size %d exceeds pool packet size %d\n", + __func__, hdr->size, MSM_MEM_POOL_PACKET_SIZE); + return -EINVAL; + } + memcpy(packet->data, inst->packet, hdr->size); + + return rc; +} + +int venus_hfi_session_property(struct msm_vidc_inst *inst, + u32 pkt_type, u32 flags, u32 port, u32 payload_type, + void *payload, u32 payload_size) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, core->header_id++); + if (rc) + goto unlock; + rc = hfi_create_packet(inst->packet, inst->packet_size, + pkt_type, + flags, + payload_type, + port, + core->packet_id++, + payload, + payload_size); + if (rc) + goto unlock; + + /* skip sending packet to firmware */ + if (inst->request) { + rc = venus_hfi_cache_packet(inst); + goto unlock; + } + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_session_close(struct msm_vidc_inst *inst) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + rc = hfi_packet_session_command(inst, + HFI_CMD_CLOSE, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED | + HFI_HOST_FLAGS_NON_DISCARDABLE), + HFI_PORT_NONE, + inst->session_id, + HFI_PAYLOAD_NONE, + NULL, + 0); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_start(struct msm_vidc_inst *inst, enum msm_vidc_port_type port) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + goto unlock; + } + + rc = hfi_packet_session_command(inst, + HFI_CMD_START, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED), + get_hfi_port(inst, port), + inst->session_id, + HFI_PAYLOAD_NONE, + NULL, + 0); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_stop(struct msm_vidc_inst *inst, enum msm_vidc_port_type port) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + goto unlock; + } + + rc = hfi_packet_session_command(inst, + HFI_CMD_STOP, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED | + HFI_HOST_FLAGS_NON_DISCARDABLE), + get_hfi_port(inst, port), + inst->session_id, + HFI_PAYLOAD_NONE, + NULL, + 0); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_session_pause(struct msm_vidc_inst *inst, enum msm_vidc_port_type port) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + goto unlock; + } + + rc = hfi_packet_session_command(inst, + HFI_CMD_PAUSE, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED), + get_hfi_port(inst, port), + inst->session_id, + HFI_PAYLOAD_NONE, + NULL, + 0); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_session_resume(struct msm_vidc_inst *inst, + enum msm_vidc_port_type port, u32 payload) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + if (port != INPUT_PORT && port != OUTPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + goto unlock; + } + + rc = hfi_packet_session_command(inst, + HFI_CMD_RESUME, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED), + get_hfi_port(inst, port), + inst->session_id, + HFI_PAYLOAD_U32, + &payload, + sizeof(u32)); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_session_drain(struct msm_vidc_inst *inst, enum msm_vidc_port_type port) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + if (port != INPUT_PORT) { + i_vpr_e(inst, "%s: invalid port %d\n", __func__, port); + goto unlock; + } + + rc = hfi_packet_session_command(inst, + HFI_CMD_DRAIN, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED | + HFI_HOST_FLAGS_NON_DISCARDABLE), + get_hfi_port(inst, port), + inst->session_id, + HFI_PAYLOAD_NONE, + NULL, + 0); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_session_command(struct msm_vidc_inst *inst, + u32 cmd, enum msm_vidc_port_type port, u32 payload_type, + void *payload, u32 payload_size) +{ + int rc = 0; + struct msm_vidc_core *core; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, + core->header_id++); + if (rc) + goto unlock; + + rc = hfi_create_packet(inst->packet, inst->packet_size, + cmd, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED), + payload_type, + get_hfi_port(inst, port), + core->packet_id++, + payload, + payload_size); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_queue_super_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer, struct msm_vidc_buffer *metabuf) +{ + int rc = 0; + struct msm_vidc_core *core; + struct hfi_buffer hfi_buffer; + struct hfi_buffer hfi_meta_buffer; + u32 frame_size, meta_size, batch_size, cnt = 0; + u64 ts_delta_us; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + /* Get super yuv buffer */ + rc = get_hfi_buffer(inst, buffer, &hfi_buffer); + if (rc) + goto unlock; + + /* Get super meta buffer */ + if (metabuf) { + rc = get_hfi_buffer(inst, metabuf, &hfi_meta_buffer); + if (rc) + goto unlock; + } + + batch_size = inst->capabilities[SUPER_FRAME].value; + frame_size = call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT); + meta_size = call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT_META); + ts_delta_us = 1000000 / (inst->capabilities[FRAME_RATE].value >> 16); + + /* Sanitize super yuv buffer */ + if (frame_size * batch_size != buffer->buffer_size) { + i_vpr_e(inst, "%s: invalid super yuv buffer. frame %u, batch %u, buffer size %u\n", + __func__, frame_size, batch_size, buffer->buffer_size); + goto unlock; + } + + /* Sanitize super meta buffer */ + if (metabuf && meta_size * batch_size > metabuf->buffer_size) { + i_vpr_e(inst, "%s: invalid super meta buffer. meta %u, batch %u, buffer size %u\n", + __func__, meta_size, batch_size, metabuf->buffer_size); + goto unlock; + } + + /* Initialize yuv buffer */ + hfi_buffer.data_size = frame_size; + hfi_buffer.addr_offset = 0; + + /* Initialize meta buffer */ + if (metabuf) { + hfi_meta_buffer.data_size = meta_size; + hfi_meta_buffer.addr_offset = 0; + } + + while (cnt < batch_size) { + /* Create header */ + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, core->header_id++); + if (rc) + goto unlock; + + /* Create yuv packet */ + update_offset(hfi_buffer.addr_offset, (cnt ? frame_size : 0u)); + update_timestamp(hfi_buffer.timestamp, (cnt ? ts_delta_us : 0u)); + rc = hfi_create_packet(inst->packet, + inst->packet_size, + HFI_CMD_BUFFER, + HFI_HOST_FLAGS_INTR_REQUIRED, + HFI_PAYLOAD_STRUCTURE, + get_hfi_port_from_buffer_type(inst, buffer->type), + core->packet_id++, + &hfi_buffer, + sizeof(hfi_buffer)); + if (rc) + goto unlock; + + /* Create meta packet */ + if (metabuf) { + update_offset(hfi_meta_buffer.addr_offset, (cnt ? meta_size : 0u)); + update_timestamp(hfi_meta_buffer.timestamp, (cnt ? ts_delta_us : 0u)); + rc = hfi_create_packet(inst->packet, + inst->packet_size, + HFI_CMD_BUFFER, + HFI_HOST_FLAGS_INTR_REQUIRED, + HFI_PAYLOAD_STRUCTURE, + get_hfi_port_from_buffer_type(inst, metabuf->type), + core->packet_id++, + &hfi_meta_buffer, + sizeof(hfi_meta_buffer)); + if (rc) + goto unlock; + } + + /* Raise interrupt only for last pkt in the batch */ + rc = __cmdq_write_intr(inst->core, inst->packet, + (cnt == batch_size - 1)); + if (rc) + goto unlock; + + /* update start timestamp */ + msm_vidc_add_buffer_stats(inst, buffer, hfi_buffer.timestamp); + + cnt++; + } +unlock: + core_unlock(core, __func__); + if (rc) + i_vpr_e(inst, "%s: queue super buffer failed: %d\n", __func__, rc); + + return rc; +} + +static int venus_hfi_add_pending_packets(struct msm_vidc_inst *inst) +{ + int rc = 0; + int num_packets = 0; + struct hfi_pending_packet *pkt_info, *dummy; + struct hfi_header *hdr, *src_hdr; + struct hfi_packet *src_pkt; + struct msm_vidc_core *core; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + + hdr = (struct hfi_header *)inst->packet; + if (hdr->size < sizeof(struct hfi_header)) { + i_vpr_e(inst, "%s: invalid hdr size %d\n", + __func__, hdr->size); + return -EINVAL; + } + + list_for_each_entry_safe(pkt_info, dummy, &inst->pending_pkts, list) { + src_hdr = (struct hfi_header *)(pkt_info->data); + num_packets = src_hdr->num_packets; + src_pkt = (struct hfi_packet *)((u8 *)src_hdr + sizeof(struct hfi_header)); + while (num_packets > 0) { + memcpy((u8 *)hdr + hdr->size, (void *)src_pkt, src_pkt->size); + hdr->num_packets++; + hdr->size += src_pkt->size; + num_packets--; + src_pkt = (struct hfi_packet *)((u8 *)src_pkt + src_pkt->size); + if ((u8 *)src_pkt < (u8 *)src_hdr || + (u8 *)src_pkt > (u8 *)src_hdr + hdr->size) { + i_vpr_e(inst, "%s: invalid packet address\n", __func__); + return -EINVAL; + } + } + list_del(&pkt_info->list); + msm_vidc_pool_free(inst, pkt_info); + } + return rc; +} + +int venus_hfi_queue_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer, struct msm_vidc_buffer *metabuf) +{ + int rc = 0; + struct msm_vidc_core *core; + struct hfi_buffer hfi_buffer, hfi_meta_buffer; + + if (!inst->packet) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + rc = get_hfi_buffer(inst, buffer, &hfi_buffer); + if (rc) + goto unlock; + + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, core->header_id++); + if (rc) + goto unlock; + + rc = hfi_create_packet(inst->packet, + inst->packet_size, + HFI_CMD_BUFFER, + HFI_HOST_FLAGS_INTR_REQUIRED, + HFI_PAYLOAD_STRUCTURE, + get_hfi_port_from_buffer_type(inst, buffer->type), + core->packet_id++, + &hfi_buffer, + sizeof(hfi_buffer)); + if (rc) + goto unlock; + + if (metabuf) { + rc = get_hfi_buffer(inst, metabuf, &hfi_meta_buffer); + if (rc) + goto unlock; + rc = hfi_create_packet(inst->packet, + inst->packet_size, + HFI_CMD_BUFFER, + HFI_HOST_FLAGS_INTR_REQUIRED, + HFI_PAYLOAD_STRUCTURE, + get_hfi_port_from_buffer_type(inst, metabuf->type), + core->packet_id++, + &hfi_meta_buffer, + sizeof(hfi_meta_buffer)); + if (rc) + goto unlock; + } + + if (is_meta_rx_inp_enabled(inst, META_OUTBUF_FENCE) && + is_output_buffer(buffer->type)) { + if (!buffer->fence_id) { + i_vpr_e(inst, "%s: fence id cannot be 0\n", __func__); + rc = -EINVAL; + goto unlock; + } + rc = hfi_create_packet(inst->packet, + inst->packet_size, + HFI_PROP_FENCE, + 0, + HFI_PAYLOAD_U64, + HFI_PORT_RAW, + core->packet_id++, + &buffer->fence_id, + sizeof(u64)); + if (rc) + goto unlock; + } + + rc = venus_hfi_add_pending_packets(inst); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + + /* update start timestamp */ + msm_vidc_add_buffer_stats(inst, buffer, hfi_buffer.timestamp); + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_release_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buffer) +{ + int rc = 0; + struct msm_vidc_core *core; + struct hfi_buffer hfi_buffer; + + if (!inst->packet || !buffer) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + rc = get_hfi_buffer(inst, buffer, &hfi_buffer); + if (rc) + goto unlock; + + /* add release flag */ + hfi_buffer.flags |= HFI_BUF_HOST_FLAG_RELEASE; + + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, core->header_id++); + if (rc) + goto unlock; + + rc = hfi_create_packet(inst->packet, + inst->packet_size, + HFI_CMD_BUFFER, + (HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED), + HFI_PAYLOAD_STRUCTURE, + get_hfi_port_from_buffer_type(inst, buffer->type), + core->packet_id++, + &hfi_buffer, + sizeof(hfi_buffer)); + if (rc) + goto unlock; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + +int venus_hfi_scale_clocks(struct msm_vidc_inst *inst, u64 freq) +{ + int rc = 0; + struct msm_vidc_core *core; + + core = inst->core; + + core_lock(core, __func__); + rc = __resume(core); + if (rc) { + i_vpr_e(inst, "%s: Resume from power collapse failed\n", __func__); + goto exit; + } + rc = call_res_op(core, set_clks, core, freq); + if (rc) + goto exit; + +exit: + core_unlock(core, __func__); + + return rc; +} + +int venus_hfi_scale_buses(struct msm_vidc_inst *inst, u64 bw_ddr, u64 bw_llcc) +{ + int rc = 0; + struct msm_vidc_core *core; + + core = inst->core; + + core_lock(core, __func__); + rc = __resume(core); + if (rc) { + i_vpr_e(inst, "%s: Resume from power collapse failed\n", __func__); + goto exit; + } + rc = call_res_op(core, set_bw, core, bw_ddr, bw_llcc); + if (rc) + goto exit; + +exit: + core_unlock(core, __func__); + + return rc; +} + +int venus_hfi_set_ir_period(struct msm_vidc_inst *inst, u32 ir_type, + enum msm_vidc_inst_capability_type cap_id) +{ + int rc = 0; + struct msm_vidc_core *core; + u32 ir_period, sync_frame_req = 0; + + core = inst->core; + + core_lock(core, __func__); + + ir_period = inst->capabilities[cap_id].value; + + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, core->header_id++); + if (rc) + goto exit; + + /* Request sync frame if ir period enabled dynamically */ + if (!inst->ir_enabled) { + inst->ir_enabled = ((ir_period > 0) ? true : false); + if (inst->ir_enabled && inst->bufq[OUTPUT_PORT].vb2q->streaming) { + sync_frame_req = HFI_SYNC_FRAME_REQUEST_WITH_PREFIX_SEQ_HDR; + rc = hfi_create_packet(inst->packet, inst->packet_size, + HFI_PROP_REQUEST_SYNC_FRAME, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32_ENUM, + msm_vidc_get_port_info(inst, REQUEST_I_FRAME), + core->packet_id++, + &sync_frame_req, + sizeof(u32)); + if (rc) + goto exit; + } + } + + rc = hfi_create_packet(inst->packet, inst->packet_size, + ir_type, + HFI_HOST_FLAGS_NONE, + HFI_PAYLOAD_U32, + msm_vidc_get_port_info(inst, cap_id), + core->packet_id++, + &ir_period, + sizeof(u32)); + if (rc) + goto exit; + + rc = __cmdq_write(inst->core, inst->packet); + if (rc) { + i_vpr_e(inst, "%s: failed to set inst->capabilities[%d] %s to fw\n", + __func__, cap_id, cap_name(cap_id)); + goto exit; + } + +exit: + core_unlock(core, __func__); + + return rc; +} + +struct device_region_info *venus_hfi_get_device_region_info( + struct msm_vidc_core *core, enum msm_vidc_device_region region) +{ + struct device_region_info *dev_reg = NULL, *match = NULL; + + if (!region || region >= MSM_VIDC_DEVICE_REGION_MAX) { + d_vpr_e("%s: invalid region %#x\n", __func__, region); + return NULL; + } + + venus_hfi_for_each_device_region(core, dev_reg) { + if (dev_reg->region == region) { + match = dev_reg; + break; + } + } + if (!match) + d_vpr_e("%s: device region %d not found\n", __func__, region); + + return match; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/venus_hfi_queue.c b/qcom/opensource/video-driver/driver/vidc/src/venus_hfi_queue.c new file mode 100644 index 0000000000..98acb02d73 --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/venus_hfi_queue.c @@ -0,0 +1,710 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "venus_hfi_queue.h" +#include "msm_vidc_core.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_memory.h" +#include "msm_vidc_platform.h" +#include "venus_hfi.h" + +static void __set_queue_hdr_defaults(struct hfi_queue_header *q_hdr) +{ + q_hdr->qhdr_status = 0x1; + q_hdr->qhdr_type = VIDC_IFACEQ_DFLT_QHDR; + q_hdr->qhdr_q_size = VIDC_IFACEQ_QUEUE_SIZE / 4; + q_hdr->qhdr_pkt_size = 0; + q_hdr->qhdr_rx_wm = 0x1; + q_hdr->qhdr_tx_wm = 0x1; + q_hdr->qhdr_rx_req = 0x1; + q_hdr->qhdr_tx_req = 0x0; + q_hdr->qhdr_rx_irq_status = 0x0; + q_hdr->qhdr_tx_irq_status = 0x0; + q_hdr->qhdr_read_idx = 0x0; + q_hdr->qhdr_write_idx = 0x0; +} + +static void __dump_packet(u8 *packet, const char *function, void *qinfo) +{ + u32 c = 0, session_id, packet_size = *(u32 *)packet; + const int row_size = 32; + struct msm_vidc_iface_q_info *q; + struct hfi_queue_header *q_hdr; + /* + * row must contain enough for 0xdeadbaad * 8 to be converted into + * "de ad ba ab " * 8 + '\0' + */ + char row[3 * 32]; + + session_id = *((u32 *)packet + 1); + + q = (struct msm_vidc_iface_q_info *)qinfo; + q_hdr = (struct hfi_queue_header *)q->q_hdr; + d_vpr_t("%08x: %s: %pK: read_idx = %u, write_idx = %u\n", + session_id, function, qinfo, q_hdr->qhdr_read_idx, q_hdr->qhdr_write_idx); + + for (c = 0; c * row_size < packet_size; ++c) { + int bytes_to_read = ((c + 1) * row_size > packet_size) ? + packet_size % row_size : row_size; + hex_dump_to_buffer(packet + c * row_size, bytes_to_read, + row_size, 4, row, sizeof(row), false); + d_vpr_t("%08x: %s\n", session_id, row); + } +} + +static int __write_queue(struct msm_vidc_iface_q_info *qinfo, u8 *packet, + bool *rx_req_is_set) +{ + struct hfi_queue_header *queue; + u32 packet_size_in_words, new_write_idx; + u32 empty_space, read_idx, write_idx; + u32 *write_ptr; + + if (!qinfo || !packet) { + d_vpr_e("%s: invalid params %pK %pK\n", + __func__, qinfo, packet); + return -EINVAL; + } else if (!qinfo->q_array.align_virtual_addr) { + d_vpr_e("Queues have already been freed\n"); + return -EINVAL; + } + + queue = (struct hfi_queue_header *)qinfo->q_hdr; + if (!queue) { + d_vpr_e("queue not present\n"); + return -ENOENT; + } + + if (msm_vidc_debug & VIDC_PKT) + __dump_packet(packet, __func__, qinfo); + + // TODO: handle writing packet + //d_vpr_e("skip writing packet\n"); + //return 0; + + packet_size_in_words = (*(u32 *)packet) >> 2; + if (!packet_size_in_words || packet_size_in_words > + qinfo->q_array.mem_size>>2) { + d_vpr_e("Invalid packet size\n"); + return -ENODATA; + } + + read_idx = queue->qhdr_read_idx; + write_idx = queue->qhdr_write_idx; + + empty_space = (write_idx >= read_idx) ? + ((qinfo->q_array.mem_size>>2) - (write_idx - read_idx)) : + (read_idx - write_idx); + if (empty_space <= packet_size_in_words) { + queue->qhdr_tx_req = 1; + d_vpr_e("Insufficient size (%d) to write (%d)\n", + empty_space, packet_size_in_words); + return -ENOTEMPTY; + } + + queue->qhdr_tx_req = 0; + + new_write_idx = write_idx + packet_size_in_words; + write_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) + + (write_idx << 2)); + if (write_ptr < (u32 *)qinfo->q_array.align_virtual_addr || + write_ptr > (u32 *)(qinfo->q_array.align_virtual_addr + + qinfo->q_array.mem_size)) { + d_vpr_e("Invalid write index\n"); + return -ENODATA; + } + + if (new_write_idx < (qinfo->q_array.mem_size >> 2)) { + memcpy(write_ptr, packet, packet_size_in_words << 2); + } else { + new_write_idx -= qinfo->q_array.mem_size >> 2; + memcpy(write_ptr, packet, (packet_size_in_words - + new_write_idx) << 2); + memcpy((void *)qinfo->q_array.align_virtual_addr, + packet + ((packet_size_in_words - new_write_idx) << 2), + new_write_idx << 2); + } + + /* + * Memory barrier to make sure packet is written before updating the + * write index + */ + mb(); + queue->qhdr_write_idx = new_write_idx; + if (rx_req_is_set) + *rx_req_is_set = true; + /* + * Memory barrier to make sure write index is updated before an + * interrupt is raised on venus. + */ + mb(); + return 0; +} + +static int __read_queue(struct msm_vidc_iface_q_info *qinfo, u8 *packet, + u32 *pb_tx_req_is_set) +{ + struct hfi_queue_header *queue; + u32 packet_size_in_words, new_read_idx; + u32 *read_ptr; + u32 receive_request = 0; + u32 read_idx, write_idx; + int rc = 0; + + if (!qinfo || !packet || !pb_tx_req_is_set) { + d_vpr_e("%s: invalid params %pK %pK %pK\n", + __func__, qinfo, packet, pb_tx_req_is_set); + return -EINVAL; + } else if (!qinfo->q_array.align_virtual_addr) { + d_vpr_e("Queues have already been freed\n"); + return -EINVAL; + } + + /* + * Memory barrier to make sure data is valid before + *reading it + */ + mb(); + queue = (struct hfi_queue_header *)qinfo->q_hdr; + + if (!queue) { + d_vpr_e("Queue memory is not allocated\n"); + return -ENOMEM; + } + + /* + * Do not set receive request for debug queue, if set, + * Venus generates interrupt for debug messages even + * when there is no response message available. + * In general debug queue will not become full as it + * is being emptied out for every interrupt from Venus. + * Venus will anyway generates interrupt if it is full. + */ + if (queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q) + receive_request = 1; + + read_idx = queue->qhdr_read_idx; + write_idx = queue->qhdr_write_idx; + + if (read_idx == write_idx) { + queue->qhdr_rx_req = receive_request; + /* + * mb() to ensure qhdr is updated in main memory + * so that venus reads the updated header values + */ + mb(); + *pb_tx_req_is_set = 0; + d_vpr_l( + "%s queue is empty, rx_req = %u, tx_req = %u, read_idx = %u\n", + receive_request ? "message" : "debug", + queue->qhdr_rx_req, queue->qhdr_tx_req, + queue->qhdr_read_idx); + return -ENODATA; + } + + read_ptr = (u32 *)((qinfo->q_array.align_virtual_addr) + + (read_idx << 2)); + if (read_ptr < (u32 *)qinfo->q_array.align_virtual_addr || + read_ptr > (u32 *)(qinfo->q_array.align_virtual_addr + + qinfo->q_array.mem_size - sizeof(*read_ptr))) { + d_vpr_e("Invalid read index\n"); + return -ENODATA; + } + + packet_size_in_words = (*read_ptr) >> 2; + if (!packet_size_in_words) { + d_vpr_e("Zero packet size\n"); + return -ENODATA; + } + + new_read_idx = read_idx + packet_size_in_words; + if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE) && + read_idx <= (qinfo->q_array.mem_size >> 2)) { + if (new_read_idx < (qinfo->q_array.mem_size >> 2)) { + memcpy(packet, read_ptr, + packet_size_in_words << 2); + } else { + new_read_idx -= (qinfo->q_array.mem_size >> 2); + memcpy(packet, read_ptr, + (packet_size_in_words - new_read_idx) << 2); + memcpy(packet + ((packet_size_in_words - + new_read_idx) << 2), + (u8 *)qinfo->q_array.align_virtual_addr, + new_read_idx << 2); + } + } else { + d_vpr_e("BAD packet received, read_idx: %#x, pkt_size: %d\n", + read_idx, packet_size_in_words << 2); + d_vpr_e("Dropping this packet\n"); + new_read_idx = write_idx; + rc = -ENODATA; + } + + queue->qhdr_rx_req = receive_request; + + queue->qhdr_read_idx = new_read_idx; + /* + * mb() to ensure qhdr is updated in main memory + * so that venus reads the updated header values + */ + mb(); + + *pb_tx_req_is_set = (queue->qhdr_tx_req == 1) ? 1 : 0; + + if ((msm_vidc_debug & VIDC_PKT) && + !(queue->qhdr_type & HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q)) { + __dump_packet(packet, __func__, qinfo); + } + + return rc; +} + +/* Writes into cmdq without raising an interrupt */ +static int __iface_cmdq_write_relaxed(struct msm_vidc_core *core, + void *pkt, bool *requires_interrupt) +{ + struct msm_vidc_iface_q_info *q_info; + //struct vidc_hal_cmd_pkt_hdr *cmd_packet; + int rc = -E2BIG; + + rc = __strict_check(core, __func__); + if (rc) + return rc; + + if (!core_in_valid_state(core)) { + d_vpr_e("%s: fw not in init state\n", __func__); + rc = -EINVAL; + goto err_q_null; + } + + //cmd_packet = (struct vidc_hal_cmd_pkt_hdr *)pkt; + //core->last_packet_type = cmd_packet->packet_type; + + q_info = &core->iface_queues[VIDC_IFACEQ_CMDQ_IDX]; + if (!q_info) { + d_vpr_e("cannot write to shared Q's\n"); + goto err_q_null; + } + + if (!q_info->q_array.align_virtual_addr) { + d_vpr_e("cannot write to shared CMD Q's\n"); + rc = -ENODATA; + goto err_q_null; + } + + if (!__write_queue(q_info, (u8 *)pkt, requires_interrupt)) + rc = 0; + else + d_vpr_e("queue full\n"); + +err_q_null: + return rc; +} + +int venus_hfi_queue_cmd_write(struct msm_vidc_core *core, void *pkt) +{ + bool needs_interrupt = false; + int rc = __iface_cmdq_write_relaxed(core, pkt, &needs_interrupt); + + if (!rc && needs_interrupt) + call_venus_op(core, raise_interrupt, core); + + return rc; +} + +int venus_hfi_queue_cmd_write_intr(struct msm_vidc_core *core, void *pkt, + bool allow_intr) +{ + bool needs_interrupt = false; + int rc = __iface_cmdq_write_relaxed(core, pkt, &needs_interrupt); + + if (!rc && allow_intr && needs_interrupt) + call_venus_op(core, raise_interrupt, core); + + return rc; +} + +int venus_hfi_queue_msg_read(struct msm_vidc_core *core, void *pkt) +{ + u32 tx_req_is_set = 0; + int rc = 0; + struct msm_vidc_iface_q_info *q_info; + + if (!pkt) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (!core_in_valid_state(core)) { + d_vpr_e("%s: fw not in init state\n", __func__); + rc = -EINVAL; + goto read_error_null; + } + + q_info = &core->iface_queues[VIDC_IFACEQ_MSGQ_IDX]; + if (!q_info->q_array.align_virtual_addr) { + d_vpr_e("cannot read from shared MSG Q's\n"); + rc = -ENODATA; + goto read_error_null; + } + + if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) { + if (tx_req_is_set) { + //call_venus_op(core, raise_interrupt, core); + d_vpr_e("%s: queue is full\n", __func__); + rc = -EINVAL; + goto read_error_null; + } + rc = 0; + } else { + rc = -ENODATA; + } + +read_error_null: + return rc; +} + +int venus_hfi_queue_dbg_read(struct msm_vidc_core *core, void *pkt) +{ + u32 tx_req_is_set = 0; + int rc = 0; + struct msm_vidc_iface_q_info *q_info; + + if (!pkt) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + q_info = &core->iface_queues[VIDC_IFACEQ_DBGQ_IDX]; + if (!q_info->q_array.align_virtual_addr) { + d_vpr_e("cannot read from shared DBG Q's\n"); + rc = -ENODATA; + goto dbg_error_null; + } + + if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) { + if (tx_req_is_set) { + d_vpr_e("%s: queue is full\n", __func__); + //call_venus_op(core, raise_interrupt, core); + rc = -EINVAL; + goto dbg_error_null; + } + rc = 0; + } else { + rc = -ENODATA; + } + +dbg_error_null: + return rc; +} + +void venus_hfi_queue_deinit(struct msm_vidc_core *core) +{ + int i; + + d_vpr_h("%s: deinitializing interface queue\n", __func__); + + if (!core->iface_q_table.align_virtual_addr) { + d_vpr_h("%s: queues already deallocated\n", __func__); + return; + } + + call_mem_op(core, memory_unmap_free, core, &core->iface_q_table.mem); + call_mem_op(core, memory_unmap_free, core, &core->sfr.mem); + call_mem_op(core, iommu_unmap, core, &core->aon_reg.mem); + call_mem_op(core, iommu_unmap, core, &core->fence_reg.mem); + call_mem_op(core, iommu_unmap, core, &core->qtimer_reg.mem); + call_mem_op(core, memory_unmap_free, core, &core->mmap_buf.mem); + call_mem_op(core, mem_dma_unmap_page, core, + &core->synx_fence_data.queue); + + for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) { + core->iface_queues[i].q_hdr = NULL; + core->iface_queues[i].q_array.align_virtual_addr = NULL; + core->iface_queues[i].q_array.align_device_addr = 0; + } + + core->iface_q_table.align_virtual_addr = NULL; + core->iface_q_table.align_device_addr = 0; + + core->sfr.align_virtual_addr = NULL; + core->sfr.align_device_addr = 0; + + core->aon_reg.align_virtual_addr = NULL; + core->aon_reg.align_device_addr = 0; + + core->fence_reg.align_virtual_addr = NULL; + core->fence_reg.align_device_addr = 0; + + core->qtimer_reg.align_virtual_addr = NULL; + core->qtimer_reg.align_device_addr = 0; + + core->mmap_buf.align_virtual_addr = NULL; + core->mmap_buf.align_device_addr = 0; +} + +int venus_hfi_reset_queue_header(struct msm_vidc_core *core) +{ + struct msm_vidc_iface_q_info *iface_q; + struct hfi_queue_header *q_hdr; + int i, rc = 0; + + for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) { + iface_q = &core->iface_queues[i]; + __set_queue_hdr_defaults(iface_q->q_hdr); + } + + iface_q = &core->iface_queues[VIDC_IFACEQ_CMDQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q; + + iface_q = &core->iface_queues[VIDC_IFACEQ_MSGQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q; + + iface_q = &core->iface_queues[VIDC_IFACEQ_DBGQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q; + /* + * Set receive request to zero on debug queue as there is no + * need of interrupt from video hardware for debug messages + */ + q_hdr->qhdr_rx_req = 0; + + return rc; +} + +static int venus_hfi_iommu_map_registers(struct msm_vidc_core *core, + enum msm_vidc_device_region reg_region, + enum msm_vidc_buffer_region buf_region, + struct msm_vidc_mem_addr *core_mem) +{ + int rc = 0; + struct device_region_info *dev_reg; + struct msm_vidc_mem mem; + + if (!core_mem) { + d_vpr_h("%s: invalid params\n", __func__); + return -EINVAL; + } + + memset(&mem, 0, sizeof(mem)); + dev_reg = venus_hfi_get_device_region_info(core, reg_region); + if (!dev_reg) { + d_vpr_h("%s: %u device region not available\n", + __func__, reg_region); + goto skip_mmap_buffer; + } + + mem.region = buf_region; + mem.phys_addr = dev_reg->phy_addr; + mem.size = dev_reg->size; + mem.device_addr = dev_reg->dev_addr; + rc = call_mem_op(core, iommu_map, core, &mem); + if (rc) { + d_vpr_e("%s: %u map failed\n", __func__, reg_region); + goto fail_alloc_queue; + } + core_mem->align_device_addr = mem.device_addr; + core_mem->mem = mem; + +skip_mmap_buffer: + return 0; +fail_alloc_queue: + return -ENOMEM; +} + +int venus_hfi_queue_init(struct msm_vidc_core *core) +{ + int rc = 0; + struct hfi_queue_table_header *q_tbl_hdr; + struct hfi_queue_header *q_hdr; + struct msm_vidc_iface_q_info *iface_q; + struct msm_vidc_mem mem; + int offset = 0; + u32 *payload; + u32 i; + + d_vpr_h("%s: initializing interface queue\n", __func__); + + if (core->iface_q_table.align_virtual_addr) { + d_vpr_h("%s: queues already allocated\n", __func__); + venus_hfi_reset_queue_header(core); + return 0; + } + + memset(&mem, 0, sizeof(mem)); + mem.type = MSM_VIDC_BUF_INTERFACE_QUEUE; + mem.region = MSM_VIDC_NON_SECURE; + mem.size = TOTAL_QSIZE; + mem.secure = false; + mem.map_kernel = true; + rc = call_mem_op(core, memory_alloc_map, core, &mem); + if (rc) { + d_vpr_e("%s: alloc and map failed\n", __func__); + goto fail_alloc_queue; + } + core->iface_q_table.align_virtual_addr = mem.kvaddr; + core->iface_q_table.align_device_addr = mem.device_addr; + core->iface_q_table.mem = mem; + + core->iface_q_table.mem_size = VIDC_IFACEQ_TABLE_SIZE; + offset += core->iface_q_table.mem_size; + + for (i = 0; i < VIDC_IFACEQ_NUMQ; i++) { + iface_q = &core->iface_queues[i]; + iface_q->q_array.align_device_addr = mem.device_addr + offset; + iface_q->q_array.align_virtual_addr = (void *)((char *)mem.kvaddr + offset); + iface_q->q_array.mem_size = VIDC_IFACEQ_QUEUE_SIZE; + offset += iface_q->q_array.mem_size; + iface_q->q_hdr = VIDC_IFACEQ_GET_QHDR_START_ADDR( + core->iface_q_table.align_virtual_addr, i); + __set_queue_hdr_defaults(iface_q->q_hdr); + } + + q_tbl_hdr = (struct hfi_queue_table_header *) + core->iface_q_table.align_virtual_addr; + q_tbl_hdr->qtbl_version = 0; + q_tbl_hdr->device_addr = (void *)core; + strlcpy(q_tbl_hdr->name, "msm_v4l2_vidc", sizeof(q_tbl_hdr->name)); + q_tbl_hdr->qtbl_size = VIDC_IFACEQ_TABLE_SIZE; + q_tbl_hdr->qtbl_qhdr0_offset = sizeof(struct hfi_queue_table_header); + q_tbl_hdr->qtbl_qhdr_size = sizeof(struct hfi_queue_header); + q_tbl_hdr->qtbl_num_q = VIDC_IFACEQ_NUMQ; + q_tbl_hdr->qtbl_num_active_q = VIDC_IFACEQ_NUMQ; + + iface_q = &core->iface_queues[VIDC_IFACEQ_CMDQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q; + + iface_q = &core->iface_queues[VIDC_IFACEQ_MSGQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q; + + iface_q = &core->iface_queues[VIDC_IFACEQ_DBGQ_IDX]; + q_hdr = iface_q->q_hdr; + q_hdr->qhdr_start_addr = iface_q->q_array.align_device_addr; + q_hdr->qhdr_type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q; + /* + * Set receive request to zero on debug queue as there is no + * need of interrupt from video hardware for debug messages + */ + q_hdr->qhdr_rx_req = 0; + + /* sfr buffer */ + memset(&mem, 0, sizeof(mem)); + mem.type = MSM_VIDC_BUF_INTERFACE_QUEUE; + mem.region = MSM_VIDC_NON_SECURE; + mem.size = ALIGNED_SFR_SIZE; + mem.secure = false; + mem.map_kernel = true; + rc = call_mem_op(core, memory_alloc_map, core, &mem); + if (rc) { + d_vpr_e("%s: sfr alloc and map failed\n", __func__); + goto fail_alloc_queue; + } + core->sfr.align_virtual_addr = mem.kvaddr; + core->sfr.align_device_addr = mem.device_addr; + core->sfr.mem = mem; + + core->sfr.mem_size = ALIGNED_SFR_SIZE; + /* write sfr buffer size in first word */ + *((u32 *)core->sfr.align_virtual_addr) = core->sfr.mem_size; + + /* map synx fence tx/rx queue buffer */ + if (core->capabilities[SUPPORTS_SYNX_FENCE].value) { + /* + * queue memory is already allocated by synx fence + * driver during msm_vidc_synx_fence_register(..) call + */ + rc = call_mem_op(core, mem_dma_map_page, core, + &core->synx_fence_data.queue); + if (rc) { + d_vpr_e("%s: synx fence queue buffer map failed\n", __func__); + goto fail_alloc_queue; + } + } + + /* map aon_reg registers */ + rc = venus_hfi_iommu_map_registers(core, MSM_VIDC_AON, + MSM_VIDC_NON_SECURE, &core->aon_reg); + if (rc) + return rc; + + /* map fence registers */ + rc = venus_hfi_iommu_map_registers(core, + MSM_VIDC_PROTOCOL_FENCE_CLIENT_VPU, + MSM_VIDC_NON_SECURE, &core->fence_reg); + if (rc) + return rc; + + /* map qtimer low registers */ + rc = venus_hfi_iommu_map_registers(core, + MSM_VIDC_QTIMER, + MSM_VIDC_NON_SECURE, &core->qtimer_reg); + if (rc) + return rc; + + /* allocate 4k buffer for HFI_MMAP_ADDR */ + memset(&mem, 0, sizeof(mem)); + mem.type = MSM_VIDC_BUF_INTERFACE_QUEUE; + mem.region = MSM_VIDC_NON_SECURE; + mem.size = ALIGNED_MMAP_BUF_SIZE; + mem.secure = false; + mem.map_kernel = true; + rc = call_mem_op(core, memory_alloc_map, core, &mem); + if (rc) { + d_vpr_e("%s: mmap buffer alloc and map failed\n", __func__); + goto fail_alloc_queue; + } + core->mmap_buf.align_virtual_addr = mem.kvaddr; + core->mmap_buf.align_device_addr = mem.device_addr; + core->mmap_buf.mem_size = ALIGNED_MMAP_BUF_SIZE; + core->mmap_buf.mem = mem; + /* initialize mmap buffer */ + /* payload of HFI_MMAP_ADDR: + * payload[0] : version + * ___________________ payloads in version 1 ________________ + * payload[1-2] : address and size of SFR + * payload[3-4] : address and size of IPCC lite memory + * payload[5-6] : address and size of AOSS global timers + * payload[7-8] : address and size of HW mutex registers + * payload[9-10] : address and size of IPCC registers + * payload[11-12] : address and size of AON registers + * payload[13-14] : address and size of synx fence queue memory + * payload[19-20] : address and size of IPC_PROTOCOL4_CLIENT_VERSION registers + * payload[21-22] : address and size of FENCE QTIMER registers + */ + memset(core->mmap_buf.align_virtual_addr, 0, ALIGNED_MMAP_BUF_SIZE); + payload = ((u32 *)core->mmap_buf.align_virtual_addr); + payload[0] = 1; + if (core->aon_reg.mem.device_addr) { + payload[11] = core->aon_reg.mem.device_addr; + payload[12] = core->aon_reg.mem.size; + } + if (core->synx_fence_data.queue.device_addr) { + payload[13] = core->synx_fence_data.queue.device_addr; + payload[14] = core->synx_fence_data.queue.size; + } + if (core->fence_reg.mem.device_addr) { + payload[19] = core->fence_reg.mem.device_addr; + payload[20] = core->fence_reg.mem.size; + } + if (core->qtimer_reg.mem.device_addr) { + payload[21] = core->qtimer_reg.mem.device_addr; + payload[22] = core->qtimer_reg.mem.size; + } + + return 0; + +fail_alloc_queue: + return -ENOMEM; +} diff --git a/qcom/opensource/video-driver/driver/vidc/src/venus_hfi_response.c b/qcom/opensource/video-driver/driver/vidc/src/venus_hfi_response.c new file mode 100644 index 0000000000..950e14303e --- /dev/null +++ b/qcom/opensource/video-driver/driver/vidc/src/venus_hfi_response.c @@ -0,0 +1,2029 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include + +#include "hfi_packet.h" +#include "venus_hfi.h" +#include "venus_hfi_response.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_driver.h" +#include "msm_vdec.h" +#include "msm_vidc_memory.h" +#include "msm_vidc_fence.h" +#include "msm_vidc_platform.h" + +#define in_range(range, val) (((range.begin) < (val)) && ((range.end) > (val))) + +extern struct msm_vidc_core *g_core; +struct msm_vidc_core_hfi_range { + u32 begin; + u32 end; + int (*handle)(struct msm_vidc_core *core, struct hfi_packet *pkt); +}; + +struct msm_vidc_inst_hfi_range { + u32 begin; + u32 end; + int (*handle)(struct msm_vidc_inst *inst, struct hfi_packet *pkt); +}; + +struct msm_vidc_hfi_buffer_handle { + enum hfi_buffer_type type; + int (*handle)(struct msm_vidc_inst *inst, struct hfi_buffer *buffer); +}; + +struct msm_vidc_hfi_packet_handle { + enum hfi_buffer_type type; + int (*handle)(struct msm_vidc_inst *inst, struct hfi_packet *pkt); +}; + +void print_psc_properties(const char *str, struct msm_vidc_inst *inst, + struct msm_vidc_subscription_params subsc_params) +{ + i_vpr_h(inst, + "%s: width %d, height %d, crop offsets[0] %#x, crop offsets[1] %#x, bit depth %#x, coded frames %d fw min count %d, poc %d, color info %d, profile %d, level %d, tier %d, fg present %d, sb enabled %d, max_num_reorder_frames %d, max_dec_frame_buffering_count %d\n", + str, (subsc_params.bitstream_resolution & HFI_BITMASK_BITSTREAM_WIDTH) >> 16, + (subsc_params.bitstream_resolution & HFI_BITMASK_BITSTREAM_HEIGHT), + subsc_params.crop_offsets[0], subsc_params.crop_offsets[1], + subsc_params.bit_depth, subsc_params.coded_frames, + subsc_params.fw_min_count, subsc_params.pic_order_cnt, + subsc_params.color_info, subsc_params.profile, subsc_params.level, + subsc_params.tier, subsc_params.av1_film_grain_present, + subsc_params.av1_super_block_enabled, + (subsc_params.max_num_reorder_frames >> 16), + (subsc_params.max_num_reorder_frames & 0x00FF)); +} + +static void print_sfr_message(struct msm_vidc_core *core) +{ + struct msm_vidc_sfr *vsfr = NULL; + u32 vsfr_size = 0; + void *p = NULL; + + vsfr = (struct msm_vidc_sfr *)core->sfr.align_virtual_addr; + if (vsfr) { + if (vsfr->buf_size != core->sfr.mem_size) { + d_vpr_e("Invalid SFR buf size %d actual %d\n", + vsfr->buf_size, core->sfr.mem_size); + return; + } + vsfr_size = vsfr->buf_size - sizeof(u32); + p = memchr(vsfr->rg_data, '\0', vsfr_size); + /* SFR isn't guaranteed to be NULL terminated */ + if (p == NULL) + vsfr->rg_data[vsfr_size - 1] = '\0'; + + d_vpr_e(FMT_STRING_MSG_SFR, vsfr->rg_data); + } +} + +u32 vidc_port_from_hfi(struct msm_vidc_inst *inst, + enum hfi_packet_port_type hfi_port) +{ + enum msm_vidc_port_type port = MAX_PORT; + + if (is_decode_session(inst)) { + switch (hfi_port) { + case HFI_PORT_BITSTREAM: + port = INPUT_PORT; + break; + case HFI_PORT_RAW: + port = OUTPUT_PORT; + break; + case HFI_PORT_NONE: + port = PORT_NONE; + break; + default: + i_vpr_e(inst, "%s: invalid hfi port type %d\n", + __func__, hfi_port); + break; + } + } else if (is_encode_session(inst)) { + switch (hfi_port) { + case HFI_PORT_RAW: + port = INPUT_PORT; + break; + case HFI_PORT_BITSTREAM: + port = OUTPUT_PORT; + break; + case HFI_PORT_NONE: + port = PORT_NONE; + break; + default: + i_vpr_e(inst, "%s: invalid hfi port type %d\n", + __func__, hfi_port); + break; + } + } else { + i_vpr_e(inst, "%s: invalid domain %#x\n", + __func__, inst->domain); + } + + return port; +} + +bool is_valid_hfi_port(struct msm_vidc_inst *inst, u32 port, + u32 buffer_type, const char *func) +{ + if (port == HFI_PORT_NONE && + buffer_type != HFI_BUFFER_ARP && + buffer_type != HFI_BUFFER_PERSIST) + goto invalid; + + if (port != HFI_PORT_BITSTREAM && port != HFI_PORT_RAW) + goto invalid; + + return true; + +invalid: + i_vpr_e(inst, "%s: invalid port %#x buffer_type %u\n", + func, port, buffer_type); + return false; +} + +bool is_valid_hfi_buffer_type(struct msm_vidc_inst *inst, + u32 buffer_type, const char *func) +{ + if (buffer_type != HFI_BUFFER_BITSTREAM && + buffer_type != HFI_BUFFER_RAW && + buffer_type != HFI_BUFFER_METADATA && + buffer_type != HFI_BUFFER_BIN && + buffer_type != HFI_BUFFER_ARP && + buffer_type != HFI_BUFFER_COMV && + buffer_type != HFI_BUFFER_NON_COMV && + buffer_type != HFI_BUFFER_LINE && + buffer_type != HFI_BUFFER_DPB && + buffer_type != HFI_BUFFER_PERSIST && + buffer_type != HFI_BUFFER_VPSS && + buffer_type != HFI_BUFFER_PARTIAL_DATA) { + i_vpr_e(inst, "%s: invalid buffer type %#x\n", + func, buffer_type); + return false; + } + return true; +} + +int validate_packet(u8 *response_pkt, u8 *core_resp_pkt, + u32 core_resp_pkt_size, const char *func) +{ + u8 *response_limit; + u32 response_pkt_size = 0; + + if (!response_pkt || !core_resp_pkt || !core_resp_pkt_size) { + d_vpr_e("%s: invalid params\n", func); + return -EINVAL; + } + + response_limit = core_resp_pkt + core_resp_pkt_size; + + if (response_pkt < core_resp_pkt || response_pkt > response_limit) { + d_vpr_e("%s: invalid packet address\n", func); + return -EINVAL; + } + + response_pkt_size = *(u32 *)response_pkt; + if (!response_pkt_size) { + d_vpr_e("%s: response packet size cannot be zero\n", func); + return -EINVAL; + } + + if (response_pkt_size < sizeof(struct hfi_packet)) { + d_vpr_e("%s: invalid packet size %d\n", + func, response_pkt_size); + return -EINVAL; + } + + if (response_pkt + response_pkt_size > response_limit) { + d_vpr_e("%s: invalid packet size %d\n", + func, response_pkt_size); + return -EINVAL; + } + return 0; +} + +static int validate_hdr_packet(struct msm_vidc_core *core, + struct hfi_header *hdr, const char *function) +{ + struct hfi_packet *packet; + u8 *pkt; + int i, rc = 0; + + if (hdr->size < sizeof(struct hfi_header) + sizeof(struct hfi_packet)) { + d_vpr_e("%s: invalid header size %d\n", __func__, hdr->size); + return -EINVAL; + } + + pkt = (u8 *)((u8 *)hdr + sizeof(struct hfi_header)); + + /* validate all packets */ + for (i = 0; i < hdr->num_packets; i++) { + packet = (struct hfi_packet *)pkt; + rc = validate_packet(pkt, core->response_packet, core->packet_size, function); + if (rc) + return rc; + + pkt += packet->size; + } + + return 0; +} + +static bool check_for_packet_payload(struct msm_vidc_inst *inst, + struct hfi_packet *pkt, const char *func) +{ + u32 payload_size = 0; + + if (pkt->payload_info == HFI_PAYLOAD_NONE) { + i_vpr_h(inst, "%s: no playload available for packet %#x\n", + func, pkt->type); + return false; + } + + switch (pkt->payload_info) { + case HFI_PAYLOAD_U32: + case HFI_PAYLOAD_S32: + case HFI_PAYLOAD_Q16: + case HFI_PAYLOAD_U32_ENUM: + case HFI_PAYLOAD_32_PACKED: + payload_size = 4; + break; + case HFI_PAYLOAD_U64: + case HFI_PAYLOAD_S64: + case HFI_PAYLOAD_64_PACKED: + payload_size = 8; + break; + case HFI_PAYLOAD_STRUCTURE: + if (pkt->type == HFI_CMD_BUFFER) + payload_size = sizeof(struct hfi_buffer); + break; + default: + payload_size = 0; + break; + } + + if (pkt->size < sizeof(struct hfi_packet) + payload_size) { + i_vpr_e(inst, + "%s: invalid payload size %u payload type %#x for packet %#x\n", + func, pkt->size, pkt->payload_info, pkt->type); + return false; + } + + return true; +} + +static int handle_session_last_flag_info(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + int rc = 0; + + if (pkt->type == HFI_INFO_HFI_FLAG_PSC_LAST) { + if (msm_vidc_allow_psc_last_flag(inst)) + rc = msm_vidc_process_psc_last_flag(inst); + else + rc = -EINVAL; + } else if (pkt->type == HFI_INFO_HFI_FLAG_DRAIN_LAST) { + if (msm_vidc_allow_drain_last_flag(inst)) + rc = msm_vidc_process_drain_last_flag(inst); + else + rc = -EINVAL; + } else { + i_vpr_e(inst, "%s: invalid packet type %#x\n", __func__, + pkt->type); + } + + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + + return rc; +} + +static int handle_session_info(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + int rc = 0; + char *info; + + switch (pkt->type) { + case HFI_INFO_UNSUPPORTED: + info = "unsupported"; + break; + case HFI_INFO_DATA_CORRUPT: + info = "data corrupt"; + inst->hfi_frame_info.data_corrupt = 1; + break; + case HFI_INFO_BUFFER_OVERFLOW: + info = "buffer overflow"; + inst->hfi_frame_info.overflow = 1; + break; + case HFI_INFO_FENCE_SIGNAL_ERROR: + info = "synx v2 fence error"; + inst->hfi_frame_info.fence_error = 1; + break; + case HFI_INFO_HFI_FLAG_DRAIN_LAST: + info = "drain last flag"; + rc = handle_session_last_flag_info(inst, pkt); + break; + case HFI_INFO_HFI_FLAG_PSC_LAST: + info = "drc last flag"; + rc = handle_session_last_flag_info(inst, pkt); + break; + default: + info = "unknown"; + break; + } + + i_vpr_h(inst, "session info (%#x): %s\n", pkt->type, info); + + return rc; +} + +static int handle_session_error(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + int rc = 0; + char *error; + + switch (pkt->type) { + case HFI_ERROR_MAX_SESSIONS: + error = "exceeded max sessions"; + break; + case HFI_ERROR_UNKNOWN_SESSION: + error = "unknown session id"; + break; + case HFI_ERROR_INVALID_STATE: + error = "invalid operation for current state"; + break; + case HFI_ERROR_INSUFFICIENT_RESOURCES: + error = "insufficient resources"; + break; + case HFI_ERROR_BUFFER_NOT_SET: + error = "internal buffers not set"; + break; + case HFI_ERROR_FATAL: + error = "fatal error"; + break; + default: + error = "unknown"; + break; + } + + i_vpr_e(inst, "%s: session error received %#x: %s\n", + __func__, pkt->type, error); + + rc = msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + return rc; +} + +int handle_system_error(struct msm_vidc_core *core, + struct hfi_packet *pkt) +{ + bool bug_on = false; + + d_vpr_e(FMT_STRING_SYSTEM_ERROR, __func__); + print_sfr_message(core); + + if (pkt) { + /* enable force bugon for requested type */ + if (pkt->type == HFI_SYS_ERROR_FATAL) { + bug_on = !!(msm_vidc_enable_bugon & MSM_VIDC_BUG_ON_FATAL); + } else if (pkt->type == HFI_SYS_ERROR_NOC) { + bug_on = !!(msm_vidc_enable_bugon & MSM_VIDC_BUG_ON_NOC); + venus_hfi_noc_error_info(core); + } else if (pkt->type == HFI_SYS_ERROR_WD_TIMEOUT) { + bug_on = !!(msm_vidc_enable_bugon & MSM_VIDC_BUG_ON_WD_TIMEOUT); + } + if (bug_on) { + d_vpr_e("%s: force bugon for type %#x\n", __func__, pkt->type); + MSM_VIDC_FATAL(true); + } + } + + core_lock(core, __func__); + msm_vidc_change_core_state(core, MSM_VIDC_CORE_ERROR, __func__); + msm_vidc_core_deinit_locked(core, true); + core_unlock(core, __func__); + + return 0; +} + +static int handle_system_init(struct msm_vidc_core *core, + struct hfi_packet *pkt) +{ + if (!(pkt->flags & HFI_FW_FLAGS_SUCCESS)) { + d_vpr_h("%s: unhandled. flags=%d\n", __func__, pkt->flags); + return 0; + } + + core_lock(core, __func__); + if (pkt->packet_id != core->sys_init_id) { + d_vpr_e("%s: invalid pkt id %u, expected %u\n", __func__, + pkt->packet_id, core->sys_init_id); + goto unlock; + } + + msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT, __func__); + d_vpr_h("%s: successful\n", __func__); + +unlock: + core_unlock(core, __func__); + return 0; +} + +static int handle_session_open(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful\n", __func__); + + return 0; +} + +static int handle_session_close(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful\n", __func__); + + signal_session_msg_receipt(inst, SIGNAL_CMD_CLOSE); + return 0; +} + +static int handle_session_start(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful for port %d\n", + __func__, pkt->port); + return 0; +} + +static int handle_session_stop(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + int rc = 0; + enum signal_session_response signal_type = -1; + + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful for port %d\n", + __func__, pkt->port); + + if (is_encode_session(inst)) { + if (pkt->port == HFI_PORT_RAW) { + signal_type = SIGNAL_CMD_STOP_INPUT; + } else if (pkt->port == HFI_PORT_BITSTREAM) { + signal_type = SIGNAL_CMD_STOP_OUTPUT; + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", + __func__, pkt->port); + return -EINVAL; + } + } else if (is_decode_session(inst)) { + if (pkt->port == HFI_PORT_RAW) { + signal_type = SIGNAL_CMD_STOP_OUTPUT; + } else if (pkt->port == HFI_PORT_BITSTREAM) { + signal_type = SIGNAL_CMD_STOP_INPUT; + } else { + i_vpr_e(inst, "%s: invalid port: %d\n", + __func__, pkt->port); + return -EINVAL; + } + } else { + i_vpr_e(inst, "%s: invalid session\n", __func__); + return -EINVAL; + } + + if (signal_type != -1) { + rc = msm_vidc_process_stop_done(inst, signal_type); + if (rc) + return rc; + } + + return 0; +} + +static int handle_session_drain(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + int rc = 0; + + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful\n", __func__); + + rc = msm_vidc_process_drain_done(inst); + if (rc) + return rc; + + return rc; +} + +static int get_driver_buffer_flags(struct msm_vidc_inst *inst, u32 hfi_flags) +{ + u32 driver_flags = 0; + + if (inst->hfi_frame_info.picture_type & HFI_PICTURE_IDR) + driver_flags |= MSM_VIDC_BUF_FLAG_KEYFRAME; + else if (inst->hfi_frame_info.picture_type & HFI_PICTURE_P) + driver_flags |= MSM_VIDC_BUF_FLAG_PFRAME; + else if (inst->hfi_frame_info.picture_type & HFI_PICTURE_B) + driver_flags |= MSM_VIDC_BUF_FLAG_BFRAME; + else if (inst->hfi_frame_info.picture_type & HFI_PICTURE_I) + driver_flags |= MSM_VIDC_BUF_FLAG_KEYFRAME; + else if (inst->hfi_frame_info.picture_type & HFI_PICTURE_CRA) + driver_flags |= MSM_VIDC_BUF_FLAG_KEYFRAME; + else if (inst->hfi_frame_info.picture_type & HFI_PICTURE_BLA) + driver_flags |= MSM_VIDC_BUF_FLAG_KEYFRAME; + + if (inst->hfi_frame_info.data_corrupt) + driver_flags |= MSM_VIDC_BUF_FLAG_ERROR; + + if (inst->hfi_frame_info.overflow) + driver_flags |= MSM_VIDC_BUF_FLAG_ERROR; + + if (inst->hfi_frame_info.no_output) { + if (inst->capabilities[META_BUF_TAG].value && + !(hfi_flags & HFI_BUF_FW_FLAG_CODEC_CONFIG)) + driver_flags |= MSM_VIDC_BUF_FLAG_ERROR; + } + + if (inst->hfi_frame_info.subframe_input) + if (inst->capabilities[META_BUF_TAG].value) + driver_flags |= MSM_VIDC_BUF_FLAG_ERROR; + + if (hfi_flags & HFI_BUF_FW_FLAG_CODEC_CONFIG) + driver_flags |= MSM_VIDC_BUF_FLAG_CODECCONFIG; + + if (hfi_flags & HFI_BUF_FW_FLAG_LAST || + hfi_flags & HFI_BUF_FW_FLAG_PSC_LAST) + driver_flags |= MSM_VIDC_BUF_FLAG_LAST; + + /* + * if last flag event is enabled then remove BUF_FLAG_LAST + * because last flag information will be sent via V4L2_EVENT_EOS + */ + if (inst->capabilities[LAST_FLAG_EVENT_ENABLE].value) + driver_flags &= ~MSM_VIDC_BUF_FLAG_LAST; + + return driver_flags; +} + +static int handle_read_only_buffer(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + struct msm_vidc_buffer *ro_buf; + struct msm_vidc_core *core; + bool found = false; + + core = inst->core; + + if (!is_decode_session(inst) || !is_output_buffer(buf->type)) + return 0; + + if (!(buf->attr & MSM_VIDC_ATTR_READ_ONLY)) + return 0; + + list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) { + if (ro_buf->device_addr == buf->device_addr) { + found = true; + break; + } + } + /* + * RO flag: add to read_only list if buffer is not present + * if present, do nothing + */ + if (!found) { + ro_buf = msm_vidc_pool_alloc(inst, MSM_MEM_POOL_BUFFER); + if (!ro_buf) { + i_vpr_e(inst, "%s: buffer alloc failed\n", __func__); + return -ENOMEM; + } + ro_buf->index = -1; + ro_buf->inst = inst; + ro_buf->type = buf->type; + ro_buf->fd = buf->fd; + ro_buf->dmabuf = buf->dmabuf; + ro_buf->device_addr = buf->device_addr; + ro_buf->data_offset = buf->data_offset; + ro_buf->dbuf_get = buf->dbuf_get; + buf->dbuf_get = 0; + INIT_LIST_HEAD(&ro_buf->list); + list_add_tail(&ro_buf->list, &inst->buffers.read_only.list); + print_vidc_buffer(VIDC_LOW, "low ", "ro buf added", inst, ro_buf); + } else { + print_vidc_buffer(VIDC_LOW, "low ", "ro buf found", inst, ro_buf); + } + ro_buf->attr |= MSM_VIDC_ATTR_READ_ONLY; + + return 0; +} + +static int handle_non_read_only_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer) +{ + struct msm_vidc_buffer *ro_buf; + + if (!is_decode_session(inst) || buffer->type != HFI_BUFFER_RAW) + return 0; + + if (buffer->flags & HFI_BUF_FW_FLAG_READONLY) + return 0; + + list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) { + if (ro_buf->device_addr == buffer->base_address) { + ro_buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY; + break; + } + } + + return 0; +} + +static int handle_psc_last_flag_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer) +{ + int rc = 0; + + if (!(buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST)) + return 0; + + if (!msm_vidc_allow_psc_last_flag(inst)) + return -EINVAL; + + rc = msm_vidc_process_psc_last_flag(inst); + if (rc) + return rc; + + return rc; +} + +static int handle_drain_last_flag_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer) +{ + int rc = 0; + + if (!(buffer->flags & HFI_BUF_FW_FLAG_LAST)) + return 0; + + if (!msm_vidc_allow_drain_last_flag(inst)) + return -EINVAL; + + rc = msm_vidc_process_drain_last_flag(inst); + if (rc) + return rc; + + return rc; +} + +static int handle_input_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf; + struct msm_vidc_core *core; + u32 frame_size, batch_size; + bool found; + + core = inst->core; + buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_INPUT, __func__); + if (!buffers) + return -EINVAL; + + found = false; + list_for_each_entry(buf, &buffers->list, list) { + if (buf->index == buffer->index) { + found = true; + break; + } + } + if (!found) { + i_vpr_e(inst, "%s: invalid buffer idx %d addr %#llx data_offset %d\n", + __func__, buffer->index, buffer->base_address, + buffer->data_offset); + return -EINVAL; + } + + /* attach dequeued flag for, only last frame in the batch */ + if (msm_vidc_is_super_buffer(inst)) { + frame_size = call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT); + batch_size = inst->capabilities[SUPER_FRAME].value; + if (!frame_size || !batch_size) { + i_vpr_e(inst, "%s: invalid size: frame %u, batch %u\n", + __func__, frame_size, batch_size); + return -EINVAL; + } + if (buffer->addr_offset / frame_size < batch_size - 1) { + i_vpr_l(inst, "%s: superframe last buffer not reached: %u, %u, %u\n", + __func__, buffer->addr_offset, frame_size, batch_size); + /* remove buffer stats for all the subframes in a superframe */ + msm_vidc_remove_buffer_stats(inst, buf, buffer->timestamp); + return 0; + } + } + + if (!(buf->attr & MSM_VIDC_ATTR_QUEUED)) { + print_vidc_buffer(VIDC_ERR, "err ", "not queued", inst, buf); + return 0; + } + + if (is_decode_session(inst) && inst->codec == MSM_VIDC_AV1) { + if (inst->hfi_frame_info.av1_tile_rows_columns) { + inst->power.fw_av1_tile_rows = + inst->hfi_frame_info.av1_tile_rows_columns >> 16; + inst->power.fw_av1_tile_columns = + inst->hfi_frame_info.av1_tile_rows_columns & 0x0000FFFF; + } + + if (inst->hfi_frame_info.av1_non_uniform_tile_spacing) + i_vpr_l(inst, "%s: av1_non_uniform_tile_spacing %d\n", + __func__, inst->hfi_frame_info.av1_non_uniform_tile_spacing); + } + + buf->data_size = buffer->data_size; + buf->attr &= ~MSM_VIDC_ATTR_QUEUED; + buf->attr |= MSM_VIDC_ATTR_DEQUEUED; + + buf->flags = 0; + buf->flags = get_driver_buffer_flags(inst, buffer->flags); + + /* handle ts_reorder for no_output prop attached input buffer */ + if (is_ts_reorder_allowed(inst) && inst->hfi_frame_info.no_output) { + i_vpr_h(inst, "%s: received no_output buffer. remove timestamp %lld\n", + __func__, buf->timestamp); + msm_vidc_ts_reorder_remove_timestamp(inst, buf->timestamp); + } + + print_vidc_buffer(VIDC_HIGH, "high", "dqbuf", inst, buf); + msm_vidc_update_stats(inst, buf, MSM_VIDC_DEBUGFS_EVENT_EBD); + + /* ebd: update end timestamp and flags in stats entry */ + msm_vidc_remove_buffer_stats(inst, buf, buffer->timestamp); + + return rc; +} + +static int msm_vidc_handle_fence_signal(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + int rc = 0; + bool signal_error = false; + struct msm_vidc_core *core = inst->core; + + if (inst->capabilities[OUTBUF_FENCE_TYPE].value == + MSM_VIDC_FENCE_NONE) + return 0; + + if (is_meta_rx_inp_enabled(inst, META_OUTBUF_FENCE)) { + if (!inst->hfi_frame_info.fence_id) { + i_vpr_e(inst, + "%s: fence id is not received although fencing is enabled\n", + __func__); + return -EINVAL; + } + } else { + if (!inst->hfi_frame_info.fence_id) { + return 0; + } + i_vpr_e(inst, + "%s: fence id: %d is received although fencing is not enabled\n", + __func__, inst->hfi_frame_info.fence_id); + signal_error = true; + goto signal; + } + + if (inst->capabilities[OUTBUF_FENCE_TYPE].value == + MSM_VIDC_SYNX_V2_FENCE) { + if (inst->hfi_frame_info.fence_error) + signal_error = true; + } else if (inst->capabilities[OUTBUF_FENCE_TYPE].value == + MSM_VIDC_SW_FENCE) { + if (!buf->data_size) + signal_error = true; + + if (inst->hfi_frame_info.fence_error) + i_vpr_e(inst, + "%s: fence error info received for SW fence\n", + __func__); + } else { + i_vpr_e(inst, "%s: invalid fence type\n", __func__); + return -EINVAL; + } + +signal: + /* fence signalling */ + if (signal_error) { + /* signal fence error */ + i_vpr_l(inst, + "%s: signalling fence error for buf idx %d daddr %#llx\n", + __func__, buf->index, buf->device_addr); + call_fence_op(core, fence_destroy, inst, + inst->hfi_frame_info.fence_id); + } else { + /* signal fence success*/ + rc = call_fence_op(core, fence_signal, inst, + inst->hfi_frame_info.fence_id); + if (rc) { + i_vpr_e(inst, "%s: failed to signal fence\n", __func__); + return -EINVAL; + } + } + + return 0; +} + +static int handle_output_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf; + struct msm_vidc_core *core; + bool found, fatal = false; + + core = inst->core; + + /* handle drain last flag buffer */ + if (buffer->flags & HFI_BUF_FW_FLAG_LAST) { + rc = handle_drain_last_flag_buffer(inst, buffer); + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + + if (is_decode_session(inst)) { + /* handle release response for decoder output buffer */ + if (buffer->flags & HFI_BUF_FW_FLAG_RELEASE_DONE) + return handle_release_output_buffer(inst, buffer); + /* handle psc last flag buffer */ + if (buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST) { + rc = handle_psc_last_flag_buffer(inst, buffer); + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + /* handle non-read only buffer */ + if (!(buffer->flags & HFI_BUF_FW_FLAG_READONLY)) { + rc = handle_non_read_only_buffer(inst, buffer); + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + } + + buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_OUTPUT, __func__); + if (!buffers) + return -EINVAL; + + found = false; + list_for_each_entry(buf, &buffers->list, list) { + if (!(buf->attr & MSM_VIDC_ATTR_QUEUED)) + continue; + if (is_decode_session(inst)) + found = (buf->index == buffer->index && + buf->device_addr == buffer->base_address && + buf->data_offset == buffer->data_offset); + else + found = (buf->index == buffer->index); + + if (found) + break; + } + if (!found) { + i_vpr_l(inst, "%s: invalid idx %d daddr %#llx\n", + __func__, buffer->index, buffer->base_address); + return 0; + } + + buf->data_offset = buffer->data_offset; + buf->data_size = buffer->data_size; + buf->timestamp = buffer->timestamp; + + buf->attr &= ~MSM_VIDC_ATTR_QUEUED; + buf->attr |= MSM_VIDC_ATTR_DEQUEUED; + + if (is_encode_session(inst)) { + /* encoder output is not expected to be corrupted */ + if (inst->hfi_frame_info.data_corrupt) { + i_vpr_e(inst, "%s: encode output is corrupted\n", __func__); + fatal = true; + } + if (inst->hfi_frame_info.overflow) { + /* overflow not expected for image session */ + if (is_image_session(inst)) { + i_vpr_e(inst, "%s: overflow detected for an image session\n", + __func__); + fatal = true; + } + + /* overflow not expected for cbr_cfr session */ + if (!buffer->data_size && inst->hfi_rc_type == HFI_RC_CBR_CFR) { + i_vpr_e(inst, "%s: overflow detected for cbr_cfr session\n", + __func__); + fatal = true; + } + } + if (fatal) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + + /* + * reset data size to zero for last flag buffer. + * reset RO flag for last flag buffer. + */ + if ((buffer->flags & HFI_BUF_FW_FLAG_LAST) || + (buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST)) { + if (buffer->data_size) { + i_vpr_e(inst, "%s: reset data size to zero for last flag buffer\n", + __func__); + buf->data_size = 0; + } + if (buffer->flags & HFI_BUF_FW_FLAG_READONLY) { + i_vpr_e(inst, "%s: reset RO flag for last flag buffer\n", + __func__); + buffer->flags &= ~HFI_BUF_FW_FLAG_READONLY; + } + } + + if (is_decode_session(inst)) { + /* RO flag is not expected when internal dpb buffers are allocated */ + if (inst->buffers.dpb.size && buffer->flags & HFI_BUF_FW_FLAG_READONLY) { + print_vidc_buffer(VIDC_ERR, "err ", "unexpected RO flag", inst, buf); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + + if (buffer->flags & HFI_BUF_FW_FLAG_READONLY) { + buf->attr |= MSM_VIDC_ATTR_READ_ONLY; + rc = handle_read_only_buffer(inst, buf); + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } else { + buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY; + } + + if (buf->dbuf_get) { + call_mem_op(core, dma_buf_put, inst, buf->dmabuf); + buf->dbuf_get = 0; + } + } + + buf->flags = 0; + buf->flags = get_driver_buffer_flags(inst, buffer->flags); + + rc = msm_vidc_handle_fence_signal(inst, buf); + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + + if (is_decode_session(inst)) { + inst->power.fw_cr = inst->hfi_frame_info.cr; + inst->power.fw_cf = inst->hfi_frame_info.cf; + } else { + inst->power.fw_cr = inst->hfi_frame_info.cr; + } + + if (!is_image_session(inst) && is_decode_session(inst) && buf->data_size) + msm_vidc_update_timestamp_rate(inst, buf->timestamp); + + /* update output buffer timestamp, if ts_reorder is enabled */ + if (is_ts_reorder_allowed(inst) && buf->data_size) + msm_vidc_ts_reorder_get_first_timestamp(inst, &buf->timestamp); + + print_vidc_buffer(VIDC_HIGH, "high", "dqbuf", inst, buf); + msm_vidc_update_stats(inst, buf, MSM_VIDC_DEBUGFS_EVENT_FBD); + + /* fbd: print stats and remove entry */ + msm_vidc_remove_buffer_stats(inst, buf, buffer->timestamp); + + return rc; +} + +static int handle_input_metadata_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf; + struct msm_vidc_core *core; + u32 frame_size, batch_size; + bool found; + + core = inst->core; + buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_INPUT_META, __func__); + if (!buffers) + return -EINVAL; + + found = false; + list_for_each_entry(buf, &buffers->list, list) { + if (buf->index == buffer->index) { + found = true; + break; + } + } + if (!found) { + i_vpr_e(inst, "%s: invalid idx %d daddr %#llx data_offset %d\n", + __func__, buffer->index, buffer->base_address, + buffer->data_offset); + return -EINVAL; + } + /* attach dequeued flag for, only last frame in the batch */ + if (msm_vidc_is_super_buffer(inst)) { + frame_size = call_session_op(core, buffer_size, inst, MSM_VIDC_BUF_INPUT_META); + batch_size = inst->capabilities[SUPER_FRAME].value; + if (!frame_size || !batch_size) { + i_vpr_e(inst, "%s: invalid size: frame %u, batch %u\n", + __func__, frame_size, batch_size); + return -EINVAL; + } + if (buffer->addr_offset / frame_size < batch_size - 1) { + i_vpr_l(inst, "%s: superframe last buffer not reached: %u, %u, %u\n", + __func__, buffer->addr_offset, frame_size, batch_size); + return 0; + } + } + + if (!(buf->attr & MSM_VIDC_ATTR_QUEUED)) { + print_vidc_buffer(VIDC_ERR, "err ", "not queued", inst, buf); + return 0; + } + + buf->data_size = buffer->data_size; + buf->attr &= ~MSM_VIDC_ATTR_QUEUED; + buf->attr |= MSM_VIDC_ATTR_DEQUEUED; + buf->flags = 0; + if (buffer->flags & HFI_BUF_FW_FLAG_LAST || + buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST) + buf->flags |= MSM_VIDC_BUF_FLAG_LAST; + + /* + * if last flag event is enabled then remove BUF_FLAG_LAST + * because last flag information will be sent via V4L2_EVENT_EOS + */ + if (inst->capabilities[LAST_FLAG_EVENT_ENABLE].value) + buf->flags &= ~MSM_VIDC_BUF_FLAG_LAST; + + print_vidc_buffer(VIDC_LOW, "low ", "dqbuf", inst, buf); + return rc; +} + +static int handle_output_metadata_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf; + bool found; + + buffers = msm_vidc_get_buffers(inst, MSM_VIDC_BUF_OUTPUT_META, __func__); + if (!buffers) + return -EINVAL; + + found = false; + list_for_each_entry(buf, &buffers->list, list) { + if (buf->index == buffer->index) { + found = true; + break; + } + } + if (!found) { + i_vpr_e(inst, "%s: invalid idx %d daddr %#llx data_offset %d\n", + __func__, buffer->index, buffer->base_address, + buffer->data_offset); + return -EINVAL; + } + + if (!(buf->attr & MSM_VIDC_ATTR_QUEUED)) { + print_vidc_buffer(VIDC_ERR, "err ", "not queued", inst, buf); + return 0; + } + + buf->data_size = buffer->data_size; + buf->attr &= ~MSM_VIDC_ATTR_QUEUED; + buf->attr |= MSM_VIDC_ATTR_DEQUEUED; + buf->flags = 0; + if (buffer->flags & HFI_BUF_FW_FLAG_LAST || + buffer->flags & HFI_BUF_FW_FLAG_PSC_LAST) + buf->flags |= MSM_VIDC_BUF_FLAG_LAST; + + /* + * if last flag event is enabled then remove BUF_FLAG_LAST + * because last flag information will be sent via V4L2_EVENT_EOS + */ + if (inst->capabilities[LAST_FLAG_EVENT_ENABLE].value) + buf->flags &= ~MSM_VIDC_BUF_FLAG_LAST; + + print_vidc_buffer(VIDC_LOW, "low ", "dqbuf", inst, buf); + return rc; +} + +static bool is_metabuffer_dequeued(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *buf) +{ + bool found = false; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buffer; + enum msm_vidc_buffer_type buffer_type; + + if (is_input_buffer(buf->type) && is_input_meta_enabled(inst)) + buffer_type = MSM_VIDC_BUF_INPUT_META; + else if (is_output_buffer(buf->type) && is_output_meta_enabled(inst)) + buffer_type = MSM_VIDC_BUF_OUTPUT_META; + else + return true; + + buffers = msm_vidc_get_buffers(inst, buffer_type, __func__); + if (!buffers) + return false; + + list_for_each_entry(buffer, &buffers->list, list) { + if (buffer->index == buf->index && + (buffer->attr & MSM_VIDC_ATTR_DEQUEUED || + buffer->attr & MSM_VIDC_ATTR_BUFFER_DONE)) { + /* + * For META_OUTBUF_FENCE case, meta buffers are + * dequeued ahead in time and completed vb2 done + * as well. Hence, check for vb2 buffer done flag since + * dequeued flag is already cleared for such buffers + */ + found = true; + break; + } + } + return found; +} + +static int msm_vidc_check_meta_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + int i; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf; + static const enum msm_vidc_buffer_type buffer_type[] = { + MSM_VIDC_BUF_INPUT, + MSM_VIDC_BUF_OUTPUT, + }; + + for (i = 0; i < ARRAY_SIZE(buffer_type); i++) { + buffers = msm_vidc_get_buffers(inst, buffer_type[i], __func__); + if (!buffers) + return -EINVAL; + + list_for_each_entry(buf, &buffers->list, list) { + if (buf->attr & MSM_VIDC_ATTR_DEQUEUED) { + if (!is_metabuffer_dequeued(inst, buf)) { + print_vidc_buffer(VIDC_ERR, "err ", + "meta not dequeued", inst, buf); + return -EINVAL; + } + } + } + } + return rc; +} + +static int handle_dequeue_buffers(struct msm_vidc_inst *inst) +{ + int rc = 0; + int i; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf; + struct msm_vidc_buffer *dummy; + static const enum msm_vidc_buffer_type buffer_type[] = { + MSM_VIDC_BUF_INPUT_META, + MSM_VIDC_BUF_INPUT, + MSM_VIDC_BUF_OUTPUT_META, + MSM_VIDC_BUF_OUTPUT, + }; + + /* check metabuffers dequeued before sending vb2_buffer_done() */ + rc = msm_vidc_check_meta_buffers(inst); + if (rc) + return rc; + + for (i = 0; i < ARRAY_SIZE(buffer_type); i++) { + buffers = msm_vidc_get_buffers(inst, buffer_type[i], __func__); + if (!buffers) + return -EINVAL; + + list_for_each_entry_safe(buf, dummy, &buffers->list, list) { + if (buf->attr & MSM_VIDC_ATTR_DEQUEUED) { + buf->attr &= ~MSM_VIDC_ATTR_DEQUEUED; + /* + * do not send vb2_buffer_done when fw returns + * same buffer again + */ + if (buf->attr & MSM_VIDC_ATTR_BUFFER_DONE) { + print_vidc_buffer(VIDC_HIGH, "high", + "vb2 done already", inst, buf); + } else { + buf->attr |= MSM_VIDC_ATTR_BUFFER_DONE; + rc = msm_vidc_vb2_buffer_done(inst, buf); + if (rc) { + print_vidc_buffer(VIDC_HIGH, "err ", + "vb2 done failed", inst, buf); + /* ignore the error */ + rc = 0; + } + } + } + } + } + + return rc; +} + +static int handle_release_internal_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf; + bool found; + + buffers = msm_vidc_get_buffers(inst, + hfi_buf_type_to_driver(inst->domain, + buffer->type, HFI_PORT_NONE), + __func__); + if (!buffers) + return -EINVAL; + + found = false; + list_for_each_entry(buf, &buffers->list, list) { + if (buf->device_addr == buffer->base_address) { + found = true; + break; + } + } + if (!found) { + i_vpr_e(inst, "%s: invalid idx %d daddr %#llx\n", + __func__, buffer->index, buffer->base_address); + return -EINVAL; + } + + if (!is_internal_buffer(buf->type)) + return 0; + + /* remove QUEUED attribute */ + buf->attr &= ~MSM_VIDC_ATTR_QUEUED; + + /* + * firmware will return/release internal buffer in two cases + * - driver sent release cmd in which case driver should destroy the buffer + * - as part stop cmd in which case driver can reuse the buffer, so skip + * destroying the buffer + */ + if (buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE) { + rc = msm_vidc_destroy_internal_buffer(inst, buf); + if (rc) + return rc; + } + return rc; +} + +int handle_release_output_buffer(struct msm_vidc_inst *inst, + struct hfi_buffer *buffer) +{ + int rc = 0; + struct msm_vidc_buffer *buf; + bool found = false; + + list_for_each_entry(buf, &inst->buffers.read_only.list, list) { + if (buf->device_addr == buffer->base_address && + buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE) { + found = true; + break; + } + } + if (!found) { + i_vpr_e(inst, "%s: invalid idx %d daddr %#llx\n", + __func__, buffer->index, buffer->base_address); + return -EINVAL; + } + + buf->attr &= ~MSM_VIDC_ATTR_READ_ONLY; + buf->attr &= ~MSM_VIDC_ATTR_PENDING_RELEASE; + print_vidc_buffer(VIDC_LOW, "low ", "release done", inst, buf); + + return rc; +} + +static int handle_session_buffer(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + int i, rc = 0; + struct hfi_buffer *buffer; + u32 hfi_handle_size = 0; + const struct msm_vidc_hfi_buffer_handle *hfi_handle_arr = NULL; + static const struct msm_vidc_hfi_buffer_handle enc_input_hfi_handle[] = { + {HFI_BUFFER_METADATA, handle_input_metadata_buffer }, + {HFI_BUFFER_RAW, handle_input_buffer }, + {HFI_BUFFER_VPSS, handle_release_internal_buffer }, + }; + static const struct msm_vidc_hfi_buffer_handle enc_output_hfi_handle[] = { + {HFI_BUFFER_METADATA, handle_output_metadata_buffer }, + {HFI_BUFFER_BITSTREAM, handle_output_buffer }, + {HFI_BUFFER_BIN, handle_release_internal_buffer }, + {HFI_BUFFER_COMV, handle_release_internal_buffer }, + {HFI_BUFFER_NON_COMV, handle_release_internal_buffer }, + {HFI_BUFFER_LINE, handle_release_internal_buffer }, + {HFI_BUFFER_ARP, handle_release_internal_buffer }, + {HFI_BUFFER_DPB, handle_release_internal_buffer }, + }; + static const struct msm_vidc_hfi_buffer_handle dec_input_hfi_handle[] = { + {HFI_BUFFER_METADATA, handle_input_metadata_buffer }, + {HFI_BUFFER_BITSTREAM, handle_input_buffer }, + {HFI_BUFFER_BIN, handle_release_internal_buffer }, + {HFI_BUFFER_COMV, handle_release_internal_buffer }, + {HFI_BUFFER_NON_COMV, handle_release_internal_buffer }, + {HFI_BUFFER_LINE, handle_release_internal_buffer }, + {HFI_BUFFER_PERSIST, handle_release_internal_buffer }, + {HFI_BUFFER_PARTIAL_DATA, handle_release_internal_buffer }, + }; + static const struct msm_vidc_hfi_buffer_handle dec_output_hfi_handle[] = { + {HFI_BUFFER_METADATA, handle_output_metadata_buffer }, + {HFI_BUFFER_RAW, handle_output_buffer }, + {HFI_BUFFER_DPB, handle_release_internal_buffer }, + }; + + if (pkt->payload_info == HFI_PAYLOAD_NONE) { + i_vpr_h(inst, "%s: received hfi buffer packet without payload\n", + __func__); + return 0; + } + + if (!check_for_packet_payload(inst, pkt, __func__)) { + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + return 0; + } + + buffer = (struct hfi_buffer *)((u8 *)pkt + sizeof(struct hfi_packet)); + if (!is_valid_hfi_buffer_type(inst, buffer->type, __func__)) { + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + return 0; + } + + if (!is_valid_hfi_port(inst, pkt->port, buffer->type, __func__)) { + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + return 0; + } + + if (is_encode_session(inst)) { + if (pkt->port == HFI_PORT_RAW) { + hfi_handle_size = ARRAY_SIZE(enc_input_hfi_handle); + hfi_handle_arr = enc_input_hfi_handle; + } else if (pkt->port == HFI_PORT_BITSTREAM) { + hfi_handle_size = ARRAY_SIZE(enc_output_hfi_handle); + hfi_handle_arr = enc_output_hfi_handle; + } + } else if (is_decode_session(inst)) { + if (pkt->port == HFI_PORT_BITSTREAM) { + hfi_handle_size = ARRAY_SIZE(dec_input_hfi_handle); + hfi_handle_arr = dec_input_hfi_handle; + } else if (pkt->port == HFI_PORT_RAW) { + hfi_handle_size = ARRAY_SIZE(dec_output_hfi_handle); + hfi_handle_arr = dec_output_hfi_handle; + } + } + + /* handle invalid session */ + if (!hfi_handle_arr || !hfi_handle_size) { + i_vpr_e(inst, "%s: invalid session %d\n", __func__, inst->domain); + return -EINVAL; + } + + /* handle session buffer */ + for (i = 0; i < hfi_handle_size; i++) { + if (hfi_handle_arr[i].type == buffer->type) { + rc = hfi_handle_arr[i].handle(inst, buffer); + if (rc) + return rc; + break; + } + } + + /* handle unknown buffer type */ + if (i == hfi_handle_size) { + i_vpr_e(inst, "%s: port %u, unknown buffer type %#x\n", __func__, + pkt->port, buffer->type); + return -EINVAL; + } + + return rc; +} + +static int handle_input_port_settings_change(struct msm_vidc_inst *inst) +{ + int rc = 0; + enum msm_vidc_allow allow = MSM_VIDC_DISALLOW; + + allow = msm_vidc_allow_input_psc(inst); + if (allow == MSM_VIDC_DISALLOW) { + return -EINVAL; + } else if (allow == MSM_VIDC_ALLOW) { + rc = msm_vidc_state_change_input_psc(inst); + if (rc) + return rc; + print_psc_properties("INPUT_PSC", inst, inst->subcr_params[INPUT_PORT]); + rc = msm_vdec_input_port_settings_change(inst); + if (rc) + return rc; + } + + return rc; +} + +static int handle_output_port_settings_change(struct msm_vidc_inst *inst) +{ + int rc = 0; + + print_psc_properties("OUTPUT_PSC", inst, inst->subcr_params[OUTPUT_PORT]); + rc = msm_vdec_output_port_settings_change(inst); + if (rc) + return rc; + + return rc; +} + +static int handle_port_settings_change(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + int rc = 0; + + i_vpr_h(inst, "%s: Received port settings change, type %d\n", + __func__, pkt->port); + + if (pkt->port == HFI_PORT_RAW) { + rc = handle_output_port_settings_change(inst); + if (rc) + goto exit; + } else if (pkt->port == HFI_PORT_BITSTREAM) { + rc = handle_input_port_settings_change(inst); + if (rc) + goto exit; + } else { + i_vpr_e(inst, "%s: invalid port type: %#x\n", + __func__, pkt->port); + rc = -EINVAL; + goto exit; + } + +exit: + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + return rc; +} + +static int handle_session_subscribe_mode(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful\n", __func__); + return 0; +} + +static int handle_session_delivery_mode(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful\n", __func__); + return 0; +} + +static int handle_session_pause(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful\n", __func__); + return 0; +} + +static int handle_session_resume(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful\n", __func__); + return 0; +} + +static int handle_session_stability(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful\n", __func__); + return 0; +} + +static int handle_session_command(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + int i, rc; + static const struct msm_vidc_hfi_packet_handle hfi_pkt_handle[] = { + {HFI_CMD_OPEN, handle_session_open }, + {HFI_CMD_CLOSE, handle_session_close }, + {HFI_CMD_START, handle_session_start }, + {HFI_CMD_STOP, handle_session_stop }, + {HFI_CMD_DRAIN, handle_session_drain }, + {HFI_CMD_BUFFER, handle_session_buffer }, + {HFI_CMD_SETTINGS_CHANGE, handle_port_settings_change }, + {HFI_CMD_SUBSCRIBE_MODE, handle_session_subscribe_mode }, + {HFI_CMD_DELIVERY_MODE, handle_session_delivery_mode }, + {HFI_CMD_PAUSE, handle_session_pause }, + {HFI_CMD_RESUME, handle_session_resume }, + {HFI_CMD_STABILITY, handle_session_stability }, + }; + + /* handle session pkt */ + for (i = 0; i < ARRAY_SIZE(hfi_pkt_handle); i++) { + if (hfi_pkt_handle[i].type == pkt->type) { + rc = hfi_pkt_handle[i].handle(inst, pkt); + if (rc) + return rc; + break; + } + } + + /* handle unknown buffer type */ + if (i == ARRAY_SIZE(hfi_pkt_handle)) { + i_vpr_e(inst, "%s: Unsupported command type: %#x\n", __func__, pkt->type); + return -EINVAL; + } + + return 0; +} + +static int handle_dpb_list_property(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + u32 payload_size, num_words_in_payload; + u8 *payload_start; + int i = 0; + struct msm_vidc_buffer *ro_buf; + bool found = false; + u64 device_addr; + + if (!is_decode_session(inst)) { + i_vpr_e(inst, + "%s: unsupported for non-decode session\n", __func__); + return -EINVAL; + } + + payload_size = pkt->size - sizeof(struct hfi_packet); + num_words_in_payload = payload_size / 4; + payload_start = (u8 *)((u8 *)pkt + sizeof(struct hfi_packet)); + memset(inst->dpb_list_payload, 0, MAX_DPB_LIST_ARRAY_SIZE); + + if (payload_size > MAX_DPB_LIST_PAYLOAD_SIZE) { + i_vpr_e(inst, + "%s: dpb list payload size %d exceeds expected max size %d\n", + __func__, payload_size, MAX_DPB_LIST_PAYLOAD_SIZE); + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + return -EINVAL; + } + memcpy(inst->dpb_list_payload, payload_start, payload_size); + + /* + * dpb_list_payload details: + * payload[0-1] : 64 bits base_address of DPB-1 + * payload[2] : 32 bits addr_offset of DPB-1 + * payload[3] : 32 bits data_offset of DPB-1 + */ + for (i = 0; (i + 3) < num_words_in_payload; i = i + 4) { + i_vpr_l(inst, + "%s: base addr %#x %#x, addr offset %#x, data offset %#x\n", + __func__, inst->dpb_list_payload[i], inst->dpb_list_payload[i + 1], + inst->dpb_list_payload[i + 2], inst->dpb_list_payload[i + 3]); + } + + list_for_each_entry(ro_buf, &inst->buffers.read_only.list, list) { + found = false; + /* do not mark RELEASE_ELIGIBLE for non-read only buffers */ + if (!(ro_buf->attr & MSM_VIDC_ATTR_READ_ONLY)) + continue; + /* no need to mark RELEASE_ELIGIBLE again */ + if (ro_buf->attr & MSM_VIDC_ATTR_RELEASE_ELIGIBLE) + continue; + /* + * do not add RELEASE_ELIGIBLE to buffers for which driver + * sent release cmd already + */ + if (ro_buf->attr & MSM_VIDC_ATTR_PENDING_RELEASE) + continue; + for (i = 0; (i + 3) < num_words_in_payload; i = i + 4) { + device_addr = *((u64 *)(&inst->dpb_list_payload[i])); + if (ro_buf->device_addr == device_addr) { + found = true; + break; + } + } + /* mark a buffer as RELEASE_ELIGIBLE if not found in dpb list */ + if (!found) + ro_buf->attr |= MSM_VIDC_ATTR_RELEASE_ELIGIBLE; + } + + return 0; +} + +static int handle_property_with_payload(struct msm_vidc_inst *inst, + struct hfi_packet *pkt, u32 port) +{ + int rc = 0; + u32 *payload_ptr = NULL; + + payload_ptr = (u32 *)((u8 *)pkt + sizeof(struct hfi_packet)); + if (!payload_ptr) { + i_vpr_e(inst, + "%s: payload_ptr cannot be null\n", __func__); + return -EINVAL; + } + + switch (pkt->type) { + case HFI_PROP_BITSTREAM_RESOLUTION: + inst->subcr_params[port].bitstream_resolution = payload_ptr[0]; + break; + case HFI_PROP_CROP_OFFSETS: + inst->subcr_params[port].crop_offsets[0] = payload_ptr[0]; + inst->subcr_params[port].crop_offsets[1] = payload_ptr[1]; + break; + case HFI_PROP_LUMA_CHROMA_BIT_DEPTH: + inst->subcr_params[port].bit_depth = payload_ptr[0]; + break; + case HFI_PROP_CODED_FRAMES: + inst->subcr_params[port].coded_frames = payload_ptr[0]; + break; + case HFI_PROP_BUFFER_FW_MIN_OUTPUT_COUNT: + inst->subcr_params[port].fw_min_count = payload_ptr[0]; + break; + case HFI_PROP_PIC_ORDER_CNT_TYPE: + inst->subcr_params[port].pic_order_cnt = payload_ptr[0]; + break; + case HFI_PROP_SIGNAL_COLOR_INFO: + inst->subcr_params[port].color_info = payload_ptr[0]; + break; + case HFI_PROP_PROFILE: + inst->subcr_params[port].profile = payload_ptr[0]; + break; + case HFI_PROP_LEVEL: + inst->subcr_params[port].level = payload_ptr[0]; + break; + case HFI_PROP_TIER: + inst->subcr_params[port].tier = payload_ptr[0]; + break; + case HFI_PROP_AV1_FILM_GRAIN_PRESENT: + inst->subcr_params[port].av1_film_grain_present = payload_ptr[0]; + break; + case HFI_PROP_AV1_SUPER_BLOCK_ENABLED: + inst->subcr_params[port].av1_super_block_enabled = payload_ptr[0]; + break; + case HFI_PROP_MAX_NUM_REORDER_FRAMES: + inst->subcr_params[port].max_num_reorder_frames = payload_ptr[0]; + break; + case HFI_PROP_PICTURE_TYPE: + inst->hfi_frame_info.picture_type = payload_ptr[0]; + if (inst->hfi_frame_info.picture_type & HFI_PICTURE_B) + inst->has_bframe = true; + if (inst->hfi_frame_info.picture_type & HFI_PICTURE_IDR) + inst->iframe = true; + else + inst->iframe = false; + break; + case HFI_PROP_SUBFRAME_INPUT: + if (port != INPUT_PORT) { + i_vpr_e(inst, + "%s: invalid port: %d for property %#x\n", + __func__, pkt->port, pkt->type); + break; + } + inst->hfi_frame_info.subframe_input = 1; + break; + case HFI_PROP_WORST_COMPRESSION_RATIO: + inst->hfi_frame_info.cr = payload_ptr[0]; + break; + case HFI_PROP_WORST_COMPLEXITY_FACTOR: + inst->hfi_frame_info.cf = payload_ptr[0]; + break; + case HFI_PROP_AV1_TILE_ROWS_COLUMNS: + inst->hfi_frame_info.av1_tile_rows_columns = + payload_ptr[0]; + break; + case HFI_PROP_AV1_UNIFORM_TILE_SPACING: + if (!payload_ptr[0]) + inst->hfi_frame_info.av1_non_uniform_tile_spacing = true; + break; + case HFI_PROP_CABAC_SESSION: + if (payload_ptr[0] == 1) + msm_vidc_update_cap_value(inst, ENTROPY_MODE, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + __func__); + else + msm_vidc_update_cap_value(inst, ENTROPY_MODE, + V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + __func__); + break; + case HFI_PROP_DPB_LIST: + rc = handle_dpb_list_property(inst, pkt); + if (rc) + break; + break; + case HFI_PROP_QUALITY_MODE: + if (inst->capabilities[QUALITY_MODE].value != payload_ptr[0]) + i_vpr_e(inst, + "%s: fw quality mode(%d) not matching the capability value(%d)\n", + __func__, payload_ptr[0], + inst->capabilities[QUALITY_MODE].value); + break; + case HFI_PROP_STAGE: + if (inst->capabilities[STAGE].value != payload_ptr[0]) + i_vpr_e(inst, + "%s: fw stage mode(%d) not matching the capability value(%d)\n", + __func__, payload_ptr[0], inst->capabilities[STAGE].value); + break; + case HFI_PROP_PIPE: + if (inst->capabilities[PIPE].value != payload_ptr[0]) + i_vpr_e(inst, + "%s: fw pipe mode(%d) not matching the capability value(%d)\n", + __func__, payload_ptr[0], inst->capabilities[PIPE].value); + break; + case HFI_PROP_FENCE: + inst->hfi_frame_info.fence_id = payload_ptr[0]; + break; + default: + i_vpr_e(inst, "%s: invalid property %#x\n", + __func__, pkt->type); + break; + } + + return rc; +} + +static int handle_property_without_payload(struct msm_vidc_inst *inst, + struct hfi_packet *pkt, + u32 port) +{ + int rc = 0; + + switch (pkt->type) { + case HFI_PROP_DPB_LIST: + /* + * if fw sends dpb list property without payload, + * it means there are no more reference buffers. + */ + rc = handle_dpb_list_property(inst, pkt); + if (rc) + break; + break; + case HFI_PROP_NO_OUTPUT: + if (port != INPUT_PORT) { + i_vpr_e(inst, + "%s: invalid port: %d for property %#x\n", + __func__, pkt->port, pkt->type); + break; + } + i_vpr_h(inst, "received no_output property\n"); + inst->hfi_frame_info.no_output = 1; + break; + default: + i_vpr_e(inst, "%s: invalid property %#x\n", + __func__, pkt->type); + break; + } + + return rc; +} + +static int handle_session_property(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + int rc = 0; + u32 port; + + i_vpr_l(inst, "%s: property type %#x\n", __func__, pkt->type); + + port = vidc_port_from_hfi(inst, pkt->port); + if (port >= MAX_PORT) { + i_vpr_e(inst, + "%s: invalid port: %d for property %#x\n", + __func__, pkt->port, pkt->type); + return -EINVAL; + } + + if (pkt->flags & HFI_FW_FLAGS_INFORMATION) { + i_vpr_h(inst, + "%s: information flag received for property %#x packet\n", + __func__, pkt->type); + return 0; + } + + if (check_for_packet_payload(inst, pkt, __func__)) { + rc = handle_property_with_payload(inst, pkt, port); + if (rc) + return rc; + } else { + rc = handle_property_without_payload(inst, pkt, port); + if (rc) + return rc; + } + + return rc; +} + +static int handle_image_version_property(struct msm_vidc_core *core, + struct hfi_packet *pkt) +{ + u32 i = 0; + u8 *str_image_version; + u32 req_bytes; + + req_bytes = pkt->size - sizeof(*pkt); + if (req_bytes < VENUS_VERSION_LENGTH - 1) { + d_vpr_e("%s: bad_pkt: %d\n", __func__, req_bytes); + return -EINVAL; + } + str_image_version = (u8 *)pkt + sizeof(struct hfi_packet); + /* + * The version string returned by firmware includes null + * characters at the start and in between. Replace the null + * characters with space, to print the version info. + */ + for (i = 0; i < VENUS_VERSION_LENGTH - 1; i++) { + if (str_image_version[i] != '\0') + core->fw_version[i] = str_image_version[i]; + else + core->fw_version[i] = ' '; + } + core->fw_version[i] = '\0'; + + d_vpr_h("%s: F/W version: %s\n", __func__, core->fw_version); + return 0; +} + +static int handle_system_property(struct msm_vidc_core *core, + struct hfi_packet *pkt) +{ + int rc = 0; + + switch (pkt->type) { + case HFI_PROP_IMAGE_VERSION: + rc = handle_image_version_property(core, pkt); + break; + default: + d_vpr_h("%s: property type %#x successful\n", + __func__, pkt->type); + break; + } + return rc; +} + +static int handle_system_response(struct msm_vidc_core *core, + struct hfi_header *hdr) +{ + int rc = 0; + struct hfi_packet *packet; + u8 *pkt, *start_pkt; + int i, j; + static const struct msm_vidc_core_hfi_range be[] = { + {HFI_SYSTEM_ERROR_BEGIN, HFI_SYSTEM_ERROR_END, handle_system_error }, + {HFI_PROP_BEGIN, HFI_PROP_END, handle_system_property }, + {HFI_CMD_BEGIN, HFI_CMD_END, handle_system_init }, + }; + + start_pkt = (u8 *)((u8 *)hdr + sizeof(struct hfi_header)); + for (i = 0; i < ARRAY_SIZE(be); i++) { + pkt = start_pkt; + for (j = 0; j < hdr->num_packets; j++) { + packet = (struct hfi_packet *)pkt; + /* handle system error */ + if (packet->flags & HFI_FW_FLAGS_SYSTEM_ERROR) { + d_vpr_e("%s: received system error %#x\n", + __func__, packet->type); + rc = handle_system_error(core, packet); + if (rc) + goto exit; + goto exit; + } + if (in_range(be[i], packet->type)) { + rc = be[i].handle(core, packet); + if (rc) + goto exit; + + /* skip processing anymore packets after system error */ + if (!i) { + d_vpr_e("%s: skip processing anymore packets\n", __func__); + goto exit; + } + } + pkt += packet->size; + } + } + +exit: + return rc; +} + +static int __handle_session_response(struct msm_vidc_inst *inst, + struct hfi_header *hdr) +{ + int rc = 0; + struct hfi_packet *packet; + u8 *pkt, *start_pkt; + bool dequeue = false; + int i, j; + static const struct msm_vidc_inst_hfi_range be[] = { + {HFI_SESSION_ERROR_BEGIN, HFI_SESSION_ERROR_END, handle_session_error }, + {HFI_INFORMATION_BEGIN, HFI_INFORMATION_END, handle_session_info }, + {HFI_PROP_BEGIN, HFI_PROP_END, handle_session_property }, + {HFI_CMD_BEGIN, HFI_CMD_END, handle_session_command }, + }; + + memset(&inst->hfi_frame_info, 0, sizeof(struct msm_vidc_hfi_frame_info)); + start_pkt = (u8 *)((u8 *)hdr + sizeof(struct hfi_header)); + for (i = 0; i < ARRAY_SIZE(be); i++) { + pkt = start_pkt; + for (j = 0; j < hdr->num_packets; j++) { + packet = (struct hfi_packet *)pkt; + /* handle session error */ + if (packet->flags & HFI_FW_FLAGS_SESSION_ERROR) { + i_vpr_e(inst, "%s: received session error %#x\n", + __func__, packet->type); + handle_session_error(inst, packet); + } + if (in_range(be[i], packet->type)) { + dequeue |= (packet->type == HFI_CMD_BUFFER); + rc = be[i].handle(inst, packet); + if (rc) + msm_vidc_change_state(inst, MSM_VIDC_ERROR, __func__); + } + pkt += packet->size; + } + } + + if (dequeue) { + rc = handle_dequeue_buffers(inst); + if (rc) + return rc; + } + memset(&inst->hfi_frame_info, 0, sizeof(struct msm_vidc_hfi_frame_info)); + + return rc; +} + +static int handle_session_response(struct msm_vidc_core *core, + struct hfi_header *hdr) +{ + struct msm_vidc_inst *inst; + struct hfi_packet *packet; + u8 *pkt; + int i, rc = 0; + bool found_ipsc = false; + + inst = get_inst(core, hdr->session_id); + if (!inst) { + d_vpr_e("%s: Invalid inst\n", __func__); + return -EINVAL; + } + + inst_lock(inst, __func__); + /* search for cmd settings change pkt */ + pkt = (u8 *)((u8 *)hdr + sizeof(struct hfi_header)); + for (i = 0; i < hdr->num_packets; i++) { + packet = (struct hfi_packet *)pkt; + if (packet->type == HFI_CMD_SETTINGS_CHANGE) { + if (packet->port == HFI_PORT_BITSTREAM) { + found_ipsc = true; + break; + } + } + pkt += packet->size; + } + + /* if ipsc packet is found, initialise subsc_params */ + if (found_ipsc) + msm_vdec_init_input_subcr_params(inst); + + rc = __handle_session_response(inst, hdr); + if (rc) + goto exit; + +exit: + inst_unlock(inst, __func__); + put_inst(inst); + return rc; +} + +int handle_response(struct msm_vidc_core *core, void *response) +{ + struct hfi_header *hdr; + int rc = 0; + + hdr = (struct hfi_header *)response; + rc = validate_hdr_packet(core, hdr, __func__); + if (rc) { + d_vpr_e("%s: hdr pkt validation failed\n", __func__); + return handle_system_error(core, NULL); + } + + if (!hdr->session_id) + return handle_system_response(core, hdr); + else + return handle_session_response(core, hdr); + + return 0; +} diff --git a/qcom/opensource/video-driver/include/uapi/vidc/media/v4l2_vidc_extensions.h b/qcom/opensource/video-driver/include/uapi/vidc/media/v4l2_vidc_extensions.h new file mode 100644 index 0000000000..781e0d80d2 --- /dev/null +++ b/qcom/opensource/video-driver/include/uapi/vidc/media/v4l2_vidc_extensions.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef __V4l2_VIDC_EXTENSIONS_H__ +#define __V4l2_VIDC_EXTENSIONS_H__ + +#include +#include + +/* AV1 */ +#ifndef V4L2_PIX_FMT_AV1 +#define V4L2_PIX_FMT_AV1 v4l2_fourcc('A', 'V', '1', '0') +#endif + +#ifndef V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE +#define V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10_STILL_PICTURE (3) +#endif + +/* vendor controls start */ +#ifdef V4L2_CTRL_CLASS_CODEC +#define V4L2_CID_MPEG_VIDC_BASE (V4L2_CTRL_CLASS_CODEC | 0x2000) +#else +#define V4L2_CID_MPEG_VIDC_BASE (V4L2_CTRL_CLASS_MPEG | 0x2000) +#endif + +#define V4L2_MPEG_MSM_VIDC_DISABLE 0 +#define V4L2_MPEG_MSM_VIDC_ENABLE 1 + +#endif diff --git a/qcom/opensource/video-driver/msm_video/Kbuild b/qcom/opensource/video-driver/msm_video/Kbuild new file mode 100644 index 0000000000..7793785822 --- /dev/null +++ b/qcom/opensource/video-driver/msm_video/Kbuild @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: GPL-2.0-only + +KBUILD_CPPFLAGS += -DCONFIG_MSM_MMRM=1 +VIDEO_DRIVER_ABS_PATH := $(VIDEO_ROOT)/msm_video/driver +VIDEO_DRIVER_REL_PATH := ../msm_video/driver + +ifeq ($(CONFIG_ARCH_PINEAPPLE), y) +include $(VIDEO_ROOT)/config/pineapple_video.conf +LINUXINCLUDE += -include $(VIDEO_ROOT)/config/pineapple_video.h +endif + +ifeq ($(CONFIG_ARCH_VOLCANO), y) +include $(VIDEO_ROOT)/config/volcano_video.conf +LINUXINCLUDE += -include $(VIDEO_ROOT)/config/volcano_video.h +endif + +ifeq ($(CONFIG_ARCH_KALAMA), y) +include $(VIDEO_ROOT)/config/kalama_video.conf +LINUXINCLUDE += -include $(VIDEO_ROOT)/config/kalama_video.h +endif + +ifeq ($(CONFIG_MSM_VIDC_PINEAPPLE), y) +LINUXINCLUDE += -I$(VIDEO_DRIVER_ABS_PATH)/platform/pineapple/inc \ + -I$(VIDEO_DRIVER_ABS_PATH)/platform/cliffs/inc \ + -I$(VIDEO_DRIVER_ABS_PATH)/variant/iris33/inc +endif +ifeq ($(CONFIG_MSM_VIDC_KALAMA), y) +LINUXINCLUDE += -I$(VIDEO_DRIVER_ABS_PATH)/platform/kalama/inc \ + -I$(VIDEO_DRIVER_ABS_PATH)/variant/iris3/inc +endif +ifeq ($(CONFIG_MSM_VIDC_VOLCANO), y) +LINUXINCLUDE += -I$(VIDEO_DRIVER_ABS_PATH)/platform/volcano/inc \ + -I$(VIDEO_DRIVER_ABS_PATH)/variant/iris2/inc +endif +LINUXINCLUDE += -I$(VIDEO_DRIVER_ABS_PATH)/platform/common/inc \ + -I$(VIDEO_DRIVER_ABS_PATH)/variant/common/inc \ + -I$(VIDEO_DRIVER_ABS_PATH)/vidc/inc \ + -I$(VIDEO_ROOT)/include/uapi/vidc \ + -I$(VIDEO_ROOT)/../mm-drivers/hw_fence/include/ \ + -I$(VIDEO_ROOT)/../synx-kernel/msm/synx/ \ + -I$(VIDEO_ROOT)/../synx-kernel/include/uapi/synx/media/ + +USERINCLUDE += -I$(VIDEO_ROOT)/include/uapi/vidc/media \ + -I$(VIDEO_ROOT)/include/uapi/vidc + +obj-m += msm_video.o + +ifeq ($(CONFIG_MSM_VIDC_PINEAPPLE), y) +msm_video-objs += $(VIDEO_DRIVER_REL_PATH)/platform/pineapple/src/msm_vidc_pineapple.o \ + $(VIDEO_DRIVER_REL_PATH)/platform/cliffs/src/msm_vidc_cliffs.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris33/src/msm_vidc_buffer_iris33.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris33/src/msm_vidc_power_iris33.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris33/src/msm_vidc_bus_iris33.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris33/src/msm_vidc_clock_iris33.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris33/src/msm_vidc_iris33.o +endif +ifeq ($(CONFIG_MSM_VIDC_KALAMA), y) +msm_video-objs += $(VIDEO_DRIVER_REL_PATH)/platform/kalama/src/msm_vidc_kalama.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris3/src/msm_vidc_buffer_iris3.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris3/src/msm_vidc_power_iris3.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris3/src/msm_vidc_bus_iris3.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris3/src/msm_vidc_clock_iris3.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris3/src/msm_vidc_iris3.o +endif +ifeq ($(CONFIG_MSM_VIDC_VOLCANO), y) +msm_video-objs += $(VIDEO_DRIVER_REL_PATH)/variant/iris2/src/msm_vidc_buffer_iris2.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris2/src/msm_vidc_iris2.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris2/src/msm_vidc_power_iris2.o \ + $(VIDEO_DRIVER_REL_PATH)/platform/volcano/src/msm_vidc_volcano.o +endif +msm_video-objs += $(VIDEO_DRIVER_REL_PATH)/platform/common/src/msm_vidc_platform.o \ + $(VIDEO_DRIVER_REL_PATH)/platform/common/src/msm_vidc_platform_ext.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/common/src/msm_vidc_variant.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_v4l2.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_vb2.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vdec.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_venc.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_driver.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_state.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_control.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_buffer.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_power.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_probe.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/resources.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/resources_ext.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/firmware.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_debug.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_memory.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_memory_ext.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_fence.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_synx.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/venus_hfi.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/venus_hfi_queue.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/hfi_packet.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/venus_hfi_response.o diff --git a/qcom/opensource/video-driver/target.bzl b/qcom/opensource/video-driver/target.bzl new file mode 100644 index 0000000000..f242e13424 --- /dev/null +++ b/qcom/opensource/video-driver/target.bzl @@ -0,0 +1,28 @@ +load(":video_modules.bzl", "video_driver_modules") +load(":video_driver_build.bzl", "define_lunch_target_variant_modules") +load("//msm-kernel:target_variants.bzl", "get_all_la_variants") +load("//msm-kernel:target_variants.bzl", "get_all_lunch_target_base_target_variants") + +def define_target_modules(): + for (target, variant) in get_all_la_variants(): + define_lunch_target_variant_modules( + target = target, + variant = variant, + registry = video_driver_modules, + modules = [ + "msm_video", + "video", + ], + ) + + for (lt, bt, v) in get_all_lunch_target_base_target_variants(): + define_lunch_target_variant_modules( + target = bt, + variant = v, + registry = video_driver_modules, + modules = [ + "msm_video", + "video", + ], + lunch_target = lt, + ) diff --git a/qcom/opensource/video-driver/video/Kbuild b/qcom/opensource/video-driver/video/Kbuild new file mode 100644 index 0000000000..8d2a307439 --- /dev/null +++ b/qcom/opensource/video-driver/video/Kbuild @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: GPL-2.0-only + +VIDEO_DRIVER_ABS_PATH := $(VIDEO_ROOT)/video/driver +VIDEO_DRIVER_REL_PATH := ../video/driver + +ifeq ($(CONFIG_ARCH_PINEAPPLE), y) +include $(VIDEO_ROOT)/config/pineapple_video.conf +LINUXINCLUDE += -include $(VIDEO_ROOT)/config/pineapple_video.h +endif + +ifeq ($(CONFIG_MSM_VIDC_PINEAPPLE), y) +LINUXINCLUDE += -I$(VIDEO_DRIVER_ABS_PATH)/platform/pineapple/inc \ + -I$(VIDEO_DRIVER_ABS_PATH)/variant/iris33/inc +endif + +ifeq ($(CONFIG_MSM_VIDC_VOLCANO), y) +LINUXINCLUDE += -I$(VIDEO_DRIVER_ABS_PATH)/platform/volcano/inc \ + -I$(VIDEO_DRIVER_ABS_PATH)/variant/iris2/inc +endif + +LINUXINCLUDE += -I$(VIDEO_DRIVER_ABS_PATH)/platform/common/inc \ + -I$(VIDEO_DRIVER_ABS_PATH)/variant/common/inc \ + -I$(VIDEO_DRIVER_ABS_PATH)/vidc/inc \ + -I$(VIDEO_ROOT)/include/uapi/vidc + +USERINCLUDE += -I$(VIDEO_ROOT)/include/uapi/vidc/media \ + -I$(VIDEO_ROOT)/include/uapi/vidc + +obj-m += video.o + +ifeq ($(CONFIG_MSM_VIDC_PINEAPPLE), y) +video-objs += $(VIDEO_DRIVER_REL_PATH)/platform/pineapple/src/pineapple.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris33/src/msm_vidc_buffer_iris33.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris33/src/msm_vidc_power_iris33.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris33/src/msm_vidc_bus_iris33.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris33/src/msm_vidc_clock_iris33.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris33/src/msm_vidc_iris33.o +endif +ifeq ($(CONFIG_MSM_VIDC_VOLCANO), y) +video-objs += $(VIDEO_DRIVER_REL_PATH)/variant/iris2/src/msm_vidc_buffer_iris2.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris2/src/msm_vidc_iris2.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/iris2/src/msm_vidc_power_iris2.o \ + $(VIDEO_DRIVER_REL_PATH)/platform/volcano/src/volcano.o +endif +video-objs += $(VIDEO_DRIVER_REL_PATH)/platform/common/src/msm_vidc_platform.o \ + $(VIDEO_DRIVER_REL_PATH)/variant/common/src/msm_vidc_variant.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_v4l2.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_vb2.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vdec.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_venc.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_driver.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_state.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_control.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_buffer.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_power.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_probe.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/resources.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/firmware.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_debug.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_memory.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/msm_vidc_fence.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/venus_hfi.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/venus_hfi_queue.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/hfi_packet.o \ + $(VIDEO_DRIVER_REL_PATH)/vidc/src/venus_hfi_response.o diff --git a/qcom/opensource/video-driver/video_driver_build.bzl b/qcom/opensource/video-driver/video_driver_build.bzl new file mode 100644 index 0000000000..d14b7df41e --- /dev/null +++ b/qcom/opensource/video-driver/video_driver_build.bzl @@ -0,0 +1,175 @@ +load("//build/kernel/kleaf:kernel.bzl", "ddk_module", "ddk_submodule") +load("//build/bazel_common_rules/dist:dist.bzl", "copy_to_dist_dir") + +def _register_module_to_map(module_map, name, path, config_option, srcs, config_srcs, deps, config_deps): + processed_config_srcs = {} + + for config_src_name in config_srcs: + config_src = config_srcs[config_src_name] + + if type(config_src) == "list": + processed_config_srcs[config_src_name] = {True: config_src} + else: + processed_config_srcs[config_src_name] = config_src + + module = struct( + name = name, + path = path, + srcs = srcs, + config_srcs = processed_config_srcs, + config_option = config_option, + deps = deps, + ) + module_map[name] = module + +def _get_config_choices(map, options): + choices = [] + for option in map: + choices.extend(map[option].get(option in options,[])) + return choices + +def _get_kernel_build_options(modules, config_options): + all_options = {option: True for option in config_options} + all_options = all_options | {module.config_option: True for module in modules if module.config_option} + return all_options + +def _get_kernel_build_module_srcs(module, options, formatter): + srcs = module.srcs + _get_config_choices(module.config_srcs, options) + print("-",module.name,",",module.config_option,",srcs =",srcs) + module_path = "{}/".format(module.path) if module.path else "" + globbed_srcs = native.glob(["{}{}".format(module_path, formatter(src)) for src in srcs]) + return globbed_srcs + +def _get_kernel_build_module_deps(module, options, formatter): + return [formatter(dep) for dep in module.deps] + +def video_module_entry(hdrs = []): + module_map = {} + def register(name, path = None, config_option = None, srcs = [], config_srcs = {}, deps = [], config_deps = {}): + _register_module_to_map(module_map, name, path, config_option, srcs, config_srcs, deps, config_deps) + return struct( + register = register, + get = module_map.get, + hdrs = hdrs, + module_map = module_map + ) + +def define_target_variant_modules(target, variant, registry, modules, config_options = []): + kernel_build = "{}_{}".format(target, variant) + kernel_build_label = "//msm-kernel:{}".format(kernel_build) + modules = [registry.get(module_name) for module_name in modules] + options = _get_kernel_build_options(modules, config_options) + build_print = lambda message : print("{}: {}".format(kernel_build, message)) + formatter = lambda s : s.replace("%b", kernel_build).replace("%t", target) + headers = ["//msm-kernel:all_headers"] + registry.hdrs + [":{}_headers".format(target)] + print(headers) + all_module_rules = [] + + for module in modules: + rule_name = "{}_{}".format(kernel_build, module.name) + module_srcs = _get_kernel_build_module_srcs(module, options, formatter) + + if not module_srcs: + continue + + ddk_submodule( + name = rule_name, + srcs = module_srcs, + out = "{}.ko".format(module.name), + deps = headers + _get_kernel_build_module_deps(module, options, formatter), + local_defines = options.keys(), + ) + all_module_rules.append(rule_name) + + ddk_module( + name = "{}_video_driver_modules".format(kernel_build), + kernel_build = kernel_build_label, + deps = all_module_rules, + ) + copy_to_dist_dir( + name = "{}_video_driver_modules_dist".format(kernel_build), + data = [":{}_video_driver_modules".format(kernel_build)], + dist_dir = "out/target/product/{}/dlkm/lib/modules/".format(target), + flat = True, + wipe_dist_dir = False, + allow_duplicate_filenames = False, + mode_overrides = {"**/*": "644"}, + log = "info", + ) + +def define_lunch_target_variant_modules(target, variant, registry, modules, lunch_target=None): + print(lunch_target) + + kernel_build = "{}_{}".format(target, variant) + print("kernel_build: "+ kernel_build) + + kernel_build_label = "//msm-kernel:{}".format(kernel_build) + print(kernel_build_label) + + if lunch_target != None: + kernel_build = "{}_{}_{}".format(target, variant, lunch_target) + print("kernel_build: "+ kernel_build) + ddk_mod_name = "{}_video_driver_modules".format(kernel_build) + print("ddk_mod_name : " + ddk_mod_name) + dist_target_name = "{}_video_driver_modules_dist".format(kernel_build) + data = [":{}_video_driver_modules".format(kernel_build)] + config_options = ["CONFIG_MSM_VIDC_{}".format(lunch_target.upper())] + else: + ddk_mod_name = "{}_video_driver_modules".format(kernel_build) + print("ddk_mod_name: " + ddk_mod_name) + dist_target_name = "{}_video_driver_modules_dist".format(kernel_build) + print("dist_target_name: " + dist_target_name) + data = [":{}_video_driver_modules".format(kernel_build)] + config_options = ["CONFIG_MSM_VIDC_{}".format(target.upper())] + + + modules = [registry.get(module_name) for module_name in modules] + + options = _get_kernel_build_options(modules, config_options) + + build_print = lambda message : print("{}: {}".format(kernel_build, message)) + + formatter = lambda s : s.replace("%b", kernel_build).replace("%t", target) + + headers = ["//msm-kernel:all_headers"] + registry.hdrs + [":{}_headers".format(target)] + print(headers) + + all_module_rules = [] + + for module in modules: + print("Module name: "+ module.name) + rule_name = "{}_{}".format(kernel_build, module.name) + module_srcs = _get_kernel_build_module_srcs(module, options, formatter) + + if not module_srcs: + continue + + ddk_submodule( + name = rule_name, + srcs = module_srcs, + out = "{}.ko".format(module.name), + deps = headers + _get_kernel_build_module_deps(module, options, formatter), + local_defines = options.keys(), + ) + all_module_rules.append(rule_name) + + ddk_module( + name = ddk_mod_name, + kernel_build = kernel_build_label, + deps = all_module_rules, + ) + + copy_to_dist_dir( + name = dist_target_name, + data = data, + dist_dir = "out/target/product/{}/dlkm/lib/modules/".format(target), + flat = True, + wipe_dist_dir = False, + allow_duplicate_filenames = False, + mode_overrides = {"**/*": "644"}, + log = "info", + ) + +def define_consolidate_gki_modules(target, registry, modules, config_options = []): + define_target_variant_modules(target, "consolidate", registry, modules, config_options) + define_target_variant_modules(target, "gki", registry, modules, config_options) \ No newline at end of file diff --git a/qcom/opensource/video-driver/video_kernel_board.mk b/qcom/opensource/video-driver/video_kernel_board.mk new file mode 100644 index 0000000000..bdb6475ebd --- /dev/null +++ b/qcom/opensource/video-driver/video_kernel_board.mk @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only +TARGET_VIDC_ENABLE := false +ifeq ($(TARGET_KERNEL_DLKM_DISABLE), true) + ifeq ($(TARGET_KERNEL_DLKM_VIDEO_OVERRIDE), true) + TARGET_VIDC_ENABLE := true + endif +else +TARGET_VIDC_ENABLE := true +endif + +# Build video kernel driver +ifeq ($(TARGET_VIDC_ENABLE),true) +ifneq ($(TARGET_BOARD_AUTO),true) +ifeq ($(call is-board-platform-in-list,$(TARGET_BOARD_PLATFORM)),true) +BOARD_VENDOR_KERNEL_MODULES += $(KERNEL_MODULES_OUT)/msm_video.ko + +BUILD_VIDEO_TECHPACK_SOURCE := true +endif +endif +endif diff --git a/qcom/opensource/video-driver/video_kernel_headers.py b/qcom/opensource/video-driver/video_kernel_headers.py new file mode 100644 index 0000000000..bfb5507a5c --- /dev/null +++ b/qcom/opensource/video-driver/video_kernel_headers.py @@ -0,0 +1,95 @@ +# Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License 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. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +import argparse +import filecmp +import os +import re +import subprocess +import sys + +def run_headers_install(verbose, gen_dir, headers_install, unifdef, prefix, h): + if not h.startswith(prefix): + print('error: expected prefix [%s] on header [%s]' % (prefix, h)) + return False + + out_h = os.path.join(gen_dir, h[len(prefix):]) + (out_h_dirname, out_h_basename) = os.path.split(out_h) + env = os.environ.copy() + env["LOC_UNIFDEF"] = unifdef + cmd = ["sh", headers_install, h, out_h] + + if verbose: + print('run_headers_install: cmd is %s' % cmd) + + result = subprocess.call(cmd, env=env) + + if result != 0: + print('error: run_headers_install: cmd %s failed %d' % (cmd, result)) + return False + return True + +def gen_video_headers(verbose, gen_dir, headers_install, unifdef, video_include_uapi): + error_count = 0 + for h in video_include_uapi: + video_uapi_include_prefix = os.path.join(h.split('/include/uapi/')[0], + 'include', + 'uapi') + os.sep + + if not run_headers_install( + verbose, gen_dir, headers_install, unifdef, + video_uapi_include_prefix, h): error_count += 1 + return error_count + +def main(): + """Parse command line arguments and perform top level control.""" + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + + # Arguments that apply to every invocation of this script. + parser.add_argument( + '--verbose', action='store_true', + help='Print output that describes the workings of this script.') + parser.add_argument( + '--header_arch', required=True, + help='The arch for which to generate headers.') + parser.add_argument( + '--gen_dir', required=True, + help='Where to place the generated files.') + parser.add_argument( + '--video_include_uapi', required=True, nargs='*', + help='The list of techpack/*/include/uapi header files.') + parser.add_argument( + '--headers_install', required=True, + help='The headers_install tool to process input headers.') + parser.add_argument( + '--unifdef', + required=True, + help='The unifdef tool used by headers_install.') + + args = parser.parse_args() + + if args.verbose: + print('header_arch [%s]' % args.header_arch) + print('gen_dir [%s]' % args.gen_dir) + print('video_include_uapi [%s]' % args.video_include_uapi) + print('headers_install [%s]' % args.headers_install) + print('unifdef [%s]' % args.unifdef) + + return gen_video_headers(args.verbose, args.gen_dir, + args.headers_install, args.unifdef, args.video_include_uapi) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/qcom/opensource/video-driver/video_kernel_product.mk b/qcom/opensource/video-driver/video_kernel_product.mk new file mode 100644 index 0000000000..a6e758958c --- /dev/null +++ b/qcom/opensource/video-driver/video_kernel_product.mk @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +TARGET_VIDC_ENABLE := false +ifeq ($(TARGET_KERNEL_DLKM_DISABLE), true) + ifeq ($(TARGET_KERNEL_DLKM_VIDEO_OVERRIDE), true) + TARGET_VIDC_ENABLE := true + endif +else +TARGET_VIDC_ENABLE := true +endif + +ifeq ($(TARGET_VIDC_ENABLE),true) +PRODUCT_PACKAGES += msm_video.ko +endif diff --git a/qcom/opensource/video-driver/video_modules.bzl b/qcom/opensource/video-driver/video_modules.bzl new file mode 100644 index 0000000000..a7329a2c64 --- /dev/null +++ b/qcom/opensource/video-driver/video_modules.bzl @@ -0,0 +1,103 @@ +load(":video_driver_build.bzl", "video_module_entry") + +video_driver_modules = video_module_entry([":video_driver_headers"]) +module_entry = video_driver_modules.register + +module_entry( + name = "msm_video", + srcs = [ + "driver/vidc/src/msm_vidc_v4l2.c", + "driver/vidc/src/msm_vidc_vb2.c", + "driver/vidc/src/msm_vidc.c", + "driver/vidc/src/msm_vdec.c", + "driver/vidc/src/msm_venc.c", + "driver/vidc/src/msm_vidc_driver.c", + "driver/vidc/src/msm_vidc_state.c", + "driver/vidc/src/msm_vidc_control.c", + "driver/vidc/src/msm_vidc_control_ext.c", + "driver/vidc/src/msm_vidc_buffer.c", + "driver/vidc/src/msm_vidc_power.c", + "driver/vidc/src/msm_vidc_probe.c", + "driver/vidc/src/resources.c", + "driver/vidc/src/resources_ext.c", + "driver/vidc/src/firmware.c", + "driver/vidc/src/msm_vidc_debug.c", + "driver/vidc/src/msm_vidc_memory.c", + "driver/vidc/src/msm_vidc_memory_ext.c", + "driver/vidc/src/msm_vidc_fence.c", + "driver/vidc/src/venus_hfi.c", + "driver/vidc/src/venus_hfi_queue.c", + "driver/vidc/src/hfi_packet.c", + "driver/vidc/src/venus_hfi_response.c", + "driver/platform/common/src/msm_vidc_platform.c", + "driver/platform/common/src/msm_vidc_platform_ext.c", + "driver/variant/common/src/msm_vidc_variant.c", + "driver/vidc/src/msm_vidc_synx.c", + ], + config_srcs = { + "CONFIG_MSM_VIDC_PINEAPPLE" : [ + "driver/variant/iris33/src/msm_vidc_buffer_iris33.c", + "driver/variant/iris33/src/msm_vidc_bus_iris33.c", + "driver/variant/iris33/src/msm_vidc_clock_iris33.c", + "driver/variant/iris33/src/msm_vidc_power_iris33.c", + "driver/variant/iris33/src/msm_vidc_iris33.c", + "driver/platform/pineapple/src/msm_vidc_pineapple.c", + "driver/platform/cliffs/src/msm_vidc_cliffs.c", + ], + "CONFIG_MSM_VIDC_VOLCANO" : [ + "driver/variant/iris2/src/msm_vidc_buffer_iris2.c", + "driver/variant/iris2/src/msm_vidc_iris2.c", + "driver/variant/iris2/src/msm_vidc_power_iris2.c", + "driver/platform/volcano/src/msm_vidc_volcano.c", + ], + }, + deps = [ + "//vendor/qcom/opensource/mm-drivers:mm_drivers_headers", + "//vendor/qcom/opensource/synx-kernel:synx_headers", + ], +) + +module_entry( + name = "video", + srcs = [ + "driver/vidc/src/msm_vidc_v4l2.c", + "driver/vidc/src/msm_vidc_vb2.c", + "driver/vidc/src/msm_vidc.c", + "driver/vidc/src/msm_vdec.c", + "driver/vidc/src/msm_venc.c", + "driver/vidc/src/msm_vidc_driver.c", + "driver/vidc/src/msm_vidc_state.c", + "driver/vidc/src/msm_vidc_control.c", + "driver/vidc/src/msm_vidc_buffer.c", + "driver/vidc/src/msm_vidc_power.c", + "driver/vidc/src/msm_vidc_probe.c", + "driver/vidc/src/resources.c", + "driver/vidc/src/firmware.c", + "driver/vidc/src/msm_vidc_debug.c", + "driver/vidc/src/msm_vidc_memory.c", + "driver/vidc/src/msm_vidc_fence.c", + "driver/vidc/src/venus_hfi.c", + "driver/vidc/src/venus_hfi_queue.c", + "driver/vidc/src/hfi_packet.c", + "driver/vidc/src/venus_hfi_response.c", + "driver/platform/common/src/msm_vidc_platform.c", + "driver/variant/common/src/msm_vidc_variant.c", + ], + config_srcs = { + "CONFIG_MSM_VIDC_PINEAPPLE" : [ + "driver/platform/pineapple/src/pineapple.c", + "driver/platform/cliffs/src/cliffs.c", + "driver/variant/iris33/src/msm_vidc_buffer_iris33.c", + "driver/variant/iris33/src/msm_vidc_power_iris33.c", + "driver/variant/iris33/src/msm_vidc_bus_iris33.c", + "driver/variant/iris33/src/msm_vidc_clock_iris33.c", + "driver/variant/iris33/src/msm_vidc_iris33.c", + ], + "CONFIG_MSM_VIDC_VOLCANO" : [ + "driver/variant/iris2/src/msm_vidc_buffer_iris2.c", + "driver/variant/iris2/src/msm_vidc_iris2.c", + "driver/variant/iris2/src/msm_vidc_power_iris2.c", + "driver/platform/volcano/src/volcano.c", + ], + } +)