From: Stanimir Varbanov Date: Mon, 17 Aug 2015 12:38:23 +0000 (+0300) Subject: media: vidc: Qualcomm video encoder/decoder driver X-Git-Tag: KARO-TXSD-2017-03-24~88^2~49^2~2 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=1d0f7e887d1b0b0ae59b4e4e29af3bedc6ee680a;p=karo-tx-linux.git media: vidc: Qualcomm video encoder/decoder driver add venus video encoder/decoder driver. Signed-off-by: Stanimir Varbanov --- diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index ccbc9742cb7a..eb349cf4f114 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -119,6 +119,7 @@ source "drivers/media/platform/exynos4-is/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" source "drivers/media/platform/am437x/Kconfig" source "drivers/media/platform/xilinx/Kconfig" +source "drivers/media/platform/msm/Kconfig" endif # V4L_PLATFORM_DRIVERS diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index efa0295af87b..722f18b4e3e4 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -55,3 +55,5 @@ obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ obj-$(CONFIG_VIDEO_XILINX) += xilinx/ ccflags-y += -I$(srctree)/drivers/media/i2c + +obj-y += msm/ diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig new file mode 100644 index 000000000000..4f55c85d6025 --- /dev/null +++ b/drivers/media/platform/msm/Kconfig @@ -0,0 +1,7 @@ +# +# MSM camera configuration +# + +comment "Qualcomm MSM Camera And Video" + +source "drivers/media/platform/msm/vidc/Kconfig" diff --git a/drivers/media/platform/msm/Makefile b/drivers/media/platform/msm/Makefile new file mode 100644 index 000000000000..ef7d98790a8e --- /dev/null +++ b/drivers/media/platform/msm/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the QCOM spcific video device drivers +# based on V4L2. +# + +obj-$(CONFIG_MSM_VIDC_V4L2) += vidc/ diff --git a/drivers/media/platform/msm/vidc/Kconfig b/drivers/media/platform/msm/vidc/Kconfig new file mode 100644 index 000000000000..da3e8bf7f0ea --- /dev/null +++ b/drivers/media/platform/msm/vidc/Kconfig @@ -0,0 +1,9 @@ +# +# VIDEO CORE +# + +menuconfig MSM_VIDC_V4L2 + tristate "Qualcomm MSM V4L2 based video driver" + depends on ARCH_QCOM && VIDEO_V4L2 + select ARM64_DMA_USE_IOMMU + select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/media/platform/msm/vidc/Makefile b/drivers/media/platform/msm/vidc/Makefile new file mode 100644 index 000000000000..a333e291c97b --- /dev/null +++ b/drivers/media/platform/msm/vidc/Makefile @@ -0,0 +1,21 @@ +# Makefile for Qualcomm vidc driver + +ccflags-y += -Idrivers/media/platform/msm/vidc +vidc-objs += \ + msm_v4l2_vidc.o \ + msm_internal-buffers.o \ + msm_vidc_common.o \ + msm_vdec.o \ + msm_vdec-ctrls.o \ + msm_venc.o \ + msm_venc-ctrls.o \ + msm_smem.o \ + msm_vidc_debug.o \ + msm_vidc_resources.o \ + msm_vidc_load.o \ + hfi/venus/venus_hfi.o \ + hfi/hfi_response_handler.o \ + hfi/hfi_packetization.o \ + hfi/vidc_hfi.o \ + +obj-$(CONFIG_MSM_VIDC_V4L2) += vidc.o diff --git a/drivers/media/platform/msm/vidc/hfi/hfi_packetization.c b/drivers/media/platform/msm/vidc/hfi/hfi_packetization.c new file mode 100644 index 000000000000..7c6d12383b95 --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi/hfi_packetization.c @@ -0,0 +1,1799 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include + +#include "hfi_packetization.h" +#include "msm_vidc_debug.h" + +/* + * Set up look-up tables to convert HAL_* to HFI_*. + * The tables below mostly take advantage of the fact that most + * HAL_* types are defined bitwise. So if we index them normally + * when declaring the tables, we end up with huge arrays with wasted + * space. So before indexing them, we apply log2 to use a more + * sensible index. + */ +static int profile_table[] = { + [ilog2(HAL_H264_PROFILE_BASELINE)] = HFI_H264_PROFILE_BASELINE, + [ilog2(HAL_H264_PROFILE_MAIN)] = HFI_H264_PROFILE_MAIN, + [ilog2(HAL_H264_PROFILE_HIGH)] = HFI_H264_PROFILE_HIGH, + [ilog2(HAL_H264_PROFILE_CONSTRAINED_BASE)] = + HFI_H264_PROFILE_CONSTRAINED_BASE, + [ilog2(HAL_H264_PROFILE_CONSTRAINED_HIGH)] = + HFI_H264_PROFILE_CONSTRAINED_HIGH, + [ilog2(HAL_VPX_PROFILE_VERSION_1)] = HFI_VPX_PROFILE_VERSION_1, + [ilog2(HAL_MVC_PROFILE_STEREO_HIGH)] = HFI_H264_PROFILE_STEREO_HIGH, +}; + +static int entropy_mode[] = { + [ilog2(HAL_H264_ENTROPY_CAVLC)] = HFI_H264_ENTROPY_CAVLC, + [ilog2(HAL_H264_ENTROPY_CABAC)] = HFI_H264_ENTROPY_CABAC, +}; + +static int cabac_model[] = { + [ilog2(HAL_H264_CABAC_MODEL_0)] = HFI_H264_CABAC_MODEL_0, + [ilog2(HAL_H264_CABAC_MODEL_1)] = HFI_H264_CABAC_MODEL_1, + [ilog2(HAL_H264_CABAC_MODEL_2)] = HFI_H264_CABAC_MODEL_2, +}; + +static int color_format[] = { + [ilog2(HAL_COLOR_FORMAT_MONOCHROME)] = HFI_COLOR_FORMAT_MONOCHROME, + [ilog2(HAL_COLOR_FORMAT_NV12)] = HFI_COLOR_FORMAT_NV12, + [ilog2(HAL_COLOR_FORMAT_NV21)] = HFI_COLOR_FORMAT_NV21, + [ilog2(HAL_COLOR_FORMAT_NV12_4x4TILE)] = HFI_COLOR_FORMAT_NV12_4x4TILE, + [ilog2(HAL_COLOR_FORMAT_NV21_4x4TILE)] = HFI_COLOR_FORMAT_NV21_4x4TILE, + [ilog2(HAL_COLOR_FORMAT_YUYV)] = HFI_COLOR_FORMAT_YUYV, + [ilog2(HAL_COLOR_FORMAT_YVYU)] = HFI_COLOR_FORMAT_YVYU, + [ilog2(HAL_COLOR_FORMAT_UYVY)] = HFI_COLOR_FORMAT_UYVY, + [ilog2(HAL_COLOR_FORMAT_VYUY)] = HFI_COLOR_FORMAT_VYUY, + [ilog2(HAL_COLOR_FORMAT_RGB565)] = HFI_COLOR_FORMAT_RGB565, + [ilog2(HAL_COLOR_FORMAT_BGR565)] = HFI_COLOR_FORMAT_BGR565, + [ilog2(HAL_COLOR_FORMAT_RGB888)] = HFI_COLOR_FORMAT_RGB888, + [ilog2(HAL_COLOR_FORMAT_BGR888)] = HFI_COLOR_FORMAT_BGR888, + /* UBWC Color formats*/ + [ilog2(HAL_COLOR_FORMAT_NV12_UBWC)] = HFI_COLOR_FORMAT_NV12_UBWC, + [ilog2(HAL_COLOR_FORMAT_NV12_TP10_UBWC)] = + HFI_COLOR_FORMAT_YUV420_TP10_UBWC, +}; + +static int nal_type[] = { + [ilog2(HAL_NAL_FORMAT_STARTCODES)] = HFI_NAL_FORMAT_STARTCODES, + [ilog2(HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER)] = + HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER, + [ilog2(HAL_NAL_FORMAT_ONE_BYTE_LENGTH)] = + HFI_NAL_FORMAT_ONE_BYTE_LENGTH, + [ilog2(HAL_NAL_FORMAT_TWO_BYTE_LENGTH)] = + HFI_NAL_FORMAT_TWO_BYTE_LENGTH, + [ilog2(HAL_NAL_FORMAT_FOUR_BYTE_LENGTH)] = + HFI_NAL_FORMAT_FOUR_BYTE_LENGTH, +}; + +static inline int to_hfi_type(int property, int hal_type) +{ + if (hal_type && roundup_pow_of_two(hal_type) != hal_type) { + /* Not a power of 2, it's not going + * to be in any of the tables anyway */ + return -EINVAL; + } + + if (hal_type) + hal_type = ilog2(hal_type); + + switch (property) { + case HAL_PARAM_PROFILE_LEVEL_CURRENT: + return (hal_type >= ARRAY_SIZE(profile_table)) ? + -ENOTSUPP : profile_table[hal_type]; + case HAL_PARAM_VENC_H264_ENTROPY_CONTROL: + return (hal_type >= ARRAY_SIZE(entropy_mode)) ? + -ENOTSUPP : entropy_mode[hal_type]; + case HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL: + return (hal_type >= ARRAY_SIZE(cabac_model)) ? + -ENOTSUPP : cabac_model[hal_type]; + case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT: + return (hal_type >= ARRAY_SIZE(color_format)) ? + -ENOTSUPP : color_format[hal_type]; + case HAL_PARAM_NAL_STREAM_FORMAT_SELECT: + return (hal_type >= ARRAY_SIZE(nal_type)) ? + -ENOTSUPP : nal_type[hal_type]; + default: + return -ENOTSUPP; + } +} + +static inline u32 to_hfi_layout(enum hal_buffer_layout_type hal_buf_layout) +{ + switch (hal_buf_layout) { + case HAL_BUFFER_LAYOUT_TOP_BOTTOM: + return HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM; + case HAL_BUFFER_LAYOUT_SEQ: + return HFI_MVC_BUFFER_LAYOUT_SEQ; + default: + dprintk(VIDC_ERR, "Invalid buffer layout: %#x\n", + hal_buf_layout); + return HFI_MVC_BUFFER_LAYOUT_SEQ; + } + + return 0; +} + +static inline u32 to_hfi_codec(enum hal_video_codec hal_codec) +{ + switch (hal_codec) { + case HAL_VIDEO_CODEC_MVC: + case HAL_VIDEO_CODEC_H264: + return HFI_VIDEO_CODEC_H264; + case HAL_VIDEO_CODEC_H263: + return HFI_VIDEO_CODEC_H263; + case HAL_VIDEO_CODEC_MPEG1: + return HFI_VIDEO_CODEC_MPEG1; + case HAL_VIDEO_CODEC_MPEG2: + return HFI_VIDEO_CODEC_MPEG2; + case HAL_VIDEO_CODEC_MPEG4: + return HFI_VIDEO_CODEC_MPEG4; + case HAL_VIDEO_CODEC_DIVX_311: + return HFI_VIDEO_CODEC_DIVX_311; + case HAL_VIDEO_CODEC_DIVX: + return HFI_VIDEO_CODEC_DIVX; + case HAL_VIDEO_CODEC_VC1: + return HFI_VIDEO_CODEC_VC1; + case HAL_VIDEO_CODEC_SPARK: + return HFI_VIDEO_CODEC_SPARK; + case HAL_VIDEO_CODEC_VP8: + return HFI_VIDEO_CODEC_VP8; + case HAL_VIDEO_CODEC_HEVC: + return HFI_VIDEO_CODEC_HEVC; + case HAL_VIDEO_CODEC_HEVC_HYBRID: + return HFI_VIDEO_CODEC_HEVC_HYBRID; + default: + dprintk(VIDC_ERR, "Invalid codec %#x\n", hal_codec); + break; + } + + return 0; +} + +static int pkt_sys_init(struct hfi_sys_init_pkt *pkt, u32 arch_type) +{ + pkt->packet_type = HFI_CMD_SYS_INIT; + pkt->size = sizeof(*pkt); + pkt->arch_type = arch_type; + + return 0; +} + +static int pkt_sys_pc_prep(struct hfi_sys_pc_prep_pkt *pkt) +{ + pkt->packet_type = HFI_CMD_SYS_PC_PREP; + pkt->size = sizeof(*pkt); + + return 0; +} + +static int pkt_sys_idle_indicator(struct hfi_sys_set_property_pkt *pkt, + u32 enable) +{ + struct hfi_enable *hfi; + + pkt->size = sizeof(*pkt) + sizeof(struct hfi_enable) + sizeof(u32); + pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IDLE_INDICATOR; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = enable; + + return 0; +} + +static int pkt_sys_debug_config(struct hfi_sys_set_property_pkt *pkt, + u32 mode) +{ + struct hfi_debug_config *hfi; + + pkt->size = sizeof(*pkt) + sizeof(struct hfi_debug_config) + + sizeof(u32); + pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_SYS_DEBUG_CONFIG; + hfi = (struct hfi_debug_config *) &pkt->rg_property_data[1]; + hfi->debug_config = mode; + hfi->debug_mode = HFI_DEBUG_MODE_QUEUE; + + if (vidc_fw_debug_mode <= HFI_DEBUG_MODE_QDSS) + hfi->debug_mode = vidc_fw_debug_mode; + + return 0; +} + +static int pkt_sys_coverage_config(struct hfi_sys_set_property_pkt *pkt, + u32 mode) +{ + pkt->size = sizeof(*pkt) + sizeof(u32); + pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_SYS_CONFIG_COVERAGE; + pkt->rg_property_data[1] = mode; + + dprintk(VIDC_DBG, "Firmware coverage mode %d\n", + pkt->rg_property_data[1]); + + return 0; +} + +static int pkt_sys_set_resource(struct hfi_sys_set_resource_pkt *pkt, + struct vidc_resource_hdr *resource_hdr, + void *resource_value) +{ + if (!pkt || !resource_hdr || !resource_value) + return -EINVAL; + + pkt->packet_type = HFI_CMD_SYS_SET_RESOURCE; + pkt->size = sizeof(*pkt); + pkt->resource_handle = hash32_ptr(resource_hdr->resource_handle); + + switch (resource_hdr->resource_id) { + case VIDC_RESOURCE_OCMEM: + case VIDC_RESOURCE_VMEM: { + struct hfi_resource_ocmem *hfioc_mem = + (struct hfi_resource_ocmem *) &pkt->rg_resource_data[0]; + phys_addr_t imem_addr = (phys_addr_t)resource_value; + + pkt->resource_type = HFI_RESOURCE_OCMEM; + pkt->size += sizeof(struct hfi_resource_ocmem) - sizeof(u32); + hfioc_mem->size = (u32)resource_hdr->size; + hfioc_mem->mem = imem_addr; + break; + } + default: + return -ENOTSUPP; + } + + return 0; +} + +static int +pkt_sys_release_resource(struct hfi_sys_release_resource_pkt *pkt, + struct vidc_resource_hdr *resource_hdr) +{ + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SYS_RELEASE_RESOURCE; + pkt->resource_handle = hash32_ptr(resource_hdr->resource_handle); + + switch (resource_hdr->resource_id) { + case VIDC_RESOURCE_OCMEM: + case VIDC_RESOURCE_VMEM: + pkt->resource_type = HFI_RESOURCE_OCMEM; + break; + default: + return -ENOTSUPP; + } + + return 0; +} + +static int pkt_sys_ping(struct hfi_cmd_sys_ping_packet *pkt) +{ + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SYS_PING; + + return 0; +} + +static int pkt_session_init(struct hfi_session_init_pkt *pkt, + struct hal_session *session, + u32 session_domain, u32 session_codec) +{ + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SYS_SESSION_INIT; + pkt->session_id = hash32_ptr(session); + pkt->session_domain = session_domain; + pkt->session_codec = to_hfi_codec(session_codec); + + if (!pkt->session_codec) + return -EINVAL; + + return 0; +} + +static int pkt_session_cmd(struct vidc_hal_session_cmd_pkt *pkt, + int pkt_type, struct hal_session *session) +{ + pkt->size = sizeof(struct vidc_hal_session_cmd_pkt); + pkt->packet_type = pkt_type; + pkt->session_id = hash32_ptr(session); + + return 0; +} + +static int pkt_sys_power_control(struct hfi_sys_set_property_pkt *pkt, + u32 enable) +{ + struct hfi_enable *hfi; + + pkt->size = sizeof(*pkt) + sizeof(struct hfi_enable) + sizeof(u32); + pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = enable; + + return 0; +} + +static u32 to_hfi_buffer(int hal_buffer) +{ + switch (hal_buffer) { + case HAL_BUFFER_INPUT: + return HFI_BUFFER_INPUT; + case HAL_BUFFER_OUTPUT: + return HFI_BUFFER_OUTPUT; + case HAL_BUFFER_OUTPUT2: + return HFI_BUFFER_OUTPUT2; + case HAL_BUFFER_EXTRADATA_INPUT: + return HFI_BUFFER_EXTRADATA_INPUT; + case HAL_BUFFER_EXTRADATA_OUTPUT: + return HFI_BUFFER_EXTRADATA_OUTPUT; + case HAL_BUFFER_EXTRADATA_OUTPUT2: + return HFI_BUFFER_EXTRADATA_OUTPUT2; + case HAL_BUFFER_INTERNAL_SCRATCH: + return HFI_BUFFER_INTERNAL_SCRATCH; + case HAL_BUFFER_INTERNAL_SCRATCH_1: + return HFI_BUFFER_INTERNAL_SCRATCH_1; + case HAL_BUFFER_INTERNAL_SCRATCH_2: + return HFI_BUFFER_INTERNAL_SCRATCH_2; + case HAL_BUFFER_INTERNAL_PERSIST: + return HFI_BUFFER_INTERNAL_PERSIST; + case HAL_BUFFER_INTERNAL_PERSIST_1: + return HFI_BUFFER_INTERNAL_PERSIST_1; + default: + break; + } + + return HAL_BUFFER_NONE; +} + +static int to_hfi_extradata_index(enum hal_extradata_id index) +{ + switch (index) { + case HAL_EXTRADATA_MB_QUANTIZATION: + return HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION; + case HAL_EXTRADATA_INTERLACE_VIDEO: + return HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA; + case HAL_EXTRADATA_VC1_FRAMEDISP: + return HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA; + case HAL_EXTRADATA_VC1_SEQDISP: + return HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA; + case HAL_EXTRADATA_TIMESTAMP: + return HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA; + case HAL_EXTRADATA_S3D_FRAME_PACKING: + return HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA; + case HAL_EXTRADATA_FRAME_RATE: + return HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA; + case HAL_EXTRADATA_PANSCAN_WINDOW: + return HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA; + case HAL_EXTRADATA_RECOVERY_POINT_SEI: + return HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA; + case HAL_EXTRADATA_MULTISLICE_INFO: + return HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO; + case HAL_EXTRADATA_NUM_CONCEALED_MB: + return HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB; + case HAL_EXTRADATA_ASPECT_RATIO: + case HAL_EXTRADATA_INPUT_CROP: + case HAL_EXTRADATA_DIGITAL_ZOOM: + return HFI_PROPERTY_PARAM_INDEX_EXTRADATA; + case HAL_EXTRADATA_MPEG2_SEQDISP: + return HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA; + case HAL_EXTRADATA_STREAM_USERDATA: + return HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA; + case HAL_EXTRADATA_FRAME_QP: + return HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA; + case HAL_EXTRADATA_FRAME_BITS_INFO: + return HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA; + case HAL_EXTRADATA_LTR_INFO: + return HFI_PROPERTY_PARAM_VENC_LTR_INFO; + case HAL_EXTRADATA_METADATA_MBI: + return HFI_PROPERTY_PARAM_VENC_MBI_DUMPING; + default: + dprintk(VIDC_WARN, "extradata index not found:%d\n", index); + break; + } + + return 0; +} + +static int to_hfi_extradata_id(enum hal_extradata_id index) +{ + switch (index) { + case HAL_EXTRADATA_ASPECT_RATIO: + return VIDC_EXTRADATA_ASPECT_RATIO; + case HAL_EXTRADATA_INPUT_CROP: + return VIDC_EXTRADATA_INPUT_CROP; + case HAL_EXTRADATA_DIGITAL_ZOOM: + return VIDC_EXTRADATA_DIGITAL_ZOOM; + default: + return to_hfi_extradata_index(index); + } + + return 0; +} + +static u32 to_hfi_buf_mode(enum hal_buffer_mode_type hal_buf_mode) +{ + switch (hal_buf_mode) { + case HAL_BUFFER_MODE_STATIC: + return HFI_BUFFER_MODE_STATIC; + case HAL_BUFFER_MODE_RING: + return HFI_BUFFER_MODE_RING; + case HAL_BUFFER_MODE_DYNAMIC: + return HFI_BUFFER_MODE_DYNAMIC; + default: + dprintk(VIDC_ERR, "invalid buffer mode:%x\n", hal_buf_mode); + return 0; + } + + return 0; +} + +static u32 to_hfi_ltr_mode(enum ltr_mode ltr_mode_type) +{ + switch (ltr_mode_type) { + case HAL_LTR_MODE_DISABLE: + return HFI_LTR_MODE_DISABLE; + case HAL_LTR_MODE_MANUAL: + return HFI_LTR_MODE_MANUAL; + case HAL_LTR_MODE_PERIODIC: + return HFI_LTR_MODE_PERIODIC; + default: + dprintk(VIDC_ERR, "invalid ltr mode:%x\n", ltr_mode_type); + return HFI_LTR_MODE_DISABLE; + } + + return 0; +} + +static int +pkt_session_set_buffers(struct hfi_session_set_buffers_pkt *pkt, + struct hal_session *session, + struct vidc_buffer_addr_info *bai) +{ + int i; + + if (!session) + return -EINVAL; + + pkt->packet_type = HFI_CMD_SESSION_SET_BUFFERS; + pkt->session_id = hash32_ptr(session); + pkt->buffer_size = bai->buffer_size; + pkt->min_buffer_size = bai->buffer_size; + pkt->num_buffers = bai->num_buffers; + + if (bai->buffer_type == HAL_BUFFER_OUTPUT || + bai->buffer_type == HAL_BUFFER_OUTPUT2) { + struct hfi_buffer_info *bi; + + pkt->extra_data_size = bai->extradata_size; + pkt->size = sizeof(*pkt) - sizeof(u32) + + (bai->num_buffers * sizeof(struct hfi_buffer_info)); + bi = (struct hfi_buffer_info *) pkt->rg_buffer_info; + for (i = 0; i < pkt->num_buffers; i++) { + bi->buffer_addr = bai->device_addr; + bi->extra_data_addr = bai->extradata_addr; + } + } else { + pkt->extra_data_size = 0; + pkt->size = sizeof(*pkt) + + ((bai->num_buffers - 1) * sizeof(u32)); + for (i = 0; i < pkt->num_buffers; i++) + pkt->rg_buffer_info[i] = bai->device_addr; + } + + pkt->buffer_type = to_hfi_buffer(bai->buffer_type); + if (!pkt->buffer_type) + return -EINVAL; + + return 0; +} + +static int +pkt_session_release_buffers(struct hfi_cmd_session_release_buffer_packet *pkt, + struct hal_session *session, + struct vidc_buffer_addr_info *bai) +{ + int i; + + if (!session) + return -EINVAL; + + pkt->packet_type = HFI_CMD_SESSION_RELEASE_BUFFERS; + pkt->session_id = hash32_ptr(session); + pkt->buffer_size = bai->buffer_size; + pkt->num_buffers = bai->num_buffers; + + if (bai->buffer_type == HAL_BUFFER_OUTPUT || + bai->buffer_type == HAL_BUFFER_OUTPUT2) { + struct hfi_buffer_info *bi; + + bi = (struct hfi_buffer_info *) pkt->rg_buffer_info; + for (i = 0; i < pkt->num_buffers; i++) { + bi->buffer_addr = bai->device_addr; + bi->extra_data_addr = bai->extradata_addr; + } + pkt->size = sizeof(struct hfi_session_set_buffers_pkt) - + sizeof(u32) + + (bai->num_buffers * sizeof(struct hfi_buffer_info)); + } else { + for (i = 0; i < pkt->num_buffers; i++) + pkt->rg_buffer_info[i] = bai->device_addr; + + pkt->extra_data_size = 0; + pkt->size = sizeof(struct hfi_session_set_buffers_pkt) + + ((bai->num_buffers - 1) * sizeof(u32)); + } + + pkt->response_req = bai->response_required; + pkt->buffer_type = to_hfi_buffer(bai->buffer_type); + if (!pkt->buffer_type) + return -EINVAL; + + return 0; +} + +static int pkt_session_etb_decoder( + struct hfi_cmd_session_empty_buffer_compressed_packet *pkt, + struct hal_session *session, struct vidc_frame_data *in_frame) +{ + if (!session || !in_frame->device_addr) + return -EINVAL; + + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER; + pkt->session_id = hash32_ptr(session); + pkt->time_stamp_hi = upper_32_bits(in_frame->timestamp); + pkt->time_stamp_lo = lower_32_bits(in_frame->timestamp); + pkt->flags = in_frame->flags; + pkt->mark_target = in_frame->mark_target; + pkt->mark_data = in_frame->mark_data; + pkt->offset = in_frame->offset; + pkt->alloc_len = in_frame->alloc_len; + pkt->filled_len = in_frame->filled_len; + pkt->input_tag = in_frame->clnt_data; + pkt->packet_buffer = in_frame->device_addr; + + return 0; +} + +static int pkt_session_etb_encoder( + struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet *pkt, + struct hal_session *session, struct vidc_frame_data *in_frame) +{ + if (!session || !in_frame->device_addr) + return -EINVAL; + + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER; + pkt->session_id = hash32_ptr(session); + pkt->view_id = 0; + pkt->time_stamp_hi = upper_32_bits(in_frame->timestamp); + pkt->time_stamp_lo = lower_32_bits(in_frame->timestamp); + pkt->flags = in_frame->flags; + pkt->mark_target = in_frame->mark_target; + pkt->mark_data = in_frame->mark_data; + pkt->offset = in_frame->offset; + pkt->alloc_len = in_frame->alloc_len; + pkt->filled_len = in_frame->filled_len; + pkt->input_tag = in_frame->clnt_data; + pkt->packet_buffer = in_frame->device_addr; + pkt->extra_data_buffer = in_frame->extradata_addr; + + return 0; +} + +static int pkt_session_ftb(struct hfi_cmd_session_fill_buffer_packet *pkt, + struct hal_session *session, + struct vidc_frame_data *out_frame) +{ + if (!session || !out_frame || !out_frame->device_addr) + return -EINVAL; + + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SESSION_FILL_BUFFER; + pkt->session_id = hash32_ptr(session); + + if (out_frame->buffer_type == HAL_BUFFER_OUTPUT) + pkt->stream_id = 0; + else if (out_frame->buffer_type == HAL_BUFFER_OUTPUT2) + pkt->stream_id = 1; + + pkt->packet_buffer = out_frame->device_addr; + pkt->extra_data_buffer = out_frame->extradata_addr; + pkt->alloc_len = out_frame->alloc_len; + pkt->filled_len = out_frame->filled_len; + pkt->offset = out_frame->offset; + pkt->rgData[0] = out_frame->extradata_size; + + return 0; +} + +static int pkt_session_parse_seq_header( + struct hfi_cmd_session_parse_sequence_header_packet *pkt, + struct hal_session *session, struct vidc_seq_hdr *seq_hdr) +{ + if (!session || !seq_hdr || !seq_hdr->seq_hdr) + return -EINVAL; + + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER; + pkt->session_id = hash32_ptr(session); + pkt->header_len = seq_hdr->seq_hdr_len; + pkt->packet_buffer = seq_hdr->seq_hdr; + + return 0; +} + +static int +pkt_session_get_seq_hdr(struct hfi_session_get_sequence_header_pkt *pkt, + struct hal_session *session, + struct vidc_seq_hdr *seq_hdr) +{ + if (!session || !seq_hdr || !seq_hdr->seq_hdr) + return -EINVAL; + + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SESSION_GET_SEQUENCE_HEADER; + pkt->session_id = hash32_ptr(session); + pkt->buffer_len = seq_hdr->seq_hdr_len; + pkt->packet_buffer = seq_hdr->seq_hdr; + + return 0; +} + +static int pkt_session_flush(struct hfi_cmd_session_flush_packet *pkt, + struct hal_session *session, enum hal_flush type) +{ + if (!session) + return -EINVAL; + + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SESSION_FLUSH; + pkt->session_id = hash32_ptr(session); + + switch (type) { + case HAL_FLUSH_INPUT: + pkt->flush_type = HFI_FLUSH_INPUT; + break; + case HAL_FLUSH_OUTPUT: + pkt->flush_type = HFI_FLUSH_OUTPUT; + break; + case HAL_FLUSH_OUTPUT2: + pkt->flush_type = HFI_FLUSH_OUTPUT2; + break; + case HAL_FLUSH_ALL: + pkt->flush_type = HFI_FLUSH_ALL; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int +pkt_session_get_property(struct hfi_cmd_session_get_property_packet *pkt, + struct hal_session *session, enum hal_property ptype) +{ + if (!session) + return -EINVAL; + + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY; + pkt->session_id = hash32_ptr(session); + pkt->num_properties = 1; + + switch (ptype) { + case HAL_PARAM_PROFILE_LEVEL_CURRENT: + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT; + break; + case HAL_PARAM_GET_BUFFER_REQUIREMENTS: + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS; + break; + default: + return -ENOTSUPP; + } + + return 0; +} + +static int +pkt_session_set_property(struct hfi_session_set_property_pkt *pkt, + struct hal_session *session, enum hal_property ptype, + void *pdata) +{ + int ret = 0; + + if (!session) + return -EINVAL; + + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY; + pkt->session_id = hash32_ptr(session); + pkt->num_properties = 1; + + switch (ptype) { + case HAL_CONFIG_FRAME_RATE: { + struct hal_frame_rate *prop = pdata; + struct hfi_frame_rate *hfi; + u32 buffer_type; + + pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_FRAME_RATE; + hfi = (struct hfi_frame_rate *) &pkt->rg_property_data[1]; + buffer_type = to_hfi_buffer(prop->buffer_type); + if (!buffer_type) + return -EINVAL; + hfi->buffer_type = buffer_type; + hfi->frame_rate = prop->frame_rate; + pkt->size += sizeof(u32) + sizeof(struct hfi_frame_rate); + break; + } + case HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT: { + struct hal_uncompressed_format_select *prop = pdata; + struct hfi_uncompressed_format_select *hfi; + u32 buffer_type; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT; + + hfi = (struct hfi_uncompressed_format_select *) + &pkt->rg_property_data[1]; + buffer_type = to_hfi_buffer(prop->buffer_type); + if (!buffer_type) + return -EINVAL; + hfi->buffer_type = buffer_type; + hfi->format = to_hfi_type(HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT, + prop->format); + pkt->size += sizeof(u32) + + sizeof(struct hfi_uncompressed_format_select); + break; + } + case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO: + break; + case HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO: + break; + case HAL_PARAM_EXTRA_DATA_HEADER_CONFIG: + break; + case HAL_PARAM_FRAME_SIZE: { + struct hal_frame_size *prop = pdata; + struct hfi_frame_size *hfi; + u32 buffer_type; + + pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_FRAME_SIZE; + hfi = (struct hfi_frame_size *) &pkt->rg_property_data[1]; + buffer_type = to_hfi_buffer(prop->buffer_type); + if (!buffer_type) + return -EINVAL; + hfi->buffer_type = buffer_type; + hfi->height = prop->height; + hfi->width = prop->width; + pkt->size += sizeof(u32) + sizeof(struct hfi_frame_size); + break; + } + case HAL_CONFIG_REALTIME: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_REALTIME; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hfi_enable *) pdata)->enable; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_BUFFER_COUNT_ACTUAL: { + struct hal_buffer_count_actual *prop = pdata; + struct hfi_buffer_count_actual *hfi; + u32 buf_type; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL; + + hfi = (struct hfi_buffer_count_actual *) + &pkt->rg_property_data[1]; + + hfi->count_actual = prop->count_actual; + buf_type = to_hfi_buffer(prop->type); + if (!buf_type) + return -EINVAL; + hfi->type = buf_type; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_BUFFER_SIZE_ACTUAL: { + struct hal_buffer_size_actual *prop = pdata; + struct hfi_buffer_size_actual *hfi; + u32 buf_type; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL; + + hfi = (struct hfi_buffer_size_actual *) + &pkt->rg_property_data[1]; + + hfi->size = prop->size; + buf_type = to_hfi_buffer(prop->type); + if (!buf_type) + return -EINVAL; + hfi->type = buf_type; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_BUFFER_DISPLAY_HOLD_COUNT_ACTUAL: { + struct hal_buffer_display_hold_count_actual *prop = pdata; + struct hfi_buffer_display_hold_count_actual *hfi; + u32 buffer_type; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_BUFFER_DISPLAY_HOLD_COUNT_ACTUAL; + + hfi = (struct hfi_buffer_display_hold_count_actual *) + &pkt->rg_property_data[1]; + hfi->hold_count = prop->hold_count; + buffer_type = to_hfi_buffer(prop->buffer_type); + if (!buffer_type) + return -EINVAL; + hfi->type = buffer_type; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_NAL_STREAM_FORMAT_SELECT: { + struct hal_nal_stream_format_select *prop = pdata; + struct hfi_nal_stream_format_select *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT; + hfi = (struct hfi_nal_stream_format_select *) + &pkt->rg_property_data[1]; + hfi->nal_stream_format_select = + to_hfi_type(HAL_PARAM_NAL_STREAM_FORMAT_SELECT, + prop->nal_stream_format_select); + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VDEC_OUTPUT_ORDER: { + int *data = pdata; + + pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER; + switch (*data) { + case HAL_OUTPUT_ORDER_DECODE: + pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DECODE; + break; + case HAL_OUTPUT_ORDER_DISPLAY: + pkt->rg_property_data[1] = HFI_OUTPUT_ORDER_DISPLAY; + break; + default: + dprintk(VIDC_ERR, "invalid output order: %#x\n", *data); + break; + } + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VDEC_PICTURE_TYPE_DECODE: { + struct hfi_enable_picture *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE; + hfi = (struct hfi_enable_picture *) &pkt->rg_property_data[1]; + hfi->picture_type = + ((struct hfi_enable_picture *)pdata)->picture_type; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hfi_enable *) pdata)->enable; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hfi_enable *) pdata)->enable; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VDEC_MULTI_STREAM: { + struct hal_multi_stream *prop = pdata; + struct hfi_multi_stream *hfi; + u32 buffer_type; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM; + hfi = (struct hfi_multi_stream *) &pkt->rg_property_data[1]; + + buffer_type = to_hfi_buffer(prop->buffer_type); + if (!buffer_type) + return -EINVAL; + hfi->buffer_type = buffer_type; + hfi->enable = prop->enable; + hfi->width = prop->width; + hfi->height = prop->height; + pkt->size += sizeof(u32) + sizeof(struct hfi_multi_stream); + break; + } + case HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT: { + struct hal_display_picture_buffer_count *prop = pdata; + struct hfi_display_picture_buffer_count *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT; + hfi = (struct hfi_display_picture_buffer_count *) + &pkt->rg_property_data[1]; + hfi->count = prop->count; + hfi->enable = prop->enable; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_DIVX_FORMAT: { + int *data = pdata; + + pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_DIVX_FORMAT; + switch (*data) { + case HAL_DIVX_FORMAT_4: + pkt->rg_property_data[1] = HFI_DIVX_FORMAT_4; + break; + case HAL_DIVX_FORMAT_5: + pkt->rg_property_data[1] = HFI_DIVX_FORMAT_5; + break; + case HAL_DIVX_FORMAT_6: + pkt->rg_property_data[1] = HFI_DIVX_FORMAT_6; + break; + default: + dprintk(VIDC_ERR, "Invalid divx format: %#x\n", *data); + break; + } + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hfi_enable *) pdata)->enable; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hfi_enable *) pdata)->enable; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VDEC_SYNC_FRAME_DECODE: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hfi_enable *) pdata)->enable; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hfi_enable *) pdata)->enable; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_CONFIG_VENC_REQUEST_IFRAME: + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME; + pkt->size += sizeof(u32); + break; + case HAL_PARAM_VENC_MPEG4_SHORT_HEADER: + break; + case HAL_PARAM_VENC_MPEG4_AC_PREDICTION: + break; + case HAL_CONFIG_VENC_TARGET_BITRATE: { + struct hfi_bitrate *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE; + hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1]; + hfi->bit_rate = ((struct hal_bitrate *)pdata)->bit_rate; + hfi->layer_id = ((struct hal_bitrate *)pdata)->layer_id; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_CONFIG_VENC_MAX_BITRATE: { + struct hfi_bitrate *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE; + hfi = (struct hfi_bitrate *) &pkt->rg_property_data[1]; + hfi->bit_rate = ((struct hal_bitrate *)pdata)->bit_rate; + hfi->layer_id = ((struct hal_bitrate *)pdata)->layer_id; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_PROFILE_LEVEL_CURRENT: { + struct hal_profile_level *prop = pdata; + struct hfi_profile_level *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT; + hfi = (struct hfi_profile_level *) &pkt->rg_property_data[1]; + hfi->level = prop->level; + hfi->profile = to_hfi_type(HAL_PARAM_PROFILE_LEVEL_CURRENT, + prop->profile); + if (hfi->profile <= 0) { + hfi->profile = HFI_H264_PROFILE_HIGH; + dprintk(VIDC_WARN, + "Profile %d not supported, falling back to high\n", + prop->profile); + } + + if (!hfi->level) { + hfi->level = 1; + dprintk(VIDC_WARN, + "Level %d not supported, falling back to high\n", + prop->level); + } + + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_H264_ENTROPY_CONTROL: { + struct hal_h264_entropy_control *prop = pdata; + struct hfi_h264_entropy_control *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL; + hfi = (struct hfi_h264_entropy_control *) + &pkt->rg_property_data[1]; + hfi->entropy_mode = to_hfi_type( + HAL_PARAM_VENC_H264_ENTROPY_CONTROL, + prop->entropy_mode); + if (hfi->entropy_mode == HAL_H264_ENTROPY_CABAC) + hfi->cabac_model = to_hfi_type( + HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL, + prop->cabac_model); + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_RATE_CONTROL: { + u32 *rc; + + pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_VENC_RATE_CONTROL; + rc = (u32 *)pdata; + switch ((enum hal_rate_control) *rc) { + case HAL_RATE_CONTROL_OFF: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_OFF; + break; + case HAL_RATE_CONTROL_CBR_CFR: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_CFR; + break; + case HAL_RATE_CONTROL_CBR_VFR: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_CBR_VFR; + break; + case HAL_RATE_CONTROL_VBR_CFR: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_CFR; + break; + case HAL_RATE_CONTROL_VBR_VFR: + pkt->rg_property_data[1] = HFI_RATE_CONTROL_VBR_VFR; + break; + default: + dprintk(VIDC_ERR, "Invalid Rate control setting: %p\n", + pdata); + break; + } + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION: { + struct hfi_mpeg4_time_resolution *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION; + hfi = (struct hfi_mpeg4_time_resolution *) + &pkt->rg_property_data[1]; + hfi->time_increment_resolution = + ((struct hal_mpeg4_time_resolution *)pdata)-> + time_increment_resolution; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION: { + struct hfi_mpeg4_header_extension *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION; + hfi = (struct hfi_mpeg4_header_extension *) + &pkt->rg_property_data[1]; + hfi->header_extension = (u32)(unsigned long) pdata; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VENC_H264_DEBLOCK_CONTROL: { + struct hal_h264_db_control *prop = pdata; + struct hfi_h264_db_control *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL; + hfi = (struct hfi_h264_db_control *) &pkt->rg_property_data[1]; + switch (prop->mode) { + case HAL_H264_DB_MODE_DISABLE: + hfi->mode = HFI_H264_DB_MODE_DISABLE; + break; + case HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY: + hfi->mode = HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY; + break; + case HAL_H264_DB_MODE_ALL_BOUNDARY: + hfi->mode = HFI_H264_DB_MODE_ALL_BOUNDARY; + break; + default: + dprintk(VIDC_ERR, "Invalid deblocking mode: %#x\n", + prop->mode); + break; + } + hfi->slice_alpha_offset = prop->slice_alpha_offset; + hfi->slice_beta_offset = prop->slice_beta_offset; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_SESSION_QP: { + struct hal_quantization *hal_quant = pdata; + struct hfi_quantization *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_SESSION_QP; + hfi = (struct hfi_quantization *) &pkt->rg_property_data[1]; + hfi->qp_i = hal_quant->qpi; + hfi->qp_p = hal_quant->qpp; + hfi->qp_b = hal_quant->qpb; + hfi->layer_id = hal_quant->layer_id; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_SESSION_QP_RANGE: { + struct hfi_quantization_range *hal_range = pdata; + struct hfi_quantization_range *hfi; + u32 min_qp, max_qp; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE; + hfi = (struct hfi_quantization_range *) + &pkt->rg_property_data[1]; + + min_qp = hal_range->min_qp; + max_qp = hal_range->max_qp; + + /* We'll be packing in the qp, so make sure we + * won't be losing data when masking */ + if (min_qp > 0xff || max_qp > 0xff) { + dprintk(VIDC_ERR, "qp value out of range\n"); + ret = -ERANGE; + break; + } + + /* When creating the packet, pack the qp value as + * 0xiippbb, where ii = qp range for I-frames, + * pp = qp range for P-frames, etc. */ + hfi->min_qp = min_qp | min_qp << 8 | min_qp << 16; + hfi->max_qp = max_qp | max_qp << 8 | max_qp << 16; + hfi->layer_id = hal_range->layer_id; + + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_SEARCH_RANGE: { + struct hal_vc1e_perf_cfg_type *hal_mv_searchrange = pdata; + struct hfi_vc1e_perf_cfg_type *hfi; + + pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_VENC_VC1_PERF_CFG; + hfi = (struct hfi_vc1e_perf_cfg_type *) + &pkt->rg_property_data[1]; + hfi->search_range_x_subsampled[0] = + hal_mv_searchrange->i_frame.x_subsampled; + hfi->search_range_x_subsampled[1] = + hal_mv_searchrange->p_frame.x_subsampled; + hfi->search_range_x_subsampled[2] = + hal_mv_searchrange->b_frame.x_subsampled; + hfi->search_range_y_subsampled[0] = + hal_mv_searchrange->i_frame.y_subsampled; + hfi->search_range_y_subsampled[1] = + hal_mv_searchrange->p_frame.y_subsampled; + hfi->search_range_y_subsampled[2] = + hal_mv_searchrange->b_frame.y_subsampled; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_MAX_NUM_B_FRAMES: { + struct hfi_max_num_b_frames *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES; + hfi = (struct hfi_max_num_b_frames *) &pkt->rg_property_data[1]; + memcpy(hfi, (struct hfi_max_num_b_frames *) pdata, + sizeof(struct hfi_max_num_b_frames)); + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_CONFIG_VENC_INTRA_PERIOD: { + struct hfi_intra_period *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD; + hfi = (struct hfi_intra_period *) &pkt->rg_property_data[1]; + memcpy(hfi, (struct hfi_intra_period *) pdata, + sizeof(struct hfi_intra_period)); + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_CONFIG_VENC_IDR_PERIOD: { + struct hfi_idr_period *hfi; + + pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD; + hfi = (struct hfi_idr_period *) &pkt->rg_property_data[1]; + hfi->idr_period = ((struct hfi_idr_period *) pdata)->idr_period; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VDEC_CONCEAL_COLOR: { + struct hfi_conceal_color *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR; + hfi = (struct hfi_conceal_color *) &pkt->rg_property_data[1]; + if (hfi) + hfi->conceal_color = + ((struct hfi_conceal_color *) pdata)-> + conceal_color; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_CONFIG_VPE_OPERATIONS: { + struct hal_operations *prop = pdata; + struct hfi_operations_type *hfi; + + pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VPE_OPERATIONS; + hfi = (struct hfi_operations_type *) &pkt->rg_property_data[1]; + switch (prop->rotate) { + case HAL_ROTATE_NONE: + hfi->rotation = HFI_ROTATE_NONE; + break; + case HAL_ROTATE_90: + hfi->rotation = HFI_ROTATE_90; + break; + case HAL_ROTATE_180: + hfi->rotation = HFI_ROTATE_180; + break; + case HAL_ROTATE_270: + hfi->rotation = HFI_ROTATE_270; + break; + default: + dprintk(VIDC_ERR, "Invalid rotation setting: %#x\n", + prop->rotate); + ret = -EINVAL; + break; + } + switch (prop->flip) { + case HAL_FLIP_NONE: + hfi->flip = HFI_FLIP_NONE; + break; + case HAL_FLIP_HORIZONTAL: + hfi->flip = HFI_FLIP_HORIZONTAL; + break; + case HAL_FLIP_VERTICAL: + hfi->flip = HFI_FLIP_VERTICAL; + break; + default: + dprintk(VIDC_ERR, "Invalid flip setting: %#x\n", + prop->flip); + ret = -EINVAL; + break; + } + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_INTRA_REFRESH: { + struct hal_intra_refresh *prop = pdata; + struct hfi_intra_refresh *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH; + hfi = (struct hfi_intra_refresh *) &pkt->rg_property_data[1]; + switch (prop->mode) { + case HAL_INTRA_REFRESH_NONE: + hfi->mode = HFI_INTRA_REFRESH_NONE; + break; + case HAL_INTRA_REFRESH_ADAPTIVE: + hfi->mode = HFI_INTRA_REFRESH_ADAPTIVE; + break; + case HAL_INTRA_REFRESH_CYCLIC: + hfi->mode = HFI_INTRA_REFRESH_CYCLIC; + break; + case HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE: + hfi->mode = HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE; + break; + case HAL_INTRA_REFRESH_RANDOM: + hfi->mode = HFI_INTRA_REFRESH_RANDOM; + break; + default: + dprintk(VIDC_ERR, + "Invalid intra refresh setting: %#x\n", + prop->mode); + break; + } + hfi->air_mbs = prop->air_mbs; + hfi->air_ref = prop->air_ref; + hfi->cir_mbs = prop->cir_mbs; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_MULTI_SLICE_CONTROL: { + struct hal_multi_slice_control *prop = pdata; + struct hfi_multi_slice_control *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL; + hfi = (struct hfi_multi_slice_control *) + &pkt->rg_property_data[1]; + switch (prop->multi_slice) { + case HAL_MULTI_SLICE_OFF: + hfi->multi_slice = HFI_MULTI_SLICE_OFF; + break; + case HAL_MULTI_SLICE_GOB: + hfi->multi_slice = HFI_MULTI_SLICE_GOB; + break; + case HAL_MULTI_SLICE_BY_MB_COUNT: + hfi->multi_slice = HFI_MULTI_SLICE_BY_MB_COUNT; + break; + case HAL_MULTI_SLICE_BY_BYTE_COUNT: + hfi->multi_slice = HFI_MULTI_SLICE_BY_BYTE_COUNT; + break; + default: + dprintk(VIDC_ERR, "Invalid slice settings: %#x\n", + prop->multi_slice); + break; + } + hfi->slice_size = prop->slice_size; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_INDEX_EXTRADATA: { + struct hal_extradata_enable *extra = pdata; + struct hfi_index_extradata_config *hfi; + int id = 0; + + pkt->rg_property_data[0] = + to_hfi_extradata_index(extra->index); + hfi = (struct hfi_index_extradata_config *) + &pkt->rg_property_data[1]; + hfi->enable = extra->enable; + id = to_hfi_extradata_id(extra->index); + if (id) { + hfi->index_extra_data_id = id; + } else { + dprintk(VIDC_WARN, "failed to find extradata id: %d\n", + id); + ret = -EINVAL; + } + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_SLICE_DELIVERY_MODE: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hal_enable *) pdata)->enable; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_H264_VUI_TIMING_INFO: { + struct hal_h264_vui_timing_info *timing_info = pdata; + struct hfi_h264_vui_timing_info *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO; + + hfi = (struct hfi_h264_vui_timing_info *) + &pkt->rg_property_data[1]; + hfi->enable = timing_info->enable; + hfi->fixed_frame_rate = timing_info->fixed_frame_rate; + hfi->time_scale = timing_info->time_scale; + + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_CONFIG_VPE_DEINTERLACE: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VPE_DEINTERLACE; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hal_enable *) pdata)->enable; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_H264_GENERATE_AUDNAL: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_H264_GENERATE_AUDNAL; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hal_enable *) pdata)->enable; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_BUFFER_ALLOC_MODE: { + struct hal_buffer_alloc_mode *hal = pdata; + struct hfi_buffer_alloc_mode *hfi; + u32 buf_type, buf_mode; + + pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE; + hfi = (struct hfi_buffer_alloc_mode *) + &pkt->rg_property_data[1]; + buf_type = to_hfi_buffer(hal->type); + if (!buf_type) + return -EINVAL; + hfi->type = buf_type; + buf_mode = to_hfi_buf_mode(hal->mode); + if (!buf_mode) + return -EINVAL; + hfi->mode = buf_mode; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VDEC_FRAME_ASSEMBLY: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hfi_enable *) pdata)->enable; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC: { + struct hal_h264_vui_bitstream_restrc *hal = pdata; + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = hal->enable; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY: { + struct hal_preserve_text_quality *hal = pdata; + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = hal->enable; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VDEC_SCS_THRESHOLD: { + struct hfi_scs_threshold *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_SCS_THRESHOLD; + hfi = (struct hfi_scs_threshold *) &pkt->rg_property_data[1]; + hfi->threshold_value = + ((struct hfi_scs_threshold *) pdata)->threshold_value; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_MVC_BUFFER_LAYOUT: { + struct hal_mvc_buffer_layout *layout_info = pdata; + struct hfi_mvc_buffer_layout_descp_type *hfi; + + pkt->rg_property_data[0] = HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT; + hfi = (struct hfi_mvc_buffer_layout_descp_type *) + &pkt->rg_property_data[1]; + hfi->layout_type = to_hfi_layout(layout_info->layout_type); + hfi->bright_view_first = layout_info->bright_view_first; + hfi->ngap = layout_info->ngap; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_LTRMODE: { + struct hal_ltr_mode *hal = pdata; + struct hfi_ltr_mode *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_LTRMODE; + hfi = (struct hfi_ltr_mode *) &pkt->rg_property_data[1]; + hfi->ltr_mode = to_hfi_ltr_mode(hal->mode); + hfi->ltr_count = hal->count; + hfi->trust_mode = hal->trust_mode; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_CONFIG_VENC_USELTRFRAME: { + struct hal_ltr_use *hal = pdata; + struct hfi_ltr_use *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_USELTRFRAME; + hfi = (struct hfi_ltr_use *) &pkt->rg_property_data[1]; + hfi->frames = hal->frames; + hfi->ref_ltr = hal->ref_ltr; + hfi->use_constrnt = hal->use_constraint; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_CONFIG_VENC_MARKLTRFRAME: { + struct hal_ltr_mark *hal = pdata; + struct hfi_ltr_mark *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME; + hfi = (struct hfi_ltr_mark *) &pkt->rg_property_data[1]; + hfi->mark_frame = hal->mark_frame; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS: { + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER; + pkt->rg_property_data[1] = *(u32 *)pdata; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_CONFIG_VENC_HIER_P_NUM_FRAMES: { + pkt->rg_property_data[0] = + HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER; + pkt->rg_property_data[1] = *(u32 *)pdata; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP; + hfi = (struct hfi_enable *)&pkt->rg_property_data[1]; + hfi->enable = ((struct hfi_enable *)pdata)->enable; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VENC_ENABLE_INITIAL_QP: { + struct hal_initial_quantization *quant = pdata; + struct hfi_initial_quantization *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_INITIAL_QP; + hfi = (struct hfi_initial_quantization *) + &pkt->rg_property_data[1]; + hfi->init_qp_enable = quant->init_qp_enable; + hfi->qp_i = quant->qpi; + hfi->qp_p = quant->qpp; + hfi->qp_b = quant->qpb; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VPE_COLOR_SPACE_CONVERSION: { + struct hal_vpe_color_space_conversion *hal = pdata; + struct hfi_vpe_color_space_conversion *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION; + hfi = (struct hfi_vpe_color_space_conversion *) + &pkt->rg_property_data[1]; + memcpy(hfi->csc_matrix, hal->csc_matrix, + sizeof(hfi->csc_matrix)); + memcpy(hfi->csc_bias, hal->csc_bias, sizeof(hfi->csc_bias)); + memcpy(hfi->csc_limit, hal->csc_limit, sizeof(hfi->csc_limit)); + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE: { + struct hal_enable *err_res = pdata; + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE; + hfi = (struct hfi_enable *)&pkt->rg_property_data[1]; + hfi->enable = err_res->enable; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_H264_NAL_SVC_EXT: { + struct hal_enable *svc_nal = pdata; + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_H264_NAL_SVC_EXT; + hfi = (struct hfi_enable *)&pkt->rg_property_data[1]; + hfi->enable = svc_nal->enable; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_CONFIG_VENC_PERF_MODE: { + pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_VENC_PERF_MODE; + pkt->rg_property_data[1] = *(u32 *)pdata; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS: { + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER; + pkt->rg_property_data[1] = *(u32 *)pdata; + pkt->size += sizeof(u32) * 2; + break; + } + case HAL_PARAM_VDEC_NON_SECURE_OUTPUT2: { + struct hfi_enable *hfi; + + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VDEC_NONCP_OUTPUT2; + hfi = (struct hfi_enable *) &pkt->rg_property_data[1]; + hfi->enable = ((struct hfi_enable *) pdata)->enable; + pkt->size += sizeof(u32) + sizeof(*hfi); + break; + } + case HAL_PARAM_VENC_HIER_P_HYBRID_MODE: { + pkt->rg_property_data[0] = + HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE; + pkt->rg_property_data[1] = + ((struct hfi_hybrid_hierp *)pdata)->layers; + pkt->size += sizeof(u32) + sizeof(struct hfi_hybrid_hierp); + break; + } + /* FOLLOWING PROPERTIES ARE NOT IMPLEMENTED IN CORE YET */ + case HAL_CONFIG_BUFFER_REQUIREMENTS: + case HAL_CONFIG_PRIORITY: + case HAL_CONFIG_BATCH_INFO: + case HAL_PARAM_METADATA_PASS_THROUGH: + case HAL_SYS_IDLE_INDICATOR: + case HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED: + case HAL_PARAM_INTERLACE_FORMAT_SUPPORTED: + case HAL_PARAM_CHROMA_SITE: + case HAL_PARAM_PROPERTIES_SUPPORTED: + case HAL_PARAM_PROFILE_LEVEL_SUPPORTED: + case HAL_PARAM_CAPABILITY_SUPPORTED: + case HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED: + case HAL_PARAM_MULTI_VIEW_FORMAT: + case HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE: + case HAL_PARAM_CODEC_SUPPORTED: + case HAL_PARAM_VDEC_MULTI_VIEW_SELECT: + case HAL_PARAM_VDEC_MB_QUANTIZATION: + case HAL_PARAM_VDEC_NUM_CONCEALED_MB: + case HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING: + case HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING: + case HAL_CONFIG_BUFFER_COUNT_ACTUAL: + case HAL_CONFIG_VDEC_MULTI_STREAM: + case HAL_PARAM_VENC_MULTI_SLICE_INFO: + case HAL_CONFIG_VENC_TIMESTAMP_SCALE: + case HAL_PARAM_VENC_LOW_LATENCY: + default: + return -ENOTSUPP; + } + + return ret; +} + +static u32 to_hfi_ssr_type(enum hal_ssr_trigger_type type) +{ + switch (type) { + case SSR_ERR_FATAL: + return HFI_TEST_SSR_SW_ERR_FATAL; + case SSR_SW_DIV_BY_ZERO: + return HFI_TEST_SSR_SW_DIV_BY_ZERO; + case SSR_HW_WDOG_IRQ: + return HFI_TEST_SSR_HW_WDOG_IRQ; + default: + dprintk(VIDC_WARN, + "SSR trigger type not recognized, using WDOG.\n"); + break; + } + + return HFI_TEST_SSR_HW_WDOG_IRQ; +} + +static int pkt_ssr_cmd(enum hal_ssr_trigger_type type, + struct hfi_sys_test_ssr_pkt *pkt) +{ + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SYS_TEST_SSR; + pkt->trigger_type = to_hfi_ssr_type(type); + + return 0; +} + +static int pkt_sys_image_version(struct hfi_sys_get_property_pkt *pkt) +{ + pkt->size = sizeof(*pkt); + pkt->packet_type = HFI_CMD_SYS_GET_PROPERTY; + pkt->num_properties = 1; + pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IMAGE_VERSION; + + return 0; +} + +static const struct hfi_packetization_ops hfi_default = { + .sys_init = pkt_sys_init, + .sys_pc_prep = pkt_sys_pc_prep, + .sys_idle_indicator = pkt_sys_idle_indicator, + .sys_power_control = pkt_sys_power_control, + .sys_set_resource = pkt_sys_set_resource, + .sys_debug_config = pkt_sys_debug_config, + .sys_coverage_config = pkt_sys_coverage_config, + .sys_release_resource = pkt_sys_release_resource, + .sys_ping = pkt_sys_ping, + .sys_image_version = pkt_sys_image_version, + .ssr_cmd = pkt_ssr_cmd, + .session_init = pkt_session_init, + .session_cmd = pkt_session_cmd, + .session_set_buffers = pkt_session_set_buffers, + .session_release_buffers = pkt_session_release_buffers, + .session_etb_decoder = pkt_session_etb_decoder, + .session_etb_encoder = pkt_session_etb_encoder, + .session_ftb = pkt_session_ftb, + .session_parse_seq_header = pkt_session_parse_seq_header, + .session_get_seq_hdr = pkt_session_get_seq_hdr, + .session_flush = pkt_session_flush, + .session_get_property = pkt_session_get_property, + .session_set_property = pkt_session_set_property, +}; + +static const struct hfi_packetization_ops *get_venus_3_x_ops(void) +{ + static const struct hfi_packetization_ops *hfi_venus_3_x; + + hfi_venus_3_x = &hfi_default; + + /* Override new HFI functions for HFI_PACKETIZATION_3XX here. */ + + return hfi_venus_3_x; +} + +const struct hfi_packetization_ops * +hfi_get_pkt_ops(enum hfi_packetization_type type) +{ + dprintk(VIDC_DBG, "%s selected\n", + type == HFI_PACKETIZATION_LEGACY ? "legacy packetization" : + type == HFI_PACKETIZATION_3XX ? "3xx packetization" : + "Unknown hfi"); + + switch (type) { + case HFI_PACKETIZATION_LEGACY: + return &hfi_default; + case HFI_PACKETIZATION_3XX: + return get_venus_3_x_ops(); + } + + return NULL; +} diff --git a/drivers/media/platform/msm/vidc/hfi/hfi_packetization.h b/drivers/media/platform/msm/vidc/hfi/hfi_packetization.h new file mode 100644 index 000000000000..338614575de0 --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi/hfi_packetization.h @@ -0,0 +1,91 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __HFI_PACKETIZATION__ +#define __HFI_PACKETIZATION__ + +#include +#include "vidc_hfi_helper.h" +#include "vidc_hfi.h" +#include "vidc_hfi_api.h" + +#define call_hfi_pkt_op(q, op, args...) \ + (((q) && (q)->pkt_ops && (q)->pkt_ops->op) ? \ + ((q)->pkt_ops->op(args)) : -EINVAL) + +enum hfi_packetization_type { + HFI_PACKETIZATION_LEGACY, + HFI_PACKETIZATION_3XX, +}; + +struct hfi_packetization_ops { + int (*sys_init)(struct hfi_sys_init_pkt *pkt, u32 arch_type); + int (*sys_pc_prep)(struct hfi_sys_pc_prep_pkt *pkt); + int (*sys_idle_indicator)(struct hfi_sys_set_property_pkt *pkt, + u32 enable); + int (*sys_power_control)(struct hfi_sys_set_property_pkt *pkt, + u32 enable); + int (*sys_set_resource)(struct hfi_sys_set_resource_pkt *pkt, + struct vidc_resource_hdr *resource_hdr, + void *resource_value); + int (*sys_debug_config)(struct hfi_sys_set_property_pkt *pkt, u32 mode); + int (*sys_coverage_config)(struct hfi_sys_set_property_pkt *pkt, + u32 mode); + int (*sys_release_resource)(struct hfi_sys_release_resource_pkt *pkt, + struct vidc_resource_hdr *resource_hdr); + int (*sys_ping)(struct hfi_cmd_sys_ping_packet *pkt); + int (*sys_image_version)(struct hfi_sys_get_property_pkt *pkt); + int (*ssr_cmd)(enum hal_ssr_trigger_type type, + struct hfi_sys_test_ssr_pkt *pkt); + int (*session_init)(struct hfi_session_init_pkt *pkt, + struct hal_session *session, + u32 session_domain, u32 session_codec); + int (*session_cmd)(struct vidc_hal_session_cmd_pkt *pkt, + int pkt_type, struct hal_session *session); + int (*session_set_buffers)(struct hfi_session_set_buffers_pkt *pkt, + struct hal_session *session, + struct vidc_buffer_addr_info *buffer_info); + int (*session_release_buffers)( + struct hfi_cmd_session_release_buffer_packet *pkt, + struct hal_session *session, + struct vidc_buffer_addr_info *buffer_info); + int (*session_etb_decoder)( + struct hfi_cmd_session_empty_buffer_compressed_packet *pkt, + struct hal_session *session, + struct vidc_frame_data *input_frame); + int (*session_etb_encoder)( + struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet + *pkt, struct hal_session *session, + struct vidc_frame_data *input_frame); + int (*session_ftb)(struct hfi_cmd_session_fill_buffer_packet *pkt, + struct hal_session *session, + struct vidc_frame_data *output_frame); + int (*session_parse_seq_header)( + struct hfi_cmd_session_parse_sequence_header_packet *pkt, + struct hal_session *session, struct vidc_seq_hdr *seq_hdr); + int (*session_get_seq_hdr)( + struct hfi_session_get_sequence_header_pkt *pkt, + struct hal_session *session, struct vidc_seq_hdr *seq_hdr); + int (*session_flush)(struct hfi_cmd_session_flush_packet *pkt, + struct hal_session *session, enum hal_flush flush_mode); + int (*session_get_property)( + struct hfi_cmd_session_get_property_packet *pkt, + struct hal_session *session, enum hal_property ptype); + int (*session_set_property)(struct hfi_session_set_property_pkt *pkt, + struct hal_session *session, + enum hal_property ptype, void *pdata); +}; + +const struct hfi_packetization_ops * +hfi_get_pkt_ops(enum hfi_packetization_type); + +#endif diff --git a/drivers/media/platform/msm/vidc/hfi/hfi_response_handler.c b/drivers/media/platform/msm/vidc/hfi/hfi_response_handler.c new file mode 100644 index 000000000000..5843bc0be3db --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi/hfi_response_handler.c @@ -0,0 +1,1292 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include + +#include "msm_vidc_debug.h" +#include "msm_vidc_common.h" + +#include "hfi/vidc_hfi_helper.h" +#include "hfi/vidc_hfi.h" + +static enum vidc_error to_vidc_error(u32 hfi_err) +{ + switch (hfi_err) { + case HFI_ERR_NONE: + case HFI_ERR_SESSION_SAME_STATE_OPERATION: + return VIDC_ERR_NONE; + case HFI_ERR_SYS_FATAL: + return VIDC_ERR_HW_FATAL; + case HFI_ERR_SYS_VERSION_MISMATCH: + case HFI_ERR_SYS_INVALID_PARAMETER: + case HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE: + case HFI_ERR_SESSION_INVALID_PARAMETER: + case HFI_ERR_SESSION_INVALID_SESSION_ID: + case HFI_ERR_SESSION_INVALID_STREAM_ID: + return VIDC_ERR_BAD_PARAM; + case HFI_ERR_SYS_INSUFFICIENT_RESOURCES: + case HFI_ERR_SYS_UNSUPPORTED_DOMAIN: + case HFI_ERR_SYS_UNSUPPORTED_CODEC: + case HFI_ERR_SESSION_UNSUPPORTED_PROPERTY: + case HFI_ERR_SESSION_UNSUPPORTED_SETTING: + case HFI_ERR_SESSION_INSUFFICIENT_RESOURCES: + case HFI_ERR_SESSION_UNSUPPORTED_STREAM: + return VIDC_ERR_NOT_SUPPORTED; + case HFI_ERR_SYS_MAX_SESSIONS_REACHED: + return VIDC_ERR_MAX_CLIENTS; + case HFI_ERR_SYS_SESSION_IN_USE: + return VIDC_ERR_CLIENT_PRESENT; + case HFI_ERR_SESSION_FATAL: + return VIDC_ERR_CLIENT_FATAL; + case HFI_ERR_SESSION_BAD_POINTER: + return VIDC_ERR_BAD_PARAM; + case HFI_ERR_SESSION_INCORRECT_STATE_OPERATION: + return VIDC_ERR_BAD_STATE; + case HFI_ERR_SESSION_STREAM_CORRUPT: + case HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED: + return VIDC_ERR_BITSTREAM_ERR; + case HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED: + return VIDC_ERR_IFRAME_EXPECTED; + case HFI_ERR_SESSION_START_CODE_NOT_FOUND: + return VIDC_ERR_START_CODE_NOT_FOUND; + case HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING: + default: + return VIDC_ERR_FAIL; + } + + return VIDC_ERR_FAIL; +} + +static struct hal_session * +to_hal_session(struct list_head *sessions, u32 session_id) +{ + struct hal_session *session = NULL; + bool found = false; + + list_for_each_entry(session, sessions, list) { + if (hash32_ptr(session) == session_id) { + found = true; + break; + } + } + + return found ? session : NULL; +} + +static void event_seq_changed(u32 device_id, struct hal_session *session, + struct hfi_msg_event_notify_pkt *pkt) +{ + struct vidc_inst *inst = session->session_id; + struct vidc_cb_event event = {0}; + int num_properties_changed; + struct hfi_frame_size *frame_sz; + struct hfi_profile_level *profile_level; + u8 *data_ptr; + u32 prop_id; + + switch (pkt->event_data1) { + case HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES: + event.hal_event_type = + HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES; + break; + case HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES: + event.hal_event_type = + HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES; + break; + default: + break; + } + + num_properties_changed = pkt->event_data2; + if (!num_properties_changed) + goto done; + + data_ptr = (u8 *) &pkt->rg_ext_event_data[0]; + do { + prop_id = *((u32 *)data_ptr); + switch (prop_id) { + case HFI_PROPERTY_PARAM_FRAME_SIZE: + data_ptr += sizeof(u32); + frame_sz = (struct hfi_frame_size *) data_ptr; + event.width = frame_sz->width; + event.height = frame_sz->height; + data_ptr += sizeof(frame_sz); + break; + case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: + data_ptr += sizeof(u32); + profile_level = (struct hfi_profile_level *) data_ptr; + event.profile = profile_level->profile; + event.level = profile_level->level; + data_ptr += sizeof(profile_level); + break; + default: + dprintk(VIDC_DBG, "%s cmd: %#x not supported\n", + __func__, prop_id); + break; + } + num_properties_changed--; + } while (num_properties_changed > 0); + +done: + if (!inst->event_notify) + return; + + inst->error = VIDC_ERR_NONE; + inst->event_notify(inst, SYS_EVENT_CHANGE, &event); +} + +static void event_release_buffer_ref(u32 device_id, struct hal_session *session, + struct hfi_msg_event_notify_pkt *pkt) +{ + struct vidc_inst *inst = session->session_id; + struct vidc_cb_event event = {0}; + struct hfi_msg_event_release_buffer_ref_pkt *data; + + data = (struct hfi_msg_event_release_buffer_ref_pkt *) + pkt->rg_ext_event_data; + + event.hal_event_type = HAL_EVENT_RELEASE_BUFFER_REFERENCE; + event.packet_buffer = data->packet_buffer; + event.extra_data_buffer = data->extra_data_buffer; + + if (!inst->event_notify) + return; + + inst->error = VIDC_ERR_NONE; + inst->event_notify(inst, SYS_EVENT_CHANGE, &event); +} + +static void event_sys_error(u32 device_id, u32 event) +{ + struct vidc_core *core; + + core = vidc_get_core(device_id); + if (IS_ERR(core)) { + dprintk(VIDC_ERR, "Got SYS_ERR but unable to identify core\n"); + return; + } + + if (!core->event_notify) + return; + + core->event_notify(core, device_id, event); +} + +static void event_session_error(u32 device_id, struct hal_session *session, + struct hfi_msg_event_notify_pkt *pkt) +{ + struct vidc_inst *inst = session->session_id; + + dprintk(VIDC_INFO, "received: SESSION_ERROR with event id:%d\n", + pkt->event_data1); + + if (!inst->event_notify) + 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 = VIDC_ERR_NONE; + break; + default: + inst->error = to_vidc_error(pkt->event_data1); + inst->event_notify(inst, SESSION_ERROR, NULL); + break; + } +} + +static void hfi_event_notify(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct hfi_msg_event_notify_pkt *pkt = packet; + + switch (pkt->event_id) { + case HFI_EVENT_SYS_ERROR: + dprintk(VIDC_ERR, "HFI_EVENT_SYS_ERROR: %d, %#x\n", + pkt->event_data1, pkt->event_data2); + event_sys_error(device_id, SYS_ERROR); + break; + } + + if (!session) { + dprintk(VIDC_ERR, "%s: got invalid session id\n", __func__); + return; + } + + switch (pkt->event_id) { + case HFI_EVENT_SESSION_ERROR: + event_session_error(device_id, session, pkt); + break; + case HFI_EVENT_SESSION_SEQUENCE_CHANGED: + event_seq_changed(device_id, session, pkt); + break; + case HFI_EVENT_RELEASE_BUFFER_REFERENCE: + event_release_buffer_ref(device_id, session, pkt); + break; + case HFI_EVENT_SESSION_PROPERTY_CHANGED: + break; + default: + break; + } +} + +static void hfi_sys_init_done(u32 device_id, void *sess, void *packet) +{ + struct hfi_msg_sys_init_done_pkt *pkt = packet; + struct vidc_hal_sys_init_done sys_init_done = {0}; + u32 rem_bytes, read_bytes = 0, num_properties; + struct vidc_core *core; + enum vidc_error error; + u8 *data_ptr; + u32 prop_id; + + error = to_vidc_error(pkt->error_type); + if (error != VIDC_ERR_NONE) + goto err_no_prop; + + if (!pkt->num_properties) { + dprintk(VIDC_ERR, "%s: no properties\n", __func__); + error = VIDC_ERR_FAIL; + goto err_no_prop; + } + + rem_bytes = pkt->size; + rem_bytes -= sizeof(struct hfi_msg_sys_init_done_pkt); + rem_bytes += sizeof(u32); + + if (!rem_bytes) { + dprintk(VIDC_ERR, "%s: missing property data\n", __func__); + error = VIDC_ERR_FAIL; + goto err_no_prop; + } + + data_ptr = (u8 *) &pkt->rg_property_data[0]; + num_properties = pkt->num_properties; + + while (num_properties && rem_bytes >= sizeof(u32)) { + prop_id = *((u32 *)data_ptr); + data_ptr += sizeof(u32); + + switch (prop_id) { + case HFI_PROPERTY_PARAM_CODEC_SUPPORTED: { + struct hfi_codec_supported *prop; + + prop = (struct hfi_codec_supported *) data_ptr; + + if (rem_bytes < sizeof(*prop)) { + error = VIDC_ERR_BAD_PARAM; + break; + } + sys_init_done.dec_codec_supported = + prop->decoder_codec_supported; + sys_init_done.enc_codec_supported = + prop->encoder_codec_supported; + break; + } + default: + dprintk(VIDC_ERR, "%s: bad property id: %x\n", __func__, + prop_id); + error = VIDC_ERR_BAD_PARAM; + break; + } + + if (!error) { + rem_bytes -= read_bytes; + data_ptr += read_bytes; + num_properties--; + } + } + +err_no_prop: + core = vidc_get_core(device_id); + if (IS_ERR(core)) { + dprintk(VIDC_ERR, "wrong device id received\n"); + return; + } + + core->enc_codecs = sys_init_done.enc_codec_supported; + core->dec_codecs = sys_init_done.dec_codec_supported; + + if (core->id == VIDC_CORE_VENUS && + (core->dec_codecs & HAL_VIDEO_CODEC_H264)) + core->dec_codecs |= HAL_VIDEO_CODEC_MVC; + + dprintk(VIDC_DBG, "supported_codecs: enc = %#x, dec = %#x\n", + core->enc_codecs, core->dec_codecs); + + core->error = error; + complete(&core->done); +} + +static void +sys_get_prop_image_version(struct hfi_msg_sys_property_info_packet *pkt) +{ + int i = 0; + char version[256]; + const u32 version_string_size = 128; + u8 *str_image_version; + int req_bytes; + + req_bytes = pkt->size - sizeof(*pkt); + + if (req_bytes < version_string_size || !pkt->rg_property_data[1] || + pkt->num_properties > 1) { + dprintk(VIDC_ERR, "%s: bad packet: %d\n", __func__, req_bytes); + return; + } + + str_image_version = (u8 *)&pkt->rg_property_data[1]; + + /* + * The version string returned by firmware includes null + * characters at the start and in between. Replace the null + * characters with space, to print the version info. + */ + for (i = 0; i < version_string_size; i++) { + if (str_image_version[i] != '\0') + version[i] = str_image_version[i]; + else + version[i] = ' '; + } + + version[i] = '\0'; + + dprintk(VIDC_DBG, "F/W version: %s\n", version); +} + +static void hfi_sys_property_info(u32 device_id, void *sess, void *packet) +{ + struct hfi_msg_sys_property_info_packet *pkt = packet; + + if (!pkt->num_properties) { + dprintk(VIDC_ERR, "%s: no properties\n", __func__); + return; + } + + switch (pkt->rg_property_data[0]) { + case HFI_PROPERTY_SYS_IMAGE_VERSION: + sys_get_prop_image_version(pkt); + break; + default: + dprintk(VIDC_ERR, "%s: unknown_property data: %x\n", __func__, + pkt->rg_property_data[0]); + break; + } +} + +static void hfi_sys_rel_resource_done(u32 device_id, void *sess, void *packet) +{ + struct hfi_msg_sys_release_resource_done_pkt *pkt = packet; + struct vidc_core *core; + + core = vidc_get_core(device_id); + if (IS_ERR(core)) { + dprintk(VIDC_ERR, "wrong core id received\n"); + return; + } + + core->error = to_vidc_error(pkt->error_type); + complete(&core->done); +} + +static void hfi_copy_cap_prop(struct hfi_capability_supported *in, + struct vidc_hal_session_init_done *sess_init_done) +{ + struct hal_capability_supported *out; + + if (!in || !sess_init_done) { + dprintk(VIDC_ERR, "%s: invalid input parameter\n", __func__); + return; + } + + switch (in->capability_type) { + case HFI_CAPABILITY_FRAME_WIDTH: + out = &sess_init_done->width; + break; + case HFI_CAPABILITY_FRAME_HEIGHT: + out = &sess_init_done->height; + break; + case HFI_CAPABILITY_MBS_PER_FRAME: + out = &sess_init_done->mbs_per_frame; + break; + case HFI_CAPABILITY_MBS_PER_SECOND: + out = &sess_init_done->mbs_per_sec; + break; + case HFI_CAPABILITY_FRAMERATE: + out = &sess_init_done->frame_rate; + break; + case HFI_CAPABILITY_SCALE_X: + out = &sess_init_done->scale_x; + break; + case HFI_CAPABILITY_SCALE_Y: + out = &sess_init_done->scale_y; + break; + case HFI_CAPABILITY_BITRATE: + out = &sess_init_done->bitrate; + break; + case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS: + out = &sess_init_done->hier_p; + break; + case HFI_CAPABILITY_ENC_LTR_COUNT: + out = &sess_init_done->ltr_count; + break; + case HFI_CAPABILITY_CP_OUTPUT2_THRESH: + out = &sess_init_done->secure_output2_threshold; + break; + default: + out = NULL; + break; + } + + if (out) { + out->min = in->min; + out->max = in->max; + out->step_size = in->step_size; + } +} + +static void +session_get_prop_profile_level(struct hfi_msg_session_property_info_packet *pkt, + struct hfi_profile_level *profile_level) +{ + struct hfi_profile_level *hfi_profile_level; + u32 req_bytes; + + req_bytes = pkt->size - sizeof(*pkt); + + if (!req_bytes || req_bytes % sizeof(struct hfi_profile_level)) { + dprintk(VIDC_ERR, "%s: bad packet\n", __func__); + return; + } + + hfi_profile_level = + (struct hfi_profile_level *) &pkt->rg_property_data[1]; + profile_level->profile = hfi_profile_level->profile; + profile_level->level = hfi_profile_level->level; + + dprintk(VIDC_DBG, "%s profile: %d level: %d\n", + __func__, profile_level->profile, profile_level->level); +} + +static void +session_get_prop_buf_req(struct hfi_msg_session_property_info_packet *pkt, + struct buffer_requirements *buffreq) +{ + struct hfi_buffer_requirements *buf_req; + u32 req_bytes; + + req_bytes = pkt->size - sizeof(*pkt); + + if (!req_bytes || req_bytes % sizeof(*buf_req) || + !pkt->rg_property_data[1]) { + dprintk(VIDC_ERR, "%s: bad packet\n", __func__); + return; + } + + buf_req = (struct hfi_buffer_requirements *) &pkt->rg_property_data[1]; + + if (!buf_req) { + dprintk(VIDC_ERR, "%s: invalid req buffer\n", __func__); + return; + } + + while (req_bytes) { + if (buf_req->size && buf_req->count_min > buf_req->count_actual) + dprintk(VIDC_WARN, "%s: bad req buffer\n", __func__); + + dprintk(VIDC_DBG, "got buffer requirements for: %x\n", + buf_req->type); + + switch (buf_req->type) { + case HFI_BUFFER_INPUT: + memcpy(&buffreq->buffer[0], buf_req, sizeof(*buf_req)); + buffreq->buffer[0].type = HAL_BUFFER_INPUT; + break; + case HFI_BUFFER_OUTPUT: + memcpy(&buffreq->buffer[1], buf_req, sizeof(*buf_req)); + buffreq->buffer[1].type = HAL_BUFFER_OUTPUT; + break; + case HFI_BUFFER_OUTPUT2: + memcpy(&buffreq->buffer[2], buf_req, sizeof(*buf_req)); + buffreq->buffer[2].type = HAL_BUFFER_OUTPUT2; + break; + case HFI_BUFFER_EXTRADATA_INPUT: + memcpy(&buffreq->buffer[3], buf_req, sizeof(*buf_req)); + buffreq->buffer[3].type = HAL_BUFFER_EXTRADATA_INPUT; + break; + case HFI_BUFFER_EXTRADATA_OUTPUT: + memcpy(&buffreq->buffer[4], buf_req, sizeof(*buf_req)); + buffreq->buffer[4].type = HAL_BUFFER_EXTRADATA_OUTPUT; + break; + case HFI_BUFFER_EXTRADATA_OUTPUT2: + memcpy(&buffreq->buffer[5], buf_req, sizeof(*buf_req)); + buffreq->buffer[5].type = HAL_BUFFER_EXTRADATA_OUTPUT2; + break; + case HFI_BUFFER_INTERNAL_SCRATCH: + memcpy(&buffreq->buffer[6], buf_req, sizeof(*buf_req)); + buffreq->buffer[6].type = HAL_BUFFER_INTERNAL_SCRATCH; + break; + case HFI_BUFFER_INTERNAL_SCRATCH_1: + memcpy(&buffreq->buffer[7], buf_req, sizeof(*buf_req)); + buffreq->buffer[7].type = HAL_BUFFER_INTERNAL_SCRATCH_1; + break; + case HFI_BUFFER_INTERNAL_SCRATCH_2: + memcpy(&buffreq->buffer[8], buf_req, sizeof(*buf_req)); + buffreq->buffer[8].type = HAL_BUFFER_INTERNAL_SCRATCH_2; + break; + case HFI_BUFFER_INTERNAL_PERSIST: + memcpy(&buffreq->buffer[9], buf_req, sizeof(*buf_req)); + buffreq->buffer[9].type = HAL_BUFFER_INTERNAL_PERSIST; + break; + case HFI_BUFFER_INTERNAL_PERSIST_1: + memcpy(&buffreq->buffer[10], buf_req, sizeof(*buf_req)); + buffreq->buffer[10].type = + HAL_BUFFER_INTERNAL_PERSIST_1; + break; + default: + dprintk(VIDC_ERR, "%s: bad buffer type: %d\n", __func__, + buf_req->type); + break; + } + + req_bytes -= sizeof(struct hfi_buffer_requirements); + buf_req++; + } +} + +static void hfi_session_prop_info(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_msg_session_property_info_packet *pkt = packet; + struct hfi_profile_level profile_level = {0}; + struct buffer_requirements bufreq; + struct getprop_buf *getprop; + void *data; + size_t len; + + inst->error = VIDC_ERR_NONE; + + if (!pkt->num_properties) { + dprintk(VIDC_ERR, "%s: no properties\n", __func__); + return; + } + + switch (pkt->rg_property_data[0]) { + case HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS: + memset(&bufreq, 0, sizeof(bufreq)); + session_get_prop_buf_req(pkt, &bufreq); + data = &bufreq; + len = sizeof(bufreq); + break; + case HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT: + session_get_prop_profile_level(pkt, &profile_level); + data = &profile_level; + len = sizeof(profile_level); + break; + default: + dprintk(VIDC_DBG, "%s: unknown property id:%x\n", __func__, + pkt->rg_property_data[0]); + return; + } + + getprop = kzalloc(sizeof(*getprop), GFP_KERNEL); + if (!getprop) { + dprintk(VIDC_ERR, "%s: getprop kzalloc failed\n", __func__); + return; + } + + getprop->data = kmemdup(data, len, GFP_KERNEL); + if (!getprop->data) { + dprintk(VIDC_ERR, "%s: kmemdup failed\n", __func__); + kfree(getprop); + return; + } + + mutex_lock(&inst->pending_getpropq.lock); + list_add_tail(&getprop->list, &inst->pending_getpropq.list); + mutex_unlock(&inst->pending_getpropq.lock); + + complete(&inst->done); +} + +static enum vidc_error +session_init_done_prop_read(struct hfi_msg_session_init_done_pkt *pkt, + struct vidc_hal_session_init_done *sess_init_done) +{ + u32 rem_bytes, num_properties; + u32 prop_id, next_offset = 0; + enum vidc_error error; + u32 prop_count = 0; + u8 *data_ptr; + + rem_bytes = pkt->size - sizeof(*pkt) + sizeof(u32); + + if (!rem_bytes) { + dprintk(VIDC_ERR, "%s: missing property info\n", __func__); + return VIDC_ERR_FAIL; + } + + error = to_vidc_error(pkt->error_type); + if (error) + return error; + + data_ptr = (u8 *) &pkt->rg_property_data[0]; + num_properties = pkt->num_properties; + + while (error == VIDC_ERR_NONE && num_properties && + rem_bytes >= sizeof(u32)) { + prop_id = *((u32 *)data_ptr); + next_offset = sizeof(u32); + + switch (prop_id) { + case HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED: { + struct hfi_capability_supported_info *prop = + (struct hfi_capability_supported_info *) + (data_ptr + next_offset); + u32 num_caps; + struct hfi_capability_supported *cap_ptr; + + if ((rem_bytes - next_offset) < sizeof(*cap_ptr)) { + error = VIDC_ERR_BAD_PARAM; + break; + } + + num_caps = prop->num_capabilities; + cap_ptr = &prop->rg_data[0]; + next_offset += sizeof(u32); + + while (num_caps && + (rem_bytes - next_offset) >= sizeof(u32)) { + hfi_copy_cap_prop(cap_ptr, sess_init_done); + cap_ptr++; + next_offset += sizeof(*cap_ptr); + num_caps--; + } + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED: { + struct hfi_uncompressed_format_supported *prop = + (struct hfi_uncompressed_format_supported *) + (data_ptr + next_offset); + u32 num_format_entries; + char *fmt_ptr; + struct hfi_uncompressed_plane_info *plane_info; + + if ((rem_bytes - next_offset) < sizeof(*prop)) { + error = VIDC_ERR_BAD_PARAM; + break; + } + + num_format_entries = prop->format_entries; + next_offset = sizeof(*prop) - sizeof(u32); + fmt_ptr = (char *)&prop->rg_format_info[0]; + + while (num_format_entries) { + u32 bytes_to_skip; + plane_info = + (struct hfi_uncompressed_plane_info *) fmt_ptr; + + if ((rem_bytes - next_offset) < + sizeof(*plane_info)) { + error = VIDC_ERR_BAD_PARAM; + break; + } + + bytes_to_skip = sizeof(*plane_info) - + sizeof(struct + hfi_uncompressed_plane_constraints) + + plane_info->num_planes * + sizeof(struct + hfi_uncompressed_plane_constraints); + + fmt_ptr += bytes_to_skip; + next_offset += bytes_to_skip; + num_format_entries--; + } + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED: { + struct hfi_properties_supported *prop = + (struct hfi_properties_supported *) + (data_ptr + next_offset); + + next_offset += sizeof(*prop) - sizeof(u32) + + prop->num_properties * sizeof(u32); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED: { + char *ptr = NULL; + int count = 0; + struct hfi_profile_level *prop_level; + struct hfi_profile_level_supported *prop = + (struct hfi_profile_level_supported *) + (data_ptr + next_offset); + + ptr = (char *) &prop->rg_profile_level[0]; + dprintk(VIDC_DBG, "prop->profile_count: %d\n", + prop->profile_count); + prop_count = prop->profile_count; + if (prop_count > MAX_PROFILE_COUNT) { + prop_count = MAX_PROFILE_COUNT; + dprintk(VIDC_WARN, + "prop count exceeds max profile count\n"); + } + while (prop_count) { + ptr++; + prop_level = (struct hfi_profile_level *) ptr; + sess_init_done-> + profile_level.profile_level[count].profile + = prop_level->profile; + sess_init_done-> + profile_level.profile_level[count].level + = prop_level->level; + prop_count--; + count++; + ptr += + sizeof(struct hfi_profile_level) / sizeof(u32); + } + next_offset += sizeof(*prop) - + sizeof(struct hfi_profile_level) + + prop->profile_count * + sizeof(struct hfi_profile_level); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED: { + next_offset += + sizeof(struct hfi_nal_stream_format_supported); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT: { + next_offset += sizeof(u32); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE: { + next_offset += sizeof(u32); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH: { + next_offset += sizeof(struct hfi_intra_refresh); + num_properties--; + break; + } + case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED: { + struct hfi_buffer_alloc_mode_supported *prop = + (struct hfi_buffer_alloc_mode_supported *) + (data_ptr + next_offset); + int i; + + if (prop->buffer_type == HFI_BUFFER_OUTPUT || + prop->buffer_type == HFI_BUFFER_OUTPUT2) { + sess_init_done->alloc_mode_out = 0; + + for (i = 0; i < prop->num_entries; i++) { + switch (prop->rg_data[i]) { + case HFI_BUFFER_MODE_STATIC: + sess_init_done->alloc_mode_out + |= HAL_BUFFER_MODE_STATIC; + break; + case HFI_BUFFER_MODE_DYNAMIC: + sess_init_done->alloc_mode_out + |= HAL_BUFFER_MODE_DYNAMIC; + break; + } + + if (i >= 32) { + dprintk(VIDC_ERR, + "%s - num_entries: %d from f/w seems suspect\n", + __func__, prop->num_entries); + break; + } + } + } + next_offset += sizeof(*prop) - + sizeof(u32) + prop->num_entries * sizeof(u32); + num_properties--; + break; + } + default: + dprintk(VIDC_DBG, "%s: default case %#x\n", __func__, + prop_id); + break; + } + + rem_bytes -= next_offset; + data_ptr += next_offset; + } + + return error; +} + +static void hfi_session_init_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_device *hdev = inst->core->hfidev; + struct hfi_msg_session_init_done_pkt *pkt = packet; + struct vidc_core_capability *cap = &inst->capability; + struct vidc_hal_session_init_done init_done; + enum vidc_error error; + + error = to_vidc_error(pkt->error_type); + if (error != VIDC_ERR_NONE) + goto done; + + memset(&init_done, 0, sizeof(init_done)); + + error = session_init_done_prop_read(pkt, &init_done); + if (error != VIDC_ERR_NONE) + goto done; + + cap->width = init_done.width; + cap->height = init_done.height; + cap->frame_rate = init_done.frame_rate; + cap->scale_x = init_done.scale_x; + cap->scale_y = init_done.scale_y; + cap->hier_p = init_done.hier_p; + cap->ltr_count = init_done.ltr_count; + cap->pixelprocess_capabilities = + call_hfi_op(hdev, get_core_capabilities); + cap->mbs_per_frame = init_done.mbs_per_frame; + cap->buffer_mode[CAPTURE_PORT] = init_done.alloc_mode_out; + cap->secure_output2_threshold = init_done.secure_output2_threshold; + cap->capability_set = true; + +done: + inst->error = error; + complete(&inst->done); +} + +static void hfi_session_load_res_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_msg_session_load_resources_done_packet *pkt = packet; + + inst->error = to_vidc_error(pkt->error_type); + complete(&inst->done); +} + +static void hfi_session_flush_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_msg_session_flush_done_packet *pkt = packet; + + inst->error = to_vidc_error(pkt->error_type); + complete(&inst->done); +} + +static void hfi_session_etb_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_msg_session_empty_buffer_done_packet *pkt = packet; + u32 flags = 0; + + inst->error = to_vidc_error(pkt->error_type); + + if (inst->error == VIDC_ERR_NOT_SUPPORTED) + flags |= V4L2_QCOM_BUF_INPUT_UNSUPPORTED; + if (inst->error == VIDC_ERR_BITSTREAM_ERR) + flags |= V4L2_QCOM_BUF_DATA_CORRUPT; + if (inst->error == VIDC_ERR_START_CODE_NOT_FOUND) + flags |= V4L2_MSM_VIDC_BUF_START_CODE_NOT_FOUND; + + if (!inst->empty_buf_done) + return; + + inst->empty_buf_done(inst, pkt->input_tag, pkt->filled_len, pkt->offset, + flags); +} + +static void hfi_session_ftb_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + bool is_decoder = session->is_decoder; + struct vidc_hal_fbd fbd = {0}; + enum hal_buffer buffer_type; + struct timeval timestamp; + int64_t time_usec = 0; + unsigned int error; + u32 flags = 0; + + if (!is_decoder) { + struct hfi_msg_session_fbd_compressed_packet *pkt = packet; + + fbd.timestamp_hi = pkt->time_stamp_hi; + fbd.timestamp_lo = pkt->time_stamp_lo; + fbd.flags1 = pkt->flags; + fbd.offset1 = pkt->offset; + fbd.alloc_len1 = pkt->alloc_len; + fbd.filled_len1 = pkt->filled_len; + fbd.picture_type = pkt->picture_type; + fbd.packet_buffer1 = pkt->packet_buffer; + fbd.extra_data_buffer = pkt->extra_data_buffer; + fbd.buffer_type = HAL_BUFFER_OUTPUT; + + error = to_vidc_error(pkt->error_type); + } else { + struct hfi_msg_session_fbd_uncompressed_plane0_packet *pkt; + + pkt = packet; + + fbd.timestamp_hi = pkt->time_stamp_hi; + fbd.timestamp_lo = pkt->time_stamp_lo; + fbd.flags1 = pkt->flags; + fbd.offset1 = pkt->offset; + fbd.alloc_len1 = pkt->alloc_len; + fbd.filled_len1 = pkt->filled_len; + fbd.picture_type = pkt->picture_type; + fbd.packet_buffer1 = pkt->packet_buffer; + fbd.extra_data_buffer = pkt->extra_data_buffer; + + if (pkt->stream_id == 0) + fbd.buffer_type = HAL_BUFFER_OUTPUT; + else if (pkt->stream_id == 1) + fbd.buffer_type = HAL_BUFFER_OUTPUT2; + + error = to_vidc_error(pkt->error_type); + } + + buffer_type = vidc_comm_get_hal_output_buffer(inst); + + if (fbd.buffer_type != buffer_type) + return; + + if (fbd.flags1 & HAL_BUFFERFLAG_READONLY) + flags |= V4L2_QCOM_BUF_FLAG_READONLY; + if (fbd.flags1 & HAL_BUFFERFLAG_EOS) + flags |= V4L2_QCOM_BUF_FLAG_EOS; + if (fbd.flags1 & HAL_BUFFERFLAG_CODECCONFIG) + flags &= ~V4L2_QCOM_BUF_FLAG_CODECCONFIG; + if (fbd.flags1 & HAL_BUFFERFLAG_SYNCFRAME) + flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME; + if (fbd.flags1 & HAL_BUFFERFLAG_EOSEQ) + flags |= V4L2_QCOM_BUF_FLAG_EOSEQ; + if (fbd.flags1 & HAL_BUFFERFLAG_DECODEONLY) + flags |= V4L2_QCOM_BUF_FLAG_DECODEONLY; + if (fbd.flags1 & HAL_BUFFERFLAG_DATACORRUPT) + flags |= V4L2_QCOM_BUF_DATA_CORRUPT; + if (fbd.flags1 & HAL_BUFFERFLAG_DROP_FRAME) + flags |= V4L2_QCOM_BUF_DROP_FRAME; + if (fbd.flags1 & HAL_BUFFERFLAG_MBAFF) + flags |= V4L2_MSM_BUF_FLAG_MBAFF; + if (fbd.flags1 & HAL_BUFFERFLAG_TS_DISCONTINUITY) + flags |= V4L2_QCOM_BUF_TS_DISCONTINUITY; + if (fbd.flags1 & HAL_BUFFERFLAG_TS_ERROR) + flags |= V4L2_QCOM_BUF_TS_ERROR; + + switch (fbd.picture_type) { + case HAL_PICTURE_IDR: + flags |= V4L2_QCOM_BUF_FLAG_IDRFRAME; + flags |= V4L2_BUF_FLAG_KEYFRAME; + break; + case HAL_PICTURE_I: + flags |= V4L2_BUF_FLAG_KEYFRAME; + break; + case HAL_PICTURE_P: + flags |= V4L2_BUF_FLAG_PFRAME; + break; + case HAL_PICTURE_B: + flags |= V4L2_BUF_FLAG_BFRAME; + break; + case HAL_FRAME_NOTCODED: + case HAL_UNUSED_PICT: + case HAL_FRAME_YUV: + break; + default: + break; + } + + if (!(fbd.flags1 & HAL_BUFFERFLAG_TIMESTAMPINVALID) && + fbd.filled_len1) { + time_usec = fbd.timestamp_hi; + time_usec = (time_usec << 32) | fbd.timestamp_lo; + } + + timestamp = ns_to_timeval(time_usec * NSEC_PER_USEC); + + if (!inst->fill_buf_done) + return; + + inst->error = error; + inst->fill_buf_done(inst, fbd.packet_buffer1, fbd.filled_len1, + fbd.offset1, flags, ×tamp); +} + +static void hfi_session_start_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_msg_session_start_done_packet *pkt = packet; + + inst->error = to_vidc_error(pkt->error_type); + complete(&inst->done); +} + +static void hfi_session_stop_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_msg_session_stop_done_packet *pkt = packet; + + inst->error = to_vidc_error(pkt->error_type); + complete(&inst->done); +} + +static void hfi_session_rel_res_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_msg_session_release_resources_done_packet *pkt = packet; + + inst->error = to_vidc_error(pkt->error_type); + complete(&inst->done); +} + +static void hfi_session_rel_buf_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_msg_session_release_buffers_done_packet *pkt = packet; + + /* + * the address of the released buffer can be extracted: + * if (pkt->rg_buffer_info) { + * cmd.data = &pkt->rg_buffer_info; + * cmd.size = sizeof(struct hfi_buffer_info); + * } + */ + inst->error = to_vidc_error(pkt->error_type); + complete(&inst->done); +} + +static void hfi_session_end_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_msg_session_end_done_pkt *pkt = packet; + + inst->error = to_vidc_error(pkt->error_type); + complete(&inst->done); +} + +static void hfi_session_abort_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_msg_sys_session_abort_done_packet *pkt = packet; + + inst->error = to_vidc_error(pkt->error_type); + complete(&inst->done); +} + +static void +hfi_session_get_seq_hdr_done(u32 device_id, void *sess, void *packet) +{ + struct hal_session *session = sess; + struct vidc_inst *inst = session->session_id; + struct hfi_msg_session_get_sequence_hdr_done_pkt *pkt = packet; + + /* + * output_done.packet_buffer1 = pkt->sequence_header; + * output_done.filled_len1 = pkt->header_len; + */ + + inst->error = to_vidc_error(pkt->error_type); + complete(&inst->done); +} + +typedef void (*done_handler)(u32, void *, void *); + +struct hfi_done_handler { + const char *name; + u32 packet; + u32 packet_sz; + u32 packet_sz2; + done_handler done; + bool is_sys_pkt; +}; + +static const struct hfi_done_handler handlers[] = { + {.name = "event_notify", + .packet = HFI_MSG_EVENT_NOTIFY, + .packet_sz = sizeof(struct hfi_msg_event_notify_pkt), + .done = hfi_event_notify, + }, + {.name = "sys_init_done", + .packet = HFI_MSG_SYS_INIT_DONE, + .packet_sz = sizeof(struct hfi_msg_sys_init_done_pkt), + .done = hfi_sys_init_done, + .is_sys_pkt = true, + }, + {.name = "sys_property_info", + .packet = HFI_MSG_SYS_PROPERTY_INFO, + .packet_sz = sizeof(struct hfi_msg_sys_property_info_packet), + .done = hfi_sys_property_info, + .is_sys_pkt = true, + }, + {.name = "sys_release_resource", + .packet = HFI_MSG_SYS_RELEASE_RESOURCE, + .packet_sz = sizeof(struct hfi_msg_sys_release_resource_done_pkt), + .done = hfi_sys_rel_resource_done, + .is_sys_pkt = true, + }, + {.name = "session_init_done", + .packet = HFI_MSG_SYS_SESSION_INIT_DONE, + .packet_sz = sizeof(struct hfi_msg_session_init_done_pkt), + .done = hfi_session_init_done, + }, + {.name = "session_end_done", + .packet = HFI_MSG_SYS_SESSION_END_DONE, + .packet_sz = sizeof(struct hfi_msg_session_end_done_pkt), + .done = hfi_session_end_done, + }, + {.name = "session_load_resources_done", + .packet = HFI_MSG_SESSION_LOAD_RESOURCES_DONE, + .packet_sz = sizeof(struct hfi_msg_session_load_resources_done_packet), + .done = hfi_session_load_res_done, + }, + {.name = "session_start_done", + .packet = HFI_MSG_SESSION_START_DONE, + .packet_sz = sizeof(struct hfi_msg_session_start_done_packet), + .done = hfi_session_start_done, + }, + {.name = "session_stop_done", + .packet = HFI_MSG_SESSION_STOP_DONE, + .packet_sz = sizeof(struct hfi_msg_session_stop_done_packet), + .done = hfi_session_stop_done, + }, + {.name = "session_abort_done", + .packet = HFI_MSG_SYS_SESSION_ABORT_DONE, + .packet_sz = sizeof(struct hfi_msg_sys_session_abort_done_packet), + .done = hfi_session_abort_done, + }, + {.name = "session_empty_buffer_done", + .packet = HFI_MSG_SESSION_EMPTY_BUFFER_DONE, + .packet_sz = sizeof(struct hfi_msg_session_empty_buffer_done_packet), + .done = hfi_session_etb_done, + }, + {.name = "session_fill_buffer_done", + .packet = HFI_MSG_SESSION_FILL_BUFFER_DONE, + .packet_sz = + sizeof(struct hfi_msg_session_fbd_uncompressed_plane0_packet), + .packet_sz2 = sizeof(struct hfi_msg_session_fbd_compressed_packet), + .done = hfi_session_ftb_done, + }, + {.name = "session_flush_done", + .packet = HFI_MSG_SESSION_FLUSH_DONE, + .packet_sz = sizeof(struct hfi_msg_session_flush_done_packet), + .done = hfi_session_flush_done, + }, + {.name = "session_propery_info", + .packet = HFI_MSG_SESSION_PROPERTY_INFO, + .packet_sz = sizeof(struct hfi_msg_session_property_info_packet), + .done = hfi_session_prop_info, + }, + {.name = "session_release_resources_done", + .packet = HFI_MSG_SESSION_RELEASE_RESOURCES_DONE, + .packet_sz = + sizeof(struct hfi_msg_session_release_resources_done_packet), + .done = hfi_session_rel_res_done, + }, + {.name = "session_get_sequence_header_done", + .packet = HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE, + .packet_sz = sizeof(struct hfi_msg_session_get_sequence_hdr_done_pkt), + .done = hfi_session_get_seq_hdr_done, + }, + {.name = "session_release_buffers_done", + .packet = HFI_MSG_SESSION_RELEASE_BUFFERS_DONE, + .packet_sz = + sizeof(struct hfi_msg_session_release_buffers_done_packet), + .done = hfi_session_rel_buf_done, + }, +}; + +void hfi_process_watchdog_timeout(u32 device_id) +{ + event_sys_error(device_id, SYS_WATCHDOG_TIMEOUT); +} + +u32 hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *hdr, + struct list_head *sessions, + struct mutex *session_lock) +{ + struct hal_session *session; + const struct hfi_done_handler *handler; + unsigned int i; + bool found = false; + + for (i = 0; i < ARRAY_SIZE(handlers); i++) { + handler = &handlers[i]; + + if (handler->packet != hdr->packet) + continue; + + found = true; + break; + } + + if (found == false) + return hdr->packet; + + if (hdr->size && hdr->size < handler->packet_sz && + hdr->size < handler->packet_sz2) { + pr_err("%s: bad packet size (%d should be %d, pkt type:%x)\n", + __func__, hdr->size, handler->packet_sz, hdr->packet); + + return hdr->packet; + } + + mutex_lock(session_lock); + if (handler->is_sys_pkt) { + session = NULL; + } else { + struct vidc_hal_session_cmd_pkt *pkt; + + pkt = (struct vidc_hal_session_cmd_pkt *)hdr; + session = to_hal_session(sessions, pkt->session_id); + + /* + * Event of type HFI_EVENT_SYS_ERROR will not have any session + * associated with it + */ + if (!session && hdr->packet != HFI_MSG_EVENT_NOTIFY) { + pr_err("%s: got invalid session id:%d\n", __func__, + pkt->session_id); + goto invalid_session; + } + } + + handler->done(device_id, session, hdr); + +invalid_session: + mutex_unlock(session_lock); + + return hdr->packet; +} diff --git a/drivers/media/platform/msm/vidc/hfi/venus/venus_hfi.c b/drivers/media/platform/msm/vidc/hfi/venus/venus_hfi.c new file mode 100644 index 000000000000..9b6bb44188c9 --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi/venus/venus_hfi.c @@ -0,0 +1,1890 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "hfi/hfi_packetization.h" +#include "msm_vidc_debug.h" +#include "venus_hfi.h" +#include "vidc_hfi_io.h" +#include "msm_smem.h" + +static struct hal_device_data hal_ctxt; + +/* Poll interval in uS */ +#define POLL_INTERVAL_US 50 + +enum tzbsp_video_state { + TZBSP_VIDEO_STATE_SUSPEND = 0, + TZBSP_VIDEO_STATE_RESUME +}; + +static int venus_hfi_session_clean(void *session); + +static void venus_pm_handler(struct work_struct *work); +static DECLARE_DELAYED_WORK(venus_hfi_pm_work, venus_pm_handler); +static int venus_hfi_resume(void *dev); +static inline int venus_power_on(struct venus_hfi_device *device); +static void venus_flush_debug_queue(struct venus_hfi_device *device, + void *packet); +static int venus_hfi_initialize_packetization(struct venus_hfi_device *device); + +static DECLARE_COMPLETION(release_resources_done); +static DECLARE_COMPLETION(pc_prep_done); + +static inline void venus_set_state(struct venus_hfi_device *hdev, + enum venus_state state) +{ + mutex_lock(&hdev->lock); + hdev->state = state; + mutex_unlock(&hdev->lock); +} + +static inline bool venus_is_valid_state(struct venus_hfi_device *hdev) +{ + return hdev->state != VENUS_STATE_DEINIT; +} + +static void venus_dump_packet(u8 *packet) +{ + u32 c = 0, packet_size = *(u32 *)packet; + const int row_size = 32; + /* + * row must contain enough for 0xdeadbaad * 8 to be converted into + * "de ad ba ab " * 8 + '\0' + */ + char row[3 * row_size]; + + for (c = 0; c * row_size < packet_size; ++c) { + int bytes_to_read = ((c + 1) * row_size > packet_size) ? + packet_size % row_size : row_size; + hex_dump_to_buffer(packet + c * row_size, bytes_to_read, + row_size, 4, row, sizeof(row), false); + dprintk(VIDC_PKT, "%s\n", row); + } +} + +static int venus_write_queue(struct iface_queue *queue, u8 *packet, + u32 *rx_req_is_set) +{ + struct hfi_queue_header *qhdr; + u32 packet_size_in_words, new_write_idx; + u32 empty_space, read_idx, write_idx; + u32 *write_ptr; + + if (!queue->qarray.kva) + return -EINVAL; + + qhdr = queue->qhdr; + if (!qhdr) + return -ENOMEM; + + if (vidc_debug & VIDC_PKT) + venus_dump_packet(packet); + + packet_size_in_words = (*(u32 *)packet) >> 2; + if (!packet_size_in_words) + return -EINVAL; + + read_idx = qhdr->read_idx; + write_idx = qhdr->write_idx; + + if (write_idx >= read_idx) + empty_space = qhdr->q_size - (write_idx - read_idx); + else + empty_space = read_idx - write_idx; + + if (empty_space <= packet_size_in_words) { + qhdr->tx_req = 1; + return -ENOSPC; + } + + qhdr->tx_req = 0; + + new_write_idx = write_idx + packet_size_in_words; + write_ptr = (u32 *)(queue->qarray.kva + (write_idx << 2)); + if (new_write_idx < qhdr->q_size) { + memcpy(write_ptr, packet, packet_size_in_words << 2); + } else { + new_write_idx -= qhdr->q_size; + memcpy(write_ptr, packet, + (packet_size_in_words - new_write_idx) << 2); + memcpy((void *)queue->qarray.kva, + packet + ((packet_size_in_words - new_write_idx) << 2), + new_write_idx << 2); + } + + /* Memory barrier to make sure packet is written before updating the + * write index + */ + mb(); + + qhdr->write_idx = new_write_idx; + *rx_req_is_set = (1 == qhdr->rx_req) ? 1 : 0; + + /* Memory barrier to make sure write index is updated before an + * interupt is raised on venus. + */ + mb(); + + return 0; +} + +static int venus_read_queue(struct iface_queue *queue, u8 *packet, + u32 *pb_tx_req_is_set) +{ + struct hfi_queue_header *qhdr; + u32 packet_size_in_words, new_read_idx; + u32 *read_ptr; + u32 receive_request = 0; + int ret = 0; + + if (!queue->qarray.kva) + return -EINVAL; + + /* Memory barrier to make sure data is valid before reading it */ + mb(); + + qhdr = queue->qhdr; + if (!qhdr) + return -ENOMEM; + + /* + * Do not set receive request for debug queue, if set, + * Venus generates interrupt for debug messages even + * when there is no response message available. + * In general debug queue will not become full as it + * is being emptied out for every interrupt from Venus. + * Venus will anyway generates interrupt if it is full. + */ + if (qhdr->type & HFI_Q_ID_CTRL_TO_HOST_MSG_Q) + receive_request = 1; + + if (qhdr->read_idx == qhdr->write_idx) { + qhdr->rx_req = receive_request; + *pb_tx_req_is_set = 0; + return -ENODATA; + } + + read_ptr = (u32 *)(queue->qarray.kva + (qhdr->read_idx << 2)); + packet_size_in_words = (*read_ptr) >> 2; + if (!packet_size_in_words) + return -EINVAL; + + new_read_idx = qhdr->read_idx + packet_size_in_words; + if (((packet_size_in_words << 2) <= VIDC_IFACEQ_VAR_HUGE_PKT_SIZE) && + qhdr->read_idx <= qhdr->q_size) { + if (new_read_idx < qhdr->q_size) { + memcpy(packet, read_ptr, packet_size_in_words << 2); + } else { + new_read_idx -= qhdr->q_size; + memcpy(packet, read_ptr, + (packet_size_in_words - new_read_idx) << 2); + memcpy(packet + + ((packet_size_in_words - new_read_idx) << 2), + (u8 *)queue->qarray.kva, + new_read_idx << 2); + } + } else { + /* bad packet received, dropping */ + new_read_idx = qhdr->write_idx; + ret = -EBADMSG; + } + + qhdr->read_idx = new_read_idx; + + if (qhdr->read_idx != qhdr->write_idx) + qhdr->rx_req = 0; + else + qhdr->rx_req = receive_request; + + *pb_tx_req_is_set = (1 == qhdr->tx_req) ? 1 : 0; + + if (vidc_debug & VIDC_PKT) + venus_dump_packet(packet); + + return ret; +} + +static int venus_alloc(struct venus_hfi_device *hdev, struct mem_desc *vmem, + u32 size, u32 align, u32 flags, u32 usage) +{ + struct smem *mem; + int ret; + + venus_hfi_resume(hdev); + + mem = smem_alloc(hdev->mem_client, size, align, flags, usage, 1); + if (IS_ERR(mem)) + return PTR_ERR(mem); + + ret = smem_cache_operations(hdev->mem_client, mem, SMEM_CACHE_CLEAN); + if (ret) { + dprintk(VIDC_WARN, "Failed to clean cache\n"); + dprintk(VIDC_WARN, "This may result in undefined behavior\n"); + } + + vmem->size = mem->size; + vmem->smem = mem; + vmem->kva = mem->kvaddr; + vmem->da = mem->da; + + return 0; +} + +static void venus_free(struct venus_hfi_device *hdev, struct smem *mem) +{ + smem_free(hdev->mem_client, mem); +} + +static void venus_writel(struct venus_hfi_device *hdev, u32 reg, u32 value) +{ + writel(value, hdev->hal_data->base + reg); +} + +static u32 venus_readl(struct venus_hfi_device *hdev, u32 reg) +{ + return readl(hdev->hal_data->base + reg); +} + +static void venus_set_registers(struct venus_hfi_device *hdev) +{ + struct reg_set *regs = &hdev->res->reg_set; + const struct reg_value_pair *tbl = regs->reg_tbl; + int i; + + for (i = 0; i < regs->count; i++) + venus_writel(hdev, tbl[i].reg, tbl[i].value); +} + +static int venus_iface_cmdq_write_nolock(struct venus_hfi_device *hdev, + void *pkt) +{ + u32 rx_req_is_set = 0; + struct iface_queue *queue; + struct vidc_hal_cmd_pkt_hdr *cmd_packet; + int ret; + + WARN(!mutex_is_locked(&hdev->lock), + "Cmd queue write lock must be acquired"); + + if (!venus_is_valid_state(hdev)) { + dprintk(VIDC_DBG, "%s: fw not in init state\n", __func__); + return -EINVAL; + } + + cmd_packet = (struct vidc_hal_cmd_pkt_hdr *)pkt; + hdev->last_packet_type = cmd_packet->packet_type; + + queue = &hdev->queues[IFACEQ_CMD_IDX]; + + ret = venus_write_queue(queue, pkt, &rx_req_is_set); + if (ret) { + dprintk(VIDC_ERR, "iface cmdq queue is full\n"); + return ret; + } + + ret = venus_power_on(hdev); + if (ret) + return ret; + + if (rx_req_is_set) + venus_writel(hdev, VIDC_CPU_IC_SOFTINT, + 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT); + + if (hdev->res->sw_power_collapsible) { + dprintk(VIDC_DBG, "cancel and queue delayed work again\n"); + + cancel_delayed_work(&venus_hfi_pm_work); + + if (!queue_delayed_work(hdev->venus_pm_workq, + &venus_hfi_pm_work, + msecs_to_jiffies( + vidc_pwr_collapse_delay))) { + dprintk(VIDC_DBG, + "PM work already scheduled\n"); + } + } + + return 0; +} + +static int venus_iface_cmdq_write(struct venus_hfi_device *hdev, void *pkt) +{ + int ret; + + mutex_lock(&hdev->lock); + ret = venus_iface_cmdq_write_nolock(hdev, pkt); + mutex_unlock(&hdev->lock); + + return ret; +} + +static int +venus_hfi_core_set_resource(void *device, struct vidc_resource_hdr *hdr, + void *resource_value, bool locked) +{ + struct venus_hfi_device *hdev = device; + struct hfi_sys_set_resource_pkt *pkt; + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + int ret; + + pkt = (struct hfi_sys_set_resource_pkt *) packet; + + ret = call_hfi_pkt_op(hdev, sys_set_resource, pkt, hdr, resource_value); + if (ret) + return ret; + + ret = locked ? venus_iface_cmdq_write(hdev, pkt) : + venus_iface_cmdq_write_nolock(hdev, pkt); + if (ret) + return ret; + + return 0; +} + +static int +venus_hfi_core_release_resource(void *device, struct vidc_resource_hdr *hdr) +{ + struct hfi_sys_release_resource_pkt pkt; + struct venus_hfi_device *hdev = device; + int ret; + + ret = call_hfi_pkt_op(hdev, sys_release_resource, &pkt, hdr); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, &pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_tzbsp_set_video_state(enum tzbsp_video_state state) +{ + return qcom_scm_set_video_state(state, 0); +} + +static int venus_reset_core(struct venus_hfi_device *hdev) +{ + u32 ctrl_status = 0, count = 0; + int max_tries = 100, ret = 0; + + venus_writel(hdev, VIDC_CTRL_INIT, 0x1); + + venus_writel(hdev, VIDC_WRAPPER_INTR_MASK, + VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK); + + while (!ctrl_status && count < max_tries) { + ctrl_status = venus_readl(hdev, VIDC_CPU_CS_SCIACMDARG0); + if ((ctrl_status & 0xfe) == 0x4) { + dprintk(VIDC_ERR, "invalid setting for UC_REGION\n"); + ret = -EINVAL; + break; + } + + usleep_range(500, 1000); + count++; + } + + if (count >= max_tries) + ret = -ETIMEDOUT; + + return ret; +} + +static int venus_run(struct venus_hfi_device *hdev) +{ + int ret; + + /* + * Re-program all of the registers that get reset as a result of + * regulator_disable() and _enable() + */ + venus_set_registers(hdev); + + venus_writel(hdev, VIDC_UC_REGION_ADDR, hdev->ifaceq_table.da); + venus_writel(hdev, VIDC_UC_REGION_SIZE, SHARED_QSIZE); + venus_writel(hdev, VIDC_CPU_CS_SCIACMDARG2, hdev->ifaceq_table.da); + venus_writel(hdev, VIDC_CPU_CS_SCIACMDARG1, 0x01); + if (hdev->sfr.da) + venus_writel(hdev, VIDC_SFR_ADDR, hdev->sfr.da); + + venus_writel(hdev, VIDC_WRAPPER_CLOCK_CONFIG, 0); + venus_writel(hdev, VIDC_WRAPPER_CPU_CLOCK_CONFIG, 0); + + ret = venus_reset_core(hdev); + if (ret) { + dprintk(VIDC_ERR, "Failed to reset venus core\n"); + return ret; + } + + return 0; +} + +static int venus_halt_axi(struct venus_hfi_device *hdev) +{ + void __iomem *base = hdev->hal_data->base; + u32 val; + int ret; + + /* Halt AXI and AXI IMEM VBIF Access */ + val = venus_readl(hdev, VENUS_VBIF_AXI_HALT_CTRL0); + val |= VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ; + venus_writel(hdev, VENUS_VBIF_AXI_HALT_CTRL0, val); + + /* Request for AXI bus port halt */ + ret = readl_poll_timeout(base + VENUS_VBIF_AXI_HALT_CTRL1, val, + val & VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK, + POLL_INTERVAL_US, + VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US); + if (ret) { + dprintk(VIDC_WARN, "AXI bus port halt timeout\n"); + return ret; + } + + return 0; +} + +static int venus_power_off(struct venus_hfi_device *hdev) +{ + int ret; + + if (!hdev->power_enabled) + return 0; + + ret = venus_halt_axi(hdev); + if (ret) { + dprintk(VIDC_WARN, "Failed to halt AXI\n"); + return ret; + } + + dprintk(VIDC_DBG, "Entering power collapse\n"); + + ret = venus_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND); + if (ret) { + dprintk(VIDC_WARN, "Failed to suspend video core %d\n", ret); + return ret; + } + + /* + * For some regulators, driver might have transfered the control to HW. + * So before touching any clocks, driver should get the regulator + * control back. Acquire regulators also makes sure that the regulators + * are turned ON. So driver can touch the clocks safely. + */ + + hdev->power_enabled = false; + + dprintk(VIDC_INFO, "Venus power collapsed\n"); + + return 0; +} + +static int venus_power_on(struct venus_hfi_device *hdev) +{ + int ret; + + if (hdev->power_enabled) + return 0; + + dprintk(VIDC_DBG, "Resuming from power collapse\n"); + + /* Reboot the firmware */ + ret = venus_tzbsp_set_video_state(TZBSP_VIDEO_STATE_RESUME); + if (ret) + goto err_set_video_state; + + ret = venus_run(hdev); + if (ret) { + dprintk(VIDC_ERR, "Failed to run venus core\n"); + goto err_run; + } + + /* + * Set the flag here to skip venus_power_on() which is + * being called again via *_alloc_set_imem() if imem is enabled + */ + hdev->power_enabled = true; + + dprintk(VIDC_INFO, "Resumed from power collapse\n"); + + return 0; + +err_run: + venus_tzbsp_set_video_state(TZBSP_VIDEO_STATE_SUSPEND); +err_set_video_state: + hdev->power_enabled = false; + dprintk(VIDC_ERR, "Failed to resume from power collapse\n"); + return ret; +} + +static int venus_iface_msgq_read_nolock(struct venus_hfi_device *hdev, + void *pkt) +{ + struct iface_queue *queue; + u32 tx_req_is_set = 0; + int ret; + + if (!venus_is_valid_state(hdev)) { + dprintk(VIDC_DBG, "%s: fw not in init state\n", __func__); + return -EINVAL; + } + + queue = &hdev->queues[IFACEQ_MSG_IDX]; + + ret = venus_read_queue(queue, (u8 *)pkt, &tx_req_is_set); + if (ret) + return ret; + + if (tx_req_is_set) + venus_writel(hdev, VIDC_CPU_IC_SOFTINT, + 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT); + + return 0; +} + +static int venus_iface_msgq_read(struct venus_hfi_device *hdev, void *pkt) +{ + int ret; + + mutex_lock(&hdev->lock); + ret = venus_iface_msgq_read_nolock(hdev, pkt); + mutex_unlock(&hdev->lock); + + return ret; +} + +static int venus_iface_dbgq_read_nolock(struct venus_hfi_device *hdev, + void *pkt) +{ + struct iface_queue *queue; + u32 tx_req_is_set = 0, value; + int ret; + + ret = venus_is_valid_state(hdev); + if (!ret) { + dprintk(VIDC_DBG, "%s: fw not in init state\n", __func__); + return -EINVAL; + } + + queue = &hdev->queues[IFACEQ_DBG_IDX]; + + ret = venus_read_queue(queue, pkt, &tx_req_is_set); + if (ret) + return ret; + + if (tx_req_is_set) { + value = 1 << VIDC_CPU_IC_SOFTINT_H2A_SHFT; + venus_writel(hdev, VIDC_CPU_IC_SOFTINT, value); + } + + return 0; +} + +static int venus_iface_dbgq_read(struct venus_hfi_device *hdev, void *pkt) +{ + int ret; + + if (!pkt) + return -EINVAL; + + mutex_lock(&hdev->lock); + ret = venus_iface_dbgq_read_nolock(hdev, pkt); + mutex_unlock(&hdev->lock); + + return ret; +} + +static void venus_set_qhdr_defaults(struct hfi_queue_header *qhdr) +{ + qhdr->status = 1; + qhdr->type = IFACEQ_DFLT_QHDR; + qhdr->q_size = IFACEQ_QUEUE_SIZE / 4; + qhdr->pkt_size = 0; + qhdr->rx_wm = 1; + qhdr->tx_wm = 1; + qhdr->rx_req = 1; + qhdr->tx_req = 0; + qhdr->rx_irq_status = 0; + qhdr->tx_irq_status = 0; + qhdr->read_idx = 0; + qhdr->write_idx = 0; +} + +static void venus_interface_queues_release(struct venus_hfi_device *hdev) +{ + mutex_lock(&hdev->lock); + + venus_free(hdev, hdev->ifaceq_table.smem); + venus_free(hdev, hdev->sfr.smem); + + memset(hdev->queues, 0, sizeof(hdev->queues)); + memset(&hdev->ifaceq_table, 0, sizeof(hdev->ifaceq_table)); + memset(&hdev->sfr, 0, sizeof(hdev->sfr)); + + smem_delete_client(hdev->mem_client); + + hdev->mem_client = NULL; + + mutex_unlock(&hdev->lock); +} + +static int venus_interface_queues_init(struct venus_hfi_device *hdev) +{ + struct hfi_queue_table_header *tbl_hdr; + struct hfi_queue_header *hdr; + struct iface_queue *queue; + struct hfi_sfr *sfr; + struct mem_desc mem; + int offset = 0, ret; + u32 i, size; + + size = SHARED_QSIZE - ALIGNED_SFR_SIZE - ALIGNED_QDSS_SIZE; + + ret = venus_alloc(hdev, &mem, size, 1, 0, + HAL_BUFFER_INTERNAL_CMD_QUEUE); + if (ret) + return ret; + + hdev->ifaceq_table.kva = mem.kva; + hdev->ifaceq_table.da = mem.da; + hdev->ifaceq_table.size = IFACEQ_TABLE_SIZE; + hdev->ifaceq_table.smem = mem.smem; + offset += hdev->ifaceq_table.size; + + for (i = 0; i < IFACEQ_NUM; i++) { + queue = &hdev->queues[i]; + queue->qarray.da = mem.da + offset; + queue->qarray.kva = mem.kva + offset; + queue->qarray.size = IFACEQ_QUEUE_SIZE; + queue->qarray.smem = NULL; + offset += queue->qarray.size; + queue->qhdr = + IFACEQ_GET_QHDR_START_ADDR(hdev->ifaceq_table.kva, i); + venus_set_qhdr_defaults(queue->qhdr); + } + + ret = venus_alloc(hdev, &mem, ALIGNED_SFR_SIZE, 1, 0, + HAL_BUFFER_INTERNAL_CMD_QUEUE); + if (ret) { + hdev->sfr.da = 0; + } else { + hdev->sfr.da = mem.da; + hdev->sfr.kva = mem.kva; + hdev->sfr.size = ALIGNED_SFR_SIZE; + hdev->sfr.smem = mem.smem; + } + + tbl_hdr = hdev->ifaceq_table.kva; + tbl_hdr->version = 0; + tbl_hdr->size = IFACEQ_TABLE_SIZE; + tbl_hdr->qhdr0_offset = sizeof(struct hfi_queue_table_header); + tbl_hdr->qhdr_size = sizeof(struct hfi_queue_header); + tbl_hdr->num_q = IFACEQ_NUM; + tbl_hdr->num_active_q = IFACEQ_NUM; + + queue = &hdev->queues[IFACEQ_CMD_IDX]; + hdr = queue->qhdr; + hdr->start_addr = queue->qarray.da; + hdr->type |= HFI_Q_ID_HOST_TO_CTRL_CMD_Q; + + queue = &hdev->queues[IFACEQ_MSG_IDX]; + hdr = queue->qhdr; + hdr->start_addr = queue->qarray.da; + hdr->type |= HFI_Q_ID_CTRL_TO_HOST_MSG_Q; + + queue = &hdev->queues[IFACEQ_DBG_IDX]; + hdr = queue->qhdr; + hdr->start_addr = queue->qarray.da; + hdr->type |= HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q; + + /* + * Set receive request to zero on debug queue as there is no + * need of interrupt from video hardware for debug messages + */ + hdr->rx_req = 0; + + sfr = hdev->sfr.kva; + sfr->buf_size = ALIGNED_SFR_SIZE; + + return 0; +} + +static int venus_sys_set_debug(struct venus_hfi_device *hdev, u32 debug) +{ + struct hfi_sys_set_property_pkt *pkt; + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + int ret; + + pkt = (struct hfi_sys_set_property_pkt *) &packet; + + ret = call_hfi_pkt_op(hdev, sys_debug_config, pkt, debug); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_sys_set_coverage(struct venus_hfi_device *hdev, u32 mode) +{ + struct hfi_sys_set_property_pkt *pkt; + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + int ret; + + pkt = (struct hfi_sys_set_property_pkt *) packet; + + ret = call_hfi_pkt_op(hdev, sys_coverage_config, pkt, mode); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_sys_set_idle_message(struct venus_hfi_device *hdev, + bool enable) +{ + struct hfi_sys_set_property_pkt *pkt; + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + int ret; + + if (!enable) + return 0; + + pkt = (struct hfi_sys_set_property_pkt *) packet; + + ret = call_hfi_pkt_op(hdev, sys_idle_indicator, pkt, enable); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_sys_set_power_control(struct venus_hfi_device *hdev, + bool enable) +{ + struct hfi_sys_set_property_pkt *pkt; + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + bool supported = false; + int ret; + + if (!supported) + return 0; + + pkt = (struct hfi_sys_set_property_pkt *) packet; + + ret = call_hfi_pkt_op(hdev, sys_power_control, pkt, enable); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_get_queue_size(struct venus_hfi_device *hdev, + unsigned int index) +{ + struct hfi_queue_header *qhdr; + + if (index >= IFACEQ_NUM) { + dprintk(VIDC_ERR, "Invalid index: %d\n", index); + return -EINVAL; + } + + qhdr = hdev->queues[index].qhdr; + if (!qhdr) { + dprintk(VIDC_ERR, "queue not present\n"); + return -EINVAL; + } + + return qhdr->read_idx - qhdr->write_idx; +} + +static void venus_set_default_sys_properties(struct venus_hfi_device *hdev) +{ + if (venus_sys_set_debug(hdev, vidc_fw_debug)) + dprintk(VIDC_WARN, "Setting fw_debug msg ON failed\n"); + + if (venus_sys_set_idle_message(hdev, + hdev->res->sys_idle_indicator || vidc_sys_idle_indicator)) + dprintk(VIDC_WARN, "Setting idle response ON failed\n"); + + if (venus_sys_set_power_control(hdev, vidc_fw_low_power_mode)) + dprintk(VIDC_WARN, "Setting h/w power collapse ON failed\n"); +} + +static int venus_send_session_cmd(void *session, int pkt_type) +{ + struct vidc_hal_session_cmd_pkt pkt; + struct hal_session *sess = session; + struct venus_hfi_device *hdev = sess->device; + int ret; + + ret = call_hfi_pkt_op(hdev, session_cmd, &pkt, pkt_type, session); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, &pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_prepare_power_collapse(struct venus_hfi_device *hdev) +{ + unsigned long timeout = msecs_to_jiffies(vidc_hw_rsp_timeout); + struct hfi_sys_pc_prep_pkt pkt; + int ret; + + init_completion(&pc_prep_done); + + ret = call_hfi_pkt_op(hdev, sys_pc_prep, &pkt); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, &pkt); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&pc_prep_done, timeout); + if (!ret) { + venus_flush_debug_queue(hdev, NULL); + return -ETIMEDOUT; + } + + return 0; +} + +static void venus_pm_handler(struct work_struct *work) +{ + struct venus_hfi_device *hdev; + u32 ctrl_status = 0; + int ret; + + hdev = list_first_entry(&hal_ctxt.dev_head, struct venus_hfi_device, + list); + if (!hdev) { + dprintk(VIDC_ERR, "%s: NULL device\n", __func__); + return; + } + + if (!hdev->power_enabled) { + dprintk(VIDC_DBG, "%s: Power already disabled\n", __func__); + return; + } + + mutex_lock(&hdev->lock); + ret = venus_is_valid_state(hdev); + mutex_unlock(&hdev->lock); + + if (!ret) { + dprintk(VIDC_WARN, + "Core is in bad state, Skipping power collapse\n"); + return; + } + + dprintk(VIDC_DBG, "Prepare for power collapse\n"); + + ret = venus_prepare_power_collapse(hdev); + if (ret) { + dprintk(VIDC_ERR, "Failed to prepare for PC %d\n", ret); + goto err_prepare_pc; + } + + mutex_lock(&hdev->lock); + + if (hdev->last_packet_type != HFI_CMD_SYS_PC_PREP) { + dprintk(VIDC_DBG, + "Last command (%#x) is not PC_PREP cmd\n", + hdev->last_packet_type); + goto skip_power_off; + } + + if (venus_get_queue_size(hdev, IFACEQ_MSG_IDX) || + venus_get_queue_size(hdev, IFACEQ_CMD_IDX)) { + dprintk(VIDC_DBG, "Cmd/msg queues are not empty\n"); + goto skip_power_off; + } + + ctrl_status = venus_readl(hdev, VIDC_CPU_CS_SCIACMDARG0); + if (!(ctrl_status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY)) { + dprintk(VIDC_DBG, + "Venus is not ready for power collapse (%#x)\n", + ctrl_status); + goto skip_power_off; + } + + ret = venus_power_off(hdev); + if (ret) { + dprintk(VIDC_ERR, "Failed venus power off\n"); + goto err_power_off; + } + + /* Cancel pending delayed works if any */ + cancel_delayed_work(&venus_hfi_pm_work); + + mutex_unlock(&hdev->lock); + + return; + +err_power_off: +skip_power_off: + + /* + * When power collapse is escaped, driver no need to inform Venus. + * Venus is self-sufficient to come out of the power collapse at + * any stage. Driver can skip power collapse and continue with + * normal execution. + */ + + /* Cancel pending delayed works if any */ + cancel_delayed_work(&venus_hfi_pm_work); + dprintk(VIDC_WARN, "Power off skipped (last pkt %#x, status: %#x)\n", + hdev->last_packet_type, ctrl_status); + + mutex_unlock(&hdev->lock); +err_prepare_pc: + return; +} + +static void venus_sfr_print(struct venus_hfi_device *hdev) +{ + struct hfi_sfr *sfr = hdev->sfr.kva; + void *p; + + if (!sfr) + return; + + p = memchr(sfr->rg_data, '\0', sfr->buf_size); + /* + * SFR isn't guaranteed to be NULL terminated since SYS_ERROR indicates + * that Venus is in the process of crashing. + */ + if (p == NULL) + sfr->rg_data[sfr->buf_size - 1] = '\0'; + + dprintk(VIDC_ERR, "SFR Message from FW: %s\n", sfr->rg_data); +} + +static void venus_process_msg_sys_error(struct venus_hfi_device *hdev, + void *packet) +{ + struct hfi_msg_event_notify_pkt *event_pkt = packet; + + if (event_pkt->event_id != HFI_EVENT_SYS_ERROR) + return; + + venus_set_state(hdev, VENUS_STATE_DEINIT); + + /* + * Once SYS_ERROR received from HW, it is safe to halt the AXI. + * With SYS_ERROR, Venus FW may have crashed and HW might be + * active and causing unnecessary transactions. Hence it is + * safe to stop all AXI transactions from venus subsystem. + */ + venus_halt_axi(hdev); + venus_sfr_print(hdev); +} + +static void venus_flush_debug_queue(struct venus_hfi_device *hdev, void *packet) +{ + bool local_packet = false; + + if (!hdev) + return; + + if (!packet) { + packet = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_TEMPORARY); + if (!packet) { + dprintk(VIDC_ERR, "In %s() Fail to allocate mem\n", + __func__); + return; + } + local_packet = true; + } + + while (!venus_iface_dbgq_read(hdev, packet)) { + struct hfi_msg_sys_coverage_pkt *pkt = packet; + + if (pkt->packet_type == HFI_MSG_SYS_COV) { +#ifdef CONFIG_MSM_VIDC_COV + int stm_size = 0; + dprintk(VIDC_DBG, "DbgQ pkt size: %d\n", pkt->msg_size); + stm_size = stm_log_inv_ts(0, 0, pkt->rg_msg_data, + pkt->msg_size); + if (stm_size == 0) + dprintk(VIDC_ERR, + "In %s, stm_log returned size of 0\n", + __func__); +#endif + } else { + struct hfi_msg_sys_debug_pkt *pkt = packet; + dprintk(VIDC_FW, "%s", pkt->rg_msg_data); + } + } + + if (local_packet) + kfree(packet); +} + +static void venus_response_handler(struct venus_hfi_device *hdev) +{ + void *pkt; + u32 ret; + + if (!hdev) { + dprintk(VIDC_ERR, "SPURIOUS_INTERRUPT\n"); + return; + } + + pkt = hdev->pkt_buf; + + if (hdev->intr_status & VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK) { + dprintk(VIDC_ERR, "received: watchdog timeout\n"); + venus_sfr_print(hdev); + disable_irq_nosync(hdev->hal_data->irq); + hfi_process_watchdog_timeout(hdev->device_id); + } + + while (!venus_iface_msgq_read(hdev, pkt)) { + ret = hfi_process_msg_packet(hdev->device_id, pkt, + &hdev->sessions, + &hdev->session_lock); + switch (ret) { + case HFI_MSG_EVENT_NOTIFY: + venus_process_msg_sys_error(hdev, pkt); + break; + case HFI_MSG_SYS_RELEASE_RESOURCE: + dprintk(VIDC_DBG, "received: HFI_MSG_SYS_RELEASE_RESOURCE\n"); + complete(&release_resources_done); + break; + case HFI_MSG_SYS_PC_PREP_DONE: + dprintk(VIDC_DBG, "received: HFI_MSG_SYS_PC_PREP_DONE\n"); + complete(&pc_prep_done); + break; + default: + break; + } + } + + venus_flush_debug_queue(hdev, pkt); +} + +static irqreturn_t venus_isr_thread(int irq, void *dev) +{ + struct venus_hfi_device *hdev = dev; + int ret; + + ret = venus_hfi_resume(hdev); + if (ret) { + dprintk(VIDC_ERR, "%s: Power enable failed\n", __func__); + return IRQ_NONE; + } + + if (hdev->res->sw_power_collapsible) { + dprintk(VIDC_DBG, "Cancel and queue delayed work again.\n"); + cancel_delayed_work(&venus_hfi_pm_work); + if (!queue_delayed_work(hdev->venus_pm_workq, + &venus_hfi_pm_work, + msecs_to_jiffies(vidc_pwr_collapse_delay))) { + dprintk(VIDC_DBG, "PM work already scheduled\n"); + } + } + + venus_response_handler(hdev); + + return IRQ_HANDLED; +} + +static irqreturn_t venus_isr(int irq, void *dev) +{ + struct venus_hfi_device *hdev = dev; + u32 status; + + status = venus_readl(hdev, VIDC_WRAPPER_INTR_STATUS); + + if (status & VIDC_WRAPPER_INTR_STATUS_A2H_BMSK || + status & VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK || + status & VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK) { + hdev->intr_status |= status; + hdev->reg_count++; + } else { + hdev->spur_count++; + } + + venus_writel(hdev, VIDC_CPU_CS_A2HSOFTINTCLR, 1); + venus_writel(hdev, VIDC_WRAPPER_INTR_CLEAR, status); + + return IRQ_WAKE_THREAD; +} + +static int venus_check_core_registered(struct hal_device_data *core, + void __iomem *reg_base, int irq) +{ + struct venus_hfi_device *hdev; + struct list_head *curr, *next; + + if (!core->dev_count) + return -EINVAL; + + list_for_each_safe(curr, next, &core->dev_head) { + hdev = list_entry(curr, struct venus_hfi_device, list); + if (hdev && hdev->hal_data->irq == irq && + hdev->hal_data->base == reg_base) + return 0; + } + + dprintk(VIDC_INFO, "Device not registered\n"); + + return -ENODEV; +} + +static int venus_request_interrupt(struct venus_hfi_device *hdev, + struct vidc_resources *res) +{ + struct hal_data *hal; + int ret; + + if (res->irq < 0 || !res->base) + return -EINVAL; + + ret = venus_check_core_registered(&hal_ctxt, res->base, res->irq); + if (!ret) { + dprintk(VIDC_ERR, "Core present/Already added\n"); + return -EEXIST; + } + + hal = kzalloc(sizeof(struct hal_data), GFP_KERNEL); + if (!hal) { + dprintk(VIDC_ERR, "Failed to alloc\n"); + return -ENOMEM; + } + + hdev->hal_data = hal; + hal->irq = res->irq; + hal->base = res->base; + + ret = request_threaded_irq(res->irq, venus_isr, + venus_isr_thread, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "vidc", hdev); + if (ret) { + dprintk(VIDC_ERR, "request_irq failed\n"); + goto err; + } + + return 0; + +err: + kfree(hal); + return ret; + +} + +static int venus_protect_cp_mem(struct venus_hfi_device *hdev) +{ + u32 cp_nonpixel_start = 0, cp_nonpixel_size = 0; + u32 cp_start = 0, cp_size = 0; + struct context_bank_info *cb; + int ret; + + if (!hdev) + return -EINVAL; + + list_for_each_entry(cb, &hdev->res->context_banks, list) { + if (!strcmp(cb->name, "venus_ns")) { + cp_size = cb->addr_range.start; + dprintk(VIDC_DBG, "%s memprot.cp_size: %#x\n", + __func__, cp_size); + } + + if (!strcmp(cb->name, "venus_sec_non_pixel")) { + cp_nonpixel_start = cb->addr_range.start; + cp_nonpixel_size = cb->addr_range.size; + dprintk(VIDC_DBG, + "%s memprot.cp_start: %#x size: %#x\n", + __func__, cp_nonpixel_start, + cp_nonpixel_size); + } + } + + ret = qcom_scm_mem_protect_video_var(cp_start, cp_size, + cp_nonpixel_start, + cp_nonpixel_size); + if (ret) { + dprintk(VIDC_ERR, "Failed to protect memory (%d)\n", ret); + return ret; + } + + return 0; +} + +static int venus_hfi_core_init(void *device) +{ + struct venus_hfi_device *hdev = device; + struct hfi_sys_get_property_pkt version_pkt; + struct hfi_sys_init_pkt pkt; + struct list_head *ptr, *next; + struct hal_session *session = NULL; + int ret; + + hdev->intr_status = 0; + hdev->power_enabled = true; + + mutex_lock(&hdev->session_lock); + list_for_each_safe(ptr, next, &hdev->sessions) { + /* This means that session list is not empty. Kick stale + * sessions out of our valid instance list, but keep the + * list_head inited so that list_del (in the future, called + * by session_clean()) will be valid. When client doesn't close + * them, then it is a genuine leak which driver can't fix. */ + session = list_entry(ptr, struct hal_session, list); + list_del_init(&session->list); + } + INIT_LIST_HEAD(&hdev->sessions); + mutex_unlock(&hdev->session_lock); + + if (hdev->mem_client) { + dprintk(VIDC_ERR, "memory client exists\n"); + return -EINVAL; + } + + hdev->mem_client = smem_new_client(hdev->res); + if (IS_ERR(hdev->mem_client)) + return PTR_ERR(hdev->mem_client); + + ret = venus_interface_queues_init(hdev); + if (ret) { + dprintk(VIDC_ERR, "failed to init queues\n"); + return ret; + } + + ret = venus_run(hdev); + if (ret) { + dprintk(VIDC_ERR, "run venus core failed (%d)\n", ret); + return ret; + } + + ret = call_hfi_pkt_op(hdev, sys_init, &pkt, HFI_VIDEO_ARCH_OX); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, &pkt); + if (ret) + return ret; + + ret = call_hfi_pkt_op(hdev, sys_image_version, &version_pkt); + if (ret || venus_iface_cmdq_write(hdev, &version_pkt)) + dprintk(VIDC_WARN, "Failed to send image version pkt to fw\n"); + + ret = venus_protect_cp_mem(hdev); + if (ret) + return ret; + + venus_set_state(hdev, VENUS_STATE_INIT); + + return 0; +} + +static int venus_hfi_core_release(void *device) +{ + struct venus_hfi_device *hdev = device; + int ret; + + if (hdev->mem_client) { + ret = venus_hfi_resume(device); + if (ret) + return ret; + + hdev->intr_status = 0; + } + + venus_set_state(hdev, VENUS_STATE_DEINIT); + + cancel_delayed_work(&venus_hfi_pm_work); + flush_workqueue(hdev->venus_pm_workq); + + venus_interface_queues_release(hdev); + + /* + * Halt the AXI to make sure there are no pending transactions. + * Clocks should be unprepared after making sure axi is halted. + */ + venus_halt_axi(hdev); + + hdev->power_enabled = false; + + return 0; +} + +static int venus_hfi_core_ping(void *device) +{ + struct venus_hfi_device *hdev = device; + struct hfi_cmd_sys_ping_packet pkt; + int ret; + + ret = call_hfi_pkt_op(hdev, sys_ping, &pkt); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, &pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_hfi_core_trigger_ssr(void *device, + enum hal_ssr_trigger_type type) +{ + struct hfi_sys_test_ssr_pkt pkt; + struct venus_hfi_device *hdev = device; + int ret; + + ret = call_hfi_pkt_op(hdev, ssr_cmd, type, &pkt); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, &pkt); + if (ret) + return ret; + + return 0; +} + +static void *venus_hfi_session_init(void *device, void *session_id, + enum hal_domain session_type, + enum hal_video_codec codec_type) +{ + struct venus_hfi_device *hdev = device; + struct hfi_session_init_pkt pkt; + struct hal_session *new_session; + int ret; + + new_session = kzalloc(sizeof(*new_session), GFP_KERNEL); + if (!new_session) + return ERR_PTR(-ENOMEM); + + new_session->session_id = session_id; + new_session->is_decoder = session_type == HAL_VIDEO_DOMAIN_DECODER; + new_session->device = hdev; + + mutex_lock(&hdev->session_lock); + list_add_tail(&new_session->list, &hdev->sessions); + mutex_unlock(&hdev->session_lock); + + venus_set_default_sys_properties(device); + + ret = call_hfi_pkt_op(hdev, session_init, &pkt, new_session, + session_type, codec_type); + if (ret) + goto err_session_init_fail; + + ret = venus_iface_cmdq_write(hdev, &pkt); + if (ret) + goto err_session_init_fail; + + return new_session; + +err_session_init_fail: + venus_hfi_session_clean(new_session); + return ERR_PTR(ret); +} + +static int venus_hfi_session_end(void *session) +{ + struct hal_session *sess = session; + struct venus_hfi_device *hdev = sess->device; + + if (vidc_fw_coverage) { + if (venus_sys_set_coverage(hdev, vidc_fw_coverage)) + dprintk(VIDC_WARN, "Fw_coverage msg ON failed\n"); + } + + return venus_send_session_cmd(session, HFI_CMD_SYS_SESSION_END); +} + +static int venus_hfi_session_abort(void *session) +{ + struct hal_session *sess = session; + struct venus_hfi_device *hdev = sess->device; + + venus_flush_debug_queue(hdev, NULL); + + return venus_send_session_cmd(session, HFI_CMD_SYS_SESSION_ABORT); +} + +static int venus_hfi_session_clean(void *session) +{ + struct hal_session *sess = session; + struct venus_hfi_device *hdev = sess->device; + + venus_flush_debug_queue(hdev, NULL); + + mutex_lock(&hdev->session_lock); + list_del(&sess->list); + kfree(sess); + mutex_unlock(&hdev->session_lock); + + return 0; +} + +static int venus_hfi_session_flush(void *sess, enum hal_flush flush_mode) +{ + struct hal_session *session = sess; + struct venus_hfi_device *hdev = session->device; + struct hfi_cmd_session_flush_packet pkt; + int ret; + + ret = call_hfi_pkt_op(hdev, session_flush, &pkt, session, flush_mode); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, &pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_hfi_session_start(void *sess) +{ + return venus_send_session_cmd(sess, HFI_CMD_SESSION_START); +} + +static int venus_hfi_session_stop(void *sess) +{ + return venus_send_session_cmd(sess, HFI_CMD_SESSION_STOP); +} + +static int venus_hfi_session_etb(void *sess, struct vidc_frame_data *in_frame) +{ + struct hal_session *session = sess; + struct venus_hfi_device *hdev = session->device; + int ret; + + if (session->is_decoder) { + struct hfi_cmd_session_empty_buffer_compressed_packet pkt; + + ret = call_hfi_pkt_op(hdev, session_etb_decoder, + &pkt, session, in_frame); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, &pkt); + } else { + struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet + pkt; + + ret = call_hfi_pkt_op(hdev, session_etb_encoder, + &pkt, session, in_frame); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, &pkt); + } + + if (ret) + return ret; + + return 0; +} + +static int venus_hfi_session_ftb(void *sess, struct vidc_frame_data *out_frame) +{ + struct hal_session *session = sess; + struct venus_hfi_device *hdev = session->device; + struct hfi_cmd_session_fill_buffer_packet pkt; + int ret; + + ret = call_hfi_pkt_op(hdev, session_ftb, &pkt, session, out_frame); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, &pkt); + if (ret) + return ret; + + return 0; +} + +static int +venus_hfi_session_set_buffers(void *sess, struct vidc_buffer_addr_info *bai) +{ + struct hal_session *session = sess; + struct venus_hfi_device *hdev = session->device; + struct hfi_session_set_buffers_pkt *pkt; + u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE]; + int ret; + + if (bai->buffer_type == HAL_BUFFER_INPUT) + return 0; + + pkt = (struct hfi_session_set_buffers_pkt *)packet; + + ret = call_hfi_pkt_op(hdev, session_set_buffers, pkt, session, bai); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_hfi_session_release_buffers(void *sess, + struct vidc_buffer_addr_info *bai) +{ + struct hal_session *session = sess; + struct venus_hfi_device *hdev = session->device; + struct hfi_cmd_session_release_buffer_packet *pkt; + u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE]; + int ret; + + if (bai->buffer_type == HAL_BUFFER_INPUT) + return 0; + + pkt = (struct hfi_cmd_session_release_buffer_packet *) packet; + + ret = call_hfi_pkt_op(hdev, session_release_buffers, pkt, session, bai); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_hfi_session_load_res(void *sess) +{ + return venus_send_session_cmd(sess, HFI_CMD_SESSION_LOAD_RESOURCES); +} + +static int venus_hfi_session_release_res(void *sess) +{ + return venus_send_session_cmd(sess, HFI_CMD_SESSION_RELEASE_RESOURCES); +} + +static int venus_hfi_session_parse_seq_hdr(void *sess, + struct vidc_seq_hdr *seq_hdr) +{ + struct hal_session *session = sess; + struct venus_hfi_device *hdev = session->device; + struct hfi_cmd_session_parse_sequence_header_packet *pkt; + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + int ret; + + pkt = (struct hfi_cmd_session_parse_sequence_header_packet *) packet; + + ret = call_hfi_pkt_op(hdev, session_parse_seq_header, + pkt, session, seq_hdr); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, pkt); + if (ret) + return ret; + + return 0; +} + +static int +venus_hfi_session_get_seq_hdr(void *sess, struct vidc_seq_hdr *seq_hdr) +{ + struct hal_session *session = sess; + struct venus_hfi_device *hdev = session->device; + struct hfi_session_get_sequence_header_pkt *pkt; + u8 packet[VIDC_IFACEQ_VAR_SMALL_PKT_SIZE]; + int ret; + + pkt = (struct hfi_session_get_sequence_header_pkt *) packet; + + ret = call_hfi_pkt_op(hdev, session_get_seq_hdr, pkt, session, seq_hdr); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, pkt); + if (ret) + return ret;; + + return 0; +} + +static int venus_hfi_session_set_property(void *sess, enum hal_property ptype, + void *pdata) +{ + struct hal_session *session = sess; + struct venus_hfi_device *hdev = session->device; + struct hfi_session_set_property_pkt *pkt; + u8 packet[VIDC_IFACEQ_VAR_LARGE_PKT_SIZE]; + int ret; + + pkt = (struct hfi_session_set_property_pkt *) packet; + + ret = call_hfi_pkt_op(hdev, session_set_property, pkt, session, ptype, + pdata); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_hfi_session_get_property(void *sess, enum hal_property ptype) +{ + struct hal_session *session = sess; + struct venus_hfi_device *hdev = session->device; + struct hfi_cmd_session_get_property_packet pkt = {0}; + int ret; + + ret = call_hfi_pkt_op(hdev, session_get_property, &pkt, session, ptype); + if (ret) + return ret; + + ret = venus_iface_cmdq_write(hdev, &pkt); + if (ret) + return ret; + + return 0; +} + +static int venus_hfi_get_stride_scanline(int color_fmt, int width, int height, + int *stride, int *scanlines) +{ + if (stride) + *stride = VENUS_Y_STRIDE(color_fmt, width); + if (scanlines) + *scanlines = VENUS_Y_SCANLINES(color_fmt, height); + + return 0; +} + +static int venus_hfi_get_core_capabilities(void) +{ + return HAL_VIDEO_ENCODER_ROTATION_CAPABILITY | + HAL_VIDEO_ENCODER_SCALING_CAPABILITY | + HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY | + HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY; +} + +static int venus_hfi_resume(void *dev) +{ + struct venus_hfi_device *hdev = dev; + int ret; + + mutex_lock(&hdev->lock); + ret = venus_power_on(hdev); + mutex_unlock(&hdev->lock); + + return ret; +} + +static int venus_hfi_suspend(void *dev) +{ + struct venus_hfi_device *hdev = dev; + int ret; + + if (hdev->power_enabled) { + ret = flush_delayed_work(&venus_hfi_pm_work); + dprintk(VIDC_INFO, "%s flush delayed work %d\n", __func__, ret); + } + + return 0; +} + +static enum hal_default_properties venus_hfi_get_default_properties(void *dev) +{ + enum hal_default_properties prop = 0; + struct venus_hfi_device *hdev = dev; + + if (hdev->packetization_type == HFI_PACKETIZATION_3XX) + prop = HAL_VIDEO_DYNAMIC_BUF_MODE; + + return prop; +} + +static const struct hfi_ops venus_hfi_ops = { + .core_init = venus_hfi_core_init, + .core_release = venus_hfi_core_release, + .core_ping = venus_hfi_core_ping, + .core_trigger_ssr = venus_hfi_core_trigger_ssr, + + .session_init = venus_hfi_session_init, + .session_end = venus_hfi_session_end, + .session_abort = venus_hfi_session_abort, + .session_clean = venus_hfi_session_clean, + .session_flush = venus_hfi_session_flush, + .session_start = venus_hfi_session_start, + .session_stop = venus_hfi_session_stop, + .session_etb = venus_hfi_session_etb, + .session_ftb = venus_hfi_session_ftb, + .session_set_buffers = venus_hfi_session_set_buffers, + .session_release_buffers = venus_hfi_session_release_buffers, + .session_load_res = venus_hfi_session_load_res, + .session_release_res = venus_hfi_session_release_res, + .session_parse_seq_hdr = venus_hfi_session_parse_seq_hdr, + .session_get_seq_hdr = venus_hfi_session_get_seq_hdr, + .session_set_property = venus_hfi_session_set_property, + .session_get_property = venus_hfi_session_get_property, + + .get_stride_scanline = venus_hfi_get_stride_scanline, + .get_core_capabilities = venus_hfi_get_core_capabilities, + .resume = venus_hfi_resume, + .suspend = venus_hfi_suspend, + .get_default_properties = venus_hfi_get_default_properties, +}; + +void venus_hfi_deinitialize(struct hfi_device *hfidev) +{ + struct venus_hfi_device *close, *tmp, *dev; + + dev = hfidev->hfi_device_data; + + list_for_each_entry_safe(close, tmp, &hal_ctxt.dev_head, list) { + if (close->hal_data->irq != dev->hal_data->irq) + continue; + + hal_ctxt.dev_count--; + list_del(&close->list); + destroy_workqueue(close->venus_pm_workq); + free_irq(dev->hal_data->irq, close); + kfree(close->hal_data); + kfree(close); + break; + } + + kfree(hfidev); +} + +static int venus_hfi_initialize_packetization(struct venus_hfi_device *hdev) +{ + const char *hfi_version; + + hfi_version = hdev->res->hfi_version; + + if (!hfi_version) { + hdev->packetization_type = HFI_PACKETIZATION_LEGACY; + } else if (!strcmp(hfi_version, "3xx")) { + hdev->packetization_type = HFI_PACKETIZATION_3XX; + } else { + dprintk(VIDC_ERR, "Unsupported hfi version\n"); + return -EINVAL; + } + + hdev->pkt_ops = hfi_get_pkt_ops(hdev->packetization_type); + if (!hdev->pkt_ops) { + dprintk(VIDC_ERR, "Failed to get pkt_ops handle\n"); + return -EINVAL; + } + + return 0; +} + +static void *venus_hfi_add_device(u32 device_id, struct vidc_resources *res) +{ + struct venus_hfi_device *hdev; + int ret; + + hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); + if (!hdev) + return ERR_PTR(-ENOMEM); + + ret = venus_request_interrupt(hdev, res); + if (ret) + goto err_kfree; + + hdev->res = res; + hdev->device_id = device_id; + + ret = venus_hfi_initialize_packetization(hdev); + if (ret) { + dprintk(VIDC_ERR, "Failed to initialize packetization\n"); + goto err_kfree; + } + + hdev->venus_pm_workq = + create_singlethread_workqueue("pm_workerq_venus"); + if (!hdev->venus_pm_workq) { + dprintk(VIDC_ERR, ": create pm workq failed\n"); + ret = -ENOMEM; + goto err_kfree; + } + + mutex_init(&hdev->lock); + mutex_init(&hdev->session_lock); + + if (!hal_ctxt.dev_count) + INIT_LIST_HEAD(&hal_ctxt.dev_head); + + INIT_LIST_HEAD(&hdev->list); + INIT_LIST_HEAD(&hdev->sessions); + list_add_tail(&hdev->list, &hal_ctxt.dev_head); + hal_ctxt.dev_count++; + + return hdev; + +err_kfree: + kfree(hdev); + return ERR_PTR(ret); +} + +struct hfi_device * +venus_hfi_initialize(u32 device_id, struct vidc_resources *res) +{ + struct hfi_device *hfidev; + + if (!res) + return ERR_PTR(-EINVAL); + + hfidev = kzalloc(sizeof(*hfidev), GFP_KERNEL); + if (!hfidev) + return ERR_PTR(-ENOMEM); + + hfidev->hfi_device_data = venus_hfi_add_device(device_id, res); + if (IS_ERR(hfidev->hfi_device_data)) + return ERR_CAST(hfidev->hfi_device_data); + + hfidev->ops = &venus_hfi_ops; + + return hfidev; +} diff --git a/drivers/media/platform/msm/vidc/hfi/venus/venus_hfi.h b/drivers/media/platform/msm/vidc/hfi/venus/venus_hfi.h new file mode 100644 index 000000000000..6cd6d59318f9 --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi/venus/venus_hfi.h @@ -0,0 +1,150 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __H_VENUS_HFI_H__ +#define __H_VENUS_HFI_H__ + +#include +#include +#include +#include + +#include "msm_vidc_resources.h" + +#include "hfi/vidc_hfi_api.h" +#include "hfi/vidc_hfi_helper.h" +#include "hfi/hfi_packetization.h" + +#define HFI_MASK_QHDR_TX_TYPE 0xFF000000 +#define HFI_MASK_QHDR_RX_TYPE 0x00FF0000 +#define HFI_MASK_QHDR_PRI_TYPE 0x0000FF00 +#define HFI_MASK_QHDR_Q_ID_TYPE 0x000000FF + +#define HFI_Q_ID_HOST_TO_CTRL_CMD_Q 0x00 +#define HFI_Q_ID_CTRL_TO_HOST_MSG_Q 0x01 +#define HFI_Q_ID_CTRL_TO_HOST_DEBUG_Q 0x02 +#define HFI_MASK_QHDR_STATUS 0x000000FF + +#define VIDC_MAX_UNCOMPRESSED_FMT_PLANES 3 + +#define IFACEQ_NUM 3 +#define IFACEQ_CMD_IDX 0 +#define IFACEQ_MSG_IDX 1 +#define IFACEQ_DBG_IDX 2 +#define IFACEQ_MAX_BUF_COUNT 50 +#define IFACEQ_MAX_PARALLEL_CLNTS 16 +#define IFACEQ_DFLT_QHDR 0x01010000 + +struct hfi_queue_table_header { + u32 version; + u32 size; + u32 qhdr0_offset; + u32 qhdr_size; + u32 num_q; + u32 num_active_q; +}; + +struct hfi_queue_header { + u32 status; + u32 start_addr; + u32 type; + u32 q_size; + u32 pkt_size; + u32 pkt_drop_cnt; + u32 rx_wm; + u32 tx_wm; + u32 rx_req; + u32 tx_req; + u32 rx_irq_status; + u32 tx_irq_status; + u32 read_idx; + u32 write_idx; +}; + +#define IFACEQ_TABLE_SIZE \ + (sizeof(struct hfi_queue_table_header) + \ + sizeof(struct hfi_queue_header) * IFACEQ_NUM) + +#define IFACEQ_QUEUE_SIZE (VIDC_IFACEQ_MAX_PKT_SIZE * \ + IFACEQ_MAX_BUF_COUNT * IFACEQ_MAX_PARALLEL_CLNTS) + +#define IFACEQ_GET_QHDR_START_ADDR(ptr, i) \ + (void *)((ptr + sizeof(struct hfi_queue_table_header)) + \ + (i * sizeof(struct hfi_queue_header))) + +#define QDSS_SIZE 4096 +#define SFR_SIZE 4096 +#define QUEUE_SIZE (IFACEQ_TABLE_SIZE + \ + (IFACEQ_QUEUE_SIZE * IFACEQ_NUM)) + +#define ALIGNED_QDSS_SIZE ALIGN(QDSS_SIZE, SZ_4K) +#define ALIGNED_SFR_SIZE ALIGN(SFR_SIZE, SZ_4K) +#define ALIGNED_QUEUE_SIZE ALIGN(QUEUE_SIZE, SZ_4K) +#define SHARED_QSIZE ALIGN(ALIGNED_SFR_SIZE + ALIGNED_QUEUE_SIZE + \ + ALIGNED_QDSS_SIZE, SZ_1M) + +struct mem_desc { + u32 da; /* device address */ + void *kva; /* kernel virtual address */ + u32 size; + struct smem *smem; +}; + +struct iface_queue { + void *qhdr; + struct mem_desc qarray; +}; + +/* Internal data used in vidc_hal not exposed to msm_vidc*/ +struct hal_data { + u32 irq; + void __iomem *base; +}; + +enum venus_state { + VENUS_STATE_DEINIT = 1, + VENUS_STATE_INIT, +}; + +struct venus_hfi_device { + struct list_head list; + struct list_head sessions; + u32 intr_status; + u32 device_id; + u32 clk_load; + u32 codecs_enabled; + u32 last_packet_type; + bool power_enabled; + struct mutex lock; + struct mutex session_lock; + struct mem_desc ifaceq_table; + struct mem_desc sfr; + struct iface_queue queues[IFACEQ_NUM]; + struct smem_client *mem_client; + struct hal_data *hal_data; + struct workqueue_struct *venus_pm_workq; + int spur_count; + int reg_count; + struct vidc_resources *res; + enum venus_state state; + const struct hfi_packetization_ops *pkt_ops; + enum hfi_packetization_type packetization_type; + u8 pkt_buf[VIDC_IFACEQ_VAR_HUGE_PKT_SIZE]; +}; + +void venus_hfi_deinitialize(struct hfi_device *device); + +struct hfi_device * +venus_hfi_initialize(u32 device_id, struct vidc_resources *res); + +#endif diff --git a/drivers/media/platform/msm/vidc/hfi/venus/vidc_hfi_io.h b/drivers/media/platform/msm/vidc/hfi/venus/vidc_hfi_io.h new file mode 100644 index 000000000000..337291b0042f --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi/venus/vidc_hfi_io.h @@ -0,0 +1,191 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __VIDC_HFI_IO_H__ +#define __VIDC_HFI_IO_H__ + +#include + +#define VENUS_VCODEC_SS_CLOCK_HALT 0x0000000C +#define VENUS_VPP_CORE_SW_RESET 0x00042004 +#define VENUS_VPP_CTRL_CTRL_RESET 0x00041008 + +#define VIDC_VBIF_BASE_OFFS 0x00080000 +#define VIDC_VBIF_VERSION (VIDC_VBIF_BASE_OFFS + 0x00) +#define VIDC_VENUS_VBIF_DDR_OUT_MAX_BURST \ + (VIDC_VBIF_BASE_OFFS + 0xD8) +#define VIDC_VENUS_VBIF_OCMEM_OUT_MAX_BURST \ + (VIDC_VBIF_BASE_OFFS + 0xDC) +#define VIDC_VENUS_VBIF_ROUND_ROBIN_QOS_ARB \ + (VIDC_VBIF_BASE_OFFS + 0x124) + +#define VIDC_CPU_BASE_OFFS 0x000C0000 +#define VIDC_CPU_CS_BASE_OFFS (VIDC_CPU_BASE_OFFS + 0x00012000) +#define VIDC_CPU_IC_BASE_OFFS (VIDC_CPU_BASE_OFFS + 0x0001F000) + +#define VIDC_CPU_CS_REMAP_OFFS (VIDC_CPU_CS_BASE_OFFS + 0x00) +#define VIDC_CPU_CS_TIMER_CONTROL (VIDC_CPU_CS_BASE_OFFS + 0x04) +#define VIDC_CPU_CS_A2HSOFTINTEN (VIDC_CPU_CS_BASE_OFFS + 0x10) +#define VIDC_CPU_CS_A2HSOFTINTENCLR (VIDC_CPU_CS_BASE_OFFS + 0x14) +#define VIDC_CPU_CS_A2HSOFTINT (VIDC_CPU_CS_BASE_OFFS + 0x18) +#define VIDC_CPU_CS_A2HSOFTINTCLR (VIDC_CPU_CS_BASE_OFFS + 0x1C) +#define VIDC_CPU_CS_SCIACMD (VIDC_CPU_CS_BASE_OFFS + 0x48) + +/* HFI_CTRL_STATUS */ +#define VIDC_CPU_CS_SCIACMDARG0 (VIDC_CPU_CS_BASE_OFFS + 0x4C) +#define VIDC_CPU_CS_SCIACMDARG0_BMSK 0xff +#define VIDC_CPU_CS_SCIACMDARG0_SHFT 0x0 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK 0xfe +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_SHFT 0x1 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_BMSK 0x1 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_STATUS_SHFT 0x0 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY 0x100 +#define VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK 0x40000000 + +/* HFI_QTBL_INFO */ +#define VIDC_CPU_CS_SCIACMDARG1 (VIDC_CPU_CS_BASE_OFFS + 0x50) + +/* HFI_QTBL_ADDR */ +#define VIDC_CPU_CS_SCIACMDARG2 (VIDC_CPU_CS_BASE_OFFS + 0x54) + +/* HFI_VERSION_INFO */ +#define VIDC_CPU_CS_SCIACMDARG3 (VIDC_CPU_CS_BASE_OFFS + 0x58) +#define VIDC_CPU_IC_IRQSTATUS (VIDC_CPU_IC_BASE_OFFS + 0x00) +#define VIDC_CPU_IC_FIQSTATUS (VIDC_CPU_IC_BASE_OFFS + 0x04) +#define VIDC_CPU_IC_RAWINTR (VIDC_CPU_IC_BASE_OFFS + 0x08) +#define VIDC_CPU_IC_INTSELECT (VIDC_CPU_IC_BASE_OFFS + 0x0C) +#define VIDC_CPU_IC_INTENABLE (VIDC_CPU_IC_BASE_OFFS + 0x10) +#define VIDC_CPU_IC_INTENACLEAR (VIDC_CPU_IC_BASE_OFFS + 0x14) +#define VIDC_CPU_IC_SOFTINT (VIDC_CPU_IC_BASE_OFFS + 0x18) +#define VIDC_CPU_IC_SOFTINT_H2A_BMSK 0x8000 +#define VIDC_CPU_IC_SOFTINT_H2A_SHFT 0xF +#define VIDC_CPU_IC_SOFTINTCLEAR (VIDC_CPU_IC_BASE_OFFS + 0x1C) + +/*--------------------------------------------------------------------------- + * MODULE: vidc_wrapper + *--------------------------------------------------------------------------*/ +#define VIDC_WRAPPER_BASE_OFFS 0x000E0000 + +#define VIDC_WRAPPER_HW_VERSION (VIDC_WRAPPER_BASE_OFFS + 0x00) +#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_MASK 0x78000000 +#define VIDC_WRAPPER_HW_VERSION_MAJOR_VERSION_SHIFT 28 +#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_MASK 0xFFF0000 +#define VIDC_WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT 16 +#define VIDC_WRAPPER_HW_VERSION_STEP_VERSION_MASK 0xFFFF + +#define VIDC_WRAPPER_CLOCK_CONFIG (VIDC_WRAPPER_BASE_OFFS + 0x04) + +#define VIDC_WRAPPER_INTR_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x0C) +#define VIDC_WRAPPER_INTR_STATUS_A2HWD_BMSK 0x10 +#define VIDC_WRAPPER_INTR_STATUS_A2HWD_SHFT 0x4 +#define VIDC_WRAPPER_INTR_STATUS_A2H_BMSK 0x4 +#define VIDC_WRAPPER_INTR_STATUS_A2H_SHFT 0x2 + +#define VIDC_WRAPPER_INTR_MASK (VIDC_WRAPPER_BASE_OFFS + 0x10) +#define VIDC_WRAPPER_INTR_MASK_A2HWD_BMSK 0x10 +#define VIDC_WRAPPER_INTR_MASK_A2HWD_SHFT 0x4 +#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK 0x8 +#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_SHFT 0x3 +#define VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK 0x4 +#define VIDC_WRAPPER_INTR_MASK_A2HCPU_SHFT 0x2 + +#define VIDC_WRAPPER_INTR_CLEAR (VIDC_WRAPPER_BASE_OFFS + 0x14) +#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_BMSK 0x10 +#define VIDC_WRAPPER_INTR_CLEAR_A2HWD_SHFT 0x4 +#define VIDC_WRAPPER_INTR_CLEAR_A2H_BMSK 0x4 +#define VIDC_WRAPPER_INTR_CLEAR_A2H_SHFT 0x2 + +#define VIDC_WRAPPER_VBIF_XIN_SW_RESET (VIDC_WRAPPER_BASE_OFFS + 0x18) +#define VIDC_WRAPPER_VBIF_XIN_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x1C) +#define VIDC_WRAPPER_CPU_CLOCK_CONFIG (VIDC_WRAPPER_BASE_OFFS + 0x2000) +#define VIDC_WRAPPER_VBIF_XIN_CPU_SW_RESET \ + (VIDC_WRAPPER_BASE_OFFS + 0x2004) +#define VIDC_WRAPPER_AXI_HALT (VIDC_WRAPPER_BASE_OFFS + 0x2008) +#define VIDC_WRAPPER_AXI_HALT_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x200C) +#define VIDC_WRAPPER_CPU_CGC_DIS (VIDC_WRAPPER_BASE_OFFS + 0x2010) +#define VIDC_VENUS_VBIF_CLK_ON (VIDC_VBIF_BASE_OFFS + 0x4) +#define VIDC_VBIF_IN_RD_LIM_CONF0 (VIDC_VBIF_BASE_OFFS + 0xB0) +#define VIDC_VBIF_IN_RD_LIM_CONF1 (VIDC_VBIF_BASE_OFFS + 0xB4) +#define VIDC_VBIF_IN_RD_LIM_CONF2 (VIDC_VBIF_BASE_OFFS + 0xB8) +#define VIDC_VBIF_IN_RD_LIM_CONF3 (VIDC_VBIF_BASE_OFFS + 0xBC) +#define VIDC_VBIF_IN_WR_LIM_CONF0 (VIDC_VBIF_BASE_OFFS + 0xC0) +#define VIDC_VBIF_IN_WR_LIM_CONF1 (VIDC_VBIF_BASE_OFFS + 0xC4) +#define VIDC_VBIF_IN_WR_LIM_CONF2 (VIDC_VBIF_BASE_OFFS + 0xC8) +#define VIDC_VBIF_IN_WR_LIM_CONF3 (VIDC_VBIF_BASE_OFFS + 0xCC) +#define VIDC_VBIF_OUT_RD_LIM_CONF0 (VIDC_VBIF_BASE_OFFS + 0xD0) +#define VIDC_VBIF_OUT_WR_LIM_CONF0 (VIDC_VBIF_BASE_OFFS + 0xD4) +#define VIDC_VBIF_DDR_OUT_MAX_BURST (VIDC_VBIF_BASE_OFFS + 0xD8) +#define VIDC_VBIF_OCMEM_OUT_MAX_BURST (VIDC_VBIF_BASE_OFFS + 0xDC) +#define VIDC_VBIF_DDR_ARB_CONF0 (VIDC_VBIF_BASE_OFFS + 0xF4) +#define VIDC_VBIF_DDR_ARB_CONF1 (VIDC_VBIF_BASE_OFFS + 0xF8) +#define VIDC_VBIF_ROUND_ROBIN_QOS_ARB (VIDC_VBIF_BASE_OFFS + 0x124) +#define VIDC_VBIF_OUT_AXI_AOOO_EN (VIDC_VBIF_BASE_OFFS + 0x178) +#define VIDC_VBIF_OUT_AXI_AOOO (VIDC_VBIF_BASE_OFFS + 0x17C) +#define VIDC_VBIF_ARB_CTL (VIDC_VBIF_BASE_OFFS + 0xF0) +#define VIDC_VBIF_OUT_AXI_AMEMTYPE_CONF0 (VIDC_VBIF_BASE_OFFS + 0x160) +#define VIDC_VBIF_OUT_AXI_AMEMTYPE_CONF1 (VIDC_VBIF_BASE_OFFS + 0x164) +#define VIDC_VBIF_ADDR_TRANS_EN (VIDC_VBIF_BASE_OFFS + 0xC00) +#define VIDC_VBIF_AT_OLD_BASE (VIDC_VBIF_BASE_OFFS + 0xC04) +#define VIDC_VBIF_AT_OLD_HIGH (VIDC_VBIF_BASE_OFFS + 0xC08) +#define VIDC_VBIF_AT_NEW_BASE (VIDC_VBIF_BASE_OFFS + 0xC10) +#define VIDC_VBIF_AT_NEW_HIGH (VIDC_VBIF_BASE_OFFS + 0xC18) +#define VENUS_VBIF_AXI_HALT_CTRL0 (VIDC_VBIF_BASE_OFFS + 0x208) +#define VENUS_VBIF_AXI_HALT_CTRL1 (VIDC_VBIF_BASE_OFFS + 0x20C) + +#define VENUS_VBIF_AXI_HALT_CTRL0_HALT_REQ BIT(0) +#define VENUS_VBIF_AXI_HALT_CTRL1_HALT_ACK BIT(0) +#define VENUS_VBIF_AXI_HALT_ACK_TIMEOUT_US 500000 + +#define VIDC_VENUS0_WRAPPER_VBIF_REQ_PRIORITY \ + (VIDC_WRAPPER_BASE_OFFS + 0x20) +#define VIDC_VENUS0_WRAPPER_VBIF_PRIORITY_LEVEL \ + (VIDC_WRAPPER_BASE_OFFS + 0x24) + +#define VIDC_CTRL_INIT 0x000D2048 +#define VIDC_CTRL_INIT_RESERVED_BITS31_1__M 0xFFFFFFFE +#define VIDC_CTRL_INIT_RESERVED_BITS31_1__S 1 +#define VIDC_CTRL_INIT_CTRL__M 0x00000001 +#define VIDC_CTRL_INIT_CTRL__S 0 + +#define VIDC_CTRL_STATUS 0x000D204C +#define VIDC_CTRL_STATUS_RESERVED_BITS31_8__M 0xFFFFFF00 +#define VIDC_CTRL_STATUS_RESERVED_BITS31_8__S 8 +#define VIDC_CTRL_ERROR_STATUS__M 0x000000FE +#define VIDC_CTRL_ERROR_STATUS__S 1 +#define VIDC_CTRL_INIT_STATUS__M 0x00000001 +#define VIDC_CTRL_INIT_STATUS__S 0 + +#define VIDC_QTBL_INFO 0x000D2050 +#define VIDC_QTBL_HOSTID__M 0xFF000000 +#define VIDC_QTBL_HOSTID__S 24 +#define VIDC_QTBL_INFO_RESERVED_BITS23_8__M 0x00FFFF00 +#define VIDC_QTBL_INFO_RESERVED_BITS23_8__S 8 +#define VIDC_QTBL_STATUS__M 0x000000FF +#define VIDC_QTBL_STATUS__S 0 + +#define VIDC_QTBL_ADDR 0x000D2054 + +#define VIDC_VERSION_INFO 0x000D2058 +#define VIDC_VERSION_INFO_MAJOR__M 0xF0000000 +#define VIDC_VERSION_INFO_MAJOR__S 28 +#define VIDC_VERSION_INFO_MINOR__M 0x0FFFFFE0 +#define VIDC_VERSION_INFO_MINOR__S 5 +#define VIDC_VERSION_INFO_BRANCH__M 0x0000001F +#define VIDC_VERSION_INFO_BRANCH__S 0 + +#define VIDC_SFR_ADDR 0x000D205C +#define VIDC_MMAP_ADDR 0x000D2060 +#define VIDC_UC_REGION_ADDR 0x000D2064 +#define VIDC_UC_REGION_SIZE 0x000D2068 + +#endif diff --git a/drivers/media/platform/msm/vidc/hfi/vidc_hfi.c b/drivers/media/platform/msm/vidc/hfi/vidc_hfi.c new file mode 100644 index 000000000000..e9806a6f38db --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi/vidc_hfi.c @@ -0,0 +1,46 @@ +/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include + +#include "msm_vidc_debug.h" +#include "vidc_hfi_api.h" +#include "hfi/venus/venus_hfi.h" + +void *vidc_hfi_init(enum vidc_hfi_type hfi_type, u32 device_id, + struct vidc_resources *res) +{ + struct hfi_device *hdev; + + switch (hfi_type) { + case VIDC_HFI_VENUS: + hdev = venus_hfi_initialize(device_id, res); + break; + default: + dprintk(VIDC_ERR, "Unsupported host-firmware interface\n"); + return ERR_PTR(-ENOTSUPP); + } + + return hdev; +} + +void vidc_hfi_deinit(enum vidc_hfi_type hfi_type, struct hfi_device *hdev) +{ + switch (hfi_type) { + case VIDC_HFI_VENUS: + venus_hfi_deinitialize(hdev); + break; + default: + dprintk(VIDC_ERR, "Unsupported host-firmware interface\n"); + return; + } +} diff --git a/drivers/media/platform/msm/vidc/hfi/vidc_hfi.h b/drivers/media/platform/msm/vidc/hfi/vidc_hfi.h new file mode 100644 index 000000000000..41e261e3b5ad --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi/vidc_hfi.h @@ -0,0 +1,878 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __H_VIDC_HFI_H__ +#define __H_VIDC_HFI_H__ + +#include "vidc_hfi_api.h" + +#define HFI_EVENT_DATA_SEQUENCE_CHANGED_SUFFICIENT_BUFFER_RESOURCES \ + (HFI_OX_BASE + 0x1) +#define HFI_EVENT_DATA_SEQUENCE_CHANGED_INSUFFICIENT_BUFFER_RESOURCES \ + (HFI_OX_BASE + 0x2) +#define HFI_EVENT_SESSION_SEQUENCE_CHANGED (HFI_OX_BASE + 0x3) +#define HFI_EVENT_SESSION_PROPERTY_CHANGED (HFI_OX_BASE + 0x4) +#define HFI_EVENT_SESSION_LTRUSE_FAILED (HFI_OX_BASE + 0x5) +#define HFI_EVENT_RELEASE_BUFFER_REFERENCE (HFI_OX_BASE + 0x6) + +#define HFI_BUFFERFLAG_EOS 0x00000001 +#define HFI_BUFFERFLAG_STARTTIME 0x00000002 +#define HFI_BUFFERFLAG_DECODEONLY 0x00000004 +#define HFI_BUFFERFLAG_DATACORRUPT 0x00000008 +#define HFI_BUFFERFLAG_ENDOFFRAME 0x00000010 +#define HFI_BUFFERFLAG_SYNCFRAME 0x00000020 +#define HFI_BUFFERFLAG_EXTRADATA 0x00000040 +#define HFI_BUFFERFLAG_CODECCONFIG 0x00000080 +#define HFI_BUFFERFLAG_TIMESTAMPINVALID 0x00000100 +#define HFI_BUFFERFLAG_READONLY 0x00000200 +#define HFI_BUFFERFLAG_ENDOFSUBFRAME 0x00000400 +#define HFI_BUFFERFLAG_EOSEQ 0x00200000 +#define HFI_BUFFERFLAG_MBAFF 0x08000000 +#define HFI_BUFFERFLAG_VPE_YUV_601_709_CSC_CLAMP 0x10000000 +#define HFI_BUFFERFLAG_DROP_FRAME 0x20000000 +#define HFI_BUFFERFLAG_TEI 0x40000000 +#define HFI_BUFFERFLAG_DISCONTINUITY 0x80000000 + +#define HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING \ + (HFI_OX_BASE + 0x1001) +#define HFI_ERR_SESSION_SAME_STATE_OPERATION \ + (HFI_OX_BASE + 0x1002) +#define HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED \ + (HFI_OX_BASE + 0x1003) +#define HFI_ERR_SESSION_START_CODE_NOT_FOUND \ + (HFI_OX_BASE + 0x1004) + +#define HFI_BUFFER_INTERNAL_SCRATCH (HFI_OX_BASE + 0x1) +#define HFI_BUFFER_EXTRADATA_INPUT (HFI_OX_BASE + 0x2) +#define HFI_BUFFER_EXTRADATA_OUTPUT (HFI_OX_BASE + 0x3) +#define HFI_BUFFER_EXTRADATA_OUTPUT2 (HFI_OX_BASE + 0x4) +#define HFI_BUFFER_INTERNAL_SCRATCH_1 (HFI_OX_BASE + 0x5) +#define HFI_BUFFER_INTERNAL_SCRATCH_2 (HFI_OX_BASE + 0x6) + +#define HFI_BUFFER_MODE_STATIC (HFI_OX_BASE + 0x1) +#define HFI_BUFFER_MODE_RING (HFI_OX_BASE + 0x2) +#define HFI_BUFFER_MODE_DYNAMIC (HFI_OX_BASE + 0x3) + +#define HFI_FLUSH_INPUT (HFI_OX_BASE + 0x1) +#define HFI_FLUSH_OUTPUT (HFI_OX_BASE + 0x2) +#define HFI_FLUSH_OUTPUT2 (HFI_OX_BASE + 0x3) +#define HFI_FLUSH_ALL (HFI_OX_BASE + 0x4) + +#define HFI_EXTRADATA_NONE 0x00000000 +#define HFI_EXTRADATA_MB_QUANTIZATION 0x00000001 +#define HFI_EXTRADATA_INTERLACE_VIDEO 0x00000002 +#define HFI_EXTRADATA_VC1_FRAMEDISP 0x00000003 +#define HFI_EXTRADATA_VC1_SEQDISP 0x00000004 +#define HFI_EXTRADATA_TIMESTAMP 0x00000005 +#define HFI_EXTRADATA_S3D_FRAME_PACKING 0x00000006 +#define HFI_EXTRADATA_FRAME_RATE 0x00000007 +#define HFI_EXTRADATA_PANSCAN_WINDOW 0x00000008 +#define HFI_EXTRADATA_RECOVERY_POINT_SEI 0x00000009 +#define HFI_EXTRADATA_MPEG2_SEQDISP 0x0000000D +#define HFI_EXTRADATA_STREAM_USERDATA 0x0000000E +#define HFI_EXTRADATA_FRAME_QP 0x0000000F +#define HFI_EXTRADATA_FRAME_BITS_INFO 0x00000010 +#define HFI_EXTRADATA_MULTISLICE_INFO 0x7F100000 +#define HFI_EXTRADATA_NUM_CONCEALED_MB 0x7F100001 +#define HFI_EXTRADATA_INDEX 0x7F100002 +#define HFI_EXTRADATA_METADATA_LTR 0x7F100004 +#define HFI_EXTRADATA_METADATA_FILLER 0x7FE00002 + +#define HFI_INDEX_EXTRADATA_INPUT_CROP 0x0700000E +#define HFI_INDEX_EXTRADATA_DIGITAL_ZOOM 0x07000010 +#define HFI_INDEX_EXTRADATA_ASPECT_RATIO 0x7F100003 + +struct hfi_buffer_alloc_mode { + u32 type; + u32 mode; +}; + +struct hfi_index_extradata_config { + int enable; + u32 index_extra_data_id; +}; + +struct hfi_extradata_header { + u32 size; + u32 version; + u32 port_index; + u32 type; + u32 data_size; + u8 rg_data[1]; +}; + +#define HFI_INTERLACE_FRAME_PROGRESSIVE 0x01 +#define HFI_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST 0x02 +#define HFI_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST 0x04 +#define HFI_INTERLACE_FRAME_TOPFIELDFIRST 0x08 +#define HFI_INTERLACE_FRAME_BOTTOMFIELDFIRST 0x10 + +#define HFI_PROPERTY_SYS_OX_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x0000) + +#define HFI_PROPERTY_PARAM_OX_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x1000) +#define HFI_PROPERTY_PARAM_BUFFER_COUNT_ACTUAL \ + (HFI_PROPERTY_PARAM_OX_START + 0x001) +#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO \ + (HFI_PROPERTY_PARAM_OX_START + 0x002) +#define HFI_PROPERTY_PARAM_INTERLACE_FORMAT_SUPPORTED \ + (HFI_PROPERTY_PARAM_OX_START + 0x003) +#define HFI_PROPERTY_PARAM_CHROMA_SITE \ + (HFI_PROPERTY_PARAM_OX_START + 0x004) +#define HFI_PROPERTY_PARAM_EXTRA_DATA_HEADER_CONFIG \ + (HFI_PROPERTY_PARAM_OX_START + 0x005) +#define HFI_PROPERTY_PARAM_INDEX_EXTRADATA \ + (HFI_PROPERTY_PARAM_OX_START + 0x006) +#define HFI_PROPERTY_PARAM_DIVX_FORMAT \ + (HFI_PROPERTY_PARAM_OX_START + 0x007) +#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE \ + (HFI_PROPERTY_PARAM_OX_START + 0x008) +#define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA \ + (HFI_PROPERTY_PARAM_OX_START + 0x009) +#define HFI_PROPERTY_PARAM_ERR_DETECTION_CODE_EXTRADATA \ + (HFI_PROPERTY_PARAM_OX_START + 0x00A) +#define HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE_SUPPORTED \ + (HFI_PROPERTY_PARAM_OX_START + 0x00B) +#define HFI_PROPERTY_PARAM_BUFFER_SIZE_ACTUAL \ + (HFI_PROPERTY_PARAM_OX_START + 0x00C) +#define HFI_PROPERTY_PARAM_BUFFER_DISPLAY_HOLD_COUNT_ACTUAL \ + (HFI_PROPERTY_PARAM_OX_START + 0x00D) + +#define HFI_PROPERTY_CONFIG_OX_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + 0x02000) +#define HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS \ + (HFI_PROPERTY_CONFIG_OX_START + 0x001) +#define HFI_PROPERTY_CONFIG_REALTIME \ + (HFI_PROPERTY_CONFIG_OX_START + 0x002) +#define HFI_PROPERTY_CONFIG_PRIORITY \ + (HFI_PROPERTY_CONFIG_OX_START + 0x003) +#define HFI_PROPERTY_CONFIG_BATCH_INFO \ + (HFI_PROPERTY_CONFIG_OX_START + 0x004) + +#define HFI_PROPERTY_PARAM_VDEC_OX_START \ + (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x3000) +#define HFI_PROPERTY_PARAM_VDEC_CONTINUE_DATA_TRANSFER \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001) +#define HFI_PROPERTY_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT\ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x002) +#define HFI_PROPERTY_PARAM_VDEC_MULTI_VIEW_SELECT \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x003) +#define HFI_PROPERTY_PARAM_VDEC_PICTURE_TYPE_DECODE \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x004) +#define HFI_PROPERTY_PARAM_VDEC_OUTPUT_ORDER \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x005) +#define HFI_PROPERTY_PARAM_VDEC_MB_QUANTIZATION \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x006) +#define HFI_PROPERTY_PARAM_VDEC_NUM_CONCEALED_MB \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x007) +#define HFI_PROPERTY_PARAM_VDEC_H264_ENTROPY_SWITCHING \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x008) +#define HFI_PROPERTY_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO\ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x009) +#define HFI_PROPERTY_PARAM_VDEC_FRAME_RATE_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00A) +#define HFI_PROPERTY_PARAM_VDEC_PANSCAN_WNDW_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00B) +#define HFI_PROPERTY_PARAM_VDEC_RECOVERY_POINT_SEI_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00C) +#define HFI_PROPERTY_PARAM_VDEC_THUMBNAIL_MODE \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00D) +#define HFI_PROPERTY_PARAM_VDEC_FRAME_ASSEMBLY \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x00E) +#define HFI_PROPERTY_PARAM_VDEC_VC1_FRAMEDISP_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x011) +#define HFI_PROPERTY_PARAM_VDEC_VC1_SEQDISP_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x012) +#define HFI_PROPERTY_PARAM_VDEC_TIMESTAMP_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x013) +#define HFI_PROPERTY_PARAM_VDEC_INTERLACE_VIDEO_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x014) +#define HFI_PROPERTY_PARAM_VDEC_AVC_SESSION_SELECT \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x015) +#define HFI_PROPERTY_PARAM_VDEC_MPEG2_SEQDISP_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x016) +#define HFI_PROPERTY_PARAM_VDEC_STREAM_USERDATA_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x017) +#define HFI_PROPERTY_PARAM_VDEC_FRAME_QP_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x018) +#define HFI_PROPERTY_PARAM_VDEC_FRAME_BITS_INFO_EXTRADATA \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x019) +#define HFI_PROPERTY_PARAM_VDEC_SCS_THRESHOLD \ + (HFI_PROPERTY_PARAM_VDEC_OX_START + 0x01A) + +#define HFI_PROPERTY_CONFIG_VDEC_OX_START \ + (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x0000) +#define HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER \ + (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x001) +#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP_REPORTING \ + (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x002) +#define HFI_PROPERTY_CONFIG_VDEC_MB_ERROR_MAP \ + (HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x003) + +#define HFI_PROPERTY_PARAM_VENC_OX_START \ + (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x5000) +#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_INFO \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x001) +#define HFI_PROPERTY_PARAM_VENC_H264_IDR_S3D_FRAME_PACKING_NAL \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x002) +#define HFI_PROPERTY_PARAM_VENC_LTR_INFO \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x003) +#define HFI_PROPERTY_PARAM_VENC_MBI_DUMPING \ + (HFI_PROPERTY_PARAM_VENC_OX_START + 0x005) + +#define HFI_PROPERTY_CONFIG_VENC_OX_START \ + (HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000) +#define HFI_PROPERTY_CONFIG_VENC_FRAME_QP \ + (HFI_PROPERTY_CONFIG_VENC_OX_START + 0x001) + +#define HFI_PROPERTY_PARAM_VPE_OX_START \ + (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x7000) +#define HFI_PROPERTY_PARAM_VPE_COLOR_SPACE_CONVERSION \ + (HFI_PROPERTY_PARAM_VPE_OX_START + 0x001) + +#define HFI_PROPERTY_CONFIG_VPE_OX_START \ + (HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x8000) + +struct hfi_batch_info { + u32 input_batch_count; + u32 output_batch_count; +}; + +struct hfi_buffer_count_actual { + u32 type; + u32 count_actual; +}; + +struct hfi_buffer_size_actual { + u32 type; + u32 size; +}; + +struct hfi_buffer_display_hold_count_actual { + u32 type; + u32 hold_count; +}; + +struct hfi_buffer_requirements { + u32 type; + u32 size; + u32 region_size; + u32 hold_count; + u32 count_min; + u32 count_actual; + u32 contiguous; + u32 alignment; +}; + +#define HFI_CHROMA_SITE_0 (HFI_OX_BASE + 0x1) +#define HFI_CHROMA_SITE_1 (HFI_OX_BASE + 0x2) +#define HFI_CHROMA_SITE_2 (HFI_OX_BASE + 0x3) +#define HFI_CHROMA_SITE_3 (HFI_OX_BASE + 0x4) +#define HFI_CHROMA_SITE_4 (HFI_OX_BASE + 0x5) +#define HFI_CHROMA_SITE_5 (HFI_OX_BASE + 0x6) + +struct hfi_data_payload { + u32 size; + u8 rg_data[1]; +}; + +struct hfi_enable_picture { + u32 picture_type; +}; + +struct hfi_display_picture_buffer_count { + int enable; + u32 count; +}; + +struct hfi_extra_data_header_config { + u32 type; + u32 buffer_type; + u32 version; + u32 port_index; + u32 client_extra_data_id; +}; + +struct hfi_interlace_format_supported { + u32 buffer_type; + u32 format; +}; + +struct hfi_buffer_alloc_mode_supported { + u32 buffer_type; + u32 num_entries; + u32 rg_data[1]; +}; + +struct hfi_mb_error_map { + u32 error_map_size; + u8 rg_error_map[1]; +}; + +struct hfi_metadata_pass_through { + int enable; + u32 size; +}; + +struct hfi_multi_view_select { + u32 view_index; +}; + +struct hfi_hybrid_hierp { + u32 layers; +}; + +#define HFI_PRIORITY_LOW 10 +#define HFI_PRIOIRTY_MEDIUM 20 +#define HFI_PRIORITY_HIGH 30 + +#define HFI_OUTPUT_ORDER_DISPLAY (HFI_OX_BASE + 0x1) +#define HFI_OUTPUT_ORDER_DECODE (HFI_OX_BASE + 0x2) + +#define HFI_RATE_CONTROL_OFF (HFI_OX_BASE + 0x1) +#define HFI_RATE_CONTROL_VBR_VFR (HFI_OX_BASE + 0x2) +#define HFI_RATE_CONTROL_VBR_CFR (HFI_OX_BASE + 0x3) +#define HFI_RATE_CONTROL_CBR_VFR (HFI_OX_BASE + 0x4) +#define HFI_RATE_CONTROL_CBR_CFR (HFI_OX_BASE + 0x5) + +struct hfi_uncompressed_plane_actual_constraints_info { + u32 buffer_type; + u32 num_planes; + struct hfi_uncompressed_plane_constraints rg_plane_format[1]; +}; + +#define HFI_CMD_SYS_OX_START (HFI_DOMAIN_BASE_COMMON + \ + HFI_ARCH_OX_OFFSET + \ + HFI_CMD_START_OFFSET + 0x0000) +#define HFI_CMD_SYS_SESSION_ABORT (HFI_CMD_SYS_OX_START + 0x001) +#define HFI_CMD_SYS_PING (HFI_CMD_SYS_OX_START + 0x002) + +#define HFI_CMD_SESSION_OX_START (HFI_DOMAIN_BASE_COMMON + \ + HFI_ARCH_OX_OFFSET + \ + HFI_CMD_START_OFFSET + 0x1000) +#define HFI_CMD_SESSION_LOAD_RESOURCES (HFI_CMD_SESSION_OX_START + 0x001) +#define HFI_CMD_SESSION_START (HFI_CMD_SESSION_OX_START + 0x002) +#define HFI_CMD_SESSION_STOP (HFI_CMD_SESSION_OX_START + 0x003) +#define HFI_CMD_SESSION_EMPTY_BUFFER (HFI_CMD_SESSION_OX_START + 0x004) +#define HFI_CMD_SESSION_FILL_BUFFER (HFI_CMD_SESSION_OX_START + 0x005) +#define HFI_CMD_SESSION_SUSPEND (HFI_CMD_SESSION_OX_START + 0x006) +#define HFI_CMD_SESSION_RESUME (HFI_CMD_SESSION_OX_START + 0x007) +#define HFI_CMD_SESSION_FLUSH (HFI_CMD_SESSION_OX_START + 0x008) +#define HFI_CMD_SESSION_GET_PROPERTY (HFI_CMD_SESSION_OX_START + 0x009) +#define HFI_CMD_SESSION_PARSE_SEQUENCE_HEADER \ + (HFI_CMD_SESSION_OX_START + 0x00A) +#define HFI_CMD_SESSION_RELEASE_BUFFERS \ + (HFI_CMD_SESSION_OX_START + 0x00B) +#define HFI_CMD_SESSION_RELEASE_RESOURCES \ + (HFI_CMD_SESSION_OX_START + 0x00C) + +#define HFI_MSG_SYS_OX_START (HFI_DOMAIN_BASE_COMMON + \ + HFI_ARCH_OX_OFFSET + \ + HFI_MSG_START_OFFSET + 0x0000) +#define HFI_MSG_SYS_PING_ACK (HFI_MSG_SYS_OX_START + 0x2) +#define HFI_MSG_SYS_SESSION_ABORT_DONE (HFI_MSG_SYS_OX_START + 0x4) + +#define HFI_MSG_SESSION_OX_START (HFI_DOMAIN_BASE_COMMON + \ + HFI_ARCH_OX_OFFSET + \ + HFI_MSG_START_OFFSET + 0x1000) +#define HFI_MSG_SESSION_LOAD_RESOURCES_DONE (HFI_MSG_SESSION_OX_START + 0x1) +#define HFI_MSG_SESSION_START_DONE (HFI_MSG_SESSION_OX_START + 0x2) +#define HFI_MSG_SESSION_STOP_DONE (HFI_MSG_SESSION_OX_START + 0x3) +#define HFI_MSG_SESSION_SUSPEND_DONE (HFI_MSG_SESSION_OX_START + 0x4) +#define HFI_MSG_SESSION_RESUME_DONE (HFI_MSG_SESSION_OX_START + 0x5) +#define HFI_MSG_SESSION_FLUSH_DONE (HFI_MSG_SESSION_OX_START + 0x6) +#define HFI_MSG_SESSION_EMPTY_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x7) +#define HFI_MSG_SESSION_FILL_BUFFER_DONE (HFI_MSG_SESSION_OX_START + 0x8) +#define HFI_MSG_SESSION_PROPERTY_INFO (HFI_MSG_SESSION_OX_START + 0x9) +#define HFI_MSG_SESSION_RELEASE_RESOURCES_DONE (HFI_MSG_SESSION_OX_START + 0xA) +#define HFI_MSG_SESSION_PARSE_SEQUENCE_HEADER_DONE \ + (HFI_MSG_SESSION_OX_START + 0xB) +#define HFI_MSG_SESSION_RELEASE_BUFFERS_DONE \ + (HFI_MSG_SESSION_OX_START + 0xC) + +#define VIDC_IFACEQ_MAX_PKT_SIZE 1024 +#define VIDC_IFACEQ_MED_PKT_SIZE 768 +#define VIDC_IFACEQ_MIN_PKT_SIZE 8 +#define VIDC_IFACEQ_VAR_SMALL_PKT_SIZE 100 +#define VIDC_IFACEQ_VAR_LARGE_PKT_SIZE 512 +#define VIDC_IFACEQ_VAR_HUGE_PKT_SIZE (1024 * 12) + +struct hfi_cmd_sys_session_abort_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_sys_ping_packet { + u32 size; + u32 packet_type; + u32 client_data; +}; + +struct hfi_cmd_session_load_resources_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_session_start_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_session_stop_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_session_empty_buffer_compressed_packet { + u32 size; + u32 packet_type; + u32 session_id; + 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 extra_data_buffer; + u32 rgData[1]; +}; + +struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet { + u32 size; + u32 packet_type; + u32 session_id; + 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 extra_data_buffer; + u32 rgData[1]; +}; + +struct hfi_cmd_session_empty_buffer_uncompressed_plane1_packet { + u32 flags; + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 packet_buffer2; + u32 rgData[1]; +}; + +struct hfi_cmd_session_empty_buffer_uncompressed_plane2_packet { + u32 flags; + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 packet_buffer3; + u32 rgData[1]; +}; + +struct hfi_cmd_session_fill_buffer_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 stream_id; + u32 offset; + u32 alloc_len; + u32 filled_len; + u32 output_tag; + u32 packet_buffer; + u32 extra_data_buffer; + u32 rgData[1]; +}; + +struct hfi_cmd_session_flush_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 flush_type; +}; + +struct hfi_cmd_session_suspend_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_session_resume_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_session_get_property_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_cmd_session_release_buffer_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 buffer_type; + u32 buffer_size; + u32 extra_data_size; + int response_req; + u32 num_buffers; + u32 rg_buffer_info[1]; +}; + +struct hfi_cmd_session_release_resources_packet { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_cmd_session_parse_sequence_header_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 header_len; + u32 packet_buffer; +}; + +struct hfi_msg_sys_session_abort_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_sys_idle_packet { + u32 size; + u32 packet_type; +}; + +struct hfi_msg_sys_ping_ack_packet { + u32 size; + u32 packet_type; + u32 client_data; +}; + +struct hfi_msg_sys_property_info_packet { + u32 size; + u32 packet_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_msg_session_load_resources_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_start_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_stop_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_suspend_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_resume_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_flush_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; + u32 flush_type; +}; + +struct hfi_msg_session_empty_buffer_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; + u32 offset; + u32 filled_len; + u32 input_tag; + u32 packet_buffer; + u32 extra_data_buffer; + u32 rgData[0]; +}; + +struct hfi_msg_session_fbd_compressed_packet { + u32 size; + u32 packet_type; + u32 session_id; + 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 extra_data_buffer; + u32 rgData[0]; +}; + +struct hfi_msg_session_fbd_uncompressed_plane0_packet { + u32 size; + u32 packet_type; + u32 session_id; + 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 extra_data_buffer; + u32 rgData[0]; +}; + +struct hfi_msg_session_fbd_uncompressed_plane1_packet { + u32 flags; + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 packet_buffer2; + u32 rgData[0]; +}; + +struct hfi_msg_session_fbd_uncompressed_plane2_packet { + u32 flags; + u32 alloc_len; + u32 filled_len; + u32 offset; + u32 packet_buffer3; + u32 rgData[0]; +}; + +struct hfi_msg_session_parse_sequence_header_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_msg_session_property_info_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_msg_session_release_resources_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_release_buffers_done_packet { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; + u32 num_buffers; + u32 rg_buffer_info[1]; +}; + +struct hfi_extradata_mb_quantization_payload { + u8 rg_mb_qp[1]; +}; + +struct hfi_extradata_vc1_pswnd { + u32 ps_wnd_h_offset; + u32 ps_wnd_v_offset; + u32 ps_wnd_width; + u32 ps_wnd_height; +}; + +struct hfi_extradata_vc1_framedisp_payload { + u32 res_pic; + u32 ref; + u32 range_map_present; + u32 range_map_y; + u32 range_map_uv; + u32 num_pan_scan_wnds; + struct hfi_extradata_vc1_pswnd rg_ps_wnd[1]; +}; + +struct hfi_extradata_vc1_seqdisp_payload { + u32 prog_seg_frm; + u32 uv_sampling_fmt; + u32 color_fmt_flag; + u32 color_primaries; + u32 transfer_char; + u32 mat_coeff; + u32 aspect_ratio; + u32 aspect_horiz; + u32 aspect_vert; +}; + +struct hfi_extradata_timestamp_payload { + u32 timestamp_low; + u32 timestamp_high; +}; + +struct hfi_extradata_s3d_frame_packing_payload { + u32 fpa_id; + int cancel_flag; + u32 fpa_type; + int quin_cunx_flag; + u32 content_interprtation_type; + int spatial_flipping_flag; + int frame0_flipped_flag; + int field_views_flag; + int current_frame_isFrame0_flag; + int frame0_self_contained_flag; + int frame1_self_contained_flag; + u32 frame0_graid_pos_x; + u32 frame0_graid_pos_y; + u32 frame1_graid_pos_x; + u32 frame1_graid_pos_y; + u32 fpa_reserved_byte; + u32 fpa_repetition_period; + int fpa_extension_flag; +}; + +struct hfi_extradata_interlace_video_payload { + u32 format; +}; + +struct hfi_extradata_num_concealed_mb_payload { + u32 num_mb_concealed; +}; + +struct hfi_extradata_sliceinfo { + u32 offset_in_stream; + u32 slice_length; +}; + +struct hfi_extradata_multislice_info_payload { + u32 num_slices; + struct hfi_extradata_sliceinfo rg_slice_info[1]; +}; + +struct hfi_index_extradata_input_crop_payload { + u32 size; + u32 version; + u32 port_index; + u32 left; + u32 top; + u32 width; + u32 height; +}; + +struct hfi_index_extradata_digital_zoom_payload { + u32 size; + u32 version; + u32 port_index; + int width; + int height; +}; + +struct hfi_index_extradata_aspect_ratio_payload { + u32 size; + u32 version; + u32 port_index; + u32 aspect_width; + u32 aspect_height; +}; + +struct hfi_extradata_panscan_wndw_payload { + u32 num_window; + struct hfi_extradata_vc1_pswnd wnd[1]; +}; + +struct hfi_extradata_frame_type_payload { + u32 frame_rate; +}; + +struct hfi_extradata_recovery_point_sei_payload { + u32 flag; +}; + +struct hal_session { + struct list_head list; + void *session_id; + bool is_decoder; + void *device; +}; + +struct hal_device_data { + struct list_head dev_head; + int dev_count; +}; + +void hfi_process_watchdog_timeout(u32 device_id); + +u32 hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr, + struct list_head *sessions, + struct mutex *session_lock); +#endif diff --git a/drivers/media/platform/msm/vidc/hfi/vidc_hfi_api.h b/drivers/media/platform/msm/vidc/hfi/vidc_hfi_api.h new file mode 100644 index 000000000000..6559b1ef67cf --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi/vidc_hfi_api.h @@ -0,0 +1,1363 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __VIDC_HFI_API_H__ +#define __VIDC_HFI_API_H__ + +#include + +#include "msm_vidc.h" +#include "msm_vidc_resources.h" + +#include "vidc_hfi_helper.h" +#include "vidc_hfi.h" + +#define HAL_BUFFERFLAG_EOS 0x00000001 +#define HAL_BUFFERFLAG_STARTTIME 0x00000002 +#define HAL_BUFFERFLAG_DECODEONLY 0x00000004 +#define HAL_BUFFERFLAG_DATACORRUPT 0x00000008 +#define HAL_BUFFERFLAG_ENDOFFRAME 0x00000010 +#define HAL_BUFFERFLAG_SYNCFRAME 0x00000020 +#define HAL_BUFFERFLAG_EXTRADATA 0x00000040 +#define HAL_BUFFERFLAG_CODECCONFIG 0x00000080 +#define HAL_BUFFERFLAG_TIMESTAMPINVALID 0x00000100 +#define HAL_BUFFERFLAG_READONLY 0x00000200 +#define HAL_BUFFERFLAG_ENDOFSUBFRAME 0x00000400 +#define HAL_BUFFERFLAG_EOSEQ 0x00200000 +#define HAL_BUFFERFLAG_MBAFF 0x08000000 +#define HAL_BUFFERFLAG_YUV_601_709_CSC_CLAMP 0x10000000 +#define HAL_BUFFERFLAG_DROP_FRAME 0x20000000 +#define HAL_BUFFERFLAG_TS_DISCONTINUITY 0x40000000 +#define HAL_BUFFERFLAG_TS_ERROR 0x80000000 + +#define HAL_DEBUG_MSG_LOW 0x00000001 +#define HAL_DEBUG_MSG_MEDIUM 0x00000002 +#define HAL_DEBUG_MSG_HIGH 0x00000004 +#define HAL_DEBUG_MSG_ERROR 0x00000008 +#define HAL_DEBUG_MSG_FATAL 0x00000010 +#define MAX_PROFILE_COUNT 16 + +#define HAL_MAX_MATRIX_COEFFS 9 +#define HAL_MAX_BIAS_COEFFS 3 +#define HAL_MAX_LIMIT_COEFFS 6 + +enum vidc_error { + VIDC_ERR_NONE = 0x0, + VIDC_ERR_FAIL = 0x80000000, + VIDC_ERR_ALLOC_FAIL, + VIDC_ERR_ILLEGAL_OP, + VIDC_ERR_BAD_PARAM, + VIDC_ERR_BAD_HANDLE, + VIDC_ERR_NOT_SUPPORTED, + VIDC_ERR_BAD_STATE, + VIDC_ERR_MAX_CLIENTS, + VIDC_ERR_IFRAME_EXPECTED, + VIDC_ERR_HW_FATAL, + VIDC_ERR_BITSTREAM_ERR, + VIDC_ERR_INDEX_NOMORE, + VIDC_ERR_SEQHDR_PARSE_FAIL, + VIDC_ERR_INSUFFICIENT_BUFFER, + VIDC_ERR_BAD_POWER_STATE, + VIDC_ERR_NO_VALID_SESSION, + VIDC_ERR_TIMEOUT, + VIDC_ERR_CMDQFULL, + VIDC_ERR_START_CODE_NOT_FOUND, + VIDC_ERR_CLIENT_PRESENT = 0x90000001, + VIDC_ERR_CLIENT_FATAL, + VIDC_ERR_CMD_QUEUE_FULL, + VIDC_ERR_UNUSED = 0x10000000 +}; + +#define HAL_BUFFER_MAX 0xb + +/* NOTE: if you change this enum you MUST update the + * "buffer-type-tz-usage-table" for any affected target + * in arch/arm/boot/dts/.dtsi + */ +enum hal_buffer { + HAL_BUFFER_NONE = 0x0, + HAL_BUFFER_INPUT = 0x1, + HAL_BUFFER_OUTPUT = 0x2, + HAL_BUFFER_OUTPUT2 = 0x4, + HAL_BUFFER_EXTRADATA_INPUT = 0x8, + HAL_BUFFER_EXTRADATA_OUTPUT = 0x10, + HAL_BUFFER_EXTRADATA_OUTPUT2 = 0x20, + HAL_BUFFER_INTERNAL_SCRATCH = 0x40, + HAL_BUFFER_INTERNAL_SCRATCH_1 = 0x80, + HAL_BUFFER_INTERNAL_SCRATCH_2 = 0x100, + HAL_BUFFER_INTERNAL_PERSIST = 0x200, + HAL_BUFFER_INTERNAL_PERSIST_1 = 0x400, + HAL_BUFFER_INTERNAL_CMD_QUEUE = 0x800, +}; + +enum hal_extradata_id { + HAL_EXTRADATA_NONE, + HAL_EXTRADATA_MB_QUANTIZATION, + HAL_EXTRADATA_INTERLACE_VIDEO, + HAL_EXTRADATA_VC1_FRAMEDISP, + HAL_EXTRADATA_VC1_SEQDISP, + HAL_EXTRADATA_TIMESTAMP, + HAL_EXTRADATA_S3D_FRAME_PACKING, + HAL_EXTRADATA_FRAME_RATE, + HAL_EXTRADATA_PANSCAN_WINDOW, + HAL_EXTRADATA_RECOVERY_POINT_SEI, + HAL_EXTRADATA_MULTISLICE_INFO, + HAL_EXTRADATA_INDEX, + HAL_EXTRADATA_NUM_CONCEALED_MB, + HAL_EXTRADATA_METADATA_FILLER, + HAL_EXTRADATA_ASPECT_RATIO, + HAL_EXTRADATA_MPEG2_SEQDISP, + HAL_EXTRADATA_STREAM_USERDATA, + HAL_EXTRADATA_FRAME_QP, + HAL_EXTRADATA_FRAME_BITS_INFO, + HAL_EXTRADATA_INPUT_CROP, + HAL_EXTRADATA_DIGITAL_ZOOM, + HAL_EXTRADATA_LTR_INFO, + HAL_EXTRADATA_METADATA_MBI, +}; + +enum hal_property { + HAL_CONFIG_FRAME_RATE = 0x04000001, + HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT, //2 + HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_CONSTRAINTS_INFO, //3 + HAL_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO, //4 + HAL_PARAM_EXTRA_DATA_HEADER_CONFIG, //5 + HAL_PARAM_INDEX_EXTRADATA, //6 + HAL_PARAM_FRAME_SIZE, //7 + HAL_CONFIG_REALTIME, //8 + HAL_PARAM_BUFFER_COUNT_ACTUAL, //9 + HAL_PARAM_BUFFER_SIZE_ACTUAL, //a + HAL_PARAM_BUFFER_DISPLAY_HOLD_COUNT_ACTUAL, //b + HAL_PARAM_NAL_STREAM_FORMAT_SELECT, //c + HAL_PARAM_VDEC_OUTPUT_ORDER, //d + HAL_PARAM_VDEC_PICTURE_TYPE_DECODE, //e + HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO, //f + HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER, //10 + HAL_PARAM_VDEC_MULTI_STREAM, //11 + HAL_PARAM_VDEC_DISPLAY_PICTURE_BUFFER_COUNT, //12 + HAL_PARAM_DIVX_FORMAT, //13 + HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING, //14 + HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER, //15 + HAL_CONFIG_VDEC_MB_ERROR_MAP, //16 + HAL_CONFIG_VENC_REQUEST_IFRAME, //17 + HAL_PARAM_VENC_MPEG4_SHORT_HEADER, //18 + HAL_PARAM_VENC_MPEG4_AC_PREDICTION, //19 + HAL_CONFIG_VENC_TARGET_BITRATE, //1a + HAL_PARAM_PROFILE_LEVEL_CURRENT, //1b + HAL_PARAM_VENC_H264_ENTROPY_CONTROL, //1c + HAL_PARAM_VENC_RATE_CONTROL, //1d + HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION, //1e + HAL_PARAM_VENC_MPEG4_HEADER_EXTENSION, //1f + HAL_PARAM_VENC_H264_DEBLOCK_CONTROL, //20 + HAL_PARAM_VENC_TEMPORAL_SPATIAL_TRADEOFF, //21 + HAL_PARAM_VENC_SESSION_QP, //22 + HAL_PARAM_VENC_SESSION_QP_RANGE, //23 + HAL_CONFIG_VENC_INTRA_PERIOD, //24 + HAL_CONFIG_VENC_IDR_PERIOD, //25 + HAL_CONFIG_VPE_OPERATIONS, //26 + HAL_PARAM_VENC_INTRA_REFRESH, //27 + HAL_PARAM_VENC_MULTI_SLICE_CONTROL, //28 + HAL_CONFIG_VPE_DEINTERLACE, //29 + HAL_SYS_DEBUG_CONFIG, //2a + HAL_CONFIG_BUFFER_REQUIREMENTS, //2b + HAL_CONFIG_PRIORITY, //2c + HAL_CONFIG_BATCH_INFO, //2d + HAL_PARAM_METADATA_PASS_THROUGH, //2e + HAL_SYS_IDLE_INDICATOR, //2f + HAL_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED, //30 + HAL_PARAM_INTERLACE_FORMAT_SUPPORTED, //31 + HAL_PARAM_CHROMA_SITE, //32 + HAL_PARAM_PROPERTIES_SUPPORTED, //33 + HAL_PARAM_PROFILE_LEVEL_SUPPORTED, //34 + HAL_PARAM_CAPABILITY_SUPPORTED, //35 + HAL_PARAM_NAL_STREAM_FORMAT_SUPPORTED, //36 + HAL_PARAM_MULTI_VIEW_FORMAT, //37 + HAL_PARAM_MAX_SEQUENCE_HEADER_SIZE, //38 + HAL_PARAM_CODEC_SUPPORTED, //39 + HAL_PARAM_VDEC_MULTI_VIEW_SELECT, //3a + HAL_PARAM_VDEC_MB_QUANTIZATION, //3b + HAL_PARAM_VDEC_NUM_CONCEALED_MB, //3c + HAL_PARAM_VDEC_H264_ENTROPY_SWITCHING, //3d + HAL_PARAM_VENC_SLICE_DELIVERY_MODE, //3e + HAL_PARAM_VENC_MPEG4_DATA_PARTITIONING, //3f + HAL_CONFIG_BUFFER_COUNT_ACTUAL, //40 + HAL_CONFIG_VDEC_MULTI_STREAM, //41 + HAL_PARAM_VENC_MULTI_SLICE_INFO, //42 + HAL_CONFIG_VENC_TIMESTAMP_SCALE, //43 + HAL_PARAM_VENC_LOW_LATENCY, //44 + HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER, //45 + HAL_PARAM_VDEC_SYNC_FRAME_DECODE, //46 + HAL_PARAM_VENC_H264_ENTROPY_CABAC_MODEL, //47 + HAL_CONFIG_VENC_MAX_BITRATE, //48 + HAL_PARAM_VENC_H264_VUI_TIMING_INFO, //49 + HAL_PARAM_VENC_H264_GENERATE_AUDNAL, //4a + HAL_PARAM_VENC_MAX_NUM_B_FRAMES, //4b + HAL_PARAM_BUFFER_ALLOC_MODE, //4c + HAL_PARAM_VDEC_FRAME_ASSEMBLY, //4d + HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC, //4e + HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY, //4f + HAL_PARAM_VDEC_CONCEAL_COLOR, //50 + HAL_PARAM_VDEC_SCS_THRESHOLD, //51 + HAL_PARAM_GET_BUFFER_REQUIREMENTS, //52 + HAL_PARAM_MVC_BUFFER_LAYOUT, //53 + HAL_PARAM_VENC_LTRMODE, //54 + HAL_CONFIG_VENC_MARKLTRFRAME, //55 + HAL_CONFIG_VENC_USELTRFRAME, //56 + HAL_CONFIG_VENC_LTRPERIOD, //57 + HAL_CONFIG_VENC_HIER_P_NUM_FRAMES, //58 + HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS, //59 + HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP, //5a + HAL_PARAM_VENC_ENABLE_INITIAL_QP, //5b + HAL_PARAM_VENC_SEARCH_RANGE, //5c + HAL_PARAM_VPE_COLOR_SPACE_CONVERSION, //5d + HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE, //5e + HAL_PARAM_VENC_H264_NAL_SVC_EXT, //5f + HAL_CONFIG_VENC_PERF_MODE, //60 + HAL_PARAM_VENC_HIER_B_MAX_ENH_LAYERS, //61 + HAL_PARAM_VDEC_NON_SECURE_OUTPUT2, //62 + HAL_PARAM_VENC_HIER_P_HYBRID_MODE, //63 +}; + +enum hal_domain { + HAL_VIDEO_DOMAIN_VPE, + HAL_VIDEO_DOMAIN_ENCODER, + HAL_VIDEO_DOMAIN_DECODER, + HAL_UNUSED_DOMAIN = 0x10000000, +}; + +enum multi_stream { + HAL_VIDEO_DECODER_NONE = 0x00000000, + HAL_VIDEO_DECODER_PRIMARY = 0x00000001, + HAL_VIDEO_DECODER_SECONDARY = 0x00000002, + HAL_VIDEO_DECODER_BOTH_OUTPUTS = 0x00000004, + HAL_VIDEO_UNUSED_OUTPUTS = 0x10000000, +}; + +enum hal_core_capabilities { + HAL_VIDEO_ENCODER_ROTATION_CAPABILITY = 0x00000001, + HAL_VIDEO_ENCODER_SCALING_CAPABILITY = 0x00000002, + HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY = 0x00000004, + HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY = 0x00000008, + HAL_VIDEO_UNUSED_CAPABILITY = 0x10000000, +}; + +enum hal_default_properties { + HAL_VIDEO_DYNAMIC_BUF_MODE = 0x00000001, + HAL_VIDEO_CONTINUE_DATA_TRANSFER = 0x00000002, +}; + +enum hal_video_codec { + HAL_VIDEO_CODEC_UNKNOWN = 0x00000000, + HAL_VIDEO_CODEC_MVC = 0x00000001, + HAL_VIDEO_CODEC_H264 = 0x00000002, + HAL_VIDEO_CODEC_H263 = 0x00000004, + HAL_VIDEO_CODEC_MPEG1 = 0x00000008, + HAL_VIDEO_CODEC_MPEG2 = 0x00000010, + HAL_VIDEO_CODEC_MPEG4 = 0x00000020, + HAL_VIDEO_CODEC_DIVX_311 = 0x00000040, + HAL_VIDEO_CODEC_DIVX = 0x00000080, + HAL_VIDEO_CODEC_VC1 = 0x00000100, + HAL_VIDEO_CODEC_SPARK = 0x00000200, + HAL_VIDEO_CODEC_VP6 = 0x00000400, + HAL_VIDEO_CODEC_VP7 = 0x00000800, + HAL_VIDEO_CODEC_VP8 = 0x00001000, + HAL_VIDEO_CODEC_HEVC = 0x00002000, + HAL_VIDEO_CODEC_HEVC_HYBRID = 0x00004000, + HAL_UNUSED_CODEC = 0x10000000, +}; + +enum hal_h263_profile { + HAL_H263_PROFILE_BASELINE = 0x00000001, + HAL_H263_PROFILE_H320CODING = 0x00000002, + HAL_H263_PROFILE_BACKWARDCOMPATIBLE = 0x00000004, + HAL_H263_PROFILE_ISWV2 = 0x00000008, + HAL_H263_PROFILE_ISWV3 = 0x00000010, + HAL_H263_PROFILE_HIGHCOMPRESSION = 0x00000020, + HAL_H263_PROFILE_INTERNET = 0x00000040, + HAL_H263_PROFILE_INTERLACE = 0x00000080, + HAL_H263_PROFILE_HIGHLATENCY = 0x00000100, + HAL_UNUSED_H263_PROFILE = 0x10000000, +}; + +enum hal_h263_level { + HAL_H263_LEVEL_10 = 0x00000001, + HAL_H263_LEVEL_20 = 0x00000002, + HAL_H263_LEVEL_30 = 0x00000004, + HAL_H263_LEVEL_40 = 0x00000008, + HAL_H263_LEVEL_45 = 0x00000010, + HAL_H263_LEVEL_50 = 0x00000020, + HAL_H263_LEVEL_60 = 0x00000040, + HAL_H263_LEVEL_70 = 0x00000080, + HAL_UNUSED_H263_LEVEL = 0x10000000, +}; + +enum hal_mpeg2_profile { + HAL_MPEG2_PROFILE_SIMPLE = 0x00000001, + HAL_MPEG2_PROFILE_MAIN = 0x00000002, + HAL_MPEG2_PROFILE_422 = 0x00000004, + HAL_MPEG2_PROFILE_SNR = 0x00000008, + HAL_MPEG2_PROFILE_SPATIAL = 0x00000010, + HAL_MPEG2_PROFILE_HIGH = 0x00000020, + HAL_UNUSED_MPEG2_PROFILE = 0x10000000, +}; + +enum hal_mpeg2_level { + HAL_MPEG2_LEVEL_LL = 0x00000001, + HAL_MPEG2_LEVEL_ML = 0x00000002, + HAL_MPEG2_LEVEL_H14 = 0x00000004, + HAL_MPEG2_LEVEL_HL = 0x00000008, + HAL_UNUSED_MEPG2_LEVEL = 0x10000000, +}; + +enum hal_mpeg4_profile { + HAL_MPEG4_PROFILE_SIMPLE = 0x00000001, + HAL_MPEG4_PROFILE_ADVANCEDSIMPLE = 0x00000002, + HAL_MPEG4_PROFILE_CORE = 0x00000004, + HAL_MPEG4_PROFILE_MAIN = 0x00000008, + HAL_MPEG4_PROFILE_NBIT = 0x00000010, + HAL_MPEG4_PROFILE_SCALABLETEXTURE = 0x00000020, + HAL_MPEG4_PROFILE_SIMPLEFACE = 0x00000040, + HAL_MPEG4_PROFILE_SIMPLEFBA = 0x00000080, + HAL_MPEG4_PROFILE_BASICANIMATED = 0x00000100, + HAL_MPEG4_PROFILE_HYBRID = 0x00000200, + HAL_MPEG4_PROFILE_ADVANCEDREALTIME = 0x00000400, + HAL_MPEG4_PROFILE_CORESCALABLE = 0x00000800, + HAL_MPEG4_PROFILE_ADVANCEDCODING = 0x00001000, + HAL_MPEG4_PROFILE_ADVANCEDCORE = 0x00002000, + HAL_MPEG4_PROFILE_ADVANCEDSCALABLE = 0x00004000, + HAL_MPEG4_PROFILE_SIMPLESCALABLE = 0x00008000, + HAL_UNUSED_MPEG4_PROFILE = 0x10000000, +}; + +enum hal_mpeg4_level { + HAL_MPEG4_LEVEL_0 = 0x00000001, + HAL_MPEG4_LEVEL_0b = 0x00000002, + HAL_MPEG4_LEVEL_1 = 0x00000004, + HAL_MPEG4_LEVEL_2 = 0x00000008, + HAL_MPEG4_LEVEL_3 = 0x00000010, + HAL_MPEG4_LEVEL_4 = 0x00000020, + HAL_MPEG4_LEVEL_4a = 0x00000040, + HAL_MPEG4_LEVEL_5 = 0x00000080, + HAL_MPEG4_LEVEL_VENDOR_START_UNUSED = 0x7F000000, + HAL_MPEG4_LEVEL_6 = 0x7F000001, + HAL_MPEG4_LEVEL_7 = 0x7F000002, + HAL_MPEG4_LEVEL_8 = 0x7F000003, + HAL_MPEG4_LEVEL_9 = 0x7F000004, + HAL_MPEG4_LEVEL_3b = 0x7F000005, + HAL_UNUSED_MPEG4_LEVEL = 0x10000000, +}; + +enum hal_h264_profile { + HAL_H264_PROFILE_BASELINE = 0x00000001, + HAL_H264_PROFILE_MAIN = 0x00000002, + HAL_H264_PROFILE_HIGH = 0x00000004, + HAL_H264_PROFILE_EXTENDED = 0x00000008, + HAL_H264_PROFILE_HIGH10 = 0x00000010, + HAL_H264_PROFILE_HIGH422 = 0x00000020, + HAL_H264_PROFILE_HIGH444 = 0x00000040, + HAL_H264_PROFILE_CONSTRAINED_BASE = 0x00000080, + HAL_H264_PROFILE_CONSTRAINED_HIGH = 0x00000100, + HAL_UNUSED_H264_PROFILE = 0x10000000, +}; + +enum hal_h264_level { + HAL_H264_LEVEL_1 = 0x00000001, + HAL_H264_LEVEL_1b = 0x00000002, + HAL_H264_LEVEL_11 = 0x00000004, + HAL_H264_LEVEL_12 = 0x00000008, + HAL_H264_LEVEL_13 = 0x00000010, + HAL_H264_LEVEL_2 = 0x00000020, + HAL_H264_LEVEL_21 = 0x00000040, + HAL_H264_LEVEL_22 = 0x00000080, + HAL_H264_LEVEL_3 = 0x00000100, + HAL_H264_LEVEL_31 = 0x00000200, + HAL_H264_LEVEL_32 = 0x00000400, + HAL_H264_LEVEL_4 = 0x00000800, + HAL_H264_LEVEL_41 = 0x00001000, + HAL_H264_LEVEL_42 = 0x00002000, + HAL_H264_LEVEL_5 = 0x00004000, + HAL_H264_LEVEL_51 = 0x00008000, + HAL_H264_LEVEL_52 = 0x00010000, + HAL_UNUSED_H264_LEVEL = 0x10000000, +}; + +enum hal_hevc_profile { + HAL_HEVC_PROFILE_MAIN = 0x00000001, + HAL_HEVC_PROFILE_MAIN10 = 0x00000002, + HAL_HEVC_PROFILE_MAIN_STILL_PIC = 0x00000004, + HAL_UNUSED_HEVC_PROFILE = 0x10000000, +}; + +enum hal_hevc_level { + HAL_HEVC_MAIN_TIER_LEVEL_1 = 0x10000001, + HAL_HEVC_MAIN_TIER_LEVEL_2 = 0x10000002, + HAL_HEVC_MAIN_TIER_LEVEL_2_1 = 0x10000004, + HAL_HEVC_MAIN_TIER_LEVEL_3 = 0x10000008, + HAL_HEVC_MAIN_TIER_LEVEL_3_1 = 0x10000010, + HAL_HEVC_MAIN_TIER_LEVEL_4 = 0x10000020, + HAL_HEVC_MAIN_TIER_LEVEL_4_1 = 0x10000040, + HAL_HEVC_MAIN_TIER_LEVEL_5 = 0x10000080, + HAL_HEVC_MAIN_TIER_LEVEL_5_1 = 0x10000100, + HAL_HEVC_MAIN_TIER_LEVEL_5_2 = 0x10000200, + HAL_HEVC_MAIN_TIER_LEVEL_6 = 0x10000400, + HAL_HEVC_MAIN_TIER_LEVEL_6_1 = 0x10000800, + HAL_HEVC_MAIN_TIER_LEVEL_6_2 = 0x10001000, + HAL_HEVC_HIGH_TIER_LEVEL_1 = 0x20000001, + HAL_HEVC_HIGH_TIER_LEVEL_2 = 0x20000002, + HAL_HEVC_HIGH_TIER_LEVEL_2_1 = 0x20000004, + HAL_HEVC_HIGH_TIER_LEVEL_3 = 0x20000008, + HAL_HEVC_HIGH_TIER_LEVEL_3_1 = 0x20000010, + HAL_HEVC_HIGH_TIER_LEVEL_4 = 0x20000020, + HAL_HEVC_HIGH_TIER_LEVEL_4_1 = 0x20000040, + HAL_HEVC_HIGH_TIER_LEVEL_5 = 0x20000080, + HAL_HEVC_HIGH_TIER_LEVEL_5_1 = 0x20000100, + HAL_HEVC_HIGH_TIER_LEVEL_5_2 = 0x20000200, + HAL_HEVC_HIGH_TIER_LEVEL_6 = 0x20000400, + HAL_HEVC_HIGH_TIER_LEVEL_6_1 = 0x20000800, + HAL_HEVC_HIGH_TIER_LEVEL_6_2 = 0x20001000, + HAL_UNUSED_HEVC_TIER_LEVEL = 0x80000000, +}; + +enum hal_hevc_tier { + HAL_HEVC_TIER_MAIN = 0x00000001, + HAL_HEVC_TIER_HIGH = 0x00000002, + HAL_UNUSED_HEVC_TIER = 0x10000000, +}; + +enum hal_vpx_profile { + HAL_VPX_PROFILE_SIMPLE = 0x00000001, + HAL_VPX_PROFILE_ADVANCED = 0x00000002, + HAL_VPX_PROFILE_VERSION_0 = 0x00000004, + HAL_VPX_PROFILE_VERSION_1 = 0x00000008, + HAL_VPX_PROFILE_VERSION_2 = 0x00000010, + HAL_VPX_PROFILE_VERSION_3 = 0x00000020, + HAL_VPX_PROFILE_UNUSED = 0x10000000, +}; + +enum hal_vc1_profile { + HAL_VC1_PROFILE_SIMPLE = 0x00000001, + HAL_VC1_PROFILE_MAIN = 0x00000002, + HAL_VC1_PROFILE_ADVANCED = 0x00000004, + HAL_UNUSED_VC1_PROFILE = 0x10000000, +}; + +enum hal_vc1_level { + HAL_VC1_LEVEL_LOW = 0x00000001, + HAL_VC1_LEVEL_MEDIUM = 0x00000002, + HAL_VC1_LEVEL_HIGH = 0x00000004, + HAL_VC1_LEVEL_0 = 0x00000008, + HAL_VC1_LEVEL_1 = 0x00000010, + HAL_VC1_LEVEL_2 = 0x00000020, + HAL_VC1_LEVEL_3 = 0x00000040, + HAL_VC1_LEVEL_4 = 0x00000080, + HAL_UNUSED_VC1_LEVEL = 0x10000000, +}; + +enum hal_divx_format { + HAL_DIVX_FORMAT_4, + HAL_DIVX_FORMAT_5, + HAL_DIVX_FORMAT_6, + HAL_UNUSED_DIVX_FORMAT = 0x10000000, +}; + +enum hal_divx_profile { + HAL_DIVX_PROFILE_QMOBILE = 0x00000001, + HAL_DIVX_PROFILE_MOBILE = 0x00000002, + HAL_DIVX_PROFILE_MT = 0x00000004, + HAL_DIVX_PROFILE_HT = 0x00000008, + HAL_DIVX_PROFILE_HD = 0x00000010, + HAL_UNUSED_DIVX_PROFILE = 0x10000000, +}; + +enum hal_mvc_profile { + HAL_MVC_PROFILE_STEREO_HIGH = 0x00001000, + HAL_UNUSED_MVC_PROFILE = 0x10000000, +}; + +enum hal_mvc_level { + HAL_MVC_LEVEL_1 = 0x00000001, + HAL_MVC_LEVEL_1b = 0x00000002, + HAL_MVC_LEVEL_11 = 0x00000004, + HAL_MVC_LEVEL_12 = 0x00000008, + HAL_MVC_LEVEL_13 = 0x00000010, + HAL_MVC_LEVEL_2 = 0x00000020, + HAL_MVC_LEVEL_21 = 0x00000040, + HAL_MVC_LEVEL_22 = 0x00000080, + HAL_MVC_LEVEL_3 = 0x00000100, + HAL_MVC_LEVEL_31 = 0x00000200, + HAL_MVC_LEVEL_32 = 0x00000400, + HAL_MVC_LEVEL_4 = 0x00000800, + HAL_MVC_LEVEL_41 = 0x00001000, + HAL_MVC_LEVEL_42 = 0x00002000, + HAL_MVC_LEVEL_5 = 0x00004000, + HAL_MVC_LEVEL_51 = 0x00008000, + HAL_UNUSED_MVC_LEVEL = 0x10000000, +}; + +struct hal_frame_rate { + enum hal_buffer buffer_type; + u32 frame_rate; +}; + +enum hal_uncompressed_format { + HAL_COLOR_FORMAT_MONOCHROME = 0x00000001, + HAL_COLOR_FORMAT_NV12 = 0x00000002, + HAL_COLOR_FORMAT_NV21 = 0x00000004, + HAL_COLOR_FORMAT_NV12_4x4TILE = 0x00000008, + HAL_COLOR_FORMAT_NV21_4x4TILE = 0x00000010, + HAL_COLOR_FORMAT_YUYV = 0x00000020, + HAL_COLOR_FORMAT_YVYU = 0x00000040, + HAL_COLOR_FORMAT_UYVY = 0x00000080, + HAL_COLOR_FORMAT_VYUY = 0x00000100, + HAL_COLOR_FORMAT_RGB565 = 0x00000200, + HAL_COLOR_FORMAT_BGR565 = 0x00000400, + HAL_COLOR_FORMAT_RGB888 = 0x00000800, + HAL_COLOR_FORMAT_BGR888 = 0x00001000, + HAL_COLOR_FORMAT_NV12_UBWC = 0x00002000, + HAL_COLOR_FORMAT_NV12_TP10_UBWC = 0x00004000, + HAL_UNUSED_COLOR = 0x10000000, +}; + +enum hal_ssr_trigger_type { + SSR_ERR_FATAL = 1, + SSR_SW_DIV_BY_ZERO, + SSR_HW_WDOG_IRQ, +}; + +enum vidc_extradata_type { + VIDC_EXTRADATA_NONE = 0x00000000, + VIDC_EXTRADATA_MB_QUANTIZATION = 0x00000001, + VIDC_EXTRADATA_INTERLACE_VIDEO = 0x00000002, + VIDC_EXTRADATA_VC1_FRAMEDISP = 0x00000003, + VIDC_EXTRADATA_VC1_SEQDISP = 0x00000004, + VIDC_EXTRADATA_TIMESTAMP = 0x00000005, + VIDC_EXTRADATA_S3D_FRAME_PACKING = 0x00000006, + VIDC_EXTRADATA_FRAME_RATE = 0x00000007, + VIDC_EXTRADATA_PANSCAN_WINDOW = 0x00000008, + VIDC_EXTRADATA_RECOVERY_POINT_SEI = 0x00000009, + VIDC_EXTRADATA_MPEG2_SEQDISP = 0x0000000D, + VIDC_EXTRADATA_STREAM_USERDATA = 0x0000000E, + VIDC_EXTRADATA_FRAME_QP = 0x0000000F, + VIDC_EXTRADATA_FRAME_BITS_INFO = 0x00000010, + VIDC_EXTRADATA_INPUT_CROP = 0x0700000E, + VIDC_EXTRADATA_DIGITAL_ZOOM = 0x07000010, + VIDC_EXTRADATA_MULTISLICE_INFO = 0x7F100000, + VIDC_EXTRADATA_NUM_CONCEALED_MB = 0x7F100001, + VIDC_EXTRADATA_INDEX = 0x7F100002, + VIDC_EXTRADATA_ASPECT_RATIO = 0x7F100003, + VIDC_EXTRADATA_METADATA_LTR = 0x7F100004, + VIDC_EXTRADATA_METADATA_FILLER = 0x7FE00002, + VIDC_EXTRADATA_METADATA_MBI = 0x7F100005, +}; + +struct hal_uncompressed_format_select { + enum hal_buffer buffer_type; + enum hal_uncompressed_format format; +}; + +struct hal_uncompressed_plane_actual { + int actual_stride; + u32 actual_plane_buffer_height; +}; + +struct hal_uncompressed_plane_actual_info { + enum hal_buffer buffer_type; + u32 num_planes; + struct hal_uncompressed_plane_actual rg_plane_format[1]; +}; + +struct hal_uncompressed_plane_constraints { + u32 stride_multiples; + u32 max_stride; + u32 min_plane_buffer_height_multiple; + u32 buffer_alignment; +}; + +struct hal_uncompressed_plane_actual_constraints_info { + enum hal_buffer buffer_type; + u32 num_planes; + struct hal_uncompressed_plane_constraints rg_plane_format[1]; +}; + +struct hal_extra_data_header_config { + u32 type; + enum hal_buffer buffer_type; + u32 version; + u32 port_index; + u32 client_extradata_id; +}; + +struct hal_frame_size { + enum hal_buffer buffer_type; + u32 width; + u32 height; +}; + +struct hal_enable { + u32 enable; +}; + +struct hal_buffer_count_actual { + enum hal_buffer type; + u32 count_actual; +}; + +struct hal_buffer_size_actual { + enum hal_buffer type; + u32 size; +}; + +struct hal_buffer_display_hold_count_actual { + enum hal_buffer buffer_type; + u32 hold_count; +}; + +enum hal_nal_stream_format { + HAL_NAL_FORMAT_STARTCODES = 0x00000001, + HAL_NAL_FORMAT_ONE_NAL_PER_BUFFER = 0x00000002, + HAL_NAL_FORMAT_ONE_BYTE_LENGTH = 0x00000004, + HAL_NAL_FORMAT_TWO_BYTE_LENGTH = 0x00000008, + HAL_NAL_FORMAT_FOUR_BYTE_LENGTH = 0x00000010, +}; + +enum hal_output_order { + HAL_OUTPUT_ORDER_DISPLAY, + HAL_OUTPUT_ORDER_DECODE, + HAL_UNUSED_OUTPUT = 0x10000000, +}; + +enum hal_picture { + HAL_PICTURE_I = 0x01, + HAL_PICTURE_P = 0x02, + HAL_PICTURE_B = 0x04, + HAL_PICTURE_IDR = 0x08, + HAL_FRAME_NOTCODED = 0x7F002000, + HAL_FRAME_YUV = 0x7F004000, + HAL_UNUSED_PICT = 0x10000000, +}; + +struct hal_extradata_enable { + u32 enable; + enum hal_extradata_id index; +}; + +struct hal_enable_picture { + u32 picture_type; +}; + +struct hal_multi_stream { + enum hal_buffer buffer_type; + u32 enable; + u32 width; + u32 height; +}; + +struct hal_display_picture_buffer_count { + u32 enable; + u32 count; +}; + +struct hal_mb_error_map { + u32 error_map_size; + u8 rg_error_map[1]; +}; + +struct hal_request_iframe { + u32 enable; +}; + +struct hal_bitrate { + u32 bit_rate; + u32 layer_id; +}; + +struct hal_profile_level { + u32 profile; + u32 level; +}; + +struct hal_profile_level_supported { + u32 profile_count; + struct hal_profile_level profile_level[MAX_PROFILE_COUNT]; +}; + +enum hal_h264_entropy { + HAL_H264_ENTROPY_CAVLC = 1, + HAL_H264_ENTROPY_CABAC = 2, + HAL_UNUSED_ENTROPY = 0x10000000, +}; + +enum hal_h264_cabac_model { + HAL_H264_CABAC_MODEL_0 = 1, + HAL_H264_CABAC_MODEL_1 = 2, + HAL_H264_CABAC_MODEL_2 = 4, + HAL_UNUSED_CABAC = 0x10000000, +}; + +struct hal_h264_entropy_control { + enum hal_h264_entropy entropy_mode; + enum hal_h264_cabac_model cabac_model; +}; + +enum hal_rate_control { + HAL_RATE_CONTROL_OFF, + HAL_RATE_CONTROL_VBR_VFR, + HAL_RATE_CONTROL_VBR_CFR, + HAL_RATE_CONTROL_CBR_VFR, + HAL_RATE_CONTROL_CBR_CFR, + HAL_UNUSED_RC = 0x10000000, +}; + +struct hal_mpeg4_time_resolution { + u32 time_increment_resolution; +}; + +struct hal_mpeg4_header_extension { + u32 header_extension; +}; + +enum hal_h264_db_mode { + HAL_H264_DB_MODE_DISABLE, + HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY, + HAL_H264_DB_MODE_ALL_BOUNDARY, + HAL_UNUSED_H264_DB = 0x10000000, +}; + +struct hal_h264_db_control { + enum hal_h264_db_mode mode; + int slice_alpha_offset; + int slice_beta_offset; +}; + +struct hal_temporal_spatial_tradeoff { + u32 ts_factor; +}; + +struct hal_quantization { + u32 qpi; + u32 qpp; + u32 qpb; + u32 layer_id; +}; + +struct hal_initial_quantization { + u32 qpi; + u32 qpp; + u32 qpb; + u32 init_qp_enable; +}; + +struct hal_quantization_range { + u32 min_qp; + u32 max_qp; + u32 layer_id; +}; + +struct hal_intra_period { + u32 pframes; + u32 bframes; +}; + +struct hal_idr_period { + u32 idr_period; +}; + +enum hal_rotate { + HAL_ROTATE_NONE, + HAL_ROTATE_90, + HAL_ROTATE_180, + HAL_ROTATE_270, + HAL_UNUSED_ROTATE = 0x10000000, +}; + +enum hal_flip { + HAL_FLIP_NONE, + HAL_FLIP_HORIZONTAL, + HAL_FLIP_VERTICAL, + HAL_UNUSED_FLIP = 0x10000000, +}; + +struct hal_operations { + enum hal_rotate rotate; + enum hal_flip flip; +}; + +enum hal_intra_refresh_mode { + HAL_INTRA_REFRESH_NONE, + HAL_INTRA_REFRESH_CYCLIC, + HAL_INTRA_REFRESH_ADAPTIVE, + HAL_INTRA_REFRESH_CYCLIC_ADAPTIVE, + HAL_INTRA_REFRESH_RANDOM, + HAL_UNUSED_INTRA = 0x10000000, +}; + +struct hal_intra_refresh { + enum hal_intra_refresh_mode mode; + u32 air_mbs; + u32 air_ref; + u32 cir_mbs; +}; + +enum hal_multi_slice { + HAL_MULTI_SLICE_OFF, + HAL_MULTI_SLICE_BY_MB_COUNT, + HAL_MULTI_SLICE_BY_BYTE_COUNT, + HAL_MULTI_SLICE_GOB, + HAL_UNUSED_SLICE = 0x10000000, +}; + +struct hal_multi_slice_control { + enum hal_multi_slice multi_slice; + u32 slice_size; +}; + +struct hal_debug_config { + u32 debug_config; +}; + +struct hal_buffer_requirements { + enum hal_buffer type; + u32 size; + u32 region_size; + u32 hold_count; + u32 count_min; + u32 count_actual; + u32 contiguous; + u32 alignment; +}; + +enum hal_priority {/* Priority increases with number */ + HAL_PRIORITY_LOW = 10, + HAL_PRIOIRTY_MEDIUM = 20, + HAL_PRIORITY_HIGH = 30, + HAL_UNUSED_PRIORITY = 0x10000000, +}; + +struct hal_batch_info { + u32 input_batch_count; + u32 output_batch_count; +}; + +struct hal_metadata_pass_through { + u32 enable; + u32 size; +}; + +struct hal_uncompressed_format_supported { + enum hal_buffer buffer_type; + u32 format_entries; + u32 rg_format_info[1]; +}; + +enum hal_interlace_format { + HAL_INTERLACE_FRAME_PROGRESSIVE = 0x01, + HAL_INTERLACE_INTERLEAVE_FRAME_TOPFIELDFIRST = 0x02, + HAL_INTERLACE_INTERLEAVE_FRAME_BOTTOMFIELDFIRST = 0x04, + HAL_INTERLACE_FRAME_TOPFIELDFIRST = 0x08, + HAL_INTERLACE_FRAME_BOTTOMFIELDFIRST = 0x10, + HAL_UNUSED_INTERLACE = 0x10000000, +}; + +struct hal_interlace_format_supported { + enum hal_buffer buffer_type; + enum hal_interlace_format format; +}; + +enum hal_chroma_site { + HAL_CHROMA_SITE_0, + HAL_CHROMA_SITE_1, + HAL_UNUSED_CHROMA = 0x10000000, +}; + +struct hal_properties_supported { + u32 num_properties; + u32 rg_properties[1]; +}; + +enum hal_capability { + HAL_CAPABILITY_FRAME_WIDTH, + HAL_CAPABILITY_FRAME_HEIGHT, + HAL_CAPABILITY_MBS_PER_FRAME, + HAL_CAPABILITY_MBS_PER_SECOND, + HAL_CAPABILITY_FRAMERATE, + HAL_CAPABILITY_SCALE_X, + HAL_CAPABILITY_SCALE_Y, + HAL_CAPABILITY_BITRATE, + HAL_CAPABILITY_SECURE_OUTPUT2_THRESHOLD, + HAL_UNUSED_CAPABILITY = 0x10000000, +}; + +struct hal_capability_supported { + enum hal_capability capability_type; + u32 min; + u32 max; + u32 step_size; +}; + +struct hal_capability_supported_info { + u32 num_capabilities; + struct hal_capability_supported rg_data[1]; +}; + +struct hal_nal_stream_format_supported { + u32 nal_stream_format_supported; +}; + +struct hal_nal_stream_format_select { + u32 nal_stream_format_select; +}; + +struct hal_multi_view_format { + u32 views; + u32 rg_view_order[1]; +}; + +enum hal_buffer_layout_type { + HAL_BUFFER_LAYOUT_TOP_BOTTOM, + HAL_BUFFER_LAYOUT_SEQ, + HAL_UNUSED_BUFFER_LAYOUT = 0x10000000, +}; + +struct hal_mvc_buffer_layout { + enum hal_buffer_layout_type layout_type; + u32 bright_view_first; + u32 ngap; +}; + +struct hal_seq_header_info { + u32 nax_header_len; +}; + +struct hal_codec_supported { + u32 decoder_codec_supported; + u32 encoder_codec_supported; +}; + +struct hal_multi_view_select { + u32 view_index; +}; + +struct hal_timestamp_scale { + u32 time_stamp_scale; +}; + + +struct hal_h264_vui_timing_info { + u32 enable; + u32 fixed_frame_rate; + u32 time_scale; +}; + +struct hal_h264_vui_bitstream_restrc { + u32 enable; +}; + +struct hal_preserve_text_quality { + u32 enable; +}; + +struct hal_vc1e_perf_cfg_type { + struct { + u32 x_subsampled; + u32 y_subsampled; + } i_frame, p_frame, b_frame; +}; + +struct hal_vpe_color_space_conversion { + u32 csc_matrix[HAL_MAX_MATRIX_COEFFS]; + u32 csc_bias[HAL_MAX_BIAS_COEFFS]; + u32 csc_limit[HAL_MAX_LIMIT_COEFFS]; +}; + +enum vidc_resource_id { + VIDC_RESOURCE_NONE, + VIDC_RESOURCE_OCMEM, + VIDC_RESOURCE_VMEM, + VIDC_UNUSED_RESOURCE = 0x10000000, +}; + +struct vidc_resource_hdr { + enum vidc_resource_id resource_id; + void *resource_handle; + u32 size; +}; + +struct vidc_buffer_addr_info { + enum hal_buffer buffer_type; + u32 buffer_size; + u32 num_buffers; + u32 device_addr; + u32 extradata_addr; + u32 extradata_size; + u32 response_required; +}; + +/* Needs to be exactly the same as hfi_buffer_info */ +struct hal_buffer_info { + u32 buffer_addr; + u32 extra_data_addr; +}; + +struct vidc_frame_plane_config { + u32 left; + u32 top; + u32 width; + u32 height; + u32 stride; + u32 scan_lines; +}; + +struct vidc_uncompressed_frame_config { + struct vidc_frame_plane_config luma_plane; + struct vidc_frame_plane_config chroma_plane; +}; + +struct vidc_frame_data { + enum hal_buffer buffer_type; + u32 device_addr; + u32 extradata_addr; + int64_t timestamp; + u32 flags; + u32 offset; + u32 alloc_len; + u32 filled_len; + u32 mark_target; + u32 mark_data; + u32 clnt_data; + u32 extradata_size; +}; + +struct vidc_seq_hdr { + u32 seq_hdr; + u32 seq_hdr_len; +}; + +enum hal_flush { + HAL_FLUSH_INPUT, + HAL_FLUSH_OUTPUT, + HAL_FLUSH_OUTPUT2, + HAL_FLUSH_ALL, + HAL_UNUSED_FLUSH = 0x10000000, +}; + +enum hal_event_type { + HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES, + HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES, + HAL_EVENT_RELEASE_BUFFER_REFERENCE, + HAL_UNUSED_SEQCHG = 0x10000000, +}; + +enum hal_buffer_mode_type { + HAL_BUFFER_MODE_STATIC = 0x001, + HAL_BUFFER_MODE_RING = 0x010, + HAL_BUFFER_MODE_DYNAMIC = 0x100, +}; + +struct hal_buffer_alloc_mode { + enum hal_buffer type; + enum hal_buffer_mode_type mode; +}; + +enum ltr_mode { + HAL_LTR_MODE_DISABLE, + HAL_LTR_MODE_MANUAL, + HAL_LTR_MODE_PERIODIC, +}; + +struct hal_ltr_mode { + enum ltr_mode mode; + u32 count; + u32 trust_mode; +}; + +struct hal_ltr_use { + u32 ref_ltr; + u32 use_constraint; + u32 frames; +}; + +struct hal_ltr_mark { + u32 mark_frame; +}; + +struct hal_venc_perf_mode { + u32 mode; +}; + +struct hal_hybrid_hierp { + u32 layers; +}; + +struct hfi_scs_threshold { + u32 threshold_value; +}; + +struct buffer_requirements { + struct hal_buffer_requirements buffer[HAL_BUFFER_MAX]; +}; + +union hal_get_property { + struct hal_frame_rate frame_rate; + struct hal_uncompressed_format_select format_select; + struct hal_uncompressed_plane_actual plane_actual; + struct hal_uncompressed_plane_actual_info plane_actual_info; + struct hal_uncompressed_plane_constraints plane_constraints; + struct hal_uncompressed_plane_actual_constraints_info + plane_constraints_info; + struct hal_extra_data_header_config extra_data_header_config; + struct hal_frame_size frame_size; + struct hal_enable enable; + struct hal_buffer_count_actual buffer_count_actual; + struct hal_extradata_enable extradata_enable; + struct hal_enable_picture enable_picture; + struct hal_multi_stream multi_stream; + struct hal_display_picture_buffer_count display_picture_buffer_count; + struct hal_mb_error_map mb_error_map; + struct hal_request_iframe request_iframe; + struct hal_bitrate bitrate; + struct hal_profile_level profile_level; + struct hal_profile_level_supported profile_level_supported; + struct hal_h264_entropy_control h264_entropy_control; + struct hal_mpeg4_time_resolution mpeg4_time_resolution; + struct hal_mpeg4_header_extension mpeg4_header_extension; + struct hal_h264_db_control h264_db_control; + struct hal_temporal_spatial_tradeoff temporal_spatial_tradeoff; + struct hal_quantization quantization; + struct hal_quantization_range quantization_range; + struct hal_intra_period intra_period; + struct hal_idr_period idr_period; + struct hal_operations operations; + struct hal_intra_refresh intra_refresh; + struct hal_multi_slice_control multi_slice_control; + struct hal_debug_config debug_config; + struct hal_batch_info batch_info; + struct hal_metadata_pass_through metadata_pass_through; + struct hal_uncompressed_format_supported uncompressed_format_supported; + struct hal_interlace_format_supported interlace_format_supported; + struct hal_properties_supported properties_supported; + struct hal_capability_supported capability_supported; + struct hal_capability_supported_info capability_supported_info; + struct hal_nal_stream_format_supported nal_stream_format_supported; + struct hal_nal_stream_format_select nal_stream_format_select; + struct hal_multi_view_format multi_view_format; + struct hal_seq_header_info seq_header_info; + struct hal_codec_supported codec_supported; + struct hal_multi_view_select multi_view_select; + struct hal_timestamp_scale timestamp_scale; + struct hal_h264_vui_timing_info h264_vui_timing_info; + struct hal_h264_vui_bitstream_restrc h264_vui_bitstream_restrc; + struct hal_preserve_text_quality preserve_text_quality; + struct hal_buffer_info buffer_info; + struct hal_buffer_alloc_mode buffer_alloc_mode; + struct buffer_requirements buf_req; +}; + +/* HAL Response */ + +enum command_response { + /* SYSTEM COMMANDS_DONE*/ + SYS_EVENT_CHANGE, + SYS_INIT_DONE, + SYS_SET_RESOURCE_DONE, + SYS_RELEASE_RESOURCE_DONE, + SYS_PING_ACK_DONE, + SYS_PC_PREP_DONE, + SYS_IDLE, + SYS_DEBUG, + SYS_WATCHDOG_TIMEOUT, + SYS_ERROR, + /* SESSION COMMANDS_DONE */ + SESSION_LOAD_RESOURCE_DONE, + SESSION_INIT_DONE, + SESSION_END_DONE, + SESSION_ABORT_DONE, + SESSION_START_DONE, + SESSION_STOP_DONE, + SESSION_ETB_DONE, + SESSION_FTB_DONE, + SESSION_FLUSH_DONE, + SESSION_SUSPEND_DONE, + SESSION_RESUME_DONE, + SESSION_SET_PROP_DONE, + SESSION_GET_PROP_DONE, + SESSION_PARSE_SEQ_HDR_DONE, + SESSION_GET_SEQ_HDR_DONE, + SESSION_RELEASE_BUFFER_DONE, + SESSION_RELEASE_RESOURCE_DONE, + SESSION_PROPERTY_INFO, + SESSION_ERROR, + RESPONSE_UNUSED = 0x10000000, +}; + +/* Event Callback structure */ + +struct vidc_cb_event { + u32 device_id; + u32 session_id; + enum vidc_error error; + u32 height; + u32 width; + u32 hal_event_type; + u32 packet_buffer; + u32 extra_data_buffer; + u32 profile; + u32 level; +}; + +/* Data callback structure */ + +struct vidc_hal_ebd { + u32 timestamp_hi; + u32 timestamp_lo; + u32 flags; + enum vidc_error error; + u32 mark_target; + u32 mark_data; + u32 stats; + u32 offset; + u32 alloc_len; + u32 filled_len; + enum hal_picture picture_type; + u32 packet_buffer; + u32 extra_data_buffer; +}; + +struct vidc_hal_fbd { + u32 stream_id; + u32 view_id; + u32 timestamp_hi; + u32 timestamp_lo; + u32 flags1; + u32 mark_target; + u32 mark_data; + u32 stats; + u32 alloc_len1; + u32 filled_len1; + u32 offset1; + u32 frame_width; + u32 frame_height; + u32 start_x_coord; + u32 start_y_coord; + u32 input_tag; + u32 input_tag1; + enum hal_picture picture_type; + u32 packet_buffer1; + u32 extra_data_buffer; + u32 flags2; + u32 alloc_len2; + u32 filled_len2; + u32 offset2; + u32 packet_buffer2; + u32 flags3; + u32 alloc_len3; + u32 filled_len3; + u32 offset3; + u32 packet_buffer3; + enum hal_buffer buffer_type; +}; + +struct vidc_cb_data_done { + u32 device_id; + void *session_id; + enum vidc_error error; + u32 size; + u32 clnt_data; + union { + struct vidc_hal_ebd input_done; + struct vidc_hal_fbd output_done; + }; +}; + +struct vidc_hal_sys_init_done { + u32 enc_codec_supported; + u32 dec_codec_supported; +}; + +struct vidc_hal_session_init_done { + struct hal_capability_supported width; + struct hal_capability_supported height; + struct hal_capability_supported mbs_per_frame; + struct hal_capability_supported mbs_per_sec; + struct hal_capability_supported frame_rate; + struct hal_capability_supported scale_x; + struct hal_capability_supported scale_y; + struct hal_capability_supported bitrate; + struct hal_capability_supported hier_p; + struct hal_capability_supported ltr_count; + struct hal_capability_supported secure_output2_threshold; + struct hal_uncompressed_format_supported uncomp_format; + struct hal_interlace_format_supported HAL_format; + struct hal_nal_stream_format_supported nal_stream_format; + struct hal_profile_level_supported profile_level; + /* allocate and released memory for above */ + struct hal_intra_refresh intra_refresh; + struct hal_seq_header_info seq_hdr_info; + enum hal_buffer_mode_type alloc_mode_out; +}; + +enum vidc_hfi_type { + VIDC_HFI_VENUS, + VIDC_HFI_Q6, +}; + +#define call_hfi_op(hdev, op, args...) \ + (((hdev) && (hdev)->ops && (hdev)->ops->op) ? \ + ((hdev)->ops->op(args)) : 0) + +struct hfi_ops { + int (*core_init)(void *device); + int (*core_release)(void *device); + int (*core_ping)(void *device); + int (*core_trigger_ssr)(void *device, enum hal_ssr_trigger_type); + + void *(*session_init)(void *device, void *session_id, + enum hal_domain session_type, + enum hal_video_codec codec_type); + int (*session_end)(void *session); + int (*session_abort)(void *session); + int (*session_clean)(void *sess); + int (*session_flush)(void *sess, enum hal_flush flush_mode); + int (*session_start)(void *sess); + int (*session_stop)(void *sess); + int (*session_etb)(void *sess, struct vidc_frame_data *input_frame); + int (*session_ftb)(void *sess, struct vidc_frame_data *output_frame); + int (*session_set_buffers)(void *sess, + struct vidc_buffer_addr_info *bai); + int (*session_release_buffers)(void *sess, + struct vidc_buffer_addr_info *bai); + int (*session_load_res)(void *sess); + int (*session_release_res)(void *sess); + int (*session_parse_seq_hdr)(void *sess, struct vidc_seq_hdr *seq_hdr); + int (*session_get_seq_hdr)(void *sess, struct vidc_seq_hdr *seq_hdr); + int (*session_set_property)(void *sess, enum hal_property ptype, + void *pdata); + int (*session_get_property)(void *sess, enum hal_property ptype); + + int (*get_stride_scanline)(int color_fmt, int width, int height, + int *stride, int *scanlines); + int (*get_core_capabilities)(void); + int (*resume)(void *dev); + int (*suspend)(void *dev); + enum hal_default_properties (*get_default_properties)(void *dev); +}; + +struct hfi_device { + void *hfi_device_data; + const struct hfi_ops *ops; +}; + +void *vidc_hfi_init(enum vidc_hfi_type hfi_type, u32 device_id, + struct vidc_resources *res); +void vidc_hfi_deinit(enum vidc_hfi_type hfi_type, struct hfi_device *hdev); + +#endif /*__VIDC_HFI_API_H__ */ diff --git a/drivers/media/platform/msm/vidc/hfi/vidc_hfi_helper.h b/drivers/media/platform/msm/vidc/hfi/vidc_hfi_helper.h new file mode 100644 index 000000000000..1015a82f2b69 --- /dev/null +++ b/drivers/media/platform/msm/vidc/hfi/vidc_hfi_helper.h @@ -0,0 +1,1059 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __H_VIDC_HFI_HELPER_H__ +#define __H_VIDC_HFI_HELPER_H__ + +#define HFI_COMMON_BASE 0 +#define HFI_OX_BASE 0x01000000 + +#define HFI_VIDEO_DOMAIN_ENCODER (HFI_COMMON_BASE + 0x1) +#define HFI_VIDEO_DOMAIN_DECODER (HFI_COMMON_BASE + 0x2) +#define HFI_VIDEO_DOMAIN_VPE (HFI_COMMON_BASE + 0x4) +#define HFI_VIDEO_DOMAIN_MBI (HFI_COMMON_BASE + 0x8) + +#define HFI_DOMAIN_BASE_COMMON (HFI_COMMON_BASE + 0) +#define HFI_DOMAIN_BASE_VDEC (HFI_COMMON_BASE + 0x01000000) +#define HFI_DOMAIN_BASE_VENC (HFI_COMMON_BASE + 0x02000000) +#define HFI_DOMAIN_BASE_VPE (HFI_COMMON_BASE + 0x03000000) + +#define HFI_VIDEO_ARCH_OX (HFI_COMMON_BASE + 0x1) + +#define HFI_ARCH_COMMON_OFFSET 0 +#define HFI_ARCH_OX_OFFSET 0x00200000 + +#define HFI_CMD_START_OFFSET 0x00010000 +#define HFI_MSG_START_OFFSET 0x00020000 + +#define HFI_ERR_NONE HFI_COMMON_BASE +#define HFI_ERR_SYS_FATAL (HFI_COMMON_BASE + 0x1) +#define HFI_ERR_SYS_INVALID_PARAMETER (HFI_COMMON_BASE + 0x2) +#define HFI_ERR_SYS_VERSION_MISMATCH (HFI_COMMON_BASE + 0x3) +#define HFI_ERR_SYS_INSUFFICIENT_RESOURCES (HFI_COMMON_BASE + 0x4) +#define HFI_ERR_SYS_MAX_SESSIONS_REACHED (HFI_COMMON_BASE + 0x5) +#define HFI_ERR_SYS_UNSUPPORTED_CODEC (HFI_COMMON_BASE + 0x6) +#define HFI_ERR_SYS_SESSION_IN_USE (HFI_COMMON_BASE + 0x7) +#define HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE (HFI_COMMON_BASE + 0x8) +#define HFI_ERR_SYS_UNSUPPORTED_DOMAIN (HFI_COMMON_BASE + 0x9) + +#define HFI_ERR_SESSION_FATAL (HFI_COMMON_BASE + 0x1001) +#define HFI_ERR_SESSION_INVALID_PARAMETER (HFI_COMMON_BASE + 0x1002) +#define HFI_ERR_SESSION_BAD_POINTER (HFI_COMMON_BASE + 0x1003) +#define HFI_ERR_SESSION_INVALID_SESSION_ID (HFI_COMMON_BASE + 0x1004) +#define HFI_ERR_SESSION_INVALID_STREAM_ID (HFI_COMMON_BASE + 0x1005) +#define HFI_ERR_SESSION_INCORRECT_STATE_OPERATION \ + (HFI_COMMON_BASE + 0x1006) +#define HFI_ERR_SESSION_UNSUPPORTED_PROPERTY (HFI_COMMON_BASE + 0x1007) + +#define HFI_ERR_SESSION_UNSUPPORTED_SETTING (HFI_COMMON_BASE + 0x1008) + +#define HFI_ERR_SESSION_INSUFFICIENT_RESOURCES (HFI_COMMON_BASE + 0x1009) + +#define HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED \ + (HFI_COMMON_BASE + 0x100a) + +#define HFI_ERR_SESSION_STREAM_CORRUPT (HFI_COMMON_BASE + 0x100b) +#define HFI_ERR_SESSION_ENC_OVERFLOW (HFI_COMMON_BASE + 0x100c) +#define HFI_ERR_SESSION_UNSUPPORTED_STREAM (HFI_COMMON_BASE + 0x100d) +#define HFI_ERR_SESSION_CMDSIZE (HFI_COMMON_BASE + 0x100e) +#define HFI_ERR_SESSION_UNSUPPORT_CMD (HFI_COMMON_BASE + 0x100f) +#define HFI_ERR_SESSION_UNSUPPORT_BUFFERTYPE (HFI_COMMON_BASE + 0x1010) +#define HFI_ERR_SESSION_BUFFERCOUNT_TOOSMALL (HFI_COMMON_BASE + 0x1011) +#define HFI_ERR_SESSION_INVALID_SCALE_FACTOR (HFI_COMMON_BASE + 0x1012) +#define HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED (HFI_COMMON_BASE + 0x1013) + +#define HFI_EVENT_SYS_ERROR (HFI_COMMON_BASE + 0x1) +#define HFI_EVENT_SESSION_ERROR (HFI_COMMON_BASE + 0x2) + +#define HFI_VIDEO_CODEC_H264 0x00000002 +#define HFI_VIDEO_CODEC_H263 0x00000004 +#define HFI_VIDEO_CODEC_MPEG1 0x00000008 +#define HFI_VIDEO_CODEC_MPEG2 0x00000010 +#define HFI_VIDEO_CODEC_MPEG4 0x00000020 +#define HFI_VIDEO_CODEC_DIVX_311 0x00000040 +#define HFI_VIDEO_CODEC_DIVX 0x00000080 +#define HFI_VIDEO_CODEC_VC1 0x00000100 +#define HFI_VIDEO_CODEC_SPARK 0x00000200 +#define HFI_VIDEO_CODEC_VP8 0x00001000 +#define HFI_VIDEO_CODEC_HEVC 0x00002000 +#define HFI_VIDEO_CODEC_HEVC_HYBRID 0x00004000 + +#define HFI_H264_PROFILE_BASELINE 0x00000001 +#define HFI_H264_PROFILE_MAIN 0x00000002 +#define HFI_H264_PROFILE_HIGH 0x00000004 +#define HFI_H264_PROFILE_STEREO_HIGH 0x00000008 +#define HFI_H264_PROFILE_MULTIVIEW_HIGH 0x00000010 +#define HFI_H264_PROFILE_CONSTRAINED_BASE 0x00000020 +#define HFI_H264_PROFILE_CONSTRAINED_HIGH 0x00000040 + +#define HFI_H264_LEVEL_1 0x00000001 +#define HFI_H264_LEVEL_1b 0x00000002 +#define HFI_H264_LEVEL_11 0x00000004 +#define HFI_H264_LEVEL_12 0x00000008 +#define HFI_H264_LEVEL_13 0x00000010 +#define HFI_H264_LEVEL_2 0x00000020 +#define HFI_H264_LEVEL_21 0x00000040 +#define HFI_H264_LEVEL_22 0x00000080 +#define HFI_H264_LEVEL_3 0x00000100 +#define HFI_H264_LEVEL_31 0x00000200 +#define HFI_H264_LEVEL_32 0x00000400 +#define HFI_H264_LEVEL_4 0x00000800 +#define HFI_H264_LEVEL_41 0x00001000 +#define HFI_H264_LEVEL_42 0x00002000 +#define HFI_H264_LEVEL_5 0x00004000 +#define HFI_H264_LEVEL_51 0x00008000 +#define HFI_H264_LEVEL_52 0x00010000 + +#define HFI_H263_PROFILE_BASELINE 0x00000001 + +#define HFI_H263_LEVEL_10 0x00000001 +#define HFI_H263_LEVEL_20 0x00000002 +#define HFI_H263_LEVEL_30 0x00000004 +#define HFI_H263_LEVEL_40 0x00000008 +#define HFI_H263_LEVEL_45 0x00000010 +#define HFI_H263_LEVEL_50 0x00000020 +#define HFI_H263_LEVEL_60 0x00000040 +#define HFI_H263_LEVEL_70 0x00000080 + +#define HFI_MPEG2_PROFILE_SIMPLE 0x00000001 +#define HFI_MPEG2_PROFILE_MAIN 0x00000002 +#define HFI_MPEG2_PROFILE_422 0x00000004 +#define HFI_MPEG2_PROFILE_SNR 0x00000008 +#define HFI_MPEG2_PROFILE_SPATIAL 0x00000010 +#define HFI_MPEG2_PROFILE_HIGH 0x00000020 + +#define HFI_MPEG2_LEVEL_LL 0x00000001 +#define HFI_MPEG2_LEVEL_ML 0x00000002 +#define HFI_MPEG2_LEVEL_H14 0x00000004 +#define HFI_MPEG2_LEVEL_HL 0x00000008 + +#define HFI_MPEG4_PROFILE_SIMPLE 0x00000001 +#define HFI_MPEG4_PROFILE_ADVANCEDSIMPLE 0x00000002 + +#define HFI_MPEG4_LEVEL_0 0x00000001 +#define HFI_MPEG4_LEVEL_0b 0x00000002 +#define HFI_MPEG4_LEVEL_1 0x00000004 +#define HFI_MPEG4_LEVEL_2 0x00000008 +#define HFI_MPEG4_LEVEL_3 0x00000010 +#define HFI_MPEG4_LEVEL_4 0x00000020 +#define HFI_MPEG4_LEVEL_4a 0x00000040 +#define HFI_MPEG4_LEVEL_5 0x00000080 +#define HFI_MPEG4_LEVEL_6 0x00000100 +#define HFI_MPEG4_LEVEL_7 0x00000200 +#define HFI_MPEG4_LEVEL_8 0x00000400 +#define HFI_MPEG4_LEVEL_9 0x00000800 +#define HFI_MPEG4_LEVEL_3b 0x00001000 + +#define HFI_VC1_PROFILE_SIMPLE 0x00000001 +#define HFI_VC1_PROFILE_MAIN 0x00000002 +#define HFI_VC1_PROFILE_ADVANCED 0x00000004 + +#define HFI_VC1_LEVEL_LOW 0x00000001 +#define HFI_VC1_LEVEL_MEDIUM 0x00000002 +#define HFI_VC1_LEVEL_HIGH 0x00000004 +#define HFI_VC1_LEVEL_0 0x00000008 +#define HFI_VC1_LEVEL_1 0x00000010 +#define HFI_VC1_LEVEL_2 0x00000020 +#define HFI_VC1_LEVEL_3 0x00000040 +#define HFI_VC1_LEVEL_4 0x00000080 + +#define HFI_VPX_PROFILE_SIMPLE 0x00000001 +#define HFI_VPX_PROFILE_ADVANCED 0x00000002 +#define HFI_VPX_PROFILE_VERSION_0 0x00000004 +#define HFI_VPX_PROFILE_VERSION_1 0x00000008 +#define HFI_VPX_PROFILE_VERSION_2 0x00000010 +#define HFI_VPX_PROFILE_VERSION_3 0x00000020 + +#define HFI_DIVX_FORMAT_4 (HFI_COMMON_BASE + 0x1) +#define HFI_DIVX_FORMAT_5 (HFI_COMMON_BASE + 0x2) +#define HFI_DIVX_FORMAT_6 (HFI_COMMON_BASE + 0x3) + +#define HFI_DIVX_PROFILE_QMOBILE 0x00000001 +#define HFI_DIVX_PROFILE_MOBILE 0x00000002 +#define HFI_DIVX_PROFILE_MT 0x00000004 +#define HFI_DIVX_PROFILE_HT 0x00000008 +#define HFI_DIVX_PROFILE_HD 0x00000010 + +#define HFI_HEVC_PROFILE_MAIN 0x00000001 +#define HFI_HEVC_PROFILE_MAIN10 0x00000002 +#define HFI_HEVC_PROFILE_MAIN_STILL_PIC 0x00000004 + +#define HFI_HEVC_LEVEL_1 0x00000001 +#define HFI_HEVC_LEVEL_2 0x00000002 +#define HFI_HEVC_LEVEL_21 0x00000004 +#define HFI_HEVC_LEVEL_3 0x00000008 +#define HFI_HEVC_LEVEL_31 0x00000010 +#define HFI_HEVC_LEVEL_4 0x00000020 +#define HFI_HEVC_LEVEL_41 0x00000040 +#define HFI_HEVC_LEVEL_5 0x00000080 +#define HFI_HEVC_LEVEL_51 0x00000100 +#define HFI_HEVC_LEVEL_52 0x00000200 +#define HFI_HEVC_LEVEL_6 0x00000400 +#define HFI_HEVC_LEVEL_61 0x00000800 +#define HFI_HEVC_LEVEL_62 0x00001000 + +#define HFI_HEVC_TIER_MAIN 0x1 +#define HFI_HEVC_TIER_HIGH0 0x2 + +#define HFI_BUFFER_INPUT (HFI_COMMON_BASE + 0x1) +#define HFI_BUFFER_OUTPUT (HFI_COMMON_BASE + 0x2) +#define HFI_BUFFER_OUTPUT2 (HFI_COMMON_BASE + 0x3) +#define HFI_BUFFER_INTERNAL_PERSIST (HFI_COMMON_BASE + 0x4) +#define HFI_BUFFER_INTERNAL_PERSIST_1 (HFI_COMMON_BASE + 0x5) + +#define HFI_VENC_PERFMODE_MAX_QUALITY 0x1 +#define HFI_VENC_PERFMODE_POWER_SAVE 0x2 + +struct hfi_buffer_info { + u32 buffer_addr; + u32 extra_data_addr; +}; + +#define HFI_PROPERTY_SYS_COMMON_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x0000) +#define HFI_PROPERTY_SYS_DEBUG_CONFIG \ + (HFI_PROPERTY_SYS_COMMON_START + 0x001) +#define HFI_PROPERTY_SYS_RESOURCE_OCMEM_REQUIREMENT_INFO \ + (HFI_PROPERTY_SYS_COMMON_START + 0x002) +#define HFI_PROPERTY_SYS_CONFIG_VCODEC_CLKFREQ \ + (HFI_PROPERTY_SYS_COMMON_START + 0x003) +#define HFI_PROPERTY_SYS_IDLE_INDICATOR \ + (HFI_PROPERTY_SYS_COMMON_START + 0x004) +#define HFI_PROPERTY_SYS_CODEC_POWER_PLANE_CTRL \ + (HFI_PROPERTY_SYS_COMMON_START + 0x005) +#define HFI_PROPERTY_SYS_IMAGE_VERSION \ + (HFI_PROPERTY_SYS_COMMON_START + 0x006) +#define HFI_PROPERTY_SYS_CONFIG_COVERAGE \ + (HFI_PROPERTY_SYS_COMMON_START + 0x007) + +#define HFI_PROPERTY_PARAM_COMMON_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x1000) +#define HFI_PROPERTY_PARAM_FRAME_SIZE \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x001) +#define HFI_PROPERTY_PARAM_UNCOMPRESSED_PLANE_ACTUAL_INFO \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x002) +#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SELECT \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x003) +#define HFI_PROPERTY_PARAM_UNCOMPRESSED_FORMAT_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x004) +#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x005) +#define HFI_PROPERTY_PARAM_PROFILE_LEVEL_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x006) +#define HFI_PROPERTY_PARAM_CAPABILITY_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x007) +#define HFI_PROPERTY_PARAM_PROPERTIES_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x008) +#define HFI_PROPERTY_PARAM_CODEC_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x009) +#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x00a) +#define HFI_PROPERTY_PARAM_NAL_STREAM_FORMAT_SELECT \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x00b) +#define HFI_PROPERTY_PARAM_MULTI_VIEW_FORMAT \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x00c) +#define HFI_PROPERTY_PARAM_MAX_SEQUENCE_HEADER_SIZE \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x00d) +#define HFI_PROPERTY_PARAM_CODEC_MASK_SUPPORTED \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x00e) +#define HFI_PROPERTY_PARAM_MVC_BUFFER_LAYOUT \ + (HFI_PROPERTY_PARAM_COMMON_START + 0x00f) + +#define HFI_PROPERTY_CONFIG_COMMON_START \ + (HFI_DOMAIN_BASE_COMMON + HFI_ARCH_COMMON_OFFSET + 0x2000) +#define HFI_PROPERTY_CONFIG_FRAME_RATE \ + (HFI_PROPERTY_CONFIG_COMMON_START + 0x001) + +#define HFI_PROPERTY_PARAM_VDEC_COMMON_START \ + (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x3000) +#define HFI_PROPERTY_PARAM_VDEC_MULTI_STREAM \ + (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x001) +#define HFI_PROPERTY_PARAM_VDEC_CONCEAL_COLOR \ + (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x002) +#define HFI_PROPERTY_PARAM_VDEC_NONCP_OUTPUT2 \ + (HFI_PROPERTY_PARAM_VDEC_COMMON_START + 0x003) + +#define HFI_PROPERTY_CONFIG_VDEC_COMMON_START \ + (HFI_DOMAIN_BASE_VDEC + HFI_ARCH_COMMON_OFFSET + 0x4000) + +#define HFI_PROPERTY_PARAM_VENC_COMMON_START \ + (HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x5000) +#define HFI_PROPERTY_PARAM_VENC_SLICE_DELIVERY_MODE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x001) +#define HFI_PROPERTY_PARAM_VENC_H264_ENTROPY_CONTROL \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x002) +#define HFI_PROPERTY_PARAM_VENC_H264_DEBLOCK_CONTROL \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x003) +#define HFI_PROPERTY_PARAM_VENC_RATE_CONTROL \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x004) +#define HFI_PROPERTY_PARAM_VENC_H264_PICORDER_CNT_TYPE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x005) +#define HFI_PROPERTY_PARAM_VENC_SESSION_QP \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x006) +#define HFI_PROPERTY_PARAM_VENC_MPEG4_AC_PREDICTION \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x007) +#define HFI_PROPERTY_PARAM_VENC_SESSION_QP_RANGE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x008) +#define HFI_PROPERTY_PARAM_VENC_MPEG4_TIME_RESOLUTION \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x009) +#define HFI_PROPERTY_PARAM_VENC_MPEG4_SHORT_HEADER \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00a) +#define HFI_PROPERTY_PARAM_VENC_MPEG4_HEADER_EXTENSION \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00b) +#define HFI_PROPERTY_PARAM_VENC_OPEN_GOP \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00c) +#define HFI_PROPERTY_PARAM_VENC_INTRA_REFRESH \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00d) +#define HFI_PROPERTY_PARAM_VENC_MULTI_SLICE_CONTROL \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00e) +#define HFI_PROPERTY_PARAM_VENC_VBV_HRD_BUF_SIZE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x00f) +#define HFI_PROPERTY_PARAM_VENC_QUALITY_VS_SPEED \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x010) +#define HFI_PROPERTY_PARAM_VENC_ADVANCED \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x012) +#define HFI_PROPERTY_PARAM_VENC_H264_SPS_ID \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x014) +#define HFI_PROPERTY_PARAM_VENC_H264_PPS_ID \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x015) +#define HFI_PROPERTY_PARAM_VENC_H264_GENERATE_AUDNAL \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x016) +#define HFI_PROPERTY_PARAM_VENC_ASPECT_RATIO \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x017) +#define HFI_PROPERTY_PARAM_VENC_NUMREF \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x018) +#define HFI_PROPERTY_PARAM_VENC_MULTIREF_P \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x019) +#define HFI_PROPERTY_PARAM_VENC_H264_NAL_SVC_EXT \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01b) +#define HFI_PROPERTY_PARAM_VENC_LTRMODE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01c) +#define HFI_PROPERTY_PARAM_VENC_VIDEO_FULL_RANGE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01d) +#define HFI_PROPERTY_PARAM_VENC_H264_VUI_TIMING_INFO \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01e) +#define HFI_PROPERTY_PARAM_VENC_VC1_PERF_CFG \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x01f) +#define HFI_PROPERTY_PARAM_VENC_MAX_NUM_B_FRAMES \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x020) +#define HFI_PROPERTY_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x021) +#define HFI_PROPERTY_PARAM_VENC_PRESERVE_TEXT_QUALITY \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x023) +#define HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x026) +#define HFI_PROPERTY_PARAM_VENC_DISABLE_RC_TIMESTAMP \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x027) +#define HFI_PROPERTY_PARAM_VENC_INITIAL_QP \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x028) +#define HFI_PROPERTY_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x029) +#define HFI_PROPERTY_PARAM_VENC_HIER_B_MAX_NUM_ENH_LAYER \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02c) +#define HFI_PROPERTY_PARAM_VENC_HIER_P_HYBRID_MODE \ + (HFI_PROPERTY_PARAM_VENC_COMMON_START + 0x02f) + +#define HFI_PROPERTY_CONFIG_VENC_COMMON_START \ + (HFI_DOMAIN_BASE_VENC + HFI_ARCH_COMMON_OFFSET + 0x6000) +#define HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x001) +#define HFI_PROPERTY_CONFIG_VENC_IDR_PERIOD \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x002) +#define HFI_PROPERTY_CONFIG_VENC_INTRA_PERIOD \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x003) +#define HFI_PROPERTY_CONFIG_VENC_REQUEST_SYNC_FRAME \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x004) +#define HFI_PROPERTY_CONFIG_VENC_SLICE_SIZE \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x005) +#define HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x007) + +#define HFI_PROPERTY_PARAM_VPE_COMMON_START \ + (HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x7000) +#define HFI_PROPERTY_CONFIG_VENC_SYNC_FRAME_SEQUENCE_HEADER \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x008) +#define HFI_PROPERTY_CONFIG_VENC_MARKLTRFRAME \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x009) +#define HFI_PROPERTY_CONFIG_VENC_USELTRFRAME \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00a) +#define HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00b) +#define HFI_PROPERTY_CONFIG_VENC_LTRPERIOD \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00c) +#define HFI_PROPERTY_CONFIG_VENC_PERF_MODE \ + (HFI_PROPERTY_CONFIG_VENC_COMMON_START + 0x00e) + +#define HFI_PROPERTY_CONFIG_VPE_COMMON_START \ + (HFI_DOMAIN_BASE_VPE + HFI_ARCH_COMMON_OFFSET + 0x8000) +#define HFI_PROPERTY_CONFIG_VPE_DEINTERLACE \ + (HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x001) +#define HFI_PROPERTY_CONFIG_VPE_OPERATIONS \ + (HFI_PROPERTY_CONFIG_VPE_COMMON_START + 0x002) + +struct hfi_bitrate { + u32 bit_rate; + u32 layer_id; +}; + +#define HFI_CAPABILITY_FRAME_WIDTH (HFI_COMMON_BASE + 0x1) +#define HFI_CAPABILITY_FRAME_HEIGHT (HFI_COMMON_BASE + 0x2) +#define HFI_CAPABILITY_MBS_PER_FRAME (HFI_COMMON_BASE + 0x3) +#define HFI_CAPABILITY_MBS_PER_SECOND (HFI_COMMON_BASE + 0x4) +#define HFI_CAPABILITY_FRAMERATE (HFI_COMMON_BASE + 0x5) +#define HFI_CAPABILITY_SCALE_X (HFI_COMMON_BASE + 0x6) +#define HFI_CAPABILITY_SCALE_Y (HFI_COMMON_BASE + 0x7) +#define HFI_CAPABILITY_BITRATE (HFI_COMMON_BASE + 0x8) +#define HFI_CAPABILITY_BFRAME (HFI_COMMON_BASE + 0x9) +#define HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS (HFI_COMMON_BASE + 0x10) +#define HFI_CAPABILITY_ENC_LTR_COUNT (HFI_COMMON_BASE + 0x11) +#define HFI_CAPABILITY_CP_OUTPUT2_THRESH (HFI_COMMON_BASE + 0x12) +#define HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS (HFI_COMMON_BASE + 0x15) + +struct hfi_capability_supported { + u32 capability_type; + u32 min; + u32 max; + u32 step_size; +}; + +struct hfi_capability_supported_info { + u32 num_capabilities; + struct hfi_capability_supported rg_data[1]; +}; + +#define HFI_DEBUG_MSG_LOW 0x00000001 +#define HFI_DEBUG_MSG_MEDIUM 0x00000002 +#define HFI_DEBUG_MSG_HIGH 0x00000004 +#define HFI_DEBUG_MSG_ERROR 0x00000008 +#define HFI_DEBUG_MSG_FATAL 0x00000010 +#define HFI_DEBUG_MSG_PERF 0x00000020 + +#define HFI_DEBUG_MODE_QUEUE 0x00000001 +#define HFI_DEBUG_MODE_QDSS 0x00000002 + +struct hfi_debug_config { + u32 debug_config; + u32 debug_mode; +}; + +struct hfi_enable { + int enable; +}; + +#define HFI_H264_DB_MODE_DISABLE (HFI_COMMON_BASE + 0x1) +#define HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY (HFI_COMMON_BASE + 0x2) +#define HFI_H264_DB_MODE_ALL_BOUNDARY (HFI_COMMON_BASE + 0x3) + +struct hfi_h264_db_control { + u32 mode; + int slice_alpha_offset; + int slice_beta_offset; +}; + +#define HFI_H264_ENTROPY_CAVLC (HFI_COMMON_BASE + 0x1) +#define HFI_H264_ENTROPY_CABAC (HFI_COMMON_BASE + 0x2) + +#define HFI_H264_CABAC_MODEL_0 (HFI_COMMON_BASE + 0x1) +#define HFI_H264_CABAC_MODEL_1 (HFI_COMMON_BASE + 0x2) +#define HFI_H264_CABAC_MODEL_2 (HFI_COMMON_BASE + 0x3) + +struct hfi_h264_entropy_control { + u32 entropy_mode; + u32 cabac_model; +}; + +struct hfi_frame_rate { + u32 buffer_type; + u32 frame_rate; +}; + +#define HFI_INTRA_REFRESH_NONE (HFI_COMMON_BASE + 0x1) +#define HFI_INTRA_REFRESH_CYCLIC (HFI_COMMON_BASE + 0x2) +#define HFI_INTRA_REFRESH_ADAPTIVE (HFI_COMMON_BASE + 0x3) +#define HFI_INTRA_REFRESH_CYCLIC_ADAPTIVE (HFI_COMMON_BASE + 0x4) +#define HFI_INTRA_REFRESH_RANDOM (HFI_COMMON_BASE + 0x5) + +struct hfi_intra_refresh { + u32 mode; + u32 air_mbs; + u32 air_ref; + u32 cir_mbs; +}; + +struct hfi_idr_period { + u32 idr_period; +}; + +struct hfi_operations_type { + u32 rotation; + u32 flip; +}; + +struct hfi_max_num_b_frames { + u32 max_num_b_frames; +}; + +struct hfi_vc1e_perf_cfg_type { + u32 search_range_x_subsampled[3]; + u32 search_range_y_subsampled[3]; +}; + +struct hfi_conceal_color { + u32 conceal_color; +}; + +struct hfi_intra_period { + u32 pframes; + u32 bframes; +}; + +struct hfi_mpeg4_header_extension { + u32 header_extension; +}; + +struct hfi_mpeg4_time_resolution { + u32 time_increment_resolution; +}; + +struct hfi_multi_stream { + u32 buffer_type; + u32 enable; + u32 width; + u32 height; +}; + +struct hfi_multi_view_format { + u32 views; + u32 rg_view_order[1]; +}; + +#define HFI_MULTI_SLICE_OFF (HFI_COMMON_BASE + 0x1) +#define HFI_MULTI_SLICE_BY_MB_COUNT (HFI_COMMON_BASE + 0x2) +#define HFI_MULTI_SLICE_BY_BYTE_COUNT (HFI_COMMON_BASE + 0x3) +#define HFI_MULTI_SLICE_GOB (HFI_COMMON_BASE + 0x4) + +struct hfi_multi_slice_control { + u32 multi_slice; + u32 slice_size; +}; + +#define HFI_NAL_FORMAT_STARTCODES 0x00000001 +#define HFI_NAL_FORMAT_ONE_NAL_PER_BUFFER 0x00000002 +#define HFI_NAL_FORMAT_ONE_BYTE_LENGTH 0x00000004 +#define HFI_NAL_FORMAT_TWO_BYTE_LENGTH 0x00000008 +#define HFI_NAL_FORMAT_FOUR_BYTE_LENGTH 0x00000010 + +struct hfi_nal_stream_format_supported { + u32 nal_stream_format_supported; +}; + +struct hfi_nal_stream_format_select { + u32 nal_stream_format_select; +}; +#define HFI_PICTURE_TYPE_I 0x01 +#define HFI_PICTURE_TYPE_P 0x02 +#define HFI_PICTURE_TYPE_B 0x04 +#define HFI_PICTURE_TYPE_IDR 0x08 + +struct hfi_profile_level { + u32 profile; + u32 level; +}; + +struct hfi_profile_level_supported { + u32 profile_count; + struct hfi_profile_level rg_profile_level[1]; +}; + +struct hfi_quality_vs_speed { + u32 quality_vs_speed; +}; + +struct hfi_quantization { + u32 qp_i; + u32 qp_p; + u32 qp_b; + u32 layer_id; +}; + +struct hfi_initial_quantization { + u32 qp_i; + u32 qp_p; + u32 qp_b; + u32 init_qp_enable; +}; + +struct hfi_quantization_range { + u32 min_qp; + u32 max_qp; + u32 layer_id; +}; + +#define HFI_LTR_MODE_DISABLE 0x0 +#define HFI_LTR_MODE_MANUAL 0x1 +#define HFI_LTR_MODE_PERIODIC 0x2 + +struct hfi_ltr_mode { + u32 ltr_mode; + u32 ltr_count; + u32 trust_mode; +}; + +struct hfi_ltr_use { + u32 ref_ltr; + u32 use_constrnt; + u32 frames; +}; + +struct hfi_ltr_mark { + u32 mark_frame; +}; + +struct hfi_frame_size { + u32 buffer_type; + u32 width; + u32 height; +}; + +struct hfi_h264_vui_timing_info { + u32 enable; + u32 fixed_frame_rate; + u32 time_scale; +}; + +/* Base Offset for UBWC color formats */ +#define HFI_COLOR_FORMAT_UBWC_BASE 0x8000 +/* Base Offset for 10-bit color formats */ +#define HFI_COLOR_FORMAT_10_BIT_BASE 0x4000 + +#define HFI_COLOR_FORMAT_MONOCHROME (HFI_COMMON_BASE + 0x1) +#define HFI_COLOR_FORMAT_NV12 (HFI_COMMON_BASE + 0x2) +#define HFI_COLOR_FORMAT_NV21 (HFI_COMMON_BASE + 0x3) +#define HFI_COLOR_FORMAT_NV12_4x4TILE (HFI_COMMON_BASE + 0x4) +#define HFI_COLOR_FORMAT_NV21_4x4TILE (HFI_COMMON_BASE + 0x5) +#define HFI_COLOR_FORMAT_YUYV (HFI_COMMON_BASE + 0x6) +#define HFI_COLOR_FORMAT_YVYU (HFI_COMMON_BASE + 0x7) +#define HFI_COLOR_FORMAT_UYVY (HFI_COMMON_BASE + 0x8) +#define HFI_COLOR_FORMAT_VYUY (HFI_COMMON_BASE + 0x9) +#define HFI_COLOR_FORMAT_RGB565 (HFI_COMMON_BASE + 0xA) +#define HFI_COLOR_FORMAT_BGR565 (HFI_COMMON_BASE + 0xB) +#define HFI_COLOR_FORMAT_RGB888 (HFI_COMMON_BASE + 0xC) +#define HFI_COLOR_FORMAT_BGR888 (HFI_COMMON_BASE + 0xD) +#define HFI_COLOR_FORMAT_YUV444 (HFI_COMMON_BASE + 0xE) +#define HFI_COLOR_FORMAT_RGBA8888 (HFI_COMMON_BASE + 0x10) + +#define HFI_COLOR_FORMAT_YUV420_TP10 \ + (HFI_COLOR_FORMAT_10_BIT_BASE + HFI_COLOR_FORMAT_NV12) + +#define HFI_COLOR_FORMAT_NV12_UBWC \ + (HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_NV12) + +#define HFI_COLOR_FORMAT_YUV420_TP10_UBWC \ + (HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_YUV420_TP10) + +#define HFI_COLOR_FORMAT_RGBA8888_UBWC \ + (HFI_COLOR_FORMAT_UBWC_BASE + HFI_COLOR_FORMAT_RGBA8888) + +#define HFI_MAX_MATRIX_COEFFS 9 +#define HFI_MAX_BIAS_COEFFS 3 +#define HFI_MAX_LIMIT_COEFFS 6 + +struct hfi_uncompressed_format_select { + u32 buffer_type; + u32 format; +}; + +struct hfi_uncompressed_format_supported { + u32 buffer_type; + u32 format_entries; + u32 rg_format_info[1]; +}; + +struct hfi_uncompressed_plane_actual { + int actual_stride; + u32 actual_plane_buffer_height; +}; + +struct hfi_uncompressed_plane_actual_info { + u32 buffer_type; + u32 num_planes; + struct hfi_uncompressed_plane_actual rg_plane_format[1]; +}; + +struct hfi_uncompressed_plane_constraints { + u32 stride_multiples; + u32 max_stride; + u32 min_plane_buffer_height_multiple; + u32 buffer_alignment; +}; + +struct hfi_uncompressed_plane_info { + u32 format; + u32 num_planes; + struct hfi_uncompressed_plane_constraints rg_plane_format[1]; +}; + +struct hfi_codec_supported { + u32 decoder_codec_supported; + u32 encoder_codec_supported; +}; + +struct hfi_properties_supported { + u32 num_properties; + u32 rg_properties[1]; +}; + +struct hfi_vpe_color_space_conversion { + u32 csc_matrix[HFI_MAX_MATRIX_COEFFS]; + u32 csc_bias[HFI_MAX_BIAS_COEFFS]; + u32 csc_limit[HFI_MAX_LIMIT_COEFFS]; +}; + +#define HFI_ROTATE_NONE (HFI_COMMON_BASE + 0x1) +#define HFI_ROTATE_90 (HFI_COMMON_BASE + 0x2) +#define HFI_ROTATE_180 (HFI_COMMON_BASE + 0x3) +#define HFI_ROTATE_270 (HFI_COMMON_BASE + 0x4) + +#define HFI_FLIP_NONE (HFI_COMMON_BASE + 0x1) +#define HFI_FLIP_HORIZONTAL (HFI_COMMON_BASE + 0x2) +#define HFI_FLIP_VERTICAL (HFI_COMMON_BASE + 0x3) + +struct hfi_operations { + u32 rotate; + u32 flip; +}; + +#define HFI_RESOURCE_OCMEM 0x00000001 + +struct hfi_resource_ocmem { + u32 size; + u32 mem; +}; + +struct hfi_resource_ocmem_requirement { + u32 session_domain; + u32 width; + u32 height; + u32 size; +}; + +struct hfi_resource_ocmem_requirement_info { + u32 num_entries; + struct hfi_resource_ocmem_requirement rg_requirements[1]; +}; + +struct hfi_property_sys_image_version_info_type { + u32 string_size; + u8 str_image_version[1]; +}; + +struct hfi_venc_config_advanced { + u8 pipe2d; + u8 hw_mode; + u8 low_delay_enforce; + u8 worker_vppsg_delay; + int close_gop; + int h264_constrain_intra_pred; + int h264_transform_8x8_flag; + int mpeg4_qpel_enable; + int multi_refp_en; + int qmatrix_en; + u8 vpp_info_packet_mode; + u8 ref_tile_mode; + u8 bitstream_flush_mode; + u32 vppsg_vspap_fb_sync_delay; + u32 rc_initial_delay; + u32 peak_bitrate_constraint; + u32 ds_display_frame_width; + u32 ds_display_frame_height; + u32 perf_tune_param_ptr; + u32 input_x_offset; + u32 input_y_offset; + u32 input_roi_width; + u32 input_roi_height; + u32 vsp_fifo_dma_sel; + u32 h264_num_ref_frames; +}; + +struct hfi_vbv_hrd_bufsize { + u32 buffer_size; +}; + +struct hfi_codec_mask_supported { + u32 codecs; + u32 video_domains; +}; + +struct hfi_seq_header_info { + u32 max_hader_len; +}; +struct hfi_aspect_ratio { + u32 aspect_width; + u32 aspect_height; +}; +#define HFI_MVC_BUFFER_LAYOUT_TOP_BOTTOM 0 +#define HFI_MVC_BUFFER_LAYOUT_SIDEBYSIDE 1 +#define HFI_MVC_BUFFER_LAYOUT_SEQ 2 + +struct hfi_mvc_buffer_layout_descp_type { + u32 layout_type; + u32 bright_view_first; + u32 ngap; +}; + +#define HFI_CMD_SYS_COMMON_START (HFI_DOMAIN_BASE_COMMON + \ + HFI_ARCH_COMMON_OFFSET + \ + HFI_CMD_START_OFFSET + 0x0000) +#define HFI_CMD_SYS_INIT (HFI_CMD_SYS_COMMON_START + 0x001) +#define HFI_CMD_SYS_PC_PREP (HFI_CMD_SYS_COMMON_START + 0x002) +#define HFI_CMD_SYS_SET_RESOURCE (HFI_CMD_SYS_COMMON_START + 0x003) +#define HFI_CMD_SYS_RELEASE_RESOURCE (HFI_CMD_SYS_COMMON_START + 0x004) +#define HFI_CMD_SYS_SET_PROPERTY (HFI_CMD_SYS_COMMON_START + 0x005) +#define HFI_CMD_SYS_GET_PROPERTY (HFI_CMD_SYS_COMMON_START + 0x006) +#define HFI_CMD_SYS_SESSION_INIT (HFI_CMD_SYS_COMMON_START + 0x007) +#define HFI_CMD_SYS_SESSION_END (HFI_CMD_SYS_COMMON_START + 0x008) +#define HFI_CMD_SYS_SET_BUFFERS (HFI_CMD_SYS_COMMON_START + 0x009) +#define HFI_CMD_SYS_TEST_START (HFI_CMD_SYS_COMMON_START + 0x100) + +#define HFI_CMD_SESSION_COMMON_START (HFI_DOMAIN_BASE_COMMON + \ + HFI_ARCH_COMMON_OFFSET + \ + HFI_CMD_START_OFFSET + 0x1000) +#define HFI_CMD_SESSION_SET_PROPERTY (HFI_CMD_SESSION_COMMON_START + 0x001) +#define HFI_CMD_SESSION_SET_BUFFERS (HFI_CMD_SESSION_COMMON_START + 0x002) +#define HFI_CMD_SESSION_GET_SEQUENCE_HEADER \ + (HFI_CMD_SESSION_COMMON_START + 0x003) + +#define HFI_MSG_SYS_COMMON_START (HFI_DOMAIN_BASE_COMMON + \ + HFI_ARCH_COMMON_OFFSET + \ + HFI_MSG_START_OFFSET + 0x0000) +#define HFI_MSG_SYS_INIT_DONE (HFI_MSG_SYS_COMMON_START + 0x1) +#define HFI_MSG_SYS_PC_PREP_DONE (HFI_MSG_SYS_COMMON_START + 0x2) +#define HFI_MSG_SYS_RELEASE_RESOURCE (HFI_MSG_SYS_COMMON_START + 0x3) +#define HFI_MSG_SYS_DEBUG (HFI_MSG_SYS_COMMON_START + 0x4) +#define HFI_MSG_SYS_SESSION_INIT_DONE (HFI_MSG_SYS_COMMON_START + 0x6) +#define HFI_MSG_SYS_SESSION_END_DONE (HFI_MSG_SYS_COMMON_START + 0x7) +#define HFI_MSG_SYS_IDLE (HFI_MSG_SYS_COMMON_START + 0x8) +#define HFI_MSG_SYS_COV (HFI_MSG_SYS_COMMON_START + 0x9) +#define HFI_MSG_SYS_PROPERTY_INFO (HFI_MSG_SYS_COMMON_START + 0xA) + +#define HFI_MSG_SESSION_COMMON_START (HFI_DOMAIN_BASE_COMMON + \ + HFI_ARCH_COMMON_OFFSET + \ + HFI_MSG_START_OFFSET + 0x1000) +#define HFI_MSG_EVENT_NOTIFY (HFI_MSG_SESSION_COMMON_START + 0x1) +#define HFI_MSG_SESSION_GET_SEQUENCE_HEADER_DONE \ + (HFI_MSG_SESSION_COMMON_START + 0x2) + +#define HFI_CMD_SYS_TEST_SSR (HFI_CMD_SYS_TEST_START + 0x1) +#define HFI_TEST_SSR_SW_ERR_FATAL 0x1 +#define HFI_TEST_SSR_SW_DIV_BY_ZERO 0x2 +#define HFI_TEST_SSR_HW_WDOG_IRQ 0x3 + +struct vidc_hal_cmd_pkt_hdr { + u32 size; + u32 packet_type; +}; + +struct vidc_hal_msg_pkt_hdr { + u32 size; + u32 packet; +}; + +struct vidc_hal_session_cmd_pkt { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_sys_init_pkt { + u32 size; + u32 packet_type; + u32 arch_type; +}; + +struct hfi_sys_pc_prep_pkt { + u32 size; + u32 packet_type; +}; + +struct hfi_sys_set_resource_pkt { + u32 size; + u32 packet_type; + u32 resource_handle; + u32 resource_type; + u32 rg_resource_data[1]; +}; + +struct hfi_sys_release_resource_pkt { + u32 size; + u32 packet_type; + u32 resource_type; + u32 resource_handle; +}; + +struct hfi_sys_set_property_pkt { + u32 size; + u32 packet_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_sys_get_property_pkt { + u32 size; + u32 packet_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_session_init_pkt { + u32 size; + u32 packet_type; + u32 session_id; + u32 session_domain; + u32 session_codec; +}; + +struct hfi_session_end_pkt { + u32 size; + u32 packet_type; + u32 session_id; +}; + +struct hfi_sys_set_buffers_pkt { + u32 size; + u32 packet_type; + u32 buffer_type; + u32 buffer_size; + u32 num_buffers; + u32 rg_buffer_addr[1]; +}; + +struct hfi_session_set_property_pkt { + u32 size; + u32 packet_type; + u32 session_id; + u32 num_properties; + u32 rg_property_data[0]; +}; + +struct hfi_session_set_buffers_pkt { + u32 size; + u32 packet_type; + u32 session_id; + u32 buffer_type; + u32 buffer_size; + u32 extra_data_size; + u32 min_buffer_size; + u32 num_buffers; + u32 rg_buffer_info[1]; +}; + +struct hfi_session_get_sequence_header_pkt { + u32 size; + u32 packet_type; + u32 session_id; + u32 buffer_len; + u32 packet_buffer; +}; + +struct hfi_msg_event_notify_pkt { + u32 size; + u32 packet_type; + u32 session_id; + u32 event_id; + u32 event_data1; + u32 event_data2; + u32 rg_ext_event_data[1]; +}; + +struct hfi_msg_event_release_buffer_ref_pkt { + u32 packet_buffer; + u32 extra_data_buffer; + u32 output_tag; +}; + +struct hfi_msg_sys_init_done_pkt { + u32 size; + u32 packet_type; + u32 error_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_msg_sys_pc_prep_done_pkt { + u32 size; + u32 packet_type; + u32 error_type; +}; + +struct hfi_msg_sys_release_resource_done_pkt { + u32 size; + u32 packet_type; + u32 resource_handle; + u32 error_type; +}; + +struct hfi_msg_session_init_done_pkt { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; + u32 num_properties; + u32 rg_property_data[1]; +}; + +struct hfi_msg_session_end_done_pkt { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; +}; + +struct hfi_msg_session_get_sequence_hdr_done_pkt { + u32 size; + u32 packet_type; + u32 session_id; + u32 error_type; + u32 header_len; + u32 sequence_header; +}; + +struct hfi_msg_sys_debug_pkt { + u32 size; + u32 packet_type; + u32 msg_type; + u32 msg_size; + u32 time_stamp_hi; + u32 time_stamp_lo; + u8 rg_msg_data[1]; +}; + +struct hfi_msg_sys_coverage_pkt { + u32 size; + u32 packet_type; + u32 msg_size; + u32 time_stamp_hi; + u32 time_stamp_lo; + u8 rg_msg_data[1]; +}; + +struct hfi_sfr { + u32 buf_size; + u8 rg_data[1]; +}; + +struct hfi_sys_test_ssr_pkt { + u32 size; + u32 packet_type; + u32 trigger_type; +}; +#endif diff --git a/drivers/media/platform/msm/vidc/msm_hfi_interface.h b/drivers/media/platform/msm/vidc/msm_hfi_interface.h new file mode 100644 index 000000000000..6b3106e1b175 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_hfi_interface.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _MSM_HFI_INTERFACE_H_ +#define _MSM_HFI_INTERFACE_H_ + +struct vidc_inst; +struct vidc_buffer_addr_info; + +int hfi_core_init(struct vidc_core *core); +int hfi_core_deinit(struct vidc_core *core); + +int hfi_session_init(struct vidc_inst *inst, u32 pixfmt); +int hfi_session_deinit(struct vidc_inst *inst); +int hfi_session_start(struct vidc_inst *inst); +int hfi_session_stop(struct vidc_inst *inst); +int hfi_session_abort(struct vidc_inst *inst); +int hfi_session_load_res(struct vidc_inst *inst); +int hfi_session_release_res(struct vidc_inst *inst); +int hfi_session_flush(struct vidc_inst *inst); +int hfi_session_release_buffers(struct vidc_inst *inst, + struct vidc_buffer_addr_info *bai); +int hfi_session_set_property(struct vidc_inst *inst, enum hal_property ptype, + void *pdata); +int hfi_session_get_property(struct vidc_inst *inst, enum hal_property ptype, + union hal_get_property *hprop); +void hfi_session_clean(struct vidc_inst *inst); + +#endif /* _MSM_HFI_INTERFACE_H_ */ \ No newline at end of file diff --git a/drivers/media/platform/msm/vidc/msm_internal-buffers.c b/drivers/media/platform/msm/vidc/msm_internal-buffers.c new file mode 100644 index 000000000000..4c8c80639c98 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_internal-buffers.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include "msm_smem.h" +#include "msm_internal-buffers.h" +#include "msm_vidc_debug.h" +#include "msm_hfi_interface.h" + +static enum hal_buffer +scratch_buf_sufficient(struct vidc_inst *inst, enum hal_buffer buffer_type) +{ + struct hal_buffer_requirements *bufreq; + struct vidc_internal_buf *buf; + int count = 0; + + bufreq = get_buff_req_buffer(inst, buffer_type); + if (!bufreq) + goto not_sufficient; + + /* Check if current scratch buffers are sufficient */ + mutex_lock(&inst->scratchbufs.lock); + list_for_each_entry(buf, &inst->scratchbufs.list, list) { + if (!buf->smem) { + dprintk(VIDC_ERR, "%s: invalid buf handle\n", __func__); + mutex_unlock(&inst->scratchbufs.lock); + goto not_sufficient; + } + + if (buf->type == buffer_type && + buf->smem->size >= bufreq->size) + count++; + } + mutex_unlock(&inst->scratchbufs.lock); + + if (count != bufreq->count_actual) + goto not_sufficient; + + dprintk(VIDC_DBG, + "Existing scratch buffer is sufficient for buffer type %#x\n", + buffer_type); + + return buffer_type; + +not_sufficient: + return HAL_BUFFER_NONE; +} + +static int set_internal_buf_on_fw(struct vidc_inst *inst, + enum hal_buffer buffer_type, + struct smem *mem, bool reuse) +{ + struct hfi_device *hdev = inst->core->hfidev; + struct vidc_buffer_addr_info bai = {0}; + int ret; + + ret = smem_cache_operations(inst->mem_client, mem, SMEM_CACHE_CLEAN); + if (ret) + dprintk(VIDC_WARN, + "Failed to clean cache. May cause undefined behavior\n"); + + bai.buffer_size = mem->size; + bai.buffer_type = buffer_type; + bai.num_buffers = 1; + bai.device_addr = mem->da; + + ret = call_hfi_op(hdev, session_set_buffers, inst->session, &bai); + if (ret) { + dprintk(VIDC_ERR, "session_set_buffers failed\n"); + return ret; + } + + return 0; +} + +static int alloc_and_set(struct vidc_inst *inst, + struct hal_buffer_requirements *bufreq, + struct vidc_list *buf_list) +{ + struct smem *smem; + struct vidc_internal_buf *buf; + u32 smem_flags = 0; + unsigned int i; + int ret = 0; + + if (!bufreq->size) + return 0; + + if (inst->flags & VIDC_SECURE) + smem_flags |= SMEM_SECURE; + + for (i = 0; i < bufreq->count_actual; i++) { + + smem = smem_alloc(inst->mem_client, bufreq->size, 1, smem_flags, + bufreq->type, 0); + if (IS_ERR(smem)) { + ret = PTR_ERR(smem); + goto err_no_mem; + } + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto fail_kzalloc; + } + + buf->smem = smem; + buf->type = bufreq->type; + + ret = set_internal_buf_on_fw(inst, bufreq->type, smem, false); + if (ret) + goto fail_set_buffers; + + mutex_lock(&buf_list->lock); + list_add_tail(&buf->list, &buf_list->list); + mutex_unlock(&buf_list->lock); + } + + return ret; + +fail_set_buffers: + kfree(buf); +fail_kzalloc: + smem_free(inst->mem_client, smem); +err_no_mem: + return ret; +} + +static bool +reuse_scratch_buffer(struct vidc_inst *inst, enum hal_buffer buffer_type) +{ + struct vidc_internal_buf *buf; + bool reused = false; + int ret = 0; + + mutex_lock(&inst->scratchbufs.lock); + list_for_each_entry(buf, &inst->scratchbufs.list, list) { + if (!buf->smem) { + reused = false; + break; + } + + if (buf->type != buffer_type) + continue; + + ret = set_internal_buf_on_fw(inst, buffer_type, buf->smem, + true); + if (ret) { + dprintk(VIDC_ERR, + "%s: session_set_buffers failed\n", __func__); + reused = false; + break; + } + + reused = true; + } + mutex_unlock(&inst->scratchbufs.lock); + + return reused; +} + +static int set_scratch_buffer(struct vidc_inst *inst, enum hal_buffer type) +{ + struct hal_buffer_requirements *bufreq; + + bufreq = get_buff_req_buffer(inst, type); + if (!bufreq) + return 0; + + dprintk(VIDC_DBG, "%s: num:%d, size:%d\n", __func__, + bufreq->count_actual, bufreq->size); + + /* + * Try reusing existing scratch buffers first. + * If it's not possible to reuse, allocate new buffers. + */ + if (reuse_scratch_buffer(inst, type)) + return 0; + + return alloc_and_set(inst, bufreq, &inst->scratchbufs); +} + +static int set_persist_buffer(struct vidc_inst *inst, enum hal_buffer type) +{ + struct hal_buffer_requirements *bufreq; + + bufreq = get_buff_req_buffer(inst, type); + if (!bufreq) + return 0; + + dprintk(VIDC_DBG, "persist: num = %d, size = %d\n", + bufreq->count_actual, bufreq->size); + + mutex_lock(&inst->persistbufs.lock); + if (!list_empty(&inst->persistbufs.list)) { + mutex_unlock(&inst->persistbufs.lock); + return 0; + } + mutex_unlock(&inst->persistbufs.lock); + + return alloc_and_set(inst, bufreq, &inst->persistbufs); +} + +int release_scratch_buffers(struct vidc_inst *inst, bool reuse) +{ + struct smem *smem; + struct vidc_internal_buf *buf, *dummy; + struct vidc_buffer_addr_info bai = {0}; + enum hal_buffer sufficiency = HAL_BUFFER_NONE; + int ret = 0; + + if (reuse) { + sufficiency |= scratch_buf_sufficient(inst, + HAL_BUFFER_INTERNAL_SCRATCH); + + sufficiency |= scratch_buf_sufficient(inst, + HAL_BUFFER_INTERNAL_SCRATCH_1); + + sufficiency |= scratch_buf_sufficient(inst, + HAL_BUFFER_INTERNAL_SCRATCH_2); + } + + mutex_lock(&inst->scratchbufs.lock); + list_for_each_entry_safe(buf, dummy, &inst->scratchbufs.list, list) { + if (!buf->smem) { + ret = -EINVAL; + goto exit; + } + + smem = buf->smem; + bai.buffer_size = smem->size; + bai.buffer_type = buf->type; + bai.num_buffers = 1; + bai.device_addr = smem->da; + bai.response_required = true; + + mutex_unlock(&inst->scratchbufs.lock); + ret = hfi_session_release_buffers(inst, &bai); + mutex_lock(&inst->scratchbufs.lock); + + /* If scratch buffers can be reused, do not free the buffers */ + if (sufficiency & buf->type) + continue; + + list_del(&buf->list); + mutex_unlock(&inst->scratchbufs.lock); + smem_free(inst->mem_client, buf->smem); + mutex_lock(&inst->scratchbufs.lock); + kfree(buf); + } + +exit: + mutex_unlock(&inst->scratchbufs.lock); + return ret; +} + +int release_persist_buffers(struct vidc_inst *inst) +{ + struct smem *smem; + struct list_head *ptr, *next; + struct vidc_internal_buf *buf; + struct vidc_buffer_addr_info bai = {0}; + int ret = 0; + + mutex_lock(&inst->persistbufs.lock); + list_for_each_safe(ptr, next, &inst->persistbufs.list) { + buf = list_entry(ptr, struct vidc_internal_buf, list); + + smem = buf->smem; + bai.buffer_size = smem->size; + bai.buffer_type = buf->type; + bai.num_buffers = 1; + bai.device_addr = smem->da; + bai.response_required = true; + + mutex_unlock(&inst->persistbufs.lock); + ret = hfi_session_release_buffers(inst, &bai); + mutex_lock(&inst->persistbufs.lock); + + list_del(&buf->list); + mutex_unlock(&inst->persistbufs.lock); + smem_free(inst->mem_client, buf->smem); + mutex_lock(&inst->persistbufs.lock); + kfree(buf); + } + mutex_unlock(&inst->persistbufs.lock); + + return ret; +} + +int set_scratch_buffers(struct vidc_inst *inst) +{ + int ret; + + ret = release_scratch_buffers(inst, true); + if (ret) + dprintk(VIDC_WARN, "Failed to release scratch buffers\n"); + + ret = set_scratch_buffer(inst, HAL_BUFFER_INTERNAL_SCRATCH); + if (ret) + goto error; + + ret = set_scratch_buffer(inst, HAL_BUFFER_INTERNAL_SCRATCH_1); + if (ret) + goto error; + + ret = set_scratch_buffer(inst, HAL_BUFFER_INTERNAL_SCRATCH_2); + if (ret) + goto error; + + return 0; +error: + release_scratch_buffers(inst, false); + return ret; +} + +int set_persist_buffers(struct vidc_inst *inst) +{ + int ret; + + ret = set_persist_buffer(inst, HAL_BUFFER_INTERNAL_PERSIST); + if (ret) + goto error; + + ret = set_persist_buffer(inst, HAL_BUFFER_INTERNAL_PERSIST_1); + if (ret) + goto error; + + return 0; + +error: + release_persist_buffers(inst); + return ret; +} diff --git a/drivers/media/platform/msm/vidc/msm_internal-buffers.h b/drivers/media/platform/msm/vidc/msm_internal-buffers.h new file mode 100644 index 000000000000..e19cc915e32a --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_internal-buffers.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _MSM_VIDC_INTERNAL_BUFFERS_H_ +#define _MSM_VIDC_INTERNAL_BUFFERS_H_ + +#include "msm_vidc_common.h" + +int set_scratch_buffers(struct vidc_inst *); +int set_persist_buffers(struct vidc_inst *); +int release_persist_buffers(struct vidc_inst *); +int release_scratch_buffers(struct vidc_inst *, bool); + +#endif /* _MSM_VIDC_INTERNAL_BUFFERS_H_ */ diff --git a/drivers/media/platform/msm/vidc/msm_media_info.h b/drivers/media/platform/msm/vidc/msm_media_info.h new file mode 100644 index 000000000000..5b26be3f7df6 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_media_info.h @@ -0,0 +1,613 @@ +#ifndef __MEDIA_INFO_H__ +#define __MEDIA_INFO_H__ + +#ifndef MSM_MEDIA_ALIGN +#define MSM_MEDIA_ALIGN(__sz, __align) (((__sz) + (__align-1)) & (~(__align-1))) +#endif + +#ifndef MSM_MEDIA_ROUNDUP +#define MSM_MEDIA_ROUNDUP(__sz, __r) (((__sz) + ((__r) - 1)) / (__r)) +#endif + +enum color_fmts { + /* Venus NV12: + * YUV 4:2:0 image with a plane of 8 bit Y samples followed + * by an interleaved U/V plane containing 8 bit 2x2 subsampled + * colour difference samples. + * + * <-------- Y/UV_Stride --------> + * <------- Width -------> + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * U V U V U V U V U V U V . . . . ^ + * U V U V U V U V U V U V . . . . | + * U V U V U V U V U V U V . . . . | + * U V U V U V U V U V U V . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . --> Buffer size alignment + * + * Y_Stride : Width aligned to 128 + * UV_Stride : Width aligned to 128 + * Y_Scanlines: Height aligned to 32 + * UV_Scanlines: Height/2 aligned to 16 + * Extradata: Arbitrary (software-imposed) padding + * Total size = align((Y_Stride * Y_Scanlines + * + UV_Stride * UV_Scanlines + Extradata), 4096) + */ + COLOR_FMT_NV12, + + /* Venus NV21: + * YUV 4:2:0 image with a plane of 8 bit Y samples followed + * by an interleaved V/U plane containing 8 bit 2x2 subsampled + * colour difference samples. + * + * <-------- Y/UV_Stride --------> + * <------- Width -------> + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * V U V U V U V U V U V U . . . . ^ + * V U V U V U V U V U V U . . . . | + * V U V U V U V U V U V U . . . . | + * V U V U V U V U V U V U . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . --> Padding & Buffer size alignment + * + * Y_Stride : Width aligned to 128 + * UV_Stride : Width aligned to 128 + * Y_Scanlines: Height aligned to 32 + * UV_Scanlines: Height/2 aligned to 16 + * Extradata: Arbitrary (software-imposed) padding + * Total size = align((Y_Stride * Y_Scanlines + * + UV_Stride * UV_Scanlines + Extradata), 4096) + */ + COLOR_FMT_NV21, + /* Venus NV12_MVTB: + * Two YUV 4:2:0 images/views one after the other + * in a top-bottom layout, same as NV12 + * with a plane of 8 bit Y samples followed + * by an interleaved U/V plane containing 8 bit 2x2 subsampled + * colour difference samples. + * + * + * <-------- Y/UV_Stride --------> + * <------- Width -------> + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ ^ + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | | + * . . . . . . . . . . . . . . . . | View_1 + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . V | + * U V U V U V U V U V U V . . . . ^ | + * U V U V U V U V U V U V . . . . | | + * U V U V U V U V U V U V . . . . | | + * U V U V U V U V U V U V . . . . UV_Scanlines | + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . V V + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . ^ ^ ^ + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . Height | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | Y_Scanlines | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . | | | + * Y Y Y Y Y Y Y Y Y Y Y Y . . . . V | | + * . . . . . . . . . . . . . . . . | View_2 + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . V | + * U V U V U V U V U V U V . . . . ^ | + * U V U V U V U V U V U V . . . . | | + * U V U V U V U V U V U V . . . . | | + * U V U V U V U V U V U V . . . . UV_Scanlines | + * . . . . . . . . . . . . . . . . | | + * . . . . . . . . . . . . . . . . V V + * . . . . . . . . . . . . . . . . --> Buffer size alignment + * + * Y_Stride : Width aligned to 128 + * UV_Stride : Width aligned to 128 + * Y_Scanlines: Height aligned to 32 + * UV_Scanlines: Height/2 aligned to 16 + * View_1 begin at: 0 (zero) + * View_2 begin at: Y_Stride * Y_Scanlines + UV_Stride * UV_Scanlines + * Extradata: Arbitrary (software-imposed) padding + * Total size = align((2*(Y_Stride * Y_Scanlines) + * + 2*(UV_Stride * UV_Scanlines) + Extradata), 4096) + */ + COLOR_FMT_NV12_MVTB, + /* Venus NV12 UBWC: + * Compressed Macro-tile format for NV12. + * Contains 4 planes in the following order - + * (A) Y_Meta_Plane + * (B) Y_UBWC_Plane + * (C) UV_Meta_Plane + * (D) UV_UBWC_Plane + * + * Y_Meta_Plane consists of meta information to decode compressed + * tile data in Y_UBWC_Plane. + * Y_UBWC_Plane consists of Y data in compressed macro-tile format. + * UBWC decoder block will use the Y_Meta_Plane data together with + * Y_UBWC_Plane data to produce loss-less uncompressed 8 bit Y samples. + * + * UV_Meta_Plane consists of meta information to decode compressed + * tile data in UV_UBWC_Plane. + * UV_UBWC_Plane consists of UV data in compressed macro-tile format. + * UBWC decoder block will use UV_Meta_Plane data together with + * UV_UBWC_Plane data to produce loss-less uncompressed 8 bit 2x2 + * subsampled color difference samples. + * + * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable + * and randomly accessible. There is no dependency between tiles. + * + * <----- Y_Meta_Stride ----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_Y_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <--Compressed tile Y Stride---> + * <------- Width -------> + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * <----- UV_Meta_Stride ----> + * M M M M M M M M M M M M . . ^ + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . M_UV_Scanlines + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * <--Compressed tile UV Stride---> + * U* V* U* V* U* V* U* V* . . . . ^ + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * + * Y_Stride = align(Width, 128) + * UV_Stride = align(Width, 128) + * Y_Scanlines = align(Height, 32) + * UV_Scanlines = align(Height/2, 16) + * Y_UBWC_Plane_size = align(Y_Stride * Y_Scanlines, 4096) + * UV_UBWC_Plane_size = align(UV_Stride * UV_Scanlines, 4096) + * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) + * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16) + * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096) + * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) + * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) + * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) + * Extradata = 8k + * + * Total size = align( Y_UBWC_Plane_size + UV_UBWC_Plane_size + + * Y_Meta_Plane_size + UV_Meta_Plane_size + Extradata, 4096) + */ + COLOR_FMT_NV12_UBWC, + /* Venus NV12 10-bit UBWC: + * Compressed Macro-tile format for NV12. + * Contains 4 planes in the following order - + * (A) Y_Meta_Plane + * (B) Y_UBWC_Plane + * (C) UV_Meta_Plane + * (D) UV_UBWC_Plane + * + * Y_Meta_Plane consists of meta information to decode compressed + * tile data in Y_UBWC_Plane. + * Y_UBWC_Plane consists of Y data in compressed macro-tile format. + * UBWC decoder block will use the Y_Meta_Plane data together with + * Y_UBWC_Plane data to produce loss-less uncompressed 10 bit Y samples. + * + * UV_Meta_Plane consists of meta information to decode compressed + * tile data in UV_UBWC_Plane. + * UV_UBWC_Plane consists of UV data in compressed macro-tile format. + * UBWC decoder block will use UV_Meta_Plane data together with + * UV_UBWC_Plane data to produce loss-less uncompressed 10 bit 2x2 + * subsampled color difference samples. + * + * Each tile in Y_UBWC_Plane/UV_UBWC_Plane is independently decodable + * and randomly accessible. There is no dependency between tiles. + * + * <----- Y_Meta_Stride -----> + * <-------- Width ------> + * M M M M M M M M M M M M . . ^ ^ + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . Height | + * M M M M M M M M M M M M . . | Meta_Y_Scanlines + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . | | + * M M M M M M M M M M M M . . V | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . V + * <--Compressed tile Y Stride---> + * <------- Width -------> + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . ^ ^ + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . Height | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | Macro_tile_Y_Scanlines + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . | | + * Y* Y* Y* Y* Y* Y* Y* Y* . . . . V | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * . . . . . . . . . . . . . . . . V + * <----- UV_Meta_Stride ----> + * M M M M M M M M M M M M . . ^ + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . | + * M M M M M M M M M M M M . . M_UV_Scanlines + * . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * <--Compressed tile UV Stride---> + * U* V* U* V* U* V* U* V* . . . . ^ + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . | + * U* V* U* V* U* V* U* V* . . . . UV_Scanlines + * . . . . . . . . . . . . . . . . | + * . . . . . . . . . . . . . . . . V + * . . . . . . . . . . . . . . . . -------> Buffer size aligned to 4k + * + * + * Y_Stride = align(Width * 4/3, 128) + * UV_Stride = align(Width * 4/3, 128) + * Y_Scanlines = align(Height, 32) + * UV_Scanlines = align(Height/2, 16) + * Y_UBWC_Plane_Size = align(Y_Stride * Y_Scanlines, 4096) + * UV_UBWC_Plane_Size = align(UV_Stride * UV_Scanlines, 4096) + * Y_Meta_Stride = align(roundup(Width, Y_TileWidth), 64) + * Y_Meta_Scanlines = align(roundup(Height, Y_TileHeight), 16) + * Y_Meta_Plane_size = align(Y_Meta_Stride * Y_Meta_Scanlines, 4096) + * UV_Meta_Stride = align(roundup(Width, UV_TileWidth), 64) + * UV_Meta_Scanlines = align(roundup(Height, UV_TileHeight), 16) + * UV_Meta_Plane_size = align(UV_Meta_Stride * UV_Meta_Scanlines, 4096) + * Extradata = 8k + */ + COLOR_FMT_NV12_BPP10_UBWC, +}; + +static inline unsigned int VENUS_EXTRADATA_SIZE(int width, int height) +{ + (void)height; + (void)width; + + /* + * In the future, calculate the size based on the w/h but just + * hardcode it for now since 8K satisfies all current usecases. + */ + return 8 * 1024; +} + +static inline unsigned int VENUS_Y_STRIDE(int color_fmt, int width) +{ + unsigned int alignment, stride = 0; + if (!width) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: + case COLOR_FMT_NV12_MVTB: + case COLOR_FMT_NV12_UBWC: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width, alignment); + break; + case COLOR_FMT_NV12_BPP10_UBWC: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width * 4/3, alignment); + break; + default: + break; + } +invalid_input: + return stride; +} + +static inline unsigned int VENUS_UV_STRIDE(int color_fmt, int width) +{ + unsigned int alignment, stride = 0; + if (!width) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: + case COLOR_FMT_NV12_MVTB: + case COLOR_FMT_NV12_UBWC: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width, alignment); + break; + case COLOR_FMT_NV12_BPP10_UBWC: + alignment = 128; + stride = MSM_MEDIA_ALIGN(width * 4/3, alignment); + break; + default: + break; + } +invalid_input: + return stride; +} + +static inline unsigned int VENUS_Y_SCANLINES(int color_fmt, int height) +{ + unsigned int alignment, sclines = 0; + if (!height) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: + case COLOR_FMT_NV12_MVTB: + case COLOR_FMT_NV12_UBWC: + case COLOR_FMT_NV12_BPP10_UBWC: + alignment = 32; + sclines = MSM_MEDIA_ALIGN(height, alignment); + break; + default: + break; + } +invalid_input: + return sclines; +} + +static inline unsigned int VENUS_UV_SCANLINES(int color_fmt, int height) +{ + unsigned int alignment, sclines = 0; + if (!height) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: + case COLOR_FMT_NV12_MVTB: + case COLOR_FMT_NV12_UBWC: + case COLOR_FMT_NV12_BPP10_UBWC: + alignment = 16; + sclines = MSM_MEDIA_ALIGN(((height + 1) >> 1), alignment); + break; + default: + break; + } +invalid_input: + return sclines; +} + +static inline unsigned int VENUS_Y_META_STRIDE(int color_fmt, int width) +{ + int y_tile_width = 0, y_meta_stride = 0; + + if (!width) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV12_UBWC: + y_tile_width = 32; + break; + case COLOR_FMT_NV12_BPP10_UBWC: + y_tile_width = 48; + break; + default: + goto invalid_input; + } + + y_meta_stride = MSM_MEDIA_ROUNDUP(width, y_tile_width); + y_meta_stride = MSM_MEDIA_ALIGN(y_meta_stride, 64); + +invalid_input: + return y_meta_stride; +} + +static inline unsigned int VENUS_Y_META_SCANLINES(int color_fmt, int height) +{ + int y_tile_height = 0, y_meta_scanlines = 0; + + if (!height) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV12_UBWC: + y_tile_height = 8; + break; + case COLOR_FMT_NV12_BPP10_UBWC: + y_tile_height = 4; + break; + default: + goto invalid_input; + } + + y_meta_scanlines = MSM_MEDIA_ROUNDUP(height, y_tile_height); + y_meta_scanlines = MSM_MEDIA_ALIGN(y_meta_scanlines, 16); + +invalid_input: + return y_meta_scanlines; +} + +static inline unsigned int VENUS_UV_META_STRIDE(int color_fmt, int width) +{ + int uv_tile_width = 0, uv_meta_stride = 0; + + if (!width) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV12_UBWC: + uv_tile_width = 16; + break; + case COLOR_FMT_NV12_BPP10_UBWC: + uv_tile_width = 24; + break; + default: + goto invalid_input; + } + + uv_meta_stride = MSM_MEDIA_ROUNDUP(width, uv_tile_width); + uv_meta_stride = MSM_MEDIA_ALIGN(uv_meta_stride, 64); + +invalid_input: + return uv_meta_stride; +} + +static inline unsigned int VENUS_UV_META_SCANLINES(int color_fmt, int height) +{ + int uv_tile_height = 0, uv_meta_scanlines = 0; + + if (!height) + goto invalid_input; + + switch (color_fmt) { + case COLOR_FMT_NV12_UBWC: + uv_tile_height = 8; + break; + case COLOR_FMT_NV12_BPP10_UBWC: + uv_tile_height = 4; + break; + default: + goto invalid_input; + } + + uv_meta_scanlines = MSM_MEDIA_ROUNDUP(height, uv_tile_height); + uv_meta_scanlines = MSM_MEDIA_ALIGN(uv_meta_scanlines, 16); + +invalid_input: + return uv_meta_scanlines; +} + +static inline unsigned int VENUS_BUFFER_SIZE(int color_fmt, int width, + int height) +{ + const unsigned int extra_size = VENUS_EXTRADATA_SIZE(width, height); + unsigned int uv_alignment = 0, size = 0; + unsigned int y_plane, uv_plane, y_stride, + uv_stride, y_sclines, uv_sclines; + unsigned int y_ubwc_plane = 0, uv_ubwc_plane = 0; + unsigned int y_meta_stride = 0, y_meta_scanlines = 0; + unsigned int uv_meta_stride = 0, uv_meta_scanlines = 0; + unsigned int y_meta_plane = 0, uv_meta_plane = 0; + + if (!width || !height) + goto invalid_input; + + y_stride = VENUS_Y_STRIDE(color_fmt, width); + uv_stride = VENUS_UV_STRIDE(color_fmt, width); + y_sclines = VENUS_Y_SCANLINES(color_fmt, height); + uv_sclines = VENUS_UV_SCANLINES(color_fmt, height); + + switch (color_fmt) { + case COLOR_FMT_NV21: + case COLOR_FMT_NV12: + uv_alignment = 4096; + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines + uv_alignment; + size = y_plane + uv_plane + extra_size; + size = MSM_MEDIA_ALIGN(size, 4096); + break; + case COLOR_FMT_NV12_MVTB: + uv_alignment = 4096; + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines + uv_alignment; + size = y_plane + uv_plane; + size = 2 * size + extra_size; + size = MSM_MEDIA_ALIGN(size, 4096); + break; + case COLOR_FMT_NV12_UBWC: + case COLOR_FMT_NV12_BPP10_UBWC: + y_ubwc_plane = MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096); + uv_ubwc_plane = MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096); + y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width); + y_meta_scanlines = VENUS_Y_META_SCANLINES(color_fmt, height); + y_meta_plane = MSM_MEDIA_ALIGN( + y_meta_stride * y_meta_scanlines, 4096); + uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width); + uv_meta_scanlines = VENUS_UV_META_SCANLINES(color_fmt, height); + uv_meta_plane = MSM_MEDIA_ALIGN(uv_meta_stride * + uv_meta_scanlines, 4096); + + size = y_ubwc_plane + uv_ubwc_plane + y_meta_plane + + uv_meta_plane + extra_size; + size = MSM_MEDIA_ALIGN(size, 4096); + break; + default: + break; + } + +invalid_input: + return size; +} + +static inline unsigned int VENUS_VIEW2_OFFSET( + int color_fmt, int width, int height) +{ + unsigned int offset = 0; + unsigned int y_plane, uv_plane, y_stride, + uv_stride, y_sclines, uv_sclines; + if (!width || !height) + goto invalid_input; + + y_stride = VENUS_Y_STRIDE(color_fmt, width); + uv_stride = VENUS_UV_STRIDE(color_fmt, width); + y_sclines = VENUS_Y_SCANLINES(color_fmt, height); + uv_sclines = VENUS_UV_SCANLINES(color_fmt, height); + switch (color_fmt) { + case COLOR_FMT_NV12_MVTB: + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines; + offset = y_plane + uv_plane; + break; + default: + break; + } +invalid_input: + return offset; +} + +#endif diff --git a/drivers/media/platform/msm/vidc/msm_smem.c b/drivers/media/platform/msm/vidc/msm_smem.c new file mode 100644 index 000000000000..320087beebd7 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_smem.c @@ -0,0 +1,191 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "msm_smem.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_resources.h" + +static int alloc_dma_mem(struct smem_client *client, size_t size, u32 align, + u32 flags, enum hal_buffer buffer_type, + struct smem *mem, int map_kernel) +{ + int ret; + + if (align > 1) { + align = ALIGN(align, SZ_4K); + size = ALIGN(size, align); + } + + size = ALIGN(size, SZ_4K); + + dprintk(VIDC_DBG, "%s: type: %x, size %zu\n", __func__, buffer_type, + size); + + mem->flags = flags; + mem->buffer_type = buffer_type; + mem->size = size; + mem->kvaddr = NULL; + mem->smem_priv = NULL; + + mem->iommu_dev = msm_iommu_get_ctx("venus_ns"); + if (IS_ERR(mem->iommu_dev)) + return PTR_ERR(mem->iommu_dev); + + init_dma_attrs(&mem->attrs); + + if (!map_kernel) + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &mem->attrs); + + mem->kvaddr = dma_alloc_attrs(mem->iommu_dev, size, &mem->da, + GFP_KERNEL, &mem->attrs); + if (!mem->kvaddr) + return -ENOMEM; + + mem->sgt = kmalloc(sizeof(*mem->sgt), GFP_KERNEL); + if (!mem->sgt) { + ret = -ENOMEM; + goto error_sgt; + } + + ret = dma_get_sgtable_attrs(mem->iommu_dev, mem->sgt, mem->kvaddr, + mem->da, mem->size, &mem->attrs); + if (ret) + goto error; + + return 0; +error: + kfree(mem->sgt); +error_sgt: + dma_free_attrs(mem->iommu_dev, mem->size, mem->kvaddr, + mem->da, &mem->attrs); + return ret; +} + +static void free_dma_mem(struct smem_client *client, struct smem *mem) +{ + dma_free_attrs(mem->iommu_dev, mem->size, mem->kvaddr, + mem->da, &mem->attrs); + kfree(mem->sgt); +} + +static int sync_dma_cache(struct smem *mem, enum smem_cache_ops cache_op) +{ + if (cache_op == SMEM_CACHE_CLEAN) { + dma_sync_sg_for_device(mem->iommu_dev, mem->sgt->sgl, + mem->sgt->nents, DMA_TO_DEVICE); + } else if (cache_op == SMEM_CACHE_INVALIDATE) { + dma_sync_sg_for_cpu(mem->iommu_dev, mem->sgt->sgl, + mem->sgt->nents, DMA_FROM_DEVICE); + } else { + dma_sync_sg_for_device(mem->iommu_dev, mem->sgt->sgl, + mem->sgt->nents, DMA_TO_DEVICE); + dma_sync_sg_for_cpu(mem->iommu_dev, mem->sgt->sgl, + mem->sgt->nents, DMA_FROM_DEVICE); + } + + return 0; +} + +int smem_cache_operations(struct smem_client *client, struct smem *mem, + enum smem_cache_ops cache_op) +{ + if (!client) + return -EINVAL; + + return sync_dma_cache(mem, cache_op); +} + +struct smem_client *smem_new_client(void *platform_resources) +{ + struct vidc_resources *res = platform_resources; + struct smem_client *client; + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return ERR_PTR(-ENOMEM); + + client->clnt = NULL; + client->res = res; + + return client; +} + +void smem_delete_client(struct smem_client *client) +{ + if (!client) + return; + + kfree(client); +} + +struct smem *smem_alloc(struct smem_client *client, size_t size, u32 align, + u32 flags, enum hal_buffer buffer_type, int map_kernel) +{ + struct smem *mem; + int ret; + + if (!client || !size) + return ERR_PTR(-EINVAL); + + mem = kzalloc(sizeof(*mem), GFP_KERNEL); + if (!mem) + return ERR_PTR(-ENOMEM); + + ret = alloc_dma_mem(client, size, align, flags, buffer_type, + mem, map_kernel); + if (ret) { + kfree(mem); + return ERR_PTR(ret); + } + + return mem; +} + +void smem_free(struct smem_client *client, struct smem *mem) +{ + if (!client || !mem) + return; + + free_dma_mem(client, mem); + kfree(mem); +}; + +struct context_bank_info * +smem_get_context_bank(struct smem_client *client, bool is_secure, + enum hal_buffer buffer_type) +{ + struct context_bank_info *cb = NULL, *match = NULL; + + if (!client) { + dprintk(VIDC_ERR, "%s - invalid params\n", __func__); + return NULL; + } + + list_for_each_entry(cb, &client->res->context_banks, list) { + if (cb->is_secure == is_secure && + cb->buffer_type & buffer_type) { + match = cb; + break; + } + } + + return match; +} diff --git a/drivers/media/platform/msm/vidc/msm_smem.h b/drivers/media/platform/msm/vidc/msm_smem.h new file mode 100644 index 000000000000..62e7cfa64bb9 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_smem.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __VIDC_MSM_SMEM_H__ +#define __VIDC_MSM_SMEM_H__ + +#include +#include + +#include "msm_vidc_resources.h" +#include "msm_vidc.h" +#include "hfi/vidc_hfi_api.h" + +enum smem_prop { + SMEM_CACHED = BIT(0), + SMEM_SECURE = BIT(1), +}; + +enum smem_cache_ops { + SMEM_CACHE_CLEAN, + SMEM_CACHE_INVALIDATE, + SMEM_CACHE_CLEAN_INVALIDATE, +}; + +struct smem { + size_t size; + void *kvaddr; + dma_addr_t da; + unsigned long flags; + void *smem_priv; + enum hal_buffer buffer_type; + struct dma_attrs attrs; + struct device *iommu_dev; + struct sg_table *sgt; +}; + +struct smem_client { + void *clnt; + struct vidc_resources *res; +}; + +struct smem_client *smem_new_client(void *platform_resources); +void smem_delete_client(struct smem_client *clt); + +struct smem *smem_alloc(struct smem_client *clt, size_t size, u32 align, + u32 flags, enum hal_buffer buffer_type, int map_kernel); +void smem_free(struct smem_client *clt, struct smem *mem); + +int smem_cache_operations(struct smem_client *clt, struct smem *mem, + enum smem_cache_ops); +struct context_bank_info * +smem_get_context_bank(struct smem_client *clt, bool is_secure, + enum hal_buffer buffer_type); + +#endif /* __VIDC_MSM_SMEM_H__ */ diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c new file mode 100644 index 000000000000..52c842b5ea0b --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -0,0 +1,571 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "msm_vidc_common.h" +#include "msm_smem.h" +#include "msm_vdec.h" +#include "msm_venc.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_internal.h" +#include "msm_vidc_resources.h" +#include "msm_hfi_interface.h" + +/* Offset base for buffers on the destination queue - used to distinguish + * between source and destination buffers when mmapping - they receive the same + * offsets but for different queues */ +#define DST_QUEUE_OFF_BASE (1 << 30) + +struct vidc_drv *vidc_driver; +unsigned int vidc_pwr_collapse_delay = 2000; + +static inline struct vidc_inst *vidc_to_inst(struct file *file) +{ + return container_of(file->private_data, struct vidc_inst, fh); +} + +static void vidc_add_inst(struct vidc_core *core, struct vidc_inst *inst) +{ + mutex_lock(&core->lock); + list_add_tail(&inst->list, &core->instances); + mutex_unlock(&core->lock); +} + +static void vidc_del_inst(struct vidc_core *core, struct vidc_inst *inst) +{ + struct vidc_inst *pos, *n; + + mutex_lock(&core->lock); + list_for_each_entry_safe(pos, n, &core->instances, list) { + if (pos == inst) + list_del(&inst->list); + } + mutex_unlock(&core->lock); +} + +static int vidc_firmware_load(struct vidc_core *core) +{ + int ret; + + if (core->rproc_booted) + return 0; + + ret = rproc_boot(core->rproc); + if (ret) + return ret; + + core->rproc_booted = true; + + return 0; +} + +static void vidc_firmware_unload(struct vidc_core *core) +{ + if (!core->rproc_booted) + return; + + rproc_shutdown(core->rproc); + core->rproc_booted = false; +} + +struct vidc_sys_error { + struct vidc_core *core; + struct delayed_work work; +}; + +static void vidc_sys_error_handler(struct work_struct *work) +{ + struct vidc_sys_error *handler; + struct vidc_core *core; + struct hfi_device *hdev; + int ret; + + handler = container_of(work, struct vidc_sys_error, work.work); + core = handler->core; + hdev = core->hfidev; + + mutex_lock(&core->lock); + if (core->state != CORE_INVALID) { + mutex_unlock(&core->lock); + goto exit; + } + + ret = call_hfi_op(hdev, core_release, hdev->hfi_device_data); + if (ret) { + dprintk(VIDC_ERR, "%s: core_release failed: %d\n", + __func__, ret); + } + + rproc_report_crash(core->rproc, RPROC_FATAL_ERROR); + + vidc_firmware_unload(core); + + ret = vidc_firmware_load(core); + if (ret) + goto exit; + + core->state = CORE_INIT; + + mutex_unlock(&core->lock); + +exit: + kfree(handler); +} + +static int vidc_event_notify(struct vidc_core *core, u32 device_id, u32 event) +{ + struct vidc_sys_error *handler; + struct vidc_inst *inst = NULL; + + switch (event) { + case SYS_WATCHDOG_TIMEOUT: + case SYS_ERROR: + break; + default: + return -EINVAL; + } + + mutex_lock(&core->lock); + + core->state = CORE_INVALID; + + list_for_each_entry(inst, &core->instances, list) + vidc_inst_set_state(inst, INST_INVALID); + + mutex_unlock(&core->lock); + + handler = kzalloc(sizeof(*handler), GFP_KERNEL); + if (!handler) + return -ENOMEM; + + handler->core = core; + INIT_DELAYED_WORK(&handler->work, vidc_sys_error_handler); + + /* + * Sleep for 5 sec to ensure venus has completed any + * pending cache operations. Without this sleep, we see + * device reset when firmware is unloaded after a sys + * error. + */ + schedule_delayed_work(&handler->work, msecs_to_jiffies(5000)); + + return 0; +} + +static int vidc_open(struct file *file) +{ + struct video_device *vdev = video_devdata(file); + struct vidc_core *core = video_drvdata(file); + struct device *dev = &core->res.pdev->dev; + struct vidc_inst *inst; + int ret = 0; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + mutex_init(&inst->sync_lock); + mutex_init(&inst->lock); + + INIT_VIDC_LIST(&inst->scratchbufs); + INIT_VIDC_LIST(&inst->persistbufs); + INIT_VIDC_LIST(&inst->pending_getpropq); + INIT_VIDC_LIST(&inst->registeredbufs); + + INIT_LIST_HEAD(&inst->bufqueue); + mutex_init(&inst->bufqueue_lock); + + if (vdev == &core->vdev_dec) + inst->session_type = VIDC_DECODER; + else + inst->session_type = VIDC_ENCODER; + + inst->state = INST_UNINIT; + inst->core = core; + + inst->mem_client = smem_new_client(&core->res); + if (IS_ERR(inst->mem_client)) { + ret = PTR_ERR(inst->mem_client); + goto err_free_inst; + } + + ret = enable_clocks(&core->res); + if (ret) { + dev_err(dev, "enable clocks\n"); + goto err_del_mem_clnt; + } + + ret = vidc_firmware_load(core); + if (ret) + goto err_dis_clks; + + ret = hfi_core_init(core); + if (ret) + goto err_fw_unload; + + inst->debugfs_root = vidc_debugfs_init_inst(inst, core->debugfs_root); + + if (inst->session_type == VIDC_DECODER) + ret = vdec_open(inst); + else + ret = venc_open(inst); + + if (ret) + goto err_core_deinit; + + if (inst->session_type == VIDC_DECODER) + v4l2_fh_init(&inst->fh, &core->vdev_dec); + else + v4l2_fh_init(&inst->fh, &core->vdev_enc); + + inst->fh.ctrl_handler = &inst->ctrl_handler; + + v4l2_fh_add(&inst->fh); + + file->private_data = &inst->fh; + + vidc_add_inst(core, inst); + + return 0; + +err_core_deinit: + hfi_core_deinit(core); +err_fw_unload: + vidc_firmware_unload(core); +err_dis_clks: + disable_clocks(&core->res); +err_del_mem_clnt: + smem_delete_client(inst->mem_client); +err_free_inst: + kfree(inst); + return ret; +} + +static int vidc_close(struct file *file) +{ + struct vidc_inst *inst = vidc_to_inst(file); + struct vidc_core *core = inst->core; + struct device *dev = &core->res.pdev->dev; + int ret; + + if (inst->session_type == VIDC_DECODER) + vdec_close(inst); + else + venc_close(inst); + + vidc_del_inst(core, inst); + + debugfs_remove_recursive(inst->debugfs_root); + + mutex_lock(&inst->pending_getpropq.lock); + WARN_ON(!list_empty(&inst->pending_getpropq.list)); + mutex_unlock(&inst->pending_getpropq.lock); + + hfi_session_clean(inst); + + ret = hfi_core_deinit(core); + if (ret) + dev_err(dev, "core: deinit failed (%d)\n", ret); + + disable_clocks(&core->res); + + smem_delete_client(inst->mem_client); + + mutex_destroy(&inst->bufqueue_lock); + mutex_destroy(&inst->scratchbufs.lock); + mutex_destroy(&inst->persistbufs.lock); + mutex_destroy(&inst->pending_getpropq.lock); + mutex_destroy(&inst->registeredbufs.lock); + + v4l2_fh_del(&inst->fh); + v4l2_fh_exit(&inst->fh); + + kfree(inst); + + return 0; +} + +static int vidc_get_poll_flags(struct vidc_inst *inst) +{ + struct vb2_queue *outq = &inst->bufq_out; + struct vb2_queue *capq = &inst->bufq_cap; + struct vb2_buffer *out_vb = NULL; + struct vb2_buffer *cap_vb = NULL; + unsigned long flags; + int ret = 0; + + if (v4l2_event_pending(&inst->fh)) + ret |= POLLPRI; + + spin_lock_irqsave(&capq->done_lock, flags); + if (!list_empty(&capq->done_list)) + cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer, + done_entry); + if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE || + cap_vb->state == VB2_BUF_STATE_ERROR)) + ret |= POLLIN | POLLRDNORM; + spin_unlock_irqrestore(&capq->done_lock, flags); + + spin_lock_irqsave(&outq->done_lock, flags); + if (!list_empty(&outq->done_list)) + out_vb = list_first_entry(&outq->done_list, struct vb2_buffer, + done_entry); + if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE || + out_vb->state == VB2_BUF_STATE_ERROR)) + ret |= POLLOUT | POLLWRNORM; + spin_unlock_irqrestore(&outq->done_lock, flags); + + return ret; +} + +static unsigned int vidc_poll(struct file *file, struct poll_table_struct *pt) +{ + struct vidc_inst *inst = vidc_to_inst(file); + struct vb2_queue *outq = &inst->bufq_out; + struct vb2_queue *capq = &inst->bufq_cap; + + poll_wait(file, &inst->fh.wait, pt); + poll_wait(file, &capq->done_wq, pt); + poll_wait(file, &outq->done_wq, pt); + + return vidc_get_poll_flags(inst); +} + +static int vidc_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct vidc_inst *inst = vidc_to_inst(file); + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + int ret; + + if (offset < DST_QUEUE_OFF_BASE) { + ret = vb2_mmap(&inst->bufq_out, vma); + } else { + vma->vm_pgoff -= DST_QUEUE_OFF_BASE >> PAGE_SHIFT; + ret = vb2_mmap(&inst->bufq_cap, vma); + } + + return ret; +} + +const struct v4l2_file_operations vidc_fops = { + .owner = THIS_MODULE, + .open = vidc_open, + .release = vidc_close, + .unlocked_ioctl = video_ioctl2, + .poll = vidc_poll, + .mmap = vidc_mmap, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = v4l2_compat_ioctl32, +#endif +}; + +static const struct of_device_id vidc_dt_match[] = { + { .compatible = "qcom,msm-vidc" }, + { } +}; + +MODULE_DEVICE_TABLE(of, vidc_dt_match); + +static int vidc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct vidc_core *core; + struct vidc_resources *res; + struct device_node *rproc; + struct resource *r; + int ret; + + if (!vidc_driver) { + vidc_driver = kzalloc(sizeof(*vidc_driver), GFP_KERNEL); + if (!vidc_driver) + return -ENOMEM; + + INIT_LIST_HEAD(&vidc_driver->cores); + mutex_init(&vidc_driver->lock); + + vidc_driver->debugfs_root = vidc_debugfs_init_drv(); + if (!vidc_driver->debugfs_root) + dev_err(dev, "create debugfs for vidc\n"); + } + + mutex_lock(&vidc_driver->lock); + if (vidc_driver->num_cores + 1 > VIDC_CORES_MAX) { + mutex_unlock(&vidc_driver->lock); + dev_warn(dev, "maximum cores reached\n"); + return -EBUSY; + } + vidc_driver->num_cores++; + mutex_unlock(&vidc_driver->lock); + + core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL); + if (!core) + return -ENOMEM; + + core->res.pdev = pdev; + platform_set_drvdata(pdev, core); + + rproc = of_parse_phandle(dev->of_node, "rproc", 0); + if (IS_ERR(rproc)) { + dev_err(dev, "cannot parse phandle rproc\n"); + return PTR_ERR(rproc); + } + + core->rproc = rproc_get_by_phandle(rproc->phandle); + if (IS_ERR(core->rproc)) + return PTR_ERR(core->rproc); + else if (!core->rproc) + return -EPROBE_DEFER; + + res = &core->res; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res->base = devm_ioremap_resource(dev, r); + if (IS_ERR(res->base)) + return PTR_ERR(res->base); + + res->irq = platform_get_irq(pdev, 0); + if (IS_ERR_VALUE(res->irq)) + return res->irq; + + ret = get_platform_resources(core); + if (ret) + return ret; + + INIT_LIST_HEAD(&core->instances); + mutex_init(&core->lock); + core->state = CORE_UNINIT; + + if (core->hfi_type == VIDC_HFI_Q6) + core->id = VIDC_CORE_Q6; + else + core->id = VIDC_CORE_VENUS; + + ret = v4l2_device_register(dev, &core->v4l2_dev); + if (ret) + return ret; + + ret = vdec_init(core, &core->vdev_dec); + if (ret) + goto err_dev_unregister; + + ret = venc_init(core, &core->vdev_enc); + if (ret) + goto err_vdec_deinit; + + core->hfidev = vidc_hfi_init(core->hfi_type, core->id, &core->res); + if (IS_ERR(core->hfidev)) { + mutex_lock(&vidc_driver->lock); + vidc_driver->num_cores--; + mutex_unlock(&vidc_driver->lock); + + ret = PTR_ERR(core->hfidev); + goto err_venc_deinit; + } + + core->event_notify = vidc_event_notify; + + mutex_lock(&vidc_driver->lock); + list_add_tail(&core->list, &vidc_driver->cores); + mutex_unlock(&vidc_driver->lock); + + core->debugfs_root = + vidc_debugfs_init_core(core, vidc_driver->debugfs_root); + + return 0; + +err_venc_deinit: + venc_deinit(core, &core->vdev_enc); +err_vdec_deinit: + vdec_deinit(core, &core->vdev_dec); +err_dev_unregister: + v4l2_device_unregister(&core->v4l2_dev); + return ret; +} + +static int vidc_remove(struct platform_device *pdev) +{ + struct vidc_core *core; + int empty; + + core = platform_get_drvdata(pdev); + if (!core) + return -EINVAL; + + vidc_hfi_deinit(core->hfi_type, core->hfidev); + vdec_deinit(core, &core->vdev_dec); + venc_deinit(core, &core->vdev_enc); + v4l2_device_unregister(&core->v4l2_dev); + + put_platform_resources(core); + + mutex_lock(&vidc_driver->lock); + list_del(&core->list); + empty = list_empty(&vidc_driver->cores); + mutex_unlock(&vidc_driver->lock); + + vidc_firmware_unload(core); + + if (!empty) + return 0; + + debugfs_remove_recursive(vidc_driver->debugfs_root); + kfree(vidc_driver); + vidc_driver = NULL; + + return 0; +} + +static int vidc_pm_suspend(struct device *dev) +{ + struct vidc_core *core = dev_get_drvdata(dev); + + if (!core) + return -EINVAL; + + return hfi_core_suspend(core); +} + +static int vidc_pm_resume(struct device *dev) +{ + return 0; +} + +static const struct dev_pm_ops vidc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(vidc_pm_suspend, vidc_pm_resume) +}; + +static struct platform_driver qcom_vidc_driver = { + .probe = vidc_probe, + .remove = vidc_remove, + .driver = { + .name = "qcom-vidc", + .of_match_table = vidc_dt_match, + .pm = &vidc_pm_ops, + }, +}; + +module_platform_driver(qcom_vidc_driver); + +MODULE_ALIAS("platform:qcom-vidc"); +MODULE_DESCRIPTION("Qualcomm video decoder driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/msm/vidc/msm_vdec-ctrls.c b/drivers/media/platform/msm/vidc/msm_vdec-ctrls.c new file mode 100644 index 000000000000..bd436423c2f2 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vdec-ctrls.c @@ -0,0 +1,1195 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include + +#include "msm_vidc_debug.h" +#include "msm_vidc_common.h" +#include "msm_vidc_load.h" +#include "msm_hfi_interface.h" + +#define DEFAULT_VIDEO_CONCEAL_COLOR_BLACK 0x8010 +#define TZ_DYNAMIC_BUFFER_FEATURE_ID 12 +#define TZ_FEATURE_VERSION(major, minor, patch) \ + (((major & 0x3FF) << 22) | ((minor & 0x3FF) << 12) | (patch & 0xFFF)) + +static const char *const mpeg_video_vidc_divx_format[] = { + "DIVX Format 4", + "DIVX Format 5", + "DIVX Format 6", + NULL +}; +static const char *mpeg_video_stream_format[] = { + "NAL Format Start Codes", + "NAL Format One NAL Per Buffer", + "NAL Format One Byte Length", + "NAL Format Two Byte Length", + "NAL Format Four Byte Length", + NULL +}; +static const char *const mpeg_video_output_order[] = { + "Display Order", + "Decode Order", + NULL +}; +static const char *const mpeg_video_vidc_extradata[] = { + "Extradata none", + "Extradata MB Quantization", + "Extradata Interlace Video", + "Extradata VC1 Framedisp", + "Extradata VC1 Seqdisp", + "Extradata timestamp", + "Extradata S3D Frame Packing", + "Extradata Frame Rate", + "Extradata Panscan Window", + "Extradata Recovery point SEI", + "Extradata Closed Caption UD", + "Extradata AFD UD", + "Extradata Multislice info", + "Extradata number of concealed MB", + "Extradata metadata filler", + "Extradata input crop", + "Extradata digital zoom", + "Extradata aspect ratio", + "Extradata mpeg2 seqdisp", +}; +static const char *const mpeg_vidc_video_alloc_mode_type[] = { + "Buffer Allocation Static", + "Buffer Allocation Ring Buffer", + "Buffer Allocation Dynamic Buffer" +}; + +static const char *const perf_level[] = { + "Nominal", + "Performance", + "Turbo" +}; + +static const char *const h263_level[] = { + "1.0", + "2.0", + "3.0", + "4.0", + "4.5", + "5.0", + "6.0", + "7.0", +}; + +static const char *const h263_profile[] = { + "Baseline", + "H320 Coding", + "Backward Compatible", + "ISWV2", + "ISWV3", + "High Compression", + "Internet", + "Interlace", + "High Latency", +}; + +static const char *const vp8_profile_level[] = { + "Unused", + "0.0", + "1.0", + "2.0", + "3.0", +}; + +static const char *const mpeg2_profile[] = { + "Simple", + "Main", + "422", + "SNR scalable", + "Spatial scalable", + "High", +}; + +static const char *const mpeg2_level[] = { + "Level 0", + "Level 1", + "Level 2", + "Level 3", +}; + +static const char *const mpeg_vidc_video_h264_mvc_layout[] = { + "Frame packing arrangement sequential", + "Frame packing arrangement top-bottom", +}; + +static struct vidc_ctrl vdec_ctrls[] = { + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT, + .name = "NAL Format", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES, + .maximum = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH, + .default_value = V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES) | + (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER) | + (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH) | + (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH) | + (1 << V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH) + ), + .qmenu = mpeg_video_stream_format, + .step = 0, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER, + .name = "Output Order", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY, + .maximum = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE, + .default_value = V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY) | + (1 << V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE) + ), + .qmenu = mpeg_video_output_order, + .step = 0, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE, + .name = "Picture Type Decoding", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 15, + .default_value = 15, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO, + .name = "Keep Aspect Ratio", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE, + .name = "Deblocker Mode", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT, + .name = "Divx Format", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4, + .maximum = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6, + .default_value = V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4) | + (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5) | + (1 << V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6) + ), + .qmenu = mpeg_video_vidc_divx_format, + .step = 0, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING, + .name = "MB Error Map Reporting", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER, + .name = "Smooth streamng", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE, + .name = "Sync Frame Decode", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE, + .maximum = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE, + .default_value = V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE, + .name = "Secure mode", + .type = V4L2_CTRL_TYPE_BUTTON, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 0, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA, + .name = "Extradata Type", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE, + .maximum = V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO, + .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO) + ), + .qmenu = mpeg_video_vidc_extradata, + .step = 0, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT, + .name = "Buffer allocation mode for input", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_STATIC, + .maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC, + .default_value = V4L2_MPEG_VIDC_VIDEO_STATIC, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_STATIC) | + (1 << V4L2_MPEG_VIDC_VIDEO_RING) | + (1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC) + ), + .qmenu = mpeg_vidc_video_alloc_mode_type, + .step = 0, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT, + .name = "Buffer allocation mode for output", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_STATIC, + .maximum = V4L2_MPEG_VIDC_VIDEO_DYNAMIC, + .default_value = V4L2_MPEG_VIDC_VIDEO_STATIC, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_STATIC) | + (1 << V4L2_MPEG_VIDC_VIDEO_RING) | + (1 << V4L2_MPEG_VIDC_VIDEO_DYNAMIC) + ), + .qmenu = mpeg_vidc_video_alloc_mode_type, + .step = 0, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY, + .name = "Video frame assembly", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE, + .maximum = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE, + .default_value = V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE, + .name = "Video decoder multi stream", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY, + .menu_skip_mask = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, + .name = "MPEG4 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, + .maximum = + V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY, + .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, + .menu_skip_mask = 0, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, + .name = "MPEG4 Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0, + .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, + .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0, + .menu_skip_mask = 0, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .name = "H264 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .menu_skip_mask = 0, + .flags = V4L2_CTRL_FLAG_VOLATILE, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .name = "H264 Level", + .type = V4L2_CTRL_TYPE_MENU, + .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_2, + .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .menu_skip_mask = 0, + .flags = V4L2_CTRL_FLAG_VOLATILE, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE, + .name = "H263 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE, + .maximum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY, + .default_value = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY) + ), + .qmenu = h263_profile, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL, + .name = "H263 Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0, + .maximum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0, + .default_value = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0) + ), + .qmenu = h263_level, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL, + .name = "VP8 Profile Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED, + .maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1, + .default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1) + ), + .qmenu = vp8_profile_level, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE, + .name = "MPEG2 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE, + .maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH, + .default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE, + .menu_skip_mask = 0, + .qmenu = mpeg2_profile, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL, + .name = "MPEG2 Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0, + .maximum = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3, + .default_value = V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0, + .menu_skip_mask = 0, + .qmenu = mpeg2_level, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD, + .name = "Video start code search threshold", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = INT_MAX, + .default_value = INT_MAX, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT, + .name = "MVC buffer layout", + .type = V4L2_CTRL_TYPE_MENU, + .maximum = V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM, + .default_value = V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL) | + (1 << V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM) + ), + .qmenu = mpeg_vidc_video_h264_mvc_layout, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR, + .name = "Picture concealed color", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0x0, + .maximum = 0xffffff, + .default_value = DEFAULT_VIDEO_CONCEAL_COLOR_BLACK, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD, + .name = "Secure scaling output2 threshold", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = INT_MAX, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + .flags = V4L2_CTRL_FLAG_VOLATILE, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2, + .name = "Non-Secure output2", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, +}; + +#define NUM_CTRLS ARRAY_SIZE(vdec_ctrls) + +#define IS_PRIV_CTRL(idx) ( \ + (V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \ + V4L2_CTRL_DRIVER_PRIV(idx)) + +static int check_tz_dynamic_buffer_support(struct vidc_inst *inst) +{ + struct device *dev = &inst->core->res.pdev->dev; + int version = qcom_scm_get_feat_version(TZ_DYNAMIC_BUFFER_FEATURE_ID); + + /* + * if the version is < 1.1.0 then dynamic buffer allocation is + * not supported + */ + if (version < TZ_FEATURE_VERSION(1, 1, 0)) { + dev_dbg(dev, "dynamic buffer mode not supported, " + "tz version is %u vs required %u\n", + version, TZ_FEATURE_VERSION(1, 1, 0)); + return -ENOTSUPP; + } + + return 0; +} + +static enum hal_buffer_mode_type get_buf_type(int val) +{ + switch (val) { + case V4L2_MPEG_VIDC_VIDEO_STATIC: + return HAL_BUFFER_MODE_STATIC; + case V4L2_MPEG_VIDC_VIDEO_RING: + return HAL_BUFFER_MODE_RING; + case V4L2_MPEG_VIDC_VIDEO_DYNAMIC: + return HAL_BUFFER_MODE_DYNAMIC; + default: + break; + } + + return 0; +} + +static int is_ctrl_valid_for_codec(struct vidc_inst *inst, + struct v4l2_ctrl *ctrl) +{ + struct device *dev = &inst->core->res.pdev->dev; + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT: + if (inst->fmt_out->pixfmt != V4L2_PIX_FMT_H264_MVC) { + dev_err(dev, "control %x only valid for MVC\n", + ctrl->id); + ret = -ENOTSUPP; + break; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + if (inst->fmt_out->pixfmt == V4L2_PIX_FMT_H264_MVC && + ctrl->val != V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH) { + dev_err(dev, "Profile %x not supported for MVC\n", + ctrl->val); + ret = -ENOTSUPP; + break; + } + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + if (inst->fmt_out->pixfmt == V4L2_PIX_FMT_H264_MVC && + ctrl->val >= V4L2_MPEG_VIDEO_H264_LEVEL_5_2) { + dev_err(dev, "Level %x not supported for MVC\n", + ctrl->val); + ret = -ENOTSUPP; + break; + } + break; + default: + break; + } + + return ret; +} + +static int try_get_ctrl(struct vidc_inst *inst, struct v4l2_ctrl *ctrl) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct hal_profile_level profile_level; + union hal_get_property hprop; + int ret = 0; + + dev_dbg(dev, "get ctrl id: %x\n", ctrl->id); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE: + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE: + ret = hfi_session_get_property(inst, + HAL_PARAM_PROFILE_LEVEL_CURRENT, + &hprop); + if (ret) { + dev_err(dev, "getting profile property (%d)\n", ret); + return ret; + } + + profile_level = hprop.profile_level; + ctrl->val = profile_level.profile; + dev_dbg(dev, "PROFILE ctrl->id:%x ctrl->val:%d\n", + ctrl->id, ctrl->val); + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL: + ret = hfi_session_get_property(inst, + HAL_PARAM_PROFILE_LEVEL_CURRENT, + &hprop); + if (ret) { + dev_err(dev, "getting level property(%d)\n", ret); + return ret; + } + + profile_level = hprop.profile_level; + ctrl->val = profile_level.level; + dev_dbg(dev, "LEVEL ctrl->id:%x ctrl->val:%d\n", + ctrl->id, ctrl->val); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD: + if (!(inst->flags & VIDC_SECURE) || + !inst->capability.secure_output2_threshold.max) { + dprintk(VIDC_ERR, "%s id:%x invalid configuration\n", + __func__, ctrl->id); + ret = -EINVAL; + break; + } + dev_dbg(dev, "Secure Scaling Threshold is %d", + inst->capability.secure_output2_threshold.max); + ctrl->val = inst->capability.secure_output2_threshold.max; + break; + default: + dev_dbg(dev, "ctrl id: %x not supported\n", ctrl->id); + break; + } + + return ret; +} + +static int vdec_v4l2_to_hal(int id, int value) +{ + switch (id) { + /* H264 */ + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + switch (value) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + return HAL_H264_PROFILE_BASELINE; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + return HAL_H264_PROFILE_CONSTRAINED_BASE; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + return HAL_H264_PROFILE_MAIN; + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + return HAL_H264_PROFILE_EXTENDED; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + return HAL_H264_PROFILE_HIGH; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: + return HAL_H264_PROFILE_HIGH10; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: + return HAL_H264_PROFILE_HIGH422; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: + return HAL_H264_PROFILE_HIGH444; + default: + return -EINVAL; + } + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + switch (value) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + return HAL_H264_LEVEL_1; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + return HAL_H264_LEVEL_1b; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + return HAL_H264_LEVEL_11; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + return HAL_H264_LEVEL_12; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + return HAL_H264_LEVEL_13; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + return HAL_H264_LEVEL_2; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + return HAL_H264_LEVEL_21; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + return HAL_H264_LEVEL_22; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + return HAL_H264_LEVEL_3; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + return HAL_H264_LEVEL_31; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + return HAL_H264_LEVEL_32; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + return HAL_H264_LEVEL_4; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + return HAL_H264_LEVEL_41; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + return HAL_H264_LEVEL_42; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + return HAL_H264_LEVEL_5; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + return HAL_H264_LEVEL_51; + default: + return -EINVAL; + } + } + + return -EINVAL; +} + +static struct v4l2_ctrl * +get_ctrl_from_cluster(int id, struct v4l2_ctrl **cluster, int ncontrols) +{ + int c; + + for (c = 0; c < ncontrols; ++c) + if (cluster[c]->id == id) + return cluster[c]; + + return NULL; +} + +/* Small helper macro for quickly getting a control and err checking */ +#define TRY_GET_CTRL(__ctrl_id) ({ \ + struct v4l2_ctrl *__temp; \ + __temp = get_ctrl_from_cluster( \ + __ctrl_id, \ + ctrl->cluster, ctrl->ncontrols); \ + if (!__temp) { \ + dprintk(VIDC_ERR, "Can't find %s (%x) in cluster\n", \ + #__ctrl_id, __ctrl_id); \ + /* Clusters are hardcoded, if we can't find */ \ + /* something then things are massively screwed up */ \ + BUG_ON(1); \ + } \ + __temp; \ + }) + +static int try_set_ctrl(struct vidc_inst *inst, struct v4l2_ctrl *ctrl) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct hal_nal_stream_format_supported stream_format; + struct hal_enable_picture enable_picture; + struct hal_enable hal_property; + struct hal_extradata_enable extra; + struct hal_buffer_alloc_mode alloc_mode; + struct hal_multi_stream multi_stream; + struct hfi_scs_threshold scs_threshold; + struct hal_mvc_buffer_layout layout; + struct v4l2_ctrl *temp_ctrl = NULL; + struct hal_profile_level profile_level; + struct hal_frame_size frame_sz; + enum hal_property prop_id = 0; + u32 property_val = 0; + void *pdata = NULL; + int ret = 0; + + ret = is_ctrl_valid_for_codec(inst, ctrl); + if (ret) + return ret; + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT: + prop_id = HAL_PARAM_NAL_STREAM_FORMAT_SELECT; + stream_format.nal_stream_format_supported = + (0x00000001 << ctrl->val); + pdata = &stream_format; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER: + prop_id = HAL_PARAM_VDEC_OUTPUT_ORDER; + property_val = ctrl->val; + pdata = &property_val; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE: + prop_id = HAL_PARAM_VDEC_PICTURE_TYPE_DECODE; + enable_picture.picture_type = ctrl->val; + pdata = &enable_picture; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO: + prop_id = HAL_PARAM_VDEC_OUTPUT2_KEEP_ASPECT_RATIO; + hal_property.enable = ctrl->val; + pdata = &hal_property; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE: + prop_id = HAL_CONFIG_VDEC_POST_LOOP_DEBLOCKER; + hal_property.enable = ctrl->val; + pdata = &hal_property; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT: + prop_id = HAL_PARAM_DIVX_FORMAT; + property_val = ctrl->val; + pdata = &property_val; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING: + prop_id = HAL_CONFIG_VDEC_MB_ERROR_MAP_REPORTING; + hal_property.enable = ctrl->val; + pdata = &hal_property; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER: + prop_id = HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER; + hal_property.enable = ctrl->val; + pdata = &hal_property; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE: + switch (ctrl->val) { + case V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE: + inst->flags &= ~VIDC_THUMBNAIL; + break; + case V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE: + inst->flags |= VIDC_THUMBNAIL; + break; + } + + prop_id = HAL_PARAM_VDEC_SYNC_FRAME_DECODE; + hal_property.enable = ctrl->val; + pdata = &hal_property; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_SECURE: + inst->flags |= VIDC_SECURE; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA: + prop_id = HAL_PARAM_INDEX_EXTRADATA; + extra.index = vidc_comm_get_hal_extradata_index(ctrl->val); + extra.enable = 1; + pdata = &extra; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT: + if (ctrl->val == V4L2_MPEG_VIDC_VIDEO_DYNAMIC) { + ret = -ENOTSUPP; + break; + } + prop_id = HAL_PARAM_BUFFER_ALLOC_MODE; + alloc_mode.mode = get_buf_type(ctrl->val); + alloc_mode.type = HAL_BUFFER_INPUT; + inst->buffer_mode[OUTPUT_PORT] = alloc_mode.mode; + pdata = &alloc_mode; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY: + prop_id = HAL_PARAM_VDEC_FRAME_ASSEMBLY; + hal_property.enable = ctrl->val; + pdata = &hal_property; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT: + prop_id = HAL_PARAM_BUFFER_ALLOC_MODE; + alloc_mode.mode = get_buf_type(ctrl->val); + + if (!(alloc_mode.mode & + inst->capability.buffer_mode[CAPTURE_PORT])) { + ret = -ENOTSUPP; + break; + } + + if (alloc_mode.mode == HAL_BUFFER_MODE_DYNAMIC && + (inst->flags & VIDC_SECURE) && + check_tz_dynamic_buffer_support(inst)) { + ret = -ENOTSUPP; + break; + } + + alloc_mode.type = HAL_BUFFER_OUTPUT; + pdata = &alloc_mode; + inst->buffer_mode[CAPTURE_PORT] = alloc_mode.mode; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE: + if (ctrl->val && !(inst->capability.pixelprocess_capabilities & + HAL_VIDEO_DECODER_MULTI_STREAM_CAPABILITY)) { + dev_err(dev, "Downscaling not supported: %#x\n", + ctrl->id); + ret = -ENOTSUPP; + break; + } + switch (ctrl->val) { + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY: + multi_stream.buffer_type = HAL_BUFFER_OUTPUT; + multi_stream.enable = true; + pdata = &multi_stream; + prop_id = HAL_PARAM_VDEC_MULTI_STREAM; + + ret = hfi_session_set_property(inst, prop_id, pdata); + if (ret) { + dev_err(dev, "enabling OUTPUT port (%d)\n", + ret); + break; + } + multi_stream.buffer_type = HAL_BUFFER_OUTPUT2; + multi_stream.enable = false; + pdata = &multi_stream; + + ret = hfi_session_set_property(inst, prop_id, pdata); + if (ret) + dev_err(dev, "disabling OUTPUT2 port (%d)\n", + ret); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY: + multi_stream.buffer_type = HAL_BUFFER_OUTPUT2; + multi_stream.enable = true; + pdata = &multi_stream; + prop_id = HAL_PARAM_VDEC_MULTI_STREAM; + + ret = hfi_session_set_property(inst, prop_id, pdata); + if (ret) { + dev_err(dev, "enabling OUTPUT2 port (%d)\n", + ret); + break; + } + multi_stream.buffer_type = HAL_BUFFER_OUTPUT; + multi_stream.enable = false; + pdata = &multi_stream; + + ret = hfi_session_set_property(inst, prop_id, pdata); + if (ret) { + dev_err(dev, "disabling OUTPUT port (%d)\n", + ret); + break; + } + + frame_sz.buffer_type = HAL_BUFFER_OUTPUT2; + frame_sz.width = inst->width; + frame_sz.height = inst->height; + pdata = &frame_sz; + prop_id = HAL_PARAM_FRAME_SIZE; + + dev_dbg(dev, "buftype: %d width: %d, height: %d\n", + frame_sz.buffer_type, frame_sz.width, + frame_sz.height); + + ret = hfi_session_set_property(inst, prop_id, pdata); + if (ret) + dev_err(dev, "setting OUTPUT2 size (%d)\n", + ret); + break; + default: + dev_err(dev, "unsupported multi stream setting\n"); + ret = -ENOTSUPP; + break; + } + break; + case V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD: + prop_id = HAL_PARAM_VDEC_SCS_THRESHOLD; + scs_threshold.threshold_value = ctrl->val; + pdata = &scs_threshold; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT: + prop_id = HAL_PARAM_MVC_BUFFER_LAYOUT; + layout.layout_type = vidc_comm_get_hal_buffer_layout(ctrl->val); + layout.bright_view_first = 0; + layout.ngap = 0; + pdata = &layout; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR: + prop_id = HAL_PARAM_VDEC_CONCEAL_COLOR; + property_val = ctrl->val; + pdata = &property_val; + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL); + prop_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.profile = vdec_v4l2_to_hal(ctrl->id, ctrl->val); + profile_level.level = + vdec_v4l2_to_hal(V4L2_CID_MPEG_VIDEO_H264_LEVEL, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE); + prop_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.level = vdec_v4l2_to_hal(ctrl->id, ctrl->val); + profile_level.profile = + vdec_v4l2_to_hal(V4L2_CID_MPEG_VIDEO_H264_PROFILE, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2: + prop_id = HAL_PARAM_VDEC_NON_SECURE_OUTPUT2; + hal_property.enable = ctrl->val; + dev_dbg(dev, "%s non_secure output2\n", + ctrl->val ? "Enabling" : "Disabling"); + pdata = &hal_property; + break; + default: + break; + } + + if (!ret && prop_id) { + dev_dbg(dev, + "Control: HAL property=%x, ctrl: id=%x, value=%x\n", + prop_id, ctrl->id, ctrl->val); + + ret = hfi_session_set_property(inst, prop_id, pdata); + } + + return ret; +} + +static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vidc_inst *inst = + container_of(ctrl->handler, struct vidc_inst, ctrl_handler); + struct device *dev = &inst->core->res.pdev->dev; + int ret = 0, c = 0; + + for (c = 0; c < ctrl->ncontrols; ++c) { + if (ctrl->cluster[c]->is_new) { + ret = try_set_ctrl(inst, ctrl->cluster[c]); + if (ret) { + dprintk(VIDC_ERR, "Failed setting %x\n", + ctrl->cluster[c]->id); + break; + } + } + } + + if (ret) + dev_err(dev, "setting control: %x (%s)", + ctrl->id, v4l2_ctrl_get_name(ctrl->id)); + + return ret; +} + +static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vidc_inst *inst = + container_of(ctrl->handler, struct vidc_inst, ctrl_handler); + struct device *dev = &inst->core->res.pdev->dev; + struct v4l2_ctrl *master = ctrl->cluster[0]; + int ret, c; + + for (c = 0; c < master->ncontrols; ++c) { + int d; + + for (d = 0; d < NUM_CTRLS; ++d) { + if (master->cluster[c]->id == inst->ctrls[d]->id && + inst->ctrls[d]->flags & V4L2_CTRL_FLAG_VOLATILE) { + ret = try_get_ctrl(inst, master->cluster[c]); + if (ret) { + dev_err(dev, "getting %x\n", + master->cluster[c]->id); + return ret; + } + break; + } + } + } + + return ret; +} + +static const struct v4l2_ctrl_ops vdec_ctrl_ops = { + .s_ctrl = vdec_op_s_ctrl, + .g_volatile_ctrl = vdec_op_g_volatile_ctrl, +}; + +static struct v4l2_ctrl **get_super_cluster(struct vidc_inst *inst, int *size) +{ + int c = 0, sz = 0; + struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) * + NUM_CTRLS, GFP_KERNEL); + + if (!size || !cluster || !inst) + return NULL; + + for (c = 0; c < NUM_CTRLS; c++) + cluster[sz++] = inst->ctrls[c]; + + *size = sz; + return cluster; +} + +int vdec_ctrl_init(struct vidc_inst *inst) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct v4l2_ctrl_config cfg; + int cluster_size = 0; + int idx = 0; + int ret = 0; + + inst->ctrls = kzalloc(sizeof(struct v4l2_ctrl *) * NUM_CTRLS, + GFP_KERNEL); + if (!inst->ctrls) + return -ENOMEM; + + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS); + if (ret) { + dev_err(dev, "control handler init (%d)\n", ret); + return ret; + } + + for (; idx < NUM_CTRLS; idx++) { + struct v4l2_ctrl *ctrl = NULL; + + if (IS_PRIV_CTRL(vdec_ctrls[idx].id)) { + memset(&cfg, 0, sizeof(cfg)); + cfg.def = vdec_ctrls[idx].default_value; + cfg.flags = 0; + cfg.id = vdec_ctrls[idx].id; + /* cfg.is_private = vdec_ctrls[idx].is_private; + * cfg.is_volatile = vdec_ctrls[idx].is_volatile; + */ + cfg.max = vdec_ctrls[idx].maximum; + cfg.min = vdec_ctrls[idx].minimum; + cfg.menu_skip_mask = vdec_ctrls[idx].menu_skip_mask; + cfg.name = vdec_ctrls[idx].name; + cfg.ops = &vdec_ctrl_ops; + cfg.step = vdec_ctrls[idx].step; + cfg.type = vdec_ctrls[idx].type; + cfg.qmenu = vdec_ctrls[idx].qmenu; + + ctrl = v4l2_ctrl_new_custom(&inst->ctrl_handler, &cfg, + NULL); + } else { + if (vdec_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) { + ctrl = v4l2_ctrl_new_std_menu( + &inst->ctrl_handler, + &vdec_ctrl_ops, + vdec_ctrls[idx].id, + vdec_ctrls[idx].maximum, + vdec_ctrls[idx].menu_skip_mask, + vdec_ctrls[idx].default_value); + } else { + ctrl = v4l2_ctrl_new_std(&inst->ctrl_handler, + &vdec_ctrl_ops, + vdec_ctrls[idx].id, + vdec_ctrls[idx].minimum, + vdec_ctrls[idx].maximum, + vdec_ctrls[idx].step, + vdec_ctrls[idx].default_value); + } + } + + if (!ctrl) { + dev_err(dev, "invalid ctrl\n"); + return -EINVAL; + } + + switch (vdec_ctrls[idx].id) { + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: + case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE: + case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + case V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD: + ctrl->flags |= vdec_ctrls[idx].flags; + break; + } + + ret = inst->ctrl_handler.error; + if (ret) { + dev_err(dev, "adding ctrl (%s) to ctrl handle (%d)\n", + vdec_ctrls[idx].name, + inst->ctrl_handler.error); + return ret; + } + + inst->ctrls[idx] = ctrl; + } + + /* Construct a super cluster of all controls */ + inst->cluster = get_super_cluster(inst, &cluster_size); + if (!inst->cluster || !cluster_size) { + dev_err(dev, "setup super cluster\n"); + return -EINVAL; + } + + v4l2_ctrl_cluster(cluster_size, inst->cluster); + + return ret; +} + +void vdec_ctrl_deinit(struct vidc_inst *inst) +{ + kfree(inst->ctrls); + kfree(inst->cluster); + v4l2_ctrl_handler_free(&inst->ctrl_handler); +} diff --git a/drivers/media/platform/msm/vidc/msm_vdec-ctrls.h b/drivers/media/platform/msm/vidc/msm_vdec-ctrls.h new file mode 100644 index 000000000000..e344f23e453c --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vdec-ctrls.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef _MSM_VDEC_CTRLS_H_ +#define _MSM_VDEC_CTRLS_H_ + +int vdec_ctrl_init(struct vidc_inst *inst); +void vdec_ctrl_deinit(struct vidc_inst *inst); + +#endif /* _MSM_VDEC_CTRLS_H_ */ diff --git a/drivers/media/platform/msm/vidc/msm_vdec.c b/drivers/media/platform/msm/vidc/msm_vdec.c new file mode 100644 index 000000000000..7ed57ea573c4 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vdec.c @@ -0,0 +1,1565 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include + +#include "msm_vdec.h" +#include "msm_vdec-ctrls.h" +#include "msm_vidc_internal.h" +#include "msm_internal-buffers.h" +#include "msm_vidc_common.h" +#include "msm_vidc_load.h" +#include "hfi/vidc_hfi_api.h" +#include "msm_vidc_debug.h" +#include "msm_hfi_interface.h" + +#define MIN_NUM_OUTPUT_BUFFERS 4 +#define MAX_NUM_OUTPUT_BUFFERS VIDEO_MAX_FRAME +#define MB_SIZE_IN_PIXEL (16 * 16) + +/* Offset base for buffers on the destination queue - used to distinguish + * between source and destination buffers when mmapping - they receive the same + * offsets but for different queues */ +#define DST_QUEUE_OFF_BASE (1 << 30) + +struct vdec_buffer { + struct vb2_buffer vb; + struct list_head list; + dma_addr_t dma_addr; + struct buffer_info bi; +}; + +#define to_vdec_buffer(buf) container_of(buf, struct vdec_buffer, vb) + +static inline struct vidc_inst *to_inst(struct file *filp, void *fh) +{ + return container_of(filp->private_data, struct vidc_inst, fh); +} + +static u32 get_framesize_nv12(int plane, u32 height, u32 width) +{ + u32 y_stride, uv_stride, y_plane; + u32 y_sclines, uv_sclines, uv_plane; + u32 size; + + y_stride = ALIGN(width, 128); + uv_stride = ALIGN(width, 128); + y_sclines = ALIGN(height, 32); + uv_sclines = ALIGN(((height + 1) >> 1), 16); + + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines + SZ_4K; + size = y_plane + uv_plane + SZ_8K; + size = ALIGN(size, SZ_4K); + + return size; +} + +static u32 get_framesize_compressed(int plane, u32 mbs_per_frame, + u32 size_per_mb) +{ + return (mbs_per_frame * size_per_mb * 3 / 2) / 2; +} + +static u32 get_framesize(struct vidc_inst *inst, const struct vidc_format *fmt, + u32 fmt_type, u32 plane) +{ + struct vidc_core_capability *cap = &inst->capability; + + if (fmt_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return fmt->get_framesize(plane, cap->mbs_per_frame.max, + MB_SIZE_IN_PIXEL); + else if (fmt_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return fmt->get_framesize(plane, inst->height, inst->width); + + return 0; +} + +static const struct vidc_format vdec_formats[] = { + { + .pixfmt = V4L2_PIX_FMT_NV12, + .num_planes = 1, + .get_framesize = get_framesize_nv12, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_NV21, + .num_planes = 1, + .get_framesize = get_framesize_nv12, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_MPEG4, + .num_planes = 1, + .get_framesize = get_framesize_compressed, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_MPEG2, + .num_planes = 1, + .get_framesize = get_framesize_compressed, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_H263, + .num_planes = 1, + .get_framesize = get_framesize_compressed, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_G, + .num_planes = 1, + .get_framesize = get_framesize_compressed, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_VC1_ANNEX_L, + .num_planes = 1, + .get_framesize = get_framesize_compressed, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_H264, + .num_planes = 1, + .get_framesize = get_framesize_compressed, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_VP8, + .num_planes = 1, + .get_framesize = get_framesize_compressed, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, +}; + +static const struct vidc_format *find_format(u32 pixfmt, u32 type) +{ + const struct vidc_format *fmt = vdec_formats; + unsigned int size = ARRAY_SIZE(vdec_formats); + unsigned int i; + + for (i = 0; i < size; i++) { + if (fmt[i].pixfmt == pixfmt) + break; + } + + if (i == size || fmt[i].type != type) + return NULL; + + return &fmt[i]; +} + + +static const struct vidc_format *find_format_by_index(int index, u32 type) +{ + const struct vidc_format *fmt = vdec_formats; + unsigned int size = ARRAY_SIZE(vdec_formats); + int i, k = 0; + + if (index < 0 || index > size) + return NULL; + + for (i = 0; i < size; i++) { + if (fmt[i].type != type) + continue; + if (k == index) + break; + k++; + } + + if (i == size) + return NULL; + + return &fmt[i]; +} + +static struct vb2_queue * +vdec_to_vb2q(struct vidc_inst *inst, enum v4l2_buf_type type) +{ + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return &inst->bufq_cap; + else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return &inst->bufq_out; + + return NULL; +} + +static int vdec_try_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + const struct vidc_format *fmt; + struct vidc_core_capability *cap = &inst->capability; + struct hfi_device *hdev = inst->core->hfidev; + int ret, i; + + fmt = find_format(pixmp->pixelformat, f->type); + if (!fmt) + return -EINVAL; + + ret = hfi_session_init(inst, inst->fmt_out->pixfmt); + if (ret) + return ret; + + pixmp->width = clamp(pixmp->width, cap->width.min, cap->width.max); + pixmp->height = clamp(pixmp->height, cap->height.min, cap->height.max); + pixmp->field = V4L2_FIELD_NONE; + pixmp->colorspace = V4L2_COLORSPACE_DEFAULT; + pixmp->num_planes = fmt->num_planes; + pixmp->flags = 0; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + enum color_fmts cfmt; + u32 *bytesperline = &pixmp->plane_fmt[0].bytesperline; + + switch (fmt->pixfmt) { + case V4L2_PIX_FMT_NV12: + cfmt = COLOR_FMT_NV12; + case V4L2_PIX_FMT_NV21: + cfmt = COLOR_FMT_NV21; + break; + default: + return -EINVAL; + } + + call_hfi_op(hdev, get_stride_scanline, cfmt, pixmp->width, + pixmp->height, bytesperline, NULL); + + for (i = 0; i < pixmp->num_planes; i++) + pixmp->plane_fmt[i].sizeimage = + get_framesize_nv12(i, pixmp->height, + pixmp->width); + } else { + pixmp->plane_fmt[0].sizeimage = + get_framesize(inst, fmt, f->type, 0); + pixmp->plane_fmt[0].bytesperline = 0; + } + + ret = hfi_session_deinit(inst); + + inst->session = NULL; + vidc_inst_set_state(inst, INST_UNINIT); + + if (ret) + return ret; + + return 0; +} + +static int vdec_g_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct device *dev = &inst->core->res.pdev->dev; + struct hfi_device *hdev = inst->core->hfidev; + const struct vidc_format *fmt; + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + struct hal_buffer_requirements bufreq = {0}; + int ret, i; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + fmt = inst->fmt_cap; + else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + fmt = inst->fmt_out; + else + return -EINVAL; + + pixmp->pixelformat = fmt->pixfmt; + pixmp->num_planes = fmt->num_planes; + + if (inst->in_reconfig) { + if (vidc_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_PRIMARY) { + inst->height = inst->reconfig_height; + inst->width = inst->reconfig_width; + } + + ret = vidc_check_session_supported(inst); + if (ret) { + dev_err(dev, "%s: unsupported session\n", __func__); + goto exit; + } + } + + pixmp->width = inst->width; + pixmp->height = inst->height; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + for (i = 0; i < fmt->num_planes; ++i) { + pixmp->plane_fmt[i].sizeimage = + get_framesize(inst, fmt, f->type, i); + pixmp->plane_fmt[i].bytesperline = 0; + } + } else { + enum color_fmts cfmt; + u32 bytesperline = 0; + + switch (fmt->pixfmt) { + case V4L2_PIX_FMT_NV12: + cfmt = COLOR_FMT_NV12; + case V4L2_PIX_FMT_NV21: + cfmt = COLOR_FMT_NV21; + break; + default: + return -EINVAL; + } + + call_hfi_op(hdev, get_stride_scanline, cfmt, inst->width, + inst->height, &bytesperline, NULL); + + ret = vidc_comm_bufrequirements(inst, HAL_BUFFER_OUTPUT, + &bufreq); + if (ret) + return ret; + + dev_dbg(dev, "buf requirements output: size:%d\n", bufreq.size); + + pixmp->plane_fmt[0].sizeimage = bufreq.size; + pixmp->plane_fmt[0].bytesperline = bytesperline; + } + +exit: + return ret; +} + +static int vdec_set_buffer_size(struct vidc_inst *inst, u32 buffer_size, + enum hal_buffer buffer_type) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct hal_buffer_size_actual buf_size_actual; + int ret; + + dev_dbg(dev, "set actual buffer_size: %d for buffer type %d to fw\n", + buffer_size, buffer_type); + + buf_size_actual.type = buffer_type; + buf_size_actual.size = buffer_size; + + ret = hfi_session_set_property(inst, HAL_PARAM_BUFFER_SIZE_ACTUAL, + &buf_size_actual); + if (ret) { + dev_err(dev, "%s: failed to set actual buffer size %u\n", + __func__, buffer_size); + return ret; + } + + return 0; +} + +static int vdec_update_out_buf_size(struct vidc_inst *inst, + struct v4l2_format *f, int nplanes) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct v4l2_plane_pix_format *fmt = f->fmt.pix_mp.plane_fmt; + struct hal_buffer_requirements *bufreq; + int ret, i; + + /* + * Compare set buffer size and update to firmware if it's bigger + * then firmware returned buffer size. + */ + for (i = 0; i < nplanes; ++i) { + enum hal_buffer type = vidc_comm_get_hal_output_buffer(inst); + + if (EXTRADATA_IDX(nplanes) && i == EXTRADATA_IDX(nplanes)) + type = HAL_BUFFER_EXTRADATA_OUTPUT; + + bufreq = get_buff_req_buffer(inst, type); + if (!bufreq) + return -EINVAL; + + if (fmt[i].sizeimage > bufreq->size) { + ret = vdec_set_buffer_size(inst, fmt[i].sizeimage, + type); + if (ret) + return ret; + } + } + + /* Query buffer requirements from firmware */ + ret = vidc_comm_get_bufreqs(inst); + if (ret) { + dev_err(dev, "Failed to get buf req, %d\n", ret); + return ret; + } + + /* Read back updated firmware size */ + for (i = 0; i < nplanes; ++i) { + enum hal_buffer type = vidc_comm_get_hal_output_buffer(inst); + + if (EXTRADATA_IDX(nplanes) && i == EXTRADATA_IDX(nplanes)) + type = HAL_BUFFER_EXTRADATA_OUTPUT; + + bufreq = get_buff_req_buffer(inst, type); + fmt[i].sizeimage = bufreq ? bufreq->size : 0; + + dev_dbg(dev, "updated buffer size for plane[%d] = %d\n", + i, fmt[i].sizeimage); + } + + return 0; +} + +static int vdec_set_properties(struct vidc_inst *inst) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct hfi_device *hdev = inst->core->hfidev; + enum hal_default_properties defaults; + int ret; + + defaults = call_hfi_op(hdev, get_default_properties, + hdev->hfi_device_data); + if (defaults < 0) + return defaults; + + if (defaults & HAL_VIDEO_DYNAMIC_BUF_MODE) { + dev_dbg(dev, "Enable dynamic buffer mode\n"); + + inst->buffer_mode[CAPTURE_PORT] = HAL_VIDEO_DYNAMIC_BUF_MODE; + } + + if (defaults & HAL_VIDEO_CONTINUE_DATA_TRANSFER) { + struct hal_enable prop = { 1 }; + u32 prop_id = HAL_PARAM_VDEC_CONTINUE_DATA_TRANSFER; + + dev_dbg(dev, "Enable continue data transfer\n"); + + ret = hfi_session_set_property(inst, prop_id, &prop); + if (ret) + return ret; + } + + return 0; +} + +static int vdec_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct device *dev = &inst->core->res.pdev->dev; + const struct vidc_format *fmt; + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + u32 pixfmt = pixmp->pixelformat; + int ret, i; + + fmt = find_format(pixfmt, f->type); + if (!fmt) + return -EINVAL; + + ret = vidc_comm_set_color_format(inst, HAL_BUFFER_OUTPUT, pixfmt); + if (ret) + return ret; + + ret = vidc_comm_get_bufreqs(inst); + if (ret) { + for (i = 0; i < fmt->num_planes; ++i) + pixmp->plane_fmt[i].sizeimage = + get_framesize(inst, fmt, f->type, i); + } else { + ret = vdec_update_out_buf_size(inst, f, fmt->num_planes); + if (ret) { + dev_err(dev, "%s: failed to update buffer size: %d\n", + __func__, ret); + return ret; + } + } + + inst->width = pixmp->width; + inst->height = pixmp->height; + inst->fmt_cap = fmt; + + pixmp->num_planes = fmt->num_planes; + + return 0; +} + +static int vdec_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct device *dev = &inst->core->res.pdev->dev; + struct hal_frame_size fs; + const struct vidc_format *fmt; + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + u32 pixfmt = pixmp->pixelformat; + struct vidc_core_capability *cap = &inst->capability; + int ret, i; + + fmt = find_format(pixfmt, f->type); + if (!fmt) + return -EINVAL; + + if (!(vidc_comm_hal_codec_type(fmt->pixfmt) & inst->core->dec_codecs)) { + dev_err(dev, "codec (%x) is not supported\n", fmt->pixfmt); + return -ENOTSUPP; + } + + inst->width = pixmp->width; + inst->height = pixmp->height; + inst->fmt_out = fmt; + + ret = hfi_session_init(inst, fmt->pixfmt); + if (ret) { + dev_err(dev, "%s: session init failed (%d)\n", __func__, ret); + return ret; + } + + ret = vidc_check_session_supported(inst); + if (ret) { + dev_err(dev, "%s: session not supported\n", __func__); + goto err; + } + + fs.buffer_type = HAL_BUFFER_INPUT; + fs.width = inst->width; + fs.height = inst->height; + + ret = hfi_session_set_property(inst, HAL_PARAM_FRAME_SIZE, &fs); + if (ret) + goto err; + + for (i = 0; i < fmt->num_planes; i++) { + pixmp->plane_fmt[i].sizeimage = + fmt->get_framesize(i, cap->mbs_per_frame.max, + MB_SIZE_IN_PIXEL); + pixmp->plane_fmt[i].bytesperline = 0; + } + + pixmp->num_planes = fmt->num_planes; + + return 0; + +err: + hfi_session_deinit(inst); + inst->session = NULL; + vidc_inst_set_state(inst, INST_UNINIT); + + return ret; +} + +static int +vdec_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = vdec_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + return vb2_reqbufs(queue, b); +} + +static int +vdec_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + strlcpy(cap->driver, VIDC_DRV_NAME, sizeof(cap->driver)); + strlcpy(cap->card, "video decoder", sizeof(cap->card)); + strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); + cap->version = VIDC_VERSION; + + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_STREAMING | + V4L2_CAP_DEVICE_CAPS; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_STREAMING; + + return 0; +} + +static int vdec_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + const struct vidc_format *fmt; + + fmt = find_format_by_index(f->index, f->type); + + memset(f->reserved, 0 , sizeof(f->reserved)); + + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->pixfmt; + + return 0; +} + +static int vdec_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + int ret = 0, i; + + if (b->memory != V4L2_MEMORY_MMAP) { + dprintk(VIDC_ERR, "Only MMAP bufs can be queried\n"); + return -EINVAL; + } + + queue = vdec_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + ret = vb2_querybuf(queue, b); + if (ret) + return ret; + + if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + for (i = 0; i < b->length; i++) + b->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE; + } + + return 0; +} + +static int vdec_prepare_buf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = vdec_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + return vb2_prepare_buf(queue, b); +} + +static int vdec_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + unsigned int state; + + queue = vdec_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + mutex_lock(&inst->lock); + state = inst->state; + mutex_unlock(&inst->lock); + + /* + * it is possible userspace to continue to queuing buffres even + * while we are in streamoff. Not sure is this a problem in + * videobuf2 core, still. Fix it here for now. + */ + if (state >= INST_STOP) + return -EINVAL; + + return vb2_qbuf(queue, b); +} + +static int +vdec_exportbuf(struct file *file, void *fh, struct v4l2_exportbuffer *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = vdec_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + return vb2_expbuf(queue, b); +} + +static int vdec_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = vdec_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + return vb2_dqbuf(queue, b, file->f_flags & O_NONBLOCK); +} + +static int vdec_streamon(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = vdec_to_vb2q(inst, type); + if (!queue) + return -EINVAL; + + return vb2_streamon(queue, type); +} + +static int vdec_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = vdec_to_vb2q(inst, type); + if (!queue) + return -EINVAL; + + return vb2_streamoff(queue, type); +} + +static int vdec_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct device *dev = &inst->core->res.pdev->dev; + struct v4l2_fract *timeperframe = &a->parm.output.timeperframe; + u64 us_per_frame, fps; + + if (!timeperframe->denominator || + a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; + do_div(us_per_frame, timeperframe->denominator); + + if (!us_per_frame) + return -EINVAL; + + fps = (u64)USEC_PER_SEC; + do_div(fps, us_per_frame); + + dev_dbg(dev, "%s: num:%d, denom:%d\n", __func__, + timeperframe->numerator, timeperframe->denominator); + + inst->fps = fps; + inst->timeperframe = *timeperframe; + + return 0; +} + +static int vdec_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct vidc_inst *inst = to_inst(file, fh); + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.capture.timeperframe = inst->timeperframe; + + return 0; +} + +static int vdec_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vidc_core_capability *capability = &inst->capability; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = capability->width.min; + fsize->stepwise.max_width = capability->width.max; + fsize->stepwise.step_width = capability->width.step_size; + fsize->stepwise.min_height = capability->height.min; + fsize->stepwise.max_height = capability->height.max; + fsize->stepwise.step_height = capability->height.step_size; + + return 0; +} + +static int vdec_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + default: + return -EINVAL; + } +} + +static int vdec_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dec) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vidc_core *core = inst->core; + int ret = 0; + + return 0; + + switch (dec->cmd) { + case V4L2_DEC_QCOM_CMD_FLUSH: + if (core->state != CORE_INVALID && + inst->state == INST_INVALID) { + ret = vidc_comm_kill_session(inst); + if (ret) + dprintk(VIDC_ERR, "session kill (%d)\n", ret); + } + + ret = vidc_comm_session_flush(inst, dec->flags); + if (ret) + dprintk(VIDC_ERR, "Failed to flush buffers: %d\n", ret); + break; + case V4L2_DEC_CMD_STOP: + if (core->state != CORE_INVALID && + inst->state == INST_INVALID) { + ret = vidc_comm_kill_session(inst); + if (ret) + dprintk(VIDC_ERR, "session kill (%d)\n", ret); + } + + ret = release_scratch_buffers(inst, false); + if (ret) + dprintk(VIDC_ERR, + "release scratch buffers (%d)\n", ret); + + ret = release_persist_buffers(inst); + if (ret) + dprintk(VIDC_ERR, + "release persist buffers (%d)\n", ret); + + if (inst->state == INST_INVALID || + core->state == CORE_INVALID) { + dprintk(VIDC_ERR, + "core and/or instance are in invalid state\n"); + vidc_queue_v4l2_event(inst, + V4L2_EVENT_MSM_VIDC_CLOSE_DONE); + goto exit; + } + + ret = hfi_session_deinit(inst); + + inst->session = NULL; + vidc_inst_set_state(inst, INST_UNINIT); + + /* Clients rely on this event for joining poll thread. + * This event should be returned even if firmware has + * failed to respond + */ + vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_CLOSE_DONE); + break; + default: + return -ENOTSUPP; + } + +exit: + return ret; +} + +static const struct v4l2_ioctl_ops vdec_ioctl_ops = { + .vidioc_querycap = vdec_querycap, + .vidioc_enum_fmt_vid_cap_mplane = vdec_enum_fmt, + .vidioc_enum_fmt_vid_out_mplane = vdec_enum_fmt, + .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt_cap, + .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt_out, + .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt, + .vidioc_g_fmt_vid_out_mplane = vdec_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = vdec_try_fmt, + .vidioc_try_fmt_vid_out_mplane = vdec_try_fmt, + .vidioc_reqbufs = vdec_reqbufs, + .vidioc_querybuf = vdec_querybuf, + .vidioc_prepare_buf = vdec_prepare_buf, + .vidioc_qbuf = vdec_qbuf, + .vidioc_expbuf = vdec_exportbuf, + .vidioc_dqbuf = vdec_dqbuf, + .vidioc_streamon = vdec_streamon, + .vidioc_streamoff = vdec_streamoff, + .vidioc_s_parm = vdec_s_parm, + .vidioc_g_parm = vdec_g_parm, + .vidioc_enum_framesizes = vdec_enum_framesizes, + .vidioc_subscribe_event = vdec_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_decoder_cmd = vdec_cmd, +}; + +static int vdec_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + void *alloc_ctxs[]) +{ + struct vidc_inst *inst = vb2_get_drv_priv(q); + struct device *dev = &inst->core->res.pdev->dev; + struct hal_buffer_requirements bufreq; + struct hal_buffer_count_actual buf_count; + enum hal_property prop_id; + int i, ret = 0; + + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + *num_planes = inst->fmt_out->num_planes; + + *num_buffers = clamp_val(*num_buffers, MIN_NUM_OUTPUT_BUFFERS, + MAX_NUM_OUTPUT_BUFFERS); + + for (i = 0; i < *num_planes; i++) { + sizes[i] = + get_framesize(inst, inst->fmt_out, q->type, i); + alloc_ctxs[i] = inst->vb2_ctx_out; + } + + prop_id = HAL_PARAM_BUFFER_COUNT_ACTUAL; + buf_count.type = HAL_BUFFER_INPUT; + buf_count.count_actual = *num_buffers; + + ret = hfi_session_set_property(inst, prop_id, &buf_count); + if (ret) { + dev_err(dev, "set buffer count %d failed (%d)\n", + buf_count.count_actual, ret); + return ret; + } + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + *num_planes = inst->fmt_cap->num_planes; + + ret = vidc_comm_bufrequirements(inst, HAL_BUFFER_OUTPUT, + &bufreq); + if (ret) + return ret; + + *num_buffers = max(*num_buffers, bufreq.count_min); + + if (*num_buffers != bufreq.count_actual) { + struct hal_buffer_display_hold_count_actual display; + + prop_id = HAL_PARAM_BUFFER_COUNT_ACTUAL; + buf_count.type = HAL_BUFFER_OUTPUT; + buf_count.count_actual = *num_buffers; + + ret = hfi_session_set_property(inst, prop_id, + &buf_count); + if (ret) { + dev_err(dev, "set buf count failed (%d)", ret); + break; + } + + prop_id = HAL_PARAM_BUFFER_DISPLAY_HOLD_COUNT_ACTUAL; + display.buffer_type = HAL_BUFFER_OUTPUT; + display.hold_count = + *num_buffers - bufreq.count_actual; + + ret = hfi_session_set_property(inst, prop_id, &display); + if (ret) { + dev_err(dev, "display hold count failed (%d)", + ret); + break; + } + } + + sizes[0] = bufreq.size; + alloc_ctxs[0] = inst->vb2_ctx_cap; + + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int vdec_buf_init(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb->vb2_queue; + struct vidc_inst *inst = vb2_get_drv_priv(q); + struct device *dev = &inst->core->res.pdev->dev; + struct hfi_device *hdev = inst->core->hfidev; + struct vdec_buffer *buf = to_vdec_buffer(vb); + struct vidc_buffer_addr_info *bai; + struct buffer_info *bi; + int ret; + + bi = &buf->bi; + bai = &bi->bai; + + memset(bai, 0, sizeof(*bai)); + + if (q->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return 0; + + bai->buffer_size = vb2_plane_size(vb, 0); + bai->buffer_type = vidc_comm_get_hal_output_buffer(inst); + bai->num_buffers = 1; + bai->device_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + + ret = call_hfi_op(hdev, session_set_buffers, inst->session, bai); + if (ret) { + dev_err(dev, "%s: session: set buffer failed\n", __func__); + return ret; + } + + mutex_lock(&inst->registeredbufs.lock); + list_add_tail(&bi->list, &inst->registeredbufs.list); + mutex_unlock(&inst->registeredbufs.lock); + + return 0; +} + +static int vdec_buf_prepare(struct vb2_buffer *vb) +{ + struct vdec_buffer *buf = to_vdec_buffer(vb); + + buf->dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + + return 0; +} + +static void __fill_flags(struct vidc_frame_data *frame_data, __u32 vb_flags) +{ + u32 *flags = &frame_data->flags; + + if (vb_flags & V4L2_QCOM_BUF_FLAG_EOS) + *flags = HAL_BUFFERFLAG_EOS; + + if (vb_flags & V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP) + *flags |= HAL_BUFFERFLAG_YUV_601_709_CSC_CLAMP; + + if (vb_flags & V4L2_QCOM_BUF_FLAG_CODECCONFIG) + *flags |= HAL_BUFFERFLAG_CODECCONFIG; + + if (vb_flags & V4L2_QCOM_BUF_FLAG_DECODEONLY) + *flags |= HAL_BUFFERFLAG_DECODEONLY; + + if (vb_flags & V4L2_QCOM_BUF_TS_DISCONTINUITY) + *flags |= HAL_BUFFERFLAG_TS_DISCONTINUITY; + + if (vb_flags & V4L2_QCOM_BUF_TS_ERROR) + *flags |= HAL_BUFFERFLAG_TS_ERROR; + + if (vb_flags & V4L2_QCOM_BUF_TIMESTAMP_INVALID) + frame_data->timestamp = LLONG_MAX; +} + +static int vdec_set_session_buf(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb->vb2_queue; + struct vidc_inst *inst = vb2_get_drv_priv(q); + struct vidc_core *core = inst->core; + struct device *dev = &core->res.pdev->dev; + struct hfi_device *hdev = core->hfidev; + struct vdec_buffer *buf = to_vdec_buffer(vb); + struct vidc_frame_data fdata; + s64 time_usec; + int ret; + + if (inst->state == INST_INVALID || core->state == CORE_INVALID) { + dev_err(dev, "core id:%d is in bad state\n", core->id); + return -EINVAL; + } + + time_usec = timeval_to_ns(&vb->v4l2_buf.timestamp); + do_div(time_usec, NSEC_PER_USEC); + + memset(&fdata, 0 , sizeof(fdata)); + + fdata.alloc_len = vb2_plane_size(vb, 0); + fdata.device_addr = buf->dma_addr; + fdata.timestamp = time_usec; + fdata.flags = 0; + fdata.clnt_data = buf->dma_addr; + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + fdata.buffer_type = HAL_BUFFER_INPUT; + fdata.filled_len = vb2_get_plane_payload(vb, 0); + fdata.offset = vb->v4l2_planes[0].data_offset; + + __fill_flags(&fdata, vb->v4l2_buf.flags); + + ret = call_hfi_op(hdev, session_etb, inst->session, &fdata); + } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fdata.buffer_type = vidc_comm_get_hal_output_buffer(inst); + fdata.filled_len = 0; + fdata.offset = 0; + + ret = call_hfi_op(hdev, session_ftb, inst->session, &fdata); + } else { + ret = -EINVAL; + } + + if (ret) { + dev_err(dev, "failed to set session buffer\n"); + return ret; + } + + return 0; +} + +static int vdec_rel_session_bufs(struct vidc_inst *inst) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct vidc_buffer_addr_info *bai; + struct buffer_info *bi, *tmp; + int ret = 0; + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry_safe(bi, tmp, &inst->registeredbufs.list, list) { + list_del(&bi->list); + bai = &bi->bai; + bai->response_required = 1; + ret = hfi_session_release_buffers(inst, bai); + if (ret) { + dev_err(dev, "%s: session release buffers failed\n", + __func__); + break; + } + } + mutex_unlock(&inst->registeredbufs.lock); + + return ret; +} + +static int start_streaming(struct vidc_inst *inst) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct list_head *ptr, *next; + struct vdec_buffer *buf; + int ret; + + inst->in_reconfig = false; + + ret = vdec_set_properties(inst); + if (ret) + return ret; + + ret = set_scratch_buffers(inst); + if (ret) { + dev_err(dev, "failed to set scratch buffers: %d\n", ret); + return ret; + } + + ret = set_persist_buffers(inst); + if (ret) { + dev_err(dev, "Failed to set persist buffers: %d\n", ret); + return ret; + } + + msm_comm_scale_clocks(inst->core); + + ret = hfi_session_load_res(inst); + if (ret) + return ret; + + ret = hfi_session_start(inst); + if (ret) + return ret; + + mutex_lock(&inst->bufqueue_lock); + list_for_each_safe(ptr, next, &inst->bufqueue) { + buf = list_entry(ptr, struct vdec_buffer, list); + + ret = vdec_set_session_buf(&buf->vb); + if (ret) + break; + } + mutex_unlock(&inst->bufqueue_lock); + + return ret; +} + +static int vdec_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct vidc_inst *inst = vb2_get_drv_priv(q); + struct device *dev = &inst->core->res.pdev->dev; + struct vb2_queue *queue; + + dev_dbg(dev, "%s: type: %d, count: %d\n", __func__, q->type, count); + + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + queue = &inst->bufq_cap; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + queue = &inst->bufq_out; + break; + default: + return -EINVAL; + } + + if (vb2_is_streaming(queue)) + return start_streaming(inst); + + return 0; +} + +static int stop_streaming(struct vidc_inst *inst) +{ + struct vidc_core *core = inst->core; + struct device *dev = &core->res.pdev->dev; + int ret, streamoff; + + mutex_lock(&inst->lock); + streamoff = inst->streamoff; + mutex_unlock(&inst->lock); + + if (streamoff) + return 0; + + ret = hfi_session_stop(inst); + if (ret) { + dev_err(dev, "session: stop failed\n"); + goto abort; + } + + ret = hfi_session_release_res(inst); + if (ret) { + dev_err(dev, "session: release resources failed\n"); + goto abort; + } + + ret = vdec_rel_session_bufs(inst); + if (ret) { + dev_err(dev, "failed to release capture buffers: %d\n", ret); + goto abort; + } + + ret = release_scratch_buffers(inst, false); + if (ret) { + dev_err(dev, "failed to release scratch buffers: %d\n", ret); + goto abort; + } + + ret = release_persist_buffers(inst); + if (ret) { + dev_err(dev, "failed to release persist buffers: %d\n", ret); + goto abort; + } + + if (inst->state == INST_INVALID || core->state == CORE_INVALID) { + dev_err(dev, "core id:%d is in invalid state\n", core->id); + ret = -EINVAL; + goto abort; + } + + ret = hfi_session_deinit(inst); + + mutex_lock(&inst->lock); + inst->streamoff = 1; + mutex_unlock(&inst->lock); + +abort: + if (ret) + hfi_session_abort(inst); + + inst->session = NULL; + vidc_inst_set_state(inst, INST_UNINIT); + + return ret; +} + +static void vdec_stop_streaming(struct vb2_queue *q) +{ + struct vidc_inst *inst = vb2_get_drv_priv(q); + struct device *dev = &inst->core->res.pdev->dev; + int ret; + + dev_dbg(dev, "%s: type: %d\n", __func__, q->type); + + ret = stop_streaming(inst); + + msm_comm_scale_clocks(inst->core); + + if (ret) + dev_err(dev, "stop streaming failed type: %d, ret: %d\n", + q->type, ret); +} + +static void vdec_buf_queue(struct vb2_buffer *vb) +{ + struct vidc_inst *inst = vb2_get_drv_priv(vb->vb2_queue); + struct vidc_core *core = inst->core; + struct device *dev = &core->res.pdev->dev; + struct vdec_buffer *buf = to_vdec_buffer(vb); + int ret; + + if (inst->state == INST_INVALID || core->state == CORE_INVALID) { + dev_err(dev, "core or instance are in invalid state\n"); + return; + } + + dev_dbg(dev, "%s: vb:%p, type:%d, addr:%pa\n", __func__, vb, + vb->vb2_queue->type, &buf->dma_addr); + + mutex_lock(&inst->bufqueue_lock); + list_add_tail(&buf->list, &inst->bufqueue); + mutex_unlock(&inst->bufqueue_lock); + + if (!vb2_is_streaming(&inst->bufq_cap) || + !vb2_is_streaming(&inst->bufq_out)) + return; + + ret = vdec_set_session_buf(vb); + if (ret) { + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + dev_err(dev, "cannot set session buffer\n"); + } +} + +static const struct vb2_ops vdec_vb2_ops = { + .queue_setup = vdec_queue_setup, + .buf_init = vdec_buf_init, + .buf_prepare = vdec_buf_prepare, + .start_streaming = vdec_start_streaming, + .stop_streaming = vdec_stop_streaming, + .buf_queue = vdec_buf_queue, +}; + +static struct vb2_buffer * +vdec_get_vb2buffer(struct vidc_inst *inst, dma_addr_t addr) +{ + struct vdec_buffer *buf; + struct vb2_buffer *vb = NULL; + + mutex_lock(&inst->bufqueue_lock); + + list_for_each_entry(buf, &inst->bufqueue, list) { + if (buf->dma_addr == addr) { + vb = &buf->vb; + break; + } + } + + if (vb) + list_del(&buf->list); + + mutex_unlock(&inst->bufqueue_lock); + + return vb; +} + +static int vdec_empty_buf_done(struct vidc_inst *inst, u32 addr, + u32 bytesused, u32 data_offset, u32 flags) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct vb2_buffer *vb; + + vb = vdec_get_vb2buffer(inst, addr); + if (!vb) + return -EFAULT; + + vb->v4l2_planes[0].bytesused = bytesused; + vb->v4l2_planes[0].data_offset = data_offset; + vb->v4l2_buf.flags = flags; + + if (vb->v4l2_planes[0].data_offset > vb->v4l2_planes[0].length) + dev_dbg(dev, "data_offset overflow length\n"); + + if (vb->v4l2_planes[0].bytesused > vb->v4l2_planes[0].length) + dev_dbg(dev, "bytesused overflow length\n"); + + if (flags & V4L2_QCOM_BUF_INPUT_UNSUPPORTED) + dev_dbg(dev, "unsupported input stream\n"); + + if (flags & V4L2_QCOM_BUF_DATA_CORRUPT) + dev_dbg(dev, "corrupted input stream\n"); + + if (flags & V4L2_MSM_VIDC_BUF_START_CODE_NOT_FOUND) + dev_dbg(dev, "start code not found\n"); + + inst->count.ebd++; + + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + + return 0; +} + +static int vdec_fill_buf_done(struct vidc_inst *inst, u32 addr, + u32 bytesused, u32 data_offset, u32 flags, + struct timeval *timestamp) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct vb2_buffer *vb; + + vb = vdec_get_vb2buffer(inst, addr); + if (!vb) + return -EFAULT; + + vb->v4l2_planes[0].bytesused = bytesused; + vb->v4l2_planes[0].data_offset = data_offset; + vb->v4l2_buf.flags = flags; + vb->v4l2_buf.timestamp = *timestamp; + + if (vb->v4l2_planes[0].data_offset > vb->v4l2_planes[0].length) + dev_warn(dev, "overflow data_offset:%d, length:%d\n", + vb->v4l2_planes[0].data_offset, + vb->v4l2_planes[0].length); + + if (vb->v4l2_planes[0].bytesused > vb->v4l2_planes[0].length) + dev_warn(dev, "overflow bytesused:%d, length:%d\n", + vb->v4l2_planes[0].bytesused, + vb->v4l2_planes[0].length); + + inst->count.fbd++; + + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + + return 0; +} + +static int vdec_event_notify(struct vidc_inst *inst, u32 event, + struct vidc_cb_event *data) +{ + struct device *dev = &inst->core->res.pdev->dev; + + switch (event) { + case SESSION_ERROR: + /* the instance lock is already taken just change the state */ + inst->state = INST_INVALID; + dev_warn(dev, "event session error\n"); + break; + case SYS_EVENT_CHANGE: + switch (data->hal_event_type) { + case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES: + dev_dbg(dev, "event sufficient resources\n"); + break; + case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES: + dev_dbg(dev, "event not sufficient resources\n"); + inst->reconfig_height = data->height; + inst->reconfig_width = data->width; + inst->in_reconfig = true; + break; + default: + break; + } + break; + default: + break; + } + + return 0; +} + +static void vdec_inst_init(struct vidc_inst *inst) +{ + inst->fmt_out = &vdec_formats[2]; + inst->fmt_cap = &vdec_formats[0]; + inst->height = DEFAULT_HEIGHT; + inst->width = DEFAULT_WIDTH; + inst->capability.height.min = MIN_SUPPORTED_HEIGHT; + inst->capability.height.max = DEFAULT_HEIGHT; + inst->capability.width.min = MIN_SUPPORTED_WIDTH; + inst->capability.width.max = DEFAULT_WIDTH; + inst->capability.buffer_mode[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC; + inst->capability.buffer_mode[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC; + inst->capability.secure_output2_threshold.min = 0; + inst->capability.secure_output2_threshold.max = 0; + inst->buffer_mode[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC; + inst->buffer_mode[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC; + inst->fps = 30; +} + +static void vdec_release_video_device(struct video_device *pvdev) +{ +} + +extern const struct v4l2_file_operations vidc_fops; + +int vdec_init(struct vidc_core *core, struct video_device *dec) +{ + int ret; + + /* setup the decoder device */ + dec->release = vdec_release_video_device; + dec->fops = &vidc_fops; + dec->ioctl_ops = &vdec_ioctl_ops; + dec->vfl_dir = VFL_DIR_M2M; + dec->v4l2_dev = &core->v4l2_dev; + + ret = video_register_device(dec, VFL_TYPE_GRABBER, 32); + if (ret) { + dprintk(VIDC_ERR, "Failed to register video decoder device"); + return ret; + } + + video_set_drvdata(dec, core); + + return 0; +} + +void vdec_deinit(struct vidc_core *core, struct video_device *dec) +{ + video_unregister_device(dec); +} + +int vdec_open(struct vidc_inst *inst) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct vb2_queue *q; + struct device *iommu_dev; + int ret; + + /* TODO: use iommu dt bindings when they are exist */ + iommu_dev = msm_iommu_get_ctx("venus_ns"); + if (IS_ERR(iommu_dev)) { + dev_err(dev, "cannot find iommu nonsecure ctx\n"); + return PTR_ERR(iommu_dev); + } + + vdec_inst_init(inst); + + ret = vdec_ctrl_init(inst); + if (ret) + return ret; + + inst->vb2_ctx_cap = vb2_dma_contig_init_ctx(iommu_dev); + if (IS_ERR(inst->vb2_ctx_cap)) + return PTR_ERR(inst->vb2_ctx_cap); + + inst->vb2_ctx_out = vb2_dma_contig_init_ctx(iommu_dev); + if (IS_ERR(inst->vb2_ctx_out)) { + ret = PTR_ERR(inst->vb2_ctx_out); + goto err_cleanup_cap; + } + + q = &inst->bufq_cap; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + q->ops = &vdec_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->drv_priv = inst; + q->buf_struct_size = sizeof(struct vdec_buffer); + q->allow_zero_bytesused = 1; + ret = vb2_queue_init(q); + if (ret) + goto err_cleanup_out; + + q = &inst->bufq_out; + q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + q->io_modes = VB2_MMAP; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + q->ops = &vdec_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->drv_priv = inst; + q->buf_struct_size = sizeof(struct vdec_buffer); + q->allow_zero_bytesused = 1; + ret = vb2_queue_init(q); + if (ret) + goto err_cap_queue_release; + + inst->empty_buf_done = vdec_empty_buf_done; + inst->fill_buf_done = vdec_fill_buf_done; + inst->event_notify = vdec_event_notify; + + return 0; + +err_cap_queue_release: + vb2_queue_release(&inst->bufq_cap); +err_cleanup_out: + vb2_dma_contig_cleanup_ctx(inst->vb2_ctx_out); +err_cleanup_cap: + vb2_dma_contig_cleanup_ctx(inst->vb2_ctx_cap); + return ret; +} + +void vdec_close(struct vidc_inst *inst) +{ + vb2_queue_release(&inst->bufq_out); + vb2_queue_release(&inst->bufq_cap); + + vb2_dma_contig_cleanup_ctx(inst->vb2_ctx_out); + vb2_dma_contig_cleanup_ctx(inst->vb2_ctx_cap); + + vdec_ctrl_deinit(inst); +} diff --git a/drivers/media/platform/msm/vidc/msm_vdec.h b/drivers/media/platform/msm/vidc/msm_vdec.h new file mode 100644 index 000000000000..be50777a8d17 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vdec.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2012, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef _MSM_VDEC_H_ +#define _MSM_VDEC_H_ + +#include "msm_vidc_internal.h" + +int vdec_init(struct vidc_core *core, struct video_device *dec); +void vdec_deinit(struct vidc_core *core, struct video_device *dec); +int vdec_open(struct vidc_inst *inst); +void vdec_close(struct vidc_inst *inst); + +#endif diff --git a/drivers/media/platform/msm/vidc/msm_venc-ctrls.c b/drivers/media/platform/msm/vidc/msm_venc-ctrls.c new file mode 100644 index 000000000000..9b0389f3cfec --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_venc-ctrls.c @@ -0,0 +1,2409 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include +#include +#include +#include +#include +#include + +#include "msm_vidc_debug.h" +#include "msm_vidc_common.h" +#include "msm_vidc_load.h" +#include "msm_hfi_interface.h" +#include "msm_venc.h" + +#define MIN_BIT_RATE 32000 +#define MAX_BIT_RATE 160000000 +#define DEFAULT_BIT_RATE 64000 +#define BIT_RATE_STEP 100 +#define DEFAULT_FRAME_RATE 15 +#define MAX_SLICE_BYTE_SIZE 1024 +#define MIN_SLICE_BYTE_SIZE 1024 +#define MAX_SLICE_MB_SIZE 300 +#define I_FRAME_QP 26 +#define P_FRAME_QP 28 +#define B_FRAME_QP 30 +#define MAX_INTRA_REFRESH_MBS 300 +#define MAX_NUM_B_FRAMES 4 +#define MAX_LTR_FRAME_COUNT 10 + +#define L_MODE \ + V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY +#define CODING \ + V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY +#define BITSTREAM_RESTRICT_ENABLED \ + V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_ENABLED +#define BITSTREAM_RESTRICT_DISABLED \ + V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_DISABLED + +#define MIN_TIME_RESOLUTION 1 +#define MAX_TIME_RESOLUTION 0xffffff +#define DEFAULT_TIME_RESOLUTION 0x7530 + +#define IS_PRIV_CTRL(idx) ( \ + (V4L2_CTRL_ID2CLASS(idx) == V4L2_CTRL_CLASS_MPEG) && \ + V4L2_CTRL_DRIVER_PRIV(idx)) + +static const char *const mpeg_video_rate_control[] = { + "No Rate Control", + "VBR VFR", + "VBR CFR", + "CBR VFR", + "CBR CFR", + NULL +}; + +static const char *const mpeg_video_rotation[] = { + "No Rotation", + "90 Degree Rotation", + "180 Degree Rotation", + "270 Degree Rotation", + NULL +}; + +static const char *const h264_video_entropy_cabac_model[] = { + "Model 0", + "Model 1", + "Model 2", + NULL +}; + +static const char *const h263_level[] = { + "1.0", + "2.0", + "3.0", + "4.0", + "4.5", + "5.0", + "6.0", + "7.0", +}; + +static const char *const h263_profile[] = { + "Baseline", + "H320 Coding", + "Backward Compatible", + "ISWV2", + "ISWV3", + "High Compression", + "Internet", + "Interlace", + "High Latency", +}; + +static const char *const hevc_tier_level[] = { + "Main Tier Level 1", + "Main Tier Level 2", + "Main Tier Level 2.1", + "Main Tier Level 3", + "Main Tier Level 3.1", + "Main Tier Level 4", + "Main Tier Level 4.1", + "Main Tier Level 5", + "Main Tier Level 5.1", + "Main Tier Level 5.2", + "Main Tier Level 6", + "Main Tier Level 6.1", + "Main Tier Level 6.2", + "High Tier Level 1", + "High Tier Level 2", + "High Tier Level 2.1", + "High Tier Level 3", + "High Tier Level 3.1", + "High Tier Level 4", + "High Tier Level 4.1", + "High Tier Level 5", + "High Tier Level 5.1", + "High Tier Level 5.2", + "High Tier Level 6", + "High Tier Level 6.1", + "High Tier Level 6.2", +}; + +static const char *const hevc_profile[] = { + "Main", + "Main10", + "Main Still Pic", +}; + +static const char *const vp8_profile_level[] = { + "Unused", + "0.0", + "1.0", + "2.0", + "3.0", +}; + +static const char *const mpeg_video_vidc_extradata[] = { + "Extradata none", + "Extradata MB Quantization", + "Extradata Interlace Video", + "Extradata VC1 Framedisp", + "Extradata VC1 Seqdisp", + "Extradata timestamp", + "Extradata S3D Frame Packing", + "Extradata Frame Rate", + "Extradata Panscan Window", + "Extradata Recovery point SEI", + "Extradata Closed Caption UD", + "Extradata AFD UD", + "Extradata Multislice info", + "Extradata number of concealed MB", + "Extradata metadata filler", + "Extradata input crop", + "Extradata digital zoom", + "Extradata aspect ratio", + "Extradata macroblock metadata", +}; + +static const char *const perf_level[] = { + "Nominal", + "Performance", + "Turbo" +}; + +static const char *const intra_refresh_modes[] = { + "None", + "Cyclic", + "Adaptive", + "Cyclic Adaptive", + "Random" +}; + +static const char *const timestamp_mode[] = { + "Honor", + "Ignore", +}; + +static struct vidc_ctrl venc_ctrls[] = { + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD, + .name = "IDR Period", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = INT_MAX, + .default_value = DEFAULT_FRAME_RATE, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES, + .name = "Intra Period for P frames", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = INT_MAX, + .default_value = 2 * DEFAULT_FRAME_RATE - 1, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES, + .name = "Intra Period for B frames", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = INT_MAX, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME, + .name = "Request I Frame", + .type = V4L2_CTRL_TYPE_BUTTON, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 0, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL, + .name = "Video Framerate and Bitrate Control", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF, + .step = 0, + .menu_skip_mask = ~( + (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR)), + .qmenu = mpeg_video_rate_control, + }, + { + .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + .name = "Bitrate Control", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .maximum = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .default_value = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .step = 0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) | + (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)), + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_BITRATE, + .name = "Bit Rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_BIT_RATE, + .maximum = MAX_BIT_RATE, + .default_value = DEFAULT_BIT_RATE, + .step = BIT_RATE_STEP, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, + .name = "Peak Bit Rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_BIT_RATE, + .maximum = MAX_BIT_RATE, + .default_value = DEFAULT_BIT_RATE, + .step = BIT_RATE_STEP, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, + .name = "Entropy Mode", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .maximum = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC, + .default_value = V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC, + .step = 0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC) | + (1 << V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC)), + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL, + .name = "CABAC Model", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0, + .step = 0, + .menu_skip_mask = ~( + (1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2)), + .qmenu = h264_video_entropy_cabac_model, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, + .name = "MPEG4 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, + .maximum = CODING, + .default_value = V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE, + .step = 1, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, + .name = "MPEG4 Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0, + .maximum = V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, + .default_value = V4L2_MPEG_VIDEO_MPEG4_LEVEL_0, + .step = 1, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .name = "H264 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .maximum = V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH, + .default_value = V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, + .step = 1, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .name = "H264 Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .maximum = V4L2_MPEG_VIDEO_H264_LEVEL_5_2, + .default_value = V4L2_MPEG_VIDEO_H264_LEVEL_1_0, + .step = 0, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE, + .name = "H263 Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE, + .maximum = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY, + .default_value = V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY)), + .qmenu = h263_profile, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL, + .name = "H263 Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0, + .maximum = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0, + .default_value = V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0)), + .qmenu = h263_level, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL, + .name = "VP8 Profile Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED, + .maximum = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1, + .default_value = V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0) | + (1 << V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1)), + .qmenu = vp8_profile_level, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE, + .name = "HEVC Profile", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN, + .maximum = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC, + .default_value = V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN, + .step = 0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC)), + .qmenu = hevc_profile, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL, + .name = "HEVC Tier and Level", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1, + .maximum = V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2, + .default_value = + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1, + .step = 0, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5) | + (1 << V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1) + ), + .qmenu = hevc_tier_level, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION, + .name = "Rotation", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE, + .step = 0, + .menu_skip_mask = ~( + (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270)), + .qmenu = mpeg_video_rotation, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, + .name = "I Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 51, + .default_value = I_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, + .name = "P Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 51, + .default_value = P_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP, + .name = "B Frame Quantization", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 51, + .default_value = B_FRAME_QP, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP, + .name = "H264 Minimum QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 51, + .default_value = 1, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP, + .name = "H264 Maximum QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 51, + .default_value = 51, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP, + .name = "VP8 Minimum QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 128, + .default_value = 1, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP, + .name = "VP8 Maximum QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 128, + .default_value = 128, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, + .name = "Slice Mode", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + .maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_GOB, + .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, + .step = 1, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE) | + (1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) | + (1 << V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) | + (1 << V4L2_MPEG_VIDEO_MULTI_SLICE_GOB)), + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES, + .name = "Slice Byte Size", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_SLICE_BYTE_SIZE, + .maximum = MAX_SLICE_BYTE_SIZE, + .default_value = MIN_SLICE_BYTE_SIZE, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, + .name = "Slice MB Size", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = MAX_SLICE_MB_SIZE, + .default_value = 1, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB, + .name = "Slice GOB", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = MAX_SLICE_MB_SIZE, + .default_value = 1, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE, + .name = "Slice delivery mode", + .type = V4L2_CTRL_TYPE_BUTTON, + .minimum = 0, + .maximum = 1, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE, + .name = "Intra Refresh Mode", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE, + .step = 0, + .menu_skip_mask = ~( + (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE) | + (1 << V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM)), + .qmenu = intra_refresh_modes, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS, + .name = "Intra Refresh AIR MBS", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_INTRA_REFRESH_MBS, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF, + .name = "Intra Refresh AIR REF", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_INTRA_REFRESH_MBS, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS, + .name = "Intra Refresh CIR MBS", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_INTRA_REFRESH_MBS, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, + .name = "H.264 Loop Filter Alpha Offset", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, + .name = "H.264 Loop Filter Beta Offset", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = -6, + .maximum = 6, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + .name = "H.264 Loop Filter Mode", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, + .maximum = L_MODE, + .default_value = V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, + .step = 1, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED) | + (1 << V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED) | + (1 << L_MODE)), + }, + { + .id = V4L2_CID_MPEG_VIDEO_HEADER_MODE, + .name = "Sequence Header Mode", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE, + .maximum = V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME, + .default_value = + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME, + .step = 1, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) | + (1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME)), + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE, + .name = "Secure mode", + .type = V4L2_CTRL_TYPE_BUTTON, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 0, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA, + .name = "Extradata Type", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDC_EXTRADATA_NONE, + .maximum = V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI, + .default_value = V4L2_MPEG_VIDC_EXTRADATA_NONE, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_EXTRADATA_NONE) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_LTR) | + (1 << V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI)), + .qmenu = mpeg_video_vidc_extradata, + .step = 0, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO, + .name = "H264 VUI Timing Info", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED, + .maximum = V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED, + .default_value = + V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER, + .name = "H264 AU Delimiter", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED, + .maximum = V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED, + .step = 1, + .default_value = + V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED, + }, + { + .id = V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, + .name = "Intra Refresh CIR MBS", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_INTRA_REFRESH_MBS, + .default_value = 0, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT, + .name = "H264 VUI Timing Info", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = BITSTREAM_RESTRICT_DISABLED, + .maximum = BITSTREAM_RESTRICT_ENABLED, + .default_value = BITSTREAM_RESTRICT_ENABLED, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY, + .name = "Preserve Text Qualty", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_DISABLED, + .maximum = V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_ENABLED, + .default_value = + V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_DISABLED, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE, + .name = "Deinterlace for encoder", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION, + .name = "Vop time increment resolution", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = MIN_TIME_RESOLUTION, + .maximum = MAX_TIME_RESOLUTION, + .default_value = DEFAULT_TIME_RESOLUTION, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER, + .name = "Request Seq Header", + .type = V4L2_CTRL_TYPE_BUTTON, + .minimum = 0, + .maximum = 0, + .default_value = 0, + .step = 0, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME, + .name = "H264 Use LTR", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_LTR_FRAME_COUNT - 1, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT, + .name = "Ltr Count", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = MAX_LTR_FRAME_COUNT, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE, + .name = "Ltr Mode", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE, + .maximum = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_PERIODIC, + .default_value = V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME, + .name = "H264 Mark LTR", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (MAX_LTR_FRAME_COUNT - 1), + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS, + .name = "Set Hier P num layers", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 3, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE, + .name = "Encoder Timestamp Mode", + .type = V4L2_CTRL_TYPE_MENU, + .minimum = + V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR, + .maximum = + V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE, + .default_value = + V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR, + .menu_skip_mask = ~( + (1 << V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR) | + (1 << V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE)), + .qmenu = timestamp_mode, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE, + .name = "VP8 Error Resilience mode", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_DISABLED, + .maximum = V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_ENABLED, + .default_value = + V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_DISABLED, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP, + .name = "Enable setting initial QP", + .type = V4L2_CTRL_TYPE_BITMASK, + .minimum = 0, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_IFRAME | + V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_PFRAME | + V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_BFRAME, + .default_value = 0, + .step = 0, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP, + .name = "Iframe initial QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 51, + .default_value = 1, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP, + .name = "Pframe initial QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 51, + .default_value = 1, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP, + .name = "Bframe initial QP", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 1, + .maximum = 51, + .default_value = 1, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE, + .name = "I-Frame X coordinate search range", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 4, + .maximum = 128, + .default_value = 4, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE, + .name = "I-Frame Y coordinate search range", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 4, + .maximum = 128, + .default_value = 4, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE, + .name = "P-Frame X coordinate search range", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 4, + .maximum = 128, + .default_value = 4, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE, + .name = "P-Frame Y coordinate search range", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 4, + .maximum = 128, + .default_value = 4, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE, + .name = "B-Frame X coordinate search range", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 4, + .maximum = 128, + .default_value = 4, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE, + .name = "B-Frame Y coordinate search range", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 4, + .maximum = 128, + .default_value = 4, + .step = 1, + .menu_skip_mask = 0, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC, + .name = "Enable H264 SVC NAL", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED, + .maximum = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED, + .default_value = V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED, + .step = 1, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE, + .name = "Set Encoder performance mode", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY, + .maximum = V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE, + .default_value = V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS, + .name = "Set Hier B num layers", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 3, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE, + .name = "Set Hybrid Hier P mode", + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = 5, + .default_value = 0, + .step = 1, + .qmenu = NULL, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC, + .type = V4L2_CTRL_TYPE_MENU, + .minimum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED, + .maximum = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_EXTENDED, + .default_value = V4L2_MPEG_VIDEO_H264_VUI_SAR_IDC_UNSPECIFIED, + .menu_skip_mask = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_GOP_SIZE, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 12, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE, + .type = V4L2_CTRL_TYPE_INTEGER, + .minimum = 0, + .maximum = (1 << 16) - 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, +}; + +#define NUM_CTRLS ARRAY_SIZE(venc_ctrls) + +/* Helper function to translate V4L2_* to HAL_* */ +static inline int venc_v4l2_to_hal(int id, int value) +{ + switch (id) { + /* MPEG4 */ + case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + switch (value) { + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0: + return HAL_MPEG4_LEVEL_0; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B: + return HAL_MPEG4_LEVEL_0b; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1: + return HAL_MPEG4_LEVEL_1; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2: + return HAL_MPEG4_LEVEL_2; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3: + return HAL_MPEG4_LEVEL_3; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4: + return HAL_MPEG4_LEVEL_4; + case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5: + return HAL_MPEG4_LEVEL_5; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: + switch (value) { + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE: + return HAL_MPEG4_PROFILE_SIMPLE; + case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE: + return HAL_MPEG4_PROFILE_ADVANCEDSIMPLE; + default: + goto unknown_value; + } + /* H264 */ + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + switch (value) { + case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE: + return HAL_H264_PROFILE_BASELINE; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE: + return HAL_H264_PROFILE_CONSTRAINED_BASE; + case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN: + return HAL_H264_PROFILE_MAIN; + case V4L2_MPEG_VIDEO_H264_PROFILE_EXTENDED: + return HAL_H264_PROFILE_EXTENDED; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH: + return HAL_H264_PROFILE_HIGH; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_10: + return HAL_H264_PROFILE_HIGH10; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_422: + return HAL_H264_PROFILE_HIGH422; + case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH_444_PREDICTIVE: + return HAL_H264_PROFILE_HIGH444; + case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH: + return HAL_H264_PROFILE_CONSTRAINED_HIGH; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + switch (value) { + case V4L2_MPEG_VIDEO_H264_LEVEL_1_0: + return HAL_H264_LEVEL_1; + case V4L2_MPEG_VIDEO_H264_LEVEL_1B: + return HAL_H264_LEVEL_1b; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_1: + return HAL_H264_LEVEL_11; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_2: + return HAL_H264_LEVEL_12; + case V4L2_MPEG_VIDEO_H264_LEVEL_1_3: + return HAL_H264_LEVEL_13; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_0: + return HAL_H264_LEVEL_2; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_1: + return HAL_H264_LEVEL_21; + case V4L2_MPEG_VIDEO_H264_LEVEL_2_2: + return HAL_H264_LEVEL_22; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_0: + return HAL_H264_LEVEL_3; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_1: + return HAL_H264_LEVEL_31; + case V4L2_MPEG_VIDEO_H264_LEVEL_3_2: + return HAL_H264_LEVEL_32; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_0: + return HAL_H264_LEVEL_4; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_1: + return HAL_H264_LEVEL_41; + case V4L2_MPEG_VIDEO_H264_LEVEL_4_2: + return HAL_H264_LEVEL_42; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_0: + return HAL_H264_LEVEL_5; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_1: + return HAL_H264_LEVEL_51; + case V4L2_MPEG_VIDEO_H264_LEVEL_5_2: + return HAL_H264_LEVEL_52; + default: + goto unknown_value; + } + /* H263 */ + case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE: + return HAL_H263_PROFILE_BASELINE; + case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING: + return HAL_H263_PROFILE_H320CODING; + case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE: + return HAL_H263_PROFILE_BACKWARDCOMPATIBLE; + case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2: + return HAL_H263_PROFILE_ISWV2; + case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3: + return HAL_H263_PROFILE_ISWV3; + case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION: + return HAL_H263_PROFILE_HIGHCOMPRESSION; + case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET: + return HAL_H263_PROFILE_INTERNET; + case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE: + return HAL_H263_PROFILE_INTERLACE; + case V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY: + return HAL_H263_PROFILE_HIGHLATENCY; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + switch (value) { + case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC: + return HAL_H264_ENTROPY_CAVLC; + case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC: + return HAL_H264_ENTROPY_CABAC; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL: + switch (value) { + case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0: + return HAL_H264_CABAC_MODEL_0; + case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1: + return HAL_H264_CABAC_MODEL_1; + case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2: + return HAL_H264_CABAC_MODEL_2; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0: + return HAL_H263_LEVEL_10; + case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0: + return HAL_H263_LEVEL_20; + case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0: + return HAL_H263_LEVEL_30; + case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0: + return HAL_H263_LEVEL_40; + case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5: + return HAL_H263_LEVEL_45; + case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0: + return HAL_H263_LEVEL_50; + case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0: + return HAL_H263_LEVEL_60; + case V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0: + return HAL_H263_LEVEL_70; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0: + return HAL_VPX_PROFILE_VERSION_0; + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1: + return HAL_VPX_PROFILE_VERSION_1; + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2: + return HAL_VPX_PROFILE_VERSION_2; + case V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3: + return HAL_VPX_PROFILE_VERSION_3; + case V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED: + return HAL_VPX_PROFILE_UNUSED; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN: + return HAL_HEVC_PROFILE_MAIN; + case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10: + return HAL_HEVC_PROFILE_MAIN10; + case V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC: + return HAL_HEVC_PROFILE_MAIN_STILL_PIC; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL: + switch (value) { + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1: + return HAL_HEVC_MAIN_TIER_LEVEL_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2: + return HAL_HEVC_MAIN_TIER_LEVEL_2; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1: + return HAL_HEVC_MAIN_TIER_LEVEL_2_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3: + return HAL_HEVC_MAIN_TIER_LEVEL_3; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1: + return HAL_HEVC_MAIN_TIER_LEVEL_3_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4: + return HAL_HEVC_MAIN_TIER_LEVEL_4; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1: + return HAL_HEVC_MAIN_TIER_LEVEL_4_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5: + return HAL_HEVC_MAIN_TIER_LEVEL_5; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1: + return HAL_HEVC_MAIN_TIER_LEVEL_5_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2: + return HAL_HEVC_MAIN_TIER_LEVEL_5_2; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6: + return HAL_HEVC_MAIN_TIER_LEVEL_6; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1: + return HAL_HEVC_MAIN_TIER_LEVEL_6_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2: + return HAL_HEVC_MAIN_TIER_LEVEL_6_2; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1: + return HAL_HEVC_HIGH_TIER_LEVEL_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2: + return HAL_HEVC_HIGH_TIER_LEVEL_2; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1: + return HAL_HEVC_HIGH_TIER_LEVEL_2_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3: + return HAL_HEVC_HIGH_TIER_LEVEL_3; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1: + return HAL_HEVC_HIGH_TIER_LEVEL_3_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4: + return HAL_HEVC_HIGH_TIER_LEVEL_4; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1: + return HAL_HEVC_HIGH_TIER_LEVEL_4_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5: + return HAL_HEVC_HIGH_TIER_LEVEL_5; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1: + return HAL_HEVC_HIGH_TIER_LEVEL_5_1; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2: + return HAL_HEVC_HIGH_TIER_LEVEL_5_2; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6: + return HAL_HEVC_HIGH_TIER_LEVEL_6; + case V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1: + return HAL_HEVC_HIGH_TIER_LEVEL_6_1; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION: + switch (value) { + case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE: + return HAL_ROTATE_NONE; + case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90: + return HAL_ROTATE_90; + case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180: + return HAL_ROTATE_180; + case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270: + return HAL_ROTATE_270; + default: + goto unknown_value; + } + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: + switch (value) { + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED: + return HAL_H264_DB_MODE_DISABLE; + case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED: + return HAL_H264_DB_MODE_ALL_BOUNDARY; + case L_MODE: + return HAL_H264_DB_MODE_SKIP_SLICE_BOUNDARY; + default: + goto unknown_value; + } + } + +unknown_value: + dprintk(VIDC_WARN, "Unknown control (%x, %d)\n", id, value); + return -EINVAL; +} + +static struct v4l2_ctrl * +get_ctrl_from_cluster(int id, struct v4l2_ctrl **cluster, int ncontrols) +{ + int c; + + for (c = 0; c < ncontrols; ++c) + if (cluster[c]->id == id) + return cluster[c]; + + return NULL; +} + +/* Small helper macro for quickly getting a control and err checking */ +#define TRY_GET_CTRL(__ctrl_id) ({ \ + struct v4l2_ctrl *__temp; \ + __temp = get_ctrl_from_cluster( \ + __ctrl_id, \ + ctrl->cluster, ctrl->ncontrols); \ + if (!__temp) { \ + dprintk(VIDC_ERR, "Can't find %s (%x) in cluster\n", \ + #__ctrl_id, __ctrl_id); \ + /* Clusters are hardcoded, if we can't find */ \ + /* something then things are massively screwed up */ \ + BUG_ON(1); \ + } \ + __temp; \ + }) + +static int try_set_ctrl(struct vidc_inst *inst, struct v4l2_ctrl *ctrl) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct vidc_core_capability *cap = &inst->capability; + struct hal_request_iframe request_iframe; + struct hal_bitrate bitrate; + struct hal_profile_level profile_level; + struct hal_h264_entropy_control h264_entropy_control; + struct hal_quantization quantization; + struct hal_intra_period intra_period; + struct hal_idr_period idr_period; + struct hal_operations operations; + struct hal_intra_refresh intra_refresh; + struct hal_multi_slice_control multi_slice_control; + struct hal_h264_db_control h264_db_control; + struct hal_enable enable; + struct hal_h264_vui_timing_info vui_timing_info; + struct hal_quantization_range qp_range; + struct hal_h264_vui_bitstream_restrc vui_bitstream_restrict; + struct hal_preserve_text_quality preserve_text_quality; + struct hal_extradata_enable extra; + struct hal_mpeg4_time_resolution time_res; + struct hal_ltr_use use_ltr; + struct hal_ltr_mark mark_ltr; + struct hal_hybrid_hierp hyb_hierp; + struct hal_ltr_mode ltr_mode; + struct hal_vc1e_perf_cfg_type search_range = { {0} }; + struct hal_initial_quantization quant; + u32 hier_p_layers = 0; + struct hal_venc_perf_mode venc_mode; + u32 property_id = 0, property_val = 0; + void *pdata = NULL; + struct v4l2_ctrl *temp_ctrl = NULL; + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD: + if (inst->fmt_cap->pixfmt != V4L2_PIX_FMT_H264 && + inst->fmt_cap->pixfmt != V4L2_PIX_FMT_H264_NO_SC) { + dev_err(dev, "Control 0x%x only valid for H264\n", + ctrl->id); + ret = -ENOTSUPP; + break; + } + + property_id = HAL_CONFIG_VENC_IDR_PERIOD; + idr_period.idr_period = ctrl->val; + pdata = &idr_period; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES: + case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES: { + int num_p, num_b; + + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES); + num_b = temp_ctrl->val; + + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES); + num_p = temp_ctrl->val; + + if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES) + num_p = ctrl->val; + else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES) + num_b = ctrl->val; + + if (num_b) { + u32 max_num_b_frames = MAX_NUM_B_FRAMES; + + property_id = HAL_PARAM_VENC_MAX_NUM_B_FRAMES; + pdata = &max_num_b_frames; + + ret = hfi_session_set_property(inst, property_id, + pdata); + if (ret) { + dev_err(dev, + "Failed : Setprop MAX_NUM_B_FRAMES %d\n", + ret); + break; + } + } + + property_id = HAL_CONFIG_VENC_INTRA_PERIOD; + intra_period.pframes = num_p; + intra_period.bframes = num_b; + pdata = &intra_period; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME: + property_id = HAL_CONFIG_VENC_REQUEST_IFRAME; + request_iframe.enable = true; + pdata = &request_iframe; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL: + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: { + struct v4l2_ctrl update_ctrl = {.id = 0}; + int final_mode = 0; + + /* V4L2_CID_MPEG_VIDEO_BITRATE_MODE and _RATE_CONTROL + * manipulate the same thing. If one control's state + * changes, try to mirror the state in the other control's + * value */ + if (ctrl->id == V4L2_CID_MPEG_VIDEO_BITRATE_MODE) { + if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) { + final_mode = HAL_RATE_CONTROL_VBR_CFR; + update_ctrl.val = + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR; + } else {/* ...if (ctrl->val == _BITRATE_MODE_CBR) */ + final_mode = HAL_RATE_CONTROL_CBR_CFR; + update_ctrl.val = + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR; + } + + update_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL; + + } else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL) { + switch (ctrl->val) { + case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF: + case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR: + case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR: + update_ctrl.val = + V4L2_MPEG_VIDEO_BITRATE_MODE_VBR; + case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR: + case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR: + update_ctrl.val = + V4L2_MPEG_VIDEO_BITRATE_MODE_CBR; + } + + final_mode = ctrl->val; + update_ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE; + } + + if (update_ctrl.id) { + temp_ctrl = TRY_GET_CTRL(update_ctrl.id); + temp_ctrl->val = update_ctrl.val; + } + + property_id = HAL_PARAM_VENC_RATE_CONTROL; + property_val = final_mode; + pdata = &property_val; + + break; + } + case V4L2_CID_MPEG_VIDEO_BITRATE: { + struct v4l2_ctrl *hier_p = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS); + + bitrate.layer_id = 0; + + if (hier_p->val && inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264) { + ret = venc_set_bitrate_for_each_layer(inst, hier_p->val, + ctrl->val); + if (ret) { + dev_err(dev, "set bitrate for multiple layers\n"); + break; + } + } else { + property_id = HAL_CONFIG_VENC_TARGET_BITRATE; + bitrate.bit_rate = ctrl->val; + bitrate.layer_id = 0; + pdata = &bitrate; + } + break; + } + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: { + struct v4l2_ctrl *avg_bitrate = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_BITRATE); + + if (ctrl->val < avg_bitrate->val) { + dev_err(dev, + "Peak bitrate (%d) is lower than average bitrate (%d)\n", + ctrl->val, avg_bitrate->val); + ret = -EINVAL; + break; + } else if (ctrl->val < avg_bitrate->val * 2) { + dev_err(dev, + "Peak bitrate (%d) ideally should be twice the average bitrate (%d)\n", + ctrl->val, avg_bitrate->val); + } + + property_id = HAL_CONFIG_VENC_MAX_BITRATE; + bitrate.bit_rate = ctrl->val; + bitrate.layer_id = 0; + pdata = &bitrate; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE: + temp_ctrl = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL); + + property_id = HAL_PARAM_VENC_H264_ENTROPY_CONTROL; + h264_entropy_control.entropy_mode = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, ctrl->val); + h264_entropy_control.cabac_model = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL, + temp_ctrl->val); + pdata = &h264_entropy_control; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE); + + property_id = HAL_PARAM_VENC_H264_ENTROPY_CONTROL; + h264_entropy_control.cabac_model = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE, ctrl->val); + h264_entropy_control.entropy_mode = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL, + temp_ctrl->val); + pdata = &h264_entropy_control; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.profile = venc_v4l2_to_hal(ctrl->id, ctrl->val); + profile_level.level = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.level = venc_v4l2_to_hal(ctrl->id, ctrl->val); + profile_level.profile = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDEO_H264_PROFILE: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LEVEL); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.profile = venc_v4l2_to_hal(ctrl->id, ctrl->val); + profile_level.level = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_LEVEL, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDEO_H264_LEVEL: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_PROFILE); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.level = venc_v4l2_to_hal(ctrl->id, ctrl->val); + profile_level.profile = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_PROFILE, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.profile = venc_v4l2_to_hal(ctrl->id, ctrl->val); + profile_level.level = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.level = venc_v4l2_to_hal(ctrl->id, ctrl->val); + profile_level.profile = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE, + ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL: + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.profile = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL, + ctrl->val); + profile_level.level = HAL_VPX_PROFILE_UNUSED; + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE: + temp_ctrl = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.profile = venc_v4l2_to_hal(ctrl->id, ctrl->val); + profile_level.level = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE); + + property_id = HAL_PARAM_PROFILE_LEVEL_CURRENT; + profile_level.level = venc_v4l2_to_hal(ctrl->id, ctrl->val); + profile_level.profile = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE, + temp_ctrl->val); + pdata = &profile_level; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_ROTATION: { + struct v4l2_ctrl *deinterlace = NULL; + + if (!(inst->capability.pixelprocess_capabilities & + HAL_VIDEO_ENCODER_ROTATION_CAPABILITY)) { + dev_err(dev, "Rotation not supported: 0x%x\n", + ctrl->id); + ret = -ENOTSUPP; + break; + } + + deinterlace = + TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE); + if (ctrl->val && deinterlace && deinterlace->val != + V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED) { + dev_err(dev, + "Rotation not supported with deinterlacing\n"); + ret = -EINVAL; + break; + } + property_id = HAL_CONFIG_VPE_OPERATIONS; + operations.rotate = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDC_VIDEO_ROTATION, + ctrl->val); + operations.flip = HAL_FLIP_NONE; + pdata = &operations; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: { + struct v4l2_ctrl *qpp, *qpb; + + qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP); + qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP); + + property_id = HAL_PARAM_VENC_SESSION_QP; + quantization.qpi = ctrl->val; + quantization.qpp = qpp->val; + quantization.qpb = qpb->val; + quantization.layer_id = 0; + + pdata = &quantization; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: { + struct v4l2_ctrl *qpi, *qpb; + + qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP); + qpb = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP); + + property_id = HAL_PARAM_VENC_SESSION_QP; + quantization.qpp = ctrl->val; + quantization.qpi = qpi->val; + quantization.qpb = qpb->val; + quantization.layer_id = 0; + + pdata = &quantization; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_B_FRAME_QP: { + struct v4l2_ctrl *qpi, *qpp; + + qpi = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP); + qpp = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP); + + property_id = HAL_PARAM_VENC_SESSION_QP; + quantization.qpb = ctrl->val; + quantization.qpi = qpi->val; + quantization.qpp = qpp->val; + quantization.layer_id = 0; + + pdata = &quantization; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_MIN_QP: { + struct v4l2_ctrl *qp_max; + + qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MAX_QP); + if (ctrl->val >= qp_max->val) { + dev_err(dev, "Bad range: Min QP (%d) > Max QP(%d)\n", + ctrl->val, qp_max->val); + ret = -ERANGE; + break; + } + + property_id = HAL_PARAM_VENC_SESSION_QP_RANGE; + qp_range.layer_id = 0; + qp_range.max_qp = qp_max->val; + qp_range.min_qp = ctrl->val; + + pdata = &qp_range; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_MAX_QP: { + struct v4l2_ctrl *qp_min; + + qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_MIN_QP); + if (ctrl->val <= qp_min->val) { + dev_err(dev, "Bad range: Max QP (%d) < Min QP(%d)\n", + ctrl->val, qp_min->val); + ret = -ERANGE; + break; + } + + property_id = HAL_PARAM_VENC_SESSION_QP_RANGE; + qp_range.layer_id = 0; + qp_range.max_qp = ctrl->val; + qp_range.min_qp = qp_min->val; + + pdata = &qp_range; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP: { + struct v4l2_ctrl *qp_max; + + qp_max = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP); + property_id = HAL_PARAM_VENC_SESSION_QP_RANGE; + qp_range.layer_id = 0; + qp_range.max_qp = qp_max->val; + qp_range.min_qp = ctrl->val; + pdata = &qp_range; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP: { + struct v4l2_ctrl *qp_min; + + qp_min = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP); + property_id = HAL_PARAM_VENC_SESSION_QP_RANGE; + qp_range.layer_id = 0; + qp_range.max_qp = ctrl->val; + qp_range.min_qp = qp_min->val; + pdata = &qp_range; + break; + } + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: { + int temp = 0; + + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: + temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB; + break; + case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: + temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES; + break; + case V4L2_MPEG_VIDEO_MULTI_SLICE_GOB: + temp = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB; + break; + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: + default: + temp = 0; + break; + } + + if (temp) + temp_ctrl = TRY_GET_CTRL(temp); + + property_id = HAL_PARAM_VENC_MULTI_SLICE_CONTROL; + multi_slice_control.multi_slice = ctrl->val; + multi_slice_control.slice_size = temp ? temp_ctrl->val : 0; + + pdata = &multi_slice_control; + break; + } + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB: + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + + property_id = HAL_PARAM_VENC_MULTI_SLICE_CONTROL; + multi_slice_control.multi_slice = temp_ctrl->val; + multi_slice_control.slice_size = ctrl->val; + pdata = &multi_slice_control; + break; + case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE: { + temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE); + + if ((temp_ctrl->val == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) + && (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 || + inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264_NO_SC)) { + property_id = HAL_PARAM_VENC_SLICE_DELIVERY_MODE; + enable.enable = true; + } else { + dev_warn(dev, + "Failed : slice delivery mode is valid "\ + "only for H264 encoder and MB based slicing\n"); + enable.enable = false; + } + pdata = &enable; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE: { + struct v4l2_ctrl *air_mbs, *air_ref, *cir_mbs; + + air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS); + air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF); + cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS); + + property_id = HAL_PARAM_VENC_INTRA_REFRESH; + + intra_refresh.mode = ctrl->val; + intra_refresh.air_mbs = air_mbs->val; + intra_refresh.air_ref = air_ref->val; + intra_refresh.cir_mbs = cir_mbs->val; + + pdata = &intra_refresh; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS: { + struct v4l2_ctrl *ir_mode, *air_ref, *cir_mbs; + + ir_mode = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE); + air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF); + cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS); + + property_id = HAL_PARAM_VENC_INTRA_REFRESH; + + intra_refresh.air_mbs = ctrl->val; + intra_refresh.mode = ir_mode->val; + intra_refresh.air_ref = air_ref->val; + intra_refresh.cir_mbs = cir_mbs->val; + + pdata = &intra_refresh; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF: { + struct v4l2_ctrl *ir_mode, *air_mbs, *cir_mbs; + + ir_mode = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE); + air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS); + cir_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS); + + property_id = HAL_PARAM_VENC_INTRA_REFRESH; + + intra_refresh.air_ref = ctrl->val; + intra_refresh.air_mbs = air_mbs->val; + intra_refresh.mode = ir_mode->val; + intra_refresh.cir_mbs = cir_mbs->val; + + pdata = &intra_refresh; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS: { + struct v4l2_ctrl *ir_mode, *air_mbs, *air_ref; + + ir_mode = TRY_GET_CTRL( + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE); + air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS); + air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF); + + property_id = HAL_PARAM_VENC_INTRA_REFRESH; + + intra_refresh.cir_mbs = ctrl->val; + intra_refresh.air_mbs = air_mbs->val; + intra_refresh.air_ref = air_ref->val; + intra_refresh.mode = ir_mode->val; + + pdata = &intra_refresh; + break; + } + case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: { + struct v4l2_ctrl *air_mbs, *air_ref; + + air_mbs = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS); + air_ref = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF); + + property_id = HAL_PARAM_VENC_INTRA_REFRESH; + + intra_refresh.cir_mbs = ctrl->val; + intra_refresh.air_mbs = air_mbs->val; + intra_refresh.air_ref = air_ref->val; + intra_refresh.mode = HAL_INTRA_REFRESH_CYCLIC; + + pdata = &intra_refresh; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE: { + struct v4l2_ctrl *alpha, *beta; + + alpha = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA); + beta = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA); + + property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL; + h264_db_control.slice_alpha_offset = alpha->val; + h264_db_control.slice_beta_offset = beta->val; + h264_db_control.mode = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + ctrl->val); + pdata = &h264_db_control; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA: { + struct v4l2_ctrl *mode, *beta; + + mode = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE); + beta = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA); + + property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL; + h264_db_control.slice_alpha_offset = ctrl->val; + h264_db_control.slice_beta_offset = beta->val; + h264_db_control.mode = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + mode->val); + pdata = &h264_db_control; + break; + } + case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA: { + struct v4l2_ctrl *mode, *alpha; + + mode = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE); + alpha = TRY_GET_CTRL(V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA); + + property_id = HAL_PARAM_VENC_H264_DEBLOCK_CONTROL; + h264_db_control.slice_alpha_offset = alpha->val; + h264_db_control.slice_beta_offset = ctrl->val; + h264_db_control.mode = venc_v4l2_to_hal( + V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE, + mode->val); + pdata = &h264_db_control; + break; + } + case V4L2_CID_MPEG_VIDEO_HEADER_MODE: + property_id = HAL_PARAM_VENC_SYNC_FRAME_SEQUENCE_HEADER; + + switch (ctrl->val) { + case V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE: + enable.enable = 0; + break; + case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME: + enable.enable = 1; + break; + case V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME: + default: + ret = -ENOTSUPP; + break; + } + pdata = &enable; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_SECURE: + inst->flags |= VIDC_SECURE; + dev_info(dev, "Setting secure mode to: %d\n", + !!(inst->flags & VIDC_SECURE)); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA: + property_id = HAL_PARAM_INDEX_EXTRADATA; + extra.index = vidc_comm_get_hal_extradata_index(ctrl->val); + extra.enable = 1; + pdata = &extra; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO: { + struct v4l2_ctrl *rc_mode; + u32 cfr = 0; + + property_id = HAL_PARAM_VENC_H264_VUI_TIMING_INFO; + rc_mode = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL); + + switch (rc_mode->val) { + case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR: + case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR: + cfr = 1; + break; + default: + cfr = 0; + break; + } + + switch (ctrl->val) { + case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED: + vui_timing_info.enable = 0; + break; + case V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED: + vui_timing_info.enable = 1; + vui_timing_info.fixed_frame_rate = cfr; + vui_timing_info.time_scale = NSEC_PER_SEC; + } + + pdata = &vui_timing_info; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER: + property_id = HAL_PARAM_VENC_H264_GENERATE_AUDNAL; + + switch (ctrl->val) { + case V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED: + enable.enable = 0; + break; + case V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED: + enable.enable = 1; + break; + default: + ret = -ENOTSUPP; + break; + } + + pdata = &enable; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT: + property_id = HAL_PARAM_VENC_H264_VUI_BITSTREAM_RESTRC; + vui_bitstream_restrict.enable = ctrl->val; + pdata = &vui_bitstream_restrict; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY: + property_id = HAL_PARAM_VENC_PRESERVE_TEXT_QUALITY; + preserve_text_quality.enable = ctrl->val; + pdata = &preserve_text_quality; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION: + property_id = HAL_PARAM_VENC_MPEG4_TIME_RESOLUTION; + time_res.time_increment_resolution = ctrl->val; + pdata = &time_res; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE: { + struct v4l2_ctrl *rotation = NULL; + + if (!(inst->capability.pixelprocess_capabilities & + HAL_VIDEO_ENCODER_DEINTERLACE_CAPABILITY)) { + dev_err(dev, "Deinterlace not supported: 0x%x\n", + ctrl->id); + ret = -ENOTSUPP; + break; + } + + rotation = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_ROTATION); + if (ctrl->val && rotation && rotation->val != + V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE) { + dev_err(dev, "Deinterlacing not supported with rotation"); + ret = -EINVAL; + break; + } + property_id = HAL_CONFIG_VPE_DEINTERLACE; + switch (ctrl->val) { + case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED: + enable.enable = 1; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED: + default: + enable.enable = 0; + break; + } + pdata = &enable; + break; + } + case V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER: + atomic_inc(&inst->seq_hdr_reqs); + break; + case V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME: + property_id = HAL_CONFIG_VENC_USELTRFRAME; + use_ltr.ref_ltr = (1 << ctrl->val); + use_ltr.use_constraint = false; + use_ltr.frames = 0; + pdata = &use_ltr; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME: + property_id = HAL_CONFIG_VENC_MARKLTRFRAME; + mark_ltr.mark_frame = ctrl->val; + pdata = &mark_ltr; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS: + property_id = HAL_CONFIG_VENC_HIER_P_NUM_FRAMES; + hier_p_layers = ctrl->val; + + ret = venc_toggle_hier_p(inst, ctrl->val); + if (ret) + break; + + if (hier_p_layers > inst->capability.hier_p.max) { + dev_err(dev, "Error setting hier p num layers %d, max supported %d\n", + hier_p_layers, inst->capability.hier_p.max); + ret= -ENOTSUPP; + break; + } + pdata = &hier_p_layers; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE: + property_id = HAL_PARAM_VENC_DISABLE_RC_TIMESTAMP; + enable.enable = (ctrl->val == + V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE); + pdata = &enable; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE: + property_id = HAL_PARAM_VENC_VPX_ERROR_RESILIENCE_MODE; + enable.enable = ctrl->val; + pdata = &enable; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC: + property_id = HAL_PARAM_VENC_H264_NAL_SVC_EXT; + enable.enable = ctrl->val; + pdata = &enable; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE: + property_id = HAL_CONFIG_VENC_PERF_MODE; + venc_mode.mode = ctrl->val; + pdata = &venc_mode; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE: + property_id = HAL_PARAM_VENC_HIER_P_HYBRID_MODE; + hyb_hierp.layers = ctrl->val; + pdata = &hyb_hierp; + break; + + case V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE: + if (ctrl->val != V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE) { + ret = venc_toggle_hier_p(inst, false); + if (ret) + break; + } + + ltr_mode.mode = ctrl->val; + ltr_mode.trust_mode = 1; + property_id = HAL_PARAM_VENC_LTRMODE; + pdata = <r_mode; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT: + ltr_mode.count = ctrl->val; + if (ltr_mode.count > cap->ltr_count.max) { + dev_err(dev, "Invalid LTR count %d, max supported %d\n", + ltr_mode.count, cap->ltr_count.max); + /* + * FIXME: Return an error (-EINVAL) + * here once VP8 supports LTR count + * capability + */ + ltr_mode.count = 1; + } + ltr_mode.trust_mode = 1; + property_id = HAL_PARAM_VENC_LTRMODE; + pdata = <r_mode; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP: + property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP; + quant.init_qp_enable = ctrl->val; + pdata = &quant; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP: + quant.qpi = ctrl->val; + property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP; + pdata = &quant; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP: + quant.qpp = ctrl->val; + property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP; + pdata = &quant; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP: + quant.qpb = ctrl->val; + property_id = HAL_PARAM_VENC_ENABLE_INITIAL_QP; + pdata = &quant; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE: + search_range.i_frame.x_subsampled = ctrl->val; + property_id = HAL_PARAM_VENC_SEARCH_RANGE; + pdata = &search_range; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE: + search_range.i_frame.y_subsampled = ctrl->val; + property_id = HAL_PARAM_VENC_SEARCH_RANGE; + pdata = &search_range; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE: + search_range.p_frame.x_subsampled = ctrl->val; + property_id = HAL_PARAM_VENC_SEARCH_RANGE; + pdata = &search_range; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE: + search_range.p_frame.y_subsampled = ctrl->val; + property_id = HAL_PARAM_VENC_SEARCH_RANGE; + pdata = &search_range; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE: + search_range.b_frame.x_subsampled = ctrl->val; + property_id = HAL_PARAM_VENC_SEARCH_RANGE; + pdata = &search_range; + break; + case V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE: + search_range.b_frame.y_subsampled = ctrl->val; + property_id = HAL_PARAM_VENC_SEARCH_RANGE; + pdata = &search_range; + break; + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_ENABLE: + case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + case V4L2_CID_MPEG_VIDEO_H264_CPB_SIZE: + case V4L2_CID_MPEG_VIDEO_H264_8X8_TRANSFORM: + ret = 0; + property_id = 0; + break; + default: + ret = -EINVAL; + break; + } + + if (!ret && property_id) { + dev_dbg(dev, "control: hal property:%x, value:%d\n", + property_id, ctrl->val); + ret = hfi_session_set_property(inst, property_id, pdata); + } + + return ret; +} + +static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vidc_inst *inst = + container_of(ctrl->handler, struct vidc_inst, ctrl_handler); + struct device *dev = &inst->core->res.pdev->dev; + int ret = 0, c; + + for (c = 0; c < ctrl->ncontrols; ++c) { + struct v4l2_ctrl *temp = ctrl->cluster[c]; + + if (!ctrl->cluster[c]->is_new) + continue; + + ret = try_set_ctrl(inst, temp); + if (ret) { + dev_err(dev, "try set ctrl: %s id: %x (%d)\n", + v4l2_ctrl_get_name(temp->id), temp->id, + ret); + break; + } + } + + if (ret) + dev_err(dev, "setting control: %x (%s) failed\n", + ctrl->id, v4l2_ctrl_get_name(ctrl->id)); + + return ret; +} + +static const struct v4l2_ctrl_ops venc_ctrl_ops = { + .s_ctrl = venc_op_s_ctrl, +}; + +static struct v4l2_ctrl **get_super_cluster(struct vidc_inst *inst, int *size) +{ + int c, sz = 0; + struct v4l2_ctrl **cluster = kmalloc(sizeof(struct v4l2_ctrl *) * + NUM_CTRLS, GFP_KERNEL); + + if (!size || !cluster || !inst) + return NULL; + + for (c = 0; c < NUM_CTRLS; c++) + cluster[sz++] = inst->ctrls[c]; + + *size = sz; + + return cluster; +} + +int venc_ctrl_init(struct vidc_inst *inst) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct v4l2_ctrl_config cfg; + int cluster_size = 0; + unsigned int idx; + int ret; + + inst->ctrls = kzalloc(sizeof(struct v4l2_ctrl *) * NUM_CTRLS, + GFP_KERNEL); + if (!inst->ctrls) + return -ENOMEM; + + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, NUM_CTRLS); + if (ret) { + dev_err(dev, "ctrl handler init (%d)\n", ret); + return ret; + } + + for (idx = 0; idx < NUM_CTRLS; idx++) { + struct v4l2_ctrl *ctrl; + + if (IS_PRIV_CTRL(venc_ctrls[idx].id)) { + memset(&cfg, 0, sizeof(cfg)); + cfg.def = venc_ctrls[idx].default_value; + cfg.flags = 0; + cfg.id = venc_ctrls[idx].id; + cfg.max = venc_ctrls[idx].maximum; + cfg.min = venc_ctrls[idx].minimum; + cfg.menu_skip_mask = venc_ctrls[idx].menu_skip_mask; + cfg.name = venc_ctrls[idx].name; + cfg.ops = &venc_ctrl_ops; + cfg.step = venc_ctrls[idx].step; + cfg.type = venc_ctrls[idx].type; + cfg.qmenu = venc_ctrls[idx].qmenu; + ctrl = v4l2_ctrl_new_custom(&inst->ctrl_handler, &cfg, + NULL); + } else { + if (venc_ctrls[idx].type == V4L2_CTRL_TYPE_MENU) { + ctrl = v4l2_ctrl_new_std_menu( + &inst->ctrl_handler, + &venc_ctrl_ops, + venc_ctrls[idx].id, + venc_ctrls[idx].maximum, + venc_ctrls[idx].menu_skip_mask, + venc_ctrls[idx].default_value); + } else { + ctrl = v4l2_ctrl_new_std( + &inst->ctrl_handler, + &venc_ctrl_ops, + venc_ctrls[idx].id, + venc_ctrls[idx].minimum, + venc_ctrls[idx].maximum, + venc_ctrls[idx].step, + venc_ctrls[idx].default_value); + } + } + + ret = inst->ctrl_handler.error; + if (ret) { + dev_err(dev, "adding ctrl (%s) to ctrl handle (%d)\n", + venc_ctrls[idx].name, ret); + return ret; + } + + inst->ctrls[idx] = ctrl; + } + + /* Construct a super cluster of all controls */ + inst->cluster = get_super_cluster(inst, &cluster_size); + if (!inst->cluster || !cluster_size) { + dev_err(dev, "setup super cluster\n"); + return -EINVAL; + } + + v4l2_ctrl_cluster(cluster_size, inst->cluster); + + return 0; +} + +void venc_ctrl_deinit(struct vidc_inst *inst) +{ + kfree(inst->ctrls); + kfree(inst->cluster); + v4l2_ctrl_handler_free(&inst->ctrl_handler); +} diff --git a/drivers/media/platform/msm/vidc/msm_venc-ctrls.h b/drivers/media/platform/msm/vidc/msm_venc-ctrls.h new file mode 100644 index 000000000000..802f8d6746a7 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_venc-ctrls.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef _MSM_VENC_CTRLS_H_ +#define _MSM_VENC_CTRLS_H_ + +int venc_ctrl_init(struct vidc_inst *inst); +void venc_ctrl_deinit(struct vidc_inst *inst); + +#endif /* _MSM_VENC_CTRLS_H_ */ diff --git a/drivers/media/platform/msm/vidc/msm_venc.c b/drivers/media/platform/msm/vidc/msm_venc.c new file mode 100644 index 000000000000..7c741cdb2961 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_venc.c @@ -0,0 +1,1521 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include + +#include "msm_vidc_internal.h" +#include "msm_vidc_common.h" +#include "hfi/vidc_hfi_api.h" +#include "msm_vidc_debug.h" +#include "msm_internal-buffers.h" +#include "msm_vidc_load.h" +#include "msm_hfi_interface.h" +#include "msm_venc-ctrls.h" + +#define MIN_NUM_OUTPUT_BUFFERS 4 +#define MIN_NUM_CAPTURE_BUFFERS 4 + +/* Offset base for buffers on the destination queue - used to distinguish + * between source and destination buffers when mmapping - they receive the same + * offsets but for different queues */ +#define DST_QUEUE_OFF_BASE (1 << 30) + +/* + * Default 601 to 709 conversion coefficients for resolution: 176x144 negative + * coeffs are converted to s4.9 format (e.g. -22 converted to ((1<<13) - 22) + * 3x3 transformation matrix coefficients in s4.9 fixed point format + */ +static u32 vpe_csc_601_to_709_matrix_coeff[HAL_MAX_MATRIX_COEFFS] = { + 470, 8170, 8148, 0, 490, 50, 0, 34, 483 +}; + +/* offset coefficients in s9 fixed point format */ +static u32 vpe_csc_601_to_709_bias_coeff[HAL_MAX_BIAS_COEFFS] = { + 34, 0, 4 +}; + +/* clamping value for Y/U/V([min,max] for Y/U/V) */ +static u32 vpe_csc_601_to_709_limit_coeff[HAL_MAX_LIMIT_COEFFS] = { + 16, 235, 16, 240, 16, 240 +}; + +struct venc_buffer { + struct vb2_buffer vb; + struct list_head list; + dma_addr_t dma_addr; + struct buffer_info bi; +}; + +#define to_venc_buffer(buf) container_of(buf, struct venc_buffer, vb) + +static inline struct vidc_inst *to_inst(struct file *filp, void *fh) +{ + return container_of(filp->private_data, struct vidc_inst, fh); +} + +static u32 get_framesize_nv12(int plane, u32 height, u32 width) +{ + u32 y_stride, uv_stride, y_plane; + u32 y_sclines, uv_sclines, uv_plane; + u32 size; + + y_stride = ALIGN(width, 128); + uv_stride = ALIGN(width, 128); + y_sclines = ALIGN(height, 32); + uv_sclines = ALIGN(((height + 1) >> 1), 16); + + y_plane = y_stride * y_sclines; + uv_plane = uv_stride * uv_sclines + SZ_4K; + size = y_plane + uv_plane + SZ_8K; + size = ALIGN(size, SZ_4K); + + return size; +} + +static u32 get_framesize_nv21(int plane, u32 height, u32 width) +{ + return get_framesize_nv12(plane, height, width); +} + +static u32 get_framesize_compressed(int plane, u32 height, u32 width) +{ + u32 sz = ALIGN(height, 32) * ALIGN(width, 32) * 3 / 2; + + return ALIGN(sz, SZ_4K); +} + +static const struct vidc_format venc_formats[] = { + { + .pixfmt = V4L2_PIX_FMT_NV12, + .num_planes = 1, + .get_framesize = get_framesize_nv12, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_NV21, + .num_planes = 1, + .get_framesize = get_framesize_nv21, + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_MPEG4, + .num_planes = 1, + .get_framesize = get_framesize_compressed, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_H263, + .num_planes = 1, + .get_framesize = get_framesize_compressed, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_H264, + .num_planes = 1, + .get_framesize = get_framesize_compressed, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, + { + .pixfmt = V4L2_PIX_FMT_VP8, + .num_planes = 1, + .get_framesize = get_framesize_compressed, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + }, +}; + +static const struct vidc_format *find_format(u32 pixfmt, int type) +{ + const struct vidc_format *fmt = venc_formats; + unsigned int size = ARRAY_SIZE(venc_formats); + unsigned int i; + + for (i = 0; i < size; i++) { + if (fmt[i].pixfmt == pixfmt) + break; + } + + if (i == size || fmt[i].type != type) + return NULL; + + return &fmt[i]; +} + +static const struct vidc_format *find_format_by_index(int index, int type) +{ + const struct vidc_format *fmt = venc_formats; + unsigned int size = ARRAY_SIZE(venc_formats); + int i, k = 0; + + if (index < 0 || index > size) + return NULL; + + for (i = 0; i < size; i++) { + if (fmt[i].type != type) + continue; + if (k == index) + break; + k++; + } + + if (i == size) + return NULL; + + return &fmt[i]; +} + +static struct vb2_queue * +venc_to_vb2q(struct vidc_inst *inst, enum v4l2_buf_type type) +{ + if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return &inst->bufq_cap; + else if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return &inst->bufq_out; + + return NULL; +} + +int venc_toggle_hier_p(struct vidc_inst *inst, int layers) +{ + int num_enh_layers = 0; + u32 prop_id; + int ret; + + if (inst->fmt_cap->pixfmt != V4L2_PIX_FMT_VP8 && + inst->fmt_cap->pixfmt != V4L2_PIX_FMT_H264) + return 0; + + num_enh_layers = layers ? : 0; + + dprintk(VIDC_DBG, "%s Hier-P in firmware\n", + num_enh_layers ? "Enable" : "Disable"); + + prop_id = HAL_PARAM_VENC_HIER_P_MAX_ENH_LAYERS; + + ret = hfi_session_set_property(inst, prop_id, &num_enh_layers); + if (ret) + return ret; + + return 0; +} + +int venc_set_bitrate_for_each_layer(struct vidc_inst *inst, u32 num_enh_layers, + u32 total_bitrate) +{ + struct hal_bitrate bitrate; + u32 bitrate_table[3][4] = { + {50, 50, 0, 0}, + {34, 33, 33, 0}, + {25, 25, 25, 25} + }; + u32 prop_id, i; + int ret; + + if (!num_enh_layers || num_enh_layers > ARRAY_SIZE(bitrate_table)) + return -EINVAL; + + prop_id = HAL_CONFIG_VENC_TARGET_BITRATE; + + for (i = 0; !ret && i <= num_enh_layers; i++) { + bitrate.bit_rate = (total_bitrate * + bitrate_table[num_enh_layers - 1][i]) / 100; + bitrate.layer_id = i; + + ret = hfi_session_set_property(inst, prop_id, &bitrate); + if (ret) + return ret; + } + + return 0; +} + +static int venc_set_csc(struct vidc_inst *inst) +{ + struct hal_vpe_color_space_conversion vpe_csc; + enum hal_property prop_id; + int ret, count = 0; + + if (!vidc_vpe_csc_601_to_709) + return 0; + + while (count < HAL_MAX_MATRIX_COEFFS) { + if (count < HAL_MAX_BIAS_COEFFS) + vpe_csc.csc_bias[count] = + vpe_csc_601_to_709_bias_coeff[count]; + if (count < HAL_MAX_LIMIT_COEFFS) + vpe_csc.csc_limit[count] = + vpe_csc_601_to_709_limit_coeff[count]; + vpe_csc.csc_matrix[count] = + vpe_csc_601_to_709_matrix_coeff[count]; + count++; + } + + prop_id = HAL_PARAM_VPE_COLOR_SPACE_CONVERSION; + + ret = hfi_session_set_property(inst, prop_id, &vpe_csc); + if (ret) { + dprintk(VIDC_ERR, "Setting VPE coefficients failed\n"); + return ret; + } + + return 0; +} + +static int venc_set_properties(struct vidc_inst *inst) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct hal_frame_rate framerate; + struct v4l2_ctrl *ctrl; + u32 prop_id; + s32 value; + int ret; + + prop_id = HAL_CONFIG_FRAME_RATE; + framerate.buffer_type = HAL_BUFFER_OUTPUT; + framerate.frame_rate = inst->fps * (1 << 16); + + ret = hfi_session_set_property(inst, prop_id, &framerate); + if (ret) { + dev_err(dev, "set framerate failed (%d)\n", ret); + return ret; + } + + /* set VUI timing info */ + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, + V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO); + if (ctrl) + ret = v4l2_ctrl_s_ctrl(ctrl, + V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED); + + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, + V4L2_CID_MPEG_VIDEO_BITRATE); + if (ctrl) { + value = v4l2_ctrl_g_ctrl(ctrl); + + ctrl = v4l2_ctrl_find(&inst->ctrl_handler, + V4L2_CID_MPEG_VIDEO_BITRATE_PEAK); + if (ctrl) { + value = value * 2; + ret = v4l2_ctrl_s_ctrl(ctrl, value); + } + } + + return 0; +} + +static int +venc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) +{ + strlcpy(cap->driver, VIDC_DRV_NAME, sizeof(cap->driver)); + strlcpy(cap->card, "video encoder", sizeof(cap->card)); + strlcpy(cap->bus_info, "media", sizeof(cap->bus_info)); + cap->version = VIDC_VERSION; + + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING | + V4L2_CAP_DEVICE_CAPS; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_STREAMING; + + return 0; +} + +static int venc_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + const struct vidc_format *fmt; + + fmt = find_format_by_index(f->index, f->type); + + memset(f->reserved, 0 , sizeof(f->reserved)); + + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->pixfmt; + + return 0; +} + +static int venc_try_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + u32 pixelformat = pixmp->pixelformat; + const struct vidc_format *fmt; + struct vidc_core_capability *cap = &inst->capability; + + fmt = find_format(pixelformat, f->type); + if (!fmt) + return -EINVAL; + + pixmp->width = clamp(pixmp->width, cap->width.min, cap->width.max); + pixmp->height = clamp(pixmp->height, cap->height.min, cap->height.max); + pixmp->field = V4L2_FIELD_NONE; + pixmp->colorspace = V4L2_COLORSPACE_DEFAULT; + pixmp->num_planes = fmt->num_planes; + pixmp->flags = 0; + + return 0; +} + +static int venc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct hfi_device *hdev = inst->core->hfidev; + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + const struct vidc_format *fmt; + int ret, i; + + ret = venc_set_csc(inst); + if (ret) + return ret; + + inst->width = pixmp->width; + inst->height = pixmp->height; + + fmt = find_format(pixmp->pixelformat, f->type); + if (!fmt) + return -EINVAL; + + ret = vidc_check_session_supported(inst); + if (ret) { + dprintk(VIDC_ERR, "%s: session not supported\n", __func__); + return ret; + } + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + ret = hfi_session_init(inst, fmt->pixfmt); + if (ret) { + dprintk(VIDC_ERR, "Failed to init session (%d)\n", ret); + return ret; + } + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + struct hal_uncompressed_format_select hal_fmt; + struct hal_buffer_requirements *bufreq; + struct hal_frame_size fs; + int extra_idx; + + fs.buffer_type = HAL_BUFFER_INPUT; + fs.width = inst->width; + fs.height = inst->height; + + ret = hfi_session_set_property(inst, HAL_PARAM_FRAME_SIZE, &fs); + if (ret) { + dprintk(VIDC_ERR, + "set framesize for input failed (%d)\n", ret); + return ret; + } + + fs.buffer_type = HAL_BUFFER_OUTPUT; + fs.width = inst->width; + fs.height = inst->height; + + ret = hfi_session_set_property(inst, HAL_PARAM_FRAME_SIZE, &fs); + if (ret) { + dprintk(VIDC_ERR, + "set framesize for output failed (%d)\n", ret); + return ret; + } + + switch (fmt->pixfmt) { + case V4L2_PIX_FMT_NV12: + hal_fmt.format = HAL_COLOR_FORMAT_NV12; + break; + case V4L2_PIX_FMT_NV21: + hal_fmt.format = HAL_COLOR_FORMAT_NV21; + break; + default: + return -ENOTSUPP; + } + + hal_fmt.buffer_type = HAL_BUFFER_INPUT; + + ret = hfi_session_set_property(inst, + HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT, &hal_fmt); + if (ret) { + dprintk(VIDC_ERR, + "setting uncompressed color format failed (%d)\n", + ret); + return ret; + } + + extra_idx = EXTRADATA_IDX(fmt->num_planes); + if (extra_idx && extra_idx < VIDEO_MAX_PLANES) { + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_EXTRADATA_INPUT); + pixmp->plane_fmt[extra_idx].sizeimage = + bufreq ? bufreq->size : 0; + } + } + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + inst->fmt_cap = fmt; + else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + inst->fmt_out = fmt; + else + return -EINVAL; + + pixmp->num_planes = fmt->num_planes; + + for (i = 0; i < fmt->num_planes; ++i) { + pixmp->plane_fmt[i].sizeimage = + fmt->get_framesize(i, pixmp->height, pixmp->width); + + pixmp->plane_fmt[i].bytesperline = 0; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + u32 bytesperline; + + call_hfi_op(hdev, get_stride_scanline, COLOR_FMT_NV12, + pixmp->width, pixmp->height, + &bytesperline, NULL); + + pixmp->plane_fmt[i].bytesperline = bytesperline; + } + } + + return 0; +} + +static int venc_g_fmt(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct hfi_device *hdev = inst->core->hfidev; + struct v4l2_pix_format_mplane *pixmp = &f->fmt.pix_mp; + struct hal_buffer_requirements *bufreq = NULL; + const struct vidc_format *fmt = NULL; + unsigned int extra_idx = 0; + u32 height, width; + int ret = 0, i; + + ret = vidc_comm_get_bufreqs(inst); + if (ret) { + dprintk(VIDC_WARN, "Getting buffer requirements failed: %d\n", + ret); + return ret; + } + + height = inst->height; + width = inst->width; + + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + fmt = inst->fmt_cap; + else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + fmt = inst->fmt_out; + else + return -ENOTSUPP; + + pixmp->pixelformat = fmt->pixfmt; + pixmp->height = height; + pixmp->width = width; + pixmp->num_planes = fmt->num_planes; + + for (i = 0; i < fmt->num_planes; ++i) { + pixmp->plane_fmt[i].sizeimage = + fmt->get_framesize(i, height, width); + + pixmp->plane_fmt[i].bytesperline = 0; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + u32 bytesperline; + + call_hfi_op(hdev, get_stride_scanline, COLOR_FMT_NV12, + width, height, &bytesperline, NULL); + + pixmp->plane_fmt[i].bytesperline = bytesperline; + } + } + + extra_idx = EXTRADATA_IDX(fmt->num_planes); + if (extra_idx && extra_idx < VIDEO_MAX_PLANES) { + if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_EXTRADATA_OUTPUT); + else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + bufreq = get_buff_req_buffer(inst, + HAL_BUFFER_EXTRADATA_INPUT); + + pixmp->plane_fmt[extra_idx].sizeimage = + bufreq ? bufreq->size : 0; + } + + return ret; +} + +static int +venc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = venc_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + return vb2_reqbufs(queue, b); +} + +static int venc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + int ret = 0, i; + + if (b->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + queue = venc_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + ret = vb2_querybuf(queue, b); + if (ret) + return ret; + + if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + for (i = 0; i < b->length; i++) + b->m.planes[i].m.mem_offset += DST_QUEUE_OFF_BASE; + } + + return 0; +} + +static int venc_prepare_buf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = venc_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + return vb2_prepare_buf(queue, b); +} + +static int venc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + unsigned int state; + + queue = venc_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + mutex_lock(&inst->lock); + state = inst->state; + mutex_unlock(&inst->lock); + + /* + * it is possible userspace to continue to queuing buffres even + * while we are in streamoff. Not sure is this a problem in + * videobuf2 core, still. Fix it here for now. + */ + if (state >= INST_STOP) + return -EINVAL; + + return vb2_qbuf(queue, b); +} + +static int +venc_exportbuf(struct file *file, void *fh, struct v4l2_exportbuffer *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = venc_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + return vb2_expbuf(queue, b); +} + +static int venc_return_buf_error(struct vidc_inst *inst, struct v4l2_buffer *b) +{ + struct vb2_queue *qcap, *qout; + struct list_head *ptr, *next; + struct venc_buffer *buf; + + qcap = &inst->bufq_cap; + qout = &inst->bufq_out; + + if (vb2_is_streaming(qcap) && vb2_is_streaming(qout)) + return 0; + + mutex_lock(&inst->bufqueue_lock); + list_for_each_safe(ptr, next, &inst->bufqueue) { + buf = list_entry(ptr, struct venc_buffer, list); + + if (buf->vb.v4l2_buf.type != b->type) + continue; + + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + mutex_unlock(&inst->bufqueue_lock); + + return 0; +} + +static int venc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = venc_to_vb2q(inst, b->type); + if (!queue) + return -EINVAL; + + venc_return_buf_error(inst, b); + + return vb2_dqbuf(queue, b, file->f_flags & O_NONBLOCK); +} + +static int venc_streamon(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = venc_to_vb2q(inst, type); + if (!queue) + return -EINVAL; + + return vb2_streamon(queue, type); +} + +static int venc_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vb2_queue *queue; + + queue = venc_to_vb2q(inst, type); + if (!queue) + return -EINVAL; + + return vb2_streamoff(queue, type); +} + +static int venc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct device *dev = &inst->core->res.pdev->dev; + struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe; + u64 us_per_frame, fps; + + if (!timeperframe->denominator || + a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + us_per_frame = timeperframe->numerator * (u64)USEC_PER_SEC; + do_div(us_per_frame, timeperframe->denominator); + + if (!us_per_frame) + return -EINVAL; + + fps = (u64)USEC_PER_SEC; + do_div(fps, us_per_frame); + + dev_dbg(dev, "%s: num:%d, denom:%d\n", __func__, + timeperframe->numerator, timeperframe->denominator); + + inst->fps = fps; + inst->timeperframe = *timeperframe; + + return 0; +} + +static int venc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct vidc_inst *inst = to_inst(file, fh); + + if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return -EINVAL; + + memset(a, 0, sizeof(*a)); + a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + a->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + a->parm.capture.timeperframe = inst->timeperframe; + + return 0; +} + +static int venc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vidc_core_capability *cap = &inst->capability; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = cap->width.min; + fsize->stepwise.max_width = cap->width.max; + fsize->stepwise.step_width = cap->width.step_size; + fsize->stepwise.min_height = cap->height.min; + fsize->stepwise.max_height = cap->height.max; + fsize->stepwise.step_height = cap->height.step_size; + + return 0; +} + +static int venc_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + default: + return -EINVAL; + } +} + +static int venc_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) +{ + struct vidc_inst *inst = to_inst(file, fh); + struct vidc_core *core = inst->core; + int ret = 0; + + switch (enc->cmd) { + case V4L2_ENC_QCOM_CMD_FLUSH: + ret = vidc_comm_session_flush(inst, enc->flags); + break; + case V4L2_ENC_CMD_STOP: + if (inst->state == INST_INVALID || core->state == CORE_INVALID) + return ret; + + ret = release_scratch_buffers(inst, false); + if (ret) + dprintk(VIDC_ERR, "Failed to release scratch buf:%d\n", + ret); + + ret = release_persist_buffers(inst); + if (ret) + dprintk(VIDC_ERR, "Failed to release persist buf:%d\n", + ret); + + ret = hfi_session_deinit(inst); + if (ret) + return ret; + + break; + default: + return -EINVAL; + } + + return ret; +} + +static const struct v4l2_ioctl_ops venc_ioctl_ops = { + .vidioc_querycap = venc_querycap, + .vidioc_enum_fmt_vid_cap_mplane = venc_enum_fmt, + .vidioc_enum_fmt_vid_out_mplane = venc_enum_fmt, + .vidioc_s_fmt_vid_cap_mplane = venc_s_fmt, + .vidioc_s_fmt_vid_out_mplane = venc_s_fmt, + .vidioc_g_fmt_vid_cap_mplane = venc_g_fmt, + .vidioc_g_fmt_vid_out_mplane = venc_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = venc_try_fmt, + .vidioc_try_fmt_vid_out_mplane = venc_try_fmt, + .vidioc_reqbufs = venc_reqbufs, + .vidioc_querybuf = venc_querybuf, + .vidioc_prepare_buf = venc_prepare_buf, + .vidioc_qbuf = venc_qbuf, + .vidioc_expbuf = venc_exportbuf, + .vidioc_dqbuf = venc_dqbuf, + .vidioc_streamon = venc_streamon, + .vidioc_streamoff = venc_streamoff, + .vidioc_s_parm = venc_s_parm, + .vidioc_g_parm = venc_g_parm, + .vidioc_enum_framesizes = venc_enum_framesizes, + .vidioc_subscribe_event = venc_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_encoder_cmd = venc_cmd, +}; + +static int venc_queue_setup(struct vb2_queue *q, + const struct v4l2_format *fmt, + unsigned int *num_buffers, + unsigned int *num_planes, unsigned int sizes[], + void *alloc_ctxs[]) +{ + struct vidc_inst *inst = vb2_get_drv_priv(q); + struct device *dev = &inst->core->res.pdev->dev; + struct hal_buffer_count_actual buf_count; + struct hal_buffer_requirements *buff_req; + enum hal_property property_id; + int i, ret = 0; + + ret = vidc_comm_get_bufreqs(inst); + if (ret) { + dev_err(dev, "buffer requirements (%d)\n", ret); + return ret; + } + + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + *num_planes = inst->fmt_cap->num_planes; + + buff_req = get_buff_req_buffer(inst, HAL_BUFFER_OUTPUT); + if (!buff_req) { + ret = -EINVAL; + break; + } + + *num_buffers = max(*num_buffers, buff_req->count_actual); + + *num_buffers = clamp_val(*num_buffers, MIN_NUM_CAPTURE_BUFFERS, + VIDEO_MAX_FRAME); + + for (i = 0; i < *num_planes; i++) { + sizes[i] = inst->fmt_cap->get_framesize(i, inst->height, + inst->width); + alloc_ctxs[i] = inst->vb2_ctx_cap; + } + + property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL; + buf_count.type = HAL_BUFFER_OUTPUT; + buf_count.count_actual = *num_buffers; + + ret = hfi_session_set_property(inst, property_id, &buf_count); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + *num_planes = inst->fmt_out->num_planes; + + buff_req = get_buff_req_buffer(inst, HAL_BUFFER_INPUT); + if (!buff_req) { + ret = -EINVAL; + break; + } + + *num_buffers = max(*num_buffers, buff_req->count_actual); + + property_id = HAL_PARAM_BUFFER_COUNT_ACTUAL; + buf_count.type = HAL_BUFFER_INPUT; + buf_count.count_actual = *num_buffers; + + ret = hfi_session_set_property(inst, property_id, &buf_count); + if (ret) + break; + + sizes[0] = inst->fmt_out->get_framesize(0, inst->height, + inst->width); + alloc_ctxs[0] = inst->vb2_ctx_out; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int venc_buf_init(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb->vb2_queue; + struct vidc_inst *inst = vb2_get_drv_priv(q); + struct device *dev = &inst->core->res.pdev->dev; + struct hfi_device *hdev = inst->core->hfidev; + struct venc_buffer *buf = to_venc_buffer(vb); + struct vidc_buffer_addr_info *bai; + struct buffer_info *bi; + int ret; + + bi = &buf->bi; + bai = &bi->bai; + + memset(bai, 0, sizeof(*bai)); + + if (q->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return 0; + + bai->buffer_size = vb2_plane_size(vb, 0); + bai->buffer_type = HAL_BUFFER_OUTPUT; + bai->num_buffers = 1; + bai->device_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + + ret = call_hfi_op(hdev, session_set_buffers, inst->session, bai); + if (ret) { + dev_err(dev, "%s: session: set buffer failed\n", __func__); + return ret; + } + + mutex_lock(&inst->registeredbufs.lock); + list_add_tail(&bi->list, &inst->registeredbufs.list); + mutex_unlock(&inst->registeredbufs.lock); + + return 0; +} + +static int venc_buf_prepare(struct vb2_buffer *vb) +{ + struct venc_buffer *buf = to_venc_buffer(vb); + + buf->dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + + return 0; +} + +static void __fill_flags(struct vidc_frame_data *frame_data, __u32 vb_flags) +{ + u32 *flags = &frame_data->flags; + + if (vb_flags & V4L2_QCOM_BUF_FLAG_EOS) + *flags = HAL_BUFFERFLAG_EOS; + + if (vb_flags & V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP) + *flags |= HAL_BUFFERFLAG_YUV_601_709_CSC_CLAMP; + + if (vb_flags & V4L2_QCOM_BUF_FLAG_CODECCONFIG) + *flags |= HAL_BUFFERFLAG_CODECCONFIG; + + if (vb_flags & V4L2_QCOM_BUF_FLAG_DECODEONLY) + *flags |= HAL_BUFFERFLAG_DECODEONLY; + + if (vb_flags & V4L2_QCOM_BUF_TS_DISCONTINUITY) + *flags |= HAL_BUFFERFLAG_TS_DISCONTINUITY; + + if (vb_flags & V4L2_QCOM_BUF_TS_ERROR) + *flags |= HAL_BUFFERFLAG_TS_ERROR; + + if (vb_flags & V4L2_QCOM_BUF_TIMESTAMP_INVALID) + frame_data->timestamp = LLONG_MAX; +} + +static int venc_set_session_buf(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb->vb2_queue; + struct vidc_inst *inst = vb2_get_drv_priv(q); + struct vidc_core *core = inst->core; + struct device *dev = &core->res.pdev->dev; + struct hfi_device *hdev = core->hfidev; + struct venc_buffer *buf = to_venc_buffer(vb); + struct vidc_frame_data fdata; + s64 time_usec; + int ret; + + if (inst->state == INST_INVALID || core->state == CORE_INVALID) { + dev_err(dev, "core id:%d is in bad state\n", core->id); + return -EINVAL; + } + + time_usec = timeval_to_ns(&vb->v4l2_buf.timestamp); + do_div(time_usec, NSEC_PER_USEC); + + memset(&fdata, 0 , sizeof(fdata)); + + fdata.alloc_len = vb2_plane_size(vb, 0); + fdata.device_addr = buf->dma_addr; + fdata.timestamp = time_usec; + fdata.flags = 0; + fdata.clnt_data = buf->dma_addr; + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + fdata.buffer_type = HAL_BUFFER_INPUT; + fdata.filled_len = vb2_get_plane_payload(vb, 0); + fdata.offset = vb->v4l2_planes[0].data_offset; + + __fill_flags(&fdata, vb->v4l2_buf.flags); + + ret = call_hfi_op(hdev, session_etb, inst->session, &fdata); + } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + fdata.buffer_type = HAL_BUFFER_OUTPUT; + fdata.filled_len = 0; + fdata.offset = 0; + + ret = call_hfi_op(hdev, session_ftb, inst->session, &fdata); + } else { + ret = -EINVAL; + } + + if (ret) { + dev_err(dev, "failed to set session buffer\n"); + return ret; + } + + return 0; +} + +static int start_streaming(struct vidc_inst *inst) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct list_head *ptr, *next; + struct venc_buffer *buf; + int ret; + + ret = venc_set_properties(inst); + if (ret) { + dev_err(dev, "set properties (%d)\n", ret); + return ret; + } + + ret = vidc_comm_get_bufreqs(inst); + if (ret) { + dev_err(dev, "buffers requirements (%d)\n", ret); + return ret; + } + + ret = set_scratch_buffers(inst); + if (ret) { + dev_err(dev, "set scratch buffers failed (%d)\n", ret); + return ret; + } + + ret = set_persist_buffers(inst); + if (ret) { + dev_err(dev, "set persist buffers failed (%d)\n", ret); + return ret; + } + + msm_comm_scale_clocks(inst->core); + + ret = hfi_session_load_res(inst); + if (ret) { + dev_err(dev, "session load resources failed (%d)\n", ret); + return ret; + } + + ret = hfi_session_start(inst); + if (ret) { + dev_err(dev, "session start failed (%d)\n", ret); + return ret; + } + + mutex_lock(&inst->bufqueue_lock); + list_for_each_safe(ptr, next, &inst->bufqueue) { + buf = list_entry(ptr, struct venc_buffer, list); + + ret = venc_set_session_buf(&buf->vb); + if (ret) + break; + } + mutex_unlock(&inst->bufqueue_lock); + + return 0; +} + +static int venc_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct vidc_inst *inst = vb2_get_drv_priv(q); + struct vb2_queue *queue; + + switch (q->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + queue = &inst->bufq_cap; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + queue = &inst->bufq_out; + break; + default: + return -EINVAL; + } + + if (vb2_is_streaming(queue)) + return start_streaming(inst); + + return 0; +} + +static void venc_buf_queue(struct vb2_buffer *vb) +{ + struct vidc_inst *inst = vb2_get_drv_priv(vb->vb2_queue); + struct vidc_core *core = inst->core; + struct device *dev = &core->res.pdev->dev; + struct venc_buffer *buf = to_venc_buffer(vb); + int ret; + + if (inst->state == INST_INVALID || core->state == CORE_INVALID) { + dev_err(dev, "core or instance are in invalid state\n"); + return; + } + + mutex_lock(&inst->bufqueue_lock); + list_add_tail(&buf->list, &inst->bufqueue); + mutex_unlock(&inst->bufqueue_lock); + + if (!vb2_is_streaming(&inst->bufq_cap) || + !vb2_is_streaming(&inst->bufq_out)) + return; + + ret = venc_set_session_buf(vb); + if (ret) { + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + dev_err(dev, "cannot set session buffer\n"); + } + + return; +} + +static int venc_rel_session_bufs(struct vidc_inst *inst) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct vidc_buffer_addr_info *bai; + struct buffer_info *bi, *tmp; + int ret = 0; + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry_safe(bi, tmp, &inst->registeredbufs.list, list) { + list_del(&bi->list); + bai = &bi->bai; + bai->response_required = 1; + ret = hfi_session_release_buffers(inst, bai); + if (ret) { + dev_err(dev, "%s: session release buffers failed\n", + __func__); + break; + } + } + mutex_unlock(&inst->registeredbufs.lock); + + return ret; +} + +static int stop_streaming(struct vidc_inst *inst) +{ + struct vidc_core *core = inst->core; + struct device *dev = &core->res.pdev->dev; + int ret, streamoff; + + mutex_lock(&inst->lock); + streamoff = inst->streamoff; + mutex_unlock(&inst->lock); + + if (streamoff) + return 0; + + ret = hfi_session_stop(inst); + if (ret) { + dev_err(dev, "session: stop failed\n"); + goto abort; + } + + ret = hfi_session_release_res(inst); + if (ret) { + dev_err(dev, "session: release resources failed\n"); + goto abort; + } + + ret = venc_rel_session_bufs(inst); + if (ret) { + dev_err(dev, "failed to release capture buffers: %d\n", ret); + goto abort; + } + + ret = release_scratch_buffers(inst, false); + if (ret) { + dev_err(dev, "failed to release scratch buffers: %d\n", ret); + goto abort; + } + + ret = release_persist_buffers(inst); + if (ret) { + dev_err(dev, "failed to release persist buffers: %d\n", ret); + goto abort; + } + + if (inst->state == INST_INVALID || core->state == CORE_INVALID) { + dev_err(dev, "core id:%d is in invalid state\n", core->id); + ret = -EINVAL; + goto abort; + } + + ret = hfi_session_deinit(inst); + + mutex_lock(&inst->lock); + inst->streamoff = 1; + mutex_unlock(&inst->lock); + +abort: + if (ret) + hfi_session_abort(inst); + + return ret; +} + +static void venc_stop_streaming(struct vb2_queue *q) +{ + struct vidc_inst *inst = vb2_get_drv_priv(q); + struct device *dev = &inst->core->res.pdev->dev; + int ret; + + dev_dbg(dev, "%s: type: %d\n", __func__, q->type); + + ret = stop_streaming(inst); + + msm_comm_scale_clocks(inst->core); + + if (ret) + dev_err(dev, "stop streaming failed type: %d, ret: %d\n", + q->type, ret); +} + +static const struct vb2_ops venc_vb2_ops = { + .queue_setup = venc_queue_setup, + .buf_init = venc_buf_init, + .buf_prepare = venc_buf_prepare, + .start_streaming = venc_start_streaming, + .stop_streaming = venc_stop_streaming, + .buf_queue = venc_buf_queue, +}; + +static struct vb2_buffer * +venc_get_vb2buffer(struct vidc_inst *inst, dma_addr_t addr) +{ + struct venc_buffer *buf; + struct vb2_buffer *vb = NULL; + + mutex_lock(&inst->bufqueue_lock); + + list_for_each_entry(buf, &inst->bufqueue, list) { + if (buf->dma_addr == addr) { + vb = &buf->vb; + break; + } + } + + if (vb) + list_del(&buf->list); + + mutex_unlock(&inst->bufqueue_lock); + + return vb; +} + +static int venc_empty_buf_done(struct vidc_inst *inst, u32 addr, + u32 bytesused, u32 data_offset, u32 flags) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct vb2_buffer *buf; + + buf = venc_get_vb2buffer(inst, addr); + if (!buf) + return -EFAULT; + + buf->v4l2_planes[0].bytesused = bytesused; + buf->v4l2_planes[0].data_offset = data_offset; + buf->v4l2_buf.flags = flags; + + if (buf->v4l2_planes[0].data_offset > buf->v4l2_planes[0].length) + dev_dbg(dev, "data_offset overflow length\n"); + + if (buf->v4l2_planes[0].bytesused > buf->v4l2_planes[0].length) + dev_dbg(dev, "bytesused overflow length\n"); + + if (flags & V4L2_QCOM_BUF_INPUT_UNSUPPORTED) + dev_dbg(dev, "unsupported input stream\n"); + + if (flags & V4L2_QCOM_BUF_DATA_CORRUPT) + dev_dbg(dev, "corrupted input stream\n"); + + if (flags & V4L2_MSM_VIDC_BUF_START_CODE_NOT_FOUND) + dev_dbg(dev, "start code not found\n"); + + inst->count.ebd++; + + vb2_buffer_done(buf, VB2_BUF_STATE_DONE); + + return 0; +} + +static int venc_fill_buf_done(struct vidc_inst *inst, u32 addr, + u32 bytesused, u32 data_offset, u32 flags, + struct timeval *timestamp) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct vb2_buffer *buf; + + buf = venc_get_vb2buffer(inst, addr); + if (!buf) + return -EFAULT; + + buf->v4l2_planes[0].bytesused = bytesused; + buf->v4l2_planes[0].data_offset = data_offset; + buf->v4l2_buf.flags = flags; + buf->v4l2_buf.timestamp = *timestamp; + + if (buf->v4l2_planes[0].data_offset > buf->v4l2_planes[0].length) + dev_warn(dev, "overflow data_offset:%d, length:%d\n", + buf->v4l2_planes[0].data_offset, + buf->v4l2_planes[0].length); + + if (buf->v4l2_planes[0].bytesused > buf->v4l2_planes[0].length) + dev_warn(dev, "overflow bytesused:%d, length:%d\n", + buf->v4l2_planes[0].bytesused, + buf->v4l2_planes[0].length); + + inst->count.fbd++; + + vb2_buffer_done(buf, VB2_BUF_STATE_DONE); + + return 0; +} + +static int venc_event_notify(struct vidc_inst *inst, u32 event, + struct vidc_cb_event *data) +{ + struct device *dev = &inst->core->res.pdev->dev; + + switch (event) { + case SESSION_ERROR: + /* the instance lock is already taken just change the state */ + inst->state = INST_INVALID; + dev_warn(dev, "event session error\n"); + break; + case SYS_EVENT_CHANGE: + switch (data->hal_event_type) { + case HAL_EVENT_SEQ_CHANGED_SUFFICIENT_RESOURCES: + dev_dbg(dev, "event sufficient resources\n"); + break; + case HAL_EVENT_SEQ_CHANGED_INSUFFICIENT_RESOURCES: + dev_dbg(dev, "event not sufficient resources\n"); + inst->reconfig_height = data->height; + inst->reconfig_width = data->width; + inst->in_reconfig = true; + break; + default: + break; + } + break; + default: + break; + } + + return 0; +} + +static void venc_inst_init(struct vidc_inst *inst) +{ + inst->fmt_cap = &venc_formats[2]; + inst->fmt_out = &venc_formats[0]; + inst->height = DEFAULT_HEIGHT; + inst->width = DEFAULT_WIDTH; + inst->fps = 15; + inst->capability.pixelprocess_capabilities = 0; + inst->buffer_mode[OUTPUT_PORT] = HAL_BUFFER_MODE_STATIC; + inst->buffer_mode[CAPTURE_PORT] = HAL_BUFFER_MODE_STATIC; +} + +static void venc_release_video_device(struct video_device *pvdev) +{ +} + +extern const struct v4l2_file_operations vidc_fops; + +int venc_init(struct vidc_core *core, struct video_device *enc) +{ + int ret; + + /* setup the decoder device */ + enc->release = venc_release_video_device; + enc->fops = &vidc_fops; + enc->ioctl_ops = &venc_ioctl_ops; + enc->vfl_dir = VFL_DIR_M2M; + enc->v4l2_dev = &core->v4l2_dev; + + ret = video_register_device(enc, VFL_TYPE_GRABBER, 33); + if (ret) { + dprintk(VIDC_ERR, "Failed to register video encoder device"); + return ret; + } + + video_set_drvdata(enc, core); + + return 0; +} + +void venc_deinit(struct vidc_core *core, struct video_device *enc) +{ + video_unregister_device(enc); +} + +int venc_open(struct vidc_inst *inst) +{ + struct device *dev = &inst->core->res.pdev->dev; + struct vb2_queue *q; + struct device *iommu_dev; + int ret; + + /* TODO: use iommu dt bindings when they are exist */ + iommu_dev = msm_iommu_get_ctx("venus_ns"); + if (IS_ERR(iommu_dev)) { + dev_err(dev, "cannot find iommu nonsecure ctx\n"); + return PTR_ERR(iommu_dev); + } + + venc_inst_init(inst); + + ret = venc_ctrl_init(inst); + if (ret) + return ret; + + inst->vb2_ctx_cap = vb2_dma_contig_init_ctx(iommu_dev); + if (IS_ERR(inst->vb2_ctx_cap)) + return PTR_ERR(inst->vb2_ctx_cap); + + inst->vb2_ctx_out = vb2_dma_contig_init_ctx(iommu_dev); + if (IS_ERR(inst->vb2_ctx_out)) { + ret = PTR_ERR(inst->vb2_ctx_out); + goto err_cleanup_cap; + } + + q = &inst->bufq_cap; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + q->io_modes = VB2_MMAP; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + q->ops = &venc_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->drv_priv = inst; + q->buf_struct_size = sizeof(struct venc_buffer); + q->allow_zero_bytesused = 1; + ret = vb2_queue_init(q); + if (ret) + goto err_cleanup_out; + + q = &inst->bufq_out; + q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + q->ops = &venc_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->drv_priv = inst; + q->buf_struct_size = sizeof(struct venc_buffer); + q->allow_zero_bytesused = 1; + ret = vb2_queue_init(q); + if (ret) + goto err_cap_queue_release; + + inst->empty_buf_done = venc_empty_buf_done; + inst->fill_buf_done = venc_fill_buf_done; + inst->event_notify = venc_event_notify; + + return 0; + +err_cap_queue_release: + vb2_queue_release(&inst->bufq_cap); +err_cleanup_out: + vb2_dma_contig_cleanup_ctx(inst->vb2_ctx_out); +err_cleanup_cap: + vb2_dma_contig_cleanup_ctx(inst->vb2_ctx_cap); + return ret; +} + +void venc_close(struct vidc_inst *inst) +{ + vb2_queue_release(&inst->bufq_out); + vb2_queue_release(&inst->bufq_cap); + + vb2_dma_contig_cleanup_ctx(inst->vb2_ctx_out); + vb2_dma_contig_cleanup_ctx(inst->vb2_ctx_cap); + + venc_ctrl_deinit(inst); +} diff --git a/drivers/media/platform/msm/vidc/msm_venc.h b/drivers/media/platform/msm/vidc/msm_venc.h new file mode 100644 index 000000000000..052c21f7325f --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_venc.h @@ -0,0 +1,27 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef _MSM_VENC_H_ +#define _MSM_VENC_H_ + +#include "msm_vidc_internal.h" + +int venc_init(struct vidc_core *core, struct video_device *enc); +void venc_deinit(struct vidc_core *core, struct video_device *enc); +int venc_open(struct vidc_inst *inst); +void venc_close(struct vidc_inst *inst); + +int venc_set_bitrate_for_each_layer(struct vidc_inst *inst, u32 num_enh_layers, + u32 total_bitrate); +int venc_toggle_hier_p(struct vidc_inst *inst, int layers); + +#endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc.h b/drivers/media/platform/msm/vidc/msm_vidc.h new file mode 100644 index 000000000000..c93925396078 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc.h @@ -0,0 +1,19 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _MSM_VIDC_H_ +#define _MSM_VIDC_H_ + + + +#endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c new file mode 100644 index 000000000000..7220a82459c6 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -0,0 +1,831 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "msm_smem.h" +#include "msm_vdec.h" +#include "msm_vidc_common.h" +#include "hfi/vidc_hfi_api.h" +#include "msm_vidc_debug.h" +#include "msm_vidc_load.h" + +#define TIMEOUT msecs_to_jiffies(vidc_hw_rsp_timeout) + +enum multi_stream vidc_comm_get_stream_output_mode(struct vidc_inst *inst) +{ + return HAL_VIDEO_DECODER_PRIMARY; +} + +enum hal_domain vidc_comm_get_hal_domain(int session_type) +{ + switch (session_type) { + case VIDC_ENCODER: + return HAL_VIDEO_DOMAIN_ENCODER; + case VIDC_DECODER: + return HAL_VIDEO_DOMAIN_DECODER; + default: + dprintk(VIDC_ERR, "Wrong domain\n"); + return HAL_UNUSED_DOMAIN; + } +} + +enum hal_video_codec vidc_comm_hal_codec_type(u32 pixfmt) +{ + dprintk(VIDC_DBG, "codec is %#x\n", pixfmt); + + switch (pixfmt) { + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_H264_NO_SC: + return HAL_VIDEO_CODEC_H264; + case V4L2_PIX_FMT_H264_MVC: + return HAL_VIDEO_CODEC_MVC; + case V4L2_PIX_FMT_H263: + return HAL_VIDEO_CODEC_H263; + case V4L2_PIX_FMT_MPEG1: + return HAL_VIDEO_CODEC_MPEG1; + case V4L2_PIX_FMT_MPEG2: + return HAL_VIDEO_CODEC_MPEG2; + case V4L2_PIX_FMT_MPEG4: + return HAL_VIDEO_CODEC_MPEG4; + case V4L2_PIX_FMT_VC1_ANNEX_G: + case V4L2_PIX_FMT_VC1_ANNEX_L: + return HAL_VIDEO_CODEC_VC1; + case V4L2_PIX_FMT_VP8: + return HAL_VIDEO_CODEC_VP8; + default: + dprintk(VIDC_ERR, "Wrong codec: %d\n", pixfmt); + return HAL_UNUSED_CODEC; + } +} + +struct vidc_core *vidc_get_core(int core_id) +{ + struct vidc_core *core; + int found = 0; + + if (core_id > VIDC_CORES_MAX) + return ERR_PTR(-EINVAL); + + mutex_lock(&vidc_driver->lock); + list_for_each_entry(core, &vidc_driver->cores, list) { + if (core->id == core_id) { + found = 1; + break; + } + } + mutex_unlock(&vidc_driver->lock); + + if (found) + return core; + + return ERR_PTR(-ENOENT); +} + +void vidc_inst_set_state(struct vidc_inst *inst, u32 state) +{ + mutex_lock(&inst->lock); + if (inst->state == INST_INVALID) { + dprintk(VIDC_DBG, + "Inst: %p is in bad state can't change state\n", + inst); + goto exit; + } + + dprintk(VIDC_DBG, "Moved inst: %p from state: %d to state: %d\n", + inst, inst->state, state); + + inst->state = state; +exit: + mutex_unlock(&inst->lock); +} + +static unsigned int vidc_inst_get_state(struct vidc_inst *inst) +{ + unsigned int state; + + mutex_lock(&inst->lock); + state = inst->state; + mutex_unlock(&inst->lock); + + return state; +} + +void vidc_queue_v4l2_event(struct vidc_inst *inst, int event_type) +{ + struct v4l2_event event = {.id = 0, .type = event_type}; + + /* TODO: this prevents NULL pointer dereference */ + return; + v4l2_event_queue_fh(&inst->fh, &event); +} + +enum hal_buffer vidc_comm_get_hal_output_buffer(struct vidc_inst *inst) +{ + if (vidc_comm_get_stream_output_mode(inst) == + HAL_VIDEO_DECODER_SECONDARY) + return HAL_BUFFER_OUTPUT2; + else + return HAL_BUFFER_OUTPUT; +} + +struct hal_buffer_requirements * +get_buff_req_buffer(struct vidc_inst *inst, enum hal_buffer type) +{ + int i; + + for (i = 0; i < HAL_BUFFER_MAX; i++) { + if (inst->buff_req.buffer[i].type == type) + return &inst->buff_req.buffer[i]; + } + + return NULL; +} + +/* HFI interface functions start here */ + +int hfi_core_init(struct vidc_core *core) +{ + struct hfi_device *hdev = core->hfidev; + int ret; + + mutex_lock(&core->lock); + + if (core->state >= CORE_INIT) { + mutex_unlock(&core->lock); + return 0; + } + + init_completion(&core->done); + + ret = call_hfi_op(hdev, core_init, hdev->hfi_device_data); + if (ret) { + mutex_unlock(&core->lock); + return ret; + } + + ret = wait_for_completion_timeout(&core->done, TIMEOUT); + if (!ret) { + mutex_unlock(&core->lock); + return -ETIMEDOUT; + } + + core->state = CORE_INIT; + + mutex_unlock(&core->lock); + + return 0; +} + +int hfi_core_deinit(struct vidc_core *core) +{ + mutex_lock(&core->lock); + if (core->state == CORE_UNINIT) { + mutex_unlock(&core->lock); + return 0; + } + mutex_unlock(&core->lock); + + msm_comm_scale_clocks(core); + + mutex_lock(&core->lock); + if (list_empty(&core->instances)) { + /* + * Delay unloading of firmware. This is useful + * in avoiding firmware download delays in cases where we + * will have a burst of back to back video playback sessions + * e.g. thumbnail generation. + */ + } + mutex_unlock(&core->lock); + + return 0; +} + +int hfi_core_suspend(struct vidc_core *core) +{ + struct hfi_device *hdev = core->hfidev; + + return call_hfi_op(hdev, suspend, hdev->hfi_device_data); +} + +int hfi_session_init(struct vidc_inst *inst, u32 pixfmt) +{ + struct hfi_device *hdev = inst->core->hfidev; + unsigned int state = vidc_inst_get_state(inst); + enum hal_domain domain; + enum hal_video_codec codec; + int ret; + + if (state != INST_UNINIT) + return -EINVAL; + + init_completion(&inst->done); + + domain = vidc_comm_get_hal_domain(inst->session_type); + codec = vidc_comm_hal_codec_type(pixfmt); + + inst->session = call_hfi_op(hdev, session_init, hdev->hfi_device_data, + inst, domain, codec); + if (IS_ERR(inst->session)) + return PTR_ERR(inst->session); + + ret = wait_for_completion_timeout(&inst->done, TIMEOUT); + if (!ret) + return -ETIMEDOUT; + + vidc_inst_set_state(inst, INST_OPEN); + + return 0; +} + +int hfi_session_deinit(struct vidc_inst *inst) +{ + struct hfi_device *hdev = inst->core->hfidev; + unsigned int state = vidc_inst_get_state(inst); + int ret; + + if (state == INST_CLOSE) + return 0; + + if (state < INST_OPEN) + return -EINVAL; + + init_completion(&inst->done); + + ret = call_hfi_op(hdev, session_end, inst->session); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&inst->done, TIMEOUT); + if (!ret) + return -ETIMEDOUT; + + vidc_inst_set_state(inst, INST_CLOSE); + + return 0; +} + +int hfi_session_start(struct vidc_inst *inst) +{ + struct hfi_device *hdev = inst->core->hfidev; + unsigned int state = vidc_inst_get_state(inst); + int ret; + + if (state != INST_LOAD_RESOURCES) + return -EINVAL; + + init_completion(&inst->done); + + ret = call_hfi_op(hdev, session_start, inst->session); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&inst->done, TIMEOUT); + if (!ret) + return -ETIMEDOUT; + + vidc_inst_set_state(inst, INST_START); + + return 0; +} + +int hfi_session_stop(struct vidc_inst *inst) +{ + struct hfi_device *hdev = inst->core->hfidev; + unsigned int state = vidc_inst_get_state(inst); + int ret; + + if (state != INST_START) + return -EINVAL; + + init_completion(&inst->done); + + ret = call_hfi_op(hdev, session_stop, inst->session); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&inst->done, TIMEOUT); + if (!ret) + return -ETIMEDOUT; + + vidc_inst_set_state(inst, INST_STOP); + + return 0; +} + +int hfi_session_abort(struct vidc_inst *inst) +{ + struct hfi_device *hdev = inst->core->hfidev; + int ret; + + init_completion(&inst->done); + + ret = call_hfi_op(hdev, session_abort, inst->session); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&inst->done, TIMEOUT); + if (!ret) + return -ETIMEDOUT; + + vidc_inst_set_state(inst, INST_CLOSE); + + return 0; +} + +int hfi_session_load_res(struct vidc_inst *inst) +{ + struct vidc_core *core = inst->core; + struct hfi_device *hdev = core->hfidev; + unsigned int state = vidc_inst_get_state(inst); + int ret; + + if (state != INST_OPEN) + return -EINVAL; + + ret = msm_comm_check_overloaded(core); + if (ret) + return ret; + + init_completion(&inst->done); + + ret = call_hfi_op(hdev, session_load_res, inst->session); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&inst->done, TIMEOUT); + if (!ret) + return -ETIMEDOUT; + + vidc_inst_set_state(inst, INST_LOAD_RESOURCES); + + return 0; +} + +int hfi_session_release_res(struct vidc_inst *inst) +{ + struct hfi_device *hdev = inst->core->hfidev; + unsigned int state = vidc_inst_get_state(inst); + int ret; + + if (state != INST_STOP) + return -EINVAL; + + init_completion(&inst->done); + + ret = call_hfi_op(hdev, session_release_res, inst->session); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&inst->done, TIMEOUT); + if (!ret) + return -ETIMEDOUT; + + vidc_inst_set_state(inst, INST_RELEASE_RESOURCES); + + return 0; +} + +int hfi_session_flush(struct vidc_inst *inst) +{ + struct hfi_device *hdev = inst->core->hfidev; + int ret; + + init_completion(&inst->done); + + ret = call_hfi_op(hdev, session_flush, inst->session, HAL_FLUSH_ALL); + if (ret) + return ret; + + ret = wait_for_completion_timeout(&inst->done, TIMEOUT); + if (!ret) + return -ETIMEDOUT; + + return 0; +} + +void hfi_session_clean(struct vidc_inst *inst) +{ + struct hfi_device *hdev = inst->core->hfidev; + int ret; + + mutex_lock(&inst->lock); + if (hdev && inst->session) { + ret = call_hfi_op(hdev, session_clean, inst->session); + if (ret) + dprintk(VIDC_ERR, "session clean failed\n"); + + inst->session = NULL; + } + mutex_unlock(&inst->lock); +} + +int hfi_session_release_buffers(struct vidc_inst *inst, + struct vidc_buffer_addr_info *bai) +{ + struct hfi_device *hdev = inst->core->hfidev; + int ret; + + init_completion(&inst->done); + + ret = call_hfi_op(hdev, session_release_buffers, inst->session, bai); + if (ret) + return ret; + + if (!bai->response_required) + return 0; + + ret = wait_for_completion_timeout(&inst->done, TIMEOUT); + if (!ret) + return -ETIMEDOUT; + + if (inst->error != VIDC_ERR_NONE) + return -EIO; + + return 0; +} + +int hfi_session_get_property(struct vidc_inst *inst, enum hal_property ptype, + union hal_get_property *hprop) +{ + struct hfi_device *hdev = inst->core->hfidev; + unsigned int state = vidc_inst_get_state(inst); + struct getprop_buf *buf; + int ret; + + if (state == INST_INVALID) + return -EINVAL; + + mutex_lock(&inst->sync_lock); + if (state < INST_OPEN || state >= INST_CLOSE) { + ret = -EINVAL; + goto exit; + } + + switch (ptype) { + case HAL_PARAM_PROFILE_LEVEL_CURRENT: + case HAL_PARAM_GET_BUFFER_REQUIREMENTS: + break; + default: + return -ENOTSUPP; + } + + init_completion(&inst->done); + + ret = call_hfi_op(hdev, session_get_property, inst->session, ptype); + if (ret) + goto exit; + + ret = wait_for_completion_timeout(&inst->done, TIMEOUT); + if (!ret) { + inst->state = INST_INVALID; + vidc_comm_kill_session(inst); + ret = -ETIMEDOUT; + goto exit; + } + + mutex_lock(&inst->pending_getpropq.lock); + if (!list_empty(&inst->pending_getpropq.list)) { + buf = list_first_entry(&inst->pending_getpropq.list, + struct getprop_buf, list); + *hprop = *((union hal_get_property *) buf->data); + kfree(buf->data); + list_del(&buf->list); + kfree(buf); + ret = 0; + } else { + /* getprop list is empty */ + ret = -EINVAL; + } + mutex_unlock(&inst->pending_getpropq.lock); +exit: + mutex_unlock(&inst->sync_lock); + return ret; +} + +int hfi_session_set_property(struct vidc_inst *inst, enum hal_property ptype, + void *pdata) +{ + struct hfi_device *hdev = inst->core->hfidev; + unsigned int state = vidc_inst_get_state(inst); + int ret = 0; + + mutex_lock(&inst->sync_lock); + if (state < INST_OPEN || state >= INST_CLOSE) { + ret = -EINVAL; + goto exit; + } + + ret = call_hfi_op(hdev, session_set_property, inst->session, ptype, + pdata); +exit: + mutex_unlock(&inst->sync_lock); + + return ret; +} + +/* End of interface functions */ + +int vidc_comm_get_bufreqs(struct vidc_inst *inst) +{ + union hal_get_property hprop; + int ret, i; + + ret = hfi_session_get_property(inst, HAL_PARAM_GET_BUFFER_REQUIREMENTS, + &hprop); + if (ret) + return ret; + + memcpy(&inst->buff_req, &hprop.buf_req, sizeof(inst->buff_req)); + + for (i = 0; i < HAL_BUFFER_MAX; i++) + dprintk(VIDC_DBG, + "buftype: %03x, actual count: %02d, size: %d, " + "count min: %d, hold count: %d, region size: %d\n", + inst->buff_req.buffer[i].type, + inst->buff_req.buffer[i].count_actual, + inst->buff_req.buffer[i].size, + inst->buff_req.buffer[i].count_min, + inst->buff_req.buffer[i].hold_count, + inst->buff_req.buffer[i].region_size); + + dprintk(VIDC_DBG, "\n"); + + dprintk(VIDC_PROF, "Input buffers: %d, Output buffers: %d\n", + inst->buff_req.buffer[0].count_actual, + inst->buff_req.buffer[1].count_actual); + + return 0; +} + +int vidc_comm_bufrequirements(struct vidc_inst *inst, enum hal_buffer type, + struct hal_buffer_requirements *out) +{ + enum hal_property ptype = HAL_PARAM_GET_BUFFER_REQUIREMENTS; + union hal_get_property hprop; + int ret, i; + + ret = hfi_session_get_property(inst, ptype, &hprop); + if (ret) + return ret; + + ret = -EINVAL; + + for (i = 0; i < HAL_BUFFER_MAX; i++) { + if (hprop.buf_req.buffer[i].type != type) + continue; + + if (out) + memcpy(out, &hprop.buf_req.buffer[i], sizeof(*out)); + ret = 0; + break; + } + + return ret; +} + +int vidc_comm_session_flush(struct vidc_inst *inst, u32 flags) +{ + struct vidc_core *core = inst->core; + struct hfi_device *hdev = core->hfidev; + bool ip_flush = false; + bool op_flush = false; + int ret = 0; + + ip_flush = flags & V4L2_QCOM_CMD_FLUSH_OUTPUT; + op_flush = flags & V4L2_QCOM_CMD_FLUSH_CAPTURE; + + if (ip_flush && !op_flush) { + dprintk(VIDC_INFO, "Input only flush not supported\n"); + return 0; + } + + if (inst->state == INST_INVALID || core->state == CORE_INVALID) { + dprintk(VIDC_ERR, "Core %p and inst %p are in bad state\n", + core, inst); + return 0; + } + + if (inst->in_reconfig && !ip_flush && op_flush) { + ret = call_hfi_op(hdev, session_flush, inst->session, + HAL_FLUSH_OUTPUT); + } else { + /* + * If flush is called after queueing buffers but before + * streamon driver should flush the pending queue + */ + + /* Do not send flush in case of session_error */ + if (!(inst->state == INST_INVALID && + core->state != CORE_INVALID)) + ret = call_hfi_op(hdev, session_flush, inst->session, + HAL_FLUSH_ALL); + } + + return ret; +} + +enum hal_extradata_id +vidc_comm_get_hal_extradata_index(enum v4l2_mpeg_vidc_extradata index) +{ + switch (index) { + case V4L2_MPEG_VIDC_EXTRADATA_NONE: + return HAL_EXTRADATA_NONE; + case V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION: + return HAL_EXTRADATA_MB_QUANTIZATION; + case V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO: + return HAL_EXTRADATA_INTERLACE_VIDEO; + case V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP: + return HAL_EXTRADATA_VC1_FRAMEDISP; + case V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP: + return HAL_EXTRADATA_VC1_SEQDISP; + case V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP: + return HAL_EXTRADATA_TIMESTAMP; + case V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING: + return HAL_EXTRADATA_S3D_FRAME_PACKING; + case V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE: + return HAL_EXTRADATA_FRAME_RATE; + case V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW: + return HAL_EXTRADATA_PANSCAN_WINDOW; + case V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI: + return HAL_EXTRADATA_RECOVERY_POINT_SEI; + case V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO: + return HAL_EXTRADATA_MULTISLICE_INFO; + case V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB: + return HAL_EXTRADATA_NUM_CONCEALED_MB; + case V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER: + return HAL_EXTRADATA_METADATA_FILLER; + case V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO: + return HAL_EXTRADATA_ASPECT_RATIO; + case V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP: + return HAL_EXTRADATA_INPUT_CROP; + case V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM: + return HAL_EXTRADATA_DIGITAL_ZOOM; + case V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP: + return HAL_EXTRADATA_MPEG2_SEQDISP; + case V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA: + return HAL_EXTRADATA_STREAM_USERDATA; + case V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP: + return HAL_EXTRADATA_FRAME_QP; + case V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO: + return HAL_EXTRADATA_FRAME_BITS_INFO; + case V4L2_MPEG_VIDC_EXTRADATA_LTR: + return HAL_EXTRADATA_LTR_INFO; + case V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI: + return HAL_EXTRADATA_METADATA_MBI; + default: + return V4L2_MPEG_VIDC_EXTRADATA_NONE; + } + + return 0; +} + +enum hal_buffer_layout_type +vidc_comm_get_hal_buffer_layout(enum v4l2_mpeg_vidc_video_mvc_layout index) +{ + switch (index) { + case V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL: + return HAL_BUFFER_LAYOUT_SEQ; + case V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM: + return HAL_BUFFER_LAYOUT_TOP_BOTTOM; + default: + break; + } + + return HAL_UNUSED_BUFFER_LAYOUT; +} + +int vidc_trigger_ssr(struct vidc_core *core, enum hal_ssr_trigger_type type) +{ + struct hfi_device *hdev; + int ret; + + if (!core || !core->hfidev) + return -EINVAL; + + hdev = core->hfidev; + + if (core->state != CORE_INIT) + return 0; + + ret = call_hfi_op(hdev, core_trigger_ssr, hdev->hfi_device_data, type); + if (ret) + return ret; + + return 0; +} + +int vidc_check_session_supported(struct vidc_inst *inst) +{ + struct vidc_core *core =inst->core; + struct vidc_core_capability *cap = &inst->capability; + int ret = 0; + + if (inst->state == INST_OPEN) { + ret = msm_comm_check_overloaded(core); + if (ret) + return ret; + } + + if (!cap->capability_set) + return 0; + + ret = -ENOTSUPP; + + if (inst->width < cap->width.min || inst->height < cap->height.min) + goto err; + + if (inst->width > cap->width.max) + goto err; + + if (inst->height * inst->width > cap->width.max * cap->height.max) + goto err; + + return 0; +err: + dprintk(VIDC_ERR, "resolution not supported\n"); + return ret; +} + +int vidc_comm_set_color_format(struct vidc_inst *inst, + enum hal_buffer buffer_type, u32 pixfmt) +{ + struct hal_uncompressed_format_select hal_fmt; + struct hfi_device *hdev = inst->core->hfidev; + int ret; + + hal_fmt.buffer_type = buffer_type; + + switch (pixfmt) { + case V4L2_PIX_FMT_NV12: + dprintk(VIDC_DBG, "set color format: nv12\n"); + hal_fmt.format = HAL_COLOR_FORMAT_NV12; + break; + case V4L2_PIX_FMT_NV21: + dprintk(VIDC_DBG, "set color format: nv21\n"); + hal_fmt.format = HAL_COLOR_FORMAT_NV21; + break; + default: + return -ENOTSUPP; + } + + ret = call_hfi_op(hdev, session_set_property, inst->session, + HAL_PARAM_UNCOMPRESSED_FORMAT_SELECT, &hal_fmt); + if (ret) { + dprintk(VIDC_ERR, "set uncompressed color format failed (%d)\n", + ret); + return ret; + } + + return 0; +} + +int vidc_comm_kill_session(struct vidc_inst *inst) +{ + int ret = 0; + + if (!inst || !inst->core || !inst->core->hfidev) { + dprintk(VIDC_ERR, "%s: invalid input parameters\n", __func__); + return -EINVAL; + } else if (!inst->session) { + /* There's no hfi session to kill */ + return 0; + } + + /* + * We're internally forcibly killing the session, if fw is aware of + * the session send session_abort to firmware to clean up and release + * the session, else just kill the session inside the driver. + */ + if ((inst->state >= INST_OPEN && inst->state < INST_CLOSE) || + inst->state == INST_INVALID) { + ret = hfi_session_abort(inst); + if (ret == -EBUSY) { + inst->event_notify(inst, SESSION_ERROR, NULL); + return 0; + } else if (ret) { + return ret; + } + vidc_inst_set_state(inst, INST_CLOSE); + } else { + inst->event_notify(inst, SESSION_ERROR, NULL); + } + + return ret; +} diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h new file mode 100644 index 000000000000..52bef1b20b26 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -0,0 +1,51 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _MSM_VIDC_COMMON_H_ +#define _MSM_VIDC_COMMON_H_ + +#include + +#include "msm_vidc_internal.h" + +struct getprop_buf { + struct list_head list; + void *data; +}; + +struct vidc_core *vidc_get_core(int core_id); + +int vidc_comm_session_flush(struct vidc_inst *inst, u32 flags); + +int vidc_comm_get_bufreqs(struct vidc_inst *inst); +struct hal_buffer_requirements *get_buff_req_buffer(struct vidc_inst *inst, + u32 buffer_type); +/* TODO: delete above buffer requirements api's and use below one */ +int vidc_comm_bufrequirements(struct vidc_inst *inst, enum hal_buffer type, + struct hal_buffer_requirements *out); + +int hfi_core_suspend(struct vidc_core *core); +enum hal_extradata_id +vidc_comm_get_hal_extradata_index(enum v4l2_mpeg_vidc_extradata index); +enum hal_buffer_layout_type +vidc_comm_get_hal_buffer_layout(enum v4l2_mpeg_vidc_video_mvc_layout index); +enum multi_stream vidc_comm_get_stream_output_mode(struct vidc_inst *inst); +enum hal_buffer vidc_comm_get_hal_output_buffer(struct vidc_inst *inst); +enum hal_video_codec vidc_comm_hal_codec_type(u32 fourcc); +enum hal_domain vidc_comm_get_hal_domain(int session_type); +int vidc_comm_set_color_format(struct vidc_inst *inst, + enum hal_buffer buffer_type, u32 fourcc); +void vidc_inst_set_state(struct vidc_inst *inst, u32 state); +int vidc_comm_kill_session(struct vidc_inst *inst); + +#endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c new file mode 100644 index 000000000000..de82944a3f83 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -0,0 +1,372 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#define CREATE_TRACE_POINTS + +#include "msm_vidc_debug.h" +#include "hfi/vidc_hfi_api.h" + +int vidc_debug = VIDC_ERR | VIDC_WARN; +int vidc_debug_out = VIDC_OUT_PRINTK; +int vidc_fw_debug = 0x18; +int vidc_fw_debug_mode = 1; +int vidc_fw_low_power_mode = 1; +int vidc_hw_rsp_timeout = 1000; +int vidc_fw_coverage = 0; +int vidc_vpe_csc_601_to_709 = 0; +int vidc_dec_dcvs_mode = 1; +int vidc_enc_dcvs_mode = 1; +int vidc_sys_idle_indicator = 0; +int vidc_firmware_unload_delay = 15000; +int vidc_thermal_mitigation_disabled = 0; + +#define MAX_DBG_BUF_SIZE 4096 + +struct debug_buffer { + char ptr[MAX_DBG_BUF_SIZE]; + char *curr; + u32 filled_size; +}; + +static struct debug_buffer dbg_buf; + +#define INIT_DBG_BUF(__buf) ({ \ + __buf.curr = __buf.ptr;\ + __buf.filled_size = 0; \ +}) + +#define DYNAMIC_BUF_OWNER(__binfo) ({ \ + atomic_read(&__binfo->ref_count) == 2 ? "video driver" : "firmware";\ +}) + +static int core_info_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static u32 write_str(struct debug_buffer *buffer, const char *fmt, ...) +{ + va_list args; + u32 size; + va_start(args, fmt); + size = vscnprintf(buffer->curr, MAX_DBG_BUF_SIZE - 1, fmt, args); + va_end(args); + buffer->curr += size; + buffer->filled_size += size; + return size; +} + +static ssize_t core_info_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct vidc_core *core = file->private_data; + struct hfi_device *hdev; + int i = 0; + if (!core || !core->hfidev) { + dprintk(VIDC_ERR, "Invalid params, core: %p\n", core); + return 0; + } + hdev = core->hfidev; + INIT_DBG_BUF(dbg_buf); + write_str(&dbg_buf, "===============================\n"); + write_str(&dbg_buf, "CORE %d: %p\n", core->id, core); + write_str(&dbg_buf, "===============================\n"); + write_str(&dbg_buf, "state: %d\n", core->state); + for (i = SYS_MSG_START; i < SYS_MSG_END; i++) { + write_str(&dbg_buf, "completions[%d]: %s\n", i, + completion_done(&core->done) ? + "pending" : "done"); + } + return simple_read_from_buffer(buf, count, ppos, + dbg_buf.ptr, dbg_buf.filled_size); +} + +static const struct file_operations core_info_fops = { + .open = core_info_open, + .read = core_info_read, +}; + +static int trigger_ssr_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) { + u32 ssr_trigger_val; + int rc; + struct vidc_core *core = filp->private_data; + rc = sscanf(buf, "%d", &ssr_trigger_val); + if (rc < 0) { + dprintk(VIDC_WARN, "returning error err %d\n", rc); + rc = -EINVAL; + } else { + vidc_trigger_ssr(core, ssr_trigger_val); + rc = count; + } + return rc; +} + +static const struct file_operations ssr_fops = { + .open = trigger_ssr_open, + .write = trigger_ssr_write, +}; + +struct dentry *vidc_debugfs_init_drv(void) +{ + bool ok = false; + struct dentry *dir = debugfs_create_dir("msm_vidc", NULL); + if (IS_ERR_OR_NULL(dir)) { + dir = NULL; + goto failed_create_dir; + } + +#define __debugfs_create(__type, __name, __value) ({ \ + struct dentry *f = debugfs_create_##__type(__name, S_IRUGO | S_IWUSR, \ + dir, __value); \ + if (IS_ERR_OR_NULL(f)) { \ + dprintk(VIDC_ERR, "Failed creating debugfs file '%pd/%s'\n", \ + dir, __name); \ + f = NULL; \ + } \ + f; \ +}) + + ok = + __debugfs_create(x32, "debug_level", &vidc_debug) && + __debugfs_create(x32, "fw_level", &vidc_fw_debug) && + __debugfs_create(u32, "fw_debug_mode", &vidc_fw_debug_mode) && + __debugfs_create(bool, "fw_coverage", &vidc_fw_coverage) && + __debugfs_create(bool, "dcvs_dec_mode", &vidc_dec_dcvs_mode) && + __debugfs_create(bool, "dcvs_enc_mode", &vidc_enc_dcvs_mode) && + __debugfs_create(u32, "fw_low_power_mode", &vidc_fw_low_power_mode) && + __debugfs_create(u32, "debug_output", &vidc_debug_out) && + __debugfs_create(u32, "hw_rsp_timeout", &vidc_hw_rsp_timeout) && + __debugfs_create(bool, "enable_vpe_csc_601_709", + &vidc_vpe_csc_601_to_709) && + __debugfs_create(bool, "sys_idle_indicator", + &vidc_sys_idle_indicator) && + __debugfs_create(u32, "firmware_unload_delay", + &vidc_firmware_unload_delay) && + __debugfs_create(bool, "disable_thermal_mitigation", + &vidc_thermal_mitigation_disabled); + +#undef __debugfs_create + + if (!ok) + goto failed_create_dir; + + return dir; + +failed_create_dir: + if (dir) + debugfs_remove_recursive(vidc_driver->debugfs_root); + + return NULL; +} + +struct dentry *vidc_debugfs_init_core(struct vidc_core *core, + struct dentry *parent) +{ + struct dentry *dir = NULL; + char debugfs_name[MAX_DEBUGFS_NAME]; + + if (!core) { + dprintk(VIDC_ERR, "Invalid params, core: %p\n", core); + goto failed_create_dir; + } + + snprintf(debugfs_name, MAX_DEBUGFS_NAME, "core%d", core->id); + dir = debugfs_create_dir(debugfs_name, parent); + if (!dir) { + dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("info", S_IRUGO, dir, core, &core_info_fops)) { + dprintk(VIDC_ERR, "debugfs_create_file: fail\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("trigger_ssr", S_IWUSR, + dir, core, &ssr_fops)) { + dprintk(VIDC_ERR, "debugfs_create_file: fail\n"); + goto failed_create_dir; + } +failed_create_dir: + return dir; +} + +static int inst_info_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t inst_info_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct vidc_inst *inst = file->private_data; + int i, j; + if (!inst) { + dprintk(VIDC_ERR, "Invalid params, core: %p\n", inst); + return 0; + } + INIT_DBG_BUF(dbg_buf); + write_str(&dbg_buf, "===============================\n"); + write_str(&dbg_buf, "INSTANCE: %p (%s)\n", inst, + inst->session_type == VIDC_ENCODER ? "Encoder" : "Decoder"); + write_str(&dbg_buf, "===============================\n"); + write_str(&dbg_buf, "core: %p\n", inst->core); + write_str(&dbg_buf, "height: %d\n", inst->height); + write_str(&dbg_buf, "width: %d\n", inst->width); + write_str(&dbg_buf, "fps: %d\n", inst->fps); + write_str(&dbg_buf, "state: %d\n", inst->state); + write_str(&dbg_buf, "secure: %d\n", !!(inst->flags & VIDC_SECURE)); + write_str(&dbg_buf, "-----------Formats-------------\n"); + for (i = 0; i < MAX_PORT_NUM; i++) { + const struct vidc_format *fmt; + + if (i == OUTPUT_PORT) + fmt = inst->fmt_out; + else + fmt = inst->fmt_cap; + + write_str(&dbg_buf, "capability: %s\n", i == OUTPUT_PORT ? + "Output" : "Capture"); + write_str(&dbg_buf, "pixformat : %x\n", fmt->pixfmt); + write_str(&dbg_buf, "planes : %d\n", fmt->num_planes); + write_str(&dbg_buf, "type: %s\n", fmt->type == OUTPUT_PORT ? + "Output" : "Capture"); + switch (inst->buffer_mode[i]) { + case HAL_BUFFER_MODE_STATIC: + write_str(&dbg_buf, "buffer mode : %s\n", "static"); + break; + case HAL_BUFFER_MODE_RING: + write_str(&dbg_buf, "buffer mode : %s\n", "ring"); + break; + case HAL_BUFFER_MODE_DYNAMIC: + write_str(&dbg_buf, "buffer mode : %s\n", "dynamic"); + break; + default: + write_str(&dbg_buf, "buffer mode : unsupported\n"); + } + + if (i == OUTPUT_PORT) + write_str(&dbg_buf, "count: %u\n", + inst->bufq_out.num_buffers); + else + write_str(&dbg_buf, "count: %u\n", + inst->bufq_cap.num_buffers); + + for (j = 0; j < fmt->num_planes; j++) + write_str(&dbg_buf, "size for plane %d: %u\n", j, + i == 0 ? inst->bufq_out.plane_sizes[j] : + inst->bufq_cap.plane_sizes[j]); + + if (i < MAX_PORT_NUM - 1) + write_str(&dbg_buf, "\n"); + } + write_str(&dbg_buf, "-------------------------------\n"); + for (i = SESSION_MSG_START; i < SESSION_MSG_END; i++) { + write_str(&dbg_buf, "completions[%d]: %s\n", i, + completion_done(&inst->done) ? + "pending" : "done"); + } + write_str(&dbg_buf, "ETB Count: %d\n", inst->count.etb); + write_str(&dbg_buf, "EBD Count: %d\n", inst->count.ebd); + write_str(&dbg_buf, "FTB Count: %d\n", inst->count.ftb); + write_str(&dbg_buf, "FBD Count: %d\n", inst->count.fbd); + + return simple_read_from_buffer(buf, count, ppos, + dbg_buf.ptr, dbg_buf.filled_size); +} + +static const struct file_operations inst_info_fops = { + .open = inst_info_open, + .read = inst_info_read, +}; + +struct dentry *vidc_debugfs_init_inst(struct vidc_inst *inst, + struct dentry *parent) +{ + struct dentry *dir = NULL; + char debugfs_name[MAX_DEBUGFS_NAME]; + if (!inst) { + dprintk(VIDC_ERR, "Invalid params, inst: %p\n", inst); + goto failed_create_dir; + } + snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%p", inst); + dir = debugfs_create_dir(debugfs_name, parent); + if (!dir) { + dprintk(VIDC_ERR, "Failed to create debugfs for msm_vidc\n"); + goto failed_create_dir; + } + if (!debugfs_create_file("info", S_IRUGO, dir, inst, &inst_info_fops)) { + dprintk(VIDC_ERR, "debugfs_create_file: fail\n"); + goto failed_create_dir; + } + inst->debug.pdata[FRAME_PROCESSING].sampling = true; +failed_create_dir: + return dir; +} + +void vidc_debugfs_update(struct vidc_inst *inst, + enum msm_vidc_debugfs_event e) +{ + struct vidc_debug *d = &inst->debug; + char a[64] = "Frame processing"; + switch (e) { + case MSM_VIDC_DEBUGFS_EVENT_ETB: + mutex_lock(&inst->lock); + inst->count.etb++; + mutex_unlock(&inst->lock); + if (inst->count.ebd && inst->count.ftb > inst->count.fbd) { + d->pdata[FRAME_PROCESSING].name[0] = '\0'; + tic(inst, FRAME_PROCESSING, a); + } + break; + case MSM_VIDC_DEBUGFS_EVENT_EBD: + mutex_lock(&inst->lock); + inst->count.ebd++; + mutex_unlock(&inst->lock); + if (inst->count.ebd && inst->count.ebd == inst->count.etb) { + toc(inst, FRAME_PROCESSING); + dprintk(VIDC_PROF, "EBD: FW needs input buffers\n"); + } + if (inst->count.ftb == inst->count.fbd) + dprintk(VIDC_PROF, "EBD: FW needs output buffers\n"); + break; + case MSM_VIDC_DEBUGFS_EVENT_FTB: { + inst->count.ftb++; + if (inst->count.ebd && inst->count.etb > inst->count.ebd) { + d->pdata[FRAME_PROCESSING].name[0] = '\0'; + tic(inst, FRAME_PROCESSING, a); + } + } + break; + case MSM_VIDC_DEBUGFS_EVENT_FBD: + inst->debug.samples++; + if (inst->count.ebd && inst->count.fbd == inst->count.ftb) { + toc(inst, FRAME_PROCESSING); + dprintk(VIDC_PROF, "FBD: FW needs output buffers\n"); + } + if (inst->count.etb == inst->count.ebd) + dprintk(VIDC_PROF, "FBD: FW needs input buffers\n"); + break; + default: + dprintk(VIDC_ERR, "Invalid state in debugfs: %d\n", e); + break; + } +} + diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.h b/drivers/media/platform/msm/vidc/msm_vidc_debug.h new file mode 100644 index 000000000000..e07bb20f1cc9 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.h @@ -0,0 +1,170 @@ +/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MSM_VIDC_DEBUG__ +#define __MSM_VIDC_DEBUG__ + +#include +#include + +#include "msm_vidc_internal.h" + +#ifndef VIDC_DBG_LABEL +#define VIDC_DBG_LABEL "msm_vidc" +#endif + +#define VIDC_DBG_TAG VIDC_DBG_LABEL ": %4s: " + +/* To enable messages OR these values and + * echo the result to debugfs file. + * + * To enable all messages set debug_level = 0x101F + */ + +enum vidc_msg_prio { + VIDC_ERR = 0x0001, + VIDC_WARN = 0x0002, + VIDC_INFO = 0x0004, + VIDC_DBG = 0x0008, + VIDC_PROF = 0x0010, + VIDC_PKT = 0x0020, + VIDC_FW = 0x1000, +}; + +enum vidc_msg_out { + VIDC_OUT_PRINTK = 0, + VIDC_OUT_FTRACE, +}; + +enum msm_vidc_debugfs_event { + MSM_VIDC_DEBUGFS_EVENT_ETB, + MSM_VIDC_DEBUGFS_EVENT_EBD, + MSM_VIDC_DEBUGFS_EVENT_FTB, + MSM_VIDC_DEBUGFS_EVENT_FBD, +}; + +extern int vidc_debug; +extern int vidc_debug_out; +extern int vidc_fw_debug; +extern int vidc_fw_debug_mode; +extern int vidc_fw_low_power_mode; +extern int vidc_hw_rsp_timeout; +extern int vidc_fw_coverage; +extern int vidc_vpe_csc_601_to_709; +extern int vidc_dec_dcvs_mode; +extern int vidc_enc_dcvs_mode; +extern int vidc_sys_idle_indicator; +extern int vidc_firmware_unload_delay; +extern int vidc_thermal_mitigation_disabled; + +#define VIDC_MSG_PRIO2STRING(__level) ({ \ + char *__str; \ + \ + switch (__level) { \ + case VIDC_ERR: \ + __str = "err"; \ + break; \ + case VIDC_WARN: \ + __str = "warn"; \ + break; \ + case VIDC_INFO: \ + __str = "info"; \ + break; \ + case VIDC_DBG: \ + __str = "dbg"; \ + break; \ + case VIDC_PROF: \ + __str = "prof"; \ + break; \ + case VIDC_PKT: \ + __str = "pkt"; \ + break; \ + case VIDC_FW: \ + __str = "fw"; \ + break; \ + default: \ + __str = "????"; \ + break; \ + } \ + \ + __str; \ + }) + +#define dprintk(__level, __fmt, arg...) \ + do { \ + if (vidc_debug & __level) { \ + if (vidc_debug_out == VIDC_OUT_PRINTK) { \ + pr_info(VIDC_DBG_TAG __fmt, \ + VIDC_MSG_PRIO2STRING(__level), \ + ## arg); \ + } else if (vidc_debug_out == VIDC_OUT_FTRACE) { \ + trace_printk(KERN_DEBUG VIDC_DBG_TAG __fmt, \ + VIDC_MSG_PRIO2STRING(__level), \ + ## arg); \ + } \ + } \ + } while (0) + +struct dentry *vidc_debugfs_init_drv(void); +struct dentry *vidc_debugfs_init_core(struct vidc_core *core, + struct dentry *parent); +struct dentry *vidc_debugfs_init_inst(struct vidc_inst *inst, + struct dentry *parent); +void vidc_debugfs_update(struct vidc_inst *inst, enum msm_vidc_debugfs_event e); + +static inline void tic(struct vidc_inst *i, enum profiling_points p, char *b) +{ + struct timeval __ddl_tv; + if (!i->debug.pdata[p].name[0]) + memcpy(i->debug.pdata[p].name, b, 64); + if ((vidc_debug & VIDC_PROF) && i->debug.pdata[p].sampling) { + do_gettimeofday(&__ddl_tv); + i->debug.pdata[p].start = + (__ddl_tv.tv_sec * 1000) + (__ddl_tv.tv_usec / 1000); + i->debug.pdata[p].sampling = false; + } +} + +static inline void toc(struct vidc_inst *i, enum profiling_points p) +{ + struct timeval __ddl_tv; + if ((vidc_debug & VIDC_PROF) && !i->debug.pdata[p].sampling) { + do_gettimeofday(&__ddl_tv); + i->debug.pdata[p].stop = (__ddl_tv.tv_sec * 1000) + + (__ddl_tv.tv_usec / 1000); + i->debug.pdata[p].cumulative += i->debug.pdata[p].stop - + i->debug.pdata[p].start; + i->debug.pdata[p].sampling = true; + } +} + +static inline void show_stats(struct vidc_inst *i) +{ + int x; + for (x = 0; x < MAX_PROFILING_POINTS; x++) { + if (i->debug.pdata[x].name[0] && (vidc_debug & VIDC_PROF)) { + if (i->debug.samples) { + dprintk(VIDC_PROF, "%s averaged %d ms/sample\n", + i->debug.pdata[x].name, + i->debug.pdata[x].cumulative / + i->debug.samples); + } + + dprintk(VIDC_PROF, "%s Samples: %d\n", + i->debug.pdata[x].name, + i->debug.samples); + } + } +} + +#endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h new file mode 100644 index 000000000000..24241d0c4570 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -0,0 +1,308 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _MSM_VIDC_INTERNAL_H_ +#define _MSM_VIDC_INTERNAL_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "msm_media_info.h" +#include "hfi/vidc_hfi_api.h" + +#define VIDC_DRV_NAME "vidc" +#define VIDC_VERSION KERNEL_VERSION(1, 0, 0); +#define MAX_DEBUGFS_NAME 50 +#define DEFAULT_TIMEOUT 3 +#define DEFAULT_HEIGHT 1088 +#define DEFAULT_WIDTH 1920 +#define MIN_SUPPORTED_WIDTH 32 +#define MIN_SUPPORTED_HEIGHT 32 + +/* Maintains the number of FTB's between each FBD over a window */ +#define DCVS_FTB_WINDOW 32 + +#define V4L2_EVENT_VIDC_BASE 10 + +#define SYS_MSG_START SYS_EVENT_CHANGE +#define SYS_MSG_END SYS_DEBUG +#define SESSION_MSG_START SESSION_LOAD_RESOURCE_DONE +#define SESSION_MSG_END SESSION_PROPERTY_INFO +#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START) +#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START) + +#define MAX_NAME_LENGTH 64 + +#define EXTRADATA_IDX(__num_planes) ((__num_planes) ? (__num_planes) - 1 : 0) + +enum vidc_ports { + OUTPUT_PORT, + CAPTURE_PORT, + MAX_PORT_NUM +}; + +/* define core states */ +#define CORE_UNINIT 0 +#define CORE_INIT 1 +#define CORE_INVALID 2 + +/* define instance states */ +#define INST_INVALID 1 +#define INST_UNINIT 2 +#define INST_OPEN 3 +#define INST_LOAD_RESOURCES 4 +#define INST_START 5 +#define INST_STOP 6 +#define INST_RELEASE_RESOURCES 7 +#define INST_CLOSE 8 + +struct vidc_list { + struct list_head list; + struct mutex lock; +}; + +static inline void INIT_VIDC_LIST(struct vidc_list *mlist) +{ + mutex_init(&mlist->lock); + INIT_LIST_HEAD(&mlist->list); +} + +struct vidc_internal_buf { + struct list_head list; + enum hal_buffer type; + struct smem *smem; +}; + +struct vidc_format { + u32 pixfmt; + int num_planes; + u32 type; + u32 (*get_framesize)(int plane, u32 height, u32 width); +}; + +struct vidc_drv { + struct mutex lock; + struct list_head cores; + int num_cores; + struct dentry *debugfs_root; + int thermal_level; +}; + +enum profiling_points { + SYS_INIT = 0, + SESSION_INIT, + LOAD_RESOURCES, + FRAME_PROCESSING, + FW_IDLE, + MAX_PROFILING_POINTS, +}; + +struct buf_count { + int etb; + int ftb; + int fbd; + int ebd; +}; + +struct dcvs_stats { + int num_ftb[DCVS_FTB_WINDOW]; + bool transition_turbo; + int ftb_index; + int ftb_counter; + bool prev_freq_lowered; + bool prev_freq_increased; + int threshold_disp_buf_high; + int threshold_disp_buf_low; + int load; + int load_low; + int load_high; + int min_threshold; + int max_threshold; + bool is_clock_scaled; + int etb_counter; + bool is_power_save_mode; + bool is_output_buff_added; + bool is_input_buff_added; + bool is_additional_buff_added; +}; + +struct profile_data { + int start; + int stop; + int cumulative; + char name[64]; + int sampling; + int average; +}; + +struct vidc_debug { + struct profile_data pdata[MAX_PROFILING_POINTS]; + int profile; + int samples; +}; + +enum vidc_modes { + VIDC_SECURE = 1 << 0, + VIDC_TURBO = 1 << 1, + VIDC_THUMBNAIL = 1 << 2, + VIDC_NOMINAL = 1 << 3, +}; + +enum core_id { + VIDC_CORE_VENUS = 0, + VIDC_CORE_Q6, + VIDC_CORES_MAX, +}; + +enum session_type { + VIDC_ENCODER = 0, + VIDC_DECODER, + VIDC_MAX_DEVICES, +}; + +struct vidc_core_capability { + struct hal_capability_supported width; + struct hal_capability_supported height; + struct hal_capability_supported frame_rate; + u32 pixelprocess_capabilities; + struct hal_capability_supported scale_x; + struct hal_capability_supported scale_y; + struct hal_capability_supported hier_p; + struct hal_capability_supported ltr_count; + struct hal_capability_supported mbs_per_frame; + struct hal_capability_supported secure_output2_threshold; + u32 capability_set; + enum hal_buffer_mode_type buffer_mode[MAX_PORT_NUM]; +}; + +struct vidc_core { + struct list_head list; + struct mutex lock; + int id; + void *hfidev; + struct video_device vdev_dec; + struct video_device vdev_enc; + struct v4l2_device v4l2_dev; + struct list_head instances; + struct dentry *debugfs_root; + unsigned int state; + struct completion done; + unsigned int error; + enum vidc_hfi_type hfi_type; + struct vidc_resources res; + u32 enc_codecs; + u32 dec_codecs; + struct rproc *rproc; + bool rproc_booted; + + int (*event_notify)(struct vidc_core *core, u32 device_id, u32 event); +}; + +struct vidc_inst { + struct list_head list; + struct mutex sync_lock, lock; + struct vidc_core *core; + + struct vidc_list scratchbufs; + struct vidc_list persistbufs; + struct vidc_list pending_getpropq; + struct vidc_list registeredbufs; + + struct list_head bufqueue; + struct mutex bufqueue_lock; + + int streamoff; + struct buffer_requirements buff_req; + void *mem_client; + struct vb2_queue bufq_out; + struct vb2_queue bufq_cap; + void *vb2_ctx_cap; + void *vb2_ctx_out; + + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl **ctrls; + struct v4l2_ctrl **cluster; + struct v4l2_fh fh; + + int (*empty_buf_done)(struct vidc_inst *inst, u32 addr, + u32 bytesused, u32 data_offset, u32 flags); + int (*fill_buf_done)(struct vidc_inst *inst, u32 addr, + u32 bytesused, u32 data_offset, u32 flags, + struct timeval *timestamp); + int (*event_notify)(struct vidc_inst *inst, u32 event, + struct vidc_cb_event *data); + + /* session fields */ + enum session_type session_type; + unsigned int state; + void *session; + u32 width; + u32 height; + u64 fps; + struct v4l2_fract timeperframe; + const struct vidc_format *fmt_out; + const struct vidc_format *fmt_cap; + struct completion done; + unsigned int error; + struct vidc_core_capability capability; + enum hal_buffer_mode_type buffer_mode[MAX_PORT_NUM]; + enum vidc_modes flags; + struct buf_count count; + bool in_reconfig; + u32 reconfig_width; + u32 reconfig_height; + + /* encoder fields */ + atomic_t seq_hdr_reqs; + + struct dentry *debugfs_root; + struct vidc_debug debug; +}; + +extern struct vidc_drv *vidc_driver; + +struct vidc_ctrl { + u32 id; + char name[MAX_NAME_LENGTH]; + enum v4l2_ctrl_type type; + s32 minimum; + s32 maximum; + s32 default_value; + u32 step; + u32 menu_skip_mask; + u32 flags; + const char * const *qmenu; +}; + +struct buffer_info { + struct list_head list; + struct vidc_buffer_addr_info bai; +}; + +int vidc_trigger_ssr(struct vidc_core *core, enum hal_ssr_trigger_type type); +int vidc_check_session_supported(struct vidc_inst *inst); +void vidc_queue_v4l2_event(struct vidc_inst *inst, int event_type); + +#endif diff --git a/drivers/media/platform/msm/vidc/msm_vidc_load.c b/drivers/media/platform/msm/vidc/msm_vidc_load.c new file mode 100644 index 000000000000..c59f8bf15d47 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_load.c @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include + +#include "msm_vidc_internal.h" +#include "msm_vidc_common.h" +#include "msm_vidc_debug.h" + +enum load_quirks { + LOAD_NO_QUIRKS = 0 << 0, + LOAD_IGNORE_TURBO_LOAD = 1 << 0, + LOAD_IGNORE_THUMBNAIL_LOAD = 1 << 1, +}; + +static inline bool is_turbo_session(struct vidc_inst *inst) +{ + return !!(inst->flags & VIDC_TURBO); +} + +static inline bool is_thumbnail_session(struct vidc_inst *inst) +{ + return !!(inst->flags & VIDC_THUMBNAIL); +} + +static inline bool is_nominal_session(struct vidc_inst *inst) +{ + return !!(inst->flags & VIDC_NOMINAL); +} + +static u32 get_mbs_per_sec(struct vidc_inst *inst) +{ + int mbs; + u32 w = inst->width; + u32 h = inst->height; + + mbs = (ALIGN(w, 16) / 16) * (ALIGN(h, 16) / 16); + + return mbs * inst->fps; +} + +static u32 get_inst_load(struct vidc_inst *inst, enum load_quirks quirks) +{ + u32 load; + + if (!(inst->state >= INST_OPEN && inst->state < INST_STOP)) + return 0; + + load = get_mbs_per_sec(inst); + + if (is_thumbnail_session(inst) && quirks & LOAD_IGNORE_THUMBNAIL_LOAD) + load = 0; + + if (is_turbo_session(inst) && !(quirks & LOAD_IGNORE_TURBO_LOAD)) + load = inst->core->res.max_load; + + return load; +} + +static u32 get_load(struct vidc_core *core, enum session_type type, + enum load_quirks quirks) +{ + struct vidc_inst *inst = NULL; + u32 mbs_per_sec = 0; + + mutex_lock(&core->lock); + list_for_each_entry(inst, &core->instances, list) { + if (inst->session_type != type) + continue; + + mbs_per_sec += get_inst_load(inst, quirks); + } + mutex_unlock(&core->lock); + + return mbs_per_sec; +} + +static int scale_clocks_load(struct vidc_core *core, u32 mbs_per_sec) +{ + struct clock_info *ci = &core->res.clock_set.clock_tbl[0]; + const struct load_freq_table *table = ci->load_freq_tbl; + unsigned long freq = table[0].freq; + int num_rows = ci->count; + int ret, i; + + if (!mbs_per_sec && num_rows > 1) { + freq = table[num_rows - 1].freq; + goto set_freq; + } + + for (i = 0; i < num_rows; i++) { + if (mbs_per_sec > table[i].load) + break; + freq = table[i].freq; + } + +set_freq: + + ret = clk_set_rate(ci->clk, freq); + if (ret) { + dprintk(VIDC_ERR, "Failed to set clock rate %lu (%d)\n", + freq, ret); + return ret; + } + + return 0; +} + +static u32 scale_clocks(struct vidc_core *core) +{ + u32 mbs_per_sec = get_load(core, VIDC_ENCODER, LOAD_NO_QUIRKS) + + get_load(core, VIDC_DECODER, LOAD_NO_QUIRKS); + + return scale_clocks_load(core, mbs_per_sec); +} + +void msm_comm_scale_clocks(struct vidc_core *core) +{ + if (scale_clocks(core)) { + dprintk(VIDC_WARN, "Failed to scale clocks. " + "Performance might be impacted\n"); + } +} + +int msm_comm_check_overloaded(struct vidc_core *core) +{ + enum load_quirks quirks; + u32 mbs_per_sec; + + quirks = LOAD_IGNORE_TURBO_LOAD | LOAD_IGNORE_THUMBNAIL_LOAD; + + mbs_per_sec = get_load(core, VIDC_DECODER, quirks) + + get_load(core, VIDC_ENCODER, quirks); + + if (mbs_per_sec > core->res.max_load) { + dprintk(VIDC_ERR, "%s: HW is overloaded, needed: %d max: %d\n", + __func__, mbs_per_sec, core->res.max_load); + return -EBUSY; + } + + return 0; +} diff --git a/drivers/media/platform/msm/vidc/msm_vidc_load.h b/drivers/media/platform/msm/vidc/msm_vidc_load.h new file mode 100644 index 000000000000..9822f3c5709b --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_load.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MSM_VIDC_LOAD_H__ +#define __MSM_VIDC_LOAD_H__ + +struct vidc_core; + +void msm_comm_scale_clocks(struct vidc_core *core); +int msm_comm_check_overloaded(struct vidc_core *core); + +#endif /* __MSM_VIDC_LOAD_H__ */ diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.c b/drivers/media/platform/msm/vidc/msm_vidc_resources.c new file mode 100644 index 000000000000..50d14dc32b6d --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.c @@ -0,0 +1,288 @@ +/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include + +#include "msm_vidc_internal.h" +#include "msm_vidc_resources.h" + +static const struct load_freq_table freq_table_8916[] = { + { 352800, 228570000 }, /* 1920x1088 @ 30 + 1280x720 @ 30 */ + { 244800, 160000000 }, /* 1920x1088 @ 30 */ + { 108000, 100000000 }, /* 1280x720 @ 30 */ +}; + +static const struct reg_value_pair reg_preset_8916[] = { + { 0xe0020, 0x05555556 }, + { 0xe0024, 0x05555556 }, + { 0x80124, 0x00000003 }, +}; + +static struct clock_info clks_8916[] = { + { .name = "core_clk", + .count = ARRAY_SIZE(freq_table_8916), + .load_freq_tbl = freq_table_8916, + }, + { .name = "iface_clk", }, + { .name = "bus_clk", }, +}; + +static int get_clock_table(struct vidc_resources *res) +{ + struct device *dev = &res->pdev->dev; + struct clock_set *clocks = &res->clock_set; + unsigned int i; + + clocks->clock_tbl = clks_8916; + clocks->count = ARRAY_SIZE(clks_8916); + + for (i = 0; i < clocks->count; i++) { + clks_8916[i].clk = devm_clk_get(dev, clks_8916[i].name); + if (IS_ERR(clks_8916[i].clk)) + return PTR_ERR(clks_8916[i].clk); + } + + return 0; +} + +int enable_clocks(struct vidc_resources *res) +{ + struct clock_set *clks = &res->clock_set; + struct clock_info *tbl = clks->clock_tbl; + int ret, i; + + for (i = 0; i < clks->count; i++) { + ret = clk_prepare_enable(tbl[i].clk); + if (ret) + goto err; + } + + return 0; +err: + while (--i) + clk_disable_unprepare(tbl[i].clk); + + return ret; +} + +void disable_clocks(struct vidc_resources *res) +{ + struct clock_set *clks = &res->clock_set; + struct clock_info *tbl = clks->clock_tbl; + int i; + + for (i = clks->count - 1; i >= 0; i--) + clk_disable_unprepare(tbl[i].clk); +} + +static void iommu_ctx_banks_detach(struct vidc_resources *res) +{ + struct context_bank_info *cb; + + list_for_each_entry(cb, &res->context_banks, list) { + if (cb->dev) + arm_iommu_detach_device(cb->dev); + if (cb->mapping) + arm_iommu_release_mapping(cb->mapping); + } +} + +static int iommu_ctx_bank_attach(struct context_bank_info *cb) +{ + struct bus_type *bus = &platform_bus_type; + struct addr_range *range = &cb->addr_range; + int ret; + + if (cb->is_secure) + bus = &msm_iommu_sec_bus_type; + + cb->mapping = arm_iommu_create_mapping(bus, range->start, + range->size, 0); + if (IS_ERR_OR_NULL(cb->mapping)) + return PTR_ERR(cb->mapping) ?: -ENODEV; + + ret = arm_iommu_attach_device(cb->dev, cb->mapping); + if (ret) + goto release_mapping; + + return 0; + +release_mapping: + arm_iommu_release_mapping(cb->mapping); + return ret; +} + +struct iommu_context { + const char *name; + u32 partition_buf_type; + u32 virt_addr_pool_start; + u32 virt_addr_pool_size; + bool is_secure; +}; + +static const struct iommu_context iommu_ctxs[] = { + { .name = "venus_ns", + .partition_buf_type = 0xfff, + /* non-secure addr pool from 1500 MB to 3548 MB */ + .virt_addr_pool_start = 0x5dc00000, + .virt_addr_pool_size = 0x8f000000, + .is_secure = false, + }, + { .name = "venus_sec_bitstream", + .partition_buf_type = 0x241, + /* secure bitstream addr pool from 1200 MB to 1500 MB */ + .virt_addr_pool_start = 0x4b000000, + .virt_addr_pool_size = 0x12c00000, + .is_secure = true, + }, + { .name = "venus_sec_pixel", + .partition_buf_type = 0x106, + /* secure pixel addr pool from 616 MB to 1200 MB */ + .virt_addr_pool_start = 0x25800000, + .virt_addr_pool_size = 0x25800000, + .is_secure = true, + }, + { .name = "venus_sec_non_pixel", + .partition_buf_type = 0x480, + /* secure non-pixel addr pool from 16 MB to 616 MB */ + .virt_addr_pool_start = 0x01000000, + .virt_addr_pool_size = 0x24800000, + .is_secure = true, + } +}; + +static int iommu_ctx_bank(struct vidc_resources *res, struct device_node *np, + const struct iommu_context *iommu_ctx) +{ + struct device *dev = &res->pdev->dev; + struct context_bank_info *cb; + int ret; + + cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL); + if (!cb) + return -ENOMEM; + + cb->name = np->name; + cb->buffer_type = iommu_ctx->partition_buf_type; + cb->addr_range.start = iommu_ctx->virt_addr_pool_start; + cb->addr_range.size = iommu_ctx->virt_addr_pool_size; + cb->is_secure = iommu_ctx->is_secure; + + cb->dev = msm_iommu_get_ctx(cb->name); + if (IS_ERR_OR_NULL(cb->dev)) { + dev_err(dev, "dt: failed to get context bank device for %s\n", + cb->name); + return PTR_ERR(cb->dev) ?: -ENODEV; + } + + ret = iommu_ctx_bank_attach(cb); + if (ret) + return ret; + + INIT_LIST_HEAD(&cb->list); + list_add_tail(&cb->list, &res->context_banks); + + return 0; +} + +static int iommu_ctx_banks(struct vidc_resources *res) +{ + struct device_node *np = res->pdev->dev.of_node, *cb; + int ret = 0, i; + + INIT_LIST_HEAD(&res->context_banks); + + for (i = 0; i < ARRAY_SIZE(iommu_ctxs); i++) { + cb = of_parse_phandle(np, "qcom,iommu-cb", i); + if (!cb) + continue; + + ret = iommu_ctx_bank(res, cb, &iommu_ctxs[i]); + if (ret) + break; + } + + if (ret) { + iommu_ctx_banks_detach(res); + return ret; + } + + return 0; +} + +int get_platform_resources(struct vidc_core *core) +{ + struct vidc_resources *res = &core->res; + struct platform_device *pdev = res->pdev; + struct device *dev = &pdev->dev; + struct device_node *np = pdev->dev.of_node; + const char *hfi_name = NULL, *propname; + int ret; + + res->load_freq_tbl = freq_table_8916; + res->load_freq_tbl_size = ARRAY_SIZE(freq_table_8916); + + res->reg_set.reg_tbl = reg_preset_8916; + res->reg_set.count = ARRAY_SIZE(reg_preset_8916); + + ret = of_property_read_string(np, "qcom,hfi", &hfi_name); + if (ret) { + dev_err(dev, "reading hfi type failed\n"); + return ret; + } + + if (!strcasecmp(hfi_name, "venus")) + core->hfi_type = VIDC_HFI_VENUS; + else if (!strcasecmp(hfi_name, "q6")) + core->hfi_type = VIDC_HFI_Q6; + else + return -EINVAL; + + ret = iommu_ctx_banks(&core->res); + if (ret) + return ret; + + propname = "qcom,enable-idle-indicator"; + res->sys_idle_indicator = of_property_read_bool(np, propname); + + propname = "qcom,hfi-version"; + ret = of_property_read_string(np, propname, &res->hfi_version); + if (ret) + dev_dbg(&pdev->dev, "legacy HFI packetization\n"); + + ret = get_clock_table(res); + if (ret) { + dev_err(dev, "load clock table failed (%d)\n", ret); + return ret; + } + + ret = of_property_read_u32(np, "qcom,max-hw-load", &res->max_load); + if (ret) { + dev_err(dev, "determine max load supported failed (%d)\n", ret); + return ret; + } + + propname = "qcom,sw-power-collapse"; + res->sw_power_collapsible = of_property_read_bool(np, propname); + + return 0; +} + +void put_platform_resources(struct vidc_core *core) +{ + iommu_ctx_banks_detach(&core->res); +} diff --git a/drivers/media/platform/msm/vidc/msm_vidc_resources.h b/drivers/media/platform/msm/vidc/msm_vidc_resources.h new file mode 100644 index 000000000000..a460bc2ac8d9 --- /dev/null +++ b/drivers/media/platform/msm/vidc/msm_vidc_resources.h @@ -0,0 +1,85 @@ +/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __MSM_VIDC_RESOURCES_H__ +#define __MSM_VIDC_RESOURCES_H__ + +#include + +struct load_freq_table { + u32 load; + unsigned long freq; +}; + +struct reg_value_pair { + u32 reg; + u32 value; +}; + +struct reg_set { + const struct reg_value_pair *reg_tbl; + int count; +}; + +struct addr_range { + u32 start; + u32 size; +}; + +struct context_bank_info { + struct list_head list; + const char *name; + u32 buffer_type; + bool is_secure; + struct addr_range addr_range; + struct device *dev; + struct dma_iommu_mapping *mapping; +}; + +struct clock_info { + const char *name; + struct clk *clk; + const struct load_freq_table *load_freq_tbl; + u32 count; /* == has_scaling iff count != 0 */ +}; + +struct clock_set { + struct clock_info *clock_tbl; + u32 count; +}; + +struct vidc_resources { + void __iomem *base; + unsigned int irq; + const struct load_freq_table *load_freq_tbl; + u32 load_freq_tbl_size; + struct reg_set reg_set; + u32 max_load; + struct platform_device *pdev; + struct clock_set clock_set; + bool sw_power_collapsible; + bool sys_idle_indicator; + struct list_head context_banks; + const char *hfi_version; +}; + +extern unsigned int vidc_pwr_collapse_delay; +struct vidc_core; + +int get_platform_resources(struct vidc_core *); +void put_platform_resources(struct vidc_core *); + +int enable_clocks(struct vidc_resources *); +void disable_clocks(struct vidc_resources *); + +#endif diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 99807f4bd39d..d0abe4a5cc47 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -369,7 +369,7 @@ enum v4l2_mpeg_video_bitrate_mode { enum v4l2_mpeg_video_header_mode { V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE = 0, V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME = 1, - + V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_I_FRAME = 2, }; #define V4L2_CID_MPEG_VIDEO_MAX_REF_PIC (V4L2_CID_MPEG_BASE+217) #define V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE (V4L2_CID_MPEG_BASE+218) @@ -380,6 +380,7 @@ enum v4l2_mpeg_video_multi_slice_mode { V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE = 0, V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB = 1, V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES = 2, + V4L2_MPEG_VIDEO_MULTI_SLICE_GOB = 3, }; #define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222) #define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) diff --git a/include/uapi/media/Kbuild b/include/uapi/media/Kbuild new file mode 100644 index 000000000000..684a730658b5 --- /dev/null +++ b/include/uapi/media/Kbuild @@ -0,0 +1,2 @@ +header-y += msm_vidc.h +header-y += msm-v4l2-controls.h diff --git a/include/uapi/media/msm-v4l2-controls.h b/include/uapi/media/msm-v4l2-controls.h new file mode 100644 index 000000000000..aa5dde669bf6 --- /dev/null +++ b/include/uapi/media/msm-v4l2-controls.h @@ -0,0 +1,446 @@ +#ifndef __MSM_V4L2_CONTROLS_H__ +#define __MSM_V4L2_CONTROLS_H__ + +#include + +/* MPEG-class control IDs specific to the msm_vidc driver */ +#define V4L2_CID_MPEG_MSM_VIDC_BASE (V4L2_CTRL_CLASS_MPEG | 0x2000) + +#define V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_PICTURE_TYPE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE+0) +#define V4L2_CID_MPEG_VIDC_VIDEO_KEEP_ASPECT_RATIO \ + (V4L2_CID_MPEG_MSM_VIDC_BASE+1) +#define V4L2_CID_MPEG_VIDC_VIDEO_POST_LOOP_DEBLOCKER_MODE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE+2) +#define V4L2_CID_MPEG_VIDC_VIDEO_DIVX_FORMAT \ + (V4L2_CID_MPEG_MSM_VIDC_BASE+3) +enum v4l2_mpeg_vidc_video_divx_format_type { + V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_4 = 0, + V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_5 = 1, + V4L2_MPEG_VIDC_VIDEO_DIVX_FORMAT_6 = 2, +}; +#define V4L2_CID_MPEG_VIDC_VIDEO_MB_ERROR_MAP_REPORTING \ + (V4L2_CID_MPEG_MSM_VIDC_BASE+4) +#define V4L2_CID_MPEG_VIDC_VIDEO_CONTINUE_DATA_TRANSFER \ + (V4L2_CID_MPEG_MSM_VIDC_BASE+5) + +#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_FORMAT (V4L2_CID_MPEG_MSM_VIDC_BASE+6) +enum v4l2_mpeg_vidc_video_stream_format { + V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_STARTCODES = 0, + V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_NAL_PER_BUFFER = 1, + V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_ONE_BYTE_LENGTH = 2, + V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_TWO_BYTE_LENGTH = 3, + V4L2_MPEG_VIDC_VIDEO_NAL_FORMAT_FOUR_BYTE_LENGTH = 4, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_OUTPUT_ORDER (V4L2_CID_MPEG_MSM_VIDC_BASE+7) +enum v4l2_mpeg_vidc_video_output_order { + V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DISPLAY = 0, + V4L2_MPEG_VIDC_VIDEO_OUTPUT_ORDER_DECODE = 1, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_RATE (V4L2_CID_MPEG_MSM_VIDC_BASE+8) +#define V4L2_CID_MPEG_VIDC_VIDEO_IDR_PERIOD (V4L2_CID_MPEG_MSM_VIDC_BASE+9) +#define V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES (V4L2_CID_MPEG_MSM_VIDC_BASE+10) +#define V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES (V4L2_CID_MPEG_MSM_VIDC_BASE+11) +#define V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_IFRAME (V4L2_CID_MPEG_MSM_VIDC_BASE+12) + +#define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL (V4L2_CID_MPEG_MSM_VIDC_BASE+13) +enum v4l2_mpeg_vidc_video_rate_control { + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF = 0, + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR = 1, + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR = 2, + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR = 3, + V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR = 4, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_ROTATION (V4L2_CID_MPEG_MSM_VIDC_BASE+14) +enum v4l2_mpeg_vidc_video_rotation { + V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_NONE = 0, + V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_90 = 1, + V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_180 = 2, + V4L2_CID_MPEG_VIDC_VIDEO_ROTATION_270 = 3, +}; +#define MSM_VIDC_BASE V4L2_CID_MPEG_MSM_VIDC_BASE +#define V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL (MSM_VIDC_BASE+15) +enum v4l2_mpeg_vidc_h264_cabac_model { + V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_0 = 0, + V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_1 = 1, + V4L2_CID_MPEG_VIDC_VIDEO_H264_CABAC_MODEL_2 = 2, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_MODE (MSM_VIDC_BASE+16) +enum v4l2_mpeg_vidc_video_intra_refresh_mode { + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_NONE = 0, + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC = 1, + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_ADAPTIVE = 2, + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_CYCLIC_ADAPTIVE = 3, + V4L2_CID_MPEG_VIDC_VIDEO_INTRA_REFRESH_RANDOM = 4, +}; +#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+17) +#define V4L2_CID_MPEG_VIDC_VIDEO_AIR_REF (V4L2_CID_MPEG_MSM_VIDC_BASE+18) +#define V4L2_CID_MPEG_VIDC_VIDEO_CIR_MBS (V4L2_CID_MPEG_MSM_VIDC_BASE+19) + +#define V4L2_CID_MPEG_VIDC_VIDEO_H263_PROFILE (V4L2_CID_MPEG_MSM_VIDC_BASE+20) +enum v4l2_mpeg_vidc_video_h263_profile { + V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BASELINE = 0, + V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_H320CODING = 1, + V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_BACKWARDCOMPATIBLE = 2, + V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV2 = 3, + V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_ISWV3 = 4, + V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHCOMPRESSION = 5, + V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERNET = 6, + V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_INTERLACE = 7, + V4L2_MPEG_VIDC_VIDEO_H263_PROFILE_HIGHLATENCY = 8, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_H263_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE+21) +enum v4l2_mpeg_vidc_video_h263_level { + V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_1_0 = 0, + V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_2_0 = 1, + V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_3_0 = 2, + V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_0 = 3, + V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_4_5 = 4, + V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_5_0 = 5, + V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_6_0 = 6, + V4L2_MPEG_VIDC_VIDEO_H263_LEVEL_7_0 = 7, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_H264_AU_DELIMITER \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 22) +enum v4l2_mpeg_vidc_video_h264_au_delimiter { + V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_DISABLED = 0, + V4L2_MPEG_VIDC_VIDEO_H264_AU_DELIMITER_ENABLED = 1 +}; +#define V4L2_CID_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 23) +enum v4l2_mpeg_vidc_video_sync_frame_decode { + V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_DISABLE = 0, + V4L2_MPEG_VIDC_VIDEO_SYNC_FRAME_DECODE_ENABLE = 1 +}; +#define V4L2_CID_MPEG_VIDC_VIDEO_SECURE (V4L2_CID_MPEG_MSM_VIDC_BASE+24) +#define V4L2_CID_MPEG_VIDC_VIDEO_EXTRADATA \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 25) +enum v4l2_mpeg_vidc_extradata { + V4L2_MPEG_VIDC_EXTRADATA_NONE = 0, + V4L2_MPEG_VIDC_EXTRADATA_MB_QUANTIZATION = 1, + V4L2_MPEG_VIDC_EXTRADATA_INTERLACE_VIDEO = 2, + V4L2_MPEG_VIDC_EXTRADATA_VC1_FRAMEDISP = 3, + V4L2_MPEG_VIDC_EXTRADATA_VC1_SEQDISP = 4, + V4L2_MPEG_VIDC_EXTRADATA_TIMESTAMP = 5, + V4L2_MPEG_VIDC_EXTRADATA_S3D_FRAME_PACKING = 6, + V4L2_MPEG_VIDC_EXTRADATA_FRAME_RATE = 7, + V4L2_MPEG_VIDC_EXTRADATA_PANSCAN_WINDOW = 8, + V4L2_MPEG_VIDC_EXTRADATA_RECOVERY_POINT_SEI = 9, + V4L2_MPEG_VIDC_EXTRADATA_MULTISLICE_INFO = 10, + V4L2_MPEG_VIDC_EXTRADATA_NUM_CONCEALED_MB = 11, + V4L2_MPEG_VIDC_EXTRADATA_METADATA_FILLER = 12, + V4L2_MPEG_VIDC_EXTRADATA_INPUT_CROP = 13, + V4L2_MPEG_VIDC_EXTRADATA_DIGITAL_ZOOM = 14, + V4L2_MPEG_VIDC_EXTRADATA_ASPECT_RATIO = 15, + V4L2_MPEG_VIDC_EXTRADATA_MPEG2_SEQDISP = 16, + V4L2_MPEG_VIDC_EXTRADATA_STREAM_USERDATA = 17, + V4L2_MPEG_VIDC_EXTRADATA_FRAME_QP = 18, + V4L2_MPEG_VIDC_EXTRADATA_FRAME_BITS_INFO = 19, + V4L2_MPEG_VIDC_EXTRADATA_LTR = 20, + V4L2_MPEG_VIDC_EXTRADATA_METADATA_MBI = 21, +}; + +#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_GOB \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 27) + +#define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_DELIVERY_MODE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 28) + +#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 29) +enum v4l2_mpeg_vidc_video_h264_vui_timing_info { + V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_DISABLED = 0, + V4L2_MPEG_VIDC_VIDEO_H264_VUI_TIMING_INFO_ENABLED = 1 +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_INPUT \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 30) +#define V4L2_CID_MPEG_VIDC_VIDEO_ALLOC_MODE_OUTPUT \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 31) +enum v4l2_mpeg_vidc_video_alloc_mode_type { + V4L2_MPEG_VIDC_VIDEO_STATIC = 0, + V4L2_MPEG_VIDC_VIDEO_RING = 1, + V4L2_MPEG_VIDC_VIDEO_DYNAMIC = 2, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_FRAME_ASSEMBLY \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 32) +enum v4l2_mpeg_vidc_video_assembly { + V4L2_MPEG_VIDC_FRAME_ASSEMBLY_DISABLE = 0, + V4L2_MPEG_VIDC_FRAME_ASSEMBLY_ENABLE = 1, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_PROFILE_LEVEL \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 33) +enum v4l2_mpeg_vidc_video_vp8_profile_level { + V4L2_MPEG_VIDC_VIDEO_VP8_UNUSED, + V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_0, + V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_1, + V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_2, + V4L2_MPEG_VIDC_VIDEO_VP8_VERSION_3, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 34) +enum v4l2_mpeg_vidc_video_h264_vui_bitstream_restrict { + V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_DISABLED = 0, + V4L2_MPEG_VIDC_VIDEO_H264_VUI_BITSTREAM_RESTRICT_ENABLED = 1 +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 35) +enum v4l2_mpeg_vidc_video_preserve_text_quality { + V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_DISABLED = 0, + V4L2_MPEG_VIDC_VIDEO_PRESERVE_TEXT_QUALITY_ENABLED = 1 +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 36) +enum v4l2_mpeg_vidc_video_deinterlace { + V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_DISABLED = 0, + V4L2_CID_MPEG_VIDC_VIDEO_DEINTERLACE_ENABLED = 1 +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_MPEG4_TIME_RESOLUTION \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 37) + +#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 38) +enum v4l2_mpeg_vidc_video_decoder_multi_stream { + V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_PRIMARY = 0, + V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_SECONDARY = 1, +}; +#define V4L2_CID_MPEG_VIDC_VIDEO_SCS_THRESHOLD \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 39) + +#define V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_LEVEL (V4L2_CID_MPEG_MSM_VIDC_BASE+40) +enum v4l2_mpeg_vidc_video_mpeg2_level { + V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_0 = 0, + V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_1 = 1, + V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_2 = 2, + V4L2_MPEG_VIDC_VIDEO_MPEG2_LEVEL_3 = 3, +}; +#define V4L2_CID_MPEG_VIDC_VIDEO_MPEG2_PROFILE (V4L2_CID_MPEG_MSM_VIDC_BASE+41) +enum v4l2_mpeg_vidc_video_mpeg2_profile { + V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SIMPLE = 0, + V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_MAIN = 1, + V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_422 = 2, + V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SNR_SCALABLE = 3, + V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_SPATIAL_SCALABLE = 4, + V4L2_MPEG_VIDC_VIDEO_MPEG2_PROFILE_HIGH = 5, +}; +#define V4L2_CID_MPEG_VIDC_VIDEO_REQUEST_SEQ_HEADER \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 42) + +#define V4L2_CID_MPEG_VIDC_VIDEO_MVC_BUFFER_LAYOUT \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 43) +enum v4l2_mpeg_vidc_video_mvc_layout { + V4L2_MPEG_VIDC_VIDEO_MVC_SEQUENTIAL = 0, + V4L2_MPEG_VIDC_VIDEO_MVC_TOP_BOTTOM = 1 +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MIN_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 44) +#define V4L2_CID_MPEG_VIDC_VIDEO_VP8_MAX_QP (V4L2_CID_MPEG_MSM_VIDC_BASE + 45) +#define V4L2_CID_MPEG_VIDC_VIDEO_CONCEAL_COLOR \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 46) + +#define V4L2_CID_MPEG_VIDC_VIDEO_LTRMODE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 47) + +enum v4l2_mpeg_vidc_video_ltrmode { + V4L2_MPEG_VIDC_VIDEO_LTR_MODE_DISABLE = 0, + V4L2_MPEG_VIDC_VIDEO_LTR_MODE_MANUAL = 1, + V4L2_MPEG_VIDC_VIDEO_LTR_MODE_PERIODIC = 2 +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_LTRCOUNT \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 48) + +#define V4L2_CID_MPEG_VIDC_VIDEO_USELTRFRAME \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 49) + +#define V4L2_CID_MPEG_VIDC_VIDEO_MARKLTRFRAME \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 50) + +#define V4L2_CID_MPEG_VIDC_VIDEO_HIER_P_NUM_LAYERS \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 51) + +#define V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 52) +enum v4l2_mpeg_vidc_video_rate_control_timestamp_mode { + V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_HONOR = 0, + V4L2_MPEG_VIDC_VIDEO_RATE_CONTROL_TIMESTAMP_MODE_IGNORE = 1, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 53) +enum vl42_mpeg_vidc_video_enable_initial_qp { + V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_IFRAME = 0x1, + V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_PFRAME = 0x2, + V4L2_CID_MPEG_VIDC_VIDEO_ENABLE_INITIAL_QP_BFRAME = 0x4, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_I_FRAME_QP \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 54) + +#define V4L2_CID_MPEG_VIDC_VIDEO_P_FRAME_QP \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 55) + +#define V4L2_CID_MPEG_VIDC_VIDEO_B_FRAME_QP \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 56) + +#define V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_X_RANGE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 57) + +#define V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_X_RANGE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 58) + +#define V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_X_RANGE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 59) + +#define V4L2_CID_MPEG_VIDC_VIDEO_IFRAME_Y_RANGE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 60) + +#define V4L2_CID_MPEG_VIDC_VIDEO_PFRAME_Y_RANGE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 61) + +#define V4L2_CID_MPEG_VIDC_VIDEO_BFRAME_Y_RANGE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 62) + +#define V4L2_CID_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 63) + +enum vl42_mpeg_vidc_video_vpx_error_resilience { + V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_DISABLED = 0, + V4L2_MPEG_VIDC_VIDEO_VPX_ERROR_RESILIENCE_ENABLED = 1, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_HEVC_PROFILE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 65) +enum v4l2_mpeg_video_hevc_profile { + V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN = 0, + V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN10 = 1, + V4L2_MPEG_VIDC_VIDEO_HEVC_PROFILE_MAIN_STILL_PIC = 2, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_HEVC_TIER_LEVEL \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 66) +enum v4l2_mpeg_video_hevc_level { + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_1 = 0, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_1 = 1, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2 = 2, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2 = 3, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_2_1 = 4, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_2_1 = 5, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3 = 6, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3 = 7, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_3_1 = 8, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_3_1 = 9, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4 = 10, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4 = 11, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_4_1 = 12, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_4_1 = 13, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5 = 14, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5 = 15, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_1 = 16, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_1 = 17, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_5_2 = 18, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_5_2 = 19, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6 = 20, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6 = 21, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_1 = 22, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_1 = 23, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_MAIN_TIER_LEVEL_6_2 = 24, + V4L2_MPEG_VIDC_VIDEO_HEVC_LEVEL_HIGH_TIER_LEVEL_6_2 = 25, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 67) + +enum vl42_mpeg_vidc_video_h264_svc_nal { + V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_DISABLED = 0, + V4L2_CID_MPEG_VIDC_VIDEO_H264_NAL_SVC_ENABLED = 1, +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_PERF_MODE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 68) + +enum v4l2_mpeg_vidc_video_perf_mode { + V4L2_MPEG_VIDC_VIDEO_PERF_MAX_QUALITY = 1, + V4L2_MPEG_VIDC_VIDEO_PERF_POWER_SAVE = 2 +}; + +#define V4L2_CID_MPEG_VIDC_VIDEO_HIER_B_NUM_LAYERS \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 69) + +#define V4L2_CID_MPEG_VIDC_VIDEO_SECURE_SCALING_THRESHOLD \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 70) + +#define V4L2_CID_MPEG_VIDC_VIDEO_NON_SECURE_OUTPUT2 \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 71) + +#define V4L2_CID_MPEG_VIDC_VIDEO_HYBRID_HIERP_MODE \ + (V4L2_CID_MPEG_MSM_VIDC_BASE + 72) + +/* Vendor extensions */ +#define V4L2_QCOM_BUF_FLAG_CODECCONFIG 0x10000 +#define V4L2_QCOM_BUF_FLAG_EOSEQ 0x20000 +#define V4L2_QCOM_BUF_TIMESTAMP_INVALID 0x40000 +#define V4L2_QCOM_BUF_FLAG_IDRFRAME 0x80000 /*Image is a IDR-frame*/ +#define V4L2_QCOM_BUF_FLAG_DECODEONLY 0x100000 +#define V4L2_QCOM_BUF_DATA_CORRUPT 0x200000 +#define V4L2_QCOM_BUF_DROP_FRAME 0x400000 +#define V4L2_QCOM_BUF_INPUT_UNSUPPORTED 0x800000 +#define V4L2_QCOM_BUF_FLAG_EOS 0x1000000 +#define V4L2_QCOM_BUF_TS_DISCONTINUITY 0x2000000 +#define V4L2_QCOM_BUF_TS_ERROR 0x4000000 +#define V4L2_QCOM_BUF_FLAG_READONLY 0x8000000 +#define V4L2_MSM_VIDC_BUF_START_CODE_NOT_FOUND 0x10000000 +#define V4L2_MSM_BUF_FLAG_YUV_601_709_CLAMP 0x20000000 +#define V4L2_MSM_BUF_FLAG_MBAFF 0x40000000 + +/* Capabilities */ +#define V4L2_CAP_QCOM_FRAMESKIP 0x2000 /* frame skipping is supported */ + +struct v4l2_qcom_frameskip { + __u64 maxframeinterval; + __u8 fpsvariance; +}; + +/* Encoder commands */ +#define V4L2_ENC_QCOM_CMD_FLUSH (4) + +/* Decoder commands */ +#define V4L2_DEC_QCOM_CMD_FLUSH (4) + +/* Flags for V4L2_DEC_QCOM_CMD_FLUSH */ +#define V4L2_DEC_QCOM_CMD_FLUSH_OUTPUT (1 << 0) +#define V4L2_DEC_QCOM_CMD_FLUSH_CAPTURE (1 << 1) + +#define V4L2_QCOM_CMD_FLUSH_OUTPUT (1 << 0) +#define V4L2_QCOM_CMD_FLUSH_CAPTURE (1 << 1) + +/* Events */ +#define V4L2_EVENT_MSM_VIDC_START (V4L2_EVENT_PRIVATE_START + 0x00001000) +#define V4L2_EVENT_MSM_VIDC_FLUSH_DONE (V4L2_EVENT_MSM_VIDC_START + 1) +#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_SUFFICIENT \ + (V4L2_EVENT_MSM_VIDC_START + 2) +#define V4L2_EVENT_MSM_VIDC_PORT_SETTINGS_CHANGED_INSUFFICIENT \ + (V4L2_EVENT_MSM_VIDC_START + 3) +#define V4L2_EVENT_MSM_VIDC_CLOSE_DONE (V4L2_EVENT_MSM_VIDC_START + 4) +#define V4L2_EVENT_MSM_VIDC_SYS_ERROR (V4L2_EVENT_MSM_VIDC_START + 5) +#define V4L2_EVENT_MSM_VIDC_RELEASE_BUFFER_REFERENCE \ + (V4L2_EVENT_MSM_VIDC_START + 6) +#define V4L2_EVENT_MSM_VIDC_RELEASE_UNQUEUED_BUFFER \ + (V4L2_EVENT_MSM_VIDC_START + 7) +#define V4L2_EVENT_MSM_VIDC_HW_OVERLOAD (V4L2_EVENT_MSM_VIDC_START + 8) +#define V4L2_EVENT_MSM_VIDC_MAX_CLIENTS (V4L2_EVENT_MSM_VIDC_START + 9) +#define V4L2_EVENT_MSM_VIDC_HW_UNSUPPORTED (V4L2_EVENT_MSM_VIDC_START + 10) + +#endif/* __MSM_V4L2_CONTROLS_H__ */