6f422178aa
Introduced CVP skip ratio property to indicate the number of buffers skipped for CVP processing. This serves as a hint to Video firmware to know the number of frames for which CVP metadata has to be reused from earlier frame to which CVP metadata was sent Change-Id: I58ad5daf9a9c6ae7a0aa48e3bd1d60e7dc9229e6 Signed-off-by: Akshata Sahukar <asahukar@codeaurora.org>
1441 lines
36 KiB
C
1441 lines
36 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
|
*/
|
|
|
|
#include <linux/ion_kernel.h>
|
|
#include "msm_cvp_external.h"
|
|
#include "msm_vidc_common.h"
|
|
|
|
#define LOWER32(a) ((u32)((u64)a))
|
|
#define UPPER32(a) ((u32)((u64)a >> 32))
|
|
|
|
static void print_cvp_buffer(u32 tag, const char *str,
|
|
struct msm_vidc_inst *inst, struct msm_cvp_buf *cbuf)
|
|
{
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!(tag & msm_vidc_debug) || !inst || !inst->cvp || !cbuf)
|
|
return;
|
|
|
|
cvp = inst->cvp;
|
|
dprintk(tag, inst->sid,
|
|
"%s: %x : idx %d fd %d size %d offset %d dbuf %pK kvaddr %pK\n",
|
|
str, cvp->sid, cbuf->index, cbuf->fd, cbuf->size,
|
|
cbuf->offset, cbuf->dbuf, cbuf->kvaddr);
|
|
}
|
|
|
|
static int fill_cvp_buffer(struct msm_cvp_buffer_type *dst,
|
|
struct msm_cvp_buf *src, u32 sid)
|
|
{
|
|
if (!dst || !src) {
|
|
s_vpr_e(sid, "%s: invalid params %pK %pK\n",
|
|
__func__, dst, src);
|
|
return -EINVAL;
|
|
}
|
|
|
|
dst->buffer_addr = -1;
|
|
dst->reserved1 = LOWER32(src->dbuf);
|
|
dst->reserved2 = UPPER32(src->dbuf);
|
|
dst->size = src->size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_cvp_get_version_info(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc;
|
|
struct msm_cvp_external *cvp;
|
|
struct cvp_kmd_arg *arg;
|
|
struct cvp_kmd_sys_properties *sys_prop;
|
|
struct cvp_kmd_sys_property *prop_data;
|
|
u32 version;
|
|
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
arg = cvp->arg;
|
|
|
|
memset(arg, 0, sizeof(struct cvp_kmd_arg));
|
|
arg->type = CVP_KMD_GET_SYS_PROPERTY;
|
|
sys_prop = (struct cvp_kmd_sys_properties *)&arg->data.sys_properties;
|
|
sys_prop->prop_num = CVP_KMD_HFI_VERSION_PROP_NUMBER;
|
|
prop_data = (struct cvp_kmd_sys_property *)
|
|
&arg->data.sys_properties.prop_data;
|
|
prop_data->prop_type = CVP_KMD_HFI_VERSION_PROP_TYPE;
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_GET_SYS_PROPERTY, arg);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: failed, rc %d\n", __func__, rc);
|
|
return rc;
|
|
}
|
|
version = prop_data->data;
|
|
s_vpr_h(inst->sid, "%s: version %#x\n", __func__, version);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_cvp_set_priority(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc;
|
|
struct msm_cvp_external *cvp;
|
|
struct cvp_kmd_arg *arg;
|
|
struct cvp_kmd_sys_properties *props;
|
|
struct cvp_kmd_sys_property *prop_array;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
arg = cvp->arg;
|
|
props = (struct cvp_kmd_sys_properties *)&arg->data.sys_properties;
|
|
prop_array = (struct cvp_kmd_sys_property *)
|
|
&arg->data.sys_properties.prop_data;
|
|
|
|
memset(arg, 0, sizeof(struct cvp_kmd_arg));
|
|
arg->type = CVP_KMD_SET_SYS_PROPERTY;
|
|
props->prop_num = 1;
|
|
prop_array[0].prop_type = CVP_KMD_PROP_SESSION_PRIORITY;
|
|
if (is_realtime_session(inst))
|
|
prop_array[0].data = VIDEO_REALTIME;
|
|
else
|
|
prop_array[0].data = VIDEO_NONREALTIME;
|
|
s_vpr_h(inst->sid, "%s: %d\n", __func__, prop_array[0].data);
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_SET_SYS_PROPERTY, arg);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: failed, rc %d\n", __func__, rc);
|
|
return rc;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_cvp_fill_planeinfo(struct msm_cvp_color_plane_info *plane_info,
|
|
u32 color_fmt, u32 width, u32 height, u32 sid)
|
|
{
|
|
int rc = 0;
|
|
u32 y_stride, y_sclines, uv_stride, uv_sclines;
|
|
u32 y_meta_stride, y_meta_scalines;
|
|
u32 uv_meta_stride, uv_meta_sclines;
|
|
|
|
switch (color_fmt) {
|
|
case COLOR_FMT_NV12:
|
|
case COLOR_FMT_P010:
|
|
case COLOR_FMT_NV12_512:
|
|
{
|
|
y_stride = VENUS_Y_STRIDE(color_fmt, width);
|
|
y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
|
|
uv_stride = VENUS_UV_STRIDE(color_fmt, width);
|
|
uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
|
|
|
|
plane_info->stride[HFI_COLOR_PLANE_METADATA] = 0;
|
|
plane_info->stride[HFI_COLOR_PLANE_PICDATA] = y_stride;
|
|
plane_info->stride[HFI_COLOR_PLANE_UV_META] = 0;
|
|
plane_info->stride[HFI_COLOR_PLANE_UV] = uv_stride;
|
|
plane_info->buf_size[HFI_COLOR_PLANE_METADATA] = 0;
|
|
plane_info->buf_size[HFI_COLOR_PLANE_PICDATA] =
|
|
y_stride * y_sclines;
|
|
plane_info->buf_size[HFI_COLOR_PLANE_UV_META] = 0;
|
|
plane_info->buf_size[HFI_COLOR_PLANE_UV] =
|
|
uv_stride * uv_sclines;
|
|
break;
|
|
}
|
|
case COLOR_FMT_NV12_UBWC:
|
|
case COLOR_FMT_NV12_BPP10_UBWC:
|
|
{
|
|
y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width);
|
|
y_meta_scalines = VENUS_Y_META_SCANLINES(color_fmt, height);
|
|
uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width);
|
|
uv_meta_sclines = VENUS_UV_META_SCANLINES(color_fmt, height);
|
|
|
|
y_stride = VENUS_Y_STRIDE(color_fmt, width);
|
|
y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
|
|
uv_stride = VENUS_UV_STRIDE(color_fmt, width);
|
|
uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
|
|
|
|
plane_info->stride[HFI_COLOR_PLANE_METADATA] = y_meta_stride;
|
|
plane_info->stride[HFI_COLOR_PLANE_PICDATA] = y_stride;
|
|
plane_info->stride[HFI_COLOR_PLANE_UV_META] = uv_meta_stride;
|
|
plane_info->stride[HFI_COLOR_PLANE_UV] = uv_stride;
|
|
plane_info->buf_size[HFI_COLOR_PLANE_METADATA] =
|
|
MSM_MEDIA_ALIGN(y_meta_stride * y_meta_scalines, 4096);
|
|
plane_info->buf_size[HFI_COLOR_PLANE_PICDATA] =
|
|
MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
|
|
plane_info->buf_size[HFI_COLOR_PLANE_UV_META] =
|
|
MSM_MEDIA_ALIGN(uv_meta_stride * uv_meta_sclines, 4096);
|
|
plane_info->buf_size[HFI_COLOR_PLANE_UV] =
|
|
MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
|
|
break;
|
|
}
|
|
default:
|
|
s_vpr_e(sid, "%s: invalid color_fmt %#x\n",
|
|
__func__, color_fmt);
|
|
rc = -EINVAL;
|
|
break;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_cvp_free_buffer(struct msm_vidc_inst *inst,
|
|
struct msm_cvp_buf *buffer)
|
|
{
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!inst || !inst->cvp || !buffer) {
|
|
d_vpr_e("%s: invalid params %pK %pK\n",
|
|
__func__, inst, buffer);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
if (buffer->kvaddr) {
|
|
dma_buf_vunmap(buffer->dbuf, buffer->kvaddr);
|
|
buffer->kvaddr = NULL;
|
|
}
|
|
if (buffer->dbuf) {
|
|
dma_buf_put(buffer->dbuf);
|
|
buffer->dbuf = NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int msm_cvp_allocate_buffer(struct msm_vidc_inst *inst,
|
|
struct msm_cvp_buf *buffer, bool kernel_map)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
int ion_flags = 0;
|
|
unsigned long heap_mask = 0;
|
|
struct dma_buf *dbuf;
|
|
|
|
if (!inst || !inst->cvp || !buffer) {
|
|
d_vpr_e("%s: invalid params %pK %pK\n",
|
|
__func__, inst, buffer);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID);
|
|
if (inst->flags & VIDC_SECURE) {
|
|
ion_flags = ION_FLAG_SECURE | ION_FLAG_CP_NON_PIXEL;
|
|
heap_mask = ION_HEAP(ION_SECURE_HEAP_ID);
|
|
}
|
|
|
|
dbuf = ion_alloc(buffer->size, heap_mask, ion_flags);
|
|
if (IS_ERR_OR_NULL(dbuf)) {
|
|
s_vpr_e(inst->sid,
|
|
"%s: failed to allocate, size %d heap_mask %#lx flags %d\n",
|
|
__func__, buffer->size, heap_mask, ion_flags);
|
|
rc = -ENOMEM;
|
|
goto error;
|
|
}
|
|
buffer->dbuf = dbuf;
|
|
buffer->fd = -1;
|
|
|
|
if (kernel_map) {
|
|
buffer->kvaddr = dma_buf_vmap(dbuf);
|
|
if (!buffer->kvaddr) {
|
|
s_vpr_e(inst->sid,
|
|
"%s: dma_buf_vmap failed\n", __func__);
|
|
rc = -EINVAL;
|
|
goto error;
|
|
}
|
|
} else {
|
|
buffer->kvaddr = NULL;
|
|
}
|
|
buffer->index = cvp->buffer_idx++;
|
|
buffer->offset = 0;
|
|
|
|
return 0;
|
|
error:
|
|
msm_cvp_free_buffer(inst, buffer);
|
|
return rc;
|
|
}
|
|
|
|
static int msm_cvp_set_clocks_and_bus(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
struct cvp_kmd_arg *arg;
|
|
struct v4l2_format *fmt;
|
|
struct cvp_kmd_usecase_desc desc;
|
|
struct cvp_kmd_request_power power;
|
|
const u32 fps_max = CVP_FRAME_RATE_MAX;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
arg = cvp->arg;
|
|
memset(&desc, 0, sizeof(struct cvp_kmd_usecase_desc));
|
|
memset(&power, 0, sizeof(struct cvp_kmd_request_power));
|
|
|
|
fmt = &inst->fmts[INPUT_PORT].v4l2_fmt;
|
|
desc.fullres_width = cvp->width;
|
|
desc.fullres_height = cvp->height;
|
|
desc.downscale_width = cvp->ds_width;
|
|
desc.downscale_height = cvp->ds_height;
|
|
desc.is_downscale = cvp->downscale;
|
|
desc.fps = min(cvp->frame_rate >> 16, fps_max);
|
|
desc.op_rate = cvp->operating_rate >> 16;
|
|
desc.colorfmt =
|
|
msm_comm_convert_color_fmt(fmt->fmt.pix_mp.pixelformat,
|
|
inst->sid);
|
|
rc = msm_cvp_est_cycles(&desc, &power);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: estimate failed\n", __func__);
|
|
return rc;
|
|
}
|
|
s_vpr_h(inst->sid, "%s: core %d controller %d ddr bw %d\n",
|
|
__func__, power.clock_cycles_a, power.clock_cycles_b,
|
|
power.ddr_bw);
|
|
|
|
memset(arg, 0, sizeof(struct cvp_kmd_arg));
|
|
arg->type = CVP_KMD_REQUEST_POWER;
|
|
memcpy(&arg->data.req_power, &power,
|
|
sizeof(struct cvp_kmd_request_power));
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_REQUEST_POWER, arg);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: request_power failed with %d\n",
|
|
__func__, rc);
|
|
return rc;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_cvp_init_downscale_resolution(struct msm_vidc_inst *inst)
|
|
{
|
|
struct msm_cvp_external *cvp;
|
|
const u32 width_max = 1920;
|
|
u32 width, height, ds_width, ds_height, temp;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
ds_width = cvp->width;
|
|
ds_height = cvp->height;
|
|
|
|
if (!cvp->downscale) {
|
|
s_vpr_h(inst->sid, "%s: downscaling not enabled\n", __func__);
|
|
goto exit;
|
|
}
|
|
|
|
/* Step 1) make width always the larger number */
|
|
if (cvp->height > cvp->width) {
|
|
width = cvp->height;
|
|
height = cvp->width;
|
|
} else {
|
|
width = cvp->width;
|
|
height = cvp->height;
|
|
}
|
|
/*
|
|
* Step 2) Downscale width by 4 and round
|
|
* make sure width stays between 480 and 1920
|
|
*/
|
|
ds_width = (width + 2) >> 2;
|
|
if (ds_width < 480)
|
|
ds_width = 480;
|
|
if (ds_width > width_max)
|
|
ds_width = width_max;
|
|
ds_height = (height * ds_width) / width;
|
|
if (ds_height < 128)
|
|
ds_height = 128;
|
|
|
|
/* Step 3) do not downscale if width is less than 480 */
|
|
if (width <= 480)
|
|
ds_width = width;
|
|
if (ds_width == width)
|
|
ds_height = height;
|
|
|
|
/* Step 4) switch width and height if already switched */
|
|
if (cvp->height > cvp->width) {
|
|
temp = ds_height;
|
|
ds_height = ds_width;
|
|
ds_width = temp;
|
|
}
|
|
|
|
exit:
|
|
cvp->ds_width = ds_width;
|
|
cvp->ds_height = ds_height;
|
|
return 0;
|
|
}
|
|
|
|
static void msm_cvp_deinit_downscale_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return;
|
|
}
|
|
cvp = inst->cvp;
|
|
s_vpr_h(inst->sid, "%s:\n", __func__);
|
|
|
|
if (cvp->src_buffer.dbuf) {
|
|
print_cvp_buffer(VIDC_HIGH, "free: src_buffer",
|
|
inst, &cvp->src_buffer);
|
|
if (msm_cvp_free_buffer(inst, &cvp->src_buffer))
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"free failed: src_buffer",
|
|
inst, &cvp->src_buffer);
|
|
}
|
|
if (cvp->ref_buffer.dbuf) {
|
|
print_cvp_buffer(VIDC_HIGH, "free: ref_buffer",
|
|
inst, &cvp->ref_buffer);
|
|
if (msm_cvp_free_buffer(inst, &cvp->ref_buffer))
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"free failed: ref_buffer",
|
|
inst, &cvp->ref_buffer);
|
|
}
|
|
}
|
|
|
|
static int msm_cvp_init_downscale_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
if (!cvp->downscale) {
|
|
s_vpr_h(inst->sid, "%s: downscaling not enabled\n", __func__);
|
|
return 0;
|
|
}
|
|
s_vpr_h(inst->sid, "%s:\n", __func__);
|
|
|
|
cvp->src_buffer.size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC,
|
|
cvp->ds_width, cvp->ds_height);
|
|
rc = msm_cvp_allocate_buffer(inst, &cvp->src_buffer, false);
|
|
if (rc) {
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"allocate failed: src_buffer",
|
|
inst, &cvp->src_buffer);
|
|
goto error;
|
|
}
|
|
print_cvp_buffer(VIDC_HIGH, "alloc: src_buffer",
|
|
inst, &cvp->src_buffer);
|
|
|
|
cvp->ref_buffer.size = cvp->src_buffer.size;
|
|
rc = msm_cvp_allocate_buffer(inst, &cvp->ref_buffer, false);
|
|
if (rc) {
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"allocate failed: ref_buffer",
|
|
inst, &cvp->ref_buffer);
|
|
goto error;
|
|
}
|
|
print_cvp_buffer(VIDC_HIGH, "alloc: ref_buffer",
|
|
inst, &cvp->ref_buffer);
|
|
|
|
return rc;
|
|
|
|
error:
|
|
msm_cvp_deinit_downscale_buffers(inst);
|
|
return rc;
|
|
}
|
|
|
|
static void msm_cvp_deinit_context_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return;
|
|
}
|
|
cvp = inst->cvp;
|
|
s_vpr_h(inst->sid, "%s:\n", __func__);
|
|
|
|
if (cvp->context_buffer.dbuf) {
|
|
print_cvp_buffer(VIDC_HIGH, "free: context_buffer",
|
|
inst, &cvp->context_buffer);
|
|
if (msm_cvp_free_buffer(inst, &cvp->context_buffer))
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"free failed: context_buffer",
|
|
inst, &cvp->context_buffer);
|
|
}
|
|
if (cvp->refcontext_buffer.dbuf) {
|
|
print_cvp_buffer(VIDC_HIGH, "free: refcontext_buffer",
|
|
inst, &cvp->refcontext_buffer);
|
|
if (msm_cvp_free_buffer(inst, &cvp->refcontext_buffer))
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"free failed: refcontext_buffer",
|
|
inst, &cvp->refcontext_buffer);
|
|
}
|
|
}
|
|
|
|
static int msm_cvp_init_context_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
s_vpr_h(inst->sid, "%s:\n", __func__);
|
|
|
|
cvp->context_buffer.size = HFI_DME_FRAME_CONTEXT_BUFFER_SIZE;
|
|
rc = msm_cvp_allocate_buffer(inst, &cvp->context_buffer, false);
|
|
if (rc) {
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"allocate failed: context_buffer",
|
|
inst, &cvp->context_buffer);
|
|
goto error;
|
|
}
|
|
print_cvp_buffer(VIDC_HIGH, "alloc: context_buffer",
|
|
inst, &cvp->context_buffer);
|
|
|
|
cvp->refcontext_buffer.size = cvp->context_buffer.size;
|
|
rc = msm_cvp_allocate_buffer(inst, &cvp->refcontext_buffer, false);
|
|
if (rc) {
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"allocate failed: refcontext_buffer",
|
|
inst, &cvp->refcontext_buffer);
|
|
goto error;
|
|
}
|
|
print_cvp_buffer(VIDC_HIGH, "alloc: refcontext_buffer",
|
|
inst, &cvp->refcontext_buffer);
|
|
|
|
return rc;
|
|
|
|
error:
|
|
msm_cvp_deinit_context_buffers(inst);
|
|
return rc;
|
|
}
|
|
|
|
static void msm_cvp_deinit_internal_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return;
|
|
}
|
|
|
|
cvp = inst->cvp;
|
|
s_vpr_h(inst->sid, "%s:\n", __func__);
|
|
|
|
if (cvp->output_buffer.dbuf) {
|
|
print_cvp_buffer(VIDC_HIGH, "free: output_buffer",
|
|
inst, &cvp->output_buffer);
|
|
rc = msm_cvp_free_buffer(inst, &cvp->output_buffer);
|
|
if (rc)
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"unregister failed: output_buffer",
|
|
inst, &cvp->output_buffer);
|
|
}
|
|
|
|
if (cvp->persist2_buffer.dbuf) {
|
|
print_cvp_buffer(VIDC_HIGH, "free: persist2_buffer",
|
|
inst, &cvp->persist2_buffer);
|
|
rc = msm_cvp_free_buffer(inst, &cvp->persist2_buffer);
|
|
if (rc)
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"free failed: persist2_buffer",
|
|
inst, &cvp->persist2_buffer);
|
|
}
|
|
}
|
|
|
|
static int msm_cvp_set_persist_buffer(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
struct cvp_kmd_arg *arg;
|
|
struct msm_cvp_session_set_persist_buffers_packet persist2_packet = {0};
|
|
|
|
if (!inst || !inst->cvp || !inst->cvp->arg) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
arg = cvp->arg;
|
|
|
|
persist2_packet.size =
|
|
sizeof(struct msm_cvp_session_set_persist_buffers_packet);
|
|
persist2_packet.packet_type = HFI_CMD_SESSION_CVP_SET_PERSIST_BUFFERS;
|
|
persist2_packet.sid = cvp->sid;
|
|
persist2_packet.cvp_op = CVP_DME;
|
|
fill_cvp_buffer(&persist2_packet.persist2_buffer,
|
|
&cvp->persist2_buffer, inst->sid);
|
|
|
|
memset(arg, 0, sizeof(struct cvp_kmd_arg));
|
|
arg->type = CVP_KMD_HFI_PERSIST_CMD;
|
|
arg->buf_offset = offsetof(
|
|
struct msm_cvp_session_set_persist_buffers_packet,
|
|
persist1_buffer) / sizeof(u32);
|
|
arg->buf_num = (sizeof(
|
|
struct msm_cvp_session_set_persist_buffers_packet) -
|
|
(arg->buf_offset * sizeof(u32))) /
|
|
sizeof(struct msm_cvp_buffer_type);
|
|
memcpy(&(arg->data.pbuf_cmd), &persist2_packet,
|
|
sizeof(struct msm_cvp_session_set_persist_buffers_packet));
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_HFI_PERSIST_CMD, arg);
|
|
if (rc) {
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"set failed: persist2_buffer",
|
|
inst, &cvp->persist2_buffer);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_cvp_init_internal_buffers(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
cvp->persist2_buffer.size = HFI_DME_INTERNAL_PERSIST_2_BUFFER_SIZE;
|
|
rc = msm_cvp_allocate_buffer(inst, &cvp->persist2_buffer, false);
|
|
if (rc) {
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"allocate failed: persist2_buffer",
|
|
inst, &cvp->persist2_buffer);
|
|
goto error;
|
|
}
|
|
print_cvp_buffer(VIDC_HIGH, "alloc: persist2_buffer",
|
|
inst, &cvp->persist2_buffer);
|
|
|
|
/* allocate one output buffer for internal use */
|
|
cvp->output_buffer.size = HFI_DME_OUTPUT_BUFFER_SIZE;
|
|
rc = msm_cvp_allocate_buffer(inst, &cvp->output_buffer, true);
|
|
if (rc) {
|
|
print_cvp_buffer(VIDC_ERR,
|
|
"allocate failed: output_buffer",
|
|
inst, &cvp->output_buffer);
|
|
goto error;
|
|
}
|
|
print_cvp_buffer(VIDC_HIGH, "alloc: output_buffer",
|
|
inst, &cvp->output_buffer);
|
|
|
|
return rc;
|
|
|
|
error:
|
|
msm_cvp_deinit_internal_buffers(inst);
|
|
return rc;
|
|
}
|
|
|
|
static int msm_cvp_prepare_extradata(struct msm_vidc_inst *inst,
|
|
struct msm_vidc_buffer *mbuf)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
struct vb2_buffer *vb;
|
|
struct dma_buf *dbuf;
|
|
char *kvaddr = NULL;
|
|
struct msm_vidc_extradata_header *e_hdr;
|
|
bool input_extradata, found_end;
|
|
char *cvpframe = NULL;
|
|
u32 cvp_metadata_valid_flag = 0;
|
|
int nIsValid_offset = 232;
|
|
|
|
if (!inst || !inst->cvp || !mbuf) {
|
|
d_vpr_e("%s: invalid params %pK %pK\n",
|
|
__func__, inst, mbuf);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
vb = &mbuf->vvb.vb2_buf;
|
|
if (vb->num_planes <= 1) {
|
|
s_vpr_e(inst->sid, "%s: extradata plane not enabled\n",
|
|
__func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
dbuf = dma_buf_get(vb->planes[1].m.fd);
|
|
if (!dbuf) {
|
|
s_vpr_e(inst->sid, "%s: dma_buf_get(%d) failed\n",
|
|
__func__, vb->planes[1].m.fd);
|
|
return -EINVAL;
|
|
}
|
|
if (dbuf->size < vb->planes[1].length) {
|
|
s_vpr_e(inst->sid, "%s: invalid size %d vs %d\n", __func__,
|
|
dbuf->size, vb->planes[1].length);
|
|
rc = -EINVAL;
|
|
goto error;
|
|
}
|
|
rc = dma_buf_begin_cpu_access(dbuf, DMA_BIDIRECTIONAL);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: begin_cpu_access failed\n", __func__);
|
|
goto error;
|
|
}
|
|
kvaddr = dma_buf_vmap(dbuf);
|
|
if (!kvaddr) {
|
|
s_vpr_e(inst->sid, "%s: dma_buf_vmap(%d) failed\n",
|
|
__func__, vb->planes[1].m.fd);
|
|
rc = -EINVAL;
|
|
goto error;
|
|
}
|
|
e_hdr = (struct msm_vidc_extradata_header *)((char *)kvaddr +
|
|
vb->planes[1].data_offset);
|
|
|
|
input_extradata =
|
|
!!((inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_ROI) ||
|
|
(inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_HDR10PLUS));
|
|
found_end = false;
|
|
while ((char *)e_hdr < (char *)(kvaddr + dbuf->size)) {
|
|
if (!input_extradata) {
|
|
found_end = true;
|
|
break;
|
|
}
|
|
if (e_hdr->type == MSM_VIDC_EXTRADATA_NONE) {
|
|
found_end = true;
|
|
break;
|
|
}
|
|
e_hdr += e_hdr->size;
|
|
}
|
|
if (!found_end) {
|
|
s_vpr_e(inst->sid, "%s: extradata_none not found\n", __func__);
|
|
e_hdr = (struct msm_vidc_extradata_header *)((char *)kvaddr +
|
|
vb->planes[1].data_offset);
|
|
}
|
|
/* check if sufficient space available */
|
|
if (((char *)e_hdr + sizeof(struct msm_vidc_extradata_header) +
|
|
sizeof(struct msm_vidc_enc_cvp_metadata_payload) +
|
|
sizeof(struct msm_vidc_extradata_header)) >
|
|
(kvaddr + dbuf->size)) {
|
|
s_vpr_e(inst->sid,
|
|
"%s: couldn't append extradata, (e_hdr[%pK] - kvaddr[%pK]) %#x, size %d\n",
|
|
__func__, e_hdr, kvaddr, (char *)e_hdr - (char *)kvaddr,
|
|
dbuf->size);
|
|
goto error;
|
|
}
|
|
if (cvp->metadata_available) {
|
|
cvp->metadata_available = false;
|
|
|
|
/* copy payload */
|
|
e_hdr->version = 0x00000001;
|
|
e_hdr->port_index = 1;
|
|
e_hdr->type = MSM_VIDC_EXTRADATA_CVP_METADATA;
|
|
e_hdr->data_size =
|
|
sizeof(struct msm_vidc_enc_cvp_metadata_payload);
|
|
e_hdr->size = sizeof(struct msm_vidc_extradata_header) +
|
|
e_hdr->data_size;
|
|
dma_buf_begin_cpu_access(cvp->output_buffer.dbuf,
|
|
DMA_BIDIRECTIONAL);
|
|
memcpy(e_hdr->data, cvp->output_buffer.kvaddr,
|
|
sizeof(struct msm_vidc_enc_cvp_metadata_payload));
|
|
cvpframe = (char *) e_hdr->data;
|
|
cvp_metadata_valid_flag = *(u32*)(cvpframe + nIsValid_offset);
|
|
s_vpr_h(inst->sid, "CVP metadata nIsValid flag = %u frame: %u",
|
|
cvp_metadata_valid_flag, cvp->framecount);
|
|
dma_buf_end_cpu_access(cvp->output_buffer.dbuf,
|
|
DMA_BIDIRECTIONAL);
|
|
}
|
|
/* fill extradata none */
|
|
e_hdr = (struct msm_vidc_extradata_header *)
|
|
((char *)e_hdr + e_hdr->size);
|
|
e_hdr->version = 0x00000001;
|
|
e_hdr->port_index = 1;
|
|
e_hdr->type = MSM_VIDC_EXTRADATA_NONE;
|
|
e_hdr->data_size = 0;
|
|
e_hdr->size = sizeof(struct msm_vidc_extradata_header) +
|
|
e_hdr->data_size;
|
|
|
|
dma_buf_vunmap(dbuf, kvaddr);
|
|
dma_buf_end_cpu_access(dbuf, DMA_BIDIRECTIONAL);
|
|
dma_buf_put(dbuf);
|
|
|
|
return rc;
|
|
|
|
error:
|
|
if (kvaddr) {
|
|
dma_buf_vunmap(dbuf, kvaddr);
|
|
dma_buf_end_cpu_access(dbuf, DMA_BIDIRECTIONAL);
|
|
}
|
|
if (dbuf)
|
|
dma_buf_put(dbuf);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_cvp_reference_management(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
struct msm_cvp_buf temp;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
/* swap context buffers */
|
|
memcpy(&temp, &cvp->refcontext_buffer, sizeof(struct msm_cvp_buf));
|
|
memcpy(&cvp->refcontext_buffer, &cvp->context_buffer,
|
|
sizeof(struct msm_cvp_buf));
|
|
memcpy(&cvp->context_buffer, &temp, sizeof(struct msm_cvp_buf));
|
|
|
|
/* swap downscale buffers */
|
|
if (cvp->downscale) {
|
|
memcpy(&temp, &cvp->ref_buffer, sizeof(struct msm_cvp_buf));
|
|
memcpy(&cvp->ref_buffer, &cvp->src_buffer,
|
|
sizeof(struct msm_cvp_buf));
|
|
memcpy(&cvp->src_buffer, &temp, sizeof(struct msm_cvp_buf));
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vidc_cvp_session_start(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp = NULL;
|
|
struct cvp_kmd_session_control *ctrl = NULL;
|
|
struct cvp_kmd_arg *arg = NULL;
|
|
|
|
if (!inst || !inst->cvp || !inst->cvp->arg) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
arg = cvp->arg;
|
|
|
|
memset(arg, 0, sizeof(struct cvp_kmd_arg));
|
|
arg->type = CVP_KMD_SESSION_CONTROL;
|
|
ctrl = (struct cvp_kmd_session_control *)&arg->data.session_ctrl;
|
|
ctrl->ctrl_type = SESSION_START;
|
|
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_SESSION_CONTROL, arg);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid,
|
|
"%s: CVP_KMD_SESSION_CONTROL failed, rc %d\n",
|
|
__func__, rc);
|
|
return rc;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vidc_cvp_session_stop(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp = NULL;
|
|
struct cvp_kmd_session_control *ctrl = NULL;
|
|
struct cvp_kmd_arg *arg = NULL;
|
|
|
|
if (!inst || !inst->cvp || !inst->cvp->arg) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
|
|
cvp = inst->cvp;
|
|
arg = cvp->arg;
|
|
|
|
memset(arg, 0, sizeof(struct cvp_kmd_arg));
|
|
|
|
arg->type = CVP_KMD_SESSION_CONTROL;
|
|
|
|
ctrl = (struct cvp_kmd_session_control *)&arg->data.session_ctrl;
|
|
ctrl->ctrl_type = SESSION_STOP;
|
|
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_SESSION_CONTROL, arg);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid,
|
|
"%s: CVP_KMD_SESSION_CONTROL failed, rc %d\n",
|
|
__func__, rc);
|
|
return rc;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_cvp_frame_process(struct msm_vidc_inst *inst,
|
|
struct msm_vidc_buffer *mbuf)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
struct vb2_buffer *vb;
|
|
struct cvp_kmd_arg *arg;
|
|
struct msm_cvp_dme_frame_packet *frame;
|
|
const u32 fps_max = CVP_FRAME_RATE_MAX;
|
|
u32 fps, operating_rate, skip_framecount, capture_rate, cvp_rate;
|
|
bool skipframe = false;
|
|
bool first_frame = false;
|
|
bool fps_data_changed = false;
|
|
|
|
if (!inst || !inst->cvp || !inst->cvp->arg || !mbuf) {
|
|
d_vpr_e("%s: invalid params %pK %pK\n",
|
|
__func__, inst, mbuf);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
arg = cvp->arg;
|
|
|
|
vb = &mbuf->vvb.vb2_buf;
|
|
cvp->fullres_buffer.index = vb->index;
|
|
cvp->fullres_buffer.fd = vb->planes[0].m.fd;
|
|
cvp->fullres_buffer.size = vb->planes[0].length;
|
|
cvp->fullres_buffer.offset = vb->planes[0].data_offset;
|
|
cvp->fullres_buffer.dbuf = mbuf->smem[0].dma_buf;
|
|
|
|
if(!cvp->framecount)
|
|
first_frame = true;
|
|
|
|
/* handle framerate or operarating rate changes dynamically */
|
|
if (cvp->frame_rate != inst->clk_data.frame_rate ||
|
|
cvp->operating_rate != inst->clk_data.operating_rate) {
|
|
/* update cvp parameters */
|
|
cvp->framecount = 0;
|
|
fps_data_changed = true;
|
|
cvp->frame_rate = inst->clk_data.frame_rate;
|
|
cvp->operating_rate = inst->clk_data.operating_rate;
|
|
rc = msm_cvp_set_clocks_and_bus(inst);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid,
|
|
"%s: unsupported dynamic changes %#x %#x\n",
|
|
__func__, cvp->frame_rate, cvp->operating_rate);
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Special handling for operating rate INT_MAX,
|
|
* client's intention is not to skip cvp preprocess
|
|
* based on operating rate, skip logic can still be
|
|
* executed based on framerate though.
|
|
*/
|
|
if (cvp->operating_rate == INT_MAX)
|
|
operating_rate = fps_max << 16;
|
|
else
|
|
operating_rate = cvp->operating_rate;
|
|
|
|
mbuf->vvb.flags &= ~V4L2_BUF_FLAG_CVPMETADATA_SKIP;
|
|
/* frame skip logic */
|
|
fps = max(cvp->frame_rate, operating_rate) >> 16;
|
|
if (fps > fps_max) {
|
|
/*
|
|
* fps <= 120: 0, 2, 4, 6 .. are not skipped
|
|
* fps <= 180: 0, 3, 6, 9 .. are not skipped
|
|
* fps <= 240: 0, 4, 8, 12 .. are not skipped
|
|
* fps <= 960: 0, 16, 32, 48 .. are not skipped
|
|
*/
|
|
fps = roundup(fps, fps_max);
|
|
cvp_rate = fps_max << 16;
|
|
skip_framecount = fps / fps_max;
|
|
skipframe = cvp->framecount % skip_framecount;
|
|
} else
|
|
cvp_rate = fps << 16;
|
|
|
|
if (skipframe) {
|
|
print_cvp_buffer(VIDC_LOW, "input frame with skipflag",
|
|
inst, &cvp->fullres_buffer);
|
|
cvp->framecount++;
|
|
cvp->metadata_available = false;
|
|
mbuf->vvb.flags |= V4L2_BUF_FLAG_CVPMETADATA_SKIP;
|
|
return 0;
|
|
}
|
|
capture_rate = fps << 16;
|
|
if (fps_data_changed) {
|
|
rc = msm_comm_set_cvp_skip_ratio(inst, capture_rate, cvp_rate);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid,"Setting CVP skip ratio failed");
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
memset(arg, 0, sizeof(struct cvp_kmd_arg));
|
|
arg->type = CVP_KMD_SEND_CMD_PKT;
|
|
arg->buf_offset = offsetof(struct msm_cvp_dme_frame_packet,
|
|
fullres_srcbuffer) / sizeof(u32);
|
|
arg->buf_num = (sizeof(struct msm_cvp_dme_frame_packet) -
|
|
(arg->buf_offset * sizeof(u32))) /
|
|
sizeof(struct msm_cvp_buffer_type);
|
|
frame = (struct msm_cvp_dme_frame_packet *)&arg->data.hfi_pkt.pkt_data;
|
|
frame->size = sizeof(struct msm_cvp_dme_frame_packet);
|
|
frame->packet_type = HFI_CMD_SESSION_CVP_DME_FRAME;
|
|
frame->sid = cvp->sid;
|
|
if (first_frame)
|
|
frame->skip_mv_calc = 1;
|
|
else
|
|
frame->skip_mv_calc = 0;
|
|
frame->min_fpx_threshold = 2;
|
|
frame->enable_descriptor_lpf = 1;
|
|
frame->enable_ncc_subpel = 1;
|
|
frame->descmatch_threshold = 52;
|
|
frame->ncc_robustness_threshold = 0;
|
|
|
|
fill_cvp_buffer(&frame->fullres_srcbuffer,
|
|
&cvp->fullres_buffer, inst->sid);
|
|
fill_cvp_buffer(&frame->videospatialtemporal_statsbuffer,
|
|
&cvp->output_buffer, inst->sid);
|
|
fill_cvp_buffer(&frame->src_buffer, &cvp->fullres_buffer, inst->sid);
|
|
if (cvp->downscale) {
|
|
fill_cvp_buffer(&frame->src_buffer, &cvp->src_buffer,
|
|
inst->sid);
|
|
fill_cvp_buffer(&frame->ref_buffer, &cvp->ref_buffer,
|
|
inst->sid);
|
|
}
|
|
fill_cvp_buffer(&frame->srcframe_contextbuffer,
|
|
&cvp->context_buffer, inst->sid);
|
|
fill_cvp_buffer(&frame->refframe_contextbuffer,
|
|
&cvp->refcontext_buffer, inst->sid);
|
|
|
|
print_cvp_buffer(VIDC_LOW, "input frame", inst, &cvp->fullres_buffer);
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_SEND_CMD_PKT, arg);
|
|
if (rc) {
|
|
print_cvp_buffer(VIDC_ERR, "send failed: input frame",
|
|
inst, &cvp->fullres_buffer);
|
|
goto error;
|
|
}
|
|
/* wait for frame done */
|
|
arg->type = CVP_KMD_RECEIVE_MSG_PKT;
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_RECEIVE_MSG_PKT, arg);
|
|
if (rc) {
|
|
print_cvp_buffer(VIDC_ERR, "wait failed: input frame",
|
|
inst, &cvp->fullres_buffer);
|
|
goto error;
|
|
}
|
|
cvp->framecount++;
|
|
cvp->metadata_available = true;
|
|
|
|
error:
|
|
return rc;
|
|
}
|
|
|
|
int msm_vidc_cvp_preprocess(struct msm_vidc_inst *inst,
|
|
struct msm_vidc_buffer *mbuf)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!inst || !inst->cvp || !mbuf) {
|
|
d_vpr_e("%s: invalid params %pK %pK\n",
|
|
__func__, inst, mbuf);
|
|
return -EINVAL;
|
|
}
|
|
if (inst->state != MSM_VIDC_START_DONE) {
|
|
s_vpr_e(inst->sid, "%s: invalid inst state %d\n",
|
|
__func__, inst->state);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
rc = msm_cvp_frame_process(inst, mbuf);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: cvp process failed\n", __func__);
|
|
return rc;
|
|
}
|
|
|
|
rc = msm_cvp_prepare_extradata(inst, mbuf);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: prepare extradata failed\n", __func__);
|
|
return rc;
|
|
}
|
|
|
|
rc = msm_cvp_reference_management(inst);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: ref management failed\n", __func__);
|
|
return rc;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vidc_cvp_session_delete(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp = NULL;
|
|
struct cvp_kmd_session_control *ctrl = NULL;
|
|
struct cvp_kmd_arg *arg = NULL;
|
|
|
|
if (!inst || !inst->cvp || !inst->cvp->arg) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
arg = cvp->arg;
|
|
|
|
memset(arg, 0, sizeof(struct cvp_kmd_arg));
|
|
arg->type = CVP_KMD_SESSION_CONTROL;
|
|
ctrl = (struct cvp_kmd_session_control *)&arg->data.session_ctrl;
|
|
ctrl->ctrl_type = SESSION_DELETE;
|
|
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_SESSION_CONTROL, arg);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid,
|
|
"%s: CVP_KMD_SESSION_CONTROL failed, rc %d\n",
|
|
__func__, rc);
|
|
return rc;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_cvp_mem_deinit(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
s_vpr_h(inst->sid, "%s: cvp session %#x\n", __func__, cvp->sid);
|
|
msm_cvp_deinit_internal_buffers(inst);
|
|
msm_cvp_deinit_context_buffers(inst);
|
|
msm_cvp_deinit_downscale_buffers(inst);
|
|
|
|
cvp->priv = NULL;
|
|
kfree(cvp->arg);
|
|
cvp->arg = NULL;
|
|
kfree(inst->cvp);
|
|
inst->cvp = NULL;
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vidc_cvp_deinit(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = msm_vidc_cvp_session_stop(inst);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: cvp stop failed with error %d\n",
|
|
__func__, rc);
|
|
}
|
|
|
|
msm_vidc_cvp_session_delete(inst);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vidc_cvp_close(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
s_vpr_h(inst->sid, "%s: cvp session %#x\n", __func__, cvp->sid);
|
|
rc = msm_cvp_close(cvp->priv);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: cvp close failed with error %d\n",
|
|
__func__, rc);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int msm_vidc_cvp_unprepare_preprocess(struct msm_vidc_inst *inst)
|
|
{
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
if (!inst->cvp) {
|
|
s_vpr_h(inst->sid, "%s: cvp not enabled or closed\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
msm_vidc_cvp_deinit(inst);
|
|
msm_vidc_cvp_close(inst);
|
|
msm_cvp_mem_deinit(inst);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int msm_vidc_cvp_session_create(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp = NULL;
|
|
struct cvp_kmd_session_control *ctrl = NULL;
|
|
struct cvp_kmd_arg *arg = NULL;
|
|
|
|
if (!inst || !inst->cvp || !inst->cvp->arg) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
arg = cvp->arg;
|
|
|
|
memset(arg, 0, sizeof(struct cvp_kmd_arg));
|
|
arg->type = CVP_KMD_SESSION_CONTROL;
|
|
ctrl = (struct cvp_kmd_session_control *)&arg->data.session_ctrl;
|
|
ctrl->ctrl_type = SESSION_CREATE;
|
|
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_SESSION_CONTROL, arg);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid,
|
|
"%s: CVP_KMD_SESSION_CONTROL failed, rc %d\n",
|
|
__func__, rc);
|
|
return rc;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vidc_cvp_getsessioninfo(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
struct cvp_kmd_arg *arg;
|
|
|
|
if (!inst || !inst->cvp || !inst->cvp->arg) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
arg = cvp->arg;
|
|
|
|
memset(arg, 0, sizeof(struct cvp_kmd_arg));
|
|
arg->type = CVP_KMD_GET_SESSION_INFO;
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_GET_SESSION_INFO, arg);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: get_session_info failed\n", __func__);
|
|
goto error;
|
|
}
|
|
cvp->sid = arg->data.session.session_id;
|
|
s_vpr_h(inst->sid, "%s: cvp session id %#x\n",
|
|
__func__, cvp->sid);
|
|
|
|
rc = msm_cvp_get_version_info(inst);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: get_version_info failed\n", __func__);
|
|
goto error;
|
|
}
|
|
return rc;
|
|
|
|
error:
|
|
msm_vidc_cvp_deinit(inst);
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vidc_cvp_dme_basic_config(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
struct cvp_kmd_arg *arg;
|
|
struct msm_cvp_dme_basic_config_packet *dmecfg;
|
|
struct v4l2_format *fmt;
|
|
u32 color_fmt;
|
|
|
|
if (!inst || !inst->cvp || !inst->cvp->arg) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
arg = cvp->arg;
|
|
|
|
memset(arg, 0, sizeof(struct cvp_kmd_arg));
|
|
arg->type = CVP_KMD_SEND_CMD_PKT;
|
|
dmecfg = (struct msm_cvp_dme_basic_config_packet *)
|
|
&arg->data.hfi_pkt.pkt_data;
|
|
dmecfg->size = sizeof(struct msm_cvp_dme_basic_config_packet);
|
|
dmecfg->packet_type = HFI_CMD_SESSION_CVP_DME_BASIC_CONFIG;
|
|
dmecfg->sid = cvp->sid;
|
|
/* source buffer format should be NV12_UBWC always */
|
|
dmecfg->srcbuffer_format = HFI_COLOR_FORMAT_NV12_UBWC;
|
|
dmecfg->src_width = cvp->ds_width;
|
|
dmecfg->src_height = cvp->ds_height;
|
|
rc = msm_cvp_fill_planeinfo(&dmecfg->srcbuffer_planeinfo,
|
|
COLOR_FMT_NV12_UBWC, dmecfg->src_width,
|
|
dmecfg->src_height, inst->sid);
|
|
if (rc)
|
|
goto error;
|
|
|
|
fmt = &inst->fmts[INPUT_PORT].v4l2_fmt;
|
|
color_fmt =
|
|
msm_comm_convert_color_fmt(fmt->fmt.pix_mp.pixelformat,
|
|
inst->sid);
|
|
dmecfg->fullresbuffer_format = msm_comm_get_hfi_uncompressed(
|
|
fmt->fmt.pix_mp.pixelformat, inst->sid);
|
|
dmecfg->fullres_width = cvp->width;
|
|
dmecfg->fullres_height = cvp->height;
|
|
rc = msm_cvp_fill_planeinfo(&dmecfg->fullresbuffer_planeinfo,
|
|
color_fmt, dmecfg->fullres_width,
|
|
dmecfg->fullres_height, inst->sid);
|
|
if (rc)
|
|
goto error;
|
|
dmecfg->ds_enable = cvp->downscale;
|
|
dmecfg->enable_lrme_robustness = 1;
|
|
dmecfg->enable_inlier_tracking = 1;
|
|
rc = msm_cvp_private(cvp->priv, CVP_KMD_SEND_CMD_PKT, arg);
|
|
if (rc) {
|
|
s_vpr_e(inst->sid, "%s: cvp configuration failed\n", __func__);
|
|
goto error;
|
|
}
|
|
|
|
error:
|
|
return rc;
|
|
}
|
|
|
|
static int msm_cvp_mem_init(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
struct v4l2_format *fmt;
|
|
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
inst->cvp = kzalloc(sizeof(struct msm_cvp_external), GFP_KERNEL);
|
|
if (!inst->cvp) {
|
|
s_vpr_e(inst->sid, "%s: failed to allocate\n", __func__);
|
|
return -ENOMEM;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
cvp->arg = kzalloc(sizeof(struct cvp_kmd_arg), GFP_KERNEL);
|
|
if (!cvp->arg) {
|
|
kfree(inst->cvp);
|
|
inst->cvp = NULL;
|
|
return -ENOMEM;
|
|
}
|
|
|
|
cvp->framecount = 0;
|
|
cvp->metadata_available = false;
|
|
fmt = &inst->fmts[INPUT_PORT].v4l2_fmt;
|
|
cvp->width = fmt->fmt.pix_mp.width;
|
|
cvp->height = fmt->fmt.pix_mp.height;
|
|
cvp->frame_rate = inst->clk_data.frame_rate;
|
|
cvp->operating_rate = inst->clk_data.operating_rate;
|
|
|
|
/* enable downscale always */
|
|
cvp->downscale = true;
|
|
rc = msm_cvp_init_downscale_resolution(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
s_vpr_h(inst->sid,
|
|
"%s: pixelformat %#x, wxh %dx%d downscale %d ds_wxh %dx%d fps %d op_rate %d\n",
|
|
__func__, fmt->fmt.pix_mp.pixelformat,
|
|
cvp->width, cvp->height, cvp->downscale,
|
|
cvp->ds_width, cvp->ds_height,
|
|
cvp->frame_rate >> 16, cvp->operating_rate >> 16);
|
|
|
|
rc = msm_cvp_init_downscale_buffers(inst);
|
|
if (rc)
|
|
goto error;
|
|
rc = msm_cvp_init_internal_buffers(inst);
|
|
if (rc)
|
|
goto error;
|
|
rc = msm_cvp_init_context_buffers(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
return rc;
|
|
|
|
error:
|
|
msm_cvp_mem_deinit(inst);
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vidc_cvp_open(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc = 0;
|
|
struct msm_cvp_external *cvp;
|
|
|
|
if (!inst || !inst->cvp) {
|
|
d_vpr_e("%s: invalid params %pK\n", __func__, inst);
|
|
return -EINVAL;
|
|
}
|
|
cvp = inst->cvp;
|
|
|
|
s_vpr_h(inst->sid, "%s: opening cvp\n", __func__);
|
|
cvp->priv = msm_cvp_open(0, MSM_VIDC_CVP);
|
|
if (!cvp->priv) {
|
|
s_vpr_e(inst->sid,
|
|
"%s: failed to open cvp session\n", __func__);
|
|
rc = -EINVAL;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static int msm_vidc_cvp_init(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc;
|
|
|
|
rc = msm_cvp_set_priority(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_vidc_cvp_session_create(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vidc_cvp_getsessioninfo(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_cvp_set_clocks_and_bus(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_vidc_cvp_dme_basic_config(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_cvp_set_persist_buffer(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
rc = msm_vidc_cvp_session_start(inst);
|
|
if (rc)
|
|
goto error;
|
|
|
|
return 0;
|
|
|
|
error:
|
|
msm_vidc_cvp_deinit(inst);
|
|
return rc;
|
|
}
|
|
|
|
int msm_vidc_cvp_prepare_preprocess(struct msm_vidc_inst *inst)
|
|
{
|
|
int rc;
|
|
|
|
if (!inst) {
|
|
d_vpr_e("%s: invalid params\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
rc = msm_cvp_mem_init(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vidc_cvp_open(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
rc = msm_vidc_cvp_init(inst);
|
|
if (rc)
|
|
return rc;
|
|
|
|
return 0;
|
|
}
|