Loading...
Note: File does not exist in v3.1.
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
15struct 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
27static 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
43static 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
71fail:
72 for (i--; i >= 0; i--)
73 regulator_set_load(s[i].consumer, regs[i].disable_load);
74 return ret;
75}
76
77static 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
98static 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
134static 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
153static 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
177static 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
209int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
210{
211 if (pm_type == DP_CORE_PM)
212 return dp_power->core_clks_on;
213
214 if (pm_type == DP_CTRL_PM)
215 return dp_power->link_clks_on;
216
217 if (pm_type == DP_STREAM_PM)
218 return dp_power->stream_clks_on;
219
220 return 0;
221}
222
223int dp_power_clk_enable(struct dp_power *dp_power,
224 enum dp_pm_type pm_type, bool enable)
225{
226 int rc = 0;
227 struct dp_power_private *power;
228
229 power = container_of(dp_power, struct dp_power_private, dp_power);
230
231 if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM &&
232 pm_type != DP_STREAM_PM) {
233 DRM_ERROR("unsupported power module: %s\n",
234 dp_parser_pm_name(pm_type));
235 return -EINVAL;
236 }
237
238 if (enable) {
239 if (pm_type == DP_CORE_PM && dp_power->core_clks_on) {
240 DRM_DEBUG_DP("core clks already enabled\n");
241 return 0;
242 }
243
244 if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) {
245 DRM_DEBUG_DP("links clks already enabled\n");
246 return 0;
247 }
248
249 if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) {
250 DRM_DEBUG_DP("pixel clks already enabled\n");
251 return 0;
252 }
253
254 if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
255 DRM_DEBUG_DP("Enable core clks before link clks\n");
256
257 rc = dp_power_clk_set_rate(power, DP_CORE_PM, enable);
258 if (rc) {
259 DRM_ERROR("fail to enable clks: %s. err=%d\n",
260 dp_parser_pm_name(DP_CORE_PM), rc);
261 return rc;
262 }
263 dp_power->core_clks_on = true;
264 }
265 }
266
267 rc = dp_power_clk_set_rate(power, pm_type, enable);
268 if (rc) {
269 DRM_ERROR("failed to '%s' clks for: %s. err=%d\n",
270 enable ? "enable" : "disable",
271 dp_parser_pm_name(pm_type), rc);
272 return rc;
273 }
274
275 if (pm_type == DP_CORE_PM)
276 dp_power->core_clks_on = enable;
277 else if (pm_type == DP_STREAM_PM)
278 dp_power->stream_clks_on = enable;
279 else
280 dp_power->link_clks_on = enable;
281
282 DRM_DEBUG_DP("%s clocks for %s\n",
283 enable ? "enable" : "disable",
284 dp_parser_pm_name(pm_type));
285 DRM_DEBUG_DP("strem_clks:%s link_clks:%s core_clks:%s\n",
286 dp_power->stream_clks_on ? "on" : "off",
287 dp_power->link_clks_on ? "on" : "off",
288 dp_power->core_clks_on ? "on" : "off");
289
290 return 0;
291}
292
293int dp_power_client_init(struct dp_power *dp_power)
294{
295 int rc = 0;
296 struct dp_power_private *power;
297
298 if (!dp_power) {
299 DRM_ERROR("invalid power data\n");
300 return -EINVAL;
301 }
302
303 power = container_of(dp_power, struct dp_power_private, dp_power);
304
305 pm_runtime_enable(&power->pdev->dev);
306
307 rc = dp_power_regulator_init(power);
308 if (rc) {
309 DRM_ERROR("failed to init regulators %d\n", rc);
310 goto error;
311 }
312
313 rc = dp_power_clk_init(power);
314 if (rc) {
315 DRM_ERROR("failed to init clocks %d\n", rc);
316 goto error;
317 }
318 return 0;
319
320error:
321 pm_runtime_disable(&power->pdev->dev);
322 return rc;
323}
324
325void dp_power_client_deinit(struct dp_power *dp_power)
326{
327 struct dp_power_private *power;
328
329 if (!dp_power) {
330 DRM_ERROR("invalid power data\n");
331 return;
332 }
333
334 power = container_of(dp_power, struct dp_power_private, dp_power);
335
336 dp_power_clk_deinit(power);
337 pm_runtime_disable(&power->pdev->dev);
338
339}
340
341int dp_power_init(struct dp_power *dp_power, bool flip)
342{
343 int rc = 0;
344 struct dp_power_private *power = NULL;
345
346 if (!dp_power) {
347 DRM_ERROR("invalid power data\n");
348 return -EINVAL;
349 }
350
351 power = container_of(dp_power, struct dp_power_private, dp_power);
352
353 pm_runtime_get_sync(&power->pdev->dev);
354 rc = dp_power_regulator_enable(power);
355 if (rc) {
356 DRM_ERROR("failed to enable regulators, %d\n", rc);
357 goto exit;
358 }
359
360 rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
361 if (rc) {
362 DRM_ERROR("failed to enable DP core clocks, %d\n", rc);
363 goto err_clk;
364 }
365
366 return 0;
367
368err_clk:
369 dp_power_regulator_disable(power);
370exit:
371 pm_runtime_put_sync(&power->pdev->dev);
372 return rc;
373}
374
375int dp_power_deinit(struct dp_power *dp_power)
376{
377 struct dp_power_private *power;
378
379 power = container_of(dp_power, struct dp_power_private, dp_power);
380
381 dp_power_clk_enable(dp_power, DP_CORE_PM, false);
382 dp_power_regulator_disable(power);
383 pm_runtime_put_sync(&power->pdev->dev);
384 return 0;
385}
386
387struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
388{
389 struct dp_power_private *power;
390 struct dp_power *dp_power;
391
392 if (!parser) {
393 DRM_ERROR("invalid input\n");
394 return ERR_PTR(-EINVAL);
395 }
396
397 power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL);
398 if (!power)
399 return ERR_PTR(-ENOMEM);
400
401 power->parser = parser;
402 power->pdev = parser->pdev;
403 power->dev = dev;
404
405 dp_power = &power->dp_power;
406
407 return dp_power;
408}