Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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