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