blob: d92a71d4af4df6a86868f15c199073c00ef7ba76 [file] [log] [blame]
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001/*
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003 *
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) "msm-dsi-display:[%s] " fmt, __func__
16
17#include <linux/list.h>
18#include <linux/of.h>
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -070019#include <linux/err.h>
Ajay Singh Parmar571e3012016-05-16 17:55:52 -070020
21#include "msm_drv.h"
Clarence Ip80ada7f2017-05-04 09:55:21 -070022#include "sde_connector.h"
Jordan Croused8e96522017-02-13 10:14:16 -070023#include "msm_mmu.h"
Ajay Singh Parmar571e3012016-05-16 17:55:52 -070024#include "dsi_display.h"
25#include "dsi_panel.h"
26#include "dsi_ctrl.h"
27#include "dsi_ctrl_hw.h"
28#include "dsi_drm.h"
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +053029#include "dsi_clk.h"
30#include "dsi_pwr.h"
Raviteja Tamatam68892de2017-06-20 04:47:19 +053031#include "sde_dbg.h"
Ajay Singh Parmar571e3012016-05-16 17:55:52 -070032
33#define to_dsi_display(x) container_of(x, struct dsi_display, host)
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -070034#define INT_BASE_10 10
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -070035#define NO_OVERRIDE -1
Ajay Singh Parmar571e3012016-05-16 17:55:52 -070036
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -040037#define MISR_BUFF_SIZE 256
38
Alan Kwong797e0892017-10-17 09:37:24 -040039#define MAX_NAME_SIZE 64
40
Ajay Singh Parmar571e3012016-05-16 17:55:52 -070041static DEFINE_MUTEX(dsi_display_list_lock);
42static LIST_HEAD(dsi_display_list);
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -070043static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN];
44static char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN];
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -070045static struct dsi_display_boot_param boot_displays[MAX_DSI_ACTIVE_DISPLAY];
46static struct device_node *default_active_node;
Ajay Singh Parmar64c19192016-06-10 16:44:56 -070047static const struct of_device_id dsi_display_dt_match[] = {
48 {.compatible = "qcom,dsi-display"},
49 {}
50};
51
Ajay Singh Parmar571e3012016-05-16 17:55:52 -070052static struct dsi_display *main_display;
53
Lloyd Atkinsone53b7372017-03-22 17:16:47 -040054void dsi_rect_intersect(const struct dsi_rect *r1,
55 const struct dsi_rect *r2,
56 struct dsi_rect *result)
57{
58 int l, t, r, b;
59
60 if (!r1 || !r2 || !result)
61 return;
62
63 l = max(r1->x, r2->x);
64 t = max(r1->y, r2->y);
65 r = min((r1->x + r1->w), (r2->x + r2->w));
66 b = min((r1->y + r1->h), (r2->y + r2->h));
67
68 if (r <= l || b <= t) {
69 memset(result, 0, sizeof(*result));
70 } else {
71 result->x = l;
72 result->y = t;
73 result->w = r - l;
74 result->h = b - t;
75 }
76}
77
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +053078int dsi_display_set_backlight(void *display, u32 bl_lvl)
79{
80 struct dsi_display *dsi_display = display;
81 struct dsi_panel *panel;
Xu Yangd566d222017-05-19 17:18:12 +080082 u32 bl_scale, bl_scale_ad;
83 u64 bl_temp;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +053084 int rc = 0;
85
Xu Yangd566d222017-05-19 17:18:12 +080086 if (dsi_display == NULL || dsi_display->panel == NULL)
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +053087 return -EINVAL;
88
89 panel = dsi_display->panel;
Vara Reddy29a427d2017-09-04 23:51:40 -070090
91 if (!dsi_panel_initialized(panel))
92 return -EINVAL;
93
Xu Yangd566d222017-05-19 17:18:12 +080094 panel->bl_config.bl_level = bl_lvl;
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +053095
Xu Yangd566d222017-05-19 17:18:12 +080096 /* scale backlight */
97 bl_scale = panel->bl_config.bl_scale;
98 bl_temp = bl_lvl * bl_scale / MAX_BL_SCALE_LEVEL;
99
100 bl_scale_ad = panel->bl_config.bl_scale_ad;
101 bl_temp = (u32)bl_temp * bl_scale_ad / MAX_AD_BL_SCALE_LEVEL;
102
103 pr_debug("bl_scale = %u, bl_scale_ad = %u, bl_lvl = %u\n",
104 bl_scale, bl_scale_ad, (u32)bl_temp);
Jeykumar Sankaran97a45312017-07-28 12:24:17 -0700105
106 rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
107 DSI_CORE_CLK, DSI_CLK_ON);
108 if (rc) {
109 pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
110 dsi_display->name, rc);
111 goto error;
112 }
113
Xu Yangd566d222017-05-19 17:18:12 +0800114 rc = dsi_panel_set_backlight(panel, (u32)bl_temp);
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +0530115 if (rc)
116 pr_err("unable to set backlight\n");
117
Jeykumar Sankaran97a45312017-07-28 12:24:17 -0700118 rc = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
119 DSI_CORE_CLK, DSI_CLK_OFF);
120 if (rc) {
121 pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
122 dsi_display->name, rc);
123 goto error;
124 }
125
126error:
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +0530127 return rc;
128}
129
Sandeep Panda79450002017-05-08 17:14:24 +0530130static int dsi_display_cmd_engine_enable(struct dsi_display *display)
131{
132 int rc = 0;
133 int i;
134 struct dsi_display_ctrl *m_ctrl, *ctrl;
135
Vara Reddyed01fe72017-10-12 04:32:45 -0700136 m_ctrl = &display->ctrl[display->cmd_master_idx];
137 mutex_lock(&m_ctrl->ctrl->ctrl_lock);
138
Sandeep Panda79450002017-05-08 17:14:24 +0530139 if (display->cmd_engine_refcount > 0) {
140 display->cmd_engine_refcount++;
Vara Reddyed01fe72017-10-12 04:32:45 -0700141 goto done;
Sandeep Panda79450002017-05-08 17:14:24 +0530142 }
143
Sandeep Panda79450002017-05-08 17:14:24 +0530144 rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON);
145 if (rc) {
146 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
147 display->name, rc);
Vara Reddyed01fe72017-10-12 04:32:45 -0700148 goto done;
Sandeep Panda79450002017-05-08 17:14:24 +0530149 }
150
151 for (i = 0; i < display->ctrl_count; i++) {
152 ctrl = &display->ctrl[i];
153 if (!ctrl->ctrl || (ctrl == m_ctrl))
154 continue;
155
156 rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl,
157 DSI_CTRL_ENGINE_ON);
158 if (rc) {
159 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
160 display->name, rc);
161 goto error_disable_master;
162 }
163 }
164
165 display->cmd_engine_refcount++;
Vara Reddyed01fe72017-10-12 04:32:45 -0700166 goto done;
Sandeep Panda79450002017-05-08 17:14:24 +0530167error_disable_master:
168 (void)dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
Vara Reddyed01fe72017-10-12 04:32:45 -0700169done:
170 mutex_unlock(&m_ctrl->ctrl->ctrl_lock);
Sandeep Panda79450002017-05-08 17:14:24 +0530171 return rc;
172}
173
174static int dsi_display_cmd_engine_disable(struct dsi_display *display)
175{
176 int rc = 0;
177 int i;
178 struct dsi_display_ctrl *m_ctrl, *ctrl;
179
Vara Reddyed01fe72017-10-12 04:32:45 -0700180 m_ctrl = &display->ctrl[display->cmd_master_idx];
181 mutex_lock(&m_ctrl->ctrl->ctrl_lock);
182
Sandeep Panda79450002017-05-08 17:14:24 +0530183 if (display->cmd_engine_refcount == 0) {
184 pr_err("[%s] Invalid refcount\n", display->name);
Vara Reddyed01fe72017-10-12 04:32:45 -0700185 goto done;
Sandeep Panda79450002017-05-08 17:14:24 +0530186 } else if (display->cmd_engine_refcount > 1) {
187 display->cmd_engine_refcount--;
Vara Reddyed01fe72017-10-12 04:32:45 -0700188 goto done;
Sandeep Panda79450002017-05-08 17:14:24 +0530189 }
190
Sandeep Panda79450002017-05-08 17:14:24 +0530191 for (i = 0; i < display->ctrl_count; i++) {
192 ctrl = &display->ctrl[i];
193 if (!ctrl->ctrl || (ctrl == m_ctrl))
194 continue;
195
196 rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl,
197 DSI_CTRL_ENGINE_OFF);
198 if (rc)
199 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
200 display->name, rc);
201 }
202
203 rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
204 if (rc) {
205 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
206 display->name, rc);
207 goto error;
208 }
209
210error:
211 display->cmd_engine_refcount = 0;
Vara Reddyed01fe72017-10-12 04:32:45 -0700212done:
213 mutex_unlock(&m_ctrl->ctrl->ctrl_lock);
Sandeep Panda79450002017-05-08 17:14:24 +0530214 return rc;
215}
216
Vara Reddyff9f4eb2017-11-22 16:15:12 -0800217static void dsi_display_aspace_cb_locked(void *cb_data, bool is_detach)
218{
219 struct dsi_display *display;
220 struct dsi_display_ctrl *display_ctrl;
221 int rc, cnt;
222
223 if (!cb_data) {
224 pr_err("aspace cb called with invalid cb_data\n");
225 return;
226 }
227 display = (struct dsi_display *)cb_data;
228
229 /*
230 * acquire panel_lock to make sure no commands are in-progress
231 * while detaching the non-secure context banks
232 */
233 dsi_panel_acquire_panel_lock(display->panel);
234
235 if (is_detach) {
236 /* invalidate the stored iova */
237 display->cmd_buffer_iova = 0;
238
239 /* return the virtual address mapping */
240 msm_gem_put_vaddr_locked(display->tx_cmd_buf);
241 msm_gem_vunmap(display->tx_cmd_buf);
242
243 } else {
244 rc = msm_gem_get_iova_locked(display->tx_cmd_buf,
245 display->aspace, &(display->cmd_buffer_iova));
246 if (rc) {
247 pr_err("failed to get the iova rc %d\n", rc);
248 goto end;
249 }
250
251 display->vaddr =
252 (void *) msm_gem_get_vaddr_locked(display->tx_cmd_buf);
253
254 if (IS_ERR_OR_NULL(display->vaddr)) {
255 pr_err("failed to get va rc %d\n", rc);
256 goto end;
257 }
258 }
259
260 for (cnt = 0; cnt < display->ctrl_count; cnt++) {
261 display_ctrl = &display->ctrl[cnt];
262 display_ctrl->ctrl->cmd_buffer_size = display->cmd_buffer_size;
263 display_ctrl->ctrl->cmd_buffer_iova = display->cmd_buffer_iova;
264 display_ctrl->ctrl->vaddr = display->vaddr;
265 }
266
267end:
268 /* release panel_lock */
269 dsi_panel_release_panel_lock(display->panel);
270}
271
272/* Allocate memory for cmd dma tx buffer */
273static int dsi_host_alloc_cmd_tx_buffer(struct dsi_display *display)
274{
275 int rc = 0, cnt = 0;
276 struct dsi_display_ctrl *display_ctrl;
277
278 mutex_lock(&display->drm_dev->struct_mutex);
279 display->tx_cmd_buf = msm_gem_new(display->drm_dev,
280 SZ_4K,
281 MSM_BO_UNCACHED);
282 mutex_unlock(&display->drm_dev->struct_mutex);
283
284 if ((display->tx_cmd_buf) == NULL) {
285 pr_err("Failed to allocate cmd tx buf memory\n");
286 rc = -ENOMEM;
287 goto error;
288 }
289
290 display->cmd_buffer_size = SZ_4K;
291
292 display->aspace = msm_gem_smmu_address_space_get(
293 display->drm_dev, MSM_SMMU_DOMAIN_UNSECURE);
294 if (!display->aspace) {
295 pr_err("failed to get aspace\n");
296 rc = -EINVAL;
297 goto free_gem;
298 }
299 /* register to aspace */
300 rc = msm_gem_address_space_register_cb(display->aspace,
301 dsi_display_aspace_cb_locked, (void *)display);
302 if (rc) {
303 pr_err("failed to register callback %d", rc);
304 goto free_gem;
305 }
306
307 rc = msm_gem_get_iova(display->tx_cmd_buf, display->aspace,
308 &(display->cmd_buffer_iova));
309 if (rc) {
310 pr_err("failed to get the iova rc %d\n", rc);
311 goto free_aspace_cb;
312 }
313
314 display->vaddr =
315 (void *) msm_gem_get_vaddr(display->tx_cmd_buf);
316 if (IS_ERR_OR_NULL(display->vaddr)) {
317 pr_err("failed to get va rc %d\n", rc);
318 rc = -EINVAL;
319 goto put_iova;
320 }
321
322 for (cnt = 0; cnt < display->ctrl_count; cnt++) {
323 display_ctrl = &display->ctrl[cnt];
324 display_ctrl->ctrl->cmd_buffer_size = SZ_4K;
325 display_ctrl->ctrl->cmd_buffer_iova =
326 display->cmd_buffer_iova;
327 display_ctrl->ctrl->vaddr = display->vaddr;
328 display_ctrl->ctrl->tx_cmd_buf = display->tx_cmd_buf;
329 }
330
331 return rc;
332
333put_iova:
334 msm_gem_put_iova(display->tx_cmd_buf, display->aspace);
335free_aspace_cb:
336 msm_gem_address_space_unregister_cb(display->aspace,
337 dsi_display_aspace_cb_locked, display);
338free_gem:
339 mutex_lock(&display->drm_dev->struct_mutex);
340 msm_gem_free_object(display->tx_cmd_buf);
341 mutex_unlock(&display->drm_dev->struct_mutex);
342error:
343 return rc;
344}
345
Sandeep Panda79450002017-05-08 17:14:24 +0530346static bool dsi_display_validate_reg_read(struct dsi_panel *panel)
347{
348 int i, j = 0;
349 int len = 0, *lenp;
350 int group = 0, count = 0;
351 struct dsi_display_mode *mode;
352 struct drm_panel_esd_config *config;
353
354 if (!panel)
355 return false;
356
357 config = &(panel->esd_config);
358
359 lenp = config->status_valid_params ?: config->status_cmds_rlen;
360 mode = panel->cur_mode;
361 count = mode->priv_info->cmd_sets[DSI_CMD_SET_PANEL_STATUS].count;
362
363 for (i = 0; i < count; i++)
364 len += lenp[i];
365
366 for (i = 0; i < len; i++)
367 j += len;
368
369 for (j = 0; j < config->groups; ++j) {
370 for (i = 0; i < len; ++i) {
371 if (config->return_buf[i] !=
372 config->status_value[group + i])
373 break;
374 }
375
376 if (i == len)
377 return true;
378 group += len;
379 }
380
381 return false;
382}
383
384static int dsi_display_read_status(struct dsi_display_ctrl *ctrl,
385 struct dsi_panel *panel)
386{
387 int i, rc = 0, count = 0, start = 0, *lenp;
388 struct drm_panel_esd_config *config;
389 struct dsi_cmd_desc *cmds;
390 u32 flags = 0;
391
392 if (!panel)
393 return -EINVAL;
394
Veera Sundaram Sankarana2d50582017-10-19 17:49:48 -0700395 /* acquire panel_lock to make sure no commands are in progress */
396 dsi_panel_acquire_panel_lock(panel);
397
Sandeep Panda79450002017-05-08 17:14:24 +0530398 config = &(panel->esd_config);
399 lenp = config->status_valid_params ?: config->status_cmds_rlen;
400 count = config->status_cmd.count;
401 cmds = config->status_cmd.cmds;
Sandeep Pandaab1c2532017-10-27 22:24:31 +0530402 if (cmds->last_command) {
403 cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND;
404 flags |= DSI_CTRL_CMD_LAST_COMMAND;
405 }
406 flags |= (DSI_CTRL_CMD_FETCH_MEMORY | DSI_CTRL_CMD_READ);
Sandeep Panda79450002017-05-08 17:14:24 +0530407
408 for (i = 0; i < count; ++i) {
409 memset(config->status_buf, 0x0, SZ_4K);
410 cmds[i].msg.rx_buf = config->status_buf;
411 cmds[i].msg.rx_len = config->status_cmds_rlen[i];
412 rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &cmds[i].msg, flags);
413 if (rc <= 0) {
414 pr_err("rx cmd transfer failed rc=%d\n", rc);
415 goto error;
416 }
417
418 memcpy(config->return_buf + start,
419 config->status_buf, lenp[i]);
420 start += lenp[i];
421 }
422
423error:
Veera Sundaram Sankarana2d50582017-10-19 17:49:48 -0700424 /* release panel_lock */
425 dsi_panel_release_panel_lock(panel);
Sandeep Panda79450002017-05-08 17:14:24 +0530426 return rc;
427}
428
429static int dsi_display_validate_status(struct dsi_display_ctrl *ctrl,
430 struct dsi_panel *panel)
431{
432 int rc = 0;
433
434 rc = dsi_display_read_status(ctrl, panel);
435 if (rc <= 0) {
436 goto exit;
437 } else {
438 /*
439 * panel status read successfully.
440 * check for validity of the data read back.
441 */
442 rc = dsi_display_validate_reg_read(panel);
443 if (!rc) {
444 rc = -EINVAL;
445 goto exit;
446 }
447 }
448
449exit:
450 return rc;
451}
452
453static int dsi_display_status_reg_read(struct dsi_display *display)
454{
455 int rc = 0, i;
456 struct dsi_display_ctrl *m_ctrl, *ctrl;
457
458 pr_debug(" ++\n");
459
460 m_ctrl = &display->ctrl[display->cmd_master_idx];
461
Vara Reddyff9f4eb2017-11-22 16:15:12 -0800462 if (display->tx_cmd_buf == NULL) {
463 rc = dsi_host_alloc_cmd_tx_buffer(display);
464 if (rc) {
465 pr_err("failed to allocate cmd tx buffer memory\n");
466 goto done;
467 }
468 }
469
Sandeep Panda79450002017-05-08 17:14:24 +0530470 rc = dsi_display_cmd_engine_enable(display);
471 if (rc) {
472 pr_err("cmd engine enable failed\n");
473 return -EPERM;
474 }
475
476 rc = dsi_display_validate_status(m_ctrl, display->panel);
477 if (rc <= 0) {
478 pr_err("[%s] read status failed on master,rc=%d\n",
479 display->name, rc);
480 goto exit;
481 }
482
483 if (!display->panel->sync_broadcast_en)
484 goto exit;
485
486 for (i = 0; i < display->ctrl_count; i++) {
487 ctrl = &display->ctrl[i];
488 if (ctrl == m_ctrl)
489 continue;
490
491 rc = dsi_display_validate_status(ctrl, display->panel);
492 if (rc <= 0) {
493 pr_err("[%s] read status failed on master,rc=%d\n",
494 display->name, rc);
495 goto exit;
496 }
497 }
Sandeep Panda79450002017-05-08 17:14:24 +0530498exit:
499 dsi_display_cmd_engine_disable(display);
Vara Reddyff9f4eb2017-11-22 16:15:12 -0800500done:
Sandeep Panda79450002017-05-08 17:14:24 +0530501 return rc;
502}
503
504static int dsi_display_status_bta_request(struct dsi_display *display)
505{
506 int rc = 0;
507
508 pr_debug(" ++\n");
509 /* TODO: trigger SW BTA and wait for acknowledgment */
510
511 return rc;
512}
513
514static int dsi_display_status_check_te(struct dsi_display *display)
515{
516 int rc = 0;
517
518 pr_debug(" ++\n");
519 /* TODO: wait for TE interrupt from panel */
520
521 return rc;
522}
523
524int dsi_display_check_status(void *display)
525{
526 struct dsi_display *dsi_display = display;
527 struct dsi_panel *panel;
528 u32 status_mode;
Sandeep Panda318cff12017-10-20 13:16:03 +0530529 int rc = 0x1;
Sandeep Panda79450002017-05-08 17:14:24 +0530530
531 if (dsi_display == NULL)
532 return -EINVAL;
533
534 panel = dsi_display->panel;
535
536 status_mode = panel->esd_config.status_mode;
537
Sandeep Panda318cff12017-10-20 13:16:03 +0530538 mutex_lock(&dsi_display->display_lock);
539
540 if (!panel->panel_initialized) {
541 pr_debug("Panel not initialized\n");
542 mutex_unlock(&dsi_display->display_lock);
543 return rc;
544 }
545
Sandeep Panda79450002017-05-08 17:14:24 +0530546 dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
547 DSI_ALL_CLKS, DSI_CLK_ON);
548
549 if (status_mode == ESD_MODE_REG_READ) {
550 rc = dsi_display_status_reg_read(dsi_display);
551 } else if (status_mode == ESD_MODE_SW_BTA) {
552 rc = dsi_display_status_bta_request(dsi_display);
553 } else if (status_mode == ESD_MODE_PANEL_TE) {
554 rc = dsi_display_status_check_te(dsi_display);
555 } else {
556 pr_warn("unsupported check status mode\n");
557 panel->esd_config.esd_enabled = false;
558 }
559
560 dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
561 DSI_ALL_CLKS, DSI_CLK_OFF);
Sandeep Panda318cff12017-10-20 13:16:03 +0530562 mutex_unlock(&dsi_display->display_lock);
Sandeep Panda79450002017-05-08 17:14:24 +0530563
564 return rc;
565}
566
Lloyd Atkinson8c49c582016-11-18 14:23:54 -0500567int dsi_display_soft_reset(void *display)
568{
569 struct dsi_display *dsi_display;
570 struct dsi_display_ctrl *ctrl;
571 int rc = 0;
572 int i;
573
574 if (!display)
575 return -EINVAL;
576
577 dsi_display = display;
578
579 for (i = 0 ; i < dsi_display->ctrl_count; i++) {
580 ctrl = &dsi_display->ctrl[i];
581 rc = dsi_ctrl_soft_reset(ctrl->ctrl);
582 if (rc) {
583 pr_err("[%s] failed to soft reset host_%d, rc=%d\n",
584 dsi_display->name, i, rc);
585 break;
586 }
587 }
588
589 return rc;
590}
Ping Li8430ee12017-02-24 14:14:44 -0800591
592enum dsi_pixel_format dsi_display_get_dst_format(void *display)
593{
594 enum dsi_pixel_format format = DSI_PIXEL_FORMAT_MAX;
595 struct dsi_display *dsi_display = (struct dsi_display *)display;
596
597 if (!dsi_display || !dsi_display->panel) {
598 pr_err("Invalid params(s) dsi_display %pK, panel %pK\n",
599 dsi_display,
600 ((dsi_display) ? dsi_display->panel : NULL));
601 return format;
602 }
603
604 format = dsi_display->panel->host_config.dst_format;
605 return format;
606}
607
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400608static void _dsi_display_setup_misr(struct dsi_display *display)
609{
610 int i;
611
612 for (i = 0; i < display->ctrl_count; i++) {
613 dsi_ctrl_setup_misr(display->ctrl[i].ctrl,
614 display->misr_enable,
615 display->misr_frame_count);
616 }
617}
618
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -0700619/**
620 * dsi_display_get_cont_splash_status - Get continuous splash status.
621 * @dsi_display: DSI display handle.
622 *
623 * Return: boolean to signify whether continuous splash is enabled.
624 */
625static bool dsi_display_get_cont_splash_status(struct dsi_display *display)
626{
627 u32 val = 0;
628 int i;
629 struct dsi_display_ctrl *ctrl;
630 struct dsi_ctrl_hw *hw;
631
632 for (i = 0; i < display->ctrl_count ; i++) {
633 ctrl = &(display->ctrl[i]);
634 if (!ctrl || !ctrl->ctrl)
635 continue;
636
637 hw = &(ctrl->ctrl->hw);
638 val = hw->ops.get_cont_splash_status(hw);
639 if (!val)
640 return false;
641 }
642 return true;
643}
644
Clarence Ip5f00c0602017-08-02 14:26:31 -0400645int dsi_display_set_power(struct drm_connector *connector,
646 int power_mode, void *disp)
647{
648 struct dsi_display *display = disp;
649 int rc = 0;
650
651 if (!display || !display->panel) {
652 pr_err("invalid display/panel\n");
653 return -EINVAL;
654 }
655
656 switch (power_mode) {
657 case SDE_MODE_DPMS_LP1:
658 rc = dsi_panel_set_lp1(display->panel);
659 break;
660 case SDE_MODE_DPMS_LP2:
661 rc = dsi_panel_set_lp2(display->panel);
662 break;
663 default:
664 rc = dsi_panel_set_nolp(display->panel);
665 break;
666 }
667 return rc;
668}
669
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700670static ssize_t debugfs_dump_info_read(struct file *file,
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400671 char __user *user_buf,
672 size_t user_len,
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700673 loff_t *ppos)
674{
675 struct dsi_display *display = file->private_data;
676 char *buf;
677 u32 len = 0;
678 int i;
679
680 if (!display)
681 return -ENODEV;
682
683 if (*ppos)
684 return 0;
685
686 buf = kzalloc(SZ_4K, GFP_KERNEL);
687 if (!buf)
688 return -ENOMEM;
689
690 len += snprintf(buf + len, (SZ_4K - len), "name = %s\n", display->name);
691 len += snprintf(buf + len, (SZ_4K - len),
692 "\tResolution = %dx%d\n",
693 display->config.video_timing.h_active,
694 display->config.video_timing.v_active);
695
696 for (i = 0; i < display->ctrl_count; i++) {
697 len += snprintf(buf + len, (SZ_4K - len),
698 "\tCTRL_%d:\n\t\tctrl = %s\n\t\tphy = %s\n",
699 i, display->ctrl[i].ctrl->name,
700 display->ctrl[i].phy->name);
701 }
702
703 len += snprintf(buf + len, (SZ_4K - len),
704 "\tPanel = %s\n", display->panel->name);
705
706 len += snprintf(buf + len, (SZ_4K - len),
707 "\tClock master = %s\n",
708 display->ctrl[display->clk_master_idx].ctrl->name);
709
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400710 if (copy_to_user(user_buf, buf, len)) {
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700711 kfree(buf);
712 return -EFAULT;
713 }
714
715 *ppos += len;
716
717 kfree(buf);
718 return len;
719}
720
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400721static ssize_t debugfs_misr_setup(struct file *file,
722 const char __user *user_buf,
723 size_t user_len,
724 loff_t *ppos)
725{
726 struct dsi_display *display = file->private_data;
727 char *buf;
728 int rc = 0;
729 size_t len;
730 u32 enable, frame_count;
731
732 if (!display)
733 return -ENODEV;
734
735 if (*ppos)
736 return 0;
737
738 buf = kzalloc(MISR_BUFF_SIZE, GFP_KERNEL);
739 if (!buf)
740 return -ENOMEM;
741
742 /* leave room for termination char */
743 len = min_t(size_t, user_len, MISR_BUFF_SIZE - 1);
744 if (copy_from_user(buf, user_buf, len)) {
745 rc = -EINVAL;
746 goto error;
747 }
748
749 buf[len] = '\0'; /* terminate the string */
750
751 if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) {
752 rc = -EINVAL;
753 goto error;
754 }
755
756 display->misr_enable = enable;
757 display->misr_frame_count = frame_count;
758
759 mutex_lock(&display->display_lock);
760 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
761 DSI_CORE_CLK, DSI_CLK_ON);
762 if (rc) {
763 pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
764 display->name, rc);
765 goto unlock;
766 }
767
768 _dsi_display_setup_misr(display);
769
770 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
771 DSI_CORE_CLK, DSI_CLK_OFF);
772 if (rc) {
773 pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
774 display->name, rc);
775 goto unlock;
776 }
777
778 rc = user_len;
779unlock:
780 mutex_unlock(&display->display_lock);
781error:
782 kfree(buf);
783 return rc;
784}
785
786static ssize_t debugfs_misr_read(struct file *file,
787 char __user *user_buf,
788 size_t user_len,
789 loff_t *ppos)
790{
791 struct dsi_display *display = file->private_data;
792 char *buf;
793 u32 len = 0;
794 int rc = 0;
795 struct dsi_ctrl *dsi_ctrl;
796 int i;
797 u32 misr;
798 size_t max_len = min_t(size_t, user_len, MISR_BUFF_SIZE);
799
800 if (!display)
801 return -ENODEV;
802
803 if (*ppos)
804 return 0;
805
806 buf = kzalloc(max_len, GFP_KERNEL);
807 if (!buf)
808 return -ENOMEM;
809
810 mutex_lock(&display->display_lock);
811 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
812 DSI_CORE_CLK, DSI_CLK_ON);
813 if (rc) {
814 pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
815 display->name, rc);
816 goto error;
817 }
818
819 for (i = 0; i < display->ctrl_count; i++) {
820 dsi_ctrl = display->ctrl[i].ctrl;
821 misr = dsi_ctrl_collect_misr(display->ctrl[i].ctrl);
822
823 len += snprintf((buf + len), max_len - len,
824 "DSI_%d MISR: 0x%x\n", dsi_ctrl->cell_index, misr);
825
826 if (len >= max_len)
827 break;
828 }
829
830 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
831 DSI_CORE_CLK, DSI_CLK_OFF);
832 if (rc) {
833 pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
834 display->name, rc);
835 goto error;
836 }
837
838 if (copy_to_user(user_buf, buf, len)) {
839 rc = -EFAULT;
840 goto error;
841 }
842
843 *ppos += len;
844
845error:
846 mutex_unlock(&display->display_lock);
847 kfree(buf);
848 return len;
849}
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700850
851static const struct file_operations dump_info_fops = {
852 .open = simple_open,
853 .read = debugfs_dump_info_read,
854};
855
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400856static const struct file_operations misr_data_fops = {
857 .open = simple_open,
858 .read = debugfs_misr_read,
859 .write = debugfs_misr_setup,
860};
861
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700862static int dsi_display_debugfs_init(struct dsi_display *display)
863{
864 int rc = 0;
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400865 struct dentry *dir, *dump_file, *misr_data;
Alan Kwong797e0892017-10-17 09:37:24 -0400866 char name[MAX_NAME_SIZE];
867 int i;
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700868
869 dir = debugfs_create_dir(display->name, NULL);
870 if (IS_ERR_OR_NULL(dir)) {
871 rc = PTR_ERR(dir);
872 pr_err("[%s] debugfs create dir failed, rc = %d\n",
873 display->name, rc);
874 goto error;
875 }
876
877 dump_file = debugfs_create_file("dump_info",
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400878 0400,
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700879 dir,
880 display,
881 &dump_info_fops);
882 if (IS_ERR_OR_NULL(dump_file)) {
883 rc = PTR_ERR(dump_file);
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400884 pr_err("[%s] debugfs create dump info file failed, rc=%d\n",
885 display->name, rc);
886 goto error_remove_dir;
887 }
888
889 misr_data = debugfs_create_file("misr_data",
890 0600,
891 dir,
892 display,
893 &misr_data_fops);
894 if (IS_ERR_OR_NULL(misr_data)) {
895 rc = PTR_ERR(misr_data);
896 pr_err("[%s] debugfs create misr datafile failed, rc=%d\n",
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700897 display->name, rc);
898 goto error_remove_dir;
899 }
900
Alan Kwong797e0892017-10-17 09:37:24 -0400901 for (i = 0; i < display->ctrl_count; i++) {
902 struct msm_dsi_phy *phy = display->ctrl[i].phy;
903
904 if (!phy || !phy->name)
905 continue;
906
907 snprintf(name, ARRAY_SIZE(name),
908 "%s_allow_phy_power_off", phy->name);
909 dump_file = debugfs_create_bool(name, 0600, dir,
910 &phy->allow_phy_power_off);
911 if (IS_ERR_OR_NULL(dump_file)) {
912 rc = PTR_ERR(dump_file);
913 pr_err("[%s] debugfs create %s failed, rc=%d\n",
914 display->name, name, rc);
915 goto error_remove_dir;
916 }
Alan Kwong60cc3552017-11-01 22:08:48 -0400917
918 snprintf(name, ARRAY_SIZE(name),
919 "%s_regulator_min_datarate_bps", phy->name);
920 dump_file = debugfs_create_u32(name, 0600, dir,
921 &phy->regulator_min_datarate_bps);
922 if (IS_ERR_OR_NULL(dump_file)) {
923 rc = PTR_ERR(dump_file);
924 pr_err("[%s] debugfs create %s failed, rc=%d\n",
925 display->name, name, rc);
926 goto error_remove_dir;
927 }
Alan Kwong797e0892017-10-17 09:37:24 -0400928 }
929
Lei Chen529da982017-10-24 16:23:42 +0800930 if (!debugfs_create_bool("ulps_enable", 0600, dir,
931 &display->panel->ulps_enabled)) {
932 pr_err("[%s] debugfs create ulps enable file failed\n",
933 display->name);
934 goto error_remove_dir;
935 }
936
937 if (!debugfs_create_bool("ulps_suspend_enable", 0600, dir,
938 &display->panel->ulps_suspend_enabled)) {
939 pr_err("[%s] debugfs create ulps-suspend enable file failed\n",
940 display->name);
941 goto error_remove_dir;
942 }
943
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700944 display->root = dir;
945 return rc;
946error_remove_dir:
947 debugfs_remove(dir);
948error:
949 return rc;
950}
951
Clarence Ip3649f8b2016-10-31 09:59:44 -0400952static int dsi_display_debugfs_deinit(struct dsi_display *display)
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700953{
Lloyd Atkinson1be10b62016-10-04 09:46:08 -0400954 debugfs_remove_recursive(display->root);
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700955
956 return 0;
957}
958
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -0700959static void adjust_timing_by_ctrl_count(const struct dsi_display *display,
960 struct dsi_display_mode *mode)
961{
962 if (display->ctrl_count > 1) {
963 mode->timing.h_active /= display->ctrl_count;
964 mode->timing.h_front_porch /= display->ctrl_count;
965 mode->timing.h_sync_width /= display->ctrl_count;
966 mode->timing.h_back_porch /= display->ctrl_count;
967 mode->timing.h_skew /= display->ctrl_count;
968 mode->pixel_clk_khz /= display->ctrl_count;
969 }
970}
971
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530972static int dsi_display_is_ulps_req_valid(struct dsi_display *display,
973 bool enable)
974{
975 /* TODO: make checks based on cont. splash */
976 int splash_enabled = false;
977
978 pr_debug("checking ulps req validity\n");
979
Lei Chen529da982017-10-24 16:23:42 +0800980 if (!dsi_panel_ulps_feature_enabled(display->panel) &&
981 !display->panel->ulps_suspend_enabled) {
982 pr_debug("%s: ULPS feature is not enabled\n", __func__);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530983 return false;
Lei Chen529da982017-10-24 16:23:42 +0800984 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530985
Lei Chen529da982017-10-24 16:23:42 +0800986 if (!dsi_panel_initialized(display->panel) &&
987 !display->panel->ulps_suspend_enabled) {
988 pr_debug("%s: panel not yet initialized\n", __func__);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530989 return false;
Lei Chen529da982017-10-24 16:23:42 +0800990 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530991
992 if (enable && display->ulps_enabled) {
993 pr_debug("ULPS already enabled\n");
994 return false;
995 } else if (!enable && !display->ulps_enabled) {
996 pr_debug("ULPS already disabled\n");
997 return false;
998 }
999
1000 /*
1001 * No need to enter ULPS when transitioning from splash screen to
1002 * boot animation since it is expected that the clocks would be turned
1003 * right back on.
1004 */
1005 if (enable && splash_enabled)
1006 return false;
1007
1008 return true;
1009}
1010
1011
1012/**
1013 * dsi_display_set_ulps() - set ULPS state for DSI lanes.
1014 * @dsi_display: DSI display handle.
1015 * @enable: enable/disable ULPS.
1016 *
1017 * ULPS can be enabled/disabled after DSI host engine is turned on.
1018 *
1019 * Return: error code.
1020 */
1021static int dsi_display_set_ulps(struct dsi_display *display, bool enable)
1022{
1023 int rc = 0;
1024 int i = 0;
1025 struct dsi_display_ctrl *m_ctrl, *ctrl;
1026
1027
1028 if (!display) {
1029 pr_err("Invalid params\n");
1030 return -EINVAL;
1031 }
1032
1033 if (!dsi_display_is_ulps_req_valid(display, enable)) {
1034 pr_debug("%s: skipping ULPS config, enable=%d\n",
1035 __func__, enable);
1036 return 0;
1037 }
1038
1039 m_ctrl = &display->ctrl[display->cmd_master_idx];
1040
1041 rc = dsi_ctrl_set_ulps(m_ctrl->ctrl, enable);
1042 if (rc) {
1043 pr_err("Ulps controller state change(%d) failed\n", enable);
1044 return rc;
1045 }
1046
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -07001047 rc = dsi_phy_set_ulps(m_ctrl->phy, &display->config, enable,
1048 display->clamp_enabled);
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +05301049 if (rc) {
1050 pr_err("Ulps PHY state change(%d) failed\n", enable);
1051 return rc;
1052 }
1053
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301054 for (i = 0; i < display->ctrl_count; i++) {
1055 ctrl = &display->ctrl[i];
1056 if (!ctrl->ctrl || (ctrl == m_ctrl))
1057 continue;
1058
1059 rc = dsi_ctrl_set_ulps(ctrl->ctrl, enable);
1060 if (rc) {
1061 pr_err("Ulps controller state change(%d) failed\n",
1062 enable);
1063 return rc;
1064 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +05301065
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -07001066 rc = dsi_phy_set_ulps(ctrl->phy, &display->config, enable,
1067 display->clamp_enabled);
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +05301068 if (rc) {
1069 pr_err("Ulps PHY state change(%d) failed\n", enable);
1070 return rc;
1071 }
1072
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301073 }
1074 display->ulps_enabled = enable;
1075 return 0;
1076}
1077
1078/**
1079 * dsi_display_set_clamp() - set clamp state for DSI IO.
1080 * @dsi_display: DSI display handle.
1081 * @enable: enable/disable clamping.
1082 *
1083 * Return: error code.
1084 */
1085static int dsi_display_set_clamp(struct dsi_display *display, bool enable)
1086{
1087 int rc = 0;
1088 int i = 0;
1089 struct dsi_display_ctrl *m_ctrl, *ctrl;
1090 bool ulps_enabled = false;
1091
1092
1093 if (!display) {
1094 pr_err("Invalid params\n");
1095 return -EINVAL;
1096 }
1097
1098 m_ctrl = &display->ctrl[display->cmd_master_idx];
1099 ulps_enabled = display->ulps_enabled;
1100
1101 rc = dsi_ctrl_set_clamp_state(m_ctrl->ctrl, enable, ulps_enabled);
1102 if (rc) {
1103 pr_err("DSI Clamp state change(%d) failed\n", enable);
1104 return rc;
1105 }
1106
1107 for (i = 0; i < display->ctrl_count; i++) {
1108 ctrl = &display->ctrl[i];
1109 if (!ctrl->ctrl || (ctrl == m_ctrl))
1110 continue;
1111
1112 rc = dsi_ctrl_set_clamp_state(ctrl->ctrl, enable, ulps_enabled);
1113 if (rc) {
1114 pr_err("DSI Clamp state change(%d) failed\n", enable);
1115 return rc;
1116 }
1117 }
1118 display->clamp_enabled = enable;
1119 return 0;
1120}
1121
1122/**
1123 * dsi_display_setup_ctrl() - setup DSI controller.
1124 * @dsi_display: DSI display handle.
1125 *
1126 * Return: error code.
1127 */
1128static int dsi_display_ctrl_setup(struct dsi_display *display)
1129{
1130 int rc = 0;
1131 int i = 0;
1132 struct dsi_display_ctrl *ctrl, *m_ctrl;
1133
1134
1135 if (!display) {
1136 pr_err("Invalid params\n");
1137 return -EINVAL;
1138 }
1139
1140 m_ctrl = &display->ctrl[display->cmd_master_idx];
1141 rc = dsi_ctrl_setup(m_ctrl->ctrl);
1142 if (rc) {
1143 pr_err("DSI controller setup failed\n");
1144 return rc;
1145 }
1146
1147 for (i = 0; i < display->ctrl_count; i++) {
1148 ctrl = &display->ctrl[i];
1149 if (!ctrl->ctrl || (ctrl == m_ctrl))
1150 continue;
1151
1152 rc = dsi_ctrl_setup(ctrl->ctrl);
1153 if (rc) {
1154 pr_err("DSI controller setup failed\n");
1155 return rc;
1156 }
1157 }
1158 return 0;
1159}
1160
1161static int dsi_display_phy_enable(struct dsi_display *display);
1162
1163/**
1164 * dsi_display_phy_idle_on() - enable DSI PHY while coming out of idle screen.
1165 * @dsi_display: DSI display handle.
Alan Kwong797e0892017-10-17 09:37:24 -04001166 * @mmss_clamp: True if clamp is enabled.
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301167 *
1168 * Return: error code.
1169 */
1170static int dsi_display_phy_idle_on(struct dsi_display *display,
1171 bool mmss_clamp)
1172{
1173 int rc = 0;
1174 int i = 0;
1175 struct dsi_display_ctrl *m_ctrl, *ctrl;
1176
1177
1178 if (!display) {
1179 pr_err("Invalid params\n");
1180 return -EINVAL;
1181 }
1182
1183 if (mmss_clamp && !display->phy_idle_power_off) {
1184 dsi_display_phy_enable(display);
1185 return 0;
1186 }
1187
1188 m_ctrl = &display->ctrl[display->cmd_master_idx];
1189 rc = dsi_phy_idle_ctrl(m_ctrl->phy, true);
1190 if (rc) {
1191 pr_err("DSI controller setup failed\n");
1192 return rc;
1193 }
1194
1195 for (i = 0; i < display->ctrl_count; i++) {
1196 ctrl = &display->ctrl[i];
1197 if (!ctrl->ctrl || (ctrl == m_ctrl))
1198 continue;
1199
1200 rc = dsi_phy_idle_ctrl(ctrl->phy, true);
1201 if (rc) {
1202 pr_err("DSI controller setup failed\n");
1203 return rc;
1204 }
1205 }
1206 display->phy_idle_power_off = false;
1207 return 0;
1208}
1209
1210/**
1211 * dsi_display_phy_idle_off() - disable DSI PHY while going to idle screen.
1212 * @dsi_display: DSI display handle.
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301213 *
1214 * Return: error code.
1215 */
1216static int dsi_display_phy_idle_off(struct dsi_display *display)
1217{
1218 int rc = 0;
1219 int i = 0;
1220 struct dsi_display_ctrl *m_ctrl, *ctrl;
1221
1222 if (!display) {
1223 pr_err("Invalid params\n");
1224 return -EINVAL;
1225 }
1226
Alan Kwong797e0892017-10-17 09:37:24 -04001227 for (i = 0; i < display->ctrl_count; i++) {
1228 struct msm_dsi_phy *phy = display->ctrl[i].phy;
1229
1230 if (!phy)
1231 continue;
1232
1233 if (!phy->allow_phy_power_off) {
1234 pr_debug("phy doesn't support this feature\n");
1235 return 0;
1236 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301237 }
1238
1239 m_ctrl = &display->ctrl[display->cmd_master_idx];
1240
1241 rc = dsi_phy_idle_ctrl(m_ctrl->phy, false);
1242 if (rc) {
1243 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
1244 display->name, rc);
1245 return rc;
1246 }
1247
1248 for (i = 0; i < display->ctrl_count; i++) {
1249 ctrl = &display->ctrl[i];
1250 if (!ctrl->ctrl || (ctrl == m_ctrl))
1251 continue;
1252
1253 rc = dsi_phy_idle_ctrl(ctrl->phy, false);
1254 if (rc) {
1255 pr_err("DSI controller setup failed\n");
1256 return rc;
1257 }
1258 }
1259 display->phy_idle_power_off = true;
1260 return 0;
1261}
1262
Clarence Ip80ada7f2017-05-04 09:55:21 -07001263void dsi_display_enable_event(struct dsi_display *display,
1264 uint32_t event_idx, struct dsi_event_cb_info *event_info,
1265 bool enable)
1266{
1267 uint32_t irq_status_idx = DSI_STATUS_INTERRUPT_COUNT;
1268 int i;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301269
Clarence Ip80ada7f2017-05-04 09:55:21 -07001270 if (!display) {
1271 pr_err("invalid display\n");
1272 return;
1273 }
1274
1275 if (event_info)
1276 event_info->event_idx = event_idx;
1277
1278 switch (event_idx) {
1279 case SDE_CONN_EVENT_VID_DONE:
1280 irq_status_idx = DSI_SINT_VIDEO_MODE_FRAME_DONE;
1281 break;
1282 case SDE_CONN_EVENT_CMD_DONE:
1283 irq_status_idx = DSI_SINT_CMD_FRAME_DONE;
1284 break;
Sandeep Panda11b20d82017-06-19 12:57:27 +05301285 case SDE_CONN_EVENT_VID_FIFO_OVERFLOW:
1286 case SDE_CONN_EVENT_CMD_FIFO_UNDERFLOW:
1287 if (event_info) {
1288 for (i = 0; i < display->ctrl_count; i++)
1289 display->ctrl[i].ctrl->recovery_cb =
1290 *event_info;
1291 }
Clarence Ip80ada7f2017-05-04 09:55:21 -07001292 default:
1293 /* nothing to do */
1294 pr_debug("[%s] unhandled event %d\n", display->name, event_idx);
1295 return;
1296 }
1297
1298 if (enable) {
1299 for (i = 0; i < display->ctrl_count; i++)
1300 dsi_ctrl_enable_status_interrupt(
1301 display->ctrl[i].ctrl, irq_status_idx,
1302 event_info);
1303 } else {
1304 for (i = 0; i < display->ctrl_count; i++)
1305 dsi_ctrl_disable_status_interrupt(
1306 display->ctrl[i].ctrl, irq_status_idx);
1307 }
1308}
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301309
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07001310/**
1311 * dsi_config_host_engine_state_for_cont_splash()- update host engine state
1312 * during continuous splash.
1313 * @display: Handle to dsi display
1314 *
1315 */
1316static void dsi_config_host_engine_state_for_cont_splash
1317 (struct dsi_display *display)
1318{
1319 int i;
1320 struct dsi_display_ctrl *ctrl;
1321 enum dsi_engine_state host_state = DSI_CTRL_ENGINE_ON;
1322
1323 /* Sequence does not matter for split dsi usecases */
1324 for (i = 0; i < display->ctrl_count; i++) {
1325 ctrl = &display->ctrl[i];
1326 if (!ctrl->ctrl)
1327 continue;
1328
1329 dsi_ctrl_update_host_engine_state_for_cont_splash(ctrl->ctrl,
1330 host_state);
1331 }
1332}
1333
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001334static int dsi_display_ctrl_power_on(struct dsi_display *display)
1335{
1336 int rc = 0;
1337 int i;
1338 struct dsi_display_ctrl *ctrl;
1339
1340 /* Sequence does not matter for split dsi usecases */
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001341 for (i = 0; i < display->ctrl_count; i++) {
1342 ctrl = &display->ctrl[i];
1343 if (!ctrl->ctrl)
1344 continue;
1345
1346 rc = dsi_ctrl_set_power_state(ctrl->ctrl,
1347 DSI_CTRL_POWER_VREG_ON);
1348 if (rc) {
1349 pr_err("[%s] Failed to set power state, rc=%d\n",
1350 ctrl->ctrl->name, rc);
1351 goto error;
1352 }
1353 }
1354
1355 return rc;
1356error:
1357 for (i = i - 1; i >= 0; i--) {
1358 ctrl = &display->ctrl[i];
1359 if (!ctrl->ctrl)
1360 continue;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301361 (void)dsi_ctrl_set_power_state(ctrl->ctrl,
1362 DSI_CTRL_POWER_VREG_OFF);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001363 }
1364 return rc;
1365}
1366
1367static int dsi_display_ctrl_power_off(struct dsi_display *display)
1368{
1369 int rc = 0;
1370 int i;
1371 struct dsi_display_ctrl *ctrl;
1372
1373 /* Sequence does not matter for split dsi usecases */
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001374 for (i = 0; i < display->ctrl_count; i++) {
1375 ctrl = &display->ctrl[i];
1376 if (!ctrl->ctrl)
1377 continue;
1378
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301379 rc = dsi_ctrl_set_power_state(ctrl->ctrl,
1380 DSI_CTRL_POWER_VREG_OFF);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001381 if (rc) {
1382 pr_err("[%s] Failed to power off, rc=%d\n",
1383 ctrl->ctrl->name, rc);
1384 goto error;
1385 }
1386 }
1387error:
1388 return rc;
1389}
1390
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07001391static void dsi_display_parse_cmdline_topology(struct dsi_display *display,
1392 unsigned int display_type)
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07001393{
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07001394 char *boot_str = NULL;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07001395 char *str = NULL;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07001396 unsigned long value;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07001397
1398 if (display_type >= MAX_DSI_ACTIVE_DISPLAY) {
1399 pr_err("display_type=%d not supported\n", display_type);
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07001400 return;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07001401 }
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07001402
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07001403 if (display_type == DSI_PRIMARY)
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07001404 boot_str = dsi_display_primary;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07001405 else
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07001406 boot_str = dsi_display_secondary;
1407
1408 str = strnstr(boot_str, ":config", strlen(boot_str));
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07001409 if (!str)
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07001410 return;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07001411
1412 if (kstrtol(str + strlen(":config"), INT_BASE_10,
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07001413 (unsigned long *)&value)) {
1414 pr_err("invalid config index override: %s\n", boot_str);
1415 return;
1416 }
1417 display->cmdline_topology = value;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07001418
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07001419 str = strnstr(boot_str, ":timing", strlen(boot_str));
1420 if (!str)
1421 return;
1422
1423 if (kstrtol(str + strlen(":timing"), INT_BASE_10,
1424 (unsigned long *)&value)) {
1425 pr_err("invalid timing index override: %s. resetting both timing and config\n",
1426 boot_str);
1427 display->cmdline_topology = NO_OVERRIDE;
1428 return;
1429 }
1430 display->cmdline_timing = value;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07001431}
1432
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07001433/**
1434 * dsi_display_name_compare()- compare whether DSI display name matches.
1435 * @node: Pointer to device node structure
1436 * @display_name: Name of display to validate
1437 *
1438 * Return: returns a bool specifying whether given display is active
1439 */
1440static bool dsi_display_name_compare(struct device_node *node,
1441 const char *display_name, int index)
1442{
1443 if (index >= MAX_DSI_ACTIVE_DISPLAY) {
1444 pr_err("Invalid Index\n");
1445 return false;
1446 }
1447
1448 if (boot_displays[index].boot_disp_en) {
1449 if (!(strcmp(&boot_displays[index].name[0], display_name))) {
1450 boot_displays[index].node = node;
1451 return true;
1452 }
1453 }
1454 return false;
1455}
1456
1457/**
1458 * dsi_display_parse_boot_display_selection()- Parse DSI boot display name
1459 *
1460 * Return: returns error status
1461 */
1462static int dsi_display_parse_boot_display_selection(void)
1463{
1464 char *pos = NULL;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07001465 char disp_buf[MAX_CMDLINE_PARAM_LEN] = {'\0'};
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07001466 int i, j, num_displays;
1467
1468 if (strlen(dsi_display_primary) == 0)
1469 return -EINVAL;
1470
1471 if ((strlen(dsi_display_secondary) > 0))
1472 num_displays = MAX_DSI_ACTIVE_DISPLAY;
1473 else {
1474 /*
1475 * Initialize secondary dsi variables
1476 * for the senario where dsi_display1
1477 * is null but dsi_display0 is valid
1478 */
1479
1480 /* Max number of displays will be one->only Primary */
1481 num_displays = 1;
1482 boot_displays[DSI_SECONDARY].is_primary = false;
1483 boot_displays[DSI_SECONDARY].name[0] = '\0';
1484 }
1485
1486 for (i = 0; i < num_displays; i++) {
1487 boot_displays[i].is_primary = false;
1488 if (i == DSI_PRIMARY) {
1489 strlcpy(disp_buf, &dsi_display_primary[0],
1490 sizeof(dsi_display_primary));
1491 pos = strnstr(disp_buf, ":",
1492 sizeof(dsi_display_primary));
1493 } else {
1494 strlcpy(disp_buf, &dsi_display_secondary[0],
1495 sizeof(dsi_display_secondary));
1496 pos = strnstr(disp_buf, ":",
1497 sizeof(dsi_display_secondary));
1498 }
1499 /* Use ':' as a delimiter to retrieve the display name */
1500 if (!pos) {
1501 pr_debug("display name[%s]is not valid\n", disp_buf);
1502 continue;
1503 }
1504
1505 for (j = 0; (disp_buf + j) < pos; j++)
1506 boot_displays[i].name[j] = *(disp_buf + j);
1507 boot_displays[i].name[j] = '\0';
1508
1509 if (i == DSI_PRIMARY) {
1510 boot_displays[i].is_primary = true;
1511 /* Currently, secondary DSI display is not supported */
1512 boot_displays[i].boot_disp_en = true;
1513 }
1514 }
1515 return 0;
1516}
1517
1518/**
1519 * validate_dsi_display_selection()- validate boot DSI display selection
1520 *
1521 * Return: returns true when both displays have unique configurations
1522 */
1523static bool validate_dsi_display_selection(void)
1524{
1525 int i, j;
1526 int rc = 0;
1527 int phy_count = 0;
1528 int ctrl_count = 0;
1529 int index = 0;
1530 bool ctrl_flags[MAX_DSI_ACTIVE_DISPLAY] = {false, false};
1531 bool phy_flags[MAX_DSI_ACTIVE_DISPLAY] = {false, false};
1532 struct device_node *node, *ctrl_node, *phy_node;
1533
1534 for (i = 0; i < MAX_DSI_ACTIVE_DISPLAY; i++) {
1535 node = boot_displays[i].node;
1536 ctrl_count = of_count_phandle_with_args(node, "qcom,dsi-ctrl",
1537 NULL);
1538
1539 for (j = 0; j < ctrl_count; j++) {
1540 ctrl_node = of_parse_phandle(node, "qcom,dsi-ctrl", j);
1541 rc = of_property_read_u32(ctrl_node, "cell-index",
1542 &index);
1543 of_node_put(ctrl_node);
1544 if (rc) {
1545 pr_err("cell index not set for ctrl_nodes\n");
1546 return false;
1547 }
1548 if (ctrl_flags[index])
1549 return false;
1550 ctrl_flags[index] = true;
1551 }
1552
1553 phy_count = of_count_phandle_with_args(node, "qcom,dsi-phy",
1554 NULL);
1555 for (j = 0; j < phy_count; j++) {
1556 phy_node = of_parse_phandle(node, "qcom,dsi-phy", j);
1557 rc = of_property_read_u32(phy_node, "cell-index",
1558 &index);
1559 of_node_put(phy_node);
1560 if (rc) {
1561 pr_err("cell index not set phy_nodes\n");
1562 return false;
1563 }
1564 if (phy_flags[index])
1565 return false;
1566 phy_flags[index] = true;
1567 }
1568 }
1569 return true;
1570}
1571
1572struct device_node *dsi_display_get_boot_display(int index)
1573{
1574
1575 pr_err("index = %d\n", index);
1576
1577 if (boot_displays[index].node)
1578 return boot_displays[index].node;
1579 else if ((index == (MAX_DSI_ACTIVE_DISPLAY - 1))
1580 && (default_active_node))
1581 return default_active_node;
1582 else
1583 return NULL;
1584}
1585
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001586static int dsi_display_phy_power_on(struct dsi_display *display)
1587{
1588 int rc = 0;
1589 int i;
1590 struct dsi_display_ctrl *ctrl;
1591
1592 /* Sequence does not matter for split dsi usecases */
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001593 for (i = 0; i < display->ctrl_count; i++) {
1594 ctrl = &display->ctrl[i];
1595 if (!ctrl->ctrl)
1596 continue;
1597
1598 rc = dsi_phy_set_power_state(ctrl->phy, true);
1599 if (rc) {
1600 pr_err("[%s] Failed to set power state, rc=%d\n",
1601 ctrl->phy->name, rc);
1602 goto error;
1603 }
1604 }
1605
1606 return rc;
1607error:
1608 for (i = i - 1; i >= 0; i--) {
1609 ctrl = &display->ctrl[i];
1610 if (!ctrl->phy)
1611 continue;
1612 (void)dsi_phy_set_power_state(ctrl->phy, false);
1613 }
1614 return rc;
1615}
1616
1617static int dsi_display_phy_power_off(struct dsi_display *display)
1618{
1619 int rc = 0;
1620 int i;
1621 struct dsi_display_ctrl *ctrl;
1622
1623 /* Sequence does not matter for split dsi usecases */
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001624 for (i = 0; i < display->ctrl_count; i++) {
1625 ctrl = &display->ctrl[i];
1626 if (!ctrl->phy)
1627 continue;
1628
1629 rc = dsi_phy_set_power_state(ctrl->phy, false);
1630 if (rc) {
1631 pr_err("[%s] Failed to power off, rc=%d\n",
1632 ctrl->ctrl->name, rc);
1633 goto error;
1634 }
1635 }
1636error:
1637 return rc;
1638}
1639
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301640static int dsi_display_set_clk_src(struct dsi_display *display)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001641{
1642 int rc = 0;
1643 int i;
1644 struct dsi_display_ctrl *m_ctrl, *ctrl;
1645
1646 /*
1647 * In case of split DSI usecases, the clock for master controller should
1648 * be enabled before the other controller. Master controller in the
1649 * clock context refers to the controller that sources the clock.
1650 */
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001651 m_ctrl = &display->ctrl[display->clk_master_idx];
1652
1653 rc = dsi_ctrl_set_clock_source(m_ctrl->ctrl,
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301654 &display->clock_info.src_clks);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001655 if (rc) {
1656 pr_err("[%s] failed to set source clocks for master, rc=%d\n",
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301657 display->name, rc);
1658 return rc;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001659 }
1660
1661 /* Turn on rest of the controllers */
1662 for (i = 0; i < display->ctrl_count; i++) {
1663 ctrl = &display->ctrl[i];
1664 if (!ctrl->ctrl || (ctrl == m_ctrl))
1665 continue;
1666
1667 rc = dsi_ctrl_set_clock_source(ctrl->ctrl,
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301668 &display->clock_info.src_clks);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001669 if (rc) {
1670 pr_err("[%s] failed to set source clocks, rc=%d\n",
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301671 display->name, rc);
1672 return rc;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001673 }
1674 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301675 return 0;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001676}
1677
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05301678static int dsi_display_phy_reset_config(struct dsi_display *display,
1679 bool enable)
1680{
1681 int rc = 0;
1682 int i;
1683 struct dsi_display_ctrl *ctrl;
1684
1685 for (i = 0 ; i < display->ctrl_count; i++) {
1686 ctrl = &display->ctrl[i];
1687 rc = dsi_ctrl_phy_reset_config(ctrl->ctrl, enable);
1688 if (rc) {
1689 pr_err("[%s] failed to %s phy reset, rc=%d\n",
1690 display->name, enable ? "mask" : "unmask", rc);
1691 return rc;
1692 }
1693 }
1694 return 0;
1695}
1696
Jeykumar Sankarana7c7bbe2017-05-31 18:12:05 -07001697static int dsi_display_ctrl_update(struct dsi_display *display)
1698{
1699 int rc = 0;
1700 int i;
1701 struct dsi_display_ctrl *ctrl;
1702
1703 for (i = 0 ; i < display->ctrl_count; i++) {
1704 ctrl = &display->ctrl[i];
1705 rc = dsi_ctrl_host_timing_update(ctrl->ctrl);
1706 if (rc) {
1707 pr_err("[%s] failed to update host_%d, rc=%d\n",
1708 display->name, i, rc);
1709 goto error_host_deinit;
1710 }
1711 }
1712
1713 return 0;
1714error_host_deinit:
1715 for (i = i - 1; i >= 0; i--) {
1716 ctrl = &display->ctrl[i];
1717 (void)dsi_ctrl_host_deinit(ctrl->ctrl);
1718 }
1719
1720 return rc;
1721}
1722
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001723static int dsi_display_ctrl_init(struct dsi_display *display)
1724{
1725 int rc = 0;
1726 int i;
1727 struct dsi_display_ctrl *ctrl;
1728
1729 for (i = 0 ; i < display->ctrl_count; i++) {
1730 ctrl = &display->ctrl[i];
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07001731 rc = dsi_ctrl_host_init(ctrl->ctrl,
1732 display->is_cont_splash_enabled);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001733 if (rc) {
1734 pr_err("[%s] failed to init host_%d, rc=%d\n",
1735 display->name, i, rc);
1736 goto error_host_deinit;
1737 }
1738 }
1739
1740 return 0;
1741error_host_deinit:
1742 for (i = i - 1; i >= 0; i--) {
1743 ctrl = &display->ctrl[i];
1744 (void)dsi_ctrl_host_deinit(ctrl->ctrl);
1745 }
1746 return rc;
1747}
1748
1749static int dsi_display_ctrl_deinit(struct dsi_display *display)
1750{
1751 int rc = 0;
1752 int i;
1753 struct dsi_display_ctrl *ctrl;
1754
1755 for (i = 0 ; i < display->ctrl_count; i++) {
1756 ctrl = &display->ctrl[i];
1757 rc = dsi_ctrl_host_deinit(ctrl->ctrl);
1758 if (rc) {
1759 pr_err("[%s] failed to deinit host_%d, rc=%d\n",
1760 display->name, i, rc);
1761 }
1762 }
1763
1764 return rc;
1765}
1766
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001767static int dsi_display_ctrl_host_enable(struct dsi_display *display)
1768{
1769 int rc = 0;
1770 int i;
1771 struct dsi_display_ctrl *m_ctrl, *ctrl;
1772
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07001773 /* Host engine states are already taken care for
1774 * continuous splash case
1775 */
1776 if (display->is_cont_splash_enabled) {
1777 pr_debug("cont splash enabled, host enable not required\n");
1778 return 0;
1779 }
1780
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001781 m_ctrl = &display->ctrl[display->cmd_master_idx];
1782
1783 rc = dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON);
1784 if (rc) {
1785 pr_err("[%s] failed to enable host engine, rc=%d\n",
1786 display->name, rc);
1787 goto error;
1788 }
1789
1790 for (i = 0; i < display->ctrl_count; i++) {
1791 ctrl = &display->ctrl[i];
1792 if (!ctrl->ctrl || (ctrl == m_ctrl))
1793 continue;
1794
1795 rc = dsi_ctrl_set_host_engine_state(ctrl->ctrl,
1796 DSI_CTRL_ENGINE_ON);
1797 if (rc) {
1798 pr_err("[%s] failed to enable sl host engine, rc=%d\n",
1799 display->name, rc);
1800 goto error_disable_master;
1801 }
1802 }
1803
1804 return rc;
1805error_disable_master:
1806 (void)dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
1807error:
1808 return rc;
1809}
1810
1811static int dsi_display_ctrl_host_disable(struct dsi_display *display)
1812{
1813 int rc = 0;
1814 int i;
1815 struct dsi_display_ctrl *m_ctrl, *ctrl;
1816
1817 m_ctrl = &display->ctrl[display->cmd_master_idx];
1818 for (i = 0; i < display->ctrl_count; i++) {
1819 ctrl = &display->ctrl[i];
1820 if (!ctrl->ctrl || (ctrl == m_ctrl))
1821 continue;
1822
1823 rc = dsi_ctrl_set_host_engine_state(ctrl->ctrl,
1824 DSI_CTRL_ENGINE_OFF);
1825 if (rc)
1826 pr_err("[%s] failed to disable host engine, rc=%d\n",
1827 display->name, rc);
1828 }
1829
1830 rc = dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
1831 if (rc) {
1832 pr_err("[%s] failed to disable host engine, rc=%d\n",
1833 display->name, rc);
1834 goto error;
1835 }
1836
1837error:
1838 return rc;
1839}
1840
1841static int dsi_display_vid_engine_enable(struct dsi_display *display)
1842{
1843 int rc = 0;
1844 int i;
1845 struct dsi_display_ctrl *m_ctrl, *ctrl;
1846
1847 m_ctrl = &display->ctrl[display->video_master_idx];
1848
1849 rc = dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON);
1850 if (rc) {
1851 pr_err("[%s] failed to enable vid engine, rc=%d\n",
1852 display->name, rc);
1853 goto error;
1854 }
1855
1856 for (i = 0; i < display->ctrl_count; i++) {
1857 ctrl = &display->ctrl[i];
1858 if (!ctrl->ctrl || (ctrl == m_ctrl))
1859 continue;
1860
1861 rc = dsi_ctrl_set_vid_engine_state(ctrl->ctrl,
1862 DSI_CTRL_ENGINE_ON);
1863 if (rc) {
1864 pr_err("[%s] failed to enable vid engine, rc=%d\n",
1865 display->name, rc);
1866 goto error_disable_master;
1867 }
1868 }
1869
1870 return rc;
1871error_disable_master:
1872 (void)dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
1873error:
1874 return rc;
1875}
1876
1877static int dsi_display_vid_engine_disable(struct dsi_display *display)
1878{
1879 int rc = 0;
1880 int i;
1881 struct dsi_display_ctrl *m_ctrl, *ctrl;
1882
1883 m_ctrl = &display->ctrl[display->video_master_idx];
1884
1885 for (i = 0; i < display->ctrl_count; i++) {
1886 ctrl = &display->ctrl[i];
1887 if (!ctrl->ctrl || (ctrl == m_ctrl))
1888 continue;
1889
1890 rc = dsi_ctrl_set_vid_engine_state(ctrl->ctrl,
1891 DSI_CTRL_ENGINE_OFF);
1892 if (rc)
1893 pr_err("[%s] failed to disable vid engine, rc=%d\n",
1894 display->name, rc);
1895 }
1896
1897 rc = dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
1898 if (rc)
1899 pr_err("[%s] failed to disable mvid engine, rc=%d\n",
1900 display->name, rc);
1901
1902 return rc;
1903}
1904
1905static int dsi_display_phy_enable(struct dsi_display *display)
1906{
1907 int rc = 0;
1908 int i;
1909 struct dsi_display_ctrl *m_ctrl, *ctrl;
1910 enum dsi_phy_pll_source m_src = DSI_PLL_SOURCE_STANDALONE;
1911
1912 m_ctrl = &display->ctrl[display->clk_master_idx];
1913 if (display->ctrl_count > 1)
1914 m_src = DSI_PLL_SOURCE_NATIVE;
1915
1916 rc = dsi_phy_enable(m_ctrl->phy,
1917 &display->config,
1918 m_src,
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07001919 true,
1920 display->is_cont_splash_enabled);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001921 if (rc) {
1922 pr_err("[%s] failed to enable DSI PHY, rc=%d\n",
1923 display->name, rc);
1924 goto error;
1925 }
1926
1927 for (i = 0; i < display->ctrl_count; i++) {
1928 ctrl = &display->ctrl[i];
1929 if (!ctrl->ctrl || (ctrl == m_ctrl))
1930 continue;
1931
1932 rc = dsi_phy_enable(ctrl->phy,
1933 &display->config,
1934 DSI_PLL_SOURCE_NON_NATIVE,
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07001935 true,
1936 display->is_cont_splash_enabled);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001937 if (rc) {
1938 pr_err("[%s] failed to enable DSI PHY, rc=%d\n",
1939 display->name, rc);
1940 goto error_disable_master;
1941 }
1942 }
1943
1944 return rc;
1945
1946error_disable_master:
1947 (void)dsi_phy_disable(m_ctrl->phy);
1948error:
1949 return rc;
1950}
1951
1952static int dsi_display_phy_disable(struct dsi_display *display)
1953{
1954 int rc = 0;
1955 int i;
1956 struct dsi_display_ctrl *m_ctrl, *ctrl;
1957
1958 m_ctrl = &display->ctrl[display->clk_master_idx];
1959
1960 for (i = 0; i < display->ctrl_count; i++) {
1961 ctrl = &display->ctrl[i];
1962 if (!ctrl->ctrl || (ctrl == m_ctrl))
1963 continue;
1964
1965 rc = dsi_phy_disable(ctrl->phy);
1966 if (rc)
1967 pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
1968 display->name, rc);
1969 }
1970
1971 rc = dsi_phy_disable(m_ctrl->phy);
1972 if (rc)
1973 pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
1974 display->name, rc);
1975
1976 return rc;
1977}
1978
1979static int dsi_display_wake_up(struct dsi_display *display)
1980{
1981 return 0;
1982}
1983
1984static int dsi_display_broadcast_cmd(struct dsi_display *display,
1985 const struct mipi_dsi_msg *msg)
1986{
1987 int rc = 0;
1988 u32 flags, m_flags;
1989 struct dsi_display_ctrl *ctrl, *m_ctrl;
1990 int i;
1991
1992 m_flags = (DSI_CTRL_CMD_BROADCAST | DSI_CTRL_CMD_BROADCAST_MASTER |
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07001993 DSI_CTRL_CMD_DEFER_TRIGGER | DSI_CTRL_CMD_FETCH_MEMORY);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001994 flags = (DSI_CTRL_CMD_BROADCAST | DSI_CTRL_CMD_DEFER_TRIGGER |
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07001995 DSI_CTRL_CMD_FETCH_MEMORY);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001996
Vara Reddy326612b2017-09-20 04:41:10 -07001997 if ((msg->flags & MIPI_DSI_MSG_LASTCOMMAND)) {
1998 flags |= DSI_CTRL_CMD_LAST_COMMAND;
1999 m_flags |= DSI_CTRL_CMD_LAST_COMMAND;
2000 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002001 /*
2002 * 1. Setup commands in FIFO
2003 * 2. Trigger commands
2004 */
2005 m_ctrl = &display->ctrl[display->cmd_master_idx];
2006 rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, msg, m_flags);
2007 if (rc) {
2008 pr_err("[%s] cmd transfer failed on master,rc=%d\n",
2009 display->name, rc);
2010 goto error;
2011 }
2012
2013 for (i = 0; i < display->ctrl_count; i++) {
2014 ctrl = &display->ctrl[i];
2015 if (ctrl == m_ctrl)
2016 continue;
2017
2018 rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, msg, flags);
2019 if (rc) {
2020 pr_err("[%s] cmd transfer failed, rc=%d\n",
2021 display->name, rc);
2022 goto error;
2023 }
2024
Clarence Ip80ada7f2017-05-04 09:55:21 -07002025 rc = dsi_ctrl_cmd_tx_trigger(ctrl->ctrl, flags);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002026 if (rc) {
2027 pr_err("[%s] cmd trigger failed, rc=%d\n",
2028 display->name, rc);
2029 goto error;
2030 }
2031 }
2032
Clarence Ip80ada7f2017-05-04 09:55:21 -07002033 rc = dsi_ctrl_cmd_tx_trigger(m_ctrl->ctrl, m_flags);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002034 if (rc) {
2035 pr_err("[%s] cmd trigger failed for master, rc=%d\n",
2036 display->name, rc);
2037 goto error;
2038 }
2039
2040error:
2041 return rc;
2042}
2043
2044static int dsi_display_phy_sw_reset(struct dsi_display *display)
2045{
2046 int rc = 0;
2047 int i;
2048 struct dsi_display_ctrl *m_ctrl, *ctrl;
2049
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07002050 /* For continuous splash use case ctrl states are updated
2051 * separately and hence we do an early return
2052 */
2053 if (display->is_cont_splash_enabled) {
2054 pr_debug("cont splash enabled, phy sw reset not required\n");
2055 return 0;
2056 }
2057
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002058 m_ctrl = &display->ctrl[display->cmd_master_idx];
2059
2060 rc = dsi_ctrl_phy_sw_reset(m_ctrl->ctrl);
2061 if (rc) {
2062 pr_err("[%s] failed to reset phy, rc=%d\n", display->name, rc);
2063 goto error;
2064 }
2065
2066 for (i = 0; i < display->ctrl_count; i++) {
2067 ctrl = &display->ctrl[i];
2068 if (!ctrl->ctrl || (ctrl == m_ctrl))
2069 continue;
2070
2071 rc = dsi_ctrl_phy_sw_reset(ctrl->ctrl);
2072 if (rc) {
2073 pr_err("[%s] failed to reset phy, rc=%d\n",
2074 display->name, rc);
2075 goto error;
2076 }
2077 }
2078
2079error:
2080 return rc;
2081}
2082
2083static int dsi_host_attach(struct mipi_dsi_host *host,
2084 struct mipi_dsi_device *dsi)
2085{
2086 return 0;
2087}
2088
2089static int dsi_host_detach(struct mipi_dsi_host *host,
2090 struct mipi_dsi_device *dsi)
2091{
2092 return 0;
2093}
2094
2095static ssize_t dsi_host_transfer(struct mipi_dsi_host *host,
2096 const struct mipi_dsi_msg *msg)
2097{
2098 struct dsi_display *display = to_dsi_display(host);
Vara Reddyff9f4eb2017-11-22 16:15:12 -08002099 int rc = 0;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002100
2101 if (!host || !msg) {
2102 pr_err("Invalid params\n");
2103 return 0;
2104 }
2105
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302106 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
2107 DSI_ALL_CLKS, DSI_CLK_ON);
2108 if (rc) {
2109 pr_err("[%s] failed to enable all DSI clocks, rc=%d\n",
2110 display->name, rc);
2111 goto error;
2112 }
2113
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002114 rc = dsi_display_wake_up(display);
2115 if (rc) {
2116 pr_err("[%s] failed to wake up display, rc=%d\n",
2117 display->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302118 goto error_disable_clks;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002119 }
2120
2121 rc = dsi_display_cmd_engine_enable(display);
2122 if (rc) {
2123 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
2124 display->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302125 goto error_disable_clks;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002126 }
2127
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07002128 if (display->tx_cmd_buf == NULL) {
Vara Reddyff9f4eb2017-11-22 16:15:12 -08002129 rc = dsi_host_alloc_cmd_tx_buffer(display);
2130 if (rc) {
2131 pr_err("failed to allocate cmd tx buffer memory\n");
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07002132 goto error_disable_cmd_engine;
2133 }
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07002134 }
2135
Lloyd Atkinson1fde2282017-02-02 16:30:00 -05002136 if (display->ctrl_count > 1 && !(msg->flags & MIPI_DSI_MSG_UNICAST)) {
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002137 rc = dsi_display_broadcast_cmd(display, msg);
2138 if (rc) {
2139 pr_err("[%s] cmd broadcast failed, rc=%d\n",
2140 display->name, rc);
2141 goto error_disable_cmd_engine;
2142 }
2143 } else {
Lloyd Atkinson1fde2282017-02-02 16:30:00 -05002144 int ctrl_idx = (msg->flags & MIPI_DSI_MSG_UNICAST) ?
2145 msg->ctrl : 0;
2146
2147 rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg,
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07002148 DSI_CTRL_CMD_FETCH_MEMORY);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002149 if (rc) {
2150 pr_err("[%s] cmd transfer failed, rc=%d\n",
2151 display->name, rc);
2152 goto error_disable_cmd_engine;
2153 }
2154 }
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07002155
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002156error_disable_cmd_engine:
2157 (void)dsi_display_cmd_engine_disable(display);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302158error_disable_clks:
2159 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
2160 DSI_ALL_CLKS, DSI_CLK_OFF);
2161 if (rc) {
Vara Reddy0fe16842017-06-01 18:42:45 -07002162 pr_err("[%s] failed to disable all DSI clocks, rc=%d\n",
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302163 display->name, rc);
2164 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002165error:
2166 return rc;
2167}
2168
2169
2170static struct mipi_dsi_host_ops dsi_host_ops = {
2171 .attach = dsi_host_attach,
2172 .detach = dsi_host_detach,
2173 .transfer = dsi_host_transfer,
2174};
2175
2176static int dsi_display_mipi_host_init(struct dsi_display *display)
2177{
2178 int rc = 0;
2179 struct mipi_dsi_host *host = &display->host;
2180
2181 host->dev = &display->pdev->dev;
2182 host->ops = &dsi_host_ops;
2183
2184 rc = mipi_dsi_host_register(host);
2185 if (rc) {
2186 pr_err("[%s] failed to register mipi dsi host, rc=%d\n",
2187 display->name, rc);
2188 goto error;
2189 }
2190
2191error:
2192 return rc;
2193}
2194static int dsi_display_mipi_host_deinit(struct dsi_display *display)
2195{
2196 int rc = 0;
2197 struct mipi_dsi_host *host = &display->host;
2198
2199 mipi_dsi_host_unregister(host);
2200
2201 host->dev = NULL;
2202 host->ops = NULL;
2203
2204 return rc;
2205}
2206
2207static int dsi_display_clocks_deinit(struct dsi_display *display)
2208{
2209 int rc = 0;
2210 struct dsi_clk_link_set *src = &display->clock_info.src_clks;
2211 struct dsi_clk_link_set *mux = &display->clock_info.mux_clks;
2212 struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks;
2213
2214 if (src->byte_clk) {
2215 devm_clk_put(&display->pdev->dev, src->byte_clk);
2216 src->byte_clk = NULL;
2217 }
2218
2219 if (src->pixel_clk) {
2220 devm_clk_put(&display->pdev->dev, src->pixel_clk);
2221 src->pixel_clk = NULL;
2222 }
2223
2224 if (mux->byte_clk) {
2225 devm_clk_put(&display->pdev->dev, mux->byte_clk);
2226 mux->byte_clk = NULL;
2227 }
2228
2229 if (mux->pixel_clk) {
2230 devm_clk_put(&display->pdev->dev, mux->pixel_clk);
2231 mux->pixel_clk = NULL;
2232 }
2233
2234 if (shadow->byte_clk) {
2235 devm_clk_put(&display->pdev->dev, shadow->byte_clk);
2236 shadow->byte_clk = NULL;
2237 }
2238
2239 if (shadow->pixel_clk) {
2240 devm_clk_put(&display->pdev->dev, shadow->pixel_clk);
2241 shadow->pixel_clk = NULL;
2242 }
2243
2244 return rc;
2245}
2246
2247static int dsi_display_clocks_init(struct dsi_display *display)
2248{
2249 int rc = 0;
2250 struct dsi_clk_link_set *src = &display->clock_info.src_clks;
2251 struct dsi_clk_link_set *mux = &display->clock_info.mux_clks;
2252 struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks;
2253
2254 src->byte_clk = devm_clk_get(&display->pdev->dev, "src_byte_clk");
2255 if (IS_ERR_OR_NULL(src->byte_clk)) {
2256 rc = PTR_ERR(src->byte_clk);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04002257 src->byte_clk = NULL;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002258 pr_err("failed to get src_byte_clk, rc=%d\n", rc);
2259 goto error;
2260 }
2261
2262 src->pixel_clk = devm_clk_get(&display->pdev->dev, "src_pixel_clk");
2263 if (IS_ERR_OR_NULL(src->pixel_clk)) {
2264 rc = PTR_ERR(src->pixel_clk);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04002265 src->pixel_clk = NULL;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002266 pr_err("failed to get src_pixel_clk, rc=%d\n", rc);
2267 goto error;
2268 }
2269
2270 mux->byte_clk = devm_clk_get(&display->pdev->dev, "mux_byte_clk");
2271 if (IS_ERR_OR_NULL(mux->byte_clk)) {
2272 rc = PTR_ERR(mux->byte_clk);
Shashank Babu Chinta Venkatacf411332017-05-10 17:30:08 -07002273 pr_debug("failed to get mux_byte_clk, rc=%d\n", rc);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04002274 mux->byte_clk = NULL;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002275 /*
2276 * Skip getting rest of clocks since one failed. This is a
2277 * non-critical failure since these clocks are requied only for
2278 * dynamic refresh use cases.
2279 */
2280 rc = 0;
2281 goto done;
2282 };
2283
2284 mux->pixel_clk = devm_clk_get(&display->pdev->dev, "mux_pixel_clk");
2285 if (IS_ERR_OR_NULL(mux->pixel_clk)) {
2286 rc = PTR_ERR(mux->pixel_clk);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04002287 mux->pixel_clk = NULL;
Shashank Babu Chinta Venkatacf411332017-05-10 17:30:08 -07002288 pr_debug("failed to get mux_pixel_clk, rc=%d\n", rc);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002289 /*
2290 * Skip getting rest of clocks since one failed. This is a
2291 * non-critical failure since these clocks are requied only for
2292 * dynamic refresh use cases.
2293 */
2294 rc = 0;
2295 goto done;
2296 };
2297
2298 shadow->byte_clk = devm_clk_get(&display->pdev->dev, "shadow_byte_clk");
2299 if (IS_ERR_OR_NULL(shadow->byte_clk)) {
2300 rc = PTR_ERR(shadow->byte_clk);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04002301 shadow->byte_clk = NULL;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002302 pr_err("failed to get shadow_byte_clk, rc=%d\n", rc);
2303 /*
2304 * Skip getting rest of clocks since one failed. This is a
2305 * non-critical failure since these clocks are requied only for
2306 * dynamic refresh use cases.
2307 */
2308 rc = 0;
2309 goto done;
2310 };
2311
2312 shadow->pixel_clk = devm_clk_get(&display->pdev->dev,
2313 "shadow_pixel_clk");
2314 if (IS_ERR_OR_NULL(shadow->pixel_clk)) {
2315 rc = PTR_ERR(shadow->pixel_clk);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04002316 shadow->pixel_clk = NULL;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002317 pr_err("failed to get shadow_pixel_clk, rc=%d\n", rc);
2318 /*
2319 * Skip getting rest of clocks since one failed. This is a
2320 * non-critical failure since these clocks are requied only for
2321 * dynamic refresh use cases.
2322 */
2323 rc = 0;
2324 goto done;
2325 };
2326
2327done:
2328 return 0;
2329error:
2330 (void)dsi_display_clocks_deinit(display);
2331 return rc;
2332}
2333
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302334static int dsi_display_clk_ctrl_cb(void *priv,
2335 struct dsi_clk_ctrl_info clk_state_info)
2336{
2337 int rc = 0;
2338 struct dsi_display *display = NULL;
2339 void *clk_handle = NULL;
2340
2341 if (!priv) {
2342 pr_err("Invalid params\n");
2343 return -EINVAL;
2344 }
2345
2346 display = priv;
2347
2348 if (clk_state_info.client == DSI_CLK_REQ_MDP_CLIENT) {
2349 clk_handle = display->mdp_clk_handle;
2350 } else if (clk_state_info.client == DSI_CLK_REQ_DSI_CLIENT) {
2351 clk_handle = display->dsi_clk_handle;
2352 } else {
2353 pr_err("invalid clk handle, return error\n");
2354 return -EINVAL;
2355 }
2356
2357 /*
2358 * TODO: Wait for CMD_MDP_DONE interrupt if MDP client tries
2359 * to turn off DSI clocks.
2360 */
2361 rc = dsi_display_clk_ctrl(clk_handle,
2362 clk_state_info.clk_type, clk_state_info.clk_state);
2363 if (rc) {
2364 pr_err("[%s] failed to %d DSI %d clocks, rc=%d\n",
2365 display->name, clk_state_info.clk_state,
2366 clk_state_info.clk_type, rc);
2367 return rc;
2368 }
2369 return 0;
2370}
2371
2372int dsi_pre_clkoff_cb(void *priv,
2373 enum dsi_clk_type clk,
2374 enum dsi_clk_state new_state)
2375{
2376 int rc = 0;
2377 struct dsi_display *display = priv;
2378
2379 if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF)) {
2380 /*
2381 * If ULPS feature is enabled, enter ULPS first.
Lei Chen529da982017-10-24 16:23:42 +08002382 * However, when blanking the panel, we should enter ULPS
2383 * only if ULPS during suspend feature is enabled.
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302384 */
Lei Chen529da982017-10-24 16:23:42 +08002385 if (!dsi_panel_initialized(display->panel)) {
2386 if (display->panel->ulps_suspend_enabled)
2387 rc = dsi_display_set_ulps(display, true);
2388 } else if (dsi_panel_ulps_feature_enabled(display->panel)) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302389 rc = dsi_display_set_ulps(display, true);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302390 }
Lei Chen529da982017-10-24 16:23:42 +08002391 if (rc)
2392 pr_err("%s: failed enable ulps, rc = %d\n",
2393 __func__, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302394 }
2395
2396 if ((clk & DSI_CORE_CLK) && (new_state == DSI_CLK_OFF)) {
2397 /*
Lei Chen529da982017-10-24 16:23:42 +08002398 * Enable DSI clamps only if entering idle power collapse or
2399 * when ULPS during suspend is enabled..
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302400 */
Lei Chen529da982017-10-24 16:23:42 +08002401 if (dsi_panel_initialized(display->panel) ||
2402 display->panel->ulps_suspend_enabled) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302403 dsi_display_phy_idle_off(display);
2404 rc = dsi_display_set_clamp(display, true);
2405 if (rc)
2406 pr_err("%s: Failed to enable dsi clamps. rc=%d\n",
2407 __func__, rc);
Veera Sundaram Sankaran518a8632017-05-01 16:37:55 -07002408
2409 rc = dsi_display_phy_reset_config(display, false);
2410 if (rc)
2411 pr_err("%s: Failed to reset phy, rc=%d\n",
2412 __func__, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302413 } else {
2414 /* Make sure that controller is not in ULPS state when
2415 * the DSI link is not active.
2416 */
2417 rc = dsi_display_set_ulps(display, false);
2418 if (rc)
2419 pr_err("%s: failed to disable ulps. rc=%d\n",
2420 __func__, rc);
2421 }
2422 }
2423
2424 return rc;
2425}
2426
2427int dsi_post_clkon_cb(void *priv,
2428 enum dsi_clk_type clk,
2429 enum dsi_clk_state curr_state)
2430{
2431 int rc = 0;
2432 struct dsi_display *display = priv;
2433 bool mmss_clamp = false;
2434
2435 if (clk & DSI_CORE_CLK) {
2436 mmss_clamp = display->clamp_enabled;
2437 /*
2438 * controller setup is needed if coming out of idle
2439 * power collapse with clamps enabled.
2440 */
2441 if (mmss_clamp)
2442 dsi_display_ctrl_setup(display);
2443
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302444 if (display->ulps_enabled && mmss_clamp) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302445 /*
2446 * ULPS Entry Request. This is needed if the lanes were
2447 * in ULPS prior to power collapse, since after
2448 * power collapse and reset, the DSI controller resets
2449 * back to idle state and not ULPS. This ulps entry
2450 * request will transition the state of the DSI
2451 * controller to ULPS which will match the state of the
2452 * DSI phy. This needs to be done prior to disabling
2453 * the DSI clamps.
2454 *
2455 * Also, reset the ulps flag so that ulps_config
2456 * function would reconfigure the controller state to
2457 * ULPS.
2458 */
2459 display->ulps_enabled = false;
2460 rc = dsi_display_set_ulps(display, true);
2461 if (rc) {
2462 pr_err("%s: Failed to enter ULPS. rc=%d\n",
2463 __func__, rc);
2464 goto error;
2465 }
2466 }
2467
Veera Sundaram Sankaran518a8632017-05-01 16:37:55 -07002468 rc = dsi_display_phy_reset_config(display, true);
2469 if (rc) {
2470 pr_err("%s: Failed to reset phy, rc=%d\n",
2471 __func__, rc);
2472 goto error;
2473 }
2474
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302475 rc = dsi_display_set_clamp(display, false);
2476 if (rc) {
2477 pr_err("%s: Failed to disable dsi clamps. rc=%d\n",
2478 __func__, rc);
2479 goto error;
2480 }
2481
2482 /*
2483 * Phy setup is needed if coming out of idle
2484 * power collapse with clamps enabled.
2485 */
2486 if (display->phy_idle_power_off || mmss_clamp)
2487 dsi_display_phy_idle_on(display, mmss_clamp);
2488 }
2489 if (clk & DSI_LINK_CLK) {
2490 if (display->ulps_enabled) {
2491 rc = dsi_display_set_ulps(display, false);
2492 if (rc) {
2493 pr_err("%s: failed to disable ulps, rc= %d\n",
2494 __func__, rc);
2495 goto error;
2496 }
2497 }
2498 }
2499error:
2500 return rc;
2501}
2502
2503int dsi_post_clkoff_cb(void *priv,
2504 enum dsi_clk_type clk_type,
2505 enum dsi_clk_state curr_state)
2506{
2507 int rc = 0;
2508 struct dsi_display *display = priv;
2509
2510 if (!display) {
2511 pr_err("%s: Invalid arg\n", __func__);
2512 return -EINVAL;
2513 }
2514
2515 if ((clk_type & DSI_CORE_CLK) &&
2516 (curr_state == DSI_CLK_OFF)) {
2517
2518 rc = dsi_display_phy_power_off(display);
2519 if (rc)
2520 pr_err("[%s] failed to power off PHY, rc=%d\n",
2521 display->name, rc);
2522
2523 rc = dsi_display_ctrl_power_off(display);
2524 if (rc)
2525 pr_err("[%s] failed to power DSI vregs, rc=%d\n",
2526 display->name, rc);
2527 }
2528 return rc;
2529}
2530
2531int dsi_pre_clkon_cb(void *priv,
2532 enum dsi_clk_type clk_type,
2533 enum dsi_clk_state new_state)
2534{
2535 int rc = 0;
2536 struct dsi_display *display = priv;
2537
2538 if (!display) {
2539 pr_err("%s: invalid input\n", __func__);
2540 return -EINVAL;
2541 }
2542
2543 if ((clk_type & DSI_CORE_CLK) && (new_state == DSI_CLK_ON)) {
2544 /*
2545 * Enable DSI core power
2546 * 1.> PANEL_PM are controlled as part of
2547 * panel_power_ctrl. Needed not be handled here.
2548 * 2.> CORE_PM are controlled by dsi clk manager.
2549 * 3.> CTRL_PM need to be enabled/disabled
2550 * only during unblank/blank. Their state should
2551 * not be changed during static screen.
2552 */
2553
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07002554 pr_debug("updating power states for ctrl and phy\n");
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302555 rc = dsi_display_ctrl_power_on(display);
2556 if (rc) {
2557 pr_err("[%s] failed to power on dsi controllers, rc=%d\n",
2558 display->name, rc);
2559 return rc;
2560 }
2561
2562 rc = dsi_display_phy_power_on(display);
2563 if (rc) {
2564 pr_err("[%s] failed to power on dsi phy, rc = %d\n",
2565 display->name, rc);
2566 return rc;
2567 }
2568
2569 pr_debug("%s: Enable DSI core power\n", __func__);
2570 }
2571
2572 return rc;
2573}
2574
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302575static void __set_lane_map_v2(u8 *lane_map_v2,
2576 enum dsi_phy_data_lanes lane0,
2577 enum dsi_phy_data_lanes lane1,
2578 enum dsi_phy_data_lanes lane2,
2579 enum dsi_phy_data_lanes lane3)
2580{
2581 lane_map_v2[DSI_LOGICAL_LANE_0] = lane0;
2582 lane_map_v2[DSI_LOGICAL_LANE_1] = lane1;
2583 lane_map_v2[DSI_LOGICAL_LANE_2] = lane2;
2584 lane_map_v2[DSI_LOGICAL_LANE_3] = lane3;
2585}
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302586
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002587static int dsi_display_parse_lane_map(struct dsi_display *display)
2588{
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302589 int rc = 0, i = 0;
2590 const char *data;
2591 u8 temp[DSI_LANE_MAX - 1];
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002592
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302593 if (!display) {
2594 pr_err("invalid params\n");
2595 return -EINVAL;
2596 }
2597
2598 /* lane-map-v2 supersedes lane-map-v1 setting */
2599 rc = of_property_read_u8_array(display->pdev->dev.of_node,
2600 "qcom,lane-map-v2", temp, (DSI_LANE_MAX - 1));
2601 if (!rc) {
2602 for (i = DSI_LOGICAL_LANE_0; i < (DSI_LANE_MAX - 1); i++)
2603 display->lane_map.lane_map_v2[i] = BIT(temp[i]);
2604 return 0;
2605 } else if (rc != EINVAL) {
Shashank Babu Chinta Venkatacf411332017-05-10 17:30:08 -07002606 pr_debug("Incorrect mapping, configure default\n");
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302607 goto set_default;
2608 }
2609
2610 /* lane-map older version, for DSI controller version < 2.0 */
2611 data = of_get_property(display->pdev->dev.of_node,
2612 "qcom,lane-map", NULL);
2613 if (!data)
2614 goto set_default;
2615
2616 if (!strcmp(data, "lane_map_3012")) {
2617 display->lane_map.lane_map_v1 = DSI_LANE_MAP_3012;
2618 __set_lane_map_v2(display->lane_map.lane_map_v2,
2619 DSI_PHYSICAL_LANE_1,
2620 DSI_PHYSICAL_LANE_2,
2621 DSI_PHYSICAL_LANE_3,
2622 DSI_PHYSICAL_LANE_0);
2623 } else if (!strcmp(data, "lane_map_2301")) {
2624 display->lane_map.lane_map_v1 = DSI_LANE_MAP_2301;
2625 __set_lane_map_v2(display->lane_map.lane_map_v2,
2626 DSI_PHYSICAL_LANE_2,
2627 DSI_PHYSICAL_LANE_3,
2628 DSI_PHYSICAL_LANE_0,
2629 DSI_PHYSICAL_LANE_1);
2630 } else if (!strcmp(data, "lane_map_1230")) {
2631 display->lane_map.lane_map_v1 = DSI_LANE_MAP_1230;
2632 __set_lane_map_v2(display->lane_map.lane_map_v2,
2633 DSI_PHYSICAL_LANE_3,
2634 DSI_PHYSICAL_LANE_0,
2635 DSI_PHYSICAL_LANE_1,
2636 DSI_PHYSICAL_LANE_2);
2637 } else if (!strcmp(data, "lane_map_0321")) {
2638 display->lane_map.lane_map_v1 = DSI_LANE_MAP_0321;
2639 __set_lane_map_v2(display->lane_map.lane_map_v2,
2640 DSI_PHYSICAL_LANE_0,
2641 DSI_PHYSICAL_LANE_3,
2642 DSI_PHYSICAL_LANE_2,
2643 DSI_PHYSICAL_LANE_1);
2644 } else if (!strcmp(data, "lane_map_1032")) {
2645 display->lane_map.lane_map_v1 = DSI_LANE_MAP_1032;
2646 __set_lane_map_v2(display->lane_map.lane_map_v2,
2647 DSI_PHYSICAL_LANE_1,
2648 DSI_PHYSICAL_LANE_0,
2649 DSI_PHYSICAL_LANE_3,
2650 DSI_PHYSICAL_LANE_2);
2651 } else if (!strcmp(data, "lane_map_2103")) {
2652 display->lane_map.lane_map_v1 = DSI_LANE_MAP_2103;
2653 __set_lane_map_v2(display->lane_map.lane_map_v2,
2654 DSI_PHYSICAL_LANE_2,
2655 DSI_PHYSICAL_LANE_1,
2656 DSI_PHYSICAL_LANE_0,
2657 DSI_PHYSICAL_LANE_3);
2658 } else if (!strcmp(data, "lane_map_3210")) {
2659 display->lane_map.lane_map_v1 = DSI_LANE_MAP_3210;
2660 __set_lane_map_v2(display->lane_map.lane_map_v2,
2661 DSI_PHYSICAL_LANE_3,
2662 DSI_PHYSICAL_LANE_2,
2663 DSI_PHYSICAL_LANE_1,
2664 DSI_PHYSICAL_LANE_0);
2665 } else {
2666 pr_warn("%s: invalid lane map %s specified. defaulting to lane_map0123\n",
2667 __func__, data);
2668 goto set_default;
2669 }
2670 return 0;
2671
2672set_default:
2673 /* default lane mapping */
2674 __set_lane_map_v2(display->lane_map.lane_map_v2, DSI_PHYSICAL_LANE_0,
2675 DSI_PHYSICAL_LANE_1, DSI_PHYSICAL_LANE_2, DSI_PHYSICAL_LANE_3);
2676 display->lane_map.lane_map_v1 = DSI_LANE_MAP_0123;
2677 return 0;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002678}
2679
2680static int dsi_display_parse_dt(struct dsi_display *display)
2681{
2682 int rc = 0;
2683 int i;
2684 u32 phy_count = 0;
2685 struct device_node *of_node;
2686
2687 /* Parse controllers */
2688 for (i = 0; i < MAX_DSI_CTRLS_PER_DISPLAY; i++) {
2689 of_node = of_parse_phandle(display->pdev->dev.of_node,
2690 "qcom,dsi-ctrl", i);
2691 if (!of_node) {
2692 if (!i) {
2693 pr_err("No controllers present\n");
2694 return -ENODEV;
2695 }
2696 break;
2697 }
2698
2699 display->ctrl[i].ctrl_of_node = of_node;
2700 display->ctrl_count++;
2701 }
2702
2703 /* Parse Phys */
2704 for (i = 0; i < MAX_DSI_CTRLS_PER_DISPLAY; i++) {
2705 of_node = of_parse_phandle(display->pdev->dev.of_node,
2706 "qcom,dsi-phy", i);
2707 if (!of_node) {
2708 if (!i) {
2709 pr_err("No PHY devices present\n");
2710 rc = -ENODEV;
2711 goto error;
2712 }
2713 break;
2714 }
2715
2716 display->ctrl[i].phy_of_node = of_node;
2717 phy_count++;
2718 }
2719
2720 if (phy_count != display->ctrl_count) {
2721 pr_err("Number of controllers does not match PHYs\n");
2722 rc = -ENODEV;
2723 goto error;
2724 }
2725
2726 of_node = of_parse_phandle(display->pdev->dev.of_node,
2727 "qcom,dsi-panel", 0);
2728 if (!of_node) {
2729 pr_err("No Panel device present\n");
2730 rc = -ENODEV;
2731 goto error;
2732 } else {
2733 display->panel_of = of_node;
2734 }
2735
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002736error:
2737 return rc;
2738}
2739
2740static int dsi_display_res_init(struct dsi_display *display)
2741{
2742 int rc = 0;
2743 int i;
2744 struct dsi_display_ctrl *ctrl;
2745
2746 for (i = 0; i < display->ctrl_count; i++) {
2747 ctrl = &display->ctrl[i];
2748 ctrl->ctrl = dsi_ctrl_get(ctrl->ctrl_of_node);
2749 if (IS_ERR_OR_NULL(ctrl->ctrl)) {
2750 rc = PTR_ERR(ctrl->ctrl);
2751 pr_err("failed to get dsi controller, rc=%d\n", rc);
2752 ctrl->ctrl = NULL;
2753 goto error_ctrl_put;
2754 }
2755
2756 ctrl->phy = dsi_phy_get(ctrl->phy_of_node);
2757 if (IS_ERR_OR_NULL(ctrl->phy)) {
2758 rc = PTR_ERR(ctrl->phy);
2759 pr_err("failed to get phy controller, rc=%d\n", rc);
2760 dsi_ctrl_put(ctrl->ctrl);
2761 ctrl->phy = NULL;
2762 goto error_ctrl_put;
2763 }
2764 }
2765
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07002766 display->panel = dsi_panel_get(&display->pdev->dev, display->panel_of,
2767 display->cmdline_topology);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002768 if (IS_ERR_OR_NULL(display->panel)) {
2769 rc = PTR_ERR(display->panel);
2770 pr_err("failed to get panel, rc=%d\n", rc);
2771 display->panel = NULL;
2772 goto error_ctrl_put;
2773 }
2774
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302775 rc = dsi_display_parse_lane_map(display);
2776 if (rc) {
2777 pr_err("Lane map not found, rc=%d\n", rc);
2778 goto error_ctrl_put;
2779 }
2780
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002781 rc = dsi_display_clocks_init(display);
2782 if (rc) {
2783 pr_err("Failed to parse clock data, rc=%d\n", rc);
2784 goto error_ctrl_put;
2785 }
2786
2787 return 0;
2788error_ctrl_put:
2789 for (i = i - 1; i >= 0; i--) {
2790 ctrl = &display->ctrl[i];
2791 dsi_ctrl_put(ctrl->ctrl);
2792 dsi_phy_put(ctrl->phy);
2793 }
2794 return rc;
2795}
2796
2797static int dsi_display_res_deinit(struct dsi_display *display)
2798{
2799 int rc = 0;
2800 int i;
2801 struct dsi_display_ctrl *ctrl;
2802
2803 rc = dsi_display_clocks_deinit(display);
2804 if (rc)
2805 pr_err("clocks deinit failed, rc=%d\n", rc);
2806
2807 for (i = 0; i < display->ctrl_count; i++) {
2808 ctrl = &display->ctrl[i];
2809 dsi_phy_put(ctrl->phy);
2810 dsi_ctrl_put(ctrl->ctrl);
2811 }
2812
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07002813 if (display->panel)
2814 dsi_panel_put(display->panel);
2815
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002816 return rc;
2817}
2818
2819static int dsi_display_validate_mode_set(struct dsi_display *display,
2820 struct dsi_display_mode *mode,
2821 u32 flags)
2822{
2823 int rc = 0;
2824 int i;
2825 struct dsi_display_ctrl *ctrl;
2826
2827 /*
2828 * To set a mode:
2829 * 1. Controllers should be turned off.
2830 * 2. Link clocks should be off.
2831 * 3. Phy should be disabled.
2832 */
2833
2834 for (i = 0; i < display->ctrl_count; i++) {
2835 ctrl = &display->ctrl[i];
2836 if ((ctrl->power_state > DSI_CTRL_POWER_VREG_ON) ||
2837 (ctrl->phy_enabled)) {
2838 rc = -EINVAL;
2839 goto error;
2840 }
2841 }
2842
2843error:
2844 return rc;
2845}
2846
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002847static bool dsi_display_is_seamless_dfps_possible(
2848 const struct dsi_display *display,
2849 const struct dsi_display_mode *tgt,
2850 const enum dsi_dfps_type dfps_type)
2851{
2852 struct dsi_display_mode *cur;
2853
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07002854 if (!display || !tgt || !display->panel) {
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002855 pr_err("Invalid params\n");
2856 return false;
2857 }
2858
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07002859 cur = display->panel->cur_mode;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002860
2861 if (cur->timing.h_active != tgt->timing.h_active) {
2862 pr_debug("timing.h_active differs %d %d\n",
2863 cur->timing.h_active, tgt->timing.h_active);
2864 return false;
2865 }
2866
2867 if (cur->timing.h_back_porch != tgt->timing.h_back_porch) {
2868 pr_debug("timing.h_back_porch differs %d %d\n",
2869 cur->timing.h_back_porch,
2870 tgt->timing.h_back_porch);
2871 return false;
2872 }
2873
2874 if (cur->timing.h_sync_width != tgt->timing.h_sync_width) {
2875 pr_debug("timing.h_sync_width differs %d %d\n",
2876 cur->timing.h_sync_width,
2877 tgt->timing.h_sync_width);
2878 return false;
2879 }
2880
2881 if (cur->timing.h_front_porch != tgt->timing.h_front_porch) {
2882 pr_debug("timing.h_front_porch differs %d %d\n",
2883 cur->timing.h_front_porch,
2884 tgt->timing.h_front_porch);
2885 if (dfps_type != DSI_DFPS_IMMEDIATE_HFP)
2886 return false;
2887 }
2888
2889 if (cur->timing.h_skew != tgt->timing.h_skew) {
2890 pr_debug("timing.h_skew differs %d %d\n",
2891 cur->timing.h_skew,
2892 tgt->timing.h_skew);
2893 return false;
2894 }
2895
2896 /* skip polarity comparison */
2897
2898 if (cur->timing.v_active != tgt->timing.v_active) {
2899 pr_debug("timing.v_active differs %d %d\n",
2900 cur->timing.v_active,
2901 tgt->timing.v_active);
2902 return false;
2903 }
2904
2905 if (cur->timing.v_back_porch != tgt->timing.v_back_porch) {
2906 pr_debug("timing.v_back_porch differs %d %d\n",
2907 cur->timing.v_back_porch,
2908 tgt->timing.v_back_porch);
2909 return false;
2910 }
2911
2912 if (cur->timing.v_sync_width != tgt->timing.v_sync_width) {
2913 pr_debug("timing.v_sync_width differs %d %d\n",
2914 cur->timing.v_sync_width,
2915 tgt->timing.v_sync_width);
2916 return false;
2917 }
2918
2919 if (cur->timing.v_front_porch != tgt->timing.v_front_porch) {
2920 pr_debug("timing.v_front_porch differs %d %d\n",
2921 cur->timing.v_front_porch,
2922 tgt->timing.v_front_porch);
2923 if (dfps_type != DSI_DFPS_IMMEDIATE_VFP)
2924 return false;
2925 }
2926
2927 /* skip polarity comparison */
2928
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05002929 if (cur->timing.refresh_rate == tgt->timing.refresh_rate)
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002930 pr_debug("timing.refresh_rate identical %d %d\n",
2931 cur->timing.refresh_rate,
2932 tgt->timing.refresh_rate);
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002933
2934 if (cur->pixel_clk_khz != tgt->pixel_clk_khz)
2935 pr_debug("pixel_clk_khz differs %d %d\n",
2936 cur->pixel_clk_khz, tgt->pixel_clk_khz);
2937
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05002938 if (cur->dsi_mode_flags != tgt->dsi_mode_flags)
2939 pr_debug("flags differs %d %d\n",
2940 cur->dsi_mode_flags, tgt->dsi_mode_flags);
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002941
2942 return true;
2943}
2944
2945static int dsi_display_dfps_update(struct dsi_display *display,
2946 struct dsi_display_mode *dsi_mode)
2947{
2948 struct dsi_mode_info *timing;
2949 struct dsi_display_ctrl *m_ctrl, *ctrl;
2950 struct dsi_display_mode *panel_mode;
2951 struct dsi_dfps_capabilities dfps_caps;
2952 int rc = 0;
Channagoud Kadabi075db3b2017-03-16 14:26:17 -07002953 int i = 0;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002954
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07002955 if (!display || !dsi_mode || !display->panel) {
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002956 pr_err("Invalid params\n");
2957 return -EINVAL;
2958 }
2959 timing = &dsi_mode->timing;
2960
2961 dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
2962 if (!dfps_caps.dfps_support) {
2963 pr_err("dfps not supported\n");
2964 return -ENOTSUPP;
2965 }
2966
2967 if (dfps_caps.type == DSI_DFPS_IMMEDIATE_CLK) {
2968 pr_err("dfps clock method not supported\n");
2969 return -ENOTSUPP;
2970 }
2971
2972 /* For split DSI, update the clock master first */
2973
2974 pr_debug("configuring seamless dynamic fps\n\n");
2975
2976 m_ctrl = &display->ctrl[display->clk_master_idx];
2977 rc = dsi_ctrl_async_timing_update(m_ctrl->ctrl, timing);
2978 if (rc) {
2979 pr_err("[%s] failed to dfps update host_%d, rc=%d\n",
2980 display->name, i, rc);
2981 goto error;
2982 }
2983
2984 /* Update the rest of the controllers */
2985 for (i = 0; i < display->ctrl_count; i++) {
2986 ctrl = &display->ctrl[i];
2987 if (!ctrl->ctrl || (ctrl == m_ctrl))
2988 continue;
2989
2990 rc = dsi_ctrl_async_timing_update(ctrl->ctrl, timing);
2991 if (rc) {
2992 pr_err("[%s] failed to dfps update host_%d, rc=%d\n",
2993 display->name, i, rc);
2994 goto error;
2995 }
2996 }
2997
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07002998 panel_mode = display->panel->cur_mode;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002999 memcpy(panel_mode, dsi_mode, sizeof(*panel_mode));
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05003000 /*
3001 * dsi_mode_flags flags are used to communicate with other drm driver
3002 * components, and are transient. They aren't inherently part of the
3003 * display panel's mode and shouldn't be saved into the cached currently
3004 * active mode.
3005 */
3006 panel_mode->dsi_mode_flags = 0;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003007
3008error:
3009 return rc;
3010}
3011
3012static int dsi_display_dfps_calc_front_porch(
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303013 u32 old_fps,
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003014 u32 new_fps,
3015 u32 a_total,
3016 u32 b_total,
3017 u32 b_fp,
3018 u32 *b_fp_out)
3019{
3020 s32 b_fp_new;
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303021 int add_porches, diff;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003022
3023 if (!b_fp_out) {
3024 pr_err("Invalid params");
3025 return -EINVAL;
3026 }
3027
3028 if (!a_total || !new_fps) {
3029 pr_err("Invalid pixel total or new fps in mode request\n");
3030 return -EINVAL;
3031 }
3032
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303033 /*
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003034 * Keep clock, other porches constant, use new fps, calc front porch
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303035 * new_vtotal = old_vtotal * (old_fps / new_fps )
3036 * new_vfp - old_vfp = new_vtotal - old_vtotal
3037 * new_vfp = old_vfp + old_vtotal * ((old_fps - new_fps)/ new_fps)
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003038 */
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303039 diff = abs(old_fps - new_fps);
3040 add_porches = mult_frac(b_total, diff, new_fps);
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003041
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303042 if (old_fps > new_fps)
3043 b_fp_new = b_fp + add_porches;
3044 else
3045 b_fp_new = b_fp - add_porches;
3046
3047 pr_debug("fps %u a %u b %u b_fp %u new_fp %d\n",
3048 new_fps, a_total, b_total, b_fp, b_fp_new);
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003049
3050 if (b_fp_new < 0) {
3051 pr_err("Invalid new_hfp calcluated%d\n", b_fp_new);
3052 return -EINVAL;
3053 }
3054
3055 /**
3056 * TODO: To differentiate from clock method when communicating to the
3057 * other components, perhaps we should set clk here to original value
3058 */
3059 *b_fp_out = b_fp_new;
3060
3061 return 0;
3062}
3063
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303064/**
3065 * dsi_display_get_dfps_timing() - Get the new dfps values.
3066 * @display: DSI display handle.
3067 * @adj_mode: Mode value structure to be changed.
3068 * It contains old timing values and latest fps value.
3069 * New timing values are updated based on new fps.
3070 * @curr_refresh_rate: Current fps rate.
3071 * If zero , current fps rate is taken from
3072 * display->panel->cur_mode.
3073 * Return: error code.
3074 */
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003075static int dsi_display_get_dfps_timing(struct dsi_display *display,
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303076 struct dsi_display_mode *adj_mode,
3077 u32 curr_refresh_rate)
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003078{
3079 struct dsi_dfps_capabilities dfps_caps;
3080 struct dsi_display_mode per_ctrl_mode;
3081 struct dsi_mode_info *timing;
3082 struct dsi_ctrl *m_ctrl;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003083
3084 int rc = 0;
3085
3086 if (!display || !adj_mode) {
3087 pr_err("Invalid params\n");
3088 return -EINVAL;
3089 }
3090 m_ctrl = display->ctrl[display->clk_master_idx].ctrl;
3091
3092 dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
3093 if (!dfps_caps.dfps_support) {
3094 pr_err("dfps not supported by panel\n");
3095 return -EINVAL;
3096 }
3097
3098 per_ctrl_mode = *adj_mode;
3099 adjust_timing_by_ctrl_count(display, &per_ctrl_mode);
3100
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303101 if (!curr_refresh_rate) {
3102 if (!dsi_display_is_seamless_dfps_possible(display,
3103 &per_ctrl_mode, dfps_caps.type)) {
3104 pr_err("seamless dynamic fps not supported for mode\n");
3105 return -EINVAL;
3106 }
3107 if (display->panel->cur_mode) {
3108 curr_refresh_rate =
3109 display->panel->cur_mode->timing.refresh_rate;
3110 } else {
3111 pr_err("cur_mode is not initialized\n");
3112 return -EINVAL;
3113 }
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003114 }
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003115 /* TODO: Remove this direct reference to the dsi_ctrl */
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003116 timing = &per_ctrl_mode.timing;
3117
3118 switch (dfps_caps.type) {
3119 case DSI_DFPS_IMMEDIATE_VFP:
3120 rc = dsi_display_dfps_calc_front_porch(
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303121 curr_refresh_rate,
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003122 timing->refresh_rate,
3123 DSI_H_TOTAL(timing),
3124 DSI_V_TOTAL(timing),
3125 timing->v_front_porch,
3126 &adj_mode->timing.v_front_porch);
3127 break;
3128
3129 case DSI_DFPS_IMMEDIATE_HFP:
3130 rc = dsi_display_dfps_calc_front_porch(
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303131 curr_refresh_rate,
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003132 timing->refresh_rate,
3133 DSI_V_TOTAL(timing),
3134 DSI_H_TOTAL(timing),
3135 timing->h_front_porch,
3136 &adj_mode->timing.h_front_porch);
3137 if (!rc)
3138 adj_mode->timing.h_front_porch *= display->ctrl_count;
3139 break;
3140
3141 default:
3142 pr_err("Unsupported DFPS mode %d\n", dfps_caps.type);
3143 rc = -ENOTSUPP;
3144 }
3145
3146 return rc;
3147}
3148
3149static bool dsi_display_validate_mode_seamless(struct dsi_display *display,
3150 struct dsi_display_mode *adj_mode)
3151{
3152 int rc = 0;
3153
3154 if (!display || !adj_mode) {
3155 pr_err("Invalid params\n");
3156 return false;
3157 }
3158
3159 /* Currently the only seamless transition is dynamic fps */
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303160 rc = dsi_display_get_dfps_timing(display, adj_mode, 0);
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003161 if (rc) {
3162 pr_debug("Dynamic FPS not supported for seamless\n");
3163 } else {
3164 pr_debug("Mode switch is seamless Dynamic FPS\n");
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05003165 adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_DFPS |
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003166 DSI_MODE_FLAG_VBLANK_PRE_MODESET;
3167 }
3168
3169 return rc;
3170}
3171
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003172static int dsi_display_set_mode_sub(struct dsi_display *display,
3173 struct dsi_display_mode *mode,
3174 u32 flags)
3175{
3176 int rc = 0;
3177 int i;
3178 struct dsi_display_ctrl *ctrl;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07003179 struct dsi_display_mode_priv_info *priv_info;
3180
3181 priv_info = mode->priv_info;
3182 if (!priv_info) {
3183 pr_err("[%s] failed to get private info of the display mode",
3184 display->name);
3185 return -EINVAL;
3186 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003187
3188 rc = dsi_panel_get_host_cfg_for_mode(display->panel,
3189 mode,
3190 &display->config);
3191 if (rc) {
3192 pr_err("[%s] failed to get host config for mode, rc=%d\n",
3193 display->name, rc);
3194 goto error;
3195 }
3196
3197 memcpy(&display->config.lane_map, &display->lane_map,
3198 sizeof(display->lane_map));
3199
Raviteja Tamatam68892de2017-06-20 04:47:19 +05303200 if (mode->dsi_mode_flags &
3201 (DSI_MODE_FLAG_DFPS | DSI_MODE_FLAG_VRR)) {
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003202 rc = dsi_display_dfps_update(display, mode);
3203 if (rc) {
3204 pr_err("[%s]DSI dfps update failed, rc=%d\n",
3205 display->name, rc);
3206 goto error;
3207 }
3208 }
3209
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003210 for (i = 0; i < display->ctrl_count; i++) {
3211 ctrl = &display->ctrl[i];
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003212 rc = dsi_ctrl_update_host_config(ctrl->ctrl, &display->config,
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05003213 mode->dsi_mode_flags, display->dsi_clk_handle);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003214 if (rc) {
3215 pr_err("[%s] failed to update ctrl config, rc=%d\n",
3216 display->name, rc);
3217 goto error;
3218 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003219 }
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07003220
Alan Kwong60cc3552017-11-01 22:08:48 -04003221 for (i = 0; i < display->ctrl_count; i++) {
3222 ctrl = &display->ctrl[i];
3223
3224 if (!ctrl->phy || !ctrl->ctrl)
3225 continue;
3226
3227 rc = dsi_phy_set_clk_freq(ctrl->phy, &ctrl->ctrl->clk_freq);
3228 if (rc) {
3229 pr_err("[%s] failed to set phy clk freq, rc=%d\n",
3230 display->name, rc);
3231 goto error;
3232 }
3233 }
3234
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07003235 if (priv_info->phy_timing_len) {
3236 for (i = 0; i < display->ctrl_count; i++) {
3237 ctrl = &display->ctrl[i];
3238 rc = dsi_phy_set_timing_params(ctrl->phy,
3239 priv_info->phy_timing_val,
3240 priv_info->phy_timing_len);
3241 if (rc)
3242 pr_err("failed to add DSI PHY timing params");
3243 }
3244 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003245error:
3246 return rc;
3247}
3248
Clarence Ip3649f8b2016-10-31 09:59:44 -04003249/**
3250 * _dsi_display_dev_init - initializes the display device
3251 * Initialization will acquire references to the resources required for the
3252 * display hardware to function.
3253 * @display: Handle to the display
3254 * Returns: Zero on success
3255 */
3256static int _dsi_display_dev_init(struct dsi_display *display)
3257{
3258 int rc = 0;
3259
3260 if (!display) {
3261 pr_err("invalid display\n");
3262 return -EINVAL;
3263 }
3264
3265 mutex_lock(&display->display_lock);
3266
3267 rc = dsi_display_parse_dt(display);
3268 if (rc) {
3269 pr_err("[%s] failed to parse dt, rc=%d\n", display->name, rc);
3270 goto error;
3271 }
3272
3273 rc = dsi_display_res_init(display);
3274 if (rc) {
3275 pr_err("[%s] failed to initialize resources, rc=%d\n",
3276 display->name, rc);
3277 goto error;
3278 }
3279error:
3280 mutex_unlock(&display->display_lock);
3281 return rc;
3282}
3283
3284/**
3285 * _dsi_display_dev_deinit - deinitializes the display device
3286 * All the resources acquired during device init will be released.
3287 * @display: Handle to the display
3288 * Returns: Zero on success
3289 */
3290static int _dsi_display_dev_deinit(struct dsi_display *display)
3291{
3292 int rc = 0;
3293
3294 if (!display) {
3295 pr_err("invalid display\n");
3296 return -EINVAL;
3297 }
3298
3299 mutex_lock(&display->display_lock);
3300
3301 rc = dsi_display_res_deinit(display);
3302 if (rc)
3303 pr_err("[%s] failed to deinitialize resource, rc=%d\n",
3304 display->name, rc);
3305
3306 mutex_unlock(&display->display_lock);
3307
3308 return rc;
3309}
3310
3311/**
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07003312 * dsi_display_splash_res_init() - Initialize resources for continuous splash
3313 * @display: Pointer to dsi display
3314 * Returns: Zero on success
3315 */
3316static int dsi_display_splash_res_init(struct dsi_display *display)
3317{
3318 int rc = 0;
3319
3320 /* Vote for gdsc required to read register address space */
3321
3322 display->cont_splash_client = sde_power_client_create(display->phandle,
3323 "cont_splash_client");
3324 rc = sde_power_resource_enable(display->phandle,
3325 display->cont_splash_client, true);
3326 if (rc) {
3327 pr_err("failed to vote gdsc for continuous splash, rc=%d\n",
3328 rc);
3329 return -EINVAL;
3330 }
3331
3332 /* Verify whether continuous splash is enabled or not */
3333 display->is_cont_splash_enabled =
3334 dsi_display_get_cont_splash_status(display);
3335 if (!display->is_cont_splash_enabled) {
3336 pr_err("Continuous splash is not enabled\n");
3337 goto splash_disabled;
3338 }
3339
3340 /* Update splash status for clock manager */
3341 dsi_display_clk_mngr_update_splash_status(display->clk_mngr,
3342 display->is_cont_splash_enabled);
3343
3344 /* Vote for Core clk and link clk. Votes on ctrl and phy
3345 * regulator are inplicit from pre clk on callback
3346 */
3347 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
3348 DSI_ALL_CLKS, DSI_CLK_ON);
3349 if (rc) {
3350 pr_err("[%s] failed to enable DSI link clocks, rc=%d\n",
3351 display->name, rc);
3352 goto clk_manager_update;
3353 }
3354
3355 /* Vote on panel regulator will be removed during suspend path */
3356 rc = dsi_pwr_enable_regulator(&display->panel->power_info, true);
3357 if (rc) {
3358 pr_err("[%s] failed to enable vregs, rc=%d\n",
3359 display->panel->name, rc);
3360 goto clks_disabled;
3361 }
3362
3363 dsi_config_host_engine_state_for_cont_splash(display);
3364
3365 return rc;
3366
3367clks_disabled:
3368 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
3369 DSI_ALL_CLKS, DSI_CLK_OFF);
3370
3371clk_manager_update:
3372 /* Update splash status for clock manager */
3373 dsi_display_clk_mngr_update_splash_status(display->clk_mngr,
3374 false);
3375
3376splash_disabled:
3377 (void)sde_power_resource_enable(display->phandle,
3378 display->cont_splash_client, false);
3379 display->is_cont_splash_enabled = false;
3380 return rc;
3381}
3382
3383/**
3384 * dsi_display_splash_res_cleanup() - cleanup for continuous splash
3385 * @display: Pointer to dsi display
3386 * Returns: Zero on success
3387 */
3388int dsi_display_splash_res_cleanup(struct dsi_display *display)
3389{
3390 int rc = 0;
3391
3392 if (!display->is_cont_splash_enabled)
3393 return 0;
3394
3395 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
3396 DSI_ALL_CLKS, DSI_CLK_OFF);
3397 if (rc)
3398 pr_err("[%s] failed to disable DSI link clocks, rc=%d\n",
3399 display->name, rc);
3400
3401 rc = sde_power_resource_enable(display->phandle,
3402 display->cont_splash_client, false);
3403 if (rc)
3404 pr_err("failed to remove vote on gdsc for continuous splash, rc=%d\n",
3405 rc);
3406
3407 display->is_cont_splash_enabled = false;
3408 /* Update splash status for clock manager */
3409 dsi_display_clk_mngr_update_splash_status(display->clk_mngr,
3410 display->is_cont_splash_enabled);
3411
3412 return rc;
3413}
3414
3415/**
Clarence Ip3649f8b2016-10-31 09:59:44 -04003416 * dsi_display_bind - bind dsi device with controlling device
3417 * @dev: Pointer to base of platform device
3418 * @master: Pointer to container of drm device
3419 * @data: Pointer to private data
3420 * Returns: Zero on success
3421 */
3422static int dsi_display_bind(struct device *dev,
3423 struct device *master,
3424 void *data)
3425{
3426 struct dsi_display_ctrl *display_ctrl;
3427 struct drm_device *drm;
3428 struct dsi_display *display;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303429 struct dsi_clk_info info;
3430 struct clk_ctrl_cb clk_cb;
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -08003431 struct msm_drm_private *priv;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303432 void *handle = NULL;
Clarence Ip3649f8b2016-10-31 09:59:44 -04003433 struct platform_device *pdev = to_platform_device(dev);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303434 char *client1 = "dsi_clk_client";
3435 char *client2 = "mdp_event_client";
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -08003436 char dsi_client_name[DSI_CLIENT_NAME_SIZE];
Clarence Ip3649f8b2016-10-31 09:59:44 -04003437 int i, rc = 0;
3438
3439 if (!dev || !pdev || !master) {
3440 pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
3441 dev, pdev, master);
3442 return -EINVAL;
3443 }
3444
3445 drm = dev_get_drvdata(master);
3446 display = platform_get_drvdata(pdev);
3447 if (!drm || !display) {
3448 pr_err("invalid param(s), drm %pK, display %pK\n",
3449 drm, display);
3450 return -EINVAL;
3451 }
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -08003452 priv = drm->dev_private;
Clarence Ip3649f8b2016-10-31 09:59:44 -04003453
3454 mutex_lock(&display->display_lock);
3455
3456 rc = dsi_display_debugfs_init(display);
3457 if (rc) {
3458 pr_err("[%s] debugfs init failed, rc=%d\n", display->name, rc);
3459 goto error;
3460 }
3461
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303462 memset(&info, 0x0, sizeof(info));
3463
Clarence Ip3649f8b2016-10-31 09:59:44 -04003464 for (i = 0; i < display->ctrl_count; i++) {
3465 display_ctrl = &display->ctrl[i];
Clarence Ip3649f8b2016-10-31 09:59:44 -04003466 rc = dsi_ctrl_drv_init(display_ctrl->ctrl, display->root);
3467 if (rc) {
3468 pr_err("[%s] failed to initialize ctrl[%d], rc=%d\n",
3469 display->name, i, rc);
3470 goto error_ctrl_deinit;
3471 }
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04003472 display_ctrl->ctrl->horiz_index = i;
Clarence Ip3649f8b2016-10-31 09:59:44 -04003473
3474 rc = dsi_phy_drv_init(display_ctrl->phy);
3475 if (rc) {
3476 pr_err("[%s] Failed to initialize phy[%d], rc=%d\n",
3477 display->name, i, rc);
3478 (void)dsi_ctrl_drv_deinit(display_ctrl->ctrl);
3479 goto error_ctrl_deinit;
3480 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303481
3482 memcpy(&info.c_clks[i], &display_ctrl->ctrl->clk_info.core_clks,
3483 sizeof(struct dsi_core_clk_info));
3484 memcpy(&info.l_clks[i], &display_ctrl->ctrl->clk_info.link_clks,
3485 sizeof(struct dsi_link_clk_info));
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -08003486 info.c_clks[i].phandle = &priv->phandle;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303487 info.bus_handle[i] =
3488 display_ctrl->ctrl->axi_bus_info.bus_handle;
Alexander Beykun32a6a182017-02-27 17:46:51 -05003489 info.ctrl_index[i] = display_ctrl->ctrl->cell_index;
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -08003490 snprintf(dsi_client_name, DSI_CLIENT_NAME_SIZE,
3491 "dsi_core_client%u", i);
3492 info.c_clks[i].dsi_core_client = sde_power_client_create(
3493 info.c_clks[i].phandle, dsi_client_name);
3494 if (IS_ERR_OR_NULL(info.c_clks[i].dsi_core_client)) {
3495 pr_err("[%s] client creation failed for ctrl[%d]",
3496 dsi_client_name, i);
3497 goto error_ctrl_deinit;
3498 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303499 }
3500
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07003501 display->phandle = &priv->phandle;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303502 info.pre_clkoff_cb = dsi_pre_clkoff_cb;
3503 info.pre_clkon_cb = dsi_pre_clkon_cb;
3504 info.post_clkoff_cb = dsi_post_clkoff_cb;
3505 info.post_clkon_cb = dsi_post_clkon_cb;
3506 info.priv_data = display;
3507 info.master_ndx = display->clk_master_idx;
3508 info.dsi_ctrl_count = display->ctrl_count;
3509 snprintf(info.name, MAX_STRING_LEN,
3510 "DSI_MNGR-%s", display->name);
3511
3512 display->clk_mngr = dsi_display_clk_mngr_register(&info);
3513 if (IS_ERR_OR_NULL(display->clk_mngr)) {
3514 rc = PTR_ERR(display->clk_mngr);
3515 display->clk_mngr = NULL;
3516 pr_err("dsi clock registration failed, rc = %d\n", rc);
3517 goto error_ctrl_deinit;
3518 }
3519
3520 handle = dsi_register_clk_handle(display->clk_mngr, client1);
3521 if (IS_ERR_OR_NULL(handle)) {
3522 rc = PTR_ERR(handle);
3523 pr_err("failed to register %s client, rc = %d\n",
3524 client1, rc);
3525 goto error_clk_deinit;
3526 } else {
3527 display->dsi_clk_handle = handle;
3528 }
3529
3530 handle = dsi_register_clk_handle(display->clk_mngr, client2);
3531 if (IS_ERR_OR_NULL(handle)) {
3532 rc = PTR_ERR(handle);
3533 pr_err("failed to register %s client, rc = %d\n",
3534 client2, rc);
3535 goto error_clk_client_deinit;
3536 } else {
3537 display->mdp_clk_handle = handle;
3538 }
3539
3540 clk_cb.priv = display;
3541 clk_cb.dsi_clk_cb = dsi_display_clk_ctrl_cb;
3542
3543 for (i = 0; i < display->ctrl_count; i++) {
3544 display_ctrl = &display->ctrl[i];
3545
3546 rc = dsi_ctrl_clk_cb_register(display_ctrl->ctrl, &clk_cb);
3547 if (rc) {
3548 pr_err("[%s] failed to register ctrl clk_cb[%d], rc=%d\n",
3549 display->name, i, rc);
3550 goto error_ctrl_deinit;
3551 }
3552
3553 rc = dsi_phy_clk_cb_register(display_ctrl->phy, &clk_cb);
3554 if (rc) {
3555 pr_err("[%s] failed to register phy clk_cb[%d], rc=%d\n",
3556 display->name, i, rc);
3557 goto error_ctrl_deinit;
3558 }
Clarence Ip3649f8b2016-10-31 09:59:44 -04003559 }
3560
3561 rc = dsi_display_mipi_host_init(display);
3562 if (rc) {
3563 pr_err("[%s] failed to initialize mipi host, rc=%d\n",
3564 display->name, rc);
3565 goto error_ctrl_deinit;
3566 }
3567
3568 rc = dsi_panel_drv_init(display->panel, &display->host);
3569 if (rc) {
3570 if (rc != -EPROBE_DEFER)
3571 pr_err("[%s] failed to initialize panel driver, rc=%d\n",
3572 display->name, rc);
3573 goto error_host_deinit;
3574 }
3575
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003576 pr_info("Successfully bind display panel '%s'\n", display->name);
Clarence Ip3649f8b2016-10-31 09:59:44 -04003577 display->drm_dev = drm;
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07003578
3579 /* Initialize resources for continuous splash */
3580 rc = dsi_display_splash_res_init(display);
3581 if (rc)
3582 pr_err("Continuous splash resource init failed, rc=%d\n", rc);
3583
Clarence Ip3649f8b2016-10-31 09:59:44 -04003584 goto error;
3585
Clarence Ip3649f8b2016-10-31 09:59:44 -04003586error_host_deinit:
3587 (void)dsi_display_mipi_host_deinit(display);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303588error_clk_client_deinit:
3589 (void)dsi_deregister_clk_handle(display->dsi_clk_handle);
3590error_clk_deinit:
3591 (void)dsi_display_clk_mngr_deregister(display->clk_mngr);
Clarence Ip3649f8b2016-10-31 09:59:44 -04003592error_ctrl_deinit:
3593 for (i = i - 1; i >= 0; i--) {
3594 display_ctrl = &display->ctrl[i];
3595 (void)dsi_phy_drv_deinit(display_ctrl->phy);
3596 (void)dsi_ctrl_drv_deinit(display_ctrl->ctrl);
3597 }
3598 (void)dsi_display_debugfs_deinit(display);
3599error:
3600 mutex_unlock(&display->display_lock);
3601 return rc;
3602}
3603
3604/**
3605 * dsi_display_unbind - unbind dsi from controlling device
3606 * @dev: Pointer to base of platform device
3607 * @master: Pointer to container of drm device
3608 * @data: Pointer to private data
3609 */
3610static void dsi_display_unbind(struct device *dev,
3611 struct device *master, void *data)
3612{
3613 struct dsi_display_ctrl *display_ctrl;
3614 struct dsi_display *display;
3615 struct platform_device *pdev = to_platform_device(dev);
3616 int i, rc = 0;
3617
3618 if (!dev || !pdev) {
3619 pr_err("invalid param(s)\n");
3620 return;
3621 }
3622
3623 display = platform_get_drvdata(pdev);
3624 if (!display) {
3625 pr_err("invalid display\n");
3626 return;
3627 }
3628
3629 mutex_lock(&display->display_lock);
3630
3631 rc = dsi_panel_drv_deinit(display->panel);
3632 if (rc)
3633 pr_err("[%s] failed to deinit panel driver, rc=%d\n",
3634 display->name, rc);
3635
3636 rc = dsi_display_mipi_host_deinit(display);
3637 if (rc)
3638 pr_err("[%s] failed to deinit mipi hosts, rc=%d\n",
3639 display->name,
3640 rc);
3641
3642 for (i = 0; i < display->ctrl_count; i++) {
3643 display_ctrl = &display->ctrl[i];
3644
3645 rc = dsi_phy_drv_deinit(display_ctrl->phy);
3646 if (rc)
3647 pr_err("[%s] failed to deinit phy%d driver, rc=%d\n",
3648 display->name, i, rc);
3649
3650 rc = dsi_ctrl_drv_deinit(display_ctrl->ctrl);
3651 if (rc)
3652 pr_err("[%s] failed to deinit ctrl%d driver, rc=%d\n",
3653 display->name, i, rc);
3654 }
3655 (void)dsi_display_debugfs_deinit(display);
3656
3657 mutex_unlock(&display->display_lock);
3658}
3659
3660static const struct component_ops dsi_display_comp_ops = {
3661 .bind = dsi_display_bind,
3662 .unbind = dsi_display_unbind,
3663};
3664
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07003665static struct platform_driver dsi_display_driver = {
3666 .probe = dsi_display_dev_probe,
3667 .remove = dsi_display_dev_remove,
3668 .driver = {
3669 .name = "msm-dsi-display",
3670 .of_match_table = dsi_display_dt_match,
3671 },
3672};
3673
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003674int dsi_display_dev_probe(struct platform_device *pdev)
3675{
3676 int rc = 0;
3677 struct dsi_display *display;
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003678 static bool display_from_cmdline, boot_displays_parsed;
3679 static bool comp_add_success;
3680 static struct device_node *primary_np, *secondary_np;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003681
3682 if (!pdev || !pdev->dev.of_node) {
3683 pr_err("pdev not found\n");
3684 return -ENODEV;
3685 }
3686
3687 display = devm_kzalloc(&pdev->dev, sizeof(*display), GFP_KERNEL);
3688 if (!display)
3689 return -ENOMEM;
3690
3691 display->name = of_get_property(pdev->dev.of_node, "label", NULL);
Samantha Tranf4259fd2017-09-28 16:42:12 -07003692 if (!display->name)
3693 display->name = "unknown";
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003694
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003695 if (!boot_displays_parsed) {
3696 boot_displays[DSI_PRIMARY].boot_disp_en = false;
3697 boot_displays[DSI_SECONDARY].boot_disp_en = false;
3698 if (dsi_display_parse_boot_display_selection())
3699 pr_debug("Display Boot param not valid/available\n");
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003700
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003701 boot_displays_parsed = true;
3702 }
3703
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07003704 /* use default topology of every mode if not overridden */
3705 display->cmdline_topology = NO_OVERRIDE;
3706 display->cmdline_timing = 0;
3707
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003708 if ((!display_from_cmdline) &&
3709 (boot_displays[DSI_PRIMARY].boot_disp_en)) {
3710 display->is_active = dsi_display_name_compare(pdev->dev.of_node,
3711 display->name, DSI_PRIMARY);
3712 if (display->is_active) {
3713 if (comp_add_success) {
3714 (void)_dsi_display_dev_deinit(main_display);
3715 component_del(&main_display->pdev->dev,
3716 &dsi_display_comp_ops);
Dhaval Patel081400e2017-06-21 19:24:48 -07003717 mutex_lock(&dsi_display_list_lock);
3718 list_del(&main_display->list);
3719 mutex_unlock(&dsi_display_list_lock);
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003720 comp_add_success = false;
3721 default_active_node = NULL;
3722 pr_debug("removed the existing comp ops\n");
3723 }
3724 /*
3725 * Need to add component for
3726 * the secondary DSI display
3727 * when more than one DSI display
3728 * is supported.
3729 */
3730 pr_debug("cmdline primary dsi: %s\n",
3731 display->name);
3732 display_from_cmdline = true;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07003733 dsi_display_parse_cmdline_topology(display,
3734 DSI_PRIMARY);
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003735 primary_np = pdev->dev.of_node;
3736 }
3737 }
3738
3739 if (boot_displays[DSI_SECONDARY].boot_disp_en) {
3740 if (!secondary_np) {
3741 if (dsi_display_name_compare(pdev->dev.of_node,
3742 display->name, DSI_SECONDARY)) {
3743 pr_debug("cmdline secondary dsi: %s\n",
3744 display->name);
3745 secondary_np = pdev->dev.of_node;
3746 if (primary_np) {
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07003747 if (validate_dsi_display_selection()) {
3748 display->is_active = true;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07003749 dsi_display_parse_cmdline_topology
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07003750 (display, DSI_SECONDARY);
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07003751 } else {
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003752 boot_displays[DSI_SECONDARY]
3753 .boot_disp_en = false;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07003754 }
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003755 }
3756 }
3757 }
3758 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003759 display->display_type = of_get_property(pdev->dev.of_node,
3760 "qcom,display-type", NULL);
3761 if (!display->display_type)
3762 display->display_type = "unknown";
3763
3764 mutex_init(&display->display_lock);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003765 display->pdev = pdev;
3766 platform_set_drvdata(pdev, display);
3767 mutex_lock(&dsi_display_list_lock);
3768 list_add(&display->list, &dsi_display_list);
3769 mutex_unlock(&dsi_display_list_lock);
Clarence Ip3649f8b2016-10-31 09:59:44 -04003770
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003771 if (!display_from_cmdline)
3772 display->is_active = of_property_read_bool(pdev->dev.of_node,
3773 "qcom,dsi-display-active");
3774
Clarence Ip3649f8b2016-10-31 09:59:44 -04003775 if (display->is_active) {
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003776 main_display = display;
Clarence Ip3649f8b2016-10-31 09:59:44 -04003777 rc = _dsi_display_dev_init(display);
3778 if (rc) {
3779 pr_err("device init failed, rc=%d\n", rc);
3780 return rc;
3781 }
3782
3783 rc = component_add(&pdev->dev, &dsi_display_comp_ops);
3784 if (rc)
3785 pr_err("component add failed, rc=%d\n", rc);
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003786
3787 comp_add_success = true;
3788 pr_debug("Component_add success: %s\n", display->name);
3789 if (!display_from_cmdline)
3790 default_active_node = pdev->dev.of_node;
Clarence Ip3649f8b2016-10-31 09:59:44 -04003791 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003792 return rc;
3793}
3794
3795int dsi_display_dev_remove(struct platform_device *pdev)
3796{
3797 int rc = 0;
3798 struct dsi_display *display;
3799 struct dsi_display *pos, *tmp;
3800
3801 if (!pdev) {
3802 pr_err("Invalid device\n");
3803 return -EINVAL;
3804 }
3805
3806 display = platform_get_drvdata(pdev);
3807
Clarence Ip3649f8b2016-10-31 09:59:44 -04003808 (void)_dsi_display_dev_deinit(display);
3809
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003810 mutex_lock(&dsi_display_list_lock);
3811 list_for_each_entry_safe(pos, tmp, &dsi_display_list, list) {
3812 if (pos == display) {
3813 list_del(&display->list);
3814 break;
3815 }
3816 }
3817 mutex_unlock(&dsi_display_list_lock);
3818
3819 platform_set_drvdata(pdev, NULL);
3820 devm_kfree(&pdev->dev, display);
3821 return rc;
3822}
3823
Clarence Ip3649f8b2016-10-31 09:59:44 -04003824int dsi_display_get_num_of_displays(void)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003825{
Clarence Ip3649f8b2016-10-31 09:59:44 -04003826 int count = 0;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003827 struct dsi_display *display;
3828
3829 mutex_lock(&dsi_display_list_lock);
3830
3831 list_for_each_entry(display, &dsi_display_list, list) {
3832 count++;
3833 }
3834
3835 mutex_unlock(&dsi_display_list_lock);
3836 return count;
3837}
3838
Clarence Ipa36c92e2016-07-26 14:33:46 -04003839int dsi_display_get_active_displays(void **display_array, u32 max_display_count)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003840{
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003841 struct dsi_display *pos;
3842 int i = 0;
3843
Clarence Ipa36c92e2016-07-26 14:33:46 -04003844 if (!display_array || !max_display_count) {
3845 if (!display_array)
3846 pr_err("invalid params\n");
3847 return 0;
3848 }
3849
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003850 mutex_lock(&dsi_display_list_lock);
3851
3852 list_for_each_entry(pos, &dsi_display_list, list) {
Clarence Ipa36c92e2016-07-26 14:33:46 -04003853 if (i >= max_display_count) {
3854 pr_err("capping display count to %d\n", i);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003855 break;
3856 }
Clarence Ipa36c92e2016-07-26 14:33:46 -04003857 if (pos->is_active)
3858 display_array[i++] = pos;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003859 }
3860
3861 mutex_unlock(&dsi_display_list_lock);
Clarence Ipa36c92e2016-07-26 14:33:46 -04003862 return i;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003863}
3864
3865struct dsi_display *dsi_display_get_display_by_name(const char *name)
3866{
3867 struct dsi_display *display = NULL, *pos;
3868
3869 mutex_lock(&dsi_display_list_lock);
3870
3871 list_for_each_entry(pos, &dsi_display_list, list) {
3872 if (!strcmp(name, pos->name))
3873 display = pos;
3874 }
3875
3876 mutex_unlock(&dsi_display_list_lock);
3877
3878 return display;
3879}
3880
3881void dsi_display_set_active_state(struct dsi_display *display, bool is_active)
3882{
3883 mutex_lock(&display->display_lock);
3884 display->is_active = is_active;
3885 mutex_unlock(&display->display_lock);
3886}
3887
Clarence Ip40d7d592016-07-15 16:02:26 -04003888int dsi_display_drm_bridge_init(struct dsi_display *display,
3889 struct drm_encoder *enc)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003890{
3891 int rc = 0;
3892 struct dsi_bridge *bridge;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003893 struct msm_drm_private *priv = NULL;
3894
Clarence Ip3649f8b2016-10-31 09:59:44 -04003895 if (!display || !display->drm_dev || !enc) {
3896 pr_err("invalid param(s)\n");
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003897 return -EINVAL;
3898 }
3899
3900 mutex_lock(&display->display_lock);
3901 priv = display->drm_dev->dev_private;
3902
3903 if (!priv) {
3904 pr_err("Private data is not present\n");
3905 rc = -EINVAL;
3906 goto error;
3907 }
3908
Clarence Ip40d7d592016-07-15 16:02:26 -04003909 if (display->bridge) {
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003910 pr_err("display is already initialize\n");
3911 goto error;
3912 }
3913
3914 bridge = dsi_drm_bridge_init(display, display->drm_dev, enc);
3915 if (IS_ERR_OR_NULL(bridge)) {
3916 rc = PTR_ERR(bridge);
Clarence Ipa36c92e2016-07-26 14:33:46 -04003917 pr_err("[%s] brige init failed, %d\n", display->name, rc);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003918 goto error;
3919 }
3920
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003921 display->bridge = bridge;
3922 priv->bridges[priv->num_bridges++] = &bridge->base;
3923
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003924error:
3925 mutex_unlock(&display->display_lock);
3926 return rc;
3927}
3928
Clarence Ip40d7d592016-07-15 16:02:26 -04003929int dsi_display_drm_bridge_deinit(struct dsi_display *display)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003930{
3931 int rc = 0;
3932
3933 if (!display) {
3934 pr_err("Invalid params\n");
3935 return -EINVAL;
3936 }
3937
3938 mutex_lock(&display->display_lock);
3939
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003940 dsi_drm_bridge_cleanup(display->bridge);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003941 display->bridge = NULL;
3942
3943 mutex_unlock(&display->display_lock);
3944 return rc;
3945}
3946
Clarence Ipa4039322016-07-15 16:23:59 -04003947int dsi_display_get_info(struct msm_display_info *info, void *disp)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003948{
Clarence Ipa4039322016-07-15 16:23:59 -04003949 struct dsi_display *display;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003950 struct dsi_panel_phy_props phy_props;
Clarence Ipa4039322016-07-15 16:23:59 -04003951 int i, rc;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003952
Clarence Ipa4039322016-07-15 16:23:59 -04003953 if (!info || !disp) {
3954 pr_err("invalid params\n");
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003955 return -EINVAL;
3956 }
Dhaval Patel60e1ff52017-02-18 21:03:40 -08003957
Clarence Ipa4039322016-07-15 16:23:59 -04003958 display = disp;
Dhaval Patel60e1ff52017-02-18 21:03:40 -08003959 if (!display->panel) {
3960 pr_err("invalid display panel\n");
3961 return -EINVAL;
3962 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003963
3964 mutex_lock(&display->display_lock);
3965 rc = dsi_panel_get_phy_props(display->panel, &phy_props);
3966 if (rc) {
3967 pr_err("[%s] failed to get panel phy props, rc=%d\n",
3968 display->name, rc);
3969 goto error;
3970 }
3971
Alan Kwong735b3db2017-05-03 06:47:52 -07003972 memset(info, 0, sizeof(struct msm_display_info));
Clarence Ipa4039322016-07-15 16:23:59 -04003973 info->intf_type = DRM_MODE_CONNECTOR_DSI;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003974 info->num_of_h_tiles = display->ctrl_count;
3975 for (i = 0; i < info->num_of_h_tiles; i++)
Alexander Beykun32a6a182017-02-27 17:46:51 -05003976 info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003977
Clarence Ipa4039322016-07-15 16:23:59 -04003978 info->is_connected = true;
Dhaval Patel020f7e122016-11-15 14:39:18 -08003979 info->is_primary = true;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003980 info->width_mm = phy_props.panel_width_mm;
3981 info->height_mm = phy_props.panel_height_mm;
Clarence Ipa4039322016-07-15 16:23:59 -04003982 info->max_width = 1920;
3983 info->max_height = 1080;
Alexander Beykunac182352017-02-27 17:46:51 -05003984
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07003985 switch (display->panel->panel_mode) {
Clarence Ipa4039322016-07-15 16:23:59 -04003986 case DSI_OP_VIDEO_MODE:
3987 info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
3988 break;
3989 case DSI_OP_CMD_MODE:
3990 info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE;
Narendra Muppallad4081e12017-04-20 19:24:08 -07003991 info->is_te_using_watchdog_timer =
3992 display->panel->te_using_watchdog_timer;
Clarence Ipa4039322016-07-15 16:23:59 -04003993 break;
3994 default:
3995 pr_err("unknwown dsi panel mode %d\n",
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07003996 display->panel->panel_mode);
Clarence Ipa4039322016-07-15 16:23:59 -04003997 break;
3998 }
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04003999
Sandeep Panda98d6ab22017-09-05 08:03:16 +05304000 if (display->panel->esd_config.esd_enabled)
4001 info->capabilities |= MSM_DISPLAY_ESD_ENABLED;
4002
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004003error:
4004 mutex_unlock(&display->display_lock);
4005 return rc;
4006}
4007
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004008static int dsi_display_get_mode_count_no_lock(struct dsi_display *display,
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004009 u32 *count)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004010{
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07004011 struct dsi_dfps_capabilities dfps_caps;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004012 int num_dfps_rates, rc = 0;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004013
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004014 if (!display || !display->panel) {
4015 pr_err("invalid display:%d panel:%d\n", display != NULL,
4016 display ? display->panel != NULL : 0);
4017 return -EINVAL;
4018 }
4019
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004020 *count = display->panel->num_timing_nodes;
4021
4022 rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
4023 if (rc) {
4024 pr_err("[%s] failed to get dfps caps from panel\n",
4025 display->name);
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004026 return rc;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004027 }
4028
4029 num_dfps_rates = !dfps_caps.dfps_support ? 1 :
4030 dfps_caps.max_refresh_rate -
4031 dfps_caps.min_refresh_rate + 1;
4032
4033 /* Inflate num_of_modes by fps in dfps */
4034 *count = display->panel->num_timing_nodes * num_dfps_rates;
4035
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004036 return 0;
4037}
4038
4039int dsi_display_get_mode_count(struct dsi_display *display,
4040 u32 *count)
4041{
4042 int rc;
4043
4044 if (!display || !display->panel) {
4045 pr_err("invalid display:%d panel:%d\n", display != NULL,
4046 display ? display->panel != NULL : 0);
4047 return -EINVAL;
4048 }
4049
4050 mutex_lock(&display->display_lock);
4051 rc = dsi_display_get_mode_count_no_lock(display, count);
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004052 mutex_unlock(&display->display_lock);
4053
4054 return 0;
4055}
4056
4057void dsi_display_put_mode(struct dsi_display *display,
4058 struct dsi_display_mode *mode)
4059{
4060 dsi_panel_put_mode(mode);
4061}
4062
4063int dsi_display_get_modes(struct dsi_display *display,
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004064 struct dsi_display_mode **out_modes)
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004065{
4066 struct dsi_dfps_capabilities dfps_caps;
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004067 u32 num_dfps_rates, panel_mode_count, total_mode_count;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004068 u32 mode_idx, array_idx = 0;
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004069 int i, rc = -EINVAL;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004070
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004071 if (!display || !out_modes) {
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004072 pr_err("Invalid params\n");
4073 return -EINVAL;
4074 }
4075
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004076 *out_modes = NULL;
4077
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004078 mutex_lock(&display->display_lock);
4079
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004080 rc = dsi_display_get_mode_count_no_lock(display, &total_mode_count);
4081 if (rc)
4082 goto error;
4083
4084 /* free any previously probed modes */
4085 kfree(display->modes);
4086
4087 display->modes = kcalloc(total_mode_count, sizeof(*display->modes),
4088 GFP_KERNEL);
4089 if (!display->modes) {
4090 rc = -ENOMEM;
4091 goto error;
4092 }
4093
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07004094 rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
4095 if (rc) {
4096 pr_err("[%s] failed to get dfps caps from panel\n",
4097 display->name);
4098 goto error;
4099 }
4100
4101 num_dfps_rates = !dfps_caps.dfps_support ? 1 :
4102 dfps_caps.max_refresh_rate -
4103 dfps_caps.min_refresh_rate + 1;
4104
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004105 panel_mode_count = display->panel->num_timing_nodes;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004106
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004107 for (mode_idx = 0; mode_idx < panel_mode_count; mode_idx++) {
4108 struct dsi_display_mode panel_mode;
4109 int topology_override = NO_OVERRIDE;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07004110
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004111 if (display->cmdline_timing == mode_idx)
4112 topology_override = display->cmdline_topology;
4113
4114 memset(&panel_mode, 0, sizeof(panel_mode));
4115
4116 rc = dsi_panel_get_mode(display->panel, mode_idx,
4117 &panel_mode, topology_override);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004118 if (rc) {
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004119 pr_err("[%s] failed to get mode idx %d from panel\n",
4120 display->name, mode_idx);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004121 goto error;
4122 }
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07004123
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07004124 if (display->ctrl_count > 1) { /* TODO: remove if */
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004125 panel_mode.timing.h_active *= display->ctrl_count;
4126 panel_mode.timing.h_front_porch *= display->ctrl_count;
4127 panel_mode.timing.h_sync_width *= display->ctrl_count;
4128 panel_mode.timing.h_back_porch *= display->ctrl_count;
4129 panel_mode.timing.h_skew *= display->ctrl_count;
4130 panel_mode.pixel_clk_khz *= display->ctrl_count;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004131 }
4132
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004133 for (i = 0; i < num_dfps_rates; i++) {
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004134 struct dsi_display_mode *sub_mode =
4135 &display->modes[array_idx];
Raviteja Tamatam68892de2017-06-20 04:47:19 +05304136 u32 curr_refresh_rate;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004137
4138 if (!sub_mode) {
4139 pr_err("invalid mode data\n");
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004140 rc = -EFAULT;
4141 goto error;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004142 }
4143
4144 memcpy(sub_mode, &panel_mode, sizeof(panel_mode));
4145
4146 if (dfps_caps.dfps_support) {
Raviteja Tamatam68892de2017-06-20 04:47:19 +05304147 curr_refresh_rate =
4148 sub_mode->timing.refresh_rate;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004149 sub_mode->timing.refresh_rate =
4150 dfps_caps.min_refresh_rate +
4151 (i % num_dfps_rates);
Raviteja Tamatam68892de2017-06-20 04:47:19 +05304152
4153 dsi_display_get_dfps_timing(display,
4154 sub_mode, curr_refresh_rate);
4155
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004156 sub_mode->pixel_clk_khz =
4157 (DSI_H_TOTAL(&sub_mode->timing) *
4158 DSI_V_TOTAL(&sub_mode->timing) *
4159 sub_mode->timing.refresh_rate) / 1000;
4160 }
4161 array_idx++;
4162 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004163 }
4164
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004165 *out_modes = display->modes;
4166 rc = 0;
4167
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004168error:
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004169 if (rc)
4170 kfree(display->modes);
4171
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004172 mutex_unlock(&display->display_lock);
4173 return rc;
4174}
4175
Lloyd Atkinson560785e2017-11-16 14:04:15 -05004176int dsi_display_find_mode(struct dsi_display *display,
4177 const struct dsi_display_mode *cmp,
4178 struct dsi_display_mode **out_mode)
4179{
4180 u32 count, i;
4181 int rc;
4182
4183 if (!display || !out_mode)
4184 return -EINVAL;
4185
4186 *out_mode = NULL;
4187
4188 rc = dsi_display_get_mode_count(display, &count);
4189 if (rc)
4190 return rc;
4191
4192 mutex_lock(&display->display_lock);
4193 for (i = 0; i < count; i++) {
4194 struct dsi_display_mode *m = &display->modes[i];
4195
4196 if (cmp->timing.v_active == m->timing.v_active &&
4197 cmp->timing.h_active == m->timing.h_active &&
4198 cmp->timing.refresh_rate == m->timing.refresh_rate) {
4199 *out_mode = m;
4200 rc = 0;
4201 break;
4202 }
4203 }
4204 mutex_unlock(&display->display_lock);
4205
4206 if (!*out_mode) {
4207 pr_err("[%s] failed to find mode for v_active %u h_active %u rate %u\n",
4208 display->name, cmp->timing.v_active,
4209 cmp->timing.h_active, cmp->timing.refresh_rate);
4210 rc = -ENOENT;
4211 }
4212
4213 return rc;
4214}
4215
Raviteja Tamatam68892de2017-06-20 04:47:19 +05304216/**
4217 * dsi_display_validate_mode_vrr() - Validate if varaible refresh case.
4218 * @display: DSI display handle.
4219 * @cur_dsi_mode: Current DSI mode.
4220 * @mode: Mode value structure to be validated.
4221 * MSM_MODE_FLAG_SEAMLESS_VRR flag is set if there
4222 * is change in fps but vactive and hactive are same.
4223 * Return: error code.
4224 */
4225int dsi_display_validate_mode_vrr(struct dsi_display *display,
4226 struct dsi_display_mode *cur_dsi_mode,
4227 struct dsi_display_mode *mode)
4228{
4229 int rc = 0;
4230 struct dsi_display_mode adj_mode, cur_mode;
4231 struct dsi_dfps_capabilities dfps_caps;
4232 u32 curr_refresh_rate;
4233
4234 if (!display || !mode) {
4235 pr_err("Invalid params\n");
4236 return -EINVAL;
4237 }
4238
4239 if (!display->panel || !display->panel->cur_mode) {
4240 pr_debug("Current panel mode not set\n");
4241 return rc;
4242 }
4243
4244 mutex_lock(&display->display_lock);
4245
4246 adj_mode = *mode;
4247 cur_mode = *cur_dsi_mode;
4248
4249 if ((cur_mode.timing.refresh_rate != adj_mode.timing.refresh_rate) &&
4250 (cur_mode.timing.v_active == adj_mode.timing.v_active) &&
4251 (cur_mode.timing.h_active == adj_mode.timing.h_active)) {
4252
4253 curr_refresh_rate = cur_mode.timing.refresh_rate;
4254 rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
4255 if (rc) {
4256 pr_err("[%s] failed to get dfps caps from panel\n",
4257 display->name);
4258 goto error;
4259 }
4260
4261 cur_mode.timing.refresh_rate =
4262 adj_mode.timing.refresh_rate;
4263
4264 rc = dsi_display_get_dfps_timing(display,
4265 &cur_mode, curr_refresh_rate);
4266 if (rc) {
4267 pr_err("[%s] seamless vrr not possible rc=%d\n",
4268 display->name, rc);
4269 goto error;
4270 }
4271 switch (dfps_caps.type) {
4272 /*
4273 * Ignore any round off factors in porch calculation.
4274 * Worse case is set to 5.
4275 */
4276 case DSI_DFPS_IMMEDIATE_VFP:
4277 if (abs(DSI_V_TOTAL(&cur_mode.timing) -
4278 DSI_V_TOTAL(&adj_mode.timing)) > 5)
4279 pr_err("Mismatch vfp fps:%d new:%d given:%d\n",
4280 adj_mode.timing.refresh_rate,
4281 cur_mode.timing.v_front_porch,
4282 adj_mode.timing.v_front_porch);
4283 break;
4284
4285 case DSI_DFPS_IMMEDIATE_HFP:
4286 if (abs(DSI_H_TOTAL(&cur_mode.timing) -
4287 DSI_H_TOTAL(&adj_mode.timing)) > 5)
4288 pr_err("Mismatch hfp fps:%d new:%d given:%d\n",
4289 adj_mode.timing.refresh_rate,
4290 cur_mode.timing.h_front_porch,
4291 adj_mode.timing.h_front_porch);
4292 break;
4293
4294 default:
4295 pr_err("Unsupported DFPS mode %d\n",
4296 dfps_caps.type);
4297 rc = -ENOTSUPP;
4298 }
4299
4300 pr_debug("Mode switch is seamless variable refresh\n");
4301 mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
4302 SDE_EVT32(curr_refresh_rate, adj_mode.timing.refresh_rate,
4303 cur_mode.timing.h_front_porch,
4304 adj_mode.timing.h_front_porch);
4305 }
4306
4307error:
4308 mutex_unlock(&display->display_lock);
4309 return rc;
4310}
4311
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004312int dsi_display_validate_mode(struct dsi_display *display,
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07004313 struct dsi_display_mode *mode,
4314 u32 flags)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004315{
4316 int rc = 0;
4317 int i;
4318 struct dsi_display_ctrl *ctrl;
4319 struct dsi_display_mode adj_mode;
4320
4321 if (!display || !mode) {
4322 pr_err("Invalid params\n");
4323 return -EINVAL;
4324 }
4325
4326 mutex_lock(&display->display_lock);
4327
4328 adj_mode = *mode;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07004329 adjust_timing_by_ctrl_count(display, &adj_mode);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004330
4331 rc = dsi_panel_validate_mode(display->panel, &adj_mode);
4332 if (rc) {
4333 pr_err("[%s] panel mode validation failed, rc=%d\n",
4334 display->name, rc);
4335 goto error;
4336 }
4337
4338 for (i = 0; i < display->ctrl_count; i++) {
4339 ctrl = &display->ctrl[i];
4340 rc = dsi_ctrl_validate_timing(ctrl->ctrl, &adj_mode.timing);
4341 if (rc) {
4342 pr_err("[%s] ctrl mode validation failed, rc=%d\n",
4343 display->name, rc);
4344 goto error;
4345 }
4346
4347 rc = dsi_phy_validate_mode(ctrl->phy, &adj_mode.timing);
4348 if (rc) {
4349 pr_err("[%s] phy mode validation failed, rc=%d\n",
4350 display->name, rc);
4351 goto error;
4352 }
4353 }
4354
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07004355 if ((flags & DSI_VALIDATE_FLAG_ALLOW_ADJUST) &&
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05004356 (mode->dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS)) {
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07004357 rc = dsi_display_validate_mode_seamless(display, mode);
4358 if (rc) {
4359 pr_err("[%s] seamless not possible rc=%d\n",
4360 display->name, rc);
4361 goto error;
4362 }
4363 }
4364
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004365error:
4366 mutex_unlock(&display->display_lock);
4367 return rc;
4368}
4369
4370int dsi_display_set_mode(struct dsi_display *display,
4371 struct dsi_display_mode *mode,
4372 u32 flags)
4373{
4374 int rc = 0;
4375 struct dsi_display_mode adj_mode;
4376
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004377 if (!display || !mode || !display->panel) {
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004378 pr_err("Invalid params\n");
4379 return -EINVAL;
4380 }
4381
4382 mutex_lock(&display->display_lock);
4383
4384 adj_mode = *mode;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07004385 adjust_timing_by_ctrl_count(display, &adj_mode);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004386
4387 rc = dsi_display_validate_mode_set(display, &adj_mode, flags);
4388 if (rc) {
4389 pr_err("[%s] mode cannot be set\n", display->name);
4390 goto error;
4391 }
4392
4393 rc = dsi_display_set_mode_sub(display, &adj_mode, flags);
4394 if (rc) {
4395 pr_err("[%s] failed to set mode\n", display->name);
4396 goto error;
4397 }
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07004398
4399 if (!display->panel->cur_mode) {
4400 display->panel->cur_mode =
4401 kzalloc(sizeof(struct dsi_display_mode), GFP_KERNEL);
4402 if (!display->panel->cur_mode) {
4403 rc = -ENOMEM;
4404 goto error;
4405 }
4406 }
4407
4408 memcpy(display->panel->cur_mode, &adj_mode, sizeof(adj_mode));
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004409error:
4410 mutex_unlock(&display->display_lock);
4411 return rc;
4412}
4413
4414int dsi_display_set_tpg_state(struct dsi_display *display, bool enable)
4415{
4416 int rc = 0;
4417 int i;
4418 struct dsi_display_ctrl *ctrl;
4419
4420 if (!display) {
4421 pr_err("Invalid params\n");
4422 return -EINVAL;
4423 }
4424
4425 for (i = 0; i < display->ctrl_count; i++) {
4426 ctrl = &display->ctrl[i];
4427 rc = dsi_ctrl_set_tpg_state(ctrl->ctrl, enable);
4428 if (rc) {
4429 pr_err("[%s] failed to set tpg state for host_%d\n",
4430 display->name, i);
4431 goto error;
4432 }
4433 }
4434
4435 display->is_tpg_enabled = enable;
4436error:
4437 return rc;
4438}
4439
Jeykumar Sankarana7c7bbe2017-05-31 18:12:05 -07004440static int dsi_display_pre_switch(struct dsi_display *display)
4441{
4442 int rc = 0;
4443
4444 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
4445 DSI_CORE_CLK, DSI_CLK_ON);
4446 if (rc) {
4447 pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
4448 display->name, rc);
4449 goto error;
4450 }
4451
4452 rc = dsi_display_ctrl_update(display);
4453 if (rc) {
4454 pr_err("[%s] failed to update DSI controller, rc=%d\n",
4455 display->name, rc);
4456 goto error_ctrl_clk_off;
4457 }
4458
4459 rc = dsi_display_set_clk_src(display);
4460 if (rc) {
4461 pr_err("[%s] failed to set DSI link clock source, rc=%d\n",
4462 display->name, rc);
4463 goto error_ctrl_deinit;
4464 }
4465
4466 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
4467 DSI_LINK_CLK, DSI_CLK_ON);
4468 if (rc) {
4469 pr_err("[%s] failed to enable DSI link clocks, rc=%d\n",
4470 display->name, rc);
4471 goto error_ctrl_deinit;
4472 }
4473
4474 goto error;
4475
4476error_ctrl_deinit:
4477 (void)dsi_display_ctrl_deinit(display);
4478error_ctrl_clk_off:
4479 (void)dsi_display_clk_ctrl(display->dsi_clk_handle,
4480 DSI_CORE_CLK, DSI_CLK_OFF);
4481error:
4482 return rc;
4483}
4484
Sandeep Panda11b20d82017-06-19 12:57:27 +05304485static void dsi_display_handle_fifo_underflow(struct work_struct *work)
4486{
4487 struct dsi_display *display = NULL;
4488
4489 display = container_of(work, struct dsi_display, fifo_underflow_work);
4490 if (!display)
4491 return;
4492 pr_debug("handle DSI FIFO underflow error\n");
4493
4494 dsi_display_clk_ctrl(display->dsi_clk_handle,
4495 DSI_ALL_CLKS, DSI_CLK_ON);
4496 dsi_display_soft_reset(display);
4497 dsi_display_clk_ctrl(display->dsi_clk_handle,
4498 DSI_ALL_CLKS, DSI_CLK_OFF);
4499}
4500
4501static void dsi_display_handle_fifo_overflow(struct work_struct *work)
4502{
4503 struct dsi_display *display = NULL;
4504 struct dsi_display_ctrl *ctrl;
4505 int i, rc;
4506 int mask = BIT(20); /* clock lane */
4507 int (*cb_func)(void *event_usr_ptr,
4508 uint32_t event_idx, uint32_t instance_idx,
4509 uint32_t data0, uint32_t data1,
4510 uint32_t data2, uint32_t data3);
4511 void *data;
4512 u32 version = 0;
4513
4514 display = container_of(work, struct dsi_display, fifo_overflow_work);
4515 if (!display || !display->panel ||
4516 (display->panel->panel_mode != DSI_OP_VIDEO_MODE))
4517 return;
4518
4519 pr_debug("handle DSI FIFO overflow error\n");
4520 dsi_display_clk_ctrl(display->dsi_clk_handle,
4521 DSI_ALL_CLKS, DSI_CLK_ON);
4522
4523 /*
4524 * below recovery sequence is not applicable to
4525 * hw version 2.0.0, 2.1.0 and 2.2.0, so return early.
4526 */
4527 ctrl = &display->ctrl[display->clk_master_idx];
4528 version = dsi_ctrl_get_hw_version(ctrl->ctrl);
4529 if (!version || (version < 0x20020001))
4530 goto end;
4531
4532 /* reset ctrl and lanes */
4533 for (i = 0 ; i < display->ctrl_count; i++) {
4534 ctrl = &display->ctrl[i];
4535 rc = dsi_ctrl_reset(ctrl->ctrl, mask);
4536 rc = dsi_phy_lane_reset(ctrl->phy);
4537 }
4538
4539 /* wait for display line count to be in active area */
4540 ctrl = &display->ctrl[display->clk_master_idx];
4541 if (ctrl->ctrl->recovery_cb.event_cb) {
4542 cb_func = ctrl->ctrl->recovery_cb.event_cb;
4543 data = ctrl->ctrl->recovery_cb.event_usr_ptr;
4544 rc = cb_func(data, SDE_CONN_EVENT_VID_FIFO_OVERFLOW,
4545 display->clk_master_idx, 0, 0, 0, 0);
4546 if (rc < 0) {
4547 pr_debug("sde callback failed\n");
4548 goto end;
4549 }
4550 }
4551
4552 /* Enable Video mode for DSI controller */
4553 for (i = 0 ; i < display->ctrl_count; i++) {
4554 ctrl = &display->ctrl[i];
4555 dsi_ctrl_vid_engine_en(ctrl->ctrl, true);
4556 }
4557 /*
4558 * Add sufficient delay to make sure
4559 * pixel transmission has started
4560 */
4561 udelay(200);
4562end:
4563 dsi_display_clk_ctrl(display->dsi_clk_handle,
4564 DSI_ALL_CLKS, DSI_CLK_OFF);
4565}
4566
4567static void dsi_display_handle_lp_rx_timeout(struct work_struct *work)
4568{
4569 struct dsi_display *display = NULL;
4570 struct dsi_display_ctrl *ctrl;
4571 int i, rc;
4572 int mask = (BIT(20) | (0xF << 16)); /* clock lane and 4 data lane */
4573 int (*cb_func)(void *event_usr_ptr,
4574 uint32_t event_idx, uint32_t instance_idx,
4575 uint32_t data0, uint32_t data1,
4576 uint32_t data2, uint32_t data3);
4577 void *data;
4578 u32 version = 0;
4579
Sandeep Panda2d5e2082017-11-19 11:17:21 +05304580 display = container_of(work, struct dsi_display, lp_rx_timeout_work);
4581 if (!display || !display->panel ||
4582 (display->panel->panel_mode != DSI_OP_VIDEO_MODE))
Sandeep Panda11b20d82017-06-19 12:57:27 +05304583 return;
4584 pr_debug("handle DSI LP RX Timeout error\n");
4585
4586 dsi_display_clk_ctrl(display->dsi_clk_handle,
4587 DSI_ALL_CLKS, DSI_CLK_ON);
4588
4589 /*
4590 * below recovery sequence is not applicable to
4591 * hw version 2.0.0, 2.1.0 and 2.2.0, so return early.
4592 */
4593 ctrl = &display->ctrl[display->clk_master_idx];
4594 version = dsi_ctrl_get_hw_version(ctrl->ctrl);
4595 if (!version || (version < 0x20020001))
4596 goto end;
4597
4598 /* reset ctrl and lanes */
4599 for (i = 0 ; i < display->ctrl_count; i++) {
4600 ctrl = &display->ctrl[i];
4601 rc = dsi_ctrl_reset(ctrl->ctrl, mask);
4602 rc = dsi_phy_lane_reset(ctrl->phy);
4603 }
4604
4605 ctrl = &display->ctrl[display->clk_master_idx];
4606 if (ctrl->ctrl->recovery_cb.event_cb) {
4607 cb_func = ctrl->ctrl->recovery_cb.event_cb;
4608 data = ctrl->ctrl->recovery_cb.event_usr_ptr;
4609 rc = cb_func(data, SDE_CONN_EVENT_VID_FIFO_OVERFLOW,
4610 display->clk_master_idx, 0, 0, 0, 0);
4611 if (rc < 0) {
4612 pr_debug("Target is in suspend/shutdown\n");
4613 goto end;
4614 }
4615 }
4616
4617 /* Enable Video mode for DSI controller */
4618 for (i = 0 ; i < display->ctrl_count; i++) {
4619 ctrl = &display->ctrl[i];
4620 dsi_ctrl_vid_engine_en(ctrl->ctrl, true);
4621 }
4622
4623 /*
4624 * Add sufficient delay to make sure
4625 * pixel transmission as started
4626 */
4627 udelay(200);
4628end:
4629 dsi_display_clk_ctrl(display->dsi_clk_handle,
4630 DSI_ALL_CLKS, DSI_CLK_OFF);
4631}
4632
4633static int dsi_display_cb_error_handler(void *data,
4634 uint32_t event_idx, uint32_t instance_idx,
4635 uint32_t data0, uint32_t data1,
4636 uint32_t data2, uint32_t data3)
4637{
4638 struct dsi_display *display = data;
4639
4640 if (!display)
4641 return -EINVAL;
4642
4643 switch (event_idx) {
4644 case DSI_FIFO_UNDERFLOW:
4645 queue_work(display->err_workq, &display->fifo_underflow_work);
4646 break;
4647 case DSI_FIFO_OVERFLOW:
4648 queue_work(display->err_workq, &display->fifo_overflow_work);
4649 break;
4650 case DSI_LP_Rx_TIMEOUT:
4651 queue_work(display->err_workq, &display->lp_rx_timeout_work);
4652 break;
4653 default:
4654 pr_warn("unhandled error interrupt: %d\n", event_idx);
4655 break;
4656 }
4657
4658 return 0;
4659}
4660
4661static void dsi_display_register_error_handler(struct dsi_display *display)
4662{
4663 int i = 0;
4664 struct dsi_display_ctrl *ctrl;
4665 struct dsi_event_cb_info event_info;
4666
4667 if (!display)
4668 return;
4669
4670 display->err_workq = create_singlethread_workqueue("dsi_err_workq");
4671 if (!display->err_workq) {
4672 pr_err("failed to create dsi workq!\n");
4673 return;
4674 }
4675
4676 INIT_WORK(&display->fifo_underflow_work,
4677 dsi_display_handle_fifo_underflow);
4678 INIT_WORK(&display->fifo_overflow_work,
4679 dsi_display_handle_fifo_overflow);
4680 INIT_WORK(&display->lp_rx_timeout_work,
4681 dsi_display_handle_lp_rx_timeout);
4682
4683 memset(&event_info, 0, sizeof(event_info));
4684
4685 event_info.event_cb = dsi_display_cb_error_handler;
4686 event_info.event_usr_ptr = display;
4687
4688 for (i = 0; i < display->ctrl_count; i++) {
4689 ctrl = &display->ctrl[i];
4690 ctrl->ctrl->irq_info.irq_err_cb = event_info;
4691 }
4692}
4693
4694static void dsi_display_unregister_error_handler(struct dsi_display *display)
4695{
4696 int i = 0;
4697 struct dsi_display_ctrl *ctrl;
4698
4699 if (!display)
4700 return;
4701
4702 for (i = 0; i < display->ctrl_count; i++) {
4703 ctrl = &display->ctrl[i];
4704 memset(&ctrl->ctrl->irq_info.irq_err_cb,
4705 0, sizeof(struct dsi_event_cb_info));
4706 }
4707
4708 if (display->err_workq)
4709 destroy_workqueue(display->err_workq);
4710}
4711
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004712int dsi_display_prepare(struct dsi_display *display)
4713{
4714 int rc = 0;
Jeykumar Sankarana7c7bbe2017-05-31 18:12:05 -07004715 struct dsi_display_mode *mode;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004716
4717 if (!display) {
4718 pr_err("Invalid params\n");
4719 return -EINVAL;
4720 }
4721
Jeykumar Sankarana7c7bbe2017-05-31 18:12:05 -07004722 if (!display->panel->cur_mode) {
4723 pr_err("no valid mode set for the display");
4724 return -EINVAL;
4725 }
4726
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004727 mutex_lock(&display->display_lock);
4728
Jeykumar Sankarana7c7bbe2017-05-31 18:12:05 -07004729 mode = display->panel->cur_mode;
4730
4731 if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
4732 /* update dsi ctrl for new mode */
4733 rc = dsi_display_pre_switch(display);
4734 if (rc)
4735 pr_err("[%s] panel pre-prepare-res-switch failed, rc=%d\n",
4736 display->name, rc);
4737
4738 goto error;
4739 }
4740
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07004741 if (!display->is_cont_splash_enabled) {
4742 /*
4743 * For continuous splash usecase we skip panel
4744 * pre prepare since the regulator vote is already
4745 * taken care in splash resource init
4746 */
4747 rc = dsi_panel_pre_prepare(display->panel);
4748 if (rc) {
4749 pr_err("[%s] panel pre-prepare failed, rc=%d\n",
4750 display->name, rc);
4751 goto error;
4752 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004753 }
4754
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05304755 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
4756 DSI_CORE_CLK, DSI_CLK_ON);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004757 if (rc) {
4758 pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
4759 display->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05304760 goto error_panel_post_unprep;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004761 }
4762
Lei Chen529da982017-10-24 16:23:42 +08004763 /*
4764 * If ULPS during suspend feature is enabled, then DSI PHY was
4765 * left on during suspend. In this case, we do not need to reset/init
4766 * PHY. This would have already been done when the CORE clocks are
4767 * turned on. However, if cont splash is disabled, the first time DSI
4768 * is powered on, phy init needs to be done unconditionally.
4769 */
4770 if (!display->panel->ulps_suspend_enabled || !display->ulps_enabled) {
4771 rc = dsi_display_phy_sw_reset(display);
4772 if (rc) {
4773 pr_err("[%s] failed to reset phy, rc=%d\n",
4774 display->name, rc);
4775 goto error_ctrl_clk_off;
4776 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004777
Lei Chen529da982017-10-24 16:23:42 +08004778 rc = dsi_display_phy_enable(display);
4779 if (rc) {
4780 pr_err("[%s] failed to enable DSI PHY, rc=%d\n",
4781 display->name, rc);
4782 goto error_ctrl_clk_off;
4783 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004784 }
4785
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07004786 rc = dsi_display_set_clk_src(display);
4787 if (rc) {
4788 pr_err("[%s] failed to set DSI link clock source, rc=%d\n",
4789 display->name, rc);
4790 goto error_phy_disable;
4791 }
4792
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004793 rc = dsi_display_ctrl_init(display);
4794 if (rc) {
4795 pr_err("[%s] failed to setup DSI controller, rc=%d\n",
4796 display->name, rc);
4797 goto error_phy_disable;
4798 }
Sandeep Panda11b20d82017-06-19 12:57:27 +05304799 /* Set up DSI ERROR event callback */
4800 dsi_display_register_error_handler(display);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004801
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07004802 rc = dsi_display_ctrl_host_enable(display);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05304803 if (rc) {
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07004804 pr_err("[%s] failed to enable DSI host, rc=%d\n",
4805 display->name, rc);
Veera Sundaram Sankaran518a8632017-05-01 16:37:55 -07004806 goto error_ctrl_deinit;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05304807 }
4808
4809 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
4810 DSI_LINK_CLK, DSI_CLK_ON);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004811 if (rc) {
4812 pr_err("[%s] failed to enable DSI link clocks, rc=%d\n",
4813 display->name, rc);
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07004814 goto error_host_engine_off;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004815 }
4816
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07004817 rc = dsi_display_soft_reset(display);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004818 if (rc) {
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07004819 pr_err("[%s] failed soft reset, rc=%d\n", display->name, rc);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004820 goto error_ctrl_link_off;
4821 }
4822
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07004823 if (!display->is_cont_splash_enabled) {
4824 /*
4825 * For continuous splash usecase we skip panel
4826 * prepare since the pnael is already in
4827 * active state and panel on commands are not needed
4828 */
4829 rc = dsi_panel_prepare(display->panel);
4830 if (rc) {
4831 pr_err("[%s] panel prepare failed, rc=%d\n",
4832 display->name, rc);
4833 goto error_ctrl_link_off;
4834 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004835 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004836 goto error;
4837
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004838error_ctrl_link_off:
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05304839 (void)dsi_display_clk_ctrl(display->dsi_clk_handle,
4840 DSI_LINK_CLK, DSI_CLK_OFF);
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07004841error_host_engine_off:
4842 (void)dsi_display_ctrl_host_disable(display);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004843error_ctrl_deinit:
4844 (void)dsi_display_ctrl_deinit(display);
4845error_phy_disable:
4846 (void)dsi_display_phy_disable(display);
4847error_ctrl_clk_off:
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05304848 (void)dsi_display_clk_ctrl(display->dsi_clk_handle,
4849 DSI_CORE_CLK, DSI_CLK_OFF);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07004850error_panel_post_unprep:
4851 (void)dsi_panel_post_unprepare(display->panel);
4852error:
4853 mutex_unlock(&display->display_lock);
4854 return rc;
4855}
4856
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04004857static int dsi_display_calc_ctrl_roi(const struct dsi_display *display,
4858 const struct dsi_display_ctrl *ctrl,
4859 const struct msm_roi_list *req_rois,
4860 struct dsi_rect *out_roi)
4861{
4862 const struct dsi_rect *bounds = &ctrl->ctrl->mode_bounds;
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07004863 struct dsi_display_mode *cur_mode;
4864 struct msm_roi_caps *roi_caps;
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04004865 struct dsi_rect req_roi = { 0 };
4866 int rc = 0;
4867
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07004868 cur_mode = display->panel->cur_mode;
4869 if (!cur_mode)
4870 return 0;
4871
4872 roi_caps = &cur_mode->priv_info->roi_caps;
4873 if (req_rois->num_rects > roi_caps->num_roi) {
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04004874 pr_err("request for %d rois greater than max %d\n",
4875 req_rois->num_rects,
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07004876 roi_caps->num_roi);
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04004877 rc = -EINVAL;
4878 goto exit;
4879 }
4880
4881 /**
4882 * if no rois, user wants to reset back to full resolution
4883 * note: h_active is already divided by ctrl_count
4884 */
4885 if (!req_rois->num_rects) {
4886 *out_roi = *bounds;
4887 goto exit;
4888 }
4889
4890 /* intersect with the bounds */
4891 req_roi.x = req_rois->roi[0].x1;
4892 req_roi.y = req_rois->roi[0].y1;
4893 req_roi.w = req_rois->roi[0].x2 - req_rois->roi[0].x1;
4894 req_roi.h = req_rois->roi[0].y2 - req_rois->roi[0].y1;
4895 dsi_rect_intersect(&req_roi, bounds, out_roi);
4896
4897exit:
4898 /* adjust the ctrl origin to be top left within the ctrl */
4899 out_roi->x = out_roi->x - bounds->x;
4900
4901 pr_debug("ctrl%d:%d: req (%d,%d,%d,%d) bnd (%d,%d,%d,%d) out (%d,%d,%d,%d)\n",
4902 ctrl->dsi_ctrl_idx, ctrl->ctrl->cell_index,
4903 req_roi.x, req_roi.y, req_roi.w, req_roi.h,
4904 bounds->x, bounds->y, bounds->w, bounds->h,
4905 out_roi->x, out_roi->y, out_roi->w, out_roi->h);
4906
4907 return rc;
4908}
4909
4910static int dsi_display_set_roi(struct dsi_display *display,
4911 struct msm_roi_list *rois)
4912{
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07004913 struct dsi_display_mode *cur_mode;
4914 struct msm_roi_caps *roi_caps;
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04004915 int rc = 0;
4916 int i;
4917
4918 if (!display || !rois || !display->panel)
4919 return -EINVAL;
4920
Jeykumar Sankaran736d79d2017-10-05 17:44:24 -07004921 cur_mode = display->panel->cur_mode;
4922 if (!cur_mode)
4923 return 0;
4924
4925 roi_caps = &cur_mode->priv_info->roi_caps;
4926 if (!roi_caps->enabled)
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04004927 return 0;
4928
4929 for (i = 0; i < display->ctrl_count; i++) {
4930 struct dsi_display_ctrl *ctrl = &display->ctrl[i];
4931 struct dsi_rect ctrl_roi;
4932 bool changed = false;
4933
4934 rc = dsi_display_calc_ctrl_roi(display, ctrl, rois, &ctrl_roi);
4935 if (rc) {
4936 pr_err("dsi_display_calc_ctrl_roi failed rc %d\n", rc);
4937 return rc;
4938 }
4939
4940 rc = dsi_ctrl_set_roi(ctrl->ctrl, &ctrl_roi, &changed);
4941 if (rc) {
4942 pr_err("dsi_ctrl_set_roi failed rc %d\n", rc);
4943 return rc;
4944 }
4945
4946 if (!changed)
4947 continue;
4948
4949 /* send the new roi to the panel via dcs commands */
4950 rc = dsi_panel_send_roi_dcs(display->panel, i, &ctrl_roi);
4951 if (rc) {
4952 pr_err("dsi_panel_set_roi failed rc %d\n", rc);
4953 return rc;
4954 }
4955
4956 /* re-program the ctrl with the timing based on the new roi */
4957 rc = dsi_ctrl_setup(ctrl->ctrl);
4958 if (rc) {
4959 pr_err("dsi_ctrl_setup failed rc %d\n", rc);
4960 return rc;
4961 }
4962 }
4963
4964 return rc;
4965}
4966
Lloyd Atkinson05d75512017-01-17 14:45:51 -05004967int dsi_display_pre_kickoff(struct dsi_display *display,
4968 struct msm_display_kickoff_params *params)
4969{
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04004970 int rc = 0;
4971
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -04004972 /* check and setup MISR */
4973 if (display->misr_enable)
4974 _dsi_display_setup_misr(display);
4975
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04004976 rc = dsi_display_set_roi(display, params->rois);
4977
4978 return rc;
Lloyd Atkinson05d75512017-01-17 14:45:51 -05004979}
4980
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07004981int dsi_display_config_ctrl_for_cont_splash(struct dsi_display *display)
4982{
4983 int rc = 0;
4984
4985 if (!display || !display->panel) {
4986 pr_err("Invalid params\n");
4987 return -EINVAL;
4988 }
4989
4990 if (!display->panel->cur_mode) {
4991 pr_err("no valid mode set for the display");
4992 return -EINVAL;
4993 }
4994
4995 if (!display->is_cont_splash_enabled)
4996 return 0;
4997
4998 if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
4999 rc = dsi_display_vid_engine_enable(display);
5000 if (rc) {
5001 pr_err("[%s]failed to enable DSI video engine, rc=%d\n",
5002 display->name, rc);
5003 goto error_out;
5004 }
5005 } else if (display->config.panel_mode == DSI_OP_CMD_MODE) {
5006 rc = dsi_display_cmd_engine_enable(display);
5007 if (rc) {
5008 pr_err("[%s]failed to enable DSI cmd engine, rc=%d\n",
5009 display->name, rc);
5010 goto error_out;
5011 }
5012 } else {
5013 pr_err("[%s] Invalid configuration\n", display->name);
5014 rc = -EINVAL;
5015 }
5016
5017error_out:
5018 return rc;
5019}
5020
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005021int dsi_display_enable(struct dsi_display *display)
5022{
5023 int rc = 0;
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07005024 struct dsi_display_mode *mode;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005025
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07005026 if (!display || !display->panel) {
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005027 pr_err("Invalid params\n");
5028 return -EINVAL;
5029 }
5030
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07005031 if (!display->panel->cur_mode) {
5032 pr_err("no valid mode set for the display");
5033 return -EINVAL;
5034 }
5035
Shashank Babu Chinta Venkata7d608732017-05-31 14:10:26 -07005036 /* Engine states and panel states are populated during splash
5037 * resource init and hence we return early
5038 */
5039 if (display->is_cont_splash_enabled) {
5040
5041 dsi_display_config_ctrl_for_cont_splash(display);
5042
5043 rc = dsi_display_splash_res_cleanup(display);
5044 if (rc) {
5045 pr_err("Continuous splash res cleanup failed, rc=%d\n",
5046 rc);
5047 return -EINVAL;
5048 }
5049
5050 display->panel->panel_initialized = true;
5051 pr_debug("cont splash enabled, display enable not required\n");
5052 return 0;
5053 }
5054
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005055 mutex_lock(&display->display_lock);
5056
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07005057 mode = display->panel->cur_mode;
5058
Jeykumar Sankarana7c7bbe2017-05-31 18:12:05 -07005059 if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
5060 rc = dsi_panel_post_switch(display->panel);
5061 if (rc) {
5062 pr_err("[%s] failed to switch DSI panel mode, rc=%d\n",
5063 display->name, rc);
5064 goto error;
5065 }
5066 } else {
5067 rc = dsi_panel_enable(display->panel);
5068 if (rc) {
5069 pr_err("[%s] failed to enable DSI panel, rc=%d\n",
5070 display->name, rc);
5071 goto error;
5072 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005073 }
5074
Jeykumar Sankaran446a5f12017-05-09 20:30:39 -07005075 if (mode->priv_info->dsc_enabled) {
5076 mode->priv_info->dsc.pic_width *= display->ctrl_count;
Alexander Beykunac182352017-02-27 17:46:51 -05005077 rc = dsi_panel_update_pps(display->panel);
5078 if (rc) {
5079 pr_err("[%s] panel pps cmd update failed, rc=%d\n",
5080 display->name, rc);
5081 goto error;
5082 }
5083 }
5084
Jeykumar Sankarana7c7bbe2017-05-31 18:12:05 -07005085 if (mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) {
5086 rc = dsi_panel_switch(display->panel);
5087 if (rc)
5088 pr_err("[%s] failed to switch DSI panel mode, rc=%d\n",
5089 display->name, rc);
5090
Dhaval Patel1b5605b2017-07-26 18:19:50 -07005091 goto error;
Jeykumar Sankarana7c7bbe2017-05-31 18:12:05 -07005092 }
5093
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07005094 if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
5095 rc = dsi_display_vid_engine_enable(display);
5096 if (rc) {
5097 pr_err("[%s]failed to enable DSI video engine, rc=%d\n",
5098 display->name, rc);
5099 goto error_disable_panel;
5100 }
5101 } else if (display->config.panel_mode == DSI_OP_CMD_MODE) {
5102 rc = dsi_display_cmd_engine_enable(display);
5103 if (rc) {
5104 pr_err("[%s]failed to enable DSI cmd engine, rc=%d\n",
5105 display->name, rc);
5106 goto error_disable_panel;
5107 }
5108 } else {
5109 pr_err("[%s] Invalid configuration\n", display->name);
5110 rc = -EINVAL;
5111 goto error_disable_panel;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005112 }
5113
5114 goto error;
5115
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07005116error_disable_panel:
5117 (void)dsi_panel_disable(display->panel);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005118error:
5119 mutex_unlock(&display->display_lock);
5120 return rc;
5121}
5122
5123int dsi_display_post_enable(struct dsi_display *display)
5124{
5125 int rc = 0;
5126
5127 if (!display) {
5128 pr_err("Invalid params\n");
5129 return -EINVAL;
5130 }
5131
5132 mutex_lock(&display->display_lock);
5133
5134 rc = dsi_panel_post_enable(display->panel);
5135 if (rc)
5136 pr_err("[%s] panel post-enable failed, rc=%d\n",
5137 display->name, rc);
5138
Veera Sundaram Sankaran4e109162017-04-21 10:36:46 -07005139 /* remove the clk vote for CMD mode panels */
5140 if (display->config.panel_mode == DSI_OP_CMD_MODE)
5141 dsi_display_clk_ctrl(display->dsi_clk_handle,
5142 DSI_ALL_CLKS, DSI_CLK_OFF);
5143
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005144 mutex_unlock(&display->display_lock);
5145 return rc;
5146}
5147
5148int dsi_display_pre_disable(struct dsi_display *display)
5149{
5150 int rc = 0;
5151
5152 if (!display) {
5153 pr_err("Invalid params\n");
5154 return -EINVAL;
5155 }
5156
5157 mutex_lock(&display->display_lock);
5158
Veera Sundaram Sankaran4e109162017-04-21 10:36:46 -07005159 /* enable the clk vote for CMD mode panels */
5160 if (display->config.panel_mode == DSI_OP_CMD_MODE)
5161 dsi_display_clk_ctrl(display->dsi_clk_handle,
5162 DSI_ALL_CLKS, DSI_CLK_ON);
5163
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005164 rc = dsi_panel_pre_disable(display->panel);
5165 if (rc)
5166 pr_err("[%s] panel pre-disable failed, rc=%d\n",
5167 display->name, rc);
5168
5169 mutex_unlock(&display->display_lock);
5170 return rc;
5171}
5172
5173int dsi_display_disable(struct dsi_display *display)
5174{
5175 int rc = 0;
5176
5177 if (!display) {
5178 pr_err("Invalid params\n");
5179 return -EINVAL;
5180 }
5181
5182 mutex_lock(&display->display_lock);
5183
5184 rc = dsi_display_wake_up(display);
5185 if (rc)
5186 pr_err("[%s] display wake up failed, rc=%d\n",
5187 display->name, rc);
5188
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07005189 if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
5190 rc = dsi_display_vid_engine_disable(display);
5191 if (rc)
5192 pr_err("[%s]failed to disable DSI vid engine, rc=%d\n",
5193 display->name, rc);
5194 } else if (display->config.panel_mode == DSI_OP_CMD_MODE) {
5195 rc = dsi_display_cmd_engine_disable(display);
5196 if (rc)
5197 pr_err("[%s]failed to disable DSI cmd engine, rc=%d\n",
5198 display->name, rc);
5199 } else {
5200 pr_err("[%s] Invalid configuration\n", display->name);
5201 rc = -EINVAL;
5202 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005203
Clarence Ip9de0bbc2017-03-02 09:56:06 -05005204 rc = dsi_panel_disable(display->panel);
5205 if (rc)
5206 pr_err("[%s] failed to disable DSI panel, rc=%d\n",
5207 display->name, rc);
5208
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005209 mutex_unlock(&display->display_lock);
5210 return rc;
5211}
5212
Alexander Beykunac182352017-02-27 17:46:51 -05005213int dsi_display_update_pps(char *pps_cmd, void *disp)
5214{
5215 struct dsi_display *display;
5216
5217 if (pps_cmd == NULL || disp == NULL) {
5218 pr_err("Invalid parameter\n");
5219 return -EINVAL;
5220 }
5221
5222 display = disp;
5223 mutex_lock(&display->display_lock);
5224 memcpy(display->panel->dsc_pps_cmd, pps_cmd, DSI_CMD_PPS_SIZE);
5225 mutex_unlock(&display->display_lock);
5226
5227 return 0;
5228}
5229
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005230int dsi_display_unprepare(struct dsi_display *display)
5231{
5232 int rc = 0;
5233
5234 if (!display) {
5235 pr_err("Invalid params\n");
5236 return -EINVAL;
5237 }
5238
5239 mutex_lock(&display->display_lock);
5240
5241 rc = dsi_display_wake_up(display);
5242 if (rc)
5243 pr_err("[%s] display wake up failed, rc=%d\n",
5244 display->name, rc);
5245
5246 rc = dsi_panel_unprepare(display->panel);
5247 if (rc)
5248 pr_err("[%s] panel unprepare failed, rc=%d\n",
5249 display->name, rc);
5250
5251 rc = dsi_display_ctrl_host_disable(display);
5252 if (rc)
5253 pr_err("[%s] failed to disable DSI host, rc=%d\n",
5254 display->name, rc);
5255
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05305256 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
5257 DSI_LINK_CLK, DSI_CLK_OFF);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005258 if (rc)
5259 pr_err("[%s] failed to disable Link clocks, rc=%d\n",
5260 display->name, rc);
5261
Sandeep Panda11b20d82017-06-19 12:57:27 +05305262 /* Free up DSI ERROR event callback */
5263 dsi_display_unregister_error_handler(display);
5264
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005265 rc = dsi_display_ctrl_deinit(display);
5266 if (rc)
5267 pr_err("[%s] failed to deinit controller, rc=%d\n",
5268 display->name, rc);
5269
Lei Chen529da982017-10-24 16:23:42 +08005270 if (!display->panel->ulps_suspend_enabled) {
5271 rc = dsi_display_phy_disable(display);
5272 if (rc)
5273 pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
5274 display->name, rc);
5275 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005276
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05305277 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
5278 DSI_CORE_CLK, DSI_CLK_OFF);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005279 if (rc)
5280 pr_err("[%s] failed to disable DSI clocks, rc=%d\n",
5281 display->name, rc);
5282
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07005283 rc = dsi_panel_post_unprepare(display->panel);
5284 if (rc)
5285 pr_err("[%s] panel post-unprepare failed, rc=%d\n",
5286 display->name, rc);
5287
5288 mutex_unlock(&display->display_lock);
5289 return rc;
5290}
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07005291
Clarence Ip3649f8b2016-10-31 09:59:44 -04005292static int __init dsi_display_register(void)
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07005293{
Clarence Ip3649f8b2016-10-31 09:59:44 -04005294 dsi_phy_drv_register();
5295 dsi_ctrl_drv_register();
5296 return platform_driver_register(&dsi_display_driver);
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07005297}
5298
Clarence Ip3649f8b2016-10-31 09:59:44 -04005299static void __exit dsi_display_unregister(void)
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07005300{
5301 platform_driver_unregister(&dsi_display_driver);
Clarence Ip3649f8b2016-10-31 09:59:44 -04005302 dsi_ctrl_drv_unregister();
5303 dsi_phy_drv_unregister();
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07005304}
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07005305module_param_string(dsi_display0, dsi_display_primary, MAX_CMDLINE_PARAM_LEN,
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07005306 0600);
5307MODULE_PARM_DESC(dsi_display0,
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07005308 "msm_drm.dsi_display0=<display node>:<configX> where <display node> is 'primary dsi display node name' and <configX> where x represents index in the topology list");
5309module_param_string(dsi_display1, dsi_display_secondary, MAX_CMDLINE_PARAM_LEN,
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07005310 0600);
5311MODULE_PARM_DESC(dsi_display1,
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07005312 "msm_drm.dsi_display1=<display node>:<configX> where <display node> is 'secondary dsi display node name' and <configX> where x represents index in the topology list");
Clarence Ip3649f8b2016-10-31 09:59:44 -04005313module_init(dsi_display_register);
5314module_exit(dsi_display_unregister);