blob: d793365f3c3611f73004eddddc571984a5e8689a [file] [log] [blame]
Ajay Singh Parmar3e5d49e2017-03-20 23:37:57 -07001/*
2 * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__
16
17#include <linux/clk.h>
18#include "dp_power.h"
19
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -070020#define DP_CLIENT_NAME_SIZE 20
21
Ajay Singh Parmar3e5d49e2017-03-20 23:37:57 -070022struct dp_power_private {
23 struct dp_parser *parser;
24 struct platform_device *pdev;
25 struct clk *pixel_clk_rcg;
26 struct clk *pixel_parent;
27
28 struct dp_power dp_power;
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -070029 struct sde_power_client *dp_core_client;
30 struct sde_power_handle *phandle;
Ajay Singh Parmar3e5d49e2017-03-20 23:37:57 -070031
32 bool core_clks_on;
33 bool link_clks_on;
34};
35
36static int dp_power_regulator_init(struct dp_power_private *power)
37{
38 int rc = 0, i = 0, j = 0;
39 struct platform_device *pdev;
40 struct dp_parser *parser;
41
42 parser = power->parser;
43 pdev = power->pdev;
44
45 for (i = DP_CORE_PM; !rc && (i < DP_MAX_PM); i++) {
46 rc = msm_dss_config_vreg(&pdev->dev,
47 parser->mp[i].vreg_config,
48 parser->mp[i].num_vreg, 1);
49 if (rc) {
50 pr_err("failed to init vregs for %s\n",
51 dp_parser_pm_name(i));
52 for (j = i - 1; j >= DP_CORE_PM; j--) {
53 msm_dss_config_vreg(&pdev->dev,
54 parser->mp[j].vreg_config,
55 parser->mp[j].num_vreg, 0);
56 }
57
58 goto error;
59 }
60 }
61error:
62 return rc;
63}
64
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -070065static void dp_power_regulator_deinit(struct dp_power_private *power)
66{
67 int rc = 0, i = 0;
68 struct platform_device *pdev;
69 struct dp_parser *parser;
70
71 parser = power->parser;
72 pdev = power->pdev;
73
74 for (i = DP_CORE_PM; (i < DP_MAX_PM); i++) {
75 rc = msm_dss_config_vreg(&pdev->dev,
76 parser->mp[i].vreg_config,
77 parser->mp[i].num_vreg, 0);
78 if (rc)
79 pr_err("failed to deinit vregs for %s\n",
80 dp_parser_pm_name(i));
81 }
82}
83
Ajay Singh Parmar3e5d49e2017-03-20 23:37:57 -070084static int dp_power_regulator_ctrl(struct dp_power_private *power, bool enable)
85{
86 int rc = 0, i = 0, j = 0;
87 struct dp_parser *parser;
88
89 parser = power->parser;
90
91 for (i = DP_CORE_PM; i < DP_MAX_PM; i++) {
92 rc = msm_dss_enable_vreg(
93 parser->mp[i].vreg_config,
94 parser->mp[i].num_vreg, enable);
95 if (rc) {
96 pr_err("failed to '%s' vregs for %s\n",
97 enable ? "enable" : "disable",
98 dp_parser_pm_name(i));
99 if (enable) {
100 for (j = i-1; j >= DP_CORE_PM; j--) {
101 msm_dss_enable_vreg(
102 parser->mp[j].vreg_config,
103 parser->mp[j].num_vreg, 0);
104 }
105 }
106 goto error;
107 }
108 }
109error:
110 return rc;
111}
112
113static int dp_power_pinctrl_set(struct dp_power_private *power, bool active)
114{
115 int rc = -EFAULT;
116 struct pinctrl_state *pin_state;
117 struct dp_parser *parser;
118
119 parser = power->parser;
120
121 if (IS_ERR_OR_NULL(parser->pinctrl.pin))
122 return PTR_ERR(parser->pinctrl.pin);
123
124 pin_state = active ? parser->pinctrl.state_active
125 : parser->pinctrl.state_suspend;
126 if (!IS_ERR_OR_NULL(pin_state)) {
127 rc = pinctrl_select_state(parser->pinctrl.pin,
128 pin_state);
129 if (rc)
130 pr_err("can not set %s pins\n",
131 active ? "dp_active"
132 : "dp_sleep");
133 } else {
134 pr_err("invalid '%s' pinstate\n",
135 active ? "dp_active"
136 : "dp_sleep");
137 }
138
139 return rc;
140}
141
142static int dp_power_clk_init(struct dp_power_private *power, bool enable)
143{
144 int rc = 0;
145 struct dss_module_power *core, *ctrl;
146 struct device *dev;
147
148 core = &power->parser->mp[DP_CORE_PM];
149 ctrl = &power->parser->mp[DP_CTRL_PM];
150
151 dev = &power->pdev->dev;
152
153 if (!core || !ctrl) {
154 pr_err("invalid power_data\n");
155 rc = -EINVAL;
156 goto exit;
157 }
158
159 if (enable) {
160 rc = msm_dss_get_clk(dev, core->clk_config, core->num_clk);
161 if (rc) {
162 pr_err("failed to get %s clk. err=%d\n",
163 dp_parser_pm_name(DP_CORE_PM), rc);
164 goto exit;
165 }
166
167 rc = msm_dss_get_clk(dev, ctrl->clk_config, ctrl->num_clk);
168 if (rc) {
169 pr_err("failed to get %s clk. err=%d\n",
170 dp_parser_pm_name(DP_CTRL_PM), rc);
171 goto ctrl_get_error;
172 }
173
174 power->pixel_clk_rcg = devm_clk_get(dev, "pixel_clk_rcg");
175 if (IS_ERR(power->pixel_clk_rcg)) {
176 pr_debug("Unable to get DP pixel clk RCG\n");
177 power->pixel_clk_rcg = NULL;
178 }
179
180 power->pixel_parent = devm_clk_get(dev, "pixel_parent");
181 if (IS_ERR(power->pixel_parent)) {
182 pr_debug("Unable to get DP pixel RCG parent\n");
183 power->pixel_parent = NULL;
184 }
185 } else {
186 if (power->pixel_parent)
187 devm_clk_put(dev, power->pixel_parent);
188
189 if (power->pixel_clk_rcg)
190 devm_clk_put(dev, power->pixel_clk_rcg);
191
192 msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk);
193 msm_dss_put_clk(core->clk_config, core->num_clk);
194 }
195
196 return rc;
197
198ctrl_get_error:
199 msm_dss_put_clk(core->clk_config, core->num_clk);
200exit:
201 return rc;
202}
203
204static int dp_power_clk_set_rate(struct dp_power_private *power,
205 enum dp_pm_type module, bool enable)
206{
207 int rc = 0;
208 struct dss_module_power *mp;
209
210 if (!power) {
211 pr_err("invalid power data\n");
212 rc = -EINVAL;
213 goto exit;
214 }
215
216 mp = &power->parser->mp[module];
217
218 if (enable) {
219 rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
220 if (rc) {
221 pr_err("failed to set clks rate.\n");
222 goto exit;
223 }
224
225 rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 1);
226 if (rc) {
227 pr_err("failed to enable clks\n");
228 goto exit;
229 }
230 } else {
231 rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 0);
232 if (rc) {
233 pr_err("failed to disable clks\n");
234 goto exit;
235 }
236 }
237exit:
238 return rc;
239}
240
241static int dp_power_clk_enable(struct dp_power *dp_power,
242 enum dp_pm_type pm_type, bool enable)
243{
244 int rc = 0;
245 struct dss_module_power *mp;
246 struct dp_power_private *power;
247
248 if (!dp_power) {
249 pr_err("invalid power data\n");
250 rc = -EINVAL;
251 goto error;
252 }
253
254 power = container_of(dp_power, struct dp_power_private, dp_power);
255
256 mp = &power->parser->mp[pm_type];
257
258 if ((pm_type != DP_CORE_PM) && (pm_type != DP_CTRL_PM)) {
259 pr_err("unsupported power module: %s\n",
260 dp_parser_pm_name(pm_type));
261 return -EINVAL;
262 }
263
264 if (enable) {
265 if ((pm_type == DP_CORE_PM)
266 && (power->core_clks_on)) {
267 pr_debug("core clks already enabled\n");
268 return 0;
269 }
270
271 if ((pm_type == DP_CTRL_PM)
272 && (power->link_clks_on)) {
273 pr_debug("links clks already enabled\n");
274 return 0;
275 }
276
277 if ((pm_type == DP_CTRL_PM) && (!power->core_clks_on)) {
278 pr_debug("Need to enable core clks before link clks\n");
279
280 rc = dp_power_clk_set_rate(power, pm_type, enable);
281 if (rc) {
282 pr_err("failed to enable clks: %s. err=%d\n",
283 dp_parser_pm_name(DP_CORE_PM), rc);
284 goto error;
285 } else {
286 power->core_clks_on = true;
287 }
288 }
289 }
290
291 rc = dp_power_clk_set_rate(power, pm_type, enable);
292 if (rc) {
293 pr_err("failed to '%s' clks for: %s. err=%d\n",
294 enable ? "enable" : "disable",
295 dp_parser_pm_name(pm_type), rc);
296 goto error;
297 }
298
299 if (pm_type == DP_CORE_PM)
300 power->core_clks_on = enable;
301 else
302 power->link_clks_on = enable;
303
304 pr_debug("%s clocks for %s\n",
305 enable ? "enable" : "disable",
306 dp_parser_pm_name(pm_type));
307 pr_debug("link_clks:%s core_clks:%s\n",
308 power->link_clks_on ? "on" : "off",
309 power->core_clks_on ? "on" : "off");
310error:
311 return rc;
312}
313
314static int dp_power_request_gpios(struct dp_power_private *power)
315{
316 int rc = 0, i;
317 struct device *dev;
318 struct dss_module_power *mp;
319 static const char * const gpio_names[] = {
320 "aux_enable", "aux_sel", "usbplug_cc",
321 };
322
323 if (!power) {
324 pr_err("invalid power data\n");
325 return -EINVAL;
326 }
327
328 dev = &power->pdev->dev;
329 mp = &power->parser->mp[DP_CORE_PM];
330
331 for (i = 0; i < ARRAY_SIZE(gpio_names); i++) {
332 unsigned int gpio = mp->gpio_config[i].gpio;
333
334 if (gpio_is_valid(gpio)) {
335 rc = devm_gpio_request(dev, gpio, gpio_names[i]);
336 if (rc) {
337 pr_err("request %s gpio failed, rc=%d\n",
338 gpio_names[i], rc);
339 goto error;
340 }
341 }
342 }
343 return 0;
344error:
345 for (i = 0; i < ARRAY_SIZE(gpio_names); i++) {
346 unsigned int gpio = mp->gpio_config[i].gpio;
347
348 if (gpio_is_valid(gpio))
349 gpio_free(gpio);
350 }
351 return rc;
352}
353
354static bool dp_power_find_gpio(const char *gpio1, const char *gpio2)
355{
356 return !!strnstr(gpio1, gpio2, strlen(gpio1));
357}
358
359static void dp_power_set_gpio(struct dp_power_private *power, bool flip)
360{
361 int i;
362 struct dss_module_power *mp = &power->parser->mp[DP_CORE_PM];
363 struct dss_gpio *config = mp->gpio_config;
364
365 for (i = 0; i < mp->num_gpio; i++) {
366 if (dp_power_find_gpio(config->gpio_name, "aux-sel"))
367 config->value = flip;
368
369 if (gpio_is_valid(config->gpio)) {
370 pr_debug("gpio %s, value %d\n", config->gpio_name,
371 config->value);
372
373 if (dp_power_find_gpio(config->gpio_name, "aux-en") ||
374 dp_power_find_gpio(config->gpio_name, "aux-sel"))
375 gpio_direction_output(config->gpio,
376 config->value);
377 else
378 gpio_set_value(config->gpio, config->value);
379
380 }
381 config++;
382 }
383}
384
385static int dp_power_config_gpios(struct dp_power_private *power, bool flip,
386 bool enable)
387{
388 int rc = 0, i;
389 struct dss_module_power *mp;
390 struct dss_gpio *config;
391
392 mp = &power->parser->mp[DP_CORE_PM];
393 config = mp->gpio_config;
394
395 if (enable) {
396 rc = dp_power_request_gpios(power);
397 if (rc) {
398 pr_err("gpio request failed\n");
399 return rc;
400 }
401
402 dp_power_set_gpio(power, flip);
403 } else {
404 for (i = 0; i < mp->num_gpio; i++) {
405 gpio_set_value(config[i].gpio, 0);
406 gpio_free(config[i].gpio);
407 }
408 }
409
410 return 0;
411}
412
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700413static int dp_power_client_init(struct dp_power *dp_power,
414 struct sde_power_handle *phandle)
415{
416 int rc = 0;
417 struct dp_power_private *power;
418 char dp_client_name[DP_CLIENT_NAME_SIZE];
419
420 if (!dp_power) {
421 pr_err("invalid power data\n");
422 return -EINVAL;
423 }
424
425 power = container_of(dp_power, struct dp_power_private, dp_power);
426
427 rc = dp_power_regulator_init(power);
428 if (rc) {
429 pr_err("failed to init regulators\n");
430 goto error_power;
431 }
432
433 rc = dp_power_clk_init(power, true);
434 if (rc) {
435 pr_err("failed to init clocks\n");
436 goto error_clk;
437 }
438
439 power->phandle = phandle;
440 snprintf(dp_client_name, DP_CLIENT_NAME_SIZE, "dp_core_client");
441 power->dp_core_client = sde_power_client_create(phandle,
442 dp_client_name);
443 if (IS_ERR_OR_NULL(power->dp_core_client)) {
444 pr_err("[%s] client creation failed for DP", dp_client_name);
445 rc = -EINVAL;
446 goto error_client;
447 }
448 return 0;
449
450error_client:
451 dp_power_clk_init(power, false);
452error_clk:
453 dp_power_regulator_deinit(power);
454error_power:
455 return rc;
456}
457
458static void dp_power_client_deinit(struct dp_power *dp_power)
459{
460 struct dp_power_private *power;
461
462 if (!dp_power) {
463 pr_err("invalid power data\n");
464 return;
465 }
466
467 power = container_of(dp_power, struct dp_power_private, dp_power);
468
469 sde_power_client_destroy(power->phandle, power->dp_core_client);
470 dp_power_clk_init(power, false);
471 dp_power_regulator_deinit(power);
472}
473
Ajay Singh Parmar3e5d49e2017-03-20 23:37:57 -0700474static int dp_power_set_pixel_clk_parent(struct dp_power *dp_power)
475{
476 int rc = 0;
477 struct dp_power_private *power;
478
479 if (!dp_power) {
480 pr_err("invalid power data\n");
481 rc = -EINVAL;
482 goto exit;
483 }
484
485 power = container_of(dp_power, struct dp_power_private, dp_power);
486
487 if (power->pixel_clk_rcg && power->pixel_parent)
488 clk_set_parent(power->pixel_clk_rcg, power->pixel_parent);
489exit:
490 return rc;
491}
492
493static int dp_power_init(struct dp_power *dp_power, bool flip)
494{
495 int rc = 0;
496 struct dp_power_private *power;
497
498 if (!dp_power) {
499 pr_err("invalid power data\n");
500 rc = -EINVAL;
501 goto exit;
502 }
503
504 power = container_of(dp_power, struct dp_power_private, dp_power);
505
506 rc = dp_power_regulator_ctrl(power, true);
507 if (rc) {
508 pr_err("failed to enable regulators\n");
509 goto exit;
510 }
511
512 rc = dp_power_pinctrl_set(power, true);
513 if (rc) {
514 pr_err("failed to set pinctrl state\n");
515 goto err_pinctrl;
516 }
517
518 rc = dp_power_config_gpios(power, flip, true);
519 if (rc) {
520 pr_err("failed to enable gpios\n");
521 goto err_gpio;
522 }
523
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700524 rc = sde_power_resource_enable(power->phandle,
525 power->dp_core_client, true);
526 if (rc) {
527 pr_err("Power resource enable failed\n");
528 goto err_sde_power;
529 }
530
Ajay Singh Parmar3e5d49e2017-03-20 23:37:57 -0700531 rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true);
532 if (rc) {
533 pr_err("failed to enable DP core clocks\n");
534 goto err_clk;
535 }
536
537 return 0;
538
539err_clk:
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700540 sde_power_resource_enable(power->phandle, power->dp_core_client, false);
541err_sde_power:
Ajay Singh Parmar3e5d49e2017-03-20 23:37:57 -0700542 dp_power_config_gpios(power, flip, false);
543err_gpio:
544 dp_power_pinctrl_set(power, false);
545err_pinctrl:
546 dp_power_regulator_ctrl(power, false);
547exit:
548 return rc;
549}
550
551static int dp_power_deinit(struct dp_power *dp_power)
552{
553 int rc = 0;
554 struct dp_power_private *power;
555
556 if (!dp_power) {
557 pr_err("invalid power data\n");
558 rc = -EINVAL;
559 goto exit;
560 }
561
562 power = container_of(dp_power, struct dp_power_private, dp_power);
563
564 dp_power_clk_enable(dp_power, DP_CORE_PM, false);
Tatenda Chipeperekwadb328a82017-09-29 15:15:56 -0700565 /*
566 * If the display power on event was not successful, for example if
567 * there was a link training failure, then the link clocks could
568 * possibly still be on. In this scenario, we need to turn off the
569 * link clocks as soon as the cable is disconnected so that the clock
570 * state is cleaned up before subsequent connection events.
571 */
572 if (power->link_clks_on)
573 dp_power_clk_enable(dp_power, DP_CTRL_PM, false);
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700574 rc = sde_power_resource_enable(power->phandle,
575 power->dp_core_client, false);
576 if (rc) {
577 pr_err("Power resource enable failed, rc=%d\n", rc);
578 goto exit;
579 }
Ajay Singh Parmar3e5d49e2017-03-20 23:37:57 -0700580 dp_power_config_gpios(power, false, false);
581 dp_power_pinctrl_set(power, false);
582 dp_power_regulator_ctrl(power, false);
583exit:
584 return rc;
585}
586
587struct dp_power *dp_power_get(struct dp_parser *parser)
588{
589 int rc = 0;
590 struct dp_power_private *power;
591 struct dp_power *dp_power;
592
593 if (!parser) {
594 pr_err("invalid input\n");
595 rc = -EINVAL;
596 goto error;
597 }
598
599 power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL);
600 if (!power) {
601 rc = -ENOMEM;
602 goto error;
603 }
604
605 power->parser = parser;
606 power->pdev = parser->pdev;
607
608 dp_power = &power->dp_power;
609
610 dp_power->init = dp_power_init;
611 dp_power->deinit = dp_power_deinit;
612 dp_power->clk_enable = dp_power_clk_enable;
613 dp_power->set_pixel_clk_parent = dp_power_set_pixel_clk_parent;
Padmanabhan Komanduru4152f392017-05-11 17:53:55 -0700614 dp_power->power_client_init = dp_power_client_init;
615 dp_power->power_client_deinit = dp_power_client_deinit;
Ajay Singh Parmar3e5d49e2017-03-20 23:37:57 -0700616
617 return dp_power;
618error:
619 return ERR_PTR(rc);
620}
621
622void dp_power_put(struct dp_power *dp_power)
623{
Tatenda Chipeperekwa47ddbcd2017-08-30 13:43:21 -0700624 struct dp_power_private *power = NULL;
625
626 if (!dp_power)
627 return;
628
629 power = container_of(dp_power, struct dp_power_private, dp_power);
Ajay Singh Parmar3e5d49e2017-03-20 23:37:57 -0700630
Ajay Singh Parmar3e5d49e2017-03-20 23:37:57 -0700631 devm_kfree(&power->pdev->dev, power);
632}