1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2016 MediaTek Inc.
4 * Author: Tiffany Lin <tiffany.lin@mediatek.com>
5 */
6
7 #include <linux/clk.h>
8 #include <linux/interrupt.h>
9 #include <linux/of.h>
10 #include <linux/pm_runtime.h>
11
12 #include "mtk_vcodec_dec_hw.h"
13 #include "mtk_vcodec_dec_pm.h"
14
mtk_vcodec_init_dec_clk(struct platform_device * pdev,struct mtk_vcodec_pm * pm)15 int mtk_vcodec_init_dec_clk(struct platform_device *pdev, struct mtk_vcodec_pm *pm)
16 {
17 struct mtk_vcodec_clk *dec_clk;
18 struct mtk_vcodec_clk_info *clk_info;
19 int i = 0, ret;
20
21 dec_clk = &pm->vdec_clk;
22 pm->dev = &pdev->dev;
23
24 dec_clk->clk_num =
25 of_property_count_strings(pdev->dev.of_node, "clock-names");
26 if (dec_clk->clk_num > 0) {
27 dec_clk->clk_info = devm_kcalloc(&pdev->dev,
28 dec_clk->clk_num, sizeof(*clk_info),
29 GFP_KERNEL);
30 if (!dec_clk->clk_info)
31 return -ENOMEM;
32 } else {
33 dev_err(&pdev->dev, "Failed to get vdec clock count");
34 return -EINVAL;
35 }
36
37 for (i = 0; i < dec_clk->clk_num; i++) {
38 clk_info = &dec_clk->clk_info[i];
39 ret = of_property_read_string_index(pdev->dev.of_node,
40 "clock-names", i, &clk_info->clk_name);
41 if (ret) {
42 dev_err(&pdev->dev, "Failed to get clock name id = %d", i);
43 return ret;
44 }
45 clk_info->vcodec_clk = devm_clk_get(&pdev->dev,
46 clk_info->clk_name);
47 if (IS_ERR(clk_info->vcodec_clk)) {
48 dev_err(&pdev->dev, "devm_clk_get (%d)%s fail", i, clk_info->clk_name);
49 return PTR_ERR(clk_info->vcodec_clk);
50 }
51 }
52
53 return 0;
54 }
55 EXPORT_SYMBOL_GPL(mtk_vcodec_init_dec_clk);
56
mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm * pm)57 static int mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm)
58 {
59 int ret;
60
61 ret = pm_runtime_resume_and_get(pm->dev);
62 if (ret)
63 dev_err(pm->dev, "pm_runtime_resume_and_get fail %d", ret);
64
65 return ret;
66 }
67
mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm * pm)68 static void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm)
69 {
70 int ret;
71
72 ret = pm_runtime_put(pm->dev);
73 if (ret && ret != -EAGAIN)
74 dev_err(pm->dev, "pm_runtime_put fail %d", ret);
75 }
76
mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm * pm)77 static void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm)
78 {
79 struct mtk_vcodec_clk *dec_clk;
80 int ret, i;
81
82 dec_clk = &pm->vdec_clk;
83 for (i = 0; i < dec_clk->clk_num; i++) {
84 ret = clk_prepare_enable(dec_clk->clk_info[i].vcodec_clk);
85 if (ret) {
86 dev_err(pm->dev, "clk_prepare_enable %d %s fail %d", i,
87 dec_clk->clk_info[i].clk_name, ret);
88 goto error;
89 }
90 }
91
92 return;
93 error:
94 for (i -= 1; i >= 0; i--)
95 clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
96 }
97
mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm * pm)98 static void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm)
99 {
100 struct mtk_vcodec_clk *dec_clk;
101 int i;
102
103 dec_clk = &pm->vdec_clk;
104 for (i = dec_clk->clk_num - 1; i >= 0; i--)
105 clk_disable_unprepare(dec_clk->clk_info[i].vcodec_clk);
106 }
107
mtk_vcodec_dec_enable_irq(struct mtk_vcodec_dec_dev * vdec_dev,int hw_idx)108 static void mtk_vcodec_dec_enable_irq(struct mtk_vcodec_dec_dev *vdec_dev, int hw_idx)
109 {
110 struct mtk_vdec_hw_dev *subdev_dev;
111
112 if (!test_bit(hw_idx, vdec_dev->subdev_bitmap))
113 return;
114
115 if (vdec_dev->vdec_pdata->is_subdev_supported) {
116 subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
117 if (subdev_dev)
118 enable_irq(subdev_dev->dec_irq);
119 else
120 dev_err(&vdec_dev->plat_dev->dev, "Failed to get hw dev\n");
121 } else {
122 enable_irq(vdec_dev->dec_irq);
123 }
124 }
125
mtk_vcodec_dec_disable_irq(struct mtk_vcodec_dec_dev * vdec_dev,int hw_idx)126 static void mtk_vcodec_dec_disable_irq(struct mtk_vcodec_dec_dev *vdec_dev, int hw_idx)
127 {
128 struct mtk_vdec_hw_dev *subdev_dev;
129
130 if (!test_bit(hw_idx, vdec_dev->subdev_bitmap))
131 return;
132
133 if (vdec_dev->vdec_pdata->is_subdev_supported) {
134 subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
135 if (subdev_dev)
136 disable_irq(subdev_dev->dec_irq);
137 else
138 dev_err(&vdec_dev->plat_dev->dev, "Failed to get hw dev\n");
139 } else {
140 disable_irq(vdec_dev->dec_irq);
141 }
142 }
143
mtk_vcodec_load_racing_info(struct mtk_vcodec_dec_ctx * ctx)144 static void mtk_vcodec_load_racing_info(struct mtk_vcodec_dec_ctx *ctx)
145 {
146 void __iomem *vdec_racing_addr;
147 int j;
148
149 mutex_lock(&ctx->dev->dec_racing_info_mutex);
150 if (atomic_inc_return(&ctx->dev->dec_active_cnt) == 1) {
151 vdec_racing_addr = ctx->dev->reg_base[VDEC_MISC] + 0x100;
152 for (j = 0; j < 132; j++)
153 writel(ctx->dev->vdec_racing_info[j], vdec_racing_addr + j * 4);
154 }
155 mutex_unlock(&ctx->dev->dec_racing_info_mutex);
156 }
157
mtk_vcodec_record_racing_info(struct mtk_vcodec_dec_ctx * ctx)158 static void mtk_vcodec_record_racing_info(struct mtk_vcodec_dec_ctx *ctx)
159 {
160 void __iomem *vdec_racing_addr;
161 int j;
162
163 mutex_lock(&ctx->dev->dec_racing_info_mutex);
164 if (atomic_dec_and_test(&ctx->dev->dec_active_cnt)) {
165 vdec_racing_addr = ctx->dev->reg_base[VDEC_MISC] + 0x100;
166 for (j = 0; j < 132; j++)
167 ctx->dev->vdec_racing_info[j] = readl(vdec_racing_addr + j * 4);
168 }
169 mutex_unlock(&ctx->dev->dec_racing_info_mutex);
170 }
171
mtk_vcodec_dec_get_pm(struct mtk_vcodec_dec_dev * vdec_dev,int hw_idx)172 static struct mtk_vcodec_pm *mtk_vcodec_dec_get_pm(struct mtk_vcodec_dec_dev *vdec_dev,
173 int hw_idx)
174 {
175 struct mtk_vdec_hw_dev *subdev_dev;
176
177 if (!test_bit(hw_idx, vdec_dev->subdev_bitmap))
178 return NULL;
179
180 if (vdec_dev->vdec_pdata->is_subdev_supported) {
181 subdev_dev = mtk_vcodec_get_hw_dev(vdec_dev, hw_idx);
182 if (subdev_dev)
183 return &subdev_dev->pm;
184
185 dev_err(&vdec_dev->plat_dev->dev, "Failed to get hw dev\n");
186 return NULL;
187 }
188
189 return &vdec_dev->pm;
190 }
191
mtk_vcodec_dec_child_dev_on(struct mtk_vcodec_dec_dev * vdec_dev,int hw_idx)192 static void mtk_vcodec_dec_child_dev_on(struct mtk_vcodec_dec_dev *vdec_dev,
193 int hw_idx)
194 {
195 struct mtk_vcodec_pm *pm;
196
197 pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx);
198 if (pm) {
199 mtk_vcodec_dec_pw_on(pm);
200 mtk_vcodec_dec_clock_on(pm);
201 }
202
203 if (hw_idx == MTK_VDEC_LAT0) {
204 pm = mtk_vcodec_dec_get_pm(vdec_dev, MTK_VDEC_LAT_SOC);
205 if (pm) {
206 mtk_vcodec_dec_pw_on(pm);
207 mtk_vcodec_dec_clock_on(pm);
208 }
209 }
210 }
211
mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dec_dev * vdec_dev,int hw_idx)212 static void mtk_vcodec_dec_child_dev_off(struct mtk_vcodec_dec_dev *vdec_dev,
213 int hw_idx)
214 {
215 struct mtk_vcodec_pm *pm;
216
217 pm = mtk_vcodec_dec_get_pm(vdec_dev, hw_idx);
218 if (pm) {
219 mtk_vcodec_dec_clock_off(pm);
220 mtk_vcodec_dec_pw_off(pm);
221 }
222
223 if (hw_idx == MTK_VDEC_LAT0) {
224 pm = mtk_vcodec_dec_get_pm(vdec_dev, MTK_VDEC_LAT_SOC);
225 if (pm) {
226 mtk_vcodec_dec_clock_off(pm);
227 mtk_vcodec_dec_pw_off(pm);
228 }
229 }
230 }
231
mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_dec_ctx * ctx,int hw_idx)232 void mtk_vcodec_dec_enable_hardware(struct mtk_vcodec_dec_ctx *ctx, int hw_idx)
233 {
234 mutex_lock(&ctx->dev->dec_mutex[hw_idx]);
235
236 if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) &&
237 hw_idx == MTK_VDEC_CORE)
238 mtk_vcodec_dec_child_dev_on(ctx->dev, MTK_VDEC_LAT0);
239 mtk_vcodec_dec_child_dev_on(ctx->dev, hw_idx);
240
241 mtk_vcodec_dec_enable_irq(ctx->dev, hw_idx);
242
243 if (IS_VDEC_INNER_RACING(ctx->dev->dec_capability))
244 mtk_vcodec_load_racing_info(ctx);
245 }
246 EXPORT_SYMBOL_GPL(mtk_vcodec_dec_enable_hardware);
247
mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_dec_ctx * ctx,int hw_idx)248 void mtk_vcodec_dec_disable_hardware(struct mtk_vcodec_dec_ctx *ctx, int hw_idx)
249 {
250 if (IS_VDEC_INNER_RACING(ctx->dev->dec_capability))
251 mtk_vcodec_record_racing_info(ctx);
252
253 mtk_vcodec_dec_disable_irq(ctx->dev, hw_idx);
254
255 mtk_vcodec_dec_child_dev_off(ctx->dev, hw_idx);
256 if (IS_VDEC_LAT_ARCH(ctx->dev->vdec_pdata->hw_arch) &&
257 hw_idx == MTK_VDEC_CORE)
258 mtk_vcodec_dec_child_dev_off(ctx->dev, MTK_VDEC_LAT0);
259
260 mutex_unlock(&ctx->dev->dec_mutex[hw_idx]);
261 }
262 EXPORT_SYMBOL_GPL(mtk_vcodec_dec_disable_hardware);
263