blob: 560964e670d0438af116d51def3bf79b68f10ea2 [file] [log] [blame]
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301/*
2 * Copyright (c) 2016-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#include <linux/of.h>
16#include <linux/delay.h>
17#include <linux/slab.h>
18#include <linux/msm-bus.h>
19#include "dsi_clk.h"
20
21struct dsi_core_clks {
22 struct dsi_core_clk_info clks;
23 u32 bus_handle;
24};
25
26struct dsi_link_clks {
27 struct dsi_link_clk_info clks;
28 struct link_clk_freq freq;
29};
30
31struct dsi_clk_mngr {
32 char name[MAX_STRING_LEN];
33 struct mutex clk_mutex;
34 struct list_head client_list;
35
36 u32 dsi_ctrl_count;
37 u32 master_ndx;
38 struct dsi_core_clks core_clks[MAX_DSI_CTRL];
39 struct dsi_link_clks link_clks[MAX_DSI_CTRL];
Alexander Beykundfbb37d2017-03-03 17:09:02 -050040 u32 ctrl_index[MAX_DSI_CTRL];
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +053041 u32 core_clk_state;
42 u32 link_clk_state;
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 void *priv_data;
50};
51
52struct dsi_clk_client_info {
53 char name[MAX_STRING_LEN];
54 u32 core_refcount;
55 u32 link_refcount;
56 u32 core_clk_state;
57 u32 link_clk_state;
58 struct list_head list;
59 struct dsi_clk_mngr *mngr;
60};
61
Alexander Beykundfbb37d2017-03-03 17:09:02 -050062static int _get_clk_mngr_index(struct dsi_clk_mngr *mngr,
63 u32 dsi_ctrl_index,
64 u32 *clk_mngr_index)
65{
66 int i;
67
68 for (i = 0; i < mngr->dsi_ctrl_count; i++) {
69 if (mngr->ctrl_index[i] == dsi_ctrl_index) {
70 *clk_mngr_index = i;
71 return 0;
72 }
73 }
74
75 return -EINVAL;
76}
77
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +053078/**
79 * dsi_clk_set_link_frequencies() - set frequencies for link clks
80 * @clks: Link clock information
81 * @pixel_clk: pixel clock frequency in KHz.
82 * @byte_clk: Byte clock frequency in KHz.
83 * @esc_clk: Escape clock frequency in KHz.
84 *
85 * return: error code in case of failure or 0 for success.
86 */
87int dsi_clk_set_link_frequencies(void *client, struct link_clk_freq freq,
88 u32 index)
89{
Alexander Beykundfbb37d2017-03-03 17:09:02 -050090 int rc = 0, clk_mngr_index = 0;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +053091 struct dsi_clk_client_info *c = client;
92 struct dsi_clk_mngr *mngr;
93
94 if (!client) {
95 pr_err("invalid params\n");
96 return -EINVAL;
97 }
98
99 mngr = c->mngr;
Alexander Beykundfbb37d2017-03-03 17:09:02 -0500100 rc = _get_clk_mngr_index(mngr, index, &clk_mngr_index);
101 if (rc) {
102 pr_err("failed to map control index %d\n", index);
103 return -EINVAL;
104 }
105
106 memcpy(&mngr->link_clks[clk_mngr_index].freq, &freq,
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530107 sizeof(struct link_clk_freq));
Alexander Beykundfbb37d2017-03-03 17:09:02 -0500108
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530109 return rc;
110}
111
112/**
113 * dsi_clk_set_pixel_clk_rate() - set frequency for pixel clock
114 * @clks: DSI link clock information.
115 * @pixel_clk: Pixel clock rate in KHz.
116 *
117 * return: error code in case of failure or 0 for success.
118 */
119int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index)
120{
121 int rc = 0;
122 struct dsi_clk_client_info *c = client;
123 struct dsi_clk_mngr *mngr;
124
125 mngr = c->mngr;
126 rc = clk_set_rate(mngr->link_clks[index].clks.pixel_clk, pixel_clk);
127 if (rc)
128 pr_err("failed to set clk rate for pixel clk, rc=%d\n", rc);
129 else
130 mngr->link_clks[index].freq.pix_clk_rate = pixel_clk;
131
132 return rc;
133}
134
135/**
136 * dsi_clk_set_byte_clk_rate() - set frequency for byte clock
137 * @client: DSI clock client pointer.
138 * @byte_clk: Pixel clock rate in Hz.
139 * @index: Index of the DSI controller.
140 * return: error code in case of failure or 0 for success.
141 */
142int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index)
143{
144 int rc = 0;
145 struct dsi_clk_client_info *c = client;
146 struct dsi_clk_mngr *mngr;
147
148 mngr = c->mngr;
149 rc = clk_set_rate(mngr->link_clks[index].clks.byte_clk, byte_clk);
150 if (rc)
151 pr_err("failed to set clk rate for byte clk, rc=%d\n", rc);
152 else
153 mngr->link_clks[index].freq.byte_clk_rate = byte_clk;
154
155 return rc;
156
157}
158
159/**
160 * dsi_clk_update_parent() - update parent clocks for specified clock
161 * @parent: link clock pair which are set as parent.
162 * @child: link clock pair whose parent has to be set.
163 */
164int dsi_clk_update_parent(struct dsi_clk_link_set *parent,
165 struct dsi_clk_link_set *child)
166{
167 int rc = 0;
168
169 rc = clk_set_parent(child->byte_clk, parent->byte_clk);
170 if (rc) {
171 pr_err("failed to set byte clk parent\n");
172 goto error;
173 }
174
175 rc = clk_set_parent(child->pixel_clk, parent->pixel_clk);
176 if (rc) {
177 pr_err("failed to set pixel clk parent\n");
178 goto error;
179 }
180error:
181 return rc;
182}
183
184int dsi_core_clk_start(struct dsi_core_clks *c_clks)
185{
186 int rc = 0;
187
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800188 if (c_clks->clks.mdp_core_clk) {
189 rc = clk_prepare_enable(c_clks->clks.mdp_core_clk);
190 if (rc) {
191 pr_err("failed to enable mdp_core_clk, rc=%d\n", rc);
192 goto error;
193 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530194 }
195
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530196 if (c_clks->clks.mnoc_clk) {
197 rc = clk_prepare_enable(c_clks->clks.mnoc_clk);
198 if (rc) {
199 pr_err("failed to enable mnoc_clk, rc=%d\n", rc);
200 goto error_disable_core_clk;
201 }
202 }
203
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800204 if (c_clks->clks.iface_clk) {
205 rc = clk_prepare_enable(c_clks->clks.iface_clk);
206 if (rc) {
207 pr_err("failed to enable iface_clk, rc=%d\n", rc);
208 goto error_disable_mnoc_clk;
209 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530210 }
211
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800212 if (c_clks->clks.bus_clk) {
213 rc = clk_prepare_enable(c_clks->clks.bus_clk);
214 if (rc) {
215 pr_err("failed to enable bus_clk, rc=%d\n", rc);
216 goto error_disable_iface_clk;
217 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530218 }
219
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800220 if (c_clks->clks.core_mmss_clk) {
221 rc = clk_prepare_enable(c_clks->clks.core_mmss_clk);
222 if (rc) {
223 pr_err("failed to enable core_mmss_clk, rc=%d\n", rc);
224 goto error_disable_bus_clk;
225 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530226 }
227
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800228 if (c_clks->bus_handle) {
229 rc = msm_bus_scale_client_update_request(c_clks->bus_handle, 1);
230 if (rc) {
231 pr_err("bus scale client enable failed, rc=%d\n", rc);
232 goto error_disable_mmss_clk;
233 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530234 }
235
236 return rc;
237
238error_disable_mmss_clk:
Veera Sundaram Sankaran9d119bd2017-04-25 21:50:03 -0700239 if (c_clks->clks.core_mmss_clk)
240 clk_disable_unprepare(c_clks->clks.core_mmss_clk);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530241error_disable_bus_clk:
Veera Sundaram Sankaran9d119bd2017-04-25 21:50:03 -0700242 if (c_clks->clks.bus_clk)
243 clk_disable_unprepare(c_clks->clks.bus_clk);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530244error_disable_iface_clk:
Veera Sundaram Sankaran9d119bd2017-04-25 21:50:03 -0700245 if (c_clks->clks.iface_clk)
246 clk_disable_unprepare(c_clks->clks.iface_clk);
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530247error_disable_mnoc_clk:
248 if (c_clks->clks.mnoc_clk)
249 clk_disable_unprepare(c_clks->clks.mnoc_clk);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530250error_disable_core_clk:
Veera Sundaram Sankaran9d119bd2017-04-25 21:50:03 -0700251 if (c_clks->clks.mdp_core_clk)
252 clk_disable_unprepare(c_clks->clks.mdp_core_clk);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530253error:
254 return rc;
255}
256
257int dsi_core_clk_stop(struct dsi_core_clks *c_clks)
258{
Veera Sundaram Sankaran9d119bd2017-04-25 21:50:03 -0700259 int rc = 0;
260
261 if (c_clks->bus_handle) {
262 rc = msm_bus_scale_client_update_request(c_clks->bus_handle, 0);
263 if (rc) {
264 pr_err("bus scale client disable failed, rc=%d\n", rc);
265 return rc;
266 }
267 }
268
269 if (c_clks->clks.core_mmss_clk)
270 clk_disable_unprepare(c_clks->clks.core_mmss_clk);
271
272 if (c_clks->clks.bus_clk)
273 clk_disable_unprepare(c_clks->clks.bus_clk);
274
275 if (c_clks->clks.iface_clk)
276 clk_disable_unprepare(c_clks->clks.iface_clk);
277
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530278 if (c_clks->clks.mnoc_clk)
279 clk_disable_unprepare(c_clks->clks.mnoc_clk);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530280
Veera Sundaram Sankaran9d119bd2017-04-25 21:50:03 -0700281 if (c_clks->clks.mdp_core_clk)
282 clk_disable_unprepare(c_clks->clks.mdp_core_clk);
283
284 return rc;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530285}
286
287static int dsi_link_clk_set_rate(struct dsi_link_clks *l_clks)
288{
289 int rc = 0;
290
291 rc = clk_set_rate(l_clks->clks.esc_clk, l_clks->freq.esc_clk_rate);
292 if (rc) {
293 pr_err("clk_set_rate failed for esc_clk rc = %d\n", rc);
294 goto error;
295 }
296
297 rc = clk_set_rate(l_clks->clks.byte_clk, l_clks->freq.byte_clk_rate);
298 if (rc) {
299 pr_err("clk_set_rate failed for byte_clk rc = %d\n", rc);
300 goto error;
301 }
302
303 rc = clk_set_rate(l_clks->clks.pixel_clk, l_clks->freq.pix_clk_rate);
304 if (rc) {
305 pr_err("clk_set_rate failed for pixel_clk rc = %d\n", rc);
306 goto error;
307 }
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530308
309 /*
310 * If byte_intf_clk is present, set rate for that too.
311 * For DPHY: byte_intf_clk_rate = byte_clk_rate / 2
312 * todo: this needs to be revisited when support for CPHY is added
313 */
314 if (l_clks->clks.byte_intf_clk) {
315 rc = clk_set_rate(l_clks->clks.byte_intf_clk,
316 (l_clks->freq.byte_clk_rate / 2));
317 if (rc) {
318 pr_err("set_rate failed for byte_intf_clk rc = %d\n",
319 rc);
320 goto error;
321 }
322 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530323error:
324 return rc;
325}
326
327static int dsi_link_clk_prepare(struct dsi_link_clks *l_clks)
328{
329 int rc = 0;
330
331 rc = clk_prepare(l_clks->clks.esc_clk);
332 if (rc) {
333 pr_err("Failed to prepare dsi esc clk, rc=%d\n", rc);
334 goto esc_clk_err;
335 }
336
337 rc = clk_prepare(l_clks->clks.byte_clk);
338 if (rc) {
339 pr_err("Failed to prepare dsi byte clk, rc=%d\n", rc);
340 goto byte_clk_err;
341 }
342
343 rc = clk_prepare(l_clks->clks.pixel_clk);
344 if (rc) {
345 pr_err("Failed to prepare dsi pixel clk, rc=%d\n", rc);
346 goto pixel_clk_err;
347 }
348
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530349 if (l_clks->clks.byte_intf_clk) {
350 rc = clk_prepare(l_clks->clks.byte_intf_clk);
351 if (rc) {
352 pr_err("Failed to prepare dsi byte intf clk, rc=%d\n",
353 rc);
354 goto byte_intf_clk_err;
355 }
356 }
357
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530358 return rc;
359
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530360byte_intf_clk_err:
361 clk_unprepare(l_clks->clks.pixel_clk);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530362pixel_clk_err:
363 clk_unprepare(l_clks->clks.byte_clk);
364byte_clk_err:
365 clk_unprepare(l_clks->clks.esc_clk);
366esc_clk_err:
367 return rc;
368}
369
370static void dsi_link_clk_unprepare(struct dsi_link_clks *l_clks)
371{
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530372 if (l_clks->clks.byte_intf_clk)
373 clk_unprepare(l_clks->clks.byte_intf_clk);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530374 clk_unprepare(l_clks->clks.pixel_clk);
375 clk_unprepare(l_clks->clks.byte_clk);
376 clk_unprepare(l_clks->clks.esc_clk);
377}
378
379static int dsi_link_clk_enable(struct dsi_link_clks *l_clks)
380{
381 int rc = 0;
382
383 rc = clk_enable(l_clks->clks.esc_clk);
384 if (rc) {
385 pr_err("Failed to enable dsi esc clk, rc=%d\n", rc);
386 goto esc_clk_err;
387 }
388
389 rc = clk_enable(l_clks->clks.byte_clk);
390 if (rc) {
391 pr_err("Failed to enable dsi byte clk, rc=%d\n", rc);
392 goto byte_clk_err;
393 }
394
395 rc = clk_enable(l_clks->clks.pixel_clk);
396 if (rc) {
397 pr_err("Failed to enable dsi pixel clk, rc=%d\n", rc);
398 goto pixel_clk_err;
399 }
400
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530401 if (l_clks->clks.byte_intf_clk) {
402 rc = clk_enable(l_clks->clks.byte_intf_clk);
403 if (rc) {
404 pr_err("Failed to enable dsi byte intf clk, rc=%d\n",
405 rc);
406 goto byte_intf_clk_err;
407 }
408 }
409
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530410 return rc;
411
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530412byte_intf_clk_err:
413 clk_disable(l_clks->clks.pixel_clk);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530414pixel_clk_err:
415 clk_disable(l_clks->clks.byte_clk);
416byte_clk_err:
417 clk_disable(l_clks->clks.esc_clk);
418esc_clk_err:
419 return rc;
420}
421
422static void dsi_link_clk_disable(struct dsi_link_clks *l_clks)
423{
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530424 if (l_clks->clks.byte_intf_clk)
425 clk_disable(l_clks->clks.byte_intf_clk);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530426 clk_disable(l_clks->clks.esc_clk);
427 clk_disable(l_clks->clks.pixel_clk);
428 clk_disable(l_clks->clks.byte_clk);
429}
430
431/**
432 * dsi_link_clk_start() - enable dsi link clocks
433 */
434int dsi_link_clk_start(struct dsi_link_clks *clks)
435{
436 int rc = 0;
437
438 rc = dsi_link_clk_set_rate(clks);
439 if (rc) {
440 pr_err("failed to set clk rates, rc = %d\n", rc);
441 goto error;
442 }
443
444 rc = dsi_link_clk_prepare(clks);
445 if (rc) {
446 pr_err("failed to prepare link clks, rc = %d\n", rc);
447 goto error;
448 }
449
450 rc = dsi_link_clk_enable(clks);
451 if (rc) {
452 pr_err("failed to enable link clks, rc = %d\n", rc);
453 goto error_unprepare;
454 }
455
456 pr_debug("Link clocks are enabled\n");
457 return rc;
458error_unprepare:
459 dsi_link_clk_unprepare(clks);
460error:
461 return rc;
462}
463
464/**
465 * dsi_link_clk_stop() - Stop DSI link clocks.
466 */
467int dsi_link_clk_stop(struct dsi_link_clks *clks)
468{
469 dsi_link_clk_disable(clks);
470 dsi_link_clk_unprepare(clks);
471
472 pr_debug("Link clocks disabled\n");
473
474 return 0;
475}
476
477static int dsi_display_core_clk_enable(struct dsi_core_clks *clks,
478 u32 ctrl_count, u32 master_ndx)
479{
480 int rc = 0;
481 int i;
482 struct dsi_core_clks *clk, *m_clks;
483
484 /*
485 * In case of split DSI usecases, the clock for master controller should
486 * be enabled before the other controller. Master controller in the
487 * clock context refers to the controller that sources the clock.
488 */
489
490 m_clks = &clks[master_ndx];
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800491 rc = sde_power_resource_enable(m_clks->clks.phandle,
492 m_clks->clks.dsi_core_client, true);
493
494 if (rc) {
495 pr_err("Power resource enable failed, rc=%d\n", rc);
496 goto error;
497 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530498
499 rc = dsi_core_clk_start(m_clks);
500 if (rc) {
501 pr_err("failed to turn on master clocks, rc=%d\n", rc);
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800502 goto error_disable_master_resource;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530503 }
504
505 /* Turn on rest of the core clocks */
506 for (i = 0; i < ctrl_count; i++) {
507 clk = &clks[i];
508 if (!clk || (clk == m_clks))
509 continue;
510
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800511 rc = sde_power_resource_enable(clk->clks.phandle,
512 clk->clks.dsi_core_client, true);
513 if (rc) {
514 pr_err("Power resource enable failed, rc=%d\n", rc);
515 goto error_disable_master;
516 }
517
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530518 rc = dsi_core_clk_start(clk);
519 if (rc) {
520 pr_err("failed to turn on clocks, rc=%d\n", rc);
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800521 (void)sde_power_resource_enable(clk->clks.phandle,
522 clk->clks.dsi_core_client, false);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530523 goto error_disable_master;
524 }
525 }
Shashank Babu Chinta Venkatae30f510e2017-04-05 13:38:39 -0700526 return rc;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530527error_disable_master:
528 (void)dsi_core_clk_stop(m_clks);
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800529
530error_disable_master_resource:
531 (void)sde_power_resource_enable(m_clks->clks.phandle,
532 m_clks->clks.dsi_core_client, false);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530533error:
534 return rc;
535}
536
537static int dsi_display_link_clk_enable(struct dsi_link_clks *clks,
538 u32 ctrl_count, u32 master_ndx)
539{
540 int rc = 0;
541 int i;
542 struct dsi_link_clks *clk, *m_clks;
543
544 /*
545 * In case of split DSI usecases, the clock for master controller should
546 * be enabled before the other controller. Master controller in the
547 * clock context refers to the controller that sources the clock.
548 */
549
550 m_clks = &clks[master_ndx];
551
552 rc = dsi_link_clk_start(m_clks);
553 if (rc) {
554 pr_err("failed to turn on master clocks, rc=%d\n", rc);
555 goto error;
556 }
557
558 /* Turn on rest of the core clocks */
559 for (i = 0; i < ctrl_count; i++) {
560 clk = &clks[i];
561 if (!clk || (clk == m_clks))
562 continue;
563
564 rc = dsi_link_clk_start(clk);
565 if (rc) {
566 pr_err("failed to turn on clocks, rc=%d\n", rc);
567 goto error_disable_master;
568 }
569 }
570 return rc;
571error_disable_master:
572 (void)dsi_link_clk_stop(m_clks);
573error:
574 return rc;
575}
576
577static int dsi_display_core_clk_disable(struct dsi_core_clks *clks,
578 u32 ctrl_count, u32 master_ndx)
579{
580 int rc = 0;
581 int i;
582 struct dsi_core_clks *clk, *m_clks;
583
584 /*
585 * In case of split DSI usecases, clock for slave DSI controllers should
586 * be disabled first before disabling clock for master controller. Slave
587 * controllers in the clock context refer to controller which source
588 * clock from another controller.
589 */
590
591 m_clks = &clks[master_ndx];
592
593 /* Turn off non-master core clocks */
594 for (i = 0; i < ctrl_count; i++) {
595 clk = &clks[i];
596 if (!clk || (clk == m_clks))
597 continue;
598
599 rc = dsi_core_clk_stop(clk);
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800600 if (rc) {
601 pr_debug("failed to turn off clocks, rc=%d\n", rc);
602 goto error;
603 }
604
605 rc = sde_power_resource_enable(clk->clks.phandle,
606 clk->clks.dsi_core_client, false);
607 if (rc) {
608 pr_err("Power resource disable failed: %d\n", rc);
609 goto error;
610 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530611 }
612
613 rc = dsi_core_clk_stop(m_clks);
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800614 if (rc) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530615 pr_err("failed to turn off master clocks, rc=%d\n", rc);
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800616 goto error;
617 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530618
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800619 rc = sde_power_resource_enable(m_clks->clks.phandle,
620 m_clks->clks.dsi_core_client, false);
621 if (rc)
622 pr_err("Power resource disable failed: %d\n", rc);
623error:
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530624 return rc;
625}
626
627static int dsi_display_link_clk_disable(struct dsi_link_clks *clks,
628 u32 ctrl_count, u32 master_ndx)
629{
630 int rc = 0;
631 int i;
632 struct dsi_link_clks *clk, *m_clks;
633
634 /*
635 * In case of split DSI usecases, clock for slave DSI controllers should
636 * be disabled first before disabling clock for master controller. Slave
637 * controllers in the clock context refer to controller which source
638 * clock from another controller.
639 */
640
641 m_clks = &clks[master_ndx];
642
643 /* Turn off non-master link clocks */
644 for (i = 0; i < ctrl_count; i++) {
645 clk = &clks[i];
646 if (!clk || (clk == m_clks))
647 continue;
648
649 rc = dsi_link_clk_stop(clk);
650 if (rc)
651 pr_err("failed to turn off clocks, rc=%d\n", rc);
652 }
653
654 rc = dsi_link_clk_stop(m_clks);
655 if (rc)
656 pr_err("failed to turn off master clocks, rc=%d\n", rc);
657
658 return rc;
659}
660
661static int dsi_update_clk_state(struct dsi_core_clks *c_clks, u32 c_state,
662 struct dsi_link_clks *l_clks, u32 l_state)
663{
664 int rc = 0;
665 struct dsi_clk_mngr *mngr;
666 bool l_c_on = false;
667
668 if (c_clks) {
669 mngr =
670 container_of(c_clks, struct dsi_clk_mngr, core_clks[0]);
671 } else if (l_clks) {
672 mngr =
673 container_of(l_clks, struct dsi_clk_mngr, link_clks[0]);
674 } else {
675 mngr = NULL;
676 }
677
678 if (!mngr)
679 return -EINVAL;
680
681 pr_debug("c_state = %d, l_state = %d\n",
682 c_clks ? c_state : -1, l_clks ? l_state : -1);
683 /*
684 * Below is the sequence to toggle DSI clocks:
685 * 1. For ON sequence, Core clocks before link clocks
686 * 2. For OFF sequence, Link clocks before core clocks.
687 */
688 if (c_clks && (c_state == DSI_CLK_ON)) {
689 if (mngr->core_clk_state == DSI_CLK_OFF) {
690 rc = mngr->pre_clkon_cb(mngr->priv_data,
691 DSI_CORE_CLK,
692 DSI_CLK_ON);
693 if (rc) {
694 pr_err("failed to turn on MDP FS rc= %d\n", rc);
695 goto error;
696 }
697 }
698 rc = dsi_display_core_clk_enable(c_clks, mngr->dsi_ctrl_count,
699 mngr->master_ndx);
700 if (rc) {
701 pr_err("failed to turn on core clks rc = %d\n", rc);
702 goto error;
703 }
704
705 if (mngr->post_clkon_cb) {
706 rc = mngr->post_clkon_cb(mngr->priv_data,
707 DSI_CORE_CLK,
708 DSI_CLK_ON);
709 if (rc)
710 pr_err("post clk on cb failed, rc = %d\n", rc);
711 }
712 mngr->core_clk_state = DSI_CLK_ON;
713 }
714
715 if (l_clks) {
716 if (l_state == DSI_CLK_ON) {
717 if (mngr->pre_clkon_cb) {
718 rc = mngr->pre_clkon_cb(mngr->priv_data,
719 DSI_LINK_CLK, l_state);
720 if (rc)
721 pr_err("pre link clk on cb failed\n");
722 }
723 rc = dsi_display_link_clk_enable(l_clks,
724 mngr->dsi_ctrl_count, mngr->master_ndx);
725 if (rc) {
726 pr_err("failed to start link clk rc= %d\n", rc);
727 goto error;
728 }
729 if (mngr->post_clkon_cb) {
730 rc = mngr->post_clkon_cb(mngr->priv_data,
731 DSI_LINK_CLK,
732 l_state);
733 if (rc)
734 pr_err("post link clk on cb failed\n");
735 }
736 } else {
737 /*
738 * Two conditions that need to be checked for Link
739 * clocks:
740 * 1. Link clocks need core clocks to be on when
741 * transitioning from EARLY_GATE to OFF state.
742 * 2. ULPS mode might have to be enabled in case of OFF
743 * state. For ULPS, Link clocks should be turned ON
744 * first before they are turned off again.
745 *
746 * If Link is going from EARLY_GATE to OFF state AND
747 * Core clock is already in EARLY_GATE or OFF state,
748 * turn on Core clocks and link clocks.
749 *
750 * ULPS state is managed as part of the pre_clkoff_cb.
751 */
752 if ((l_state == DSI_CLK_OFF) &&
753 (mngr->link_clk_state ==
754 DSI_CLK_EARLY_GATE) &&
755 (mngr->core_clk_state !=
756 DSI_CLK_ON)) {
757 rc = dsi_display_core_clk_enable(
758 mngr->core_clks, mngr->dsi_ctrl_count,
759 mngr->master_ndx);
760 if (rc) {
761 pr_err("core clks did not start\n");
762 goto error;
763 }
764
765 rc = dsi_display_link_clk_enable(l_clks,
766 mngr->dsi_ctrl_count, mngr->master_ndx);
767 if (rc) {
768 pr_err("Link clks did not start\n");
769 goto error;
770 }
771 l_c_on = true;
772 pr_debug("ECG: core and Link_on\n");
773 }
774
775 if (mngr->pre_clkoff_cb) {
776 rc = mngr->pre_clkoff_cb(mngr->priv_data,
777 DSI_LINK_CLK, l_state);
778 if (rc)
779 pr_err("pre link clk off cb failed\n");
780 }
781
782 rc = dsi_display_link_clk_disable(l_clks,
783 mngr->dsi_ctrl_count, mngr->master_ndx);
784 if (rc) {
785 pr_err("failed to stop link clk, rc = %d\n",
786 rc);
787 goto error;
788 }
789
790 if (mngr->post_clkoff_cb) {
791 rc = mngr->post_clkoff_cb(mngr->priv_data,
792 DSI_LINK_CLK, l_state);
793 if (rc)
794 pr_err("post link clk off cb failed\n");
795 }
796 /*
797 * This check is to save unnecessary clock state
798 * change when going from EARLY_GATE to OFF. In the
799 * case where the request happens for both Core and Link
800 * clocks in the same call, core clocks need to be
801 * turned on first before OFF state can be entered.
802 *
803 * Core clocks are turned on here for Link clocks to go
804 * to OFF state. If core clock request is also present,
805 * then core clocks can be turned off Core clocks are
806 * transitioned to OFF state.
807 */
808 if (l_c_on && (!(c_clks && (c_state == DSI_CLK_OFF)
809 && (mngr->core_clk_state ==
810 DSI_CLK_EARLY_GATE)))) {
811 rc = dsi_display_core_clk_disable(
812 mngr->core_clks, mngr->dsi_ctrl_count,
813 mngr->master_ndx);
814 if (rc) {
815 pr_err("core clks did not stop\n");
816 goto error;
817 }
818
819 l_c_on = false;
820 pr_debug("ECG: core off\n");
821 } else
822 pr_debug("ECG: core off skip\n");
823 }
824
825 mngr->link_clk_state = l_state;
826 }
827
828 if (c_clks && (c_state != DSI_CLK_ON)) {
829 /*
830 * When going to OFF state from EARLY GATE state, Core clocks
831 * should be turned on first so that the IOs can be clamped.
832 * l_c_on flag is set, then the core clocks were turned before
833 * to the Link clocks go to OFF state. So Core clocks are
834 * already ON and this step can be skipped.
835 *
836 * IOs are clamped in pre_clkoff_cb callback.
837 */
838 if ((c_state == DSI_CLK_OFF) &&
839 (mngr->core_clk_state ==
840 DSI_CLK_EARLY_GATE) && !l_c_on) {
841 rc = dsi_display_core_clk_enable(mngr->core_clks,
842 mngr->dsi_ctrl_count, mngr->master_ndx);
843 if (rc) {
844 pr_err("core clks did not start\n");
845 goto error;
846 }
847 pr_debug("ECG: core on\n");
848 } else
849 pr_debug("ECG: core on skip\n");
850
851 if (mngr->pre_clkoff_cb) {
852 rc = mngr->pre_clkoff_cb(mngr->priv_data,
853 DSI_CORE_CLK,
854 c_state);
855 if (rc)
856 pr_err("pre core clk off cb failed\n");
857 }
858
859 rc = dsi_display_core_clk_disable(c_clks, mngr->dsi_ctrl_count,
860 mngr->master_ndx);
861 if (rc) {
862 pr_err("failed to turn off core clks rc = %d\n", rc);
863 goto error;
864 }
865
866 if (c_state == DSI_CLK_OFF) {
867 if (mngr->post_clkoff_cb) {
868 rc = mngr->post_clkoff_cb(mngr->priv_data,
869 DSI_CORE_CLK,
870 DSI_CLK_OFF);
871 if (rc)
872 pr_err("post clkoff cb fail, rc = %d\n",
873 rc);
874 }
875 }
876 mngr->core_clk_state = c_state;
877 }
878
879error:
880 return rc;
881}
882
883static int dsi_recheck_clk_state(struct dsi_clk_mngr *mngr)
884{
885 int rc = 0;
886 struct list_head *pos = NULL;
887 struct dsi_clk_client_info *c;
888 u32 new_core_clk_state = DSI_CLK_OFF;
889 u32 new_link_clk_state = DSI_CLK_OFF;
890 u32 old_c_clk_state = DSI_CLK_OFF;
891 u32 old_l_clk_state = DSI_CLK_OFF;
892 struct dsi_core_clks *c_clks = NULL;
893 struct dsi_link_clks *l_clks = NULL;
894
895 /*
896 * Conditions to maintain DSI manager clock state based on
897 * clock states of various clients:
898 * 1. If any client has clock in ON state, DSI manager clock state
899 * should be ON.
900 * 2. If any client is in ECG state with rest of them turned OFF,
901 * go to Early gate state.
902 * 3. If all clients have clocks as OFF, then go to OFF state.
903 */
904 list_for_each(pos, &mngr->client_list) {
905 c = list_entry(pos, struct dsi_clk_client_info, list);
906 if (c->core_clk_state == DSI_CLK_ON) {
907 new_core_clk_state = DSI_CLK_ON;
908 break;
909 } else if (c->core_clk_state == DSI_CLK_EARLY_GATE) {
910 new_core_clk_state = DSI_CLK_EARLY_GATE;
911 }
912 }
913
914 list_for_each(pos, &mngr->client_list) {
915 c = list_entry(pos, struct dsi_clk_client_info, list);
916 if (c->link_clk_state == DSI_CLK_ON) {
917 new_link_clk_state = DSI_CLK_ON;
918 break;
919 } else if (c->link_clk_state == DSI_CLK_EARLY_GATE) {
920 new_link_clk_state = DSI_CLK_EARLY_GATE;
921 }
922 }
923
924 if (new_core_clk_state != mngr->core_clk_state)
925 c_clks = mngr->core_clks;
926
927 if (new_link_clk_state != mngr->link_clk_state)
928 l_clks = mngr->link_clks;
929
930 old_c_clk_state = mngr->core_clk_state;
931 old_l_clk_state = mngr->link_clk_state;
932
933 pr_debug("c_clk_state (%d -> %d)\n",
934 old_c_clk_state, new_core_clk_state);
935 pr_debug("l_clk_state (%d -> %d)\n",
936 old_l_clk_state, new_link_clk_state);
937
938 if (c_clks || l_clks) {
939 rc = dsi_update_clk_state(c_clks, new_core_clk_state,
940 l_clks, new_link_clk_state);
941 if (rc) {
942 pr_err("failed to update clock state, rc = %d\n", rc);
943 goto error;
944 }
945 }
946
947error:
948 return rc;
949}
950
951int dsi_clk_req_state(void *client, enum dsi_clk_type clk,
952 enum dsi_clk_state state)
953{
954 int rc = 0;
955 struct dsi_clk_client_info *c = client;
956 struct dsi_clk_mngr *mngr;
957 bool changed = false;
958
959 if (!client || !clk || clk > (DSI_CORE_CLK | DSI_LINK_CLK) ||
960 state > DSI_CLK_EARLY_GATE) {
961 pr_err("Invalid params, client = %pK, clk = 0x%x, state = %d\n",
962 client, clk, state);
963 return -EINVAL;
964 }
965
966 mngr = c->mngr;
967 mutex_lock(&mngr->clk_mutex);
968
969 pr_debug("[%s]%s: CLK=%d, new_state=%d, core=%d, linkl=%d\n",
970 mngr->name, c->name, clk, state, c->core_clk_state,
971 c->link_clk_state);
972
973 /*
974 * Clock refcount handling as below:
975 * i. Increment refcount whenever ON is called.
976 * ii. Decrement refcount when transitioning from ON state to
977 * either OFF or EARLY_GATE.
978 * iii. Do not decrement refcount when changing from
979 * EARLY_GATE to OFF.
980 */
981 if (state == DSI_CLK_ON) {
982 if (clk & DSI_CORE_CLK) {
983 c->core_refcount++;
984 if (c->core_clk_state != DSI_CLK_ON) {
985 c->core_clk_state = DSI_CLK_ON;
986 changed = true;
987 }
988 }
989 if (clk & DSI_LINK_CLK) {
990 c->link_refcount++;
991 if (c->link_clk_state != DSI_CLK_ON) {
992 c->link_clk_state = DSI_CLK_ON;
993 changed = true;
994 }
995 }
996 } else if ((state == DSI_CLK_EARLY_GATE) ||
997 (state == DSI_CLK_OFF)) {
998 if (clk & DSI_CORE_CLK) {
999 if (c->core_refcount == 0) {
1000 if ((c->core_clk_state ==
1001 DSI_CLK_EARLY_GATE) &&
1002 (state == DSI_CLK_OFF)) {
1003 changed = true;
1004 c->core_clk_state = DSI_CLK_OFF;
1005 } else {
1006 pr_warn("Core refcount is zero for %s",
1007 c->name);
1008 }
1009 } else {
1010 c->core_refcount--;
1011 if (c->core_refcount == 0) {
1012 c->core_clk_state = state;
1013 changed = true;
1014 }
1015 }
1016 }
1017 if (clk & DSI_LINK_CLK) {
1018 if (c->link_refcount == 0) {
1019 if ((c->link_clk_state ==
1020 DSI_CLK_EARLY_GATE) &&
1021 (state == DSI_CLK_OFF)) {
1022 changed = true;
1023 c->link_clk_state = DSI_CLK_OFF;
1024 } else {
1025 pr_warn("Link refcount is zero for %s",
1026 c->name);
1027 }
1028 } else {
1029 c->link_refcount--;
1030 if (c->link_refcount == 0) {
1031 c->link_clk_state = state;
1032 changed = true;
1033 }
1034 }
1035 }
1036 }
1037 pr_debug("[%s]%s: change=%d, Core (ref=%d, state=%d), Link (ref=%d, state=%d)\n",
1038 mngr->name, c->name, changed, c->core_refcount,
1039 c->core_clk_state, c->link_refcount, c->link_clk_state);
1040
1041 if (changed) {
1042 rc = dsi_recheck_clk_state(mngr);
1043 if (rc)
1044 pr_err("Failed to adjust clock state rc = %d\n", rc);
1045 }
1046
1047 mutex_unlock(&mngr->clk_mutex);
1048 return rc;
1049}
1050
1051DEFINE_MUTEX(dsi_mngr_clk_mutex);
1052
1053int dsi_display_clk_ctrl(void *handle,
1054 enum dsi_clk_type clk_type, enum dsi_clk_state clk_state)
1055{
1056 int rc = 0;
1057
1058 if (!handle) {
1059 pr_err("%s: Invalid arg\n", __func__);
1060 return -EINVAL;
1061 }
1062
1063 mutex_lock(&dsi_mngr_clk_mutex);
1064 rc = dsi_clk_req_state(handle, clk_type, clk_state);
1065 if (rc)
1066 pr_err("%s: failed set clk state, rc = %d\n", __func__, rc);
1067 mutex_unlock(&dsi_mngr_clk_mutex);
1068
1069 return rc;
1070}
1071
1072void *dsi_register_clk_handle(void *clk_mngr, char *client)
1073{
1074 void *handle = NULL;
1075 struct dsi_clk_mngr *mngr = clk_mngr;
1076 struct dsi_clk_client_info *c;
1077
1078 if (!mngr) {
1079 pr_err("bad params\n");
1080 return ERR_PTR(-EINVAL);
1081 }
1082
1083 mutex_lock(&mngr->clk_mutex);
1084
1085 c = kzalloc(sizeof(*c), GFP_KERNEL);
1086 if (!c) {
1087 handle = ERR_PTR(-ENOMEM);
1088 goto error;
1089 }
1090
1091 strlcpy(c->name, client, MAX_STRING_LEN);
1092 c->mngr = mngr;
1093
1094 list_add(&c->list, &mngr->client_list);
1095
1096 pr_debug("[%s]: Added new client (%s)\n", mngr->name, c->name);
1097 handle = c;
1098error:
1099 mutex_unlock(&mngr->clk_mutex);
1100 return handle;
1101}
1102
1103int dsi_deregister_clk_handle(void *client)
1104{
1105 int rc = 0;
1106 struct dsi_clk_client_info *c = client;
1107 struct dsi_clk_mngr *mngr;
1108 struct list_head *pos = NULL;
1109 struct list_head *tmp = NULL;
1110 struct dsi_clk_client_info *node = NULL;
1111
1112 if (!client) {
1113 pr_err("Invalid params\n");
1114 return -EINVAL;
1115 }
1116
1117 mngr = c->mngr;
1118 pr_debug("%s: ENTER\n", mngr->name);
1119 mutex_lock(&mngr->clk_mutex);
1120 c->core_clk_state = DSI_CLK_OFF;
1121 c->link_clk_state = DSI_CLK_OFF;
1122
1123 rc = dsi_recheck_clk_state(mngr);
1124 if (rc) {
1125 pr_err("clock state recheck failed rc = %d\n", rc);
1126 goto error;
1127 }
1128
1129 list_for_each_safe(pos, tmp, &mngr->client_list) {
1130 node = list_entry(pos, struct dsi_clk_client_info,
1131 list);
1132 if (node == c) {
1133 list_del(&node->list);
1134 pr_debug("Removed device (%s)\n", node->name);
1135 kfree(node);
1136 break;
1137 }
1138 }
1139
1140error:
1141 mutex_unlock(&mngr->clk_mutex);
1142 pr_debug("%s: EXIT, rc = %d\n", mngr->name, rc);
1143 return rc;
1144}
1145
1146void *dsi_display_clk_mngr_register(struct dsi_clk_info *info)
1147{
1148 struct dsi_clk_mngr *mngr;
1149 int i = 0;
1150
1151 if (!info) {
1152 pr_err("Invalid params\n");
1153 return ERR_PTR(-EINVAL);
1154 }
1155
1156 mngr = kzalloc(sizeof(*mngr), GFP_KERNEL);
1157 if (!mngr) {
1158 mngr = ERR_PTR(-ENOMEM);
1159 goto error;
1160 }
1161
1162 mutex_init(&mngr->clk_mutex);
1163 mngr->dsi_ctrl_count = info->dsi_ctrl_count;
1164 mngr->master_ndx = info->master_ndx;
1165
1166 if (mngr->dsi_ctrl_count > MAX_DSI_CTRL) {
1167 kfree(mngr);
1168 return ERR_PTR(-EINVAL);
1169 }
1170
1171 for (i = 0; i < mngr->dsi_ctrl_count; i++) {
1172 memcpy(&mngr->core_clks[i].clks, &info->c_clks[i],
1173 sizeof(struct dsi_core_clk_info));
1174 memcpy(&mngr->link_clks[i].clks, &info->l_clks[i],
1175 sizeof(struct dsi_link_clk_info));
1176 mngr->core_clks[i].bus_handle = info->bus_handle[i];
Alexander Beykundfbb37d2017-03-03 17:09:02 -05001177 mngr->ctrl_index[i] = info->ctrl_index[i];
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301178 }
1179
1180 INIT_LIST_HEAD(&mngr->client_list);
1181 mngr->pre_clkon_cb = info->pre_clkon_cb;
1182 mngr->post_clkon_cb = info->post_clkon_cb;
1183 mngr->pre_clkoff_cb = info->pre_clkoff_cb;
1184 mngr->post_clkoff_cb = info->post_clkoff_cb;
1185 mngr->priv_data = info->priv_data;
1186 memcpy(mngr->name, info->name, MAX_STRING_LEN);
1187
1188error:
1189 pr_debug("EXIT, rc = %ld\n", PTR_ERR(mngr));
1190 return mngr;
1191}
1192
1193int dsi_display_clk_mngr_deregister(void *clk_mngr)
1194{
1195 int rc = 0;
1196 struct dsi_clk_mngr *mngr = clk_mngr;
1197 struct list_head *position = NULL;
1198 struct list_head *tmp = NULL;
1199 struct dsi_clk_client_info *node = NULL;
1200
1201 if (!mngr) {
1202 pr_err("Invalid params\n");
1203 return -EINVAL;
1204 }
1205
1206 pr_debug("%s: ENTER\n", mngr->name);
1207 mutex_lock(&mngr->clk_mutex);
1208
1209 list_for_each_safe(position, tmp, &mngr->client_list) {
1210 node = list_entry(position, struct dsi_clk_client_info,
1211 list);
1212 list_del(&node->list);
1213 pr_debug("Removed device (%s)\n", node->name);
1214 kfree(node);
1215 }
1216
1217 rc = dsi_recheck_clk_state(mngr);
1218 if (rc)
1219 pr_err("failed to disable all clocks\n");
1220
1221 mutex_unlock(&mngr->clk_mutex);
1222 pr_debug("%s: EXIT, rc = %d\n", mngr->name, rc);
1223 kfree(mngr);
1224 return rc;
1225}
1226