Linux Audio

Check our new training course

Linux kernel drivers training

May 6-19, 2025
Register
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}