xref: /openbmc/linux/drivers/gpu/drm/msm/dp/dp_power.c (revision 5085e036)
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 = devm_clk_bulk_get(dev, core->num_clk, core->clocks);
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 = devm_clk_bulk_get(dev, ctrl->num_clk, ctrl->clocks);
117 	if (rc) {
118 		DRM_ERROR("failed to get %s clk. err=%d\n",
119 			dp_parser_pm_name(DP_CTRL_PM), rc);
120 		return -ENODEV;
121 	}
122 
123 	rc = devm_clk_bulk_get(dev, stream->num_clk, stream->clocks);
124 	if (rc) {
125 		DRM_ERROR("failed to get %s clk. err=%d\n",
126 			dp_parser_pm_name(DP_CTRL_PM), rc);
127 		return -ENODEV;
128 	}
129 
130 	return 0;
131 }
132 
133 int dp_power_clk_status(struct dp_power *dp_power, enum dp_pm_type pm_type)
134 {
135 	struct dp_power_private *power;
136 
137 	power = container_of(dp_power, struct dp_power_private, dp_power);
138 
139 	drm_dbg_dp(power->drm_dev,
140 		"core_clk_on=%d link_clk_on=%d stream_clk_on=%d\n",
141 		dp_power->core_clks_on, dp_power->link_clks_on, dp_power->stream_clks_on);
142 
143 	if (pm_type == DP_CORE_PM)
144 		return dp_power->core_clks_on;
145 
146 	if (pm_type == DP_CTRL_PM)
147 		return dp_power->link_clks_on;
148 
149 	if (pm_type == DP_STREAM_PM)
150 		return dp_power->stream_clks_on;
151 
152 	return 0;
153 }
154 
155 int dp_power_clk_enable(struct dp_power *dp_power,
156 		enum dp_pm_type pm_type, bool enable)
157 {
158 	int rc = 0;
159 	struct dp_power_private *power;
160 	struct dss_module_power *mp;
161 
162 	power = container_of(dp_power, struct dp_power_private, dp_power);
163 
164 	if (pm_type != DP_CORE_PM && pm_type != DP_CTRL_PM &&
165 			pm_type != DP_STREAM_PM) {
166 		DRM_ERROR("unsupported power module: %s\n",
167 				dp_parser_pm_name(pm_type));
168 		return -EINVAL;
169 	}
170 
171 	if (enable) {
172 		if (pm_type == DP_CORE_PM && dp_power->core_clks_on) {
173 			drm_dbg_dp(power->drm_dev,
174 					"core clks already enabled\n");
175 			return 0;
176 		}
177 
178 		if (pm_type == DP_CTRL_PM && dp_power->link_clks_on) {
179 			drm_dbg_dp(power->drm_dev,
180 					"links clks already enabled\n");
181 			return 0;
182 		}
183 
184 		if (pm_type == DP_STREAM_PM && dp_power->stream_clks_on) {
185 			drm_dbg_dp(power->drm_dev,
186 					"pixel clks already enabled\n");
187 			return 0;
188 		}
189 
190 		if ((pm_type == DP_CTRL_PM) && (!dp_power->core_clks_on)) {
191 			drm_dbg_dp(power->drm_dev,
192 					"Enable core clks before link clks\n");
193 			mp = &power->parser->mp[DP_CORE_PM];
194 
195 			rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
196 			if (rc) {
197 				DRM_ERROR("fail to enable clks: %s. err=%d\n",
198 					dp_parser_pm_name(DP_CORE_PM), rc);
199 				return rc;
200 			}
201 			dp_power->core_clks_on = true;
202 		}
203 	}
204 
205 	mp = &power->parser->mp[pm_type];
206 	if (enable) {
207 		rc = clk_bulk_prepare_enable(mp->num_clk, mp->clocks);
208 		if (rc) {
209 			DRM_ERROR("failed to enable clks, err: %d\n", rc);
210 			return rc;
211 		}
212 	} else {
213 		clk_bulk_disable_unprepare(mp->num_clk, mp->clocks);
214 	}
215 
216 	if (pm_type == DP_CORE_PM)
217 		dp_power->core_clks_on = enable;
218 	else if (pm_type == DP_STREAM_PM)
219 		dp_power->stream_clks_on = enable;
220 	else
221 		dp_power->link_clks_on = enable;
222 
223 	drm_dbg_dp(power->drm_dev, "%s clocks for %s\n",
224 			enable ? "enable" : "disable",
225 			dp_parser_pm_name(pm_type));
226 	drm_dbg_dp(power->drm_dev,
227 		"strem_clks:%s link_clks:%s core_clks:%s\n",
228 		dp_power->stream_clks_on ? "on" : "off",
229 		dp_power->link_clks_on ? "on" : "off",
230 		dp_power->core_clks_on ? "on" : "off");
231 
232 	return 0;
233 }
234 
235 int dp_power_client_init(struct dp_power *dp_power)
236 {
237 	int rc = 0;
238 	struct dp_power_private *power;
239 
240 	if (!dp_power) {
241 		DRM_ERROR("invalid power data\n");
242 		return -EINVAL;
243 	}
244 
245 	power = container_of(dp_power, struct dp_power_private, dp_power);
246 
247 	pm_runtime_enable(&power->pdev->dev);
248 
249 	rc = dp_power_regulator_init(power);
250 	if (rc) {
251 		DRM_ERROR("failed to init regulators %d\n", rc);
252 		goto error;
253 	}
254 
255 	rc = dp_power_clk_init(power);
256 	if (rc) {
257 		DRM_ERROR("failed to init clocks %d\n", rc);
258 		goto error;
259 	}
260 	return 0;
261 
262 error:
263 	pm_runtime_disable(&power->pdev->dev);
264 	return rc;
265 }
266 
267 void dp_power_client_deinit(struct dp_power *dp_power)
268 {
269 	struct dp_power_private *power;
270 
271 	if (!dp_power) {
272 		DRM_ERROR("invalid power data\n");
273 		return;
274 	}
275 
276 	power = container_of(dp_power, struct dp_power_private, dp_power);
277 
278 	pm_runtime_disable(&power->pdev->dev);
279 }
280 
281 int dp_power_init(struct dp_power *dp_power, bool flip)
282 {
283 	int rc = 0;
284 	struct dp_power_private *power = NULL;
285 
286 	if (!dp_power) {
287 		DRM_ERROR("invalid power data\n");
288 		return -EINVAL;
289 	}
290 
291 	power = container_of(dp_power, struct dp_power_private, dp_power);
292 
293 	pm_runtime_get_sync(&power->pdev->dev);
294 	rc = dp_power_regulator_enable(power);
295 	if (rc) {
296 		DRM_ERROR("failed to enable regulators, %d\n", rc);
297 		goto exit;
298 	}
299 
300 	rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
301 	if (rc) {
302 		DRM_ERROR("failed to enable DP core clocks, %d\n", rc);
303 		goto err_clk;
304 	}
305 
306 	return 0;
307 
308 err_clk:
309 	dp_power_regulator_disable(power);
310 exit:
311 	pm_runtime_put_sync(&power->pdev->dev);
312 	return rc;
313 }
314 
315 int dp_power_deinit(struct dp_power *dp_power)
316 {
317 	struct dp_power_private *power;
318 
319 	power = container_of(dp_power, struct dp_power_private, dp_power);
320 
321 	dp_power_clk_enable(dp_power, DP_CORE_PM, false);
322 	dp_power_regulator_disable(power);
323 	pm_runtime_put_sync(&power->pdev->dev);
324 	return 0;
325 }
326 
327 struct dp_power *dp_power_get(struct device *dev, struct dp_parser *parser)
328 {
329 	struct dp_power_private *power;
330 	struct dp_power *dp_power;
331 
332 	if (!parser) {
333 		DRM_ERROR("invalid input\n");
334 		return ERR_PTR(-EINVAL);
335 	}
336 
337 	power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL);
338 	if (!power)
339 		return ERR_PTR(-ENOMEM);
340 
341 	power->parser = parser;
342 	power->pdev = parser->pdev;
343 	power->dev = dev;
344 
345 	dp_power = &power->dp_power;
346 
347 	return dp_power;
348 }
349