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