FILE
mtk_vcodec_dec_hw.c
File preview with syntax highlighting.
linux-6.19.14/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_hw.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2021 MediaTek Inc. 4 * Author: Yunfei Dong <yunfei.dong@mediatek.com> 5 */ 6 7#include <linux/interrupt.h> 8#include <linux/irq.h> 9#include <linux/module.h> 10#include <linux/of.h> 11#include <linux/of_device.h> 12#include <linux/pm_runtime.h> 13#include <linux/slab.h> 14 15#include "mtk_vcodec_dec.h" 16#include "mtk_vcodec_dec_hw.h" 17#include "mtk_vcodec_dec_pm.h" 18#include "../common/mtk_vcodec_intr.h" 19 20static const struct of_device_id mtk_vdec_hw_match[] = { 21 { 22 .compatible = "mediatek,mtk-vcodec-lat", 23 .data = (void *)MTK_VDEC_LAT0, 24 }, 25 { 26 .compatible = "mediatek,mtk-vcodec-core", 27 .data = (void *)MTK_VDEC_CORE, 28 }, 29 { 30 .compatible = "mediatek,mtk-vcodec-lat-soc", 31 .data = (void *)MTK_VDEC_LAT_SOC, 32 }, 33 {}, 34}; 35MODULE_DEVICE_TABLE(of, mtk_vdec_hw_match); 36 37static int mtk_vdec_hw_prob_done(struct mtk_vcodec_dec_dev *vdec_dev) 38{ 39 struct platform_device *pdev = vdec_dev->plat_dev; 40 struct device_node *subdev_node; 41 enum mtk_vdec_hw_id hw_idx; 42 const struct of_device_id *of_id; 43 int i; 44 45 for (i = 0; i < ARRAY_SIZE(mtk_vdec_hw_match); i++) { 46 of_id = &mtk_vdec_hw_match[i]; 47 subdev_node = of_find_compatible_node(NULL, NULL, 48 of_id->compatible); 49 if (!subdev_node) 50 continue; 51 52 of_node_put(subdev_node); 53 54 hw_idx = (enum mtk_vdec_hw_id)(uintptr_t)of_id->data; 55 if (!test_bit(hw_idx, vdec_dev->subdev_bitmap)) { 56 dev_err(&pdev->dev, "vdec %d is not ready", hw_idx); 57 return -EAGAIN; 58 } 59 } 60 61 return 0; 62} 63 64static irqreturn_t mtk_vdec_hw_irq_handler(int irq, void *priv) 65{ 66 struct mtk_vdec_hw_dev *dev = priv; 67 struct mtk_vcodec_dec_ctx *ctx; 68 u32 cg_status; 69 unsigned int dec_done_status; 70 void __iomem *vdec_misc_addr = dev->reg_base[VDEC_HW_MISC] + 71 VDEC_IRQ_CFG_REG; 72 73 ctx = mtk_vcodec_get_curr_ctx(dev->main_dev, dev->hw_idx); 74 75 /* check if HW active or not */ 76 cg_status = readl(dev->reg_base[VDEC_HW_SYS] + VDEC_HW_ACTIVE_ADDR); 77 if (cg_status & VDEC_HW_ACTIVE_MASK) { 78 mtk_v4l2_vdec_err(ctx, "vdec active is not 0x0 (0x%08x)", cg_status); 79 return IRQ_HANDLED; 80 } 81 82 dec_done_status = readl(vdec_misc_addr); 83 if ((dec_done_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) != 84 MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) 85 return IRQ_HANDLED; 86 87 /* clear interrupt */ 88 writel(dec_done_status | VDEC_IRQ_CFG, vdec_misc_addr); 89 writel(dec_done_status & ~VDEC_IRQ_CLR, vdec_misc_addr); 90 91 wake_up_dec_ctx(ctx, MTK_INST_IRQ_RECEIVED, dev->hw_idx); 92 93 mtk_v4l2_vdec_dbg(3, ctx, "wake up ctx %d, dec_done_status=%x", 94 ctx->id, dec_done_status); 95 96 return IRQ_HANDLED; 97} 98 99static int mtk_vdec_hw_init_irq(struct mtk_vdec_hw_dev *dev) 100{ 101 struct platform_device *pdev = dev->plat_dev; 102 int ret; 103 104 dev->dec_irq = platform_get_irq(pdev, 0); 105 if (dev->dec_irq < 0) 106 return dev->dec_irq; 107 108 irq_set_status_flags(dev->dec_irq, IRQ_NOAUTOEN); 109 ret = devm_request_irq(&pdev->dev, dev->dec_irq, 110 mtk_vdec_hw_irq_handler, 0, pdev->name, dev); 111 if (ret) { 112 dev_err(&pdev->dev, "Failed to install dev->dec_irq %d (%d)", 113 dev->dec_irq, ret); 114 return ret; 115 } 116 117 return 0; 118} 119 120static int mtk_vdec_hw_probe(struct platform_device *pdev) 121{ 122 struct device *dev = &pdev->dev; 123 struct mtk_vdec_hw_dev *subdev_dev; 124 struct mtk_vcodec_dec_dev *main_dev; 125 const struct of_device_id *of_id; 126 int hw_idx; 127 int ret; 128 129 if (!dev->parent) { 130 dev_err(dev, "no parent for hardware devices.\n"); 131 return -ENODEV; 132 } 133 134 main_dev = dev_get_drvdata(dev->parent); 135 if (!main_dev) { 136 dev_err(dev, "failed to get parent driver data"); 137 return -EINVAL; 138 } 139 140 subdev_dev = devm_kzalloc(dev, sizeof(*subdev_dev), GFP_KERNEL); 141 if (!subdev_dev) 142 return -ENOMEM; 143 144 subdev_dev->plat_dev = pdev; 145 ret = mtk_vcodec_init_dec_clk(pdev, &subdev_dev->pm); 146 if (ret) 147 return ret; 148 149 ret = devm_pm_runtime_enable(&pdev->dev); 150 if (ret) 151 return ret; 152 153 of_id = of_match_device(mtk_vdec_hw_match, dev); 154 if (!of_id) { 155 dev_err(dev, "Can't get vdec subdev id.\n"); 156 return -EINVAL; 157 } 158 159 hw_idx = (enum mtk_vdec_hw_id)(uintptr_t)of_id->data; 160 if (hw_idx >= MTK_VDEC_HW_MAX) { 161 dev_err(dev, "Hardware index %d not correct.\n", hw_idx); 162 return -EINVAL; 163 } 164 165 main_dev->subdev_dev[hw_idx] = subdev_dev; 166 subdev_dev->hw_idx = hw_idx; 167 subdev_dev->main_dev = main_dev; 168 subdev_dev->reg_base[VDEC_HW_SYS] = main_dev->reg_base[VDEC_HW_SYS]; 169 set_bit(subdev_dev->hw_idx, main_dev->subdev_bitmap); 170 171 if (IS_SUPPORT_VDEC_HW_IRQ(hw_idx)) { 172 ret = mtk_vdec_hw_init_irq(subdev_dev); 173 if (ret) 174 return ret; 175 } 176 177 subdev_dev->reg_base[VDEC_HW_MISC] = 178 devm_platform_ioremap_resource(pdev, 0); 179 if (IS_ERR((__force void *)subdev_dev->reg_base[VDEC_HW_MISC])) { 180 ret = PTR_ERR((__force void *)subdev_dev->reg_base[VDEC_HW_MISC]); 181 return ret; 182 } 183 184 if (!main_dev->subdev_prob_done) 185 main_dev->subdev_prob_done = mtk_vdec_hw_prob_done; 186 187 platform_set_drvdata(pdev, subdev_dev); 188 return 0; 189} 190 191static struct platform_driver mtk_vdec_driver = { 192 .probe = mtk_vdec_hw_probe, 193 .driver = { 194 .name = "mtk-vdec-comp", 195 .of_match_table = mtk_vdec_hw_match, 196 }, 197}; 198module_platform_driver(mtk_vdec_driver); 199 200MODULE_LICENSE("GPL v2"); 201MODULE_DESCRIPTION("Mediatek video decoder hardware driver");
~/
Read-only file preview.