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