techpack: video: add video driver
Add initial video driver files. Change-Id: Icd48bbf31e435cf36f149d6c3267cf3a4d7913b3 Signed-off-by: Maheshwar Ajja <majja@codeaurora.org>
This commit is contained in:
46
Makefile
Normal file
46
Makefile
Normal file
@@ -0,0 +1,46 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
# auto-detect subdirs
|
||||
ifneq ($(CONFIG_ARCH_QTI_VM), y)
|
||||
ifeq ($(CONFIG_ARCH_WAIPIO), y)
|
||||
include $(srctree)/techpack/video/config/waipio_video.conf
|
||||
LINUXINCLUDE += -include $(srctree)/techpack/video/config/waipio_video.h
|
||||
endif
|
||||
endif
|
||||
|
||||
LINUXINCLUDE += -I$(srctree)/techpack/video/include \
|
||||
-I$(srctree)/techpack/video/include/uapi \
|
||||
-I$(srctree)/techpack/video/include/uapi/vidc \
|
||||
-I$(srctree)/techpack/video/driver/vidc/inc \
|
||||
-I$(srctree)/techpack/video/driver/platform/waipio/inc \
|
||||
-I$(srctree)/techpack/video/driver/variant/iris2/inc
|
||||
|
||||
USERINCLUDE += -I$(srctree)/techpack/video/include/uapi
|
||||
|
||||
ccflags-y += -I$(srctree)/techpack/video/driver/vidc/src/ \
|
||||
-I$(srctree)/techpack/video/driver/platform/waipio/src/ \
|
||||
-I$(srctree)/techpack/video/driver/variant/iris2/src
|
||||
|
||||
msm-vidc-objs := driver/vidc/src/msm_vidc_v4l2.o \
|
||||
driver/vidc/src/msm_vidc_vb2.o \
|
||||
driver/vidc/src/msm_vidc.o \
|
||||
driver/vidc/src/msm_vdec.o \
|
||||
driver/vidc/src/msm_venc.o \
|
||||
driver/vidc/src/msm_vidc_vb2.o \
|
||||
driver/vidc/src/msm_vidc_driver.o \
|
||||
driver/vidc/src/msm_vidc_probe.o \
|
||||
driver/vidc/src/msm_vidc_dt.o \
|
||||
driver/vidc/src/msm_vidc_platform.o \
|
||||
driver/vidc/src/msm_vidc_debug.o \
|
||||
driver/vidc/src/msm_vidc_memory.o \
|
||||
driver/vidc/src/venus_hfi.o
|
||||
|
||||
ifneq ($(CONFIG_ARCH_QTI_VM), y)
|
||||
ifeq ($(CONFIG_ARCH_WAIPIO), y)
|
||||
msm-vidc-objs += driver/platform/waipio/src/msm_vidc_waipio.o \
|
||||
driver/hfi/iris2/src/msm_vidc_iris2.o
|
||||
endif
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_MSM_VIDC_V4L2) := msm-vidc.o
|
||||
|
1
config/waipio_video.conf
Normal file
1
config/waipio_video.conf
Normal file
@@ -0,0 +1 @@
|
||||
export CONFIG_MSM_VIDC_V4L2=m
|
8
config/waipio_video.h
Normal file
8
config/waipio_video.h
Normal file
@@ -0,0 +1,8 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#define CONFIG_MSM_VIDC_V4L2 1
|
||||
#define CONFIG_MSM_VIDC_IRIS2 1
|
||||
#define CONFIG_MSM_VIDC_WAIPIO 1
|
13
driver/platform/waipio/inc/msm_vidc_waipio.h
Normal file
13
driver/platform/waipio/inc/msm_vidc_waipio.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VIDC_WAIPIO_H_
|
||||
#define _MSM_VIDC_WAIPIO_H_
|
||||
|
||||
#include "msm_vidc_core.h"
|
||||
|
||||
int msm_vidc_init_platform_waipio(struct msm_vidc_core *core);
|
||||
|
||||
#endif // _MSM_VIDC_WAIPIO_H_
|
236
driver/platform/waipio/src/msm_vidc_waipio.c
Normal file
236
driver/platform/waipio/src/msm_vidc_waipio.c
Normal file
@@ -0,0 +1,236 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "msm_vidc_waipio.h"
|
||||
#include "msm_vidc_platform.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_core.h"
|
||||
|
||||
#define DDR_TYPE_LPDDR4 0x6
|
||||
#define DDR_TYPE_LPDDR4X 0x7
|
||||
#define DDR_TYPE_LPDDR5 0x8
|
||||
#define DDR_TYPE_LPDDR5X 0x9
|
||||
|
||||
#define UBWC_CONFIG(mco, mlo, hbo, bslo, bso, rs, mc, ml, hbb, bsl, bsp) \
|
||||
{ \
|
||||
.override_bit_info.max_channel_override = mco, \
|
||||
.override_bit_info.mal_length_override = mlo, \
|
||||
.override_bit_info.hb_override = hbo, \
|
||||
.override_bit_info.bank_swzl_level_override = bslo, \
|
||||
.override_bit_info.bank_spreading_override = bso, \
|
||||
.override_bit_info.reserved = rs, \
|
||||
.max_channels = mc, \
|
||||
.mal_length = ml, \
|
||||
.highest_bank_bit = hbb, \
|
||||
.bank_swzl_level = bsl, \
|
||||
.bank_spreading = bsp, \
|
||||
}
|
||||
|
||||
#define ENC MSM_VIDC_ENCODER
|
||||
#define DEC MSM_VIDC_DECODER
|
||||
#define H264 MSM_VIDC_H264
|
||||
#define HEVC MSM_VIDC_HEVC
|
||||
#define VP9 MSM_VIDC_VP9
|
||||
#define MPEG2 MSM_VIDC_MPEG2
|
||||
#define CODECS_ALL (MSM_VIDC_H264 | MSM_VIDC_HEVC | \
|
||||
MSM_VIDC_VP9 | MSM_VIDC_MPEG2)
|
||||
|
||||
static struct msm_vidc_core_data core_data_waipio[] = {
|
||||
/* {type, value} */
|
||||
{ENC_CODECS, H264|HEVC},
|
||||
{DEC_CODECS, H264|HEVC|VP9|MPEG2},
|
||||
{MAX_SESSION_COUNT, 16},
|
||||
{MAX_SECURE_SESSION_COUNT, 3},
|
||||
{MAX_MBPF, 173056}, /* (8192x4320)/256 + (4096x2176)/256*/
|
||||
{MAX_MBPS, 7833600}, /* max_load
|
||||
* 7680x4320@60fps or 3840x2176@240fps
|
||||
* which is greater than 4096x2176@120fps,
|
||||
* 8192x4320@48fps
|
||||
*/
|
||||
{MAX_MBPF_HQ, 8160}, /* ((1920x1088)/256) */
|
||||
{MAX_MBPS_HQ, 489600}, /* ((1920x1088)/256)@60fps */
|
||||
{MAX_MBPF_B_FRAME, 32640}, /* 3840x2176/256 */
|
||||
{MAX_MBPS_B_FRAME, 1958400}, /* 3840x2176/256 MBs@60fps */
|
||||
{SW_PC, 1},
|
||||
{SW_PC_DELAY, 1500}, /* 1500 ms */
|
||||
{FW_UNLOAD, 0},
|
||||
{FW_UNLOAD_DELAY, 1000}, /* 1000 ms */
|
||||
{HW_RESPONSE_TIMEOUT, 1000}, /* 1000 ms */
|
||||
{DEBUG_TIMEOUT, 0},
|
||||
{PREFIX_BUF_COUNT_PIX, 18},
|
||||
{PREFIX_BUF_SIZE_PIX, 13434880}, /* Calculated by VENUS_BUFFER_SIZE for 4096x2160 UBWC */
|
||||
{PREFIX_BUF_COUNT_NON_PIX, 1},
|
||||
{PREFIX_BUF_SIZE_NON_PIX, 209715200}, /*
|
||||
* Internal buffer size is calculated for secure decode session
|
||||
* of resolution 4k (4096x2160)
|
||||
* Internal buf size = calculate_scratch_size() +
|
||||
* calculate_scratch1_size() + calculate_persist1_size()
|
||||
* Take maximum between VP9 10bit, HEVC 10bit, AVC, MPEG2 secure
|
||||
* decoder sessions
|
||||
*/
|
||||
{PAGEFAULT_NON_FATAL, 1},
|
||||
{PAGETABLE_CACHING, 0},
|
||||
{DCVS, 1},
|
||||
{DECODE_BATCH, 1},
|
||||
{DECODE_BATCH_TIMEOUT, 200},
|
||||
{AV_SYNC_WINDOW_SIZE, 40},
|
||||
};
|
||||
|
||||
static struct msm_vidc_instance_data instance_data_waipio[] = {
|
||||
/* {type, domains, codecs, min, max, step_or_menu, value} */
|
||||
{FRAME_WIDTH, ENC|DEC, CODECS_ALL, 128, 8192, 1, 1920},
|
||||
{FRAME_HEIGHT, ENC|DEC, CODECS_ALL, 128, 8192, 1, 1080},
|
||||
/* (8192 * 4320) / 256 */
|
||||
{MBPF, ENC|DEC, CODECS_ALL, 64, 138240, 1, 138240},
|
||||
/* ((1920 * 1088) / 256) * 960 fps */
|
||||
{MBPS, ENC|DEC, CODECS_ALL, 64, 7833600, 1, 7833600},
|
||||
{FRAME_RATE, ENC|DEC, CODECS_ALL, 1, 960, 1, 30},
|
||||
{BIT_RATE, ENC|DEC, CODECS_ALL, 1, 220000000, 1, 20000000},
|
||||
{BIT_RATE, ENC, HEVC, 1, 160000000, 1, 20000000},
|
||||
{CABAC_BIT_RATE, ENC, H264, 1, 160000000, 1, 20000000},
|
||||
{SCALE_X, ENC, CODECS_ALL, 8192, 65536, 1, 8192},
|
||||
{SCALE_Y, ENC, CODECS_ALL, 8192, 65536, 1, 8192},
|
||||
{SCALE_X, DEC, CODECS_ALL, 65536, 65536, 1, 65536},
|
||||
{SCALE_Y, DEC, CODECS_ALL, 65536, 65536, 1, 65536},
|
||||
{B_FRAME, ENC, H264|HEVC, 0, 1, 1, 0},
|
||||
{HIER_P_LAYERS, ENC, H264|HEVC, 0, 6, 1, 0},
|
||||
{LTR_COUNT, ENC, H264|HEVC, 0, 2, 1, 0},
|
||||
/* ((4096 * 2304) / 256) * 60 fps */
|
||||
{POWER_SAVE_MBPS, ENC, CODECS_ALL,
|
||||
0, 2211840, 1, 2211840},
|
||||
{I_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 10},
|
||||
{P_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20},
|
||||
{B_FRAME_QP, ENC, H264|HEVC, 0, 51, 1, 20},
|
||||
{I_FRAME_QP, ENC, VP9, 0, 127, 1, 20},
|
||||
{P_FRAME_QP, ENC, VP9, 0, 127, 1, 40},
|
||||
{B_FRAME_QP, ENC, VP9, 0, 127, 1, 40},
|
||||
/* 10 slices */
|
||||
{SLICE_BYTE, ENC, H264|HEVC, 1, 10, 1, 10},
|
||||
{SLICE_MB, ENC, H264|HEVC, 1, 10, 1, 10},
|
||||
|
||||
/* Mpeg2 decoder specific */
|
||||
{FRAME_WIDTH, DEC, MPEG2, 128, 1920, 1, 1920},
|
||||
{FRAME_HEIGHT, DEC, MPEG2, 128, 1920, 1, 1080},
|
||||
/* (1920 * 1088) / 256 */
|
||||
{MBPF, DEC, MPEG2, 64, 8160, 1, 8160},
|
||||
/* ((1920 * 1088) / 256) * 30*/
|
||||
{MBPS, DEC, MPEG2, 64, 244800, 1, 244800},
|
||||
{FRAME_RATE, DEC, MPEG2, 1, 30, 1, 30},
|
||||
{BIT_RATE, DEC, MPEG2, 1, 40000000, 1, 20000000},
|
||||
|
||||
/* Secure usecase specific */
|
||||
{SECURE_FRAME_WIDTH, ENC|DEC, CODECS_ALL, 128, 4096, 1, 1920},
|
||||
{SECURE_FRAME_HEIGHT, ENC|DEC, CODECS_ALL, 128, 4096, 1, 1080},
|
||||
/* (4096 * 2304) / 256 */
|
||||
{SECURE_MBPF, ENC|DEC, CODECS_ALL, 64, 36864, 1, 36864},
|
||||
{SECURE_BIT_RATE, ENC|DEC, CODECS_ALL, 1, 40000000, 1, 20000000},
|
||||
|
||||
/* Batch Mode Decode */
|
||||
{BATCH_MBPF, DEC, CODECS_ALL, 64, 34816, 1, 34816},
|
||||
/* (4096 * 2176) / 256 */
|
||||
{BATCH_FRAME_RATE, DEC, CODECS_ALL, 1, 120, 1, 120},
|
||||
|
||||
/* Lossless encoding usecase specific */
|
||||
{LOSSLESS_FRAME_WIDTH, ENC, H264|HEVC, 128, 4096, 1, 1920},
|
||||
{LOSSLESS_FRAME_HEIGHT, ENC, H264|HEVC, 128, 4096, 1, 1080},
|
||||
/* (4096 * 2304) / 256 */
|
||||
{LOSSLESS_MBPF, ENC, H264|HEVC, 64, 36864, 1, 36864},
|
||||
|
||||
/* All intra encoding usecase specific */
|
||||
{ALL_INTRA_FRAME_RATE, ENC, H264|HEVC, 1, 240, 1, 30},
|
||||
|
||||
/* Image specific */
|
||||
{HEVC_IMAGE_FRAME_WIDTH, ENC, HEVC, 128, 512, 1, 512},
|
||||
{HEVC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 128, 512, 1, 512},
|
||||
{HEIC_IMAGE_FRAME_WIDTH, ENC, HEVC, 512, 16384, 1, 16384},
|
||||
{HEIC_IMAGE_FRAME_HEIGHT, ENC, HEVC, 512, 16384, 1, 16384},
|
||||
|
||||
{MB_CYCLES_VSP, ENC, CODECS_ALL, 25, 25, 1, 25},
|
||||
{MB_CYCLES_VPP, ENC, CODECS_ALL, 675, 675, 1, 675},
|
||||
{MB_CYCLES_LP, ENC, CODECS_ALL, 320, 320, 1, 320},
|
||||
{MB_CYCLES_VSP, DEC, CODECS_ALL, 25, 25, 1, 25},
|
||||
{MB_CYCLES_VSP, DEC, VP9, 60, 60, 1, 60},
|
||||
{MB_CYCLES_VPP, DEC, CODECS_ALL, 200, 200, 1, 200},
|
||||
{MB_CYCLES_LP, DEC, CODECS_ALL, 200, 200, 1, 200},
|
||||
{MB_CYCLES_FW, ENC|DEC, CODECS_ALL, 326389, 326389, 1, 326389},
|
||||
{MB_CYCLES_FW_VPP, ENC|DEC, CODECS_ALL, 44156, 44156, 1, 44156},
|
||||
};
|
||||
|
||||
/*
|
||||
* Custom conversion coefficients for resolution: 176x144 negative
|
||||
* coeffs are converted to s4.9 format
|
||||
* (e.g. -22 converted to ((1 << 13) - 22)
|
||||
* 3x3 transformation matrix coefficients in s4.9 fixed point format
|
||||
*/
|
||||
static u32 vpe_csc_custom_matrix_coeff[MAX_MATRIX_COEFFS] = {
|
||||
440, 8140, 8098, 0, 460, 52, 0, 34, 463
|
||||
};
|
||||
|
||||
/* offset coefficients in s9 fixed point format */
|
||||
static u32 vpe_csc_custom_bias_coeff[MAX_BIAS_COEFFS] = {
|
||||
53, 0, 4
|
||||
};
|
||||
|
||||
/* clamping value for Y/U/V([min,max] for Y/U/V) */
|
||||
static u32 vpe_csc_custom_limit_coeff[MAX_LIMIT_COEFFS] = {
|
||||
16, 235, 16, 240, 16, 240
|
||||
};
|
||||
|
||||
/* Default UBWC config for LPDDR5 */
|
||||
static struct msm_vidc_ubwc_config_data ubwc_config_waipio[] = {
|
||||
UBWC_CONFIG(1, 1, 1, 0, 0, 0, 8, 32, 16, 0, 0),
|
||||
};
|
||||
|
||||
static struct msm_vidc_platform_data waipio_data = {
|
||||
.core_data = core_data_waipio,
|
||||
.core_data_size = ARRAY_SIZE(core_data_waipio),
|
||||
.instance_data = instance_data_waipio,
|
||||
.instance_data_size = ARRAY_SIZE(instance_data_waipio),
|
||||
.csc_data.vpe_csc_custom_bias_coeff = vpe_csc_custom_bias_coeff,
|
||||
.csc_data.vpe_csc_custom_matrix_coeff = vpe_csc_custom_matrix_coeff,
|
||||
.csc_data.vpe_csc_custom_limit_coeff = vpe_csc_custom_limit_coeff,
|
||||
.ubwc_config = ubwc_config_waipio,
|
||||
};
|
||||
|
||||
static int msm_vidc_init_data(struct msm_vidc_core *core)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_ubwc_config_data *ubwc_config;
|
||||
u32 ddr_type;
|
||||
|
||||
if (!core || !core->platform) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
d_vpr_h("%s: initialize waipio data\n", __func__);
|
||||
|
||||
ubwc_config = waipio_data.ubwc_config;
|
||||
ddr_type = of_fdt_get_ddrtype();
|
||||
if (ddr_type == -ENOENT)
|
||||
d_vpr_e("Failed to get ddr type, use LPDDR5\n");
|
||||
|
||||
if (ddr_type == DDR_TYPE_LPDDR4 || ddr_type == DDR_TYPE_LPDDR4X)
|
||||
ubwc_config->highest_bank_bit = 0xf;
|
||||
d_vpr_h("%s: DDR Type 0x%x hbb 0x%x\n", __func__,
|
||||
ddr_type, ubwc_config->highest_bank_bit);
|
||||
|
||||
core->platform->data = waipio_data;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vidc_init_platform_waipio(struct msm_vidc_core *core)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc = msm_vidc_init_data(core);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
15
driver/variant/iris2/inc/msm_vidc_iris2.h
Normal file
15
driver/variant/iris2/inc/msm_vidc_iris2.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "msm_vidc_core.h"
|
||||
|
||||
//#if defined(CONFIG_MSM_VIDC_IRIS2)
|
||||
int msm_vidc_init_iris2(struct msm_vidc_core *core);
|
||||
//#else
|
||||
//static inline int msm_vidc_init_iris2(struct msm_vidc_core *core)
|
||||
//{
|
||||
// return -EINVAL;
|
||||
//}
|
||||
//#endif
|
558
driver/variant/iris2/src/msm_vidc_iris2.c
Normal file
558
driver/variant/iris2/src/msm_vidc_iris2.c
Normal file
@@ -0,0 +1,558 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include "msm_vidc_iris2.h"
|
||||
#include "venus_hfi.h"
|
||||
#include "msm_vidc_core.h"
|
||||
#include "msm_vidc_dt.h"
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
|
||||
|
||||
#define VBIF_BASE_OFFS_IRIS2 0x00080000
|
||||
#define CPU_BASE_OFFS_IRIS2 0x000A0000
|
||||
#define AON_BASE_OFFS 0x000E0000
|
||||
#define CPU_CS_BASE_OFFS_IRIS2 (CPU_BASE_OFFS_IRIS2)
|
||||
#define CPU_IC_BASE_OFFS_IRIS2 (CPU_BASE_OFFS_IRIS2)
|
||||
|
||||
#define CPU_CS_A2HSOFTINTCLR_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x1C)
|
||||
#define CPU_CS_VCICMD_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x20)
|
||||
#define CPU_CS_VCICMDARG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x24)
|
||||
#define CPU_CS_VCICMDARG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x28)
|
||||
#define CPU_CS_VCICMDARG2_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x2C)
|
||||
#define CPU_CS_VCICMDARG3_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x30)
|
||||
#define CPU_CS_VMIMSG_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x34)
|
||||
#define CPU_CS_VMIMSGAG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x38)
|
||||
#define CPU_CS_VMIMSGAG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x3C)
|
||||
#define CPU_CS_SCIACMD_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x48)
|
||||
#define CPU_CS_H2XSOFTINTEN_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x148)
|
||||
|
||||
/* HFI_CTRL_STATUS */
|
||||
#define CPU_CS_SCIACMDARG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x4C)
|
||||
#define CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS2 0xfe
|
||||
#define CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_IRIS2 0x100
|
||||
#define CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS2 0x40000000
|
||||
|
||||
/* HFI_QTBL_INFO */
|
||||
#define CPU_CS_SCIACMDARG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x50)
|
||||
|
||||
/* HFI_QTBL_ADDR */
|
||||
#define CPU_CS_SCIACMDARG2_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x54)
|
||||
|
||||
/* HFI_VERSION_INFO */
|
||||
#define CPU_CS_SCIACMDARG3_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x58)
|
||||
|
||||
/* SFR_ADDR */
|
||||
#define CPU_CS_SCIBCMD_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x5C)
|
||||
|
||||
/* MMAP_ADDR */
|
||||
#define CPU_CS_SCIBCMDARG0_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x60)
|
||||
|
||||
/* UC_REGION_ADDR */
|
||||
#define CPU_CS_SCIBARG1_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x64)
|
||||
|
||||
/* UC_REGION_ADDR */
|
||||
#define CPU_CS_SCIBARG2_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x68)
|
||||
|
||||
/* FAL10 Feature Control */
|
||||
#define CPU_CS_X2RPMh_IRIS2 (CPU_CS_BASE_OFFS_IRIS2 + 0x168)
|
||||
#define CPU_CS_X2RPMh_MASK0_BMSK_IRIS2 0x1
|
||||
#define CPU_CS_X2RPMh_MASK0_SHFT_IRIS2 0x0
|
||||
#define CPU_CS_X2RPMh_MASK1_BMSK_IRIS2 0x2
|
||||
#define CPU_CS_X2RPMh_MASK1_SHFT_IRIS2 0x1
|
||||
#define CPU_CS_X2RPMh_SWOVERRIDE_BMSK_IRIS2 0x4
|
||||
#define CPU_CS_X2RPMh_SWOVERRIDE_SHFT_IRIS2 0x3
|
||||
|
||||
#define CPU_IC_SOFTINT_IRIS2 (CPU_IC_BASE_OFFS_IRIS2 + 0x150)
|
||||
#define CPU_IC_SOFTINT_H2A_SHFT_IRIS2 0x0
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------------------
|
||||
* MODULE: wrapper
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
#define WRAPPER_BASE_OFFS_IRIS2 0x000B0000
|
||||
#define WRAPPER_INTR_STATUS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x0C)
|
||||
#define WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2 0x8
|
||||
#define WRAPPER_INTR_STATUS_A2H_BMSK_IRIS2 0x4
|
||||
|
||||
#define WRAPPER_INTR_MASK_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x10)
|
||||
#define WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS2 0x8
|
||||
#define WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS2 0x4
|
||||
|
||||
#define WRAPPER_CPU_CLOCK_CONFIG_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x2000)
|
||||
#define WRAPPER_CPU_CGC_DIS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x2010)
|
||||
#define WRAPPER_CPU_STATUS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x2014)
|
||||
|
||||
#define WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x54)
|
||||
#define WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2 (WRAPPER_BASE_OFFS_IRIS2 + 0x58)
|
||||
/*
|
||||
* --------------------------------------------------------------------------
|
||||
* MODULE: tz_wrapper
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
#define WRAPPER_TZ_BASE_OFFS 0x000C0000
|
||||
#define WRAPPER_TZ_CPU_CLOCK_CONFIG (WRAPPER_TZ_BASE_OFFS)
|
||||
#define WRAPPER_TZ_CPU_STATUS (WRAPPER_TZ_BASE_OFFS + 0x10)
|
||||
|
||||
#define CTRL_INIT_IRIS2 CPU_CS_SCIACMD_IRIS2
|
||||
|
||||
#define CTRL_STATUS_IRIS2 CPU_CS_SCIACMDARG0_IRIS2
|
||||
#define CTRL_ERROR_STATUS__M_IRIS2 \
|
||||
CPU_CS_SCIACMDARG0_HFI_CTRL_ERROR_STATUS_BMSK_IRIS2
|
||||
#define CTRL_INIT_IDLE_MSG_BMSK_IRIS2 \
|
||||
CPU_CS_SCIACMDARG0_HFI_CTRL_INIT_IDLE_MSG_BMSK_IRIS2
|
||||
#define CTRL_STATUS_PC_READY_IRIS2 \
|
||||
CPU_CS_SCIACMDARG0_HFI_CTRL_PC_READY_IRIS2
|
||||
|
||||
|
||||
#define QTBL_INFO_IRIS2 CPU_CS_SCIACMDARG1_IRIS2
|
||||
|
||||
#define QTBL_ADDR_IRIS2 CPU_CS_SCIACMDARG2_IRIS2
|
||||
|
||||
#define VERSION_INFO_IRIS2 CPU_CS_SCIACMDARG3_IRIS2
|
||||
|
||||
#define SFR_ADDR_IRIS2 CPU_CS_SCIBCMD_IRIS2
|
||||
#define MMAP_ADDR_IRIS2 CPU_CS_SCIBCMDARG0_IRIS2
|
||||
#define UC_REGION_ADDR_IRIS2 CPU_CS_SCIBARG1_IRIS2
|
||||
#define UC_REGION_SIZE_IRIS2 CPU_CS_SCIBARG2_IRIS2
|
||||
|
||||
#define AON_WRAPPER_MVP_NOC_LPI_CONTROL (AON_BASE_OFFS)
|
||||
#define AON_WRAPPER_MVP_NOC_LPI_STATUS (AON_BASE_OFFS + 0x4)
|
||||
|
||||
/*
|
||||
* --------------------------------------------------------------------------
|
||||
* MODULE: vcodec noc error log registers (iris2)
|
||||
* --------------------------------------------------------------------------
|
||||
*/
|
||||
#define VCODEC_NOC_VIDEO_A_NOC_BASE_OFFS 0x00010000
|
||||
#define VCODEC_NOC_ERL_MAIN_SWID_LOW 0x00011200
|
||||
#define VCODEC_NOC_ERL_MAIN_SWID_HIGH 0x00011204
|
||||
#define VCODEC_NOC_ERL_MAIN_MAINCTL_LOW 0x00011208
|
||||
#define VCODEC_NOC_ERL_MAIN_ERRVLD_LOW 0x00011210
|
||||
#define VCODEC_NOC_ERL_MAIN_ERRCLR_LOW 0x00011218
|
||||
#define VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW 0x00011220
|
||||
#define VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH 0x00011224
|
||||
#define VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW 0x00011228
|
||||
#define VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH 0x0001122C
|
||||
#define VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW 0x00011230
|
||||
#define VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH 0x00011234
|
||||
#define VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW 0x00011238
|
||||
#define VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH 0x0001123C
|
||||
|
||||
static int __interrupt_init_iris2(struct msm_vidc_core *vidc_core)
|
||||
{
|
||||
u32 mask_val = 0;
|
||||
struct msm_vidc_core *core = vidc_core;
|
||||
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* All interrupts should be disabled initially 0x1F6 : Reset value */
|
||||
mask_val = __read_register(core, WRAPPER_INTR_MASK_IRIS2);
|
||||
|
||||
/* Write 0 to unmask CPU and WD interrupts */
|
||||
mask_val &= ~(WRAPPER_INTR_MASK_A2HWD_BMSK_IRIS2|
|
||||
WRAPPER_INTR_MASK_A2HCPU_BMSK_IRIS2);
|
||||
__write_register(core, WRAPPER_INTR_MASK_IRIS2, mask_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __setup_ucregion_memory_map_iris2(struct msm_vidc_core *vidc_core)
|
||||
{
|
||||
struct msm_vidc_core *core = vidc_core;
|
||||
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
__write_register(core, UC_REGION_ADDR_IRIS2,
|
||||
(u32)core->iface_q_table.align_device_addr);
|
||||
__write_register(core, UC_REGION_SIZE_IRIS2, SHARED_QSIZE);
|
||||
__write_register(core, QTBL_ADDR_IRIS2,
|
||||
(u32)core->iface_q_table.align_device_addr);
|
||||
__write_register(core, QTBL_INFO_IRIS2, 0x01);
|
||||
if (core->sfr.align_device_addr)
|
||||
__write_register(core, SFR_ADDR_IRIS2,
|
||||
(u32)core->sfr.align_device_addr);
|
||||
/* update queues vaddr for debug purpose */
|
||||
__write_register(core, CPU_CS_VCICMDARG0_IRIS2,
|
||||
(u32)core->iface_q_table.align_virtual_addr);
|
||||
__write_register(core, CPU_CS_VCICMDARG1_IRIS2,
|
||||
(u32)((u64)core->iface_q_table.align_virtual_addr >> 32));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __power_off_iris2(struct msm_vidc_core *vidc_core)
|
||||
{
|
||||
u32 lpi_status, reg_status = 0, count = 0, max_count = 10;
|
||||
struct msm_vidc_core *core = vidc_core;
|
||||
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!core->power_enabled)
|
||||
return 0;
|
||||
|
||||
if (!(core->intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2))
|
||||
disable_irq_nosync(core->dt->irq);
|
||||
core->intr_status = 0;
|
||||
|
||||
/* HPG 6.1.2 Step 1 */
|
||||
__write_register(core, CPU_CS_X2RPMh_IRIS2, 0x3);
|
||||
|
||||
/* HPG 6.1.2 Step 2, noc to low power */
|
||||
//if (core->res->vpu_ver == VPU_VERSION_IRIS2_1)
|
||||
// goto skip_aon_mvp_noc;
|
||||
|
||||
__write_register(core, AON_WRAPPER_MVP_NOC_LPI_CONTROL, 0x1);
|
||||
while (!reg_status && count < max_count) {
|
||||
lpi_status =
|
||||
__read_register(core,
|
||||
AON_WRAPPER_MVP_NOC_LPI_STATUS);
|
||||
reg_status = lpi_status & BIT(0);
|
||||
d_vpr_h("Noc: lpi_status %d noc_status %d (count %d)\n",
|
||||
lpi_status, reg_status, count);
|
||||
usleep_range(50, 100);
|
||||
count++;
|
||||
}
|
||||
if (count == max_count)
|
||||
d_vpr_e("NOC not in qaccept status %d\n", reg_status);
|
||||
|
||||
//skip_aon_mvp_noc:
|
||||
/* HPG 6.1.2 Step 3, debug bridge to low power */
|
||||
__write_register(core,
|
||||
WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS2, 0x7);
|
||||
reg_status = 0;
|
||||
count = 0;
|
||||
while ((reg_status != 0x7) && count < max_count) {
|
||||
lpi_status = __read_register(core,
|
||||
WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2);
|
||||
reg_status = lpi_status & 0x7;
|
||||
d_vpr_h("DBLP Set : lpi_status %d reg_status %d (count %d)\n",
|
||||
lpi_status, reg_status, count);
|
||||
usleep_range(50, 100);
|
||||
count++;
|
||||
}
|
||||
if (count == max_count)
|
||||
d_vpr_e("DBLP Set: status %d\n", reg_status);
|
||||
|
||||
/* HPG 6.1.2 Step 4, debug bridge to lpi release */
|
||||
__write_register(core,
|
||||
WRAPPER_DEBUG_BRIDGE_LPI_CONTROL_IRIS2, 0x0);
|
||||
lpi_status = 0x1;
|
||||
count = 0;
|
||||
while (lpi_status && count < max_count) {
|
||||
lpi_status = __read_register(core,
|
||||
WRAPPER_DEBUG_BRIDGE_LPI_STATUS_IRIS2);
|
||||
d_vpr_h("DBLP Release: lpi_status %d(count %d)\n",
|
||||
lpi_status, count);
|
||||
usleep_range(50, 100);
|
||||
count++;
|
||||
}
|
||||
if (count == max_count)
|
||||
d_vpr_e("DBLP Release: lpi_status %d\n", lpi_status);
|
||||
|
||||
/* HPG 6.1.2 Step 6 */
|
||||
__disable_unprepare_clks(core);
|
||||
|
||||
/* HPG 6.1.2 Step 5 */
|
||||
if (__disable_regulators(core))
|
||||
d_vpr_e("%s: Failed to disable regulators\n", __func__);
|
||||
|
||||
if (__unvote_buses(core))
|
||||
d_vpr_e("%s: Failed to unvote for buses\n", __func__);
|
||||
core->power_enabled = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __prepare_pc_iris2(struct msm_vidc_core *vidc_core)
|
||||
{
|
||||
int rc = 0;
|
||||
u32 wfi_status = 0, idle_status = 0, pc_ready = 0;
|
||||
u32 ctrl_status = 0;
|
||||
int count = 0;
|
||||
const int max_tries = 10;
|
||||
struct msm_vidc_core *core = vidc_core;
|
||||
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctrl_status = __read_register(core, CTRL_STATUS_IRIS2);
|
||||
pc_ready = ctrl_status & CTRL_STATUS_PC_READY_IRIS2;
|
||||
idle_status = ctrl_status & BIT(30);
|
||||
|
||||
if (pc_ready) {
|
||||
d_vpr_h("Already in pc_ready state\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
wfi_status = BIT(0) & __read_register(core, WRAPPER_TZ_CPU_STATUS);
|
||||
if (!wfi_status || !idle_status) {
|
||||
d_vpr_e("Skipping PC, wfi status not set\n");
|
||||
goto skip_power_off;
|
||||
}
|
||||
|
||||
rc = __prepare_pc(core);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed __prepare_pc %d\n", rc);
|
||||
goto skip_power_off;
|
||||
}
|
||||
|
||||
while (count < max_tries) {
|
||||
wfi_status = BIT(0) & __read_register(core,
|
||||
WRAPPER_TZ_CPU_STATUS);
|
||||
ctrl_status = __read_register(core,
|
||||
CTRL_STATUS_IRIS2);
|
||||
if (wfi_status && (ctrl_status & CTRL_STATUS_PC_READY_IRIS2))
|
||||
break;
|
||||
usleep_range(150, 250);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == max_tries) {
|
||||
d_vpr_e("Skip PC. Core is not in right state\n");
|
||||
goto skip_power_off;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
skip_power_off:
|
||||
d_vpr_e("Skip PC, wfi=%#x, idle=%#x, pcr=%#x, ctrl=%#x)\n",
|
||||
wfi_status, idle_status, pc_ready, ctrl_status);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static int __raise_interrupt_iris2(struct msm_vidc_core *vidc_core)
|
||||
{
|
||||
struct msm_vidc_core *core = vidc_core;
|
||||
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
__write_register(core, CPU_IC_SOFTINT_IRIS2,
|
||||
1 << CPU_IC_SOFTINT_H2A_SHFT_IRIS2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __watchdog_iris2(struct msm_vidc_core *vidc_core, u32 intr_status)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_core *core = vidc_core;
|
||||
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2)
|
||||
rc = 1;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int __noc_error_info_iris2(struct msm_vidc_core *vidc_core)
|
||||
{
|
||||
u32 val = 0;
|
||||
struct msm_vidc_core *core = vidc_core;
|
||||
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
//if (core->res->vpu_ver == VPU_VERSION_IRIS2_1)
|
||||
// return;
|
||||
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_SWID_LOW);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_SWID_LOW: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_SWID_HIGH);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_SWID_HIGH: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_MAINCTL_LOW);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_MAINCTL_LOW: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRVLD_LOW);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRVLD_LOW: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRCLR_LOW);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRCLR_LOW: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG0_LOW: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG0_HIGH: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG1_LOW: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG1_HIGH: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG2_LOW: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG2_HIGH: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG3_LOW: %#x\n", val);
|
||||
val = __read_register(core, VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH);
|
||||
d_vpr_e("VCODEC_NOC_ERL_MAIN_ERRLOG3_HIGH: %#x\n", val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __clear_interrupt_iris2(struct msm_vidc_core *vidc_core)
|
||||
{
|
||||
u32 intr_status = 0, mask = 0;
|
||||
struct msm_vidc_core *core = vidc_core;
|
||||
|
||||
if (!core) {
|
||||
d_vpr_e("%s: NULL core\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
intr_status = __read_register(core, WRAPPER_INTR_STATUS_IRIS2);
|
||||
mask = (WRAPPER_INTR_STATUS_A2H_BMSK_IRIS2|
|
||||
WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2|
|
||||
CTRL_INIT_IDLE_MSG_BMSK_IRIS2);
|
||||
|
||||
if (intr_status & mask) {
|
||||
core->intr_status |= intr_status;
|
||||
core->reg_count++;
|
||||
d_vpr_l("INTERRUPT: times: %d interrupt_status: %d\n",
|
||||
core->reg_count, intr_status);
|
||||
} else {
|
||||
core->spur_count++;
|
||||
}
|
||||
|
||||
__write_register(core, CPU_CS_A2HSOFTINTCLR_IRIS2, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __boot_firmware_iris2(struct msm_vidc_core *vidc_core)
|
||||
{
|
||||
int rc = 0;
|
||||
u32 ctrl_init_val = 0, ctrl_status = 0, count = 0, max_tries = 1000;
|
||||
struct msm_vidc_core *core = vidc_core;
|
||||
|
||||
if (!core) {
|
||||
d_vpr_e("%s: NULL core\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctrl_init_val = BIT(0);
|
||||
|
||||
__write_register(core, CTRL_INIT_IRIS2, ctrl_init_val);
|
||||
while (!ctrl_status && count < max_tries) {
|
||||
ctrl_status = __read_register(core, CTRL_STATUS_IRIS2);
|
||||
if ((ctrl_status & CTRL_ERROR_STATUS__M_IRIS2) == 0x4) {
|
||||
d_vpr_e("invalid setting for UC_REGION\n");
|
||||
break;
|
||||
}
|
||||
|
||||
usleep_range(50, 100);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count >= max_tries) {
|
||||
d_vpr_e("Error booting up vidc firmware\n");
|
||||
rc = -ETIME;
|
||||
}
|
||||
|
||||
/* Enable interrupt before sending commands to venus */
|
||||
__write_register(core, CPU_CS_H2XSOFTINTEN_IRIS2, 0x1);
|
||||
__write_register(core, CPU_CS_X2RPMh_IRIS2, 0x0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct msm_vidc_venus_ops iris2_ops = {
|
||||
.boot_firmware = __boot_firmware_iris2,
|
||||
.interrupt_init = __interrupt_init_iris2,
|
||||
.raise_interrupt = __raise_interrupt_iris2,
|
||||
.clear_interrupt = __clear_interrupt_iris2,
|
||||
.setup_ucregion_memmap = __setup_ucregion_memory_map_iris2,
|
||||
.clock_config_on_enable = NULL,
|
||||
.reset_ahb2axi_bridge = __reset_ahb2axi_bridge,
|
||||
.power_off = __power_off_iris2,
|
||||
.prepare_pc = __prepare_pc_iris2,
|
||||
.watchdog = __watchdog_iris2,
|
||||
.noc_error_info = __noc_error_info_iris2,
|
||||
};
|
||||
|
||||
static int msm_vidc_buffer_size(struct msm_vidc_inst *inst,
|
||||
enum msm_vidc_buffer_type type)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!inst) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vidc_buffer_min_count(struct msm_vidc_inst *inst,
|
||||
enum msm_vidc_buffer_type type)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!inst) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vidc_buffer_extra_count(struct msm_vidc_inst *inst,
|
||||
enum msm_vidc_buffer_type type)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!inst) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct msm_vidc_session_ops msm_session_ops = {
|
||||
.buffer_size = msm_vidc_buffer_size,
|
||||
.min_count = msm_vidc_buffer_min_count,
|
||||
.extra_count = msm_vidc_buffer_extra_count,
|
||||
.calc_freq = NULL,
|
||||
.calc_bw = NULL,
|
||||
.decide_work_route = NULL,
|
||||
.decide_work_mode = NULL,
|
||||
.decide_core_and_power_mode = NULL,
|
||||
};
|
||||
|
||||
int msm_vidc_init_iris2(struct msm_vidc_core *core)
|
||||
{
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
core->venus_ops = &iris2_ops;
|
||||
core->session_ops = &msm_session_ops;
|
||||
|
||||
return 0;
|
||||
}
|
68
driver/vidc/inc/fixedpoint.h
Normal file
68
driver/vidc/inc/fixedpoint.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, 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
|
53
driver/vidc/inc/hfi_packet.h
Normal file
53
driver/vidc/inc/hfi_packet.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _HFI_PACKET_H_
|
||||
#define _HFI_PACKET_H_
|
||||
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_inst.h"
|
||||
#include "msm_vidc_core.h"
|
||||
|
||||
struct hfi_header {
|
||||
u32 size;
|
||||
u32 session_id;
|
||||
u32 header_id;
|
||||
u32 reserved[4];
|
||||
u32 num_packets;
|
||||
};
|
||||
|
||||
struct hfi_packet {
|
||||
u32 size;
|
||||
u32 type;
|
||||
u32 flags;
|
||||
u32 payload_info;
|
||||
u32 port;
|
||||
u32 packet_id;
|
||||
u32 reserved[2];
|
||||
};
|
||||
|
||||
struct hfi_buffer {
|
||||
u32 type;
|
||||
u32 index;
|
||||
u64 base_address;
|
||||
u32 addr_offset;
|
||||
u32 buffer_size;
|
||||
u32 data_offset;
|
||||
u32 data_size;
|
||||
u32 flags;
|
||||
u64 timestamp;
|
||||
u32 reserved[5];
|
||||
};
|
||||
|
||||
int hfi_packet_sys_init(struct msm_vidc_core *core,
|
||||
void *packet, u32 packet_size);
|
||||
int hfi_packet_image_version(struct msm_vidc_core *core,
|
||||
void *packet, u32 packet_size);
|
||||
int hfi_packet_sys_debug_config(struct msm_vidc_core *core,
|
||||
void *packet, u32 packet_size, u32 mode);
|
||||
int hfi_packet_sys_pc_prep(struct msm_vidc_core *core,
|
||||
void *packet, u32 packet_size);
|
||||
|
||||
#endif // _HFI_PACKET_H_
|
15
driver/vidc/inc/msm_vdec.h
Normal file
15
driver/vidc/inc/msm_vdec.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VDEC_H_
|
||||
#define _MSM_VDEC_H_
|
||||
|
||||
#include "msm_vidc_core.h"
|
||||
#include "msm_vidc_inst.h"
|
||||
|
||||
int msm_vdec_inst_init(struct msm_vidc_inst *inst);
|
||||
int msm_vdec_ctrl_init(struct msm_vidc_inst *inst);
|
||||
|
||||
#endif // _MSM_VDEC_H_
|
15
driver/vidc/inc/msm_venc.h
Normal file
15
driver/vidc/inc/msm_venc.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VENC_H_
|
||||
#define _MSM_VENC_H_
|
||||
|
||||
#include "msm_vidc_core.h"
|
||||
#include "msm_vidc_inst.h"
|
||||
|
||||
int msm_venc_inst_init(struct msm_vidc_inst *inst);
|
||||
int msm_venc_ctrl_init(struct msm_vidc_inst *inst);
|
||||
|
||||
#endif // _MSM_VENC_H_
|
48
driver/vidc/inc/msm_vidc.h
Normal file
48
driver/vidc/inc/msm_vidc.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VIDC_H_
|
||||
#define _MSM_VIDC_H_
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/media-device.h>
|
||||
|
||||
union msm_v4l2_cmd {
|
||||
struct v4l2_decoder_cmd dec;
|
||||
struct v4l2_encoder_cmd enc;
|
||||
};
|
||||
|
||||
void *msm_vidc_open(void *core, u32 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 media_device *mdev,
|
||||
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_query_menu(void *instance, struct v4l2_querymenu *qmenu);
|
||||
int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i);
|
||||
int msm_vidc_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);
|
||||
#endif
|
248
driver/vidc/inc/msm_vidc_bus.h
Normal file
248
driver/vidc/inc/msm_vidc_bus.h
Normal file
@@ -0,0 +1,248 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, 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 "msm_vidc_internal.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(const char *name)
|
||||
{
|
||||
if (!strcmp(name, "venus-llcc"))
|
||||
return LLCC;
|
||||
else if (!strcmp(name, "venus-ddr"))
|
||||
return DDR;
|
||||
else
|
||||
return PERF;
|
||||
}
|
||||
|
||||
#define DUMP_HEADER_MAGIC 0xdeadbeef
|
||||
#define DUMP_FP_FMT "%FP" /* special format for fp_t */
|
||||
|
||||
struct dump {
|
||||
char *key;
|
||||
char *format;
|
||||
size_t val;
|
||||
};
|
||||
|
||||
struct lut const *__lut(int width, int height, int fps);
|
||||
fp_t __compression_ratio(struct lut const *entry, int bpp);
|
||||
void __dump(struct dump dump[], int len);
|
||||
|
||||
static inline bool __ubwc(enum msm_vidc_colorformat_type f)
|
||||
{
|
||||
switch (f) {
|
||||
case MSM_VIDC_FMT_NV12_UBWC:
|
||||
case MSM_VIDC_FMT_NV12_TP10_UBWC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int __bpp(enum msm_vidc_colorformat_type f)
|
||||
{
|
||||
switch (f) {
|
||||
case MSM_VIDC_FMT_NV12:
|
||||
case MSM_VIDC_FMT_NV21:
|
||||
case MSM_VIDC_FMT_NV12_UBWC:
|
||||
case MSM_VIDC_FMT_RGBA8888_UBWC:
|
||||
return 8;
|
||||
case MSM_VIDC_FMT_NV12_P010_UBWC:
|
||||
case MSM_VIDC_FMT_NV12_TP10_UBWC:
|
||||
return 10;
|
||||
default:
|
||||
d_vpr_e("Unsupported colorformat (%x)", f);
|
||||
return INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __H_MSM_VIDC_BUS_DEFS_H__
|
106
driver/vidc/inc/msm_vidc_core.h
Normal file
106
driver/vidc/inc/msm_vidc_core.h
Normal file
@@ -0,0 +1,106 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VIDC_CORE_H_
|
||||
#define _MSM_VIDC_CORE_H_
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "msm_vidc_internal.h"
|
||||
|
||||
struct msm_vidc_core;
|
||||
|
||||
#define call_venus_op(d, op, ...) \
|
||||
(((d) && (d)->venus_ops && (d)->venus_ops->op) ? \
|
||||
((d)->venus_ops->op(__VA_ARGS__)):0)
|
||||
|
||||
struct msm_vidc_venus_ops {
|
||||
int (*boot_firmware)(struct msm_vidc_core *core);
|
||||
int (*reset_ahb2axi_bridge)(struct msm_vidc_core *core);
|
||||
int (*clock_config_on_enable)(struct msm_vidc_core *core);
|
||||
int (*interrupt_init)(struct msm_vidc_core *core);
|
||||
int (*setup_ucregion_memmap)(struct msm_vidc_core *core);
|
||||
int (*raise_interrupt)(struct msm_vidc_core *core);
|
||||
int (*clear_interrupt)(struct msm_vidc_core *core);
|
||||
int (*prepare_pc)(struct msm_vidc_core *core);
|
||||
int (*power_off)(struct msm_vidc_core *core);
|
||||
int (*watchdog)(struct msm_vidc_core *core, u32 intr_status);
|
||||
int (*noc_error_info)(struct msm_vidc_core *core);
|
||||
};
|
||||
|
||||
struct msm_vidc_mem_addr {
|
||||
u32 align_device_addr;
|
||||
u8 *align_virtual_addr;
|
||||
u32 mem_size;
|
||||
struct msm_vidc_map map;
|
||||
struct msm_vidc_alloc alloc;
|
||||
};
|
||||
|
||||
struct msm_vidc_iface_q_info {
|
||||
void *q_hdr;
|
||||
struct msm_vidc_mem_addr q_array;
|
||||
};
|
||||
|
||||
struct msm_video_device {
|
||||
enum msm_vidc_domain_type type;
|
||||
struct video_device vdev;
|
||||
};
|
||||
|
||||
struct msm_vidc_core_power {
|
||||
u64 clk_freq;
|
||||
u64 bw_ddr;
|
||||
u64 bw_llcc;
|
||||
};
|
||||
|
||||
enum msm_vidc_core_state {
|
||||
MSM_VIDC_CORE_DEINIT = 0,
|
||||
MSM_VIDC_CORE_INIT = 1,
|
||||
MSM_VIDC_CORE_ERROR = 2,
|
||||
};
|
||||
|
||||
struct msm_vidc_core {
|
||||
struct platform_device *pdev;
|
||||
struct msm_video_device vdev[2];
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct list_head instances;
|
||||
struct list_head dangling_instances;
|
||||
struct dentry *debugfs_root;
|
||||
enum msm_vidc_core_state state;
|
||||
struct mutex lock;
|
||||
struct msm_vidc_dt *dt;
|
||||
struct msm_vidc_platform *platform;
|
||||
u8 __iomem *register_base_addr;
|
||||
u32 intr_status;
|
||||
u32 spur_count;
|
||||
u32 reg_count;
|
||||
bool power_enabled;
|
||||
struct msm_vidc_mem_addr sfr;
|
||||
struct msm_vidc_mem_addr iface_q_table;
|
||||
struct msm_vidc_iface_q_info iface_queues[VIDC_IFACEQ_NUMQ];
|
||||
struct work_struct device_work;
|
||||
struct workqueue_struct *device_workq;
|
||||
struct delayed_work pm_work;
|
||||
struct workqueue_struct *pm_workq;
|
||||
struct delayed_work fw_unload_work;
|
||||
struct delayed_work batch_work;
|
||||
struct work_struct ssr_work;
|
||||
struct msm_vidc_core_power power;
|
||||
struct msm_vidc_ssr ssr;
|
||||
bool smmu_fault_handled;
|
||||
u32 skip_pc_count;
|
||||
u32 last_packet_type;
|
||||
u8 *packet;
|
||||
u32 packet_size;
|
||||
struct v4l2_file_operations *v4l2_file_ops;
|
||||
struct v4l2_ioctl_ops *v4l2_ioctl_ops;
|
||||
struct v4l2_ctrl_ops *v4l2_ctrl_ops;
|
||||
struct vb2_ops *vb2_ops;
|
||||
struct vb2_mem_ops *vb2_mem_ops;
|
||||
struct msm_vidc_venus_ops *venus_ops;
|
||||
struct msm_vidc_session_ops *session_ops;
|
||||
struct msm_vidc_memory_ops *mem_ops;
|
||||
};
|
||||
|
||||
#endif // _MSM_VIDC_CORE_H_
|
94
driver/vidc/inc/msm_vidc_debug.h
Normal file
94
driver/vidc/inc/msm_vidc_debug.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, 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 <linux/time.h>
|
||||
|
||||
#ifndef VIDC_DBG_LABEL
|
||||
#define VIDC_DBG_LABEL "msm_vidc"
|
||||
#endif
|
||||
|
||||
#define VIDC_DBG_TAG VIDC_DBG_LABEL ": %6s: %08x: %5s: "
|
||||
#define FW_DBG_TAG VIDC_DBG_LABEL ": %6s: "
|
||||
#define DEFAULT_SID ((u32)-1)
|
||||
|
||||
extern int msm_vidc_debug;
|
||||
extern bool msm_vidc_lossless_encode;
|
||||
extern bool msm_vidc_syscache_disable;
|
||||
|
||||
/* 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 = 0x00000001,
|
||||
VIDC_INFO = 0x00000001,
|
||||
VIDC_HIGH = 0x00000002,
|
||||
VIDC_LOW = 0x00000004,
|
||||
VIDC_PERF = 0x00000008,
|
||||
VIDC_PKT = 0x00000010,
|
||||
VIDC_BUS = 0x00000020,
|
||||
VIDC_ENCODER = 0x00000100,
|
||||
VIDC_DECODER = 0x00000200,
|
||||
VIDC_PRINTK = 0x00001000,
|
||||
VIDC_FTRACE = 0x00002000,
|
||||
FW_LOW = 0x00010000,
|
||||
FW_MEDIUM = 0x00020000,
|
||||
FW_HIGH = 0x00040000,
|
||||
FW_ERROR = 0x00080000,
|
||||
FW_FATAL = 0x00100000,
|
||||
FW_PERF = 0x00200000,
|
||||
FW_PRINTK = 0x10000000,
|
||||
FW_FTRACE = 0x20000000,
|
||||
};
|
||||
#define FW_LOGSHIFT 16
|
||||
#define FW_LOGMASK 0x0FFF0000
|
||||
|
||||
#define dprintk(__level, sid, __fmt, ...) \
|
||||
do { \
|
||||
pr_err(VIDC_DBG_TAG __fmt, \
|
||||
"level", \
|
||||
sid, \
|
||||
"codec", \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define s_vpr_e(sid, __fmt, ...) dprintk(VIDC_ERR, sid, __fmt, ##__VA_ARGS__)
|
||||
#define s_vpr_i(sid, __fmt, ...) dprintk(VIDC_INFO, sid, __fmt, ##__VA_ARGS__)
|
||||
#define s_vpr_h(sid, __fmt, ...) dprintk(VIDC_HIGH, sid, __fmt, ##__VA_ARGS__)
|
||||
#define s_vpr_l(sid, __fmt, ...) dprintk(VIDC_LOW, sid, __fmt, ##__VA_ARGS__)
|
||||
#define s_vpr_p(sid, __fmt, ...) dprintk(VIDC_PERF, sid, __fmt, ##__VA_ARGS__)
|
||||
#define s_vpr_t(sid, __fmt, ...) dprintk(VIDC_PKT, sid, __fmt, ##__VA_ARGS__)
|
||||
#define s_vpr_b(sid, __fmt, ...) dprintk(VIDC_BUS, sid, __fmt, ##__VA_ARGS__)
|
||||
#define s_vpr_hp(sid, __fmt, ...) \
|
||||
dprintk(VIDC_HIGH|VIDC_PERF, sid, __fmt, ##__VA_ARGS__)
|
||||
|
||||
#define d_vpr_e(__fmt, ...) \
|
||||
dprintk(VIDC_ERR, DEFAULT_SID, __fmt, ##__VA_ARGS__)
|
||||
#define d_vpr_i(__fmt, ...) \
|
||||
dprintk(VIDC_INFO, DEFAULT_SID, __fmt, ##__VA_ARGS__)
|
||||
#define d_vpr_h(__fmt, ...) \
|
||||
dprintk(VIDC_HIGH, DEFAULT_SID, __fmt, ##__VA_ARGS__)
|
||||
#define d_vpr_l(__fmt, ...) \
|
||||
dprintk(VIDC_LOW, DEFAULT_SID, __fmt, ##__VA_ARGS__)
|
||||
#define d_vpr_p(__fmt, ...) \
|
||||
dprintk(VIDC_PERF, DEFAULT_SID, __fmt, ##__VA_ARGS__)
|
||||
#define d_vpr_t(__fmt, ...) \
|
||||
dprintk(VIDC_PKT, DEFAULT_SID, __fmt, ##__VA_ARGS__)
|
||||
#define d_vpr_b(__fmt, ...) \
|
||||
dprintk(VIDC_BUS, DEFAULT_SID, __fmt, ##__VA_ARGS__)
|
||||
|
||||
#define MSM_VIDC_ERROR(value) \
|
||||
do { if (value) \
|
||||
d_vpr_e("BugOn"); \
|
||||
} while (0)
|
||||
#endif
|
41
driver/vidc/inc/msm_vidc_driver.h
Normal file
41
driver/vidc/inc/msm_vidc_driver.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VIDC_DRIVER_H_
|
||||
#define _MSM_VIDC_DRIVER_H_
|
||||
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/iommu.h>
|
||||
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_core.h"
|
||||
#include "msm_vidc_inst.h"
|
||||
|
||||
static inline is_decode_session(struct msm_vidc_inst *inst)
|
||||
{
|
||||
return inst->domain == MSM_VIDC_DECODER;
|
||||
}
|
||||
|
||||
static inline is_encode_session(struct msm_vidc_inst *inst)
|
||||
{
|
||||
return inst->domain == MSM_VIDC_ENCODER;
|
||||
}
|
||||
|
||||
int msm_vidc_add_session(struct msm_vidc_inst *inst);
|
||||
int msm_vidc_core_init(struct msm_vidc_core *core);
|
||||
int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
|
||||
struct device *dev, unsigned long iova, int flags, void *data);
|
||||
int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
|
||||
enum msm_vidc_ssr_trigger_type type);
|
||||
void msm_vidc_ssr_handler(struct work_struct *work);
|
||||
void msm_vidc_pm_work_handler(struct work_struct *work);
|
||||
void msm_vidc_fw_unload_handler(struct work_struct *work);
|
||||
void msm_vidc_batch_handler(struct work_struct *work);
|
||||
int msm_vidc_setup_event_queue(struct msm_vidc_inst *inst);
|
||||
int msm_vidc_queue_init(struct msm_vidc_inst *inst);
|
||||
u32 msm_vidc_convert_color_fmt(u32 v4l2_fmt);
|
||||
|
||||
#endif // _MSM_VIDC_DRIVER_H_
|
||||
|
227
driver/vidc/inc/msm_vidc_dt.h
Normal file
227
driver/vidc/inc/msm_vidc_dt.h
Normal file
@@ -0,0 +1,227 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VIDC_DT_H_
|
||||
#define _MSM_VIDC_DT_H_
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/soc/qcom/llcc-qcom.h>
|
||||
|
||||
#include "msm_vidc_internal.h"
|
||||
|
||||
/*
|
||||
* These are helper macros to iterate over various lists within
|
||||
* msm_vidc_core->dt. 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)->dt->__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)->dt->\
|
||||
__thingy##_set.__thingy##_tbl[__from]; \
|
||||
__thing < &(__device)->dt->__thingy##_set.__thingy##_tbl[0] + \
|
||||
((__device)->dt->__thingy##_set.count - __from); \
|
||||
++__thing)
|
||||
|
||||
#define venus_hfi_for_each_thing_reverse_continue(__device, __thing, __thingy, \
|
||||
__from) \
|
||||
for (__thing = &(__device)->dt->\
|
||||
__thingy##_set.__thingy##_tbl[__from]; \
|
||||
__thing >= &(__device)->dt->__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)
|
||||
|
||||
struct reg_value_pair {
|
||||
u32 reg;
|
||||
u32 value;
|
||||
u32 mask;
|
||||
};
|
||||
|
||||
struct reg_set {
|
||||
struct reg_value_pair *reg_tbl;
|
||||
u32 count;
|
||||
};
|
||||
|
||||
struct addr_range {
|
||||
u32 start;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct addr_set {
|
||||
struct addr_range *addr_tbl;
|
||||
u32 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 {
|
||||
const char *name;
|
||||
u32 range[2];
|
||||
struct device *dev;
|
||||
struct icc_path *path;
|
||||
};
|
||||
|
||||
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_dt {
|
||||
void *core;
|
||||
phys_addr_t register_base;
|
||||
u32 register_size;
|
||||
u32 irq;
|
||||
u32 sku_version;
|
||||
struct allowed_clock_rates_table *allowed_clks_tbl;
|
||||
u32 allowed_clks_tbl_size;
|
||||
struct clock_freq_table clock_freq_tbl;
|
||||
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;
|
||||
struct regulator_set regulator_set;
|
||||
struct clock_set clock_set;
|
||||
struct bus_set bus_set;
|
||||
struct reset_set reset_set;
|
||||
struct list_head context_banks;
|
||||
struct mutex cb_lock;
|
||||
const char *fw_name;
|
||||
void *fw_cookie;
|
||||
};
|
||||
|
||||
int msm_vidc_init_dt(struct platform_device *pdev);
|
||||
int msm_vidc_read_context_bank_resources_from_dt(struct platform_device *pdev);
|
||||
void msm_vidc_deinit_dt(struct platform_device *pdev);
|
||||
|
||||
#endif // _MSM_VIDC_DT_H_
|
107
driver/vidc/inc/msm_vidc_inst.h
Normal file
107
driver/vidc/inc/msm_vidc_inst.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VIDC_INST_H_
|
||||
#define _MSM_VIDC_INST_H_
|
||||
|
||||
#include "msm_vidc_internal.h"
|
||||
|
||||
struct msm_vidc_inst;
|
||||
|
||||
#define call_session_op(c, op, ...) \
|
||||
(((c) && (c)->session_ops && (c)->session_ops->op) ? \
|
||||
((c)->session_ops->op(__VA_ARGS__)) : 0)
|
||||
|
||||
struct msm_vidc_session_ops {
|
||||
int (*calc_freq)(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf);
|
||||
int (*calc_bw)(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf);
|
||||
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);
|
||||
int (*buffer_size)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type);
|
||||
int (*min_count)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type);
|
||||
int (*extra_count)(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type type);
|
||||
};
|
||||
|
||||
struct msm_vidc_allocations {
|
||||
struct msm_vidc_alloc_info scratch;
|
||||
struct msm_vidc_alloc_info scratch_1;
|
||||
struct msm_vidc_alloc_info scratch_2;
|
||||
struct msm_vidc_alloc_info persist;
|
||||
struct msm_vidc_alloc_info persist_1;
|
||||
};
|
||||
|
||||
struct msm_vidc_maps {
|
||||
struct msm_vidc_map_info input;
|
||||
struct msm_vidc_map_info output;
|
||||
struct msm_vidc_map_info input_meta;
|
||||
struct msm_vidc_map_info output_meta;
|
||||
struct msm_vidc_map_info scratch;
|
||||
struct msm_vidc_map_info scratch_1;
|
||||
struct msm_vidc_map_info scratch_2;
|
||||
struct msm_vidc_map_info persist;
|
||||
struct msm_vidc_map_info persist_1;
|
||||
};
|
||||
|
||||
struct msm_vidc_buffers {
|
||||
struct msm_vidc_buffer_info input;
|
||||
struct msm_vidc_buffer_info output;
|
||||
struct msm_vidc_buffer_info input_meta;
|
||||
struct msm_vidc_buffer_info output_meta;
|
||||
struct msm_vidc_buffer_info scratch;
|
||||
struct msm_vidc_buffer_info scratch_1;
|
||||
struct msm_vidc_buffer_info scratch_2;
|
||||
struct msm_vidc_buffer_info persist;
|
||||
struct msm_vidc_buffer_info persist_1;
|
||||
};
|
||||
|
||||
enum msm_vidc_inst_state {
|
||||
MSM_VIDC_OPEN = 1,
|
||||
MSM_VIDC_START_INPUT = 2,
|
||||
MSM_VIDC_START_OUTPUT = 3,
|
||||
MSM_VIDC_START = 4,
|
||||
MSM_VIDC_DRC = 5,
|
||||
MSM_VIDC_DRC_LAST_FLAG = 6,
|
||||
MSM_VIDC_DRAIN = 7,
|
||||
MSM_VIDC_DRAIN_LAST_FLAG = 8,
|
||||
MSM_VIDC_DRC_DRAIN = 9,
|
||||
MSM_VIDC_DRC_DRAIN_LAST_FLAG = 10,
|
||||
MSM_VIDC_DRAIN_START_INPUT = 11,
|
||||
MSM_VIDC_ERROR = 12,
|
||||
};
|
||||
|
||||
struct msm_vidc_inst {
|
||||
struct list_head list;
|
||||
struct mutex lock;
|
||||
enum msm_vidc_inst_state state;
|
||||
enum msm_vidc_domain_type domain;
|
||||
enum msm_vidc_codec_type codec;
|
||||
void *core;
|
||||
struct kref kref;
|
||||
u32 session_id;
|
||||
u32 sid;
|
||||
struct v4l2_format fmts[MAX_PORT];
|
||||
struct v4l2_ctrl_handler ctrl_handler;
|
||||
struct v4l2_fh event_handler;
|
||||
struct v4l2_ctrl **ctrls;
|
||||
u32 num_ctrls;
|
||||
struct vb2_queue vb2q[MAX_PORT];
|
||||
struct msm_vidc_properties prop;
|
||||
struct msm_vidc_power power;
|
||||
struct msm_vidc_buffers buffers;
|
||||
struct msm_vidc_maps maps;
|
||||
struct msm_vidc_allocations allocations;
|
||||
struct msm_vidc_port_settings port_settings[MAX_PORT];
|
||||
struct msm_vidc_decode_batch decode_batch;
|
||||
struct msm_vidc_decode_vpp_delay decode_vpp_delay;
|
||||
struct msm_vidc_session_idle session_idle;
|
||||
struct list_head input_ts;
|
||||
struct list_head enc_input_crs;
|
||||
struct list_head decode_bitrate_data;
|
||||
struct dentry *debugfs_root;
|
||||
struct msm_vidc_debug debug;
|
||||
};
|
||||
|
||||
#endif // _MSM_VIDC_INST_H_
|
468
driver/vidc/inc/msm_vidc_internal.h
Normal file
468
driver/vidc/inc/msm_vidc_internal.h
Normal file
@@ -0,0 +1,468 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VIDC_INTERNAL_H_
|
||||
#define _MSM_VIDC_INTERNAL_H_
|
||||
|
||||
#include <linux/bits.h>
|
||||
#include <linux/workqueue.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>
|
||||
|
||||
#define MAX_NAME_LENGTH 128
|
||||
#define MAX_MATRIX_COEFFS 9
|
||||
#define MAX_BIAS_COEFFS 3
|
||||
#define MAX_LIMIT_COEFFS 6
|
||||
#define MAX_DEBUGFS_NAME 50
|
||||
#define DEFAULT_TIMEOUT 3
|
||||
#define DEFAULT_HEIGHT 240
|
||||
#define DEFAULT_WIDTH 320
|
||||
#define MIN_SUPPORTED_WIDTH 32
|
||||
#define MIN_SUPPORTED_HEIGHT 32
|
||||
#define DEFAULT_FPS 30
|
||||
#define MINIMUM_FPS 1
|
||||
#define MAXIMUM_FPS 960
|
||||
#define SINGLE_INPUT_BUFFER 1
|
||||
#define SINGLE_OUTPUT_BUFFER 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
|
||||
#define MAX_BSE_VPP_DELAY 6
|
||||
#define DEFAULT_BSE_VPP_DELAY 2
|
||||
|
||||
/* Maintains the number of FTB's between each FBD over a window */
|
||||
#define DCVS_FTB_WINDOW 16
|
||||
/* Superframe can have maximum of 32 frames */
|
||||
#define VIDC_SUPERFRAME_MAX 32
|
||||
#define COLOR_RANGE_UNSPECIFIED (-1)
|
||||
|
||||
#define V4L2_EVENT_VIDC_BASE 10
|
||||
#define INPUT_PLANE V4L2_BUF_TYPE_VIDEO_OUTPUT
|
||||
#define OUTPUT_PLANE V4L2_BUF_TYPE_VIDEO_CAPTURE
|
||||
#define INPUT_META_PLANE V4L2_BUF_TYPE_META_OUTPUT
|
||||
#define OUTPUT_META_PLANE V4L2_BUF_TYPE_META_CAPTURE
|
||||
|
||||
#define VIDC_IFACEQ_MAX_PKT_SIZE 1024
|
||||
#define VIDC_IFACEQ_MED_PKT_SIZE 768
|
||||
#define VIDC_IFACEQ_MIN_PKT_SIZE 8
|
||||
#define VIDC_IFACEQ_VAR_SMALL_PKT_SIZE 100
|
||||
#define VIDC_IFACEQ_VAR_LARGE_PKT_SIZE 512
|
||||
#define VIDC_IFACEQ_VAR_HUGE_PKT_SIZE (1024*12)
|
||||
|
||||
#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))
|
||||
|
||||
/*
|
||||
* Convert Q16 number into Integer and Fractional part upto 2 places.
|
||||
* Ex : 105752 / 65536 = 1.61; 1.61 in Q16 = 105752;
|
||||
* Integer part = 105752 / 65536 = 1;
|
||||
* Reminder = 105752 * 0xFFFF = 40216; Last 16 bits.
|
||||
* Fractional part = 40216 * 100 / 65536 = 61;
|
||||
* Now convert to FP(1, 61, 100).
|
||||
*/
|
||||
#define Q16_INT(q) ((q) >> 16)
|
||||
#define Q16_FRAC(q) ((((q) & 0xFFFF) * 100) >> 16)
|
||||
|
||||
enum msm_vidc_domain_type {
|
||||
MSM_VIDC_ENCODER = BIT(0),
|
||||
MSM_VIDC_DECODER = BIT(1),
|
||||
};
|
||||
|
||||
enum msm_vidc_codec_type {
|
||||
MSM_VIDC_H264 = BIT(0),
|
||||
MSM_VIDC_HEVC = BIT(1),
|
||||
MSM_VIDC_VP9 = BIT(2),
|
||||
MSM_VIDC_MPEG2 = BIT(3),
|
||||
};
|
||||
|
||||
enum msm_vidc_colorformat_type {
|
||||
MSM_VIDC_FMT_NV12 = BIT(0),
|
||||
MSM_VIDC_FMT_NV21 = BIT(1),
|
||||
MSM_VIDC_FMT_NV12_UBWC = BIT(2),
|
||||
MSM_VIDC_FMT_NV12_P010_UBWC = BIT(3),
|
||||
MSM_VIDC_FMT_NV12_TP10_UBWC = BIT(4),
|
||||
MSM_VIDC_FMT_RGBA8888_UBWC = BIT(5),
|
||||
MSM_VIDC_FMT_SDE_Y_CBCR_H2V2_P010_VENUS = BIT(6),
|
||||
};
|
||||
|
||||
enum msm_vidc_buffer_type {
|
||||
MSM_VIDC_QUEUE = BIT(0),
|
||||
MSM_VIDC_INPUT = BIT(1),
|
||||
MSM_VIDC_OUTPUT = BIT(2),
|
||||
MSM_VIDC_INPUT_META = BIT(3),
|
||||
MSM_VIDC_OUTPUT_META = BIT(4),
|
||||
MSM_VIDC_DPB = BIT(5),
|
||||
MSM_VIDC_ARP = BIT(6),
|
||||
MSM_VIDC_LINE = BIT(7),
|
||||
MSM_VIDC_BIN = BIT(8),
|
||||
};
|
||||
|
||||
enum msm_vidc_buffer_attributes {
|
||||
MSM_VIDC_DEFERRED_SUBMISSION = BIT(0),
|
||||
MSM_VIDC_READ_ONLY = BIT(1),
|
||||
MSM_VIDC_PENDING_RELEASE = BIT(2),
|
||||
};
|
||||
|
||||
enum msm_vidc_buffer_region {
|
||||
MSM_VIDC_NON_SECURE = BIT(0),
|
||||
MSM_VIDC_SECURE_PIXEL = BIT(1),
|
||||
MSM_VIDC_SECURE_NONPIXEL = BIT(2),
|
||||
MSM_VIDC_SECURE_BITSTREAM = BIT(3),
|
||||
};
|
||||
|
||||
enum msm_vidc_port_type {
|
||||
INPUT_PORT,
|
||||
OUTPUT_PORT,
|
||||
INPUT_META_PORT,
|
||||
OUTPUT_META_PORT,
|
||||
MAX_PORT,
|
||||
};
|
||||
|
||||
enum msm_vidc_core_data_type {
|
||||
ENC_CODECS = 0,
|
||||
DEC_CODECS,
|
||||
MAX_SESSION_COUNT,
|
||||
MAX_SECURE_SESSION_COUNT,
|
||||
MAX_LOAD,
|
||||
MAX_MBPF,
|
||||
MAX_MBPS,
|
||||
MAX_MBPF_HQ,
|
||||
MAX_MBPS_HQ,
|
||||
MAX_MBPF_B_FRAME,
|
||||
MAX_MBPS_B_FRAME,
|
||||
SW_PC,
|
||||
SW_PC_DELAY,
|
||||
FW_UNLOAD,
|
||||
FW_UNLOAD_DELAY,
|
||||
HW_RESPONSE_TIMEOUT,
|
||||
DEBUG_TIMEOUT,
|
||||
PREFIX_BUF_COUNT_PIX,
|
||||
PREFIX_BUF_SIZE_PIX,
|
||||
PREFIX_BUF_COUNT_NON_PIX,
|
||||
PREFIX_BUF_SIZE_NON_PIX,
|
||||
PAGEFAULT_NON_FATAL,
|
||||
PAGETABLE_CACHING,
|
||||
DCVS,
|
||||
DECODE_BATCH,
|
||||
DECODE_BATCH_TIMEOUT,
|
||||
AV_SYNC_WINDOW_SIZE,
|
||||
CLK_FREQ_THRESHOLD,
|
||||
};
|
||||
|
||||
enum msm_vidc_instance_data_type {
|
||||
FRAME_WIDTH,
|
||||
FRAME_HEIGHT,
|
||||
MBPF,
|
||||
MBPS,
|
||||
FRAME_RATE,
|
||||
BIT_RATE,
|
||||
CABAC_BIT_RATE,
|
||||
LTR_COUNT,
|
||||
LCU_SIZE,
|
||||
POWER_SAVE_MBPS,
|
||||
SCALE_X,
|
||||
SCALE_Y,
|
||||
PROFILE,
|
||||
LEVEL,
|
||||
I_FRAME_QP,
|
||||
P_FRAME_QP,
|
||||
B_FRAME_QP,
|
||||
B_FRAME,
|
||||
HIER_P_LAYERS,
|
||||
BLUR_WIDTH,
|
||||
BLUR_HEIGHT,
|
||||
SLICE_BYTE,
|
||||
SLICE_MB,
|
||||
SECURE,
|
||||
SECURE_FRAME_WIDTH,
|
||||
SECURE_FRAME_HEIGHT,
|
||||
SECURE_MBPF,
|
||||
SECURE_BIT_RATE,
|
||||
BATCH_MBPF,
|
||||
BATCH_FRAME_RATE,
|
||||
LOSSLESS_FRAME_WIDTH,
|
||||
LOSSLESS_FRAME_HEIGHT,
|
||||
LOSSLESS_MBPF,
|
||||
ALL_INTRA_FRAME_RATE,
|
||||
HEVC_IMAGE_FRAME_WIDTH,
|
||||
HEVC_IMAGE_FRAME_HEIGHT,
|
||||
HEIC_IMAGE_FRAME_WIDTH,
|
||||
HEIC_IMAGE_FRAME_HEIGHT,
|
||||
MB_CYCLES_VSP,
|
||||
MB_CYCLES_VPP,
|
||||
MB_CYCLES_LP,
|
||||
MB_CYCLES_FW,
|
||||
MB_CYCLES_FW_VPP,
|
||||
};
|
||||
|
||||
enum efuse_purpose {
|
||||
SKU_VERSION = 0,
|
||||
};
|
||||
|
||||
enum sku_version {
|
||||
SKU_VERSION_0 = 0,
|
||||
SKU_VERSION_1,
|
||||
SKU_VERSION_2,
|
||||
};
|
||||
|
||||
enum msm_vidc_ssr_trigger_type {
|
||||
SSR_ERR_FATAL = 1,
|
||||
SSR_SW_DIV_BY_ZERO,
|
||||
SSR_HW_WDOG_IRQ,
|
||||
};
|
||||
|
||||
enum msm_vidc_cache_op {
|
||||
MSM_VIDC_CACHE_CLEAN,
|
||||
MSM_VIDC_CACHE_INVALIDATE,
|
||||
MSM_VIDC_CACHE_CLEAN_INVALIDATE,
|
||||
};
|
||||
|
||||
enum msm_vidc_dcvs_flags {
|
||||
MSM_VIDC_DCVS_INCR = BIT(0),
|
||||
MSM_VIDC_DCVS_DECR = BIT(1),
|
||||
};
|
||||
|
||||
enum msm_vidc_clock_properties {
|
||||
CLOCK_PROP_HAS_SCALING = BIT(0),
|
||||
CLOCK_PROP_HAS_MEM_RETENTION = BIT(1),
|
||||
};
|
||||
|
||||
enum profiling_points {
|
||||
FRAME_PROCESSING = 0,
|
||||
MAX_PROFILING_POINTS,
|
||||
};
|
||||
|
||||
#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_IFACEQ_NUMQ 3
|
||||
#define VIDC_IFACEQ_CMDQ_IDX 0
|
||||
#define VIDC_IFACEQ_MSGQ_IDX 1
|
||||
#define VIDC_IFACEQ_DBGQ_IDX 2
|
||||
#define VIDC_IFACEQ_MAX_BUF_COUNT 50
|
||||
#define VIDC_IFACE_MAX_PARALLEL_CLNTS 16
|
||||
#define VIDC_IFACEQ_DFLT_QHDR 0x01010000
|
||||
|
||||
struct hfi_queue_table_header {
|
||||
u32 qtbl_version;
|
||||
u32 qtbl_size;
|
||||
u32 qtbl_qhdr0_offset;
|
||||
u32 qtbl_qhdr_size;
|
||||
u32 qtbl_num_q;
|
||||
u32 qtbl_num_active_q;
|
||||
void *device_addr;
|
||||
char name[256];
|
||||
};
|
||||
|
||||
struct hfi_queue_header {
|
||||
u32 qhdr_status;
|
||||
u32 qhdr_start_addr;
|
||||
u32 qhdr_type;
|
||||
u32 qhdr_q_size;
|
||||
u32 qhdr_pkt_size;
|
||||
u32 qhdr_pkt_drop_cnt;
|
||||
u32 qhdr_rx_wm;
|
||||
u32 qhdr_tx_wm;
|
||||
u32 qhdr_rx_req;
|
||||
u32 qhdr_tx_req;
|
||||
u32 qhdr_rx_irq_status;
|
||||
u32 qhdr_tx_irq_status;
|
||||
u32 qhdr_read_idx;
|
||||
u32 qhdr_write_idx;
|
||||
};
|
||||
|
||||
#define VIDC_IFACEQ_TABLE_SIZE (sizeof(struct hfi_queue_table_header) \
|
||||
+ sizeof(struct hfi_queue_header) * VIDC_IFACEQ_NUMQ)
|
||||
|
||||
#define VIDC_IFACEQ_QUEUE_SIZE (VIDC_IFACEQ_MAX_PKT_SIZE * \
|
||||
VIDC_IFACEQ_MAX_BUF_COUNT * VIDC_IFACE_MAX_PARALLEL_CLNTS)
|
||||
|
||||
#define VIDC_IFACEQ_GET_QHDR_START_ADDR(ptr, i) \
|
||||
(void *)((ptr + sizeof(struct hfi_queue_table_header)) + \
|
||||
(i * sizeof(struct hfi_queue_header)))
|
||||
|
||||
#define QDSS_SIZE 4096
|
||||
#define SFR_SIZE 4096
|
||||
|
||||
#define 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)
|
||||
|
||||
struct buf_count {
|
||||
u32 etb;
|
||||
u32 ftb;
|
||||
u32 fbd;
|
||||
u32 ebd;
|
||||
};
|
||||
|
||||
struct profile_data {
|
||||
u32 start;
|
||||
u32 stop;
|
||||
u32 cumulative;
|
||||
char name[64];
|
||||
u32 sampling;
|
||||
u32 average;
|
||||
};
|
||||
|
||||
struct msm_vidc_debug {
|
||||
struct profile_data pdata[MAX_PROFILING_POINTS];
|
||||
u32 profile;
|
||||
u32 samples;
|
||||
struct buf_count count;
|
||||
};
|
||||
|
||||
struct msm_vidc_input_cr_data {
|
||||
struct list_head list;
|
||||
u32 index;
|
||||
u32 input_cr;
|
||||
};
|
||||
|
||||
struct msm_vidc_timestamps {
|
||||
struct list_head list;
|
||||
u64 timestamp_us;
|
||||
u32 framerate;
|
||||
bool is_valid;
|
||||
};
|
||||
|
||||
struct msm_vidc_session_idle {
|
||||
bool idle;
|
||||
u64 last_activity_time_ns;
|
||||
};
|
||||
|
||||
struct msm_vidc_port_settings {
|
||||
u32 aligned_width;
|
||||
u32 aligned_height;
|
||||
u32 crop_width;
|
||||
u32 crop_height;
|
||||
u32 min_count;
|
||||
u32 poc;
|
||||
};
|
||||
|
||||
struct msm_vidc_decode_vpp_delay {
|
||||
bool enable;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct msm_vidc_decode_batch {
|
||||
bool enable;
|
||||
u32 size;
|
||||
struct delayed_work work;
|
||||
};
|
||||
|
||||
struct msm_vidc_power {
|
||||
u32 buffer_counter;
|
||||
u32 min_threshold;
|
||||
u32 nom_threshold;
|
||||
u32 max_threshold;
|
||||
bool dcvs_mode;
|
||||
u32 dcvs_window;
|
||||
u64 min_freq;
|
||||
u64 curr_freq;
|
||||
u32 ddr_bw;
|
||||
u32 sys_cache_bw;
|
||||
u32 dcvs_flags;
|
||||
};
|
||||
|
||||
struct msm_vidc_alloc {
|
||||
enum msm_vidc_buffer_type buffer_type;
|
||||
enum msm_vidc_buffer_region region;
|
||||
u32 size;
|
||||
u8 cached:1;
|
||||
u8 secure:1;
|
||||
u8 map_kernel:1;
|
||||
struct dma_buf *dmabuf;
|
||||
void *kvaddr;
|
||||
};
|
||||
|
||||
struct msm_vidc_alloc_info {
|
||||
struct list_head list; // list of "struct msm_vidc_alloc"
|
||||
};
|
||||
|
||||
struct msm_vidc_map {
|
||||
bool valid;
|
||||
enum msm_vidc_buffer_type buffer_type;
|
||||
enum msm_vidc_buffer_region region;
|
||||
struct dma_buf *dmabuf;
|
||||
u32 refcount;
|
||||
u64 device_addr;
|
||||
struct sg_table *table;
|
||||
struct dma_buf_attachment *attach;
|
||||
};
|
||||
|
||||
struct msm_vidc_map_info {
|
||||
struct list_head list; // list of "struct msm_vidc_map"
|
||||
};
|
||||
|
||||
struct msm_vidc_buffer {
|
||||
bool valid;
|
||||
enum msm_vidc_buffer_type type;
|
||||
u32 index;
|
||||
int fd;
|
||||
u32 buffer_size;
|
||||
u32 data_offset;
|
||||
u32 data_size;
|
||||
u64 device_addr;
|
||||
void *dmabuf;
|
||||
u32 flags;
|
||||
u64 timestamp;
|
||||
enum msm_vidc_buffer_attributes attr;
|
||||
};
|
||||
|
||||
struct msm_vidc_buffer_info {
|
||||
struct list_head list; // list of "struct msm_vidc_buffer"
|
||||
u32 min_count;
|
||||
u32 extra_count;
|
||||
u32 actual_count;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct msm_vidc_properties {
|
||||
u32 frame_rate;
|
||||
u32 operating_rate;
|
||||
u32 bit_rate;
|
||||
u32 profile;
|
||||
u32 level;
|
||||
u32 entropy_mode;
|
||||
u32 rc_type;
|
||||
};
|
||||
|
||||
struct msm_vidc_ssr {
|
||||
bool trigger;
|
||||
enum msm_vidc_ssr_trigger_type ssr_type;
|
||||
};
|
||||
|
||||
#define call_mem_op(c, op, ...) \
|
||||
(((c) && (c)->mem_ops && (c)->mem_ops->op) ? \
|
||||
((c)->mem_ops->op(__VA_ARGS__)) : 0)
|
||||
|
||||
struct msm_vidc_memory_ops {
|
||||
int (*allocate)(void *inst, struct msm_vidc_buffer *mbuf);
|
||||
int (*dma_map)(void *inst, struct msm_vidc_buffer *mbuf);
|
||||
int (*dma_unmap)(void *inst, struct msm_vidc_buffer *mbuf);
|
||||
int (*free)(void *inst, struct msm_vidc_buffer *mbuf);
|
||||
int (*cache_op)(void *inst, struct msm_vidc_buffer *mbuf,
|
||||
enum msm_vidc_cache_op cache_op);
|
||||
};
|
||||
|
||||
#endif // _MSM_VIDC_INTERNAL_H_
|
23
driver/vidc/inc/msm_vidc_memory.h
Normal file
23
driver/vidc/inc/msm_vidc_memory.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VIDC_MEMORY_H_
|
||||
#define _MSM_VIDC_MEMORY_H_
|
||||
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_core.h"
|
||||
|
||||
int msm_vidc_memory_alloc(struct msm_vidc_core *core,
|
||||
struct msm_vidc_alloc *alloc);
|
||||
int msm_vidc_memory_free(struct msm_vidc_core *core,
|
||||
struct msm_vidc_alloc *alloc);
|
||||
int msm_vidc_memory_map(struct msm_vidc_core *core,
|
||||
struct msm_vidc_map *map);
|
||||
int msm_vidc_memory_unmap(struct msm_vidc_core *core,
|
||||
struct msm_vidc_map *map);
|
||||
struct dma_buf *msm_vidc_memory_get_dmabuf(int fd);
|
||||
void msm_vidc_memory_put_dmabuf(void *dmabuf);
|
||||
|
||||
#endif // _MSM_VIDC_MEMORY_H_
|
78
driver/vidc/inc/msm_vidc_platform.h
Normal file
78
driver/vidc/inc/msm_vidc_platform.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VIDC_PLATFORM_H_
|
||||
#define _MSM_VIDC_PLATFORM_H_
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "msm_vidc_internal.h"
|
||||
|
||||
struct msm_vidc_core_data {
|
||||
enum msm_vidc_core_data_type type;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
struct msm_vidc_instance_data {
|
||||
enum msm_vidc_instance_data_type type;
|
||||
enum msm_vidc_domain_type domains;
|
||||
enum msm_vidc_codec_type codecs;
|
||||
u32 min;
|
||||
u32 max;
|
||||
u32 step_or_menu;
|
||||
u32 value;
|
||||
};
|
||||
|
||||
struct msm_vidc_csc_coeff {
|
||||
u32 *vpe_csc_custom_matrix_coeff;
|
||||
u32 *vpe_csc_custom_bias_coeff;
|
||||
u32 *vpe_csc_custom_limit_coeff;
|
||||
};
|
||||
|
||||
struct msm_vidc_efuse_data {
|
||||
u32 start_address;
|
||||
u32 size;
|
||||
u32 mask;
|
||||
u32 shift;
|
||||
enum efuse_purpose purpose;
|
||||
};
|
||||
|
||||
struct msm_vidc_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_core_data *core_data;
|
||||
u32 core_data_size;
|
||||
struct msm_vidc_instance_data *instance_data;
|
||||
u32 instance_data_size;
|
||||
struct allowed_clock_rates_table *allowed_clks_tbl;
|
||||
u32 allowed_clks_tbl_size;
|
||||
struct msm_vidc_csc_coeff csc_data;
|
||||
struct msm_vidc_ubwc_config_data *ubwc_config;
|
||||
};
|
||||
|
||||
struct msm_vidc_platform {
|
||||
void *core;
|
||||
struct msm_vidc_platform_data data;
|
||||
};
|
||||
|
||||
int msm_vidc_init_platform(struct platform_device *pdev);
|
||||
int msm_vidc_deinit_platform(struct platform_device *pdev);
|
||||
|
||||
#endif // _MSM_VIDC_PLATFORM_H_
|
55
driver/vidc/inc/msm_vidc_v4l2.h
Normal file
55
driver/vidc/inc/msm_vidc_v4l2.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VIDC_V4L2_H_
|
||||
#define _MSM_VIDC_V4L2_H_
|
||||
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fs.h>
|
||||
#include <media/v4l2-dev.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
|
||||
int msm_v4l2_open(struct file *filp);
|
||||
int msm_v4l2_close(struct file *filp);
|
||||
int msm_v4l2_querycap(struct file *filp, void *fh,
|
||||
struct v4l2_capability *cap);
|
||||
int msm_v4l2_enum_fmt(struct file *file, void *fh,
|
||||
struct v4l2_fmtdesc *f);
|
||||
int msm_v4l2_s_fmt(struct file *file, void *fh,
|
||||
struct v4l2_format *f);
|
||||
int msm_v4l2_g_fmt(struct file *file, void *fh,
|
||||
struct v4l2_format *f);
|
||||
int msm_v4l2_s_ctrl(struct file *file, void *fh,
|
||||
struct v4l2_control *a);
|
||||
int msm_v4l2_g_ctrl(struct file *file, void *fh,
|
||||
struct v4l2_control *a);
|
||||
int msm_v4l2_reqbufs(struct file *file, void *fh,
|
||||
struct v4l2_requestbuffers *b);
|
||||
int msm_v4l2_qbuf(struct file *file, void *fh,
|
||||
struct v4l2_buffer *b);
|
||||
int msm_v4l2_dqbuf(struct file *file, void *fh,
|
||||
struct v4l2_buffer *b);
|
||||
int msm_v4l2_streamon(struct file *file, void *fh,
|
||||
enum v4l2_buf_type i);
|
||||
int msm_v4l2_streamoff(struct file *file, void *fh,
|
||||
enum v4l2_buf_type i);
|
||||
int msm_v4l2_subscribe_event(struct v4l2_fh *fh,
|
||||
const struct v4l2_event_subscription *sub);
|
||||
int msm_v4l2_unsubscribe_event(struct v4l2_fh *fh,
|
||||
const struct v4l2_event_subscription *sub);
|
||||
int msm_v4l2_decoder_cmd(struct file *file, void *fh,
|
||||
struct v4l2_decoder_cmd *dec);
|
||||
int msm_v4l2_encoder_cmd(struct file *file, void *fh,
|
||||
struct v4l2_encoder_cmd *enc);
|
||||
int msm_v4l2_enum_framesizes(struct file *file, void *fh,
|
||||
struct v4l2_frmsizeenum *fsize);
|
||||
int msm_v4l2_queryctrl(struct file *file, void *fh,
|
||||
struct v4l2_queryctrl *ctrl);
|
||||
int msm_v4l2_querymenu(struct file *file, void *fh,
|
||||
struct v4l2_querymenu *qmenu);
|
||||
unsigned int msm_v4l2_poll(struct file *filp,
|
||||
struct poll_table_struct *pt);
|
||||
#endif // _MSM_VIDC_V4L2_H_
|
25
driver/vidc/inc/msm_vidc_vb2.h
Normal file
25
driver/vidc/inc/msm_vidc_vb2.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _MSM_VIDC_VB2_H_
|
||||
#define _MSM_VIDC_VB2_H_
|
||||
|
||||
#include <media/videobuf2-core.h>
|
||||
#include <media/videobuf2-v4l2.h>
|
||||
|
||||
/* vb2_mem_ops */
|
||||
void *msm_vb2_get_userptr(struct device *dev, unsigned long vaddr,
|
||||
unsigned long size, enum dma_data_direction dma_dir);
|
||||
void msm_vb2_put_userptr(void *buf_priv);
|
||||
|
||||
/* vb2_ops */
|
||||
int msm_vidc_queue_setup(struct vb2_queue *q,
|
||||
unsigned int *num_buffers, unsigned int *num_planes,
|
||||
unsigned int sizes[], struct device *alloc_devs[]);
|
||||
int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count);
|
||||
void msm_vidc_stop_streaming(struct vb2_queue *q);
|
||||
void msm_vidc_buf_queue(struct vb2_buffer *vb2);
|
||||
void msm_vidc_buf_cleanup(struct vb2_buffer *vb);
|
||||
#endif // _MSM_VIDC_VB2_H_
|
71
driver/vidc/inc/venus_hfi.h
Normal file
71
driver/vidc/inc/venus_hfi.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VENUS_HFI_H_
|
||||
#define _VENUS_HFI_H_
|
||||
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_inst.h"
|
||||
#include "msm_vidc_core.h"
|
||||
|
||||
#define VIDC_MAX_NAME_LENGTH 64
|
||||
#define VIDC_MAX_PC_SKIP_COUNT 10
|
||||
#define VIDC_MAX_SUBCACHES 4
|
||||
#define VIDC_MAX_SUBCACHE_SIZE 52
|
||||
|
||||
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_buffer_addr_info {
|
||||
enum msm_vidc_buffer_type buffer_type;
|
||||
u32 buffer_size;
|
||||
u32 num_buffers;
|
||||
u32 align_device_addr;
|
||||
u32 extradata_addr;
|
||||
u32 extradata_size;
|
||||
u32 response_required;
|
||||
};
|
||||
|
||||
struct hfi_resource_subcache_type {
|
||||
u32 size;
|
||||
u32 sc_id;
|
||||
};
|
||||
|
||||
struct hfi_resource_syscache_info_type {
|
||||
u32 num_entries;
|
||||
struct hfi_resource_subcache_type rg_subcache_entries[1];
|
||||
};
|
||||
|
||||
int venus_hfi_core_init(struct msm_vidc_core *core);
|
||||
int venus_hfi_core_release(struct msm_vidc_core *core);
|
||||
int venus_hfi_suspend(struct msm_vidc_core *core);
|
||||
int venus_hfi_session_open(struct msm_vidc_core *core, struct msm_vidc_inst *inst);
|
||||
void venus_hfi_work_handler(struct work_struct *work);
|
||||
void venus_hfi_pm_work_handler(struct work_struct *work);
|
||||
|
||||
void __write_register(struct msm_vidc_core *core,
|
||||
u32 reg, u32 value);
|
||||
int __read_register(struct msm_vidc_core *core, u32 reg);
|
||||
void __disable_unprepare_clks(struct msm_vidc_core *core);
|
||||
int __disable_regulators(struct msm_vidc_core *core);
|
||||
int __unvote_buses(struct msm_vidc_core *core);
|
||||
int __prepare_pc(struct msm_vidc_core *core);
|
||||
|
||||
int __reset_ahb2axi_bridge(struct msm_vidc_core *core);
|
||||
int __clock_config_on_enable(struct msm_vidc_core *core);
|
||||
int __interrupt_init(struct msm_vidc_core *core);
|
||||
int __setup_ucregion_memmap(struct msm_vidc_core *core);
|
||||
int __raise_interrupt(struct msm_vidc_core *core);
|
||||
int __power_off(struct msm_vidc_core *core);
|
||||
|
||||
#endif // _VENUS_HFI_H_
|
21
driver/vidc/src/hfi_packet.c
Normal file
21
driver/vidc/src/hfi_packet.c
Normal file
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "hfi_packet.h"
|
||||
#include "msm_vidc_core.h"
|
||||
#include "msm_vidc_inst.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
|
||||
int hfi_packet_sys_init(struct msm_vidc_core *core, void *pkt, u32 pkt_size)
|
||||
{
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hfi_packet_sys_pc_prep(struct msm_vidc_core *core, void *pkt, u32 pkt_size)
|
||||
{
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
return 0;
|
||||
}
|
108
driver/vidc/src/msm_vdec.c
Normal file
108
driver/vidc/src/msm_vdec.c
Normal file
@@ -0,0 +1,108 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <media/msm_vidc_utils.h>
|
||||
#include <media/msm_media_info.h>
|
||||
|
||||
#include "msm_vdec.h"
|
||||
#include "msm_vidc_core.h"
|
||||
#include "msm_vidc_inst.h"
|
||||
#include "msm_vidc_driver.h"
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_platform.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
|
||||
|
||||
int msm_vdec_inst_init(struct msm_vidc_inst *inst)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_core *core;
|
||||
struct v4l2_format *f;
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
if (!inst || !inst->core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
core = inst->core;
|
||||
|
||||
INIT_DELAYED_WORK(&inst->decode_batch.work, msm_vidc_batch_handler);
|
||||
|
||||
f = &inst->fmts[INPUT_PORT];
|
||||
f->type = INPUT_PLANE;
|
||||
f->fmt.pix.width = DEFAULT_WIDTH;
|
||||
f->fmt.pix.height = DEFAULT_HEIGHT;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
|
||||
f->fmt.pix.bytesperline = 0;
|
||||
f->fmt.pix.sizeimage = call_session_op(core, buffer_size,
|
||||
inst, MSM_VIDC_INPUT);
|
||||
inst->buffers.input.min_count =
|
||||
call_session_op(core, min_count, inst, MSM_VIDC_INPUT);
|
||||
inst->buffers.input.extra_count =
|
||||
call_session_op(core, extra_count, inst, MSM_VIDC_INPUT);
|
||||
inst->buffers.input.actual_count =
|
||||
inst->buffers.input.min_count +
|
||||
inst->buffers.input.extra_count;
|
||||
inst->buffers.input.size = f->fmt.pix.sizeimage;
|
||||
|
||||
f = &inst->fmts[INPUT_META_PORT];
|
||||
f->type = INPUT_META_PLANE;
|
||||
f->fmt.meta.dataformat = V4L2_PIX_FMT_VIDC_META;
|
||||
f->fmt.meta.buffersize = call_session_op(core, buffer_size,
|
||||
inst, MSM_VIDC_INPUT_META);
|
||||
inst->buffers.input_meta.min_count = inst->buffers.input.min_count;
|
||||
inst->buffers.input_meta.extra_count = inst->buffers.input.extra_count;
|
||||
inst->buffers.input_meta.actual_count = inst->buffers.input.actual_count;
|
||||
inst->buffers.input_meta.size = f->fmt.meta.buffersize;
|
||||
|
||||
f = &inst->fmts[OUTPUT_PORT];
|
||||
f->type = OUTPUT_PLANE;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12_UBWC;
|
||||
f->fmt.pix.width = VENUS_Y_STRIDE(
|
||||
msm_vidc_convert_color_fmt(f->fmt.pix.pixelformat), DEFAULT_WIDTH);
|
||||
f->fmt.pix.height = VENUS_Y_SCANLINES(
|
||||
msm_vidc_convert_color_fmt(f->fmt.pix.pixelformat), DEFAULT_HEIGHT);
|
||||
f->fmt.pix.bytesperline = f->fmt.pix.width;
|
||||
f->fmt.pix.sizeimage = call_session_op(core, buffer_size,
|
||||
inst, MSM_VIDC_OUTPUT);
|
||||
inst->buffers.output.min_count =
|
||||
call_session_op(core, min_count, inst, MSM_VIDC_OUTPUT);
|
||||
inst->buffers.output.extra_count =
|
||||
call_session_op(core, extra_count, inst, MSM_VIDC_OUTPUT);
|
||||
inst->buffers.output.actual_count =
|
||||
inst->buffers.output.min_count +
|
||||
inst->buffers.output.extra_count;
|
||||
inst->buffers.output.size = f->fmt.pix.sizeimage;
|
||||
|
||||
f = &inst->fmts[OUTPUT_META_PORT];
|
||||
f->type = OUTPUT_META_PLANE;
|
||||
f->fmt.meta.dataformat = V4L2_PIX_FMT_VIDC_META;
|
||||
f->fmt.meta.buffersize = call_session_op(core, buffer_size,
|
||||
inst, MSM_VIDC_OUTPUT_META);
|
||||
inst->buffers.output_meta.min_count = inst->buffers.output.min_count;
|
||||
inst->buffers.output_meta.extra_count = inst->buffers.output.extra_count;
|
||||
inst->buffers.output_meta.actual_count = inst->buffers.output.actual_count;
|
||||
inst->buffers.output_meta.size = f->fmt.meta.buffersize;
|
||||
|
||||
inst->prop.frame_rate = DEFAULT_FPS << 16;
|
||||
inst->prop.operating_rate = DEFAULT_FPS << 16;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vdec_ctrl_init(struct msm_vidc_inst *inst)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_core *core;
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
if (!inst || !inst->core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
core = inst->core;
|
||||
|
||||
return rc;
|
||||
}
|
106
driver/vidc/src/msm_venc.c
Normal file
106
driver/vidc/src/msm_venc.c
Normal file
@@ -0,0 +1,106 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <media/msm_vidc_utils.h>
|
||||
#include <media/msm_media_info.h>
|
||||
|
||||
#include "msm_venc.h"
|
||||
#include "msm_vidc_core.h"
|
||||
#include "msm_vidc_inst.h"
|
||||
#include "msm_vidc_driver.h"
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_platform.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
|
||||
|
||||
int msm_venc_inst_init(struct msm_vidc_inst *inst)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_core *core;
|
||||
struct v4l2_format *f;
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
if (!inst || !inst->core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
core = inst->core;
|
||||
|
||||
f = &inst->fmts[OUTPUT_PORT];
|
||||
f->type = OUTPUT_PLANE;
|
||||
f->fmt.pix.width = DEFAULT_WIDTH;
|
||||
f->fmt.pix.height = DEFAULT_HEIGHT;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
|
||||
f->fmt.pix.bytesperline = 0;
|
||||
f->fmt.pix.sizeimage = call_session_op(core, buffer_size,
|
||||
inst, MSM_VIDC_OUTPUT);
|
||||
inst->buffers.output.min_count =
|
||||
call_session_op(core, min_count, inst, MSM_VIDC_OUTPUT);
|
||||
inst->buffers.output.extra_count =
|
||||
call_session_op(core, extra_count, inst, MSM_VIDC_OUTPUT);
|
||||
inst->buffers.output.actual_count =
|
||||
inst->buffers.output.min_count +
|
||||
inst->buffers.output.extra_count;
|
||||
inst->buffers.output.size = f->fmt.pix.sizeimage;
|
||||
|
||||
f = &inst->fmts[OUTPUT_META_PORT];
|
||||
f->type = OUTPUT_META_PLANE;
|
||||
f->fmt.meta.dataformat = V4L2_PIX_FMT_VIDC_META;
|
||||
f->fmt.meta.buffersize = call_session_op(core, buffer_size,
|
||||
inst, MSM_VIDC_OUTPUT_META);
|
||||
inst->buffers.output_meta.min_count = inst->buffers.output.min_count;
|
||||
inst->buffers.output_meta.extra_count = inst->buffers.output.extra_count;
|
||||
inst->buffers.output_meta.actual_count = inst->buffers.output.actual_count;
|
||||
inst->buffers.output_meta.size = f->fmt.meta.buffersize;
|
||||
|
||||
f = &inst->fmts[INPUT_PORT];
|
||||
f->type = INPUT_PLANE;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_NV12_UBWC;
|
||||
f->fmt.pix.width = VENUS_Y_STRIDE(
|
||||
msm_vidc_convert_color_fmt(f->fmt.pix.pixelformat), DEFAULT_WIDTH);
|
||||
f->fmt.pix.height = VENUS_Y_SCANLINES(
|
||||
msm_vidc_convert_color_fmt(f->fmt.pix.pixelformat), DEFAULT_HEIGHT);
|
||||
f->fmt.pix.bytesperline = f->fmt.pix.width;
|
||||
f->fmt.pix.sizeimage = call_session_op(core, buffer_size,
|
||||
inst, MSM_VIDC_INPUT);
|
||||
inst->buffers.input.min_count =
|
||||
call_session_op(core, min_count, inst, MSM_VIDC_INPUT);
|
||||
inst->buffers.input.extra_count =
|
||||
call_session_op(core, extra_count, inst, MSM_VIDC_INPUT);
|
||||
inst->buffers.input.actual_count =
|
||||
inst->buffers.input.min_count +
|
||||
inst->buffers.input.extra_count;
|
||||
inst->buffers.input.size = f->fmt.pix.sizeimage;
|
||||
|
||||
f = &inst->fmts[INPUT_META_PORT];
|
||||
f->type = INPUT_META_PLANE;
|
||||
f->fmt.meta.dataformat = V4L2_PIX_FMT_VIDC_META;
|
||||
f->fmt.meta.buffersize = call_session_op(core, buffer_size,
|
||||
inst, MSM_VIDC_INPUT_META);
|
||||
inst->buffers.input_meta.min_count = inst->buffers.input.min_count;
|
||||
inst->buffers.input_meta.extra_count = inst->buffers.input.extra_count;
|
||||
inst->buffers.input_meta.actual_count = inst->buffers.input.actual_count;
|
||||
inst->buffers.input_meta.size = f->fmt.meta.buffersize;
|
||||
|
||||
inst->prop.frame_rate = DEFAULT_FPS << 16;
|
||||
inst->prop.operating_rate = DEFAULT_FPS << 16;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_venc_ctrl_init(struct msm_vidc_inst *inst)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_core *core;
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
if (!inst || !inst->core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
core = inst->core;
|
||||
|
||||
return rc;
|
||||
}
|
457
driver/vidc/src/msm_vidc.c
Normal file
457
driver/vidc/src/msm_vidc.c
Normal file
@@ -0,0 +1,457 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "msm_vidc.h"
|
||||
#include "msm_vidc_core.h"
|
||||
#include "msm_vidc_inst.h"
|
||||
#include "msm_vdec.h"
|
||||
#include "msm_venc.h"
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_driver.h"
|
||||
#include "msm_vidc_vb2.h"
|
||||
#include "msm_vidc_v4l2.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
|
||||
#define MSM_VIDC_DRV_NAME "msm_vidc_driver"
|
||||
/* kernel/msm-4.19 */
|
||||
#define MSM_VIDC_VERSION ((0 << 16) + (4 << 8) + 19)
|
||||
|
||||
#define MAX_EVENTS 30
|
||||
|
||||
bool valid_v4l2_buffer(struct v4l2_buffer *b,
|
||||
struct msm_vidc_inst *inst)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
static int get_poll_flags(struct msm_vidc_inst *inst)
|
||||
{
|
||||
int rc = 0;
|
||||
struct vb2_queue *outq = &inst->bufq[PORT_INPUT].vb2_bufq;
|
||||
struct vb2_queue *capq = &inst->bufq[PORT_OUTPUT].vb2_bufq;
|
||||
struct vb2_buffer *out_vb = NULL;
|
||||
struct vb2_buffer *cap_vb = NULL;
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (v4l2_event_pending(&inst->event_handler))
|
||||
rc |= POLLPRI;
|
||||
|
||||
spin_lock_irqsave(&capq->done_lock, flags);
|
||||
if (!list_empty(&capq->done_list))
|
||||
cap_vb = list_first_entry(&capq->done_list, struct vb2_buffer,
|
||||
done_entry);
|
||||
if (cap_vb && (cap_vb->state == VB2_BUF_STATE_DONE
|
||||
|| cap_vb->state == VB2_BUF_STATE_ERROR))
|
||||
rc |= POLLIN | POLLRDNORM;
|
||||
spin_unlock_irqrestore(&capq->done_lock, flags);
|
||||
|
||||
spin_lock_irqsave(&outq->done_lock, flags);
|
||||
if (!list_empty(&outq->done_list))
|
||||
out_vb = list_first_entry(&outq->done_list, struct vb2_buffer,
|
||||
done_entry);
|
||||
if (out_vb && (out_vb->state == VB2_BUF_STATE_DONE
|
||||
|| out_vb->state == VB2_BUF_STATE_ERROR))
|
||||
rc |= POLLOUT | POLLWRNORM;
|
||||
spin_unlock_irqrestore(&outq->done_lock, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
*/
|
||||
|
||||
int msm_vidc_poll(void *instance, struct file *filp,
|
||||
struct poll_table_struct *wait)
|
||||
{
|
||||
/*
|
||||
struct msm_vidc_inst *inst = instance;
|
||||
struct vb2_queue *outq = NULL;
|
||||
struct vb2_queue *capq = NULL;
|
||||
|
||||
if (!inst)
|
||||
return -EINVAL;
|
||||
|
||||
outq = &inst->bufq[PORT_INPUT].vb2_bufq;
|
||||
capq = &inst->bufq[PORT_OUTPUT].vb2_bufq;
|
||||
|
||||
poll_wait(filp, &inst->event_handler.wait, wait);
|
||||
poll_wait(filp, &capq->done_wq, wait);
|
||||
poll_wait(filp, &outq->done_wq, wait);
|
||||
return get_poll_flags(inst);
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_poll);
|
||||
|
||||
int msm_vidc_querycap(void *instance, struct v4l2_capability *cap)
|
||||
{
|
||||
struct msm_vidc_inst *inst = instance;
|
||||
|
||||
if (!inst || !cap)
|
||||
return -EINVAL;
|
||||
|
||||
strlcpy(cap->driver, MSM_VIDC_DRV_NAME, sizeof(cap->driver));
|
||||
cap->bus_info[0] = 0;
|
||||
cap->version = MSM_VIDC_VERSION;
|
||||
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE |
|
||||
V4L2_CAP_VIDEO_OUTPUT_MPLANE |
|
||||
V4L2_CAP_STREAMING;
|
||||
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
|
||||
|
||||
memset(cap->reserved, 0, sizeof(cap->reserved));
|
||||
|
||||
if (inst->domain == MSM_VIDC_DECODER)
|
||||
strlcpy(cap->card, "msm_vidc_decoder", sizeof(cap->card));
|
||||
else if (inst->domain == MSM_VIDC_ENCODER)
|
||||
strlcpy(cap->card, "msm_vidc_encoder", sizeof(cap->card));
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_querycap);
|
||||
|
||||
int msm_vidc_enum_fmt(void *instance, struct v4l2_fmtdesc *f)
|
||||
{
|
||||
struct msm_vidc_inst *inst = instance;
|
||||
|
||||
if (!inst || !f)
|
||||
return -EINVAL;
|
||||
|
||||
if (inst->domain == MSM_VIDC_DECODER)
|
||||
return 0;//msm_vdec_enum_fmt(instance, f);
|
||||
else if (inst->domain == MSM_VIDC_ENCODER)
|
||||
return 0;//msm_venc_enum_fmt(instance, f);
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_enum_fmt);
|
||||
|
||||
int msm_vidc_query_ctrl(void *instance, struct v4l2_queryctrl *q_ctrl)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_inst *inst = instance;
|
||||
struct v4l2_ctrl *ctrl;
|
||||
|
||||
if (!inst || !q_ctrl) {
|
||||
d_vpr_e("%s: invalid params %pK %pK\n",
|
||||
__func__, inst, q_ctrl);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctrl = v4l2_ctrl_find(&inst->ctrl_handler, q_ctrl->id);
|
||||
if (!ctrl) {
|
||||
s_vpr_e(inst->sid, "%s: get_ctrl failed for id %d\n",
|
||||
__func__, q_ctrl->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
q_ctrl->minimum = ctrl->minimum;
|
||||
q_ctrl->maximum = ctrl->maximum;
|
||||
q_ctrl->default_value = ctrl->default_value;
|
||||
/* remove tier info for HEVC level */
|
||||
if (q_ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_LEVEL) {
|
||||
q_ctrl->minimum &= ~(0xF << 28);
|
||||
q_ctrl->maximum &= ~(0xF << 28);
|
||||
}
|
||||
if (ctrl->type == V4L2_CTRL_TYPE_MENU) {
|
||||
q_ctrl->flags = ~(ctrl->menu_skip_mask);
|
||||
} else {
|
||||
q_ctrl->flags = 0;
|
||||
q_ctrl->step = ctrl->step;
|
||||
}
|
||||
s_vpr_h(inst->sid,
|
||||
"query ctrl: %s: min %d, max %d, default %d step %d flags %#x\n",
|
||||
ctrl->name, q_ctrl->minimum, q_ctrl->maximum,
|
||||
q_ctrl->default_value, q_ctrl->step, q_ctrl->flags);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_query_ctrl);
|
||||
|
||||
int msm_vidc_query_menu(void *instance, struct v4l2_querymenu *qmenu)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_inst *inst = instance;
|
||||
struct v4l2_ctrl *ctrl;
|
||||
|
||||
if (!inst || !qmenu) {
|
||||
d_vpr_e("%s: invalid params %pK %pK\n",
|
||||
__func__, inst, qmenu);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctrl = v4l2_ctrl_find(&inst->ctrl_handler, qmenu->id);
|
||||
if (!ctrl) {
|
||||
s_vpr_e(inst->sid, "%s: get_ctrl failed for id %d\n",
|
||||
__func__, qmenu->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ctrl->type != V4L2_CTRL_TYPE_MENU) {
|
||||
s_vpr_e(inst->sid, "%s: ctrl: %s: type (%d) is not MENU type\n",
|
||||
__func__, ctrl->name, ctrl->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (qmenu->index < ctrl->minimum || qmenu->index > ctrl->maximum)
|
||||
return -EINVAL;
|
||||
|
||||
if (ctrl->menu_skip_mask & (1 << qmenu->index))
|
||||
rc = -EINVAL;
|
||||
|
||||
s_vpr_h(inst->sid,
|
||||
"%s: ctrl: %s: min %d, max %d, menu_skip_mask %#x, qmenu: id %d, index %d, %s\n",
|
||||
__func__, ctrl->name, ctrl->minimum, ctrl->maximum,
|
||||
ctrl->menu_skip_mask, qmenu->id, qmenu->index,
|
||||
rc ? "not supported" : "supported");
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_query_menu);
|
||||
|
||||
int msm_vidc_s_fmt(void *instance, struct v4l2_format *f)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_inst *inst = instance;
|
||||
|
||||
if (!inst || !f)
|
||||
return -EINVAL;
|
||||
|
||||
if (inst->domain == MSM_VIDC_DECODER)
|
||||
rc = 0;//msm_vdec_s_fmt(instance, f);
|
||||
if (inst->domain == MSM_VIDC_ENCODER)
|
||||
rc = 0;//msm_venc_s_fmt(instance, f);
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_s_fmt);
|
||||
|
||||
int msm_vidc_g_fmt(void *instance, struct v4l2_format *f)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_inst *inst = instance;
|
||||
|
||||
if (!inst || !f)
|
||||
return -EINVAL;
|
||||
|
||||
if (inst->domain == MSM_VIDC_DECODER)
|
||||
rc = 0;//msm_vdec_g_fmt(instance, f);
|
||||
if (inst->domain == MSM_VIDC_ENCODER)
|
||||
rc = 0;//msm_venc_g_fmt(instance, f);
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_g_fmt);
|
||||
|
||||
int msm_vidc_s_ctrl(void *instance, struct v4l2_control *control)
|
||||
{
|
||||
struct msm_vidc_inst *inst = instance;
|
||||
|
||||
if (!inst || !control)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;//msm_comm_s_ctrl(instance, control);
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_s_ctrl);
|
||||
|
||||
int msm_vidc_g_ctrl(void *instance, struct v4l2_control *control)
|
||||
{
|
||||
struct msm_vidc_inst *inst = instance;
|
||||
struct v4l2_ctrl *ctrl = NULL;
|
||||
int rc = 0;
|
||||
|
||||
if (!inst || !control)
|
||||
return -EINVAL;
|
||||
|
||||
ctrl = v4l2_ctrl_find(&inst->ctrl_handler, control->id);
|
||||
if (ctrl) {
|
||||
rc = 0;//try_get_ctrl_for_instance(inst, ctrl);
|
||||
if (!rc)
|
||||
control->value = ctrl->val;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_g_ctrl);
|
||||
|
||||
int msm_vidc_reqbufs(void *instance, struct v4l2_requestbuffers *b)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_reqbufs);
|
||||
|
||||
int msm_vidc_qbuf(void *instance, struct media_device *mdev,
|
||||
struct v4l2_buffer *b)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_qbuf);
|
||||
|
||||
int msm_vidc_dqbuf(void *instance, struct v4l2_buffer *b)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_dqbuf);
|
||||
|
||||
int msm_vidc_streamon(void *instance, enum v4l2_buf_type i)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_streamon);
|
||||
|
||||
int msm_vidc_streamoff(void *instance, enum v4l2_buf_type i)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_streamoff);
|
||||
|
||||
int msm_vidc_cmd(void *instance, union msm_v4l2_cmd *cmd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_cmd);
|
||||
|
||||
int msm_vidc_enum_framesizes(void *instance, struct v4l2_frmsizeenum *fsize)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_enum_framesizes);
|
||||
|
||||
int msm_vidc_subscribe_event(void *inst,
|
||||
const struct v4l2_event_subscription *sub)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
|
||||
|
||||
if (!inst || !sub)
|
||||
return -EINVAL;
|
||||
|
||||
rc = v4l2_event_subscribe(&vidc_inst->event_handler,
|
||||
sub, MAX_EVENTS, NULL);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_subscribe_event);
|
||||
|
||||
int msm_vidc_unsubscribe_event(void *inst,
|
||||
const struct v4l2_event_subscription *sub)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
|
||||
|
||||
if (!inst || !sub)
|
||||
return -EINVAL;
|
||||
|
||||
rc = v4l2_event_unsubscribe(&vidc_inst->event_handler, sub);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_unsubscribe_event);
|
||||
|
||||
int msm_vidc_dqevent(void *inst, struct v4l2_event *event)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_inst *vidc_inst = (struct msm_vidc_inst *)inst;
|
||||
|
||||
if (!inst || !event)
|
||||
return -EINVAL;
|
||||
|
||||
rc = v4l2_event_dequeue(&vidc_inst->event_handler, event, false);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_dqevent);
|
||||
|
||||
void *msm_vidc_open(void *vidc_core, u32 session_type)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_inst *inst;
|
||||
struct msm_vidc_core *core;
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
core = vidc_core;
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (session_type != MSM_VIDC_DECODER &&
|
||||
session_type != MSM_VIDC_ENCODER) {
|
||||
d_vpr_e("%s: invalid session_type %d\n",
|
||||
__func__, session_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (core->state == MSM_VIDC_CORE_ERROR) {
|
||||
d_vpr_e("%s: core invalid state\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (core->state == MSM_VIDC_CORE_DEINIT) {
|
||||
rc = msm_vidc_core_init(core);
|
||||
if (rc)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inst = kzalloc(sizeof(*inst), GFP_KERNEL);
|
||||
if (!inst) {
|
||||
d_vpr_e("%s: failed to allocate inst memory\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
inst->core = core;
|
||||
|
||||
rc = msm_vidc_add_session(inst);
|
||||
if (rc) {
|
||||
d_vpr_e("%s: failed to get session id\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s_vpr_i(inst->sid, "Opening video instance: %d\n", session_type);
|
||||
|
||||
kref_init(&inst->kref);
|
||||
INIT_LIST_HEAD(&inst->buffers.input.list);
|
||||
INIT_LIST_HEAD(&inst->buffers.input_meta.list);
|
||||
INIT_LIST_HEAD(&inst->buffers.output.list);
|
||||
INIT_LIST_HEAD(&inst->buffers.output_meta.list);
|
||||
INIT_LIST_HEAD(&inst->buffers.scratch.list);
|
||||
INIT_LIST_HEAD(&inst->buffers.scratch_1.list);
|
||||
INIT_LIST_HEAD(&inst->buffers.scratch_2.list);
|
||||
INIT_LIST_HEAD(&inst->buffers.persist.list);
|
||||
INIT_LIST_HEAD(&inst->buffers.persist_1.list);
|
||||
inst->domain = session_type;
|
||||
inst->state = MSM_VIDC_OPEN;
|
||||
//inst->debugfs_root =
|
||||
// msm_vidc_debugfs_init_inst(inst, core->debugfs_root);
|
||||
|
||||
if (is_decode_session(inst)) {
|
||||
rc = msm_vdec_inst_init(inst);
|
||||
if (rc)
|
||||
goto error;
|
||||
rc = msm_vdec_ctrl_init(inst);
|
||||
if (rc)
|
||||
goto error;
|
||||
} else if (is_encode_session(inst)) {
|
||||
rc = msm_venc_inst_init(inst);
|
||||
if (rc)
|
||||
goto error;
|
||||
rc = msm_venc_ctrl_init(inst);
|
||||
if (rc)
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = msm_vidc_queue_init(inst);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
rc = msm_vidc_setup_event_queue(inst);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
//msm_power_setup(inst);
|
||||
// send cmd to firmware here
|
||||
|
||||
return inst;
|
||||
|
||||
error:
|
||||
msm_vidc_close(inst);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_open);
|
||||
|
||||
int msm_vidc_close(void *instance)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_vidc_close);
|
16
driver/vidc/src/msm_vidc_debug.c
Normal file
16
driver/vidc/src/msm_vidc_debug.c
Normal file
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "msm_vidc_debug.h"
|
||||
|
||||
int msm_vidc_debug = VIDC_HIGH | VIDC_LOW | VIDC_PKT | VIDC_ERR | VIDC_PRINTK |
|
||||
FW_ERROR | FW_FATAL | FW_FTRACE;
|
||||
EXPORT_SYMBOL(msm_vidc_debug);
|
||||
|
||||
bool msm_vidc_lossless_encode = !true;
|
||||
EXPORT_SYMBOL(msm_vidc_lossless_encode);
|
||||
|
||||
bool msm_vidc_syscache_disable = !true;
|
||||
EXPORT_SYMBOL(msm_vidc_syscache_disable);
|
151
driver/vidc/src/msm_vidc_driver.c
Normal file
151
driver/vidc/src/msm_vidc_driver.c
Normal file
@@ -0,0 +1,151 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <media/msm_vidc_utils.h>
|
||||
#include <media/msm_media_info.h>
|
||||
|
||||
#include "msm_vidc_driver.h"
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
#include "venus_hfi.h"
|
||||
|
||||
u32 msm_vidc_convert_color_fmt(u32 v4l2_fmt)
|
||||
{
|
||||
switch (v4l2_fmt) {
|
||||
case V4L2_PIX_FMT_NV12:
|
||||
return COLOR_FMT_NV12;
|
||||
case V4L2_PIX_FMT_NV21:
|
||||
return COLOR_FMT_NV21;
|
||||
case V4L2_PIX_FMT_NV12_512:
|
||||
return COLOR_FMT_NV12_512;
|
||||
case V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS:
|
||||
return COLOR_FMT_P010;
|
||||
case V4L2_PIX_FMT_NV12_UBWC:
|
||||
return COLOR_FMT_NV12_UBWC;
|
||||
case V4L2_PIX_FMT_NV12_TP10_UBWC:
|
||||
return COLOR_FMT_NV12_BPP10_UBWC;
|
||||
case V4L2_PIX_FMT_RGBA8888_UBWC:
|
||||
return COLOR_FMT_RGBA8888_UBWC;
|
||||
default:
|
||||
d_vpr_e(
|
||||
"Invalid v4l2 color fmt FMT : %x, Set default(NV12)",
|
||||
v4l2_fmt);
|
||||
return COLOR_FMT_NV12;
|
||||
}
|
||||
}
|
||||
|
||||
int msm_vidc_setup_event_queue(struct msm_vidc_inst *inst)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vidc_queue_init(struct msm_vidc_inst *inst)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vidc_add_session(struct msm_vidc_inst *inst)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_inst *i;
|
||||
struct msm_vidc_core *core;
|
||||
u32 count = 0;
|
||||
|
||||
if (!inst || !inst->core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
core = inst->core;
|
||||
|
||||
mutex_lock(&core->lock);
|
||||
list_for_each_entry(i, &core->instances, list)
|
||||
count++;
|
||||
|
||||
if (count < MAX_SUPPORTED_INSTANCES) {
|
||||
list_add_tail(&inst->list, &core->instances);
|
||||
} else {
|
||||
d_vpr_e("%s: total sessions %d reached max limit %d\n",
|
||||
__func__, count, MAX_SUPPORTED_INSTANCES);
|
||||
rc = -EINVAL;
|
||||
}
|
||||
mutex_unlock(&core->lock);
|
||||
|
||||
/* assign session_id */
|
||||
inst->session_id = count + 1;
|
||||
inst->sid = inst->session_id;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vidc_core_init(struct msm_vidc_core *core)
|
||||
{
|
||||
int rc;
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&core->lock);
|
||||
if (core->state == MSM_VIDC_CORE_ERROR) {
|
||||
d_vpr_e("%s: core invalid state\n", __func__);
|
||||
rc = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
if (core->state == MSM_VIDC_CORE_INIT) {
|
||||
rc = 0;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
rc = venus_hfi_core_init(core);
|
||||
if (rc) {
|
||||
d_vpr_e("%s: core init failed\n", __func__);
|
||||
core->state = MSM_VIDC_CORE_DEINIT;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
core->state = MSM_VIDC_CORE_INIT;
|
||||
core->smmu_fault_handled = false;
|
||||
core->ssr.trigger = false;
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&core->lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vidc_smmu_fault_handler(struct iommu_domain *domain,
|
||||
struct device *dev, unsigned long iova, int flags, void *data)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int msm_vidc_trigger_ssr(struct msm_vidc_core *core,
|
||||
enum msm_vidc_ssr_trigger_type type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void msm_vidc_ssr_handler(struct work_struct *work)
|
||||
{
|
||||
}
|
||||
|
||||
void msm_vidc_pm_work_handler(struct work_struct *work)
|
||||
{
|
||||
}
|
||||
|
||||
void msm_vidc_fw_unload_handler(struct work_struct *work)
|
||||
{
|
||||
}
|
||||
|
||||
void msm_vidc_batch_handler(struct work_struct *work)
|
||||
{
|
||||
}
|
970
driver/vidc/src/msm_vidc_dt.c
Normal file
970
driver/vidc/src/msm_vidc_dt.c
Normal file
@@ -0,0 +1,970 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/iommu.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/sort.h>
|
||||
|
||||
#include "msm_vidc_dt.h"
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_core.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
#include "msm_vidc_driver.h"
|
||||
|
||||
static size_t get_u32_array_num_elements(struct device_node *np,
|
||||
char *name)
|
||||
{
|
||||
int len;
|
||||
size_t num_elements = 0;
|
||||
|
||||
if (!of_get_property(np, name, &len)) {
|
||||
d_vpr_e("Failed to read %s from device tree\n", name);
|
||||
goto fail_read;
|
||||
}
|
||||
|
||||
num_elements = len / sizeof(u32);
|
||||
if (num_elements <= 0) {
|
||||
d_vpr_e("%s not specified in device tree\n", name);
|
||||
goto fail_read;
|
||||
}
|
||||
return num_elements;
|
||||
|
||||
fail_read:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* msm_vidc_load_u32_table() - load dtsi table entries
|
||||
* @pdev: A pointer to the platform device.
|
||||
* @of_node: A pointer to the device node.
|
||||
* @table_name: A pointer to the dtsi table entry name.
|
||||
* @struct_size: The size of the structure which is nothing but
|
||||
* a single entry in the dtsi table.
|
||||
* @table: A pointer to the table pointer which needs to be
|
||||
* filled by the dtsi table entries.
|
||||
* @num_elements: Number of elements pointer which needs to be filled
|
||||
* with the number of elements in the table.
|
||||
*
|
||||
* This is a generic implementation to load single or multiple array
|
||||
* table from dtsi. The array elements should be of size equal to u32.
|
||||
*
|
||||
* Return: Return '0' for success else appropriate error value.
|
||||
*/
|
||||
static 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)
|
||||
{
|
||||
int rc = 0, num_elemts = 0;
|
||||
u32 *ptbl = NULL;
|
||||
|
||||
if (!of_find_property(of_node, table_name, NULL)) {
|
||||
d_vpr_h("%s not found\n", table_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
num_elemts = get_u32_array_num_elements(of_node, table_name);
|
||||
if (!num_elemts) {
|
||||
d_vpr_e("no elements in %s\n", table_name);
|
||||
return 0;
|
||||
}
|
||||
num_elemts /= struct_size / sizeof(u32);
|
||||
|
||||
ptbl = devm_kzalloc(&pdev->dev, num_elemts * struct_size, GFP_KERNEL);
|
||||
if (!ptbl) {
|
||||
d_vpr_e("Failed to alloc table %s\n", table_name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (of_property_read_u32_array(of_node, table_name, ptbl,
|
||||
num_elemts * struct_size / sizeof(u32))) {
|
||||
d_vpr_e("Failed to read %s\n", table_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*table = ptbl;
|
||||
if (num_elements)
|
||||
*num_elements = num_elemts;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* A comparator to compare loads (needed later on) */
|
||||
static int cmp(const void *a, const void *b)
|
||||
{
|
||||
/* want to sort in reverse so flip the comparison */
|
||||
return ((struct allowed_clock_rates_table *)b)->clock_rate -
|
||||
((struct allowed_clock_rates_table *)a)->clock_rate;
|
||||
}
|
||||
|
||||
static void msm_vidc_free_allowed_clocks_table(struct msm_vidc_dt *dt)
|
||||
{
|
||||
dt->allowed_clks_tbl = NULL;
|
||||
}
|
||||
|
||||
static void msm_vidc_free_reg_table(struct msm_vidc_dt *dt)
|
||||
{
|
||||
dt->reg_set.reg_tbl = NULL;
|
||||
}
|
||||
|
||||
static void msm_vidc_free_qdss_addr_table(struct msm_vidc_dt *dt)
|
||||
{
|
||||
dt->qdss_addr_set.addr_tbl = NULL;
|
||||
}
|
||||
|
||||
static void msm_vidc_free_bus_table(struct msm_vidc_dt *dt)
|
||||
{
|
||||
dt->bus_set.bus_tbl = NULL;
|
||||
dt->bus_set.count = 0;
|
||||
}
|
||||
|
||||
static void msm_vidc_free_buffer_usage_table(struct msm_vidc_dt *dt)
|
||||
{
|
||||
dt->buffer_usage_set.buffer_usage_tbl = NULL;
|
||||
}
|
||||
|
||||
static void msm_vidc_free_regulator_table(struct msm_vidc_dt *dt)
|
||||
{
|
||||
int c = 0;
|
||||
|
||||
for (c = 0; c < dt->regulator_set.count; ++c) {
|
||||
struct regulator_info *rinfo =
|
||||
&dt->regulator_set.regulator_tbl[c];
|
||||
|
||||
rinfo->name = NULL;
|
||||
}
|
||||
|
||||
dt->regulator_set.regulator_tbl = NULL;
|
||||
dt->regulator_set.count = 0;
|
||||
}
|
||||
|
||||
static void msm_vidc_free_clock_table(struct msm_vidc_dt *dt)
|
||||
{
|
||||
dt->clock_set.clock_tbl = NULL;
|
||||
dt->clock_set.count = 0;
|
||||
}
|
||||
|
||||
static int msm_vidc_load_fw_name(struct msm_vidc_core *core)
|
||||
{
|
||||
struct platform_device *pdev = core->pdev;
|
||||
|
||||
return of_property_read_string_index(pdev->dev.of_node,
|
||||
"vidc,firmware-name", 0, &core->dt->fw_name);
|
||||
}
|
||||
|
||||
static int msm_vidc_load_reg_table(struct msm_vidc_core *core)
|
||||
{
|
||||
struct reg_set *reg_set;
|
||||
struct platform_device *pdev = core->pdev;
|
||||
struct msm_vidc_dt *dt = core->dt;
|
||||
int i;
|
||||
int rc = 0;
|
||||
|
||||
if (!of_find_property(pdev->dev.of_node, "qcom,reg-presets", NULL)) {
|
||||
/*
|
||||
* qcom,reg-presets is an optional property. It likely won't be
|
||||
* present if we don't have any register settings to program
|
||||
*/
|
||||
d_vpr_h("reg-presets not found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
reg_set = &dt->reg_set;
|
||||
reg_set->count = get_u32_array_num_elements(pdev->dev.of_node,
|
||||
"qcom,reg-presets");
|
||||
reg_set->count /= sizeof(*reg_set->reg_tbl) / sizeof(u32);
|
||||
|
||||
if (!reg_set->count) {
|
||||
d_vpr_h("no elements in reg set\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
reg_set->reg_tbl = devm_kzalloc(&pdev->dev, reg_set->count *
|
||||
sizeof(*(reg_set->reg_tbl)), GFP_KERNEL);
|
||||
if (!reg_set->reg_tbl) {
|
||||
d_vpr_e("%s: Failed to alloc register table\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (of_property_read_u32_array(pdev->dev.of_node, "qcom,reg-presets",
|
||||
(u32 *)reg_set->reg_tbl, reg_set->count * 3)) {
|
||||
d_vpr_e("Failed to read register table\n");
|
||||
msm_vidc_free_reg_table(core->dt);
|
||||
return -EINVAL;
|
||||
}
|
||||
for (i = 0; i < reg_set->count; i++) {
|
||||
d_vpr_h("reg = %#x, value = %#x, mask = %#x\n",
|
||||
reg_set->reg_tbl[i].reg, reg_set->reg_tbl[i].value,
|
||||
reg_set->reg_tbl[i].mask);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
static int msm_vidc_load_qdss_table(struct msm_vidc_core *core)
|
||||
{
|
||||
struct addr_set *qdss_addr_set;
|
||||
struct platform_device *pdev = core->pdev;
|
||||
struct msm_vidc_dt *dt = core->dt;
|
||||
int i;
|
||||
int rc = 0;
|
||||
|
||||
if (!of_find_property(pdev->dev.of_node, "qcom,qdss-presets", NULL)) {
|
||||
/*
|
||||
* qcom,qdss-presets is an optional property. It likely won't be
|
||||
* present if we don't have any register settings to program
|
||||
*/
|
||||
d_vpr_h("qdss-presets not found\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
qdss_addr_set = &dt->qdss_addr_set;
|
||||
qdss_addr_set->count = get_u32_array_num_elements(pdev->dev.of_node,
|
||||
"qcom,qdss-presets");
|
||||
qdss_addr_set->count /= sizeof(*qdss_addr_set->addr_tbl) / sizeof(u32);
|
||||
|
||||
if (!qdss_addr_set->count) {
|
||||
d_vpr_h("no elements in qdss reg set\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
qdss_addr_set->addr_tbl = devm_kzalloc(&pdev->dev,
|
||||
qdss_addr_set->count * sizeof(*qdss_addr_set->addr_tbl),
|
||||
GFP_KERNEL);
|
||||
if (!qdss_addr_set->addr_tbl) {
|
||||
d_vpr_e("%s: Failed to alloc register table\n", __func__);
|
||||
rc = -ENOMEM;
|
||||
goto err_qdss_addr_tbl;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32_array(pdev->dev.of_node, "qcom,qdss-presets",
|
||||
(u32 *)qdss_addr_set->addr_tbl, qdss_addr_set->count * 2);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to read qdss address table\n");
|
||||
msm_vidc_free_qdss_addr_table(core->dt);
|
||||
rc = -EINVAL;
|
||||
goto err_qdss_addr_tbl;
|
||||
}
|
||||
|
||||
for (i = 0; i < qdss_addr_set->count; i++) {
|
||||
d_vpr_h("qdss addr = %x, value = %x\n",
|
||||
qdss_addr_set->addr_tbl[i].start,
|
||||
qdss_addr_set->addr_tbl[i].size);
|
||||
}
|
||||
err_qdss_addr_tbl:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vidc_load_subcache_info(struct msm_vidc_core *core)
|
||||
{
|
||||
int rc = 0, num_subcaches = 0, c;
|
||||
struct platform_device *pdev = core->pdev;
|
||||
struct msm_vidc_dt *dt = core->dt;
|
||||
struct subcache_set *subcaches = &dt->subcache_set;
|
||||
|
||||
num_subcaches = of_property_count_strings(pdev->dev.of_node,
|
||||
"cache-slice-names");
|
||||
if (num_subcaches <= 0) {
|
||||
d_vpr_h("No subcaches found\n");
|
||||
goto err_load_subcache_table_fail;
|
||||
}
|
||||
|
||||
subcaches->subcache_tbl = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*subcaches->subcache_tbl) * num_subcaches, GFP_KERNEL);
|
||||
if (!subcaches->subcache_tbl) {
|
||||
d_vpr_e("Failed to allocate memory for subcache tbl\n");
|
||||
rc = -ENOMEM;
|
||||
goto err_load_subcache_table_fail;
|
||||
}
|
||||
|
||||
subcaches->count = num_subcaches;
|
||||
d_vpr_h("Found %d subcaches\n", num_subcaches);
|
||||
|
||||
for (c = 0; c < num_subcaches; ++c) {
|
||||
struct subcache_info *vsc = &dt->subcache_set.subcache_tbl[c];
|
||||
|
||||
of_property_read_string_index(pdev->dev.of_node,
|
||||
"cache-slice-names", c, &vsc->name);
|
||||
}
|
||||
|
||||
dt->sys_cache_present = true;
|
||||
|
||||
return 0;
|
||||
|
||||
err_load_subcache_table_fail:
|
||||
dt->sys_cache_present = false;
|
||||
subcaches->count = 0;
|
||||
subcaches->subcache_tbl = NULL;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vidc_load_allowed_clocks_table(
|
||||
struct msm_vidc_core *core)
|
||||
{
|
||||
int rc = 0;
|
||||
struct platform_device *pdev = core->pdev;
|
||||
struct msm_vidc_dt *dt = core->dt;
|
||||
|
||||
if (!of_find_property(pdev->dev.of_node,
|
||||
"qcom,allowed-clock-rates", NULL)) {
|
||||
d_vpr_h("allowed-clock-rates not found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = msm_vidc_load_u32_table(pdev, pdev->dev.of_node,
|
||||
"qcom,allowed-clock-rates",
|
||||
sizeof(*dt->allowed_clks_tbl),
|
||||
(u32 **)&dt->allowed_clks_tbl,
|
||||
&dt->allowed_clks_tbl_size);
|
||||
if (rc) {
|
||||
d_vpr_e("%s: failed to read allowed clocks table\n", __func__);
|
||||
return rc;
|
||||
}
|
||||
|
||||
sort(dt->allowed_clks_tbl, dt->allowed_clks_tbl_size,
|
||||
sizeof(*dt->allowed_clks_tbl), cmp, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_vidc_load_bus_table(struct msm_vidc_core *core)
|
||||
{
|
||||
struct platform_device *pdev = core->pdev;
|
||||
struct msm_vidc_dt *dt = core->dt;
|
||||
struct bus_set *buses = &dt->bus_set;
|
||||
int c = 0, num_buses = 0, rc = 0;
|
||||
u32 *bus_ranges = NULL;
|
||||
|
||||
num_buses = of_property_count_strings(pdev->dev.of_node,
|
||||
"interconnect-names");
|
||||
if (num_buses <= 0) {
|
||||
d_vpr_e("No buses found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buses->count = num_buses;
|
||||
d_vpr_h("Found %d bus interconnects\n", num_buses);
|
||||
|
||||
bus_ranges = kzalloc(2 * num_buses * sizeof(*bus_ranges), GFP_KERNEL);
|
||||
if (!bus_ranges) {
|
||||
d_vpr_e("No memory to read bus ranges\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32_array(pdev->dev.of_node,
|
||||
"qcom,bus-range-kbps", bus_ranges,
|
||||
num_buses * 2);
|
||||
if (rc) {
|
||||
d_vpr_e(
|
||||
"Failed to read bus ranges: defaulting to <0 INT_MAX>\n");
|
||||
for (c = 0; c < num_buses; c++) {
|
||||
bus_ranges[c * 2] = 0;
|
||||
bus_ranges[c * 2 + 1] = INT_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
buses->bus_tbl = devm_kzalloc(&pdev->dev, num_buses *
|
||||
sizeof(*buses->bus_tbl), GFP_KERNEL);
|
||||
if (!buses->bus_tbl) {
|
||||
d_vpr_e("No memory for bus table\n");
|
||||
rc = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (c = 0; c < num_buses; c++) {
|
||||
struct bus_info *bus = &dt->bus_set.bus_tbl[c];
|
||||
|
||||
of_property_read_string_index(pdev->dev.of_node,
|
||||
"interconnect-names", c, &bus->name);
|
||||
|
||||
bus->dev = &pdev->dev;
|
||||
bus->range[0] = bus_ranges[c * 2];
|
||||
bus->range[1] = bus_ranges[c * 2 + 1];
|
||||
|
||||
d_vpr_h("Found bus %s\n", bus->name);
|
||||
}
|
||||
|
||||
exit:
|
||||
kfree(bus_ranges);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* TODO: move this to platform data */
|
||||
static int msm_vidc_load_buffer_usage_table(struct msm_vidc_core *core)
|
||||
{
|
||||
int rc = 0;
|
||||
struct platform_device *pdev = core->pdev;
|
||||
struct msm_vidc_dt *dt = core->dt;
|
||||
struct buffer_usage_set *buffer_usage_set = &dt->buffer_usage_set;
|
||||
|
||||
if (!of_find_property(pdev->dev.of_node,
|
||||
"qcom,buffer-type-tz-usage-table", NULL)) {
|
||||
/*
|
||||
* qcom,buffer-type-tz-usage-table is an optional property. It
|
||||
* likely won't be present if the core doesn't support content
|
||||
* protection
|
||||
*/
|
||||
d_vpr_h("buffer-type-tz-usage-table not found\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer_usage_set->count = get_u32_array_num_elements(
|
||||
pdev->dev.of_node, "qcom,buffer-type-tz-usage-table");
|
||||
buffer_usage_set->count /=
|
||||
sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32);
|
||||
if (!buffer_usage_set->count) {
|
||||
d_vpr_h("no elements in buffer usage set\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer_usage_set->buffer_usage_tbl = devm_kzalloc(&pdev->dev,
|
||||
buffer_usage_set->count *
|
||||
sizeof(*buffer_usage_set->buffer_usage_tbl),
|
||||
GFP_KERNEL);
|
||||
if (!buffer_usage_set->buffer_usage_tbl) {
|
||||
d_vpr_e("%s: Failed to alloc buffer usage table\n",
|
||||
__func__);
|
||||
rc = -ENOMEM;
|
||||
goto err_load_buf_usage;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32_array(pdev->dev.of_node,
|
||||
"qcom,buffer-type-tz-usage-table",
|
||||
(u32 *)buffer_usage_set->buffer_usage_tbl,
|
||||
buffer_usage_set->count *
|
||||
sizeof(*buffer_usage_set->buffer_usage_tbl) / sizeof(u32));
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to read buffer usage table\n");
|
||||
goto err_load_buf_usage;
|
||||
}
|
||||
|
||||
return 0;
|
||||
err_load_buf_usage:
|
||||
msm_vidc_free_buffer_usage_table(core->dt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vidc_load_regulator_table(struct msm_vidc_core *core)
|
||||
{
|
||||
int rc = 0;
|
||||
struct platform_device *pdev = core->pdev;
|
||||
struct msm_vidc_dt *dt = core->dt;
|
||||
struct regulator_set *regulators = &dt->regulator_set;
|
||||
struct device_node *domains_parent_node = NULL;
|
||||
struct property *domains_property = NULL;
|
||||
int reg_count = 0;
|
||||
|
||||
regulators->count = 0;
|
||||
regulators->regulator_tbl = NULL;
|
||||
|
||||
domains_parent_node = pdev->dev.of_node;
|
||||
for_each_property_of_node(domains_parent_node, domains_property) {
|
||||
const char *search_string = "-supply";
|
||||
char *supply;
|
||||
bool matched = false;
|
||||
|
||||
/* check if current property is possibly a regulator */
|
||||
supply = strnstr(domains_property->name, search_string,
|
||||
strlen(domains_property->name) + 1);
|
||||
matched = supply && (*(supply + strlen(search_string)) == '\0');
|
||||
if (!matched)
|
||||
continue;
|
||||
|
||||
reg_count++;
|
||||
}
|
||||
|
||||
regulators->regulator_tbl = devm_kzalloc(&pdev->dev,
|
||||
sizeof(*regulators->regulator_tbl) *
|
||||
reg_count, GFP_KERNEL);
|
||||
|
||||
if (!regulators->regulator_tbl) {
|
||||
rc = -ENOMEM;
|
||||
d_vpr_e("Failed to alloc memory for regulator table\n");
|
||||
goto err_reg_tbl_alloc;
|
||||
}
|
||||
|
||||
for_each_property_of_node(domains_parent_node, domains_property) {
|
||||
const char *search_string = "-supply";
|
||||
char *supply;
|
||||
bool matched = false;
|
||||
struct device_node *regulator_node = NULL;
|
||||
struct regulator_info *rinfo = NULL;
|
||||
|
||||
/* check if current property is possibly a regulator */
|
||||
supply = strnstr(domains_property->name, search_string,
|
||||
strlen(domains_property->name) + 1);
|
||||
matched = supply && (supply[strlen(search_string)] == '\0');
|
||||
if (!matched)
|
||||
continue;
|
||||
|
||||
/* make sure prop isn't being misused */
|
||||
regulator_node = of_parse_phandle(domains_parent_node,
|
||||
domains_property->name, 0);
|
||||
if (IS_ERR(regulator_node)) {
|
||||
d_vpr_e("%s is not a phandle\n",
|
||||
domains_property->name);
|
||||
continue;
|
||||
}
|
||||
regulators->count++;
|
||||
|
||||
/* populate regulator info */
|
||||
rinfo = ®ulators->regulator_tbl[regulators->count - 1];
|
||||
rinfo->name = devm_kzalloc(&pdev->dev,
|
||||
(supply - domains_property->name) + 1, GFP_KERNEL);
|
||||
if (!rinfo->name) {
|
||||
rc = -ENOMEM;
|
||||
d_vpr_e("Failed to alloc memory for regulator name\n");
|
||||
goto err_reg_name_alloc;
|
||||
}
|
||||
strlcpy(rinfo->name, domains_property->name,
|
||||
(supply - domains_property->name) + 1);
|
||||
|
||||
rinfo->has_hw_power_collapse = of_property_read_bool(
|
||||
regulator_node, "qcom,support-hw-trigger");
|
||||
|
||||
d_vpr_h("Found regulator %s: h/w collapse = %s\n",
|
||||
rinfo->name,
|
||||
rinfo->has_hw_power_collapse ? "yes" : "no");
|
||||
}
|
||||
|
||||
if (!regulators->count)
|
||||
d_vpr_h("No regulators found");
|
||||
|
||||
return 0;
|
||||
|
||||
err_reg_name_alloc:
|
||||
err_reg_tbl_alloc:
|
||||
msm_vidc_free_regulator_table(core->dt);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vidc_load_clock_table(struct msm_vidc_core *core)
|
||||
{
|
||||
int rc = 0, num_clocks = 0, c = 0;
|
||||
struct platform_device *pdev = core->pdev;
|
||||
struct msm_vidc_dt *dt = core->dt;
|
||||
int *clock_props = NULL;
|
||||
struct clock_set *clocks = &dt->clock_set;
|
||||
|
||||
num_clocks = of_property_count_strings(pdev->dev.of_node,
|
||||
"clock-names");
|
||||
if (num_clocks <= 0) {
|
||||
d_vpr_h("No clocks found\n");
|
||||
clocks->count = 0;
|
||||
rc = 0;
|
||||
goto err_load_clk_table_fail;
|
||||
}
|
||||
|
||||
clock_props = devm_kzalloc(&pdev->dev, num_clocks *
|
||||
sizeof(*clock_props), GFP_KERNEL);
|
||||
if (!clock_props) {
|
||||
d_vpr_e("No memory to read clock properties\n");
|
||||
rc = -ENOMEM;
|
||||
goto err_load_clk_table_fail;
|
||||
}
|
||||
|
||||
rc = of_property_read_u32_array(pdev->dev.of_node,
|
||||
"qcom,clock-configs", clock_props,
|
||||
num_clocks);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to read clock properties: %d\n", rc);
|
||||
goto err_load_clk_prop_fail;
|
||||
}
|
||||
|
||||
clocks->clock_tbl = devm_kzalloc(&pdev->dev, sizeof(*clocks->clock_tbl)
|
||||
* num_clocks, GFP_KERNEL);
|
||||
if (!clocks->clock_tbl) {
|
||||
d_vpr_e("Failed to allocate memory for clock tbl\n");
|
||||
rc = -ENOMEM;
|
||||
goto err_load_clk_prop_fail;
|
||||
}
|
||||
|
||||
clocks->count = num_clocks;
|
||||
d_vpr_h("Found %d clocks\n", num_clocks);
|
||||
|
||||
for (c = 0; c < num_clocks; ++c) {
|
||||
struct clock_info *vc = &dt->clock_set.clock_tbl[c];
|
||||
|
||||
of_property_read_string_index(pdev->dev.of_node,
|
||||
"clock-names", c, &vc->name);
|
||||
|
||||
if (clock_props[c] & CLOCK_PROP_HAS_SCALING) {
|
||||
vc->has_scaling = true;
|
||||
} else {
|
||||
vc->has_scaling = false;
|
||||
}
|
||||
|
||||
if (clock_props[c] & CLOCK_PROP_HAS_MEM_RETENTION)
|
||||
vc->has_mem_retention = true;
|
||||
else
|
||||
vc->has_mem_retention = false;
|
||||
|
||||
d_vpr_h("Found clock %s: scale-able = %s\n", vc->name,
|
||||
vc->has_scaling ? "yes" : "no");
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
|
||||
err_load_clk_prop_fail:
|
||||
err_load_clk_table_fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vidc_load_reset_table(struct msm_vidc_core *core)
|
||||
{
|
||||
struct platform_device *pdev = core->pdev;
|
||||
struct msm_vidc_dt *dt = core->dt;
|
||||
struct reset_set *rst = &dt->reset_set;
|
||||
int num_clocks = 0, c = 0;
|
||||
|
||||
num_clocks = of_property_count_strings(pdev->dev.of_node,
|
||||
"reset-names");
|
||||
if (num_clocks <= 0) {
|
||||
d_vpr_h("No reset clocks found\n");
|
||||
rst->count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rst->reset_tbl = devm_kcalloc(&pdev->dev, num_clocks,
|
||||
sizeof(*rst->reset_tbl), GFP_KERNEL);
|
||||
if (!rst->reset_tbl)
|
||||
return -ENOMEM;
|
||||
|
||||
rst->count = num_clocks;
|
||||
d_vpr_h("Found %d reset clocks\n", num_clocks);
|
||||
|
||||
for (c = 0; c < num_clocks; ++c) {
|
||||
struct reset_info *rc = &dt->reset_set.reset_tbl[c];
|
||||
|
||||
of_property_read_string_index(pdev->dev.of_node,
|
||||
"reset-names", c, &rc->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_decide_dt_node(struct msm_vidc_core *core)
|
||||
{
|
||||
int rc = 0;
|
||||
struct platform_device *pdev = core->pdev;
|
||||
u32 sku_index = 0;
|
||||
|
||||
rc = of_property_read_u32(pdev->dev.of_node, "sku-index",
|
||||
&sku_index);
|
||||
if (rc) {
|
||||
d_vpr_h("'sku_index' not found in node\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_vidc_read_resources_from_dt(struct platform_device *pdev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_core *core;
|
||||
struct msm_vidc_dt *dt;
|
||||
struct resource *kres;
|
||||
|
||||
if (!pdev) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
core = dev_get_drvdata(&pdev->dev);
|
||||
if (!core || !core->dt) {
|
||||
d_vpr_e("%s: core not found in device %s",
|
||||
dev_name(&pdev->dev));
|
||||
return -EINVAL;
|
||||
}
|
||||
dt = core->dt;
|
||||
|
||||
rc = msm_decide_dt_node(core);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
INIT_LIST_HEAD(&dt->context_banks);
|
||||
|
||||
kres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dt->register_base = kres ? kres->start : -1;
|
||||
dt->register_size = kres ? (kres->end + 1 - kres->start) : -1;
|
||||
|
||||
kres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
dt->irq = kres ? kres->start : -1;
|
||||
|
||||
rc = msm_vidc_load_fw_name(core);
|
||||
if (rc)
|
||||
d_vpr_e("%s: failed to load fw name, rc %d, using default fw\n",
|
||||
__func__, rc);
|
||||
|
||||
rc = msm_vidc_load_subcache_info(core);
|
||||
if (rc)
|
||||
d_vpr_e("Failed to load subcache info: %d\n", rc);
|
||||
|
||||
rc = msm_vidc_load_qdss_table(core);
|
||||
if (rc)
|
||||
d_vpr_e("Failed to load qdss reg table: %d\n", rc);
|
||||
|
||||
rc = msm_vidc_load_reg_table(core);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to load reg table: %d\n", rc);
|
||||
goto err_load_reg_table;
|
||||
}
|
||||
|
||||
// TODO: move this table to platform
|
||||
rc = msm_vidc_load_buffer_usage_table(core);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to load buffer usage table: %d\n", rc);
|
||||
goto err_load_buffer_usage_table;
|
||||
}
|
||||
|
||||
rc = msm_vidc_load_regulator_table(core);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to load list of regulators %d\n", rc);
|
||||
goto err_load_regulator_table;
|
||||
}
|
||||
|
||||
rc = msm_vidc_load_bus_table(core);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to load bus table: %d\n", rc);
|
||||
goto err_load_bus_table;
|
||||
}
|
||||
|
||||
rc = msm_vidc_load_clock_table(core);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to load clock table: %d\n", rc);
|
||||
goto err_load_clock_table;
|
||||
}
|
||||
|
||||
// TODO: move this table to platform
|
||||
rc = msm_vidc_load_allowed_clocks_table(core);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to load allowed clocks table: %d\n", rc);
|
||||
goto err_load_allowed_clocks_table;
|
||||
}
|
||||
|
||||
rc = msm_vidc_load_reset_table(core);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to load reset table: %d\n", rc);
|
||||
goto err_load_reset_table;
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
||||
err_load_reset_table:
|
||||
msm_vidc_free_allowed_clocks_table(core->dt);
|
||||
err_load_allowed_clocks_table:
|
||||
msm_vidc_free_clock_table(core->dt);
|
||||
err_load_clock_table:
|
||||
msm_vidc_free_bus_table(core->dt);
|
||||
err_load_bus_table:
|
||||
msm_vidc_free_regulator_table(core->dt);
|
||||
err_load_regulator_table:
|
||||
msm_vidc_free_buffer_usage_table(core->dt);
|
||||
err_load_buffer_usage_table:
|
||||
msm_vidc_free_reg_table(core->dt);
|
||||
err_load_reg_table:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vidc_setup_context_bank(struct msm_vidc_core *core,
|
||||
struct context_bank_info *cb, struct device *dev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct bus_type *bus;
|
||||
|
||||
if (!core || !dev || !cb) {
|
||||
d_vpr_e("%s: Invalid Input params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
cb->dev = dev;
|
||||
|
||||
bus = cb->dev->bus;
|
||||
if (IS_ERR_OR_NULL(bus)) {
|
||||
d_vpr_e("%s: failed to get bus type\n", __func__);
|
||||
rc = PTR_ERR(bus) ? PTR_ERR(bus) : -ENODEV;
|
||||
goto remove_cb;
|
||||
}
|
||||
|
||||
cb->domain = iommu_get_domain_for_dev(cb->dev);
|
||||
|
||||
/*
|
||||
* configure device segment size and segment boundary to ensure
|
||||
* iommu mapping returns one mapping (which is required for partial
|
||||
* cache operations)
|
||||
*/
|
||||
if (!dev->dma_parms)
|
||||
dev->dma_parms =
|
||||
devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL);
|
||||
dma_set_max_seg_size(dev, (unsigned int)DMA_BIT_MASK(32));
|
||||
dma_set_seg_boundary(dev, (unsigned long)DMA_BIT_MASK(64));
|
||||
|
||||
d_vpr_h("Attached %s and created mapping\n", dev_name(dev));
|
||||
d_vpr_h(
|
||||
"Context bank: %s, buffer_type: %#x, is_secure: %d, address range start: %#x, size: %#x, dev: %pK, domain: %pK",
|
||||
cb->name, cb->buffer_type, cb->is_secure, cb->addr_range.start,
|
||||
cb->addr_range.size, cb->dev, cb->domain);
|
||||
|
||||
remove_cb:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vidc_populate_context_bank(struct device *dev,
|
||||
struct msm_vidc_core *core)
|
||||
{
|
||||
int rc = 0;
|
||||
struct context_bank_info *cb = NULL;
|
||||
struct device_node *np = NULL;
|
||||
|
||||
if (!dev || !core || !core->dt) {
|
||||
d_vpr_e("%s: invalid inputs\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
np = dev->of_node;
|
||||
cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL);
|
||||
if (!cb) {
|
||||
d_vpr_e("%s: Failed to allocate cb\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&cb->list);
|
||||
list_add_tail(&cb->list, &core->dt->context_banks);
|
||||
|
||||
rc = of_property_read_string(np, "label", &cb->name);
|
||||
if (rc) {
|
||||
d_vpr_h("Failed to read cb label from device tree\n");
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
d_vpr_h("%s: context bank has name %s\n", __func__, cb->name);
|
||||
rc = of_property_read_u32_array(np, "virtual-addr-pool",
|
||||
(u32 *)&cb->addr_range, 2);
|
||||
if (rc) {
|
||||
d_vpr_e("Could not read addr pool: context bank: %s %d\n",
|
||||
cb->name, rc);
|
||||
goto err_setup_cb;
|
||||
}
|
||||
|
||||
cb->is_secure = of_property_read_bool(np, "qcom,secure-context-bank");
|
||||
d_vpr_h("context bank %s: secure = %d\n",
|
||||
cb->name, cb->is_secure);
|
||||
|
||||
/* setup buffer type for each sub device*/
|
||||
rc = of_property_read_u32(np, "buffer-types", &cb->buffer_type);
|
||||
if (rc) {
|
||||
d_vpr_e("failed to load buffer_type info %d\n", rc);
|
||||
rc = -ENOENT;
|
||||
goto err_setup_cb;
|
||||
}
|
||||
d_vpr_h("context bank %s address start %x size %x buffer_type %x\n",
|
||||
cb->name, cb->addr_range.start,
|
||||
cb->addr_range.size, cb->buffer_type);
|
||||
|
||||
rc = msm_vidc_setup_context_bank(core, cb, dev);
|
||||
if (rc) {
|
||||
d_vpr_e("Cannot setup context bank %d\n", rc);
|
||||
goto err_setup_cb;
|
||||
}
|
||||
|
||||
iommu_set_fault_handler(cb->domain,
|
||||
msm_vidc_smmu_fault_handler, (void *)core);
|
||||
|
||||
return 0;
|
||||
|
||||
err_setup_cb:
|
||||
list_del(&cb->list);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vidc_read_context_bank_resources_from_dt(struct platform_device *pdev)
|
||||
{
|
||||
struct msm_vidc_core *core;
|
||||
int rc = 0;
|
||||
|
||||
if (!pdev) {
|
||||
d_vpr_e("Invalid platform device\n");
|
||||
return -EINVAL;
|
||||
} else if (!pdev->dev.parent) {
|
||||
d_vpr_e("Failed to find a parent for %s\n",
|
||||
dev_name(&pdev->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
core = dev_get_drvdata(pdev->dev.parent);
|
||||
if (!core) {
|
||||
d_vpr_e("Failed to find cookie in parent device %s",
|
||||
dev_name(pdev->dev.parent));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = msm_vidc_populate_context_bank(&pdev->dev, core);
|
||||
if (rc)
|
||||
d_vpr_e("Failed to probe context bank\n");
|
||||
else
|
||||
d_vpr_h("Successfully probed context bank\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void msm_vidc_deinit_dt(struct platform_device *pdev)
|
||||
{
|
||||
struct msm_vidc_core *core;
|
||||
|
||||
if (!pdev) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
core = dev_get_drvdata(&pdev->dev);
|
||||
if (!core) {
|
||||
d_vpr_e("%s: core not found in device %s",
|
||||
dev_name(&pdev->dev));
|
||||
return;
|
||||
} else if (!core->dt) {
|
||||
d_vpr_e("%s: invalid dt in device %s",
|
||||
dev_name(&pdev->dev));
|
||||
return;
|
||||
}
|
||||
|
||||
msm_vidc_free_clock_table(core->dt);
|
||||
msm_vidc_free_regulator_table(core->dt);
|
||||
msm_vidc_free_allowed_clocks_table(core->dt);
|
||||
msm_vidc_free_reg_table(core->dt);
|
||||
msm_vidc_free_qdss_addr_table(core->dt);
|
||||
msm_vidc_free_bus_table(core->dt);
|
||||
msm_vidc_free_buffer_usage_table(core->dt);
|
||||
}
|
||||
|
||||
int msm_vidc_init_dt(struct platform_device *pdev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_dt *dt;
|
||||
struct msm_vidc_core *core;
|
||||
|
||||
if (!pdev) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
core = dev_get_drvdata(&pdev->dev);
|
||||
if (!core) {
|
||||
d_vpr_e("%s: core not found in device %s",
|
||||
dev_name(&pdev->dev));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dt = kzalloc(sizeof(struct msm_vidc_dt), GFP_KERNEL);
|
||||
if (!dt)
|
||||
return -ENOMEM;
|
||||
|
||||
core->dt = dt;
|
||||
dt->core = core;
|
||||
|
||||
rc = msm_vidc_read_resources_from_dt(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
407
driver/vidc/src/msm_vidc_memory.c
Normal file
407
driver/vidc/src/msm_vidc_memory.c
Normal file
@@ -0,0 +1,407 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/msm_ion.h>
|
||||
#include <linux/ion.h>
|
||||
|
||||
#include "msm_vidc_memory.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_dt.h"
|
||||
#include "msm_vidc_core.h"
|
||||
|
||||
|
||||
static int get_ion_secure_flag(enum msm_vidc_buffer_region region)
|
||||
{
|
||||
u32 ion_flag = 0;
|
||||
|
||||
switch (region) {
|
||||
case MSM_VIDC_SECURE_PIXEL:
|
||||
ion_flag = ION_FLAG_CP_PIXEL;
|
||||
break;
|
||||
case MSM_VIDC_SECURE_NONPIXEL:
|
||||
ion_flag = ION_FLAG_CP_NON_PIXEL;
|
||||
break;
|
||||
case MSM_VIDC_SECURE_BITSTREAM:
|
||||
ion_flag = ION_FLAG_CP_BITSTREAM;
|
||||
break;
|
||||
default:
|
||||
d_vpr_e("invalid secure region : %#x\n", region);
|
||||
}
|
||||
|
||||
return ion_flag;
|
||||
}
|
||||
|
||||
struct context_bank_info *get_context_bank(struct msm_vidc_core *core,
|
||||
enum msm_vidc_buffer_region region)
|
||||
{
|
||||
char *name;
|
||||
struct context_bank_info *cb = NULL, *match = NULL;
|
||||
|
||||
switch (region) {
|
||||
case MSM_VIDC_NON_SECURE:
|
||||
name = "venus_ns";
|
||||
break;
|
||||
case MSM_VIDC_SECURE_PIXEL:
|
||||
name = "venus_sec_pixel";
|
||||
break;
|
||||
case MSM_VIDC_SECURE_NONPIXEL:
|
||||
name = "venus_sec_non_pixel";
|
||||
break;
|
||||
case MSM_VIDC_SECURE_BITSTREAM:
|
||||
name = "venus_sec_bitstream";
|
||||
break;
|
||||
default:
|
||||
d_vpr_e("invalid region : %#x\n", region);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry(cb, &core->dt->context_banks, list) {
|
||||
if (!strcmp(cb->name, name)) {
|
||||
match = cb;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match)
|
||||
d_vpr_e("cb not found for region %#x\n", region);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
struct dma_buf *msm_vidc_memory_get_dmabuf(int fd)
|
||||
{
|
||||
struct dma_buf *dmabuf;
|
||||
|
||||
dmabuf = dma_buf_get(fd);
|
||||
if (IS_ERR_OR_NULL(dmabuf)) {
|
||||
d_vpr_e("Failed to get dmabuf for %d, error %ld\n",
|
||||
fd, PTR_ERR(dmabuf));
|
||||
dmabuf = NULL;
|
||||
}
|
||||
|
||||
return dmabuf;
|
||||
}
|
||||
|
||||
void msm_vidc_memory_put_dmabuf(void *dmabuf)
|
||||
{
|
||||
if (!dmabuf) {
|
||||
d_vpr_e("%s: NULL dmabuf\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
dma_buf_put((struct dma_buf *)dmabuf);
|
||||
}
|
||||
|
||||
int msm_vidc_memory_map(struct msm_vidc_core *core, struct msm_vidc_map *map)
|
||||
{
|
||||
int rc = 0;
|
||||
struct dma_buf_attachment *attach = NULL;
|
||||
struct sg_table *table = NULL;
|
||||
struct context_bank_info *cb = NULL;
|
||||
|
||||
if (!core || !map) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (map->refcount) {
|
||||
map->refcount++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cb = get_context_bank(core, map->region);
|
||||
if (!cb) {
|
||||
d_vpr_e("%s: Failed to get context bank device\n",
|
||||
__func__);
|
||||
rc = -EIO;
|
||||
goto error_cb;
|
||||
}
|
||||
|
||||
/* Prepare a dma buf for dma on the given device */
|
||||
attach = dma_buf_attach(map->dmabuf, cb->dev);
|
||||
if (IS_ERR_OR_NULL(attach)) {
|
||||
rc = PTR_ERR(attach) ? PTR_ERR(attach) : -ENOMEM;
|
||||
d_vpr_e("Failed to attach dmabuf\n");
|
||||
goto error_attach;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 (core->dt->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;
|
||||
d_vpr_e("Failed to map table\n");
|
||||
goto error_table;
|
||||
}
|
||||
if (!table->sgl) {
|
||||
d_vpr_e("sgl is NULL\n");
|
||||
rc = -ENOMEM;
|
||||
goto error_sg;
|
||||
}
|
||||
|
||||
map->device_addr = table->sgl->dma_address;
|
||||
map->table = table;
|
||||
map->attach = attach;
|
||||
map->refcount++;
|
||||
return 0;
|
||||
|
||||
error_sg:
|
||||
dma_buf_unmap_attachment(attach, table, DMA_BIDIRECTIONAL);
|
||||
error_table:
|
||||
dma_buf_detach(map->dmabuf, attach);
|
||||
error_attach:
|
||||
error_cb:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vidc_memory_unmap(struct msm_vidc_core *core, struct msm_vidc_map *map)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!core || !map) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (map->refcount) {
|
||||
map->refcount--;
|
||||
} else {
|
||||
d_vpr_e("unmap called while refcount is zero already\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (map->refcount)
|
||||
goto exit;
|
||||
|
||||
dma_buf_unmap_attachment(map->attach, map->table, DMA_BIDIRECTIONAL);
|
||||
dma_buf_detach(map->dmabuf, map->attach);
|
||||
|
||||
map->device_addr = 0x0;
|
||||
map->dmabuf = NULL;
|
||||
map->attach = NULL;
|
||||
map->table = NULL;
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vidc_memory_alloc(struct msm_vidc_core *core, struct msm_vidc_alloc *mem)
|
||||
{
|
||||
int rc = 0;
|
||||
int ion_flags = 0;
|
||||
int ion_secure_flag = 0;
|
||||
unsigned long heap_mask = 0;
|
||||
int size = 0;
|
||||
|
||||
if (!mem) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size = ALIGN(mem->size, SZ_4K);
|
||||
|
||||
if (mem->cached)
|
||||
ion_flags |= ION_FLAG_CACHED;
|
||||
|
||||
if (mem->secure) {
|
||||
ion_secure_flag = get_ion_secure_flag(mem->region);
|
||||
ion_flags |= ION_FLAG_SECURE | ion_secure_flag;
|
||||
heap_mask = ION_HEAP(ION_SECURE_HEAP_ID);
|
||||
} else {
|
||||
heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID);
|
||||
}
|
||||
|
||||
mem->dmabuf = ion_alloc(size, heap_mask, ion_flags);
|
||||
if (IS_ERR_OR_NULL(mem->dmabuf)) {
|
||||
d_vpr_e("%s: ion alloc failed\n", __func__);
|
||||
mem->dmabuf = NULL;
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (mem->map_kernel) {
|
||||
dma_buf_begin_cpu_access(mem->dmabuf, DMA_BIDIRECTIONAL);
|
||||
mem->kvaddr = dma_buf_vmap(mem->dmabuf);
|
||||
if (!mem->kvaddr) {
|
||||
d_vpr_e("%s: kernel map failed\n", __func__);
|
||||
rc = -EIO;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
d_vpr_h(
|
||||
"%s: dmabuf = %pK, size = %d, kvaddr = %pK, buffer_type = %#x\n",
|
||||
__func__, mem->dmabuf, mem->size,
|
||||
mem->kvaddr, mem->buffer_type);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
msm_vidc_memory_free(core, mem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vidc_memory_free(struct msm_vidc_core *core, struct msm_vidc_alloc *mem)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!mem || !mem->dmabuf) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
d_vpr_h(
|
||||
"%s: dmabuf = %pK, size = %d, kvaddr = %pK, buffer_type = %#x\n",
|
||||
__func__, mem->dmabuf, mem->size,
|
||||
mem->kvaddr, mem->buffer_type);
|
||||
|
||||
if (mem->kvaddr) {
|
||||
dma_buf_vunmap(mem->dmabuf, mem->kvaddr);
|
||||
mem->kvaddr = NULL;
|
||||
dma_buf_end_cpu_access(mem->dmabuf, DMA_BIDIRECTIONAL);
|
||||
}
|
||||
|
||||
if (mem->dmabuf) {
|
||||
dma_buf_put(mem->dmabuf);
|
||||
mem->dmabuf = NULL;
|
||||
}
|
||||
|
||||
return rc;
|
||||
};
|
||||
/*
|
||||
int msm_memory_cache_operations(struct dma_buf *dbuf,
|
||||
enum smem_cache_ops cache_op, unsigned long offset,
|
||||
unsigned long size, u32 sid)
|
||||
{
|
||||
int rc = 0;
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (!dbuf) {
|
||||
s_vpr_e(sid, "%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = dma_buf_get_flags(dbuf, &flags);
|
||||
if (rc) {
|
||||
s_vpr_e(sid, "%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:
|
||||
s_vpr_e(sid, "%s: cache (%d) operation not supported\n",
|
||||
__func__, cache_op);
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_smem_memory_prefetch(struct msm_vidc_inst *inst)
|
||||
{
|
||||
int i, rc = 0;
|
||||
struct memory_regions *vidc_regions = NULL;
|
||||
struct ion_prefetch_region ion_region[MEMORY_REGIONS_MAX];
|
||||
|
||||
if (!inst) {
|
||||
d_vpr_e("%s: invalid parameters\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vidc_regions = &inst->regions;
|
||||
if (vidc_regions->num_regions > MEMORY_REGIONS_MAX) {
|
||||
s_vpr_e(inst->sid, "%s: invalid num_regions %d, max %d\n",
|
||||
__func__, vidc_regions->num_regions,
|
||||
MEMORY_REGIONS_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(ion_region, 0, sizeof(ion_region));
|
||||
for (i = 0; i < vidc_regions->num_regions; i++) {
|
||||
ion_region[i].size = vidc_regions->region[i].size;
|
||||
ion_region[i].vmid = vidc_regions->region[i].vmid;
|
||||
}
|
||||
|
||||
rc = msm_ion_heap_prefetch(ION_SECURE_HEAP_ID, ion_region,
|
||||
vidc_regions->num_regions);
|
||||
if (rc)
|
||||
s_vpr_e(inst->sid, "%s: prefetch failed, ret: %d\n",
|
||||
__func__, rc);
|
||||
else
|
||||
s_vpr_l(inst->sid, "%s: prefetch succeeded\n", __func__);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_smem_memory_drain(struct msm_vidc_inst *inst)
|
||||
{
|
||||
int i, rc = 0;
|
||||
struct memory_regions *vidc_regions = NULL;
|
||||
struct ion_prefetch_region ion_region[MEMORY_REGIONS_MAX];
|
||||
|
||||
if (!inst) {
|
||||
d_vpr_e("%s: invalid parameters\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vidc_regions = &inst->regions;
|
||||
if (vidc_regions->num_regions > MEMORY_REGIONS_MAX) {
|
||||
s_vpr_e(inst->sid, "%s: invalid num_regions %d, max %d\n",
|
||||
__func__, vidc_regions->num_regions,
|
||||
MEMORY_REGIONS_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(ion_region, 0, sizeof(ion_region));
|
||||
for (i = 0; i < vidc_regions->num_regions; i++) {
|
||||
ion_region[i].size = vidc_regions->region[i].size;
|
||||
ion_region[i].vmid = vidc_regions->region[i].vmid;
|
||||
}
|
||||
|
||||
rc = msm_ion_heap_drain(ION_SECURE_HEAP_ID, ion_region,
|
||||
vidc_regions->num_regions);
|
||||
if (rc)
|
||||
s_vpr_e(inst->sid, "%s: drain failed, ret: %d\n", __func__, rc);
|
||||
else
|
||||
s_vpr_l(inst->sid, "%s: drain succeeded\n", __func__);
|
||||
|
||||
return rc;
|
||||
}
|
||||
*/
|
133
driver/vidc/src/msm_vidc_platform.c
Normal file
133
driver/vidc/src/msm_vidc_platform.c
Normal file
@@ -0,0 +1,133 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include "msm_vidc_waipio.h"
|
||||
|
||||
#include "msm_vidc_platform.h"
|
||||
#include "msm_vidc_iris2.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
#include "msm_vidc_v4l2.h"
|
||||
#include "msm_vidc_vb2.h"
|
||||
|
||||
|
||||
static struct v4l2_file_operations msm_v4l2_file_operations = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = msm_v4l2_open,
|
||||
.release = msm_v4l2_close,
|
||||
.unlocked_ioctl = video_ioctl2,
|
||||
.poll = msm_v4l2_poll,
|
||||
};
|
||||
|
||||
static struct v4l2_ioctl_ops msm_v4l2_ioctl_ops = {
|
||||
.vidioc_querycap = msm_v4l2_querycap,
|
||||
.vidioc_enum_fmt_vid_cap = msm_v4l2_enum_fmt,
|
||||
.vidioc_enum_fmt_vid_out = msm_v4l2_enum_fmt,
|
||||
.vidioc_enum_framesizes = msm_v4l2_enum_framesizes,
|
||||
.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_querymenu = msm_v4l2_querymenu,
|
||||
.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,
|
||||
};
|
||||
|
||||
static struct v4l2_ctrl_ops msm_v4l2_ctrl_ops = {
|
||||
//.s_ctrl = msm_vidc_s_ctrl,
|
||||
};
|
||||
|
||||
static struct vb2_ops msm_vb2_ops = {
|
||||
.queue_setup = msm_vidc_queue_setup,
|
||||
.start_streaming = msm_vidc_start_streaming,
|
||||
.buf_queue = msm_vidc_buf_queue,
|
||||
.buf_cleanup = msm_vidc_buf_cleanup,
|
||||
.stop_streaming = msm_vidc_stop_streaming,
|
||||
};
|
||||
|
||||
static struct vb2_mem_ops msm_vb2_mem_ops = {
|
||||
.get_userptr = msm_vb2_get_userptr,
|
||||
.put_userptr = msm_vb2_put_userptr,
|
||||
};
|
||||
|
||||
static int msm_vidc_init_ops(struct msm_vidc_core *core)
|
||||
{
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
d_vpr_h("%s: initialize ops\n", __func__);
|
||||
core->v4l2_file_ops = &msm_v4l2_file_operations;
|
||||
core->v4l2_ioctl_ops = &msm_v4l2_ioctl_ops;
|
||||
core->v4l2_ctrl_ops = &msm_v4l2_ctrl_ops;
|
||||
core->vb2_ops = &msm_vb2_ops;
|
||||
core->vb2_mem_ops = &msm_vb2_mem_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msm_vidc_init_platform(struct platform_device *pdev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_platform *platform;
|
||||
struct msm_vidc_core *core;
|
||||
|
||||
if (!pdev) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
|
||||
core = dev_get_drvdata(&pdev->dev);
|
||||
if (!core) {
|
||||
d_vpr_e("%s: core not found in device %s",
|
||||
dev_name(&pdev->dev));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
platform = kzalloc(sizeof(struct msm_vidc_platform), GFP_KERNEL);
|
||||
if (!platform)
|
||||
return -ENOMEM;
|
||||
|
||||
core->platform = platform;
|
||||
platform->core = core;
|
||||
|
||||
/* selected ops can be re-assigned in platform specific file */
|
||||
rc = msm_vidc_init_ops(core);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-vidc")) { // "qcom,msm-vidc-waipio"
|
||||
rc = msm_vidc_init_platform_waipio(core);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (of_device_is_compatible(pdev->dev.of_node, "qcom,msm-vidc")) { // "qcom,msm-vidc-iris2"
|
||||
rc = msm_vidc_init_iris2(core);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int msm_vidc_deinit_platform(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
}
|
367
driver/vidc/src/msm_vidc_probe.c
Normal file
367
driver/vidc/src/msm_vidc_probe.c
Normal file
@@ -0,0 +1,367 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irqreturn.h>
|
||||
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
#include "msm_vidc_driver.h"
|
||||
#include "msm_vidc_dt.h"
|
||||
#include "msm_vidc_platform.h"
|
||||
#include "msm_vidc_core.h"
|
||||
#include "venus_hfi.h"
|
||||
|
||||
#define BASE_DEVICE_NUMBER 32
|
||||
|
||||
static irqreturn_t msm_vidc_isr(int irq, void *data)
|
||||
{
|
||||
struct msm_vidc_core *core = data;
|
||||
|
||||
d_vpr_e("%s()\n", __func__);
|
||||
|
||||
disable_irq_nosync(irq);
|
||||
queue_work(core->device_workq, &core->device_work);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int msm_vidc_init_irq(struct msm_vidc_core *core)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_dt *dt;
|
||||
|
||||
d_vpr_e("%s()\n", __func__);
|
||||
|
||||
if (!core || !core->pdev || !core->dt) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
dt = core->dt;
|
||||
|
||||
core->register_base_addr = devm_ioremap_nocache(&core->pdev->dev,
|
||||
dt->register_base, dt->register_size);
|
||||
if (!core->register_base_addr) {
|
||||
d_vpr_e("could not map reg addr %pa of size %d\n",
|
||||
&dt->register_base, dt->register_size);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = request_irq(dt->irq, msm_vidc_isr, IRQF_TRIGGER_HIGH,
|
||||
"msm_vidc", core);
|
||||
if (unlikely(rc)) {
|
||||
d_vpr_e("%s: request_irq failed\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
disable_irq_nosync(dt->irq);
|
||||
|
||||
d_vpr_h("%s: reg_base = %pa, reg_size = %d\n",
|
||||
__func__, &dt->register_base, dt->register_size);
|
||||
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
if (core->device_workq)
|
||||
destroy_workqueue(core->device_workq);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct attribute *msm_vidc_core_attrs[] = {
|
||||
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"},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, msm_vidc_dt_match);
|
||||
|
||||
|
||||
void msm_vidc_release_video_device(struct video_device *vdev)
|
||||
{
|
||||
d_vpr_e("%s:\n", __func__);
|
||||
}
|
||||
|
||||
static int msm_vidc_register_video_device(struct msm_vidc_core *core,
|
||||
enum msm_vidc_domain_type type, int nr)
|
||||
{
|
||||
int rc = 0;
|
||||
int index;
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
|
||||
if (type == MSM_VIDC_DECODER)
|
||||
index = 0;
|
||||
else if (type == MSM_VIDC_ENCODER)
|
||||
index = 1;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
core->vdev[index].vdev.release =
|
||||
msm_vidc_release_video_device;
|
||||
core->vdev[index].vdev.fops = core->v4l2_file_ops;
|
||||
core->vdev[index].vdev.ioctl_ops = core->v4l2_ioctl_ops;
|
||||
core->vdev[index].vdev.vfl_dir = VFL_DIR_M2M;
|
||||
core->vdev[index].type = type;
|
||||
core->vdev[index].vdev.v4l2_dev = &core->v4l2_dev;
|
||||
core->vdev[index].vdev.device_caps =
|
||||
V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_OUTPUT_MPLANE |
|
||||
V4L2_CAP_STREAMING;
|
||||
rc = video_register_device(&core->vdev[index].vdev,
|
||||
VFL_TYPE_GRABBER, nr);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to register the video device\n");
|
||||
return rc;
|
||||
}
|
||||
video_set_drvdata(&core->vdev[index].vdev, core);
|
||||
//rc = device_create_file(&core->vdev[index].vdev.dev, &dev_attr_link_name);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to create video device file\n");
|
||||
video_unregister_device(&core->vdev[index].vdev);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_vidc_initialize_core(struct msm_vidc_core *core)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid params\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
|
||||
core->state = MSM_VIDC_CORE_DEINIT;
|
||||
|
||||
core->device_workq = create_singlethread_workqueue("device_workq");
|
||||
if (!core->device_workq) {
|
||||
d_vpr_e("%s: create device workq failed\n", __func__);
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
core->pm_workq = create_singlethread_workqueue("pm_workq");
|
||||
if (!core->pm_workq) {
|
||||
d_vpr_e("%s: create pm workq failed\n", __func__);
|
||||
destroy_workqueue(core->device_workq);
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_init(&core->lock);
|
||||
INIT_LIST_HEAD(&core->instances);
|
||||
INIT_LIST_HEAD(&core->dangling_instances);
|
||||
|
||||
INIT_WORK(&core->device_work, venus_hfi_work_handler);
|
||||
INIT_DELAYED_WORK(&core->pm_work, venus_hfi_pm_work_handler);
|
||||
INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler);
|
||||
INIT_DELAYED_WORK(&core->batch_work, msm_vidc_batch_handler);
|
||||
INIT_WORK(&core->ssr_work, msm_vidc_ssr_handler);
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vidc_probe_video_device(struct platform_device *pdev)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_core *core;
|
||||
int nr = BASE_DEVICE_NUMBER;
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
|
||||
core = kzalloc(sizeof(*core), GFP_KERNEL);
|
||||
if (!core)
|
||||
return -ENOMEM;
|
||||
|
||||
core->pdev = pdev;
|
||||
dev_set_drvdata(&pdev->dev, core);
|
||||
|
||||
rc = msm_vidc_initialize_core(core);
|
||||
if (rc) {
|
||||
d_vpr_e("%s: init core failed with %d\n", __func__, rc);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = msm_vidc_init_dt(pdev);
|
||||
if (rc) {
|
||||
d_vpr_e("%s: init dt failed with %d\n", __func__, rc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = msm_vidc_init_platform(pdev);
|
||||
if (rc) {
|
||||
d_vpr_e("%s: init platform failed with %d\n", __func__, rc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = msm_vidc_init_irq(core);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = sysfs_create_group(&pdev->dev.kobj, &msm_vidc_core_attr_group);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to create attributes\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = v4l2_device_register(&pdev->dev, &core->v4l2_dev);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to register v4l2 device\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* setup the decoder device */
|
||||
rc = msm_vidc_register_video_device(core, MSM_VIDC_DECODER, nr);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to register video decoder\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* setup the encoder device */
|
||||
rc = msm_vidc_register_video_device(core, MSM_VIDC_ENCODER, nr + 1);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to register video encoder\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
//rc = msm_vidc_debugfs_init_core(core);
|
||||
|
||||
d_vpr_h("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) {
|
||||
d_vpr_e("Failed to trigger probe for sub-devices\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int msm_vidc_probe_context_bank(struct platform_device *pdev)
|
||||
{
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
|
||||
return msm_vidc_read_context_bank_resources_from_dt(pdev);
|
||||
}
|
||||
|
||||
static int msm_vidc_probe(struct platform_device *pdev)
|
||||
{
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
|
||||
/*
|
||||
* 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_video_device(pdev);
|
||||
} else if (of_device_is_compatible(pdev->dev.of_node,
|
||||
"qcom,msm-vidc,context-bank")) {
|
||||
return msm_vidc_probe_context_bank(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;
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
|
||||
/*
|
||||
struct msm_vidc_core *core;
|
||||
|
||||
if (!pdev) {
|
||||
d_vpr_e("%s: invalid input %pK", __func__, pdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
core = dev_get_drvdata(&pdev->dev);
|
||||
if (!core) {
|
||||
d_vpr_e("%s: invalid core", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (core->vidc_core_workq)
|
||||
destroy_workqueue(core->vidc_core_workq);
|
||||
vidc_hfi_deinitialize(core->hfi_type, core->device);
|
||||
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 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,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init msm_vidc_init(void)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
|
||||
rc = platform_driver_register(&msm_vidc_driver);
|
||||
if (rc) {
|
||||
d_vpr_e("Failed to register platform driver\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit msm_vidc_exit(void)
|
||||
{
|
||||
d_vpr_h("%s()\n", __func__);
|
||||
|
||||
platform_driver_unregister(&msm_vidc_driver);
|
||||
}
|
||||
|
||||
module_init(msm_vidc_init);
|
||||
module_exit(msm_vidc_exit);
|
||||
|
||||
MODULE_SOFTDEP("pre: subsys-pil-tz");
|
||||
MODULE_LICENSE("GPL v2");
|
200
driver/vidc/src/msm_vidc_v4l2.c
Normal file
200
driver/vidc/src/msm_vidc_v4l2.c
Normal file
@@ -0,0 +1,200 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "msm_vidc_v4l2.h"
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_core.h"
|
||||
#include "msm_vidc_inst.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
#include "msm_vidc.h"
|
||||
|
||||
static 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
vidc_inst = msm_vidc_open(core, vid_dev->type);
|
||||
if (!vidc_inst) {
|
||||
d_vpr_e("Failed to create instance, type = %d\n",
|
||||
vid_dev->type);
|
||||
return -ENOMEM;
|
||||
}
|
||||
clear_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags);
|
||||
filp->private_data = &(vidc_inst->event_handler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msm_v4l2_close(struct file *filp)
|
||||
{
|
||||
int rc = 0;
|
||||
struct msm_vidc_inst *vidc_inst;
|
||||
|
||||
vidc_inst = get_vidc_inst(filp, NULL);
|
||||
|
||||
rc = msm_vidc_close(vidc_inst);
|
||||
filp->private_data = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct video_device *vdev = video_devdata(file);
|
||||
return msm_vidc_qbuf(get_vidc_inst(file, fh), vdev->v4l2_dev->mdev, 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)dec);
|
||||
}
|
||||
|
||||
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_cmd((void *)vidc_inst, (union msm_v4l2_cmd *)enc);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int msm_v4l2_querymenu(struct file *file, void *fh,
|
||||
struct v4l2_querymenu *qmenu)
|
||||
{
|
||||
struct msm_vidc_inst *vidc_inst = get_vidc_inst(file, fh);
|
||||
|
||||
return msm_vidc_query_menu((void *)vidc_inst, qmenu);
|
||||
}
|
44
driver/vidc/src/msm_vidc_vb2.c
Normal file
44
driver/vidc/src/msm_vidc_vb2.c
Normal file
@@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "msm_vidc_vb2.h"
|
||||
#include "msm_vidc_core.h"
|
||||
#include "msm_vidc_inst.h"
|
||||
#include "msm_vidc_internal.h"
|
||||
#include "msm_vidc_debug.h"
|
||||
|
||||
void *msm_vb2_get_userptr(struct device *dev, unsigned long vaddr,
|
||||
unsigned long size, enum dma_data_direction dma_dir)
|
||||
{
|
||||
return (void *)0xdeadbeef;
|
||||
}
|
||||
|
||||
void msm_vb2_put_userptr(void *buf_priv)
|
||||
{
|
||||
}
|
||||
|
||||
int msm_vidc_queue_setup(struct vb2_queue *q,
|
||||
unsigned int *num_buffers, unsigned int *num_planes,
|
||||
unsigned int sizes[], struct device *alloc_devs[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int msm_vidc_start_streaming(struct vb2_queue *q, unsigned int count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void msm_vidc_stop_streaming(struct vb2_queue *q)
|
||||
{
|
||||
}
|
||||
|
||||
void msm_vidc_buf_queue(struct vb2_buffer *vb2)
|
||||
{
|
||||
}
|
||||
|
||||
void msm_vidc_buf_cleanup(struct vb2_buffer *vb)
|
||||
{
|
||||
}
|
2351
driver/vidc/src/venus_hfi.c
Normal file
2351
driver/vidc/src/venus_hfi.c
Normal file
File diff suppressed because it is too large
Load Diff
1355
include/uapi/vidc/media/msm_media_info.h
Normal file
1355
include/uapi/vidc/media/msm_media_info.h
Normal file
File diff suppressed because it is too large
Load Diff
32
include/uapi/vidc/media/msm_vidc_utils.h
Normal file
32
include/uapi/vidc/media/msm_vidc_utils.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __MSM_VIDC_UTILS_H__
|
||||
#define __MSM_VIDC_UTILS_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/v4l2-controls.h>
|
||||
|
||||
/* vendor color format start */
|
||||
/* UBWC 8-bit Y/CbCr 4:2:0 */
|
||||
#define V4L2_PIX_FMT_NV12_UBWC v4l2_fourcc('Q', '1', '2', '8')
|
||||
/* NV12_512 8-bit Y/CbCr 4:2:0 */
|
||||
#define V4L2_PIX_FMT_NV12_512 v4l2_fourcc('Q', '5', '1', '2')
|
||||
/* NV12 10-bit Y/CbCr 4:2:0 */
|
||||
#define V4L2_PIX_FMT_NV12_P010_UBWC v4l2_fourcc('Q', '1', '2', 'B')
|
||||
/* UBWC 10-bit Y/CbCr 4:2:0 */
|
||||
#define V4L2_PIX_FMT_NV12_TP10_UBWC v4l2_fourcc('Q', '1', '2', 'A')
|
||||
#define V4L2_PIX_FMT_RGBA8888_UBWC v4l2_fourcc('Q', 'R', 'G', 'B')
|
||||
/* Y/CbCr 4:2:0 P10 Venus */
|
||||
#define V4L2_PIX_FMT_SDE_Y_CBCR_H2V2_P010_VENUS v4l2_fourcc('Q', 'P', '1', '0')
|
||||
#define V4L2_PIX_FMT_VIDC_META v4l2_fourcc('Q', 'M', 'E', 'T')
|
||||
/* vendor color format end */
|
||||
|
||||
/* vendor controls start */
|
||||
#define V4L2_CID_MPEG_MSM_VIDC_BASE (V4L2_CTRL_CLASS_MPEG | 0x2000)
|
||||
|
||||
/* vendor controls end */
|
||||
|
||||
#endif // __MSM_VIDC_UTILS_H__
|
Reference in New Issue
Block a user