| // 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(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"); |