// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2023 MediaTek Inc. * Author: Yunfei Dong */ #include #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(sizeof(*dbgfs_inst), GFP_KERNEL); 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:%ld\n", PTR_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; 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");