FILE
mtk_vcodec_enc_drv.c
File preview with syntax highlighting.
linux-6.19.14/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3* Copyright (c) 2016 MediaTek Inc. 4* Author: PC Chen <pc.chen@mediatek.com> 5* Tiffany Lin <tiffany.lin@mediatek.com> 6*/ 7 8#include <linux/slab.h> 9#include <linux/interrupt.h> 10#include <linux/irq.h> 11#include <linux/module.h> 12#include <linux/of.h> 13#include <linux/platform_device.h> 14#include <linux/pm_runtime.h> 15#include <media/v4l2-event.h> 16#include <media/v4l2-mem2mem.h> 17#include <media/videobuf2-dma-contig.h> 18 19#include "mtk_vcodec_enc.h" 20#include "mtk_vcodec_enc_pm.h" 21#include "../common/mtk_vcodec_intr.h" 22 23static const struct mtk_video_fmt mtk_video_formats_output[] = { 24 { 25 .fourcc = V4L2_PIX_FMT_NV12M, 26 .type = MTK_FMT_FRAME, 27 .num_planes = 2, 28 }, 29 { 30 .fourcc = V4L2_PIX_FMT_NV21M, 31 .type = MTK_FMT_FRAME, 32 .num_planes = 2, 33 }, 34 { 35 .fourcc = V4L2_PIX_FMT_YUV420M, 36 .type = MTK_FMT_FRAME, 37 .num_planes = 3, 38 }, 39 { 40 .fourcc = V4L2_PIX_FMT_YVU420M, 41 .type = MTK_FMT_FRAME, 42 .num_planes = 3, 43 }, 44}; 45 46static const struct mtk_video_fmt mtk_video_formats_capture_h264[] = { 47 { 48 .fourcc = V4L2_PIX_FMT_H264, 49 .type = MTK_FMT_ENC, 50 .num_planes = 1, 51 }, 52}; 53 54static const struct mtk_video_fmt mtk_video_formats_capture_vp8[] = { 55 { 56 .fourcc = V4L2_PIX_FMT_VP8, 57 .type = MTK_FMT_ENC, 58 .num_planes = 1, 59 }, 60}; 61 62static void clean_irq_status(unsigned int irq_status, void __iomem *addr) 63{ 64 if (irq_status & MTK_VENC_IRQ_STATUS_PAUSE) 65 writel(MTK_VENC_IRQ_STATUS_PAUSE, addr); 66 67 if (irq_status & MTK_VENC_IRQ_STATUS_SWITCH) 68 writel(MTK_VENC_IRQ_STATUS_SWITCH, addr); 69 70 if (irq_status & MTK_VENC_IRQ_STATUS_DRAM) 71 writel(MTK_VENC_IRQ_STATUS_DRAM, addr); 72 73 if (irq_status & MTK_VENC_IRQ_STATUS_SPS) 74 writel(MTK_VENC_IRQ_STATUS_SPS, addr); 75 76 if (irq_status & MTK_VENC_IRQ_STATUS_PPS) 77 writel(MTK_VENC_IRQ_STATUS_PPS, addr); 78 79 if (irq_status & MTK_VENC_IRQ_STATUS_FRM) 80 writel(MTK_VENC_IRQ_STATUS_FRM, addr); 81 82} 83static irqreturn_t mtk_vcodec_enc_irq_handler(int irq, void *priv) 84{ 85 struct mtk_vcodec_enc_dev *dev = priv; 86 struct mtk_vcodec_enc_ctx *ctx; 87 unsigned long flags; 88 void __iomem *addr; 89 int core_id; 90 91 spin_lock_irqsave(&dev->irqlock, flags); 92 ctx = dev->curr_ctx; 93 spin_unlock_irqrestore(&dev->irqlock, flags); 94 95 core_id = dev->venc_pdata->core_id; 96 if (core_id < 0 || core_id >= NUM_MAX_VCODEC_REG_BASE) { 97 mtk_v4l2_venc_err(ctx, "Invalid core id: %d, ctx id: %d", core_id, ctx->id); 98 return IRQ_HANDLED; 99 } 100 101 mtk_v4l2_venc_dbg(1, ctx, "id: %d, core id: %d", ctx->id, core_id); 102 103 addr = dev->reg_base[core_id] + MTK_VENC_IRQ_ACK_OFFSET; 104 105 ctx->irq_status = readl(dev->reg_base[core_id] + 106 (MTK_VENC_IRQ_STATUS_OFFSET)); 107 108 clean_irq_status(ctx->irq_status, addr); 109 110 wake_up_enc_ctx(ctx, MTK_INST_IRQ_RECEIVED, 0); 111 return IRQ_HANDLED; 112} 113 114static int fops_vcodec_open(struct file *file) 115{ 116 struct mtk_vcodec_enc_dev *dev = video_drvdata(file); 117 struct mtk_vcodec_enc_ctx *ctx = NULL; 118 int ret = 0; 119 struct vb2_queue *src_vq; 120 unsigned long flags; 121 122 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 123 if (!ctx) 124 return -ENOMEM; 125 126 mutex_lock(&dev->dev_mutex); 127 /* 128 * Use simple counter to uniquely identify this context. Only 129 * used for logging. 130 */ 131 ctx->id = dev->id_counter++; 132 v4l2_fh_init(&ctx->fh, video_devdata(file)); 133 v4l2_fh_add(&ctx->fh, file); 134 INIT_LIST_HEAD(&ctx->list); 135 ctx->dev = dev; 136 init_waitqueue_head(&ctx->queue[0]); 137 mutex_init(&ctx->q_mutex); 138 139 ctx->type = MTK_INST_ENCODER; 140 ret = mtk_vcodec_enc_ctrls_setup(ctx); 141 if (ret) { 142 mtk_v4l2_venc_err(ctx, "Failed to setup controls() (%d)", ret); 143 goto err_ctrls_setup; 144 } 145 ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_enc, ctx, 146 &mtk_vcodec_enc_queue_init); 147 if (IS_ERR((__force void *)ctx->m2m_ctx)) { 148 ret = PTR_ERR((__force void *)ctx->m2m_ctx); 149 mtk_v4l2_venc_err(ctx, "Failed to v4l2_m2m_ctx_init() (%d)", ret); 150 goto err_m2m_ctx_init; 151 } 152 src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, 153 V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); 154 ctx->empty_flush_buf.vb.vb2_buf.vb2_queue = src_vq; 155 mtk_vcodec_enc_set_default_params(ctx); 156 157 if (v4l2_fh_is_singular(&ctx->fh)) { 158 /* 159 * load fireware to checks if it was loaded already and 160 * does nothing in that case 161 */ 162 ret = mtk_vcodec_fw_load_firmware(dev->fw_handler); 163 if (ret < 0) { 164 /* 165 * Return 0 if downloading firmware successfully, 166 * otherwise it is failed 167 */ 168 mtk_v4l2_venc_err(ctx, "vpu_load_firmware failed!"); 169 goto err_load_fw; 170 } 171 172 dev->enc_capability = 173 mtk_vcodec_fw_get_venc_capa(dev->fw_handler); 174 mtk_v4l2_venc_dbg(0, ctx, "encoder capability %x", dev->enc_capability); 175 } 176 177 mtk_v4l2_venc_dbg(2, ctx, "Create instance [%d]@%p m2m_ctx=%p ", 178 ctx->id, ctx, ctx->m2m_ctx); 179 180 spin_lock_irqsave(&dev->dev_ctx_lock, flags); 181 list_add(&ctx->list, &dev->ctx_list); 182 spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); 183 184 mutex_unlock(&dev->dev_mutex); 185 mtk_v4l2_venc_dbg(0, ctx, "%s encoder [%d]", dev_name(&dev->plat_dev->dev), 186 ctx->id); 187 return ret; 188 189 /* Deinit when failure occurred */ 190err_load_fw: 191 v4l2_m2m_ctx_release(ctx->m2m_ctx); 192err_m2m_ctx_init: 193 v4l2_ctrl_handler_free(&ctx->ctrl_hdl); 194err_ctrls_setup: 195 v4l2_fh_del(&ctx->fh, file); 196 v4l2_fh_exit(&ctx->fh); 197 kfree(ctx); 198 mutex_unlock(&dev->dev_mutex); 199 200 return ret; 201} 202 203static int fops_vcodec_release(struct file *file) 204{ 205 struct mtk_vcodec_enc_dev *dev = video_drvdata(file); 206 struct mtk_vcodec_enc_ctx *ctx = file_to_enc_ctx(file); 207 unsigned long flags; 208 209 mtk_v4l2_venc_dbg(1, ctx, "[%d] encoder", ctx->id); 210 mutex_lock(&dev->dev_mutex); 211 212 v4l2_m2m_ctx_release(ctx->m2m_ctx); 213 mtk_vcodec_enc_release(ctx); 214 v4l2_fh_del(&ctx->fh, file); 215 v4l2_fh_exit(&ctx->fh); 216 v4l2_ctrl_handler_free(&ctx->ctrl_hdl); 217 218 /* 219 * Cancel any pending encode work before freeing the context. 220 * Although v4l2_m2m_ctx_release() waits for m2m job completion, 221 * the workqueue handler (mtk_venc_worker) may still be accessing 222 * the context after v4l2_m2m_job_finish() returns. Without this, 223 * a use-after-free occurs when the worker accesses ctx after kfree. 224 */ 225 cancel_work_sync(&ctx->encode_work); 226 227 spin_lock_irqsave(&dev->dev_ctx_lock, flags); 228 list_del_init(&ctx->list); 229 spin_unlock_irqrestore(&dev->dev_ctx_lock, flags); 230 kfree(ctx); 231 mutex_unlock(&dev->dev_mutex); 232 return 0; 233} 234 235static const struct v4l2_file_operations mtk_vcodec_fops = { 236 .owner = THIS_MODULE, 237 .open = fops_vcodec_open, 238 .release = fops_vcodec_release, 239 .poll = v4l2_m2m_fop_poll, 240 .unlocked_ioctl = video_ioctl2, 241 .mmap = v4l2_m2m_fop_mmap, 242}; 243 244static int mtk_vcodec_probe(struct platform_device *pdev) 245{ 246 struct mtk_vcodec_enc_dev *dev; 247 struct video_device *vfd_enc; 248 phandle rproc_phandle; 249 enum mtk_vcodec_fw_type fw_type; 250 int ret; 251 252 dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 253 if (!dev) 254 return -ENOMEM; 255 256 INIT_LIST_HEAD(&dev->ctx_list); 257 dev->plat_dev = pdev; 258 259 if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu", 260 &rproc_phandle)) { 261 fw_type = VPU; 262 } else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp", 263 &rproc_phandle)) { 264 fw_type = SCP; 265 } else { 266 dev_err(&pdev->dev, "[MTK VCODEC] Could not get venc IPI device"); 267 return -ENODEV; 268 } 269 dma_set_max_seg_size(&pdev->dev, UINT_MAX); 270 271 dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, ENCODER); 272 if (IS_ERR(dev->fw_handler)) 273 return PTR_ERR(dev->fw_handler); 274 275 dev->venc_pdata = of_device_get_match_data(&pdev->dev); 276 ret = mtk_vcodec_init_enc_clk(dev); 277 if (ret < 0) { 278 dev_err(&pdev->dev, "[MTK VCODEC] Failed to get mtk vcodec clock source!"); 279 goto err_enc_pm; 280 } 281 282 pm_runtime_enable(&pdev->dev); 283 284 dev->reg_base[dev->venc_pdata->core_id] = 285 devm_platform_ioremap_resource(pdev, 0); 286 if (IS_ERR(dev->reg_base[dev->venc_pdata->core_id])) { 287 ret = PTR_ERR(dev->reg_base[dev->venc_pdata->core_id]); 288 goto err_res; 289 } 290 291 dev->enc_irq = platform_get_irq(pdev, 0); 292 if (dev->enc_irq < 0) { 293 ret = dev->enc_irq; 294 goto err_res; 295 } 296 297 irq_set_status_flags(dev->enc_irq, IRQ_NOAUTOEN); 298 ret = devm_request_irq(&pdev->dev, dev->enc_irq, 299 mtk_vcodec_enc_irq_handler, 300 0, pdev->name, dev); 301 if (ret) { 302 dev_err(&pdev->dev, 303 "[MTK VCODEC] Failed to install dev->enc_irq %d (%d) core_id (%d)", 304 dev->enc_irq, ret, dev->venc_pdata->core_id); 305 ret = -EINVAL; 306 goto err_res; 307 } 308 309 mutex_init(&dev->enc_mutex); 310 mutex_init(&dev->dev_mutex); 311 spin_lock_init(&dev->dev_ctx_lock); 312 spin_lock_init(&dev->irqlock); 313 314 snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", 315 "[MTK_V4L2_VENC]"); 316 317 ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); 318 if (ret) { 319 dev_err(&pdev->dev, "[MTK VCODEC] v4l2_device_register err=%d", ret); 320 goto err_res; 321 } 322 323 /* allocate video device for encoder and register it */ 324 vfd_enc = video_device_alloc(); 325 if (!vfd_enc) { 326 dev_err(&pdev->dev, "[MTK VCODEC] Failed to allocate video device"); 327 ret = -ENOMEM; 328 goto err_enc_alloc; 329 } 330 vfd_enc->fops = &mtk_vcodec_fops; 331 vfd_enc->ioctl_ops = &mtk_venc_ioctl_ops; 332 vfd_enc->release = video_device_release; 333 vfd_enc->lock = &dev->dev_mutex; 334 vfd_enc->v4l2_dev = &dev->v4l2_dev; 335 vfd_enc->vfl_dir = VFL_DIR_M2M; 336 vfd_enc->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | 337 V4L2_CAP_STREAMING; 338 339 snprintf(vfd_enc->name, sizeof(vfd_enc->name), "%s", 340 MTK_VCODEC_ENC_NAME); 341 video_set_drvdata(vfd_enc, dev); 342 dev->vfd_enc = vfd_enc; 343 platform_set_drvdata(pdev, dev); 344 345 dev->m2m_dev_enc = v4l2_m2m_init(&mtk_venc_m2m_ops); 346 if (IS_ERR((__force void *)dev->m2m_dev_enc)) { 347 dev_err(&pdev->dev, "[MTK VCODEC] Failed to init mem2mem enc device"); 348 ret = PTR_ERR((__force void *)dev->m2m_dev_enc); 349 goto err_enc_mem_init; 350 } 351 352 dev->encode_workqueue = 353 alloc_ordered_workqueue(MTK_VCODEC_ENC_NAME, 354 WQ_MEM_RECLAIM | 355 WQ_FREEZABLE); 356 if (!dev->encode_workqueue) { 357 dev_err(&pdev->dev, "[MTK VCODEC] Failed to create encode workqueue"); 358 ret = -EINVAL; 359 goto err_event_workq; 360 } 361 362 ret = video_register_device(vfd_enc, VFL_TYPE_VIDEO, -1); 363 if (ret) { 364 dev_err(&pdev->dev, "[MTK VCODEC] Failed to register video device"); 365 goto err_enc_reg; 366 } 367 368 mtk_vcodec_dbgfs_init(dev, true); 369 dev_dbg(&pdev->dev, "[MTK VCODEC] encoder %d registered as /dev/video%d", 370 dev->venc_pdata->core_id, vfd_enc->num); 371 372 return 0; 373 374err_enc_reg: 375 destroy_workqueue(dev->encode_workqueue); 376err_event_workq: 377 v4l2_m2m_release(dev->m2m_dev_enc); 378err_enc_mem_init: 379 video_unregister_device(vfd_enc); 380err_enc_alloc: 381 v4l2_device_unregister(&dev->v4l2_dev); 382err_res: 383 pm_runtime_disable(dev->pm.dev); 384err_enc_pm: 385 mtk_vcodec_fw_release(dev->fw_handler); 386 return ret; 387} 388 389static const struct mtk_vcodec_enc_pdata mt8173_avc_pdata = { 390 .capture_formats = mtk_video_formats_capture_h264, 391 .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), 392 .output_formats = mtk_video_formats_output, 393 .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), 394 .min_bitrate = 64, 395 .max_bitrate = 60000000, 396 .core_id = VENC_SYS, 397}; 398 399static const struct mtk_vcodec_enc_pdata mt8173_vp8_pdata = { 400 .capture_formats = mtk_video_formats_capture_vp8, 401 .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_vp8), 402 .output_formats = mtk_video_formats_output, 403 .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), 404 .min_bitrate = 64, 405 .max_bitrate = 9000000, 406 .core_id = VENC_LT_SYS, 407}; 408 409static const struct mtk_vcodec_enc_pdata mt8183_pdata = { 410 .uses_ext = true, 411 .capture_formats = mtk_video_formats_capture_h264, 412 .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), 413 .output_formats = mtk_video_formats_output, 414 .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), 415 .min_bitrate = 64, 416 .max_bitrate = 40000000, 417 .core_id = VENC_SYS, 418}; 419 420static const struct mtk_vcodec_enc_pdata mt8188_pdata = { 421 .uses_ext = true, 422 .capture_formats = mtk_video_formats_capture_h264, 423 .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), 424 .output_formats = mtk_video_formats_output, 425 .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), 426 .min_bitrate = 64, 427 .max_bitrate = 50000000, 428 .core_id = VENC_SYS, 429 .uses_34bit = true, 430}; 431 432static const struct mtk_vcodec_enc_pdata mt8192_pdata = { 433 .uses_ext = true, 434 .capture_formats = mtk_video_formats_capture_h264, 435 .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), 436 .output_formats = mtk_video_formats_output, 437 .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), 438 .min_bitrate = 64, 439 .max_bitrate = 100000000, 440 .core_id = VENC_SYS, 441}; 442 443static const struct mtk_vcodec_enc_pdata mt8195_pdata = { 444 .uses_ext = true, 445 .capture_formats = mtk_video_formats_capture_h264, 446 .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_h264), 447 .output_formats = mtk_video_formats_output, 448 .num_output_formats = ARRAY_SIZE(mtk_video_formats_output), 449 .min_bitrate = 64, 450 .max_bitrate = 100000000, 451 .core_id = VENC_SYS, 452}; 453 454static const struct of_device_id mtk_vcodec_enc_match[] = { 455 {.compatible = "mediatek,mt8173-vcodec-enc", 456 .data = &mt8173_avc_pdata}, 457 {.compatible = "mediatek,mt8173-vcodec-enc-vp8", 458 .data = &mt8173_vp8_pdata}, 459 {.compatible = "mediatek,mt8183-vcodec-enc", .data = &mt8183_pdata}, 460 {.compatible = "mediatek,mt8188-vcodec-enc", .data = &mt8188_pdata}, 461 {.compatible = "mediatek,mt8192-vcodec-enc", .data = &mt8192_pdata}, 462 {.compatible = "mediatek,mt8195-vcodec-enc", .data = &mt8195_pdata}, 463 {}, 464}; 465MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match); 466 467static void mtk_vcodec_enc_remove(struct platform_device *pdev) 468{ 469 struct mtk_vcodec_enc_dev *dev = platform_get_drvdata(pdev); 470 471 destroy_workqueue(dev->encode_workqueue); 472 if (dev->m2m_dev_enc) 473 v4l2_m2m_release(dev->m2m_dev_enc); 474 475 if (dev->vfd_enc) 476 video_unregister_device(dev->vfd_enc); 477 478 mtk_vcodec_dbgfs_deinit(&dev->dbgfs); 479 v4l2_device_unregister(&dev->v4l2_dev); 480 pm_runtime_disable(dev->pm.dev); 481 mtk_vcodec_fw_release(dev->fw_handler); 482} 483 484static struct platform_driver mtk_vcodec_enc_driver = { 485 .probe = mtk_vcodec_probe, 486 .remove = mtk_vcodec_enc_remove, 487 .driver = { 488 .name = MTK_VCODEC_ENC_NAME, 489 .of_match_table = mtk_vcodec_enc_match, 490 }, 491}; 492 493module_platform_driver(mtk_vcodec_enc_driver); 494 495 496MODULE_LICENSE("GPL v2"); 497MODULE_DESCRIPTION("Mediatek video codec V4L2 encoder driver");
~/
Read-only file preview.