xref: /openbmc/linux/drivers/gpu/drm/msm/dp/dp_power.c (revision d57cc3b9)
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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