Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,15 @@
config VIDEO_QCOM_VENUS
tristate "Qualcomm Venus V4L2 encoder/decoder driver"
depends on V4L_MEM2MEM_DRIVERS
depends on VIDEO_DEV && QCOM_SMEM
depends on (ARCH_QCOM && ARM64 && IOMMU_API) || COMPILE_TEST
select OF_DYNAMIC if ARCH_QCOM
select QCOM_MDT_LOADER
select QCOM_SCM
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
help
This is a V4L2 driver for Qualcomm Venus video accelerator
hardware. It accelerates encoding and decoding operations
on various Qualcomm SoCs.
To compile this driver as a module choose m here.
@@ -0,0 +1,15 @@
# SPDX-License-Identifier: GPL-2.0
# Makefile for Qualcomm Venus driver
venus-core-objs += core.o helpers.o firmware.o \
hfi_venus.o hfi_msgs.o hfi_cmds.o hfi.o \
hfi_parser.o pm_helpers.o dbgfs.o \
hfi_platform.o hfi_platform_v4.o \
hfi_platform_v6.o hfi_plat_bufs_v6.o \
venus-dec-objs += vdec.o vdec_ctrls.o
venus-enc-objs += venc.o venc_ctrls.o
obj-$(CONFIG_VIDEO_QCOM_VENUS) += venus-core.o
obj-$(CONFIG_VIDEO_QCOM_VENUS) += venus-dec.o
obj-$(CONFIG_VIDEO_QCOM_VENUS) += venus-enc.o
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,602 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#ifndef __VENUS_CORE_H_
#define __VENUS_CORE_H_
#include <linux/bitops.h>
#include <linux/list.h>
#include <media/videobuf2-v4l2.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include "dbgfs.h"
#include "hfi.h"
#include "hfi_platform.h"
#include "hfi_helper.h"
#define VDBGL "VenusLow : "
#define VDBGM "VenusMed : "
#define VDBGH "VenusHigh: "
#define VDBGFW "VenusFW : "
#define VIDC_CLKS_NUM_MAX 4
#define VIDC_VCODEC_CLKS_NUM_MAX 2
#define VIDC_RESETS_NUM_MAX 2
#define VIDC_MAX_HIER_CODING_LAYER 6
#define VENUS_MAX_FPS 240
extern int venus_fw_debug;
struct freq_tbl {
unsigned int load;
unsigned long freq;
};
struct reg_val {
u32 reg;
u32 value;
};
struct bw_tbl {
u32 mbs_per_sec;
u32 avg;
u32 peak;
u32 avg_10bit;
u32 peak_10bit;
};
enum vpu_version {
VPU_VERSION_AR50,
VPU_VERSION_AR50_LITE,
VPU_VERSION_IRIS1,
#if (!IS_ENABLED(CONFIG_VIDEO_QCOM_IRIS))
VPU_VERSION_IRIS2,
VPU_VERSION_IRIS2_1,
#endif
};
struct firmware_version {
u32 major;
u32 minor;
u32 rev;
};
struct venus_resources {
u64 dma_mask;
const struct freq_tbl *freq_tbl;
unsigned int freq_tbl_size;
const struct bw_tbl *bw_tbl_enc;
unsigned int bw_tbl_enc_size;
const struct bw_tbl *bw_tbl_dec;
unsigned int bw_tbl_dec_size;
const struct reg_val *reg_tbl;
unsigned int reg_tbl_size;
const struct hfi_ubwc_config *ubwc_conf;
const char * const clks[VIDC_CLKS_NUM_MAX];
unsigned int clks_num;
const char * const vcodec_clks[VIDC_VCODEC_CLKS_NUM_MAX];
const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX];
const char * const vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
unsigned int vcodec_clks_num;
const char **vcodec_pmdomains;
unsigned int vcodec_pmdomains_num;
const char **opp_pmdomain;
unsigned int opp_pmdomain_num;
unsigned int vcodec_num;
const u32 dec_codec_blacklist;
const u32 enc_codec_blacklist;
const char * const resets[VIDC_RESETS_NUM_MAX];
unsigned int resets_num;
enum hfi_version hfi_version;
enum vpu_version vpu_version;
u8 num_vpp_pipes;
u32 max_load;
unsigned int vmem_id;
u32 vmem_size;
u32 vmem_addr;
u32 cp_start;
u32 cp_size;
u32 cp_nonpixel_start;
u32 cp_nonpixel_size;
const char *fwname;
const char *enc_nodename;
const char *dec_nodename;
const struct firmware_version *min_fw;
};
enum venus_fmt {
VENUS_FMT_NV12 = 0,
VENUS_FMT_QC08C = 1,
VENUS_FMT_QC10C = 2,
VENUS_FMT_P010 = 3,
VENUS_FMT_H264 = 4,
VENUS_FMT_VP8 = 5,
VENUS_FMT_VP9 = 6,
VENUS_FMT_HEVC = 7,
VENUS_FMT_VC1_ANNEX_G = 8,
VENUS_FMT_VC1_ANNEX_L = 9,
VENUS_FMT_MPEG4 = 10,
VENUS_FMT_MPEG2 = 11,
VENUS_FMT_H263 = 12,
VENUS_FMT_XVID = 13,
};
struct venus_format {
u32 pixfmt;
unsigned int num_planes;
u32 type;
u32 flags;
};
/**
* struct venus_core - holds core parameters valid for all instances
*
* @base: IO memory base address
* @vbif_base: IO memory vbif base address
* @cpu_base: IO memory cpu base address
* @cpu_cs_base: IO memory cpu_cs base address
* @cpu_ic_base: IO memory cpu_ic base address
* @wrapper_base: IO memory wrapper base address
* @wrapper_tz_base: IO memory wrapper TZ base address
* @aon_base: AON base address
* @irq: Venus irq
* @clks: an array of struct clk pointers
* @vcodec_clks: an array of vcodec struct clk pointers
* @vcodec0_clks: an array of vcodec0 struct clk pointers
* @vcodec1_clks: an array of vcodec1 struct clk pointers
* @video_path: an interconnect handle to video to/from memory path
* @cpucfg_path: an interconnect handle to cpu configuration path
* @pmdomains: a pointer to a list of pmdomains
* @opp_pmdomain: an OPP power-domain
* @resets: an array of reset signals
* @vdev_dec: a reference to video device structure for decoder instances
* @vdev_enc: a reference to video device structure for encoder instances
* @v4l2_dev: a holder for v4l2 device structure
* @res: a reference to venus resources structure
* @dev: convenience struct device pointer
* @dev_dec: convenience struct device pointer for decoder device
* @dev_enc: convenience struct device pointer for encoder device
* @use_tz: a flag that suggests presence of trustzone
* @fw: structure of firmware parameters
* @lock: a lock for this strucure
* @instances: a list_head of all instances
* @insts_count: num of instances
* @state: the state of the venus core
* @done: a completion for sync HFI operations
* @error: an error returned during last HFI sync operations
* @sys_error: an error flag that signal system error event
* @sys_err_done: a waitqueue to wait for system error recovery end
* @core_ops: the core operations
* @pm_ops: a pointer to pm operations
* @pm_lock: a lock for PM operations
* @enc_codecs: encoders supported by this core
* @dec_codecs: decoders supported by this core
* @max_sessions_supported: holds the maximum number of sessions
* @priv: a private filed for HFI operations
* @ops: the core HFI operations
* @work: a delayed work for handling system fatal error
* @caps: an array of supported HFI capabilities
* @codecs_count: platform codecs count
* @core0_usage_count: usage counter for core0
* @core1_usage_count: usage counter for core1
* @root: debugfs root directory
* @venus_ver: the venus firmware version
* @dump_core: a flag indicating that a core dump is required
* @ocs: OF changeset pointer
* @hwmode_dev: a flag indicating that HW_CTRL_TRIGGER is used in clock driver
*/
struct venus_core {
void __iomem *base;
void __iomem *vbif_base;
void __iomem *cpu_base;
void __iomem *cpu_cs_base;
void __iomem *cpu_ic_base;
void __iomem *wrapper_base;
void __iomem *wrapper_tz_base;
void __iomem *aon_base;
int irq;
struct clk *clks[VIDC_CLKS_NUM_MAX];
struct clk *vcodec_clks[VIDC_VCODEC_CLKS_NUM_MAX];
struct clk *vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX];
struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
struct icc_path *video_path;
struct icc_path *cpucfg_path;
struct dev_pm_domain_list *pmdomains;
struct dev_pm_domain_list *opp_pmdomain;
struct reset_control *resets[VIDC_RESETS_NUM_MAX];
struct video_device *vdev_dec;
struct video_device *vdev_enc;
struct v4l2_device v4l2_dev;
const struct venus_resources *res;
struct device *dev;
struct device *dev_dec;
struct device *dev_enc;
unsigned int use_tz;
struct video_firmware {
struct device *dev;
struct iommu_domain *iommu_domain;
size_t mapped_mem_size;
phys_addr_t mem_phys;
size_t mem_size;
} fw;
struct mutex lock;
struct list_head instances;
atomic_t insts_count;
unsigned int state;
struct completion done;
unsigned int error;
unsigned long sys_error;
wait_queue_head_t sys_err_done;
const struct hfi_core_ops *core_ops;
const struct venus_pm_ops *pm_ops;
struct mutex pm_lock;
unsigned long enc_codecs;
unsigned long dec_codecs;
unsigned int max_sessions_supported;
void *priv;
const struct hfi_ops *ops;
struct delayed_work work;
struct hfi_plat_caps caps[MAX_CODEC_NUM];
unsigned int codecs_count;
unsigned int core0_usage_count;
unsigned int core1_usage_count;
struct dentry *root;
struct firmware_version venus_ver;
unsigned long dump_core;
struct of_changeset *ocs;
bool hwmode_dev;
};
struct vdec_controls {
u32 post_loop_deb_mode;
u32 profile;
u32 level;
u32 display_delay;
u32 display_delay_enable;
u64 conceal_color;
};
struct venc_controls {
u16 gop_size;
u32 num_p_frames;
u32 num_b_frames;
u32 bitrate_mode;
u32 bitrate;
u32 bitrate_peak;
u32 rc_enable;
u32 const_quality;
u32 frame_skip_mode;
u32 layer_bitrate;
u32 h264_i_period;
u32 h264_entropy_mode;
u32 h264_i_qp;
u32 h264_p_qp;
u32 h264_b_qp;
u32 h264_min_qp;
u32 h264_max_qp;
u32 h264_i_min_qp;
u32 h264_i_max_qp;
u32 h264_p_min_qp;
u32 h264_p_max_qp;
u32 h264_b_min_qp;
u32 h264_b_max_qp;
u32 h264_loop_filter_mode;
s32 h264_loop_filter_alpha;
s32 h264_loop_filter_beta;
u32 h264_8x8_transform;
u32 h264_hier_layers;
u32 h264_hier_layer_bitrate[VIDC_MAX_HIER_CODING_LAYER];
u32 hevc_i_qp;
u32 hevc_p_qp;
u32 hevc_b_qp;
u32 hevc_min_qp;
u32 hevc_max_qp;
u32 hevc_i_min_qp;
u32 hevc_i_max_qp;
u32 hevc_p_min_qp;
u32 hevc_p_max_qp;
u32 hevc_b_min_qp;
u32 hevc_b_max_qp;
u32 vp8_min_qp;
u32 vp8_max_qp;
u32 multi_slice_mode;
u32 multi_slice_max_bytes;
u32 multi_slice_max_mb;
u32 header_mode;
bool aud_enable;
u32 intra_refresh_type;
u32 intra_refresh_period;
struct {
u32 h264;
u32 mpeg4;
u32 hevc;
u32 vp8;
u32 vp9;
} profile;
struct {
u32 h264;
u32 mpeg4;
u32 hevc;
u32 vp9;
} level;
u32 base_priority_id;
u32 ltr_count;
struct v4l2_ctrl_hdr10_cll_info cll;
struct v4l2_ctrl_hdr10_mastering_display mastering;
};
struct venus_buffer {
struct vb2_v4l2_buffer vb;
struct list_head list;
dma_addr_t dma_addr;
u32 size;
struct list_head reg_list;
u32 flags;
struct list_head ref_list;
};
struct clock_data {
u32 core_id;
unsigned long freq;
unsigned long vpp_freq;
unsigned long vsp_freq;
unsigned long low_power_freq;
};
#define to_venus_buffer(ptr) container_of(ptr, struct venus_buffer, vb)
enum venus_dec_state {
VENUS_DEC_STATE_DEINIT = 0,
VENUS_DEC_STATE_INIT = 1,
VENUS_DEC_STATE_CAPTURE_SETUP = 2,
VENUS_DEC_STATE_STOPPED = 3,
VENUS_DEC_STATE_SEEK = 4,
VENUS_DEC_STATE_DRAIN = 5,
VENUS_DEC_STATE_DECODING = 6,
VENUS_DEC_STATE_DRC = 7,
};
enum venus_enc_state {
VENUS_ENC_STATE_DEINIT = 0,
VENUS_ENC_STATE_INIT = 1,
VENUS_ENC_STATE_ENCODING = 2,
VENUS_ENC_STATE_STOPPED = 3,
VENUS_ENC_STATE_DRAIN = 4,
};
struct venus_ts_metadata {
bool used;
u64 ts_ns;
u64 ts_us;
u32 flags;
struct v4l2_timecode tc;
};
enum venus_inst_modes {
VENUS_LOW_POWER = BIT(0),
};
/**
* struct venus_inst - holds per instance parameters
*
* @list: used for attach an instance to the core
* @lock: instance lock
* @core: a reference to the core struct
* @clk_data: clock data per core ID
* @dpbbufs: a list of decoded picture buffers
* @internalbufs: a list of internal bufferes
* @registeredbufs: a list of registered capture bufferes
* @delayed_process: a list of delayed buffers
* @delayed_process_work: a work_struct for process delayed buffers
* @nonblock: nonblocking flag
* @ctrl_handler: v4l control handler
* @controls: a union of decoder and encoder control parameters
* @fh: a holder of v4l file handle structure
* @streamon_cap: stream on flag for capture queue
* @streamon_out: stream on flag for output queue
* @width: current capture width
* @height: current capture height
* @crop: current crop rectangle
* @fw_min_cnt: firmware minimum buffer count
* @out_width: current output width
* @out_height: current output height
* @colorspace: current color space
* @ycbcr_enc: current YCbCr encoding
* @quantization: current quantization
* @xfer_func: current xfer function
* @codec_state: current decoder API state (see DEC_STATE_)
* @enc_state: current encoder API state (see ENC_STATE_)
* @reconf_wait: wait queue for resolution change event
* @subscriptions: used to hold current events subscriptions
* @buf_count: used to count number of buffers (reqbuf(0))
* @tss: timestamp metadata
* @payloads: cache plane payload to use it for clock/BW scaling
* @fps: holds current FPS
* @timeperframe: holds current time per frame structure
* @fmt_out: a reference to output format structure
* @fmt_cap: a reference to capture format structure
* @num_input_bufs: holds number of input buffers
* @num_output_bufs: holds number of output buffers
* @input_buf_size: holds input buffer size
* @output_buf_size: holds output buffer size
* @output2_buf_size: holds secondary decoder output buffer size
* @dpb_buftype: decoded picture buffer type
* @dpb_fmt: decoded picture buffer raw format
* @opb_buftype: output picture buffer type
* @opb_fmt: output picture buffer raw format
* @reconfig: a flag raised by decoder when the stream resolution changed
* @hfi_codec: current codec for this instance in HFI space
* @sequence_cap: a sequence counter for capture queue
* @sequence_out: a sequence counter for output queue
* @m2m_dev: a reference to m2m device structure
* @m2m_ctx: a reference to m2m context structure
* @ctx_q_lock: a lock to serialize video device ioctl calls
* @state: current state of the instance
* @done: a completion for sync HFI operation
* @error: an error returned during last HFI sync operation
* @session_error: a flag rised by HFI interface in case of session error
* @ops: HFI operations
* @session_type: the type of the session (decoder or encoder)
* @hprop: a union used as a holder by get property
* @core_acquired: the Core has been acquired
* @bit_depth: current bitstream bit-depth
* @pic_struct: bitstream progressive vs interlaced
* @next_buf_last: a flag to mark next queued capture buffer as last
* @drain_active: Drain sequence is in progress
* @flags: bitmask flags describing current instance mode
* @dpb_ids: DPB buffer ID's
*/
struct venus_inst {
struct list_head list;
struct mutex lock;
struct venus_core *core;
struct clock_data clk_data;
struct list_head dpbbufs;
struct list_head internalbufs;
struct list_head registeredbufs;
struct list_head delayed_process;
struct work_struct delayed_process_work;
bool nonblock;
struct v4l2_ctrl_handler ctrl_handler;
union {
struct vdec_controls dec;
struct venc_controls enc;
} controls;
struct v4l2_fh fh;
unsigned int streamon_cap, streamon_out;
u32 width;
u32 height;
struct v4l2_rect crop;
u32 fw_min_cnt;
u32 out_width;
u32 out_height;
u32 colorspace;
u8 ycbcr_enc;
u8 quantization;
u8 xfer_func;
enum venus_dec_state codec_state;
enum venus_enc_state enc_state;
wait_queue_head_t reconf_wait;
unsigned int subscriptions;
int buf_count;
struct venus_ts_metadata tss[VIDEO_MAX_FRAME];
unsigned long payloads[VIDEO_MAX_FRAME];
u64 fps;
struct v4l2_fract timeperframe;
const struct venus_format *fmt_out;
const struct venus_format *fmt_cap;
unsigned int num_input_bufs;
unsigned int num_output_bufs;
unsigned int input_buf_size;
unsigned int output_buf_size;
unsigned int output2_buf_size;
u32 dpb_buftype;
u32 dpb_fmt;
u32 opb_buftype;
u32 opb_fmt;
bool reconfig;
u32 hfi_codec;
u32 sequence_cap;
u32 sequence_out;
struct v4l2_m2m_dev *m2m_dev;
struct v4l2_m2m_ctx *m2m_ctx;
struct mutex ctx_q_lock;
unsigned int state;
struct completion done;
unsigned int error;
bool session_error;
const struct hfi_inst_ops *ops;
u32 session_type;
union hfi_get_property hprop;
unsigned int core_acquired: 1;
unsigned int bit_depth;
unsigned int pic_struct;
bool next_buf_last;
bool drain_active;
enum venus_inst_modes flags;
struct ida dpb_ids;
};
#define IS_V1(core) ((core)->res->hfi_version == HFI_VERSION_1XX)
#define IS_V3(core) ((core)->res->hfi_version == HFI_VERSION_3XX)
#define IS_V4(core) ((core)->res->hfi_version == HFI_VERSION_4XX)
#if (!IS_ENABLED(CONFIG_VIDEO_QCOM_IRIS))
#define IS_V6(core) ((core)->res->hfi_version == HFI_VERSION_6XX)
#else
#define IS_V6(core) (((void)(core), 0))
#endif
#define IS_AR50(core) ((core)->res->vpu_version == VPU_VERSION_AR50)
#define IS_AR50_LITE(core) ((core)->res->vpu_version == VPU_VERSION_AR50_LITE)
#define IS_IRIS1(core) ((core)->res->vpu_version == VPU_VERSION_IRIS1)
#if (!IS_ENABLED(CONFIG_VIDEO_QCOM_IRIS))
#define IS_IRIS2(core) ((core)->res->vpu_version == VPU_VERSION_IRIS2)
#define IS_IRIS2_1(core) ((core)->res->vpu_version == VPU_VERSION_IRIS2_1)
#else
#define IS_IRIS2(core) (((void)(core), 0))
#define IS_IRIS2_1(core) (((void)(core), 0))
#endif
static inline bool is_lite(struct venus_core *core)
{
return IS_AR50_LITE(core);
}
#define ctrl_to_inst(ctrl) \
container_of((ctrl)->handler, struct venus_inst, ctrl_handler)
static inline struct venus_inst *to_inst(struct file *filp)
{
return container_of(file_to_v4l2_fh(filp), struct venus_inst, fh);
}
static inline void *to_hfi_priv(struct venus_core *core)
{
return core->priv;
}
static inline struct hfi_plat_caps *
venus_caps_by_codec(struct venus_core *core, u32 codec, u32 domain)
{
unsigned int c;
for (c = 0; c < core->codecs_count; c++) {
if (core->caps[c].codec == codec &&
core->caps[c].domain == domain)
return &core->caps[c];
}
return NULL;
}
static inline bool
is_fw_rev_or_newer(struct venus_core *core, u32 vmajor, u32 vminor, u32 vrev)
{
return ((core)->venus_ver.major == vmajor &&
(core)->venus_ver.minor == vminor &&
(core)->venus_ver.rev >= vrev);
}
static inline bool
is_fw_rev_or_older(struct venus_core *core, u32 vmajor, u32 vminor, u32 vrev)
{
return ((core)->venus_ver.major == vmajor &&
(core)->venus_ver.minor == vminor &&
(core)->venus_ver.rev <= vrev);
}
void venus_close_common(struct venus_inst *inst, struct file *filp);
#endif
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2020 Linaro Ltd.
*/
#include <linux/debugfs.h>
#include <linux/fault-inject.h>
#include "core.h"
#ifdef CONFIG_FAULT_INJECTION
DECLARE_FAULT_ATTR(venus_ssr_attr);
#endif
void venus_dbgfs_init(struct venus_core *core)
{
core->root = debugfs_create_dir("venus", NULL);
debugfs_create_x32("fw_level", 0644, core->root, &venus_fw_debug);
#ifdef CONFIG_FAULT_INJECTION
fault_create_debugfs_attr("fail_ssr", core->root, &venus_ssr_attr);
#endif
}
void venus_dbgfs_deinit(struct venus_core *core)
{
debugfs_remove_recursive(core->root);
}
@@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2020 Linaro Ltd. */
#ifndef __VENUS_DBGFS_H__
#define __VENUS_DBGFS_H__
#include <linux/fault-inject.h>
struct venus_core;
#ifdef CONFIG_FAULT_INJECTION
extern struct fault_attr venus_ssr_attr;
static inline bool venus_fault_inject_ssr(void)
{
return should_fail(&venus_ssr_attr, 1);
}
#else
static inline bool venus_fault_inject_ssr(void) { return false; }
#endif
void venus_dbgfs_init(struct venus_core *core);
void venus_dbgfs_deinit(struct venus_core *core);
#endif
@@ -0,0 +1,384 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2017 Linaro Ltd.
*/
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/iommu.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_reserved_mem.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/firmware/qcom/qcom_scm.h>
#include <linux/sizes.h>
#include <linux/soc/qcom/mdt_loader.h>
#include "core.h"
#include "firmware.h"
#include "hfi_venus_io.h"
#define VENUS_PAS_ID 9
#define VENUS_FW_MEM_SIZE (6 * SZ_1M)
#define VENUS_FW_START_ADDR 0x0
static void venus_reset_cpu(struct venus_core *core)
{
u32 fw_size = core->fw.mapped_mem_size;
void __iomem *wrapper_base;
if (IS_IRIS2(core) || IS_IRIS2_1(core))
wrapper_base = core->wrapper_tz_base;
else
wrapper_base = core->wrapper_base;
writel(0, wrapper_base + WRAPPER_FW_START_ADDR);
writel(fw_size, wrapper_base + WRAPPER_FW_END_ADDR);
writel(0, wrapper_base + WRAPPER_CPA_START_ADDR);
writel(fw_size, wrapper_base + WRAPPER_CPA_END_ADDR);
writel(fw_size, wrapper_base + WRAPPER_NONPIX_START_ADDR);
writel(fw_size, wrapper_base + WRAPPER_NONPIX_END_ADDR);
if (IS_IRIS2(core) || IS_IRIS2_1(core)) {
/* Bring XTSS out of reset */
writel(0, wrapper_base + WRAPPER_TZ_XTSS_SW_RESET);
} else {
writel(0x0, wrapper_base + WRAPPER_CPU_CGC_DIS);
writel(0x0, wrapper_base + WRAPPER_CPU_CLOCK_CONFIG);
/* Bring ARM9 out of reset */
writel(0, wrapper_base + WRAPPER_A9SS_SW_RESET);
}
}
int venus_set_hw_state(struct venus_core *core, bool resume)
{
int ret;
if (core->use_tz) {
ret = qcom_scm_set_remote_state(resume, 0);
if (resume && ret == -EINVAL)
ret = 0;
return ret;
}
if (resume) {
venus_reset_cpu(core);
} else {
if (IS_IRIS2(core) || IS_IRIS2_1(core))
writel(WRAPPER_XTSS_SW_RESET_BIT,
core->wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET);
else
writel(WRAPPER_A9SS_SW_RESET_BIT,
core->wrapper_base + WRAPPER_A9SS_SW_RESET);
}
return 0;
}
static int venus_load_fw(struct venus_core *core, const char *fwname,
phys_addr_t *mem_phys, size_t *mem_size)
{
const struct firmware *mdt;
struct resource res;
struct device *dev;
ssize_t fw_size;
void *mem_va;
int ret;
*mem_phys = 0;
*mem_size = 0;
dev = core->dev;
ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res);
if (ret) {
dev_err(dev, "failed to lookup reserved memory-region\n");
return -EINVAL;
}
ret = request_firmware(&mdt, fwname, dev);
if (ret < 0)
return ret;
fw_size = qcom_mdt_get_size(mdt);
if (fw_size < 0) {
ret = fw_size;
goto err_release_fw;
}
*mem_phys = res.start;
*mem_size = resource_size(&res);
if (*mem_size < fw_size || fw_size > VENUS_FW_MEM_SIZE) {
ret = -EINVAL;
goto err_release_fw;
}
mem_va = memremap(*mem_phys, *mem_size, MEMREMAP_WC);
if (!mem_va) {
dev_err(dev, "unable to map memory region %pa size %#zx\n", mem_phys, *mem_size);
ret = -ENOMEM;
goto err_release_fw;
}
if (core->use_tz)
ret = qcom_mdt_load(dev, mdt, fwname, VENUS_PAS_ID,
mem_va, *mem_phys, *mem_size, NULL);
else
ret = qcom_mdt_load_no_init(dev, mdt, fwname, mem_va,
*mem_phys, *mem_size, NULL);
memunmap(mem_va);
err_release_fw:
release_firmware(mdt);
return ret;
}
static int venus_boot_no_tz(struct venus_core *core, phys_addr_t mem_phys,
size_t mem_size)
{
struct iommu_domain *iommu;
struct device *dev;
int ret;
dev = core->fw.dev;
if (!dev)
return -EPROBE_DEFER;
iommu = core->fw.iommu_domain;
core->fw.mapped_mem_size = mem_size;
ret = iommu_map(iommu, VENUS_FW_START_ADDR, mem_phys, mem_size,
IOMMU_READ | IOMMU_WRITE | IOMMU_PRIV, GFP_KERNEL);
if (ret) {
dev_err(dev, "could not map video firmware region\n");
return ret;
}
venus_reset_cpu(core);
return 0;
}
static int venus_shutdown_no_tz(struct venus_core *core)
{
const size_t mapped = core->fw.mapped_mem_size;
struct iommu_domain *iommu;
size_t unmapped;
u32 reg;
struct device *dev = core->fw.dev;
void __iomem *wrapper_base = core->wrapper_base;
void __iomem *wrapper_tz_base = core->wrapper_tz_base;
if (IS_IRIS2(core) || IS_IRIS2_1(core)) {
/* Assert the reset to XTSS */
reg = readl(wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET);
reg |= WRAPPER_XTSS_SW_RESET_BIT;
writel(reg, wrapper_tz_base + WRAPPER_TZ_XTSS_SW_RESET);
} else {
/* Assert the reset to ARM9 */
reg = readl(wrapper_base + WRAPPER_A9SS_SW_RESET);
reg |= WRAPPER_A9SS_SW_RESET_BIT;
writel(reg, wrapper_base + WRAPPER_A9SS_SW_RESET);
}
iommu = core->fw.iommu_domain;
if (core->fw.mapped_mem_size && iommu) {
unmapped = iommu_unmap(iommu, VENUS_FW_START_ADDR, mapped);
if (unmapped != mapped)
dev_err(dev, "failed to unmap firmware\n");
else
core->fw.mapped_mem_size = 0;
}
return 0;
}
int venus_firmware_cfg(struct venus_core *core)
{
void __iomem *cpu_cs_base = core->cpu_cs_base;
if (IS_AR50_LITE(core))
writel(CPU_CS_VCICMD_ARP_OFF, cpu_cs_base + CPU_CS_VCICMD);
return 0;
}
int venus_boot(struct venus_core *core)
{
struct device *dev = core->dev;
const struct venus_resources *res = core->res;
const char *fwpath = NULL;
phys_addr_t mem_phys;
size_t mem_size;
int ret;
if (!IS_ENABLED(CONFIG_QCOM_MDT_LOADER) ||
(core->use_tz && !qcom_scm_is_available()))
return -EPROBE_DEFER;
ret = of_property_read_string_index(dev->of_node, "firmware-name", 0,
&fwpath);
if (ret)
fwpath = core->res->fwname;
ret = venus_load_fw(core, fwpath, &mem_phys, &mem_size);
if (ret) {
dev_err(dev, "fail to load video firmware\n");
return -EINVAL;
}
core->fw.mem_size = mem_size;
core->fw.mem_phys = mem_phys;
if (core->use_tz)
ret = qcom_scm_pas_auth_and_reset(VENUS_PAS_ID);
else
ret = venus_boot_no_tz(core, mem_phys, mem_size);
if (ret)
return ret;
if (core->use_tz && res->cp_size) {
/*
* Clues for porting using downstream data:
* cp_start = 0
* cp_size = venus_ns/virtual-addr-pool[0] - yes, address and not size!
* This works, as the non-secure context bank is placed
* contiguously right after the Content Protection region.
*
* cp_nonpixel_start = venus_sec_non_pixel/virtual-addr-pool[0]
* cp_nonpixel_size = venus_sec_non_pixel/virtual-addr-pool[1]
*/
ret = qcom_scm_mem_protect_video_var(res->cp_start,
res->cp_size,
res->cp_nonpixel_start,
res->cp_nonpixel_size);
if (ret) {
qcom_scm_pas_shutdown(VENUS_PAS_ID);
dev_err(dev, "set virtual address ranges fail (%d)\n",
ret);
return ret;
}
}
return 0;
}
int venus_shutdown(struct venus_core *core)
{
int ret;
if (core->use_tz)
ret = qcom_scm_pas_shutdown(VENUS_PAS_ID);
else
ret = venus_shutdown_no_tz(core);
return ret;
}
int venus_firmware_check(struct venus_core *core)
{
const struct firmware_version *req = core->res->min_fw;
const struct firmware_version *run = &core->venus_ver;
if (!req)
return 0;
if (!is_fw_rev_or_newer(core, req->major, req->minor, req->rev))
goto error;
return 0;
error:
dev_err(core->dev, "Firmware v%d.%d.%d < v%d.%d.%d\n",
run->major, run->minor, run->rev,
req->major, req->minor, req->rev);
return -EINVAL;
}
int venus_firmware_init(struct venus_core *core)
{
struct platform_device_info info;
struct iommu_domain *iommu_dom;
struct platform_device *pdev;
struct device_node *np;
int ret;
np = of_get_child_by_name(core->dev->of_node, "video-firmware");
if (!np) {
core->use_tz = true;
return 0;
}
memset(&info, 0, sizeof(info));
info.fwnode = &np->fwnode;
info.parent = core->dev;
info.name = np->name;
info.dma_mask = DMA_BIT_MASK(32);
pdev = platform_device_register_full(&info);
if (IS_ERR(pdev)) {
of_node_put(np);
return PTR_ERR(pdev);
}
pdev->dev.of_node = np;
ret = of_dma_configure(&pdev->dev, np, true);
if (ret) {
dev_err(core->dev, "dma configure fail\n");
goto err_unregister;
}
core->fw.dev = &pdev->dev;
iommu_dom = iommu_paging_domain_alloc(core->fw.dev);
if (IS_ERR(iommu_dom)) {
dev_err(core->fw.dev, "Failed to allocate iommu domain\n");
ret = PTR_ERR(iommu_dom);
goto err_unregister;
}
ret = iommu_attach_device(iommu_dom, core->fw.dev);
if (ret) {
dev_err(core->fw.dev, "could not attach device\n");
goto err_iommu_free;
}
core->fw.iommu_domain = iommu_dom;
of_node_put(np);
return 0;
err_iommu_free:
iommu_domain_free(iommu_dom);
err_unregister:
platform_device_unregister(pdev);
of_node_put(np);
return ret;
}
void venus_firmware_deinit(struct venus_core *core)
{
struct iommu_domain *iommu;
if (!core->fw.dev)
return;
iommu = core->fw.iommu_domain;
iommu_detach_device(iommu, core->fw.dev);
if (core->fw.iommu_domain) {
iommu_domain_free(iommu);
core->fw.iommu_domain = NULL;
}
platform_device_unregister(to_platform_device(core->fw.dev));
}
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (C) 2017 Linaro Ltd.
*/
#ifndef __VENUS_FIRMWARE_H__
#define __VENUS_FIRMWARE_H__
struct device;
int venus_firmware_init(struct venus_core *core);
void venus_firmware_deinit(struct venus_core *core);
int venus_firmware_check(struct venus_core *core);
int venus_firmware_cfg(struct venus_core *core);
int venus_boot(struct venus_core *core);
int venus_shutdown(struct venus_core *core);
int venus_set_hw_state(struct venus_core *core, bool suspend);
static inline int venus_set_hw_state_suspend(struct venus_core *core)
{
return venus_set_hw_state(core, false);
}
static inline int venus_set_hw_state_resume(struct venus_core *core)
{
return venus_set_hw_state(core, true);
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,74 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#ifndef __VENUS_HELPERS_H__
#define __VENUS_HELPERS_H__
#include <media/videobuf2-v4l2.h>
struct venus_inst;
struct venus_core;
bool venus_helper_check_codec(struct venus_inst *inst, u32 v4l2_pixfmt);
struct vb2_v4l2_buffer *venus_helper_find_buf(struct venus_inst *inst,
unsigned int type, u32 idx);
void venus_helper_change_dpb_owner(struct venus_inst *inst,
struct vb2_v4l2_buffer *vbuf, unsigned int type,
unsigned int buf_type, u32 idx);
void venus_helper_buffers_done(struct venus_inst *inst, unsigned int type,
enum vb2_buffer_state state);
int venus_helper_vb2_buf_init(struct vb2_buffer *vb);
int venus_helper_vb2_buf_prepare(struct vb2_buffer *vb);
void venus_helper_vb2_buf_queue(struct vb2_buffer *vb);
void venus_helper_vb2_stop_streaming(struct vb2_queue *q);
int venus_helper_vb2_start_streaming(struct venus_inst *inst);
void venus_helper_vb2_queue_error(struct venus_inst *inst);
void venus_helper_m2m_device_run(void *priv);
void venus_helper_m2m_job_abort(void *priv);
int venus_helper_get_bufreq(struct venus_inst *inst, u32 type,
struct hfi_buffer_requirements *req);
u32 venus_helper_get_framesz_raw(u32 hfi_fmt, u32 width, u32 height);
u32 venus_helper_get_framesz(u32 v4l2_fmt, u32 width, u32 height);
int venus_helper_set_input_resolution(struct venus_inst *inst,
unsigned int width, unsigned int height);
int venus_helper_set_output_resolution(struct venus_inst *inst,
unsigned int width, unsigned int height,
u32 buftype);
int venus_helper_set_work_mode(struct venus_inst *inst);
int venus_helper_set_format_constraints(struct venus_inst *inst);
int venus_helper_set_num_bufs(struct venus_inst *inst, unsigned int input_bufs,
unsigned int output_bufs,
unsigned int output2_bufs);
int venus_helper_set_raw_format(struct venus_inst *inst, u32 hfi_format,
u32 buftype);
int venus_helper_set_color_format(struct venus_inst *inst, u32 fmt);
int venus_helper_set_dyn_bufmode(struct venus_inst *inst);
int venus_helper_set_bufsize(struct venus_inst *inst, u32 bufsize, u32 buftype);
int venus_helper_set_multistream(struct venus_inst *inst, bool out_en,
bool out2_en);
unsigned int venus_helper_get_opb_size(struct venus_inst *inst);
void venus_helper_acquire_buf_ref(struct vb2_v4l2_buffer *vbuf);
void venus_helper_release_buf_ref(struct venus_inst *inst, unsigned int idx);
void venus_helper_init_instance(struct venus_inst *inst);
int venus_helper_session_init(struct venus_inst *inst);
int venus_helper_get_out_fmts(struct venus_inst *inst, u32 fmt, u32 *out_fmt,
u32 *out2_fmt, bool ubwc);
bool venus_helper_check_format(struct venus_inst *inst, u32 v4l2_pixfmt);
int venus_helper_alloc_dpb_bufs(struct venus_inst *inst);
int venus_helper_free_dpb_bufs(struct venus_inst *inst);
int venus_helper_intbufs_alloc(struct venus_inst *inst);
int venus_helper_intbufs_free(struct venus_inst *inst);
int venus_helper_intbufs_realloc(struct venus_inst *inst);
int venus_helper_queue_dpb_bufs(struct venus_inst *inst);
int venus_helper_unregister_bufs(struct venus_inst *inst);
int venus_helper_process_initial_cap_bufs(struct venus_inst *inst);
int venus_helper_process_initial_out_bufs(struct venus_inst *inst);
void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us,
struct vb2_v4l2_buffer *vbuf);
int venus_helper_get_profile_level(struct venus_inst *inst, u32 *profile, u32 *level);
int venus_helper_set_profile_level(struct venus_inst *inst, u32 profile, u32 level);
int venus_helper_set_stride(struct venus_inst *inst, unsigned int aligned_width,
unsigned int aligned_height);
#endif
@@ -0,0 +1,569 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/completion.h>
#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include "core.h"
#include "hfi.h"
#include "hfi_cmds.h"
#include "hfi_venus.h"
#define TIMEOUT msecs_to_jiffies(1000)
static u32 to_codec_type(u32 pixfmt)
{
switch (pixfmt) {
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_H264_NO_SC:
return HFI_VIDEO_CODEC_H264;
case V4L2_PIX_FMT_H263:
return HFI_VIDEO_CODEC_H263;
case V4L2_PIX_FMT_MPEG1:
return HFI_VIDEO_CODEC_MPEG1;
case V4L2_PIX_FMT_MPEG2:
return HFI_VIDEO_CODEC_MPEG2;
case V4L2_PIX_FMT_MPEG4:
return HFI_VIDEO_CODEC_MPEG4;
case V4L2_PIX_FMT_VC1_ANNEX_G:
case V4L2_PIX_FMT_VC1_ANNEX_L:
return HFI_VIDEO_CODEC_VC1;
case V4L2_PIX_FMT_VP8:
return HFI_VIDEO_CODEC_VP8;
case V4L2_PIX_FMT_VP9:
return HFI_VIDEO_CODEC_VP9;
case V4L2_PIX_FMT_XVID:
return HFI_VIDEO_CODEC_DIVX;
case V4L2_PIX_FMT_HEVC:
return HFI_VIDEO_CODEC_HEVC;
default:
return 0;
}
}
int hfi_core_init(struct venus_core *core)
{
int ret = 0;
mutex_lock(&core->lock);
if (core->state >= CORE_INIT)
goto unlock;
reinit_completion(&core->done);
ret = core->ops->core_init(core);
if (ret)
goto unlock;
ret = wait_for_completion_timeout(&core->done, TIMEOUT);
if (!ret) {
ret = -ETIMEDOUT;
goto unlock;
}
ret = 0;
if (core->error != HFI_ERR_NONE) {
ret = -EIO;
goto unlock;
}
core->state = CORE_INIT;
unlock:
mutex_unlock(&core->lock);
return ret;
}
int hfi_core_deinit(struct venus_core *core, bool blocking)
{
int ret = 0, empty;
mutex_lock(&core->lock);
if (core->state == CORE_UNINIT)
goto unlock;
empty = list_empty(&core->instances);
if (!empty && !blocking) {
ret = -EBUSY;
goto unlock;
}
if (!empty) {
mutex_unlock(&core->lock);
wait_var_event(&core->insts_count,
!atomic_read(&core->insts_count));
mutex_lock(&core->lock);
}
if (!core->ops)
goto unlock;
ret = core->ops->core_deinit(core);
if (!ret)
core->state = CORE_UNINIT;
unlock:
mutex_unlock(&core->lock);
return ret;
}
int hfi_core_suspend(struct venus_core *core)
{
if (core->state != CORE_INIT)
return 0;
return core->ops->suspend(core);
}
int hfi_core_resume(struct venus_core *core, bool force)
{
if (!force && core->state != CORE_INIT)
return 0;
return core->ops->resume(core);
}
int hfi_core_trigger_ssr(struct venus_core *core, u32 type)
{
return core->ops->core_trigger_ssr(core, type);
}
static int wait_session_msg(struct venus_inst *inst)
{
int ret;
ret = wait_for_completion_timeout(&inst->done, TIMEOUT);
if (!ret)
return -ETIMEDOUT;
if (inst->error != HFI_ERR_NONE)
return -EIO;
return 0;
}
int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops)
{
struct venus_core *core = inst->core;
bool max;
int ret;
if (!ops)
return -EINVAL;
inst->state = INST_UNINIT;
init_completion(&inst->done);
inst->ops = ops;
mutex_lock(&core->lock);
if (test_bit(0, &inst->core->sys_error)) {
ret = -EIO;
goto unlock;
}
max = atomic_add_unless(&core->insts_count, 1,
core->max_sessions_supported);
if (!max) {
ret = -EAGAIN;
} else {
list_add_tail(&inst->list, &core->instances);
ret = 0;
}
unlock:
mutex_unlock(&core->lock);
return ret;
}
EXPORT_SYMBOL_GPL(hfi_session_create);
int hfi_session_init(struct venus_inst *inst, u32 pixfmt)
{
struct venus_core *core = inst->core;
const struct hfi_ops *ops = core->ops;
int ret;
/*
* If core shutdown is in progress or if we are in system
* recovery, return an error as during system error recovery
* session_init() can't pass successfully
*/
mutex_lock(&core->lock);
if (!core->ops || test_bit(0, &inst->core->sys_error)) {
mutex_unlock(&core->lock);
return -EIO;
}
mutex_unlock(&core->lock);
if (inst->state != INST_UNINIT)
return -EALREADY;
inst->hfi_codec = to_codec_type(pixfmt);
reinit_completion(&inst->done);
ret = ops->session_init(inst, inst->session_type, inst->hfi_codec);
if (ret)
return ret;
ret = wait_session_msg(inst);
if (ret)
return ret;
inst->state = INST_INIT;
return 0;
}
EXPORT_SYMBOL_GPL(hfi_session_init);
void hfi_session_destroy(struct venus_inst *inst)
{
struct venus_core *core = inst->core;
mutex_lock(&core->lock);
list_del_init(&inst->list);
if (atomic_dec_and_test(&core->insts_count))
wake_up_var(&core->insts_count);
mutex_unlock(&core->lock);
}
EXPORT_SYMBOL_GPL(hfi_session_destroy);
int hfi_session_deinit(struct venus_inst *inst)
{
const struct hfi_ops *ops = inst->core->ops;
int ret;
if (inst->state == INST_UNINIT)
return 0;
if (inst->state < INST_INIT)
return -EINVAL;
if (test_bit(0, &inst->core->sys_error))
goto done;
reinit_completion(&inst->done);
ret = ops->session_end(inst);
if (ret)
return ret;
ret = wait_session_msg(inst);
if (ret)
return ret;
done:
inst->state = INST_UNINIT;
return 0;
}
EXPORT_SYMBOL_GPL(hfi_session_deinit);
int hfi_session_start(struct venus_inst *inst)
{
const struct hfi_ops *ops = inst->core->ops;
int ret;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
if (inst->state != INST_LOAD_RESOURCES)
return -EINVAL;
reinit_completion(&inst->done);
ret = ops->session_start(inst);
if (ret)
return ret;
ret = wait_session_msg(inst);
if (ret)
return ret;
inst->state = INST_START;
return 0;
}
EXPORT_SYMBOL_GPL(hfi_session_start);
int hfi_session_stop(struct venus_inst *inst)
{
const struct hfi_ops *ops = inst->core->ops;
int ret;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
if (inst->state != INST_START)
return -EINVAL;
reinit_completion(&inst->done);
ret = ops->session_stop(inst);
if (ret)
return ret;
ret = wait_session_msg(inst);
if (ret)
return ret;
inst->state = INST_STOP;
return 0;
}
EXPORT_SYMBOL_GPL(hfi_session_stop);
int hfi_session_continue(struct venus_inst *inst)
{
struct venus_core *core = inst->core;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
if (core->res->hfi_version == HFI_VERSION_1XX)
return 0;
return core->ops->session_continue(inst);
}
EXPORT_SYMBOL_GPL(hfi_session_continue);
int hfi_session_abort(struct venus_inst *inst)
{
const struct hfi_ops *ops = inst->core->ops;
int ret;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
reinit_completion(&inst->done);
ret = ops->session_abort(inst);
if (ret)
return ret;
ret = wait_session_msg(inst);
if (ret)
return ret;
return 0;
}
EXPORT_SYMBOL_GPL(hfi_session_abort);
int hfi_session_load_res(struct venus_inst *inst)
{
const struct hfi_ops *ops = inst->core->ops;
int ret;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
if (inst->state != INST_INIT)
return -EINVAL;
reinit_completion(&inst->done);
ret = ops->session_load_res(inst);
if (ret)
return ret;
ret = wait_session_msg(inst);
if (ret)
return ret;
inst->state = INST_LOAD_RESOURCES;
return 0;
}
int hfi_session_unload_res(struct venus_inst *inst)
{
const struct hfi_ops *ops = inst->core->ops;
int ret;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
if (inst->state != INST_STOP)
return -EINVAL;
reinit_completion(&inst->done);
ret = ops->session_release_res(inst);
if (ret)
return ret;
ret = wait_session_msg(inst);
if (ret)
return ret;
inst->state = INST_RELEASE_RESOURCES;
return 0;
}
EXPORT_SYMBOL_GPL(hfi_session_unload_res);
int hfi_session_flush(struct venus_inst *inst, u32 type, bool block)
{
const struct hfi_ops *ops = inst->core->ops;
int ret;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
reinit_completion(&inst->done);
ret = ops->session_flush(inst, type);
if (ret)
return ret;
if (block) {
ret = wait_session_msg(inst);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(hfi_session_flush);
int hfi_session_set_buffers(struct venus_inst *inst, struct hfi_buffer_desc *bd)
{
const struct hfi_ops *ops = inst->core->ops;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
return ops->session_set_buffers(inst, bd);
}
int hfi_session_unset_buffers(struct venus_inst *inst,
struct hfi_buffer_desc *bd)
{
const struct hfi_ops *ops = inst->core->ops;
int ret;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
reinit_completion(&inst->done);
ret = ops->session_unset_buffers(inst, bd);
if (ret)
return ret;
if (!bd->response_required)
return 0;
ret = wait_session_msg(inst);
if (ret)
return ret;
return 0;
}
int hfi_session_get_property(struct venus_inst *inst, u32 ptype,
union hfi_get_property *hprop)
{
const struct hfi_ops *ops = inst->core->ops;
int ret;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
if (inst->state < INST_INIT || inst->state >= INST_STOP)
return -EINVAL;
reinit_completion(&inst->done);
ret = ops->session_get_property(inst, ptype);
if (ret)
return ret;
ret = wait_session_msg(inst);
if (ret)
return ret;
*hprop = inst->hprop;
return 0;
}
EXPORT_SYMBOL_GPL(hfi_session_get_property);
int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata)
{
const struct hfi_ops *ops = inst->core->ops;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
if (inst->state < INST_INIT || inst->state >= INST_STOP)
return -EINVAL;
return ops->session_set_property(inst, ptype, pdata);
}
EXPORT_SYMBOL_GPL(hfi_session_set_property);
int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *fd)
{
const struct hfi_ops *ops = inst->core->ops;
if (test_bit(0, &inst->core->sys_error))
return -EIO;
if (fd->buffer_type == HFI_BUFFER_INPUT)
return ops->session_etb(inst, fd);
else if (fd->buffer_type == HFI_BUFFER_OUTPUT ||
fd->buffer_type == HFI_BUFFER_OUTPUT2)
return ops->session_ftb(inst, fd);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(hfi_session_process_buf);
irqreturn_t hfi_isr_thread(int irq, void *dev_id)
{
struct venus_core *core = dev_id;
return core->ops->isr_thread(core);
}
irqreturn_t hfi_isr(int irq, void *dev)
{
struct venus_core *core = dev;
return core->ops->isr(core);
}
int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops)
{
if (!ops)
return -EINVAL;
atomic_set(&core->insts_count, 0);
core->core_ops = ops;
core->state = CORE_UNINIT;
init_completion(&core->done);
pkt_set_version(core->res->hfi_version);
return venus_hfi_create(core);
}
void hfi_destroy(struct venus_core *core)
{
venus_hfi_destroy(core);
}
void hfi_reinit(struct venus_core *core)
{
venus_hfi_queues_reinit(core);
}
@@ -0,0 +1,176 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#ifndef __HFI_H__
#define __HFI_H__
#include <linux/interrupt.h>
#include "hfi_helper.h"
#define VIDC_SESSION_TYPE_VPE 0
#define VIDC_SESSION_TYPE_ENC 1
#define VIDC_SESSION_TYPE_DEC 2
#define VIDC_RESOURCE_NONE 0
#define VIDC_RESOURCE_OCMEM 1
#define VIDC_RESOURCE_VMEM 2
struct hfi_buffer_desc {
u32 buffer_type;
u32 buffer_size;
u32 num_buffers;
u32 device_addr;
u32 extradata_addr;
u32 extradata_size;
u32 response_required;
};
struct hfi_frame_data {
u32 buffer_type;
u32 device_addr;
u32 extradata_addr;
u64 timestamp;
u32 flags;
u32 offset;
u32 alloc_len;
u32 filled_len;
u32 mark_target;
u32 mark_data;
u32 clnt_data;
u32 extradata_size;
};
union hfi_get_property {
struct hfi_profile_level profile_level;
struct hfi_buffer_requirements bufreq[HFI_BUFFER_TYPE_MAX];
};
/* HFI events */
#define EVT_SYS_EVENT_CHANGE 1
#define EVT_SYS_WATCHDOG_TIMEOUT 2
#define EVT_SYS_ERROR 3
#define EVT_SESSION_ERROR 4
/* HFI event callback structure */
struct hfi_event_data {
u32 error;
u32 height;
u32 width;
u32 event_type;
u32 packet_buffer;
u32 extradata_buffer;
u32 tag;
u32 profile;
u32 level;
/* the following properties start appear from v4 onwards */
u32 bit_depth;
u32 pic_struct;
u32 colour_space;
u32 entropy_mode;
u32 buf_count;
struct {
u32 left, top;
u32 width, height;
} input_crop;
};
/* define core states */
#define CORE_UNINIT 0
#define CORE_INIT 1
/* define instance states */
#define INST_UNINIT 2
#define INST_INIT 3
#define INST_LOAD_RESOURCES 4
#define INST_START 5
#define INST_STOP 6
#define INST_RELEASE_RESOURCES 7
struct venus_core;
struct venus_inst;
struct hfi_core_ops {
void (*event_notify)(struct venus_core *core, u32 event);
};
struct hfi_inst_ops {
void (*buf_done)(struct venus_inst *inst, unsigned int buf_type,
u32 tag, u32 bytesused, u32 data_offset, u32 flags,
u32 hfi_flags, u64 timestamp_us);
void (*event_notify)(struct venus_inst *inst, u32 event,
struct hfi_event_data *data);
void (*flush_done)(struct venus_inst *inst);
};
struct hfi_ops {
int (*core_init)(struct venus_core *core);
int (*core_deinit)(struct venus_core *core);
int (*core_trigger_ssr)(struct venus_core *core, u32 trigger_type);
int (*session_init)(struct venus_inst *inst, u32 session_type,
u32 codec);
int (*session_end)(struct venus_inst *inst);
int (*session_abort)(struct venus_inst *inst);
int (*session_flush)(struct venus_inst *inst, u32 flush_mode);
int (*session_start)(struct venus_inst *inst);
int (*session_stop)(struct venus_inst *inst);
int (*session_continue)(struct venus_inst *inst);
int (*session_etb)(struct venus_inst *inst, struct hfi_frame_data *fd);
int (*session_ftb)(struct venus_inst *inst, struct hfi_frame_data *fd);
int (*session_set_buffers)(struct venus_inst *inst,
struct hfi_buffer_desc *bd);
int (*session_unset_buffers)(struct venus_inst *inst,
struct hfi_buffer_desc *bd);
int (*session_load_res)(struct venus_inst *inst);
int (*session_release_res)(struct venus_inst *inst);
int (*session_parse_seq_hdr)(struct venus_inst *inst, u32 seq_hdr,
u32 seq_hdr_len);
int (*session_get_seq_hdr)(struct venus_inst *inst, u32 seq_hdr,
u32 seq_hdr_len);
int (*session_set_property)(struct venus_inst *inst, u32 ptype,
void *pdata);
int (*session_get_property)(struct venus_inst *inst, u32 ptype);
int (*resume)(struct venus_core *core);
int (*suspend)(struct venus_core *core);
/* interrupt operations */
irqreturn_t (*isr)(struct venus_core *core);
irqreturn_t (*isr_thread)(struct venus_core *core);
};
int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops);
void hfi_destroy(struct venus_core *core);
void hfi_reinit(struct venus_core *core);
int hfi_core_init(struct venus_core *core);
int hfi_core_deinit(struct venus_core *core, bool blocking);
int hfi_core_suspend(struct venus_core *core);
int hfi_core_resume(struct venus_core *core, bool force);
int hfi_core_trigger_ssr(struct venus_core *core, u32 type);
int hfi_session_create(struct venus_inst *inst, const struct hfi_inst_ops *ops);
void hfi_session_destroy(struct venus_inst *inst);
int hfi_session_init(struct venus_inst *inst, u32 pixfmt);
int hfi_session_deinit(struct venus_inst *inst);
int hfi_session_start(struct venus_inst *inst);
int hfi_session_stop(struct venus_inst *inst);
int hfi_session_continue(struct venus_inst *inst);
int hfi_session_abort(struct venus_inst *inst);
int hfi_session_load_res(struct venus_inst *inst);
int hfi_session_unload_res(struct venus_inst *inst);
int hfi_session_flush(struct venus_inst *inst, u32 type, bool block);
int hfi_session_set_buffers(struct venus_inst *inst,
struct hfi_buffer_desc *bd);
int hfi_session_unset_buffers(struct venus_inst *inst,
struct hfi_buffer_desc *bd);
int hfi_session_get_property(struct venus_inst *inst, u32 ptype,
union hfi_get_property *hprop);
int hfi_session_set_property(struct venus_inst *inst, u32 ptype, void *pdata);
int hfi_session_process_buf(struct venus_inst *inst, struct hfi_frame_data *f);
irqreturn_t hfi_isr_thread(int irq, void *dev_id);
irqreturn_t hfi_isr(int irq, void *dev);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,296 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#ifndef __VENUS_HFI_CMDS_H__
#define __VENUS_HFI_CMDS_H__
#include "hfi.h"
/* commands */
#define HFI_CMD_SYS_INIT 0x10001
#define HFI_CMD_SYS_PC_PREP 0x10002
#define HFI_CMD_SYS_SET_RESOURCE 0x10003
#define HFI_CMD_SYS_RELEASE_RESOURCE 0x10004
#define HFI_CMD_SYS_SET_PROPERTY 0x10005
#define HFI_CMD_SYS_GET_PROPERTY 0x10006
#define HFI_CMD_SYS_SESSION_INIT 0x10007
#define HFI_CMD_SYS_SESSION_END 0x10008
#define HFI_CMD_SYS_SET_BUFFERS 0x10009
#define HFI_CMD_SYS_TEST_SSR 0x10101
#define HFI_CMD_SESSION_SET_PROPERTY 0x11001
#define HFI_CMD_SESSION_SET_BUFFERS 0x11002
#define HFI_CMD_SESSION_GET_SEQUENCE_HEADER 0x11003
#define HFI_CMD_SYS_SESSION_ABORT 0x210001
#define HFI_CMD_SYS_PING 0x210002
#define HFI_CMD_SESSION_LOAD_RESOURCES 0x211001
#define HFI_CMD_SESSION_START 0x211002
#define HFI_CMD_SESSION_STOP 0x211003
#define HFI_CMD_SESSION_EMPTY_BUFFER 0x211004
#define HFI_CMD_SESSION_FILL_BUFFER 0x211005
#define HFI_CMD_SESSION_SUSPEND 0x211006
#define HFI_CMD_SESSION_RESUME 0x211007
#define HFI_CMD_SESSION_FLUSH 0x211008
#define HFI_CMD_SESSION_GET_PROPERTY 0x211009
#define HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER 0x21100a
#define HFI_CMD_SESSION_RELEASE_BUFFERS 0x21100b
#define HFI_CMD_SESSION_RELEASE_RESOURCES 0x21100c
#define HFI_CMD_SESSION_CONTINUE 0x21100d
#define HFI_CMD_SESSION_SYNC 0x21100e
/* command packets */
struct hfi_sys_init_pkt {
struct hfi_pkt_hdr hdr;
u32 arch_type;
};
struct hfi_sys_pc_prep_pkt {
struct hfi_pkt_hdr hdr;
};
struct hfi_sys_set_resource_pkt {
struct hfi_pkt_hdr hdr;
u32 resource_handle;
u32 resource_type;
u32 resource_data[];
};
struct hfi_sys_release_resource_pkt {
struct hfi_pkt_hdr hdr;
u32 resource_type;
u32 resource_handle;
};
struct hfi_sys_set_property_pkt {
struct hfi_pkt_hdr hdr;
u32 num_properties;
u32 data[];
};
struct hfi_sys_get_property_pkt {
struct hfi_pkt_hdr hdr;
u32 num_properties;
u32 data;
};
struct hfi_sys_set_buffers_pkt {
struct hfi_pkt_hdr hdr;
u32 buffer_type;
u32 buffer_size;
u32 num_buffers;
u32 buffer_addr[];
};
struct hfi_sys_ping_pkt {
struct hfi_pkt_hdr hdr;
u32 client_data;
};
struct hfi_session_init_pkt {
struct hfi_session_hdr_pkt shdr;
u32 session_domain;
u32 session_codec;
};
struct hfi_session_end_pkt {
struct hfi_session_hdr_pkt shdr;
};
struct hfi_session_abort_pkt {
struct hfi_session_hdr_pkt shdr;
};
struct hfi_session_set_property_pkt {
struct hfi_session_hdr_pkt shdr;
u32 num_properties;
u32 data[];
};
struct hfi_session_set_buffers_pkt {
struct hfi_session_hdr_pkt shdr;
u32 buffer_type;
u32 buffer_size;
u32 extradata_size;
u32 min_buffer_size;
u32 num_buffers;
u32 buffer_info[];
};
struct hfi_session_get_sequence_header_pkt {
struct hfi_session_hdr_pkt shdr;
u32 buffer_len;
u32 packet_buffer;
};
struct hfi_session_load_resources_pkt {
struct hfi_session_hdr_pkt shdr;
};
struct hfi_session_start_pkt {
struct hfi_session_hdr_pkt shdr;
};
struct hfi_session_stop_pkt {
struct hfi_session_hdr_pkt shdr;
};
struct hfi_session_empty_buffer_compressed_pkt {
struct hfi_session_hdr_pkt shdr;
u32 time_stamp_hi;
u32 time_stamp_lo;
u32 flags;
u32 mark_target;
u32 mark_data;
u32 offset;
u32 alloc_len;
u32 filled_len;
u32 input_tag;
u32 packet_buffer;
u32 extradata_buffer;
u32 data;
};
struct hfi_session_empty_buffer_uncompressed_plane0_pkt {
struct hfi_session_hdr_pkt shdr;
u32 view_id;
u32 time_stamp_hi;
u32 time_stamp_lo;
u32 flags;
u32 mark_target;
u32 mark_data;
u32 alloc_len;
u32 filled_len;
u32 offset;
u32 input_tag;
u32 packet_buffer;
u32 extradata_buffer;
u32 data;
};
struct hfi_session_empty_buffer_uncompressed_plane1_pkt {
u32 flags;
u32 alloc_len;
u32 filled_len;
u32 offset;
u32 packet_buffer2;
u32 data;
};
struct hfi_session_empty_buffer_uncompressed_plane2_pkt {
u32 flags;
u32 alloc_len;
u32 filled_len;
u32 offset;
u32 packet_buffer3;
u32 data;
};
struct hfi_session_fill_buffer_pkt {
struct hfi_session_hdr_pkt shdr;
u32 stream_id;
u32 offset;
u32 alloc_len;
u32 filled_len;
u32 output_tag;
u32 packet_buffer;
u32 extradata_buffer;
u32 data;
};
struct hfi_session_flush_pkt {
struct hfi_session_hdr_pkt shdr;
u32 flush_type;
};
struct hfi_session_suspend_pkt {
struct hfi_session_hdr_pkt shdr;
};
struct hfi_session_resume_pkt {
struct hfi_session_hdr_pkt shdr;
};
struct hfi_session_get_property_pkt {
struct hfi_session_hdr_pkt shdr;
u32 num_properties;
u32 data;
};
struct hfi_session_release_buffer_pkt {
struct hfi_session_hdr_pkt shdr;
u32 buffer_type;
u32 buffer_size;
u32 extradata_size;
u32 response_req;
u32 num_buffers;
u32 buffer_info[] __counted_by(num_buffers);
};
struct hfi_session_release_resources_pkt {
struct hfi_session_hdr_pkt shdr;
};
struct hfi_session_parse_sequence_header_pkt {
struct hfi_session_hdr_pkt shdr;
u32 header_len;
u32 packet_buffer;
};
struct hfi_sfr {
u32 buf_size;
u8 data[] __counted_by(buf_size);
};
struct hfi_sys_test_ssr_pkt {
struct hfi_pkt_hdr hdr;
u32 trigger_type;
};
void pkt_set_version(enum hfi_version version);
void pkt_sys_init(struct hfi_sys_init_pkt *pkt, u32 arch_type);
void pkt_sys_pc_prep(struct hfi_sys_pc_prep_pkt *pkt);
void pkt_sys_idle_indicator(struct hfi_sys_set_property_pkt *pkt, u32 enable);
void pkt_sys_power_control(struct hfi_sys_set_property_pkt *pkt, u32 enable);
void pkt_sys_ubwc_config(struct hfi_sys_set_property_pkt *pkt, const struct hfi_ubwc_config *hfi);
int pkt_sys_set_resource(struct hfi_sys_set_resource_pkt *pkt, u32 id, u32 size,
u32 addr, void *cookie);
int pkt_sys_unset_resource(struct hfi_sys_release_resource_pkt *pkt, u32 id,
u32 size, void *cookie);
void pkt_sys_debug_config(struct hfi_sys_set_property_pkt *pkt, u32 mode,
u32 config);
void pkt_sys_coverage_config(struct hfi_sys_set_property_pkt *pkt, u32 mode);
void pkt_sys_ping(struct hfi_sys_ping_pkt *pkt, u32 cookie);
void pkt_sys_image_version(struct hfi_sys_get_property_pkt *pkt);
int pkt_sys_ssr_cmd(struct hfi_sys_test_ssr_pkt *pkt, u32 trigger_type);
int pkt_session_init(struct hfi_session_init_pkt *pkt, void *cookie,
u32 session_type, u32 codec);
void pkt_session_cmd(struct hfi_session_pkt *pkt, u32 pkt_type, void *cookie);
int pkt_session_set_buffers(struct hfi_session_set_buffers_pkt *pkt,
void *cookie, struct hfi_buffer_desc *bd);
int pkt_session_unset_buffers(struct hfi_session_release_buffer_pkt *pkt,
void *cookie, struct hfi_buffer_desc *bd);
int pkt_session_etb_decoder(struct hfi_session_empty_buffer_compressed_pkt *pkt,
void *cookie, struct hfi_frame_data *input_frame);
int pkt_session_etb_encoder(
struct hfi_session_empty_buffer_uncompressed_plane0_pkt *pkt,
void *cookie, struct hfi_frame_data *input_frame);
int pkt_session_ftb(struct hfi_session_fill_buffer_pkt *pkt,
void *cookie, struct hfi_frame_data *output_frame);
int pkt_session_parse_seq_header(
struct hfi_session_parse_sequence_header_pkt *pkt,
void *cookie, u32 seq_hdr, u32 seq_hdr_len);
int pkt_session_get_seq_hdr(struct hfi_session_get_sequence_header_pkt *pkt,
void *cookie, u32 seq_hdr, u32 seq_hdr_len);
int pkt_session_flush(struct hfi_session_flush_pkt *pkt, void *cookie,
u32 flush_mode);
int pkt_session_get_property(struct hfi_session_get_property_pkt *pkt,
void *cookie, u32 ptype);
int pkt_session_set_property(struct hfi_session_set_property_pkt *pkt,
void *cookie, u32 ptype, void *pdata);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,862 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#include <linux/hash.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/soc/qcom/smem.h>
#include <media/videobuf2-v4l2.h>
#include "core.h"
#include "hfi.h"
#include "hfi_helper.h"
#include "hfi_msgs.h"
#include "hfi_parser.h"
#define SMEM_IMG_VER_TBL 469
#define VER_STR_SZ 128
#define SMEM_IMG_OFFSET_VENUS (14 * 128)
static void event_seq_changed(struct venus_core *core, struct venus_inst *inst,
struct hfi_msg_event_notify_pkt *pkt)
{
enum hfi_version ver = core->res->hfi_version;
struct hfi_event_data event = {0};
int num_properties_changed;
struct hfi_framesize *frame_sz;
struct hfi_profile_level *profile_level;
struct hfi_bit_depth *pixel_depth;
struct hfi_pic_struct *pic_struct;
struct hfi_colour_space *colour_info;
struct hfi_buffer_requirements *bufreq;
struct hfi_extradata_input_crop *crop;
struct hfi_dpb_counts *dpb_count;
u32 ptype, rem_bytes;
u32 size_read = 0;
u8 *data_ptr;
inst->error = HFI_ERR_NONE;
switch (pkt->event_data1) {
case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUF_RESOURCES:
case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUF_RESOURCES:
break;
default:
inst->error = HFI_ERR_SESSION_INVALID_PARAMETER;
inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event);
return;
}
event.event_type = pkt->event_data1;
num_properties_changed = pkt->event_data2;
if (!num_properties_changed)
goto error;
data_ptr = (u8 *)&pkt->ext_event_data[0];
rem_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
do {
if (rem_bytes < sizeof(u32))
goto error;
ptype = *((u32 *)data_ptr);
data_ptr += sizeof(u32);
rem_bytes -= sizeof(u32);
switch (ptype) {
case HFI_PROPERTY_PARAM_FRAME_SIZE:
if (rem_bytes < sizeof(struct hfi_framesize))
goto error;
frame_sz = (struct hfi_framesize *)data_ptr;
event.width = frame_sz->width;
event.height = frame_sz->height;
size_read = sizeof(struct hfi_framesize);
break;
case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
if (rem_bytes < sizeof(struct hfi_profile_level))
goto error;
profile_level = (struct hfi_profile_level *)data_ptr;
event.profile = profile_level->profile;
event.level = profile_level->level;
size_read = sizeof(struct hfi_profile_level);
break;
case HFI_PROPERTY_PARAM_VDEC_PIXEL_BITDEPTH:
if (rem_bytes < sizeof(struct hfi_bit_depth))
goto error;
pixel_depth = (struct hfi_bit_depth *)data_ptr;
event.bit_depth = pixel_depth->bit_depth;
size_read = sizeof(struct hfi_bit_depth);
break;
case HFI_PROPERTY_PARAM_VDEC_PIC_STRUCT:
if (rem_bytes < sizeof(struct hfi_pic_struct))
goto error;
pic_struct = (struct hfi_pic_struct *)data_ptr;
event.pic_struct = pic_struct->progressive_only;
size_read = sizeof(struct hfi_pic_struct);
break;
case HFI_PROPERTY_PARAM_VDEC_COLOUR_SPACE:
if (rem_bytes < sizeof(struct hfi_colour_space))
goto error;
colour_info = (struct hfi_colour_space *)data_ptr;
event.colour_space = colour_info->colour_space;
size_read = sizeof(struct hfi_colour_space);
break;
case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
if (rem_bytes < sizeof(u32))
goto error;
event.entropy_mode = *(u32 *)data_ptr;
size_read = sizeof(u32);
break;
case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
if (rem_bytes < sizeof(struct hfi_buffer_requirements))
goto error;
bufreq = (struct hfi_buffer_requirements *)data_ptr;
event.buf_count = hfi_bufreq_get_count_min(bufreq, ver);
size_read = sizeof(struct hfi_buffer_requirements);
break;
case HFI_INDEX_EXTRADATA_INPUT_CROP:
if (rem_bytes < sizeof(struct hfi_extradata_input_crop))
goto error;
crop = (struct hfi_extradata_input_crop *)data_ptr;
event.input_crop.left = crop->left;
event.input_crop.top = crop->top;
event.input_crop.width = crop->width;
event.input_crop.height = crop->height;
size_read = sizeof(struct hfi_extradata_input_crop);
break;
case HFI_PROPERTY_PARAM_VDEC_DPB_COUNTS:
if (rem_bytes < sizeof(struct hfi_dpb_counts))
goto error;
dpb_count = (struct hfi_dpb_counts *)data_ptr;
event.buf_count = dpb_count->fw_min_cnt;
size_read = sizeof(struct hfi_dpb_counts);
break;
default:
size_read = 0;
break;
}
data_ptr += size_read;
rem_bytes -= size_read;
num_properties_changed--;
} while (num_properties_changed > 0);
inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event);
return;
error:
inst->error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES;
inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event);
}
static void event_release_buffer_ref(struct venus_core *core,
struct venus_inst *inst,
struct hfi_msg_event_notify_pkt *pkt)
{
struct hfi_event_data event = {0};
struct hfi_msg_event_release_buffer_ref_pkt *data;
data = (struct hfi_msg_event_release_buffer_ref_pkt *)
pkt->ext_event_data;
event.event_type = HFI_EVENT_RELEASE_BUFFER_REFERENCE;
event.packet_buffer = data->packet_buffer;
event.extradata_buffer = data->extradata_buffer;
event.tag = data->output_tag;
inst->error = HFI_ERR_NONE;
inst->ops->event_notify(inst, EVT_SYS_EVENT_CHANGE, &event);
}
static void event_sys_error(struct venus_core *core, u32 event,
struct hfi_msg_event_notify_pkt *pkt)
{
if (pkt)
dev_dbg(core->dev, VDBGH
"sys error (session id:%x, data1:%x, data2:%x)\n",
pkt->shdr.session_id, pkt->event_data1,
pkt->event_data2);
core->core_ops->event_notify(core, event);
}
static void
event_session_error(struct venus_core *core, struct venus_inst *inst,
struct hfi_msg_event_notify_pkt *pkt)
{
struct device *dev = core->dev;
dev_dbg(dev, VDBGH "session error: event id:%x, session id:%x\n",
pkt->event_data1, pkt->shdr.session_id);
if (!inst)
return;
switch (pkt->event_data1) {
/* non fatal session errors */
case HFI_ERR_SESSION_INVALID_SCALE_FACTOR:
case HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE:
case HFI_ERR_SESSION_UNSUPPORTED_SETTING:
case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED:
inst->error = HFI_ERR_NONE;
break;
default:
dev_err(dev, "session error: event id:%x (%x), session id:%x\n",
pkt->event_data1, pkt->event_data2,
pkt->shdr.session_id);
inst->error = pkt->event_data1;
inst->ops->event_notify(inst, EVT_SESSION_ERROR, NULL);
break;
}
}
static void hfi_event_notify(struct venus_core *core, struct venus_inst *inst,
void *packet)
{
struct hfi_msg_event_notify_pkt *pkt = packet;
if (!packet)
return;
switch (pkt->event_id) {
case HFI_EVENT_SYS_ERROR:
event_sys_error(core, EVT_SYS_ERROR, pkt);
break;
case HFI_EVENT_SESSION_ERROR:
event_session_error(core, inst, pkt);
break;
case HFI_EVENT_SESSION_SEQUENCE_CHANGED:
event_seq_changed(core, inst, pkt);
break;
case HFI_EVENT_RELEASE_BUFFER_REFERENCE:
event_release_buffer_ref(core, inst, pkt);
break;
case HFI_EVENT_SESSION_PROPERTY_CHANGED:
break;
default:
break;
}
}
static void hfi_sys_init_done(struct venus_core *core, struct venus_inst *inst,
void *packet)
{
struct hfi_msg_sys_init_done_pkt *pkt = packet;
int rem_bytes;
u32 error;
error = pkt->error_type;
if (error != HFI_ERR_NONE)
goto done;
if (!pkt->num_properties) {
error = HFI_ERR_SYS_INVALID_PARAMETER;
goto done;
}
rem_bytes = pkt->hdr.size - sizeof(*pkt);
if (rem_bytes <= 0) {
/* missing property data */
error = HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
goto done;
}
error = hfi_parser(core, inst, pkt->data, rem_bytes);
done:
core->error = error;
/*
* Since core_init could ask for the firmware version to be validated,
* completion might have to wait until the version is retrieved.
*/
if (!core->res->min_fw)
complete(&core->done);
}
static void
sys_get_prop_image_version(struct venus_core *core,
struct hfi_msg_sys_property_info_pkt *pkt)
{
struct device *dev = core->dev;
u8 *smem_tbl_ptr;
u8 *img_ver;
int req_bytes;
size_t smem_blk_sz;
int ret;
req_bytes = pkt->hdr.size - sizeof(*pkt);
if (req_bytes < VER_STR_SZ || !pkt->data[0] || pkt->num_properties > 1)
/* bad packet */
return;
img_ver = pkt->data;
if (!img_ver)
return;
ret = sscanf(img_ver, "14:video-firmware.%u.%u-%u",
&core->venus_ver.major, &core->venus_ver.minor, &core->venus_ver.rev);
if (ret)
goto done;
ret = sscanf(img_ver, "14:VIDEO.VPU.%u.%u-%u",
&core->venus_ver.major, &core->venus_ver.minor, &core->venus_ver.rev);
if (ret)
goto done;
ret = sscanf(img_ver, "14:VIDEO.VE.%u.%u-%u",
&core->venus_ver.major, &core->venus_ver.minor, &core->venus_ver.rev);
if (ret)
goto done;
dev_err(dev, VDBGL "error reading F/W version\n");
return;
done:
dev_dbg(dev, VDBGL "F/W version: %s, major %u, minor %u, revision %u\n",
img_ver, core->venus_ver.major, core->venus_ver.minor, core->venus_ver.rev);
smem_tbl_ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY,
SMEM_IMG_VER_TBL, &smem_blk_sz);
if (!IS_ERR(smem_tbl_ptr) && smem_blk_sz >= SMEM_IMG_OFFSET_VENUS + VER_STR_SZ)
memcpy(smem_tbl_ptr + SMEM_IMG_OFFSET_VENUS,
img_ver, VER_STR_SZ);
/* core_init could have had to wait for a version check */
if (core->res->min_fw)
complete(&core->done);
}
static void hfi_sys_property_info(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_sys_property_info_pkt *pkt = packet;
struct device *dev = core->dev;
if (!pkt->num_properties) {
dev_dbg(dev, VDBGL "no properties\n");
return;
}
switch (pkt->property) {
case HFI_PROPERTY_SYS_IMAGE_VERSION:
sys_get_prop_image_version(core, pkt);
break;
default:
dev_dbg(dev, VDBGL "unknown property data\n");
break;
}
}
static void hfi_sys_rel_resource_done(struct venus_core *core,
struct venus_inst *inst,
void *packet)
{
struct hfi_msg_sys_release_resource_done_pkt *pkt = packet;
core->error = pkt->error_type;
complete(&core->done);
}
static void hfi_sys_ping_done(struct venus_core *core, struct venus_inst *inst,
void *packet)
{
struct hfi_msg_sys_ping_ack_pkt *pkt = packet;
core->error = HFI_ERR_NONE;
if (pkt->client_data != 0xbeef)
core->error = HFI_ERR_SYS_FATAL;
complete(&core->done);
}
static void hfi_sys_idle_done(struct venus_core *core, struct venus_inst *inst,
void *packet)
{
dev_dbg(core->dev, VDBGL "sys idle\n");
}
static void hfi_sys_pc_prepare_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_sys_pc_prep_done_pkt *pkt = packet;
dev_dbg(core->dev, VDBGL "pc prepare done (error %x)\n",
pkt->error_type);
}
static unsigned int
session_get_prop_profile_level(struct hfi_msg_session_property_info_pkt *pkt,
struct hfi_profile_level *profile_level)
{
struct hfi_profile_level *hfi;
u32 req_bytes;
req_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
if (!req_bytes || req_bytes % sizeof(struct hfi_profile_level))
/* bad packet */
return HFI_ERR_SESSION_INVALID_PARAMETER;
hfi = (struct hfi_profile_level *)&pkt->data[0];
profile_level->profile = hfi->profile;
profile_level->level = hfi->level;
return HFI_ERR_NONE;
}
static unsigned int
session_get_prop_buf_req(struct hfi_msg_session_property_info_pkt *pkt,
struct hfi_buffer_requirements *bufreq)
{
struct hfi_buffer_requirements *buf_req;
u32 req_bytes;
unsigned int idx = 0;
req_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
if (!req_bytes || req_bytes % sizeof(*buf_req) || !pkt->data[0])
/* bad packet */
return HFI_ERR_SESSION_INVALID_PARAMETER;
buf_req = (struct hfi_buffer_requirements *)&pkt->data[0];
if (!buf_req)
return HFI_ERR_SESSION_INVALID_PARAMETER;
while (req_bytes) {
memcpy(&bufreq[idx], buf_req, sizeof(*bufreq));
idx++;
if (idx >= HFI_BUFFER_TYPE_MAX)
return HFI_ERR_SESSION_INVALID_PARAMETER;
req_bytes -= sizeof(struct hfi_buffer_requirements);
buf_req++;
}
return HFI_ERR_NONE;
}
static void hfi_session_prop_info(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_session_property_info_pkt *pkt = packet;
struct device *dev = core->dev;
union hfi_get_property *hprop = &inst->hprop;
unsigned int error = HFI_ERR_NONE;
if (!pkt->num_properties) {
error = HFI_ERR_SESSION_INVALID_PARAMETER;
dev_err(dev, "%s: no properties\n", __func__);
goto done;
}
switch (pkt->property) {
case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS:
memset(hprop->bufreq, 0, sizeof(hprop->bufreq));
error = session_get_prop_buf_req(pkt, hprop->bufreq);
break;
case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT:
memset(&hprop->profile_level, 0, sizeof(hprop->profile_level));
error = session_get_prop_profile_level(pkt,
&hprop->profile_level);
break;
case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
break;
default:
dev_dbg(dev, VDBGM "unknown property id:%x\n", pkt->property);
return;
}
done:
inst->error = error;
complete(&inst->done);
}
static void hfi_session_init_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_session_init_done_pkt *pkt = packet;
int rem_bytes;
u32 error;
error = pkt->error_type;
if (error != HFI_ERR_NONE)
goto done;
if (!IS_V1(core))
goto done;
rem_bytes = pkt->shdr.hdr.size - sizeof(*pkt);
if (rem_bytes <= 0) {
error = HFI_ERR_SESSION_INSUFFICIENT_RESOURCES;
goto done;
}
error = hfi_parser(core, inst, pkt->data, rem_bytes);
done:
inst->error = error;
complete(&inst->done);
}
static void hfi_session_load_res_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_session_load_resources_done_pkt *pkt = packet;
inst->error = pkt->error_type;
complete(&inst->done);
}
static void hfi_session_flush_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_session_flush_done_pkt *pkt = packet;
inst->error = pkt->error_type;
complete(&inst->done);
if (inst->ops->flush_done)
inst->ops->flush_done(inst);
}
static void hfi_session_etb_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_session_empty_buffer_done_pkt *pkt = packet;
inst->error = pkt->error_type;
inst->ops->buf_done(inst, HFI_BUFFER_INPUT, pkt->input_tag,
pkt->filled_len, pkt->offset, 0, 0, 0);
}
static void hfi_session_ftb_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
u32 session_type = inst->session_type;
u64 timestamp_us = 0;
u32 timestamp_hi = 0, timestamp_lo = 0;
unsigned int error;
u32 flags = 0, hfi_flags = 0, offset = 0, filled_len = 0;
u32 pic_type = 0, buffer_type = 0, output_tag = -1;
if (session_type == VIDC_SESSION_TYPE_ENC) {
struct hfi_msg_session_fbd_compressed_pkt *pkt = packet;
timestamp_hi = pkt->time_stamp_hi;
timestamp_lo = pkt->time_stamp_lo;
hfi_flags = pkt->flags;
offset = pkt->offset;
filled_len = pkt->filled_len;
pic_type = pkt->picture_type;
output_tag = pkt->output_tag;
buffer_type = HFI_BUFFER_OUTPUT;
error = pkt->error_type;
} else if (session_type == VIDC_SESSION_TYPE_DEC) {
struct hfi_msg_session_fbd_uncompressed_plane0_pkt *pkt =
packet;
timestamp_hi = pkt->time_stamp_hi;
timestamp_lo = pkt->time_stamp_lo;
hfi_flags = pkt->flags;
offset = pkt->offset;
filled_len = pkt->filled_len;
pic_type = pkt->picture_type;
output_tag = pkt->output_tag;
if (pkt->stream_id == 0)
buffer_type = HFI_BUFFER_OUTPUT;
else if (pkt->stream_id == 1)
buffer_type = HFI_BUFFER_OUTPUT2;
error = pkt->error_type;
} else {
error = HFI_ERR_SESSION_INVALID_PARAMETER;
}
if (buffer_type != HFI_BUFFER_OUTPUT &&
buffer_type != HFI_BUFFER_OUTPUT2)
goto done;
if (hfi_flags & HFI_BUFFERFLAG_EOS)
flags |= V4L2_BUF_FLAG_LAST;
switch (pic_type) {
case HFI_PICTURE_IDR:
case HFI_PICTURE_I:
flags |= V4L2_BUF_FLAG_KEYFRAME;
break;
case HFI_PICTURE_P:
flags |= V4L2_BUF_FLAG_PFRAME;
break;
case HFI_PICTURE_B:
flags |= V4L2_BUF_FLAG_BFRAME;
break;
case HFI_FRAME_NOTCODED:
case HFI_UNUSED_PICT:
case HFI_FRAME_YUV:
default:
break;
}
if (!(hfi_flags & HFI_BUFFERFLAG_TIMESTAMPINVALID) && filled_len) {
timestamp_us = timestamp_hi;
timestamp_us = (timestamp_us << 32) | timestamp_lo;
}
done:
inst->error = error;
inst->ops->buf_done(inst, buffer_type, output_tag, filled_len,
offset, flags, hfi_flags, timestamp_us);
}
static void hfi_session_start_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_session_start_done_pkt *pkt = packet;
inst->error = pkt->error_type;
complete(&inst->done);
}
static void hfi_session_stop_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_session_stop_done_pkt *pkt = packet;
inst->error = pkt->error_type;
complete(&inst->done);
}
static void hfi_session_rel_res_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_session_release_resources_done_pkt *pkt = packet;
inst->error = pkt->error_type;
complete(&inst->done);
}
static void hfi_session_rel_buf_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_session_release_buffers_done_pkt *pkt = packet;
inst->error = pkt->error_type;
complete(&inst->done);
}
static void hfi_session_end_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_session_end_done_pkt *pkt = packet;
inst->error = pkt->error_type;
complete(&inst->done);
}
static void hfi_session_abort_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_sys_session_abort_done_pkt *pkt = packet;
inst->error = pkt->error_type;
complete(&inst->done);
}
static void hfi_session_get_seq_hdr_done(struct venus_core *core,
struct venus_inst *inst, void *packet)
{
struct hfi_msg_session_get_sequence_hdr_done_pkt *pkt = packet;
inst->error = pkt->error_type;
complete(&inst->done);
}
struct hfi_done_handler {
u32 pkt;
u32 pkt_sz;
u32 pkt_sz2;
void (*done)(struct venus_core *, struct venus_inst *, void *);
bool is_sys_pkt;
};
static const struct hfi_done_handler handlers[] = {
{.pkt = HFI_MSG_EVENT_NOTIFY,
.pkt_sz = sizeof(struct hfi_msg_event_notify_pkt),
.done = hfi_event_notify,
},
{.pkt = HFI_MSG_SYS_INIT,
.pkt_sz = sizeof(struct hfi_msg_sys_init_done_pkt),
.done = hfi_sys_init_done,
.is_sys_pkt = true,
},
{.pkt = HFI_MSG_SYS_PROPERTY_INFO,
.pkt_sz = sizeof(struct hfi_msg_sys_property_info_pkt),
.done = hfi_sys_property_info,
.is_sys_pkt = true,
},
{.pkt = HFI_MSG_SYS_RELEASE_RESOURCE,
.pkt_sz = sizeof(struct hfi_msg_sys_release_resource_done_pkt),
.done = hfi_sys_rel_resource_done,
.is_sys_pkt = true,
},
{.pkt = HFI_MSG_SYS_PING_ACK,
.pkt_sz = sizeof(struct hfi_msg_sys_ping_ack_pkt),
.done = hfi_sys_ping_done,
.is_sys_pkt = true,
},
{.pkt = HFI_MSG_SYS_IDLE,
.pkt_sz = sizeof(struct hfi_msg_sys_idle_pkt),
.done = hfi_sys_idle_done,
.is_sys_pkt = true,
},
{.pkt = HFI_MSG_SYS_PC_PREP,
.pkt_sz = sizeof(struct hfi_msg_sys_pc_prep_done_pkt),
.done = hfi_sys_pc_prepare_done,
.is_sys_pkt = true,
},
{.pkt = HFI_MSG_SYS_SESSION_INIT,
.pkt_sz = sizeof(struct hfi_msg_session_init_done_pkt),
.done = hfi_session_init_done,
},
{.pkt = HFI_MSG_SYS_SESSION_END,
.pkt_sz = sizeof(struct hfi_msg_session_end_done_pkt),
.done = hfi_session_end_done,
},
{.pkt = HFI_MSG_SESSION_LOAD_RESOURCES,
.pkt_sz = sizeof(struct hfi_msg_session_load_resources_done_pkt),
.done = hfi_session_load_res_done,
},
{.pkt = HFI_MSG_SESSION_START,
.pkt_sz = sizeof(struct hfi_msg_session_start_done_pkt),
.done = hfi_session_start_done,
},
{.pkt = HFI_MSG_SESSION_STOP,
.pkt_sz = sizeof(struct hfi_msg_session_stop_done_pkt),
.done = hfi_session_stop_done,
},
{.pkt = HFI_MSG_SYS_SESSION_ABORT,
.pkt_sz = sizeof(struct hfi_msg_sys_session_abort_done_pkt),
.done = hfi_session_abort_done,
},
{.pkt = HFI_MSG_SESSION_EMPTY_BUFFER,
.pkt_sz = sizeof(struct hfi_msg_session_empty_buffer_done_pkt),
.done = hfi_session_etb_done,
},
{.pkt = HFI_MSG_SESSION_FILL_BUFFER,
.pkt_sz = sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_pkt),
.pkt_sz2 = sizeof(struct hfi_msg_session_fbd_compressed_pkt),
.done = hfi_session_ftb_done,
},
{.pkt = HFI_MSG_SESSION_FLUSH,
.pkt_sz = sizeof(struct hfi_msg_session_flush_done_pkt),
.done = hfi_session_flush_done,
},
{.pkt = HFI_MSG_SESSION_PROPERTY_INFO,
.pkt_sz = sizeof(struct hfi_msg_session_property_info_pkt),
.done = hfi_session_prop_info,
},
{.pkt = HFI_MSG_SESSION_RELEASE_RESOURCES,
.pkt_sz = sizeof(struct hfi_msg_session_release_resources_done_pkt),
.done = hfi_session_rel_res_done,
},
{.pkt = HFI_MSG_SESSION_GET_SEQUENCE_HEADER,
.pkt_sz = sizeof(struct hfi_msg_session_get_sequence_hdr_done_pkt),
.done = hfi_session_get_seq_hdr_done,
},
{.pkt = HFI_MSG_SESSION_RELEASE_BUFFERS,
.pkt_sz = sizeof(struct hfi_msg_session_release_buffers_done_pkt),
.done = hfi_session_rel_buf_done,
},
};
void hfi_process_watchdog_timeout(struct venus_core *core)
{
event_sys_error(core, EVT_SYS_WATCHDOG_TIMEOUT, NULL);
}
static struct venus_inst *to_instance(struct venus_core *core, u32 session_id)
{
struct venus_inst *inst;
mutex_lock(&core->lock);
list_for_each_entry(inst, &core->instances, list)
if (hash32_ptr(inst) == session_id) {
mutex_unlock(&core->lock);
return inst;
}
mutex_unlock(&core->lock);
return NULL;
}
u32 hfi_process_msg_packet(struct venus_core *core, struct hfi_pkt_hdr *hdr)
{
const struct hfi_done_handler *handler;
struct device *dev = core->dev;
struct venus_inst *inst;
bool found = false;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(handlers); i++) {
handler = &handlers[i];
if (handler->pkt != hdr->pkt_type)
continue;
found = true;
break;
}
if (!found)
return hdr->pkt_type;
if (hdr->size && hdr->size < handler->pkt_sz &&
hdr->size < handler->pkt_sz2) {
dev_err(dev, "bad packet size (%d should be %d, pkt type:%x)\n",
hdr->size, handler->pkt_sz, hdr->pkt_type);
return hdr->pkt_type;
}
if (handler->is_sys_pkt) {
inst = NULL;
} else {
struct hfi_session_pkt *pkt;
pkt = (struct hfi_session_pkt *)hdr;
inst = to_instance(core, pkt->shdr.session_id);
if (!inst)
dev_warn(dev, "no valid instance(pkt session_id:%x, pkt:%x)\n",
pkt->shdr.session_id,
handler ? handler->pkt : 0);
/*
* Event of type HFI_EVENT_SYS_ERROR will not have any session
* associated with it
*/
if (!inst && hdr->pkt_type != HFI_MSG_EVENT_NOTIFY) {
dev_err(dev, "got invalid session id:%x\n",
pkt->shdr.session_id);
goto invalid_session;
}
}
handler->done(core, inst, hdr);
invalid_session:
return hdr->pkt_type;
}
@@ -0,0 +1,276 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#ifndef __VENUS_HFI_MSGS_H__
#define __VENUS_HFI_MSGS_H__
/* message calls */
#define HFI_MSG_SYS_INIT 0x20001
#define HFI_MSG_SYS_PC_PREP 0x20002
#define HFI_MSG_SYS_RELEASE_RESOURCE 0x20003
#define HFI_MSG_SYS_DEBUG 0x20004
#define HFI_MSG_SYS_SESSION_INIT 0x20006
#define HFI_MSG_SYS_SESSION_END 0x20007
#define HFI_MSG_SYS_IDLE 0x20008
#define HFI_MSG_SYS_COV 0x20009
#define HFI_MSG_SYS_PROPERTY_INFO 0x2000a
#define HFI_MSG_EVENT_NOTIFY 0x21001
#define HFI_MSG_SESSION_GET_SEQUENCE_HEADER 0x21002
#define HFI_MSG_SYS_PING_ACK 0x220002
#define HFI_MSG_SYS_SESSION_ABORT 0x220004
#define HFI_MSG_SESSION_LOAD_RESOURCES 0x221001
#define HFI_MSG_SESSION_START 0x221002
#define HFI_MSG_SESSION_STOP 0x221003
#define HFI_MSG_SESSION_SUSPEND 0x221004
#define HFI_MSG_SESSION_RESUME 0x221005
#define HFI_MSG_SESSION_FLUSH 0x221006
#define HFI_MSG_SESSION_EMPTY_BUFFER 0x221007
#define HFI_MSG_SESSION_FILL_BUFFER 0x221008
#define HFI_MSG_SESSION_PROPERTY_INFO 0x221009
#define HFI_MSG_SESSION_RELEASE_RESOURCES 0x22100a
#define HFI_MSG_SESSION_PARSE_SEQUENCE_HEADER 0x22100b
#define HFI_MSG_SESSION_RELEASE_BUFFERS 0x22100c
#define HFI_PICTURE_I 0x00000001
#define HFI_PICTURE_P 0x00000002
#define HFI_PICTURE_B 0x00000004
#define HFI_PICTURE_IDR 0x00000008
#define HFI_FRAME_NOTCODED 0x7f002000
#define HFI_FRAME_YUV 0x7f004000
#define HFI_UNUSED_PICT 0x10000000
/* message packets */
struct hfi_msg_event_notify_pkt {
struct hfi_session_hdr_pkt shdr;
u32 event_id;
u32 event_data1;
u32 event_data2;
u32 ext_event_data[];
};
struct hfi_msg_event_release_buffer_ref_pkt {
u32 packet_buffer;
u32 extradata_buffer;
u32 output_tag;
};
struct hfi_msg_sys_init_done_pkt {
struct hfi_pkt_hdr hdr;
u32 error_type;
u32 num_properties;
u32 data[];
};
struct hfi_msg_sys_pc_prep_done_pkt {
struct hfi_pkt_hdr hdr;
u32 error_type;
};
struct hfi_msg_sys_release_resource_done_pkt {
struct hfi_pkt_hdr hdr;
u32 resource_handle;
u32 error_type;
};
struct hfi_msg_session_init_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
u32 num_properties;
u32 data[];
};
struct hfi_msg_session_end_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
};
struct hfi_msg_session_get_sequence_hdr_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
u32 header_len;
u32 sequence_header;
};
struct hfi_msg_sys_session_abort_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
};
struct hfi_msg_sys_idle_pkt {
struct hfi_pkt_hdr hdr;
};
struct hfi_msg_sys_ping_ack_pkt {
struct hfi_pkt_hdr hdr;
u32 client_data;
};
struct hfi_msg_sys_property_info_pkt {
struct hfi_pkt_hdr hdr;
u32 num_properties;
u32 property;
u8 data[];
};
struct hfi_msg_session_load_resources_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
};
struct hfi_msg_session_start_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
};
struct hfi_msg_session_stop_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
};
struct hfi_msg_session_suspend_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
};
struct hfi_msg_session_resume_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
};
struct hfi_msg_session_flush_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
u32 flush_type;
};
struct hfi_msg_session_empty_buffer_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
u32 offset;
u32 filled_len;
u32 input_tag;
u32 packet_buffer;
u32 extradata_buffer;
u32 data[];
};
struct hfi_msg_session_fbd_compressed_pkt {
struct hfi_session_hdr_pkt shdr;
u32 time_stamp_hi;
u32 time_stamp_lo;
u32 error_type;
u32 flags;
u32 mark_target;
u32 mark_data;
u32 stats;
u32 offset;
u32 alloc_len;
u32 filled_len;
u32 input_tag;
u32 output_tag;
u32 picture_type;
u32 packet_buffer;
u32 extradata_buffer;
u32 data[];
};
struct hfi_msg_session_fbd_uncompressed_plane0_pkt {
struct hfi_session_hdr_pkt shdr;
u32 stream_id;
u32 view_id;
u32 error_type;
u32 time_stamp_hi;
u32 time_stamp_lo;
u32 flags;
u32 mark_target;
u32 mark_data;
u32 stats;
u32 alloc_len;
u32 filled_len;
u32 offset;
u32 frame_width;
u32 frame_height;
u32 start_x_coord;
u32 start_y_coord;
u32 input_tag;
u32 input_tag2;
u32 output_tag;
u32 picture_type;
u32 packet_buffer;
u32 extradata_buffer;
u32 data[];
};
struct hfi_msg_session_fbd_uncompressed_plane1_pkt {
u32 flags;
u32 alloc_len;
u32 filled_len;
u32 offset;
u32 packet_buffer2;
u32 data[];
};
struct hfi_msg_session_fbd_uncompressed_plane2_pkt {
u32 flags;
u32 alloc_len;
u32 filled_len;
u32 offset;
u32 packet_buffer3;
u32 data[];
};
struct hfi_msg_session_parse_sequence_header_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
u32 num_properties;
u32 data[];
};
struct hfi_msg_session_property_info_pkt {
struct hfi_session_hdr_pkt shdr;
u32 num_properties;
u32 property;
u8 data[];
};
struct hfi_msg_session_release_resources_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
};
struct hfi_msg_session_release_buffers_done_pkt {
struct hfi_session_hdr_pkt shdr;
u32 error_type;
u32 num_buffers;
u32 buffer_info[];
};
struct hfi_msg_sys_debug_pkt {
struct hfi_pkt_hdr hdr;
u32 msg_type;
u32 msg_size;
u32 time_stamp_hi;
u32 time_stamp_lo;
u8 msg_data[];
};
struct hfi_msg_sys_coverage_pkt {
struct hfi_pkt_hdr hdr;
u32 msg_size;
u32 time_stamp_hi;
u32 time_stamp_lo;
u8 msg_data[];
};
struct venus_core;
struct hfi_pkt_hdr;
void hfi_process_watchdog_timeout(struct venus_core *core);
u32 hfi_process_msg_packet(struct venus_core *core, struct hfi_pkt_hdr *hdr);
#endif
@@ -0,0 +1,388 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2018 Linaro Ltd.
*
* Author: Stanimir Varbanov <stanimir.varbanov@linaro.org>
*/
#include <linux/bitops.h>
#include <linux/kernel.h>
#include "core.h"
#include "hfi_helper.h"
#include "hfi_parser.h"
typedef void (*func)(struct hfi_plat_caps *cap, const void *data,
unsigned int size);
static void init_codecs(struct venus_core *core)
{
struct hfi_plat_caps *caps = core->caps, *cap;
unsigned long bit;
core->codecs_count = 0;
if (hweight_long(core->dec_codecs) + hweight_long(core->enc_codecs) > MAX_CODEC_NUM)
return;
for_each_set_bit(bit, &core->dec_codecs, MAX_CODEC_NUM) {
cap = &caps[core->codecs_count++];
cap->codec = BIT(bit);
cap->domain = VIDC_SESSION_TYPE_DEC;
cap->valid = false;
}
for_each_set_bit(bit, &core->enc_codecs, MAX_CODEC_NUM) {
cap = &caps[core->codecs_count++];
cap->codec = BIT(bit);
cap->domain = VIDC_SESSION_TYPE_ENC;
cap->valid = false;
}
}
static void for_each_codec(struct hfi_plat_caps *caps, unsigned int caps_num,
u32 codecs, u32 domain, func cb, void *data,
unsigned int size)
{
struct hfi_plat_caps *cap;
unsigned int i;
for (i = 0; i < caps_num; i++) {
cap = &caps[i];
if (cap->valid && cap->domain == domain)
continue;
if (cap->codec & codecs && cap->domain == domain)
cb(cap, data, size);
}
}
static void
fill_buf_mode(struct hfi_plat_caps *cap, const void *data, unsigned int num)
{
const u32 *type = data;
if (*type == HFI_BUFFER_MODE_DYNAMIC)
cap->cap_bufs_mode_dynamic = true;
}
static int
parse_alloc_mode(struct venus_core *core, u32 codecs, u32 domain, void *data)
{
struct hfi_buffer_alloc_mode_supported *mode = data;
u32 num_entries = mode->num_entries;
u32 *type;
if (num_entries > MAX_ALLOC_MODE_ENTRIES)
return -EINVAL;
type = mode->data;
while (num_entries--) {
if (mode->buffer_type == HFI_BUFFER_OUTPUT ||
mode->buffer_type == HFI_BUFFER_OUTPUT2)
for_each_codec(core->caps, ARRAY_SIZE(core->caps),
codecs, domain, fill_buf_mode, type, 1);
type++;
}
return sizeof(*mode);
}
static void fill_profile_level(struct hfi_plat_caps *cap, const void *data,
unsigned int num)
{
const struct hfi_profile_level *pl = data;
if (cap->num_pl + num >= HFI_MAX_PROFILE_COUNT)
return;
memcpy(&cap->pl[cap->num_pl], pl, num * sizeof(*pl));
cap->num_pl += num;
}
static int
parse_profile_level(struct venus_core *core, u32 codecs, u32 domain, void *data)
{
struct hfi_profile_level_supported *pl = data;
struct hfi_profile_level *proflevel = pl->profile_level;
struct hfi_profile_level pl_arr[HFI_MAX_PROFILE_COUNT] = {};
if (pl->profile_count > HFI_MAX_PROFILE_COUNT)
return -EINVAL;
memcpy(pl_arr, proflevel, pl->profile_count * sizeof(*proflevel));
for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
fill_profile_level, pl_arr, pl->profile_count);
return pl->profile_count * sizeof(*proflevel) + sizeof(u32);
}
static void
fill_caps(struct hfi_plat_caps *cap, const void *data, unsigned int num)
{
const struct hfi_capability *caps = data;
if (cap->num_caps + num >= MAX_CAP_ENTRIES)
return;
memcpy(&cap->caps[cap->num_caps], caps, num * sizeof(*caps));
cap->num_caps += num;
}
static int
parse_caps(struct venus_core *core, u32 codecs, u32 domain, void *data)
{
struct hfi_capabilities *caps = data;
struct hfi_capability *cap = caps->data;
u32 num_caps = caps->num_capabilities;
struct hfi_capability caps_arr[MAX_CAP_ENTRIES] = {};
if (num_caps > MAX_CAP_ENTRIES)
return -EINVAL;
memcpy(caps_arr, cap, num_caps * sizeof(*cap));
for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
fill_caps, caps_arr, num_caps);
return sizeof(*caps);
}
static void fill_raw_fmts(struct hfi_plat_caps *cap, const void *fmts,
unsigned int num_fmts)
{
const struct raw_formats *formats = fmts;
if (cap->num_fmts + num_fmts >= MAX_FMT_ENTRIES)
return;
memcpy(&cap->fmts[cap->num_fmts], formats, num_fmts * sizeof(*formats));
cap->num_fmts += num_fmts;
}
static int
parse_raw_formats(struct venus_core *core, u32 codecs, u32 domain, void *data)
{
struct hfi_uncompressed_format_supported *fmt = data;
struct hfi_uncompressed_plane_info *pinfo = &fmt->plane_info;
struct hfi_uncompressed_plane_constraints *constr;
struct raw_formats rawfmts[MAX_FMT_ENTRIES] = {};
u32 entries = fmt->format_entries;
unsigned int i = 0;
u32 num_planes = 0;
u32 size;
while (entries) {
num_planes = pinfo->num_planes;
rawfmts[i].fmt = pinfo->format;
rawfmts[i].buftype = fmt->buffer_type;
i++;
if (i >= MAX_FMT_ENTRIES)
return -EINVAL;
if (pinfo->num_planes > MAX_PLANES)
break;
pinfo = (void *)pinfo + sizeof(*constr) * num_planes +
2 * sizeof(u32);
entries--;
}
for_each_codec(core->caps, ARRAY_SIZE(core->caps), codecs, domain,
fill_raw_fmts, rawfmts, i);
size = fmt->format_entries * (sizeof(*constr) * num_planes + 2 * sizeof(u32))
+ 2 * sizeof(u32);
return size;
}
static int parse_codecs(struct venus_core *core, void *data)
{
struct hfi_codec_supported *codecs = data;
core->dec_codecs = codecs->dec_codecs;
core->enc_codecs = codecs->enc_codecs;
if (core->res->dec_codec_blacklist)
core->dec_codecs &= ~core->res->dec_codec_blacklist;
if (core->res->enc_codec_blacklist)
core->enc_codecs &= ~core->res->enc_codec_blacklist;
return sizeof(*codecs);
}
static int parse_max_sessions(struct venus_core *core, const void *data)
{
const struct hfi_max_sessions_supported *sessions = data;
core->max_sessions_supported = sessions->max_sessions;
return sizeof(*sessions);
}
static int parse_codecs_mask(u32 *codecs, u32 *domain, void *data)
{
struct hfi_codec_mask_supported *mask = data;
*codecs = mask->codecs;
*domain = mask->video_domains;
return sizeof(*mask);
}
static void parser_init(struct venus_inst *inst, u32 *codecs, u32 *domain)
{
if (!inst || !IS_V1(inst->core))
return;
*codecs = inst->hfi_codec;
*domain = inst->session_type;
}
static void parser_fini(struct venus_inst *inst, u32 codecs, u32 domain)
{
struct hfi_plat_caps *caps, *cap;
unsigned int i;
u32 dom;
if (!inst || !IS_V1(inst->core))
return;
caps = inst->core->caps;
dom = inst->session_type;
for (i = 0; i < MAX_CODEC_NUM; i++) {
cap = &caps[i];
if (cap->codec & codecs && cap->domain == dom)
cap->valid = true;
}
}
static int hfi_platform_parser(struct venus_core *core, struct venus_inst *inst)
{
const struct hfi_platform *plat;
const struct hfi_plat_caps *caps = NULL;
u32 enc_codecs, dec_codecs, count = 0;
unsigned int entries;
plat = hfi_platform_get(core->res->hfi_version);
if (!plat)
return -EINVAL;
if (inst)
return 0;
if (plat->codecs)
plat->codecs(core, &enc_codecs, &dec_codecs, &count);
if (plat->capabilities)
caps = plat->capabilities(core, &entries);
if (!caps || !entries || !count)
return -EINVAL;
core->enc_codecs = enc_codecs;
core->dec_codecs = dec_codecs;
core->codecs_count = count;
core->max_sessions_supported = MAX_SESSIONS;
memset(core->caps, 0, sizeof(*caps) * MAX_CODEC_NUM);
memcpy(core->caps, caps, sizeof(*caps) * entries);
return 0;
}
u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,
u32 size)
{
u32 *words = buf, *payload, codecs = 0, domain = 0;
u32 *frame_size = buf + size;
u32 rem_bytes = size;
int ret;
ret = hfi_platform_parser(core, inst);
if (!ret)
return HFI_ERR_NONE;
if (size % 4)
return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
parser_init(inst, &codecs, &domain);
if (core->res->hfi_version > HFI_VERSION_1XX) {
core->codecs_count = 0;
memset(core->caps, 0, sizeof(core->caps));
}
while (words < frame_size) {
payload = words + 1;
switch (*words) {
case HFI_PROPERTY_PARAM_CODEC_SUPPORTED:
if (rem_bytes <= sizeof(struct hfi_codec_supported))
return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
ret = parse_codecs(core, payload);
if (ret < 0)
return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
init_codecs(core);
break;
case HFI_PROPERTY_PARAM_MAX_SESSIONS_SUPPORTED:
if (rem_bytes <= sizeof(struct hfi_max_sessions_supported))
return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
ret = parse_max_sessions(core, payload);
break;
case HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED:
if (rem_bytes <= sizeof(struct hfi_codec_mask_supported))
return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
ret = parse_codecs_mask(&codecs, &domain, payload);
break;
case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED:
if (rem_bytes <= sizeof(struct hfi_uncompressed_format_supported))
return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
ret = parse_raw_formats(core, codecs, domain, payload);
break;
case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED:
if (rem_bytes <= sizeof(struct hfi_capabilities))
return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
ret = parse_caps(core, codecs, domain, payload);
break;
case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED:
if (rem_bytes <= sizeof(struct hfi_profile_level_supported))
return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
ret = parse_profile_level(core, codecs, domain, payload);
break;
case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED:
if (rem_bytes <= sizeof(struct hfi_buffer_alloc_mode_supported))
return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
ret = parse_alloc_mode(core, codecs, domain, payload);
break;
default:
ret = sizeof(u32);
break;
}
if (ret < 0)
return HFI_ERR_SYS_INSUFFICIENT_RESOURCES;
words += ret / sizeof(u32);
rem_bytes -= ret;
}
if (!core->max_sessions_supported)
core->max_sessions_supported = MAX_SESSIONS;
parser_fini(inst, codecs, domain);
return HFI_ERR_NONE;
}
@@ -0,0 +1,120 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (C) 2018 Linaro Ltd. */
#ifndef __VENUS_HFI_PARSER_H__
#define __VENUS_HFI_PARSER_H__
#include "core.h"
u32 hfi_parser(struct venus_core *core, struct venus_inst *inst,
void *buf, u32 size);
#define WHICH_CAP_MIN 0
#define WHICH_CAP_MAX 1
#define WHICH_CAP_STEP 2
static inline u32 get_cap(struct venus_inst *inst, u32 type, u32 which)
{
struct venus_core *core = inst->core;
struct hfi_capability *cap = NULL;
struct hfi_plat_caps *caps;
unsigned int i;
caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type);
if (!caps)
return 0;
for (i = 0; i < caps->num_caps; i++) {
if (caps->caps[i].capability_type == type) {
cap = &caps->caps[i];
break;
}
}
if (!cap)
return 0;
switch (which) {
case WHICH_CAP_MIN:
return cap->min;
case WHICH_CAP_MAX:
return cap->max;
case WHICH_CAP_STEP:
return cap->step_size;
default:
break;
}
return 0;
}
static inline u32 cap_min(struct venus_inst *inst, u32 type)
{
return get_cap(inst, type, WHICH_CAP_MIN);
}
static inline u32 cap_max(struct venus_inst *inst, u32 type)
{
return get_cap(inst, type, WHICH_CAP_MAX);
}
static inline u32 cap_step(struct venus_inst *inst, u32 type)
{
return get_cap(inst, type, WHICH_CAP_STEP);
}
static inline u32 frame_width_min(struct venus_inst *inst)
{
return cap_min(inst, HFI_CAPABILITY_FRAME_WIDTH);
}
static inline u32 frame_width_max(struct venus_inst *inst)
{
return cap_max(inst, HFI_CAPABILITY_FRAME_WIDTH);
}
static inline u32 frame_width_step(struct venus_inst *inst)
{
return cap_step(inst, HFI_CAPABILITY_FRAME_WIDTH);
}
static inline u32 frame_height_min(struct venus_inst *inst)
{
return cap_min(inst, HFI_CAPABILITY_FRAME_HEIGHT);
}
static inline u32 frame_height_max(struct venus_inst *inst)
{
return cap_max(inst, HFI_CAPABILITY_FRAME_HEIGHT);
}
static inline u32 frame_height_step(struct venus_inst *inst)
{
return cap_step(inst, HFI_CAPABILITY_FRAME_HEIGHT);
}
static inline u32 frate_min(struct venus_inst *inst)
{
return cap_min(inst, HFI_CAPABILITY_FRAMERATE);
}
static inline u32 frate_max(struct venus_inst *inst)
{
return cap_max(inst, HFI_CAPABILITY_FRAMERATE);
}
static inline u32 frate_step(struct venus_inst *inst)
{
return cap_step(inst, HFI_CAPABILITY_FRAMERATE);
}
static inline u32 core_num_max(struct venus_inst *inst)
{
return cap_max(inst, HFI_CAPABILITY_MAX_VIDEOCORES);
}
static inline u32 mbs_per_frame_max(struct venus_inst *inst)
{
return cap_max(inst, HFI_CAPABILITY_MBS_PER_FRAME);
}
#endif
@@ -0,0 +1,41 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#ifndef __HFI_PLATFORM_BUFFERS_H__
#define __HFI_PLATFORM_BUFFERS_H__
#include <linux/types.h>
#include "hfi_helper.h"
struct hfi_plat_buffers_params {
u32 width;
u32 height;
u32 out_width;
u32 out_height;
u32 codec;
u32 hfi_color_fmt;
u32 hfi_dpb_color_fmt;
enum hfi_version version;
u32 num_vpp_pipes;
union {
struct {
u32 max_mbs_per_frame;
u32 buffer_size_limit;
bool is_secondary_output;
bool is_interlaced;
} dec;
struct {
u32 work_mode;
u32 rc_type;
u32 num_b_frames;
bool is_tenbit;
} enc;
};
};
int hfi_plat_bufreq_v6(struct hfi_plat_buffers_params *params, u32 session_type,
u32 buftype, struct hfi_buffer_requirements *bufreq);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include "hfi_platform.h"
const struct hfi_platform *hfi_platform_get(enum hfi_version version)
{
switch (version) {
case HFI_VERSION_4XX:
return &hfi_plat_v4;
case HFI_VERSION_6XX:
return &hfi_plat_v6;
default:
break;
}
return NULL;
}
unsigned long
hfi_platform_get_codec_vpp_freq(struct venus_core *core,
enum hfi_version version, u32 codec,
u32 session_type)
{
const struct hfi_platform *plat;
unsigned long freq = 0;
plat = hfi_platform_get(version);
if (!plat)
return 0;
if (plat->codec_vpp_freq)
freq = plat->codec_vpp_freq(core, session_type, codec);
return freq;
}
unsigned long
hfi_platform_get_codec_vsp_freq(struct venus_core *core,
enum hfi_version version, u32 codec,
u32 session_type)
{
const struct hfi_platform *plat;
unsigned long freq = 0;
plat = hfi_platform_get(version);
if (!plat)
return 0;
if (plat->codec_vpp_freq)
freq = plat->codec_vsp_freq(core, session_type, codec);
return freq;
}
unsigned long
hfi_platform_get_codec_lp_freq(struct venus_core *core,
enum hfi_version version, u32 codec,
u32 session_type)
{
const struct hfi_platform *plat;
unsigned long freq = 0;
plat = hfi_platform_get(version);
if (!plat)
return 0;
if (plat->codec_lp_freq)
freq = plat->codec_lp_freq(core, session_type, codec);
return freq;
}
@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#ifndef __HFI_PLATFORM_H__
#define __HFI_PLATFORM_H__
#include <linux/types.h>
#include <linux/videodev2.h>
#include "hfi.h"
#include "hfi_plat_bufs.h"
#include "hfi_helper.h"
#define MAX_PLANES 4
#define MAX_FMT_ENTRIES 32
#define MAX_CAP_ENTRIES 32
#define MAX_ALLOC_MODE_ENTRIES 16
#define MAX_CODEC_NUM 32
#define MAX_SESSIONS 16
struct raw_formats {
u32 buftype;
u32 fmt;
};
struct hfi_plat_caps {
u32 codec;
u32 domain;
bool cap_bufs_mode_dynamic;
unsigned int num_caps;
struct hfi_capability caps[MAX_CAP_ENTRIES];
unsigned int num_pl;
struct hfi_profile_level pl[HFI_MAX_PROFILE_COUNT];
unsigned int num_fmts;
struct raw_formats fmts[MAX_FMT_ENTRIES];
bool valid; /* used only for Venus v1xx */
};
struct hfi_platform_codec_freq_data {
u32 pixfmt;
u32 session_type;
unsigned long vpp_freq;
unsigned long vsp_freq;
unsigned long low_power_freq;
};
struct hfi_platform {
unsigned long (*codec_vpp_freq)(struct venus_core *core,
u32 session_type, u32 codec);
unsigned long (*codec_vsp_freq)(struct venus_core *core,
u32 session_type, u32 codec);
unsigned long (*codec_lp_freq)(struct venus_core *core,
u32 session_type, u32 codec);
void (*codecs)(struct venus_core *core, u32 *enc_codecs,
u32 *dec_codecs, u32 *count);
const struct hfi_plat_caps *(*capabilities)(struct venus_core *core,
unsigned int *entries);
int (*bufreq)(struct hfi_plat_buffers_params *params, u32 session_type,
u32 buftype, struct hfi_buffer_requirements *bufreq);
};
extern const struct hfi_platform hfi_plat_v4;
extern const struct hfi_platform hfi_plat_v6;
const struct hfi_platform *hfi_platform_get(enum hfi_version version);
unsigned long hfi_platform_get_codec_vpp_freq(struct venus_core *core,
enum hfi_version version,
u32 codec, u32 session_type);
unsigned long hfi_platform_get_codec_vsp_freq(struct venus_core *core,
enum hfi_version version,
u32 codec, u32 session_type);
unsigned long hfi_platform_get_codec_lp_freq(struct venus_core *core,
enum hfi_version version,
u32 codec, u32 session_type);
#endif
@@ -0,0 +1,481 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include "core.h"
#include "hfi_platform.h"
static const struct hfi_plat_caps caps[] = {
{
.codec = HFI_VIDEO_CODEC_H264,
.domain = VIDC_SESSION_TYPE_DEC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 4096, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 4096, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 2073600, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 2, 1},
.caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 3, 1},
.num_caps = 10,
.pl[0] = {HFI_H264_PROFILE_BASELINE, HFI_H264_LEVEL_52},
.pl[1] = {HFI_H264_PROFILE_MAIN, HFI_H264_LEVEL_52},
.pl[2] = {HFI_H264_PROFILE_HIGH, HFI_H264_LEVEL_52},
.pl[3] = {HFI_H264_PROFILE_CONSTRAINED_BASE, HFI_H264_LEVEL_52},
.pl[4] = {HFI_H264_PROFILE_CONSTRAINED_HIGH, HFI_H264_LEVEL_52},
.num_pl = 5,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_HEVC,
.domain = VIDC_SESSION_TYPE_DEC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 4096, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 4096, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 2073600, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 2, 1},
.caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 3, 1},
.num_caps = 10,
.pl[0] = {HFI_HEVC_PROFILE_MAIN, HFI_HEVC_LEVEL_6 | HFI_HEVC_TIER_HIGH0 << 28},
.pl[1] = {HFI_HEVC_PROFILE_MAIN10, HFI_HEVC_LEVEL_6 | HFI_HEVC_TIER_HIGH0 << 28},
.num_pl = 2,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010},
.fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.num_fmts = 7,
}, {
.codec = HFI_VIDEO_CODEC_VP8,
.domain = VIDC_SESSION_TYPE_DEC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 4096, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 4096, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 2073600, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 2, 1},
.caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 3, 1},
.num_caps = 10,
.pl[0] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_0},
.pl[1] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_1},
.pl[2] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_2},
.pl[3] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_3},
.num_pl = 4,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_VP9,
.domain = VIDC_SESSION_TYPE_DEC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 4096, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 4096, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 2073600, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 2, 1},
.caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 3, 1},
.num_caps = 10,
.pl[0] = {HFI_VP9_PROFILE_P0, 200},
.pl[1] = {HFI_VP9_PROFILE_P2_10B, 200},
.num_pl = 2,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010},
.fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.num_fmts = 7,
}, {
.codec = HFI_VIDEO_CODEC_MPEG2,
.domain = VIDC_SESSION_TYPE_DEC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 1920, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 1920, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 8160, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 40000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 4096, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 4096, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 244800, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 30, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 2, 1},
.caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 1, 1},
.num_caps = 10,
.pl[0] = {HFI_MPEG2_PROFILE_SIMPLE, HFI_MPEG2_LEVEL_H14},
.pl[1] = {HFI_MPEG2_PROFILE_MAIN, HFI_MPEG2_LEVEL_H14},
.num_pl = 2,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_H264,
.domain = VIDC_SESSION_TYPE_ENC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 8192, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 8192, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 1036800, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 3, 1},
.caps[9] = {HFI_CAPABILITY_PEAKBITRATE, 32000, 160000000, 1},
.caps[10] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 5, 1},
.caps[11] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 4, 1},
.caps[12] = {HFI_CAPABILITY_LCU_SIZE, 16, 16, 1},
.caps[13] = {HFI_CAPABILITY_BFRAME, 0, 1, 1},
.caps[14] = {HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS, 0, 5, 1},
.caps[15] = {HFI_CAPABILITY_I_FRAME_QP, 0, 51, 1},
.caps[16] = {HFI_CAPABILITY_P_FRAME_QP, 0, 51, 1},
.caps[17] = {HFI_CAPABILITY_B_FRAME_QP, 0, 51, 1},
.caps[18] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 2, 1},
.caps[19] = {HFI_CAPABILITY_RATE_CONTROL_MODES, 0x1000001, 0x1000005, 1},
.caps[20] = {HFI_CAPABILITY_COLOR_SPACE_CONVERSION, 0, 2, 1},
.num_caps = 21,
.pl[0] = {HFI_H264_PROFILE_BASELINE, HFI_H264_LEVEL_52},
.pl[1] = {HFI_H264_PROFILE_MAIN, HFI_H264_LEVEL_52},
.pl[2] = {HFI_H264_PROFILE_HIGH, HFI_H264_LEVEL_52},
.pl[3] = {HFI_H264_PROFILE_CONSTRAINED_BASE, HFI_H264_LEVEL_52},
.pl[4] = {HFI_H264_PROFILE_CONSTRAINED_HIGH, HFI_H264_LEVEL_52},
.num_pl = 5,
.fmts[0] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12},
.fmts[1] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.fmts[3] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_P010},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_HEVC,
.domain = VIDC_SESSION_TYPE_ENC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 8192, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 8192, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 1036800, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 480, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 3, 1},
.caps[9] = {HFI_CAPABILITY_PEAKBITRATE, 32000, 160000000, 1},
.caps[10] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 5, 1},
.caps[11] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 4, 1},
.caps[12] = {HFI_CAPABILITY_LCU_SIZE, 32, 32, 1},
.caps[13] = {HFI_CAPABILITY_BFRAME, 0, 1, 1},
.caps[14] = {HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS, 0, 5, 1},
.caps[15] = {HFI_CAPABILITY_I_FRAME_QP, 0, 63, 1},
.caps[16] = {HFI_CAPABILITY_P_FRAME_QP, 0, 63, 1},
.caps[17] = {HFI_CAPABILITY_B_FRAME_QP, 0, 63, 1},
.caps[18] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 2, 1},
.caps[19] = {HFI_CAPABILITY_RATE_CONTROL_MODES, 0x1000001, 0x1000005, 1},
.caps[20] = {HFI_CAPABILITY_COLOR_SPACE_CONVERSION, 0, 2, 1},
.caps[21] = {HFI_CAPABILITY_ROTATION, 1, 4, 90},
.caps[22] = {HFI_CAPABILITY_BLUR_WIDTH, 96, 4096, 1},
.caps[23] = {HFI_CAPABILITY_BLUR_HEIGHT, 96, 4096, 1},
.num_caps = 24,
.pl[0] = {HFI_HEVC_PROFILE_MAIN, HFI_HEVC_LEVEL_6 | HFI_HEVC_TIER_HIGH0},
.pl[1] = {HFI_HEVC_PROFILE_MAIN10, HFI_HEVC_LEVEL_6 | HFI_HEVC_TIER_HIGH0},
.num_pl = 2,
.fmts[0] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12},
.fmts[1] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.fmts[3] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_P010},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_VP8,
.domain = VIDC_SESSION_TYPE_ENC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 96, 4096, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 96, 4096, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 1, 36864, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 120000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 8192, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 8192, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 1, 1036800, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 240, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 1, 3, 1},
.caps[9] = {HFI_CAPABILITY_PEAKBITRATE, 32000, 160000000, 1},
.caps[10] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 3, 1},
.caps[11] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 2, 1},
.caps[12] = {HFI_CAPABILITY_LCU_SIZE, 16, 16, 1},
.caps[13] = {HFI_CAPABILITY_BFRAME, 0, 1, 1},
.caps[14] = {HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS, 0, 5, 1},
.caps[15] = {HFI_CAPABILITY_I_FRAME_QP, 0, 127, 1},
.caps[16] = {HFI_CAPABILITY_P_FRAME_QP, 0, 127, 1},
.caps[17] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 2, 1},
.caps[18] = {HFI_CAPABILITY_RATE_CONTROL_MODES, 0x1000001, 0x1000005, 1},
.caps[19] = {HFI_CAPABILITY_BLUR_WIDTH, 96, 4096, 1},
.caps[20] = {HFI_CAPABILITY_BLUR_HEIGHT, 96, 4096, 1},
.caps[21] = {HFI_CAPABILITY_COLOR_SPACE_CONVERSION, 0, 2, 1},
.caps[22] = {HFI_CAPABILITY_ROTATION, 1, 4, 90},
.num_caps = 23,
.pl[0] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_0},
.pl[1] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_1},
.pl[2] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_2},
.pl[3] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_3},
.num_pl = 4,
.fmts[0] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12},
.fmts[1] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.fmts[3] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_P010},
.num_fmts = 4,
} };
static const struct hfi_plat_caps caps_lite[] = {
{
.codec = HFI_VIDEO_CODEC_H264,
.domain = VIDC_SESSION_TYPE_DEC,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 1920, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 1920, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 8160, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 60000000, 1 },
.caps[4] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 244800, 1},
.caps[5] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1},
.caps[6] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.num_caps = 7,
.pl[0] = { HFI_H264_PROFILE_BASELINE, HFI_H264_LEVEL_5},
.pl[1] = {HFI_H264_PROFILE_MAIN, HFI_H264_LEVEL_5},
.pl[2] = {HFI_H264_PROFILE_HIGH, HFI_H264_LEVEL_5},
.pl[3] = {HFI_H264_PROFILE_CONSTRAINED_BASE, HFI_H264_LEVEL_5},
.pl[4] = {HFI_H264_PROFILE_CONSTRAINED_HIGH, HFI_H264_LEVEL_5},
.num_pl = 5,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_HEVC,
.domain = VIDC_SESSION_TYPE_DEC,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 1920, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 1920, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 8160, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 60000000, 1 },
.caps[4] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 244800, 1},
.caps[5] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1},
.caps[6] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.num_caps = 7,
.pl[0] = {HFI_HEVC_PROFILE_MAIN, HFI_HEVC_LEVEL_5 | HFI_HEVC_TIER_HIGH0 << 28 },
.pl[1] = {HFI_HEVC_PROFILE_MAIN10, HFI_HEVC_LEVEL_5 | HFI_HEVC_TIER_HIGH0 << 28 },
.num_pl = 2,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_VP9,
.domain = VIDC_SESSION_TYPE_DEC,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 1920, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 1920, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 8160, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 60000000, 1 },
.caps[4] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 244800, 1},
.caps[5] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1},
.caps[6] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.num_caps = 7,
.pl[0] = {HFI_VP9_PROFILE_P0, 200},
.pl[1] = {HFI_VP9_PROFILE_P2_10B, 200},
.num_pl = 2,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_H264,
.domain = VIDC_SESSION_TYPE_ENC,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 1920, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 1920, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 8160, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 60000000, 1 },
.caps[4] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 244800, 1},
.caps[5] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1},
.caps[6] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.caps[7] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 6, 1},
.caps[8] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 4, 1},
.caps[9] = {HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE, 0, 244800, 1},
.caps[10] = {HFI_CAPABILITY_I_FRAME_QP, 0, 51, 1},
.caps[11] = {HFI_CAPABILITY_P_FRAME_QP, 0, 51, 1},
.caps[12] = {HFI_CAPABILITY_B_FRAME_QP, 0, 51, 1},
.caps[13] = {HFI_CAPABILITY_SLICE_BYTE, 1, 10, 1},
.caps[14] = {HFI_CAPABILITY_SLICE_MB, 1, 10, 1},
.num_caps = 15,
.pl[0] = {HFI_H264_PROFILE_BASELINE, HFI_H264_LEVEL_5},
.pl[1] = {HFI_H264_PROFILE_MAIN, HFI_H264_LEVEL_5},
.pl[2] = {HFI_H264_PROFILE_HIGH, HFI_H264_LEVEL_5},
.pl[3] = {HFI_H264_PROFILE_CONSTRAINED_BASE, HFI_H264_LEVEL_5},
.pl[4] = {HFI_H264_PROFILE_CONSTRAINED_HIGH, HFI_H264_LEVEL_5},
.num_pl = 5,
.fmts[0] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12},
.fmts[1] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.num_fmts = 2,
}, {
.codec = HFI_VIDEO_CODEC_HEVC,
.domain = VIDC_SESSION_TYPE_ENC,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 1920, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 1920, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 8160, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 60000000, 1 },
.caps[4] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 244800, 1},
.caps[5] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1},
.caps[6] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.caps[7] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 6, 1},
.caps[8] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 4, 1},
.caps[9] = {HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE, 0, 244800, 1},
.caps[10] = {HFI_CAPABILITY_I_FRAME_QP, 0, 51, 1},
.caps[11] = {HFI_CAPABILITY_P_FRAME_QP, 0, 51, 1},
.caps[12] = {HFI_CAPABILITY_B_FRAME_QP, 0, 51, 1},
.caps[13] = {HFI_CAPABILITY_SLICE_BYTE, 1, 10, 1},
.caps[14] = {HFI_CAPABILITY_SLICE_MB, 1, 10, 1},
.num_caps = 15,
.pl[0] = {HFI_HEVC_PROFILE_MAIN, HFI_HEVC_LEVEL_5 | HFI_HEVC_TIER_HIGH0},
.pl[1] = {HFI_HEVC_PROFILE_MAIN10, HFI_HEVC_LEVEL_5 | HFI_HEVC_TIER_HIGH0},
.num_pl = 2,
.fmts[0] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12},
.fmts[1] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.num_fmts = 2,
} };
static const struct hfi_plat_caps *get_capabilities(struct venus_core *core,
unsigned int *entries)
{
*entries = is_lite(core) ? ARRAY_SIZE(caps_lite) : ARRAY_SIZE(caps);
return is_lite(core) ? caps_lite : caps;
}
static void get_codecs(struct venus_core *core,
u32 *enc_codecs, u32 *dec_codecs, u32 *count)
{
const struct hfi_plat_caps *caps;
unsigned int num;
size_t i;
*enc_codecs = 0;
*dec_codecs = 0;
caps = get_capabilities(core, &num);
for (i = 0; i < num; caps++, i++) {
if (caps->domain == VIDC_SESSION_TYPE_ENC)
*enc_codecs |= caps->codec;
else
*dec_codecs |= caps->codec;
}
*count = num;
}
static const struct hfi_platform_codec_freq_data codec_freq_data[] = {
{ V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
{ V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
{ V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 10, 320 },
{ V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
{ V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
{ V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
{ V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
{ V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 10, 200 },
};
static const struct hfi_platform_codec_freq_data codec_freq_data_lite[] = {
{ V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 440, 0, 440 },
{ V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 440, 0, 440 },
{ V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 440, 0, 440 },
{ V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 0, 675 },
{ V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 0, 675 },
};
static const struct hfi_platform_codec_freq_data *
get_codec_freq_data(struct venus_core *core, u32 session_type, u32 pixfmt)
{
const struct hfi_platform_codec_freq_data *data;
unsigned int i, data_size;
const struct hfi_platform_codec_freq_data *found = NULL;
if (is_lite(core)) {
data = codec_freq_data_lite;
data_size = ARRAY_SIZE(codec_freq_data_lite);
} else {
data = codec_freq_data;
data_size = ARRAY_SIZE(codec_freq_data);
}
for (i = 0; i < data_size; i++) {
if (data[i].pixfmt == pixfmt && data[i].session_type == session_type) {
found = &data[i];
break;
}
}
return found;
}
static unsigned long codec_vpp_freq(struct venus_core *core,
u32 session_type, u32 codec)
{
const struct hfi_platform_codec_freq_data *data;
data = get_codec_freq_data(core, session_type, codec);
if (data)
return data->vpp_freq;
return 0;
}
static unsigned long codec_vsp_freq(struct venus_core *core,
u32 session_type, u32 codec)
{
const struct hfi_platform_codec_freq_data *data;
data = get_codec_freq_data(core, session_type, codec);
if (data)
return data->vsp_freq;
return 0;
}
static unsigned long codec_lp_freq(struct venus_core *core,
u32 session_type, u32 codec)
{
const struct hfi_platform_codec_freq_data *data;
data = get_codec_freq_data(core, session_type, codec);
if (data)
return data->low_power_freq;
return 0;
}
const struct hfi_platform hfi_plat_v4 = {
.codec_vpp_freq = codec_vpp_freq,
.codec_vsp_freq = codec_vsp_freq,
.codec_lp_freq = codec_lp_freq,
.codecs = get_codecs,
.capabilities = get_capabilities,
};
@@ -0,0 +1,347 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include "core.h"
#include "hfi_platform.h"
static const struct hfi_plat_caps caps[] = {
{
.codec = HFI_VIDEO_CODEC_H264,
.domain = VIDC_SESSION_TYPE_DEC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 8192, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 8192, 1},
/* ((5760 * 2880) / 256) */
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 138240, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 220000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 65536, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 65536, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 960, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.num_caps = 9,
.pl[0] = {HFI_H264_PROFILE_BASELINE, HFI_H264_LEVEL_52},
.pl[1] = {HFI_H264_PROFILE_MAIN, HFI_H264_LEVEL_52},
.pl[2] = {HFI_H264_PROFILE_HIGH, HFI_H264_LEVEL_52},
.pl[3] = {HFI_H264_PROFILE_CONSTRAINED_BASE, HFI_H264_LEVEL_52},
.pl[4] = {HFI_H264_PROFILE_CONSTRAINED_HIGH, HFI_H264_LEVEL_52},
.num_pl = 5,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_HEVC,
.domain = VIDC_SESSION_TYPE_DEC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 8192, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 8192, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 138240, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 220000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 65536, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 65536, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 960, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 3, 1},
.num_caps = 10,
.pl[0] = {HFI_HEVC_PROFILE_MAIN, HFI_HEVC_LEVEL_6 | HFI_HEVC_TIER_HIGH0},
.pl[1] = {HFI_HEVC_PROFILE_MAIN10, HFI_HEVC_LEVEL_6 | HFI_HEVC_TIER_HIGH0},
.num_pl = 2,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010},
.fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.num_fmts = 7,
}, {
.codec = HFI_VIDEO_CODEC_VP8,
.domain = VIDC_SESSION_TYPE_DEC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 4096, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 4096, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 36864, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 100000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 65536, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 65536, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 4423680, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 3, 1},
.num_caps = 10,
.pl[0] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_0},
.pl[1] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_1},
.pl[2] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_2},
.pl[3] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_3},
.num_pl = 4,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_VP9,
.domain = VIDC_SESSION_TYPE_DEC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 8192, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 8192, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 138240, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 220000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 65536, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 65536, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 960, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 3, 1},
.num_caps = 10,
.pl[0] = {HFI_VP9_PROFILE_P0, 200},
.pl[1] = {HFI_VP9_PROFILE_P2_10B, 200},
.num_pl = 2,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[4] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.fmts[5] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_P010},
.fmts[6] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.num_fmts = 7,
}, {
.codec = HFI_VIDEO_CODEC_MPEG2,
.domain = VIDC_SESSION_TYPE_DEC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 1920, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 1920, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 8160, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 40000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 65536, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 65536, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 30, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.caps[9] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 1, 1},
.num_caps = 10,
.pl[0] = {HFI_MPEG2_PROFILE_SIMPLE, HFI_MPEG2_LEVEL_H14},
.pl[1] = {HFI_MPEG2_PROFILE_MAIN, HFI_MPEG2_LEVEL_H14},
.num_pl = 2,
.fmts[0] = {HFI_BUFFER_OUTPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[1] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV12},
.fmts[3] = {HFI_BUFFER_OUTPUT2, HFI_COLOR_FORMAT_NV21},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_H264,
.domain = VIDC_SESSION_TYPE_ENC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 8192, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 8192, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 138240, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 220000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 8192, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 8192, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 960, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.caps[9] = {HFI_CAPABILITY_PEAKBITRATE, 32000, 160000000, 1},
.caps[10] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 6, 1},
.caps[11] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 2, 1},
.caps[12] = {HFI_CAPABILITY_LCU_SIZE, 16, 16, 1},
.caps[13] = {HFI_CAPABILITY_BFRAME, 0, 1, 1},
.caps[14] = {HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS, 0, 6, 1},
.caps[15] = {HFI_CAPABILITY_I_FRAME_QP, 0, 51, 1},
.caps[16] = {HFI_CAPABILITY_P_FRAME_QP, 0, 51, 1},
.caps[17] = {HFI_CAPABILITY_B_FRAME_QP, 0, 51, 1},
.caps[18] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 2, 1},
.caps[19] = {HFI_CAPABILITY_RATE_CONTROL_MODES, 0x1000001, 0x1000005, 1},
.caps[20] = {HFI_CAPABILITY_COLOR_SPACE_CONVERSION, 0, 2, 1},
.num_caps = 21,
.pl[0] = {HFI_H264_PROFILE_BASELINE, HFI_H264_LEVEL_52},
.pl[1] = {HFI_H264_PROFILE_MAIN, HFI_H264_LEVEL_52},
.pl[2] = {HFI_H264_PROFILE_HIGH, HFI_H264_LEVEL_52},
.pl[3] = {HFI_H264_PROFILE_CONSTRAINED_BASE, HFI_H264_LEVEL_52},
.pl[4] = {HFI_H264_PROFILE_CONSTRAINED_HIGH, HFI_H264_LEVEL_52},
.num_pl = 5,
.fmts[0] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12},
.fmts[1] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.fmts[3] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_P010},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_HEVC,
.domain = VIDC_SESSION_TYPE_ENC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 8192, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 8192, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 138240, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 160000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 8192, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 8192, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 7833600, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 960, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.caps[9] = {HFI_CAPABILITY_PEAKBITRATE, 32000, 160000000, 1},
.caps[10] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 5, 1},
.caps[11] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 2, 1},
.caps[12] = {HFI_CAPABILITY_LCU_SIZE, 32, 32, 1},
.caps[13] = {HFI_CAPABILITY_BFRAME, 0, 1, 1},
.caps[14] = {HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS, 0, 5, 1},
.caps[15] = {HFI_CAPABILITY_I_FRAME_QP, 0, 51, 1},
.caps[16] = {HFI_CAPABILITY_P_FRAME_QP, 0, 51, 1},
.caps[17] = {HFI_CAPABILITY_B_FRAME_QP, 0, 51, 1},
.caps[18] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 2, 1},
.caps[19] = {HFI_CAPABILITY_RATE_CONTROL_MODES, 0x1000001, 0x1000005, 1},
.caps[20] = {HFI_CAPABILITY_COLOR_SPACE_CONVERSION, 0, 2, 1},
.caps[21] = {HFI_CAPABILITY_ROTATION, 1, 4, 90},
.caps[22] = {HFI_CAPABILITY_BLUR_WIDTH, 96, 4096, 1},
.caps[23] = {HFI_CAPABILITY_BLUR_HEIGHT, 96, 4096, 1},
.num_caps = 24,
.pl[0] = {HFI_HEVC_PROFILE_MAIN, HFI_HEVC_LEVEL_6 | HFI_HEVC_TIER_HIGH0},
.pl[1] = {HFI_HEVC_PROFILE_MAIN10, HFI_HEVC_LEVEL_6 | HFI_HEVC_TIER_HIGH0},
.num_pl = 2,
.fmts[0] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12},
.fmts[1] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.fmts[3] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_P010},
.num_fmts = 4,
}, {
.codec = HFI_VIDEO_CODEC_VP8,
.domain = VIDC_SESSION_TYPE_ENC,
.cap_bufs_mode_dynamic = true,
.caps[0] = {HFI_CAPABILITY_FRAME_WIDTH, 128, 4096, 1},
.caps[1] = {HFI_CAPABILITY_FRAME_HEIGHT, 128, 4096, 1},
.caps[2] = {HFI_CAPABILITY_MBS_PER_FRAME, 64, 36864, 1},
.caps[3] = {HFI_CAPABILITY_BITRATE, 1, 74000000, 1},
.caps[4] = {HFI_CAPABILITY_SCALE_X, 8192, 65536, 1},
.caps[5] = {HFI_CAPABILITY_SCALE_Y, 8192, 65536, 1},
.caps[6] = {HFI_CAPABILITY_MBS_PER_SECOND, 64, 4423680, 1},
.caps[7] = {HFI_CAPABILITY_FRAMERATE, 1, 120, 1},
.caps[8] = {HFI_CAPABILITY_MAX_VIDEOCORES, 0, 1, 1},
.caps[9] = {HFI_CAPABILITY_PEAKBITRATE, 32000, 160000000, 1},
.caps[10] = {HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS, 0, 3, 1},
.caps[11] = {HFI_CAPABILITY_ENC_LTR_COUNT, 0, 2, 1},
.caps[12] = {HFI_CAPABILITY_LCU_SIZE, 16, 16, 1},
.caps[13] = {HFI_CAPABILITY_BFRAME, 0, 0, 1},
.caps[14] = {HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS, 0, 5, 1},
.caps[15] = {HFI_CAPABILITY_I_FRAME_QP, 0, 127, 1},
.caps[16] = {HFI_CAPABILITY_P_FRAME_QP, 0, 127, 1},
.caps[17] = {HFI_CAPABILITY_MAX_WORKMODES, 1, 2, 1},
.caps[18] = {HFI_CAPABILITY_RATE_CONTROL_MODES, 0x1000001, 0x1000005, 1},
.caps[19] = {HFI_CAPABILITY_BLUR_WIDTH, 96, 4096, 1},
.caps[20] = {HFI_CAPABILITY_BLUR_HEIGHT, 96, 4096, 1},
.caps[21] = {HFI_CAPABILITY_COLOR_SPACE_CONVERSION, 0, 2, 1},
.caps[22] = {HFI_CAPABILITY_ROTATION, 1, 4, 90},
.num_caps = 23,
.pl[0] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_0},
.pl[1] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_1},
.pl[2] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_2},
.pl[3] = {HFI_VPX_PROFILE_MAIN, HFI_VPX_LEVEL_VERSION_3},
.num_pl = 4,
.fmts[0] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12},
.fmts[1] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_NV12_UBWC},
.fmts[2] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_YUV420_TP10_UBWC},
.fmts[3] = {HFI_BUFFER_INPUT, HFI_COLOR_FORMAT_P010},
.num_fmts = 4,
} };
static const struct hfi_plat_caps *get_capabilities(struct venus_core *core,
unsigned int *entries)
{
if (is_lite(core))
return NULL;
*entries = ARRAY_SIZE(caps);
return caps;
}
static void get_codecs(struct venus_core *core, u32 *enc_codecs,
u32 *dec_codecs, u32 *count)
{
if (is_lite(core))
return;
*enc_codecs = HFI_VIDEO_CODEC_H264 | HFI_VIDEO_CODEC_HEVC |
HFI_VIDEO_CODEC_VP8;
*dec_codecs = HFI_VIDEO_CODEC_H264 | HFI_VIDEO_CODEC_HEVC |
HFI_VIDEO_CODEC_VP8 | HFI_VIDEO_CODEC_VP9 |
HFI_VIDEO_CODEC_MPEG2;
*count = 8;
}
static const struct hfi_platform_codec_freq_data codec_freq_data[] = {
{ V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_ENC, 675, 25, 320 },
{ V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_ENC, 675, 25, 320 },
{ V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_ENC, 675, 60, 320 },
{ V4L2_PIX_FMT_MPEG2, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
{ V4L2_PIX_FMT_H264, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
{ V4L2_PIX_FMT_HEVC, VIDC_SESSION_TYPE_DEC, 200, 25, 200 },
{ V4L2_PIX_FMT_VP8, VIDC_SESSION_TYPE_DEC, 200, 60, 200 },
{ V4L2_PIX_FMT_VP9, VIDC_SESSION_TYPE_DEC, 200, 60, 200 },
};
static const struct hfi_platform_codec_freq_data *
get_codec_freq_data(struct venus_core *core, u32 session_type, u32 pixfmt)
{
const struct hfi_platform_codec_freq_data *data = codec_freq_data;
unsigned int i, data_size = ARRAY_SIZE(codec_freq_data);
const struct hfi_platform_codec_freq_data *found = NULL;
if (is_lite(core))
return NULL;
for (i = 0; i < data_size; i++) {
if (data[i].pixfmt == pixfmt && data[i].session_type == session_type) {
found = &data[i];
break;
}
}
return found;
}
static unsigned long codec_vpp_freq(struct venus_core *core, u32 session_type,
u32 codec)
{
const struct hfi_platform_codec_freq_data *data;
data = get_codec_freq_data(core, session_type, codec);
if (data)
return data->vpp_freq;
return 0;
}
static unsigned long codec_vsp_freq(struct venus_core *core, u32 session_type,
u32 codec)
{
const struct hfi_platform_codec_freq_data *data;
data = get_codec_freq_data(core, session_type, codec);
if (data)
return data->vsp_freq;
return 0;
}
static unsigned long codec_lp_freq(struct venus_core *core, u32 session_type,
u32 codec)
{
const struct hfi_platform_codec_freq_data *data;
data = get_codec_freq_data(core, session_type, codec);
if (data)
return data->low_power_freq;
return 0;
}
const struct hfi_platform hfi_plat_v6 = {
.codec_vpp_freq = codec_vpp_freq,
.codec_vsp_freq = codec_vsp_freq,
.codec_lp_freq = codec_lp_freq,
.codecs = get_codecs,
.capabilities = get_capabilities,
.bufreq = hfi_plat_bufreq_v6,
};
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#ifndef __VENUS_HFI_VENUS_H__
#define __VENUS_HFI_VENUS_H__
struct venus_core;
void venus_hfi_destroy(struct venus_core *core);
int venus_hfi_create(struct venus_core *core);
void venus_hfi_queues_reinit(struct venus_core *core);
#endif
@@ -0,0 +1,164 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#ifndef __VENUS_HFI_VENUS_IO_H__
#define __VENUS_HFI_VENUS_IO_H__
#define VBIF_BASE 0x80000
#define VBIF_AXI_HALT_CTRL0 0x208
#define VBIF_AXI_HALT_CTRL1 0x20c
#define VBIF_AXI_HALT_CTRL0_HALT_REQ BIT(0)
#define VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0)
#define VBIF_AXI_HALT_ACK_TIMEOUT_US 500000
#define CPU_BASE 0xc0000
#define CPU_CS_BASE (CPU_BASE + 0x12000)
#define CPU_IC_BASE (CPU_BASE + 0x1f000)
#define CPU_BASE_V6 0xa0000
#define CPU_CS_BASE_V6 CPU_BASE_V6
#define CPU_IC_BASE_V6 (CPU_BASE_V6 + 0x138)
#define CPU_CS_A2HSOFTINTCLR 0x1c
#define VIDC_CTRL_INIT 0x48
#define VIDC_CTRL_INIT_RESERVED_BITS31_1_MASK 0xfffffffe
#define VIDC_CTRL_INIT_RESERVED_BITS31_1_SHIFT 1
#define VIDC_CTRL_INIT_CTRL_MASK 0x1
#define VIDC_CTRL_INIT_CTRL_SHIFT 0
/* HFI control status */
#define CPU_CS_SCIACMDARG0 0x4c
#define CPU_CS_SCIACMDARG0_MASK 0xff
#define CPU_CS_SCIACMDARG0_SHIFT 0x0
#define CPU_CS_SCIACMDARG0_ERROR_STATUS_MASK 0xfe
#define CPU_CS_SCIACMDARG0_ERROR_STATUS_SHIFT 0x1
#define CPU_CS_SCIACMDARG0_INIT_STATUS_MASK 0x1
#define CPU_CS_SCIACMDARG0_INIT_STATUS_SHIFT 0x0
#define CPU_CS_SCIACMDARG0_PC_READY BIT(8)
#define CPU_CS_SCIACMDARG0_INIT_IDLE_MSG_MASK BIT(30)
/* HFI queue table info */
#define CPU_CS_SCIACMDARG1 0x50
/* HFI queue table address */
#define CPU_CS_SCIACMDARG2 0x54
/* Venus cpu */
#define CPU_CS_SCIACMDARG3 0x58
#define CPU_CS_VCICMD 0x20
#define CPU_CS_VCICMD_ARP_OFF BIT(0)
#define SFR_ADDR 0x5c
#define MMAP_ADDR 0x60
#define UC_REGION_ADDR 0x64
#define UC_REGION_SIZE 0x68
#define CPU_CS_H2XSOFTINTEN_V6 0x148
#define CPU_CS_X2RPMH_V6 0x168
#define CPU_CS_X2RPMH_MASK0_BMSK_V6 0x1
#define CPU_CS_X2RPMH_MASK0_SHFT_V6 0x0
#define CPU_CS_X2RPMH_MASK1_BMSK_V6 0x2
#define CPU_CS_X2RPMH_MASK1_SHFT_V6 0x1
#define CPU_CS_X2RPMH_SWOVERRIDE_BMSK_V6 0x4
#define CPU_CS_X2RPMH_SWOVERRIDE_SHFT_V6 0x3
/* Relative to CPU_IC_BASE */
#define CPU_IC_SOFTINT 0x18
#define CPU_IC_SOFTINT_V6 0x150
#define CPU_IC_SOFTINT_H2A_MASK 0x8000
#define CPU_IC_SOFTINT_H2A_SHIFT 0xf
#define CPU_IC_SOFTINT_H2A_SHIFT_V6 0x0
/* Venus wrapper */
#define WRAPPER_BASE_V6 0x000b0000
#define WRAPPER_BASE 0x000e0000
#define WRAPPER_HW_VERSION 0x00
#define WRAPPER_HW_VERSION_MAJOR_VERSION_MASK 0x78000000
#define WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT 28
#define WRAPPER_HW_VERSION_MINOR_VERSION_MASK 0xfff0000
#define WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT 16
#define WRAPPER_HW_VERSION_STEP_VERSION_MASK 0xffff
#define WRAPPER_CLOCK_CONFIG 0x04
#define WRAPPER_INTR_STATUS 0x0c
#define WRAPPER_INTR_STATUS_A2HWD_MASK 0x10
#define WRAPPER_INTR_STATUS_A2HWD_SHIFT 0x4
#define WRAPPER_INTR_STATUS_A2H_MASK 0x4
#define WRAPPER_INTR_STATUS_A2H_SHIFT 0x2
#define WRAPPER_INTR_MASK 0x10
#define WRAPPER_INTR_MASK_A2HWD_BASK 0x10
#define WRAPPER_INTR_MASK_A2HWD_SHIFT 0x4
#define WRAPPER_INTR_MASK_A2HVCODEC_MASK 0x8
#define WRAPPER_INTR_MASK_A2HVCODEC_SHIFT 0x3
#define WRAPPER_INTR_MASK_A2HCPU_MASK 0x4
#define WRAPPER_INTR_MASK_A2HCPU_SHIFT 0x2
#define WRAPPER_INTR_STATUS_A2HWD_MASK_V4_LITE 0x10
#define WRAPPER_INTR_STATUS_A2HWD_MASK_V6 0x8
#define WRAPPER_INTR_MASK_A2HWD_BASK_V6 0x8
#define WRAPPER_INTR_CLEAR 0x14
#define WRAPPER_INTR_CLEAR_A2HWD_MASK 0x10
#define WRAPPER_INTR_CLEAR_A2HWD_SHIFT 0x4
#define WRAPPER_INTR_CLEAR_A2H_MASK 0x4
#define WRAPPER_INTR_CLEAR_A2H_SHIFT 0x2
#define WRAPPER_POWER_STATUS 0x44
#define WRAPPER_VDEC_VCODEC_POWER_CONTROL 0x48
#define WRAPPER_VENC_VCODEC_POWER_CONTROL 0x4c
#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_V6 0x54
#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS_V6 0x58
#define WRAPPER_VDEC_VENC_AHB_BRIDGE_SYNC_RESET 0x64
#define WRAPPER_CPU_CLOCK_CONFIG 0x2000
#define WRAPPER_CPU_AXI_HALT 0x2008
#define WRAPPER_CPU_AXI_HALT_HALT BIT(16)
#define WRAPPER_CPU_AXI_HALT_STATUS 0x200c
#define WRAPPER_CPU_AXI_HALT_STATUS_IDLE BIT(24)
#define WRAPPER_CPU_CGC_DIS 0x2010
#define WRAPPER_CPU_STATUS 0x2014
#define WRAPPER_CPU_STATUS_WFI BIT(0)
#define WRAPPER_SW_RESET 0x3000
#define WRAPPER_CPA_START_ADDR 0x1020
#define WRAPPER_CPA_END_ADDR 0x1024
#define WRAPPER_FW_START_ADDR 0x1028
#define WRAPPER_FW_END_ADDR 0x102C
#define WRAPPER_NONPIX_START_ADDR 0x1030
#define WRAPPER_NONPIX_END_ADDR 0x1034
#define WRAPPER_A9SS_SW_RESET 0x3000
#define WRAPPER_A9SS_SW_RESET_BIT BIT(4)
/* Venus 4xx */
#define WRAPPER_VCODEC0_MMCC_POWER_STATUS 0x90
#define WRAPPER_VCODEC0_MMCC_POWER_CONTROL 0x94
#define WRAPPER_VCODEC1_MMCC_POWER_STATUS 0x110
#define WRAPPER_VCODEC1_MMCC_POWER_CONTROL 0x114
/* Venus 6xx */
#define WRAPPER_CORE_POWER_STATUS_V6 0x80
#define WRAPPER_CORE_POWER_CONTROL_V6 0x84
/* Wrapper TZ 6xx */
#define WRAPPER_TZ_BASE_V6 0x000c0000
#define WRAPPER_TZ_CPU_STATUS_V6 0x10
#define WRAPPER_TZ_XTSS_SW_RESET 0x1000
#define WRAPPER_XTSS_SW_RESET_BIT BIT(0)
/* Venus AON */
#define AON_BASE_V6 0x000e0000
#define AON_WRAPPER_MVP_NOC_LPI_CONTROL 0x00
#define AON_WRAPPER_MVP_NOC_LPI_STATUS 0x04
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,66 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2019 Linaro Ltd. */
#ifndef __VENUS_PM_HELPERS_H__
#define __VENUS_PM_HELPERS_H__
struct device;
struct venus_core;
#define POWER_ON 1
#define POWER_OFF 0
struct venus_pm_ops {
int (*core_get)(struct venus_core *core);
void (*core_put)(struct venus_core *core);
int (*core_power)(struct venus_core *core, int on);
int (*vdec_get)(struct device *dev);
void (*vdec_put)(struct device *dev);
int (*vdec_power)(struct device *dev, int on);
int (*venc_get)(struct device *dev);
void (*venc_put)(struct device *dev);
int (*venc_power)(struct device *dev, int on);
int (*coreid_power)(struct venus_inst *inst, int on);
int (*load_scale)(struct venus_inst *inst);
};
const struct venus_pm_ops *venus_pm_get(enum hfi_version version);
static inline int venus_pm_load_scale(struct venus_inst *inst)
{
struct venus_core *core = inst->core;
if (!core->pm_ops || !core->pm_ops->load_scale)
return 0;
return core->pm_ops->load_scale(inst);
}
static inline int venus_pm_acquire_core(struct venus_inst *inst)
{
struct venus_core *core = inst->core;
const struct venus_pm_ops *pm_ops = core->pm_ops;
int ret = 0;
if (pm_ops && pm_ops->coreid_power)
ret = pm_ops->coreid_power(inst, POWER_ON);
return ret;
}
static inline int venus_pm_release_core(struct venus_inst *inst)
{
struct venus_core *core = inst->core;
const struct venus_pm_ops *pm_ops = core->pm_ops;
int ret = 0;
if (pm_ops && pm_ops->coreid_power)
ret = pm_ops->coreid_power(inst, POWER_OFF);
return ret;
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#ifndef __VENUS_VDEC_H__
#define __VENUS_VDEC_H__
struct venus_inst;
int vdec_ctrl_init(struct venus_inst *inst);
#endif
@@ -0,0 +1,189 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#include <linux/types.h>
#include <media/v4l2-ctrls.h>
#include "core.h"
#include "helpers.h"
#include "vdec.h"
static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct venus_inst *inst = ctrl_to_inst(ctrl);
struct vdec_controls *ctr = &inst->controls.dec;
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
ctr->post_loop_deb_mode = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
ctr->profile = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
ctr->level = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY:
ctr->display_delay = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:
ctr->display_delay_enable = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR:
ctr->conceal_color = *ctrl->p_new.p_s64;
break;
default:
return -EINVAL;
}
return 0;
}
static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
struct venus_inst *inst = ctrl_to_inst(ctrl);
struct vdec_controls *ctr = &inst->controls.dec;
struct hfi_buffer_requirements bufreq;
enum hfi_version ver = inst->core->res->hfi_version;
u32 profile, level;
int ret;
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
ret = venus_helper_get_profile_level(inst, &profile, &level);
if (!ret)
ctr->profile = profile;
ctrl->val = ctr->profile;
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
ret = venus_helper_get_profile_level(inst, &profile, &level);
if (!ret)
ctr->level = level;
ctrl->val = ctr->level;
break;
case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
ctrl->val = ctr->post_loop_deb_mode;
break;
case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE:
ret = venus_helper_get_bufreq(inst, HFI_BUFFER_OUTPUT, &bufreq);
if (!ret)
ctrl->val = hfi_bufreq_get_count_min(&bufreq, ver);
break;
default:
return -EINVAL;
}
return 0;
}
static const struct v4l2_ctrl_ops vdec_ctrl_ops = {
.s_ctrl = vdec_op_s_ctrl,
.g_volatile_ctrl = vdec_op_g_volatile_ctrl,
};
int vdec_ctrl_init(struct venus_inst *inst)
{
struct v4l2_ctrl *ctrl;
int ret;
ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 12);
if (ret)
return ret;
ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY,
~((1 << V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE) |
(1 << V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE)),
V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
0, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH)),
V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_LEVEL,
V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
0, V4L2_MPEG_VIDEO_H264_LEVEL_1_0);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_VP8_PROFILE,
V4L2_MPEG_VIDEO_VP8_PROFILE_3,
0, V4L2_MPEG_VIDEO_VP8_PROFILE_0);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
V4L2_MPEG_VIDEO_VP9_PROFILE_3,
0, V4L2_MPEG_VIDEO_VP9_PROFILE_0);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_VP9_LEVEL,
V4L2_MPEG_VIDEO_VP9_LEVEL_6_2,
0, V4L2_MPEG_VIDEO_VP9_LEVEL_1_0);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, 0, 1, 1, 0);
ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 32, 1, 1);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY,
0, 16383, 1, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE,
0, 1, 1, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_DEC_CONCEAL_COLOR, 0,
0xffffffffffffLL, 1, 0x8000800010LL);
ret = inst->ctrl_handler.error;
if (ret) {
v4l2_ctrl_handler_free(&inst->ctrl_handler);
return ret;
}
return 0;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#ifndef __VENUS_VENC_H__
#define __VENUS_VENC_H__
struct venus_inst;
int venc_ctrl_init(struct venus_inst *inst);
#endif
@@ -0,0 +1,740 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
* Copyright (C) 2017 Linaro Ltd.
*/
#include <linux/types.h>
#include <media/v4l2-ctrls.h>
#include "core.h"
#include "venc.h"
#include "helpers.h"
#define BITRATE_MIN 32000
#define BITRATE_MAX 160000000
#define BITRATE_DEFAULT 1000000
#define BITRATE_DEFAULT_PEAK (BITRATE_DEFAULT * 2)
#define BITRATE_STEP 100
#define SLICE_BYTE_SIZE_MAX 1024
#define SLICE_BYTE_SIZE_MIN 1024
#define SLICE_MB_SIZE_MAX 300
#define AT_SLICE_BOUNDARY \
V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY
#define MAX_LTR_FRAME_COUNT 4
static int venc_calc_bpframes(u32 gop_size, u32 conseq_b, u32 *bf, u32 *pf)
{
u32 half = (gop_size - 1) >> 1;
u32 b, p, ratio;
bool found = false;
if (!gop_size)
return -EINVAL;
*bf = *pf = 0;
if (!conseq_b) {
*pf = gop_size - 1;
return 0;
}
b = p = half;
for (; b <= gop_size - 1; b++, p--) {
if (b % p)
continue;
ratio = b / p;
if (ratio == conseq_b) {
found = true;
break;
}
if (ratio > conseq_b)
break;
}
if (!found)
return -EINVAL;
if (b + p + 1 != gop_size)
return -EINVAL;
*bf = b;
*pf = p;
return 0;
}
static int dynamic_bitrate_update(struct venus_inst *inst, u32 bitrate,
u32 layer_id)
{
int ret = 0;
mutex_lock(&inst->lock);
if (inst->streamon_out && inst->streamon_cap) {
u32 ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
struct hfi_bitrate brate = { .bitrate = bitrate, .layer_id = layer_id };
ret = hfi_session_set_property(inst, ptype, &brate);
}
mutex_unlock(&inst->lock);
return ret;
}
static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct venus_inst *inst = ctrl_to_inst(ctrl);
struct venc_controls *ctr = &inst->controls.enc;
struct hfi_enable en = { .enable = 1 };
struct hfi_ltr_use ltr_use;
struct hfi_ltr_mark ltr_mark;
u32 bframes;
u32 ptype;
int ret;
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
ctr->bitrate_mode = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
ctr->bitrate = ctrl->val;
ret = dynamic_bitrate_update(inst, ctr->bitrate, 0);
if (ret)
return ret;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
ctr->bitrate_peak = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
ctr->h264_entropy_mode = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
ctr->profile.mpeg4 = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
ctr->profile.h264 = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
ctr->profile.hevc = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
ctr->profile.vp8 = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
ctr->level.mpeg4 = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
ctr->level.h264 = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
ctr->level.hevc = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
ctr->h264_i_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
ctr->h264_p_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP:
ctr->h264_b_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
ctr->h264_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP:
ctr->h264_i_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP:
ctr->h264_p_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP:
ctr->h264_b_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
ctr->h264_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP:
ctr->h264_i_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP:
ctr->h264_p_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP:
ctr->h264_b_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP:
ctr->hevc_i_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP:
ctr->hevc_p_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP:
ctr->hevc_b_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP:
ctr->hevc_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP:
ctr->hevc_i_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP:
ctr->hevc_p_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP:
ctr->hevc_b_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP:
ctr->hevc_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP:
ctr->hevc_i_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP:
ctr->hevc_p_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP:
ctr->hevc_b_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
ctr->multi_slice_mode = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES:
ctr->multi_slice_max_bytes = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
ctr->multi_slice_max_mb = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
ctr->h264_loop_filter_alpha = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
ctr->h264_loop_filter_beta = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
ctr->h264_loop_filter_mode = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
ctr->header_mode = ctrl->val;
mutex_lock(&inst->lock);
if (inst->streamon_out && inst->streamon_cap) {
if (ctrl->val == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE)
en.enable = 0;
else
en.enable = 1;
ptype = HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER;
ret = hfi_session_set_property(inst, ptype, &en);
if (ret) {
mutex_unlock(&inst->lock);
return ret;
}
}
mutex_unlock(&inst->lock);
break;
case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
ret = venc_calc_bpframes(ctrl->val, ctr->num_b_frames, &bframes,
&ctr->num_p_frames);
if (ret)
return ret;
ctr->gop_size = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_I_PERIOD:
ctr->h264_i_period = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP:
ctr->vp8_min_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP:
ctr->vp8_max_qp = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_B_FRAMES:
ret = venc_calc_bpframes(ctr->gop_size, ctrl->val, &bframes,
&ctr->num_p_frames);
if (ret)
return ret;
ctr->num_b_frames = bframes;
break;
case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME:
mutex_lock(&inst->lock);
if (inst->streamon_out && inst->streamon_cap) {
ptype = HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME;
ret = hfi_session_set_property(inst, ptype, &en);
if (ret) {
mutex_unlock(&inst->lock);
return ret;
}
}
mutex_unlock(&inst->lock);
break;
case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
ctr->rc_enable = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY:
ctr->const_quality = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
ctr->frame_skip_mode = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID:
ctr->base_priority_id = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_AU_DELIMITER:
ctr->aud_enable = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_LTR_COUNT:
ctr->ltr_count = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX:
mutex_lock(&inst->lock);
if (inst->streamon_out && inst->streamon_cap) {
ptype = HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME;
ltr_mark.mark_frame = ctrl->val;
ret = hfi_session_set_property(inst, ptype, &ltr_mark);
if (ret) {
mutex_unlock(&inst->lock);
return ret;
}
}
mutex_unlock(&inst->lock);
break;
case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES:
mutex_lock(&inst->lock);
if (inst->streamon_out && inst->streamon_cap) {
ptype = HFI_PROPERTY_CONFIG_VENC_USELTRFRAME;
ltr_use.ref_ltr = ctrl->val;
ltr_use.use_constrnt = true;
ltr_use.frames = 0;
ret = hfi_session_set_property(inst, ptype, &ltr_use);
if (ret) {
mutex_unlock(&inst->lock);
return ret;
}
}
mutex_unlock(&inst->lock);
break;
case V4L2_CID_COLORIMETRY_HDR10_CLL_INFO:
ctr->cll = *ctrl->p_new.p_hdr10_cll;
break;
case V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY:
ctr->mastering = *ctrl->p_new.p_hdr10_mastering;
break;
case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE:
ctr->intra_refresh_type = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD:
ctr->intra_refresh_period = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM:
if (ctr->profile.h264 != V4L2_MPEG_VIDEO_H264_PROFILE_HIGH &&
ctr->profile.h264 != V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH)
return -EINVAL;
/*
* In video firmware, 8x8 transform is supported only for
* high profile(HP) and constrained high profile(CHP).
* If client wants to disable 8x8 transform for HP/CHP,
* it is better to set profile as main profile(MP).
* Because there is no difference between HP and MP
* if we disable 8x8 transform for HP.
*/
ctr->h264_8x8_transform = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE:
if (ctrl->val != V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P)
return -EINVAL;
break;
case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING:
ctr->layer_bitrate = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:
if (ctrl->val > VIDC_MAX_HIER_CODING_LAYER)
return -EINVAL;
ctr->h264_hier_layers = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR:
ctr->h264_hier_layer_bitrate[0] = ctrl->val;
ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[0], 0);
if (ret)
return ret;
break;
case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR:
ctr->h264_hier_layer_bitrate[1] = ctrl->val;
ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[1], 1);
if (ret)
return ret;
break;
case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR:
ctr->h264_hier_layer_bitrate[2] = ctrl->val;
ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[2], 2);
if (ret)
return ret;
break;
case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR:
ctr->h264_hier_layer_bitrate[3] = ctrl->val;
ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[3], 3);
if (ret)
return ret;
break;
case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR:
ctr->h264_hier_layer_bitrate[4] = ctrl->val;
ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[4], 4);
if (ret)
return ret;
break;
case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR:
ctr->h264_hier_layer_bitrate[5] = ctrl->val;
ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[5], 5);
if (ret)
return ret;
break;
default:
return -EINVAL;
}
return 0;
}
static int venc_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
struct venus_inst *inst = ctrl_to_inst(ctrl);
struct hfi_buffer_requirements bufreq;
enum hfi_version ver = inst->core->res->hfi_version;
int ret;
switch (ctrl->id) {
case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
ret = venus_helper_get_bufreq(inst, HFI_BUFFER_INPUT, &bufreq);
if (!ret)
ctrl->val = hfi_bufreq_get_count_min(&bufreq, ver);
break;
default:
return -EINVAL;
}
return 0;
}
static const struct v4l2_ctrl_ops venc_ctrl_ops = {
.s_ctrl = venc_op_s_ctrl,
.g_volatile_ctrl = venc_op_g_volatile_ctrl,
};
int venc_ctrl_init(struct venus_inst *inst)
{
int ret;
struct v4l2_ctrl_hdr10_mastering_display p_hdr10_mastering = {
{ 34000, 13250, 7500 },
{ 16000, 34500, 3000 }, 15635, 16450, 10000000, 500,
};
struct v4l2_ctrl_hdr10_cll_info p_hdr10_cll = { 1000, 400 };
ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 59);
if (ret)
return ret;
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
~((1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) |
(1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)),
V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE,
V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC,
0, V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY,
~((1 << V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE) |
(1 << V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE)),
V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
V4L2_MPEG_VIDEO_MPEG4_LEVEL_5,
0, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10,
~((1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) |
(1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) |
(1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10)),
V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2,
0, V4L2_MPEG_VIDEO_HEVC_LEVEL_1);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH,
~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH)),
V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_LEVEL,
V4L2_MPEG_VIDEO_H264_LEVEL_5_1,
0, V4L2_MPEG_VIDEO_H264_LEVEL_1_0);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
AT_SLICE_BOUNDARY,
0, V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEADER_MODE,
V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
~((1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) |
(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME)),
V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES,
0, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_VP8_PROFILE,
V4L2_MPEG_VIDEO_VP8_PROFILE_3,
0, V4L2_MPEG_VIDEO_VP8_PROFILE_0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 4, 11, 1, 4);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_BITRATE, BITRATE_MIN, BITRATE_MAX,
BITRATE_STEP, BITRATE_DEFAULT);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, BITRATE_MIN, BITRATE_MAX,
BITRATE_STEP, BITRATE_DEFAULT_PEAK);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 1, 51, 1, 26);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 1, 51, 1, 28);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, 1, 51, 1, 30);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 1, 51, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP, 1, 51, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, 0, 1, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP, 1, 51, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MIN_QP, 1, 51, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 1, 51, 1, 51);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP, 1, 51, 1, 51);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP, 1, 51, 1, 51);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_B_FRAME_MAX_QP, 1, 51, 1, 51);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_QP, 1, 63, 1, 26);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_QP, 1, 63, 1, 28);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_QP, 1, 63, 1, 30);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_MIN_QP, 1, 63, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MIN_QP, 1, 63, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MIN_QP, 1, 63, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MIN_QP, 1, 63, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_MAX_QP, 1, 63, 1, 63);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_I_FRAME_MAX_QP, 1, 63, 1, 63);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_P_FRAME_MAX_QP, 1, 63, 1, 63);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_HEVC_B_FRAME_MAX_QP, 1, 63, 1, 63);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, SLICE_BYTE_SIZE_MIN,
SLICE_BYTE_SIZE_MAX, 1, SLICE_BYTE_SIZE_MIN);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1,
SLICE_MB_SIZE_MAX, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, -6, 6, 1, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, -6, 6, 1, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, (1 << 16) - 1, 1, 30);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_VPX_MIN_QP, 1, 128, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_VPX_MAX_QP, 1, 128, 1, 128);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 4, 1, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, 0, (1 << 16) - 1, 1, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME, 0, 0, 0, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, 0, 1, 1, 1);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, 0, 100, 1, 0);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE,
V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
~((1 << V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) |
(1 << V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT)),
V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID, 0,
6, 1, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_AU_DELIMITER, 0, 1, 1, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES, 0,
((1 << MAX_LTR_FRAME_COUNT) - 1), 0, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_LTR_COUNT, 0,
MAX_LTR_FRAME_COUNT, 1, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX, 0,
(MAX_LTR_FRAME_COUNT - 1), 1, 0);
v4l2_ctrl_new_std_compound(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_COLORIMETRY_HDR10_CLL_INFO,
v4l2_ctrl_ptr_create(&p_hdr10_cll),
v4l2_ctrl_ptr_create(NULL),
v4l2_ctrl_ptr_create(NULL));
v4l2_ctrl_new_std_compound(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_COLORIMETRY_HDR10_MASTERING_DISPLAY,
v4l2_ctrl_ptr_create((void *)&p_hdr10_mastering),
v4l2_ctrl_ptr_create(NULL),
v4l2_ctrl_ptr_create(NULL));
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE,
V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_CYCLIC,
0, V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD_TYPE_RANDOM);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, 0,
((4096 * 2304) >> 8), 1, 0);
if (IS_V4(inst->core) || IS_V6(inst->core)) {
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE,
V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
1, V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, 0, 1, 1, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, 0,
VIDC_MAX_HIER_CODING_LAYER, 1, 0);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR,
BITRATE_MIN, BITRATE_MAX, BITRATE_STEP, BITRATE_DEFAULT);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR,
BITRATE_MIN, BITRATE_MAX,
BITRATE_STEP, BITRATE_DEFAULT);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR,
BITRATE_MIN, BITRATE_MAX,
BITRATE_STEP, BITRATE_DEFAULT);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR,
BITRATE_MIN, BITRATE_MAX,
BITRATE_STEP, BITRATE_DEFAULT);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR,
BITRATE_MIN, BITRATE_MAX,
BITRATE_STEP, BITRATE_DEFAULT);
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR,
BITRATE_MIN, BITRATE_MAX,
BITRATE_STEP, BITRATE_DEFAULT);
}
ret = inst->ctrl_handler.error;
if (ret)
goto err;
ret = v4l2_ctrl_handler_setup(&inst->ctrl_handler);
if (ret)
goto err;
return 0;
err:
v4l2_ctrl_handler_free(&inst->ctrl_handler);
return ret;
}