Merge tag 'drm-misc-next-fixes-2021-09-09' of git://anongit.freedesktop.org/drm/drm...
[linux-2.6-microblaze.git] / drivers / gpu / drm / msm / dp / dp_power.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2012-2020, The Linux Foundation. All rights reserved.
4  */
5
6 #define pr_fmt(fmt)     "[drm-dp] %s: " fmt, __func__
7
8 #include <linux/clk.h>
9 #include <linux/clk-provider.h>
10 #include <linux/regulator/consumer.h>
11 #include <linux/pm_opp.h>
12 #include "dp_power.h"
13 #include "msm_drv.h"
14
15 struct dp_power_private {
16         struct dp_parser *parser;
17         struct platform_device *pdev;
18         struct device *dev;
19         struct clk *link_clk_src;
20         struct clk *pixel_provider;
21         struct clk *link_provider;
22         struct regulator_bulk_data supplies[DP_DEV_REGULATOR_MAX];
23
24         struct dp_power dp_power;
25 };
26
27 static void dp_power_regulator_disable(struct dp_power_private *power)
28 {
29         struct regulator_bulk_data *s = power->supplies;
30         const struct dp_reg_entry *regs = power->parser->regulator_cfg->regs;
31         int num = power->parser->regulator_cfg->num;
32         int i;
33
34         DBG("");
35         for (i = num - 1; i >= 0; i--)
36                 if (regs[i].disable_load >= 0)
37                         regulator_set_load(s[i].consumer,
38                                            regs[i].disable_load);
39
40         regulator_bulk_disable(num, s);
41 }
42
43 static int dp_power_regulator_enable(struct dp_power_private *power)
44 {
45         struct regulator_bulk_data *s = power->supplies;
46         const struct dp_reg_entry *regs = power->parser->regulator_cfg->regs;
47         int num = power->parser->regulator_cfg->num;
48         int ret, i;
49
50         DBG("");
51         for (i = 0; i < num; i++) {
52                 if (regs[i].enable_load >= 0) {
53                         ret = regulator_set_load(s[i].consumer,
54                                                  regs[i].enable_load);
55                         if (ret < 0) {
56                                 pr_err("regulator %d set op mode failed, %d\n",
57                                         i, ret);
58                                 goto fail;
59                         }
60                 }
61         }
62
63         ret = regulator_bulk_enable(num, s);
64         if (ret < 0) {
65                 pr_err("regulator enable failed, %d\n", ret);
66                 goto fail;
67         }
68
69         return 0;
70
71 fail:
72         for (i--; i >= 0; i--)
73                 regulator_set_load(s[i].consumer, regs[i].disable_load);
74         return ret;
75 }
76
77 static int dp_power_regulator_init(struct dp_power_private *power)
78 {
79         struct regulator_bulk_data *s = power->supplies;
80         const struct dp_reg_entry *regs = power->parser->regulator_cfg->regs;
81         struct platform_device *pdev = power->pdev;
82         int num = power->parser->regulator_cfg->num;
83         int i, ret;
84
85         for (i = 0; i < num; i++)
86                 s[i].supply = regs[i].name;
87
88         ret = devm_regulator_bulk_get(&pdev->dev, num, s);
89         if (ret < 0) {
90                 pr_err("%s: failed to init regulator, ret=%d\n",
91                                                 __func__, ret);
92                 return ret;
93         }
94
95         return 0;
96 }
97
98 static int dp_power_clk_init(struct dp_power_private *power)
99 {
100         int rc = 0;
101         struct dss_module_power *core, *ctrl, *stream;
102         struct device *dev = &power->pdev->dev;
103
104         core = &power->parser->mp[DP_CORE_PM];
105         ctrl = &power->parser->mp[DP_CTRL_PM];
106         stream = &power->parser->mp[DP_STREAM_PM];
107
108         rc = msm_dss_get_clk(dev, core->clk_config, core->num_clk);
109         if (rc) {
110                 DRM_ERROR("failed to get %s clk. err=%d\n",
111                         dp_parser_pm_name(DP_CORE_PM), rc);
112                 return rc;
113         }
114
115         rc = msm_dss_get_clk(dev, ctrl->clk_config, ctrl->num_clk);
116         if (rc) {
117                 DRM_ERROR("failed to get %s clk. err=%d\n",
118                         dp_parser_pm_name(DP_CTRL_PM), rc);
119                 msm_dss_put_clk(core->clk_config, core->num_clk);
120                 return -ENODEV;
121         }
122
123         rc = msm_dss_get_clk(dev, stream->clk_config, stream->num_clk);
124         if (rc) {
125                 DRM_ERROR("failed to get %s clk. err=%d\n",
126                         dp_parser_pm_name(DP_CTRL_PM), rc);
127                 msm_dss_put_clk(core->clk_config, core->num_clk);
128                 return -ENODEV;
129         }
130
131         return 0;
132 }
133
134 static int dp_power_clk_deinit(struct dp_power_private *power)
135 {
136         struct dss_module_power *core, *ctrl, *stream;
137
138         core = &power->parser->mp[DP_CORE_PM];
139         ctrl = &power->parser->mp[DP_CTRL_PM];
140         stream = &power->parser->mp[DP_STREAM_PM];
141
142         if (!core || !ctrl || !stream) {
143                 DRM_ERROR("invalid power_data\n");
144                 return -EINVAL;
145         }
146
147         msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk);
148         msm_dss_put_clk(core->clk_config, core->num_clk);
149         msm_dss_put_clk(stream->clk_config, stream->num_clk);
150         return 0;
151 }
152
153 static int dp_power_clk_set_link_rate(struct dp_power_private *power,
154                         struct dss_clk *clk_arry, int num_clk, int enable)
155 {
156         u32 rate;
157         int i, rc = 0;
158
159         for (i = 0; i < num_clk; i++) {
160                 if (clk_arry[i].clk) {
161                         if (clk_arry[i].type == DSS_CLK_PCLK) {
162                                 if (enable)
163                                         rate = clk_arry[i].rate;
164                                 else
165                                         rate = 0;
166
167                                 rc = dev_pm_opp_set_rate(power->dev, rate);
168                                 if (rc)
169                                         break;
170                         }
171
172                 }
173         }
174         return rc;
175 }
176
177 static int dp_power_clk_set_rate(struct dp_power_private *power,
178                 enum dp_pm_type module, bool enable)
179 {
180         int rc = 0;
181         struct dss_module_power *mp = &power->parser->mp[module];
182
183         if (module == DP_CTRL_PM) {
184                 rc = dp_power_clk_set_link_rate(power, mp->clk_config, mp->num_clk, enable);
185                 if (rc) {
186                         DRM_ERROR("failed to set link clks rate\n");
187                         return rc;
188                 }
189         } else {
190
191                 if (enable) {
192                         rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
193                         if (rc) {
194                                 DRM_ERROR("failed to set clks rate\n");
195                                 return rc;
196                         }
197                 }
198         }
199
200         rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, enable);
201         if (rc) {
202                 DRM_ERROR("failed to %d clks, err: %d\n", enable, rc);
203                 return rc;
204         }
205
206         return 0;
207 }
208
209 int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
210 {
211         DRM_DEBUG_DP("core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
212                 dp_power->core_clks_on, dp_power->link_clks_on, dp_power->stream_clks_on);
213
214         if (pm_type == DP_CORE_PM)
215                 return dp_power->core_clks_on;
216
217         if (pm_type == DP_CTRL_PM)
218                 return dp_power->link_clks_on;
219
220         if (pm_type == DP_STREAM_PM)
221                 return dp_power->stream_clks_on;
222
223         return 0;
224 }
225
226 int dp_power_clk_enable(struct dp_power *dp_power,
227                 enum dp_pm_type pm_type, bool enable)
228 {
229         int rc = 0;
230         struct dp_power_private *power;
231
232         power = container_of(dp_power, struct dp_power_private, dp_power);
233
234         if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM &&
235                         pm_type != DP_STREAM_PM) {
236                 DRM_ERROR("unsupported power module: %s\n",
237                                 dp_parser_pm_name(pm_type));
238                 return -EINVAL;
239         }
240
241         if (enable) {
242                 if (pm_type == DP_CORE_PM && dp_power->core_clks_on) {
243                         DRM_DEBUG_DP("core clks already enabled\n");
244                         return 0;
245                 }
246
247                 if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) {
248                         DRM_DEBUG_DP("links clks already enabled\n");
249                         return 0;
250                 }
251
252                 if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) {
253                         DRM_DEBUG_DP("pixel clks already enabled\n");
254                         return 0;
255                 }
256
257                 if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
258                         DRM_DEBUG_DP("Enable core clks before link clks\n");
259
260                         rc = dp_power_clk_set_rate(power, DP_CORE_PM, enable);
261                         if (rc) {
262                                 DRM_ERROR("fail to enable clks: %s. err=%d\n",
263                                         dp_parser_pm_name(DP_CORE_PM), rc);
264                                 return rc;
265                         }
266                         dp_power->core_clks_on = true;
267                 }
268         }
269
270         rc = dp_power_clk_set_rate(power, pm_type, enable);
271         if (rc) {
272                 DRM_ERROR("failed to '%s' clks for: %s. err=%d\n",
273                         enable ? "enable" : "disable",
274                         dp_parser_pm_name(pm_type), rc);
275                 return rc;
276         }
277
278         if (pm_type == DP_CORE_PM)
279                 dp_power->core_clks_on = enable;
280         else if (pm_type == DP_STREAM_PM)
281                 dp_power->stream_clks_on = enable;
282         else
283                 dp_power->link_clks_on = enable;
284
285         DRM_DEBUG_DP("%s clocks for %s\n",
286                         enable ? "enable" : "disable",
287                         dp_parser_pm_name(pm_type));
288         DRM_DEBUG_DP("strem_clks:%s link_clks:%s core_clks:%s\n",
289                 dp_power->stream_clks_on ? "on" : "off",
290                 dp_power->link_clks_on ? "on" : "off",
291                 dp_power->core_clks_on ? "on" : "off");
292
293         return 0;
294 }
295
296 int dp_power_client_init(struct dp_power *dp_power)
297 {
298         int rc = 0;
299         struct dp_power_private *power;
300
301         if (!dp_power) {
302                 DRM_ERROR("invalid power data\n");
303                 return -EINVAL;
304         }
305
306         power = container_of(dp_power, struct dp_power_private, dp_power);
307
308         pm_runtime_enable(&power->pdev->dev);
309
310         rc = dp_power_regulator_init(power);
311         if (rc) {
312                 DRM_ERROR("failed to init regulators %d\n", rc);
313                 goto error;
314         }
315
316         rc = dp_power_clk_init(power);
317         if (rc) {
318                 DRM_ERROR("failed to init clocks %d\n", rc);
319                 goto error;
320         }
321         return 0;
322
323 error:
324         pm_runtime_disable(&power->pdev->dev);
325         return rc;
326 }
327
328 void dp_power_client_deinit(struct dp_power *dp_power)
329 {
330         struct dp_power_private *power;
331
332         if (!dp_power) {
333                 DRM_ERROR("invalid power data\n");
334                 return;
335         }
336
337         power = container_of(dp_power, struct dp_power_private, dp_power);
338
339         dp_power_clk_deinit(power);
340         pm_runtime_disable(&power->pdev->dev);
341
342 }
343
344 int dp_power_init(struct dp_power *dp_power, bool flip)
345 {
346         int rc = 0;
347         struct dp_power_private *power = NULL;
348
349         if (!dp_power) {
350                 DRM_ERROR("invalid power data\n");
351                 return -EINVAL;
352         }
353
354         power = container_of(dp_power, struct dp_power_private, dp_power);
355
356         pm_runtime_get_sync(&power->pdev->dev);
357         rc = dp_power_regulator_enable(power);
358         if (rc) {
359                 DRM_ERROR("failed to enable regulators, %d\n", rc);
360                 goto exit;
361         }
362
363         rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
364         if (rc) {
365                 DRM_ERROR("failed to enable DP core clocks, %d\n", rc);
366                 goto err_clk;
367         }
368
369         return 0;
370
371 err_clk:
372         dp_power_regulator_disable(power);
373 exit:
374         pm_runtime_put_sync(&power->pdev->dev);
375         return rc;
376 }
377
378 int dp_power_deinit(struct dp_power *dp_power)
379 {
380         struct dp_power_private *power;
381
382         power = container_of(dp_power, struct dp_power_private, dp_power);
383
384         dp_power_clk_enable(dp_power, DP_CORE_PM, false);
385         dp_power_regulator_disable(power);
386         pm_runtime_put_sync(&power->pdev->dev);
387         return 0;
388 }
389
390 struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
391 {
392         struct dp_power_private *power;
393         struct dp_power *dp_power;
394
395         if (!parser) {
396                 DRM_ERROR("invalid input\n");
397                 return ERR_PTR(-EINVAL);
398         }
399
400         power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL);
401         if (!power)
402                 return ERR_PTR(-ENOMEM);
403
404         power->parser = parser;
405         power->pdev = parser->pdev;
406         power->dev = dev;
407
408         dp_power = &power->dp_power;
409
410         return dp_power;
411 }