Add 'qcom/opensource/video-driver/' from commit 'd0f80c27eee09bc53817f8cfd085691c88989c7e'

git-subtree-dir: qcom/opensource/video-driver
git-subtree-mainline: e44c5532de
git-subtree-split: d0f80c27ee
Change-Id:
repo: https://git.codelinaro.org/clo/la/platform/vendor/opensource/video-driver
tag: VIDEO.LA.4.0.r2-06100-lanai.0
This commit is contained in:
David Wronek 2024-10-06 16:45:47 +02:00
commit f1b172d58b
119 changed files with 79982 additions and 0 deletions

View File

@ -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
}

View File

@ -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

View File

@ -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()

View File

@ -0,0 +1 @@
obj-m := msm_video/ video/

View File

@ -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

View File

@ -0,0 +1 @@
export CONFIG_MSM_VIDC_KALAMA=y

View File

@ -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

View File

@ -0,0 +1 @@
export CONFIG_MSM_VIDC_PINEAPPLE=y

View File

@ -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

View File

@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-only
export CONFIG_MSM_VIDC_VOLCANO=y

View File

@ -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

View File

@ -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_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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 <linux/platform_device.h>
#include <media/v4l2-ctrls.h>
#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_

View File

@ -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

View File

@ -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 <linux/types.h>
/* 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_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,259 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <media/v4l2_vidc_extensions.h>
#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;
}

View File

@ -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;

View File

@ -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_

File diff suppressed because it is too large Load Diff

View File

@ -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_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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_

File diff suppressed because it is too large Load Diff

View File

@ -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 <linux/types.h>
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

View File

@ -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 <linux/errno.h>
#include <linux/iopoll.h>
#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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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__

View File

@ -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_

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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__

View File

@ -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_

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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__

View File

@ -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_

View File

@ -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

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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 <linux/types.h>
#include <linux/bits.h>
/*
* 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

View File

@ -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 <linux/types.h>
#include <linux/bits.h>
#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__

View File

@ -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_

View File

@ -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 <linux/types.h>
#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__

View File

@ -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

View File

@ -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_

View File

@ -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_

View File

@ -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 <linux/videodev2.h>
#include <media/media-device.h>
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

View File

@ -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__

View File

@ -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

View File

@ -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 <linux/platform_device.h>
#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_

View File

@ -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 <linux/types.h>
#include <linux/errno.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
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

View File

@ -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 <linux/workqueue.h>
#include <linux/iommu.h>
#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_

View File

@ -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 <linux/tracepoint.h>
#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 <trace/define_trace.h>

View File

@ -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__

View File

@ -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_

File diff suppressed because it is too large Load Diff

View File

@ -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_

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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_

View File

@ -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 <linux/poll.h>
#include <linux/fs.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
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_

View File

@ -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 <media/videobuf2-core.h>
#include <media/videobuf2-v4l2.h>
#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_

View File

@ -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

View File

@ -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_

View File

@ -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 <linux/irqreturn.h>
#include <linux/clk.h>
#include <linux/regulator/consumer.h>
#include <linux/clk-provider.h>
#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_

View File

@ -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 <linux/types.h>
#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

View File

@ -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__

View File

@ -0,0 +1,294 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
*/
#include <linux/types.h>
#include <linux/list.h>
#include <linux/of_address.h>
#include <linux/devcoredump.h>
#include <linux/firmware.h>
#include <linux/qcom_scm.h>
#include <linux/soc/qcom/mdt_loader.h>
#include <linux/soc/qcom/smem.h>
#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);
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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 <linux/types.h>
#include <linux/hash.h>
#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;
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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 <linux/dma-buf.h>
#include <linux/dma-heap.h>
#include <linux/dma-mapping.h>
#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;
}

View File

@ -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 <linux/dma-buf.h>
#include <linux/dma-heap.h>
#include <linux/qcom-dma-mapping.h>
#include <linux/mem-buf.h>
#include <soc/qcom/secure_buffer.h>
#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;
}

View File

@ -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__);
}

Some files were not shown because too many files have changed in this diff Show More