File Index
Files and directories
Sign in
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 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.