Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,21 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-common.o
mtk-vcodec-common-y := mtk_vcodec_intr.o \
mtk_vcodec_util.o \
mtk_vcodec_fw.o \
ifneq ($(CONFIG_VIDEO_MEDIATEK_VCODEC_VPU),)
mtk-vcodec-common-y += mtk_vcodec_fw_vpu.o
endif
ifneq ($(CONFIG_VIDEO_MEDIATEK_VCODEC_SCP),)
mtk-vcodec-common-y += mtk_vcodec_fw_scp.o
endif
ifneq ($(CONFIG_DEBUG_FS),)
obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dbgfs.o
mtk-vcodec-dbgfs-y := mtk_vcodec_dbgfs.o
endif
@@ -0,0 +1,147 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023 MediaTek Inc.
* Author: Yunfei Dong <yunfei.dong@mediatek.com>
*/
#ifndef _MTK_VCODEC_COM_DRV_H_
#define _MTK_VCODEC_COM_DRV_H_
#include <linux/platform_device.h>
#include <linux/videodev2.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-core.h>
#define MTK_VCODEC_MAX_PLANES 3
#define WAIT_INTR_TIMEOUT_MS 1000
/*
* enum mtk_q_type - Type of queue
*/
enum mtk_q_type {
MTK_Q_DATA_SRC = 0,
MTK_Q_DATA_DST = 1,
};
/*
* enum mtk_hw_reg_idx - MTK hw register base index
*/
enum mtk_hw_reg_idx {
VDEC_SYS,
VDEC_MISC,
VDEC_LD,
VDEC_TOP,
VDEC_CM,
VDEC_AD,
VDEC_AV,
VDEC_PP,
VDEC_HWD,
VDEC_HWQ,
VDEC_HWB,
VDEC_HWG,
NUM_MAX_VDEC_REG_BASE,
/* h264 encoder */
VENC_SYS = NUM_MAX_VDEC_REG_BASE,
/* vp8 encoder */
VENC_LT_SYS,
NUM_MAX_VCODEC_REG_BASE
};
/*
* struct mtk_vcodec_clk_info - Structure used to store clock name
*/
struct mtk_vcodec_clk_info {
const char *clk_name;
struct clk *vcodec_clk;
};
/*
* struct mtk_vcodec_clk - Structure used to store vcodec clock information
*/
struct mtk_vcodec_clk {
struct mtk_vcodec_clk_info *clk_info;
int clk_num;
};
/*
* struct mtk_vcodec_pm - Power management data structure
*/
struct mtk_vcodec_pm {
struct mtk_vcodec_clk vdec_clk;
struct mtk_vcodec_clk venc_clk;
struct device *dev;
};
/*
* enum mtk_vdec_hw_id - Hardware index used to separate
* different hardware
*/
enum mtk_vdec_hw_id {
MTK_VDEC_CORE,
MTK_VDEC_LAT0,
MTK_VDEC_LAT1,
MTK_VDEC_LAT_SOC,
MTK_VDEC_HW_MAX,
};
/**
* enum mtk_instance_state - The state of an MTK Vcodec instance.
* @MTK_STATE_FREE: default state when instance is created
* @MTK_STATE_INIT: vcodec instance is initialized
* @MTK_STATE_HEADER: vdec had sps/pps header parsed or venc
* had sps/pps header encoded
* @MTK_STATE_FLUSH: vdec is flushing. Only used by decoder
* @MTK_STATE_ABORT: vcodec should be aborted
*/
enum mtk_instance_state {
MTK_STATE_FREE = 0,
MTK_STATE_INIT = 1,
MTK_STATE_HEADER = 2,
MTK_STATE_FLUSH = 3,
MTK_STATE_ABORT = 4,
};
enum mtk_fmt_type {
MTK_FMT_DEC = 0,
MTK_FMT_ENC = 1,
MTK_FMT_FRAME = 2,
};
/*
* struct mtk_video_fmt - Structure used to store information about pixelformats
*/
struct mtk_video_fmt {
u32 fourcc;
enum mtk_fmt_type type;
u32 num_planes;
u32 flags;
struct v4l2_frmsize_stepwise frmsize;
};
/*
* struct mtk_q_data - Structure used to store information about queue
*/
struct mtk_q_data {
unsigned int visible_width;
unsigned int visible_height;
unsigned int coded_width;
unsigned int coded_height;
enum v4l2_field field;
unsigned int bytesperline[MTK_VCODEC_MAX_PLANES];
unsigned int sizeimage[MTK_VCODEC_MAX_PLANES];
const struct mtk_video_fmt *fmt;
};
/*
* enum mtk_instance_type - The type of an MTK Vcodec instance.
*/
enum mtk_instance_type {
MTK_INST_DECODER = 0,
MTK_INST_ENCODER = 1,
};
#endif /* _MTK_VCODEC_COM_DRV_H_ */
@@ -0,0 +1,231 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023 MediaTek Inc.
* Author: Yunfei Dong <yunfei.dong@mediatek.com>
*/
#include <linux/debugfs.h>
#include "mtk_vcodec_dbgfs.h"
#include "../decoder/mtk_vcodec_dec_drv.h"
#include "../encoder/mtk_vcodec_enc_drv.h"
#include "mtk_vcodec_util.h"
static void mtk_vdec_dbgfs_get_format_type(struct mtk_vcodec_dec_ctx *ctx, char *buf,
int *used, int total)
{
int curr_len;
switch (ctx->current_codec) {
case V4L2_PIX_FMT_H264_SLICE:
curr_len = snprintf(buf + *used, total - *used,
"\toutput format: h264 slice\n");
break;
case V4L2_PIX_FMT_VP8_FRAME:
curr_len = snprintf(buf + *used, total - *used,
"\toutput format: vp8 slice\n");
break;
case V4L2_PIX_FMT_VP9_FRAME:
curr_len = snprintf(buf + *used, total - *used,
"\toutput format: vp9 slice\n");
break;
default:
curr_len = snprintf(buf + *used, total - *used,
"\tunsupported output format: 0x%x\n",
ctx->current_codec);
}
*used += curr_len;
switch (ctx->capture_fourcc) {
case V4L2_PIX_FMT_MM21:
curr_len = snprintf(buf + *used, total - *used,
"\tcapture format: MM21\n");
break;
case V4L2_PIX_FMT_MT21C:
curr_len = snprintf(buf + *used, total - *used,
"\tcapture format: MT21C\n");
break;
default:
curr_len = snprintf(buf + *used, total - *used,
"\tunsupported capture format: 0x%x\n",
ctx->capture_fourcc);
}
*used += curr_len;
}
static void mtk_vdec_dbgfs_get_help(char *buf, int *used, int total)
{
int curr_len;
curr_len = snprintf(buf + *used, total - *used,
"help: (1: echo -'info' > vdec 2: cat vdec)\n");
*used += curr_len;
curr_len = snprintf(buf + *used, total - *used,
"\t-picinfo: get resolution\n");
*used += curr_len;
curr_len = snprintf(buf + *used, total - *used,
"\t-format: get output & capture queue format\n");
*used += curr_len;
}
static ssize_t mtk_vdec_dbgfs_write(struct file *filp, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct mtk_vcodec_dec_dev *vcodec_dev = filp->private_data;
struct mtk_vcodec_dbgfs *dbgfs = &vcodec_dev->dbgfs;
mutex_lock(&dbgfs->dbgfs_lock);
dbgfs->buf_size = simple_write_to_buffer(dbgfs->dbgfs_buf, sizeof(dbgfs->dbgfs_buf),
ppos, ubuf, count);
mutex_unlock(&dbgfs->dbgfs_lock);
if (dbgfs->buf_size > 0)
return count;
return dbgfs->buf_size;
}
static ssize_t mtk_vdec_dbgfs_read(struct file *filp, char __user *ubuf,
size_t count, loff_t *ppos)
{
struct mtk_vcodec_dec_dev *vcodec_dev = filp->private_data;
struct mtk_vcodec_dbgfs *dbgfs = &vcodec_dev->dbgfs;
struct mtk_vcodec_dbgfs_inst *dbgfs_inst;
struct mtk_vcodec_dec_ctx *ctx;
int total_len = 200 * (dbgfs->inst_count == 0 ? 1 : dbgfs->inst_count);
int used_len = 0, curr_len, ret;
bool dbgfs_index[MTK_VDEC_DBGFS_MAX] = {0};
char *buf = kmalloc(total_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
if (strstr(dbgfs->dbgfs_buf, "-help") || dbgfs->buf_size == 1) {
mtk_vdec_dbgfs_get_help(buf, &used_len, total_len);
goto read_buffer;
}
if (strstr(dbgfs->dbgfs_buf, "-picinfo"))
dbgfs_index[MTK_VDEC_DBGFS_PICINFO] = true;
if (strstr(dbgfs->dbgfs_buf, "-format"))
dbgfs_index[MTK_VDEC_DBGFS_FORMAT] = true;
mutex_lock(&dbgfs->dbgfs_lock);
list_for_each_entry(dbgfs_inst, &dbgfs->dbgfs_head, node) {
ctx = dbgfs_inst->vcodec_ctx;
curr_len = snprintf(buf + used_len, total_len - used_len,
"inst[%d]:\n ", ctx->id);
used_len += curr_len;
if (dbgfs_index[MTK_VDEC_DBGFS_PICINFO]) {
curr_len = snprintf(buf + used_len, total_len - used_len,
"\treal(%dx%d)=>align(%dx%d)\n",
ctx->picinfo.pic_w, ctx->picinfo.pic_h,
ctx->picinfo.buf_w, ctx->picinfo.buf_h);
used_len += curr_len;
}
if (dbgfs_index[MTK_VDEC_DBGFS_FORMAT])
mtk_vdec_dbgfs_get_format_type(ctx, buf, &used_len, total_len);
}
mutex_unlock(&dbgfs->dbgfs_lock);
read_buffer:
ret = simple_read_from_buffer(ubuf, count, ppos, buf, used_len);
kfree(buf);
return ret;
}
static const struct file_operations vdec_fops = {
.open = simple_open,
.write = mtk_vdec_dbgfs_write,
.read = mtk_vdec_dbgfs_read,
};
void mtk_vcodec_dbgfs_create(struct mtk_vcodec_dec_ctx *ctx)
{
struct mtk_vcodec_dbgfs_inst *dbgfs_inst;
struct mtk_vcodec_dec_dev *vcodec_dev = ctx->dev;
dbgfs_inst = kzalloc_obj(*dbgfs_inst);
if (!dbgfs_inst)
return;
list_add_tail(&dbgfs_inst->node, &vcodec_dev->dbgfs.dbgfs_head);
vcodec_dev->dbgfs.inst_count++;
dbgfs_inst->inst_id = ctx->id;
dbgfs_inst->vcodec_ctx = ctx;
}
EXPORT_SYMBOL_GPL(mtk_vcodec_dbgfs_create);
void mtk_vcodec_dbgfs_remove(struct mtk_vcodec_dec_dev *vcodec_dev, int ctx_id)
{
struct mtk_vcodec_dbgfs_inst *dbgfs_inst;
list_for_each_entry(dbgfs_inst, &vcodec_dev->dbgfs.dbgfs_head, node) {
if (dbgfs_inst->inst_id == ctx_id) {
vcodec_dev->dbgfs.inst_count--;
list_del(&dbgfs_inst->node);
kfree(dbgfs_inst);
return;
}
}
}
EXPORT_SYMBOL_GPL(mtk_vcodec_dbgfs_remove);
static void mtk_vcodec_dbgfs_vdec_init(struct mtk_vcodec_dec_dev *vcodec_dev)
{
struct dentry *vcodec_root;
vcodec_dev->dbgfs.vcodec_root = debugfs_create_dir("vcodec-dec", NULL);
if (IS_ERR(vcodec_dev->dbgfs.vcodec_root))
dev_err(&vcodec_dev->plat_dev->dev, "create vcodec dir err:%pe\n",
vcodec_dev->dbgfs.vcodec_root);
vcodec_root = vcodec_dev->dbgfs.vcodec_root;
debugfs_create_x32("mtk_v4l2_dbg_level", 0644, vcodec_root, &mtk_v4l2_dbg_level);
debugfs_create_x32("mtk_vcodec_dbg", 0644, vcodec_root, &mtk_vcodec_dbg);
vcodec_dev->dbgfs.inst_count = 0;
INIT_LIST_HEAD(&vcodec_dev->dbgfs.dbgfs_head);
debugfs_create_file("vdec", 0200, vcodec_root, vcodec_dev, &vdec_fops);
mutex_init(&vcodec_dev->dbgfs.dbgfs_lock);
}
static void mtk_vcodec_dbgfs_venc_init(struct mtk_vcodec_enc_dev *vcodec_dev)
{
struct dentry *vcodec_root;
vcodec_dev->dbgfs.vcodec_root = debugfs_create_dir("vcodec-enc", NULL);
if (IS_ERR(vcodec_dev->dbgfs.vcodec_root))
dev_err(&vcodec_dev->plat_dev->dev, "create venc dir err:%d\n",
IS_ERR(vcodec_dev->dbgfs.vcodec_root));
vcodec_root = vcodec_dev->dbgfs.vcodec_root;
debugfs_create_x32("mtk_v4l2_dbg_level", 0644, vcodec_root, &mtk_v4l2_dbg_level);
debugfs_create_x32("mtk_vcodec_dbg", 0644, vcodec_root, &mtk_vcodec_dbg);
vcodec_dev->dbgfs.inst_count = 0;
}
void mtk_vcodec_dbgfs_init(void *vcodec_dev, bool is_encode)
{
if (is_encode)
mtk_vcodec_dbgfs_venc_init(vcodec_dev);
else
mtk_vcodec_dbgfs_vdec_init(vcodec_dev);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_dbgfs_init);
void mtk_vcodec_dbgfs_deinit(struct mtk_vcodec_dbgfs *dbgfs)
{
debugfs_remove_recursive(dbgfs->vcodec_root);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_dbgfs_deinit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Mediatek video codec driver");
@@ -0,0 +1,74 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023 MediaTek Inc.
* Author: Yunfei Dong <yunfei.dong@mediatek.com>
*/
#ifndef __MTK_VCODEC_DBGFS_H__
#define __MTK_VCODEC_DBGFS_H__
struct mtk_vcodec_dec_dev;
struct mtk_vcodec_dec_ctx;
/*
* enum mtk_vdec_dbgfs_log_index - used to get different debug information
*/
enum mtk_vdec_dbgfs_log_index {
MTK_VDEC_DBGFS_PICINFO,
MTK_VDEC_DBGFS_FORMAT,
MTK_VDEC_DBGFS_MAX,
};
/**
* struct mtk_vcodec_dbgfs_inst - debugfs information for each inst
* @node: list node for each inst
* @vcodec_ctx: struct mtk_vcodec_dec_ctx
* @inst_id: index of the context that the same with ctx->id
*/
struct mtk_vcodec_dbgfs_inst {
struct list_head node;
struct mtk_vcodec_dec_ctx *vcodec_ctx;
int inst_id;
};
/**
* struct mtk_vcodec_dbgfs - dbgfs information
* @dbgfs_head: list head used to link each instance
* @vcodec_root: vcodec dbgfs entry
* @dbgfs_lock: dbgfs lock used to protect dbgfs_buf
* @dbgfs_buf: dbgfs buf used to store dbgfs cmd
* @buf_size: buffer size of dbgfs
* @inst_count: the count of total instance
*/
struct mtk_vcodec_dbgfs {
struct list_head dbgfs_head;
struct dentry *vcodec_root;
struct mutex dbgfs_lock;
char dbgfs_buf[1024];
int buf_size;
int inst_count;
};
#if defined(CONFIG_DEBUG_FS)
void mtk_vcodec_dbgfs_create(struct mtk_vcodec_dec_ctx *ctx);
void mtk_vcodec_dbgfs_remove(struct mtk_vcodec_dec_dev *vcodec_dev, int ctx_id);
void mtk_vcodec_dbgfs_init(void *vcodec_dev, bool is_encode);
void mtk_vcodec_dbgfs_deinit(struct mtk_vcodec_dbgfs *dbgfs);
#else
static inline void mtk_vcodec_dbgfs_create(struct mtk_vcodec_dec_ctx *ctx)
{
}
static inline void mtk_vcodec_dbgfs_remove(struct mtk_vcodec_dec_dev *vcodec_dev, int ctx_id)
{
}
static inline void mtk_vcodec_dbgfs_init(void *vcodec_dev, bool is_encode)
{
}
static inline void mtk_vcodec_dbgfs_deinit(struct mtk_vcodec_dbgfs *dbgfs)
{
}
#endif
#endif
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: GPL-2.0
#include "../decoder/mtk_vcodec_dec_drv.h"
#include "../encoder/mtk_vcodec_enc_drv.h"
#include "mtk_vcodec_fw_priv.h"
struct mtk_vcodec_fw *mtk_vcodec_fw_select(void *priv, enum mtk_vcodec_fw_type type,
enum mtk_vcodec_fw_use fw_use)
{
struct platform_device *plat_dev;
if (fw_use == ENCODER)
plat_dev = ((struct mtk_vcodec_enc_dev *)priv)->plat_dev;
else
plat_dev = ((struct mtk_vcodec_dec_dev *)priv)->plat_dev;
switch (type) {
case VPU:
return mtk_vcodec_fw_vpu_init(priv, fw_use);
case SCP:
return mtk_vcodec_fw_scp_init(priv, fw_use);
default:
dev_err(&plat_dev->dev, "Invalid vcodec fw type");
return ERR_PTR(-EINVAL);
}
}
EXPORT_SYMBOL_GPL(mtk_vcodec_fw_select);
void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw)
{
fw->ops->release(fw);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_fw_release);
int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw)
{
return fw->ops->load_firmware(fw);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_fw_load_firmware);
unsigned int mtk_vcodec_fw_get_vdec_capa(struct mtk_vcodec_fw *fw)
{
return fw->ops->get_vdec_capa(fw);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_vdec_capa);
unsigned int mtk_vcodec_fw_get_venc_capa(struct mtk_vcodec_fw *fw)
{
return fw->ops->get_venc_capa(fw);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_venc_capa);
void *mtk_vcodec_fw_map_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_addr)
{
return fw->ops->map_dm_addr(fw, mem_addr);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_fw_map_dm_addr);
int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id,
mtk_vcodec_ipi_handler handler,
const char *name, void *priv)
{
return fw->ops->ipi_register(fw, id, handler, name, priv);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_register);
int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
unsigned int len, unsigned int wait)
{
return fw->ops->ipi_send(fw, id, buf, len, wait);
}
EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_send);
int mtk_vcodec_fw_get_type(struct mtk_vcodec_fw *fw)
{
return fw->type;
}
EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_type);
@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _MTK_VCODEC_FW_H_
#define _MTK_VCODEC_FW_H_
#include <linux/remoteproc.h>
#include <linux/remoteproc/mtk_scp.h>
#include "../../vpu/mtk_vpu.h"
struct mtk_vcodec_dec_dev;
struct mtk_vcodec_enc_dev;
enum mtk_vcodec_fw_type {
VPU,
SCP,
};
enum mtk_vcodec_fw_use {
DECODER,
ENCODER,
};
struct mtk_vcodec_fw;
typedef void (*mtk_vcodec_ipi_handler) (void *data,
unsigned int len, void *priv);
struct mtk_vcodec_fw *mtk_vcodec_fw_select(void *priv, enum mtk_vcodec_fw_type type,
enum mtk_vcodec_fw_use fw_use);
void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw);
int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw);
unsigned int mtk_vcodec_fw_get_vdec_capa(struct mtk_vcodec_fw *fw);
unsigned int mtk_vcodec_fw_get_venc_capa(struct mtk_vcodec_fw *fw);
void *mtk_vcodec_fw_map_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_addr);
int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id,
mtk_vcodec_ipi_handler handler,
const char *name, void *priv);
int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id,
void *buf, unsigned int len, unsigned int wait);
int mtk_vcodec_fw_get_type(struct mtk_vcodec_fw *fw);
#endif /* _MTK_VCODEC_FW_H_ */
@@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _MTK_VCODEC_FW_PRIV_H_
#define _MTK_VCODEC_FW_PRIV_H_
#include "mtk_vcodec_fw.h"
struct mtk_vcodec_dec_dev;
struct mtk_vcodec_enc_dev;
struct mtk_vcodec_fw {
enum mtk_vcodec_fw_type type;
const struct mtk_vcodec_fw_ops *ops;
struct platform_device *pdev;
struct mtk_scp *scp;
enum mtk_vcodec_fw_use fw_use;
};
struct mtk_vcodec_fw_ops {
int (*load_firmware)(struct mtk_vcodec_fw *fw);
unsigned int (*get_vdec_capa)(struct mtk_vcodec_fw *fw);
unsigned int (*get_venc_capa)(struct mtk_vcodec_fw *fw);
void *(*map_dm_addr)(struct mtk_vcodec_fw *fw, u32 dtcm_dmem_addr);
int (*ipi_register)(struct mtk_vcodec_fw *fw, int id,
mtk_vcodec_ipi_handler handler, const char *name,
void *priv);
int (*ipi_send)(struct mtk_vcodec_fw *fw, int id, void *buf,
unsigned int len, unsigned int wait);
void (*release)(struct mtk_vcodec_fw *fw);
};
#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCODEC_VPU)
struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(void *priv, enum mtk_vcodec_fw_use fw_use);
#else
static inline struct mtk_vcodec_fw *
mtk_vcodec_fw_vpu_init(void *priv, enum mtk_vcodec_fw_use fw_use)
{
return ERR_PTR(-ENODEV);
}
#endif /* CONFIG_VIDEO_MEDIATEK_VCODEC_VPU */
#if IS_ENABLED(CONFIG_VIDEO_MEDIATEK_VCODEC_SCP)
struct mtk_vcodec_fw *mtk_vcodec_fw_scp_init(void *priv, enum mtk_vcodec_fw_use fw_use);
#else
static inline struct mtk_vcodec_fw *
mtk_vcodec_fw_scp_init(void *priv, enum mtk_vcodec_fw_use fw_use)
{
return ERR_PTR(-ENODEV);
}
#endif /* CONFIG_VIDEO_MEDIATEK_VCODEC_SCP */
#endif /* _MTK_VCODEC_FW_PRIV_H_ */
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: GPL-2.0
#include "../decoder/mtk_vcodec_dec_drv.h"
#include "../encoder/mtk_vcodec_enc_drv.h"
#include "mtk_vcodec_fw_priv.h"
static int mtk_vcodec_scp_load_firmware(struct mtk_vcodec_fw *fw)
{
return rproc_boot(scp_get_rproc(fw->scp));
}
static unsigned int mtk_vcodec_scp_get_vdec_capa(struct mtk_vcodec_fw *fw)
{
return scp_get_vdec_hw_capa(fw->scp);
}
static unsigned int mtk_vcodec_scp_get_venc_capa(struct mtk_vcodec_fw *fw)
{
return scp_get_venc_hw_capa(fw->scp);
}
static void *mtk_vcodec_vpu_scp_dm_addr(struct mtk_vcodec_fw *fw,
u32 dtcm_dmem_addr)
{
return scp_mapping_dm_addr(fw->scp, dtcm_dmem_addr);
}
static int mtk_vcodec_scp_set_ipi_register(struct mtk_vcodec_fw *fw, int id,
mtk_vcodec_ipi_handler handler,
const char *name, void *priv)
{
return scp_ipi_register(fw->scp, id, handler, priv);
}
static int mtk_vcodec_scp_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
unsigned int len, unsigned int wait)
{
return scp_ipi_send(fw->scp, id, buf, len, wait);
}
static void mtk_vcodec_scp_release(struct mtk_vcodec_fw *fw)
{
scp_put(fw->scp);
}
static const struct mtk_vcodec_fw_ops mtk_vcodec_rproc_msg = {
.load_firmware = mtk_vcodec_scp_load_firmware,
.get_vdec_capa = mtk_vcodec_scp_get_vdec_capa,
.get_venc_capa = mtk_vcodec_scp_get_venc_capa,
.map_dm_addr = mtk_vcodec_vpu_scp_dm_addr,
.ipi_register = mtk_vcodec_scp_set_ipi_register,
.ipi_send = mtk_vcodec_scp_ipi_send,
.release = mtk_vcodec_scp_release,
};
struct mtk_vcodec_fw *mtk_vcodec_fw_scp_init(void *priv, enum mtk_vcodec_fw_use fw_use)
{
struct mtk_vcodec_fw *fw;
struct platform_device *plat_dev;
struct mtk_scp *scp;
if (fw_use == ENCODER) {
struct mtk_vcodec_enc_dev *enc_dev = priv;
plat_dev = enc_dev->plat_dev;
} else if (fw_use == DECODER) {
struct mtk_vcodec_dec_dev *dec_dev = priv;
plat_dev = dec_dev->plat_dev;
} else {
pr_err("Invalid fw_use %d (use a reasonable fw id here)\n", fw_use);
return ERR_PTR(-EINVAL);
}
scp = scp_get(plat_dev);
if (!scp) {
dev_err(&plat_dev->dev, "could not get vdec scp handle");
return ERR_PTR(-EPROBE_DEFER);
}
fw = devm_kzalloc(&plat_dev->dev, sizeof(*fw), GFP_KERNEL);
if (!fw) {
scp_put(scp);
return ERR_PTR(-ENOMEM);
}
fw->type = SCP;
fw->ops = &mtk_vcodec_rproc_msg;
fw->scp = scp;
return fw;
}
@@ -0,0 +1,132 @@
// SPDX-License-Identifier: GPL-2.0
#include "../decoder/mtk_vcodec_dec_drv.h"
#include "../encoder/mtk_vcodec_enc_drv.h"
#include "mtk_vcodec_fw_priv.h"
static int mtk_vcodec_vpu_load_firmware(struct mtk_vcodec_fw *fw)
{
return vpu_load_firmware(fw->pdev);
}
static unsigned int mtk_vcodec_vpu_get_vdec_capa(struct mtk_vcodec_fw *fw)
{
return vpu_get_vdec_hw_capa(fw->pdev);
}
static unsigned int mtk_vcodec_vpu_get_venc_capa(struct mtk_vcodec_fw *fw)
{
return vpu_get_venc_hw_capa(fw->pdev);
}
static void *mtk_vcodec_vpu_map_dm_addr(struct mtk_vcodec_fw *fw,
u32 dtcm_dmem_addr)
{
return vpu_mapping_dm_addr(fw->pdev, dtcm_dmem_addr);
}
static int mtk_vcodec_vpu_set_ipi_register(struct mtk_vcodec_fw *fw, int id,
mtk_vcodec_ipi_handler handler,
const char *name, void *priv)
{
return vpu_ipi_register(fw->pdev, id, handler, name, priv);
}
static int mtk_vcodec_vpu_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
unsigned int len, unsigned int wait)
{
return vpu_ipi_send(fw->pdev, id, buf, len);
}
static void mtk_vcodec_vpu_release(struct mtk_vcodec_fw *fw)
{
put_device(&fw->pdev->dev);
}
static void mtk_vcodec_vpu_reset_dec_handler(void *priv)
{
struct mtk_vcodec_dec_dev *dev = priv;
struct mtk_vcodec_dec_ctx *ctx;
unsigned long flags;
dev_err(&dev->plat_dev->dev, "Watchdog timeout!!");
spin_lock_irqsave(&dev->dev_ctx_lock, flags);
list_for_each_entry(ctx, &dev->ctx_list, list) {
ctx->state = MTK_STATE_ABORT;
mtk_v4l2_vdec_dbg(0, ctx, "[%d] Change to state MTK_STATE_ABORT", ctx->id);
}
spin_unlock_irqrestore(&dev->dev_ctx_lock, flags);
}
static void mtk_vcodec_vpu_reset_enc_handler(void *priv)
{
struct mtk_vcodec_enc_dev *dev = priv;
struct mtk_vcodec_enc_ctx *ctx;
unsigned long flags;
dev_err(&dev->plat_dev->dev, "Watchdog timeout!!");
spin_lock_irqsave(&dev->dev_ctx_lock, flags);
list_for_each_entry(ctx, &dev->ctx_list, list) {
ctx->state = MTK_STATE_ABORT;
mtk_v4l2_vdec_dbg(0, ctx, "[%d] Change to state MTK_STATE_ABORT", ctx->id);
}
spin_unlock_irqrestore(&dev->dev_ctx_lock, flags);
}
static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = {
.load_firmware = mtk_vcodec_vpu_load_firmware,
.get_vdec_capa = mtk_vcodec_vpu_get_vdec_capa,
.get_venc_capa = mtk_vcodec_vpu_get_venc_capa,
.map_dm_addr = mtk_vcodec_vpu_map_dm_addr,
.ipi_register = mtk_vcodec_vpu_set_ipi_register,
.ipi_send = mtk_vcodec_vpu_ipi_send,
.release = mtk_vcodec_vpu_release,
};
struct mtk_vcodec_fw *mtk_vcodec_fw_vpu_init(void *priv, enum mtk_vcodec_fw_use fw_use)
{
struct platform_device *fw_pdev;
struct platform_device *plat_dev;
struct mtk_vcodec_fw *fw;
enum rst_id rst_id;
if (fw_use == ENCODER) {
struct mtk_vcodec_enc_dev *enc_dev = priv;
plat_dev = enc_dev->plat_dev;
rst_id = VPU_RST_ENC;
} else if (fw_use == DECODER) {
struct mtk_vcodec_dec_dev *dec_dev = priv;
plat_dev = dec_dev->plat_dev;
rst_id = VPU_RST_DEC;
} else {
pr_err("Invalid fw_use %d (use a reasonable fw id here)\n", fw_use);
return ERR_PTR(-EINVAL);
}
fw_pdev = vpu_get_plat_device(plat_dev);
if (!fw_pdev) {
dev_err(&plat_dev->dev, "firmware device is not ready");
return ERR_PTR(-EINVAL);
}
if (fw_use == DECODER)
vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_vpu_reset_dec_handler, priv, rst_id);
else
vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_vpu_reset_enc_handler, priv, rst_id);
fw = devm_kzalloc(&plat_dev->dev, sizeof(*fw), GFP_KERNEL);
if (!fw) {
put_device(&fw_pdev->dev);
return ERR_PTR(-ENOMEM);
}
fw->type = VPU;
fw->ops = &mtk_vcodec_vpu_msg;
fw->pdev = fw_pdev;
fw->fw_use = fw_use;
return fw;
}
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Tiffany Lin <tiffany.lin@mediatek.com>
*/
#include <linux/errno.h>
#include <linux/wait.h>
#include "../decoder/mtk_vcodec_dec_drv.h"
#include "../encoder/mtk_vcodec_enc_drv.h"
#include "mtk_vcodec_intr.h"
int mtk_vcodec_wait_for_done_ctx(void *priv, int command, unsigned int timeout_ms,
unsigned int hw_id)
{
int instance_type = *((int *)priv);
long timeout_jiff, ret;
int ctx_id, ctx_type, status = 0;
int *ctx_int_cond, *ctx_int_type;
wait_queue_head_t *ctx_queue;
struct platform_device *pdev;
if (instance_type == DECODER) {
struct mtk_vcodec_dec_ctx *ctx;
ctx = priv;
ctx_id = ctx->id;
ctx_type = ctx->type;
ctx_int_cond = ctx->int_cond;
ctx_int_type = ctx->int_type;
ctx_queue = ctx->queue;
pdev = ctx->dev->plat_dev;
} else {
struct mtk_vcodec_enc_ctx *ctx;
ctx = priv;
ctx_id = ctx->id;
ctx_type = ctx->type;
ctx_int_cond = ctx->int_cond;
ctx_int_type = ctx->int_type;
ctx_queue = ctx->queue;
pdev = ctx->dev->plat_dev;
}
timeout_jiff = msecs_to_jiffies(timeout_ms);
ret = wait_event_interruptible_timeout(ctx_queue[hw_id],
ctx_int_cond[hw_id],
timeout_jiff);
if (!ret) {
status = -1; /* timeout */
dev_err(&pdev->dev, "[%d] cmd=%d, type=%d, dec timeout=%ums (%d %d)",
ctx_id, command, ctx_type, timeout_ms,
ctx_int_cond[hw_id], ctx_int_type[hw_id]);
} else if (-ERESTARTSYS == ret) {
status = -1;
dev_err(&pdev->dev, "[%d] cmd=%d, type=%d, dec inter fail (%d %d)",
ctx_id, command, ctx_type,
ctx_int_cond[hw_id], ctx_int_type[hw_id]);
}
ctx_int_cond[hw_id] = 0;
ctx_int_type[hw_id] = 0;
return status;
}
EXPORT_SYMBOL(mtk_vcodec_wait_for_done_ctx);
@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: Tiffany Lin <tiffany.lin@mediatek.com>
*/
#ifndef _MTK_VCODEC_INTR_H_
#define _MTK_VCODEC_INTR_H_
#define MTK_INST_IRQ_RECEIVED 0x1
struct mtk_vcodec_dec_ctx;
struct mtk_vcodec_enc_ctx;
/* timeout is ms */
int mtk_vcodec_wait_for_done_ctx(void *priv, int command, unsigned int timeout_ms,
unsigned int hw_id);
#endif /* _MTK_VCODEC_INTR_H_ */
@@ -0,0 +1,174 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
* Tiffany Lin <tiffany.lin@mediatek.com>
*/
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include "../decoder/mtk_vcodec_dec_drv.h"
#include "../encoder/mtk_vcodec_enc_drv.h"
#include "../decoder/mtk_vcodec_dec_hw.h"
#if defined(CONFIG_DEBUG_FS)
int mtk_vcodec_dbg;
EXPORT_SYMBOL(mtk_vcodec_dbg);
int mtk_v4l2_dbg_level;
EXPORT_SYMBOL(mtk_v4l2_dbg_level);
#endif
void __iomem *mtk_vcodec_get_reg_addr(void __iomem **reg_base, unsigned int reg_idx)
{
if (reg_idx >= NUM_MAX_VCODEC_REG_BASE) {
pr_err(MTK_DBG_V4L2_STR "Invalid arguments, reg_idx=%d", reg_idx);
return NULL;
}
return reg_base[reg_idx];
}
EXPORT_SYMBOL(mtk_vcodec_get_reg_addr);
int mtk_vcodec_write_vdecsys(struct mtk_vcodec_dec_ctx *ctx, unsigned int reg,
unsigned int val)
{
struct mtk_vcodec_dec_dev *dev = ctx->dev;
if (dev->vdecsys_regmap)
return regmap_write(dev->vdecsys_regmap, reg, val);
writel(val, dev->reg_base[VDEC_SYS] + reg);
return 0;
}
EXPORT_SYMBOL(mtk_vcodec_write_vdecsys);
int mtk_vcodec_mem_alloc(void *priv, struct mtk_vcodec_mem *mem)
{
enum mtk_instance_type inst_type = *((unsigned int *)priv);
struct platform_device *plat_dev;
int id;
if (inst_type == MTK_INST_ENCODER) {
struct mtk_vcodec_enc_ctx *enc_ctx = priv;
plat_dev = enc_ctx->dev->plat_dev;
id = enc_ctx->id;
} else {
struct mtk_vcodec_dec_ctx *dec_ctx = priv;
plat_dev = dec_ctx->dev->plat_dev;
id = dec_ctx->id;
}
mem->va = dma_alloc_attrs(&plat_dev->dev, mem->size, &mem->dma_addr,
GFP_KERNEL, DMA_ATTR_ALLOC_SINGLE_PAGES);
if (!mem->va) {
mtk_v4l2_err(plat_dev, "%s dma_alloc size=0x%zx failed!",
__func__, mem->size);
return -ENOMEM;
}
mtk_v4l2_debug(plat_dev, 3, "[%d] - va = %p dma = 0x%lx size = 0x%zx", id, mem->va,
(unsigned long)mem->dma_addr, mem->size);
return 0;
}
EXPORT_SYMBOL(mtk_vcodec_mem_alloc);
void mtk_vcodec_mem_free(void *priv, struct mtk_vcodec_mem *mem)
{
enum mtk_instance_type inst_type = *((unsigned int *)priv);
struct platform_device *plat_dev;
int id;
if (inst_type == MTK_INST_ENCODER) {
struct mtk_vcodec_enc_ctx *enc_ctx = priv;
plat_dev = enc_ctx->dev->plat_dev;
id = enc_ctx->id;
} else {
struct mtk_vcodec_dec_ctx *dec_ctx = priv;
plat_dev = dec_ctx->dev->plat_dev;
id = dec_ctx->id;
}
if (!mem->va) {
mtk_v4l2_err(plat_dev, "%s: Tried to free a NULL VA", __func__);
if (mem->size)
mtk_v4l2_err(plat_dev, "Failed to free %zu bytes", mem->size);
return;
}
mtk_v4l2_debug(plat_dev, 3, "[%d] - va = %p dma = 0x%lx size = 0x%zx", id, mem->va,
(unsigned long)mem->dma_addr, mem->size);
dma_free_coherent(&plat_dev->dev, mem->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_get_hw_dev(struct mtk_vcodec_dec_dev *dev, int hw_idx)
{
if (hw_idx >= MTK_VDEC_HW_MAX || hw_idx < 0 || !dev->subdev_dev[hw_idx]) {
dev_err(&dev->plat_dev->dev, "hw idx is out of range:%d", hw_idx);
return NULL;
}
return dev->subdev_dev[hw_idx];
}
EXPORT_SYMBOL(mtk_vcodec_get_hw_dev);
void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dec_dev *vdec_dev,
struct mtk_vcodec_dec_ctx *ctx, int hw_idx)
{
unsigned long flags;
struct mtk_vdec_hw_dev *subdev_dev;
spin_lock_irqsave(&vdec_dev->irqlock, flags);
if (vdec_dev->vdec_pdata->is_subdev_supported) {
subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
if (!subdev_dev) {
dev_err(&vdec_dev->plat_dev->dev, "Failed to get hw dev");
spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
return;
}
subdev_dev->curr_ctx = ctx;
} else {
vdec_dev->curr_ctx = ctx;
}
spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
}
EXPORT_SYMBOL(mtk_vcodec_set_curr_ctx);
struct mtk_vcodec_dec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dec_dev *vdec_dev,
unsigned int hw_idx)
{
unsigned long flags;
struct mtk_vcodec_dec_ctx *ctx;
struct mtk_vdec_hw_dev *subdev_dev;
spin_lock_irqsave(&vdec_dev->irqlock, flags);
if (vdec_dev->vdec_pdata->is_subdev_supported) {
subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
if (!subdev_dev) {
dev_err(&vdec_dev->plat_dev->dev, "Failed to get hw dev");
spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
return NULL;
}
ctx = subdev_dev->curr_ctx;
} else {
ctx = vdec_dev->curr_ctx;
}
spin_unlock_irqrestore(&vdec_dev->irqlock, flags);
return ctx;
}
EXPORT_SYMBOL(mtk_vcodec_get_curr_ctx);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("Mediatek video codec driver");
@@ -0,0 +1,75 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2016 MediaTek Inc.
* Author: PC Chen <pc.chen@mediatek.com>
* Tiffany Lin <tiffany.lin@mediatek.com>
*/
#ifndef _MTK_VCODEC_UTIL_H_
#define _MTK_VCODEC_UTIL_H_
#include <linux/types.h>
#include <linux/dma-direction.h>
#define MTK_DBG_VCODEC_STR "[MTK_VCODEC]"
#define MTK_DBG_V4L2_STR "[MTK_V4L2]"
struct mtk_vcodec_mem {
size_t size;
void *va;
dma_addr_t dma_addr;
};
struct mtk_vcodec_fb {
size_t size;
dma_addr_t dma_addr;
};
struct mtk_vcodec_dec_ctx;
struct mtk_vcodec_dec_dev;
#undef pr_fmt
#define pr_fmt(fmt) "%s(),%d: " fmt, __func__, __LINE__
#define mtk_v4l2_err(plat_dev, fmt, args...) \
dev_err(&(plat_dev)->dev, "[MTK_V4L2][ERROR] " fmt "\n", ##args)
#define mtk_vcodec_err(inst_id, plat_dev, fmt, args...) \
dev_err(&(plat_dev)->dev, "[MTK_VCODEC][ERROR][%d]: " fmt "\n", inst_id, ##args)
#if defined(CONFIG_DEBUG_FS)
extern int mtk_v4l2_dbg_level;
extern int mtk_vcodec_dbg;
#define mtk_v4l2_debug(plat_dev, level, fmt, args...) \
do { \
if (mtk_v4l2_dbg_level >= (level)) \
dev_dbg(&(plat_dev)->dev, "[MTK_V4L2] %s, %d: " fmt "\n", \
__func__, __LINE__, ##args); \
} while (0)
#define mtk_vcodec_debug(inst_id, plat_dev, fmt, args...) \
do { \
if (mtk_vcodec_dbg) \
dev_dbg(&(plat_dev)->dev, "[MTK_VCODEC][%d]: %s, %d " fmt "\n", \
inst_id, __func__, __LINE__, ##args); \
} while (0)
#else
#define mtk_v4l2_debug(plat_dev, level, fmt, args...) \
dev_dbg(&(plat_dev)->dev, "[MTK_V4L2]: " fmt "\n", ##args)
#define mtk_vcodec_debug(inst_id, plat_dev, fmt, args...) \
dev_dbg(&(plat_dev)->dev, "[MTK_VCODEC][%d]: " fmt "\n", inst_id, ##args)
#endif
void __iomem *mtk_vcodec_get_reg_addr(void __iomem **reg_base, unsigned int reg_idx);
int mtk_vcodec_write_vdecsys(struct mtk_vcodec_dec_ctx *ctx, unsigned int reg, unsigned int val);
int mtk_vcodec_mem_alloc(void *priv, struct mtk_vcodec_mem *mem);
void mtk_vcodec_mem_free(void *priv, struct mtk_vcodec_mem *mem);
void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dec_dev *vdec_dev,
struct mtk_vcodec_dec_ctx *ctx, int hw_idx);
struct mtk_vcodec_dec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dec_dev *vdec_dev,
unsigned int hw_idx);
void *mtk_vcodec_get_hw_dev(struct mtk_vcodec_dec_dev *dev, int hw_idx);
#endif /* _MTK_VCODEC_UTIL_H_ */