techpack: video: Video driver kernel project initial snapshot

This change brings msm vidc driver from base 4.19 kernel project.
It is the first source code snapshot from base kernel project.

Change-Id: I1d600c4e9459b9013f4b607890c52644f6d94f0c
Signed-off-by: Shivendra Kakrania <shiven@codeaurora.org>
This commit is contained in:
Shivendra Kakrania 2019-04-29 15:20:26 -07:00
commit 4ae4cb1749
45 changed files with 37996 additions and 2 deletions

View file

@ -1,3 +1,12 @@
# SPDX-License-Identifier: GPL-2.0-only
ccflags-y := -Wno-unused-function
obj-y := vid.o
# auto-detect subdirs
ifeq ($(CONFIG_ARCH_KONA), y)
include $(srctree)/techpack/video/config/konavid.conf
endif
ifeq ($(CONFIG_ARCH_KONA), y)
LINUXINCLUDE += -include $(srctree)/techpack/video/config/konavidconf.h
endif
obj-y +=msm/

1
config/konavid.conf Normal file
View file

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

6
config/konavidconf.h Normal file
View file

@ -0,0 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
#define CONFIG_MSM_VIDC_V4L2 1

27
msm/Makefile Normal file
View file

@ -0,0 +1,27 @@
# SPDX-License-Identifier: GPL-2.0-only
ccflags-y += -I$(srctree)/techpack/video/msm/vidc/ \
-I$(srctree)/drivers/devfreq/
msm-vidc-objs := vidc/msm_v4l2_vidc.o \
vidc/msm_v4l2_private.o \
vidc/msm_vidc_platform.o \
vidc/msm_vidc_common.o \
vidc/msm_vidc.o \
vidc/msm_vdec.o \
vidc/msm_venc.o \
vidc/msm_cvp_internal.o \
vidc/msm_cvp_external.o \
vidc/msm_smem.o \
vidc/msm_vidc_debug.o \
vidc/msm_vidc_res_parse.o \
vidc/venus_hfi.o \
vidc/hfi_response_handler.o \
vidc/hfi_packetization.o \
vidc/vidc_hfi.o \
vidc/msm_vidc_clocks.o \
vidc/msm_vidc_bus_iris1.o \
vidc/msm_vidc_bus_iris2.o \
vidc/msm_vidc_buffer_calculations.o
obj-$(CONFIG_MSM_VIDC_V4L2) := msm-vidc.o

68
msm/vidc/fixedpoint.h Normal file
View file

@ -0,0 +1,68 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*/
#ifdef _FIXP_ARITH_H
#error "This implementation is meant to override fixp-arith.h, don't use both"
#endif
#ifndef _FIXEDPOINT_H_
#define _FIXEDPOINT_H_
#include <linux/types.h>
#include <linux/bits.h>
/*
* Normally would typedef'ed, but checkpatch doesn't like typedef.
* Also should be normally typedef'ed to intmax_t but that doesn't seem to be
* available in the kernel
*/
#define fp_t size_t
/* (Arbitrarily) make the first 25% of the bits to be the fractional bits */
#define FP_FRACTIONAL_BITS ((sizeof(fp_t) * 8) / 4)
#define FP(__i, __f_n, __f_d) \
((((fp_t)(__i)) << FP_FRACTIONAL_BITS) + \
(((__f_n) << FP_FRACTIONAL_BITS) / (__f_d)))
#define FP_INT(__i) FP(__i, 0, 1)
#define FP_ONE FP_INT(1)
#define FP_ZERO FP_INT(0)
static inline size_t fp_frac_base(void)
{
return GENMASK(FP_FRACTIONAL_BITS - 1, 0);
}
static inline size_t fp_frac(fp_t a)
{
return a & GENMASK(FP_FRACTIONAL_BITS - 1, 0);
}
static inline size_t fp_int(fp_t a)
{
return a >> FP_FRACTIONAL_BITS;
}
static inline size_t fp_round(fp_t a)
{
/* is the fractional part >= frac_max / 2? */
bool round_up = fp_frac(a) >= fp_frac_base() / 2;
return fp_int(a) + round_up;
}
static inline fp_t fp_mult(fp_t a, fp_t b)
{
return (a * b) >> FP_FRACTIONAL_BITS;
}
static inline fp_t fp_div(fp_t a, fp_t b)
{
return (a << FP_FRACTIONAL_BITS) / b;
}
#endif

View file

@ -0,0 +1,894 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#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.
*/
enum hal_domain vidc_get_hal_domain(u32 hfi_domain)
{
enum hal_domain hal_domain = 0;
switch (hfi_domain) {
case HFI_VIDEO_DOMAIN_VPE:
hal_domain = HAL_VIDEO_DOMAIN_VPE;
break;
case HFI_VIDEO_DOMAIN_ENCODER:
hal_domain = HAL_VIDEO_DOMAIN_ENCODER;
break;
case HFI_VIDEO_DOMAIN_DECODER:
hal_domain = HAL_VIDEO_DOMAIN_DECODER;
break;
case HFI_VIDEO_DOMAIN_CVP:
hal_domain = HAL_VIDEO_DOMAIN_CVP;
break;
default:
dprintk(VIDC_ERR, "%s: invalid domain %x\n",
__func__, hfi_domain);
hal_domain = 0;
break;
}
return hal_domain;
}
enum hal_video_codec vidc_get_hal_codec(u32 hfi_codec)
{
enum hal_video_codec hal_codec = 0;
switch (hfi_codec) {
case HFI_VIDEO_CODEC_H264:
hal_codec = HAL_VIDEO_CODEC_H264;
break;
case HFI_VIDEO_CODEC_MPEG1:
hal_codec = HAL_VIDEO_CODEC_MPEG1;
break;
case HFI_VIDEO_CODEC_MPEG2:
hal_codec = HAL_VIDEO_CODEC_MPEG2;
break;
case HFI_VIDEO_CODEC_VP8:
hal_codec = HAL_VIDEO_CODEC_VP8;
break;
case HFI_VIDEO_CODEC_HEVC:
hal_codec = HAL_VIDEO_CODEC_HEVC;
break;
case HFI_VIDEO_CODEC_VP9:
hal_codec = HAL_VIDEO_CODEC_VP9;
break;
case HFI_VIDEO_CODEC_TME:
hal_codec = HAL_VIDEO_CODEC_TME;
break;
case HFI_VIDEO_CODEC_CVP:
hal_codec = HAL_VIDEO_CODEC_CVP;
break;
default:
dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
__func__, hfi_codec);
hal_codec = 0;
break;
}
return hal_codec;
}
u32 vidc_get_hfi_domain(enum hal_domain hal_domain)
{
u32 hfi_domain;
switch (hal_domain) {
case HAL_VIDEO_DOMAIN_VPE:
hfi_domain = HFI_VIDEO_DOMAIN_VPE;
break;
case HAL_VIDEO_DOMAIN_ENCODER:
hfi_domain = HFI_VIDEO_DOMAIN_ENCODER;
break;
case HAL_VIDEO_DOMAIN_DECODER:
hfi_domain = HFI_VIDEO_DOMAIN_DECODER;
break;
case HAL_VIDEO_DOMAIN_CVP:
hfi_domain = HFI_VIDEO_DOMAIN_CVP;
break;
default:
dprintk(VIDC_ERR, "%s: invalid domain 0x%x\n",
__func__, hal_domain);
hfi_domain = 0;
break;
}
return hfi_domain;
}
u32 vidc_get_hfi_codec(enum hal_video_codec hal_codec)
{
u32 hfi_codec = 0;
switch (hal_codec) {
case HAL_VIDEO_CODEC_H264:
hfi_codec = HFI_VIDEO_CODEC_H264;
break;
case HAL_VIDEO_CODEC_MPEG1:
hfi_codec = HFI_VIDEO_CODEC_MPEG1;
break;
case HAL_VIDEO_CODEC_MPEG2:
hfi_codec = HFI_VIDEO_CODEC_MPEG2;
break;
case HAL_VIDEO_CODEC_VP8:
hfi_codec = HFI_VIDEO_CODEC_VP8;
break;
case HAL_VIDEO_CODEC_HEVC:
hfi_codec = HFI_VIDEO_CODEC_HEVC;
break;
case HAL_VIDEO_CODEC_VP9:
hfi_codec = HFI_VIDEO_CODEC_VP9;
break;
case HAL_VIDEO_CODEC_TME:
hfi_codec = HFI_VIDEO_CODEC_TME;
break;
case HAL_VIDEO_CODEC_CVP:
hfi_codec = HFI_VIDEO_CODEC_CVP;
break;
default:
dprintk(VIDC_INFO, "%s: invalid codec 0x%x\n",
__func__, hal_codec);
hfi_codec = 0;
break;
}
return hfi_codec;
}
int create_pkt_cmd_sys_init(struct hfi_cmd_sys_init_packet *pkt,
u32 arch_type)
{
int rc = 0;
if (!pkt)
return -EINVAL;
pkt->packet_type = HFI_CMD_SYS_INIT;
pkt->size = sizeof(struct hfi_cmd_sys_init_packet);
pkt->arch_type = arch_type;
return rc;
}
int create_pkt_cmd_sys_pc_prep(struct hfi_cmd_sys_pc_prep_packet *pkt)
{
int rc = 0;
if (!pkt)
return -EINVAL;
pkt->packet_type = HFI_CMD_SYS_PC_PREP;
pkt->size = sizeof(struct hfi_cmd_sys_pc_prep_packet);
return rc;
}
int create_pkt_cmd_sys_debug_config(
struct hfi_cmd_sys_set_property_packet *pkt,
u32 mode)
{
struct hfi_debug_config *hfi;
if (!pkt)
return -EINVAL;
pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
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 (msm_vidc_fw_debug_mode
<= (HFI_DEBUG_MODE_QUEUE | HFI_DEBUG_MODE_QDSS))
hfi->debug_mode = msm_vidc_fw_debug_mode;
return 0;
}
int create_pkt_cmd_sys_coverage_config(
struct hfi_cmd_sys_set_property_packet *pkt,
u32 mode)
{
if (!pkt) {
dprintk(VIDC_ERR, "In %s(), No input packet\n", __func__);
return -EINVAL;
}
pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
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;
}
int create_pkt_cmd_sys_set_resource(
struct hfi_cmd_sys_set_resource_packet *pkt,
struct vidc_resource_hdr *res_hdr,
void *res_value)
{
int rc = 0;
u32 i = 0;
if (!pkt || !res_hdr || !res_value) {
dprintk(VIDC_ERR,
"Invalid paramas pkt %pK res_hdr %pK res_value %pK\n",
pkt, res_hdr, res_value);
return -EINVAL;
}
pkt->packet_type = HFI_CMD_SYS_SET_RESOURCE;
pkt->size = sizeof(struct hfi_cmd_sys_set_resource_packet);
pkt->resource_handle = hash32_ptr(res_hdr->resource_handle);
switch (res_hdr->resource_id) {
case VIDC_RESOURCE_SYSCACHE:
{
struct hfi_resource_syscache_info_type *res_sc_info =
(struct hfi_resource_syscache_info_type *) res_value;
struct hfi_resource_subcache_type *res_sc =
(struct hfi_resource_subcache_type *)
&(res_sc_info->rg_subcache_entries[0]);
struct hfi_resource_syscache_info_type *hfi_sc_info =
(struct hfi_resource_syscache_info_type *)
&pkt->rg_resource_data[0];
struct hfi_resource_subcache_type *hfi_sc =
(struct hfi_resource_subcache_type *)
&(hfi_sc_info->rg_subcache_entries[0]);
pkt->resource_type = HFI_RESOURCE_SYSCACHE;
hfi_sc_info->num_entries = res_sc_info->num_entries;
pkt->size += (sizeof(struct hfi_resource_subcache_type))
* hfi_sc_info->num_entries;
for (i = 0; i < hfi_sc_info->num_entries; i++) {
hfi_sc[i] = res_sc[i];
dprintk(VIDC_DBG, "entry hfi#%d, sc_id %d, size %d\n",
i, hfi_sc[i].sc_id, hfi_sc[i].size);
}
break;
}
default:
dprintk(VIDC_ERR,
"Invalid resource_id %d\n", res_hdr->resource_id);
rc = -ENOTSUPP;
}
return rc;
}
int create_pkt_cmd_sys_release_resource(
struct hfi_cmd_sys_release_resource_packet *pkt,
struct vidc_resource_hdr *res_hdr)
{
int rc = 0;
if (!pkt || !res_hdr) {
dprintk(VIDC_ERR,
"Invalid paramas pkt %pK res_hdr %pK\n",
pkt, res_hdr);
return -EINVAL;
}
pkt->size = sizeof(struct hfi_cmd_sys_release_resource_packet);
pkt->packet_type = HFI_CMD_SYS_RELEASE_RESOURCE;
pkt->resource_handle = hash32_ptr(res_hdr->resource_handle);
switch (res_hdr->resource_id) {
case VIDC_RESOURCE_SYSCACHE:
pkt->resource_type = HFI_RESOURCE_SYSCACHE;
break;
default:
dprintk(VIDC_ERR,
"Invalid resource_id %d\n", res_hdr->resource_id);
rc = -ENOTSUPP;
}
dprintk(VIDC_DBG,
"rel_res: pkt_type 0x%x res_type 0x%x prepared\n",
pkt->packet_type, pkt->resource_type);
return rc;
}
inline int create_pkt_cmd_sys_session_init(
struct hfi_cmd_sys_session_init_packet *pkt,
struct hal_session *session,
u32 session_domain, u32 session_codec)
{
int rc = 0;
if (!pkt)
return -EINVAL;
pkt->size = sizeof(struct hfi_cmd_sys_session_init_packet);
pkt->packet_type = HFI_CMD_SYS_SESSION_INIT;
pkt->session_id = hash32_ptr(session);
pkt->session_domain = vidc_get_hfi_domain(session_domain);
pkt->session_codec = vidc_get_hfi_codec(session_codec);
if (!pkt->session_codec)
return -EINVAL;
return rc;
}
int create_pkt_cmd_sys_ubwc_config(
struct hfi_cmd_sys_set_property_packet *pkt,
struct msm_vidc_ubwc_config_data *ubwc_config)
{
int rc = 0;
struct hfi_cmd_sys_set_ubwc_config_packet_type *hfi;
if (!pkt)
return -EINVAL;
pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
sizeof(struct hfi_cmd_sys_set_ubwc_config_packet_type)
+ sizeof(u32);
pkt->packet_type = HFI_CMD_SYS_SET_PROPERTY;
pkt->num_properties = 1;
pkt->rg_property_data[0] = HFI_PROPERTY_SYS_UBWC_CONFIG;
hfi = (struct hfi_cmd_sys_set_ubwc_config_packet_type *)
&pkt->rg_property_data[1];
hfi->max_channels = ubwc_config->max_channels;
hfi->override_bit_info.max_channel_override =
ubwc_config->override_bit_info.max_channel_override;
hfi->mal_length = ubwc_config->mal_length;
hfi->override_bit_info.mal_length_override =
ubwc_config->override_bit_info.mal_length_override;
hfi->highest_bank_bit = ubwc_config->highest_bank_bit;
hfi->override_bit_info.hb_override =
ubwc_config->override_bit_info.hb_override;
hfi->bank_swzl_level = ubwc_config->bank_swzl_level;
hfi->override_bit_info.bank_swzl_level_override =
ubwc_config->override_bit_info.bank_swzl_level_override;
hfi->bank_spreading = ubwc_config->bank_spreading;
hfi->override_bit_info.bank_spreading_override =
ubwc_config->override_bit_info.bank_spreading_override;
return rc;
}
int create_pkt_cmd_session_cmd(struct vidc_hal_session_cmd_pkt *pkt,
int pkt_type, struct hal_session *session)
{
int rc = 0;
if (!pkt)
return -EINVAL;
pkt->size = sizeof(struct vidc_hal_session_cmd_pkt);
pkt->packet_type = pkt_type;
pkt->session_id = hash32_ptr(session);
return rc;
}
int create_pkt_cmd_sys_power_control(
struct hfi_cmd_sys_set_property_packet *pkt, u32 enable)
{
struct hfi_enable *hfi;
if (!pkt) {
dprintk(VIDC_ERR, "No input packet\n");
return -EINVAL;
}
pkt->size = sizeof(struct hfi_cmd_sys_set_property_packet) +
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 get_hfi_buffer(int hal_buffer)
{
u32 buffer;
switch (hal_buffer) {
case HAL_BUFFER_INPUT:
buffer = HFI_BUFFER_INPUT;
break;
case HAL_BUFFER_OUTPUT:
buffer = HFI_BUFFER_OUTPUT;
break;
case HAL_BUFFER_OUTPUT2:
buffer = HFI_BUFFER_OUTPUT2;
break;
case HAL_BUFFER_EXTRADATA_INPUT:
buffer = HFI_BUFFER_EXTRADATA_INPUT;
break;
case HAL_BUFFER_EXTRADATA_OUTPUT:
buffer = HFI_BUFFER_EXTRADATA_OUTPUT;
break;
case HAL_BUFFER_EXTRADATA_OUTPUT2:
buffer = HFI_BUFFER_EXTRADATA_OUTPUT2;
break;
case HAL_BUFFER_INTERNAL_SCRATCH:
buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH;
break;
case HAL_BUFFER_INTERNAL_SCRATCH_1:
buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_1;
break;
case HAL_BUFFER_INTERNAL_SCRATCH_2:
buffer = HFI_BUFFER_COMMON_INTERNAL_SCRATCH_2;
break;
case HAL_BUFFER_INTERNAL_PERSIST:
buffer = HFI_BUFFER_INTERNAL_PERSIST;
break;
case HAL_BUFFER_INTERNAL_PERSIST_1:
buffer = HFI_BUFFER_INTERNAL_PERSIST_1;
break;
default:
dprintk(VIDC_ERR, "Invalid buffer: %#x\n",
hal_buffer);
buffer = 0;
break;
}
return buffer;
}
int create_pkt_cmd_session_set_buffers(
struct hfi_cmd_session_set_buffers_packet *pkt,
struct hal_session *session,
struct vidc_buffer_addr_info *buffer_info)
{
int rc = 0;
u32 i = 0;
if (!pkt || !session)
return -EINVAL;
pkt->packet_type = HFI_CMD_SESSION_SET_BUFFERS;
pkt->session_id = hash32_ptr(session);
pkt->buffer_size = buffer_info->buffer_size;
pkt->min_buffer_size = buffer_info->buffer_size;
pkt->num_buffers = buffer_info->num_buffers;
if (buffer_info->buffer_type == HAL_BUFFER_OUTPUT ||
buffer_info->buffer_type == HAL_BUFFER_OUTPUT2) {
struct hfi_buffer_info *buff;
pkt->extra_data_size = buffer_info->extradata_size;
pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
sizeof(u32) + (buffer_info->num_buffers *
sizeof(struct hfi_buffer_info));
buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
for (i = 0; i < pkt->num_buffers; i++) {
buff->buffer_addr =
(u32)buffer_info->align_device_addr;
buff->extra_data_addr =
(u32)buffer_info->extradata_addr;
}
} else {
pkt->extra_data_size = 0;
pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
((buffer_info->num_buffers - 1) * sizeof(u32));
for (i = 0; i < pkt->num_buffers; i++) {
pkt->rg_buffer_info[i] =
(u32)buffer_info->align_device_addr;
}
}
pkt->buffer_type = get_hfi_buffer(buffer_info->buffer_type);
if (!pkt->buffer_type)
return -EINVAL;
return rc;
}
int create_pkt_cmd_session_release_buffers(
struct hfi_cmd_session_release_buffer_packet *pkt,
struct hal_session *session,
struct vidc_buffer_addr_info *buffer_info)
{
int rc = 0;
u32 i = 0;
if (!pkt || !session)
return -EINVAL;
pkt->packet_type = HFI_CMD_SESSION_RELEASE_BUFFERS;
pkt->session_id = hash32_ptr(session);
pkt->buffer_size = buffer_info->buffer_size;
pkt->num_buffers = buffer_info->num_buffers;
if (buffer_info->buffer_type == HAL_BUFFER_OUTPUT ||
buffer_info->buffer_type == HAL_BUFFER_OUTPUT2) {
struct hfi_buffer_info *buff;
buff = (struct hfi_buffer_info *) pkt->rg_buffer_info;
for (i = 0; i < pkt->num_buffers; i++) {
buff->buffer_addr =
(u32)buffer_info->align_device_addr;
buff->extra_data_addr =
(u32)buffer_info->extradata_addr;
}
pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) -
sizeof(u32) + (buffer_info->num_buffers *
sizeof(struct hfi_buffer_info));
} else {
for (i = 0; i < pkt->num_buffers; i++) {
pkt->rg_buffer_info[i] =
(u32)buffer_info->align_device_addr;
}
pkt->extra_data_size = 0;
pkt->size = sizeof(struct hfi_cmd_session_set_buffers_packet) +
((buffer_info->num_buffers - 1) * sizeof(u32));
}
pkt->response_req = buffer_info->response_required;
pkt->buffer_type = get_hfi_buffer(buffer_info->buffer_type);
if (!pkt->buffer_type)
return -EINVAL;
return rc;
}
int create_pkt_cmd_session_register_buffer(
struct hfi_cmd_session_register_buffers_packet *pkt,
struct hal_session *session,
struct vidc_register_buffer *buffer)
{
int rc = 0;
u32 i;
struct hfi_buffer_mapping_type *buf;
if (!pkt || !session) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
pkt->packet_type = HFI_CMD_SESSION_REGISTER_BUFFERS;
pkt->session_id = hash32_ptr(session);
pkt->client_data = buffer->client_data;
pkt->response_req = buffer->response_required;
pkt->num_buffers = 1;
pkt->size = sizeof(struct hfi_cmd_session_register_buffers_packet) -
sizeof(u32) + (pkt->num_buffers *
sizeof(struct hfi_buffer_mapping_type));
buf = (struct hfi_buffer_mapping_type *)pkt->buffer;
for (i = 0; i < pkt->num_buffers; i++) {
buf->index = buffer->index;
buf->device_addr = buffer->device_addr;
buf->size = buffer->size;
buf++;
}
return rc;
}
int create_pkt_cmd_session_unregister_buffer(
struct hfi_cmd_session_unregister_buffers_packet *pkt,
struct hal_session *session,
struct vidc_unregister_buffer *buffer)
{
int rc = 0;
u32 i;
struct hfi_buffer_mapping_type *buf;
if (!pkt || !session) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
pkt->packet_type = HFI_CMD_SESSION_UNREGISTER_BUFFERS;
pkt->session_id = hash32_ptr(session);
pkt->client_data = buffer->client_data;
pkt->response_req = buffer->response_required;
pkt->num_buffers = 1;
pkt->size = sizeof(struct hfi_cmd_session_unregister_buffers_packet) -
sizeof(u32) + (pkt->num_buffers *
sizeof(struct hfi_buffer_mapping_type));
buf = (struct hfi_buffer_mapping_type *)pkt->buffer;
for (i = 0; i < pkt->num_buffers; i++) {
buf->index = buffer->index;
buf->device_addr = buffer->device_addr;
buf->size = buffer->size;
buf++;
}
return rc;
}
int create_pkt_cmd_session_etb_decoder(
struct hfi_cmd_session_empty_buffer_compressed_packet *pkt,
struct hal_session *session, struct vidc_frame_data *input_frame)
{
int rc = 0;
if (!pkt || !session)
return -EINVAL;
pkt->size =
sizeof(struct hfi_cmd_session_empty_buffer_compressed_packet);
pkt->packet_type = HFI_CMD_SESSION_EMPTY_BUFFER;
pkt->session_id = hash32_ptr(session);
pkt->time_stamp_hi = upper_32_bits(input_frame->timestamp);
pkt->time_stamp_lo = lower_32_bits(input_frame->timestamp);
pkt->flags = input_frame->flags;
pkt->mark_target = input_frame->mark_target;
pkt->mark_data = input_frame->mark_data;
pkt->offset = input_frame->offset;
pkt->alloc_len = input_frame->alloc_len;
pkt->filled_len = input_frame->filled_len;
pkt->input_tag = input_frame->clnt_data;
pkt->packet_buffer = (u32)input_frame->device_addr;
trace_msm_v4l2_vidc_buffer_event_start("ETB",
input_frame->device_addr, input_frame->timestamp,
input_frame->alloc_len, input_frame->filled_len,
input_frame->offset);
if (!pkt->packet_buffer)
rc = -EINVAL;
return rc;
}
int create_pkt_cmd_session_etb_encoder(
struct hfi_cmd_session_empty_buffer_uncompressed_plane0_packet *pkt,
struct hal_session *session, struct vidc_frame_data *input_frame)
{
int rc = 0;
if (!pkt || !session)
return -EINVAL;
pkt->size = sizeof(struct
hfi_cmd_session_empty_buffer_uncompressed_plane0_packet);
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(input_frame->timestamp);
pkt->time_stamp_lo = lower_32_bits(input_frame->timestamp);
pkt->flags = input_frame->flags;
pkt->mark_target = input_frame->mark_target;
pkt->mark_data = input_frame->mark_data;
pkt->offset = input_frame->offset;
pkt->alloc_len = input_frame->alloc_len;
pkt->filled_len = input_frame->filled_len;
pkt->input_tag = input_frame->clnt_data;
pkt->packet_buffer = (u32)input_frame->device_addr;
pkt->extra_data_buffer = (u32)input_frame->extradata_addr;
trace_msm_v4l2_vidc_buffer_event_start("ETB",
input_frame->device_addr, input_frame->timestamp,
input_frame->alloc_len, input_frame->filled_len,
input_frame->offset);
if (!pkt->packet_buffer)
rc = -EINVAL;
return rc;
}
int create_pkt_cmd_session_ftb(struct hfi_cmd_session_fill_buffer_packet *pkt,
struct hal_session *session,
struct vidc_frame_data *output_frame)
{
int rc = 0;
if (!pkt || !session || !output_frame)
return -EINVAL;
pkt->size = sizeof(struct hfi_cmd_session_fill_buffer_packet);
pkt->packet_type = HFI_CMD_SESSION_FILL_BUFFER;
pkt->session_id = hash32_ptr(session);
if (output_frame->buffer_type == HAL_BUFFER_OUTPUT)
pkt->stream_id = 0;
else if (output_frame->buffer_type == HAL_BUFFER_OUTPUT2)
pkt->stream_id = 1;
if (!output_frame->device_addr)
return -EINVAL;
pkt->packet_buffer = (u32)output_frame->device_addr;
pkt->extra_data_buffer = (u32)output_frame->extradata_addr;
pkt->alloc_len = output_frame->alloc_len;
pkt->filled_len = output_frame->filled_len;
pkt->offset = output_frame->offset;
pkt->rgData[0] = output_frame->extradata_size;
trace_msm_v4l2_vidc_buffer_event_start("FTB",
output_frame->device_addr, output_frame->timestamp,
output_frame->alloc_len, output_frame->filled_len,
output_frame->offset);
return rc;
}
int create_pkt_cmd_session_get_buf_req(
struct hfi_cmd_session_get_property_packet *pkt,
struct hal_session *session)
{
int rc = 0;
if (!pkt || !session)
return -EINVAL;
pkt->size = sizeof(struct hfi_cmd_session_get_property_packet);
pkt->packet_type = HFI_CMD_SESSION_GET_PROPERTY;
pkt->session_id = hash32_ptr(session);
pkt->num_properties = 1;
pkt->rg_property_data[0] = HFI_PROPERTY_CONFIG_BUFFER_REQUIREMENTS;
return rc;
}
int create_pkt_cmd_session_flush(struct hfi_cmd_session_flush_packet *pkt,
struct hal_session *session, enum hal_flush flush_mode)
{
int rc = 0;
if (!pkt || !session)
return -EINVAL;
pkt->size = sizeof(struct hfi_cmd_session_flush_packet);
pkt->packet_type = HFI_CMD_SESSION_FLUSH;
pkt->session_id = hash32_ptr(session);
switch (flush_mode) {
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_ALL:
pkt->flush_type = HFI_FLUSH_ALL;
break;
default:
dprintk(VIDC_ERR, "Invalid flush mode: %#x\n", flush_mode);
return -EINVAL;
}
return rc;
}
int create_pkt_cmd_session_set_property(
struct hfi_cmd_session_set_property_packet *pkt,
struct hal_session *session,
u32 ptype, void *pdata, u32 size)
{
if (!pkt || !session)
return -EINVAL;
pkt->size = sizeof(struct hfi_cmd_session_set_property_packet);
pkt->packet_type = HFI_CMD_SESSION_SET_PROPERTY;
pkt->session_id = hash32_ptr(session);
pkt->num_properties = 1;
pkt->size += size;
pkt->rg_property_data[0] = ptype;
if (size && pdata)
memcpy(&pkt->rg_property_data[1], pdata, size);
dprintk(VIDC_DBG, "Setting HAL Property = 0x%x\n", ptype);
return 0;
}
static int get_hfi_ssr_type(enum hal_ssr_trigger_type type)
{
int rc = HFI_TEST_SSR_HW_WDOG_IRQ;
switch (type) {
case SSR_ERR_FATAL:
rc = HFI_TEST_SSR_SW_ERR_FATAL;
break;
case SSR_SW_DIV_BY_ZERO:
rc = HFI_TEST_SSR_SW_DIV_BY_ZERO;
break;
case SSR_HW_WDOG_IRQ:
rc = HFI_TEST_SSR_HW_WDOG_IRQ;
break;
default:
dprintk(VIDC_WARN,
"SSR trigger type not recognized, using WDOG.\n");
}
return rc;
}
int create_pkt_ssr_cmd(enum hal_ssr_trigger_type type,
struct hfi_cmd_sys_test_ssr_packet *pkt)
{
if (!pkt) {
dprintk(VIDC_ERR, "Invalid params, device: %pK\n", pkt);
return -EINVAL;
}
pkt->size = sizeof(struct hfi_cmd_sys_test_ssr_packet);
pkt->packet_type = HFI_CMD_SYS_TEST_SSR;
pkt->trigger_type = get_hfi_ssr_type(type);
return 0;
}
int create_pkt_cmd_sys_image_version(
struct hfi_cmd_sys_get_property_packet *pkt)
{
if (!pkt) {
dprintk(VIDC_ERR, "%s invalid param :%pK\n", __func__, pkt);
return -EINVAL;
}
pkt->size = sizeof(struct hfi_cmd_sys_get_property_packet);
pkt->packet_type = HFI_CMD_SYS_GET_PROPERTY;
pkt->num_properties = 1;
pkt->rg_property_data[0] = HFI_PROPERTY_SYS_IMAGE_VERSION;
return 0;
}
int create_pkt_cmd_session_sync_process(
struct hfi_cmd_session_sync_process_packet *pkt,
struct hal_session *session)
{
if (!pkt || !session)
return -EINVAL;
*pkt = (struct hfi_cmd_session_sync_process_packet) {0};
pkt->size = sizeof(*pkt);
pkt->packet_type = HFI_CMD_SESSION_SYNC;
pkt->session_id = hash32_ptr(session);
pkt->sync_id = 0;
return 0;
}
static struct hfi_packetization_ops hfi_default = {
.sys_init = create_pkt_cmd_sys_init,
.sys_pc_prep = create_pkt_cmd_sys_pc_prep,
.sys_power_control = create_pkt_cmd_sys_power_control,
.sys_set_resource = create_pkt_cmd_sys_set_resource,
.sys_debug_config = create_pkt_cmd_sys_debug_config,
.sys_coverage_config = create_pkt_cmd_sys_coverage_config,
.sys_release_resource = create_pkt_cmd_sys_release_resource,
.sys_image_version = create_pkt_cmd_sys_image_version,
.sys_ubwc_config = create_pkt_cmd_sys_ubwc_config,
.ssr_cmd = create_pkt_ssr_cmd,
.session_init = create_pkt_cmd_sys_session_init,
.session_cmd = create_pkt_cmd_session_cmd,
.session_set_buffers = create_pkt_cmd_session_set_buffers,
.session_release_buffers = create_pkt_cmd_session_release_buffers,
.session_register_buffer = create_pkt_cmd_session_register_buffer,
.session_unregister_buffer = create_pkt_cmd_session_unregister_buffer,
.session_etb_decoder = create_pkt_cmd_session_etb_decoder,
.session_etb_encoder = create_pkt_cmd_session_etb_encoder,
.session_ftb = create_pkt_cmd_session_ftb,
.session_get_buf_req = create_pkt_cmd_session_get_buf_req,
.session_flush = create_pkt_cmd_session_flush,
.session_set_property = create_pkt_cmd_session_set_property,
};
struct hfi_packetization_ops *hfi_get_pkt_ops_handle(
enum hfi_packetization_type type)
{
dprintk(VIDC_DBG, "%s selected\n",
type == HFI_PACKETIZATION_4XX ?
"4xx packetization" : "Unknown hfi");
switch (type) {
case HFI_PACKETIZATION_4XX:
return &hfi_default;
}
return NULL;
}

View file

@ -0,0 +1,91 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef __HFI_PACKETIZATION_H__
#define __HFI_PACKETIZATION_H__
#include <linux/types.h>
#include "vidc_hfi_helper.h"
#include "vidc_hfi.h"
#include "vidc_hfi_api.h"
#define call_hfi_pkt_op(q, op, ...) \
(((q) && (q)->pkt_ops && (q)->pkt_ops->op) ? \
((q)->pkt_ops->op(__VA_ARGS__)) : 0)
enum hfi_packetization_type {
HFI_PACKETIZATION_4XX,
};
struct hfi_packetization_ops {
int (*sys_init)(struct hfi_cmd_sys_init_packet *pkt, u32 arch_type);
int (*sys_pc_prep)(struct hfi_cmd_sys_pc_prep_packet *pkt);
int (*sys_power_control)(struct hfi_cmd_sys_set_property_packet *pkt,
u32 enable);
int (*sys_set_resource)(
struct hfi_cmd_sys_set_resource_packet *pkt,
struct vidc_resource_hdr *resource_hdr,
void *resource_value);
int (*sys_debug_config)(struct hfi_cmd_sys_set_property_packet *pkt,
u32 mode);
int (*sys_coverage_config)(struct hfi_cmd_sys_set_property_packet *pkt,
u32 mode);
int (*sys_release_resource)(
struct hfi_cmd_sys_release_resource_packet *pkt,
struct vidc_resource_hdr *resource_hdr);
int (*sys_image_version)(struct hfi_cmd_sys_get_property_packet *pkt);
int (*sys_ubwc_config)(struct hfi_cmd_sys_set_property_packet *pkt,
struct msm_vidc_ubwc_config_data *ubwc_config);
int (*ssr_cmd)(enum hal_ssr_trigger_type type,
struct hfi_cmd_sys_test_ssr_packet *pkt);
int (*session_init)(
struct hfi_cmd_sys_session_init_packet *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_cmd_session_set_buffers_packet *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_register_buffer)(
struct hfi_cmd_session_register_buffers_packet *pkt,
struct hal_session *session,
struct vidc_register_buffer *buffer);
int (*session_unregister_buffer)(
struct hfi_cmd_session_unregister_buffers_packet *pkt,
struct hal_session *session,
struct vidc_unregister_buffer *buffer);
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_get_buf_req)(
struct hfi_cmd_session_get_property_packet *pkt,
struct hal_session *session);
int (*session_flush)(struct hfi_cmd_session_flush_packet *pkt,
struct hal_session *session, enum hal_flush flush_mode);
int (*session_set_property)(
struct hfi_cmd_session_set_property_packet *pkt,
struct hal_session *session,
u32 ptype, void *pdata, u32 size);
int (*session_sync_process)(
struct hfi_cmd_session_sync_process_packet *pkt,
struct hal_session *session);
};
struct hfi_packetization_ops *hfi_get_pkt_ops_handle(
enum hfi_packetization_type);
#endif

File diff suppressed because it is too large Load diff

955
msm/vidc/msm_cvp_external.c Normal file
View file

@ -0,0 +1,955 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
#include <linux/ion_kernel.h>
#include "msm_cvp_external.h"
#include "msm_vidc_common.h"
static void print_cvp_buffer(u32 tag, const char *str,
struct msm_vidc_inst *inst, struct msm_cvp_buf *cbuf)
{
struct msm_cvp_external *cvp;
if (!(tag & msm_vidc_debug) || !inst || !inst->cvp || !cbuf)
return;
cvp = inst->cvp;
dprintk(tag,
"%s: %x : idx %d fd %d size %d offset %d dbuf %pK kvaddr %pK\n",
str, cvp->session_id, cbuf->index, cbuf->fd, cbuf->size,
cbuf->offset, cbuf->dbuf, cbuf->kvaddr);
}
static int msm_cvp_fill_planeinfo(struct cvp_kmd_color_plane_info *plane_info,
u32 color_fmt, u32 width, u32 height)
{
int rc = 0;
u32 y_stride, y_sclines, uv_stride, uv_sclines;
u32 y_meta_stride, y_meta_scalines;
u32 uv_meta_stride, uv_meta_sclines;
switch (color_fmt) {
case COLOR_FMT_NV12:
case COLOR_FMT_P010:
case COLOR_FMT_NV12_512:
{
y_stride = VENUS_Y_STRIDE(color_fmt, width);
y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
uv_stride = VENUS_UV_STRIDE(color_fmt, width);
uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
plane_info->stride[HFI_COLOR_PLANE_METADATA] = 0;
plane_info->stride[HFI_COLOR_PLANE_PICDATA] = y_stride;
plane_info->stride[HFI_COLOR_PLANE_UV_META] = 0;
plane_info->stride[HFI_COLOR_PLANE_UV] = uv_stride;
plane_info->buf_size[HFI_COLOR_PLANE_METADATA] = 0;
plane_info->buf_size[HFI_COLOR_PLANE_PICDATA] =
y_stride * y_sclines;
plane_info->buf_size[HFI_COLOR_PLANE_UV_META] = 0;
plane_info->buf_size[HFI_COLOR_PLANE_UV] =
uv_stride * uv_sclines;
break;
}
case COLOR_FMT_NV12_UBWC:
case COLOR_FMT_NV12_BPP10_UBWC:
{
y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width);
y_meta_scalines = VENUS_Y_META_SCANLINES(color_fmt, height);
uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width);
uv_meta_sclines = VENUS_UV_META_SCANLINES(color_fmt, height);
y_stride = VENUS_Y_STRIDE(color_fmt, width);
y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
uv_stride = VENUS_UV_STRIDE(color_fmt, width);
uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
plane_info->stride[HFI_COLOR_PLANE_METADATA] = y_meta_stride;
plane_info->stride[HFI_COLOR_PLANE_PICDATA] = y_stride;
plane_info->stride[HFI_COLOR_PLANE_UV_META] = uv_meta_stride;
plane_info->stride[HFI_COLOR_PLANE_UV] = uv_stride;
plane_info->buf_size[HFI_COLOR_PLANE_METADATA] =
MSM_MEDIA_ALIGN(y_meta_stride * y_meta_scalines, 4096);
plane_info->buf_size[HFI_COLOR_PLANE_PICDATA] =
MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
plane_info->buf_size[HFI_COLOR_PLANE_UV_META] =
MSM_MEDIA_ALIGN(uv_meta_stride * uv_meta_sclines, 4096);
plane_info->buf_size[HFI_COLOR_PLANE_UV] =
MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
break;
}
default:
dprintk(VIDC_ERR, "%s: invalid color_fmt %#x\n",
__func__, color_fmt);
rc = -EINVAL;
break;
}
return rc;
}
static int msm_cvp_free_buffer(struct msm_vidc_inst *inst,
struct msm_cvp_buf *buffer)
{
struct msm_cvp_external *cvp;
if (!inst || !inst->cvp || !buffer) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
if (buffer->kvaddr) {
dma_buf_vunmap(buffer->dbuf, buffer->kvaddr);
buffer->kvaddr = NULL;
}
if (buffer->dbuf) {
dma_buf_put(buffer->dbuf);
buffer->dbuf = NULL;
}
return 0;
}
static int msm_cvp_allocate_buffer(struct msm_vidc_inst *inst,
struct msm_cvp_buf *buffer, bool kernel_map)
{
int rc = 0;
struct msm_cvp_external *cvp;
int ion_flags = 0;
unsigned long heap_mask = 0;
struct dma_buf *dbuf;
int fd;
if (!inst || !inst->cvp || !buffer) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID);
if (inst->flags & VIDC_SECURE) {
ion_flags = ION_FLAG_SECURE | ION_FLAG_CP_NON_PIXEL;
heap_mask = ION_HEAP(ION_SECURE_HEAP_ID);
}
dbuf = ion_alloc(buffer->size, heap_mask, ion_flags);
if (IS_ERR_OR_NULL(dbuf)) {
dprintk(VIDC_ERR,
"%s: failed to allocate, size %d heap_mask %#lx flags %d\n",
__func__, buffer->size, heap_mask, ion_flags);
rc = -ENOMEM;
goto error;
}
buffer->dbuf = dbuf;
fd = dma_buf_fd(dbuf, O_CLOEXEC);
if (fd < 0) {
dprintk(VIDC_ERR, "%s: failed to get fd\n", __func__);
rc = -ENOMEM;
goto error;
}
buffer->fd = fd;
if (kernel_map) {
buffer->kvaddr = dma_buf_vmap(dbuf);
if (!buffer->kvaddr) {
dprintk(VIDC_ERR,
"%s: dma_buf_vmap failed\n", __func__);
rc = -EINVAL;
goto error;
}
} else {
buffer->kvaddr = NULL;
}
buffer->index = cvp->buffer_idx++;
buffer->offset = 0;
return 0;
error:
msm_cvp_free_buffer(inst, buffer);
return rc;
}
static void msm_cvp_deinit_downscale_buffers(struct msm_vidc_inst *inst)
{
struct msm_cvp_external *cvp;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return;
}
cvp = inst->cvp;
dprintk(VIDC_DBG, "%s:\n", __func__);
if (cvp->src_buffer.dbuf) {
print_cvp_buffer(VIDC_DBG, "free: src_buffer",
inst, &cvp->src_buffer);
if (msm_cvp_free_buffer(inst, &cvp->src_buffer))
print_cvp_buffer(VIDC_ERR,
"free failed: src_buffer",
inst, &cvp->src_buffer);
}
if (cvp->ref_buffer.dbuf) {
print_cvp_buffer(VIDC_DBG, "free: ref_buffer",
inst, &cvp->ref_buffer);
if (msm_cvp_free_buffer(inst, &cvp->ref_buffer))
print_cvp_buffer(VIDC_ERR,
"free failed: ref_buffer",
inst, &cvp->ref_buffer);
}
}
static int msm_cvp_init_downscale_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
if (!cvp->downscale) {
dprintk(VIDC_DBG, "%s: downscaling not enabled\n", __func__);
return 0;
}
dprintk(VIDC_DBG, "%s:\n", __func__);
cvp->src_buffer.size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC,
cvp->ds_width, cvp->ds_height);
rc = msm_cvp_allocate_buffer(inst, &cvp->src_buffer, false);
if (rc) {
print_cvp_buffer(VIDC_ERR,
"allocate failed: src_buffer",
inst, &cvp->src_buffer);
goto error;
}
print_cvp_buffer(VIDC_DBG, "alloc: src_buffer",
inst, &cvp->src_buffer);
cvp->ref_buffer.size = cvp->src_buffer.size;
rc = msm_cvp_allocate_buffer(inst, &cvp->ref_buffer, false);
if (rc) {
print_cvp_buffer(VIDC_ERR,
"allocate failed: ref_buffer",
inst, &cvp->ref_buffer);
goto error;
}
print_cvp_buffer(VIDC_DBG, "alloc: ref_buffer",
inst, &cvp->ref_buffer);
return rc;
error:
msm_cvp_deinit_downscale_buffers(inst);
return rc;
}
static void msm_cvp_deinit_context_buffers(struct msm_vidc_inst *inst)
{
struct msm_cvp_external *cvp;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return;
}
cvp = inst->cvp;
dprintk(VIDC_DBG, "%s:\n", __func__);
if (cvp->context_buffer.dbuf) {
print_cvp_buffer(VIDC_DBG, "free: context_buffer",
inst, &cvp->context_buffer);
if (msm_cvp_free_buffer(inst, &cvp->context_buffer))
print_cvp_buffer(VIDC_ERR,
"free failed: context_buffer",
inst, &cvp->context_buffer);
}
if (cvp->refcontext_buffer.dbuf) {
print_cvp_buffer(VIDC_DBG, "free: refcontext_buffer",
inst, &cvp->refcontext_buffer);
if (msm_cvp_free_buffer(inst, &cvp->refcontext_buffer))
print_cvp_buffer(VIDC_ERR,
"free failed: refcontext_buffer",
inst, &cvp->refcontext_buffer);
}
}
static int msm_cvp_init_context_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
dprintk(VIDC_DBG, "%s:\n", __func__);
cvp->context_buffer.size = HFI_DME_FRAME_CONTEXT_BUFFER_SIZE;
rc = msm_cvp_allocate_buffer(inst, &cvp->context_buffer, false);
if (rc) {
print_cvp_buffer(VIDC_ERR,
"allocate failed: context_buffer",
inst, &cvp->context_buffer);
goto error;
}
print_cvp_buffer(VIDC_DBG, "alloc: context_buffer",
inst, &cvp->context_buffer);
cvp->refcontext_buffer.size = cvp->context_buffer.size;
rc = msm_cvp_allocate_buffer(inst, &cvp->refcontext_buffer, false);
if (rc) {
print_cvp_buffer(VIDC_ERR,
"allocate failed: refcontext_buffer",
inst, &cvp->refcontext_buffer);
goto error;
}
print_cvp_buffer(VIDC_DBG, "alloc: refcontext_buffer",
inst, &cvp->refcontext_buffer);
return rc;
error:
msm_cvp_deinit_context_buffers(inst);
return rc;
}
static void msm_cvp_deinit_internal_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
struct cvp_kmd_arg *arg;
struct msm_cvp_session_release_persist_buffers_packet persist2_packet;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return;
}
cvp = inst->cvp;
dprintk(VIDC_DBG, "%s:\n", __func__);
if (cvp->output_buffer.dbuf) {
print_cvp_buffer(VIDC_DBG, "free: output_buffer",
inst, &cvp->output_buffer);
rc = msm_cvp_free_buffer(inst, &cvp->output_buffer);
if (rc)
print_cvp_buffer(VIDC_ERR,
"unregister failed: output_buffer",
inst, &cvp->output_buffer);
}
if (cvp->persist2_buffer.dbuf) {
print_cvp_buffer(VIDC_DBG, "free: persist2_buffer",
inst, &cvp->persist2_buffer);
memset(&persist2_packet, 0, sizeof(struct
msm_cvp_session_release_persist_buffers_packet));
persist2_packet.size = sizeof(struct
msm_cvp_session_release_persist_buffers_packet);
persist2_packet.packet_type =
HFI_CMD_SESSION_CVP_RELEASE_PERSIST_BUFFERS;
persist2_packet.session_id = cvp->session_id;
persist2_packet.cvp_op = CVP_DME;
persist2_packet.persist2_buffer.buffer_addr =
cvp->persist2_buffer.fd;
persist2_packet.persist2_buffer.size =
cvp->persist2_buffer.size;
arg = kzalloc(sizeof(struct cvp_kmd_arg), GFP_KERNEL);
if (arg) {
memset(arg, 0, sizeof(struct cvp_kmd_arg));
arg->type = CVP_KMD_HFI_PERSIST_CMD;
memcpy(&(arg->data.pbuf_cmd), &persist2_packet,
sizeof(struct
msm_cvp_session_release_persist_buffers_packet));
rc = msm_cvp_private(cvp->priv,
CVP_KMD_HFI_PERSIST_CMD, arg);
if (rc)
print_cvp_buffer(VIDC_ERR,
"release failed: persist2_buffer",
inst, &cvp->persist2_buffer);
kfree(arg);
}
rc = msm_cvp_free_buffer(inst, &cvp->persist2_buffer);
if (rc)
print_cvp_buffer(VIDC_ERR,
"free failed: persist2_buffer",
inst, &cvp->persist2_buffer);
}
}
static int msm_cvp_init_internal_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
struct cvp_kmd_arg *arg;
struct msm_cvp_session_set_persist_buffers_packet persist2_packet;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
arg = kzalloc(sizeof(struct cvp_kmd_arg), GFP_KERNEL);
if (!arg)
return -ENOMEM;
cvp = inst->cvp;
dprintk(VIDC_DBG, "%s:\n", __func__);
cvp->persist2_buffer.size = HFI_DME_INTERNAL_PERSIST_2_BUFFER_SIZE;
rc = msm_cvp_allocate_buffer(inst, &cvp->persist2_buffer, false);
if (rc) {
print_cvp_buffer(VIDC_ERR,
"allocate failed: persist2_buffer",
inst, &cvp->persist2_buffer);
goto error;
}
print_cvp_buffer(VIDC_DBG, "alloc: persist2_buffer",
inst, &cvp->persist2_buffer);
/* set buffer */
memset(&persist2_packet, 0,
sizeof(struct msm_cvp_session_set_persist_buffers_packet));
persist2_packet.size =
sizeof(struct msm_cvp_session_set_persist_buffers_packet);
persist2_packet.packet_type = HFI_CMD_SESSION_CVP_SET_PERSIST_BUFFERS;
persist2_packet.session_id = cvp->session_id;
persist2_packet.cvp_op = CVP_DME;
persist2_packet.persist2_buffer.buffer_addr = cvp->persist2_buffer.fd;
persist2_packet.persist2_buffer.size = cvp->persist2_buffer.size;
memset(arg, 0, sizeof(struct cvp_kmd_arg));
arg->type = CVP_KMD_HFI_PERSIST_CMD;
if (sizeof(struct cvp_kmd_persist_buf) <
sizeof(struct msm_cvp_session_set_persist_buffers_packet)) {
dprintk(VIDC_ERR, "%s: insufficient size\n", __func__);
goto error;
}
memcpy(&(arg->data.pbuf_cmd), &persist2_packet,
sizeof(struct msm_cvp_session_set_persist_buffers_packet));
rc = msm_cvp_private(cvp->priv, CVP_KMD_HFI_PERSIST_CMD, arg);
if (rc) {
print_cvp_buffer(VIDC_ERR,
"set failed: persist2_buffer",
inst, &cvp->persist2_buffer);
goto error;
}
/* allocate one output buffer for internal use */
cvp->output_buffer.size = HFI_DME_OUTPUT_BUFFER_SIZE;
rc = msm_cvp_allocate_buffer(inst, &cvp->output_buffer, true);
if (rc) {
print_cvp_buffer(VIDC_ERR,
"allocate failed: output_buffer",
inst, &cvp->output_buffer);
goto error;
}
print_cvp_buffer(VIDC_DBG, "alloc: output_buffer",
inst, &cvp->output_buffer);
kfree(arg);
return rc;
error:
msm_cvp_deinit_internal_buffers(inst);
kfree(arg);
return rc;
}
static int msm_cvp_prepare_extradata(struct msm_vidc_inst *inst,
struct vb2_buffer *vb)
{
int rc = 0;
struct msm_cvp_external *cvp;
struct dma_buf *dbuf = NULL;
char *kvaddr = NULL;
struct msm_vidc_extradata_header *e_hdr;
bool input_extradata, found_end;
if (!inst || !inst->cvp || !vb) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
if (vb->num_planes <= 1) {
dprintk(VIDC_ERR, "%s: extradata plane not enabled\n",
__func__);
return -EINVAL;
}
cvp = inst->cvp;
dbuf = dma_buf_get(vb->planes[1].m.fd);
if (!dbuf) {
dprintk(VIDC_ERR, "%s: dma_buf_get(%d) failed\n",
__func__, vb->planes[1].m.fd);
return -EINVAL;
}
if (dbuf->size < vb->planes[1].length) {
dprintk(VIDC_ERR, "%s: invalid size %d vs %d\n", __func__,
dbuf->size, vb->planes[1].length);
rc = -EINVAL;
goto error;
}
rc = dma_buf_begin_cpu_access(dbuf, DMA_BIDIRECTIONAL);
if (rc) {
dprintk(VIDC_ERR, "%s: begin_cpu_access failed\n", __func__);
goto error;
}
kvaddr = dma_buf_vmap(dbuf);
if (!kvaddr) {
dprintk(VIDC_ERR, "%s: dma_buf_vmap(%d) failed\n",
__func__, vb->planes[1].m.fd);
rc = -EINVAL;
goto error;
}
e_hdr = (struct msm_vidc_extradata_header *)((char *)kvaddr +
vb->planes[1].data_offset);
input_extradata =
!!((inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_ROI) ||
(inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_HDR10PLUS));
found_end = false;
while ((char *)e_hdr < (char *)(kvaddr + dbuf->size)) {
if (!input_extradata) {
found_end = true;
break;
}
if (e_hdr->type == MSM_VIDC_EXTRADATA_NONE) {
found_end = true;
break;
}
e_hdr += e_hdr->size;
}
if (!found_end) {
dprintk(VIDC_ERR, "%s: extradata_none not found\n", __func__);
e_hdr = (struct msm_vidc_extradata_header *)((char *)kvaddr +
vb->planes[1].data_offset);
}
/* check if sufficient space available */
if (((char *)e_hdr + sizeof(struct msm_vidc_extradata_header) +
sizeof(struct msm_vidc_enc_cvp_metadata_payload) +
sizeof(struct msm_vidc_extradata_header)) >
(kvaddr + dbuf->size)) {
dprintk(VIDC_ERR,
"%s: couldn't append extradata, (e_hdr[%pK] - kvaddr[%pK]) %#x, size %d\n",
__func__, e_hdr, kvaddr, (char *)e_hdr - (char *)kvaddr,
dbuf->size);
goto error;
}
/* copy payload */
e_hdr->version = 0x00000001;
e_hdr->port_index = 1;
e_hdr->type = MSM_VIDC_EXTRADATA_CVP_METADATA;
e_hdr->data_size = sizeof(struct msm_vidc_enc_cvp_metadata_payload);
e_hdr->size = sizeof(struct msm_vidc_extradata_header) +
e_hdr->data_size;
dma_buf_begin_cpu_access(cvp->output_buffer.dbuf, DMA_BIDIRECTIONAL);
memcpy(e_hdr->data, cvp->output_buffer.kvaddr,
sizeof(struct msm_vidc_enc_cvp_metadata_payload));
dma_buf_end_cpu_access(cvp->output_buffer.dbuf, DMA_BIDIRECTIONAL);
/* fill extradata none */
e_hdr = (struct msm_vidc_extradata_header *)
((char *)e_hdr + e_hdr->size);
e_hdr->version = 0x00000001;
e_hdr->port_index = 1;
e_hdr->type = MSM_VIDC_EXTRADATA_NONE;
e_hdr->data_size = 0;
e_hdr->size = sizeof(struct msm_vidc_extradata_header) +
e_hdr->data_size;
dma_buf_vunmap(dbuf, kvaddr);
dma_buf_end_cpu_access(dbuf, DMA_BIDIRECTIONAL);
dma_buf_put(dbuf);
return rc;
error:
if (kvaddr) {
dma_buf_vunmap(dbuf, kvaddr);
dma_buf_end_cpu_access(dbuf, DMA_BIDIRECTIONAL);
}
if (dbuf)
dma_buf_put(dbuf);
return rc;
}
static int msm_cvp_reference_management(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
struct msm_cvp_buf temp;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
/* swap context buffers */
memcpy(&temp, &cvp->refcontext_buffer, sizeof(struct msm_cvp_buf));
memcpy(&cvp->refcontext_buffer, &cvp->context_buffer,
sizeof(struct msm_cvp_buf));
memcpy(&cvp->context_buffer, &temp, sizeof(struct msm_cvp_buf));
/* swap downscale buffers */
if (cvp->downscale) {
memcpy(&temp, &cvp->ref_buffer, sizeof(struct msm_cvp_buf));
memcpy(&cvp->ref_buffer, &cvp->src_buffer,
sizeof(struct msm_cvp_buf));
memcpy(&cvp->src_buffer, &temp, sizeof(struct msm_cvp_buf));
}
return rc;
}
static int msm_cvp_frame_process(struct msm_vidc_inst *inst,
struct vb2_buffer *vb)
{
int rc = 0;
struct msm_cvp_external *cvp;
struct cvp_kmd_arg *arg;
struct msm_cvp_dme_frame_packet *frame;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
arg = kzalloc(sizeof(struct cvp_kmd_arg), GFP_KERNEL);
if (!arg)
return -ENOMEM;
cvp = inst->cvp;
cvp->fullres_buffer.index = vb->index;
cvp->fullres_buffer.fd = vb->planes[0].m.fd;
cvp->fullres_buffer.size = vb->planes[0].length;
cvp->fullres_buffer.offset = vb->planes[0].data_offset;
arg->type = CVP_KMD_SEND_CMD_PKT;
frame = (struct msm_cvp_dme_frame_packet *)&arg->data.hfi_pkt.pkt_data;
frame->size = sizeof(struct msm_cvp_dme_frame_packet);
frame->packet_type = HFI_CMD_SESSION_CVP_DME_FRAME;
frame->session_id = cvp->session_id;
if (!cvp->framecount)
frame->skip_mv_calc = 1;
else
frame->skip_mv_calc = 0;
frame->min_fpx_threshold = 2;
frame->enable_descriptor_lpf = 1;
frame->enable_ncc_subpel = 1;
frame->descmatch_threshold = 52;
frame->ncc_robustness_threshold = 0;
frame->fullres_srcbuffer.buffer_addr = cvp->fullres_buffer.fd;
frame->fullres_srcbuffer.size = cvp->fullres_buffer.size;
frame->videospatialtemporal_statsbuffer.buffer_addr =
cvp->output_buffer.fd;
frame->videospatialtemporal_statsbuffer.size =
cvp->output_buffer.size;
frame->src_buffer.buffer_addr = cvp->fullres_buffer.fd;
frame->src_buffer.size = cvp->fullres_buffer.size;
if (cvp->downscale) {
frame->src_buffer.buffer_addr = cvp->src_buffer.fd;
frame->src_buffer.size = cvp->src_buffer.size;
frame->ref_buffer.buffer_addr = cvp->ref_buffer.fd;
frame->ref_buffer.size = cvp->ref_buffer.size;
}
frame->srcframe_contextbuffer.buffer_addr = cvp->context_buffer.fd;
frame->srcframe_contextbuffer.size = cvp->context_buffer.size;
frame->refframe_contextbuffer.buffer_addr = cvp->refcontext_buffer.fd;
frame->refframe_contextbuffer.size = cvp->refcontext_buffer.size;
print_cvp_buffer(VIDC_DBG, "input frame", inst, &cvp->fullres_buffer);
rc = msm_cvp_private(cvp->priv, CVP_KMD_SEND_CMD_PKT, arg);
if (rc) {
print_cvp_buffer(VIDC_ERR, "send failed: input frame",
inst, &cvp->fullres_buffer);
goto error;
}
/* wait for frame done */
arg->type = CVP_KMD_RECEIVE_MSG_PKT;
rc = msm_cvp_private(cvp->priv, CVP_KMD_RECEIVE_MSG_PKT, arg);
if (rc) {
print_cvp_buffer(VIDC_ERR, "wait failed: input frame",
inst, &cvp->fullres_buffer);
goto error;
}
cvp->framecount++;
error:
kfree(arg);
return rc;
}
int msm_vidc_cvp_preprocess(struct msm_vidc_inst *inst, struct vb2_buffer *vb)
{
int rc = 0;
struct msm_cvp_external *cvp;
if (!inst || !inst->cvp || !vb) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
if (inst->state != MSM_VIDC_START_DONE) {
dprintk(VIDC_ERR, "%s: invalid inst state %d\n",
__func__, inst->state);
return -EINVAL;
}
cvp = inst->cvp;
rc = msm_cvp_frame_process(inst, vb);
if (rc) {
dprintk(VIDC_ERR, "%s: cvp process failed\n", __func__);
return rc;
}
rc = msm_cvp_prepare_extradata(inst, vb);
if (rc) {
dprintk(VIDC_ERR, "%s: prepare extradata failed\n", __func__);
return rc;
}
rc = msm_cvp_reference_management(inst);
if (rc) {
dprintk(VIDC_ERR, "%s: ref management failed\n", __func__);
return rc;
}
return rc;
}
static int msm_vidc_cvp_deinit(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
dprintk(VIDC_DBG, "%s: cvp session %#x\n", __func__, cvp->session_id);
msm_cvp_deinit_internal_buffers(inst);
msm_cvp_deinit_context_buffers(inst);
msm_cvp_deinit_downscale_buffers(inst);
return rc;
}
static int msm_vidc_cvp_close(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
dprintk(VIDC_DBG, "%s: cvp session %#x\n", __func__, cvp->session_id);
rc = msm_cvp_close(cvp->priv);
if (rc)
dprintk(VIDC_ERR,
"%s: cvp close failed with error %d\n", __func__, rc);
cvp->priv = NULL;
kfree(inst->cvp);
inst->cvp = NULL;
return rc;
}
int msm_vidc_cvp_unprepare_preprocess(struct msm_vidc_inst *inst)
{
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
if (!inst->cvp) {
dprintk(VIDC_DBG, "%s: cvp not enabled or closed\n", __func__);
return 0;
}
msm_vidc_cvp_deinit(inst);
msm_vidc_cvp_close(inst);
return 0;
}
static int msm_vidc_cvp_init(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
struct v4l2_format *f;
struct cvp_kmd_arg *arg;
struct msm_cvp_dme_basic_config_packet *dmecfg;
u32 color_fmt;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
arg = kzalloc(sizeof(struct cvp_kmd_arg), GFP_KERNEL);
if (!arg)
return -ENOMEM;
f = &inst->fmts[INPUT_PORT].v4l2_fmt;
cvp = inst->cvp;
cvp->framecount = 0;
cvp->width = f->fmt.pix_mp.width;
cvp->height = f->fmt.pix_mp.height;
color_fmt = msm_comm_convert_color_fmt(f->fmt.pix_mp.pixelformat);
/* enable downscale always */
cvp->downscale = true;
if (cvp->width * cvp->height < 640 * 480) {
cvp->ds_width = cvp->width;
cvp->ds_height = cvp->height;
} else if (cvp->width * cvp->height < 1920 * 1080) {
if (cvp->ds_width >= cvp->ds_height) {
cvp->ds_width = 480;
cvp->ds_height = 270;
} else {
cvp->ds_width = 270;
cvp->ds_height = 480;
}
} else {
cvp->ds_width = cvp->width / 4;
cvp->ds_height = cvp->height / 4;
}
dprintk(VIDC_DBG,
"%s: pixelformat %#x, wxh %dx%d downscale %d ds_wxh %dx%d\n",
__func__, f->fmt.pix_mp.pixelformat,
cvp->width, cvp->height, cvp->downscale,
cvp->ds_width, cvp->ds_height);
memset(arg, 0, sizeof(struct cvp_kmd_arg));
arg->type = CVP_KMD_SEND_CMD_PKT;
dmecfg = (struct msm_cvp_dme_basic_config_packet *)
&arg->data.hfi_pkt.pkt_data;
dmecfg->size = sizeof(struct msm_cvp_dme_basic_config_packet);
dmecfg->packet_type = HFI_CMD_SESSION_CVP_DME_BASIC_CONFIG;
dmecfg->session_id = cvp->session_id;
/* source buffer format should be NV12_UBWC always */
dmecfg->srcbuffer_format = HFI_COLOR_FORMAT_NV12_UBWC;
dmecfg->src_width = cvp->ds_width;
dmecfg->src_height = cvp->ds_height;
rc = msm_cvp_fill_planeinfo(&dmecfg->srcbuffer_planeinfo,
COLOR_FMT_NV12_UBWC, dmecfg->src_width, dmecfg->src_height);
if (rc)
goto error;
dmecfg->fullresbuffer_format = msm_comm_get_hfi_uncompressed(
f->fmt.pix_mp.pixelformat);
dmecfg->fullres_width = cvp->width;
dmecfg->fullres_height = cvp->height;
rc = msm_cvp_fill_planeinfo(&dmecfg->fullresbuffer_planeinfo,
color_fmt, dmecfg->fullres_width, dmecfg->fullres_height);
if (rc)
goto error;
dmecfg->ds_enable = cvp->downscale;
dmecfg->enable_lrme_robustness = 1;
dmecfg->enable_inlier_tracking = 1;
rc = msm_cvp_private(cvp->priv, CVP_KMD_SEND_CMD_PKT, arg);
if (rc) {
dprintk(VIDC_ERR, "%s: cvp configuration failed\n", __func__);
goto error;
}
rc = msm_cvp_init_downscale_buffers(inst);
if (rc)
goto error;
rc = msm_cvp_init_internal_buffers(inst);
if (rc)
goto error;
rc = msm_cvp_init_context_buffers(inst);
if (rc)
goto error;
kfree(arg);
return rc;
error:
msm_vidc_cvp_deinit(inst);
kfree(arg);
return rc;
}
static int msm_vidc_cvp_open(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
struct cvp_kmd_arg *arg;
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
arg = kzalloc(sizeof(struct cvp_kmd_arg), GFP_KERNEL);
if (!arg)
return -ENOMEM;
inst->cvp = kzalloc(sizeof(struct msm_cvp_external), GFP_KERNEL);
if (!inst->cvp) {
dprintk(VIDC_ERR, "%s: failed to allocate\n", __func__);
rc = -ENOMEM;
goto error;
}
cvp = inst->cvp;
dprintk(VIDC_DBG, "%s: opening cvp\n", __func__);
cvp->priv = msm_cvp_open(0, MSM_VIDC_CVP);
if (!cvp->priv) {
dprintk(VIDC_ERR, "%s: failed to open cvp session\n", __func__);
rc = -EINVAL;
goto error;
}
memset(arg, 0, sizeof(struct cvp_kmd_arg));
arg->type = CVP_KMD_GET_SESSION_INFO;
rc = msm_cvp_private(cvp->priv, CVP_KMD_GET_SESSION_INFO, arg);
if (rc) {
dprintk(VIDC_ERR, "%s: get_session_info failed\n", __func__);
goto error;
}
cvp->session_id = arg->data.session.session_id;
dprintk(VIDC_DBG, "%s: cvp session id %#x\n",
__func__, cvp->session_id);
kfree(arg);
return 0;
error:
msm_vidc_cvp_close(inst);
kfree(inst->cvp);
inst->cvp = NULL;
kfree(arg);
return rc;
}
int msm_vidc_cvp_prepare_preprocess(struct msm_vidc_inst *inst)
{
int rc;
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
rc = msm_vidc_cvp_open(inst);
if (rc)
return rc;
rc = msm_vidc_cvp_init(inst);
if (rc)
return rc;
return 0;
}

168
msm/vidc/msm_cvp_external.h Normal file
View file

@ -0,0 +1,168 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_CVP_EXTERNAL_H_
#define _MSM_CVP_EXTERNAL_H_
#include <media/msm_media_info.h>
#include <media/msm_cvp_private.h>
#include <media/msm_cvp_vidc.h>
#include "msm_vidc_internal.h"
#include "msm_vidc_debug.h"
#define CVP_DME (24)
#define HFI_COMMON_BASE (0)
#define HFI_VIDEO_DOMAIN_CVP (HFI_COMMON_BASE + 0x8)
#define HFI_DOMAIN_BASE_COMMON (HFI_COMMON_BASE + 0)
#define HFI_DOMAIN_BASE_CVP (HFI_COMMON_BASE + 0x04000000)
#define HFI_ARCH_COMMON_OFFSET (0)
#define HFI_CMD_START_OFFSET (0x00010000)
#define HFI_CMD_SESSION_CVP_START \
(HFI_DOMAIN_BASE_CVP + HFI_ARCH_COMMON_OFFSET + \
HFI_CMD_START_OFFSET + 0x1000)
#define HFI_CMD_SESSION_CVP_DME_FRAME \
(HFI_CMD_SESSION_CVP_START + 0x03A)
#define HFI_CMD_SESSION_CVP_DME_BASIC_CONFIG \
(HFI_CMD_SESSION_CVP_START + 0x03B)
#define HFI_CMD_SESSION_CVP_SET_PERSIST_BUFFERS \
(HFI_CMD_SESSION_CVP_START + 0x04D)
#define HFI_CMD_SESSION_CVP_RELEASE_PERSIST_BUFFERS \
(HFI_CMD_SESSION_CVP_START + 0x050)
#define HFI_DME_OUTPUT_BUFFER_SIZE (256 * 4)
#define HFI_DME_INTERNAL_PERSIST_2_BUFFER_SIZE (512 * 1024)
#define HFI_DME_FRAME_CONTEXT_BUFFER_SIZE (64 * 1024)
enum HFI_COLOR_PLANE_TYPE {
HFI_COLOR_PLANE_METADATA,
HFI_COLOR_PLANE_PICDATA,
HFI_COLOR_PLANE_UV_META,
HFI_COLOR_PLANE_UV,
HFI_MAX_COLOR_PLANES
};
static inline bool is_vidc_cvp_enabled(struct msm_vidc_inst *inst)
{
return !!inst->cvp;
}
static inline bool is_vidc_cvp_allowed(struct msm_vidc_inst *inst)
{
return false;
}
struct msm_cvp_buffer_type {
u32 buffer_addr;
u32 size;
};
struct msm_cvp_session_release_persist_buffers_packet {
u32 size;
u32 packet_type;
u32 session_id;
struct cvp_kmd_client_data client_data;
u32 cvp_op;
struct msm_cvp_buffer_type persist1_buffer;
struct msm_cvp_buffer_type persist2_buffer;
};
struct msm_cvp_session_set_persist_buffers_packet {
u32 size;
u32 packet_type;
u32 session_id;
struct cvp_kmd_client_data client_data;
u32 cvp_op;
struct msm_cvp_buffer_type persist1_buffer;
struct msm_cvp_buffer_type persist2_buffer;
};
struct msm_cvp_dme_frame_packet {
u32 size;
u32 packet_type;
u32 session_id;
struct cvp_kmd_client_data client_data;
u32 skip_mv_calc;
u32 min_fpx_threshold;
u32 enable_descriptor_lpf;
u32 enable_ncc_subpel;
u32 descmatch_threshold;
int ncc_robustness_threshold;
struct msm_cvp_buffer_type fullres_srcbuffer;
struct msm_cvp_buffer_type src_buffer;
struct msm_cvp_buffer_type srcframe_contextbuffer;
struct msm_cvp_buffer_type prsp_buffer;
struct msm_cvp_buffer_type grid_buffer;
struct msm_cvp_buffer_type ref_buffer;
struct msm_cvp_buffer_type refframe_contextbuffer;
struct msm_cvp_buffer_type videospatialtemporal_statsbuffer;
};
struct msm_cvp_dme_basic_config_packet {
u32 size;
u32 packet_type;
u32 session_id;
struct cvp_kmd_client_data client_data;
u32 srcbuffer_format;
struct cvp_kmd_color_plane_info srcbuffer_planeinfo;
u32 src_width;
u32 src_height;
u32 fullres_width;
u32 fullres_height;
u32 fullresbuffer_format;
struct cvp_kmd_color_plane_info fullresbuffer_planeinfo;
u32 ds_enable;
u32 enable_lrme_robustness;
u32 enable_inlier_tracking;
u32 override_defaults;
s32 inlier_step;
s32 outlier_step;
s32 follow_globalmotion_step;
s32 nomv_conveyedinfo_step;
s32 invalid_transform_step;
s32 valid_transform_min_confidence_for_updates;
u32 min_inlier_weight_threshold;
u32 ncc_threshold;
u32 min_allowed_tar_var;
u32 meaningful_ncc_diff;
u32 robustness_distmap[8];
u32 ransac_threshold;
};
struct msm_cvp_buf {
u32 index;
int fd;
u32 size;
u32 offset;
struct dma_buf *dbuf;
void *kvaddr;
};
struct msm_cvp_external {
void *priv;
u32 session_id;
u32 width;
u32 height;
u32 ds_width;
u32 ds_height;
bool downscale;
u32 framecount;
u32 buffer_idx;
struct msm_cvp_buf fullres_buffer;
struct msm_cvp_buf src_buffer;
struct msm_cvp_buf ref_buffer;
struct msm_cvp_buf output_buffer;
struct msm_cvp_buf context_buffer;
struct msm_cvp_buf refcontext_buffer;
struct msm_cvp_buf persist2_buffer;
};
int msm_vidc_cvp_preprocess(struct msm_vidc_inst *inst,
struct vb2_buffer *vb);
int msm_vidc_cvp_prepare_preprocess(struct msm_vidc_inst *inst);
int msm_vidc_cvp_unprepare_preprocess(struct msm_vidc_inst *inst);
#endif

627
msm/vidc/msm_cvp_internal.c Normal file
View file

@ -0,0 +1,627 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#include "msm_cvp_internal.h"
#define MSM_VIDC_NOMINAL_CYCLES (444 * 1000 * 1000)
#define MSM_VIDC_UHD60E_VPSS_CYCLES (111 * 1000 * 1000)
#define MSM_VIDC_UHD60E_ISE_CYCLES (175 * 1000 * 1000)
#define MAX_CVP_VPSS_CYCLES (MSM_VIDC_NOMINAL_CYCLES - \
MSM_VIDC_UHD60E_VPSS_CYCLES)
#define MAX_CVP_ISE_CYCLES (MSM_VIDC_NOMINAL_CYCLES - \
MSM_VIDC_UHD60E_ISE_CYCLES)
static void print_client_buffer(u32 tag, const char *str,
struct msm_vidc_inst *inst, struct msm_cvp_buffer *cbuf)
{
if (!(tag & msm_vidc_debug) || !inst || !cbuf)
return;
dprintk(tag,
"%s: %x : idx %2d fd %d off %d size %d type %d flags 0x%x\n",
str, hash32_ptr(inst->session), cbuf->index, cbuf->fd,
cbuf->offset, cbuf->size, cbuf->type, cbuf->flags);
}
static void print_cvp_buffer(u32 tag, const char *str,
struct msm_vidc_inst *inst, struct msm_vidc_cvp_buffer *cbuf)
{
if (!(tag & msm_vidc_debug) || !inst || !cbuf)
return;
dprintk(tag,
"%s: %x : idx %2d fd %d off %d daddr %x size %d type %d flags 0x%x\n",
str, hash32_ptr(inst->session), cbuf->buf.index, cbuf->buf.fd,
cbuf->buf.offset, cbuf->smem.device_addr, cbuf->buf.size,
cbuf->buf.type, cbuf->buf.flags);
}
static enum hal_buffer get_hal_buftype(const char *str, unsigned int type)
{
enum hal_buffer buftype = HAL_BUFFER_NONE;
if (type == MSM_CVP_BUFTYPE_INPUT)
buftype = HAL_BUFFER_INPUT;
else if (type == MSM_CVP_BUFTYPE_OUTPUT)
buftype = HAL_BUFFER_OUTPUT;
else if (type == MSM_CVP_BUFTYPE_INTERNAL_1)
buftype = HAL_BUFFER_INTERNAL_SCRATCH_1;
else if (type == MSM_CVP_BUFTYPE_INTERNAL_2)
buftype = HAL_BUFFER_INTERNAL_SCRATCH_1;
else
dprintk(VIDC_ERR, "%s: unknown buffer type %#x\n",
str, type);
return buftype;
}
void handle_session_register_buffer_done(enum hal_command_response cmd,
void *resp)
{
struct msm_vidc_cb_cmd_done *response = resp;
struct msm_vidc_inst *inst;
struct msm_vidc_cvp_buffer *cbuf;
struct v4l2_event event = {0};
u32 *data;
bool found;
if (!response) {
dprintk(VIDC_ERR, "%s: invalid response\n", __func__);
return;
}
inst = get_inst(get_vidc_core(response->device_id),
response->session_id);
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid session %pK\n", __func__,
response->session_id);
return;
}
mutex_lock(&inst->cvpbufs.lock);
found = false;
list_for_each_entry(cbuf, &inst->cvpbufs.list, list) {
if (response->data.regbuf.client_data ==
cbuf->smem.device_addr) {
found = true;
break;
}
}
mutex_unlock(&inst->cvpbufs.lock);
if (!found) {
dprintk(VIDC_ERR, "%s: client_data %x not found\n",
__func__, response->data.regbuf.client_data);
goto exit;
}
print_cvp_buffer(VIDC_DBG, "register_done", inst, cbuf);
event.type = V4L2_EVENT_MSM_VIDC_REGISTER_BUFFER_DONE;
data = (u32 *)event.u.data;
data[0] = cbuf->buf.index;
data[1] = cbuf->buf.type;
data[2] = cbuf->buf.fd;
data[3] = cbuf->buf.offset;
v4l2_event_queue_fh(&inst->event_handler, &event);
exit:
put_inst(inst);
}
void handle_session_unregister_buffer_done(enum hal_command_response cmd,
void *resp)
{
int rc;
struct msm_vidc_cb_cmd_done *response = resp;
struct msm_vidc_inst *inst;
struct msm_vidc_cvp_buffer *cbuf, *dummy;
struct v4l2_event event = {0};
u32 *data;
bool found;
if (!response) {
dprintk(VIDC_ERR, "%s: invalid response\n", __func__);
return;
}
inst = get_inst(get_vidc_core(response->device_id),
response->session_id);
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid session %pK\n", __func__,
response->session_id);
return;
}
mutex_lock(&inst->cvpbufs.lock);
found = false;
list_for_each_entry_safe(cbuf, dummy, &inst->cvpbufs.list, list) {
if (response->data.unregbuf.client_data ==
cbuf->smem.device_addr) {
found = true;
break;
}
}
mutex_unlock(&inst->cvpbufs.lock);
if (!found) {
dprintk(VIDC_ERR, "%s: client_data %x not found\n",
__func__, response->data.unregbuf.client_data);
goto exit;
}
print_cvp_buffer(VIDC_DBG, "unregister_done", inst, cbuf);
rc = inst->smem_ops->smem_unmap_dma_buf(inst, &cbuf->smem);
if (rc) {
print_cvp_buffer(VIDC_ERR, "unmap fail", inst, cbuf);
goto exit;
}
event.type = V4L2_EVENT_MSM_VIDC_UNREGISTER_BUFFER_DONE;
data = (u32 *)event.u.data;
data[0] = cbuf->buf.index;
data[1] = cbuf->buf.type;
data[2] = cbuf->buf.fd;
data[3] = cbuf->buf.offset;
v4l2_event_queue_fh(&inst->event_handler, &event);
mutex_lock(&inst->cvpbufs.lock);
list_del(&cbuf->list);
mutex_unlock(&inst->cvpbufs.lock);
kfree(cbuf);
cbuf = NULL;
exit:
put_inst(inst);
}
static void print_cvp_cycles(struct msm_vidc_inst *inst)
{
struct msm_vidc_core *core;
struct msm_vidc_inst *temp;
if (!inst || !inst->core)
return;
core = inst->core;
mutex_lock(&core->lock);
list_for_each_entry(temp, &core->instances, list) {
if (temp->session_type == MSM_VIDC_CVP) {
dprintk(VIDC_ERR, "session %#x, vpss %d ise %d\n",
hash32_ptr(temp->session),
temp->clk_data.vpss_cycles,
temp->clk_data.ise_cycles);
}
}
mutex_unlock(&core->lock);
}
static bool msm_cvp_check_session_supported(struct msm_vidc_inst *inst,
u32 vpss_cycles, u32 ise_cycles)
{
struct msm_vidc_core *core;
struct msm_vidc_inst *temp;
u32 total_vpss_cycles = 0;
u32 total_ise_cycles = 0;
if (!inst || !inst->core) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return false;
}
core = inst->core;
mutex_lock(&core->lock);
list_for_each_entry(temp, &core->instances, list) {
if (temp->session_type == MSM_VIDC_CVP) {
total_vpss_cycles += inst->clk_data.vpss_cycles;
total_ise_cycles += inst->clk_data.ise_cycles;
}
}
mutex_unlock(&core->lock);
if ((total_vpss_cycles > MAX_CVP_VPSS_CYCLES) ||
(total_ise_cycles > MAX_CVP_ISE_CYCLES))
return false;
return true;
}
static int msm_cvp_scale_clocks_and_bus(struct msm_vidc_inst *inst)
{
int rc = 0;
if (!inst || !inst->core) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
rc = msm_vidc_set_clocks(inst->core);
if (rc) {
dprintk(VIDC_ERR,
"%s: failed set_clocks for inst %pK (%#x)\n",
__func__, inst, hash32_ptr(inst->session));
goto exit;
}
rc = msm_comm_vote_bus(inst->core);
if (rc) {
dprintk(VIDC_ERR,
"%s: failed vote_bus for inst %pK (%#x)\n",
__func__, inst, hash32_ptr(inst->session));
goto exit;
}
exit:
return rc;
}
static int msm_cvp_get_session_info(struct msm_vidc_inst *inst,
struct msm_cvp_session_info *session)
{
int rc = 0;
if (!inst || !inst->core || !session) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
session->session_id = hash32_ptr(inst->session);
dprintk(VIDC_DBG, "%s: id 0x%x\n", __func__, session->session_id);
return rc;
}
static int msm_cvp_request_power(struct msm_vidc_inst *inst,
struct msm_cvp_request_power *power)
{
int rc = 0;
if (!inst || !power) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
dprintk(VIDC_DBG,
"%s: clock_cycles_a %d, clock_cycles_b %d, ddr_bw %d sys_cache_bw %d\n",
__func__, power->clock_cycles_a, power->clock_cycles_b,
power->ddr_bw, power->sys_cache_bw);
rc = msm_cvp_check_session_supported(inst, power->clock_cycles_a,
power->clock_cycles_b);
if (!rc) {
dprintk(VIDC_ERR,
"%s: session %#x rejected, cycles: vpss %d, ise %d\n",
__func__, hash32_ptr(inst->session),
power->clock_cycles_a, power->clock_cycles_b);
print_cvp_cycles(inst);
msm_comm_kill_session(inst);
return -EOVERFLOW;
}
inst->clk_data.min_freq = max(power->clock_cycles_a,
power->clock_cycles_b);
/* convert client provided bps into kbps as expected by driver */
inst->clk_data.ddr_bw = power->ddr_bw / 1000;
inst->clk_data.sys_cache_bw = power->sys_cache_bw / 1000;
rc = msm_cvp_scale_clocks_and_bus(inst);
if (rc) {
dprintk(VIDC_ERR,
"%s: failed to scale clocks and bus for inst %pK (%#x)\n",
__func__, inst, hash32_ptr(inst->session));
goto exit;
}
if (!inst->clk_data.min_freq && !inst->clk_data.ddr_bw &&
!inst->clk_data.sys_cache_bw) {
rc = msm_cvp_inst_pause(inst);
if (rc) {
dprintk(VIDC_ERR,
"%s: failed to pause inst %pK (%#x)\n",
__func__, inst, hash32_ptr(inst->session));
goto exit;
}
} else {
rc = msm_cvp_inst_resume(inst);
if (rc) {
dprintk(VIDC_ERR,
"%s: failed to resume inst %pK (%#x)\n",
__func__, inst, hash32_ptr(inst->session));
goto exit;
}
}
exit:
return rc;
}
static int msm_cvp_register_buffer(struct msm_vidc_inst *inst,
struct msm_cvp_buffer *buf)
{
int rc = 0;
bool found;
struct hfi_device *hdev;
struct msm_vidc_cvp_buffer *cbuf;
struct vidc_register_buffer vbuf;
if (!inst || !inst->core || !buf) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
hdev = inst->core->device;
print_client_buffer(VIDC_DBG, "register", inst, buf);
mutex_lock(&inst->cvpbufs.lock);
found = false;
list_for_each_entry(cbuf, &inst->cvpbufs.list, list) {
if (cbuf->buf.index == buf->index &&
cbuf->buf.fd == buf->fd &&
cbuf->buf.offset == buf->offset) {
found = true;
break;
}
}
mutex_unlock(&inst->cvpbufs.lock);
if (found) {
print_client_buffer(VIDC_ERR, "duplicate", inst, buf);
return -EINVAL;
}
cbuf = kzalloc(sizeof(struct msm_vidc_cvp_buffer), GFP_KERNEL);
if (!cbuf) {
dprintk(VIDC_ERR, "%s: cbuf alloc failed\n", __func__);
return -ENOMEM;
}
mutex_lock(&inst->cvpbufs.lock);
list_add_tail(&cbuf->list, &inst->cvpbufs.list);
mutex_unlock(&inst->cvpbufs.lock);
memcpy(&cbuf->buf, buf, sizeof(struct msm_cvp_buffer));
cbuf->smem.buffer_type = get_hal_buftype(__func__, buf->type);
cbuf->smem.fd = buf->fd;
cbuf->smem.offset = buf->offset;
cbuf->smem.size = buf->size;
rc = inst->smem_ops->smem_map_dma_buf(inst, &cbuf->smem);
if (rc) {
print_client_buffer(VIDC_ERR, "map failed", inst, buf);
goto exit;
}
memset(&vbuf, 0, sizeof(struct vidc_register_buffer));
vbuf.index = buf->index;
vbuf.type = get_hal_buftype(__func__, buf->type);
vbuf.size = buf->size;
vbuf.device_addr = cbuf->smem.device_addr;
vbuf.client_data = cbuf->smem.device_addr;
vbuf.response_required = true;
rc = call_hfi_op(hdev, session_register_buffer,
(void *)inst->session, &vbuf);
if (rc) {
print_cvp_buffer(VIDC_ERR, "register failed", inst, cbuf);
goto exit;
}
return rc;
exit:
if (cbuf->smem.device_addr)
inst->smem_ops->smem_unmap_dma_buf(inst, &cbuf->smem);
mutex_lock(&inst->cvpbufs.lock);
list_del(&cbuf->list);
mutex_unlock(&inst->cvpbufs.lock);
kfree(cbuf);
cbuf = NULL;
return rc;
}
static int msm_cvp_unregister_buffer(struct msm_vidc_inst *inst,
struct msm_cvp_buffer *buf)
{
int rc = 0;
bool found;
struct hfi_device *hdev;
struct msm_vidc_cvp_buffer *cbuf;
struct vidc_unregister_buffer vbuf;
if (!inst || !inst->core || !buf) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
hdev = inst->core->device;
print_client_buffer(VIDC_DBG, "unregister", inst, buf);
mutex_lock(&inst->cvpbufs.lock);
found = false;
list_for_each_entry(cbuf, &inst->cvpbufs.list, list) {
if (cbuf->buf.index == buf->index &&
cbuf->buf.fd == buf->fd &&
cbuf->buf.offset == buf->offset) {
found = true;
break;
}
}
mutex_unlock(&inst->cvpbufs.lock);
if (!found) {
print_client_buffer(VIDC_ERR, "invalid", inst, buf);
return -EINVAL;
}
memset(&vbuf, 0, sizeof(struct vidc_unregister_buffer));
vbuf.index = cbuf->buf.index;
vbuf.type = get_hal_buftype(__func__, cbuf->buf.type);
vbuf.size = cbuf->buf.size;
vbuf.device_addr = cbuf->smem.device_addr;
vbuf.client_data = cbuf->smem.device_addr;
vbuf.response_required = true;
rc = call_hfi_op(hdev, session_unregister_buffer,
(void *)inst->session, &vbuf);
if (rc)
print_cvp_buffer(VIDC_ERR, "unregister failed", inst, cbuf);
return rc;
}
int msm_vidc_cvp(struct msm_vidc_inst *inst, struct msm_vidc_arg *arg)
{
int rc = 0;
if (!inst || !arg) {
dprintk(VIDC_ERR, "%s: invalid args\n", __func__);
return -EINVAL;
}
switch (arg->type) {
case MSM_CVP_GET_SESSION_INFO:
{
struct msm_cvp_session_info *session =
(struct msm_cvp_session_info *)&arg->data.session;
rc = msm_cvp_get_session_info(inst, session);
break;
}
case MSM_CVP_REQUEST_POWER:
{
struct msm_cvp_request_power *power =
(struct msm_cvp_request_power *)&arg->data.req_power;
rc = msm_cvp_request_power(inst, power);
break;
}
case MSM_CVP_REGISTER_BUFFER:
{
struct msm_cvp_buffer *buf =
(struct msm_cvp_buffer *)&arg->data.regbuf;
rc = msm_cvp_register_buffer(inst, buf);
break;
}
case MSM_CVP_UNREGISTER_BUFFER:
{
struct msm_cvp_buffer *buf =
(struct msm_cvp_buffer *)&arg->data.unregbuf;
rc = msm_cvp_unregister_buffer(inst, buf);
break;
}
default:
dprintk(VIDC_ERR, "%s: unknown arg type 0x%x\n",
__func__, arg->type);
rc = -ENOTSUPP;
break;
}
return rc;
}
static struct msm_vidc_ctrl msm_cvp_ctrls[] = {
{
.id = V4L2_CID_MPEG_VIDC_VIDEO_SECURE,
.name = "Secure mode",
.type = V4L2_CTRL_TYPE_BUTTON,
.minimum = 0,
.maximum = 1,
.default_value = 0,
.step = 1,
.menu_skip_mask = 0,
.qmenu = NULL,
},
};
int msm_cvp_ctrl_init(struct msm_vidc_inst *inst,
const struct v4l2_ctrl_ops *ctrl_ops)
{
return msm_comm_ctrl_init(inst, msm_cvp_ctrls,
ARRAY_SIZE(msm_cvp_ctrls), ctrl_ops);
}
int msm_cvp_inst_pause(struct msm_vidc_inst *inst)
{
int rc;
struct hfi_device *hdev;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
hdev = inst->core->device;
rc = call_hfi_op(hdev, session_pause, (void *)inst->session);
if (rc)
dprintk(VIDC_ERR, "%s: failed to pause inst %pK (%#x)\n",
__func__, inst, hash32_ptr(inst->session));
return rc;
}
int msm_cvp_inst_resume(struct msm_vidc_inst *inst)
{
int rc;
struct hfi_device *hdev;
if (!inst || !inst->core || !inst->core->device) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
hdev = inst->core->device;
rc = call_hfi_op(hdev, session_resume, (void *)inst->session);
if (rc)
dprintk(VIDC_ERR, "%s: failed to resume inst %pK (%#x)\n",
__func__, inst, hash32_ptr(inst->session));
return rc;
}
int msm_cvp_inst_deinit(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_vidc_cvp_buffer *cbuf, *temp;
if (!inst || !inst->core) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
dprintk(VIDC_DBG, "%s: inst %pK (%#x)\n", __func__,
inst, hash32_ptr(inst->session));
rc = msm_comm_try_state(inst, MSM_VIDC_CLOSE_DONE);
if (rc)
dprintk(VIDC_ERR, "%s: close failed\n", __func__);
mutex_lock(&inst->cvpbufs.lock);
list_for_each_entry_safe(cbuf, temp, &inst->cvpbufs.list, list) {
print_cvp_buffer(VIDC_ERR, "unregistered", inst, cbuf);
rc = inst->smem_ops->smem_unmap_dma_buf(inst, &cbuf->smem);
if (rc)
dprintk(VIDC_ERR, "%s: unmap failed\n", __func__);
list_del(&cbuf->list);
kfree(cbuf);
}
mutex_unlock(&inst->cvpbufs.lock);
inst->clk_data.min_freq = 0;
inst->clk_data.ddr_bw = 0;
inst->clk_data.sys_cache_bw = 0;
rc = msm_cvp_scale_clocks_and_bus(inst);
if (rc)
dprintk(VIDC_ERR, "%s: failed to scale_clocks_and_bus\n",
__func__);
return rc;
}
int msm_cvp_inst_init(struct msm_vidc_inst *inst)
{
int rc = 0;
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
dprintk(VIDC_DBG, "%s: inst %pK (%#x)\n", __func__,
inst, hash32_ptr(inst->session));
/* set default frequency */
inst->clk_data.core_id = VIDC_CORE_ID_2;
inst->clk_data.min_freq = 1000;
inst->clk_data.ddr_bw = 1000;
inst->clk_data.sys_cache_bw = 1000;
return rc;
}

View file

@ -0,0 +1,25 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_CVP_INTERNAL_H_
#define _MSM_CVP_INTERNAL_H_
#include "msm_vidc_internal.h"
#include "msm_vidc_common.h"
#include "msm_vidc_clocks.h"
#include "msm_vidc_debug.h"
void handle_session_register_buffer_done(enum hal_command_response cmd,
void *resp);
void handle_session_unregister_buffer_done(enum hal_command_response cmd,
void *resp);
int msm_vidc_cvp(struct msm_vidc_inst *inst, struct msm_vidc_arg *arg);
int msm_cvp_inst_init(struct msm_vidc_inst *inst);
int msm_cvp_inst_deinit(struct msm_vidc_inst *inst);
int msm_cvp_inst_pause(struct msm_vidc_inst *inst);
int msm_cvp_inst_resume(struct msm_vidc_inst *inst);
int msm_cvp_ctrl_init(struct msm_vidc_inst *inst,
const struct v4l2_ctrl_ops *ctrl_ops);
#endif

594
msm/vidc/msm_smem.c Normal file
View file

@ -0,0 +1,594 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#include <asm/dma-iommu.h>
#include <linux/dma-buf.h>
#include <linux/dma-direction.h>
#include <linux/iommu.h>
#include <linux/msm_dma_iommu_mapping.h>
#include <linux/msm_ion.h>
#include <linux/ion_kernel.h>
#include <linux/slab.h>
#include <linux/types.h>
#include "msm_vidc.h"
#include "msm_vidc_debug.h"
#include "msm_vidc_resources.h"
static int msm_dma_get_device_address(struct dma_buf *dbuf, unsigned long align,
dma_addr_t *iova, unsigned long *buffer_size,
unsigned long flags, enum hal_buffer buffer_type,
unsigned long session_type, struct msm_vidc_platform_resources *res,
struct dma_mapping_info *mapping_info)
{
int rc = 0;
struct dma_buf_attachment *attach;
struct sg_table *table = NULL;
struct context_bank_info *cb = NULL;
if (!dbuf || !iova || !buffer_size || !mapping_info) {
dprintk(VIDC_ERR, "Invalid params: %pK, %pK, %pK, %pK\n",
dbuf, iova, buffer_size, mapping_info);
return -EINVAL;
}
if (is_iommu_present(res)) {
cb = msm_smem_get_context_bank(
session_type, (flags & SMEM_SECURE),
res, buffer_type);
if (!cb) {
dprintk(VIDC_ERR,
"%s: Failed to get context bank device\n",
__func__);
rc = -EIO;
goto mem_map_failed;
}
/* Check if the dmabuf size matches expected size */
if (dbuf->size < *buffer_size) {
rc = -EINVAL;
dprintk(VIDC_ERR,
"Size mismatch: Dmabuf size: %zu Expected Size: %lu",
dbuf->size, *buffer_size);
msm_vidc_res_handle_fatal_hw_error(res,
true);
goto mem_buf_size_mismatch;
}
/* Prepare a dma buf for dma on the given device */
attach = dma_buf_attach(dbuf, cb->dev);
if (IS_ERR_OR_NULL(attach)) {
rc = PTR_ERR(attach) ? PTR_ERR(attach) : -ENOMEM;
dprintk(VIDC_ERR, "Failed to attach dmabuf\n");
goto mem_buf_attach_failed;
}
/*
* Get the scatterlist for the given attachment
* Mapping of sg is taken care by map attachment
*/
attach->dma_map_attrs = DMA_ATTR_DELAYED_UNMAP;
/*
* We do not need dma_map function to perform cache operations
* on the whole buffer size and hence pass skip sync flag.
* We do the required cache operations separately for the
* required buffer size
*/
attach->dma_map_attrs |= DMA_ATTR_SKIP_CPU_SYNC;
if (res->sys_cache_present)
attach->dma_map_attrs |=
DMA_ATTR_IOMMU_USE_UPSTREAM_HINT;
table = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
if (IS_ERR_OR_NULL(table)) {
rc = PTR_ERR(table) ? PTR_ERR(table) : -ENOMEM;
dprintk(VIDC_ERR, "Failed to map table\n");
goto mem_map_table_failed;
}
/* debug trace's need to be updated later */
trace_msm_smem_buffer_iommu_op_start("MAP", 0, 0,
align, *iova, *buffer_size);
if (table->sgl) {
*iova = table->sgl->dma_address;
*buffer_size = table->sgl->dma_length;
} else {
dprintk(VIDC_ERR, "sgl is NULL\n");
rc = -ENOMEM;
goto mem_map_sg_failed;
}
mapping_info->dev = cb->dev;
mapping_info->domain = cb->domain;
mapping_info->table = table;
mapping_info->attach = attach;
mapping_info->buf = dbuf;
mapping_info->cb_info = (void *)cb;
trace_msm_smem_buffer_iommu_op_end("MAP", 0, 0,
align, *iova, *buffer_size);
} else {
dprintk(VIDC_DBG, "iommu not present, use phys mem addr\n");
}
return 0;
mem_map_sg_failed:
dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL);
mem_map_table_failed:
dma_buf_detach(dbuf, attach);
mem_buf_size_mismatch:
mem_buf_attach_failed:
mem_map_failed:
return rc;
}
static int msm_dma_put_device_address(u32 flags,
struct dma_mapping_info *mapping_info,
enum hal_buffer buffer_type)
{
int rc = 0;
if (!mapping_info) {
dprintk(VIDC_WARN, "Invalid mapping_info\n");
return -EINVAL;
}
if (!mapping_info->dev || !mapping_info->table ||
!mapping_info->buf || !mapping_info->attach ||
!mapping_info->cb_info) {
dprintk(VIDC_WARN, "Invalid params\n");
return -EINVAL;
}
trace_msm_smem_buffer_iommu_op_start("UNMAP", 0, 0, 0, 0, 0);
dma_buf_unmap_attachment(mapping_info->attach,
mapping_info->table, DMA_BIDIRECTIONAL);
dma_buf_detach(mapping_info->buf, mapping_info->attach);
trace_msm_smem_buffer_iommu_op_end("UNMAP", 0, 0, 0, 0, 0);
mapping_info->dev = NULL;
mapping_info->domain = NULL;
mapping_info->table = NULL;
mapping_info->attach = NULL;
mapping_info->buf = NULL;
mapping_info->cb_info = NULL;
return rc;
}
struct dma_buf *msm_smem_get_dma_buf(int fd)
{
struct dma_buf *dma_buf;
dma_buf = dma_buf_get(fd);
if (IS_ERR_OR_NULL(dma_buf)) {
dprintk(VIDC_ERR, "Failed to get dma_buf for %d, error %ld\n",
fd, PTR_ERR(dma_buf));
dma_buf = NULL;
}
return dma_buf;
}
void msm_smem_put_dma_buf(void *dma_buf)
{
if (!dma_buf) {
dprintk(VIDC_ERR, "%s: NULL dma_buf\n", __func__);
return;
}
dma_buf_put((struct dma_buf *)dma_buf);
}
int msm_smem_map_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem)
{
int rc = 0;
dma_addr_t iova = 0;
u32 temp = 0;
unsigned long buffer_size = 0;
unsigned long align = SZ_4K;
struct dma_buf *dbuf;
unsigned long ion_flags = 0;
if (!inst || !smem) {
dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
__func__, inst, smem);
rc = -EINVAL;
goto exit;
}
if (smem->refcount) {
smem->refcount++;
goto exit;
}
dbuf = msm_smem_get_dma_buf(smem->fd);
if (!dbuf) {
rc = -EINVAL;
goto exit;
}
smem->dma_buf = dbuf;
rc = dma_buf_get_flags(dbuf, &ion_flags);
if (rc) {
dprintk(VIDC_ERR, "Failed to get dma buf flags: %d\n", rc);
goto exit;
}
if (ion_flags & ION_FLAG_CACHED)
smem->flags |= SMEM_CACHED;
if (ion_flags & ION_FLAG_SECURE)
smem->flags |= SMEM_SECURE;
buffer_size = smem->size;
rc = msm_dma_get_device_address(dbuf, align, &iova, &buffer_size,
smem->flags, smem->buffer_type, inst->session_type,
&(inst->core->resources), &smem->mapping_info);
if (rc) {
dprintk(VIDC_ERR, "Failed to get device address: %d\n", rc);
goto exit;
}
temp = (u32)iova;
if ((dma_addr_t)temp != iova) {
dprintk(VIDC_ERR, "iova(%pa) truncated to %#x", &iova, temp);
rc = -EINVAL;
goto exit;
}
smem->device_addr = (u32)iova + smem->offset;
smem->refcount++;
exit:
return rc;
}
int msm_smem_unmap_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem)
{
int rc = 0;
if (!inst || !smem) {
dprintk(VIDC_ERR, "%s: Invalid params: %pK %pK\n",
__func__, inst, smem);
rc = -EINVAL;
goto exit;
}
if (smem->refcount) {
smem->refcount--;
} else {
dprintk(VIDC_WARN,
"unmap called while refcount is zero already\n");
return -EINVAL;
}
if (smem->refcount)
goto exit;
rc = msm_dma_put_device_address(smem->flags, &smem->mapping_info,
smem->buffer_type);
if (rc) {
dprintk(VIDC_ERR, "Failed to put device address: %d\n", rc);
goto exit;
}
msm_smem_put_dma_buf(smem->dma_buf);
smem->device_addr = 0x0;
smem->dma_buf = NULL;
exit:
return rc;
}
static int get_secure_flag_for_buffer_type(
u32 session_type, enum hal_buffer buffer_type)
{
switch (buffer_type) {
case HAL_BUFFER_INPUT:
if (session_type == MSM_VIDC_ENCODER)
return ION_FLAG_CP_PIXEL;
else
return ION_FLAG_CP_BITSTREAM;
case HAL_BUFFER_OUTPUT:
case HAL_BUFFER_OUTPUT2:
if (session_type == MSM_VIDC_ENCODER)
return ION_FLAG_CP_BITSTREAM;
else
return ION_FLAG_CP_PIXEL;
case HAL_BUFFER_INTERNAL_SCRATCH:
return ION_FLAG_CP_BITSTREAM;
case HAL_BUFFER_INTERNAL_SCRATCH_1:
return ION_FLAG_CP_NON_PIXEL;
case HAL_BUFFER_INTERNAL_SCRATCH_2:
return ION_FLAG_CP_PIXEL;
case HAL_BUFFER_INTERNAL_PERSIST:
if (session_type == MSM_VIDC_ENCODER)
return ION_FLAG_CP_NON_PIXEL;
else
return ION_FLAG_CP_BITSTREAM;
case HAL_BUFFER_INTERNAL_PERSIST_1:
return ION_FLAG_CP_NON_PIXEL;
default:
WARN(1, "No matching secure flag for buffer type : %x\n",
buffer_type);
return -EINVAL;
}
}
static int alloc_dma_mem(size_t size, u32 align, u32 flags,
enum hal_buffer buffer_type, int map_kernel,
struct msm_vidc_platform_resources *res, u32 session_type,
struct msm_smem *mem)
{
dma_addr_t iova = 0;
unsigned long buffer_size = 0;
unsigned long heap_mask = 0;
int rc = 0;
int ion_flags = 0;
struct dma_buf *dbuf = NULL;
if (!res) {
dprintk(VIDC_ERR, "%s: NULL res\n", __func__);
return -EINVAL;
}
align = ALIGN(align, SZ_4K);
size = ALIGN(size, SZ_4K);
if (is_iommu_present(res)) {
if (flags & SMEM_ADSP) {
dprintk(VIDC_DBG, "Allocating from ADSP heap\n");
heap_mask = ION_HEAP(ION_ADSP_HEAP_ID);
} else {
heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID);
}
} else {
dprintk(VIDC_DBG,
"allocate shared memory from adsp heap size %zx align %d\n",
size, align);
heap_mask = ION_HEAP(ION_ADSP_HEAP_ID);
}
if (flags & SMEM_CACHED)
ion_flags |= ION_FLAG_CACHED;
if ((flags & SMEM_SECURE) ||
(buffer_type == HAL_BUFFER_INTERNAL_PERSIST &&
session_type == MSM_VIDC_ENCODER)) {
int secure_flag =
get_secure_flag_for_buffer_type(
session_type, buffer_type);
if (secure_flag < 0) {
rc = secure_flag;
goto fail_shared_mem_alloc;
}
ion_flags |= ION_FLAG_SECURE | secure_flag;
heap_mask = ION_HEAP(ION_SECURE_HEAP_ID);
if (res->slave_side_cp) {
heap_mask = ION_HEAP(ION_CP_MM_HEAP_ID);
size = ALIGN(size, SZ_1M);
align = ALIGN(size, SZ_1M);
}
flags |= SMEM_SECURE;
}
trace_msm_smem_buffer_dma_op_start("ALLOC", (u32)buffer_type,
heap_mask, size, align, flags, map_kernel);
dbuf = ion_alloc(size, heap_mask, ion_flags);
if (IS_ERR_OR_NULL(dbuf)) {
dprintk(VIDC_ERR,
"Failed to allocate shared memory = %zx, %#x\n",
size, flags);
rc = -ENOMEM;
goto fail_shared_mem_alloc;
}
trace_msm_smem_buffer_dma_op_end("ALLOC", (u32)buffer_type,
heap_mask, size, align, flags, map_kernel);
mem->flags = flags;
mem->buffer_type = buffer_type;
mem->offset = 0;
mem->size = size;
mem->dma_buf = dbuf;
mem->kvaddr = NULL;
rc = msm_dma_get_device_address(dbuf, align, &iova,
&buffer_size, flags, buffer_type,
session_type, res, &mem->mapping_info);
if (rc) {
dprintk(VIDC_ERR, "Failed to get device address: %d\n",
rc);
goto fail_device_address;
}
mem->device_addr = (u32)iova;
if ((dma_addr_t)mem->device_addr != iova) {
dprintk(VIDC_ERR, "iova(%pa) truncated to %#x",
&iova, mem->device_addr);
goto fail_device_address;
}
if (map_kernel) {
dma_buf_begin_cpu_access(dbuf, DMA_BIDIRECTIONAL);
mem->kvaddr = dma_buf_vmap(dbuf);
if (!mem->kvaddr) {
dprintk(VIDC_ERR,
"Failed to map shared mem in kernel\n");
rc = -EIO;
goto fail_map;
}
}
dprintk(VIDC_DBG,
"%s: dma_buf = %pK, device_addr = %x, size = %d, kvaddr = %pK, buffer_type = %#x, flags = %#lx\n",
__func__, mem->dma_buf, mem->device_addr, mem->size,
mem->kvaddr, mem->buffer_type, mem->flags);
return rc;
fail_map:
if (map_kernel)
dma_buf_end_cpu_access(dbuf, DMA_BIDIRECTIONAL);
fail_device_address:
dma_buf_put(dbuf);
fail_shared_mem_alloc:
return rc;
}
static int free_dma_mem(struct msm_smem *mem)
{
dprintk(VIDC_DBG,
"%s: dma_buf = %pK, device_addr = %x, size = %d, kvaddr = %pK, buffer_type = %#x\n",
__func__, mem->dma_buf, mem->device_addr, mem->size,
mem->kvaddr, mem->buffer_type);
if (mem->device_addr) {
msm_dma_put_device_address(mem->flags,
&mem->mapping_info, mem->buffer_type);
mem->device_addr = 0x0;
}
if (mem->kvaddr) {
dma_buf_vunmap(mem->dma_buf, mem->kvaddr);
mem->kvaddr = NULL;
dma_buf_end_cpu_access(mem->dma_buf, DMA_BIDIRECTIONAL);
}
if (mem->dma_buf) {
trace_msm_smem_buffer_dma_op_start("FREE",
(u32)mem->buffer_type, -1, mem->size, -1,
mem->flags, -1);
dma_buf_put(mem->dma_buf);
mem->dma_buf = NULL;
trace_msm_smem_buffer_dma_op_end("FREE", (u32)mem->buffer_type,
-1, mem->size, -1, mem->flags, -1);
}
return 0;
}
int msm_smem_alloc(size_t size, u32 align, u32 flags,
enum hal_buffer buffer_type, int map_kernel,
void *res, u32 session_type, struct msm_smem *smem)
{
int rc = 0;
if (!smem || !size) {
dprintk(VIDC_ERR, "%s: NULL smem or %d size\n",
__func__, (u32)size);
return -EINVAL;
}
rc = alloc_dma_mem(size, align, flags, buffer_type, map_kernel,
(struct msm_vidc_platform_resources *)res,
session_type, smem);
return rc;
}
int msm_smem_free(struct msm_smem *smem)
{
int rc = 0;
if (!smem) {
dprintk(VIDC_ERR, "NULL smem passed\n");
return -EINVAL;
}
rc = free_dma_mem(smem);
return rc;
};
int msm_smem_cache_operations(struct dma_buf *dbuf,
enum smem_cache_ops cache_op, unsigned long offset, unsigned long size)
{
int rc = 0;
unsigned long flags = 0;
if (!dbuf) {
dprintk(VIDC_ERR, "%s: Invalid params\n", __func__);
return -EINVAL;
}
/* Return if buffer doesn't support caching */
rc = dma_buf_get_flags(dbuf, &flags);
if (rc) {
dprintk(VIDC_ERR, "%s: dma_buf_get_flags failed, err %d\n",
__func__, rc);
return rc;
} else if (!(flags & ION_FLAG_CACHED)) {
return rc;
}
switch (cache_op) {
case SMEM_CACHE_CLEAN:
case SMEM_CACHE_CLEAN_INVALIDATE:
rc = dma_buf_begin_cpu_access_partial(dbuf, DMA_TO_DEVICE,
offset, size);
if (rc)
break;
rc = dma_buf_end_cpu_access_partial(dbuf, DMA_TO_DEVICE,
offset, size);
break;
case SMEM_CACHE_INVALIDATE:
rc = dma_buf_begin_cpu_access_partial(dbuf, DMA_TO_DEVICE,
offset, size);
if (rc)
break;
rc = dma_buf_end_cpu_access_partial(dbuf, DMA_FROM_DEVICE,
offset, size);
break;
default:
dprintk(VIDC_ERR, "%s: cache (%d) operation not supported\n",
__func__, cache_op);
rc = -EINVAL;
break;
}
return rc;
}
struct context_bank_info *msm_smem_get_context_bank(u32 session_type,
bool is_secure, struct msm_vidc_platform_resources *res,
enum hal_buffer buffer_type)
{
struct context_bank_info *cb = NULL, *match = NULL;
/*
* HAL_BUFFER_INPUT is directly mapped to bitstream CB in DT
* as the buffer type structure was initially designed
* just for decoder. For Encoder, input should be mapped to
* yuvpixel CB. Persist is mapped to nonpixel CB.
* So swap the buffer types just in this local scope.
*/
if (is_secure && session_type == MSM_VIDC_ENCODER) {
if (buffer_type == HAL_BUFFER_INPUT)
buffer_type = HAL_BUFFER_OUTPUT;
else if (buffer_type == HAL_BUFFER_OUTPUT)
buffer_type = HAL_BUFFER_INPUT;
else if (buffer_type == HAL_BUFFER_INTERNAL_PERSIST)
buffer_type = HAL_BUFFER_INTERNAL_PERSIST_1;
}
list_for_each_entry(cb, &res->context_banks, list) {
if (cb->is_secure == is_secure &&
cb->buffer_type & buffer_type) {
match = cb;
break;
}
}
if (!match)
dprintk(VIDC_ERR,
"%s: cb not found for buffer_type %x, is_secure %d\n",
__func__, buffer_type, is_secure);
return match;
}

226
msm/vidc/msm_v4l2_private.c Normal file
View file

@ -0,0 +1,226 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
#include "msm_v4l2_private.h"
static int convert_from_user(struct msm_vidc_arg *kp, unsigned long arg)
{
int rc = 0;
int i;
struct msm_vidc_arg __user *up = compat_ptr(arg);
if (!kp || !up) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
if (get_user(kp->type, &up->type))
return -EFAULT;
switch (kp->type) {
case MSM_CVP_GET_SESSION_INFO:
{
struct msm_cvp_session_info *k, *u;
k = &kp->data.session;
u = &up->data.session;
if (get_user(k->session_id, &u->session_id))
return -EFAULT;
for (i = 0; i < 10; i++)
if (get_user(k->reserved[i], &u->reserved[i]))
return -EFAULT;
break;
}
case MSM_CVP_REQUEST_POWER:
{
struct msm_cvp_request_power *k, *u;
k = &kp->data.req_power;
u = &up->data.req_power;
if (get_user(k->clock_cycles_a, &u->clock_cycles_a) ||
get_user(k->clock_cycles_b, &u->clock_cycles_b) ||
get_user(k->ddr_bw, &u->ddr_bw) ||
get_user(k->sys_cache_bw, &u->sys_cache_bw))
return -EFAULT;
for (i = 0; i < 8; i++)
if (get_user(k->reserved[i], &u->reserved[i]))
return -EFAULT;
break;
}
case MSM_CVP_REGISTER_BUFFER:
{
struct msm_cvp_buffer *k, *u;
k = &kp->data.regbuf;
u = &up->data.regbuf;
if (get_user(k->type, &u->type) ||
get_user(k->index, &u->index) ||
get_user(k->fd, &u->fd) ||
get_user(k->size, &u->size) ||
get_user(k->offset, &u->offset) ||
get_user(k->pixelformat, &u->pixelformat) ||
get_user(k->flags, &u->flags))
return -EFAULT;
for (i = 0; i < 5; i++)
if (get_user(k->reserved[i], &u->reserved[i]))
return -EFAULT;
break;
}
case MSM_CVP_UNREGISTER_BUFFER:
{
struct msm_cvp_buffer *k, *u;
k = &kp->data.unregbuf;
u = &up->data.unregbuf;
if (get_user(k->type, &u->type) ||
get_user(k->index, &u->index) ||
get_user(k->fd, &u->fd) ||
get_user(k->size, &u->size) ||
get_user(k->offset, &u->offset) ||
get_user(k->pixelformat, &u->pixelformat) ||
get_user(k->flags, &u->flags))
return -EFAULT;
for (i = 0; i < 5; i++)
if (get_user(k->reserved[i], &u->reserved[i]))
return -EFAULT;
break;
}
default:
dprintk(VIDC_ERR, "%s: unknown cmd type 0x%x\n",
__func__, kp->type);
rc = -EINVAL;
break;
}
return rc;
}
static int convert_to_user(struct msm_vidc_arg *kp, unsigned long arg)
{
int rc = 0;
int i;
struct msm_vidc_arg __user *up = compat_ptr(arg);
if (!kp || !up) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
if (put_user(kp->type, &up->type))
return -EFAULT;
switch (kp->type) {
case MSM_CVP_GET_SESSION_INFO:
{
struct msm_cvp_session_info *k, *u;
k = &kp->data.session;
u = &up->data.session;
if (put_user(k->session_id, &u->session_id))
return -EFAULT;
for (i = 0; i < 10; i++)
if (put_user(k->reserved[i], &u->reserved[i]))
return -EFAULT;
break;
}
case MSM_CVP_REQUEST_POWER:
{
struct msm_cvp_request_power *k, *u;
k = &kp->data.req_power;
u = &up->data.req_power;
if (put_user(k->clock_cycles_a, &u->clock_cycles_a) ||
put_user(k->clock_cycles_b, &u->clock_cycles_b) ||
put_user(k->ddr_bw, &u->ddr_bw) ||
put_user(k->sys_cache_bw, &u->sys_cache_bw))
return -EFAULT;
for (i = 0; i < 8; i++)
if (put_user(k->reserved[i], &u->reserved[i]))
return -EFAULT;
break;
}
case MSM_CVP_REGISTER_BUFFER:
{
struct msm_cvp_buffer *k, *u;
k = &kp->data.regbuf;
u = &up->data.regbuf;
if (put_user(k->type, &u->type) ||
put_user(k->index, &u->index) ||
put_user(k->fd, &u->fd) ||
put_user(k->size, &u->size) ||
put_user(k->offset, &u->offset) ||
put_user(k->pixelformat, &u->pixelformat) ||
put_user(k->flags, &u->flags))
return -EFAULT;
for (i = 0; i < 5; i++)
if (put_user(k->reserved[i], &u->reserved[i]))
return -EFAULT;
break;
}
case MSM_CVP_UNREGISTER_BUFFER:
{
struct msm_cvp_buffer *k, *u;
k = &kp->data.unregbuf;
u = &up->data.unregbuf;
if (put_user(k->type, &u->type) ||
put_user(k->index, &u->index) ||
put_user(k->fd, &u->fd) ||
put_user(k->size, &u->size) ||
put_user(k->offset, &u->offset) ||
put_user(k->pixelformat, &u->pixelformat) ||
put_user(k->flags, &u->flags))
return -EFAULT;
for (i = 0; i < 5; i++)
if (put_user(k->reserved[i], &u->reserved[i]))
return -EFAULT;
break;
}
default:
dprintk(VIDC_ERR, "%s: unknown cmd type 0x%x\n",
__func__, kp->type);
rc = -EINVAL;
break;
}
return rc;
}
long msm_v4l2_private(struct file *filp, unsigned int cmd, unsigned long arg)
{
int rc;
struct msm_vidc_inst *inst;
struct msm_vidc_arg karg;
if (!filp || !filp->private_data) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
inst = container_of(filp->private_data, struct msm_vidc_inst,
event_handler);
memset(&karg, 0, sizeof(struct msm_vidc_arg));
/*
* the arg points to user space memory and needs
* to be converted to kernel space before using it.
* Check do_video_ioctl() for more details.
*/
if (convert_from_user(&karg, arg))
return -EFAULT;
rc = msm_vidc_private((void *)inst, cmd, &karg);
if (rc) {
dprintk(VIDC_ERR, "%s: failed cmd type %x\n",
__func__, karg.type);
return -EINVAL;
}
if (convert_to_user(&karg, arg))
return -EFAULT;
return rc;
}

View file

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_V4L2_PRIVATE_H_
#define _MSM_V4L2_PRIVATE_H_
#include <media/msm_vidc_private.h>
#include "msm_vidc_debug.h"
long msm_v4l2_private(struct file *file, unsigned int cmd, unsigned long arg);
#endif

783
msm/vidc/msm_v4l2_vidc.c Normal file
View file

@ -0,0 +1,783 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#include <linux/debugfs.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/version.h>
#include <linux/io.h>
#include "msm_vidc.h"
#include "msm_vidc_common.h"
#include "msm_vidc_debug.h"
#include "msm_vidc_internal.h"
#include "msm_vidc_res_parse.h"
#include "msm_vidc_resources.h"
#include "vidc_hfi_api.h"
#include "msm_v4l2_private.h"
#include "msm_vidc_clocks.h"
#define BASE_DEVICE_NUMBER 32
struct msm_vidc_drv *vidc_driver;
static inline struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh)
{
if (!filp->private_data)
return NULL;
return container_of(filp->private_data,
struct msm_vidc_inst, event_handler);
}
static int msm_v4l2_open(struct file *filp)
{
struct video_device *vdev = video_devdata(filp);
struct msm_video_device *vid_dev =
container_of(vdev, struct msm_video_device, vdev);
struct msm_vidc_core *core = video_drvdata(filp);
struct msm_vidc_inst *vidc_inst;
trace_msm_v4l2_vidc_open_start("msm v4l2_open start");
vidc_inst = msm_vidc_open(core->id, vid_dev->type);
if (!vidc_inst) {
dprintk(VIDC_ERR,
"Failed to create video instance, core: %d, type = %d\n",
core->id, vid_dev->type);
return -ENOMEM;
}
clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
filp->private_data = &(vidc_inst->event_handler);
trace_msm_v4l2_vidc_open_end("msm v4l2_open end");
return 0;
}
static int msm_v4l2_close(struct file *filp)
{
int rc = 0;
struct msm_vidc_inst *vidc_inst;
trace_msm_v4l2_vidc_close_start("msm v4l2_close start");
vidc_inst = get_vidc_inst(filp, NULL);
rc = msm_vidc_close(vidc_inst);
filp->private_data = NULL;
trace_msm_v4l2_vidc_close_end("msm v4l2_close end");
return rc;
}
static int msm_v4l2_querycap(struct file *filp, void *fh,
struct v4l2_capability *cap)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, fh);
return msm_vidc_querycap((void *)vidc_inst, cap);
}
int msm_v4l2_enum_fmt(struct file *file, void *fh,
struct v4l2_fmtdesc *f)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_enum_fmt((void *)vidc_inst, f);
}
int msm_v4l2_s_fmt(struct file *file, void *fh,
struct v4l2_format *f)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_s_fmt((void *)vidc_inst, f);
}
int msm_v4l2_g_fmt(struct file *file, void *fh,
struct v4l2_format *f)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_g_fmt((void *)vidc_inst, f);
}
int msm_v4l2_s_ctrl(struct file *file, void *fh,
struct v4l2_control *a)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_s_ctrl((void *)vidc_inst, a);
}
int msm_v4l2_g_ctrl(struct file *file, void *fh,
struct v4l2_control *a)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_g_ctrl((void *)vidc_inst, a);
}
int msm_v4l2_reqbufs(struct file *file, void *fh,
struct v4l2_requestbuffers *b)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_reqbufs((void *)vidc_inst, b);
}
int msm_v4l2_qbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
return msm_vidc_qbuf(get_vidc_inst(file, fh), b);
}
int msm_v4l2_dqbuf(struct file *file, void *fh,
struct v4l2_buffer *b)
{
return msm_vidc_dqbuf(get_vidc_inst(file, fh), b);
}
int msm_v4l2_streamon(struct file *file, void *fh,
enum v4l2_buf_type i)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_streamon((void *)vidc_inst, i);
}
int msm_v4l2_streamoff(struct file *file, void *fh,
enum v4l2_buf_type i)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_streamoff((void *)vidc_inst, i);
}
static int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
struct msm_vidc_inst *vidc_inst = container_of(fh,
struct msm_vidc_inst, event_handler);
return msm_vidc_subscribe_event((void *)vidc_inst, sub);
}
static int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
const struct v4l2_event_subscription *sub)
{
struct msm_vidc_inst *vidc_inst = container_of(fh,
struct msm_vidc_inst, event_handler);
return msm_vidc_unsubscribe_event((void *)vidc_inst, sub);
}
static int msm_v4l2_decoder_cmd(struct file *file, void *fh,
struct v4l2_decoder_cmd *dec)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_comm_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)dec);
}
static int msm_v4l2_encoder_cmd(struct file *file, void *fh,
struct v4l2_encoder_cmd *enc)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_comm_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)enc);
}
static int msm_v4l2_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_enum_framesizes((void *)vidc_inst, fsize);
}
static int msm_v4l2_queryctrl(struct file *file, void *fh,
struct v4l2_queryctrl *ctrl)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_query_ctrl((void *)vidc_inst, ctrl);
}
static long msm_v4l2_default(struct file *file, void *fh,
bool valid_prio, unsigned int cmd, void *arg)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
return msm_vidc_private((void *)vidc_inst, cmd, arg);
}
const struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
.vidioc_querycap = msm_v4l2_querycap,
.vidioc_enum_fmt_vid_cap_mplane = msm_v4l2_enum_fmt,
.vidioc_enum_fmt_vid_out_mplane = msm_v4l2_enum_fmt,
.vidioc_s_fmt_vid_cap_mplane = msm_v4l2_s_fmt,
.vidioc_s_fmt_vid_out_mplane = msm_v4l2_s_fmt,
.vidioc_g_fmt_vid_cap_mplane = msm_v4l2_g_fmt,
.vidioc_g_fmt_vid_out_mplane = msm_v4l2_g_fmt,
.vidioc_reqbufs = msm_v4l2_reqbufs,
.vidioc_qbuf = msm_v4l2_qbuf,
.vidioc_dqbuf = msm_v4l2_dqbuf,
.vidioc_streamon = msm_v4l2_streamon,
.vidioc_streamoff = msm_v4l2_streamoff,
.vidioc_s_ctrl = msm_v4l2_s_ctrl,
.vidioc_g_ctrl = msm_v4l2_g_ctrl,
.vidioc_queryctrl = msm_v4l2_queryctrl,
.vidioc_subscribe_event = msm_v4l2_subscribe_event,
.vidioc_unsubscribe_event = msm_v4l2_unsubscribe_event,
.vidioc_decoder_cmd = msm_v4l2_decoder_cmd,
.vidioc_encoder_cmd = msm_v4l2_encoder_cmd,
.vidioc_enum_framesizes = msm_v4l2_enum_framesizes,
.vidioc_default = msm_v4l2_default,
};
static const struct v4l2_ioctl_ops msm_v4l2_enc_ioctl_ops = { 0 };
static unsigned int msm_v4l2_poll(struct file *filp,
struct poll_table_struct *pt)
{
struct msm_vidc_inst *vidc_inst = get_vidc_inst(filp, NULL);
return msm_vidc_poll((void *)vidc_inst, filp, pt);
}
static const struct v4l2_file_operations msm_v4l2_vidc_fops = {
.owner = THIS_MODULE,
.open = msm_v4l2_open,
.release = msm_v4l2_close,
.unlocked_ioctl = video_ioctl2,
.compat_ioctl32 = msm_v4l2_private,
.poll = msm_v4l2_poll,
};
void msm_vidc_release_video_device(struct video_device *pvdev)
{
}
static int read_platform_resources(struct msm_vidc_core *core,
struct platform_device *pdev)
{
int rc = 0;
if (!core || !pdev) {
dprintk(VIDC_ERR, "%s: Invalid params %pK %pK\n",
__func__, core, pdev);
return -EINVAL;
}
core->hfi_type = VIDC_HFI_VENUS;
core->resources.pdev = pdev;
if (pdev->dev.of_node) {
/* Target supports DT, parse from it */
rc = read_platform_resources_from_drv_data(core);
rc = read_platform_resources_from_dt(&core->resources);
} else {
dprintk(VIDC_ERR, "pdev node is NULL\n");
rc = -EINVAL;
}
return rc;
}
static int msm_vidc_initialize_core(struct platform_device *pdev,
struct msm_vidc_core *core)
{
int i = 0;
int rc = 0;
if (!core)
return -EINVAL;
rc = read_platform_resources(core, pdev);
if (rc) {
dprintk(VIDC_ERR, "Failed to get platform resources\n");
return rc;
}
INIT_LIST_HEAD(&core->instances);
mutex_init(&core->lock);
core->state = VIDC_CORE_UNINIT;
for (i = SYS_MSG_INDEX(SYS_MSG_START);
i <= SYS_MSG_INDEX(SYS_MSG_END); i++) {
init_completion(&core->completions[i]);
}
INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
INIT_WORK(&core->ssr_work, msm_vidc_ssr_handler);
msm_vidc_init_core_clk_ops(core);
return rc;
}
static ssize_t link_name_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct msm_vidc_core *core = dev_get_drvdata(dev);
if (core)
if (dev == &core->vdev[MSM_VIDC_DECODER].vdev.dev)
return snprintf(buf, PAGE_SIZE, "venus_dec");
else if (dev == &core->vdev[MSM_VIDC_ENCODER].vdev.dev)
return snprintf(buf, PAGE_SIZE, "venus_enc");
else if (dev == &core->vdev[MSM_VIDC_CVP].vdev.dev)
return snprintf(buf, PAGE_SIZE, "venus_cvp");
else
return 0;
else
return 0;
}
static DEVICE_ATTR_RO(link_name);
static ssize_t pwr_collapse_delay_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned long val = 0;
int rc = 0;
struct msm_vidc_core *core = NULL;
rc = kstrtoul(buf, 0, &val);
if (rc)
return rc;
else if (!val)
return -EINVAL;
core = get_vidc_core(MSM_VIDC_CORE_VENUS);
if (!core)
return -EINVAL;
core->resources.msm_vidc_pwr_collapse_delay = val;
return count;
}
static ssize_t pwr_collapse_delay_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct msm_vidc_core *core = NULL;
core = get_vidc_core(MSM_VIDC_CORE_VENUS);
if (!core)
return -EINVAL;
return snprintf(buf, PAGE_SIZE, "%u\n",
core->resources.msm_vidc_pwr_collapse_delay);
}
static DEVICE_ATTR_RW(pwr_collapse_delay);
static ssize_t thermal_level_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", vidc_driver->thermal_level);
}
static ssize_t thermal_level_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int rc = 0, val = 0;
rc = kstrtoint(buf, 0, &val);
if (rc || val < 0) {
dprintk(VIDC_WARN,
"Invalid thermal level value: %s\n", buf);
return -EINVAL;
}
dprintk(VIDC_DBG, "Thermal level old %d new %d\n",
vidc_driver->thermal_level, val);
if (val == vidc_driver->thermal_level)
return count;
vidc_driver->thermal_level = val;
msm_comm_handle_thermal_event();
return count;
}
static DEVICE_ATTR_RW(thermal_level);
static ssize_t sku_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%d",
vidc_driver->sku_version);
}
static DEVICE_ATTR_RO(sku_version);
static struct attribute *msm_vidc_core_attrs[] = {
&dev_attr_pwr_collapse_delay.attr,
&dev_attr_thermal_level.attr,
&dev_attr_sku_version.attr,
NULL
};
static struct attribute_group msm_vidc_core_attr_group = {
.attrs = msm_vidc_core_attrs,
};
static const struct of_device_id msm_vidc_dt_match[] = {
{.compatible = "qcom,msm-vidc"},
{.compatible = "qcom,msm-vidc,context-bank"},
{.compatible = "qcom,msm-vidc,bus"},
{.compatible = "qcom,msm-vidc,mem-cdsp"},
{}
};
static int msm_vidc_register_video_device(enum session_type sess_type,
int nr, struct msm_vidc_core *core, struct device *dev)
{
int rc = 0;
core->vdev[sess_type].vdev.release =
msm_vidc_release_video_device;
core->vdev[sess_type].vdev.fops = &msm_v4l2_vidc_fops;
core->vdev[sess_type].vdev.ioctl_ops = &msm_v4l2_ioctl_ops;
core->vdev[sess_type].vdev.vfl_dir = VFL_DIR_M2M;
core->vdev[sess_type].type = sess_type;
core->vdev[sess_type].vdev.v4l2_dev = &core->v4l2_dev;
rc = video_register_device(&core->vdev[sess_type].vdev,
VFL_TYPE_GRABBER, nr);
if (rc) {
dprintk(VIDC_ERR, "Failed to register the video device\n");
return rc;
}
video_set_drvdata(&core->vdev[sess_type].vdev, core);
dev = &core->vdev[sess_type].vdev.dev;
rc = device_create_file(dev, &dev_attr_link_name);
if (rc) {
dprintk(VIDC_ERR, "Failed to create video device file\n");
video_unregister_device(&core->vdev[sess_type].vdev);
return rc;
}
return 0;
}
static int msm_vidc_probe_vidc_device(struct platform_device *pdev)
{
int rc = 0;
struct msm_vidc_core *core;
struct device *dev = NULL;
int nr = BASE_DEVICE_NUMBER;
if (!vidc_driver) {
dprintk(VIDC_ERR, "Invalid vidc driver\n");
return -EINVAL;
}
core = kzalloc(sizeof(*core), GFP_KERNEL);
if (!core)
return -ENOMEM;
core->platform_data = vidc_get_drv_data(&pdev->dev);
dev_set_drvdata(&pdev->dev, core);
rc = msm_vidc_initialize_core(pdev, core);
if (rc) {
dprintk(VIDC_ERR, "Failed to init core\n");
goto err_core_init;
}
rc = sysfs_create_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
if (rc) {
dprintk(VIDC_ERR,
"Failed to create attributes\n");
goto err_core_init;
}
core->id = MSM_VIDC_CORE_VENUS;
rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
if (rc) {
dprintk(VIDC_ERR, "Failed to register v4l2 device\n");
goto err_v4l2_register;
}
/* setup the decoder device */
rc = msm_vidc_register_video_device(MSM_VIDC_DECODER,
nr, core, dev);
if (rc) {
dprintk(VIDC_ERR, "Failed to register video decoder\n");
goto err_dec;
}
/* setup the encoder device */
rc = msm_vidc_register_video_device(MSM_VIDC_ENCODER,
nr + 1, core, dev);
if (rc) {
dprintk(VIDC_ERR, "Failed to register video encoder\n");
goto err_enc;
}
/* setup the cvp device */
if (core->resources.domain_cvp) {
rc = msm_vidc_register_video_device(MSM_VIDC_CVP,
nr + 2, core, dev);
if (rc) {
dprintk(VIDC_ERR, "Failed to register video CVP\n");
goto err_cvp;
}
}
/* finish setting up the 'core' */
mutex_lock(&vidc_driver->lock);
if (vidc_driver->num_cores + 1 > MSM_VIDC_CORES_MAX) {
mutex_unlock(&vidc_driver->lock);
dprintk(VIDC_ERR, "Maximum cores already exist, core_no = %d\n",
vidc_driver->num_cores);
goto err_cores_exceeded;
}
vidc_driver->num_cores++;
mutex_unlock(&vidc_driver->lock);
core->device = vidc_hfi_initialize(core->hfi_type, core->id,
&core->resources, &handle_cmd_response);
if (IS_ERR_OR_NULL(core->device)) {
mutex_lock(&vidc_driver->lock);
vidc_driver->num_cores--;
mutex_unlock(&vidc_driver->lock);
rc = PTR_ERR(core->device) ?
PTR_ERR(core->device) : -EBADHANDLE;
if (rc != -EPROBE_DEFER)
dprintk(VIDC_ERR, "Failed to create HFI device\n");
else
dprintk(VIDC_DBG, "msm_vidc: request probe defer\n");
goto err_cores_exceeded;
}
mutex_lock(&vidc_driver->lock);
list_add_tail(&core->list, &vidc_driver->cores);
mutex_unlock(&vidc_driver->lock);
core->debugfs_root = msm_vidc_debugfs_init_core(
core, vidc_driver->debugfs_root);
vidc_driver->sku_version = core->resources.sku_version;
dprintk(VIDC_DBG, "populating sub devices\n");
/*
* Trigger probe for each sub-device i.e. qcom,msm-vidc,context-bank.
* When msm_vidc_probe is called for each sub-device, parse the
* context-bank details and store it in core->resources.context_banks
* list.
*/
rc = of_platform_populate(pdev->dev.of_node, msm_vidc_dt_match, NULL,
&pdev->dev);
if (rc) {
dprintk(VIDC_ERR, "Failed to trigger probe for sub-devices\n");
goto err_fail_sub_device_probe;
}
return rc;
err_fail_sub_device_probe:
vidc_hfi_deinitialize(core->hfi_type, core->device);
err_cores_exceeded:
if (core->resources.domain_cvp) {
device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev,
&dev_attr_link_name);
video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev);
}
err_cvp:
device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev,
&dev_attr_link_name);
video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
err_enc:
device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev,
&dev_attr_link_name);
video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
err_dec:
v4l2_device_unregister(&core->v4l2_dev);
err_v4l2_register:
sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
err_core_init:
dev_set_drvdata(&pdev->dev, NULL);
kfree(core);
return rc;
}
static int msm_vidc_probe_mem_cdsp(struct platform_device *pdev)
{
return read_mem_cdsp_resources_from_dt(pdev);
}
static int msm_vidc_probe_context_bank(struct platform_device *pdev)
{
return read_context_bank_resources_from_dt(pdev);
}
static int msm_vidc_probe_bus(struct platform_device *pdev)
{
return read_bus_resources_from_dt(pdev);
}
static int msm_vidc_probe(struct platform_device *pdev)
{
/*
* Sub devices probe will be triggered by of_platform_populate() towards
* the end of the probe function after msm-vidc device probe is
* completed. Return immediately after completing sub-device probe.
*/
if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-vidc")) {
return msm_vidc_probe_vidc_device(pdev);
} else if (of_device_is_compatible(pdev->dev.of_node,
"qcom,msm-vidc,bus")) {
return msm_vidc_probe_bus(pdev);
} else if (of_device_is_compatible(pdev->dev.of_node,
"qcom,msm-vidc,context-bank")) {
return msm_vidc_probe_context_bank(pdev);
} else if (of_device_is_compatible(pdev->dev.of_node,
"qcom,msm-vidc,mem-cdsp")) {
return msm_vidc_probe_mem_cdsp(pdev);
}
/* How did we end up here? */
MSM_VIDC_ERROR(1);
return -EINVAL;
}
static int msm_vidc_remove(struct platform_device *pdev)
{
int rc = 0;
struct msm_vidc_core *core;
if (!pdev) {
dprintk(VIDC_ERR, "%s invalid input %pK", __func__, pdev);
return -EINVAL;
}
core = dev_get_drvdata(&pdev->dev);
if (!core) {
dprintk(VIDC_ERR, "%s invalid core", __func__);
return -EINVAL;
}
vidc_hfi_deinitialize(core->hfi_type, core->device);
if (core->resources.domain_cvp) {
device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev,
&dev_attr_link_name);
video_unregister_device(&core->vdev[MSM_VIDC_CVP].vdev);
}
device_remove_file(&core->vdev[MSM_VIDC_ENCODER].vdev.dev,
&dev_attr_link_name);
video_unregister_device(&core->vdev[MSM_VIDC_ENCODER].vdev);
device_remove_file(&core->vdev[MSM_VIDC_DECODER].vdev.dev,
&dev_attr_link_name);
video_unregister_device(&core->vdev[MSM_VIDC_DECODER].vdev);
v4l2_device_unregister(&core->v4l2_dev);
msm_vidc_free_platform_resources(&core->resources);
sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
dev_set_drvdata(&pdev->dev, NULL);
mutex_destroy(&core->lock);
kfree(core);
return rc;
}
static int msm_vidc_pm_suspend(struct device *dev)
{
int rc = 0;
struct msm_vidc_core *core;
/*
* Bail out if
* - driver possibly not probed yet
* - not the main device. We don't support power management on
* subdevices (e.g. context banks)
*/
if (!dev || !dev->driver ||
!of_device_is_compatible(dev->of_node, "qcom,msm-vidc"))
return 0;
core = dev_get_drvdata(dev);
if (!core) {
dprintk(VIDC_ERR, "%s invalid core\n", __func__);
return -EINVAL;
}
rc = msm_vidc_suspend(core->id);
if (rc == -ENOTSUPP)
rc = 0;
else if (rc)
dprintk(VIDC_WARN, "Failed to suspend: %d\n", rc);
return rc;
}
static int msm_vidc_pm_resume(struct device *dev)
{
dprintk(VIDC_INFO, "%s\n", __func__);
return 0;
}
static const struct dev_pm_ops msm_vidc_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(msm_vidc_pm_suspend, msm_vidc_pm_resume)
};
MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
static struct platform_driver msm_vidc_driver = {
.probe = msm_vidc_probe,
.remove = msm_vidc_remove,
.driver = {
.name = "msm_vidc_v4l2",
.of_match_table = msm_vidc_dt_match,
.pm = &msm_vidc_pm_ops,
},
};
static int __init msm_vidc_init(void)
{
int rc = 0;
vidc_driver = kzalloc(sizeof(*vidc_driver),
GFP_KERNEL);
if (!vidc_driver) {
dprintk(VIDC_ERR,
"Failed to allocate memroy for msm_vidc_drv\n");
return -ENOMEM;
}
INIT_LIST_HEAD(&vidc_driver->cores);
mutex_init(&vidc_driver->lock);
vidc_driver->debugfs_root = msm_vidc_debugfs_init_drv();
if (!vidc_driver->debugfs_root)
dprintk(VIDC_ERR,
"Failed to create debugfs for msm_vidc\n");
rc = platform_driver_register(&msm_vidc_driver);
if (rc) {
dprintk(VIDC_ERR,
"Failed to register platform driver\n");
debugfs_remove_recursive(vidc_driver->debugfs_root);
kfree(vidc_driver);
vidc_driver = NULL;
}
return rc;
}
static void __exit msm_vidc_exit(void)
{
platform_driver_unregister(&msm_vidc_driver);
debugfs_remove_recursive(vidc_driver->debugfs_root);
mutex_destroy(&vidc_driver->lock);
kfree(vidc_driver);
vidc_driver = NULL;
}
module_init(msm_vidc_init);
module_exit(msm_vidc_exit);
MODULE_LICENSE("GPL v2");

1514
msm/vidc/msm_vdec.c Normal file

File diff suppressed because it is too large Load diff

26
msm/vidc/msm_vdec.h Normal file
View file

@ -0,0 +1,26 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_VDEC_H_
#define _MSM_VDEC_H_
#include "msm_vidc.h"
#include "msm_vidc_internal.h"
#define MSM_VDEC_DVC_NAME "msm_vidc_vdec"
int msm_vdec_inst_init(struct msm_vidc_inst *inst);
int msm_vdec_ctrl_init(struct msm_vidc_inst *inst,
const struct v4l2_ctrl_ops *ctrl_ops);
int msm_vdec_enum_fmt(struct msm_vidc_inst *inst,
struct v4l2_fmtdesc *f);
int msm_vdec_s_fmt(struct msm_vidc_inst *inst,
struct v4l2_format *f);
int msm_vdec_g_fmt(struct msm_vidc_inst *inst,
struct v4l2_format *f);
int msm_vdec_s_ctrl(struct msm_vidc_inst *inst,
struct v4l2_ctrl *ctrl);
int msm_vdec_g_ctrl(struct msm_vidc_inst *inst,
struct v4l2_ctrl *ctrl);
int msm_vdec_set_properties(struct msm_vidc_inst *inst);
#endif

4069
msm/vidc/msm_venc.c Normal file

File diff suppressed because it is too large Load diff

40
msm/vidc/msm_venc.h Normal file
View file

@ -0,0 +1,40 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_VENC_H_
#define _MSM_VENC_H_
#include "msm_vidc.h"
#include "msm_vidc_internal.h"
#define MSM_VENC_DVC_NAME "msm_vidc_venc"
int msm_venc_inst_init(struct msm_vidc_inst *inst);
int msm_venc_ctrl_init(struct msm_vidc_inst *inst,
const struct v4l2_ctrl_ops *ctrl_ops);
int msm_venc_enum_fmt(struct msm_vidc_inst *inst,
struct v4l2_fmtdesc *f);
int msm_venc_s_fmt(struct msm_vidc_inst *inst,
struct v4l2_format *f);
int msm_venc_g_fmt(struct msm_vidc_inst *inst,
struct v4l2_format *f);
int msm_venc_s_ctrl(struct msm_vidc_inst *inst,
struct v4l2_ctrl *ctrl);
int msm_venc_set_properties(struct msm_vidc_inst *inst);
int msm_venc_set_extradata(struct msm_vidc_inst *inst);
int msm_venc_set_frame_rate(struct msm_vidc_inst *inst);
int msm_venc_set_bitrate(struct msm_vidc_inst *inst);
int msm_venc_set_layer_bitrate(struct msm_vidc_inst *inst);
int msm_venc_set_operating_rate(struct msm_vidc_inst *inst);
int msm_venc_set_idr_period(struct msm_vidc_inst *inst);
int msm_venc_set_intra_period(struct msm_vidc_inst *inst);
int msm_venc_set_ltr_useframe(struct msm_vidc_inst *inst);
int msm_venc_set_ltr_markframe(struct msm_vidc_inst *inst);
int msm_venc_set_dyn_qp(struct msm_vidc_inst *inst, struct v4l2_ctrl *ctrl);
int msm_venc_set_request_keyframe(struct msm_vidc_inst *inst);
int msm_venc_set_intra_refresh_mode(struct msm_vidc_inst *inst);
int msm_venc_set_hp_max_layer(struct msm_vidc_inst *inst);
int msm_venc_set_hp_layer(struct msm_vidc_inst *inst);
int msm_venc_set_base_layer_priority_id(struct msm_vidc_inst *inst);
int msm_venc_set_lossless(struct msm_vidc_inst *inst);
#endif

1818
msm/vidc/msm_vidc.c Normal file

File diff suppressed because it is too large Load diff

135
msm/vidc/msm_vidc.h Normal file
View file

@ -0,0 +1,135 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_VIDC_H_
#define _MSM_VIDC_H_
#include <linux/poll.h>
#include <linux/videodev2.h>
#include <linux/types.h>
#include <linux/msm_ion.h>
#include <media/msm_vidc_private.h>
#include <media/msm_vidc_utils.h>
#define HAL_BUFFER_MAX 0xe
#define V4L2_CID_MPEG_VIDC_VIDEO_STREAM_OUTPUT_MODE \
(V4L2_CID_MPEG_MSM_VIDC_BASE + 22)
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,
};
enum smem_type {
SMEM_DMA = 1,
};
enum smem_prop {
SMEM_UNCACHED = 0x1,
SMEM_CACHED = 0x2,
SMEM_SECURE = 0x4,
SMEM_ADSP = 0x8,
};
/* NOTE: if you change this enum you MUST update the
* "buffer-type-tz-usage-table" for any affected target
* in arch/arm/boot/dts/<arch>.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,
HAL_BUFFER_INTERNAL_RECON = 0x1000,
};
struct dma_mapping_info {
struct device *dev;
struct iommu_domain *domain;
struct sg_table *table;
struct dma_buf_attachment *attach;
struct dma_buf *buf;
void *cb_info;
};
struct msm_smem {
u32 refcount;
int fd;
void *dma_buf;
void *kvaddr;
u32 device_addr;
dma_addr_t dma_handle;
unsigned int offset;
unsigned int size;
unsigned long flags;
enum hal_buffer buffer_type;
struct dma_mapping_info mapping_info;
};
enum smem_cache_ops {
SMEM_CACHE_CLEAN,
SMEM_CACHE_INVALIDATE,
SMEM_CACHE_CLEAN_INVALIDATE,
};
enum core_id {
MSM_VIDC_CORE_VENUS = 0,
MSM_VIDC_CORE_Q6,
MSM_VIDC_CORES_MAX,
};
enum session_type {
MSM_VIDC_ENCODER = 0,
MSM_VIDC_DECODER,
MSM_VIDC_CVP,
MSM_VIDC_UNKNOWN,
MSM_VIDC_MAX_DEVICES = MSM_VIDC_UNKNOWN,
};
union msm_v4l2_cmd {
struct v4l2_decoder_cmd dec;
struct v4l2_encoder_cmd enc;
};
void *msm_vidc_open(int core_id, int session_type);
int msm_vidc_close(void *instance);
int msm_vidc_suspend(int core_id);
int msm_vidc_querycap(void *instance, struct v4l2_capability *cap);
int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f);
int msm_vidc_s_fmt(void *instance, struct v4l2_format *f);
int msm_vidc_g_fmt(void *instance, struct v4l2_format *f);
int msm_vidc_s_ctrl(void *instance, struct v4l2_control *a);
int msm_vidc_s_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
int msm_vidc_g_ext_ctrl(void *instance, struct v4l2_ext_controls *a);
int msm_vidc_g_ctrl(void *instance, struct v4l2_control *a);
int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b);
int msm_vidc_release_buffer(void *instance, int buffer_type,
unsigned int buffer_index);
int msm_vidc_qbuf(void *instance, struct v4l2_buffer *b);
int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b);
int msm_vidc_streamon(void *instance, enum v4l2_buf_type i);
int msm_vidc_query_ctrl(void *instance, struct v4l2_queryctrl *ctrl);
int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd);
int msm_vidc_poll(void *instance, struct file *filp,
struct poll_table_struct *pt);
int msm_vidc_subscribe_event(void *instance,
const struct v4l2_event_subscription *sub);
int msm_vidc_unsubscribe_event(void *instance,
const struct v4l2_event_subscription *sub);
int msm_vidc_dqevent(void *instance, struct v4l2_event *event);
int msm_vidc_g_crop(void *instance, struct v4l2_crop *a);
int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize);
int msm_vidc_private(void *vidc_inst, unsigned int cmd,
struct msm_vidc_arg *arg);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
#ifndef __H_MSM_VIDC_BUFFER_MEM_DEFS_H__
#define __H_MSM_VIDC_BUFFER_MEM_DEFS_H__
struct msm_vidc_dec_buff_size_calculators {
u32 (*calculate_scratch_size)(struct msm_vidc_inst *inst, u32 width,
u32 height, bool is_interlaced);
u32 (*calculate_scratch1_size)(struct msm_vidc_inst *inst, u32 width,
u32 height, u32 min_buf_count, bool split_mode_enabled);
u32 (*calculate_persist1_size)(void);
};
struct msm_vidc_enc_buff_size_calculators {
u32 (*calculate_scratch_size)(struct msm_vidc_inst *inst, u32 width,
u32 height, u32 work_mode);
u32 (*calculate_scratch1_size)(struct msm_vidc_inst *inst,
u32 width, u32 height, u32 num_ref, bool ten_bit);
u32 (*calculate_scratch2_size)(struct msm_vidc_inst *inst,
u32 width, u32 height, u32 num_ref, bool ten_bit);
u32 (*calculate_persist_size)(void);
};
void msm_vidc_init_buffer_size_calculators(struct msm_vidc_inst *inst);
int msm_vidc_init_buffer_count(struct msm_vidc_inst *inst);
int msm_vidc_get_extra_buff_count(struct msm_vidc_inst *inst,
enum hal_buffer buffer_type);
u32 msm_vidc_calculate_dec_input_frame_size(struct msm_vidc_inst *inst);
u32 msm_vidc_calculate_dec_output_frame_size(struct msm_vidc_inst *inst);
u32 msm_vidc_calculate_dec_output_extra_size(struct msm_vidc_inst *inst);
u32 msm_vidc_calculate_enc_input_frame_size(struct msm_vidc_inst *inst);
u32 msm_vidc_calculate_enc_output_frame_size(struct msm_vidc_inst *inst);
u32 msm_vidc_calculate_enc_input_extra_size(struct msm_vidc_inst *inst);
u32 msm_vidc_calculate_enc_output_extra_size(struct msm_vidc_inst *inst);
u32 msm_vidc_set_buffer_count_for_thumbnail(struct msm_vidc_inst *inst);
#endif // __H_MSM_VIDC_BUFFER_MEM_DEFS_H__

283
msm/vidc/msm_vidc_bus.h Normal file
View file

@ -0,0 +1,283 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
*/
#ifndef __H_MSM_VIDC_BUS_DEFS_H__
#define __H_MSM_VIDC_BUS_DEFS_H__
#include "fixedpoint.h"
#include "msm_vidc_debug.h"
#include "vidc_hfi_api.h"
#define COMPRESSION_RATIO_MAX 5
enum vidc_bus_type {
PERF,
DDR,
LLCC,
};
/*
* Minimum dimensions for which to calculate bandwidth.
* This means that anything bandwidth(0, 0) ==
* bandwidth(BASELINE_DIMENSIONS.width, BASELINE_DIMENSIONS.height)
*/
static const struct {
int height, width;
} BASELINE_DIMENSIONS = {
.width = 1280,
.height = 720,
};
/* converts Mbps to bps (the "b" part can be bits or bytes based on context) */
#define kbps(__mbps) ((__mbps) * 1000)
#define bps(__mbps) (kbps(__mbps) * 1000)
#define GENERATE_COMPRESSION_PROFILE(__bpp, __worst) { \
.bpp = __bpp, \
.ratio = __worst, \
}
/*
* The below table is a structural representation of the following table:
* Resolution | Bitrate | Compression Ratio |
* ............|............|.........................................|
* Width Height|Average High|Avg_8bpc Worst_8bpc Avg_10bpc Worst_10bpc|
* 1280 720| 7 14| 1.69 1.28 1.49 1.23|
* 1920 1080| 20 40| 1.69 1.28 1.49 1.23|
* 2560 1440| 32 64| 2.2 1.26 1.97 1.22|
* 3840 2160| 42 84| 2.2 1.26 1.97 1.22|
* 4096 2160| 44 88| 2.2 1.26 1.97 1.22|
* 4096 2304| 48 96| 2.2 1.26 1.97 1.22|
*/
static struct lut {
int frame_size; /* width x height */
int frame_rate;
unsigned long bitrate;
struct {
int bpp;
fp_t ratio;
} compression_ratio[COMPRESSION_RATIO_MAX];
} const LUT[] = {
{
.frame_size = 1280 * 720,
.frame_rate = 30,
.bitrate = 14,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 28, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 23, 100)),
}
},
{
.frame_size = 1280 * 720,
.frame_rate = 60,
.bitrate = 22,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 28, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 23, 100)),
}
},
{
.frame_size = 1920 * 1088,
.frame_rate = 30,
.bitrate = 40,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 28, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 23, 100)),
}
},
{
.frame_size = 1920 * 1088,
.frame_rate = 60,
.bitrate = 64,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 28, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 23, 100)),
}
},
{
.frame_size = 2560 * 1440,
.frame_rate = 30,
.bitrate = 64,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 26, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 22, 100)),
}
},
{
.frame_size = 2560 * 1440,
.frame_rate = 60,
.bitrate = 102,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 26, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 22, 100)),
}
},
{
.frame_size = 3840 * 2160,
.frame_rate = 30,
.bitrate = 84,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 26, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 22, 100)),
}
},
{
.frame_size = 3840 * 2160,
.frame_rate = 60,
.bitrate = 134,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 26, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 22, 100)),
}
},
{
.frame_size = 4096 * 2160,
.frame_rate = 30,
.bitrate = 88,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 26, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 22, 100)),
}
},
{
.frame_size = 4096 * 2160,
.frame_rate = 60,
.bitrate = 141,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 26, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 22, 100)),
}
},
{
.frame_size = 4096 * 2304,
.frame_rate = 30,
.bitrate = 96,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 26, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 22, 100)),
}
},
{
.frame_size = 4096 * 2304,
.frame_rate = 60,
.bitrate = 154,
.compression_ratio = {
GENERATE_COMPRESSION_PROFILE(8,
FP(1, 26, 100)),
GENERATE_COMPRESSION_PROFILE(10,
FP(1, 22, 100)),
}
},
};
static inline u32 get_type_frm_name(char *name)
{
if (!strcmp(name, "venus-llcc"))
return LLCC;
else if (!strcmp(name, "venus-ddr"))
return DDR;
else
return PERF;
}
#define DUMP_HEADER_MAGIC 0xdeadbeef
#define DUMP_FP_FMT "%FP" /* special format for fp_t */
struct dump {
char *key;
char *format;
size_t val;
};
struct vidc_bus_vote_data {
enum hal_domain domain;
enum hal_video_codec codec;
enum hal_uncompressed_format color_formats[2];
int num_formats; /* 1 = DPB-OPB unified; 2 = split */
int input_height, input_width, bitrate;
int output_height, output_width;
int rotation;
int compression_ratio;
int complexity_factor;
int input_cr;
u32 ddr_bw;
u32 sys_cache_bw;
bool use_dpb_read;
unsigned int lcu_size;
unsigned int fps;
enum msm_vidc_power_mode power_mode;
u32 work_mode;
bool use_sys_cache;
bool b_frames_enabled;
};
struct msm_vidc_bus_data {
struct vidc_bus_vote_data *data;
u32 data_count;
unsigned long (*calc_bw)(struct bus_info *bus,
struct msm_vidc_bus_data *data);
};
unsigned long calc_bw_iris1(struct bus_info *bus,
struct msm_vidc_bus_data *vidc_data);
unsigned long calc_bw_iris2(struct bus_info *bus,
struct msm_vidc_bus_data *vidc_data);
struct lut const *__lut(int width, int height, int fps);
fp_t __compression_ratio(struct lut const *entry, int bpp);
void __dump(struct dump dump[], int len);
static inline bool __ubwc(enum hal_uncompressed_format f)
{
switch (f) {
case HAL_COLOR_FORMAT_NV12_UBWC:
case HAL_COLOR_FORMAT_NV12_TP10_UBWC:
return true;
default:
return false;
}
}
static inline int __bpp(enum hal_uncompressed_format f)
{
switch (f) {
case HAL_COLOR_FORMAT_NV12:
case HAL_COLOR_FORMAT_NV21:
case HAL_COLOR_FORMAT_NV12_UBWC:
return 8;
case HAL_COLOR_FORMAT_NV12_TP10_UBWC:
case HAL_COLOR_FORMAT_P010:
return 10;
default:
dprintk(VIDC_ERR,
"Unsupported colorformat (%x)", f);
return INT_MAX;
}
}
#endif // __H_MSM_VIDC_BUS_DEFS_H__

View file

@ -0,0 +1,699 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*/
#include "msm_vidc_bus.h"
#include "msm_vidc_internal.h"
struct lut const *__lut(int width, int height, int fps)
{
int frame_size = height * width, c = 0;
do {
if (LUT[c].frame_size >= frame_size && LUT[c].frame_rate >= fps)
return &LUT[c];
} while (++c < ARRAY_SIZE(LUT));
return &LUT[ARRAY_SIZE(LUT) - 1];
}
fp_t __compression_ratio(struct lut const *entry, int bpp)
{
int c = 0;
for (c = 0; c < COMPRESSION_RATIO_MAX; ++c) {
if (entry->compression_ratio[c].bpp == bpp)
return entry->compression_ratio[c].ratio;
}
WARN(true, "Shouldn't be here, LUT possibly corrupted?\n");
return FP_ZERO; /* impossible */
}
void __dump(struct dump dump[], int len)
{
int c = 0;
for (c = 0; c < len; ++c) {
char format_line[128] = "", formatted_line[128] = "";
if (dump[c].val == DUMP_HEADER_MAGIC) {
snprintf(formatted_line, sizeof(formatted_line), "%s\n",
dump[c].key);
} else {
bool fp_format = !strcmp(dump[c].format, DUMP_FP_FMT);
if (!fp_format) {
snprintf(format_line, sizeof(format_line),
" %-35s: %s\n", dump[c].key,
dump[c].format);
snprintf(formatted_line, sizeof(formatted_line),
format_line, dump[c].val);
} else {
size_t integer_part, fractional_part;
integer_part = fp_int(dump[c].val);
fractional_part = fp_frac(dump[c].val);
snprintf(formatted_line, sizeof(formatted_line),
" %-35s: %zd + %zd/%zd\n",
dump[c].key, integer_part,
fractional_part,
fp_frac_base());
}
}
dprintk(VIDC_DBG, "%s", formatted_line);
}
}
static unsigned long __calculate_vpe(struct vidc_bus_vote_data *d,
enum vidc_bus_type type)
{
return 0;
}
static unsigned long __calculate_cvp(struct vidc_bus_vote_data *d,
enum vidc_bus_type type)
{
unsigned long ret = 0;
switch (type) {
case DDR:
ret = d->ddr_bw;
break;
case LLCC:
ret = d->sys_cache_bw;
break;
default:
dprintk(VIDC_ERR, "%s - Unknown type\n", __func__);
break;
}
return ret;
}
static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d,
enum vidc_bus_type type)
{
/*
* XXX: Don't fool around with any of the hardcoded numbers unless you
* know /exactly/ what you're doing. Many of these numbers are
* measured heuristics and hardcoded numbers taken from the firmware.
*/
/* Decoder parameters */
int width, height, lcu_size, fps, dpb_bpp;
bool unified_dpb_opb, dpb_compression_enabled = true,
opb_compression_enabled = false,
llc_ref_read_l2_cache_enabled = false,
llc_top_line_buf_enabled = false;
fp_t dpb_read_compression_factor, dpb_opb_scaling_ratio,
dpb_write_compression_factor, opb_write_compression_factor,
qsmmu_bw_overhead_factor;
bool is_h264_category = true;
/* Derived parameters */
int lcu_per_frame, collocated_bytes_per_lcu, tnbr_per_lcu;
unsigned long bitrate;
fp_t bins_to_bit_factor, vsp_read_factor, vsp_write_factor,
dpb_factor, dpb_write_factor,
y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp, y_bw_10bpp_p010,
motion_vector_complexity = 0;
fp_t dpb_total = 0;
/* Output parameters */
struct {
fp_t vsp_read, vsp_write, collocated_read, collocated_write,
dpb_read, dpb_write, opb_read, opb_write,
line_buffer_read, line_buffer_write,
total;
} ddr = {0};
struct {
fp_t dpb_read, line_buffer_read, line_buffer_write, total;
} llc = {0};
unsigned long ret = 0;
unsigned int integer_part, frac_part;
width = max(d->input_width, BASELINE_DIMENSIONS.width);
height = max(d->input_height, BASELINE_DIMENSIONS.height);
fps = d->fps;
lcu_size = d->lcu_size;
dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX;
unified_dpb_opb = d->num_formats == 1;
dpb_opb_scaling_ratio = fp_div(FP_INT(d->input_width * d->input_height),
FP_INT(d->output_width * d->output_height));
opb_compression_enabled = d->num_formats >= 2 &&
__ubwc(d->color_formats[1]);
/*
* convert q16 number into integer and fractional part upto 2 places.
* ex : 105752 / 65536 = 1.61; 1.61 in q16 = 105752;
* integer part = 105752 / 65536 = 1;
* reminder = 105752 - 1 * 65536 = 40216;
* fractional part = 40216 * 100 / 65536 = 61;
* now converto to fp(1, 61, 100) for below code.
*/
integer_part = d->compression_ratio >> 16;
frac_part =
((d->compression_ratio - (integer_part << 16)) * 100) >> 16;
dpb_read_compression_factor = FP(integer_part, frac_part, 100);
integer_part = d->complexity_factor >> 16;
frac_part =
((d->complexity_factor - (integer_part << 16)) * 100) >> 16;
motion_vector_complexity = FP(integer_part, frac_part, 100);
dpb_write_compression_factor = dpb_read_compression_factor;
opb_write_compression_factor = opb_compression_enabled ?
dpb_write_compression_factor : FP_ONE;
if (d->codec == HAL_VIDEO_CODEC_HEVC ||
d->codec == HAL_VIDEO_CODEC_VP9) {
/* H264, VP8, MPEG2 use the same settings */
/* HEVC, VP9 use the same setting */
is_h264_category = false;
}
if (d->use_sys_cache) {
llc_ref_read_l2_cache_enabled = true;
if (is_h264_category)
llc_top_line_buf_enabled = true;
}
/* Derived parameters setup */
lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
DIV_ROUND_UP(height, lcu_size);
bitrate = (d->bitrate + 1000000 - 1) / 1000000;
bins_to_bit_factor = FP_INT(4);
vsp_write_factor = bins_to_bit_factor;
vsp_read_factor = bins_to_bit_factor + FP_INT(2);
collocated_bytes_per_lcu = lcu_size == 16 ? 16 :
lcu_size == 32 ? 64 : 256;
dpb_factor = FP(1, 50, 100);
dpb_write_factor = FP(1, 5, 100);
tnbr_per_lcu = lcu_size == 16 ? 128 :
lcu_size == 32 ? 64 : 128;
/* .... For DDR & LLC ...... */
ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate),
vsp_read_factor), FP_INT(8));
ddr.vsp_write = fp_div(fp_mult(FP_INT(bitrate),
vsp_write_factor), FP_INT(8));
ddr.collocated_read = fp_div(FP_INT(lcu_per_frame *
collocated_bytes_per_lcu * fps), FP_INT(bps(1)));
ddr.collocated_write = ddr.collocated_read;
y_bw_no_ubwc_8bpp = fp_div(fp_mult(
FP_INT((int)(width * height)), FP_INT((int)fps)),
FP_INT(1000 * 1000));
y_bw_no_ubwc_10bpp = fp_div(fp_mult(y_bw_no_ubwc_8bpp, FP_INT(256)),
FP_INT(192));
y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2;
ddr.dpb_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp;
ddr.dpb_read = fp_div(fp_mult(ddr.dpb_read,
fp_mult(dpb_factor, motion_vector_complexity)),
dpb_read_compression_factor);
ddr.dpb_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp;
ddr.dpb_write = fp_div(fp_mult(ddr.dpb_write,
fp_mult(dpb_factor, dpb_write_factor)),
dpb_write_compression_factor);
dpb_total = ddr.dpb_read + ddr.dpb_write;
if (llc_ref_read_l2_cache_enabled) {
ddr.dpb_read = fp_div(ddr.dpb_read, is_h264_category ?
FP(1, 15, 100) : FP(1, 30, 100));
llc.dpb_read = dpb_total - ddr.dpb_write - ddr.dpb_read;
}
ddr.opb_read = FP_ZERO;
ddr.opb_write = unified_dpb_opb ? FP_ZERO : (dpb_bpp == 8 ?
y_bw_no_ubwc_8bpp : (opb_compression_enabled ?
y_bw_no_ubwc_10bpp : y_bw_10bpp_p010));
ddr.opb_write = fp_div(fp_mult(dpb_factor, ddr.opb_write),
fp_mult(dpb_opb_scaling_ratio, opb_write_compression_factor));
ddr.line_buffer_read = FP_INT(tnbr_per_lcu *
lcu_per_frame * fps / bps(1));
ddr.line_buffer_write = ddr.line_buffer_read;
if (llc_top_line_buf_enabled) {
llc.line_buffer_read = ddr.line_buffer_read;
llc.line_buffer_write = ddr.line_buffer_write;
ddr.line_buffer_write = ddr.line_buffer_read = FP_ZERO;
}
ddr.total = ddr.vsp_read + ddr.vsp_write +
ddr.collocated_read + ddr.collocated_write +
ddr.dpb_read + ddr.dpb_write +
ddr.opb_read + ddr.opb_write +
ddr.line_buffer_read + ddr.line_buffer_write;
qsmmu_bw_overhead_factor = FP(1, 3, 100);
ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
llc.total = llc.dpb_read + llc.line_buffer_read +
llc.line_buffer_write + ddr.total;
/* Dump all the variables for easier debugging */
if (msm_vidc_debug & VIDC_PROF) {
struct dump dump[] = {
{"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC},
{"lcu size", "%d", lcu_size},
{"dpb bitdepth", "%d", dpb_bpp},
{"frame rate", "%d", fps},
{"dpb/opb unified", "%d", unified_dpb_opb},
{"dpb/opb downscaling ratio", DUMP_FP_FMT,
dpb_opb_scaling_ratio},
{"dpb compression", "%d", dpb_compression_enabled},
{"opb compression", "%d", opb_compression_enabled},
{"dpb read compression factor", DUMP_FP_FMT,
dpb_read_compression_factor},
{"dpb write compression factor", DUMP_FP_FMT,
dpb_write_compression_factor},
{"frame width", "%d", width},
{"frame height", "%d", height},
{"llc ref read l2 cache enabled", "%d",
llc_ref_read_l2_cache_enabled},
{"llc top line buf enabled", "%d",
llc_top_line_buf_enabled},
{"DERIVED PARAMETERS (1)", "", DUMP_HEADER_MAGIC},
{"lcus/frame", "%d", lcu_per_frame},
{"bitrate (Mbit/sec)", "%d", bitrate},
{"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor},
{"dpb write factor", DUMP_FP_FMT, dpb_write_factor},
{"vsp read factor", DUMP_FP_FMT, vsp_read_factor},
{"vsp write factor", DUMP_FP_FMT, vsp_write_factor},
{"tnbr/lcu", "%d", tnbr_per_lcu},
{"collocated bytes/LCU", "%d", collocated_bytes_per_lcu},
{"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp},
{"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp},
{"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC},
{"mv complexity", DUMP_FP_FMT, motion_vector_complexity},
{"qsmmu_bw_overhead_factor", DUMP_FP_FMT,
qsmmu_bw_overhead_factor},
{"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC},
{"vsp read", DUMP_FP_FMT, ddr.vsp_read},
{"vsp write", DUMP_FP_FMT, ddr.vsp_write},
{"collocated read", DUMP_FP_FMT, ddr.collocated_read},
{"collocated write", DUMP_FP_FMT, ddr.collocated_write},
{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read},
{"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write},
{"opb read", DUMP_FP_FMT, ddr.opb_read},
{"opb write", DUMP_FP_FMT, ddr.opb_write},
{"dpb read", DUMP_FP_FMT, ddr.dpb_read},
{"dpb write", DUMP_FP_FMT, ddr.dpb_write},
{"dpb total", DUMP_FP_FMT, dpb_total},
{"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC},
{"llc dpb read", DUMP_FP_FMT, llc.dpb_read},
{"llc line buffer read", DUMP_FP_FMT, llc.line_buffer_read},
{"llc line buffer write", DUMP_FP_FMT, llc.line_buffer_write},
};
__dump(dump, ARRAY_SIZE(dump));
}
switch (type) {
case DDR:
ret = kbps(fp_round(ddr.total));
break;
case LLCC:
ret = kbps(fp_round(llc.total));
break;
default:
dprintk(VIDC_ERR, "%s - Unknown type\n", __func__);
}
return ret;
}
static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d,
enum vidc_bus_type type)
{
/*
* XXX: Don't fool around with any of the hardcoded numbers unless you
* know /exactly/ what you're doing. Many of these numbers are
* measured heuristics and hardcoded numbers taken from the firmware.
*/
/* Encoder Parameters */
int width, height, fps, lcu_size, bitrate, lcu_per_frame,
collocated_bytes_per_lcu, tnbr_per_lcu, dpb_bpp,
original_color_format, vertical_tile_width;
bool work_mode_1, original_compression_enabled,
low_power, rotation, cropping_or_scaling,
b_frames_enabled = false,
llc_ref_chroma_cache_enabled = false,
llc_top_line_buf_enabled = false,
llc_vpss_rot_line_buf_enabled = false;
fp_t bins_to_bit_factor, dpb_compression_factor,
original_compression_factor,
original_compression_factor_y,
y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp, y_bw_10bpp_p010,
input_compression_factor,
downscaling_ratio,
ref_y_read_bw_factor, ref_cbcr_read_bw_factor,
recon_write_bw_factor, mese_read_factor,
total_ref_read_crcb,
qsmmu_bw_overhead_factor;
fp_t integer_part, frac_part;
unsigned long ret = 0;
/* Output parameters */
struct {
fp_t vsp_read, vsp_write, collocated_read, collocated_write,
ref_read_y, ref_read_crcb, ref_write,
ref_write_overlap, orig_read,
line_buffer_read, line_buffer_write,
mese_read, mese_write,
total;
} ddr = {0};
struct {
fp_t ref_read_crcb, line_buffer, total;
} llc = {0};
/* Encoder Parameters setup */
rotation = d->rotation;
cropping_or_scaling = false;
vertical_tile_width = 960;
recon_write_bw_factor = FP(1, 8, 100);
ref_y_read_bw_factor = FP(1, 30, 100);
ref_cbcr_read_bw_factor = FP(1, 50, 100);
/* Derived Parameters */
fps = d->fps;
width = max(d->output_width, BASELINE_DIMENSIONS.width);
height = max(d->output_height, BASELINE_DIMENSIONS.height);
downscaling_ratio = fp_div(FP_INT(d->input_width * d->input_height),
FP_INT(d->output_width * d->output_height));
downscaling_ratio = max(downscaling_ratio, FP_ONE);
bitrate = d->bitrate > 0 ? (d->bitrate + 1000000 - 1) / 1000000 :
__lut(width, height, fps)->bitrate;
lcu_size = d->lcu_size;
lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
DIV_ROUND_UP(height, lcu_size);
tnbr_per_lcu = 16;
y_bw_no_ubwc_8bpp = fp_div(fp_mult(
FP_INT((int)(width * height)), FP_INT(fps)),
FP_INT(1000 * 1000));
y_bw_no_ubwc_10bpp = fp_div(fp_mult(y_bw_no_ubwc_8bpp,
FP_INT(256)), FP_INT(192));
y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2;
b_frames_enabled = d->b_frames_enabled;
original_color_format = d->num_formats >= 1 ?
d->color_formats[0] : HAL_UNUSED_COLOR;
dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX;
original_compression_enabled = __ubwc(original_color_format);
work_mode_1 = d->work_mode == HFI_WORKMODE_1;
low_power = d->power_mode == VIDC_POWER_LOW;
bins_to_bit_factor = FP_INT(4);
if (d->use_sys_cache) {
llc_ref_chroma_cache_enabled = true;
llc_top_line_buf_enabled = true,
llc_vpss_rot_line_buf_enabled = true;
}
/*
* Convert Q16 number into Integer and Fractional part upto 2 places.
* Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752;
* Integer part = 105752 / 65536 = 1;
* Reminder = 105752 - 1 * 65536 = 40216;
* Fractional part = 40216 * 100 / 65536 = 61;
* Now converto to FP(1, 61, 100) for below code.
*/
integer_part = d->compression_ratio >> 16;
frac_part =
((d->compression_ratio - (integer_part * 65536)) * 100) >> 16;
dpb_compression_factor = FP(integer_part, frac_part, 100);
integer_part = d->input_cr >> 16;
frac_part =
((d->input_cr - (integer_part * 65536)) * 100) >> 16;
input_compression_factor = FP(integer_part, frac_part, 100);
original_compression_factor = original_compression_factor_y =
!original_compression_enabled ? FP_ONE :
__compression_ratio(__lut(width, height, fps), dpb_bpp);
/* use input cr if it is valid (not 1), otherwise use lut */
if (original_compression_enabled &&
input_compression_factor != FP_ONE) {
original_compression_factor = input_compression_factor;
/* Luma usually has lower compression factor than Chroma,
* input cf is overall cf, add 1.08 factor for Luma cf
*/
original_compression_factor_y =
input_compression_factor > FP(1, 8, 100) ?
fp_div(input_compression_factor, FP(1, 8, 100)) :
input_compression_factor;
}
mese_read_factor = fp_div(FP_INT((width * height * fps)/4),
original_compression_factor_y);
mese_read_factor = fp_div(fp_mult(mese_read_factor, FP(2, 53, 100)),
FP_INT(1000 * 1000));
ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate), bins_to_bit_factor),
FP_INT(8));
ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8));
collocated_bytes_per_lcu = lcu_size == 16 ? 16 :
lcu_size == 32 ? 64 : 256;
ddr.collocated_read = fp_div(FP_INT(lcu_per_frame *
collocated_bytes_per_lcu * fps), FP_INT(bps(1)));
ddr.collocated_write = ddr.collocated_read;
ddr.ref_read_y = ddr.ref_read_crcb = dpb_bpp == 8 ?
y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp;
if (width != vertical_tile_width) {
ddr.ref_read_y = fp_mult(ddr.ref_read_y,
ref_y_read_bw_factor);
}
ddr.ref_read_y = fp_div(ddr.ref_read_y, dpb_compression_factor);
if (b_frames_enabled)
ddr.ref_read_y = fp_mult(ddr.ref_read_y, FP_INT(2));
ddr.ref_read_crcb = fp_mult(ddr.ref_read_crcb, FP(0, 50, 100));
ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb, dpb_compression_factor);
if (b_frames_enabled)
ddr.ref_read_crcb = fp_mult(ddr.ref_read_crcb, FP_INT(2));
if (llc_ref_chroma_cache_enabled) {
total_ref_read_crcb = ddr.ref_read_crcb;
ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb,
ref_cbcr_read_bw_factor);
llc.ref_read_crcb = total_ref_read_crcb - ddr.ref_read_crcb;
}
ddr.ref_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp;
ddr.ref_write = fp_mult(ddr.ref_write,
(fp_div(FP(1, 50, 100), dpb_compression_factor)));
ddr.ref_write_overlap = fp_div(fp_mult(ddr.ref_write,
(recon_write_bw_factor - FP_ONE)),
recon_write_bw_factor);
ddr.orig_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp :
(original_compression_enabled ? y_bw_no_ubwc_10bpp :
y_bw_10bpp_p010);
ddr.orig_read = fp_div(fp_mult(fp_mult(ddr.orig_read, FP(1, 50, 100)),
downscaling_ratio), original_compression_factor);
if (rotation == 90 || rotation == 270)
ddr.orig_read *= lcu_size == 32 ? (dpb_bpp == 8 ? 1 : 3) : 2;
ddr.line_buffer_read = FP_INT(tnbr_per_lcu * lcu_per_frame *
fps / bps(1));
ddr.line_buffer_write = ddr.line_buffer_read;
if (llc_top_line_buf_enabled) {
llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write;
ddr.line_buffer_read = ddr.line_buffer_write = FP_ZERO;
}
ddr.mese_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp;
ddr.mese_read = fp_div(fp_mult(ddr.mese_read, FP(1, 37, 100)),
original_compression_factor_y) + mese_read_factor;
ddr.mese_write = FP_INT((width * height)/512) +
fp_div(FP_INT((width * height)/4),
original_compression_factor_y) +
FP_INT((width * height)/128);
ddr.mese_write = fp_div(fp_mult(ddr.mese_write, FP_INT(fps)),
FP_INT(1000 * 1000));
ddr.total = ddr.vsp_read + ddr.vsp_write +
ddr.collocated_read + ddr.collocated_write +
ddr.ref_read_y + ddr.ref_read_crcb +
ddr.ref_write + ddr.ref_write_overlap +
ddr.orig_read +
ddr.line_buffer_read + ddr.line_buffer_write +
ddr.mese_read + ddr.mese_write;
qsmmu_bw_overhead_factor = FP(1, 3, 100);
ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
llc.total = llc.ref_read_crcb + llc.line_buffer + ddr.total;
if (msm_vidc_debug & VIDC_PROF) {
struct dump dump[] = {
{"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC},
{"width", "%d", width},
{"height", "%d", height},
{"fps", "%d", fps},
{"dpb bitdepth", "%d", dpb_bpp},
{"input downscaling ratio", DUMP_FP_FMT, downscaling_ratio},
{"rotation", "%d", rotation},
{"cropping or scaling", "%d", cropping_or_scaling},
{"low power mode", "%d", low_power},
{"work Mode", "%d", work_mode_1},
{"B frame enabled", "%d", b_frames_enabled},
{"original frame format", "%#x", original_color_format},
{"original compression enabled", "%d",
original_compression_enabled},
{"dpb compression factor", DUMP_FP_FMT,
dpb_compression_factor},
{"input compression factor", DUMP_FP_FMT,
input_compression_factor},
{"llc ref chroma cache enabled", DUMP_FP_FMT,
llc_ref_chroma_cache_enabled},
{"llc top line buf enabled", DUMP_FP_FMT,
llc_top_line_buf_enabled},
{"llc vpss rot line buf enabled ", DUMP_FP_FMT,
llc_vpss_rot_line_buf_enabled},
{"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC},
{"lcu size", "%d", lcu_size},
{"bitrate (Mbit/sec)", "%lu", bitrate},
{"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor},
{"original compression factor", DUMP_FP_FMT,
original_compression_factor},
{"original compression factor y", DUMP_FP_FMT,
original_compression_factor_y},
{"mese read factor", DUMP_FP_FMT,
mese_read_factor},
{"qsmmu_bw_overhead_factor",
DUMP_FP_FMT, qsmmu_bw_overhead_factor},
{"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp},
{"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp},
{"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC},
{"vsp read", DUMP_FP_FMT, ddr.vsp_read},
{"vsp write", DUMP_FP_FMT, ddr.vsp_write},
{"collocated read", DUMP_FP_FMT, ddr.collocated_read},
{"collocated write", DUMP_FP_FMT, ddr.collocated_write},
{"ref read y", DUMP_FP_FMT, ddr.ref_read_y},
{"ref read crcb", DUMP_FP_FMT, ddr.ref_read_crcb},
{"ref write", DUMP_FP_FMT, ddr.ref_write},
{"ref write overlap", DUMP_FP_FMT, ddr.ref_write_overlap},
{"original read", DUMP_FP_FMT, ddr.orig_read},
{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read},
{"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write},
{"mese read", DUMP_FP_FMT, ddr.mese_read},
{"mese write", DUMP_FP_FMT, ddr.mese_write},
{"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC},
{"llc ref read crcb", DUMP_FP_FMT, llc.ref_read_crcb},
{"llc line buffer", DUMP_FP_FMT, llc.line_buffer},
};
__dump(dump, ARRAY_SIZE(dump));
}
switch (type) {
case DDR:
ret = kbps(fp_round(ddr.total));
break;
case LLCC:
ret = kbps(fp_round(llc.total));
break;
default:
dprintk(VIDC_ERR, "%s - Unknown type\n", __func__);
}
return ret;
}
static unsigned long __calculate(struct vidc_bus_vote_data *d,
enum vidc_bus_type type)
{
unsigned long value = 0;
switch (d->domain) {
case HAL_VIDEO_DOMAIN_VPE:
value = __calculate_vpe(d, type);
break;
case HAL_VIDEO_DOMAIN_ENCODER:
value = __calculate_encoder(d, type);
break;
case HAL_VIDEO_DOMAIN_DECODER:
value = __calculate_decoder(d, type);
break;
case HAL_VIDEO_DOMAIN_CVP:
value = __calculate_cvp(d, type);
break;
default:
dprintk(VIDC_ERR, "Unknown Domain");
}
return value;
}
unsigned long calc_bw_iris1(struct bus_info *bus,
struct msm_vidc_bus_data *vidc_data)
{
unsigned long ab_kbps = 0, c = 0;
enum vidc_bus_type type;
if (!vidc_data || !vidc_data->data_count || !vidc_data->data)
goto exit;
for (c = 0; c < vidc_data->data_count; ++c) {
if (vidc_data->data->power_mode == VIDC_POWER_TURBO) {
ab_kbps = INT_MAX;
goto exit;
}
}
type = get_type_frm_name(bus->name);
for (c = 0; c < vidc_data->data_count; ++c)
ab_kbps += __calculate(&vidc_data->data[c], type);
exit:
trace_msm_vidc_perf_bus_vote(bus->name, ab_kbps);
return ab_kbps;
}

View file

@ -0,0 +1,637 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
*/
#include "msm_vidc_bus.h"
#include "msm_vidc_internal.h"
static unsigned long __calculate_vpe(struct vidc_bus_vote_data *d,
enum vidc_bus_type type)
{
return 0;
}
static unsigned long __calculate_cvp(struct vidc_bus_vote_data *d,
enum vidc_bus_type type)
{
unsigned long ret = 0;
switch (type) {
case DDR:
ret = d->ddr_bw;
break;
case LLCC:
ret = d->sys_cache_bw;
break;
default:
dprintk(VIDC_ERR, "%s - Unknown type\n", __func__);
break;
}
return ret;
}
static unsigned long __calculate_decoder(struct vidc_bus_vote_data *d,
enum vidc_bus_type type)
{
/*
* XXX: Don't fool around with any of the hardcoded numbers unless you
* know /exactly/ what you're doing. Many of these numbers are
* measured heuristics and hardcoded numbers taken from the firmware.
*/
/* Decoder parameters */
int width, height, lcu_size, fps, dpb_bpp;
bool unified_dpb_opb, dpb_compression_enabled = true,
opb_compression_enabled = false,
llc_ref_read_l2_cache_enabled = false,
llc_top_line_buf_enabled = false;
fp_t dpb_read_compression_factor, dpb_opb_scaling_ratio,
dpb_write_compression_factor, opb_write_compression_factor,
qsmmu_bw_overhead_factor;
bool is_h264_category = true;
/* Derived parameters */
int lcu_per_frame, collocated_bytes_per_lcu, tnbr_per_lcu;
unsigned long bitrate;
fp_t bins_to_bit_factor, vsp_read_factor, vsp_write_factor,
dpb_factor, dpb_write_factor,
y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp, y_bw_10bpp_p010,
motion_vector_complexity = 0;
fp_t dpb_total = 0;
/* Output parameters */
struct {
fp_t vsp_read, vsp_write, collocated_read, collocated_write,
dpb_read, dpb_write, opb_read, opb_write,
line_buffer_read, line_buffer_write,
total;
} ddr = {0};
struct {
fp_t dpb_read, line_buffer_read, line_buffer_write, total;
} llc = {0};
unsigned long ret = 0;
unsigned int integer_part, frac_part;
width = max(d->input_width, BASELINE_DIMENSIONS.width);
height = max(d->input_height, BASELINE_DIMENSIONS.height);
fps = d->fps;
lcu_size = d->lcu_size;
dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX;
unified_dpb_opb = d->num_formats == 1;
dpb_opb_scaling_ratio = fp_div(FP_INT(d->input_width * d->input_height),
FP_INT(d->output_width * d->output_height));
opb_compression_enabled = d->num_formats >= 2 &&
__ubwc(d->color_formats[1]);
/*
* convert q16 number into integer and fractional part upto 2 places.
* ex : 105752 / 65536 = 1.61; 1.61 in q16 = 105752;
* integer part = 105752 / 65536 = 1;
* reminder = 105752 - 1 * 65536 = 40216;
* fractional part = 40216 * 100 / 65536 = 61;
* now converto to fp(1, 61, 100) for below code.
*/
integer_part = d->compression_ratio >> 16;
frac_part =
((d->compression_ratio - (integer_part << 16)) * 100) >> 16;
dpb_read_compression_factor = FP(integer_part, frac_part, 100);
integer_part = d->complexity_factor >> 16;
frac_part =
((d->complexity_factor - (integer_part << 16)) * 100) >> 16;
motion_vector_complexity = FP(integer_part, frac_part, 100);
dpb_write_compression_factor = dpb_read_compression_factor;
opb_write_compression_factor = opb_compression_enabled ?
dpb_write_compression_factor : FP_ONE;
if (d->codec == HAL_VIDEO_CODEC_HEVC ||
d->codec == HAL_VIDEO_CODEC_VP9) {
/* H264, VP8, MPEG2 use the same settings */
/* HEVC, VP9 use the same setting */
is_h264_category = false;
}
if (d->use_sys_cache) {
llc_ref_read_l2_cache_enabled = true;
if (is_h264_category)
llc_top_line_buf_enabled = true;
}
/* Derived parameters setup */
lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
DIV_ROUND_UP(height, lcu_size);
bitrate = __lut(width, height, fps)->bitrate;
bins_to_bit_factor = FP_INT(4);
vsp_write_factor = bins_to_bit_factor;
vsp_read_factor = bins_to_bit_factor + FP_INT(2);
collocated_bytes_per_lcu = lcu_size == 16 ? 16 :
lcu_size == 32 ? 64 : 256;
dpb_factor = FP(1, 50, 100);
dpb_write_factor = FP(1, 5, 100);
tnbr_per_lcu = lcu_size == 16 ? 128 :
lcu_size == 32 ? 64 : 128;
/* .... For DDR & LLC ...... */
ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate),
vsp_read_factor), FP_INT(8));
ddr.vsp_write = fp_div(fp_mult(FP_INT(bitrate),
vsp_write_factor), FP_INT(8));
ddr.collocated_read = fp_div(FP_INT(lcu_per_frame *
collocated_bytes_per_lcu * fps), FP_INT(bps(1)));
ddr.collocated_write = ddr.collocated_read;
y_bw_no_ubwc_8bpp = fp_div(fp_mult(
FP_INT((int)(width * height)), FP_INT((int)fps)),
FP_INT(1000 * 1000));
y_bw_no_ubwc_10bpp = fp_div(fp_mult(y_bw_no_ubwc_8bpp, FP_INT(256)),
FP_INT(192));
y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2;
ddr.dpb_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp;
ddr.dpb_read = fp_div(fp_mult(ddr.dpb_read,
fp_mult(dpb_factor, motion_vector_complexity)),
dpb_read_compression_factor);
ddr.dpb_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp;
ddr.dpb_write = fp_div(fp_mult(ddr.dpb_write,
fp_mult(dpb_factor, dpb_write_factor)),
dpb_write_compression_factor);
dpb_total = ddr.dpb_read + ddr.dpb_write;
if (llc_ref_read_l2_cache_enabled) {
ddr.dpb_read = fp_div(ddr.dpb_read, is_h264_category ?
FP(1, 15, 100) : FP(1, 30, 100));
llc.dpb_read = dpb_total - ddr.dpb_write - ddr.dpb_read;
}
ddr.opb_read = FP_ZERO;
ddr.opb_write = unified_dpb_opb ? FP_ZERO : (dpb_bpp == 8 ?
y_bw_no_ubwc_8bpp : (opb_compression_enabled ?
y_bw_no_ubwc_10bpp : y_bw_10bpp_p010));
ddr.opb_write = fp_div(fp_mult(dpb_factor, ddr.opb_write),
fp_mult(dpb_opb_scaling_ratio, opb_write_compression_factor));
ddr.line_buffer_read = FP_INT(tnbr_per_lcu *
lcu_per_frame * fps / bps(1));
ddr.line_buffer_write = ddr.line_buffer_read;
if (llc_top_line_buf_enabled) {
llc.line_buffer_read = ddr.line_buffer_read;
llc.line_buffer_write = ddr.line_buffer_write;
ddr.line_buffer_write = ddr.line_buffer_read = FP_ZERO;
}
ddr.total = ddr.vsp_read + ddr.vsp_write +
ddr.collocated_read + ddr.collocated_write +
ddr.dpb_read + ddr.dpb_write +
ddr.opb_read + ddr.opb_write +
ddr.line_buffer_read + ddr.line_buffer_write;
qsmmu_bw_overhead_factor = FP(1, 3, 100);
ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
llc.total = llc.dpb_read + llc.line_buffer_read +
llc.line_buffer_write + ddr.total;
/* Dump all the variables for easier debugging */
if (msm_vidc_debug & VIDC_PROF) {
struct dump dump[] = {
{"DECODER PARAMETERS", "", DUMP_HEADER_MAGIC},
{"lcu size", "%d", lcu_size},
{"dpb bitdepth", "%d", dpb_bpp},
{"frame rate", "%d", fps},
{"dpb/opb unified", "%d", unified_dpb_opb},
{"dpb/opb downscaling ratio", DUMP_FP_FMT,
dpb_opb_scaling_ratio},
{"dpb compression", "%d", dpb_compression_enabled},
{"opb compression", "%d", opb_compression_enabled},
{"dpb read compression factor", DUMP_FP_FMT,
dpb_read_compression_factor},
{"dpb write compression factor", DUMP_FP_FMT,
dpb_write_compression_factor},
{"frame width", "%d", width},
{"frame height", "%d", height},
{"llc ref read l2 cache enabled", "%d",
llc_ref_read_l2_cache_enabled},
{"llc top line buf enabled", "%d",
llc_top_line_buf_enabled},
{"DERIVED PARAMETERS (1)", "", DUMP_HEADER_MAGIC},
{"lcus/frame", "%d", lcu_per_frame},
{"bitrate (Mbit/sec)", "%d", bitrate},
{"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor},
{"dpb write factor", DUMP_FP_FMT, dpb_write_factor},
{"vsp read factor", DUMP_FP_FMT, vsp_read_factor},
{"vsp write factor", DUMP_FP_FMT, vsp_write_factor},
{"tnbr/lcu", "%d", tnbr_per_lcu},
{"collocated bytes/LCU", "%d", collocated_bytes_per_lcu},
{"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp},
{"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp},
{"DERIVED PARAMETERS (2)", "", DUMP_HEADER_MAGIC},
{"mv complexity", DUMP_FP_FMT, motion_vector_complexity},
{"qsmmu_bw_overhead_factor", DUMP_FP_FMT,
qsmmu_bw_overhead_factor},
{"INTERMEDIATE DDR B/W", "", DUMP_HEADER_MAGIC},
{"vsp read", DUMP_FP_FMT, ddr.vsp_read},
{"vsp write", DUMP_FP_FMT, ddr.vsp_write},
{"collocated read", DUMP_FP_FMT, ddr.collocated_read},
{"collocated write", DUMP_FP_FMT, ddr.collocated_write},
{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read},
{"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write},
{"opb read", DUMP_FP_FMT, ddr.opb_read},
{"opb write", DUMP_FP_FMT, ddr.opb_write},
{"dpb read", DUMP_FP_FMT, ddr.dpb_read},
{"dpb write", DUMP_FP_FMT, ddr.dpb_write},
{"dpb total", DUMP_FP_FMT, dpb_total},
{"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC},
{"llc dpb read", DUMP_FP_FMT, llc.dpb_read},
{"llc line buffer read", DUMP_FP_FMT, llc.line_buffer_read},
{"llc line buffer write", DUMP_FP_FMT, llc.line_buffer_write},
};
__dump(dump, ARRAY_SIZE(dump));
}
switch (type) {
case DDR:
ret = kbps(fp_round(ddr.total));
break;
case LLCC:
ret = kbps(fp_round(llc.total));
break;
default:
dprintk(VIDC_ERR, "%s - Unknown type\n", __func__);
}
return ret;
}
static unsigned long __calculate_encoder(struct vidc_bus_vote_data *d,
enum vidc_bus_type type)
{
/*
* XXX: Don't fool around with any of the hardcoded numbers unless you
* know /exactly/ what you're doing. Many of these numbers are
* measured heuristics and hardcoded numbers taken from the firmware.
*/
/* Encoder Parameters */
int width, height, fps, lcu_size, bitrate, lcu_per_frame,
collocated_bytes_per_lcu, tnbr_per_lcu, dpb_bpp,
original_color_format, vertical_tile_width, rotation;
bool work_mode_1, original_compression_enabled,
low_power, cropping_or_scaling,
b_frames_enabled = false,
llc_ref_chroma_cache_enabled = false,
llc_top_line_buf_enabled = false,
llc_vpss_rot_line_buf_enabled = false;
fp_t bins_to_bit_factor, dpb_compression_factor,
original_compression_factor,
original_compression_factor_y,
y_bw_no_ubwc_8bpp, y_bw_no_ubwc_10bpp, y_bw_10bpp_p010,
input_compression_factor,
downscaling_ratio,
ref_y_read_bw_factor, ref_cbcr_read_bw_factor,
recon_write_bw_factor, mese_read_factor,
total_ref_read_crcb,
qsmmu_bw_overhead_factor;
fp_t integer_part, frac_part;
unsigned long ret = 0;
/* Output parameters */
struct {
fp_t vsp_read, vsp_write, collocated_read, collocated_write,
ref_read_y, ref_read_crcb, ref_write,
ref_write_overlap, orig_read,
line_buffer_read, line_buffer_write,
mese_read, mese_write,
total;
} ddr = {0};
struct {
fp_t ref_read_crcb, line_buffer, total;
} llc = {0};
/* Encoder Parameters setup */
rotation = d->rotation;
cropping_or_scaling = false;
vertical_tile_width = 960;
recon_write_bw_factor = FP(1, 8, 100);
ref_y_read_bw_factor = FP(1, 30, 100);
ref_cbcr_read_bw_factor = FP(1, 50, 100);
/* Derived Parameters */
fps = d->fps;
width = max(d->output_width, BASELINE_DIMENSIONS.width);
height = max(d->output_height, BASELINE_DIMENSIONS.height);
downscaling_ratio = fp_div(FP_INT(d->input_width * d->input_height),
FP_INT(d->output_width * d->output_height));
downscaling_ratio = max(downscaling_ratio, FP_ONE);
bitrate = d->bitrate > 0 ? d->bitrate / 1000000 :
__lut(width, height, fps)->bitrate;
lcu_size = d->lcu_size;
lcu_per_frame = DIV_ROUND_UP(width, lcu_size) *
DIV_ROUND_UP(height, lcu_size);
tnbr_per_lcu = 16;
y_bw_no_ubwc_8bpp = fp_div(fp_mult(
FP_INT((int)(width * height)), FP_INT(fps)),
FP_INT(1000 * 1000));
y_bw_no_ubwc_10bpp = fp_div(fp_mult(y_bw_no_ubwc_8bpp,
FP_INT(256)), FP_INT(192));
y_bw_10bpp_p010 = y_bw_no_ubwc_8bpp * 2;
b_frames_enabled = d->b_frames_enabled;
original_color_format = d->num_formats >= 1 ?
d->color_formats[0] : HAL_UNUSED_COLOR;
dpb_bpp = d->num_formats >= 1 ? __bpp(d->color_formats[0]) : INT_MAX;
original_compression_enabled = __ubwc(original_color_format);
work_mode_1 = d->work_mode == HFI_WORKMODE_1;
low_power = d->power_mode == VIDC_POWER_LOW;
bins_to_bit_factor = FP_INT(4);
if (d->use_sys_cache) {
llc_ref_chroma_cache_enabled = true;
llc_top_line_buf_enabled = true,
llc_vpss_rot_line_buf_enabled = true;
}
/*
* Convert Q16 number into Integer and Fractional part upto 2 places.
* Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752;
* Integer part = 105752 / 65536 = 1;
* Reminder = 105752 - 1 * 65536 = 40216;
* Fractional part = 40216 * 100 / 65536 = 61;
* Now converto to FP(1, 61, 100) for below code.
*/
integer_part = d->compression_ratio >> 16;
frac_part =
((d->compression_ratio - (integer_part * 65536)) * 100) >> 16;
dpb_compression_factor = FP(integer_part, frac_part, 100);
integer_part = d->input_cr >> 16;
frac_part =
((d->input_cr - (integer_part * 65536)) * 100) >> 16;
input_compression_factor = FP(integer_part, frac_part, 100);
original_compression_factor = original_compression_factor_y =
!original_compression_enabled ? FP_ONE :
__compression_ratio(__lut(width, height, fps), dpb_bpp);
/* use input cr if it is valid (not 1), otherwise use lut */
if (original_compression_enabled &&
input_compression_factor != FP_ONE) {
original_compression_factor = input_compression_factor;
/* Luma usually has lower compression factor than Chroma,
* input cf is overall cf, add 1.08 factor for Luma cf
*/
original_compression_factor_y =
input_compression_factor > FP(1, 8, 100) ?
fp_div(input_compression_factor, FP(1, 8, 100)) :
input_compression_factor;
}
mese_read_factor = fp_div(FP_INT((width * height * fps)/4),
original_compression_factor_y);
mese_read_factor = fp_div(fp_mult(mese_read_factor, FP(2, 53, 100)),
FP_INT(1000 * 1000));
ddr.vsp_read = fp_div(fp_mult(FP_INT(bitrate), bins_to_bit_factor),
FP_INT(8));
ddr.vsp_write = ddr.vsp_read + fp_div(FP_INT(bitrate), FP_INT(8));
collocated_bytes_per_lcu = lcu_size == 16 ? 16 :
lcu_size == 32 ? 64 : 256;
ddr.collocated_read = fp_div(FP_INT(lcu_per_frame *
collocated_bytes_per_lcu * fps), FP_INT(bps(1)));
ddr.collocated_write = ddr.collocated_read;
ddr.ref_read_y = ddr.ref_read_crcb = dpb_bpp == 8 ?
y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp;
if (width != vertical_tile_width) {
ddr.ref_read_y = fp_mult(ddr.ref_read_y,
ref_y_read_bw_factor);
}
ddr.ref_read_y = fp_div(ddr.ref_read_y, dpb_compression_factor);
if (b_frames_enabled)
ddr.ref_read_y = fp_mult(ddr.ref_read_y, FP_INT(2));
ddr.ref_read_crcb = fp_mult(ddr.ref_read_crcb, FP(0, 50, 100));
ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb, dpb_compression_factor);
if (b_frames_enabled)
ddr.ref_read_crcb = fp_mult(ddr.ref_read_crcb, FP_INT(2));
if (llc_ref_chroma_cache_enabled) {
total_ref_read_crcb = ddr.ref_read_crcb;
ddr.ref_read_crcb = fp_div(ddr.ref_read_crcb,
ref_cbcr_read_bw_factor);
llc.ref_read_crcb = total_ref_read_crcb - ddr.ref_read_crcb;
}
ddr.ref_write = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp;
ddr.ref_write = fp_mult(ddr.ref_write,
(fp_div(FP(1, 50, 100), dpb_compression_factor)));
ddr.ref_write_overlap = fp_div(fp_mult(ddr.ref_write,
(recon_write_bw_factor - FP_ONE)),
recon_write_bw_factor);
ddr.orig_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp :
(original_compression_enabled ? y_bw_no_ubwc_10bpp :
y_bw_10bpp_p010);
ddr.orig_read = fp_div(fp_mult(fp_mult(ddr.orig_read, FP(1, 50, 100)),
downscaling_ratio), original_compression_factor);
if (rotation == 90 || rotation == 270)
ddr.orig_read *= lcu_size == 32 ? (dpb_bpp == 8 ? 1 : 3) : 2;
ddr.line_buffer_read = FP_INT(tnbr_per_lcu * lcu_per_frame *
fps / bps(1));
ddr.line_buffer_write = ddr.line_buffer_read;
if (llc_top_line_buf_enabled) {
llc.line_buffer = ddr.line_buffer_read + ddr.line_buffer_write;
ddr.line_buffer_read = ddr.line_buffer_write = FP_ZERO;
}
ddr.mese_read = dpb_bpp == 8 ? y_bw_no_ubwc_8bpp : y_bw_no_ubwc_10bpp;
ddr.mese_read = fp_div(fp_mult(ddr.mese_read, FP(1, 37, 100)),
original_compression_factor_y) + mese_read_factor;
ddr.mese_write = FP_INT((width * height)/512) +
fp_div(FP_INT((width * height)/4),
original_compression_factor_y) +
FP_INT((width * height)/128);
ddr.mese_write = fp_div(fp_mult(ddr.mese_write, FP_INT(fps)),
FP_INT(1000 * 1000));
ddr.total = ddr.vsp_read + ddr.vsp_write +
ddr.collocated_read + ddr.collocated_write +
ddr.ref_read_y + ddr.ref_read_crcb +
ddr.ref_write + ddr.ref_write_overlap +
ddr.orig_read +
ddr.line_buffer_read + ddr.line_buffer_write +
ddr.mese_read + ddr.mese_write;
qsmmu_bw_overhead_factor = FP(1, 3, 100);
ddr.total = fp_mult(ddr.total, qsmmu_bw_overhead_factor);
llc.total = llc.ref_read_crcb + llc.line_buffer + ddr.total;
if (msm_vidc_debug & VIDC_PROF) {
struct dump dump[] = {
{"ENCODER PARAMETERS", "", DUMP_HEADER_MAGIC},
{"width", "%d", width},
{"height", "%d", height},
{"fps", "%d", fps},
{"dpb bitdepth", "%d", dpb_bpp},
{"input downscaling ratio", DUMP_FP_FMT, downscaling_ratio},
{"rotation", "%d", rotation},
{"cropping or scaling", "%d", cropping_or_scaling},
{"low power mode", "%d", low_power},
{"work Mode", "%d", work_mode_1},
{"B frame enabled", "%d", b_frames_enabled},
{"original frame format", "%#x", original_color_format},
{"original compression enabled", "%d",
original_compression_enabled},
{"dpb compression factor", DUMP_FP_FMT,
dpb_compression_factor},
{"input compression factor", DUMP_FP_FMT,
input_compression_factor},
{"llc ref chroma cache enabled", DUMP_FP_FMT,
llc_ref_chroma_cache_enabled},
{"llc top line buf enabled", DUMP_FP_FMT,
llc_top_line_buf_enabled},
{"llc vpss rot line buf enabled ", DUMP_FP_FMT,
llc_vpss_rot_line_buf_enabled},
{"DERIVED PARAMETERS", "", DUMP_HEADER_MAGIC},
{"lcu size", "%d", lcu_size},
{"bitrate (Mbit/sec)", "%lu", bitrate},
{"bins to bit factor", DUMP_FP_FMT, bins_to_bit_factor},
{"original compression factor", DUMP_FP_FMT,
original_compression_factor},
{"original compression factor y", DUMP_FP_FMT,
original_compression_factor_y},
{"mese read factor", DUMP_FP_FMT,
mese_read_factor},
{"qsmmu_bw_overhead_factor",
DUMP_FP_FMT, qsmmu_bw_overhead_factor},
{"bw for NV12 8bpc)", DUMP_FP_FMT, y_bw_no_ubwc_8bpp},
{"bw for NV12 10bpc)", DUMP_FP_FMT, y_bw_no_ubwc_10bpp},
{"INTERMEDIATE B/W DDR", "", DUMP_HEADER_MAGIC},
{"vsp read", DUMP_FP_FMT, ddr.vsp_read},
{"vsp write", DUMP_FP_FMT, ddr.vsp_write},
{"collocated read", DUMP_FP_FMT, ddr.collocated_read},
{"collocated write", DUMP_FP_FMT, ddr.collocated_write},
{"ref read y", DUMP_FP_FMT, ddr.ref_read_y},
{"ref read crcb", DUMP_FP_FMT, ddr.ref_read_crcb},
{"ref write", DUMP_FP_FMT, ddr.ref_write},
{"ref write overlap", DUMP_FP_FMT, ddr.ref_write_overlap},
{"original read", DUMP_FP_FMT, ddr.orig_read},
{"line buffer read", DUMP_FP_FMT, ddr.line_buffer_read},
{"line buffer write", DUMP_FP_FMT, ddr.line_buffer_write},
{"mese read", DUMP_FP_FMT, ddr.mese_read},
{"mese write", DUMP_FP_FMT, ddr.mese_write},
{"INTERMEDIATE LLC B/W", "", DUMP_HEADER_MAGIC},
{"llc ref read crcb", DUMP_FP_FMT, llc.ref_read_crcb},
{"llc line buffer", DUMP_FP_FMT, llc.line_buffer},
};
__dump(dump, ARRAY_SIZE(dump));
}
switch (type) {
case DDR:
ret = kbps(fp_round(ddr.total));
break;
case LLCC:
ret = kbps(fp_round(llc.total));
break;
default:
dprintk(VIDC_ERR, "%s - Unknown governor\n", __func__);
}
return ret;
}
static unsigned long __calculate(struct vidc_bus_vote_data *d,
enum vidc_bus_type type)
{
unsigned long value = 0;
switch (d->domain) {
case HAL_VIDEO_DOMAIN_VPE:
value = __calculate_vpe(d, type);
break;
case HAL_VIDEO_DOMAIN_ENCODER:
value = __calculate_encoder(d, type);
break;
case HAL_VIDEO_DOMAIN_DECODER:
value = __calculate_decoder(d, type);
break;
case HAL_VIDEO_DOMAIN_CVP:
value = __calculate_cvp(d, type);
break;
default:
dprintk(VIDC_ERR, "Unknown Domain");
}
return value;
}
unsigned long calc_bw_iris2(struct bus_info *bus,
struct msm_vidc_bus_data *vidc_data)
{
unsigned long ab_kbps = 0, c = 0;
enum vidc_bus_type type;
if (!vidc_data || !vidc_data->data_count || !vidc_data->data)
goto exit;
for (c = 0; c < vidc_data->data_count; ++c) {
if (vidc_data->data->power_mode == VIDC_POWER_TURBO) {
ab_kbps = INT_MAX;
goto exit;
}
}
type = get_type_frm_name(bus->name);
for (c = 0; c < vidc_data->data_count; ++c)
ab_kbps += __calculate(&vidc_data->data[c], type);
exit:
trace_msm_vidc_perf_bus_vote(bus->name, ab_kbps);
return ab_kbps;
}

1828
msm/vidc/msm_vidc_clocks.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,33 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_VIDC_CLOCKS_H_
#define _MSM_VIDC_CLOCKS_H_
#include "msm_vidc_internal.h"
void msm_clock_data_reset(struct msm_vidc_inst *inst);
int msm_vidc_set_clocks(struct msm_vidc_core *core);
int msm_comm_vote_bus(struct msm_vidc_core *core);
int msm_dcvs_try_enable(struct msm_vidc_inst *inst);
int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst);
int msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst);
int msm_comm_init_clocks_and_bus_data(struct msm_vidc_inst *inst);
void msm_comm_free_freq_table(struct msm_vidc_inst *inst);
int msm_vidc_decide_work_route_iris1(struct msm_vidc_inst *inst);
int msm_vidc_decide_work_mode_iris1(struct msm_vidc_inst *inst);
int msm_vidc_decide_work_route_iris2(struct msm_vidc_inst *inst);
int msm_vidc_decide_work_mode_iris2(struct msm_vidc_inst *inst);
int msm_vidc_decide_core_and_power_mode_iris1(struct msm_vidc_inst *inst);
int msm_vidc_decide_core_and_power_mode_iris2(struct msm_vidc_inst *inst);
void msm_print_core_status(struct msm_vidc_core *core, u32 core_id);
void msm_vidc_clear_freq_entry(struct msm_vidc_inst *inst,
u32 device_addr);
void msm_comm_free_input_cr_table(struct msm_vidc_inst *inst);
void msm_comm_update_input_cr(struct msm_vidc_inst *inst, u32 index,
u32 cr);
void update_recon_stats(struct msm_vidc_inst *inst,
struct recon_stats_type *recon_stats);
void msm_vidc_init_core_clk_ops(struct msm_vidc_core *core);
#endif

6783
msm/vidc/msm_vidc_common.c Normal file

File diff suppressed because it is too large Load diff

283
msm/vidc/msm_vidc_common.h Normal file
View file

@ -0,0 +1,283 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_VIDC_COMMON_H_
#define _MSM_VIDC_COMMON_H_
#include "msm_vidc_internal.h"
#include "msm_vidc_debug.h"
#define MAX_DEC_BATCH_SIZE 6
#define SKIP_BATCH_WINDOW 100
#define MIN_FRAME_QUALITY 0
#define MAX_FRAME_QUALITY 100
#define DEFAULT_FRAME_QUALITY 95
#define FRAME_QUALITY_STEP 1
#define HEIC_GRID_DIMENSION 512
#define CBR_MB_LIMIT (((1280+15)/16)*((720+15)/16)*30)
#define CBR_VFR_MB_LIMIT (((640+15)/16)*((480+15)/16)*30)
#define V4L2_CID_MPEG_VIDEO_UNKNOWN (V4L2_CID_MPEG_MSM_VIDC_BASE + 0xFFF)
struct vb2_buf_entry {
struct list_head list;
struct vb2_buffer *vb;
};
struct getprop_buf {
struct list_head list;
void *data;
};
enum load_calc_quirks {
LOAD_CALC_NO_QUIRKS = 0,
LOAD_CALC_IGNORE_TURBO_LOAD = 1 << 0,
LOAD_CALC_IGNORE_THUMBNAIL_LOAD = 1 << 1,
LOAD_CALC_IGNORE_NON_REALTIME_LOAD = 1 << 2,
};
enum client_set_controls {
CLIENT_SET_I_QP = 0x1,
CLIENT_SET_P_QP = 0x2,
CLIENT_SET_B_QP = 0x4,
CLIENT_SET_MIN_QP = 0x8,
CLIENT_SET_MAX_QP = 0x10,
};
static inline bool is_turbo_session(struct msm_vidc_inst *inst)
{
return !!(inst->flags & VIDC_TURBO);
}
static inline bool is_thumbnail_session(struct msm_vidc_inst *inst)
{
return !!(inst->flags & VIDC_THUMBNAIL);
}
static inline bool is_low_power_session(struct msm_vidc_inst *inst)
{
return !!(inst->flags & VIDC_LOW_POWER);
}
static inline struct v4l2_ctrl *get_ctrl(struct msm_vidc_inst *inst,
u32 id)
{
int i;
for (i = 0; i < inst->num_ctrls; i++) {
if (inst->ctrls[i]->id == id)
return inst->ctrls[i];
}
dprintk(VIDC_ERR, "%s: control id (%#x) not found\n", __func__, id);
MSM_VIDC_ERROR(true);
return inst->ctrls[0];
}
static inline u32 get_v4l2_codec(struct msm_vidc_inst *inst)
{
struct v4l2_format *f;
u32 port;
port = (inst->session_type == MSM_VIDC_DECODER) ? INPUT_PORT :
OUTPUT_PORT;
f = &inst->fmts[port].v4l2_fmt;
return f->fmt.pix_mp.pixelformat;
}
static inline bool is_realtime_session(struct msm_vidc_inst *inst)
{
return !!(inst->flags & VIDC_REALTIME);
}
static inline bool is_secure_session(struct msm_vidc_inst *inst)
{
return !!(inst->flags & VIDC_SECURE);
}
static inline bool is_decode_session(struct msm_vidc_inst *inst)
{
return inst->session_type == MSM_VIDC_DECODER;
}
static inline bool is_encode_session(struct msm_vidc_inst *inst)
{
return inst->session_type == MSM_VIDC_ENCODER;
}
static inline bool is_primary_output_mode(struct msm_vidc_inst *inst)
{
return inst->stream_output_mode == HAL_VIDEO_DECODER_PRIMARY;
}
static inline bool is_secondary_output_mode(struct msm_vidc_inst *inst)
{
return inst->stream_output_mode == HAL_VIDEO_DECODER_SECONDARY;
}
static inline bool in_port_reconfig(struct msm_vidc_inst *inst)
{
return inst->in_reconfig && inst->bufq[INPUT_PORT].vb2_bufq.streaming;
}
static inline int msm_comm_g_ctrl(struct msm_vidc_inst *inst,
struct v4l2_control *ctrl)
{
return v4l2_g_ctrl(&inst->ctrl_handler, ctrl);
}
static inline int msm_comm_s_ctrl(struct msm_vidc_inst *inst,
struct v4l2_control *ctrl)
{
return v4l2_s_ctrl(NULL, &inst->ctrl_handler, ctrl);
}
bool is_batching_allowed(struct msm_vidc_inst *inst);
enum hal_buffer get_hal_buffer_type(unsigned int type,
unsigned int plane_num);
void put_inst(struct msm_vidc_inst *inst);
struct msm_vidc_inst *get_inst(struct msm_vidc_core *core,
void *session_id);
void change_inst_state(struct msm_vidc_inst *inst, enum instance_state state);
struct msm_vidc_core *get_vidc_core(int core_id);
const struct msm_vidc_format_desc *msm_comm_get_pixel_fmt_index(
const struct msm_vidc_format_desc fmt[], int size, int index);
struct msm_vidc_format_desc *msm_comm_get_pixel_fmt_fourcc(
struct msm_vidc_format_desc fmt[], int size, int fourcc);
struct msm_vidc_format_constraint *msm_comm_get_pixel_fmt_constraints(
struct msm_vidc_format_constraint fmt[], int size, int fourcc);
int msm_comm_set_color_format_constraints(struct msm_vidc_inst *inst,
enum hal_buffer buffer_type,
struct msm_vidc_format_constraint *pix_constraint);
struct buf_queue *msm_comm_get_vb2q(
struct msm_vidc_inst *inst, enum v4l2_buf_type type);
int msm_comm_try_state(struct msm_vidc_inst *inst, int state);
int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst);
int msm_comm_try_get_buff_req(struct msm_vidc_inst *inst,
union hal_get_property *hprop);
int msm_comm_set_recon_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_scratch_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_set_buffer_count(struct msm_vidc_inst *inst,
int host_count, int act_count, enum hal_buffer type);
int msm_comm_set_dpb_only_buffers(struct msm_vidc_inst *inst);
int msm_comm_queue_dpb_only_buffers(struct msm_vidc_inst *inst);
int msm_comm_qbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf);
int msm_comm_qbufs(struct msm_vidc_inst *inst);
void msm_comm_flush_dynamic_buffers(struct msm_vidc_inst *inst);
int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags);
int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst,
bool check_for_reuse);
int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst);
int msm_comm_release_recon_buffers(struct msm_vidc_inst *inst);
void msm_comm_release_eos_buffers(struct msm_vidc_inst *inst);
int msm_comm_release_dpb_only_buffers(struct msm_vidc_inst *inst,
bool force_release);
void msm_comm_validate_output_buffers(struct msm_vidc_inst *inst);
int msm_comm_force_cleanup(struct msm_vidc_inst *inst);
int msm_comm_suspend(int core_id);
struct hal_buffer_requirements *get_buff_req_buffer(
struct msm_vidc_inst *inst, u32 buffer_type);
#define IS_PRIV_CTRL(idx) (\
(V4L2_CTRL_ID2WHICH(idx) == V4L2_CTRL_CLASS_MPEG) && \
V4L2_CTRL_DRIVER_PRIV(idx))
void msm_comm_session_clean(struct msm_vidc_inst *inst);
int msm_comm_kill_session(struct msm_vidc_inst *inst);
void msm_comm_generate_session_error(struct msm_vidc_inst *inst);
void msm_comm_generate_sys_error(struct msm_vidc_inst *inst);
enum multi_stream msm_comm_get_stream_output_mode(struct msm_vidc_inst *inst);
int msm_comm_set_stream_output_mode(struct msm_vidc_inst *inst,
enum multi_stream mode);
enum hal_buffer msm_comm_get_hal_output_buffer(struct msm_vidc_inst *inst);
int msm_comm_smem_alloc(struct msm_vidc_inst *inst, size_t size, u32 align,
u32 flags, enum hal_buffer buffer_type, int map_kernel,
struct msm_smem *smem);
void msm_comm_smem_free(struct msm_vidc_inst *inst, struct msm_smem *smem);
int msm_comm_smem_cache_operations(struct msm_vidc_inst *inst,
struct msm_smem *mem, enum smem_cache_ops cache_ops);
enum hal_video_codec get_hal_codec(int fourcc);
enum hal_domain get_hal_domain(int session_type);
int msm_comm_check_core_init(struct msm_vidc_core *core);
int msm_comm_get_inst_load(struct msm_vidc_inst *inst,
enum load_calc_quirks quirks);
int msm_comm_get_inst_load_per_core(struct msm_vidc_inst *inst,
enum load_calc_quirks quirks);
int msm_comm_get_load(struct msm_vidc_core *core,
enum session_type type, enum load_calc_quirks quirks);
int msm_comm_set_color_format(struct msm_vidc_inst *inst,
enum hal_buffer buffer_type, int fourcc);
int msm_comm_g_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl);
int msm_comm_s_ctrl(struct msm_vidc_inst *inst, struct v4l2_control *ctrl);
int msm_comm_g_ctrl_for_id(struct msm_vidc_inst *inst, int id);
int msm_comm_ctrl_init(struct msm_vidc_inst *inst,
struct msm_vidc_ctrl *drv_ctrls, u32 num_ctrls,
const struct v4l2_ctrl_ops *ctrl_ops);
int msm_comm_ctrl_deinit(struct msm_vidc_inst *inst);
void msm_comm_cleanup_internal_buffers(struct msm_vidc_inst *inst);
bool msm_comm_turbo_session(struct msm_vidc_inst *inst);
void msm_comm_print_inst_info(struct msm_vidc_inst *inst);
int msm_comm_v4l2_to_hfi(int id, int value);
int msm_comm_hfi_to_v4l2(int id, int value);
int msm_comm_get_v4l2_profile(int fourcc, int profile);
int msm_comm_get_v4l2_level(int fourcc, int level);
int msm_comm_session_continue(void *instance);
int msm_vidc_send_pending_eos_buffers(struct msm_vidc_inst *inst);
enum hal_uncompressed_format msm_comm_get_hal_uncompressed(int fourcc);
u32 msm_comm_get_hfi_uncompressed(int fourcc);
u32 msm_comm_convert_color_fmt(u32 v4l2_fmt);
struct vb2_buffer *msm_comm_get_vb_using_vidc_buffer(
struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf);
struct msm_vidc_buffer *msm_comm_get_buffer_using_device_planes(
struct msm_vidc_inst *inst, u32 type, u32 *planes);
struct msm_vidc_buffer *msm_comm_get_vidc_buffer(struct msm_vidc_inst *inst,
struct vb2_buffer *vb2);
void msm_comm_put_vidc_buffer(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf);
void handle_release_buffer_reference(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf);
int msm_comm_vb2_buffer_done(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf);
int msm_comm_flush_vidc_buffer(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf);
int msm_comm_unmap_vidc_buffer(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf);
bool msm_comm_compare_dma_plane(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf, unsigned long *dma_planes, u32 i);
bool msm_comm_compare_dma_planes(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf, unsigned long *dma_planes);
bool msm_comm_compare_vb2_plane(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf, struct vb2_buffer *vb2, u32 i);
bool msm_comm_compare_vb2_planes(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf, struct vb2_buffer *vb2);
bool msm_comm_compare_device_plane(struct msm_vidc_buffer *mbuf,
u32 type, u32 *planes, u32 i);
bool msm_comm_compare_device_planes(struct msm_vidc_buffer *mbuf,
u32 type, u32 *planes);
int msm_comm_qbuf_cache_operations(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf);
int msm_comm_dqbuf_cache_operations(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf);
void print_vidc_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf);
void print_vb2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
struct vb2_buffer *vb2);
void print_v4l2_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst,
struct v4l2_buffer *v4l2);
void kref_put_mbuf(struct msm_vidc_buffer *mbuf);
bool kref_get_mbuf(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf);
void msm_comm_store_filled_length(struct msm_vidc_list *data_list,
u32 index, u32 filled_length);
void msm_comm_fetch_filled_length(struct msm_vidc_list *data_list,
u32 index, u32 *filled_length);
void msm_comm_store_mark_data(struct msm_vidc_list *data_list,
u32 index, u32 mark_data, u32 mark_target);
void msm_comm_fetch_mark_data(struct msm_vidc_list *data_list,
u32 index, u32 *mark_data, u32 *mark_target);
int msm_comm_release_mark_data(struct msm_vidc_inst *inst);
int msm_comm_qbuf_decode_batch(struct msm_vidc_inst *inst,
struct msm_vidc_buffer *mbuf);
int msm_comm_num_queued_bufs(struct msm_vidc_inst *inst, u32 type);
int msm_comm_set_index_extradata(struct msm_vidc_inst *inst,
uint32_t extradata_id, uint32_t value);
int msm_comm_set_extradata(struct msm_vidc_inst *inst, uint32_t extradata_id,
uint32_t value);
bool msm_comm_check_for_inst_overload(struct msm_vidc_core *core);
#endif

533
msm/vidc/msm_vidc_debug.c Normal file
View file

@ -0,0 +1,533 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#define CREATE_TRACE_POINTS
#define MAX_SSR_STRING_LEN 10
#include "msm_vidc_debug.h"
#include "vidc_hfi_api.h"
#include <linux/of_fdt.h>
int msm_vidc_debug = VIDC_ERR | VIDC_WARN;
EXPORT_SYMBOL(msm_vidc_debug);
int msm_vidc_debug_out = VIDC_OUT_PRINTK;
EXPORT_SYMBOL(msm_vidc_debug_out);
bool msm_vidc_lossless_encode = !true;
EXPORT_SYMBOL(msm_vidc_lossless_encode);
int msm_vidc_fw_debug = HFI_DEBUG_MSG_HIGH |
HFI_DEBUG_MSG_ERROR | HFI_DEBUG_MSG_FATAL;
int msm_vidc_fw_debug_mode = 1;
bool msm_vidc_fw_coverage = !true;
bool msm_vidc_thermal_mitigation_disabled = !true;
int msm_vidc_clock_voting = !1;
bool msm_vidc_syscache_disable = !true;
#define MAX_DBG_BUF_SIZE 4096
#define DYNAMIC_BUF_OWNER(__binfo) ({ \
atomic_read(&__binfo->ref_count) >= 2 ? "video driver" : "firmware";\
})
struct core_inst_pair {
struct msm_vidc_core *core;
struct msm_vidc_inst *inst;
};
static u32 write_str(char *buffer,
size_t size, const char *fmt, ...)
{
va_list args;
u32 len;
va_start(args, fmt);
len = vscnprintf(buffer, size, fmt, args);
va_end(args);
return len;
}
static ssize_t core_info_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct msm_vidc_core *core = file->private_data;
struct hfi_device *hdev;
struct hal_fw_info fw_info = { {0} };
char *dbuf, *cur, *end;
int i = 0, rc = 0;
ssize_t len = 0;
if (!core || !core->device) {
dprintk(VIDC_ERR, "Invalid params, core: %pK\n", core);
return 0;
}
dbuf = kzalloc(MAX_DBG_BUF_SIZE, GFP_KERNEL);
if (!dbuf) {
dprintk(VIDC_ERR, "%s: Allocation failed!\n", __func__);
return -ENOMEM;
}
cur = dbuf;
end = cur + MAX_DBG_BUF_SIZE;
hdev = core->device;
cur += write_str(cur, end - cur, "===============================\n");
cur += write_str(cur, end - cur, "CORE %d: %pK\n", core->id, core);
cur += write_str(cur, end - cur, "===============================\n");
cur += write_str(cur, end - cur, "Core state: %d\n", core->state);
rc = call_hfi_op(hdev, get_fw_info, hdev->hfi_device_data, &fw_info);
if (rc) {
dprintk(VIDC_WARN, "Failed to read FW info\n");
goto err_fw_info;
}
cur += write_str(cur, end - cur,
"FW version : %s\n", &fw_info.version);
cur += write_str(cur, end - cur,
"base addr: 0x%x\n", fw_info.base_addr);
cur += write_str(cur, end - cur,
"register_base: 0x%x\n", fw_info.register_base);
cur += write_str(cur, end - cur,
"register_size: %u\n", fw_info.register_size);
cur += write_str(cur, end - cur, "irq: %u\n", fw_info.irq);
cur += write_str(cur, end - cur,
"ddr_type: %d\n", of_fdt_get_ddrtype());
err_fw_info:
for (i = SYS_MSG_START; i < SYS_MSG_END; i++) {
cur += write_str(cur, end - cur, "completions[%d]: %s\n", i,
completion_done(&core->completions[SYS_MSG_INDEX(i)]) ?
"pending" : "done");
}
len = simple_read_from_buffer(buf, count, ppos,
dbuf, cur - dbuf);
kfree(dbuf);
return len;
}
static const struct file_operations core_info_fops = {
.open = simple_open,
.read = core_info_read,
};
static ssize_t trigger_ssr_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long ssr_trigger_val = 0;
int rc = 0;
struct msm_vidc_core *core = filp->private_data;
size_t size = MAX_SSR_STRING_LEN;
char kbuf[MAX_SSR_STRING_LEN + 1] = {0};
if (!buf)
return -EINVAL;
if (!count)
goto exit;
if (count < size)
size = count;
if (copy_from_user(kbuf, buf, size)) {
dprintk(VIDC_WARN, "%s User memory fault\n", __func__);
rc = -EFAULT;
goto exit;
}
rc = kstrtoul(kbuf, 0, &ssr_trigger_val);
if (rc) {
dprintk(VIDC_WARN, "returning error err %d\n", rc);
rc = -EINVAL;
} else {
msm_vidc_trigger_ssr(core, ssr_trigger_val);
rc = count;
}
exit:
return rc;
}
static const struct file_operations ssr_fops = {
.open = simple_open,
.write = trigger_ssr_write,
};
struct dentry *msm_vidc_debugfs_init_drv(void)
{
bool ok = false;
struct dentry *dir = NULL;
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, 0644, \
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", &msm_vidc_debug) &&
__debugfs_create(x32, "fw_level", &msm_vidc_fw_debug) &&
__debugfs_create(u32, "fw_debug_mode", &msm_vidc_fw_debug_mode) &&
__debugfs_create(bool, "fw_coverage", &msm_vidc_fw_coverage) &&
__debugfs_create(u32, "debug_output", &msm_vidc_debug_out) &&
__debugfs_create(bool, "disable_thermal_mitigation",
&msm_vidc_thermal_mitigation_disabled) &&
__debugfs_create(u32, "core_clock_voting",
&msm_vidc_clock_voting) &&
__debugfs_create(bool, "disable_video_syscache",
&msm_vidc_syscache_disable) &&
__debugfs_create(bool, "lossless_encoding",
&msm_vidc_lossless_encode);
#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 *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
struct dentry *parent)
{
struct dentry *dir = NULL;
char debugfs_name[MAX_DEBUGFS_NAME];
if (!core) {
dprintk(VIDC_ERR, "Invalid params, core: %pK\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", 0444, dir, core, &core_info_fops)) {
dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
goto failed_create_dir;
}
if (!debugfs_create_file("trigger_ssr", 0200,
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)
{
dprintk(VIDC_INFO, "Open inode ptr: %pK\n", inode->i_private);
file->private_data = inode->i_private;
return 0;
}
static int publish_unreleased_reference(struct msm_vidc_inst *inst,
char **dbuf, char *end)
{
struct msm_vidc_buffer *temp = NULL;
char *cur = *dbuf;
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid param\n", __func__);
return -EINVAL;
}
if (inst->buffer_mode_set[OUTPUT_PORT] == HAL_BUFFER_MODE_DYNAMIC) {
cur += write_str(cur, end - cur, "Pending buffer references\n");
mutex_lock(&inst->registeredbufs.lock);
list_for_each_entry(temp, &inst->registeredbufs.list, list) {
struct vb2_buffer *vb2 = &temp->vvb.vb2_buf;
if (vb2->type == OUTPUT_MPLANE) {
cur += write_str(cur, end - cur,
"\tbuffer: %#x fd[0] = %d size %d refcount = %d\n",
temp->smem[0].device_addr,
vb2->planes[0].m.fd,
vb2->planes[0].length,
temp->smem[0].refcount);
}
}
mutex_unlock(&inst->registeredbufs.lock);
}
*dbuf = cur;
return 0;
}
static void put_inst_helper(struct kref *kref)
{
struct msm_vidc_inst *inst = container_of(kref,
struct msm_vidc_inst, kref);
msm_vidc_destroy(inst);
}
static ssize_t inst_info_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct core_inst_pair *idata = file->private_data;
struct msm_vidc_core *core;
struct msm_vidc_inst *inst, *temp = NULL;
char *dbuf, *cur, *end;
int i, j;
ssize_t len = 0;
struct v4l2_format *f;
if (!idata || !idata->core || !idata->inst) {
dprintk(VIDC_ERR, "%s: Invalid params\n", __func__);
return 0;
}
core = idata->core;
inst = idata->inst;
mutex_lock(&core->lock);
list_for_each_entry(temp, &core->instances, list) {
if (temp == inst)
break;
}
inst = ((temp == inst) && kref_get_unless_zero(&inst->kref)) ?
inst : NULL;
mutex_unlock(&core->lock);
if (!inst) {
dprintk(VIDC_ERR, "%s: Instance has become obsolete", __func__);
return 0;
}
dbuf = kzalloc(MAX_DBG_BUF_SIZE, GFP_KERNEL);
if (!dbuf) {
dprintk(VIDC_ERR, "%s: Allocation failed!\n", __func__);
len = -ENOMEM;
goto failed_alloc;
}
cur = dbuf;
end = cur + MAX_DBG_BUF_SIZE;
f = &inst->fmts[OUTPUT_PORT].v4l2_fmt;
cur += write_str(cur, end - cur, "==============================\n");
cur += write_str(cur, end - cur, "INSTANCE: %pK (%s)\n", inst,
inst->session_type == MSM_VIDC_ENCODER ? "Encoder" : "Decoder");
cur += write_str(cur, end - cur, "==============================\n");
cur += write_str(cur, end - cur, "core: %pK\n", inst->core);
cur += write_str(cur, end - cur, "height: %d\n", f->fmt.pix_mp.height);
cur += write_str(cur, end - cur, "width: %d\n", f->fmt.pix_mp.width);
cur += write_str(cur, end - cur, "fps: %d\n",
inst->clk_data.frame_rate >> 16);
cur += write_str(cur, end - cur, "state: %d\n", inst->state);
cur += write_str(cur, end - cur, "secure: %d\n",
!!(inst->flags & VIDC_SECURE));
cur += write_str(cur, end - cur, "-----------Formats-------------\n");
for (i = 0; i < MAX_PORT_NUM; i++) {
f = &inst->fmts[i].v4l2_fmt;
cur += write_str(cur, end - cur, "capability: %s\n",
i == INPUT_PORT ? "Output" : "Capture");
cur += write_str(cur, end - cur, "name : %s\n",
inst->fmts[i].name);
cur += write_str(cur, end - cur, "planes : %d\n",
f->fmt.pix_mp.num_planes);
cur += write_str(cur, end - cur,
"type: %s\n", i == INPUT_PORT ?
"Output" : "Capture");
switch (inst->buffer_mode_set[i]) {
case HAL_BUFFER_MODE_STATIC:
cur += write_str(cur, end - cur,
"buffer mode : %s\n", "static");
break;
case HAL_BUFFER_MODE_DYNAMIC:
cur += write_str(cur, end - cur,
"buffer mode : %s\n", "dynamic");
break;
default:
cur += write_str(cur, end - cur,
"buffer mode : unsupported\n");
}
cur += write_str(cur, end - cur, "count: %u\n",
inst->bufq[i].vb2_bufq.num_buffers);
for (j = 0; j < f->fmt.pix_mp.num_planes; j++)
cur += write_str(cur, end - cur,
"size for plane %d: %u\n",
j, f->fmt.pix_mp.plane_fmt[j].sizeimage);
if (i < MAX_PORT_NUM - 1)
cur += write_str(cur, end - cur, "\n");
}
cur += write_str(cur, end - cur, "-------------------------------\n");
for (i = SESSION_MSG_START; i < SESSION_MSG_END; i++) {
cur += write_str(cur, end - cur, "completions[%d]: %s\n", i,
completion_done(&inst->completions[SESSION_MSG_INDEX(i)]) ?
"pending" : "done");
}
cur += write_str(cur, end - cur, "ETB Count: %d\n", inst->count.etb);
cur += write_str(cur, end - cur, "EBD Count: %d\n", inst->count.ebd);
cur += write_str(cur, end - cur, "FTB Count: %d\n", inst->count.ftb);
cur += write_str(cur, end - cur, "FBD Count: %d\n", inst->count.fbd);
publish_unreleased_reference(inst, &cur, end);
len = simple_read_from_buffer(buf, count, ppos,
dbuf, cur - dbuf);
kfree(dbuf);
failed_alloc:
kref_put(&inst->kref, put_inst_helper);
return len;
}
static int inst_info_release(struct inode *inode, struct file *file)
{
dprintk(VIDC_INFO, "Release inode ptr: %pK\n", inode->i_private);
file->private_data = NULL;
return 0;
}
static const struct file_operations inst_info_fops = {
.open = inst_info_open,
.read = inst_info_read,
.release = inst_info_release,
};
struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
struct dentry *parent)
{
struct dentry *dir = NULL, *info = NULL;
char debugfs_name[MAX_DEBUGFS_NAME];
struct core_inst_pair *idata = NULL;
if (!inst) {
dprintk(VIDC_ERR, "Invalid params, inst: %pK\n", inst);
goto exit;
}
snprintf(debugfs_name, MAX_DEBUGFS_NAME, "inst_%p", inst);
idata = kzalloc(sizeof(struct core_inst_pair), GFP_KERNEL);
if (!idata) {
dprintk(VIDC_ERR, "%s: Allocation failed!\n", __func__);
goto exit;
}
idata->core = inst->core;
idata->inst = 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;
}
info = debugfs_create_file("info", 0444, dir,
idata, &inst_info_fops);
if (!info) {
dprintk(VIDC_ERR, "debugfs_create_file: fail\n");
goto failed_create_file;
}
dir->d_inode->i_private = info->d_inode->i_private;
inst->debug.pdata[FRAME_PROCESSING].sampling = true;
return dir;
failed_create_file:
debugfs_remove_recursive(dir);
dir = NULL;
failed_create_dir:
kfree(idata);
exit:
return dir;
}
void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst)
{
struct dentry *dentry = NULL;
if (!inst || !inst->debugfs_root)
return;
dentry = inst->debugfs_root;
if (dentry->d_inode) {
dprintk(VIDC_INFO, "Destroy %pK\n", dentry->d_inode->i_private);
kfree(dentry->d_inode->i_private);
dentry->d_inode->i_private = NULL;
}
debugfs_remove_recursive(dentry);
inst->debugfs_root = NULL;
}
void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
enum msm_vidc_debugfs_event e)
{
struct msm_vidc_debug *d = &inst->debug;
char a[64] = "Frame processing";
switch (e) {
case MSM_VIDC_DEBUGFS_EVENT_ETB:
inst->count.etb++;
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:
inst->count.ebd++;
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->count.fbd++;
inst->debug.samples++;
if (inst->count.fbd &&
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;
}
}
int msm_vidc_check_ratelimit(void)
{
static DEFINE_RATELIMIT_STATE(_rs,
VIDC_DBG_SESSION_RATELIMIT_INTERVAL,
VIDC_DBG_SESSION_RATELIMIT_BURST);
return __ratelimit(&_rs);
}

209
msm/vidc/msm_vidc_debug.h Normal file
View file

@ -0,0 +1,209 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef __MSM_VIDC_DEBUG__
#define __MSM_VIDC_DEBUG__
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/types.h>
#include "msm_vidc_internal.h"
#include "trace/events/msm_vidc_events.h"
#ifndef VIDC_DBG_LABEL
#define VIDC_DBG_LABEL "msm_vidc"
#endif
/*
* This enforces a rate limit: not more than 6 messages
* in every 1s.
*/
#define VIDC_DBG_SESSION_RATELIMIT_INTERVAL (1 * HZ)
#define VIDC_DBG_SESSION_RATELIMIT_BURST 6
#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,
};
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 msm_vidc_debug;
extern int msm_vidc_debug_out;
extern int msm_vidc_fw_debug;
extern int msm_vidc_fw_debug_mode;
extern bool msm_vidc_fw_coverage;
extern bool msm_vidc_thermal_mitigation_disabled;
extern int msm_vidc_clock_voting;
extern bool msm_vidc_syscache_disable;
extern bool msm_vidc_lossless_encode;
#define dprintk(__level, __fmt, ...) \
do { \
if (msm_vidc_debug & __level) { \
if (msm_vidc_debug_out == VIDC_OUT_PRINTK) { \
pr_info(VIDC_DBG_TAG __fmt, \
get_debug_level_str(__level), \
##__VA_ARGS__); \
} \
} \
} while (0)
#define dprintk_ratelimit(__level, __fmt, arg...) \
do { \
if (msm_vidc_debug & __level) { \
if (msm_vidc_debug_out == VIDC_OUT_PRINTK && \
msm_vidc_check_ratelimit()) { \
pr_info(VIDC_DBG_TAG __fmt, \
get_debug_level_str(__level), \
## arg); \
} \
} \
} while (0)
#define MSM_VIDC_ERROR(value) \
do { if (value) \
dprintk(VIDC_DBG, "BugOn"); \
BUG_ON(value); \
} while (0)
struct dentry *msm_vidc_debugfs_init_drv(void);
struct dentry *msm_vidc_debugfs_init_core(struct msm_vidc_core *core,
struct dentry *parent);
struct dentry *msm_vidc_debugfs_init_inst(struct msm_vidc_inst *inst,
struct dentry *parent);
void msm_vidc_debugfs_deinit_inst(struct msm_vidc_inst *inst);
void msm_vidc_debugfs_update(struct msm_vidc_inst *inst,
enum msm_vidc_debugfs_event e);
int msm_vidc_check_ratelimit(void);
static inline char *get_debug_level_str(int level)
{
switch (level) {
case VIDC_ERR:
return "err";
case VIDC_WARN:
return "warn";
case VIDC_INFO:
return "info";
case VIDC_DBG:
return "dbg";
case VIDC_PROF:
return "prof";
case VIDC_PKT:
return "pkt";
case VIDC_FW:
return "fw";
default:
return "???";
}
}
static inline void tic(struct msm_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 ((msm_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 msm_vidc_inst *i, enum profiling_points p)
{
struct timeval __ddl_tv;
if ((msm_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 msm_vidc_inst *i)
{
int x;
for (x = 0; x < MAX_PROFILING_POINTS; x++) {
if (i->debug.pdata[x].name[0] &&
(msm_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);
}
}
}
static inline void msm_vidc_res_handle_fatal_hw_error(
struct msm_vidc_platform_resources *resources,
bool enable_fatal)
{
enable_fatal &= resources->debug_timeout;
MSM_VIDC_ERROR(enable_fatal);
}
static inline void msm_vidc_handle_hw_error(struct msm_vidc_core *core)
{
bool enable_fatal = true;
/*
* In current implementation user-initiated SSR triggers
* a fatal error from hardware. However, there is no way
* to know if fatal error is due to SSR or not. Handle
* user SSR as non-fatal.
*/
if (core->trigger_ssr) {
core->trigger_ssr = false;
enable_fatal = false;
}
/* Video driver can decide FATAL handling of HW errors
* based on multiple factors. This condition check will
* be enhanced later.
*/
msm_vidc_res_handle_fatal_hw_error(&core->resources, enable_fatal);
}
#endif

View file

@ -0,0 +1,593 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef _MSM_VIDC_INTERNAL_H_
#define _MSM_VIDC_INTERNAL_H_
#include <linux/atomic.h>
#include <linux/list.h>
#include <linux/time.h>
#include <linux/types.h>
#include <linux/completion.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
#include <linux/kref.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ctrls.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-v4l2.h>
#include "msm_vidc.h"
#include <media/msm_media_info.h>
#include "vidc_hfi_api.h"
#include "vidc_hfi_helper.h"
#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
/* kernel/msm-4.19 */
#define MSM_VIDC_VERSION ((0 << 16) + (4 << 8) + 19)
#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
#define DEFAULT_FPS 30
#define MINIMUM_FPS 1
#define MAXIMUM_FPS 960
#define MIN_NUM_INPUT_BUFFERS 1
#define MIN_NUM_OUTPUT_BUFFERS 1
#define MAX_NUM_INPUT_BUFFERS VIDEO_MAX_FRAME // same as VB2_MAX_FRAME
#define MAX_NUM_OUTPUT_BUFFERS VIDEO_MAX_FRAME // same as VB2_MAX_FRAME
#define MAX_SUPPORTED_INSTANCES 16
/* Maintains the number of FTB's between each FBD over a window */
#define DCVS_FTB_WINDOW 16
#define V4L2_EVENT_VIDC_BASE 10
#define INPUT_MPLANE V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE
#define OUTPUT_MPLANE V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
#define RATE_CONTROL_OFF (V4L2_MPEG_VIDEO_BITRATE_MODE_CQ + 1)
#define RATE_CONTROL_LOSSLESS (V4L2_MPEG_VIDEO_BITRATE_MODE_CQ + 2)
#define SYS_MSG_START HAL_SYS_INIT_DONE
#define SYS_MSG_END HAL_SYS_ERROR
#define SESSION_MSG_START HAL_SESSION_EVENT_CHANGE
#define SESSION_MSG_END HAL_SESSION_ERROR
#define SYS_MSG_INDEX(__msg) (__msg - SYS_MSG_START)
#define SESSION_MSG_INDEX(__msg) (__msg - SESSION_MSG_START)
#define MAX_NAME_LENGTH 64
#define NUM_MBS_PER_SEC(__height, __width, __fps) \
(NUM_MBS_PER_FRAME(__height, __width) * __fps)
#define NUM_MBS_PER_FRAME(__height, __width) \
((ALIGN(__height, 16) / 16) * (ALIGN(__width, 16) / 16))
#define call_core_op(c, op, ...) \
(((c) && (c)->core_ops && (c)->core_ops->op) ? \
((c)->core_ops->op(__VA_ARGS__)) : 0)
struct msm_vidc_inst;
enum vidc_ports {
INPUT_PORT,
OUTPUT_PORT,
MAX_PORT_NUM
};
enum vidc_core_state {
VIDC_CORE_UNINIT = 0,
VIDC_CORE_INIT,
VIDC_CORE_INIT_DONE,
};
/*
* Do not change the enum values unless
* you know what you are doing
*/
enum instance_state {
MSM_VIDC_CORE_UNINIT_DONE = 0x0001,
MSM_VIDC_CORE_INIT,
MSM_VIDC_CORE_INIT_DONE,
MSM_VIDC_OPEN,
MSM_VIDC_OPEN_DONE,
MSM_VIDC_LOAD_RESOURCES,
MSM_VIDC_LOAD_RESOURCES_DONE,
MSM_VIDC_START,
MSM_VIDC_START_DONE,
MSM_VIDC_STOP,
MSM_VIDC_STOP_DONE,
MSM_VIDC_RELEASE_RESOURCES,
MSM_VIDC_RELEASE_RESOURCES_DONE,
MSM_VIDC_CLOSE,
MSM_VIDC_CLOSE_DONE,
MSM_VIDC_CORE_UNINIT,
MSM_VIDC_CORE_INVALID
};
struct buf_info {
struct list_head list;
struct vb2_buffer *buf;
};
struct msm_vidc_list {
struct list_head list;
struct mutex lock;
};
static inline void INIT_MSM_VIDC_LIST(struct msm_vidc_list *mlist)
{
mutex_init(&mlist->lock);
INIT_LIST_HEAD(&mlist->list);
}
static inline void DEINIT_MSM_VIDC_LIST(struct msm_vidc_list *mlist)
{
mutex_destroy(&mlist->lock);
}
enum buffer_owner {
DRIVER,
FIRMWARE,
CLIENT,
MAX_OWNER
};
struct vidc_freq_data {
struct list_head list;
u32 device_addr;
unsigned long freq;
bool turbo;
};
struct vidc_input_cr_data {
struct list_head list;
u32 index;
u32 input_cr;
};
struct recon_buf {
struct list_head list;
u32 buffer_index;
u32 CR;
u32 CF;
};
struct eos_buf {
struct list_head list;
struct msm_smem smem;
};
struct internal_buf {
struct list_head list;
enum hal_buffer buffer_type;
struct msm_smem smem;
enum buffer_owner buffer_ownership;
bool mark_remove;
};
struct msm_vidc_csc_coeff {
u32 *vpe_csc_custom_matrix_coeff;
u32 *vpe_csc_custom_bias_coeff;
u32 *vpe_csc_custom_limit_coeff;
};
struct msm_vidc_buf_data {
struct list_head list;
u32 index;
u32 mark_data;
u32 mark_target;
u32 filled_length;
};
struct msm_vidc_common_data {
char key[128];
int value;
};
struct msm_vidc_codec_data {
u32 fourcc;
enum session_type session_type;
int vpp_cycles;
int vsp_cycles;
int low_power_cycles;
};
struct msm_vidc_codec_capability {
enum hal_capability capability_type;
enum hal_domain domains;
enum hal_video_codec codecs;
u32 min;
u32 max;
u32 step_size;
u32 default_value;
};
struct msm_vidc_codec {
enum hal_domain domain;
enum hal_video_codec codec;
};
enum efuse_purpose {
SKU_VERSION = 0,
};
enum sku_version {
SKU_VERSION_0 = 0,
SKU_VERSION_1,
SKU_VERSION_2,
};
struct msm_vidc_efuse_data {
u32 start_address;
u32 size;
u32 mask;
u32 shift;
enum efuse_purpose purpose;
};
enum vpu_version {
VPU_VERSION_AR50 = 1,
VPU_VERSION_IRIS1,
VPU_VERSION_IRIS2,
};
struct msm_vidc_ubwc_config_data {
struct {
u32 max_channel_override : 1;
u32 mal_length_override : 1;
u32 hb_override : 1;
u32 bank_swzl_level_override : 1;
u32 bank_spreading_override : 1;
u32 reserved : 27;
} override_bit_info;
u32 max_channels;
u32 mal_length;
u32 highest_bank_bit;
u32 bank_swzl_level;
u32 bank_spreading;
};
struct msm_vidc_platform_data {
struct msm_vidc_common_data *common_data;
unsigned int common_data_length;
struct msm_vidc_codec_data *codec_data;
unsigned int codec_data_length;
struct msm_vidc_codec *codecs;
uint32_t codecs_count;
struct msm_vidc_codec_capability *codec_caps;
uint32_t codec_caps_count;
struct msm_vidc_csc_coeff csc_data;
struct msm_vidc_efuse_data *efuse_data;
unsigned int efuse_data_length;
unsigned int sku_version;
uint32_t vpu_ver;
struct msm_vidc_ubwc_config_data *ubwc_config;
};
struct msm_vidc_format_desc {
char name[MAX_NAME_LENGTH];
u8 description[32];
u32 fourcc;
};
struct msm_vidc_format {
char name[MAX_NAME_LENGTH];
u8 description[32];
u32 count_min;
u32 count_min_host;
u32 count_actual;
struct v4l2_format v4l2_fmt;
};
struct msm_vidc_format_constraint {
u32 fourcc;
u32 num_planes;
u32 y_max_stride;
u32 y_buffer_alignment;
u32 uv_max_stride;
u32 uv_buffer_alignment;
};
struct msm_vidc_drv {
struct mutex lock;
struct list_head cores;
int num_cores;
struct dentry *debugfs_root;
int thermal_level;
u32 sku_version;
};
struct msm_video_device {
int type;
struct video_device vdev;
};
struct session_crop {
u32 left;
u32 top;
u32 width;
u32 height;
};
struct session_prop {
struct session_crop crop_info;
u32 fps;
u32 bitrate;
bool bframe_changed;
u32 extradata_ctrls;
};
struct buf_queue {
struct vb2_queue vb2_bufq;
struct mutex lock;
};
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 batch_mode {
bool enable;
u32 size;
};
enum dcvs_flags {
MSM_VIDC_DCVS_INCR = BIT(0),
MSM_VIDC_DCVS_DECR = BIT(1),
};
struct clock_data {
int buffer_counter;
u64 load;
u64 load_low;
u64 load_norm;
u64 load_high;
int min_threshold;
int max_threshold;
enum hal_buffer buffer_type;
bool dcvs_mode;
unsigned long bitrate;
unsigned long min_freq;
unsigned long curr_freq;
u32 vpss_cycles;
u32 ise_cycles;
u32 ddr_bw;
u32 sys_cache_bw;
u32 operating_rate;
struct msm_vidc_codec_data *entry;
u32 core_id;
u32 dpb_fourcc;
u32 opb_fourcc;
u32 work_mode;
bool low_latency_mode;
bool is_cbr_plus;
u32 work_route;
u32 dcvs_flags;
u32 frame_rate;
};
struct profile_data {
int start;
int stop;
int cumulative;
char name[64];
int sampling;
int average;
};
struct msm_vidc_debug {
struct profile_data pdata[MAX_PROFILING_POINTS];
int profile;
int samples;
};
enum msm_vidc_modes {
VIDC_SECURE = BIT(0),
VIDC_TURBO = BIT(1),
VIDC_THUMBNAIL = BIT(2),
VIDC_LOW_POWER = BIT(3),
VIDC_REALTIME = BIT(4),
};
struct msm_vidc_core_ops {
unsigned long (*calc_freq)(struct msm_vidc_inst *inst, u32 filled_len);
int (*decide_work_route)(struct msm_vidc_inst *inst);
int (*decide_work_mode)(struct msm_vidc_inst *inst);
int (*decide_core_and_power_mode)(struct msm_vidc_inst *inst);
};
struct msm_vidc_core {
struct list_head list;
struct mutex lock;
int id;
struct hfi_device *device;
struct msm_vidc_platform_data *platform_data;
struct msm_video_device vdev[MSM_VIDC_MAX_DEVICES];
struct v4l2_device v4l2_dev;
struct list_head instances;
struct dentry *debugfs_root;
enum vidc_core_state state;
struct completion completions[SYS_MSG_END - SYS_MSG_START + 1];
enum msm_vidc_hfi_type hfi_type;
struct msm_vidc_platform_resources resources;
struct msm_vidc_capability *capabilities;
struct delayed_work fw_unload_work;
struct work_struct ssr_work;
enum hal_ssr_trigger_type ssr_type;
bool smmu_fault_handled;
bool trigger_ssr;
unsigned long min_freq;
unsigned long curr_freq;
struct msm_vidc_core_ops *core_ops;
};
struct msm_vidc_inst;
struct msm_vidc_inst_smem_ops {
int (*smem_map_dma_buf)(struct msm_vidc_inst *inst,
struct msm_smem *smem);
int (*smem_unmap_dma_buf)(struct msm_vidc_inst *inst,
struct msm_smem *smem);
};
struct msm_vidc_inst {
struct list_head list;
struct mutex sync_lock, lock, flush_lock;
struct msm_vidc_core *core;
enum session_type session_type;
void *session;
struct msm_cvp_external *cvp;
struct session_prop prop;
enum instance_state state;
struct msm_vidc_format fmts[MAX_PORT_NUM];
struct buf_queue bufq[MAX_PORT_NUM];
struct msm_vidc_list freqs;
struct msm_vidc_list input_crs;
struct msm_vidc_list scratchbufs;
struct msm_vidc_list persistbufs;
struct msm_vidc_list pending_getpropq;
struct msm_vidc_list outputbufs;
struct msm_vidc_list reconbufs;
struct msm_vidc_list eosbufs;
struct msm_vidc_list registeredbufs;
struct msm_vidc_list cvpbufs;
struct msm_vidc_list etb_data;
struct msm_vidc_list fbd_data;
struct buffer_requirements buff_req;
struct v4l2_ctrl_handler ctrl_handler;
struct completion completions[SESSION_MSG_END - SESSION_MSG_START + 1];
struct v4l2_ctrl **cluster;
struct v4l2_fh event_handler;
struct msm_smem *extradata_handle;
bool in_reconfig;
u32 reconfig_width;
u32 reconfig_height;
struct dentry *debugfs_root;
void *priv;
struct msm_vidc_debug debug;
struct buf_count count;
struct clock_data clk_data;
enum msm_vidc_modes flags;
struct msm_vidc_capability capability;
u32 buffer_size_limit;
enum buffer_mode_type buffer_mode_set[MAX_PORT_NUM];
enum multi_stream stream_output_mode;
struct v4l2_ctrl **ctrls;
u32 num_ctrls;
int bit_depth;
struct kref kref;
bool in_flush;
u32 pic_struct;
u32 colour_space;
u32 profile;
u32 level;
u32 grid_enable;
u32 frame_quality;
u32 rc_type;
u32 hybrid_hp;
u32 layer_bitrate;
u32 client_set_ctrls;
struct internal_buf *dpb_extra_binfo;
struct msm_vidc_codec_data *codec_data;
struct hal_hdr10_pq_sei hdr10_sei_params;
struct batch_mode batch;
struct msm_vidc_inst_smem_ops *smem_ops;
int (*buffer_size_calculators)(struct msm_vidc_inst *inst);
};
extern struct msm_vidc_drv *vidc_driver;
struct msm_vidc_ctrl_cluster {
struct v4l2_ctrl **cluster;
struct list_head list;
};
struct msm_vidc_ctrl {
u32 id;
char name[MAX_NAME_LENGTH];
enum v4l2_ctrl_type type;
s64 minimum;
s64 maximum;
s64 default_value;
u32 step;
u32 menu_skip_mask;
u32 flags;
const char * const *qmenu;
};
void handle_cmd_response(enum hal_command_response cmd, void *data);
int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
enum hal_ssr_trigger_type type);
int msm_vidc_noc_error_info(struct msm_vidc_core *core);
bool heic_encode_session_supported(struct msm_vidc_inst *inst);
int msm_vidc_check_session_supported(struct msm_vidc_inst *inst);
int msm_vidc_check_scaling_supported(struct msm_vidc_inst *inst);
void msm_vidc_queue_v4l2_event(struct msm_vidc_inst *inst, int event_type);
enum msm_vidc_flags {
MSM_VIDC_FLAG_DEFERRED = BIT(0),
MSM_VIDC_FLAG_RBR_PENDING = BIT(1),
MSM_VIDC_FLAG_QUEUED = BIT(2),
};
struct msm_vidc_buffer {
struct list_head list;
struct kref kref;
struct msm_smem smem[VIDEO_MAX_PLANES];
struct vb2_v4l2_buffer vvb;
enum msm_vidc_flags flags;
};
struct msm_vidc_cvp_buffer {
struct list_head list;
struct msm_smem smem;
struct msm_cvp_buffer buf;
};
void msm_comm_handle_thermal_event(void);
int msm_smem_alloc(size_t size, u32 align, u32 flags,
enum hal_buffer buffer_type, int map_kernel,
void *res, u32 session_type, struct msm_smem *smem);
int msm_smem_free(struct msm_smem *smem);
struct context_bank_info *msm_smem_get_context_bank(u32 session_type,
bool is_secure, struct msm_vidc_platform_resources *res,
enum hal_buffer buffer_type);
int msm_smem_map_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem);
int msm_smem_unmap_dma_buf(struct msm_vidc_inst *inst, struct msm_smem *smem);
struct dma_buf *msm_smem_get_dma_buf(int fd);
void msm_smem_put_dma_buf(void *dma_buf);
int msm_smem_cache_operations(struct dma_buf *dbuf,
enum smem_cache_ops cache_op, unsigned long offset, unsigned long size);
void msm_vidc_fw_unload_handler(struct work_struct *work);
void msm_vidc_ssr_handler(struct work_struct *work);
/*
* XXX: normally should be in msm_vidc.h, but that's meant for public APIs,
* whereas this is private
*/
int msm_vidc_destroy(struct msm_vidc_inst *inst);
void *vidc_get_drv_data(struct device *dev);
#endif

1024
msm/vidc/msm_vidc_platform.c Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,30 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*/
#ifndef DT_PARSE
#define DT_PARSE
#include <linux/of.h>
#include "msm_vidc_resources.h"
#include "msm_vidc_common.h"
void msm_vidc_free_platform_resources(
struct msm_vidc_platform_resources *res);
int read_hfi_type(struct platform_device *pdev);
int read_platform_resources_from_drv_data(
struct msm_vidc_core *core);
int read_platform_resources_from_dt(
struct msm_vidc_platform_resources *res);
int read_context_bank_resources_from_dt(struct platform_device *pdev);
int read_bus_resources_from_dt(struct platform_device *pdev);
int read_mem_cdsp_resources_from_dt(struct platform_device *pdev);
int msm_vidc_load_u32_table(struct platform_device *pdev,
struct device_node *of_node, char *table_name, int struct_size,
u32 **table, u32 *num_elements);
#endif

View file

@ -0,0 +1,216 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved.
*/
#ifndef __MSM_VIDC_RESOURCES_H__
#define __MSM_VIDC_RESOURCES_H__
#include <linux/platform_device.h>
#include "msm_vidc.h"
#include <linux/soc/qcom/llcc-qcom.h>
#define MAX_BUFFER_TYPES 32
struct dcvs_table {
u32 load;
u32 load_low;
u32 load_high;
u32 supported_codecs;
};
struct dcvs_limit {
u32 min_mbpf;
u32 fps;
};
struct reg_value_pair {
u32 reg;
u32 value;
};
struct reg_set {
struct reg_value_pair *reg_tbl;
int count;
};
struct addr_range {
u32 start;
u32 size;
};
struct addr_set {
struct addr_range *addr_tbl;
int count;
};
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 iommu_domain *domain;
};
struct buffer_usage_table {
u32 buffer_type;
u32 tz_usage;
};
struct buffer_usage_set {
struct buffer_usage_table *buffer_usage_tbl;
u32 count;
};
struct regulator_info {
struct regulator *regulator;
bool has_hw_power_collapse;
char *name;
};
struct regulator_set {
struct regulator_info *regulator_tbl;
u32 count;
};
struct clock_info {
const char *name;
struct clk *clk;
u32 count;
bool has_scaling;
bool has_mem_retention;
};
struct clock_set {
struct clock_info *clock_tbl;
u32 count;
};
struct bus_info {
char *name;
int master;
int slave;
unsigned int range[2];
struct device *dev;
struct msm_bus_client_handle *client;
bool is_prfm_mode;
const char *mode;
};
struct bus_set {
struct bus_info *bus_tbl;
u32 count;
};
struct reset_info {
struct reset_control *rst;
const char *name;
};
struct reset_set {
struct reset_info *reset_tbl;
u32 count;
};
struct allowed_clock_rates_table {
u32 clock_rate;
};
struct clock_profile_entry {
u32 codec_mask;
u32 vpp_cycles;
u32 vsp_cycles;
u32 low_power_cycles;
};
struct clock_freq_table {
struct clock_profile_entry *clk_prof_entries;
u32 count;
};
struct subcache_info {
const char *name;
bool isactive;
bool isset;
struct llcc_slice_desc *subcache;
};
struct subcache_set {
struct subcache_info *subcache_tbl;
u32 count;
};
struct msm_vidc_mem_cdsp {
struct device *dev;
};
struct msm_vidc_platform_resources {
phys_addr_t firmware_base;
phys_addr_t register_base;
uint32_t register_size;
uint32_t irq;
uint32_t sku_version;
struct allowed_clock_rates_table *allowed_clks_tbl;
u32 allowed_clks_tbl_size;
struct clock_freq_table clock_freq_tbl;
struct dcvs_table *dcvs_tbl;
uint32_t dcvs_tbl_size;
struct dcvs_limit *dcvs_limit;
bool sys_cache_present;
bool sys_cache_res_set;
struct subcache_set subcache_set;
struct reg_set reg_set;
struct addr_set qdss_addr_set;
struct buffer_usage_set buffer_usage_set;
uint32_t max_load;
uint32_t max_hq_mbs_per_frame;
uint32_t max_hq_mbs_per_sec;
uint32_t max_bframe_mbs_per_frame;
uint32_t max_bframe_mbs_per_sec;
struct platform_device *pdev;
struct regulator_set regulator_set;
struct clock_set clock_set;
struct bus_set bus_set;
struct reset_set reset_set;
bool sw_power_collapsible;
bool slave_side_cp;
struct list_head context_banks;
bool thermal_mitigable;
const char *fw_name;
const char *hfi_version;
bool never_unload_fw;
bool debug_timeout;
uint32_t pm_qos_latency_us;
uint32_t max_inst_count;
uint32_t max_secure_inst_count;
int msm_vidc_hw_rsp_timeout;
int msm_vidc_firmware_unload_delay;
uint32_t msm_vidc_pwr_collapse_delay;
bool domain_cvp;
bool non_fatal_pagefaults;
bool cache_pagetables;
bool decode_batching;
bool dcvs;
struct msm_vidc_codec_data *codec_data;
int codec_data_count;
struct msm_vidc_codec *codecs;
uint32_t codecs_count;
struct msm_vidc_codec_capability *codec_caps;
uint32_t codec_caps_count;
struct msm_vidc_csc_coeff *csc_coeff_data;
struct msm_vidc_mem_cdsp mem_cdsp;
uint32_t vpu_ver;
uint32_t fw_cycles;
uint32_t fw_vpp_cycles;
struct msm_vidc_ubwc_config_data *ubwc_config;
};
static inline bool is_iommu_present(struct msm_vidc_platform_resources *res)
{
return !list_empty(&res->context_banks);
}
#endif

5203
msm/vidc/venus_hfi.c Normal file

File diff suppressed because it is too large Load diff

289
msm/vidc/venus_hfi.h Normal file
View file

@ -0,0 +1,289 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef __H_VENUS_HFI_H__
#define __H_VENUS_HFI_H__
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/pm_qos.h>
#include <linux/spinlock.h>
#include "vidc_hfi_api.h"
#include "vidc_hfi_helper.h"
#include "vidc_hfi_api.h"
#include "vidc_hfi.h"
#include "msm_vidc_resources.h"
#include "hfi_packetization.h"
#include "msm_vidc_bus.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 VIDC_IFACEQ_NUMQ 3
#define VIDC_IFACEQ_CMDQ_IDX 0
#define VIDC_IFACEQ_MSGQ_IDX 1
#define VIDC_IFACEQ_DBGQ_IDX 2
#define VIDC_IFACEQ_MAX_BUF_COUNT 50
#define VIDC_IFACE_MAX_PARALLEL_CLNTS 16
#define VIDC_IFACEQ_DFLT_QHDR 0x01010000
#define VIDC_MAX_NAME_LENGTH 64
#define VIDC_MAX_PC_SKIP_COUNT 10
#define VIDC_MAX_SUBCACHES 4
#define VIDC_MAX_SUBCACHE_SIZE 52
struct hfi_queue_table_header {
u32 qtbl_version;
u32 qtbl_size;
u32 qtbl_qhdr0_offset;
u32 qtbl_qhdr_size;
u32 qtbl_num_q;
u32 qtbl_num_active_q;
void *device_addr;
char name[256];
};
struct hfi_queue_header {
u32 qhdr_status;
u32 qhdr_start_addr;
u32 qhdr_type;
u32 qhdr_q_size;
u32 qhdr_pkt_size;
u32 qhdr_pkt_drop_cnt;
u32 qhdr_rx_wm;
u32 qhdr_tx_wm;
u32 qhdr_rx_req;
u32 qhdr_tx_req;
u32 qhdr_rx_irq_status;
u32 qhdr_tx_irq_status;
u32 qhdr_read_idx;
u32 qhdr_write_idx;
};
struct hfi_mem_map_table {
u32 mem_map_num_entries;
u32 mem_map_table_base_addr;
};
struct hfi_mem_map {
u32 virtual_addr;
u32 physical_addr;
u32 size;
u32 attr;
};
#define VIDC_IFACEQ_TABLE_SIZE (sizeof(struct hfi_queue_table_header) \
+ sizeof(struct hfi_queue_header) * VIDC_IFACEQ_NUMQ)
#define VIDC_IFACEQ_QUEUE_SIZE (VIDC_IFACEQ_MAX_PKT_SIZE * \
VIDC_IFACEQ_MAX_BUF_COUNT * VIDC_IFACE_MAX_PARALLEL_CLNTS)
#define VIDC_IFACEQ_GET_QHDR_START_ADDR(ptr, i) \
(void *)((ptr + sizeof(struct hfi_queue_table_header)) + \
(i * sizeof(struct hfi_queue_header)))
#define QDSS_SIZE 4096
#define SFR_SIZE 4096
#define QUEUE_SIZE (VIDC_IFACEQ_TABLE_SIZE + \
(VIDC_IFACEQ_QUEUE_SIZE * VIDC_IFACEQ_NUMQ))
#define ALIGNED_QDSS_SIZE ALIGN(QDSS_SIZE, SZ_4K)
#define ALIGNED_SFR_SIZE ALIGN(SFR_SIZE, SZ_4K)
#define ALIGNED_QUEUE_SIZE ALIGN(QUEUE_SIZE, SZ_4K)
#define SHARED_QSIZE ALIGN(ALIGNED_SFR_SIZE + ALIGNED_QUEUE_SIZE + \
ALIGNED_QDSS_SIZE, SZ_1M)
enum vidc_hw_reg {
VIDC_HWREG_CTRL_STATUS = 0x1,
VIDC_HWREG_QTBL_INFO = 0x2,
VIDC_HWREG_QTBL_ADDR = 0x3,
VIDC_HWREG_CTRLR_RESET = 0x4,
VIDC_HWREG_IFACEQ_FWRXREQ = 0x5,
VIDC_HWREG_IFACEQ_FWTXREQ = 0x6,
VIDC_HWREG_VHI_SOFTINTEN = 0x7,
VIDC_HWREG_VHI_SOFTINTSTATUS = 0x8,
VIDC_HWREG_VHI_SOFTINTCLR = 0x9,
VIDC_HWREG_HVI_SOFTINTEN = 0xA,
};
struct vidc_mem_addr {
u32 align_device_addr;
u8 *align_virtual_addr;
u32 mem_size;
struct msm_smem mem_data;
};
struct vidc_iface_q_info {
void *q_hdr;
struct vidc_mem_addr q_array;
};
/*
* These are helper macros to iterate over various lists within
* venus_hfi_device->res. The intention is to cut down on a lot of boiler-plate
* code
*/
/* Read as "for each 'thing' in a set of 'thingies'" */
#define venus_hfi_for_each_thing(__device, __thing, __thingy) \
venus_hfi_for_each_thing_continue(__device, __thing, __thingy, 0)
#define venus_hfi_for_each_thing_reverse(__device, __thing, __thingy) \
venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \
(__device)->res->__thingy##_set.count - 1)
/* TODO: the __from parameter technically not required since we can figure it
* out with some pointer magic (i.e. __thing - __thing##_tbl[0]). If this macro
* sees extensive use, probably worth cleaning it up but for now omitting it
* since it introduces unnecessary complexity.
*/
#define venus_hfi_for_each_thing_continue(__device, __thing, __thingy, __from) \
for (__thing = &(__device)->res->\
__thingy##_set.__thingy##_tbl[__from]; \
__thing < &(__device)->res->__thingy##_set.__thingy##_tbl[0] + \
((__device)->res->__thingy##_set.count - __from); \
++__thing)
#define venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \
__from) \
for (__thing = &(__device)->res->\
__thingy##_set.__thingy##_tbl[__from]; \
__thing >= &(__device)->res->__thingy##_set.__thingy##_tbl[0]; \
--__thing)
/* Regular set helpers */
#define venus_hfi_for_each_regulator(__device, __rinfo) \
venus_hfi_for_each_thing(__device, __rinfo, regulator)
#define venus_hfi_for_each_regulator_reverse(__device, __rinfo) \
venus_hfi_for_each_thing_reverse(__device, __rinfo, regulator)
#define venus_hfi_for_each_regulator_reverse_continue(__device, __rinfo, \
__from) \
venus_hfi_for_each_thing_reverse_continue(__device, __rinfo, \
regulator, __from)
/* Clock set helpers */
#define venus_hfi_for_each_clock(__device, __cinfo) \
venus_hfi_for_each_thing(__device, __cinfo, clock)
#define venus_hfi_for_each_clock_reverse(__device, __cinfo) \
venus_hfi_for_each_thing_reverse(__device, __cinfo, clock)
#define venus_hfi_for_each_clock_reverse_continue(__device, __rinfo, \
__from) \
venus_hfi_for_each_thing_reverse_continue(__device, __rinfo, \
clock, __from)
/* Bus set helpers */
#define venus_hfi_for_each_bus(__device, __binfo) \
venus_hfi_for_each_thing(__device, __binfo, bus)
#define venus_hfi_for_each_bus_reverse(__device, __binfo) \
venus_hfi_for_each_thing_reverse(__device, __binfo, bus)
/* Subcache set helpers */
#define venus_hfi_for_each_subcache(__device, __sinfo) \
venus_hfi_for_each_thing(__device, __sinfo, subcache)
#define venus_hfi_for_each_subcache_reverse(__device, __sinfo) \
venus_hfi_for_each_thing_reverse(__device, __sinfo, subcache)
#define call_venus_op(d, op, ...) \
(((d) && (d)->vpu_ops && (d)->vpu_ops->op) ? \
((d)->vpu_ops->op(__VA_ARGS__)):0)
/* Internal data used in vidc_hal not exposed to msm_vidc*/
struct hal_data {
u32 irq;
phys_addr_t firmware_base;
u8 __iomem *register_base;
u32 register_size;
};
struct venus_resources {
struct msm_vidc_fw fw;
};
enum dsp_flag {
DSP_INIT = BIT(0),
DSP_SUSPEND = BIT(1),
};
enum venus_hfi_state {
VENUS_STATE_DEINIT = 1,
VENUS_STATE_INIT,
};
enum reset_state {
INIT = 1,
ASSERT,
DEASSERT,
};
struct venus_hfi_device;
struct venus_hfi_vpu_ops {
void (*interrupt_init)(struct venus_hfi_device *ptr);
void (*setup_dsp_uc_memmap)(struct venus_hfi_device *device);
void (*clock_config_on_enable)(struct venus_hfi_device *device);
int (*reset_ahb2axi_bridge)(struct venus_hfi_device *device);
void (*power_off)(struct venus_hfi_device *device);
void (*noc_error_info)(struct venus_hfi_device *device);
};
struct venus_hfi_device {
struct list_head list;
struct list_head sess_head;
u32 intr_status;
u32 device_id;
u32 clk_freq;
u32 last_packet_type;
unsigned long clk_bitrate;
unsigned long scaled_rate;
struct msm_vidc_bus_data bus_vote;
bool power_enabled;
struct mutex lock;
msm_vidc_callback callback;
struct vidc_mem_addr iface_q_table;
struct vidc_mem_addr dsp_iface_q_table;
struct vidc_mem_addr qdss;
struct vidc_mem_addr sfr;
struct vidc_mem_addr mem_addr;
struct vidc_iface_q_info iface_queues[VIDC_IFACEQ_NUMQ];
struct vidc_iface_q_info dsp_iface_queues[VIDC_IFACEQ_NUMQ];
u32 dsp_flags;
struct hal_data *hal_data;
struct workqueue_struct *vidc_workq;
struct workqueue_struct *venus_pm_workq;
int spur_count;
int reg_count;
struct venus_resources resources;
struct msm_vidc_platform_resources *res;
enum venus_hfi_state state;
struct hfi_packetization_ops *pkt_ops;
enum hfi_packetization_type packetization_type;
struct msm_vidc_cb_info *response_pkt;
u8 *raw_packet;
struct pm_qos_request qos;
unsigned int skip_pc_count;
struct venus_hfi_vpu_ops *vpu_ops;
};
void venus_hfi_delete_device(void *device);
int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id,
struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback);
#endif

64
msm/vidc/vidc_hfi.c Normal file
View file

@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*/
#include <linux/slab.h>
#include "msm_vidc_debug.h"
#include "vidc_hfi_api.h"
#include "venus_hfi.h"
struct hfi_device *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type,
u32 device_id, struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback)
{
struct hfi_device *hdev = NULL;
int rc = 0;
hdev = kzalloc(sizeof(struct hfi_device), GFP_KERNEL);
if (!hdev) {
dprintk(VIDC_ERR, "%s: failed to allocate hdev\n", __func__);
return NULL;
}
switch (hfi_type) {
case VIDC_HFI_VENUS:
rc = venus_hfi_initialize(hdev, device_id, res, callback);
break;
default:
dprintk(VIDC_ERR, "Unsupported host-firmware interface\n");
goto err_hfi_init;
}
if (rc) {
if (rc != -EPROBE_DEFER)
dprintk(VIDC_ERR, "%s device init failed rc = %d",
__func__, rc);
goto err_hfi_init;
}
return hdev;
err_hfi_init:
kfree(hdev);
return ERR_PTR(rc);
}
void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
struct hfi_device *hdev)
{
if (!hdev) {
dprintk(VIDC_ERR, "%s invalid device %pK", __func__, hdev);
return;
}
switch (hfi_type) {
case VIDC_HFI_VENUS:
venus_hfi_delete_device(hdev->hfi_device_data);
break;
default:
dprintk(VIDC_ERR, "Unsupported host-firmware interface\n");
}
kfree(hdev);
}

841
msm/vidc/vidc_hfi.h Normal file
View file

@ -0,0 +1,841 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef __H_VIDC_HFI_H__
#define __H_VIDC_HFI_H__
#include <media/msm_media_info.h>
#include "vidc_hfi_helper.h"
#include "vidc_hfi_api.h"
#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_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_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_BUFFER_FLAG_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_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_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_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_VPX_COLORSPACE 0x00000014
#define HFI_EXTRADATA_UBWC_CR_STAT_INFO 0x00000019
#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_OUTPUT_CROP 0x0700000F
#define HFI_INDEX_EXTRADATA_ASPECT_RATIO 0x7F100003
struct hfi_buffer_alloc_mode {
u32 buffer_type;
u32 buffer_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_INTERLACE_FRAME_MBAFF 0x20
#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_INDEX_EXTRADATA \
(HFI_PROPERTY_PARAM_OX_START + 0x006)
#define HFI_PROPERTY_PARAM_S3D_FRAME_PACKING_EXTRADATA \
(HFI_PROPERTY_PARAM_OX_START + 0x009)
#define HFI_PROPERTY_PARAM_BUFFER_SIZE_MINIMUM \
(HFI_PROPERTY_PARAM_OX_START + 0x00C)
#define HFI_PROPERTY_PARAM_SYNC_BASED_INTERRUPT \
(HFI_PROPERTY_PARAM_OX_START + 0x00E)
#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_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_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_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_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_VUI_DISPLAY_INFO_EXTRADATA \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x01B)
#define HFI_PROPERTY_PARAM_VDEC_VQZIP_SEI_EXTRADATA \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001C)
#define HFI_PROPERTY_PARAM_VDEC_VPX_COLORSPACE_EXTRADATA \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001D)
#define HFI_PROPERTY_PARAM_VDEC_MASTER_DISP_COL_SEI_EXTRADATA \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001E)
#define HFI_PROPERTY_PARAM_VDEC_CLL_SEI_EXTRADATA \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x001F)
#define HFI_PROPERTY_PARAM_VDEC_COLOUR_REMAPPING_INFO_SEI_EXTRADATA \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x0020)
#define HFI_PROPERTY_PARAM_VDEC_DOWN_SCALAR \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x0021)
#define HFI_PROPERTY_PARAM_VDEC_UBWC_CR_STAT_INFO_EXTRADATA \
(HFI_PROPERTY_PARAM_VDEC_OX_START + 0x0022)
#define HFI_PROPERTY_PARAM_HDR10_HIST_EXTRADATA \
(HFI_PROPERTY_PARAM_OX_START + 0x0023)
#define HFI_PROPERTY_CONFIG_VDEC_OX_START \
(HFI_DOMAIN_BASE_VDEC + HFI_ARCH_OX_OFFSET + 0x4000)
#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_CONFIG_VDEC_ENTROPY \
(HFI_PROPERTY_CONFIG_VDEC_OX_START + 0x004)
#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_PARAM_VENC_FRAME_QP_EXTRADATA \
(HFI_PROPERTY_PARAM_VENC_OX_START + 0x006)
#define HFI_PROPERTY_PARAM_VENC_ROI_QP_EXTRADATA \
(HFI_PROPERTY_PARAM_VENC_OX_START + 0x008)
#define HFI_PROPERTY_PARAM_VENC_HDR10PLUS_METADATA_EXTRADATA \
(HFI_PROPERTY_PARAM_VENC_OX_START + 0x00A)
#define HFI_PROPERTY_PARAM_VENC_CVP_METADATA_EXTRADATA \
(HFI_PROPERTY_PARAM_VENC_OX_START + 0x00B)
#define HFI_PROPERTY_CONFIG_VENC_OX_START \
(HFI_DOMAIN_BASE_VENC + HFI_ARCH_OX_OFFSET + 0x6000)
#define HFI_PROPERTY_PARAM_VPE_OX_START \
(HFI_DOMAIN_BASE_VPE + HFI_ARCH_OX_OFFSET + 0x7000)
#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 buffer_type;
u32 buffer_count_actual;
u32 buffer_count_min_host;
};
struct hfi_buffer_size_minimum {
u32 buffer_type;
u32 buffer_size;
};
struct hfi_buffer_requirements {
u32 buffer_type;
u32 buffer_size;
u32 buffer_region_size;
u32 buffer_count_min;
u32 buffer_count_min_host;
u32 buffer_count_actual;
u32 contiguous;
u32 buffer_alignment;
};
struct hfi_data_payload {
u32 size;
u8 rg_data[1];
};
struct hfi_enable_picture {
u32 picture_type;
};
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)
#define HFI_RATE_CONTROL_MBR_CFR (HFI_OX_BASE + 0x6)
#define HFI_RATE_CONTROL_MBR_VFR (HFI_OX_BASE + 0x7)
#define HFI_RATE_CONTROL_CQ (HFI_OX_BASE + 0x8)
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_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_CMD_SESSION_CONTINUE (HFI_CMD_SESSION_OX_START + 0x00D)
#define HFI_CMD_SESSION_SYNC (HFI_CMD_SESSION_OX_START + 0x00E)
#define HFI_CMD_SESSION_CVP_START \
(HFI_DOMAIN_BASE_CVP + HFI_ARCH_COMMON_OFFSET + \
HFI_CMD_START_OFFSET + 0x1000)
#define HFI_CMD_SESSION_REGISTER_BUFFERS \
(HFI_CMD_SESSION_CVP_START + 0x0A0)
#define HFI_CMD_SESSION_UNREGISTER_BUFFERS \
(HFI_CMD_SESSION_CVP_START + 0x0A1)
#define HFI_MSG_SYS_OX_START \
(HFI_DOMAIN_BASE_COMMON + HFI_ARCH_OX_OFFSET + HFI_MSG_START_OFFSET + 0x0000)
#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_RELEASE_BUFFERS_DONE \
(HFI_MSG_SESSION_OX_START + 0xC)
#define HFI_MSG_SESSION_CVP_START \
(HFI_DOMAIN_BASE_CVP + HFI_ARCH_COMMON_OFFSET + \
HFI_MSG_START_OFFSET + 0x1000)
#define HFI_MSG_SESSION_REGISTER_BUFFERS_DONE \
(HFI_MSG_SESSION_CVP_START + 0x0A0)
#define HFI_MSG_SESSION_UNREGISTER_BUFFERS_DONE \
(HFI_MSG_SESSION_CVP_START + 0x0A1)
#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_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_msg_sys_session_abort_done_packet {
u32 size;
u32 packet_type;
u32 session_id;
u32 error_type;
};
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_ubwc_cr_stats_info_type {
u32 cr_stats_info0;
u32 cr_stats_info1;
u32 cr_stats_info2;
u32 cr_stats_info3;
u32 cr_stats_info4;
u32 cr_stats_info5;
u32 cr_stats_info6;
};
struct hfi_frame_cr_stats_type {
u32 frame_index;
struct hfi_ubwc_cr_stats_info_type ubwc_stats_info;
u32 complexity_number;
};
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 flags;
struct hfi_frame_cr_stats_type ubwc_cr_stats;
u32 rgData[0];
};
struct hfi_msg_session_fill_buffer_done_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_fill_buffer_done_uncompressed_plane1_packet {
u32 flags;
u32 alloc_len;
u32 filled_len;
u32 offset;
u32 packet_buffer2;
u32 rgData[0];
};
struct hfi_msg_session_fill_buffer_done_uncompressed_plane2_packet {
u32 flags;
u32 alloc_len;
u32 filled_len;
u32 offset;
u32 packet_buffer3;
u32 rgData[0];
};
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_msg_session_register_buffers_done_packet {
u32 size;
u32 packet_type;
u32 session_id;
u32 client_data;
u32 error_type;
};
struct hfi_msg_session_unregister_buffers_done_packet {
u32 size;
u32 packet_type;
u32 session_id;
u32 client_data;
u32 error_type;
};
struct hfi_extradata_mb_quantization_payload {
u8 rg_mb_qp[1];
};
struct hfi_extradata_timestamp_payload {
u32 time_stamp_low;
u32 time_stamp_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_conceal_color_type {
u32 value_8bit;
u32 value_10bit;
};
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_output_crop_payload {
u32 size;
u32 version;
u32 port_index;
u32 left;
u32 top;
u32 display_width;
u32 display_height;
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_frame_type_payload {
u32 frame_rate;
};
struct hfi_extradata_recovery_point_sei_payload {
u32 flag;
};
struct hfi_cmd_session_continue_packet {
u32 size;
u32 packet_type;
u32 session_id;
};
enum session_flags {
SESSION_PAUSE = BIT(1),
};
struct hal_session {
struct list_head list;
void *session_id;
bool is_decoder;
enum hal_video_codec codec;
enum hal_domain domain;
u32 flags;
void *device;
};
struct hal_device_data {
struct list_head dev_head;
int dev_count;
};
struct msm_vidc_fw {
void *cookie;
};
int hfi_process_msg_packet(u32 device_id, struct vidc_hal_msg_pkt_hdr *msg_hdr,
struct msm_vidc_cb_info *info);
#endif

752
msm/vidc/vidc_hfi_api.h Normal file
View file

@ -0,0 +1,752 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef __VIDC_HFI_API_H__
#define __VIDC_HFI_API_H__
#include <linux/log2.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/hash.h>
#include "msm_vidc.h"
#include "msm_vidc_resources.h"
#define CONTAINS(__a, __sz, __t) (\
(__t >= __a) && \
(__t < __a + __sz) \
)
#define OVERLAPS(__t, __tsz, __a, __asz) (\
(__t <= __a) && \
(__t + __tsz >= __a + __asz) \
)
#define HAL_BUFFERFLAG_EOS 0x00000001
#define HAL_BUFFERFLAG_STARTTIME 0x00000002
#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_READONLY 0x00000200
#define HAL_BUFFERFLAG_ENDOFSUBFRAME 0x00000400
#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
#define VENUS_VERSION_LENGTH 128
#define IDR_PERIOD 1
/* 16 video sessions */
#define VIDC_MAX_SESSIONS 16
struct vidc_bus_vote_data;
enum vidc_status {
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_NOC_ERROR,
VIDC_ERR_CLIENT_PRESENT = 0x90000001,
VIDC_ERR_CLIENT_FATAL,
VIDC_ERR_CMD_QUEUE_FULL,
VIDC_ERR_UNUSED = 0x10000000
};
enum hal_domain {
HAL_VIDEO_DOMAIN_VPE = BIT(0),
HAL_VIDEO_DOMAIN_ENCODER = BIT(1),
HAL_VIDEO_DOMAIN_DECODER = BIT(2),
HAL_VIDEO_DOMAIN_CVP = BIT(3),
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_VP9 = 0x00004000,
HAL_VIDEO_CODEC_TME = 0x00008000,
HAL_VIDEO_CODEC_CVP = 0x00010000,
HAL_VIDEO_CODEC_HEVC_HYBRID = 0x80000000,
HAL_UNUSED_CODEC = 0x10000000,
};
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_COLOR_FORMAT_RGBA8888 = 0x00008000,
HAL_COLOR_FORMAT_RGBA8888_UBWC = 0x00010000,
HAL_COLOR_FORMAT_P010 = 0x00020000,
HAL_COLOR_FORMAT_NV12_512 = 0x00040000,
HAL_UNUSED_COLOR = 0x10000000,
};
enum hal_ssr_trigger_type {
SSR_ERR_FATAL = 1,
SSR_SW_DIV_BY_ZERO,
SSR_HW_WDOG_IRQ,
};
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_intra_refresh_mode {
HAL_INTRA_REFRESH_NONE = 0x1,
HAL_INTRA_REFRESH_CYCLIC = 0x2,
HAL_INTRA_REFRESH_RANDOM = 0x5,
HAL_UNUSED_INTRA = 0x10000000,
};
struct hal_intra_refresh {
enum hal_intra_refresh_mode mode;
u32 ir_mbs;
};
struct hal_buffer_requirements {
enum hal_buffer buffer_type;
u32 buffer_size;
u32 buffer_region_size;
u32 buffer_count_min;
u32 buffer_count_min_host;
u32 buffer_count_actual;
u32 contiguous;
u32 buffer_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_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,
};
enum hal_capability {
CAP_FRAME_WIDTH = 0x1,
CAP_FRAME_HEIGHT,
CAP_MBS_PER_FRAME,
CAP_MBS_PER_SECOND,
CAP_FRAMERATE,
CAP_SCALE_X,
CAP_SCALE_Y,
CAP_BITRATE,
CAP_BFRAME,
CAP_PEAKBITRATE,
CAP_HIER_P_NUM_ENH_LAYERS,
CAP_LTR_COUNT,
CAP_SECURE_OUTPUT2_THRESHOLD,
CAP_HIER_B_NUM_ENH_LAYERS,
CAP_LCU_SIZE,
CAP_HIER_P_HYBRID_NUM_ENH_LAYERS,
CAP_MBS_PER_SECOND_POWER_SAVE,
CAP_EXTRADATA,
CAP_PROFILE,
CAP_LEVEL,
CAP_I_FRAME_QP,
CAP_P_FRAME_QP,
CAP_B_FRAME_QP,
CAP_RATE_CONTROL_MODES,
CAP_BLUR_WIDTH,
CAP_BLUR_HEIGHT,
CAP_SLICE_BYTE,
CAP_SLICE_MB,
CAP_SECURE,
CAP_MAX_NUM_B_FRAMES,
CAP_MAX_VIDEOCORES,
CAP_MAX_WORKMODES,
CAP_UBWC_CR_STATS,
CAP_SECURE_FRAME_WIDTH,
CAP_SECURE_FRAME_HEIGHT,
CAP_SECURE_MBS_PER_FRAME,
CAP_SECURE_BITRATE,
CAP_BATCH_MAX_MB_PER_FRAME,
CAP_BATCH_MAX_FPS,
CAP_MAX,
};
struct hal_capability_supported {
enum hal_capability capability_type;
u32 min;
u32 max;
u32 step_size;
u32 default_value;
};
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_codec_supported {
u32 decoder_codec_supported;
u32 encoder_codec_supported;
};
enum hal_core_id {
VIDC_CORE_ID_DEFAULT = 0,
VIDC_CORE_ID_1 = 1, /* 0b01 */
VIDC_CORE_ID_2 = 2, /* 0b10 */
VIDC_CORE_ID_3 = 3, /* 0b11 */
VIDC_CORE_ID_UNUSED = 0x10000000,
};
enum vidc_resource_id {
VIDC_RESOURCE_NONE,
VIDC_RESOURCE_SYSCACHE,
VIDC_UNUSED_RESOURCE = 0x10000000,
};
struct vidc_resource_hdr {
enum vidc_resource_id resource_id;
void *resource_handle;
};
struct vidc_register_buffer {
enum hal_buffer type;
u32 index;
u32 size;
u32 device_addr;
u32 response_required;
u32 client_data;
};
struct vidc_unregister_buffer {
enum hal_buffer type;
u32 index;
u32 size;
u32 device_addr;
u32 response_required;
u32 client_data;
};
struct vidc_buffer_addr_info {
enum hal_buffer buffer_type;
u32 buffer_size;
u32 num_buffers;
u32 align_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 hal_fw_info {
char version[VENUS_VERSION_LENGTH];
phys_addr_t base_addr;
int register_base;
int register_size;
int irq;
};
enum hal_flush {
HAL_FLUSH_INPUT,
HAL_FLUSH_OUTPUT,
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 buffer_mode_type {
HAL_BUFFER_MODE_DYNAMIC = 0x100,
HAL_BUFFER_MODE_STATIC = 0x001,
};
struct hal_buffer_alloc_mode {
enum hal_buffer buffer_type;
enum buffer_mode_type buffer_mode;
};
enum ltr_mode {
HAL_LTR_MODE_DISABLE,
HAL_LTR_MODE_MANUAL,
};
struct buffer_requirements {
struct hal_buffer_requirements buffer[HAL_BUFFER_MAX];
};
struct hal_conceal_color {
u32 conceal_color_8bit;
u32 conceal_color_10bit;
};
union hal_get_property {
struct hal_batch_info batch_info;
struct hal_uncompressed_format_supported uncompressed_format_supported;
struct hal_interlace_format_supported interlace_format_supported;
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_buffer_info buffer_info;
struct hal_buffer_alloc_mode buffer_alloc_mode;
struct buffer_requirements buf_req;
struct hal_conceal_color conceal_color;
};
/* HAL Response */
#define IS_HAL_SYS_CMD(cmd) ((cmd) >= HAL_SYS_INIT_DONE && \
(cmd) <= HAL_SYS_ERROR)
#define IS_HAL_SESSION_CMD(cmd) ((cmd) >= HAL_SESSION_EVENT_CHANGE && \
(cmd) <= HAL_SESSION_ERROR)
enum hal_command_response {
/* SYSTEM COMMANDS_DONE*/
HAL_SYS_INIT_DONE,
HAL_SYS_SET_RESOURCE_DONE,
HAL_SYS_RELEASE_RESOURCE_DONE,
HAL_SYS_PC_PREP_DONE,
HAL_SYS_IDLE,
HAL_SYS_DEBUG,
HAL_SYS_WATCHDOG_TIMEOUT,
HAL_SYS_ERROR,
/* SESSION COMMANDS_DONE */
HAL_SESSION_EVENT_CHANGE,
HAL_SESSION_LOAD_RESOURCE_DONE,
HAL_SESSION_INIT_DONE,
HAL_SESSION_END_DONE,
HAL_SESSION_ABORT_DONE,
HAL_SESSION_START_DONE,
HAL_SESSION_STOP_DONE,
HAL_SESSION_ETB_DONE,
HAL_SESSION_FTB_DONE,
HAL_SESSION_FLUSH_DONE,
HAL_SESSION_SUSPEND_DONE,
HAL_SESSION_RESUME_DONE,
HAL_SESSION_SET_PROP_DONE,
HAL_SESSION_GET_PROP_DONE,
HAL_SESSION_RELEASE_BUFFER_DONE,
HAL_SESSION_REGISTER_BUFFER_DONE,
HAL_SESSION_UNREGISTER_BUFFER_DONE,
HAL_SESSION_RELEASE_RESOURCE_DONE,
HAL_SESSION_PROPERTY_INFO,
HAL_SESSION_ERROR,
HAL_RESPONSE_UNUSED = 0x10000000,
};
struct ubwc_cr_stats_info_type {
u32 cr_stats_info0;
u32 cr_stats_info1;
u32 cr_stats_info2;
u32 cr_stats_info3;
u32 cr_stats_info4;
u32 cr_stats_info5;
u32 cr_stats_info6;
};
struct recon_stats_type {
u32 buffer_index;
u32 complexity_number;
struct ubwc_cr_stats_info_type ubwc_stats_info;
};
struct vidc_hal_ebd {
u32 timestamp_hi;
u32 timestamp_lo;
u32 flags;
enum vidc_status status;
u32 mark_target;
u32 mark_data;
u32 stats;
u32 offset;
u32 alloc_len;
u32 filled_len;
u32 picture_type;
struct recon_stats_type recon_stats;
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;
u32 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 msm_vidc_capability {
enum hal_domain domain;
enum hal_video_codec codec;
struct hal_capability_supported cap[CAP_MAX];
};
struct vidc_hal_sys_init_done {
u32 dec_codec_supported;
u32 enc_codec_supported;
u32 max_sessions_supported;
};
struct vidc_hal_session_init_done {
struct msm_vidc_capability capability;
};
struct msm_vidc_cb_cmd_done {
u32 device_id;
void *session_id;
enum vidc_status status;
u32 size;
union {
struct vidc_resource_hdr resource_hdr;
struct vidc_buffer_addr_info buffer_addr_info;
struct vidc_frame_plane_config frame_plane_config;
struct vidc_uncompressed_frame_config uncompressed_frame_config;
struct vidc_frame_data frame_data;
struct vidc_hal_ebd ebd;
struct vidc_hal_fbd fbd;
struct vidc_hal_sys_init_done sys_init_done;
struct vidc_hal_session_init_done session_init_done;
struct hal_buffer_info buffer_info;
struct vidc_register_buffer regbuf;
struct vidc_unregister_buffer unregbuf;
union hal_get_property property;
enum hal_flush flush_type;
} data;
};
struct hal_index_extradata_input_crop_payload {
u32 size;
u32 version;
u32 port_index;
u32 left;
u32 top;
u32 width;
u32 height;
};
struct msm_vidc_cb_event {
u32 device_id;
void *session_id;
enum vidc_status status;
u32 height;
u32 width;
int bit_depth;
u32 hal_event_type;
u32 packet_buffer;
u32 extra_data_buffer;
u32 pic_struct;
u32 colour_space;
u32 profile;
u32 level;
u32 entropy_mode;
u32 capture_buf_count;
struct hal_index_extradata_input_crop_payload crop_data;
};
struct msm_vidc_cb_data_done {
u32 device_id;
void *session_id;
enum vidc_status status;
u32 size;
u32 clnt_data;
union {
struct vidc_hal_ebd input_done;
struct vidc_hal_fbd output_done;
};
};
struct msm_vidc_cb_info {
enum hal_command_response response_type;
union {
struct msm_vidc_cb_cmd_done cmd;
struct msm_vidc_cb_event event;
struct msm_vidc_cb_data_done data;
} response;
};
enum msm_vidc_hfi_type {
VIDC_HFI_VENUS,
};
enum msm_vidc_thermal_level {
VIDC_THERMAL_NORMAL = 0,
VIDC_THERMAL_LOW,
VIDC_THERMAL_HIGH,
VIDC_THERMAL_CRITICAL
};
enum msm_vidc_power_mode {
VIDC_POWER_NORMAL = 0,
VIDC_POWER_LOW,
VIDC_POWER_TURBO
};
struct hal_cmd_sys_get_property_packet {
u32 size;
u32 packet_type;
u32 num_properties;
u32 rg_property_data[1];
};
struct hal_hdr10_pq_sei {
struct msm_vidc_mastering_display_colour_sei_payload disp_color_sei;
struct msm_vidc_content_light_level_sei_payload cll_sei;
};
struct hal_vbv_hdr_buf_size {
u32 vbv_hdr_buf_size;
};
#define call_hfi_op(q, op, ...) \
(((q) && (q)->op) ? ((q)->op(__VA_ARGS__)) : 0)
struct hfi_device {
void *hfi_device_data;
/*Add function pointers for all the hfi functions below*/
int (*core_init)(void *device);
int (*core_release)(void *device);
int (*core_trigger_ssr)(void *device, enum hal_ssr_trigger_type);
int (*session_init)(void *device, void *session_id,
enum hal_domain session_type, enum hal_video_codec codec_type,
void **new_session);
int (*session_end)(void *session);
int (*session_abort)(void *session);
int (*session_set_buffers)(void *sess,
struct vidc_buffer_addr_info *buffer_info);
int (*session_release_buffers)(void *sess,
struct vidc_buffer_addr_info *buffer_info);
int (*session_register_buffer)(void *sess,
struct vidc_register_buffer *buffer);
int (*session_unregister_buffer)(void *sess,
struct vidc_unregister_buffer *buffer);
int (*session_load_res)(void *sess);
int (*session_release_res)(void *sess);
int (*session_start)(void *sess);
int (*session_continue)(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_process_batch)(void *sess,
int num_etbs, struct vidc_frame_data etbs[],
int num_ftbs, struct vidc_frame_data ftbs[]);
int (*session_get_buf_req)(void *sess);
int (*session_flush)(void *sess, enum hal_flush flush_mode);
int (*session_set_property)(void *sess, u32 ptype,
void *pdata, u32 size);
int (*session_pause)(void *sess);
int (*session_resume)(void *sess);
int (*scale_clocks)(void *dev, u32 freq);
int (*vote_bus)(void *dev, struct vidc_bus_vote_data *data,
int num_data);
int (*get_fw_info)(void *dev, struct hal_fw_info *fw_info);
int (*session_clean)(void *sess);
int (*get_core_capabilities)(void *dev);
int (*suspend)(void *dev);
int (*flush_debug_queue)(void *dev);
int (*noc_error_info)(void *dev);
enum hal_default_properties (*get_default_properties)(void *dev);
};
typedef void (*hfi_cmd_response_callback) (enum hal_command_response cmd,
void *data);
typedef void (*msm_vidc_callback) (u32 response, void *callback);
struct hfi_device *vidc_hfi_initialize(enum msm_vidc_hfi_type hfi_type,
u32 device_id, struct msm_vidc_platform_resources *res,
hfi_cmd_response_callback callback);
void vidc_hfi_deinitialize(enum msm_vidc_hfi_type hfi_type,
struct hfi_device *hdev);
u32 vidc_get_hfi_domain(enum hal_domain hal_domain);
u32 vidc_get_hfi_codec(enum hal_video_codec hal_codec);
enum hal_domain vidc_get_hal_domain(u32 hfi_domain);
enum hal_video_codec vidc_get_hal_codec(u32 hfi_codec);
#endif /*__VIDC_HFI_API_H__ */

1083
msm/vidc/vidc_hfi_helper.h Normal file

File diff suppressed because it is too large Load diff

220
msm/vidc/vidc_hfi_io.h Normal file
View file

@ -0,0 +1,220 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
*/
#ifndef __VIDC_HFI_IO_H__
#define __VIDC_HFI_IO_H__
#include <linux/io.h>
#define VIDC_VBIF_BASE_OFFS 0x00080000
#define VIDC_CPU_BASE_OFFS 0x000A0000
#define VIDEO_CC_BASE_OFFS 0x000F0000
#define VIDC_AON_BASE_OFFS 0x000E0000
#define VIDC_CPU_CS_BASE_OFFS (VIDC_CPU_BASE_OFFS)
#define VIDC_CPU_IC_BASE_OFFS (VIDC_CPU_BASE_OFFS)
#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_VMIMSG (VIDC_CPU_CS_BASE_OFFS + 0x34)
#define VIDC_CPU_CS_VMIMSGAG0 (VIDC_CPU_CS_BASE_OFFS + 0x38)
#define VIDC_CPU_CS_VMIMSGAG1 (VIDC_CPU_CS_BASE_OFFS + 0x3C)
#define VIDC_CPU_CS_VMIMSGAG2 (VIDC_CPU_CS_BASE_OFFS + 0x40)
#define VIDC_CPU_CS_VMIMSGAG3 (VIDC_CPU_CS_BASE_OFFS + 0x44)
#define VIDC_CPU_CS_SCIACMD (VIDC_CPU_CS_BASE_OFFS + 0x48)
#define VIDC_CPU_CS_H2XSOFTINTEN (VIDC_CPU_CS_BASE_OFFS + 0x148)
/* 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)
/* VIDC_SFR_ADDR */
#define VIDC_CPU_CS_SCIBCMD (VIDC_CPU_CS_BASE_OFFS + 0x5C)
/* VIDC_MMAP_ADDR */
#define VIDC_CPU_CS_SCIBCMDARG0 (VIDC_CPU_CS_BASE_OFFS + 0x60)
/* VIDC_UC_REGION_ADDR */
#define VIDC_CPU_CS_SCIBARG1 (VIDC_CPU_CS_BASE_OFFS + 0x64)
/* VIDC_UC_REGION_ADDR */
#define VIDC_CPU_CS_SCIBARG2 (VIDC_CPU_CS_BASE_OFFS + 0x68)
#define VIDC_CPU_CS_SCIBARG3 (VIDC_CPU_CS_BASE_OFFS + 0x6C)
/* FAL10 Feature Control */
#define VIDC_CPU_CS_X2RPMh (VIDC_CPU_CS_BASE_OFFS + 0x168)
#define VIDC_CPU_CS_X2RPMh_MASK0_BMSK 0x1
#define VIDC_CPU_CS_X2RPMh_MASK0_SHFT 0x0
#define VIDC_CPU_CS_X2RPMh_MASK1_BMSK 0x2
#define VIDC_CPU_CS_X2RPMh_MASK1_SHFT 0x1
#define VIDC_CPU_CS_X2RPMh_SWOVERRIDE_BMSK 0x4
#define VIDC_CPU_CS_X2RPMh_SWOVERRIDE_SHFT 0x3
#define VIDC_CPU_IC_SOFTINT (VIDC_CPU_IC_BASE_OFFS + 0x150)
#define VIDC_CPU_IC_SOFTINT_H2A_BMSK 0x1
#define VIDC_CPU_IC_SOFTINT_H2A_SHFT 0x0
#define VIDC_CPU_IC_SOFTINTCLEAR (VIDC_CPU_IC_BASE_OFFS + 0x154)
/*
* --------------------------------------------------------------------------
* MODULE: vidc_wrapper
* --------------------------------------------------------------------------
*/
#define VIDC_WRAPPER_BASE_OFFS 0x000B0000
#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 0x8
#define VIDC_WRAPPER_INTR_STATUS_A2HWD_SHFT 0x3
#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 0x8
#define VIDC_WRAPPER_INTR_MASK_A2HWD_SHFT 0x3
#define VIDC_WRAPPER_INTR_MASK_A2HVCODEC_BMSK 0x8
#define VIDC_WRAPPER_INTR_MASK_A2HCPU_BMSK 0x4
#define VIDC_WRAPPER_INTR_MASK_A2HCPU_SHFT 0x2
#define VIDC_WRAPPER_CPU_CLOCK_CONFIG (VIDC_WRAPPER_BASE_OFFS + 0x2000)
#define VIDC_WRAPPER_CPU_CGC_DIS (VIDC_WRAPPER_BASE_OFFS + 0x2010)
#define VIDC_WRAPPER_CPU_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x2014)
#define VIDC_WRAPPER_DEBUG_BRIDGE_LPI_CONTROL (VIDC_WRAPPER_BASE_OFFS + 0x54)
#define VIDC_WRAPPER_DEBUG_BRIDGE_LPI_STATUS (VIDC_WRAPPER_BASE_OFFS + 0x58)
/*
* --------------------------------------------------------------------------
* MODULE: vidc_tz_wrapper
* --------------------------------------------------------------------------
*/
#define VIDC_WRAPPER_TZ_BASE_OFFS 0x000C0000
#define VIDC_WRAPPER_TZ_CPU_CLOCK_CONFIG (VIDC_WRAPPER_TZ_BASE_OFFS)
#define VIDC_WRAPPER_TZ_CPU_STATUS (VIDC_WRAPPER_TZ_BASE_OFFS + 0x10)
#define VIDC_VENUS_VBIF_CLK_ON (VIDC_VBIF_BASE_OFFS + 0x4)
#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_CTRL_INIT VIDC_CPU_CS_SCIACMD
#define VIDC_CTRL_STATUS VIDC_CPU_CS_SCIACMDARG0
#define VIDC_CTRL_ERROR_STATUS__M \
VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK
#define VIDC_CTRL_INIT_IDLE_MSG_BMSK \
VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK
#define VIDC_CTRL_STATUS_PC_READY \
VIDC_CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY
#define VIDC_QTBL_INFO VIDC_CPU_CS_SCIACMDARG1
#define VIDC_QTBL_ADDR VIDC_CPU_CS_SCIACMDARG2
#define VIDC_VERSION_INFO VIDC_CPU_CS_SCIACMDARG3
#define VIDC_SFR_ADDR VIDC_CPU_CS_SCIBCMD
#define VIDC_MMAP_ADDR VIDC_CPU_CS_SCIBCMDARG0
#define VIDC_UC_REGION_ADDR VIDC_CPU_CS_SCIBARG1
#define VIDC_UC_REGION_SIZE VIDC_CPU_CS_SCIBARG2
/* HFI_DSP_QTBL_ADDR
* 31:3 - HFI_DSP_QTBL_ADDR
* 4-byte aligned Address
*/
#define HFI_DSP_QTBL_ADDR VIDC_CPU_CS_VMIMSG
/* HFI_DSP_UC_REGION_ADDR
* 31:20 - HFI_DSP_UC_REGION_ADDR
* 1MB aligned address.
* Uncached Region start Address. This region covers
* HFI DSP QTable,
* HFI DSP Queue Headers,
* HFI DSP Queues,
*/
#define HFI_DSP_UC_REGION_ADDR VIDC_CPU_CS_VMIMSGAG0
/* HFI_DSP_UC_REGION_SIZE
* 31:20 - HFI_DSP_UC_REGION_SIZE
* Multiples of 1MB.
* Size of the DSP_UC_REGION Uncached Region
*/
#define HFI_DSP_UC_REGION_SIZE VIDC_CPU_CS_VMIMSGAG1
/*
* --------------------------------------------------------------------------
* MODULE: vcodec noc error log registers (iris1)
* --------------------------------------------------------------------------
*/
#define VCODEC_CORE0_VIDEO_NOC_BASE_OFFS 0x00004000
#define VCODEC_CORE1_VIDEO_NOC_BASE_OFFS 0x0000C000
#define VCODEC_COREX_VIDEO_NOC_ERR_SWID_LOW_OFFS 0x0500
#define VCODEC_COREX_VIDEO_NOC_ERR_SWID_HIGH_OFFS 0x0504
#define VCODEC_COREX_VIDEO_NOC_ERR_MAINCTL_LOW_OFFS 0x0508
#define VCODEC_COREX_VIDEO_NOC_ERR_ERRVLD_LOW_OFFS 0x0510
#define VCODEC_COREX_VIDEO_NOC_ERR_ERRCLR_LOW_OFFS 0x0518
#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG0_LOW_OFFS 0x0520
#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG0_HIGH_OFFS 0x0524
#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG1_LOW_OFFS 0x0528
#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG1_HIGH_OFFS 0x052C
#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG2_LOW_OFFS 0x0530
#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG2_HIGH_OFFS 0x0534
#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG3_LOW_OFFS 0x0538
#define VCODEC_COREX_VIDEO_NOC_ERR_ERRLOG3_HIGH_OFFS 0x053C
#define VIDC_AON_WRAPPER_MVP_NOC_LPI_CONTROL (VIDC_AON_BASE_OFFS)
#define VIDC_AON_WRAPPER_MVP_NOC_LPI_STATUS (VIDC_AON_BASE_OFFS + 0x4)
/*
* --------------------------------------------------------------------------
* MODULE: vcodec noc error log registers (iris2)
* --------------------------------------------------------------------------
*/
#define VCODEC_NOC_VIDEO_A_NOC_BASE_OFFS 0x00010000
#define VCODEC_NOC_ERL_MAIN_SWID_LOW 0x00011200
#define VCODEC_NOC_ERL_MAIN_SWID_HIGH 0x00011204
#define VCODEC_NOC_ERL_MAIN_MAINCTL_LOW 0x00011208
#define VCODEC_NOC_ERL_MAIN_ERRVLD_LOW 0x00011210
#define VCODEC_NOC_ERL_MAIN_ERRCLR_LOW 0x00011218
#define VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW 0x00011220
#define VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH 0x00011224
#define VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW 0x00011228
#define VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH 0x0001122C
#define VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW 0x00011230
#define VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH 0x00011234
#define VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW 0x00011238
#define VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH 0x0001123C
#
#endif