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