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