Author | Tokens | Token Proportion | Commits | Commit Proportion |
---|---|---|---|---|
Yunfei Dong | 719 | 77.90% | 9 | 69.23% |
Tiffany Lin | 198 | 21.45% | 2 | 15.38% |
Xiongfeng Wang | 5 | 0.54% | 1 | 7.69% |
Alexandre Courbot | 1 | 0.11% | 1 | 7.69% |
Total | 923 | 13 |
// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2021 MediaTek Inc. * Author: Yunfei Dong <yunfei.dong@mediatek.com> */ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/pm_runtime.h> #include <linux/slab.h> #include "mtk_vcodec_drv.h" #include "mtk_vcodec_dec.h" #include "mtk_vcodec_dec_hw.h" #include "mtk_vcodec_dec_pm.h" #include "mtk_vcodec_intr.h" #include "mtk_vcodec_util.h" static const struct of_device_id mtk_vdec_hw_match[] = { { .compatible = "mediatek,mtk-vcodec-lat", .data = (void *)MTK_VDEC_LAT0, }, { .compatible = "mediatek,mtk-vcodec-core", .data = (void *)MTK_VDEC_CORE, }, { .compatible = "mediatek,mtk-vcodec-lat-soc", .data = (void *)MTK_VDEC_LAT_SOC, }, {}, }; MODULE_DEVICE_TABLE(of, mtk_vdec_hw_match); static int mtk_vdec_hw_prob_done(struct mtk_vcodec_dev *vdec_dev) { struct platform_device *pdev = vdec_dev->plat_dev; struct device_node *subdev_node; enum mtk_vdec_hw_id hw_idx; const struct of_device_id *of_id; int i; for (i = 0; i < ARRAY_SIZE(mtk_vdec_hw_match); i++) { of_id = &mtk_vdec_hw_match[i]; subdev_node = of_find_compatible_node(NULL, NULL, of_id->compatible); if (!subdev_node) continue; of_node_put(subdev_node); hw_idx = (enum mtk_vdec_hw_id)(uintptr_t)of_id->data; if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) { dev_err(&pdev->dev, "vdec %d is not ready", hw_idx); return -EAGAIN; } } return 0; } static irqreturn_t mtk_vdec_hw_irq_handler(int irq, void *priv) { struct mtk_vdec_hw_dev *dev = priv; struct mtk_vcodec_ctx *ctx; u32 cg_status; unsigned int dec_done_status; void __iomem *vdec_misc_addr = dev->reg_base[VDEC_HW_MISC] + VDEC_IRQ_CFG_REG; ctx = mtk_vcodec_get_curr_ctx(dev->main_dev, dev->hw_idx); /* check if HW active or not */ cg_status = readl(dev->reg_base[VDEC_HW_SYS]); if (cg_status & VDEC_HW_ACTIVE) { mtk_v4l2_err("vdec active is not 0x0 (0x%08x)", cg_status); return IRQ_HANDLED; } dec_done_status = readl(vdec_misc_addr); if ((dec_done_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) != MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) return IRQ_HANDLED; /* clear interrupt */ writel(dec_done_status | VDEC_IRQ_CFG, vdec_misc_addr); writel(dec_done_status & ~VDEC_IRQ_CLR, vdec_misc_addr); wake_up_ctx(ctx, MTK_INST_IRQ_RECEIVED, dev->hw_idx); mtk_v4l2_debug(3, "wake up ctx %d, dec_done_status=%x", ctx->id, dec_done_status); return IRQ_HANDLED; } static int mtk_vdec_hw_init_irq(struct mtk_vdec_hw_dev *dev) { struct platform_device *pdev = dev->plat_dev; int ret; dev->dec_irq = platform_get_irq(pdev, 0); if (dev->dec_irq < 0) return dev->dec_irq; irq_set_status_flags(dev->dec_irq, IRQ_NOAUTOEN); ret = devm_request_irq(&pdev->dev, dev->dec_irq, mtk_vdec_hw_irq_handler, 0, pdev->name, dev); if (ret) { dev_err(&pdev->dev, "Failed to install dev->dec_irq %d (%d)", dev->dec_irq, ret); return ret; } return 0; } static int mtk_vdec_hw_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mtk_vdec_hw_dev *subdev_dev; struct mtk_vcodec_dev *main_dev; const struct of_device_id *of_id; int hw_idx; int ret; if (!dev->parent) { dev_err(dev, "no parent for hardware devices.\n"); return -ENODEV; } main_dev = dev_get_drvdata(dev->parent); if (!main_dev) { dev_err(dev, "failed to get parent driver data"); return -EINVAL; } subdev_dev = devm_kzalloc(dev, sizeof(*subdev_dev), GFP_KERNEL); if (!subdev_dev) return -ENOMEM; subdev_dev->plat_dev = pdev; ret = mtk_vcodec_init_dec_clk(pdev, &subdev_dev->pm); if (ret) return ret; pm_runtime_enable(&pdev->dev); of_id = of_match_device(mtk_vdec_hw_match, dev); if (!of_id) { dev_err(dev, "Can't get vdec subdev id.\n"); ret = -EINVAL; goto err; } hw_idx = (enum mtk_vdec_hw_id)(uintptr_t)of_id->data; if (hw_idx >= MTK_VDEC_HW_MAX) { dev_err(dev, "Hardware index %d not correct.\n", hw_idx); ret = -EINVAL; goto err; } main_dev->subdev_dev[hw_idx] = subdev_dev; subdev_dev->hw_idx = hw_idx; subdev_dev->main_dev = main_dev; subdev_dev->reg_base[VDEC_HW_SYS] = main_dev->reg_base[VDEC_HW_SYS]; set_bit(subdev_dev->hw_idx, main_dev->subdev_bitmap); if (IS_SUPPORT_VDEC_HW_IRQ(hw_idx)) { ret = mtk_vdec_hw_init_irq(subdev_dev); if (ret) goto err; } subdev_dev->reg_base[VDEC_HW_MISC] = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR((__force void *)subdev_dev->reg_base[VDEC_HW_MISC])) { ret = PTR_ERR((__force void *)subdev_dev->reg_base[VDEC_HW_MISC]); goto err; } if (!main_dev->subdev_prob_done) main_dev->subdev_prob_done = mtk_vdec_hw_prob_done; platform_set_drvdata(pdev, subdev_dev); return 0; err: pm_runtime_disable(subdev_dev->pm.dev); return ret; } static struct platform_driver mtk_vdec_driver = { .probe = mtk_vdec_hw_probe, .driver = { .name = "mtk-vdec-comp", .of_match_table = mtk_vdec_hw_match, }, }; module_platform_driver(mtk_vdec_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Mediatek video decoder hardware driver");
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with Cregit http://github.com/cregit/cregit
Version 2.0-RC1