]> Git Repo - J-linux.git/blob - drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_pm.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / media / platform / mediatek / vcodec / decoder / mtk_vcodec_dec_pm.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2016 MediaTek Inc.
4  * Author: Tiffany Lin <[email protected]>
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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);
This page took 0.043435 seconds and 4 git commands to generate.