blob: 372c93e64feaca8bf3be593573b71071745636b6 [file] [log] [blame]
Sachin Bhayareeeb88892018-01-02 16:36:01 +05301/* Copyright (c) 2015-2016, 2018, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#define pr_fmt(fmt) "mdss-dsi-clk:[%s] " fmt, __func__
15#include <linux/clk/msm-clk.h>
16#include <linux/clk.h>
17#include <linux/list.h>
18
19#include "mdss_dsi_clk.h"
20#include "mdss_dsi.h"
21#include "mdss_debug.h"
22
23#define MAX_CLIENT_NAME_LEN 20
24struct dsi_core_clks {
25 struct mdss_dsi_core_clk_info clks;
26 u32 current_clk_state;
27};
28
29struct dsi_link_clks {
30 struct mdss_dsi_link_clk_info clks;
31 u32 current_clk_state;
32 u32 byte_clk_rate;
33 u32 pix_clk_rate;
34 u32 esc_clk_rate;
35};
36
37struct mdss_dsi_clk_mngr {
38 char name[DSI_CLK_NAME_LEN];
39 struct dsi_core_clks core_clks;
40 struct dsi_link_clks link_clks;
41
42 struct reg_bus_client *reg_bus_clt;
43
44 pre_clockoff_cb pre_clkoff_cb;
45 post_clockoff_cb post_clkoff_cb;
46 post_clockon_cb post_clkon_cb;
47 pre_clockon_cb pre_clkon_cb;
48
49 struct list_head client_list;
50 struct mutex clk_mutex;
51
52 void *priv_data;
53};
54
55struct mdss_dsi_clk_client_info {
56 char name[MAX_CLIENT_NAME_LEN];
57 u32 core_refcount;
58 u32 link_refcount;
59 u32 core_clk_state;
60 u32 link_clk_state;
61
62 struct list_head list;
63
64 struct mdss_dsi_clk_mngr *mngr;
65};
66
67static int dsi_core_clk_start(struct dsi_core_clks *c_clks)
68{
69 int rc = 0;
70 struct mdss_dsi_clk_mngr *mngr;
71
72 mngr = container_of(c_clks, struct mdss_dsi_clk_mngr, core_clks);
73
74 rc = clk_prepare_enable(c_clks->clks.mdp_core_clk);
75 if (rc) {
76 pr_err("%s: failed to enable mdp_core_clock. rc=%d\n",
77 __func__, rc);
78 goto error;
79 }
80
81 rc = clk_prepare_enable(c_clks->clks.ahb_clk);
82 if (rc) {
83 pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
84 goto disable_core_clk;
85 }
86
87 rc = clk_prepare_enable(c_clks->clks.axi_clk);
88 if (rc) {
89 pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc);
90 goto disable_ahb_clk;
91 }
92
93 if (c_clks->clks.mmss_misc_ahb_clk) {
94 rc = clk_prepare_enable(c_clks->clks.mmss_misc_ahb_clk);
95 if (rc) {
96 pr_err("%s: failed to enable mmss misc ahb clk.rc=%d\n",
97 __func__, rc);
98 goto disable_axi_clk;
99 }
100 }
101
102 rc = mdss_update_reg_bus_vote(mngr->reg_bus_clt, VOTE_INDEX_LOW);
103 if (rc) {
104 pr_err("failed to vote for reg bus\n");
105 goto disable_mmss_misc_clk;
106 }
107
108 pr_debug("%s:CORE CLOCK IS ON\n", mngr->name);
109 return rc;
110
111disable_mmss_misc_clk:
112 if (c_clks->clks.mmss_misc_ahb_clk)
113 clk_disable_unprepare(c_clks->clks.mmss_misc_ahb_clk);
114disable_axi_clk:
115 clk_disable_unprepare(c_clks->clks.axi_clk);
116disable_ahb_clk:
117 clk_disable_unprepare(c_clks->clks.ahb_clk);
118disable_core_clk:
119 clk_disable_unprepare(c_clks->clks.mdp_core_clk);
120error:
121 pr_debug("%s: EXIT, rc = %d\n", mngr->name, rc);
122 return rc;
123}
124
125static int dsi_core_clk_stop(struct dsi_core_clks *c_clks)
126{
127 int rc = 0;
128 struct mdss_dsi_clk_mngr *mngr;
129
130 mngr = container_of(c_clks, struct mdss_dsi_clk_mngr, core_clks);
131
132 mdss_update_reg_bus_vote(mngr->reg_bus_clt, VOTE_INDEX_DISABLE);
133 if (c_clks->clks.mmss_misc_ahb_clk)
134 clk_disable_unprepare(c_clks->clks.mmss_misc_ahb_clk);
135 clk_disable_unprepare(c_clks->clks.axi_clk);
136 clk_disable_unprepare(c_clks->clks.ahb_clk);
137 clk_disable_unprepare(c_clks->clks.mdp_core_clk);
138
139 pr_debug("%s: CORE CLOCK IS OFF\n", mngr->name);
140 return rc;
141}
142
143static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks)
144{
145 int rc = 0;
146 struct mdss_dsi_clk_mngr *mngr;
147 struct mdss_dsi_ctrl_pdata *ctrl;
148
149 mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks);
150
151 /*
152 * In an ideal world, cont_splash_enabled should not be required inside
153 * the clock manager. But, in the current driver cont_splash_enabled
154 * flag is set inside mdp driver and there is no interface event
155 * associated with this flag setting. Also, set rate for clock need not
156 * be called for every enable call. It should be done only once when
157 * coming out of suspend.
158 */
159 ctrl = mngr->priv_data;
160 if (ctrl->panel_data.panel_info.cont_splash_enabled)
161 return 0;
162
163 rc = clk_set_rate(l_clks->clks.esc_clk, l_clks->esc_clk_rate);
164 if (rc) {
165 pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc);
166 goto error;
167 }
168
169 rc = clk_set_rate(l_clks->clks.byte_clk, l_clks->byte_clk_rate);
170 if (rc) {
171 pr_err("clk_set_rate failed for byte_clk rc = %d\n", rc);
172 goto error;
173 }
174
175 rc = clk_set_rate(l_clks->clks.pixel_clk, l_clks->pix_clk_rate);
176 if (rc) {
177 pr_err("clk_set_rate failed for pixel_clk rc = %d\n", rc);
178 goto error;
179 }
180
181error:
182 return rc;
183}
184
185static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks)
186{
187 int rc = 0;
188
189 rc = clk_prepare(l_clks->clks.esc_clk);
190 if (rc) {
191 pr_err("%s: Failed to prepare dsi esc clk\n", __func__);
192 goto esc_clk_err;
193 }
194
195 rc = clk_prepare(l_clks->clks.byte_clk);
196 if (rc) {
197 pr_err("%s: Failed to prepare dsi byte clk\n", __func__);
198 goto byte_clk_err;
199 }
200
201 rc = clk_prepare(l_clks->clks.pixel_clk);
202 if (rc) {
203 pr_err("%s: Failed to prepare dsi pixel clk\n", __func__);
204 goto pixel_clk_err;
205 }
206
207 return rc;
208
209pixel_clk_err:
210 clk_unprepare(l_clks->clks.byte_clk);
211byte_clk_err:
212 clk_unprepare(l_clks->clks.esc_clk);
213esc_clk_err:
214 return rc;
215}
216
217static int dsi_link_clk_unprepare(struct dsi_link_clks *l_clks)
218{
219 int rc = 0;
220
221 clk_unprepare(l_clks->clks.pixel_clk);
222 clk_unprepare(l_clks->clks.byte_clk);
223 clk_unprepare(l_clks->clks.esc_clk);
224
225 return rc;
226}
227
228static int dsi_link_clk_enable(struct dsi_link_clks *l_clks)
229{
230 int rc = 0;
231
232 rc = clk_enable(l_clks->clks.esc_clk);
233 if (rc) {
234 pr_err("%s: Failed to enable dsi esc clk\n", __func__);
235 goto esc_clk_err;
236 }
237
238 rc = clk_enable(l_clks->clks.byte_clk);
239 if (rc) {
240 pr_err("%s: Failed to enable dsi byte clk\n", __func__);
241 goto byte_clk_err;
242 }
243
244 rc = clk_enable(l_clks->clks.pixel_clk);
245 if (rc) {
246 pr_err("%s: Failed to enable dsi pixel clk\n", __func__);
247 goto pixel_clk_err;
248 }
249
250 return rc;
251
252pixel_clk_err:
253 clk_disable(l_clks->clks.byte_clk);
254byte_clk_err:
255 clk_disable(l_clks->clks.esc_clk);
256esc_clk_err:
257 return rc;
258}
259
260static int dsi_link_clk_disable(struct dsi_link_clks *l_clks)
261{
262 int rc = 0;
263
264 clk_disable(l_clks->clks.esc_clk);
265 clk_disable(l_clks->clks.pixel_clk);
266 clk_disable(l_clks->clks.byte_clk);
267
268 return rc;
269}
270
271
272static int dsi_link_clk_start(struct dsi_link_clks *l_clks)
273{
274 int rc = 0;
275 struct mdss_dsi_clk_mngr *mngr;
276
277 mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks);
278
279 rc = dsi_link_clk_set_rate(l_clks);
280 if (rc) {
281 pr_err("failed to set clk rates, rc = %d\n", rc);
282 goto error;
283 }
284
285 rc = dsi_link_clk_prepare(l_clks);
286 if (rc) {
287 pr_err("failed to prepare link clks, rc = %d\n", rc);
288 goto error;
289 }
290
291 rc = dsi_link_clk_enable(l_clks);
292 if (rc) {
293 pr_err("failed to enable link clks, rc = %d\n", rc);
294 goto error_unprepare;
295 }
296
297 pr_debug("%s: LINK CLOCK IS ON\n", mngr->name);
298 return rc;
299error_unprepare:
300 dsi_link_clk_unprepare(l_clks);
301error:
302 return rc;
303}
304
305static int dsi_link_clk_stop(struct dsi_link_clks *l_clks)
306{
307 int rc = 0;
308 struct mdss_dsi_clk_mngr *mngr;
309
310 mngr = container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks);
311
312 (void)dsi_link_clk_disable(l_clks);
313
314 (void)dsi_link_clk_unprepare(l_clks);
315 pr_debug("%s: LINK CLOCK IS OFF\n", mngr->name);
316
317 return rc;
318}
319
320static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,
321 struct dsi_link_clks *l_clks, u32 l_state)
322{
323 int rc = 0;
324 struct mdss_dsi_clk_mngr *mngr;
325 bool l_c_on = false;
326
327 if (c_clks) {
328 mngr =
329 container_of(c_clks, struct mdss_dsi_clk_mngr, core_clks);
330 } else if (l_clks) {
331 mngr =
332 container_of(l_clks, struct mdss_dsi_clk_mngr, link_clks);
333 } else {
334 mngr = NULL;
335 }
336
337 if (!mngr)
338 return -EINVAL;
339
340 pr_debug("%s: c_state = %d, l_state = %d\n", mngr ? mngr->name : "NA",
341 c_clks ? c_state : -1, l_clks ? l_state : -1);
342 /*
343 * Clock toggle order:
344 * 1. When turning on, Core clocks before link clocks
345 * 2. When turning off, Link clocks before core clocks.
346 */
347 if (c_clks && (c_state == MDSS_DSI_CLK_ON)) {
348 if (c_clks->current_clk_state == MDSS_DSI_CLK_OFF) {
349 rc = mngr->pre_clkon_cb(mngr->priv_data,
350 MDSS_DSI_CORE_CLK,
351 MDSS_DSI_CLK_ON);
352 if (rc) {
353 pr_err("failed to turn on MDP FS rc= %d\n", rc);
354 goto error;
355 }
356 }
357 rc = dsi_core_clk_start(c_clks);
358 if (rc) {
359 pr_err("failed to turn on core clks rc = %d\n", rc);
360 goto error;
361 }
362
363 if (mngr->post_clkon_cb) {
364 rc = mngr->post_clkon_cb(mngr->priv_data,
365 MDSS_DSI_CORE_CLK,
366 MDSS_DSI_CLK_ON);
367 if (rc)
368 pr_err("post clk on cb failed, rc = %d\n", rc);
369 }
370 c_clks->current_clk_state = MDSS_DSI_CLK_ON;
371 }
372
373 if (l_clks) {
374
375 if (l_state == MDSS_DSI_CLK_ON) {
376 if (mngr->pre_clkon_cb) {
377 rc = mngr->pre_clkon_cb(mngr->priv_data,
378 MDSS_DSI_LINK_CLK, l_state);
379 if (rc)
380 pr_err("pre link clk on cb failed\n");
381 }
382 rc = dsi_link_clk_start(l_clks);
383 if (rc) {
384 pr_err("failed to start link clk rc= %d\n", rc);
385 goto error;
386 }
387 if (mngr->post_clkon_cb) {
388 rc = mngr->post_clkon_cb(mngr->priv_data,
389 MDSS_DSI_LINK_CLK,
390 l_state);
391 if (rc)
392 pr_err("post link clk on cb failed\n");
393 }
394 } else {
395 /*
396 * Two conditions that need to be checked for Link
397 * clocks:
398 * 1. Link clocks need core clocks to be on when
399 * transitioning from EARLY_GATE to OFF state.
400 * 2. ULPS mode might have to be enabled in case of OFF
401 * state. For ULPS, Link clocks should be turned ON
402 * first before they are turned off again.
403 *
404 * If Link is going from EARLY_GATE to OFF state AND
405 * Core clock is already in EARLY_GATE or OFF state,
406 * turn on Core clocks and link clocks.
407 *
408 * ULPS state is managed as part of the pre_clkoff_cb.
409 */
410 if ((l_state == MDSS_DSI_CLK_OFF) &&
411 (l_clks->current_clk_state ==
412 MDSS_DSI_CLK_EARLY_GATE) &&
413 (mngr->core_clks.current_clk_state !=
414 MDSS_DSI_CLK_ON)) {
415 rc = dsi_core_clk_start(&mngr->core_clks);
416 if (rc) {
417 pr_err("core clks did not start\n");
418 goto error;
419 }
420
421 rc = dsi_link_clk_start(l_clks);
422 if (rc) {
423 pr_err("Link clks did not start\n");
424 goto error;
425 }
426 l_c_on = true;
427 pr_debug("ECG: core and Link_on\n");
428 }
429
430 if (mngr->pre_clkoff_cb) {
431 rc = mngr->pre_clkoff_cb(mngr->priv_data,
432 MDSS_DSI_LINK_CLK, l_state);
433 if (rc)
434 pr_err("pre link clk off cb failed\n");
435 }
436
437 rc = dsi_link_clk_stop(l_clks);
438 if (rc) {
439 pr_err("failed to stop link clk, rc = %d\n",
440 rc);
441 goto error;
442 }
443
444 if (mngr->post_clkoff_cb) {
445 rc = mngr->post_clkoff_cb(mngr->priv_data,
446 MDSS_DSI_LINK_CLK, l_state);
447 if (rc)
448 pr_err("post link clk off cb failed\n");
449 }
450 /*
451 * This check is to save unnecessary clock state
452 * change when going from EARLY_GATE to OFF. In the
453 * case where the request happens for both Core and Link
454 * clocks in the same call, core clocks need to be
455 * turned on first before OFF state can be entered.
456 *
457 * Core clocks are turned on here for Link clocks to go
458 * to OFF state. If core clock request is also present,
459 * then core clocks can be turned off Core clocks are
460 * transitioned to OFF state.
461 */
462 if (l_c_on && (!(c_clks && (c_state == MDSS_DSI_CLK_OFF)
463 && (c_clks->current_clk_state ==
464 MDSS_DSI_CLK_EARLY_GATE)))) {
465 rc = dsi_core_clk_stop(&mngr->core_clks);
466 if (rc) {
467 pr_err("core clks did not stop\n");
468 goto error;
469 }
470
471 l_c_on = false;
472 pr_debug("ECG: core off\n");
473 } else
474 pr_debug("ECG: core off skip\n");
475 }
476
477 l_clks->current_clk_state = l_state;
478 }
479
480 if (c_clks && (c_state != MDSS_DSI_CLK_ON)) {
481
482 /*
483 * When going to OFF state from EARLY GATE state, Core clocks
484 * should be turned on first so that the IOs can be clamped.
485 * l_c_on flag is set, then the core clocks were turned before
486 * to the Link clocks go to OFF state. So Core clocks are
487 * already ON and this step can be skipped.
488 *
489 * IOs are clamped in pre_clkoff_cb callback.
490 */
491 if ((c_state == MDSS_DSI_CLK_OFF) &&
492 (c_clks->current_clk_state ==
493 MDSS_DSI_CLK_EARLY_GATE) && !l_c_on) {
494 rc = dsi_core_clk_start(&mngr->core_clks);
495 if (rc) {
496 pr_err("core clks did not start\n");
497 goto error;
498 }
499 pr_debug("ECG: core on\n");
500 } else
501 pr_debug("ECG: core on skip\n");
502
503 if (mngr->pre_clkoff_cb) {
504 rc = mngr->pre_clkoff_cb(mngr->priv_data,
505 MDSS_DSI_CORE_CLK,
506 c_state);
507 if (rc)
508 pr_err("pre core clk off cb failed\n");
509 }
510
511 rc = dsi_core_clk_stop(c_clks);
512 if (rc) {
513 pr_err("failed to turn off core clks rc = %d\n", rc);
514 goto error;
515 }
516
517 if (c_state == MDSS_DSI_CLK_OFF) {
518 if (mngr->post_clkoff_cb) {
519 rc = mngr->post_clkoff_cb(mngr->priv_data,
520 MDSS_DSI_CORE_CLK,
521 MDSS_DSI_CLK_OFF);
522 if (rc)
523 pr_err("post clkoff cb fail, rc = %d\n",
524 rc);
525 }
526 }
527 c_clks->current_clk_state = c_state;
528 }
529
530error:
531 return rc;
532}
533
534static int dsi_recheck_clk_state(struct mdss_dsi_clk_mngr *mngr)
535{
536 int rc = 0;
537 struct list_head *pos = NULL;
538 struct mdss_dsi_clk_client_info *c;
539 u32 new_core_clk_state = MDSS_DSI_CLK_OFF;
540 u32 new_link_clk_state = MDSS_DSI_CLK_OFF;
541 u32 old_c_clk_state = MDSS_DSI_CLK_OFF;
542 u32 old_l_clk_state = MDSS_DSI_CLK_OFF;
543 struct dsi_core_clks *c_clks = NULL;
544 struct dsi_link_clks *l_clks = NULL;
545
546 /*
547 * Rules to maintain clock state:
548 * 1. If any client is in ON state, clocks should be ON.
549 * 2. If any client is in ECG state with rest of them turned OFF,
550 * go to Early gate state.
551 * 3. If all clients are off, then goto OFF state.
552 */
553 list_for_each(pos, &mngr->client_list) {
554 c = list_entry(pos, struct mdss_dsi_clk_client_info, list);
555 if (c->core_clk_state == MDSS_DSI_CLK_ON) {
556 new_core_clk_state = MDSS_DSI_CLK_ON;
557 break;
558 } else if (c->core_clk_state == MDSS_DSI_CLK_EARLY_GATE) {
559 new_core_clk_state = MDSS_DSI_CLK_EARLY_GATE;
560 }
561 }
562
563 list_for_each(pos, &mngr->client_list) {
564 c = list_entry(pos, struct mdss_dsi_clk_client_info, list);
565 if (c->link_clk_state == MDSS_DSI_CLK_ON) {
566 new_link_clk_state = MDSS_DSI_CLK_ON;
567 break;
568 } else if (c->link_clk_state == MDSS_DSI_CLK_EARLY_GATE) {
569 new_link_clk_state = MDSS_DSI_CLK_EARLY_GATE;
570 }
571 }
572
573 if (new_core_clk_state != mngr->core_clks.current_clk_state)
574 c_clks = &mngr->core_clks;
575
576 if (new_link_clk_state != mngr->link_clks.current_clk_state)
577 l_clks = &mngr->link_clks;
578
579 old_c_clk_state = mngr->core_clks.current_clk_state;
580 old_l_clk_state = mngr->link_clks.current_clk_state;
581
582 pr_debug("%s: c_clk_state (%d -> %d)\n", mngr->name,
583 old_c_clk_state, new_core_clk_state);
584 pr_debug("%s: l_clk_state (%d -> %d)\n", mngr->name,
585 old_l_clk_state, new_link_clk_state);
586
587 MDSS_XLOG(old_c_clk_state, new_core_clk_state, old_l_clk_state,
588 new_link_clk_state);
589 if (c_clks || l_clks) {
590 rc = dsi_update_clk_state(c_clks, new_core_clk_state,
591 l_clks, new_link_clk_state);
592 if (rc) {
593 pr_err("failed to update clock state, rc = %d\n", rc);
594 goto error;
595 }
596 }
597
598error:
599 return rc;
600}
601
602static int dsi_set_clk_rate(struct mdss_dsi_clk_mngr *mngr, int clk, u32 rate,
603 u32 flags)
604{
605 int rc = 0;
606
607 pr_debug("%s: clk = %d, rate = %d, flags = %d\n", mngr->name,
608 clk, rate, flags);
609
610 MDSS_XLOG(clk, rate, flags);
611 switch (clk) {
612 case MDSS_DSI_LINK_ESC_CLK:
613 mngr->link_clks.esc_clk_rate = rate;
614 if (!flags) {
615 rc = clk_set_rate(mngr->link_clks.clks.esc_clk, rate);
616 if (rc)
617 pr_err("set rate failed for esc clk rc=%d\n",
618 rc);
619 }
620 break;
621 case MDSS_DSI_LINK_BYTE_CLK:
622 mngr->link_clks.byte_clk_rate = rate;
623 if (!flags) {
624 rc = clk_set_rate(mngr->link_clks.clks.byte_clk, rate);
625 if (rc)
626 pr_err("set rate failed for byte clk rc=%d\n",
627 rc);
628 }
629 break;
630 case MDSS_DSI_LINK_PIX_CLK:
631 mngr->link_clks.pix_clk_rate = rate;
632 if (!flags) {
633 rc = clk_set_rate(mngr->link_clks.clks.pixel_clk, rate);
634 if (rc)
635 pr_err("failed to set rate for pix clk rc=%d\n",
636 rc);
637 }
638 break;
639 default:
640 pr_err("Unsupported clock (%d)\n", clk);
641 rc = -ENOTSUPP;
642 break;
643 }
644
645 return rc;
646}
647
648void *mdss_dsi_clk_register(void *clk_mngr, struct mdss_dsi_clk_client *client)
649{
650 void *handle = NULL;
651 struct mdss_dsi_clk_mngr *mngr = clk_mngr;
652 struct mdss_dsi_clk_client_info *c;
653
654 if (!mngr) {
655 pr_err("bad params\n");
656 return ERR_PTR(-EINVAL);
657 }
658
659 pr_debug("%s: ENTER\n", mngr->name);
660
661 mutex_lock(&mngr->clk_mutex);
662
663 c = kzalloc(sizeof(*c), GFP_KERNEL);
664 if (!c) {
665 handle = ERR_PTR(-ENOMEM);
666 goto error;
667 }
668
669 strlcpy(c->name, client->client_name, MAX_CLIENT_NAME_LEN);
670 c->mngr = mngr;
671
672 list_add(&c->list, &mngr->client_list);
673
674 pr_debug("%s: Added new client (%s)\n", mngr->name, c->name);
675 handle = c;
676error:
677 mutex_unlock(&mngr->clk_mutex);
678 pr_debug("%s: EXIT, rc = %ld\n", mngr->name, PTR_ERR(handle));
679 return handle;
680}
681
682int mdss_dsi_clk_deregister(void *client)
683{
684 int rc = 0;
685 struct mdss_dsi_clk_client_info *c = client;
686 struct mdss_dsi_clk_mngr *mngr;
687 struct list_head *pos = NULL;
688 struct list_head *tmp = NULL;
689 struct mdss_dsi_clk_client_info *node;
690
691 if (!client) {
692 pr_err("Invalid params\n");
693 return -EINVAL;
694 }
695
696 mngr = c->mngr;
697 pr_debug("%s: ENTER\n", mngr->name);
698 mutex_lock(&mngr->clk_mutex);
699 c->core_clk_state = MDSS_DSI_CLK_OFF;
700 c->link_clk_state = MDSS_DSI_CLK_OFF;
701
702 rc = dsi_recheck_clk_state(mngr);
703 if (rc) {
704 pr_err("clock state recheck failed rc = %d\n", rc);
705 goto error;
706 }
707
708 list_for_each_safe(pos, tmp, &mngr->client_list) {
709 node = list_entry(pos, struct mdss_dsi_clk_client_info,
710 list);
711 if (node == c) {
712 list_del(&node->list);
713 pr_debug("Removed device (%s)\n", node->name);
714 kfree(node);
715 break;
716 }
717 }
718
719error:
720 mutex_unlock(&mngr->clk_mutex);
721 pr_debug("%s: EXIT, rc = %d\n", mngr->name, rc);
722 return rc;
723}
724
725bool is_dsi_clk_in_ecg_state(void *client)
726{
727 struct mdss_dsi_clk_client_info *c = client;
728 struct mdss_dsi_clk_mngr *mngr;
729 bool is_ecg = false;
730
731
732 if (!client) {
733 pr_err("Invalid client params\n");
734 goto end;
735 }
736
737 mngr = c->mngr;
738
739 mutex_lock(&mngr->clk_mutex);
740 is_ecg = (c->core_clk_state == MDSS_DSI_CLK_EARLY_GATE);
741 mutex_unlock(&mngr->clk_mutex);
742
743end:
744 return is_ecg;
745}
746
747int mdss_dsi_clk_req_state(void *client, enum mdss_dsi_clk_type clk,
748 enum mdss_dsi_clk_state state, u32 index)
749{
750 int rc = 0;
751 struct mdss_dsi_clk_client_info *c = client;
752 struct mdss_dsi_clk_mngr *mngr;
753 bool changed = false;
754
755 if (!client || !clk || clk > (MDSS_DSI_CORE_CLK | MDSS_DSI_LINK_CLK) ||
756 state > MDSS_DSI_CLK_EARLY_GATE) {
757 pr_err("Invalid params, client = %pK, clk = 0x%x, state = %d\n",
758 client, clk, state);
759 return -EINVAL;
760 }
761
762 mngr = c->mngr;
763 mutex_lock(&mngr->clk_mutex);
764
765 pr_debug("[%s]%s: CLK=%d, new_state=%d, core=%d, linkl=%d\n",
766 c->name, mngr->name, clk, state, c->core_clk_state,
767 c->link_clk_state);
768
769 MDSS_XLOG(index, clk, state, c->core_clk_state, c->link_clk_state);
770 /*
771 * Refcount handling rules:
772 * 1. Increment refcount whenever ON is called
773 * 2. Do not decrement when going from EARLY_GATE to OFF.
774 * 3. Decrement refcount when either OFF or EARLY_GATE is called
775 */
776 if (state == MDSS_DSI_CLK_ON) {
777 if (clk & MDSS_DSI_CORE_CLK) {
778 c->core_refcount++;
779 if (c->core_clk_state != MDSS_DSI_CLK_ON) {
780 c->core_clk_state = MDSS_DSI_CLK_ON;
781 changed = true;
782 }
783 }
784 if (clk & MDSS_DSI_LINK_CLK) {
785 c->link_refcount++;
786 if (c->link_clk_state != MDSS_DSI_CLK_ON) {
787 c->link_clk_state = MDSS_DSI_CLK_ON;
788 changed = true;
789 }
790 }
791 } else if ((state == MDSS_DSI_CLK_EARLY_GATE) ||
792 (state == MDSS_DSI_CLK_OFF)) {
793 if (clk & MDSS_DSI_CORE_CLK) {
794 if (c->core_refcount == 0) {
795 if ((c->core_clk_state ==
796 MDSS_DSI_CLK_EARLY_GATE) &&
797 (state == MDSS_DSI_CLK_OFF)) {
798 changed = true;
799 c->core_clk_state = MDSS_DSI_CLK_OFF;
800 } else {
801 pr_warn("Core refcount is zero for %s",
802 c->name);
803 }
804 } else {
805 c->core_refcount--;
806 if (c->core_refcount == 0) {
807 c->core_clk_state = state;
808 changed = true;
809 }
810 }
811 }
812 if (clk & MDSS_DSI_LINK_CLK) {
813 if (c->link_refcount == 0) {
814 if ((c->link_clk_state ==
815 MDSS_DSI_CLK_EARLY_GATE) &&
816 (state == MDSS_DSI_CLK_OFF)) {
817 changed = true;
818 c->link_clk_state = MDSS_DSI_CLK_OFF;
819 } else {
820 pr_warn("Link refcount is zero for %s",
821 c->name);
822 }
823 } else {
824 c->link_refcount--;
825 if (c->link_refcount == 0) {
826 c->link_clk_state = state;
827 changed = true;
828 }
829 }
830 }
831 }
832 pr_debug("[%s]%s: change=%d, Core (ref=%d, state=%d), Link (ref=%d, state=%d)\n",
833 c->name, mngr->name, changed, c->core_refcount,
834 c->core_clk_state, c->link_refcount, c->link_clk_state);
835 MDSS_XLOG(index, clk, state, c->core_clk_state, c->link_clk_state);
836
837 if (changed) {
838 rc = dsi_recheck_clk_state(mngr);
839 if (rc)
840 pr_err("Failed to adjust clock state rc = %d\n", rc);
841 }
842
843 mutex_unlock(&mngr->clk_mutex);
844 return rc;
845}
846
847int mdss_dsi_clk_set_link_rate(void *client, enum mdss_dsi_link_clk_type clk,
848 u32 rate, u32 flags)
849{
850 int rc = 0;
851 struct mdss_dsi_clk_client_info *c = client;
852 struct mdss_dsi_clk_mngr *mngr;
853
854 if (!client || (clk > MDSS_DSI_LINK_CLK_MAX)) {
855 pr_err("Invalid params, client = %pK, clk = 0x%x", client, clk);
856 return -EINVAL;
857 }
858
859 mngr = c->mngr;
860 pr_debug("%s: ENTER\n", mngr->name);
861 mutex_lock(&mngr->clk_mutex);
862
863 rc = dsi_set_clk_rate(mngr, clk, rate, flags);
864 if (rc)
865 pr_err("Failed to set rate for clk %d, rate = %d, rc = %d\n",
866 clk, rate, rc);
867
868 mutex_unlock(&mngr->clk_mutex);
869 pr_debug("%s: EXIT, rc = %d\n", mngr->name, rc);
870 return rc;
871}
872
873void *mdss_dsi_clk_init(struct mdss_dsi_clk_info *info)
874{
875 struct mdss_dsi_clk_mngr *mngr;
876
877 if (!info) {
878 pr_err("Invalid params\n");
879 return ERR_PTR(-EINVAL);
880 }
881 pr_debug("ENTER %s\n", info->name);
882 mngr = kzalloc(sizeof(*mngr), GFP_KERNEL);
883 if (!mngr) {
884 mngr = ERR_PTR(-ENOMEM);
885 goto error;
886 }
887
888 mutex_init(&mngr->clk_mutex);
889 memcpy(&mngr->core_clks.clks, &info->core_clks, sizeof(struct
890 mdss_dsi_core_clk_info));
891 memcpy(&mngr->link_clks.clks, &info->link_clks, sizeof(struct
892 mdss_dsi_link_clk_info));
893
894 INIT_LIST_HEAD(&mngr->client_list);
895 mngr->pre_clkon_cb = info->pre_clkon_cb;
896 mngr->post_clkon_cb = info->post_clkon_cb;
897 mngr->pre_clkoff_cb = info->pre_clkoff_cb;
898 mngr->post_clkoff_cb = info->post_clkoff_cb;
899 mngr->priv_data = info->priv_data;
900 mngr->reg_bus_clt = mdss_reg_bus_vote_client_create(info->name);
901 if (IS_ERR(mngr->reg_bus_clt)) {
902 pr_err("Unable to get handle for reg bus vote\n");
903 kfree(mngr);
904 mngr = ERR_PTR(-EINVAL);
905 goto error;
906 }
907 memcpy(mngr->name, info->name, DSI_CLK_NAME_LEN);
908error:
909 pr_debug("EXIT %s, rc = %ld\n", mngr->name, PTR_ERR(mngr));
910 return mngr;
911}
912
913int mdss_dsi_clk_deinit(void *clk_mngr)
914{
915 int rc = 0;
916 struct mdss_dsi_clk_mngr *mngr = clk_mngr;
917 struct list_head *position = NULL;
918 struct list_head *tmp = NULL;
919 struct mdss_dsi_clk_client_info *node;
920
921 if (!mngr) {
922 pr_err("Invalid params\n");
923 return -EINVAL;
924 }
925
926 pr_debug("%s: ENTER\n", mngr->name);
927 mutex_lock(&mngr->clk_mutex);
928
929 list_for_each_safe(position, tmp, &mngr->client_list) {
930 node = list_entry(position, struct mdss_dsi_clk_client_info,
931 list);
932 list_del(&node->list);
933 pr_debug("Removed device (%s)\n", node->name);
934 kfree(node);
935 }
936
937 rc = dsi_recheck_clk_state(mngr);
938 if (rc)
939 pr_err("failed to disable all clocks\n");
940 mdss_reg_bus_vote_client_destroy(mngr->reg_bus_clt);
941 mutex_unlock(&mngr->clk_mutex);
942 pr_debug("%s: EXIT, rc = %d\n", mngr->name, rc);
943 kfree(mngr);
944 return rc;
945}
946
947int mdss_dsi_clk_force_toggle(void *client, u32 clk)
948{
949 int rc = 0;
950 struct mdss_dsi_clk_client_info *c = client;
951 struct mdss_dsi_clk_mngr *mngr;
952
953 if (!client || !clk || clk >= MDSS_DSI_CLKS_MAX) {
954 pr_err("Invalid params, client = %pK, clk = 0x%x\n",
955 client, clk);
956 return -EINVAL;
957 }
958
959 mngr = c->mngr;
960 mutex_lock(&mngr->clk_mutex);
961
962 if ((clk & MDSS_DSI_CORE_CLK) &&
963 (mngr->core_clks.current_clk_state == MDSS_DSI_CLK_ON)) {
964
965 rc = dsi_core_clk_stop(&mngr->core_clks);
966 if (rc) {
967 pr_err("failed to stop core clks\n");
968 goto error;
969 }
970
971 rc = dsi_core_clk_start(&mngr->core_clks);
972 if (rc)
973 pr_err("failed to start core clks\n");
974
975 } else if (clk & MDSS_DSI_CORE_CLK) {
976 pr_err("cannot reset, core clock is off\n");
977 rc = -ENOTSUPP;
978 goto error;
979 }
980
981 if ((clk & MDSS_DSI_LINK_CLK) &&
982 (mngr->link_clks.current_clk_state == MDSS_DSI_CLK_ON)) {
983
984 rc = dsi_link_clk_stop(&mngr->link_clks);
985 if (rc) {
986 pr_err("failed to stop link clks\n");
987 goto error;
988 }
989
990 rc = dsi_link_clk_start(&mngr->link_clks);
991 if (rc)
992 pr_err("failed to start link clks\n");
993
994 } else if (clk & MDSS_DSI_LINK_CLK) {
995 pr_err("cannot reset, link clock is off\n");
996 rc = -ENOTSUPP;
997 goto error;
998 }
999
1000error:
1001 mutex_unlock(&mngr->clk_mutex);
1002 return rc;
1003}