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
14struct 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
25static 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
41static 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
69fail:
70	for (i--; i >= 0; i--)
71		regulator_set_load(s[i].consumer, regs[i].disable_load);
72	return ret;
73}
74
75static 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
96static 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
132static 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
151static 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
174int 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
188int 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
258int 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
285error:
286	pm_runtime_disable(&power->pdev->dev);
287	return rc;
288}
289
290void 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
306int 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
333err_clk:
334	dp_power_regulator_disable(power);
335exit:
336	pm_runtime_put_sync(&power->pdev->dev);
337	return rc;
338}
339
340int 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
352struct 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