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