blob: e1fe0e9394f91d6d45e85f2c450f490022b50d57 [file] [log] [blame]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/dma-buf.h>
#include <linux/sync_file.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <dev_ion.h>
#include <linux/amlogic/media/vfm/vframe.h>
#include <linux/amlogic/media/video_sink/v4lvideo_ext.h>
#include <linux/amlogic/media/codec_mm/codec_mm.h>
#include <linux/amlogic/media/utils/am_com.h>
#include "meson_uvm_nn_processor.h"
static int uvm_nn_debug;
module_param(uvm_nn_debug, int, 0644);
static int uvm_open_nn;
module_param(uvm_open_nn, int, 0644);
#define PRINT_ERROR 0X0
#define PRINT_OTHER 0X0001
#define PRINT_NN_DUMP 0X0002
int nn_print(int debug_flag, const char *fmt, ...)
{
if ((uvm_nn_debug & debug_flag) ||
debug_flag == PRINT_ERROR) {
unsigned char buf[256];
int len = 0;
va_list args;
va_start(args, fmt);
len = sprintf(buf, "uvm_nn:[%d]", 0);
vsnprintf(buf + len, 256 - len, fmt, args);
pr_info("%s", buf);
va_end(args);
}
return 0;
}
int nn_get_hf_info(int shared_fd, struct vf_nn_sr_t *nn_sr, int *di_flag)
{
struct uvm_hook_mod *uhmod = NULL;
struct dma_buf *dmabuf = NULL;
bool is_dec_vf = false, is_v4l_vf = false;
struct vframe_s *vf = NULL;
struct file_private_data *file_private_data = NULL;
struct hf_info_t *hf_info;
dmabuf = dma_buf_get(shared_fd);
if (IS_ERR_OR_NULL(dmabuf)) {
nn_print(PRINT_ERROR,
"Invalid dmabuf %s %d\n", __func__, __LINE__);
return -EINVAL;
}
if (!dmabuf_is_uvm(dmabuf)) {
nn_print(PRINT_ERROR,
"%s: dmabuf is not uvm.dmabuf=%px, shared_fd=%d\n",
__func__, dmabuf, shared_fd);
dma_buf_put(dmabuf);
return -EINVAL;
}
is_dec_vf = is_valid_mod_type(dmabuf, VF_SRC_DECODER);
is_v4l_vf = is_valid_mod_type(dmabuf, VF_PROCESS_V4LVIDEO);
if (is_dec_vf) {
vf = dmabuf_get_vframe(dmabuf);
if (vf->vf_ext && (vf->flag & VFRAME_FLAG_CONTAIN_POST_FRAME))
vf = vf->vf_ext;
nn_print(PRINT_OTHER, "vframe type: %d\n", vf->type);
dmabuf_put_vframe(dmabuf);
} else {
uhmod = uvm_get_hook_mod(dmabuf, VF_PROCESS_V4LVIDEO);
if (IS_ERR_OR_NULL(uhmod) || !uhmod->arg) {
nn_print(PRINT_OTHER, "get_fh err: no v4lvideo\n");
dma_buf_put(dmabuf);
return -EINVAL;
}
file_private_data = uhmod->arg;
uvm_put_hook_mod(dmabuf, VF_PROCESS_V4LVIDEO);
if (!file_private_data)
nn_print(PRINT_ERROR, "invalid fd no uvm/v4lvideo\n");
else
vf = &file_private_data->vf;
}
if (vf) {
hf_info = vf->hf_info;
if (hf_info) {
nn_sr->hf_phy_addr = hf_info->phy_addr;
nn_sr->hf_width = hf_info->width;
nn_sr->hf_height = hf_info->height;
nn_sr->hf_align_w = hf_info->buffer_w;
nn_sr->hf_align_h = hf_info->buffer_h;
if (vf->type_original & VIDTYPE_INTERLACE)
*di_flag = 1;
else
*di_flag = 0;
nn_print(PRINT_OTHER, "has hf:phy=%llx omx_index=%d\n",
hf_info->phy_addr, vf->omx_index);
} else {
nn_print(PRINT_OTHER, "no hf info\n");
nn_sr->hf_phy_addr = 0;
nn_sr->hf_width = 0;
nn_sr->hf_height = 0;
*di_flag = 0;
}
} else {
nn_print(PRINT_ERROR, "not find vf\n");
dma_buf_put(dmabuf);
return -EINVAL;
}
dma_buf_put(dmabuf);
return 0;
}
void free_nn_data(void *arg)
{
struct vf_nn_sr_t *nn_sr = (struct vf_nn_sr_t *)arg;
if (arg) {
nn_print(PRINT_OTHER, "%s: nn_out_file_count =%d, nn_sr=%px\n",
__func__, nn_sr->nn_out_file_count, nn_sr);
if (nn_sr->nn_out_file) {
fput(nn_sr->nn_out_file);
if (nn_sr->nn_out_file_count == 0)
nn_print(PRINT_ERROR,
"%s: nn_out_file_count is 0!!\n", __func__);
nn_sr->nn_out_file_count--;
}
kfree((u8 *)arg);
} else {
nn_print(PRINT_ERROR, "%s: arg is NULL\n", __func__);
}
}
int attach_nn_hook_mod_info(int shared_fd,
char *buf, struct uvm_hook_mod_info *info)
{
struct vf_nn_sr_t *nn_sr = NULL;
int ret = 0;
struct uvm_hook_mod *uhmod = NULL;
struct dma_buf *dmabuf = NULL;
struct uvm_handle *handle;
struct uvm_ai_sr_info *ai_sr_info = (struct uvm_ai_sr_info *)buf;
struct vf_nn_sr_t nn_sr_t;
bool attached = false;
int src_interlace_flag = 0;
memset(&nn_sr_t, 0, sizeof(struct vf_nn_sr_t));
if (!uvm_open_nn) {
ai_sr_info->hf_phy_addr = 0;
ai_sr_info->hf_width = 0;
ai_sr_info->hf_height = 0;
} else {
ret = nn_get_hf_info(shared_fd, &nn_sr_t, &src_interlace_flag);
ai_sr_info->hf_phy_addr = nn_sr_t.hf_phy_addr;
ai_sr_info->hf_width = nn_sr_t.hf_width;
ai_sr_info->hf_height = nn_sr_t.hf_height;
}
if (ret) {
nn_print(PRINT_OTHER, "attach:get hf info error\n");
return -EINVAL;
}
dmabuf = dma_buf_get(shared_fd);
if (IS_ERR_OR_NULL(dmabuf)) {
nn_print(PRINT_ERROR,
"Invalid dmabuf %s %d\n", __func__, __LINE__);
return -EINVAL;
}
if (!dmabuf_is_uvm(dmabuf)) {
nn_print(PRINT_ERROR,
"attach:dmabuf is not uvm.dmabuf=%px, shared_fd=%d\n",
dmabuf, shared_fd);
dma_buf_put(dmabuf);
return -EINVAL;
}
handle = dmabuf->priv;
uhmod = uvm_get_hook_mod(dmabuf, PROCESS_NN);
if (IS_ERR_OR_NULL(uhmod)) {
nn_sr = kzalloc(sizeof(*nn_sr), GFP_KERNEL);
nn_print(PRINT_OTHER, "attach:first attach, need alloc\n");
if (!nn_sr) {
dma_buf_put(dmabuf);
return -ENOMEM;
}
} else {
uvm_put_hook_mod(dmabuf, PROCESS_NN);
attached = true;
nn_sr = uhmod->arg;
if (!nn_sr) {
nn_print(PRINT_ERROR,
"attach:nn_sr is null, dmabuf=%p\n", dmabuf);
dma_buf_put(dmabuf);
return -EINVAL;
}
nn_print(PRINT_OTHER, "nn_sr=%px\n", nn_sr);
if (nn_sr->nn_out_file_count != 0) {
fput(nn_sr->nn_out_file);
nn_sr->nn_out_file_count--;
} else {
nn_print(PRINT_OTHER,
"%s: nn_out_file_count is 0!!\n", __func__);
}
memset(nn_sr, 0, sizeof(struct vf_nn_sr_t));
}
*nn_sr = nn_sr_t;
nn_sr->nn_status = ai_sr_info->nn_status;
nn_print(PRINT_OTHER,
"attach: shared_fd=%d, fence_fd=%d, %d*%d, nn_status=%d, nn_sr=%px\n",
ai_sr_info->shared_fd,
ai_sr_info->fence_fd,
ai_sr_info->hf_width,
ai_sr_info->hf_height,
nn_sr->nn_status,
nn_sr);
nn_sr->nn_out_dma_buf = NULL;
nn_sr->shared_fd = shared_fd;
if (ai_sr_info->fence_fd != -1)
nn_sr->fence = sync_file_get_fence(ai_sr_info->fence_fd);
else
nn_sr->fence = NULL;
dma_buf_put(dmabuf);
if (attached)
return 0;
info->type = PROCESS_NN;
info->arg = nn_sr;
info->free = free_nn_data;
info->acquire_fence = NULL;
info->getinfo = nn_mod_getinfo;
info->setinfo = nn_mod_setinfo;
return 0;
}
int dump_hf(struct vf_nn_sr_t *nn_sr_dst)
{
struct file *fp;
char name_buf[32];
int write_size;
u8 *data;
mm_segment_t fs;
loff_t pos;
snprintf(name_buf, sizeof(name_buf), "/data/tmp/hf.yuv");
fp = filp_open(name_buf, O_CREAT | O_RDWR, 0644);
if (IS_ERR(fp))
return -1;
write_size = nn_sr_dst->hf_align_w * nn_sr_dst->hf_align_h;
data = codec_mm_vmap(nn_sr_dst->hf_phy_addr, write_size);
if (!data)
return -2;
fs = get_fs();
set_fs(KERNEL_DS);
pos = 0;
vfs_write(fp, data, write_size, &pos);
vfs_fsync(fp, 0);
nn_print(PRINT_OTHER, "nn: write %u size to addr%p\n", write_size, data);
codec_mm_unmap_phyaddr(data);
filp_close(fp, NULL);
set_fs(fs);
return 0;
}
int nn_mod_setinfo(void *arg, char *buf)
{
struct uvm_ai_sr_info *nn_sr_src = NULL;
struct vf_nn_sr_t *nn_sr_dst = NULL;
int nn_out_fd;
int ret = -1;
size_t len;
phys_addr_t addr = 0;
nn_sr_src = (struct uvm_ai_sr_info *)buf;
nn_sr_dst = (struct vf_nn_sr_t *)arg;
nn_out_fd = nn_sr_src->nn_out_fd;
if (nn_out_fd != -1) {
nn_sr_dst->nn_out_file = fget(nn_out_fd);
fput(nn_sr_dst->nn_out_file);
nn_sr_dst->nn_out_dma_buf = NULL;
ret = meson_ion_share_fd_to_phys(nn_out_fd, &addr, &len);
if (ret < 0) {
nn_print(PRINT_ERROR, "import out fd %d failed\n", nn_out_fd);
return -EINVAL;
}
nn_sr_dst->nn_out_phy_addr = addr;
} else {
nn_sr_dst->nn_out_dma_buf = NULL;
nn_sr_dst->nn_out_phy_addr = 0;
}
nn_sr_dst->nn_index = nn_sr_src->nn_index;
nn_sr_dst->nn_out_width = nn_sr_src->nn_out_width;
nn_sr_dst->nn_out_height = nn_sr_src->nn_out_height;
nn_sr_dst->nn_mode = nn_sr_src->nn_mode;
if (nn_sr_src->nn_status == NN_START_DOING) {
do_gettimeofday(&nn_sr_dst->start_time);
get_file(nn_sr_dst->nn_out_file);
nn_sr_dst->nn_out_file_count++;
}
nn_sr_dst->nn_status = nn_sr_src->nn_status;/*this must at the last line of this function*/
nn_print(PRINT_OTHER,
"setinfo: shared_fd =%d, nn_fd=%d,status=%d, nn_index=%d, nn_mode=%d\n",
nn_sr_src->shared_fd, nn_out_fd,
nn_sr_src->nn_status,
nn_sr_src->nn_index,
nn_sr_dst->nn_mode);
return 0;
}
int nn_mod_getinfo(void *arg, char *buf)
{
struct vf_nn_sr_t *vf_nn_sr = NULL;
struct uvm_ai_sr_info *si_sr_info = NULL;
int ret = -1;
phys_addr_t addr = 0;
u8 *data_hf;
u8 *data_tmp;
int hf_size;
int src_interlace_flag = 0;
si_sr_info = (struct uvm_ai_sr_info *)buf;
vf_nn_sr = (struct vf_nn_sr_t *)arg;
if (si_sr_info->get_info_type != GET_HF_INFO &&
si_sr_info->get_info_type != GET_HF_DATA) {
nn_print(PRINT_ERROR, "%s: err get_info_type =%d\n",
__func__, si_sr_info->get_info_type);
return -EINVAL;
}
if (si_sr_info->get_info_type == GET_HF_INFO) {
ret = nn_get_hf_info(si_sr_info->shared_fd,
vf_nn_sr,
&src_interlace_flag);
if (ret) {
nn_print(PRINT_OTHER, "get hf info error\n");
return -EINVAL;
}
}
si_sr_info->hf_phy_addr = vf_nn_sr->hf_phy_addr;
si_sr_info->hf_width = vf_nn_sr->hf_width;
si_sr_info->hf_height = vf_nn_sr->hf_height;
si_sr_info->hf_align_w = vf_nn_sr->hf_align_w;
si_sr_info->hf_align_h = vf_nn_sr->hf_align_h;
si_sr_info->nn_out_phy_addr = vf_nn_sr->nn_out_phy_addr;
si_sr_info->nn_status = vf_nn_sr->nn_status;
si_sr_info->nn_index = vf_nn_sr->nn_index;
si_sr_info->src_interlace_flag = src_interlace_flag;
if (si_sr_info->get_info_type == GET_HF_INFO) {
nn_print(PRINT_OTHER, "getinfo: hf_phy_addr=%llx, %d*%d\n",
si_sr_info->hf_phy_addr,
si_sr_info->hf_width,
si_sr_info->hf_height);
return 0;
}
if ((uvm_nn_debug & PRINT_NN_DUMP) &&
si_sr_info->hf_phy_addr) {
hf_size = si_sr_info->hf_align_w * si_sr_info->hf_align_h;
data_hf = codec_mm_vmap(si_sr_info->hf_phy_addr, hf_size);
data_tmp = codec_mm_vmap(addr, hf_size);
if (data_hf && data_tmp)
memcpy(data_tmp, data_hf, hf_size);
if (data_hf)
codec_mm_unmap_phyaddr(data_hf);
if (data_tmp)
codec_mm_unmap_phyaddr(data_tmp);
}
return 0;
}