android_kernel_xiaomi_sm8350/msm/vidc/msm_cvp_external.c
Maheshwar Ajja e8ea759822 msm: vidc: amend cvp module structures
Align strctures as expected by CVP firmware.

Change-Id: Ib0a379d8dbcf0c65a8eef1561778f2fa972b517c
Signed-off-by: Maheshwar Ajja <majja@codeaurora.org>
2019-05-31 13:00:11 -07:00

1088 lines
29 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"
static void print_cvp_buffer(u32 tag, const char *str,
struct msm_vidc_inst *inst, struct msm_cvp_buf *cbuf)
{
struct msm_cvp_external *cvp;
if (!(tag & msm_vidc_debug) || !inst || !inst->cvp || !cbuf)
return;
cvp = inst->cvp;
dprintk(tag,
"%s: %x : idx %d fd %d size %d offset %d dbuf %pK kvaddr %pK\n",
str, cvp->session_id, cbuf->index, cbuf->fd, cbuf->size,
cbuf->offset, cbuf->dbuf, cbuf->kvaddr);
}
static int msm_cvp_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) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
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) {
dprintk(VIDC_ERR, "%s: failed, rc %d\n", __func__, rc);
return rc;
}
version = prop_data->data;
dprintk(VIDC_HIGH, "%s: version %#x\n", __func__, version);
return 0;
}
static int msm_cvp_fill_planeinfo(struct msm_cvp_color_plane_info *plane_info,
u32 color_fmt, u32 width, u32 height)
{
int rc = 0;
u32 y_stride, y_sclines, uv_stride, uv_sclines;
u32 y_meta_stride, y_meta_scalines;
u32 uv_meta_stride, uv_meta_sclines;
switch (color_fmt) {
case COLOR_FMT_NV12:
case COLOR_FMT_P010:
case COLOR_FMT_NV12_512:
{
y_stride = VENUS_Y_STRIDE(color_fmt, width);
y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
uv_stride = VENUS_UV_STRIDE(color_fmt, width);
uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
plane_info->stride[HFI_COLOR_PLANE_METADATA] = 0;
plane_info->stride[HFI_COLOR_PLANE_PICDATA] = y_stride;
plane_info->stride[HFI_COLOR_PLANE_UV_META] = 0;
plane_info->stride[HFI_COLOR_PLANE_UV] = uv_stride;
plane_info->buf_size[HFI_COLOR_PLANE_METADATA] = 0;
plane_info->buf_size[HFI_COLOR_PLANE_PICDATA] =
y_stride * y_sclines;
plane_info->buf_size[HFI_COLOR_PLANE_UV_META] = 0;
plane_info->buf_size[HFI_COLOR_PLANE_UV] =
uv_stride * uv_sclines;
break;
}
case COLOR_FMT_NV12_UBWC:
case COLOR_FMT_NV12_BPP10_UBWC:
{
y_meta_stride = VENUS_Y_META_STRIDE(color_fmt, width);
y_meta_scalines = VENUS_Y_META_SCANLINES(color_fmt, height);
uv_meta_stride = VENUS_UV_META_STRIDE(color_fmt, width);
uv_meta_sclines = VENUS_UV_META_SCANLINES(color_fmt, height);
y_stride = VENUS_Y_STRIDE(color_fmt, width);
y_sclines = VENUS_Y_SCANLINES(color_fmt, height);
uv_stride = VENUS_UV_STRIDE(color_fmt, width);
uv_sclines = VENUS_UV_SCANLINES(color_fmt, height);
plane_info->stride[HFI_COLOR_PLANE_METADATA] = y_meta_stride;
plane_info->stride[HFI_COLOR_PLANE_PICDATA] = y_stride;
plane_info->stride[HFI_COLOR_PLANE_UV_META] = uv_meta_stride;
plane_info->stride[HFI_COLOR_PLANE_UV] = uv_stride;
plane_info->buf_size[HFI_COLOR_PLANE_METADATA] =
MSM_MEDIA_ALIGN(y_meta_stride * y_meta_scalines, 4096);
plane_info->buf_size[HFI_COLOR_PLANE_PICDATA] =
MSM_MEDIA_ALIGN(y_stride * y_sclines, 4096);
plane_info->buf_size[HFI_COLOR_PLANE_UV_META] =
MSM_MEDIA_ALIGN(uv_meta_stride * uv_meta_sclines, 4096);
plane_info->buf_size[HFI_COLOR_PLANE_UV] =
MSM_MEDIA_ALIGN(uv_stride * uv_sclines, 4096);
break;
}
default:
dprintk(VIDC_ERR, "%s: invalid color_fmt %#x\n",
__func__, color_fmt);
rc = -EINVAL;
break;
}
return rc;
}
static int msm_cvp_free_buffer(struct msm_vidc_inst *inst,
struct msm_cvp_buf *buffer)
{
struct msm_cvp_external *cvp;
if (!inst || !inst->cvp || !buffer) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
if (buffer->kvaddr) {
dma_buf_vunmap(buffer->dbuf, buffer->kvaddr);
buffer->kvaddr = NULL;
}
if (buffer->dbuf) {
dma_buf_put(buffer->dbuf);
buffer->dbuf = NULL;
}
return 0;
}
static int msm_cvp_allocate_buffer(struct msm_vidc_inst *inst,
struct msm_cvp_buf *buffer, bool kernel_map)
{
int rc = 0;
struct msm_cvp_external *cvp;
int ion_flags = 0;
unsigned long heap_mask = 0;
struct dma_buf *dbuf;
int fd;
if (!inst || !inst->cvp || !buffer) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
heap_mask = ION_HEAP(ION_SYSTEM_HEAP_ID);
if (inst->flags & VIDC_SECURE) {
ion_flags = ION_FLAG_SECURE | ION_FLAG_CP_NON_PIXEL;
heap_mask = ION_HEAP(ION_SECURE_HEAP_ID);
}
dbuf = ion_alloc(buffer->size, heap_mask, ion_flags);
if (IS_ERR_OR_NULL(dbuf)) {
dprintk(VIDC_ERR,
"%s: failed to allocate, size %d heap_mask %#lx flags %d\n",
__func__, buffer->size, heap_mask, ion_flags);
rc = -ENOMEM;
goto error;
}
buffer->dbuf = dbuf;
fd = dma_buf_fd(dbuf, O_CLOEXEC);
if (fd < 0) {
dprintk(VIDC_ERR, "%s: failed to get fd\n", __func__);
rc = -ENOMEM;
goto error;
}
buffer->fd = fd;
if (kernel_map) {
buffer->kvaddr = dma_buf_vmap(dbuf);
if (!buffer->kvaddr) {
dprintk(VIDC_ERR,
"%s: dma_buf_vmap failed\n", __func__);
rc = -EINVAL;
goto error;
}
} else {
buffer->kvaddr = NULL;
}
buffer->index = cvp->buffer_idx++;
buffer->offset = 0;
return 0;
error:
msm_cvp_free_buffer(inst, buffer);
return rc;
}
static 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) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
ds_width = cvp->width;
ds_height = cvp->height;
if (!cvp->downscale) {
dprintk(VIDC_HIGH, "%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 (height > 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) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return;
}
cvp = inst->cvp;
dprintk(VIDC_HIGH, "%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) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
if (!cvp->downscale) {
dprintk(VIDC_HIGH, "%s: downscaling not enabled\n", __func__);
return 0;
}
dprintk(VIDC_HIGH, "%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) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return;
}
cvp = inst->cvp;
dprintk(VIDC_HIGH, "%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) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
dprintk(VIDC_HIGH, "%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;
struct cvp_kmd_arg *arg;
struct msm_cvp_session_release_persist_buffers_packet persist2_packet;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return;
}
cvp = inst->cvp;
dprintk(VIDC_HIGH, "%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);
memset(&persist2_packet, 0, sizeof(struct
msm_cvp_session_release_persist_buffers_packet));
persist2_packet.size = sizeof(struct
msm_cvp_session_release_persist_buffers_packet);
persist2_packet.packet_type =
HFI_CMD_SESSION_CVP_RELEASE_PERSIST_BUFFERS;
persist2_packet.session_id = cvp->session_id;
persist2_packet.cvp_op = CVP_DME;
persist2_packet.persist2_buffer.buffer_addr =
cvp->persist2_buffer.fd;
persist2_packet.persist2_buffer.size =
cvp->persist2_buffer.size;
arg = kzalloc(sizeof(struct cvp_kmd_arg), GFP_KERNEL);
if (arg) {
arg->type = CVP_KMD_HFI_PERSIST_CMD;
arg->buf_offset = offsetof(struct
msm_cvp_session_release_persist_buffers_packet,
persist1_buffer) / sizeof(u32);
arg->buf_num = (sizeof(struct
msm_cvp_session_release_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_release_persist_buffers_packet));
rc = msm_cvp_private(cvp->priv,
CVP_KMD_HFI_PERSIST_CMD, arg);
if (rc)
print_cvp_buffer(VIDC_ERR,
"release failed: persist2_buffer",
inst, &cvp->persist2_buffer);
kfree(arg);
} else {
dprintk(VIDC_ERR, "%s: alloc failed\n", __func__);
}
rc = msm_cvp_free_buffer(inst, &cvp->persist2_buffer);
if (rc)
print_cvp_buffer(VIDC_ERR,
"free failed: persist2_buffer",
inst, &cvp->persist2_buffer);
}
}
static int msm_cvp_init_internal_buffers(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
struct cvp_kmd_arg *arg;
struct msm_cvp_session_set_persist_buffers_packet persist2_packet;
if (!inst || !inst->cvp || !inst->cvp->arg) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
arg = cvp->arg;
dprintk(VIDC_HIGH, "%s:\n", __func__);
cvp->persist2_buffer.size = HFI_DME_INTERNAL_PERSIST_2_BUFFER_SIZE;
rc = msm_cvp_allocate_buffer(inst, &cvp->persist2_buffer, false);
if (rc) {
print_cvp_buffer(VIDC_ERR,
"allocate failed: persist2_buffer",
inst, &cvp->persist2_buffer);
goto error;
}
print_cvp_buffer(VIDC_HIGH, "alloc: persist2_buffer",
inst, &cvp->persist2_buffer);
/* set buffer */
memset(&persist2_packet, 0,
sizeof(struct msm_cvp_session_set_persist_buffers_packet));
persist2_packet.size =
sizeof(struct msm_cvp_session_set_persist_buffers_packet);
persist2_packet.packet_type = HFI_CMD_SESSION_CVP_SET_PERSIST_BUFFERS;
persist2_packet.session_id = cvp->session_id;
persist2_packet.cvp_op = CVP_DME;
persist2_packet.persist2_buffer.buffer_addr = cvp->persist2_buffer.fd;
persist2_packet.persist2_buffer.size = cvp->persist2_buffer.size;
memset(arg, 0, sizeof(struct cvp_kmd_arg));
arg->type = CVP_KMD_HFI_PERSIST_CMD;
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);
goto error;
}
/* allocate one output buffer for internal use */
cvp->output_buffer.size = HFI_DME_OUTPUT_BUFFER_SIZE;
rc = msm_cvp_allocate_buffer(inst, &cvp->output_buffer, true);
if (rc) {
print_cvp_buffer(VIDC_ERR,
"allocate failed: output_buffer",
inst, &cvp->output_buffer);
goto error;
}
print_cvp_buffer(VIDC_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;
if (!inst || !inst->cvp || !mbuf) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
vb = &mbuf->vvb.vb2_buf;
if (vb->num_planes <= 1) {
dprintk(VIDC_ERR, "%s: extradata plane not enabled\n",
__func__);
return -EINVAL;
}
dbuf = dma_buf_get(vb->planes[1].m.fd);
if (!dbuf) {
dprintk(VIDC_ERR, "%s: dma_buf_get(%d) failed\n",
__func__, vb->planes[1].m.fd);
return -EINVAL;
}
if (dbuf->size < vb->planes[1].length) {
dprintk(VIDC_ERR, "%s: invalid size %d vs %d\n", __func__,
dbuf->size, vb->planes[1].length);
rc = -EINVAL;
goto error;
}
rc = dma_buf_begin_cpu_access(dbuf, DMA_BIDIRECTIONAL);
if (rc) {
dprintk(VIDC_ERR, "%s: begin_cpu_access failed\n", __func__);
goto error;
}
kvaddr = dma_buf_vmap(dbuf);
if (!kvaddr) {
dprintk(VIDC_ERR, "%s: dma_buf_vmap(%d) failed\n",
__func__, vb->planes[1].m.fd);
rc = -EINVAL;
goto error;
}
e_hdr = (struct msm_vidc_extradata_header *)((char *)kvaddr +
vb->planes[1].data_offset);
input_extradata =
!!((inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_ROI) ||
(inst->prop.extradata_ctrls & EXTRADATA_ENC_INPUT_HDR10PLUS));
found_end = false;
while ((char *)e_hdr < (char *)(kvaddr + dbuf->size)) {
if (!input_extradata) {
found_end = true;
break;
}
if (e_hdr->type == MSM_VIDC_EXTRADATA_NONE) {
found_end = true;
break;
}
e_hdr += e_hdr->size;
}
if (!found_end) {
dprintk(VIDC_ERR, "%s: extradata_none not found\n", __func__);
e_hdr = (struct msm_vidc_extradata_header *)((char *)kvaddr +
vb->planes[1].data_offset);
}
/* check if sufficient space available */
if (((char *)e_hdr + sizeof(struct msm_vidc_extradata_header) +
sizeof(struct msm_vidc_enc_cvp_metadata_payload) +
sizeof(struct msm_vidc_extradata_header)) >
(kvaddr + dbuf->size)) {
dprintk(VIDC_ERR,
"%s: couldn't append extradata, (e_hdr[%pK] - kvaddr[%pK]) %#x, size %d\n",
__func__, e_hdr, kvaddr, (char *)e_hdr - (char *)kvaddr,
dbuf->size);
goto error;
}
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));
dma_buf_end_cpu_access(cvp->output_buffer.dbuf,
DMA_BIDIRECTIONAL);
}
/* fill extradata none */
e_hdr = (struct msm_vidc_extradata_header *)
((char *)e_hdr + e_hdr->size);
e_hdr->version = 0x00000001;
e_hdr->port_index = 1;
e_hdr->type = MSM_VIDC_EXTRADATA_NONE;
e_hdr->data_size = 0;
e_hdr->size = sizeof(struct msm_vidc_extradata_header) +
e_hdr->data_size;
dma_buf_vunmap(dbuf, kvaddr);
dma_buf_end_cpu_access(dbuf, DMA_BIDIRECTIONAL);
dma_buf_put(dbuf);
return rc;
error:
if (kvaddr) {
dma_buf_vunmap(dbuf, kvaddr);
dma_buf_end_cpu_access(dbuf, DMA_BIDIRECTIONAL);
}
if (dbuf)
dma_buf_put(dbuf);
return rc;
}
static int msm_cvp_reference_management(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
struct msm_cvp_buf temp;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
/* swap context buffers */
memcpy(&temp, &cvp->refcontext_buffer, sizeof(struct msm_cvp_buf));
memcpy(&cvp->refcontext_buffer, &cvp->context_buffer,
sizeof(struct msm_cvp_buf));
memcpy(&cvp->context_buffer, &temp, sizeof(struct msm_cvp_buf));
/* swap downscale buffers */
if (cvp->downscale) {
memcpy(&temp, &cvp->ref_buffer, sizeof(struct msm_cvp_buf));
memcpy(&cvp->ref_buffer, &cvp->src_buffer,
sizeof(struct msm_cvp_buf));
memcpy(&cvp->src_buffer, &temp, sizeof(struct msm_cvp_buf));
}
return rc;
}
static int msm_cvp_frame_process(struct msm_vidc_inst *inst,
struct 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 = 60;
u32 fps, skip_framecount;
bool skipframe = false;
if (!inst || !inst->cvp || !inst->cvp->arg || !mbuf) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
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;
/* frame skip logic */
fps = max(inst->clk_data.operating_rate,
inst->clk_data.frame_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 = ALIGN(fps, fps_max);
skip_framecount = fps / fps_max;
skipframe = !(cvp->framecount % skip_framecount);
}
if (skipframe) {
print_cvp_buffer(VIDC_LOW, "input frame skipped",
inst, &cvp->fullres_buffer);
cvp->framecount++;
cvp->metadata_available = false;
return 0;
}
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->session_id = cvp->session_id;
if (!cvp->framecount)
frame->skip_mv_calc = 1;
else
frame->skip_mv_calc = 0;
frame->min_fpx_threshold = 2;
frame->enable_descriptor_lpf = 1;
frame->enable_ncc_subpel = 1;
frame->descmatch_threshold = 52;
frame->ncc_robustness_threshold = 0;
frame->fullres_srcbuffer.buffer_addr = cvp->fullres_buffer.fd;
frame->fullres_srcbuffer.size = cvp->fullres_buffer.size;
frame->videospatialtemporal_statsbuffer.buffer_addr =
cvp->output_buffer.fd;
frame->videospatialtemporal_statsbuffer.size =
cvp->output_buffer.size;
frame->src_buffer.buffer_addr = cvp->fullres_buffer.fd;
frame->src_buffer.size = cvp->fullres_buffer.size;
if (cvp->downscale) {
frame->src_buffer.buffer_addr = cvp->src_buffer.fd;
frame->src_buffer.size = cvp->src_buffer.size;
frame->ref_buffer.buffer_addr = cvp->ref_buffer.fd;
frame->ref_buffer.size = cvp->ref_buffer.size;
}
frame->srcframe_contextbuffer.buffer_addr = cvp->context_buffer.fd;
frame->srcframe_contextbuffer.size = cvp->context_buffer.size;
frame->refframe_contextbuffer.buffer_addr = cvp->refcontext_buffer.fd;
frame->refframe_contextbuffer.size = cvp->refcontext_buffer.size;
print_cvp_buffer(VIDC_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) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
if (inst->state != MSM_VIDC_START_DONE) {
dprintk(VIDC_ERR, "%s: invalid inst state %d\n",
__func__, inst->state);
return -EINVAL;
}
cvp = inst->cvp;
rc = msm_cvp_frame_process(inst, mbuf);
if (rc) {
dprintk(VIDC_ERR, "%s: cvp process failed\n", __func__);
return rc;
}
rc = msm_cvp_prepare_extradata(inst, mbuf);
if (rc) {
dprintk(VIDC_ERR, "%s: prepare extradata failed\n", __func__);
return rc;
}
rc = msm_cvp_reference_management(inst);
if (rc) {
dprintk(VIDC_ERR, "%s: ref management failed\n", __func__);
return rc;
}
return rc;
}
static int msm_vidc_cvp_deinit(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
dprintk(VIDC_HIGH, "%s: cvp session %#x\n", __func__, cvp->session_id);
msm_cvp_deinit_internal_buffers(inst);
msm_cvp_deinit_context_buffers(inst);
msm_cvp_deinit_downscale_buffers(inst);
return rc;
}
static int msm_vidc_cvp_close(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
if (!inst || !inst->cvp) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
dprintk(VIDC_HIGH, "%s: cvp session %#x\n", __func__, cvp->session_id);
rc = msm_cvp_close(cvp->priv);
if (rc)
dprintk(VIDC_ERR,
"%s: cvp close failed with error %d\n", __func__, rc);
cvp->priv = NULL;
kfree(cvp->arg);
cvp->arg = NULL;
kfree(inst->cvp);
inst->cvp = NULL;
return rc;
}
int msm_vidc_cvp_unprepare_preprocess(struct msm_vidc_inst *inst)
{
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
if (!inst->cvp) {
dprintk(VIDC_HIGH, "%s: cvp not enabled or closed\n", __func__);
return 0;
}
msm_vidc_cvp_deinit(inst);
msm_vidc_cvp_close(inst);
return 0;
}
static int msm_vidc_cvp_init(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
struct v4l2_format *f;
struct cvp_kmd_arg *arg;
struct msm_cvp_dme_basic_config_packet *dmecfg;
u32 color_fmt;
if (!inst || !inst->cvp || !inst->cvp->arg) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
cvp = inst->cvp;
arg = cvp->arg;
cvp->framecount = 0;
cvp->metadata_available = false;
f = &inst->fmts[INPUT_PORT].v4l2_fmt;
cvp->width = f->fmt.pix_mp.width;
cvp->height = f->fmt.pix_mp.height;
color_fmt = msm_comm_convert_color_fmt(f->fmt.pix_mp.pixelformat);
/* enable downscale always */
cvp->downscale = true;
rc = msm_cvp_init_downscale_resolution(inst);
if (rc)
goto error;
dprintk(VIDC_HIGH,
"%s: pixelformat %#x, wxh %dx%d downscale %d ds_wxh %dx%d\n",
__func__, f->fmt.pix_mp.pixelformat,
cvp->width, cvp->height, cvp->downscale,
cvp->ds_width, cvp->ds_height);
memset(arg, 0, sizeof(struct cvp_kmd_arg));
arg->type = CVP_KMD_SEND_CMD_PKT;
dmecfg = (struct msm_cvp_dme_basic_config_packet *)
&arg->data.hfi_pkt.pkt_data;
dmecfg->size = sizeof(struct msm_cvp_dme_basic_config_packet);
dmecfg->packet_type = HFI_CMD_SESSION_CVP_DME_BASIC_CONFIG;
dmecfg->session_id = cvp->session_id;
/* source buffer format should be NV12_UBWC always */
dmecfg->srcbuffer_format = HFI_COLOR_FORMAT_NV12_UBWC;
dmecfg->src_width = cvp->ds_width;
dmecfg->src_height = cvp->ds_height;
rc = msm_cvp_fill_planeinfo(&dmecfg->srcbuffer_planeinfo,
COLOR_FMT_NV12_UBWC, dmecfg->src_width, dmecfg->src_height);
if (rc)
goto error;
dmecfg->fullresbuffer_format = msm_comm_get_hfi_uncompressed(
f->fmt.pix_mp.pixelformat);
dmecfg->fullres_width = cvp->width;
dmecfg->fullres_height = cvp->height;
rc = msm_cvp_fill_planeinfo(&dmecfg->fullresbuffer_planeinfo,
color_fmt, dmecfg->fullres_width, dmecfg->fullres_height);
if (rc)
goto error;
dmecfg->ds_enable = cvp->downscale;
dmecfg->enable_lrme_robustness = 1;
dmecfg->enable_inlier_tracking = 1;
rc = msm_cvp_private(cvp->priv, CVP_KMD_SEND_CMD_PKT, arg);
if (rc) {
dprintk(VIDC_ERR, "%s: cvp configuration failed\n", __func__);
goto error;
}
rc = msm_cvp_init_downscale_buffers(inst);
if (rc)
goto error;
rc = msm_cvp_init_internal_buffers(inst);
if (rc)
goto error;
rc = msm_cvp_init_context_buffers(inst);
if (rc)
goto error;
return rc;
error:
msm_vidc_cvp_deinit(inst);
return rc;
}
static int msm_vidc_cvp_open(struct msm_vidc_inst *inst)
{
int rc = 0;
struct msm_cvp_external *cvp;
struct cvp_kmd_arg *arg;
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
inst->cvp = kzalloc(sizeof(struct msm_cvp_external), GFP_KERNEL);
if (!inst->cvp) {
dprintk(VIDC_ERR, "%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;
}
arg = cvp->arg;
dprintk(VIDC_HIGH, "%s: opening cvp\n", __func__);
cvp->priv = msm_cvp_open(0, MSM_VIDC_CVP);
if (!cvp->priv) {
dprintk(VIDC_ERR, "%s: failed to open cvp session\n", __func__);
rc = -EINVAL;
goto error;
}
memset(arg, 0, sizeof(struct cvp_kmd_arg));
arg->type = CVP_KMD_GET_SESSION_INFO;
rc = msm_cvp_private(cvp->priv, CVP_KMD_GET_SESSION_INFO, arg);
if (rc) {
dprintk(VIDC_ERR, "%s: get_session_info failed\n", __func__);
goto error;
}
cvp->session_id = arg->data.session.session_id;
dprintk(VIDC_HIGH, "%s: cvp session id %#x\n",
__func__, cvp->session_id);
rc = msm_cvp_get_version_info(inst);
if (rc) {
dprintk(VIDC_ERR, "%s: get_version_info failed\n", __func__);
goto error;
}
return 0;
error:
msm_vidc_cvp_close(inst);
return rc;
}
int msm_vidc_cvp_prepare_preprocess(struct msm_vidc_inst *inst)
{
int rc;
if (!inst) {
dprintk(VIDC_ERR, "%s: invalid params\n", __func__);
return -EINVAL;
}
rc = msm_vidc_cvp_open(inst);
if (rc)
return rc;
rc = msm_vidc_cvp_init(inst);
if (rc)
return rc;
return 0;
}