364 lines
9.9 KiB
C
364 lines
9.9 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2019 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/module.h>
|
|
#include <media/v4l2-mem2mem.h>
|
|
#include <media/videobuf2-dma-contig.h>
|
|
|
|
#include "mtk_vcodec_drv.h"
|
|
#include "mtk_vcodec_util.h"
|
|
#include "mtk_vcu.h"
|
|
#include "mtk_vcodec_dec.h"
|
|
#include "vdec_drv_if.h"
|
|
#include "venc_drv_if.h"
|
|
|
|
#define LOG_INFO_SIZE 64
|
|
#define MAX_SUPPORTED_LOG_PARAMS_COUNT 12
|
|
|
|
/* For encoder, this will enable logs in venc/*/
|
|
bool mtk_vcodec_dbg;
|
|
EXPORT_SYMBOL(mtk_vcodec_dbg);
|
|
|
|
/* For vcodec performance measure */
|
|
bool mtk_vcodec_perf;
|
|
EXPORT_SYMBOL(mtk_vcodec_perf);
|
|
|
|
/* The log level of v4l2 encoder or decoder driver.
|
|
* That is, files under mtk-vcodec/.
|
|
*/
|
|
int mtk_v4l2_dbg_level;
|
|
EXPORT_SYMBOL(mtk_v4l2_dbg_level);
|
|
|
|
void __iomem *mtk_vcodec_get_dec_reg_addr(struct mtk_vcodec_ctx *data,
|
|
unsigned int reg_idx)
|
|
{
|
|
struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
|
|
|
|
if (!data || reg_idx >= NUM_MAX_VDEC_REG_BASE) {
|
|
mtk_v4l2_err("Invalid arguments, reg_idx=%d", reg_idx);
|
|
return NULL;
|
|
}
|
|
return ctx->dev->dec_reg_base[reg_idx];
|
|
}
|
|
EXPORT_SYMBOL(mtk_vcodec_get_dec_reg_addr);
|
|
|
|
void __iomem *mtk_vcodec_get_enc_reg_addr(struct mtk_vcodec_ctx *data,
|
|
unsigned int reg_idx)
|
|
{
|
|
struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
|
|
|
|
if (!data || reg_idx >= NUM_MAX_VENC_REG_BASE) {
|
|
mtk_v4l2_err("Invalid arguments, reg_idx=%d", reg_idx);
|
|
return NULL;
|
|
}
|
|
return ctx->dev->enc_reg_base[reg_idx];
|
|
}
|
|
EXPORT_SYMBOL(mtk_vcodec_get_enc_reg_addr);
|
|
|
|
|
|
int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data,
|
|
struct mtk_vcodec_mem *mem)
|
|
{
|
|
unsigned long size = mem->size;
|
|
struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
|
|
struct device *dev = &ctx->dev->plat_dev->dev;
|
|
|
|
mem->va = dma_alloc_coherent(dev, size, &mem->dma_addr, GFP_KERNEL);
|
|
|
|
if (!mem->va) {
|
|
mtk_v4l2_err("%s dma_alloc size=%ld failed!", dev_name(dev),
|
|
size);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
memset(mem->va, 0, size);
|
|
|
|
mtk_v4l2_debug(4, "[%d] - va = %p", ctx->id, mem->va);
|
|
mtk_v4l2_debug(4, "[%d] - dma = 0x%lx", ctx->id,
|
|
(unsigned long)mem->dma_addr);
|
|
mtk_v4l2_debug(4, "[%d] size = 0x%lx", ctx->id, size);
|
|
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(mtk_vcodec_mem_alloc);
|
|
|
|
void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data,
|
|
struct mtk_vcodec_mem *mem)
|
|
{
|
|
unsigned long size = mem->size;
|
|
struct mtk_vcodec_ctx *ctx = (struct mtk_vcodec_ctx *)data;
|
|
struct device *dev = &ctx->dev->plat_dev->dev;
|
|
|
|
if (!mem->va) {
|
|
mtk_v4l2_err("%s dma_free size=%ld failed!", dev_name(dev),
|
|
size);
|
|
return;
|
|
}
|
|
|
|
mtk_v4l2_debug(4, "[%d] - va = %p", ctx->id, mem->va);
|
|
mtk_v4l2_debug(4, "[%d] - dma = 0x%lx", ctx->id,
|
|
(unsigned long)mem->dma_addr);
|
|
mtk_v4l2_debug(4, "[%d] size = 0x%lx", ctx->id, size);
|
|
|
|
dma_free_coherent(dev, size, mem->va, mem->dma_addr);
|
|
mem->va = NULL;
|
|
mem->dma_addr = 0;
|
|
mem->size = 0;
|
|
}
|
|
EXPORT_SYMBOL(mtk_vcodec_mem_free);
|
|
|
|
void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *dev,
|
|
struct mtk_vcodec_ctx *ctx, unsigned int hw_id)
|
|
{
|
|
unsigned long flags;
|
|
|
|
spin_lock_irqsave(&dev->irqlock, flags);
|
|
dev->curr_dec_ctx[hw_id] = ctx;
|
|
spin_unlock_irqrestore(&dev->irqlock, flags);
|
|
}
|
|
EXPORT_SYMBOL(mtk_vcodec_set_curr_ctx);
|
|
|
|
struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *dev,
|
|
unsigned int hw_id)
|
|
{
|
|
unsigned long flags;
|
|
struct mtk_vcodec_ctx *ctx;
|
|
|
|
spin_lock_irqsave(&dev->irqlock, flags);
|
|
ctx = dev->curr_dec_ctx[hw_id];
|
|
spin_unlock_irqrestore(&dev->irqlock, flags);
|
|
return ctx;
|
|
}
|
|
EXPORT_SYMBOL(mtk_vcodec_get_curr_ctx);
|
|
|
|
void mtk_vcodec_add_ctx_list(struct mtk_vcodec_ctx *ctx)
|
|
{
|
|
mutex_lock(&ctx->dev->ctx_mutex);
|
|
list_add(&ctx->list, &ctx->dev->ctx_list);
|
|
mutex_unlock(&ctx->dev->ctx_mutex);
|
|
}
|
|
EXPORT_SYMBOL_GPL(mtk_vcodec_add_ctx_list);
|
|
|
|
void mtk_vcodec_del_ctx_list(struct mtk_vcodec_ctx *ctx)
|
|
{
|
|
mutex_lock(&ctx->dev->ctx_mutex);
|
|
list_del_init(&ctx->list);
|
|
mutex_unlock(&ctx->dev->ctx_mutex);
|
|
}
|
|
EXPORT_SYMBOL_GPL(mtk_vcodec_del_ctx_list);
|
|
|
|
|
|
struct vdec_fb *mtk_vcodec_get_fb(struct mtk_vcodec_ctx *ctx)
|
|
{
|
|
struct vb2_buffer *dst_buf, *src_buf;
|
|
struct vdec_fb *pfb;
|
|
struct mtk_video_dec_buf *dst_buf_info;
|
|
struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2;
|
|
int i;
|
|
|
|
if (!ctx) {
|
|
mtk_v4l2_err("Ctx is NULL!");
|
|
return NULL;
|
|
}
|
|
|
|
/* for getting timestamp*/
|
|
src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
|
|
src_vb2_v4l2 = container_of(src_buf, struct vb2_v4l2_buffer, vb2_buf);
|
|
|
|
mtk_v4l2_debug_enter();
|
|
dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
|
|
if (dst_buf != NULL) {
|
|
dst_vb2_v4l2 = container_of(
|
|
dst_buf, struct vb2_v4l2_buffer, vb2_buf);
|
|
dst_buf_info = container_of(
|
|
dst_vb2_v4l2, struct mtk_video_dec_buf, vb);
|
|
pfb = &dst_buf_info->frame_buffer;
|
|
pfb->num_planes = dst_vb2_v4l2->vb2_buf.num_planes;
|
|
pfb->index = dst_buf->index;
|
|
|
|
mutex_lock(&ctx->buf_lock);
|
|
for (i = 0; i < dst_vb2_v4l2->vb2_buf.num_planes; i++) {
|
|
pfb->fb_base[i].va = vb2_plane_vaddr(dst_buf, i);
|
|
#ifdef CONFIG_VB2_MEDIATEK_DMA_SG
|
|
pfb->fb_base[i].dma_addr =
|
|
mtk_vb2_dma_contig_plane_dma_addr(dst_buf, i);
|
|
#else
|
|
pfb->fb_base[i].dma_addr =
|
|
vb2_dma_contig_plane_dma_addr(dst_buf, i);
|
|
#endif
|
|
pfb->fb_base[i].size = ctx->picinfo.fb_sz[i];
|
|
pfb->fb_base[i].length = dst_buf->planes[i].length;
|
|
pfb->fb_base[i].dmabuf = dst_buf->planes[i].dbuf;
|
|
if (dst_buf_info->used == false) {
|
|
get_file(dst_buf->planes[i].dbuf->file);
|
|
mtk_v4l2_debug(4, "[Ref cnt] id=%d Ref get dma %p", dst_buf->index,
|
|
dst_buf->planes[i].dbuf);
|
|
}
|
|
}
|
|
pfb->status = 0;
|
|
dst_buf_info->used = true;
|
|
ctx->fb_list[pfb->index + 1] = (uintptr_t)pfb;
|
|
mutex_unlock(&ctx->buf_lock);
|
|
|
|
mtk_v4l2_debug(1, "[%d] id=%d pfb=0x%p %llx VA=%p dma_addr[0]=%lx dma_addr[1]=%lx Size=%zx fd:%x, dma_general_buf = %p, general_buf_fd = %d",
|
|
ctx->id, dst_buf->index, pfb, (unsigned long long)pfb,
|
|
pfb->fb_base[0].va,
|
|
(unsigned long)pfb->fb_base[0].dma_addr,
|
|
(unsigned long)pfb->fb_base[1].dma_addr,
|
|
pfb->fb_base[0].size,
|
|
dst_buf->planes[0].m.fd,
|
|
pfb->dma_general_buf,
|
|
pfb->general_buf_fd);
|
|
|
|
dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
|
|
if (dst_buf != NULL)
|
|
mtk_v4l2_debug(8, "[%d] index=%d, num_rdy_bufs=%d\n",
|
|
ctx->id, dst_buf->index,
|
|
v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx));
|
|
} else {
|
|
mtk_v4l2_err("[%d] No free framebuffer in v4l2!!\n", ctx->id);
|
|
pfb = NULL;
|
|
}
|
|
mtk_v4l2_debug_leave();
|
|
|
|
return pfb;
|
|
}
|
|
EXPORT_SYMBOL(mtk_vcodec_get_fb);
|
|
|
|
|
|
void v4l2_m2m_buf_queue_check(struct v4l2_m2m_ctx *m2m_ctx,
|
|
void *vbuf)
|
|
{
|
|
struct v4l2_m2m_buffer *b = container_of(vbuf,
|
|
struct v4l2_m2m_buffer, vb);
|
|
mtk_v4l2_debug(8, "[Debug] b %p b->list.next %p prev %p %p %p\n",
|
|
b, b->list.next, b->list.prev,
|
|
LIST_POISON1, LIST_POISON2);
|
|
|
|
if (WARN_ON(IS_ERR_OR_NULL(m2m_ctx) ||
|
|
(b->list.next != LIST_POISON1 && b->list.next) ||
|
|
(b->list.prev != LIST_POISON2 && b->list.prev))) {
|
|
v4l2_aee_print("b %p next %p prev %p already in rdyq %p %p\n",
|
|
b, b->list.next, b->list.prev,
|
|
LIST_POISON1, LIST_POISON2);
|
|
return;
|
|
}
|
|
v4l2_m2m_buf_queue(m2m_ctx, vbuf);
|
|
}
|
|
EXPORT_SYMBOL(v4l2_m2m_buf_queue_check);
|
|
|
|
void mtk_vcodec_set_log(struct mtk_vcodec_ctx *ctx, char *val)
|
|
{
|
|
int i, argc = 0;
|
|
char (*argv)[LOG_PARAM_INFO_SIZE] = NULL;
|
|
char *temp = NULL;
|
|
char *token = NULL;
|
|
long temp_val = 0;
|
|
char *log = NULL;
|
|
char vcu_log[128] = {0};
|
|
struct venc_enc_param *enc_prm = NULL;
|
|
|
|
if (ctx == NULL || val == NULL || strlen(val) == 0)
|
|
return;
|
|
|
|
mtk_v4l2_debug(0, "val: %s", val);
|
|
|
|
argv = kzalloc(MAX_SUPPORTED_LOG_PARAMS_COUNT * 2 * LOG_PARAM_INFO_SIZE, GFP_KERNEL);
|
|
if (!argv)
|
|
return;
|
|
log = kzalloc(LOG_PROPERTY_SIZE, GFP_KERNEL);
|
|
if (!log) {
|
|
kfree(argv);
|
|
return;
|
|
}
|
|
|
|
strncpy(log, val, LOG_PROPERTY_SIZE - 1);
|
|
temp = log;
|
|
for (token = strsep(&temp, "\n\r ");
|
|
token != NULL && argc < MAX_SUPPORTED_LOG_PARAMS_COUNT * 2;
|
|
token = strsep(&temp, "\n\r ")) {
|
|
if (strlen(token) == 0)
|
|
continue;
|
|
strncpy(argv[argc], token, LOG_PARAM_INFO_SIZE);
|
|
argv[argc][LOG_PARAM_INFO_SIZE - 1] = '\0';
|
|
argc++;
|
|
}
|
|
|
|
for (i = 0; i < argc-1; i += 2) {
|
|
if (strlen(argv[i]) == 0)
|
|
continue;
|
|
if (strcmp("-mtk_vcodec_dbg", argv[i]) == 0) {
|
|
if (kstrtol(argv[i+1], 0, &temp_val) == 0) {
|
|
mtk_vcodec_dbg = temp_val;
|
|
mtk_v4l2_debug(0, "mtk_vcodec_dbg: %d\n", mtk_vcodec_dbg);
|
|
}
|
|
} else if (strcmp("-mtk_vcodec_perf", argv[i]) == 0) {
|
|
if (kstrtol(argv[i+1], 0, &temp_val) == 0) {
|
|
mtk_vcodec_perf = temp_val;
|
|
mtk_v4l2_debug(0, "mtk_vcodec_perf: %d\n", mtk_vcodec_perf);
|
|
}
|
|
} else if (strcmp("-mtk_v4l2_dbg_level", argv[i]) == 0) {
|
|
if (kstrtol(argv[i+1], 0, &temp_val) == 0) {
|
|
mtk_v4l2_dbg_level = temp_val;
|
|
mtk_v4l2_debug(0, "mtk_v4l2_dbg_level: %d\n", mtk_v4l2_dbg_level);
|
|
}
|
|
} else {
|
|
memset(vcu_log, 0x00, sizeof(vcu_log));
|
|
snprintf(vcu_log, sizeof(vcu_log) - 1, "%s %s", argv[i], argv[i+1]);
|
|
if (ctx->type == MTK_INST_DECODER) {
|
|
vdec_if_set_param(ctx, SET_PARAM_DEC_LOG, vcu_log);
|
|
} else {
|
|
enc_prm = kzalloc(sizeof(*enc_prm), GFP_KERNEL);
|
|
if (enc_prm) {
|
|
enc_prm->log = vcu_log;
|
|
venc_if_set_param(ctx, VENC_SET_PARAM_LOG, enc_prm);
|
|
kfree(enc_prm);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
kfree(argv);
|
|
kfree(log);
|
|
}
|
|
|
|
void mtk_vcodec_get_log(struct mtk_vcodec_ctx *ctx, char *val)
|
|
{
|
|
int len = 0;
|
|
|
|
if (!ctx || !val) {
|
|
mtk_v4l2_err("Invalid arguments, ctx=0x%x, val=0x%x", ctx, val);
|
|
return;
|
|
}
|
|
|
|
memset(val, 0x00, LOG_PROPERTY_SIZE);
|
|
|
|
if (ctx->type == MTK_INST_DECODER)
|
|
vdec_if_get_param(ctx, GET_PARAM_DEC_LOG, val);
|
|
else
|
|
venc_if_get_param(ctx, VENC_GET_PARAM_LOG, val);
|
|
|
|
// join kernel log level
|
|
len = strlen(val);
|
|
if (len < LOG_PROPERTY_SIZE)
|
|
snprintf(val + len, LOG_PROPERTY_SIZE - 1 - len,
|
|
" %s %d", "-mtk_vcodec_dbg", mtk_vcodec_dbg);
|
|
|
|
len = strlen(val);
|
|
if (len < LOG_PROPERTY_SIZE)
|
|
snprintf(val + len, LOG_PROPERTY_SIZE - 1 - len,
|
|
" %s %d", "-mtk_vcodec_perf", mtk_vcodec_perf);
|
|
|
|
len = strlen(val);
|
|
if (len < LOG_PROPERTY_SIZE)
|
|
snprintf(val + len, LOG_PROPERTY_SIZE - 1 - len,
|
|
" %s %d", "-mtk_v4l2_dbg_level", mtk_v4l2_dbg_level);
|
|
|
|
mtk_v4l2_debug(0, "val: %s", val);
|
|
}
|
|
EXPORT_SYMBOL_GPL(mtk_vcodec_get_log);
|
|
|