blob: 34e6d039995df6215575576441bb8369caf64590 [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"
Ajay Singh Parmar571e3012016-05-16 17:55:52 -070031
32#define to_dsi_display(x) container_of(x, struct dsi_display, host)
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -070033#define INT_BASE_10 10
Ajay Singh Parmar571e3012016-05-16 17:55:52 -070034
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -040035#define MISR_BUFF_SIZE 256
36
Ajay Singh Parmar571e3012016-05-16 17:55:52 -070037static DEFINE_MUTEX(dsi_display_list_lock);
38static LIST_HEAD(dsi_display_list);
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -070039static char dsi_display_primary[MAX_CMDLINE_PARAM_LEN];
40static char dsi_display_secondary[MAX_CMDLINE_PARAM_LEN];
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -070041static struct dsi_display_boot_param boot_displays[MAX_DSI_ACTIVE_DISPLAY];
42static struct device_node *default_active_node;
Ajay Singh Parmar64c19192016-06-10 16:44:56 -070043static const struct of_device_id dsi_display_dt_match[] = {
44 {.compatible = "qcom,dsi-display"},
45 {}
46};
47
Ajay Singh Parmar571e3012016-05-16 17:55:52 -070048static struct dsi_display *main_display;
49
Lloyd Atkinsone53b7372017-03-22 17:16:47 -040050void dsi_rect_intersect(const struct dsi_rect *r1,
51 const struct dsi_rect *r2,
52 struct dsi_rect *result)
53{
54 int l, t, r, b;
55
56 if (!r1 || !r2 || !result)
57 return;
58
59 l = max(r1->x, r2->x);
60 t = max(r1->y, r2->y);
61 r = min((r1->x + r1->w), (r2->x + r2->w));
62 b = min((r1->y + r1->h), (r2->y + r2->h));
63
64 if (r <= l || b <= t) {
65 memset(result, 0, sizeof(*result));
66 } else {
67 result->x = l;
68 result->y = t;
69 result->w = r - l;
70 result->h = b - t;
71 }
72}
73
Vishnuvardhan Prodduturi75b96802016-10-17 18:45:55 +053074int dsi_display_set_backlight(void *display, u32 bl_lvl)
75{
76 struct dsi_display *dsi_display = display;
77 struct dsi_panel *panel;
78 int rc = 0;
79
80 if (dsi_display == NULL)
81 return -EINVAL;
82
83 panel = dsi_display->panel;
84
85 rc = dsi_panel_set_backlight(panel, bl_lvl);
86 if (rc)
87 pr_err("unable to set backlight\n");
88
89 return rc;
90}
91
Lloyd Atkinson8c49c582016-11-18 14:23:54 -050092int dsi_display_soft_reset(void *display)
93{
94 struct dsi_display *dsi_display;
95 struct dsi_display_ctrl *ctrl;
96 int rc = 0;
97 int i;
98
99 if (!display)
100 return -EINVAL;
101
102 dsi_display = display;
103
104 for (i = 0 ; i < dsi_display->ctrl_count; i++) {
105 ctrl = &dsi_display->ctrl[i];
106 rc = dsi_ctrl_soft_reset(ctrl->ctrl);
107 if (rc) {
108 pr_err("[%s] failed to soft reset host_%d, rc=%d\n",
109 dsi_display->name, i, rc);
110 break;
111 }
112 }
113
114 return rc;
115}
Ping Li8430ee12017-02-24 14:14:44 -0800116
117enum dsi_pixel_format dsi_display_get_dst_format(void *display)
118{
119 enum dsi_pixel_format format = DSI_PIXEL_FORMAT_MAX;
120 struct dsi_display *dsi_display = (struct dsi_display *)display;
121
122 if (!dsi_display || !dsi_display->panel) {
123 pr_err("Invalid params(s) dsi_display %pK, panel %pK\n",
124 dsi_display,
125 ((dsi_display) ? dsi_display->panel : NULL));
126 return format;
127 }
128
129 format = dsi_display->panel->host_config.dst_format;
130 return format;
131}
132
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400133static void _dsi_display_setup_misr(struct dsi_display *display)
134{
135 int i;
136
137 for (i = 0; i < display->ctrl_count; i++) {
138 dsi_ctrl_setup_misr(display->ctrl[i].ctrl,
139 display->misr_enable,
140 display->misr_frame_count);
141 }
142}
143
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700144static ssize_t debugfs_dump_info_read(struct file *file,
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400145 char __user *user_buf,
146 size_t user_len,
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700147 loff_t *ppos)
148{
149 struct dsi_display *display = file->private_data;
150 char *buf;
151 u32 len = 0;
152 int i;
153
154 if (!display)
155 return -ENODEV;
156
157 if (*ppos)
158 return 0;
159
160 buf = kzalloc(SZ_4K, GFP_KERNEL);
161 if (!buf)
162 return -ENOMEM;
163
164 len += snprintf(buf + len, (SZ_4K - len), "name = %s\n", display->name);
165 len += snprintf(buf + len, (SZ_4K - len),
166 "\tResolution = %dx%d\n",
167 display->config.video_timing.h_active,
168 display->config.video_timing.v_active);
169
170 for (i = 0; i < display->ctrl_count; i++) {
171 len += snprintf(buf + len, (SZ_4K - len),
172 "\tCTRL_%d:\n\t\tctrl = %s\n\t\tphy = %s\n",
173 i, display->ctrl[i].ctrl->name,
174 display->ctrl[i].phy->name);
175 }
176
177 len += snprintf(buf + len, (SZ_4K - len),
178 "\tPanel = %s\n", display->panel->name);
179
180 len += snprintf(buf + len, (SZ_4K - len),
181 "\tClock master = %s\n",
182 display->ctrl[display->clk_master_idx].ctrl->name);
183
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400184 if (copy_to_user(user_buf, buf, len)) {
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700185 kfree(buf);
186 return -EFAULT;
187 }
188
189 *ppos += len;
190
191 kfree(buf);
192 return len;
193}
194
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400195static ssize_t debugfs_misr_setup(struct file *file,
196 const char __user *user_buf,
197 size_t user_len,
198 loff_t *ppos)
199{
200 struct dsi_display *display = file->private_data;
201 char *buf;
202 int rc = 0;
203 size_t len;
204 u32 enable, frame_count;
205
206 if (!display)
207 return -ENODEV;
208
209 if (*ppos)
210 return 0;
211
212 buf = kzalloc(MISR_BUFF_SIZE, GFP_KERNEL);
213 if (!buf)
214 return -ENOMEM;
215
216 /* leave room for termination char */
217 len = min_t(size_t, user_len, MISR_BUFF_SIZE - 1);
218 if (copy_from_user(buf, user_buf, len)) {
219 rc = -EINVAL;
220 goto error;
221 }
222
223 buf[len] = '\0'; /* terminate the string */
224
225 if (sscanf(buf, "%u %u", &enable, &frame_count) != 2) {
226 rc = -EINVAL;
227 goto error;
228 }
229
230 display->misr_enable = enable;
231 display->misr_frame_count = frame_count;
232
233 mutex_lock(&display->display_lock);
234 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
235 DSI_CORE_CLK, DSI_CLK_ON);
236 if (rc) {
237 pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
238 display->name, rc);
239 goto unlock;
240 }
241
242 _dsi_display_setup_misr(display);
243
244 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
245 DSI_CORE_CLK, DSI_CLK_OFF);
246 if (rc) {
247 pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
248 display->name, rc);
249 goto unlock;
250 }
251
252 rc = user_len;
253unlock:
254 mutex_unlock(&display->display_lock);
255error:
256 kfree(buf);
257 return rc;
258}
259
260static ssize_t debugfs_misr_read(struct file *file,
261 char __user *user_buf,
262 size_t user_len,
263 loff_t *ppos)
264{
265 struct dsi_display *display = file->private_data;
266 char *buf;
267 u32 len = 0;
268 int rc = 0;
269 struct dsi_ctrl *dsi_ctrl;
270 int i;
271 u32 misr;
272 size_t max_len = min_t(size_t, user_len, MISR_BUFF_SIZE);
273
274 if (!display)
275 return -ENODEV;
276
277 if (*ppos)
278 return 0;
279
280 buf = kzalloc(max_len, GFP_KERNEL);
281 if (!buf)
282 return -ENOMEM;
283
284 mutex_lock(&display->display_lock);
285 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
286 DSI_CORE_CLK, DSI_CLK_ON);
287 if (rc) {
288 pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
289 display->name, rc);
290 goto error;
291 }
292
293 for (i = 0; i < display->ctrl_count; i++) {
294 dsi_ctrl = display->ctrl[i].ctrl;
295 misr = dsi_ctrl_collect_misr(display->ctrl[i].ctrl);
296
297 len += snprintf((buf + len), max_len - len,
298 "DSI_%d MISR: 0x%x\n", dsi_ctrl->cell_index, misr);
299
300 if (len >= max_len)
301 break;
302 }
303
304 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
305 DSI_CORE_CLK, DSI_CLK_OFF);
306 if (rc) {
307 pr_err("[%s] failed to disable DSI core clocks, rc=%d\n",
308 display->name, rc);
309 goto error;
310 }
311
312 if (copy_to_user(user_buf, buf, len)) {
313 rc = -EFAULT;
314 goto error;
315 }
316
317 *ppos += len;
318
319error:
320 mutex_unlock(&display->display_lock);
321 kfree(buf);
322 return len;
323}
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700324
325static const struct file_operations dump_info_fops = {
326 .open = simple_open,
327 .read = debugfs_dump_info_read,
328};
329
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400330static const struct file_operations misr_data_fops = {
331 .open = simple_open,
332 .read = debugfs_misr_read,
333 .write = debugfs_misr_setup,
334};
335
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700336static int dsi_display_debugfs_init(struct dsi_display *display)
337{
338 int rc = 0;
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400339 struct dentry *dir, *dump_file, *misr_data;
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700340
341 dir = debugfs_create_dir(display->name, NULL);
342 if (IS_ERR_OR_NULL(dir)) {
343 rc = PTR_ERR(dir);
344 pr_err("[%s] debugfs create dir failed, rc = %d\n",
345 display->name, rc);
346 goto error;
347 }
348
349 dump_file = debugfs_create_file("dump_info",
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400350 0400,
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700351 dir,
352 display,
353 &dump_info_fops);
354 if (IS_ERR_OR_NULL(dump_file)) {
355 rc = PTR_ERR(dump_file);
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -0400356 pr_err("[%s] debugfs create dump info file failed, rc=%d\n",
357 display->name, rc);
358 goto error_remove_dir;
359 }
360
361 misr_data = debugfs_create_file("misr_data",
362 0600,
363 dir,
364 display,
365 &misr_data_fops);
366 if (IS_ERR_OR_NULL(misr_data)) {
367 rc = PTR_ERR(misr_data);
368 pr_err("[%s] debugfs create misr datafile failed, rc=%d\n",
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700369 display->name, rc);
370 goto error_remove_dir;
371 }
372
373 display->root = dir;
374 return rc;
375error_remove_dir:
376 debugfs_remove(dir);
377error:
378 return rc;
379}
380
Clarence Ip3649f8b2016-10-31 09:59:44 -0400381static int dsi_display_debugfs_deinit(struct dsi_display *display)
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700382{
Lloyd Atkinson1be10b62016-10-04 09:46:08 -0400383 debugfs_remove_recursive(display->root);
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700384
385 return 0;
386}
387
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -0700388static void adjust_timing_by_ctrl_count(const struct dsi_display *display,
389 struct dsi_display_mode *mode)
390{
391 if (display->ctrl_count > 1) {
392 mode->timing.h_active /= display->ctrl_count;
393 mode->timing.h_front_porch /= display->ctrl_count;
394 mode->timing.h_sync_width /= display->ctrl_count;
395 mode->timing.h_back_porch /= display->ctrl_count;
396 mode->timing.h_skew /= display->ctrl_count;
397 mode->pixel_clk_khz /= display->ctrl_count;
398 }
399}
400
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530401static int dsi_display_is_ulps_req_valid(struct dsi_display *display,
402 bool enable)
403{
404 /* TODO: make checks based on cont. splash */
405 int splash_enabled = false;
406
407 pr_debug("checking ulps req validity\n");
408
409 if (!dsi_panel_ulps_feature_enabled(display->panel))
410 return false;
411
412 /* TODO: ULPS during suspend */
413 if (!dsi_panel_initialized(display->panel))
414 return false;
415
416 if (enable && display->ulps_enabled) {
417 pr_debug("ULPS already enabled\n");
418 return false;
419 } else if (!enable && !display->ulps_enabled) {
420 pr_debug("ULPS already disabled\n");
421 return false;
422 }
423
424 /*
425 * No need to enter ULPS when transitioning from splash screen to
426 * boot animation since it is expected that the clocks would be turned
427 * right back on.
428 */
429 if (enable && splash_enabled)
430 return false;
431
432 return true;
433}
434
435
436/**
437 * dsi_display_set_ulps() - set ULPS state for DSI lanes.
438 * @dsi_display: DSI display handle.
439 * @enable: enable/disable ULPS.
440 *
441 * ULPS can be enabled/disabled after DSI host engine is turned on.
442 *
443 * Return: error code.
444 */
445static int dsi_display_set_ulps(struct dsi_display *display, bool enable)
446{
447 int rc = 0;
448 int i = 0;
449 struct dsi_display_ctrl *m_ctrl, *ctrl;
450
451
452 if (!display) {
453 pr_err("Invalid params\n");
454 return -EINVAL;
455 }
456
457 if (!dsi_display_is_ulps_req_valid(display, enable)) {
458 pr_debug("%s: skipping ULPS config, enable=%d\n",
459 __func__, enable);
460 return 0;
461 }
462
463 m_ctrl = &display->ctrl[display->cmd_master_idx];
464
465 rc = dsi_ctrl_set_ulps(m_ctrl->ctrl, enable);
466 if (rc) {
467 pr_err("Ulps controller state change(%d) failed\n", enable);
468 return rc;
469 }
470
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700471 rc = dsi_phy_set_ulps(m_ctrl->phy, &display->config, enable,
472 display->clamp_enabled);
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530473 if (rc) {
474 pr_err("Ulps PHY state change(%d) failed\n", enable);
475 return rc;
476 }
477
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530478 for (i = 0; i < display->ctrl_count; i++) {
479 ctrl = &display->ctrl[i];
480 if (!ctrl->ctrl || (ctrl == m_ctrl))
481 continue;
482
483 rc = dsi_ctrl_set_ulps(ctrl->ctrl, enable);
484 if (rc) {
485 pr_err("Ulps controller state change(%d) failed\n",
486 enable);
487 return rc;
488 }
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530489
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -0700490 rc = dsi_phy_set_ulps(ctrl->phy, &display->config, enable,
491 display->clamp_enabled);
Padmanabhan Komanduru56611ef2016-12-19 12:21:11 +0530492 if (rc) {
493 pr_err("Ulps PHY state change(%d) failed\n", enable);
494 return rc;
495 }
496
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530497 }
498 display->ulps_enabled = enable;
499 return 0;
500}
501
502/**
503 * dsi_display_set_clamp() - set clamp state for DSI IO.
504 * @dsi_display: DSI display handle.
505 * @enable: enable/disable clamping.
506 *
507 * Return: error code.
508 */
509static int dsi_display_set_clamp(struct dsi_display *display, bool enable)
510{
511 int rc = 0;
512 int i = 0;
513 struct dsi_display_ctrl *m_ctrl, *ctrl;
514 bool ulps_enabled = false;
515
516
517 if (!display) {
518 pr_err("Invalid params\n");
519 return -EINVAL;
520 }
521
522 m_ctrl = &display->ctrl[display->cmd_master_idx];
523 ulps_enabled = display->ulps_enabled;
524
525 rc = dsi_ctrl_set_clamp_state(m_ctrl->ctrl, enable, ulps_enabled);
526 if (rc) {
527 pr_err("DSI Clamp state change(%d) failed\n", enable);
528 return rc;
529 }
530
531 for (i = 0; i < display->ctrl_count; i++) {
532 ctrl = &display->ctrl[i];
533 if (!ctrl->ctrl || (ctrl == m_ctrl))
534 continue;
535
536 rc = dsi_ctrl_set_clamp_state(ctrl->ctrl, enable, ulps_enabled);
537 if (rc) {
538 pr_err("DSI Clamp state change(%d) failed\n", enable);
539 return rc;
540 }
541 }
542 display->clamp_enabled = enable;
543 return 0;
544}
545
546/**
547 * dsi_display_setup_ctrl() - setup DSI controller.
548 * @dsi_display: DSI display handle.
549 *
550 * Return: error code.
551 */
552static int dsi_display_ctrl_setup(struct dsi_display *display)
553{
554 int rc = 0;
555 int i = 0;
556 struct dsi_display_ctrl *ctrl, *m_ctrl;
557
558
559 if (!display) {
560 pr_err("Invalid params\n");
561 return -EINVAL;
562 }
563
564 m_ctrl = &display->ctrl[display->cmd_master_idx];
565 rc = dsi_ctrl_setup(m_ctrl->ctrl);
566 if (rc) {
567 pr_err("DSI controller setup failed\n");
568 return rc;
569 }
570
571 for (i = 0; i < display->ctrl_count; i++) {
572 ctrl = &display->ctrl[i];
573 if (!ctrl->ctrl || (ctrl == m_ctrl))
574 continue;
575
576 rc = dsi_ctrl_setup(ctrl->ctrl);
577 if (rc) {
578 pr_err("DSI controller setup failed\n");
579 return rc;
580 }
581 }
582 return 0;
583}
584
585static int dsi_display_phy_enable(struct dsi_display *display);
586
587/**
588 * dsi_display_phy_idle_on() - enable DSI PHY while coming out of idle screen.
589 * @dsi_display: DSI display handle.
590 * @enable: enable/disable DSI PHY.
591 *
592 * Return: error code.
593 */
594static int dsi_display_phy_idle_on(struct dsi_display *display,
595 bool mmss_clamp)
596{
597 int rc = 0;
598 int i = 0;
599 struct dsi_display_ctrl *m_ctrl, *ctrl;
600
601
602 if (!display) {
603 pr_err("Invalid params\n");
604 return -EINVAL;
605 }
606
607 if (mmss_clamp && !display->phy_idle_power_off) {
608 dsi_display_phy_enable(display);
609 return 0;
610 }
611
612 m_ctrl = &display->ctrl[display->cmd_master_idx];
613 rc = dsi_phy_idle_ctrl(m_ctrl->phy, true);
614 if (rc) {
615 pr_err("DSI controller setup failed\n");
616 return rc;
617 }
618
619 for (i = 0; i < display->ctrl_count; i++) {
620 ctrl = &display->ctrl[i];
621 if (!ctrl->ctrl || (ctrl == m_ctrl))
622 continue;
623
624 rc = dsi_phy_idle_ctrl(ctrl->phy, true);
625 if (rc) {
626 pr_err("DSI controller setup failed\n");
627 return rc;
628 }
629 }
630 display->phy_idle_power_off = false;
631 return 0;
632}
633
634/**
635 * dsi_display_phy_idle_off() - disable DSI PHY while going to idle screen.
636 * @dsi_display: DSI display handle.
637 * @enable: enable/disable DSI PHY.
638 *
639 * Return: error code.
640 */
641static int dsi_display_phy_idle_off(struct dsi_display *display)
642{
643 int rc = 0;
644 int i = 0;
645 struct dsi_display_ctrl *m_ctrl, *ctrl;
646
647 if (!display) {
648 pr_err("Invalid params\n");
649 return -EINVAL;
650 }
651
652 if (!display->panel->allow_phy_power_off) {
653 pr_debug("panel doesn't support this feature\n");
654 return 0;
655 }
656
657 m_ctrl = &display->ctrl[display->cmd_master_idx];
658
659 rc = dsi_phy_idle_ctrl(m_ctrl->phy, false);
660 if (rc) {
661 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
662 display->name, rc);
663 return rc;
664 }
665
666 for (i = 0; i < display->ctrl_count; i++) {
667 ctrl = &display->ctrl[i];
668 if (!ctrl->ctrl || (ctrl == m_ctrl))
669 continue;
670
671 rc = dsi_phy_idle_ctrl(ctrl->phy, false);
672 if (rc) {
673 pr_err("DSI controller setup failed\n");
674 return rc;
675 }
676 }
677 display->phy_idle_power_off = true;
678 return 0;
679}
680
Clarence Ip80ada7f2017-05-04 09:55:21 -0700681void dsi_display_enable_event(struct dsi_display *display,
682 uint32_t event_idx, struct dsi_event_cb_info *event_info,
683 bool enable)
684{
685 uint32_t irq_status_idx = DSI_STATUS_INTERRUPT_COUNT;
686 int i;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530687
Clarence Ip80ada7f2017-05-04 09:55:21 -0700688 if (!display) {
689 pr_err("invalid display\n");
690 return;
691 }
692
693 if (event_info)
694 event_info->event_idx = event_idx;
695
696 switch (event_idx) {
697 case SDE_CONN_EVENT_VID_DONE:
698 irq_status_idx = DSI_SINT_VIDEO_MODE_FRAME_DONE;
699 break;
700 case SDE_CONN_EVENT_CMD_DONE:
701 irq_status_idx = DSI_SINT_CMD_FRAME_DONE;
702 break;
703 default:
704 /* nothing to do */
705 pr_debug("[%s] unhandled event %d\n", display->name, event_idx);
706 return;
707 }
708
709 if (enable) {
710 for (i = 0; i < display->ctrl_count; i++)
711 dsi_ctrl_enable_status_interrupt(
712 display->ctrl[i].ctrl, irq_status_idx,
713 event_info);
714 } else {
715 for (i = 0; i < display->ctrl_count; i++)
716 dsi_ctrl_disable_status_interrupt(
717 display->ctrl[i].ctrl, irq_status_idx);
718 }
719}
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530720
Ajay Singh Parmar571e3012016-05-16 17:55:52 -0700721static int dsi_display_ctrl_power_on(struct dsi_display *display)
722{
723 int rc = 0;
724 int i;
725 struct dsi_display_ctrl *ctrl;
726
727 /* Sequence does not matter for split dsi usecases */
Ajay Singh Parmar571e3012016-05-16 17:55:52 -0700728 for (i = 0; i < display->ctrl_count; i++) {
729 ctrl = &display->ctrl[i];
730 if (!ctrl->ctrl)
731 continue;
732
733 rc = dsi_ctrl_set_power_state(ctrl->ctrl,
734 DSI_CTRL_POWER_VREG_ON);
735 if (rc) {
736 pr_err("[%s] Failed to set power state, rc=%d\n",
737 ctrl->ctrl->name, rc);
738 goto error;
739 }
740 }
741
742 return rc;
743error:
744 for (i = i - 1; i >= 0; i--) {
745 ctrl = &display->ctrl[i];
746 if (!ctrl->ctrl)
747 continue;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530748 (void)dsi_ctrl_set_power_state(ctrl->ctrl,
749 DSI_CTRL_POWER_VREG_OFF);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -0700750 }
751 return rc;
752}
753
754static int dsi_display_ctrl_power_off(struct dsi_display *display)
755{
756 int rc = 0;
757 int i;
758 struct dsi_display_ctrl *ctrl;
759
760 /* Sequence does not matter for split dsi usecases */
Ajay Singh Parmar571e3012016-05-16 17:55:52 -0700761 for (i = 0; i < display->ctrl_count; i++) {
762 ctrl = &display->ctrl[i];
763 if (!ctrl->ctrl)
764 continue;
765
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530766 rc = dsi_ctrl_set_power_state(ctrl->ctrl,
767 DSI_CTRL_POWER_VREG_OFF);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -0700768 if (rc) {
769 pr_err("[%s] Failed to power off, rc=%d\n",
770 ctrl->ctrl->name, rc);
771 goto error;
772 }
773 }
774error:
775 return rc;
776}
777
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -0700778static int dsi_display_parse_cmdline_topology(unsigned int display_type)
779{
780 char *str = NULL;
781 int top_index = -1;
782
783 if (display_type >= MAX_DSI_ACTIVE_DISPLAY) {
784 pr_err("display_type=%d not supported\n", display_type);
785 return -EINVAL;
786 }
787 if (display_type == DSI_PRIMARY)
788 str = strnstr(dsi_display_primary,
789 ":config", strlen(dsi_display_primary));
790 else
791 str = strnstr(dsi_display_secondary,
792 ":config", strlen(dsi_display_secondary));
793 if (!str)
794 return -EINVAL;
795
796 if (kstrtol(str + strlen(":config"), INT_BASE_10,
797 (unsigned long *)&top_index))
798 return -EINVAL;
799
800 return top_index;
801}
802
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -0700803/**
804 * dsi_display_name_compare()- compare whether DSI display name matches.
805 * @node: Pointer to device node structure
806 * @display_name: Name of display to validate
807 *
808 * Return: returns a bool specifying whether given display is active
809 */
810static bool dsi_display_name_compare(struct device_node *node,
811 const char *display_name, int index)
812{
813 if (index >= MAX_DSI_ACTIVE_DISPLAY) {
814 pr_err("Invalid Index\n");
815 return false;
816 }
817
818 if (boot_displays[index].boot_disp_en) {
819 if (!(strcmp(&boot_displays[index].name[0], display_name))) {
820 boot_displays[index].node = node;
821 return true;
822 }
823 }
824 return false;
825}
826
827/**
828 * dsi_display_parse_boot_display_selection()- Parse DSI boot display name
829 *
830 * Return: returns error status
831 */
832static int dsi_display_parse_boot_display_selection(void)
833{
834 char *pos = NULL;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -0700835 char disp_buf[MAX_CMDLINE_PARAM_LEN] = {'\0'};
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -0700836 int i, j, num_displays;
837
838 if (strlen(dsi_display_primary) == 0)
839 return -EINVAL;
840
841 if ((strlen(dsi_display_secondary) > 0))
842 num_displays = MAX_DSI_ACTIVE_DISPLAY;
843 else {
844 /*
845 * Initialize secondary dsi variables
846 * for the senario where dsi_display1
847 * is null but dsi_display0 is valid
848 */
849
850 /* Max number of displays will be one->only Primary */
851 num_displays = 1;
852 boot_displays[DSI_SECONDARY].is_primary = false;
853 boot_displays[DSI_SECONDARY].name[0] = '\0';
854 }
855
856 for (i = 0; i < num_displays; i++) {
857 boot_displays[i].is_primary = false;
858 if (i == DSI_PRIMARY) {
859 strlcpy(disp_buf, &dsi_display_primary[0],
860 sizeof(dsi_display_primary));
861 pos = strnstr(disp_buf, ":",
862 sizeof(dsi_display_primary));
863 } else {
864 strlcpy(disp_buf, &dsi_display_secondary[0],
865 sizeof(dsi_display_secondary));
866 pos = strnstr(disp_buf, ":",
867 sizeof(dsi_display_secondary));
868 }
869 /* Use ':' as a delimiter to retrieve the display name */
870 if (!pos) {
871 pr_debug("display name[%s]is not valid\n", disp_buf);
872 continue;
873 }
874
875 for (j = 0; (disp_buf + j) < pos; j++)
876 boot_displays[i].name[j] = *(disp_buf + j);
877 boot_displays[i].name[j] = '\0';
878
879 if (i == DSI_PRIMARY) {
880 boot_displays[i].is_primary = true;
881 /* Currently, secondary DSI display is not supported */
882 boot_displays[i].boot_disp_en = true;
883 }
884 }
885 return 0;
886}
887
888/**
889 * validate_dsi_display_selection()- validate boot DSI display selection
890 *
891 * Return: returns true when both displays have unique configurations
892 */
893static bool validate_dsi_display_selection(void)
894{
895 int i, j;
896 int rc = 0;
897 int phy_count = 0;
898 int ctrl_count = 0;
899 int index = 0;
900 bool ctrl_flags[MAX_DSI_ACTIVE_DISPLAY] = {false, false};
901 bool phy_flags[MAX_DSI_ACTIVE_DISPLAY] = {false, false};
902 struct device_node *node, *ctrl_node, *phy_node;
903
904 for (i = 0; i < MAX_DSI_ACTIVE_DISPLAY; i++) {
905 node = boot_displays[i].node;
906 ctrl_count = of_count_phandle_with_args(node, "qcom,dsi-ctrl",
907 NULL);
908
909 for (j = 0; j < ctrl_count; j++) {
910 ctrl_node = of_parse_phandle(node, "qcom,dsi-ctrl", j);
911 rc = of_property_read_u32(ctrl_node, "cell-index",
912 &index);
913 of_node_put(ctrl_node);
914 if (rc) {
915 pr_err("cell index not set for ctrl_nodes\n");
916 return false;
917 }
918 if (ctrl_flags[index])
919 return false;
920 ctrl_flags[index] = true;
921 }
922
923 phy_count = of_count_phandle_with_args(node, "qcom,dsi-phy",
924 NULL);
925 for (j = 0; j < phy_count; j++) {
926 phy_node = of_parse_phandle(node, "qcom,dsi-phy", j);
927 rc = of_property_read_u32(phy_node, "cell-index",
928 &index);
929 of_node_put(phy_node);
930 if (rc) {
931 pr_err("cell index not set phy_nodes\n");
932 return false;
933 }
934 if (phy_flags[index])
935 return false;
936 phy_flags[index] = true;
937 }
938 }
939 return true;
940}
941
942struct device_node *dsi_display_get_boot_display(int index)
943{
944
945 pr_err("index = %d\n", index);
946
947 if (boot_displays[index].node)
948 return boot_displays[index].node;
949 else if ((index == (MAX_DSI_ACTIVE_DISPLAY - 1))
950 && (default_active_node))
951 return default_active_node;
952 else
953 return NULL;
954}
955
Ajay Singh Parmar571e3012016-05-16 17:55:52 -0700956static int dsi_display_phy_power_on(struct dsi_display *display)
957{
958 int rc = 0;
959 int i;
960 struct dsi_display_ctrl *ctrl;
961
962 /* Sequence does not matter for split dsi usecases */
Ajay Singh Parmar571e3012016-05-16 17:55:52 -0700963 for (i = 0; i < display->ctrl_count; i++) {
964 ctrl = &display->ctrl[i];
965 if (!ctrl->ctrl)
966 continue;
967
968 rc = dsi_phy_set_power_state(ctrl->phy, true);
969 if (rc) {
970 pr_err("[%s] Failed to set power state, rc=%d\n",
971 ctrl->phy->name, rc);
972 goto error;
973 }
974 }
975
976 return rc;
977error:
978 for (i = i - 1; i >= 0; i--) {
979 ctrl = &display->ctrl[i];
980 if (!ctrl->phy)
981 continue;
982 (void)dsi_phy_set_power_state(ctrl->phy, false);
983 }
984 return rc;
985}
986
987static int dsi_display_phy_power_off(struct dsi_display *display)
988{
989 int rc = 0;
990 int i;
991 struct dsi_display_ctrl *ctrl;
992
993 /* Sequence does not matter for split dsi usecases */
Ajay Singh Parmar571e3012016-05-16 17:55:52 -0700994 for (i = 0; i < display->ctrl_count; i++) {
995 ctrl = &display->ctrl[i];
996 if (!ctrl->phy)
997 continue;
998
999 rc = dsi_phy_set_power_state(ctrl->phy, false);
1000 if (rc) {
1001 pr_err("[%s] Failed to power off, rc=%d\n",
1002 ctrl->ctrl->name, rc);
1003 goto error;
1004 }
1005 }
1006error:
1007 return rc;
1008}
1009
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301010static int dsi_display_set_clk_src(struct dsi_display *display)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001011{
1012 int rc = 0;
1013 int i;
1014 struct dsi_display_ctrl *m_ctrl, *ctrl;
1015
1016 /*
1017 * In case of split DSI usecases, the clock for master controller should
1018 * be enabled before the other controller. Master controller in the
1019 * clock context refers to the controller that sources the clock.
1020 */
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001021 m_ctrl = &display->ctrl[display->clk_master_idx];
1022
1023 rc = dsi_ctrl_set_clock_source(m_ctrl->ctrl,
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301024 &display->clock_info.src_clks);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001025 if (rc) {
1026 pr_err("[%s] failed to set source clocks for master, rc=%d\n",
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301027 display->name, rc);
1028 return rc;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001029 }
1030
1031 /* Turn on rest of the controllers */
1032 for (i = 0; i < display->ctrl_count; i++) {
1033 ctrl = &display->ctrl[i];
1034 if (!ctrl->ctrl || (ctrl == m_ctrl))
1035 continue;
1036
1037 rc = dsi_ctrl_set_clock_source(ctrl->ctrl,
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301038 &display->clock_info.src_clks);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001039 if (rc) {
1040 pr_err("[%s] failed to set source clocks, rc=%d\n",
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301041 display->name, rc);
1042 return rc;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001043 }
1044 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301045 return 0;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001046}
1047
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05301048static int dsi_display_phy_reset_config(struct dsi_display *display,
1049 bool enable)
1050{
1051 int rc = 0;
1052 int i;
1053 struct dsi_display_ctrl *ctrl;
1054
1055 for (i = 0 ; i < display->ctrl_count; i++) {
1056 ctrl = &display->ctrl[i];
1057 rc = dsi_ctrl_phy_reset_config(ctrl->ctrl, enable);
1058 if (rc) {
1059 pr_err("[%s] failed to %s phy reset, rc=%d\n",
1060 display->name, enable ? "mask" : "unmask", rc);
1061 return rc;
1062 }
1063 }
1064 return 0;
1065}
1066
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001067static int dsi_display_ctrl_init(struct dsi_display *display)
1068{
1069 int rc = 0;
1070 int i;
1071 struct dsi_display_ctrl *ctrl;
1072
1073 for (i = 0 ; i < display->ctrl_count; i++) {
1074 ctrl = &display->ctrl[i];
1075 rc = dsi_ctrl_host_init(ctrl->ctrl);
1076 if (rc) {
1077 pr_err("[%s] failed to init host_%d, rc=%d\n",
1078 display->name, i, rc);
1079 goto error_host_deinit;
1080 }
1081 }
1082
1083 return 0;
1084error_host_deinit:
1085 for (i = i - 1; i >= 0; i--) {
1086 ctrl = &display->ctrl[i];
1087 (void)dsi_ctrl_host_deinit(ctrl->ctrl);
1088 }
1089 return rc;
1090}
1091
1092static int dsi_display_ctrl_deinit(struct dsi_display *display)
1093{
1094 int rc = 0;
1095 int i;
1096 struct dsi_display_ctrl *ctrl;
1097
1098 for (i = 0 ; i < display->ctrl_count; i++) {
1099 ctrl = &display->ctrl[i];
1100 rc = dsi_ctrl_host_deinit(ctrl->ctrl);
1101 if (rc) {
1102 pr_err("[%s] failed to deinit host_%d, rc=%d\n",
1103 display->name, i, rc);
1104 }
1105 }
1106
1107 return rc;
1108}
1109
1110static int dsi_display_cmd_engine_enable(struct dsi_display *display)
1111{
1112 int rc = 0;
1113 int i;
1114 struct dsi_display_ctrl *m_ctrl, *ctrl;
1115
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07001116 if (display->cmd_engine_refcount > 0) {
1117 display->cmd_engine_refcount++;
1118 return 0;
1119 }
1120
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001121 m_ctrl = &display->ctrl[display->cmd_master_idx];
1122
1123 rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON);
1124 if (rc) {
1125 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
1126 display->name, rc);
1127 goto error;
1128 }
1129
1130 for (i = 0; i < display->ctrl_count; i++) {
1131 ctrl = &display->ctrl[i];
1132 if (!ctrl->ctrl || (ctrl == m_ctrl))
1133 continue;
1134
1135 rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl,
1136 DSI_CTRL_ENGINE_ON);
1137 if (rc) {
1138 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
1139 display->name, rc);
1140 goto error_disable_master;
1141 }
1142 }
1143
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07001144 display->cmd_engine_refcount++;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001145 return rc;
1146error_disable_master:
1147 (void)dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
1148error:
1149 return rc;
1150}
1151
1152static int dsi_display_cmd_engine_disable(struct dsi_display *display)
1153{
1154 int rc = 0;
1155 int i;
1156 struct dsi_display_ctrl *m_ctrl, *ctrl;
1157
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07001158 if (display->cmd_engine_refcount == 0) {
1159 pr_err("[%s] Invalid refcount\n", display->name);
1160 return 0;
1161 } else if (display->cmd_engine_refcount > 1) {
1162 display->cmd_engine_refcount--;
1163 return 0;
1164 }
1165
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001166 m_ctrl = &display->ctrl[display->cmd_master_idx];
1167 for (i = 0; i < display->ctrl_count; i++) {
1168 ctrl = &display->ctrl[i];
1169 if (!ctrl->ctrl || (ctrl == m_ctrl))
1170 continue;
1171
1172 rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl,
1173 DSI_CTRL_ENGINE_OFF);
1174 if (rc)
1175 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
1176 display->name, rc);
1177 }
1178
1179 rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
1180 if (rc) {
1181 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
1182 display->name, rc);
1183 goto error;
1184 }
1185
1186error:
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07001187 display->cmd_engine_refcount = 0;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001188 return rc;
1189}
1190
1191static int dsi_display_ctrl_host_enable(struct dsi_display *display)
1192{
1193 int rc = 0;
1194 int i;
1195 struct dsi_display_ctrl *m_ctrl, *ctrl;
1196
1197 m_ctrl = &display->ctrl[display->cmd_master_idx];
1198
1199 rc = dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON);
1200 if (rc) {
1201 pr_err("[%s] failed to enable host engine, rc=%d\n",
1202 display->name, rc);
1203 goto error;
1204 }
1205
1206 for (i = 0; i < display->ctrl_count; i++) {
1207 ctrl = &display->ctrl[i];
1208 if (!ctrl->ctrl || (ctrl == m_ctrl))
1209 continue;
1210
1211 rc = dsi_ctrl_set_host_engine_state(ctrl->ctrl,
1212 DSI_CTRL_ENGINE_ON);
1213 if (rc) {
1214 pr_err("[%s] failed to enable sl host engine, rc=%d\n",
1215 display->name, rc);
1216 goto error_disable_master;
1217 }
1218 }
1219
1220 return rc;
1221error_disable_master:
1222 (void)dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
1223error:
1224 return rc;
1225}
1226
1227static int dsi_display_ctrl_host_disable(struct dsi_display *display)
1228{
1229 int rc = 0;
1230 int i;
1231 struct dsi_display_ctrl *m_ctrl, *ctrl;
1232
1233 m_ctrl = &display->ctrl[display->cmd_master_idx];
1234 for (i = 0; i < display->ctrl_count; i++) {
1235 ctrl = &display->ctrl[i];
1236 if (!ctrl->ctrl || (ctrl == m_ctrl))
1237 continue;
1238
1239 rc = dsi_ctrl_set_host_engine_state(ctrl->ctrl,
1240 DSI_CTRL_ENGINE_OFF);
1241 if (rc)
1242 pr_err("[%s] failed to disable host engine, rc=%d\n",
1243 display->name, rc);
1244 }
1245
1246 rc = dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
1247 if (rc) {
1248 pr_err("[%s] failed to disable host engine, rc=%d\n",
1249 display->name, rc);
1250 goto error;
1251 }
1252
1253error:
1254 return rc;
1255}
1256
1257static int dsi_display_vid_engine_enable(struct dsi_display *display)
1258{
1259 int rc = 0;
1260 int i;
1261 struct dsi_display_ctrl *m_ctrl, *ctrl;
1262
1263 m_ctrl = &display->ctrl[display->video_master_idx];
1264
1265 rc = dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON);
1266 if (rc) {
1267 pr_err("[%s] failed to enable vid engine, rc=%d\n",
1268 display->name, rc);
1269 goto error;
1270 }
1271
1272 for (i = 0; i < display->ctrl_count; i++) {
1273 ctrl = &display->ctrl[i];
1274 if (!ctrl->ctrl || (ctrl == m_ctrl))
1275 continue;
1276
1277 rc = dsi_ctrl_set_vid_engine_state(ctrl->ctrl,
1278 DSI_CTRL_ENGINE_ON);
1279 if (rc) {
1280 pr_err("[%s] failed to enable vid engine, rc=%d\n",
1281 display->name, rc);
1282 goto error_disable_master;
1283 }
1284 }
1285
1286 return rc;
1287error_disable_master:
1288 (void)dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
1289error:
1290 return rc;
1291}
1292
1293static int dsi_display_vid_engine_disable(struct dsi_display *display)
1294{
1295 int rc = 0;
1296 int i;
1297 struct dsi_display_ctrl *m_ctrl, *ctrl;
1298
1299 m_ctrl = &display->ctrl[display->video_master_idx];
1300
1301 for (i = 0; i < display->ctrl_count; i++) {
1302 ctrl = &display->ctrl[i];
1303 if (!ctrl->ctrl || (ctrl == m_ctrl))
1304 continue;
1305
1306 rc = dsi_ctrl_set_vid_engine_state(ctrl->ctrl,
1307 DSI_CTRL_ENGINE_OFF);
1308 if (rc)
1309 pr_err("[%s] failed to disable vid engine, rc=%d\n",
1310 display->name, rc);
1311 }
1312
1313 rc = dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
1314 if (rc)
1315 pr_err("[%s] failed to disable mvid engine, rc=%d\n",
1316 display->name, rc);
1317
1318 return rc;
1319}
1320
1321static int dsi_display_phy_enable(struct dsi_display *display)
1322{
1323 int rc = 0;
1324 int i;
1325 struct dsi_display_ctrl *m_ctrl, *ctrl;
1326 enum dsi_phy_pll_source m_src = DSI_PLL_SOURCE_STANDALONE;
1327
1328 m_ctrl = &display->ctrl[display->clk_master_idx];
1329 if (display->ctrl_count > 1)
1330 m_src = DSI_PLL_SOURCE_NATIVE;
1331
1332 rc = dsi_phy_enable(m_ctrl->phy,
1333 &display->config,
1334 m_src,
1335 true);
1336 if (rc) {
1337 pr_err("[%s] failed to enable DSI PHY, rc=%d\n",
1338 display->name, rc);
1339 goto error;
1340 }
1341
1342 for (i = 0; i < display->ctrl_count; i++) {
1343 ctrl = &display->ctrl[i];
1344 if (!ctrl->ctrl || (ctrl == m_ctrl))
1345 continue;
1346
1347 rc = dsi_phy_enable(ctrl->phy,
1348 &display->config,
1349 DSI_PLL_SOURCE_NON_NATIVE,
1350 true);
1351 if (rc) {
1352 pr_err("[%s] failed to enable DSI PHY, rc=%d\n",
1353 display->name, rc);
1354 goto error_disable_master;
1355 }
1356 }
1357
1358 return rc;
1359
1360error_disable_master:
1361 (void)dsi_phy_disable(m_ctrl->phy);
1362error:
1363 return rc;
1364}
1365
1366static int dsi_display_phy_disable(struct dsi_display *display)
1367{
1368 int rc = 0;
1369 int i;
1370 struct dsi_display_ctrl *m_ctrl, *ctrl;
1371
1372 m_ctrl = &display->ctrl[display->clk_master_idx];
1373
1374 for (i = 0; i < display->ctrl_count; i++) {
1375 ctrl = &display->ctrl[i];
1376 if (!ctrl->ctrl || (ctrl == m_ctrl))
1377 continue;
1378
1379 rc = dsi_phy_disable(ctrl->phy);
1380 if (rc)
1381 pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
1382 display->name, rc);
1383 }
1384
1385 rc = dsi_phy_disable(m_ctrl->phy);
1386 if (rc)
1387 pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
1388 display->name, rc);
1389
1390 return rc;
1391}
1392
1393static int dsi_display_wake_up(struct dsi_display *display)
1394{
1395 return 0;
1396}
1397
1398static int dsi_display_broadcast_cmd(struct dsi_display *display,
1399 const struct mipi_dsi_msg *msg)
1400{
1401 int rc = 0;
1402 u32 flags, m_flags;
1403 struct dsi_display_ctrl *ctrl, *m_ctrl;
1404 int i;
1405
1406 m_flags = (DSI_CTRL_CMD_BROADCAST | DSI_CTRL_CMD_BROADCAST_MASTER |
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07001407 DSI_CTRL_CMD_DEFER_TRIGGER | DSI_CTRL_CMD_FETCH_MEMORY);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001408 flags = (DSI_CTRL_CMD_BROADCAST | DSI_CTRL_CMD_DEFER_TRIGGER |
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07001409 DSI_CTRL_CMD_FETCH_MEMORY);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001410
1411 /*
1412 * 1. Setup commands in FIFO
1413 * 2. Trigger commands
1414 */
1415 m_ctrl = &display->ctrl[display->cmd_master_idx];
1416 rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, msg, m_flags);
1417 if (rc) {
1418 pr_err("[%s] cmd transfer failed on master,rc=%d\n",
1419 display->name, rc);
1420 goto error;
1421 }
1422
1423 for (i = 0; i < display->ctrl_count; i++) {
1424 ctrl = &display->ctrl[i];
1425 if (ctrl == m_ctrl)
1426 continue;
1427
1428 rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, msg, flags);
1429 if (rc) {
1430 pr_err("[%s] cmd transfer failed, rc=%d\n",
1431 display->name, rc);
1432 goto error;
1433 }
1434
Clarence Ip80ada7f2017-05-04 09:55:21 -07001435 rc = dsi_ctrl_cmd_tx_trigger(ctrl->ctrl, flags);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001436 if (rc) {
1437 pr_err("[%s] cmd trigger failed, rc=%d\n",
1438 display->name, rc);
1439 goto error;
1440 }
1441 }
1442
Clarence Ip80ada7f2017-05-04 09:55:21 -07001443 rc = dsi_ctrl_cmd_tx_trigger(m_ctrl->ctrl, m_flags);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001444 if (rc) {
1445 pr_err("[%s] cmd trigger failed for master, rc=%d\n",
1446 display->name, rc);
1447 goto error;
1448 }
1449
1450error:
1451 return rc;
1452}
1453
1454static int dsi_display_phy_sw_reset(struct dsi_display *display)
1455{
1456 int rc = 0;
1457 int i;
1458 struct dsi_display_ctrl *m_ctrl, *ctrl;
1459
1460 m_ctrl = &display->ctrl[display->cmd_master_idx];
1461
1462 rc = dsi_ctrl_phy_sw_reset(m_ctrl->ctrl);
1463 if (rc) {
1464 pr_err("[%s] failed to reset phy, rc=%d\n", display->name, rc);
1465 goto error;
1466 }
1467
1468 for (i = 0; i < display->ctrl_count; i++) {
1469 ctrl = &display->ctrl[i];
1470 if (!ctrl->ctrl || (ctrl == m_ctrl))
1471 continue;
1472
1473 rc = dsi_ctrl_phy_sw_reset(ctrl->ctrl);
1474 if (rc) {
1475 pr_err("[%s] failed to reset phy, rc=%d\n",
1476 display->name, rc);
1477 goto error;
1478 }
1479 }
1480
1481error:
1482 return rc;
1483}
1484
1485static int dsi_host_attach(struct mipi_dsi_host *host,
1486 struct mipi_dsi_device *dsi)
1487{
1488 return 0;
1489}
1490
1491static int dsi_host_detach(struct mipi_dsi_host *host,
1492 struct mipi_dsi_device *dsi)
1493{
1494 return 0;
1495}
1496
1497static ssize_t dsi_host_transfer(struct mipi_dsi_host *host,
1498 const struct mipi_dsi_msg *msg)
1499{
1500 struct dsi_display *display = to_dsi_display(host);
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07001501 struct dsi_display_ctrl *display_ctrl;
Jordan Croused8e96522017-02-13 10:14:16 -07001502 struct msm_gem_address_space *aspace = NULL;
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07001503 int rc = 0, cnt = 0;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001504
1505 if (!host || !msg) {
1506 pr_err("Invalid params\n");
1507 return 0;
1508 }
1509
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301510 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
1511 DSI_ALL_CLKS, DSI_CLK_ON);
1512 if (rc) {
1513 pr_err("[%s] failed to enable all DSI clocks, rc=%d\n",
1514 display->name, rc);
1515 goto error;
1516 }
1517
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001518 rc = dsi_display_wake_up(display);
1519 if (rc) {
1520 pr_err("[%s] failed to wake up display, rc=%d\n",
1521 display->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301522 goto error_disable_clks;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001523 }
1524
1525 rc = dsi_display_cmd_engine_enable(display);
1526 if (rc) {
1527 pr_err("[%s] failed to enable cmd engine, rc=%d\n",
1528 display->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301529 goto error_disable_clks;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001530 }
1531
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07001532 if (display->tx_cmd_buf == NULL) {
1533 mutex_lock(&display->drm_dev->struct_mutex);
1534 display->tx_cmd_buf = msm_gem_new(display->drm_dev,
1535 SZ_4K,
1536 MSM_BO_UNCACHED);
1537 mutex_unlock(&display->drm_dev->struct_mutex);
1538
1539 display->cmd_buffer_size = SZ_4K;
1540
1541 if ((display->tx_cmd_buf) == NULL) {
1542 pr_err("value of display->tx_cmd_buf is NULL");
1543 goto error_disable_cmd_engine;
1544 }
Jordan Croused8e96522017-02-13 10:14:16 -07001545
1546 aspace = msm_gem_smmu_address_space_get(display->drm_dev,
1547 MSM_SMMU_DOMAIN_UNSECURE);
1548 if (!aspace) {
1549 pr_err("failed to get aspace\n");
1550 rc = -EINVAL;
1551 goto free_gem;
1552 }
1553
1554 rc = msm_gem_get_iova(display->tx_cmd_buf, aspace,
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07001555 &(display->cmd_buffer_iova));
1556 if (rc) {
1557 pr_err("failed to get the iova rc %d\n", rc);
1558 goto free_gem;
1559 }
1560
1561 display->vaddr =
1562 (void *) msm_gem_get_vaddr(display->tx_cmd_buf);
1563
1564 if (IS_ERR_OR_NULL(display->vaddr)) {
1565 pr_err("failed to get va rc %d\n", rc);
1566 rc = -EINVAL;
1567 goto put_iova;
1568 }
1569
1570 for (cnt = 0; cnt < display->ctrl_count; cnt++) {
1571 display_ctrl = &display->ctrl[cnt];
1572 display_ctrl->ctrl->cmd_buffer_size = SZ_4K;
1573 display_ctrl->ctrl->cmd_buffer_iova =
1574 display->cmd_buffer_iova;
1575 display_ctrl->ctrl->vaddr = display->vaddr;
1576 }
1577 }
1578
Lloyd Atkinson1fde2282017-02-02 16:30:00 -05001579 if (display->ctrl_count > 1 && !(msg->flags & MIPI_DSI_MSG_UNICAST)) {
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001580 rc = dsi_display_broadcast_cmd(display, msg);
1581 if (rc) {
1582 pr_err("[%s] cmd broadcast failed, rc=%d\n",
1583 display->name, rc);
1584 goto error_disable_cmd_engine;
1585 }
1586 } else {
Lloyd Atkinson1fde2282017-02-02 16:30:00 -05001587 int ctrl_idx = (msg->flags & MIPI_DSI_MSG_UNICAST) ?
1588 msg->ctrl : 0;
1589
1590 rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg,
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07001591 DSI_CTRL_CMD_FETCH_MEMORY);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001592 if (rc) {
1593 pr_err("[%s] cmd transfer failed, rc=%d\n",
1594 display->name, rc);
1595 goto error_disable_cmd_engine;
1596 }
1597 }
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07001598
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001599error_disable_cmd_engine:
1600 (void)dsi_display_cmd_engine_disable(display);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301601error_disable_clks:
1602 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
1603 DSI_ALL_CLKS, DSI_CLK_OFF);
1604 if (rc) {
Vara Reddy0fe16842017-06-01 18:42:45 -07001605 pr_err("[%s] failed to disable all DSI clocks, rc=%d\n",
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301606 display->name, rc);
1607 }
Vara Reddy0fe16842017-06-01 18:42:45 -07001608 return rc;
1609put_iova:
Jordan Croused8e96522017-02-13 10:14:16 -07001610 msm_gem_put_iova(display->tx_cmd_buf, aspace);
Vara Reddy0fe16842017-06-01 18:42:45 -07001611free_gem:
1612 msm_gem_free_object(display->tx_cmd_buf);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001613error:
1614 return rc;
1615}
1616
1617
1618static struct mipi_dsi_host_ops dsi_host_ops = {
1619 .attach = dsi_host_attach,
1620 .detach = dsi_host_detach,
1621 .transfer = dsi_host_transfer,
1622};
1623
1624static int dsi_display_mipi_host_init(struct dsi_display *display)
1625{
1626 int rc = 0;
1627 struct mipi_dsi_host *host = &display->host;
1628
1629 host->dev = &display->pdev->dev;
1630 host->ops = &dsi_host_ops;
1631
1632 rc = mipi_dsi_host_register(host);
1633 if (rc) {
1634 pr_err("[%s] failed to register mipi dsi host, rc=%d\n",
1635 display->name, rc);
1636 goto error;
1637 }
1638
1639error:
1640 return rc;
1641}
1642static int dsi_display_mipi_host_deinit(struct dsi_display *display)
1643{
1644 int rc = 0;
1645 struct mipi_dsi_host *host = &display->host;
1646
1647 mipi_dsi_host_unregister(host);
1648
1649 host->dev = NULL;
1650 host->ops = NULL;
1651
1652 return rc;
1653}
1654
1655static int dsi_display_clocks_deinit(struct dsi_display *display)
1656{
1657 int rc = 0;
1658 struct dsi_clk_link_set *src = &display->clock_info.src_clks;
1659 struct dsi_clk_link_set *mux = &display->clock_info.mux_clks;
1660 struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks;
1661
1662 if (src->byte_clk) {
1663 devm_clk_put(&display->pdev->dev, src->byte_clk);
1664 src->byte_clk = NULL;
1665 }
1666
1667 if (src->pixel_clk) {
1668 devm_clk_put(&display->pdev->dev, src->pixel_clk);
1669 src->pixel_clk = NULL;
1670 }
1671
1672 if (mux->byte_clk) {
1673 devm_clk_put(&display->pdev->dev, mux->byte_clk);
1674 mux->byte_clk = NULL;
1675 }
1676
1677 if (mux->pixel_clk) {
1678 devm_clk_put(&display->pdev->dev, mux->pixel_clk);
1679 mux->pixel_clk = NULL;
1680 }
1681
1682 if (shadow->byte_clk) {
1683 devm_clk_put(&display->pdev->dev, shadow->byte_clk);
1684 shadow->byte_clk = NULL;
1685 }
1686
1687 if (shadow->pixel_clk) {
1688 devm_clk_put(&display->pdev->dev, shadow->pixel_clk);
1689 shadow->pixel_clk = NULL;
1690 }
1691
1692 return rc;
1693}
1694
1695static int dsi_display_clocks_init(struct dsi_display *display)
1696{
1697 int rc = 0;
1698 struct dsi_clk_link_set *src = &display->clock_info.src_clks;
1699 struct dsi_clk_link_set *mux = &display->clock_info.mux_clks;
1700 struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks;
1701
1702 src->byte_clk = devm_clk_get(&display->pdev->dev, "src_byte_clk");
1703 if (IS_ERR_OR_NULL(src->byte_clk)) {
1704 rc = PTR_ERR(src->byte_clk);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04001705 src->byte_clk = NULL;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001706 pr_err("failed to get src_byte_clk, rc=%d\n", rc);
1707 goto error;
1708 }
1709
1710 src->pixel_clk = devm_clk_get(&display->pdev->dev, "src_pixel_clk");
1711 if (IS_ERR_OR_NULL(src->pixel_clk)) {
1712 rc = PTR_ERR(src->pixel_clk);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04001713 src->pixel_clk = NULL;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001714 pr_err("failed to get src_pixel_clk, rc=%d\n", rc);
1715 goto error;
1716 }
1717
1718 mux->byte_clk = devm_clk_get(&display->pdev->dev, "mux_byte_clk");
1719 if (IS_ERR_OR_NULL(mux->byte_clk)) {
1720 rc = PTR_ERR(mux->byte_clk);
Shashank Babu Chinta Venkatacf411332017-05-10 17:30:08 -07001721 pr_debug("failed to get mux_byte_clk, rc=%d\n", rc);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04001722 mux->byte_clk = NULL;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001723 /*
1724 * Skip getting rest of clocks since one failed. This is a
1725 * non-critical failure since these clocks are requied only for
1726 * dynamic refresh use cases.
1727 */
1728 rc = 0;
1729 goto done;
1730 };
1731
1732 mux->pixel_clk = devm_clk_get(&display->pdev->dev, "mux_pixel_clk");
1733 if (IS_ERR_OR_NULL(mux->pixel_clk)) {
1734 rc = PTR_ERR(mux->pixel_clk);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04001735 mux->pixel_clk = NULL;
Shashank Babu Chinta Venkatacf411332017-05-10 17:30:08 -07001736 pr_debug("failed to get mux_pixel_clk, rc=%d\n", rc);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001737 /*
1738 * Skip getting rest of clocks since one failed. This is a
1739 * non-critical failure since these clocks are requied only for
1740 * dynamic refresh use cases.
1741 */
1742 rc = 0;
1743 goto done;
1744 };
1745
1746 shadow->byte_clk = devm_clk_get(&display->pdev->dev, "shadow_byte_clk");
1747 if (IS_ERR_OR_NULL(shadow->byte_clk)) {
1748 rc = PTR_ERR(shadow->byte_clk);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04001749 shadow->byte_clk = NULL;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001750 pr_err("failed to get shadow_byte_clk, rc=%d\n", rc);
1751 /*
1752 * Skip getting rest of clocks since one failed. This is a
1753 * non-critical failure since these clocks are requied only for
1754 * dynamic refresh use cases.
1755 */
1756 rc = 0;
1757 goto done;
1758 };
1759
1760 shadow->pixel_clk = devm_clk_get(&display->pdev->dev,
1761 "shadow_pixel_clk");
1762 if (IS_ERR_OR_NULL(shadow->pixel_clk)) {
1763 rc = PTR_ERR(shadow->pixel_clk);
Lloyd Atkinson1be10b62016-10-04 09:46:08 -04001764 shadow->pixel_clk = NULL;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07001765 pr_err("failed to get shadow_pixel_clk, rc=%d\n", rc);
1766 /*
1767 * Skip getting rest of clocks since one failed. This is a
1768 * non-critical failure since these clocks are requied only for
1769 * dynamic refresh use cases.
1770 */
1771 rc = 0;
1772 goto done;
1773 };
1774
1775done:
1776 return 0;
1777error:
1778 (void)dsi_display_clocks_deinit(display);
1779 return rc;
1780}
1781
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301782static int dsi_display_clk_ctrl_cb(void *priv,
1783 struct dsi_clk_ctrl_info clk_state_info)
1784{
1785 int rc = 0;
1786 struct dsi_display *display = NULL;
1787 void *clk_handle = NULL;
1788
1789 if (!priv) {
1790 pr_err("Invalid params\n");
1791 return -EINVAL;
1792 }
1793
1794 display = priv;
1795
1796 if (clk_state_info.client == DSI_CLK_REQ_MDP_CLIENT) {
1797 clk_handle = display->mdp_clk_handle;
1798 } else if (clk_state_info.client == DSI_CLK_REQ_DSI_CLIENT) {
1799 clk_handle = display->dsi_clk_handle;
1800 } else {
1801 pr_err("invalid clk handle, return error\n");
1802 return -EINVAL;
1803 }
1804
1805 /*
1806 * TODO: Wait for CMD_MDP_DONE interrupt if MDP client tries
1807 * to turn off DSI clocks.
1808 */
1809 rc = dsi_display_clk_ctrl(clk_handle,
1810 clk_state_info.clk_type, clk_state_info.clk_state);
1811 if (rc) {
1812 pr_err("[%s] failed to %d DSI %d clocks, rc=%d\n",
1813 display->name, clk_state_info.clk_state,
1814 clk_state_info.clk_type, rc);
1815 return rc;
1816 }
1817 return 0;
1818}
1819
1820int dsi_pre_clkoff_cb(void *priv,
1821 enum dsi_clk_type clk,
1822 enum dsi_clk_state new_state)
1823{
1824 int rc = 0;
1825 struct dsi_display *display = priv;
1826
1827 if ((clk & DSI_LINK_CLK) && (new_state == DSI_CLK_OFF)) {
1828 /*
1829 * If ULPS feature is enabled, enter ULPS first.
1830 */
1831 if (dsi_panel_initialized(display->panel) &&
1832 dsi_panel_ulps_feature_enabled(display->panel)) {
1833 rc = dsi_display_set_ulps(display, true);
1834 if (rc) {
1835 pr_err("%s: failed enable ulps, rc = %d\n",
1836 __func__, rc);
1837 }
1838 }
1839 }
1840
1841 if ((clk & DSI_CORE_CLK) && (new_state == DSI_CLK_OFF)) {
1842 /*
1843 * Enable DSI clamps only if entering idle power collapse.
1844 */
Veera Sundaram Sankaranbb3680f2017-04-21 13:20:46 -07001845 if (dsi_panel_initialized(display->panel)) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301846 dsi_display_phy_idle_off(display);
1847 rc = dsi_display_set_clamp(display, true);
1848 if (rc)
1849 pr_err("%s: Failed to enable dsi clamps. rc=%d\n",
1850 __func__, rc);
Veera Sundaram Sankaran518a8632017-05-01 16:37:55 -07001851
1852 rc = dsi_display_phy_reset_config(display, false);
1853 if (rc)
1854 pr_err("%s: Failed to reset phy, rc=%d\n",
1855 __func__, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301856 } else {
1857 /* Make sure that controller is not in ULPS state when
1858 * the DSI link is not active.
1859 */
1860 rc = dsi_display_set_ulps(display, false);
1861 if (rc)
1862 pr_err("%s: failed to disable ulps. rc=%d\n",
1863 __func__, rc);
1864 }
1865 }
1866
1867 return rc;
1868}
1869
1870int dsi_post_clkon_cb(void *priv,
1871 enum dsi_clk_type clk,
1872 enum dsi_clk_state curr_state)
1873{
1874 int rc = 0;
1875 struct dsi_display *display = priv;
1876 bool mmss_clamp = false;
1877
1878 if (clk & DSI_CORE_CLK) {
1879 mmss_clamp = display->clamp_enabled;
1880 /*
1881 * controller setup is needed if coming out of idle
1882 * power collapse with clamps enabled.
1883 */
1884 if (mmss_clamp)
1885 dsi_display_ctrl_setup(display);
1886
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05301887 if (display->ulps_enabled && mmss_clamp) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301888 /*
1889 * ULPS Entry Request. This is needed if the lanes were
1890 * in ULPS prior to power collapse, since after
1891 * power collapse and reset, the DSI controller resets
1892 * back to idle state and not ULPS. This ulps entry
1893 * request will transition the state of the DSI
1894 * controller to ULPS which will match the state of the
1895 * DSI phy. This needs to be done prior to disabling
1896 * the DSI clamps.
1897 *
1898 * Also, reset the ulps flag so that ulps_config
1899 * function would reconfigure the controller state to
1900 * ULPS.
1901 */
1902 display->ulps_enabled = false;
1903 rc = dsi_display_set_ulps(display, true);
1904 if (rc) {
1905 pr_err("%s: Failed to enter ULPS. rc=%d\n",
1906 __func__, rc);
1907 goto error;
1908 }
1909 }
1910
Veera Sundaram Sankaran518a8632017-05-01 16:37:55 -07001911 rc = dsi_display_phy_reset_config(display, true);
1912 if (rc) {
1913 pr_err("%s: Failed to reset phy, rc=%d\n",
1914 __func__, rc);
1915 goto error;
1916 }
1917
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301918 rc = dsi_display_set_clamp(display, false);
1919 if (rc) {
1920 pr_err("%s: Failed to disable dsi clamps. rc=%d\n",
1921 __func__, rc);
1922 goto error;
1923 }
1924
1925 /*
1926 * Phy setup is needed if coming out of idle
1927 * power collapse with clamps enabled.
1928 */
1929 if (display->phy_idle_power_off || mmss_clamp)
1930 dsi_display_phy_idle_on(display, mmss_clamp);
1931 }
1932 if (clk & DSI_LINK_CLK) {
1933 if (display->ulps_enabled) {
1934 rc = dsi_display_set_ulps(display, false);
1935 if (rc) {
1936 pr_err("%s: failed to disable ulps, rc= %d\n",
1937 __func__, rc);
1938 goto error;
1939 }
1940 }
1941 }
1942error:
1943 return rc;
1944}
1945
1946int dsi_post_clkoff_cb(void *priv,
1947 enum dsi_clk_type clk_type,
1948 enum dsi_clk_state curr_state)
1949{
1950 int rc = 0;
1951 struct dsi_display *display = priv;
1952
1953 if (!display) {
1954 pr_err("%s: Invalid arg\n", __func__);
1955 return -EINVAL;
1956 }
1957
1958 if ((clk_type & DSI_CORE_CLK) &&
1959 (curr_state == DSI_CLK_OFF)) {
1960
1961 rc = dsi_display_phy_power_off(display);
1962 if (rc)
1963 pr_err("[%s] failed to power off PHY, rc=%d\n",
1964 display->name, rc);
1965
1966 rc = dsi_display_ctrl_power_off(display);
1967 if (rc)
1968 pr_err("[%s] failed to power DSI vregs, rc=%d\n",
1969 display->name, rc);
1970 }
1971 return rc;
1972}
1973
1974int dsi_pre_clkon_cb(void *priv,
1975 enum dsi_clk_type clk_type,
1976 enum dsi_clk_state new_state)
1977{
1978 int rc = 0;
1979 struct dsi_display *display = priv;
1980
1981 if (!display) {
1982 pr_err("%s: invalid input\n", __func__);
1983 return -EINVAL;
1984 }
1985
1986 if ((clk_type & DSI_CORE_CLK) && (new_state == DSI_CLK_ON)) {
1987 /*
1988 * Enable DSI core power
1989 * 1.> PANEL_PM are controlled as part of
1990 * panel_power_ctrl. Needed not be handled here.
1991 * 2.> CORE_PM are controlled by dsi clk manager.
1992 * 3.> CTRL_PM need to be enabled/disabled
1993 * only during unblank/blank. Their state should
1994 * not be changed during static screen.
1995 */
1996
1997 rc = dsi_display_ctrl_power_on(display);
1998 if (rc) {
1999 pr_err("[%s] failed to power on dsi controllers, rc=%d\n",
2000 display->name, rc);
2001 return rc;
2002 }
2003
2004 rc = dsi_display_phy_power_on(display);
2005 if (rc) {
2006 pr_err("[%s] failed to power on dsi phy, rc = %d\n",
2007 display->name, rc);
2008 return rc;
2009 }
2010
2011 pr_debug("%s: Enable DSI core power\n", __func__);
2012 }
2013
2014 return rc;
2015}
2016
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302017static void __set_lane_map_v2(u8 *lane_map_v2,
2018 enum dsi_phy_data_lanes lane0,
2019 enum dsi_phy_data_lanes lane1,
2020 enum dsi_phy_data_lanes lane2,
2021 enum dsi_phy_data_lanes lane3)
2022{
2023 lane_map_v2[DSI_LOGICAL_LANE_0] = lane0;
2024 lane_map_v2[DSI_LOGICAL_LANE_1] = lane1;
2025 lane_map_v2[DSI_LOGICAL_LANE_2] = lane2;
2026 lane_map_v2[DSI_LOGICAL_LANE_3] = lane3;
2027}
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302028
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002029static int dsi_display_parse_lane_map(struct dsi_display *display)
2030{
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302031 int rc = 0, i = 0;
2032 const char *data;
2033 u8 temp[DSI_LANE_MAX - 1];
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002034
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302035 if (!display) {
2036 pr_err("invalid params\n");
2037 return -EINVAL;
2038 }
2039
2040 /* lane-map-v2 supersedes lane-map-v1 setting */
2041 rc = of_property_read_u8_array(display->pdev->dev.of_node,
2042 "qcom,lane-map-v2", temp, (DSI_LANE_MAX - 1));
2043 if (!rc) {
2044 for (i = DSI_LOGICAL_LANE_0; i < (DSI_LANE_MAX - 1); i++)
2045 display->lane_map.lane_map_v2[i] = BIT(temp[i]);
2046 return 0;
2047 } else if (rc != EINVAL) {
Shashank Babu Chinta Venkatacf411332017-05-10 17:30:08 -07002048 pr_debug("Incorrect mapping, configure default\n");
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302049 goto set_default;
2050 }
2051
2052 /* lane-map older version, for DSI controller version < 2.0 */
2053 data = of_get_property(display->pdev->dev.of_node,
2054 "qcom,lane-map", NULL);
2055 if (!data)
2056 goto set_default;
2057
2058 if (!strcmp(data, "lane_map_3012")) {
2059 display->lane_map.lane_map_v1 = DSI_LANE_MAP_3012;
2060 __set_lane_map_v2(display->lane_map.lane_map_v2,
2061 DSI_PHYSICAL_LANE_1,
2062 DSI_PHYSICAL_LANE_2,
2063 DSI_PHYSICAL_LANE_3,
2064 DSI_PHYSICAL_LANE_0);
2065 } else if (!strcmp(data, "lane_map_2301")) {
2066 display->lane_map.lane_map_v1 = DSI_LANE_MAP_2301;
2067 __set_lane_map_v2(display->lane_map.lane_map_v2,
2068 DSI_PHYSICAL_LANE_2,
2069 DSI_PHYSICAL_LANE_3,
2070 DSI_PHYSICAL_LANE_0,
2071 DSI_PHYSICAL_LANE_1);
2072 } else if (!strcmp(data, "lane_map_1230")) {
2073 display->lane_map.lane_map_v1 = DSI_LANE_MAP_1230;
2074 __set_lane_map_v2(display->lane_map.lane_map_v2,
2075 DSI_PHYSICAL_LANE_3,
2076 DSI_PHYSICAL_LANE_0,
2077 DSI_PHYSICAL_LANE_1,
2078 DSI_PHYSICAL_LANE_2);
2079 } else if (!strcmp(data, "lane_map_0321")) {
2080 display->lane_map.lane_map_v1 = DSI_LANE_MAP_0321;
2081 __set_lane_map_v2(display->lane_map.lane_map_v2,
2082 DSI_PHYSICAL_LANE_0,
2083 DSI_PHYSICAL_LANE_3,
2084 DSI_PHYSICAL_LANE_2,
2085 DSI_PHYSICAL_LANE_1);
2086 } else if (!strcmp(data, "lane_map_1032")) {
2087 display->lane_map.lane_map_v1 = DSI_LANE_MAP_1032;
2088 __set_lane_map_v2(display->lane_map.lane_map_v2,
2089 DSI_PHYSICAL_LANE_1,
2090 DSI_PHYSICAL_LANE_0,
2091 DSI_PHYSICAL_LANE_3,
2092 DSI_PHYSICAL_LANE_2);
2093 } else if (!strcmp(data, "lane_map_2103")) {
2094 display->lane_map.lane_map_v1 = DSI_LANE_MAP_2103;
2095 __set_lane_map_v2(display->lane_map.lane_map_v2,
2096 DSI_PHYSICAL_LANE_2,
2097 DSI_PHYSICAL_LANE_1,
2098 DSI_PHYSICAL_LANE_0,
2099 DSI_PHYSICAL_LANE_3);
2100 } else if (!strcmp(data, "lane_map_3210")) {
2101 display->lane_map.lane_map_v1 = DSI_LANE_MAP_3210;
2102 __set_lane_map_v2(display->lane_map.lane_map_v2,
2103 DSI_PHYSICAL_LANE_3,
2104 DSI_PHYSICAL_LANE_2,
2105 DSI_PHYSICAL_LANE_1,
2106 DSI_PHYSICAL_LANE_0);
2107 } else {
2108 pr_warn("%s: invalid lane map %s specified. defaulting to lane_map0123\n",
2109 __func__, data);
2110 goto set_default;
2111 }
2112 return 0;
2113
2114set_default:
2115 /* default lane mapping */
2116 __set_lane_map_v2(display->lane_map.lane_map_v2, DSI_PHYSICAL_LANE_0,
2117 DSI_PHYSICAL_LANE_1, DSI_PHYSICAL_LANE_2, DSI_PHYSICAL_LANE_3);
2118 display->lane_map.lane_map_v1 = DSI_LANE_MAP_0123;
2119 return 0;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002120}
2121
2122static int dsi_display_parse_dt(struct dsi_display *display)
2123{
2124 int rc = 0;
2125 int i;
2126 u32 phy_count = 0;
2127 struct device_node *of_node;
2128
2129 /* Parse controllers */
2130 for (i = 0; i < MAX_DSI_CTRLS_PER_DISPLAY; i++) {
2131 of_node = of_parse_phandle(display->pdev->dev.of_node,
2132 "qcom,dsi-ctrl", i);
2133 if (!of_node) {
2134 if (!i) {
2135 pr_err("No controllers present\n");
2136 return -ENODEV;
2137 }
2138 break;
2139 }
2140
2141 display->ctrl[i].ctrl_of_node = of_node;
2142 display->ctrl_count++;
2143 }
2144
2145 /* Parse Phys */
2146 for (i = 0; i < MAX_DSI_CTRLS_PER_DISPLAY; i++) {
2147 of_node = of_parse_phandle(display->pdev->dev.of_node,
2148 "qcom,dsi-phy", i);
2149 if (!of_node) {
2150 if (!i) {
2151 pr_err("No PHY devices present\n");
2152 rc = -ENODEV;
2153 goto error;
2154 }
2155 break;
2156 }
2157
2158 display->ctrl[i].phy_of_node = of_node;
2159 phy_count++;
2160 }
2161
2162 if (phy_count != display->ctrl_count) {
2163 pr_err("Number of controllers does not match PHYs\n");
2164 rc = -ENODEV;
2165 goto error;
2166 }
2167
2168 of_node = of_parse_phandle(display->pdev->dev.of_node,
2169 "qcom,dsi-panel", 0);
2170 if (!of_node) {
2171 pr_err("No Panel device present\n");
2172 rc = -ENODEV;
2173 goto error;
2174 } else {
2175 display->panel_of = of_node;
2176 }
2177
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002178error:
2179 return rc;
2180}
2181
2182static int dsi_display_res_init(struct dsi_display *display)
2183{
2184 int rc = 0;
2185 int i;
2186 struct dsi_display_ctrl *ctrl;
2187
2188 for (i = 0; i < display->ctrl_count; i++) {
2189 ctrl = &display->ctrl[i];
2190 ctrl->ctrl = dsi_ctrl_get(ctrl->ctrl_of_node);
2191 if (IS_ERR_OR_NULL(ctrl->ctrl)) {
2192 rc = PTR_ERR(ctrl->ctrl);
2193 pr_err("failed to get dsi controller, rc=%d\n", rc);
2194 ctrl->ctrl = NULL;
2195 goto error_ctrl_put;
2196 }
2197
2198 ctrl->phy = dsi_phy_get(ctrl->phy_of_node);
2199 if (IS_ERR_OR_NULL(ctrl->phy)) {
2200 rc = PTR_ERR(ctrl->phy);
2201 pr_err("failed to get phy controller, rc=%d\n", rc);
2202 dsi_ctrl_put(ctrl->ctrl);
2203 ctrl->phy = NULL;
2204 goto error_ctrl_put;
2205 }
2206 }
2207
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07002208 display->panel = dsi_panel_get(&display->pdev->dev, display->panel_of,
2209 display->cmdline_topology);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002210 if (IS_ERR_OR_NULL(display->panel)) {
2211 rc = PTR_ERR(display->panel);
2212 pr_err("failed to get panel, rc=%d\n", rc);
2213 display->panel = NULL;
2214 goto error_ctrl_put;
2215 }
2216
Padmanabhan Komanduruee89d212016-12-19 12:51:31 +05302217 if (display->panel->phy_timing_len) {
2218 for (i = 0; i < display->ctrl_count; i++) {
2219 ctrl = &display->ctrl[i];
2220 rc = dsi_phy_set_timing_params(ctrl->phy,
2221 display->panel->phy_timing_val,
2222 display->panel->phy_timing_len);
2223 if (rc)
2224 pr_err("failed to add DSI PHY timing params");
2225 }
2226 }
2227
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302228 rc = dsi_display_parse_lane_map(display);
2229 if (rc) {
2230 pr_err("Lane map not found, rc=%d\n", rc);
2231 goto error_ctrl_put;
2232 }
2233
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002234 rc = dsi_display_clocks_init(display);
2235 if (rc) {
2236 pr_err("Failed to parse clock data, rc=%d\n", rc);
2237 goto error_ctrl_put;
2238 }
2239
2240 return 0;
2241error_ctrl_put:
2242 for (i = i - 1; i >= 0; i--) {
2243 ctrl = &display->ctrl[i];
2244 dsi_ctrl_put(ctrl->ctrl);
2245 dsi_phy_put(ctrl->phy);
2246 }
2247 return rc;
2248}
2249
2250static int dsi_display_res_deinit(struct dsi_display *display)
2251{
2252 int rc = 0;
2253 int i;
2254 struct dsi_display_ctrl *ctrl;
2255
2256 rc = dsi_display_clocks_deinit(display);
2257 if (rc)
2258 pr_err("clocks deinit failed, rc=%d\n", rc);
2259
2260 for (i = 0; i < display->ctrl_count; i++) {
2261 ctrl = &display->ctrl[i];
2262 dsi_phy_put(ctrl->phy);
2263 dsi_ctrl_put(ctrl->ctrl);
2264 }
2265
2266 return rc;
2267}
2268
2269static int dsi_display_validate_mode_set(struct dsi_display *display,
2270 struct dsi_display_mode *mode,
2271 u32 flags)
2272{
2273 int rc = 0;
2274 int i;
2275 struct dsi_display_ctrl *ctrl;
2276
2277 /*
2278 * To set a mode:
2279 * 1. Controllers should be turned off.
2280 * 2. Link clocks should be off.
2281 * 3. Phy should be disabled.
2282 */
2283
2284 for (i = 0; i < display->ctrl_count; i++) {
2285 ctrl = &display->ctrl[i];
2286 if ((ctrl->power_state > DSI_CTRL_POWER_VREG_ON) ||
2287 (ctrl->phy_enabled)) {
2288 rc = -EINVAL;
2289 goto error;
2290 }
2291 }
2292
2293error:
2294 return rc;
2295}
2296
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002297static bool dsi_display_is_seamless_dfps_possible(
2298 const struct dsi_display *display,
2299 const struct dsi_display_mode *tgt,
2300 const enum dsi_dfps_type dfps_type)
2301{
2302 struct dsi_display_mode *cur;
2303
2304 if (!display || !tgt) {
2305 pr_err("Invalid params\n");
2306 return false;
2307 }
2308
2309 cur = &display->panel->mode;
2310
2311 if (cur->timing.h_active != tgt->timing.h_active) {
2312 pr_debug("timing.h_active differs %d %d\n",
2313 cur->timing.h_active, tgt->timing.h_active);
2314 return false;
2315 }
2316
2317 if (cur->timing.h_back_porch != tgt->timing.h_back_porch) {
2318 pr_debug("timing.h_back_porch differs %d %d\n",
2319 cur->timing.h_back_porch,
2320 tgt->timing.h_back_porch);
2321 return false;
2322 }
2323
2324 if (cur->timing.h_sync_width != tgt->timing.h_sync_width) {
2325 pr_debug("timing.h_sync_width differs %d %d\n",
2326 cur->timing.h_sync_width,
2327 tgt->timing.h_sync_width);
2328 return false;
2329 }
2330
2331 if (cur->timing.h_front_porch != tgt->timing.h_front_porch) {
2332 pr_debug("timing.h_front_porch differs %d %d\n",
2333 cur->timing.h_front_porch,
2334 tgt->timing.h_front_porch);
2335 if (dfps_type != DSI_DFPS_IMMEDIATE_HFP)
2336 return false;
2337 }
2338
2339 if (cur->timing.h_skew != tgt->timing.h_skew) {
2340 pr_debug("timing.h_skew differs %d %d\n",
2341 cur->timing.h_skew,
2342 tgt->timing.h_skew);
2343 return false;
2344 }
2345
2346 /* skip polarity comparison */
2347
2348 if (cur->timing.v_active != tgt->timing.v_active) {
2349 pr_debug("timing.v_active differs %d %d\n",
2350 cur->timing.v_active,
2351 tgt->timing.v_active);
2352 return false;
2353 }
2354
2355 if (cur->timing.v_back_porch != tgt->timing.v_back_porch) {
2356 pr_debug("timing.v_back_porch differs %d %d\n",
2357 cur->timing.v_back_porch,
2358 tgt->timing.v_back_porch);
2359 return false;
2360 }
2361
2362 if (cur->timing.v_sync_width != tgt->timing.v_sync_width) {
2363 pr_debug("timing.v_sync_width differs %d %d\n",
2364 cur->timing.v_sync_width,
2365 tgt->timing.v_sync_width);
2366 return false;
2367 }
2368
2369 if (cur->timing.v_front_porch != tgt->timing.v_front_porch) {
2370 pr_debug("timing.v_front_porch differs %d %d\n",
2371 cur->timing.v_front_porch,
2372 tgt->timing.v_front_porch);
2373 if (dfps_type != DSI_DFPS_IMMEDIATE_VFP)
2374 return false;
2375 }
2376
2377 /* skip polarity comparison */
2378
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05002379 if (cur->timing.refresh_rate == tgt->timing.refresh_rate)
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002380 pr_debug("timing.refresh_rate identical %d %d\n",
2381 cur->timing.refresh_rate,
2382 tgt->timing.refresh_rate);
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002383
2384 if (cur->pixel_clk_khz != tgt->pixel_clk_khz)
2385 pr_debug("pixel_clk_khz differs %d %d\n",
2386 cur->pixel_clk_khz, tgt->pixel_clk_khz);
2387
2388 if (cur->panel_mode != tgt->panel_mode) {
2389 pr_debug("panel_mode differs %d %d\n",
2390 cur->panel_mode, tgt->panel_mode);
2391 return false;
2392 }
2393
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05002394 if (cur->dsi_mode_flags != tgt->dsi_mode_flags)
2395 pr_debug("flags differs %d %d\n",
2396 cur->dsi_mode_flags, tgt->dsi_mode_flags);
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002397
2398 return true;
2399}
2400
2401static int dsi_display_dfps_update(struct dsi_display *display,
2402 struct dsi_display_mode *dsi_mode)
2403{
2404 struct dsi_mode_info *timing;
2405 struct dsi_display_ctrl *m_ctrl, *ctrl;
2406 struct dsi_display_mode *panel_mode;
2407 struct dsi_dfps_capabilities dfps_caps;
2408 int rc = 0;
Channagoud Kadabi075db3b2017-03-16 14:26:17 -07002409 int i = 0;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002410
2411 if (!display || !dsi_mode) {
2412 pr_err("Invalid params\n");
2413 return -EINVAL;
2414 }
2415 timing = &dsi_mode->timing;
2416
2417 dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
2418 if (!dfps_caps.dfps_support) {
2419 pr_err("dfps not supported\n");
2420 return -ENOTSUPP;
2421 }
2422
2423 if (dfps_caps.type == DSI_DFPS_IMMEDIATE_CLK) {
2424 pr_err("dfps clock method not supported\n");
2425 return -ENOTSUPP;
2426 }
2427
2428 /* For split DSI, update the clock master first */
2429
2430 pr_debug("configuring seamless dynamic fps\n\n");
2431
2432 m_ctrl = &display->ctrl[display->clk_master_idx];
2433 rc = dsi_ctrl_async_timing_update(m_ctrl->ctrl, timing);
2434 if (rc) {
2435 pr_err("[%s] failed to dfps update host_%d, rc=%d\n",
2436 display->name, i, rc);
2437 goto error;
2438 }
2439
2440 /* Update the rest of the controllers */
2441 for (i = 0; i < display->ctrl_count; i++) {
2442 ctrl = &display->ctrl[i];
2443 if (!ctrl->ctrl || (ctrl == m_ctrl))
2444 continue;
2445
2446 rc = dsi_ctrl_async_timing_update(ctrl->ctrl, timing);
2447 if (rc) {
2448 pr_err("[%s] failed to dfps update host_%d, rc=%d\n",
2449 display->name, i, rc);
2450 goto error;
2451 }
2452 }
2453
2454 panel_mode = &display->panel->mode;
2455 memcpy(panel_mode, dsi_mode, sizeof(*panel_mode));
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05002456 /*
2457 * dsi_mode_flags flags are used to communicate with other drm driver
2458 * components, and are transient. They aren't inherently part of the
2459 * display panel's mode and shouldn't be saved into the cached currently
2460 * active mode.
2461 */
2462 panel_mode->dsi_mode_flags = 0;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002463
2464error:
2465 return rc;
2466}
2467
2468static int dsi_display_dfps_calc_front_porch(
2469 u64 clk_hz,
2470 u32 new_fps,
2471 u32 a_total,
2472 u32 b_total,
2473 u32 b_fp,
2474 u32 *b_fp_out)
2475{
2476 s32 b_fp_new;
2477
2478 if (!b_fp_out) {
2479 pr_err("Invalid params");
2480 return -EINVAL;
2481 }
2482
2483 if (!a_total || !new_fps) {
2484 pr_err("Invalid pixel total or new fps in mode request\n");
2485 return -EINVAL;
2486 }
2487
2488 /**
2489 * Keep clock, other porches constant, use new fps, calc front porch
2490 * clk = (hor * ver * fps)
2491 * hfront = clk / (vtotal * fps)) - hactive - hback - hsync
2492 */
2493 b_fp_new = (clk_hz / (a_total * new_fps)) - (b_total - b_fp);
2494
2495 pr_debug("clk %llu fps %u a %u b %u b_fp %u new_fp %d\n",
2496 clk_hz, new_fps, a_total, b_total, b_fp, b_fp_new);
2497
2498 if (b_fp_new < 0) {
2499 pr_err("Invalid new_hfp calcluated%d\n", b_fp_new);
2500 return -EINVAL;
2501 }
2502
2503 /**
2504 * TODO: To differentiate from clock method when communicating to the
2505 * other components, perhaps we should set clk here to original value
2506 */
2507 *b_fp_out = b_fp_new;
2508
2509 return 0;
2510}
2511
2512static int dsi_display_get_dfps_timing(struct dsi_display *display,
2513 struct dsi_display_mode *adj_mode)
2514{
2515 struct dsi_dfps_capabilities dfps_caps;
2516 struct dsi_display_mode per_ctrl_mode;
2517 struct dsi_mode_info *timing;
2518 struct dsi_ctrl *m_ctrl;
2519 u64 clk_hz;
2520
2521 int rc = 0;
2522
2523 if (!display || !adj_mode) {
2524 pr_err("Invalid params\n");
2525 return -EINVAL;
2526 }
2527 m_ctrl = display->ctrl[display->clk_master_idx].ctrl;
2528
2529 dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
2530 if (!dfps_caps.dfps_support) {
2531 pr_err("dfps not supported by panel\n");
2532 return -EINVAL;
2533 }
2534
2535 per_ctrl_mode = *adj_mode;
2536 adjust_timing_by_ctrl_count(display, &per_ctrl_mode);
2537
2538 if (!dsi_display_is_seamless_dfps_possible(display,
2539 &per_ctrl_mode, dfps_caps.type)) {
2540 pr_err("seamless dynamic fps not supported for mode\n");
2541 return -EINVAL;
2542 }
2543
2544 /* TODO: Remove this direct reference to the dsi_ctrl */
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302545 clk_hz = m_ctrl->clk_freq.pix_clk_rate;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002546 timing = &per_ctrl_mode.timing;
2547
2548 switch (dfps_caps.type) {
2549 case DSI_DFPS_IMMEDIATE_VFP:
2550 rc = dsi_display_dfps_calc_front_porch(
2551 clk_hz,
2552 timing->refresh_rate,
2553 DSI_H_TOTAL(timing),
2554 DSI_V_TOTAL(timing),
2555 timing->v_front_porch,
2556 &adj_mode->timing.v_front_porch);
2557 break;
2558
2559 case DSI_DFPS_IMMEDIATE_HFP:
2560 rc = dsi_display_dfps_calc_front_porch(
2561 clk_hz,
2562 timing->refresh_rate,
2563 DSI_V_TOTAL(timing),
2564 DSI_H_TOTAL(timing),
2565 timing->h_front_porch,
2566 &adj_mode->timing.h_front_porch);
2567 if (!rc)
2568 adj_mode->timing.h_front_porch *= display->ctrl_count;
2569 break;
2570
2571 default:
2572 pr_err("Unsupported DFPS mode %d\n", dfps_caps.type);
2573 rc = -ENOTSUPP;
2574 }
2575
2576 return rc;
2577}
2578
2579static bool dsi_display_validate_mode_seamless(struct dsi_display *display,
2580 struct dsi_display_mode *adj_mode)
2581{
2582 int rc = 0;
2583
2584 if (!display || !adj_mode) {
2585 pr_err("Invalid params\n");
2586 return false;
2587 }
2588
2589 /* Currently the only seamless transition is dynamic fps */
2590 rc = dsi_display_get_dfps_timing(display, adj_mode);
2591 if (rc) {
2592 pr_debug("Dynamic FPS not supported for seamless\n");
2593 } else {
2594 pr_debug("Mode switch is seamless Dynamic FPS\n");
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05002595 adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_DFPS |
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002596 DSI_MODE_FLAG_VBLANK_PRE_MODESET;
2597 }
2598
2599 return rc;
2600}
2601
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002602static int dsi_display_set_mode_sub(struct dsi_display *display,
2603 struct dsi_display_mode *mode,
2604 u32 flags)
2605{
2606 int rc = 0;
2607 int i;
2608 struct dsi_display_ctrl *ctrl;
2609
2610 rc = dsi_panel_get_host_cfg_for_mode(display->panel,
2611 mode,
2612 &display->config);
2613 if (rc) {
2614 pr_err("[%s] failed to get host config for mode, rc=%d\n",
2615 display->name, rc);
2616 goto error;
2617 }
2618
2619 memcpy(&display->config.lane_map, &display->lane_map,
2620 sizeof(display->lane_map));
2621
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05002622 if (mode->dsi_mode_flags & DSI_MODE_FLAG_DFPS) {
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002623 rc = dsi_display_dfps_update(display, mode);
2624 if (rc) {
2625 pr_err("[%s]DSI dfps update failed, rc=%d\n",
2626 display->name, rc);
2627 goto error;
2628 }
2629 }
2630
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002631 for (i = 0; i < display->ctrl_count; i++) {
2632 ctrl = &display->ctrl[i];
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002633 rc = dsi_ctrl_update_host_config(ctrl->ctrl, &display->config,
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05002634 mode->dsi_mode_flags, display->dsi_clk_handle);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002635 if (rc) {
2636 pr_err("[%s] failed to update ctrl config, rc=%d\n",
2637 display->name, rc);
2638 goto error;
2639 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002640 }
2641error:
2642 return rc;
2643}
2644
Clarence Ip3649f8b2016-10-31 09:59:44 -04002645/**
2646 * _dsi_display_dev_init - initializes the display device
2647 * Initialization will acquire references to the resources required for the
2648 * display hardware to function.
2649 * @display: Handle to the display
2650 * Returns: Zero on success
2651 */
2652static int _dsi_display_dev_init(struct dsi_display *display)
2653{
2654 int rc = 0;
2655
2656 if (!display) {
2657 pr_err("invalid display\n");
2658 return -EINVAL;
2659 }
2660
2661 mutex_lock(&display->display_lock);
2662
2663 rc = dsi_display_parse_dt(display);
2664 if (rc) {
2665 pr_err("[%s] failed to parse dt, rc=%d\n", display->name, rc);
2666 goto error;
2667 }
2668
2669 rc = dsi_display_res_init(display);
2670 if (rc) {
2671 pr_err("[%s] failed to initialize resources, rc=%d\n",
2672 display->name, rc);
2673 goto error;
2674 }
2675error:
2676 mutex_unlock(&display->display_lock);
2677 return rc;
2678}
2679
2680/**
2681 * _dsi_display_dev_deinit - deinitializes the display device
2682 * All the resources acquired during device init will be released.
2683 * @display: Handle to the display
2684 * Returns: Zero on success
2685 */
2686static int _dsi_display_dev_deinit(struct dsi_display *display)
2687{
2688 int rc = 0;
2689
2690 if (!display) {
2691 pr_err("invalid display\n");
2692 return -EINVAL;
2693 }
2694
2695 mutex_lock(&display->display_lock);
2696
2697 rc = dsi_display_res_deinit(display);
2698 if (rc)
2699 pr_err("[%s] failed to deinitialize resource, rc=%d\n",
2700 display->name, rc);
2701
2702 mutex_unlock(&display->display_lock);
2703
2704 return rc;
2705}
2706
2707/**
2708 * dsi_display_bind - bind dsi device with controlling device
2709 * @dev: Pointer to base of platform device
2710 * @master: Pointer to container of drm device
2711 * @data: Pointer to private data
2712 * Returns: Zero on success
2713 */
2714static int dsi_display_bind(struct device *dev,
2715 struct device *master,
2716 void *data)
2717{
2718 struct dsi_display_ctrl *display_ctrl;
2719 struct drm_device *drm;
2720 struct dsi_display *display;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302721 struct dsi_clk_info info;
2722 struct clk_ctrl_cb clk_cb;
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -08002723 struct msm_drm_private *priv;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302724 void *handle = NULL;
Clarence Ip3649f8b2016-10-31 09:59:44 -04002725 struct platform_device *pdev = to_platform_device(dev);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302726 char *client1 = "dsi_clk_client";
2727 char *client2 = "mdp_event_client";
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -08002728 char dsi_client_name[DSI_CLIENT_NAME_SIZE];
Clarence Ip3649f8b2016-10-31 09:59:44 -04002729 int i, rc = 0;
2730
2731 if (!dev || !pdev || !master) {
2732 pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n",
2733 dev, pdev, master);
2734 return -EINVAL;
2735 }
2736
2737 drm = dev_get_drvdata(master);
2738 display = platform_get_drvdata(pdev);
2739 if (!drm || !display) {
2740 pr_err("invalid param(s), drm %pK, display %pK\n",
2741 drm, display);
2742 return -EINVAL;
2743 }
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -08002744 priv = drm->dev_private;
Clarence Ip3649f8b2016-10-31 09:59:44 -04002745
2746 mutex_lock(&display->display_lock);
2747
2748 rc = dsi_display_debugfs_init(display);
2749 if (rc) {
2750 pr_err("[%s] debugfs init failed, rc=%d\n", display->name, rc);
2751 goto error;
2752 }
2753
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302754 memset(&info, 0x0, sizeof(info));
2755
Clarence Ip3649f8b2016-10-31 09:59:44 -04002756 for (i = 0; i < display->ctrl_count; i++) {
2757 display_ctrl = &display->ctrl[i];
Clarence Ip3649f8b2016-10-31 09:59:44 -04002758 rc = dsi_ctrl_drv_init(display_ctrl->ctrl, display->root);
2759 if (rc) {
2760 pr_err("[%s] failed to initialize ctrl[%d], rc=%d\n",
2761 display->name, i, rc);
2762 goto error_ctrl_deinit;
2763 }
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04002764 display_ctrl->ctrl->horiz_index = i;
Clarence Ip3649f8b2016-10-31 09:59:44 -04002765
2766 rc = dsi_phy_drv_init(display_ctrl->phy);
2767 if (rc) {
2768 pr_err("[%s] Failed to initialize phy[%d], rc=%d\n",
2769 display->name, i, rc);
2770 (void)dsi_ctrl_drv_deinit(display_ctrl->ctrl);
2771 goto error_ctrl_deinit;
2772 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302773
2774 memcpy(&info.c_clks[i], &display_ctrl->ctrl->clk_info.core_clks,
2775 sizeof(struct dsi_core_clk_info));
2776 memcpy(&info.l_clks[i], &display_ctrl->ctrl->clk_info.link_clks,
2777 sizeof(struct dsi_link_clk_info));
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -08002778 info.c_clks[i].phandle = &priv->phandle;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302779 info.bus_handle[i] =
2780 display_ctrl->ctrl->axi_bus_info.bus_handle;
Alexander Beykun32a6a182017-02-27 17:46:51 -05002781 info.ctrl_index[i] = display_ctrl->ctrl->cell_index;
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -08002782 snprintf(dsi_client_name, DSI_CLIENT_NAME_SIZE,
2783 "dsi_core_client%u", i);
2784 info.c_clks[i].dsi_core_client = sde_power_client_create(
2785 info.c_clks[i].phandle, dsi_client_name);
2786 if (IS_ERR_OR_NULL(info.c_clks[i].dsi_core_client)) {
2787 pr_err("[%s] client creation failed for ctrl[%d]",
2788 dsi_client_name, i);
2789 goto error_ctrl_deinit;
2790 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302791 }
2792
2793 info.pre_clkoff_cb = dsi_pre_clkoff_cb;
2794 info.pre_clkon_cb = dsi_pre_clkon_cb;
2795 info.post_clkoff_cb = dsi_post_clkoff_cb;
2796 info.post_clkon_cb = dsi_post_clkon_cb;
2797 info.priv_data = display;
2798 info.master_ndx = display->clk_master_idx;
2799 info.dsi_ctrl_count = display->ctrl_count;
2800 snprintf(info.name, MAX_STRING_LEN,
2801 "DSI_MNGR-%s", display->name);
2802
2803 display->clk_mngr = dsi_display_clk_mngr_register(&info);
2804 if (IS_ERR_OR_NULL(display->clk_mngr)) {
2805 rc = PTR_ERR(display->clk_mngr);
2806 display->clk_mngr = NULL;
2807 pr_err("dsi clock registration failed, rc = %d\n", rc);
2808 goto error_ctrl_deinit;
2809 }
2810
2811 handle = dsi_register_clk_handle(display->clk_mngr, client1);
2812 if (IS_ERR_OR_NULL(handle)) {
2813 rc = PTR_ERR(handle);
2814 pr_err("failed to register %s client, rc = %d\n",
2815 client1, rc);
2816 goto error_clk_deinit;
2817 } else {
2818 display->dsi_clk_handle = handle;
2819 }
2820
2821 handle = dsi_register_clk_handle(display->clk_mngr, client2);
2822 if (IS_ERR_OR_NULL(handle)) {
2823 rc = PTR_ERR(handle);
2824 pr_err("failed to register %s client, rc = %d\n",
2825 client2, rc);
2826 goto error_clk_client_deinit;
2827 } else {
2828 display->mdp_clk_handle = handle;
2829 }
2830
2831 clk_cb.priv = display;
2832 clk_cb.dsi_clk_cb = dsi_display_clk_ctrl_cb;
2833
2834 for (i = 0; i < display->ctrl_count; i++) {
2835 display_ctrl = &display->ctrl[i];
2836
2837 rc = dsi_ctrl_clk_cb_register(display_ctrl->ctrl, &clk_cb);
2838 if (rc) {
2839 pr_err("[%s] failed to register ctrl clk_cb[%d], rc=%d\n",
2840 display->name, i, rc);
2841 goto error_ctrl_deinit;
2842 }
2843
2844 rc = dsi_phy_clk_cb_register(display_ctrl->phy, &clk_cb);
2845 if (rc) {
2846 pr_err("[%s] failed to register phy clk_cb[%d], rc=%d\n",
2847 display->name, i, rc);
2848 goto error_ctrl_deinit;
2849 }
Clarence Ip3649f8b2016-10-31 09:59:44 -04002850 }
2851
2852 rc = dsi_display_mipi_host_init(display);
2853 if (rc) {
2854 pr_err("[%s] failed to initialize mipi host, rc=%d\n",
2855 display->name, rc);
2856 goto error_ctrl_deinit;
2857 }
2858
2859 rc = dsi_panel_drv_init(display->panel, &display->host);
2860 if (rc) {
2861 if (rc != -EPROBE_DEFER)
2862 pr_err("[%s] failed to initialize panel driver, rc=%d\n",
2863 display->name, rc);
2864 goto error_host_deinit;
2865 }
2866
2867 rc = dsi_panel_get_mode_count(display->panel, &display->num_of_modes);
2868 if (rc) {
2869 pr_err("[%s] failed to get mode count, rc=%d\n",
2870 display->name, rc);
2871 goto error_panel_deinit;
2872 }
2873
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07002874 pr_info("Successfully bind display panel '%s'\n", display->name);
Clarence Ip3649f8b2016-10-31 09:59:44 -04002875 display->drm_dev = drm;
2876 goto error;
2877
2878error_panel_deinit:
2879 (void)dsi_panel_drv_deinit(display->panel);
2880error_host_deinit:
2881 (void)dsi_display_mipi_host_deinit(display);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302882error_clk_client_deinit:
2883 (void)dsi_deregister_clk_handle(display->dsi_clk_handle);
2884error_clk_deinit:
2885 (void)dsi_display_clk_mngr_deregister(display->clk_mngr);
Clarence Ip3649f8b2016-10-31 09:59:44 -04002886error_ctrl_deinit:
2887 for (i = i - 1; i >= 0; i--) {
2888 display_ctrl = &display->ctrl[i];
2889 (void)dsi_phy_drv_deinit(display_ctrl->phy);
2890 (void)dsi_ctrl_drv_deinit(display_ctrl->ctrl);
2891 }
2892 (void)dsi_display_debugfs_deinit(display);
2893error:
2894 mutex_unlock(&display->display_lock);
2895 return rc;
2896}
2897
2898/**
2899 * dsi_display_unbind - unbind dsi from controlling device
2900 * @dev: Pointer to base of platform device
2901 * @master: Pointer to container of drm device
2902 * @data: Pointer to private data
2903 */
2904static void dsi_display_unbind(struct device *dev,
2905 struct device *master, void *data)
2906{
2907 struct dsi_display_ctrl *display_ctrl;
2908 struct dsi_display *display;
2909 struct platform_device *pdev = to_platform_device(dev);
2910 int i, rc = 0;
2911
2912 if (!dev || !pdev) {
2913 pr_err("invalid param(s)\n");
2914 return;
2915 }
2916
2917 display = platform_get_drvdata(pdev);
2918 if (!display) {
2919 pr_err("invalid display\n");
2920 return;
2921 }
2922
2923 mutex_lock(&display->display_lock);
2924
2925 rc = dsi_panel_drv_deinit(display->panel);
2926 if (rc)
2927 pr_err("[%s] failed to deinit panel driver, rc=%d\n",
2928 display->name, rc);
2929
2930 rc = dsi_display_mipi_host_deinit(display);
2931 if (rc)
2932 pr_err("[%s] failed to deinit mipi hosts, rc=%d\n",
2933 display->name,
2934 rc);
2935
2936 for (i = 0; i < display->ctrl_count; i++) {
2937 display_ctrl = &display->ctrl[i];
2938
2939 rc = dsi_phy_drv_deinit(display_ctrl->phy);
2940 if (rc)
2941 pr_err("[%s] failed to deinit phy%d driver, rc=%d\n",
2942 display->name, i, rc);
2943
2944 rc = dsi_ctrl_drv_deinit(display_ctrl->ctrl);
2945 if (rc)
2946 pr_err("[%s] failed to deinit ctrl%d driver, rc=%d\n",
2947 display->name, i, rc);
2948 }
2949 (void)dsi_display_debugfs_deinit(display);
2950
2951 mutex_unlock(&display->display_lock);
2952}
2953
2954static const struct component_ops dsi_display_comp_ops = {
2955 .bind = dsi_display_bind,
2956 .unbind = dsi_display_unbind,
2957};
2958
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07002959static struct platform_driver dsi_display_driver = {
2960 .probe = dsi_display_dev_probe,
2961 .remove = dsi_display_dev_remove,
2962 .driver = {
2963 .name = "msm-dsi-display",
2964 .of_match_table = dsi_display_dt_match,
2965 },
2966};
2967
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002968int dsi_display_dev_probe(struct platform_device *pdev)
2969{
2970 int rc = 0;
2971 struct dsi_display *display;
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07002972 static bool display_from_cmdline, boot_displays_parsed;
2973 static bool comp_add_success;
2974 static struct device_node *primary_np, *secondary_np;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002975
2976 if (!pdev || !pdev->dev.of_node) {
2977 pr_err("pdev not found\n");
2978 return -ENODEV;
2979 }
2980
2981 display = devm_kzalloc(&pdev->dev, sizeof(*display), GFP_KERNEL);
2982 if (!display)
2983 return -ENOMEM;
2984
2985 display->name = of_get_property(pdev->dev.of_node, "label", NULL);
2986
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07002987 if (!boot_displays_parsed) {
2988 boot_displays[DSI_PRIMARY].boot_disp_en = false;
2989 boot_displays[DSI_SECONDARY].boot_disp_en = false;
2990 if (dsi_display_parse_boot_display_selection())
2991 pr_debug("Display Boot param not valid/available\n");
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07002992
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07002993 boot_displays_parsed = true;
2994 }
2995
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07002996 /* Initialize cmdline_topology to use default topology */
2997 display->cmdline_topology = -1;
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07002998 if ((!display_from_cmdline) &&
2999 (boot_displays[DSI_PRIMARY].boot_disp_en)) {
3000 display->is_active = dsi_display_name_compare(pdev->dev.of_node,
3001 display->name, DSI_PRIMARY);
3002 if (display->is_active) {
3003 if (comp_add_success) {
3004 (void)_dsi_display_dev_deinit(main_display);
3005 component_del(&main_display->pdev->dev,
3006 &dsi_display_comp_ops);
Dhaval Patel081400e2017-06-21 19:24:48 -07003007 mutex_lock(&dsi_display_list_lock);
3008 list_del(&main_display->list);
3009 mutex_unlock(&dsi_display_list_lock);
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003010 comp_add_success = false;
3011 default_active_node = NULL;
3012 pr_debug("removed the existing comp ops\n");
3013 }
3014 /*
3015 * Need to add component for
3016 * the secondary DSI display
3017 * when more than one DSI display
3018 * is supported.
3019 */
3020 pr_debug("cmdline primary dsi: %s\n",
3021 display->name);
3022 display_from_cmdline = true;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07003023 display->cmdline_topology =
3024 dsi_display_parse_cmdline_topology(DSI_PRIMARY);
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003025 primary_np = pdev->dev.of_node;
3026 }
3027 }
3028
3029 if (boot_displays[DSI_SECONDARY].boot_disp_en) {
3030 if (!secondary_np) {
3031 if (dsi_display_name_compare(pdev->dev.of_node,
3032 display->name, DSI_SECONDARY)) {
3033 pr_debug("cmdline secondary dsi: %s\n",
3034 display->name);
3035 secondary_np = pdev->dev.of_node;
3036 if (primary_np) {
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07003037 if (validate_dsi_display_selection()) {
3038 display->is_active = true;
3039 display->cmdline_topology =
3040 dsi_display_parse_cmdline_topology
3041 (DSI_SECONDARY);
3042 } else {
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003043 boot_displays[DSI_SECONDARY]
3044 .boot_disp_en = false;
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07003045 }
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003046 }
3047 }
3048 }
3049 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003050 display->display_type = of_get_property(pdev->dev.of_node,
3051 "qcom,display-type", NULL);
3052 if (!display->display_type)
3053 display->display_type = "unknown";
3054
3055 mutex_init(&display->display_lock);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003056 display->pdev = pdev;
3057 platform_set_drvdata(pdev, display);
3058 mutex_lock(&dsi_display_list_lock);
3059 list_add(&display->list, &dsi_display_list);
3060 mutex_unlock(&dsi_display_list_lock);
Clarence Ip3649f8b2016-10-31 09:59:44 -04003061
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003062 if (!display_from_cmdline)
3063 display->is_active = of_property_read_bool(pdev->dev.of_node,
3064 "qcom,dsi-display-active");
3065
Clarence Ip3649f8b2016-10-31 09:59:44 -04003066 if (display->is_active) {
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003067 main_display = display;
Clarence Ip3649f8b2016-10-31 09:59:44 -04003068 rc = _dsi_display_dev_init(display);
3069 if (rc) {
3070 pr_err("device init failed, rc=%d\n", rc);
3071 return rc;
3072 }
3073
3074 rc = component_add(&pdev->dev, &dsi_display_comp_ops);
3075 if (rc)
3076 pr_err("component add failed, rc=%d\n", rc);
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003077
3078 comp_add_success = true;
3079 pr_debug("Component_add success: %s\n", display->name);
3080 if (!display_from_cmdline)
3081 default_active_node = pdev->dev.of_node;
Clarence Ip3649f8b2016-10-31 09:59:44 -04003082 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003083 return rc;
3084}
3085
3086int dsi_display_dev_remove(struct platform_device *pdev)
3087{
3088 int rc = 0;
3089 struct dsi_display *display;
3090 struct dsi_display *pos, *tmp;
3091
3092 if (!pdev) {
3093 pr_err("Invalid device\n");
3094 return -EINVAL;
3095 }
3096
3097 display = platform_get_drvdata(pdev);
3098
Clarence Ip3649f8b2016-10-31 09:59:44 -04003099 (void)_dsi_display_dev_deinit(display);
3100
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003101 mutex_lock(&dsi_display_list_lock);
3102 list_for_each_entry_safe(pos, tmp, &dsi_display_list, list) {
3103 if (pos == display) {
3104 list_del(&display->list);
3105 break;
3106 }
3107 }
3108 mutex_unlock(&dsi_display_list_lock);
3109
3110 platform_set_drvdata(pdev, NULL);
3111 devm_kfree(&pdev->dev, display);
3112 return rc;
3113}
3114
Clarence Ip3649f8b2016-10-31 09:59:44 -04003115int dsi_display_get_num_of_displays(void)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003116{
Clarence Ip3649f8b2016-10-31 09:59:44 -04003117 int count = 0;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003118 struct dsi_display *display;
3119
3120 mutex_lock(&dsi_display_list_lock);
3121
3122 list_for_each_entry(display, &dsi_display_list, list) {
3123 count++;
3124 }
3125
3126 mutex_unlock(&dsi_display_list_lock);
3127 return count;
3128}
3129
Clarence Ipa36c92e2016-07-26 14:33:46 -04003130int dsi_display_get_active_displays(void **display_array, u32 max_display_count)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003131{
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003132 struct dsi_display *pos;
3133 int i = 0;
3134
Clarence Ipa36c92e2016-07-26 14:33:46 -04003135 if (!display_array || !max_display_count) {
3136 if (!display_array)
3137 pr_err("invalid params\n");
3138 return 0;
3139 }
3140
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003141 mutex_lock(&dsi_display_list_lock);
3142
3143 list_for_each_entry(pos, &dsi_display_list, list) {
Clarence Ipa36c92e2016-07-26 14:33:46 -04003144 if (i >= max_display_count) {
3145 pr_err("capping display count to %d\n", i);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003146 break;
3147 }
Clarence Ipa36c92e2016-07-26 14:33:46 -04003148 if (pos->is_active)
3149 display_array[i++] = pos;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003150 }
3151
3152 mutex_unlock(&dsi_display_list_lock);
Clarence Ipa36c92e2016-07-26 14:33:46 -04003153 return i;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003154}
3155
3156struct dsi_display *dsi_display_get_display_by_name(const char *name)
3157{
3158 struct dsi_display *display = NULL, *pos;
3159
3160 mutex_lock(&dsi_display_list_lock);
3161
3162 list_for_each_entry(pos, &dsi_display_list, list) {
3163 if (!strcmp(name, pos->name))
3164 display = pos;
3165 }
3166
3167 mutex_unlock(&dsi_display_list_lock);
3168
3169 return display;
3170}
3171
3172void dsi_display_set_active_state(struct dsi_display *display, bool is_active)
3173{
3174 mutex_lock(&display->display_lock);
3175 display->is_active = is_active;
3176 mutex_unlock(&display->display_lock);
3177}
3178
Clarence Ip40d7d592016-07-15 16:02:26 -04003179int dsi_display_drm_bridge_init(struct dsi_display *display,
3180 struct drm_encoder *enc)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003181{
3182 int rc = 0;
3183 struct dsi_bridge *bridge;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003184 struct msm_drm_private *priv = NULL;
3185
Clarence Ip3649f8b2016-10-31 09:59:44 -04003186 if (!display || !display->drm_dev || !enc) {
3187 pr_err("invalid param(s)\n");
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003188 return -EINVAL;
3189 }
3190
3191 mutex_lock(&display->display_lock);
3192 priv = display->drm_dev->dev_private;
3193
3194 if (!priv) {
3195 pr_err("Private data is not present\n");
3196 rc = -EINVAL;
3197 goto error;
3198 }
3199
Clarence Ip40d7d592016-07-15 16:02:26 -04003200 if (display->bridge) {
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003201 pr_err("display is already initialize\n");
3202 goto error;
3203 }
3204
3205 bridge = dsi_drm_bridge_init(display, display->drm_dev, enc);
3206 if (IS_ERR_OR_NULL(bridge)) {
3207 rc = PTR_ERR(bridge);
Clarence Ipa36c92e2016-07-26 14:33:46 -04003208 pr_err("[%s] brige init failed, %d\n", display->name, rc);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003209 goto error;
3210 }
3211
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003212 display->bridge = bridge;
3213 priv->bridges[priv->num_bridges++] = &bridge->base;
3214
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003215error:
3216 mutex_unlock(&display->display_lock);
3217 return rc;
3218}
3219
Clarence Ip40d7d592016-07-15 16:02:26 -04003220int dsi_display_drm_bridge_deinit(struct dsi_display *display)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003221{
3222 int rc = 0;
3223
3224 if (!display) {
3225 pr_err("Invalid params\n");
3226 return -EINVAL;
3227 }
3228
3229 mutex_lock(&display->display_lock);
3230
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003231 dsi_drm_bridge_cleanup(display->bridge);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003232 display->bridge = NULL;
3233
3234 mutex_unlock(&display->display_lock);
3235 return rc;
3236}
3237
Clarence Ipa4039322016-07-15 16:23:59 -04003238int dsi_display_get_info(struct msm_display_info *info, void *disp)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003239{
Clarence Ipa4039322016-07-15 16:23:59 -04003240 struct dsi_display *display;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003241 struct dsi_panel_phy_props phy_props;
Dhaval Patel60e1ff52017-02-18 21:03:40 -08003242 struct dsi_mode_info *timing;
Clarence Ipa4039322016-07-15 16:23:59 -04003243 int i, rc;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003244
Clarence Ipa4039322016-07-15 16:23:59 -04003245 if (!info || !disp) {
3246 pr_err("invalid params\n");
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003247 return -EINVAL;
3248 }
Dhaval Patel60e1ff52017-02-18 21:03:40 -08003249
Clarence Ipa4039322016-07-15 16:23:59 -04003250 display = disp;
Dhaval Patel60e1ff52017-02-18 21:03:40 -08003251 if (!display->panel) {
3252 pr_err("invalid display panel\n");
3253 return -EINVAL;
3254 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003255
3256 mutex_lock(&display->display_lock);
3257 rc = dsi_panel_get_phy_props(display->panel, &phy_props);
3258 if (rc) {
3259 pr_err("[%s] failed to get panel phy props, rc=%d\n",
3260 display->name, rc);
3261 goto error;
3262 }
3263
Alan Kwong735b3db2017-05-03 06:47:52 -07003264 memset(info, 0, sizeof(struct msm_display_info));
Clarence Ipa4039322016-07-15 16:23:59 -04003265 info->intf_type = DRM_MODE_CONNECTOR_DSI;
Dhaval Patel60e1ff52017-02-18 21:03:40 -08003266 timing = &display->panel->mode.timing;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003267
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003268 info->num_of_h_tiles = display->ctrl_count;
3269 for (i = 0; i < info->num_of_h_tiles; i++)
Alexander Beykun32a6a182017-02-27 17:46:51 -05003270 info->h_tile_instance[i] = display->ctrl[i].ctrl->cell_index;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003271
Clarence Ipa4039322016-07-15 16:23:59 -04003272 info->is_connected = true;
Dhaval Patel020f7e122016-11-15 14:39:18 -08003273 info->is_primary = true;
Dhaval Patel60e1ff52017-02-18 21:03:40 -08003274 info->frame_rate = timing->refresh_rate;
3275 info->vtotal = DSI_V_TOTAL(timing);
3276 info->prefill_lines = display->panel->panel_prefill_lines;
Dhaval Patelf5cc5a32017-07-10 17:33:23 -07003277 info->jitter_numer = display->panel->panel_jitter_numer;
3278 info->jitter_denom = display->panel->panel_jitter_denom;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003279 info->width_mm = phy_props.panel_width_mm;
3280 info->height_mm = phy_props.panel_height_mm;
Clarence Ipa4039322016-07-15 16:23:59 -04003281 info->max_width = 1920;
3282 info->max_height = 1080;
Alexander Beykunac182352017-02-27 17:46:51 -05003283 info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE;
3284
3285 if (display->panel->dsc_enabled) {
3286 info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC;
3287 memcpy(&info->comp_info.dsc_info, &display->panel->dsc,
3288 sizeof(struct msm_display_dsc_info));
3289 }
Lloyd Atkinsone404caf2016-07-13 17:26:45 -04003290
Clarence Ipa4039322016-07-15 16:23:59 -04003291 switch (display->panel->mode.panel_mode) {
3292 case DSI_OP_VIDEO_MODE:
3293 info->capabilities |= MSM_DISPLAY_CAP_VID_MODE;
3294 break;
3295 case DSI_OP_CMD_MODE:
3296 info->capabilities |= MSM_DISPLAY_CAP_CMD_MODE;
Narendra Muppallad4081e12017-04-20 19:24:08 -07003297 info->is_te_using_watchdog_timer =
3298 display->panel->te_using_watchdog_timer;
Clarence Ipa4039322016-07-15 16:23:59 -04003299 break;
3300 default:
3301 pr_err("unknwown dsi panel mode %d\n",
3302 display->panel->mode.panel_mode);
3303 break;
3304 }
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04003305
3306 memcpy(&info->roi_caps, &display->panel->roi_caps,
3307 sizeof(info->roi_caps));
3308
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003309error:
3310 mutex_unlock(&display->display_lock);
3311 return rc;
3312}
3313
3314int dsi_display_get_modes(struct dsi_display *display,
3315 struct dsi_display_mode *modes,
3316 u32 *count)
3317{
3318 int rc = 0;
3319 int i;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003320 struct dsi_dfps_capabilities dfps_caps;
3321 int num_dfps_rates;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003322
3323 if (!display || !count) {
3324 pr_err("Invalid params\n");
3325 return -EINVAL;
3326 }
3327
3328 mutex_lock(&display->display_lock);
3329
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003330 rc = dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
3331 if (rc) {
3332 pr_err("[%s] failed to get dfps caps from panel\n",
3333 display->name);
3334 goto error;
3335 }
3336
3337 num_dfps_rates = !dfps_caps.dfps_support ? 1 :
3338 dfps_caps.max_refresh_rate -
3339 dfps_caps.min_refresh_rate + 1;
3340
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003341 if (!modes) {
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003342 /* Inflate num_of_modes by fps in dfps */
3343 *count = display->num_of_modes * num_dfps_rates;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003344 goto error;
3345 }
3346
3347 for (i = 0; i < *count; i++) {
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003348 /* Insert the dfps "sub-modes" between main panel modes */
3349 int panel_mode_idx = i / num_dfps_rates;
3350
3351 rc = dsi_panel_get_mode(display->panel, panel_mode_idx, modes);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003352 if (rc) {
3353 pr_err("[%s] failed to get mode from panel\n",
3354 display->name);
3355 goto error;
3356 }
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003357
3358 if (dfps_caps.dfps_support) {
3359 modes->timing.refresh_rate = dfps_caps.min_refresh_rate
3360 + (i % num_dfps_rates);
3361 modes->pixel_clk_khz = (DSI_H_TOTAL(&modes->timing) *
3362 DSI_V_TOTAL(&modes->timing) *
3363 modes->timing.refresh_rate) / 1000;
3364 }
3365
3366 if (display->ctrl_count > 1) { /* TODO: remove if */
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003367 modes->timing.h_active *= display->ctrl_count;
3368 modes->timing.h_front_porch *= display->ctrl_count;
3369 modes->timing.h_sync_width *= display->ctrl_count;
3370 modes->timing.h_back_porch *= display->ctrl_count;
3371 modes->timing.h_skew *= display->ctrl_count;
3372 modes->pixel_clk_khz *= display->ctrl_count;
3373 }
3374
3375 modes++;
3376 }
3377
3378error:
3379 mutex_unlock(&display->display_lock);
3380 return rc;
3381}
3382
3383int dsi_display_validate_mode(struct dsi_display *display,
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003384 struct dsi_display_mode *mode,
3385 u32 flags)
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003386{
3387 int rc = 0;
3388 int i;
3389 struct dsi_display_ctrl *ctrl;
3390 struct dsi_display_mode adj_mode;
3391
3392 if (!display || !mode) {
3393 pr_err("Invalid params\n");
3394 return -EINVAL;
3395 }
3396
3397 mutex_lock(&display->display_lock);
3398
3399 adj_mode = *mode;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003400 adjust_timing_by_ctrl_count(display, &adj_mode);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003401
3402 rc = dsi_panel_validate_mode(display->panel, &adj_mode);
3403 if (rc) {
3404 pr_err("[%s] panel mode validation failed, rc=%d\n",
3405 display->name, rc);
3406 goto error;
3407 }
3408
3409 for (i = 0; i < display->ctrl_count; i++) {
3410 ctrl = &display->ctrl[i];
3411 rc = dsi_ctrl_validate_timing(ctrl->ctrl, &adj_mode.timing);
3412 if (rc) {
3413 pr_err("[%s] ctrl mode validation failed, rc=%d\n",
3414 display->name, rc);
3415 goto error;
3416 }
3417
3418 rc = dsi_phy_validate_mode(ctrl->phy, &adj_mode.timing);
3419 if (rc) {
3420 pr_err("[%s] phy mode validation failed, rc=%d\n",
3421 display->name, rc);
3422 goto error;
3423 }
3424 }
3425
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003426 if ((flags & DSI_VALIDATE_FLAG_ALLOW_ADJUST) &&
Lloyd Atkinson7d12ce02016-12-13 11:32:57 -05003427 (mode->dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS)) {
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003428 rc = dsi_display_validate_mode_seamless(display, mode);
3429 if (rc) {
3430 pr_err("[%s] seamless not possible rc=%d\n",
3431 display->name, rc);
3432 goto error;
3433 }
3434 }
3435
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003436error:
3437 mutex_unlock(&display->display_lock);
3438 return rc;
3439}
3440
3441int dsi_display_set_mode(struct dsi_display *display,
3442 struct dsi_display_mode *mode,
3443 u32 flags)
3444{
3445 int rc = 0;
3446 struct dsi_display_mode adj_mode;
3447
3448 if (!display || !mode) {
3449 pr_err("Invalid params\n");
3450 return -EINVAL;
3451 }
3452
3453 mutex_lock(&display->display_lock);
3454
3455 adj_mode = *mode;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07003456 adjust_timing_by_ctrl_count(display, &adj_mode);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003457
3458 rc = dsi_display_validate_mode_set(display, &adj_mode, flags);
3459 if (rc) {
3460 pr_err("[%s] mode cannot be set\n", display->name);
3461 goto error;
3462 }
3463
3464 rc = dsi_display_set_mode_sub(display, &adj_mode, flags);
3465 if (rc) {
3466 pr_err("[%s] failed to set mode\n", display->name);
3467 goto error;
3468 }
3469error:
3470 mutex_unlock(&display->display_lock);
3471 return rc;
3472}
3473
3474int dsi_display_set_tpg_state(struct dsi_display *display, bool enable)
3475{
3476 int rc = 0;
3477 int i;
3478 struct dsi_display_ctrl *ctrl;
3479
3480 if (!display) {
3481 pr_err("Invalid params\n");
3482 return -EINVAL;
3483 }
3484
3485 for (i = 0; i < display->ctrl_count; i++) {
3486 ctrl = &display->ctrl[i];
3487 rc = dsi_ctrl_set_tpg_state(ctrl->ctrl, enable);
3488 if (rc) {
3489 pr_err("[%s] failed to set tpg state for host_%d\n",
3490 display->name, i);
3491 goto error;
3492 }
3493 }
3494
3495 display->is_tpg_enabled = enable;
3496error:
3497 return rc;
3498}
3499
3500int dsi_display_prepare(struct dsi_display *display)
3501{
3502 int rc = 0;
3503
3504 if (!display) {
3505 pr_err("Invalid params\n");
3506 return -EINVAL;
3507 }
3508
3509 mutex_lock(&display->display_lock);
3510
3511 rc = dsi_panel_pre_prepare(display->panel);
3512 if (rc) {
3513 pr_err("[%s] panel pre-prepare failed, rc=%d\n",
3514 display->name, rc);
3515 goto error;
3516 }
3517
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303518 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
3519 DSI_CORE_CLK, DSI_CLK_ON);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003520 if (rc) {
3521 pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
3522 display->name, rc);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303523 goto error_panel_post_unprep;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003524 }
3525
3526 rc = dsi_display_phy_sw_reset(display);
3527 if (rc) {
3528 pr_err("[%s] failed to reset phy, rc=%d\n", display->name, rc);
3529 goto error_ctrl_clk_off;
3530 }
3531
3532 rc = dsi_display_phy_enable(display);
3533 if (rc) {
3534 pr_err("[%s] failed to enable DSI PHY, rc=%d\n",
3535 display->name, rc);
3536 goto error_ctrl_clk_off;
3537 }
3538
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07003539 rc = dsi_display_set_clk_src(display);
3540 if (rc) {
3541 pr_err("[%s] failed to set DSI link clock source, rc=%d\n",
3542 display->name, rc);
3543 goto error_phy_disable;
3544 }
3545
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003546 rc = dsi_display_ctrl_init(display);
3547 if (rc) {
3548 pr_err("[%s] failed to setup DSI controller, rc=%d\n",
3549 display->name, rc);
3550 goto error_phy_disable;
3551 }
3552
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07003553 rc = dsi_display_ctrl_host_enable(display);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303554 if (rc) {
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07003555 pr_err("[%s] failed to enable DSI host, rc=%d\n",
3556 display->name, rc);
Veera Sundaram Sankaran518a8632017-05-01 16:37:55 -07003557 goto error_ctrl_deinit;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303558 }
3559
3560 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
3561 DSI_LINK_CLK, DSI_CLK_ON);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003562 if (rc) {
3563 pr_err("[%s] failed to enable DSI link clocks, rc=%d\n",
3564 display->name, rc);
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07003565 goto error_host_engine_off;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003566 }
3567
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07003568 rc = dsi_display_soft_reset(display);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003569 if (rc) {
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07003570 pr_err("[%s] failed soft reset, rc=%d\n", display->name, rc);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003571 goto error_ctrl_link_off;
3572 }
3573
3574 rc = dsi_panel_prepare(display->panel);
3575 if (rc) {
3576 pr_err("[%s] panel prepare failed, rc=%d\n", display->name, rc);
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07003577 goto error_ctrl_link_off;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003578 }
3579
3580 goto error;
3581
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003582error_ctrl_link_off:
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303583 (void)dsi_display_clk_ctrl(display->dsi_clk_handle,
3584 DSI_LINK_CLK, DSI_CLK_OFF);
Sandeep Pandadb8ae1b2017-08-03 15:18:32 -07003585error_host_engine_off:
3586 (void)dsi_display_ctrl_host_disable(display);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003587error_ctrl_deinit:
3588 (void)dsi_display_ctrl_deinit(display);
3589error_phy_disable:
3590 (void)dsi_display_phy_disable(display);
3591error_ctrl_clk_off:
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303592 (void)dsi_display_clk_ctrl(display->dsi_clk_handle,
3593 DSI_CORE_CLK, DSI_CLK_OFF);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003594error_panel_post_unprep:
3595 (void)dsi_panel_post_unprepare(display->panel);
3596error:
3597 mutex_unlock(&display->display_lock);
3598 return rc;
3599}
3600
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04003601static int dsi_display_calc_ctrl_roi(const struct dsi_display *display,
3602 const struct dsi_display_ctrl *ctrl,
3603 const struct msm_roi_list *req_rois,
3604 struct dsi_rect *out_roi)
3605{
3606 const struct dsi_rect *bounds = &ctrl->ctrl->mode_bounds;
3607 struct dsi_rect req_roi = { 0 };
3608 int rc = 0;
3609
3610 if (req_rois->num_rects > display->panel->roi_caps.num_roi) {
3611 pr_err("request for %d rois greater than max %d\n",
3612 req_rois->num_rects,
3613 display->panel->roi_caps.num_roi);
3614 rc = -EINVAL;
3615 goto exit;
3616 }
3617
3618 /**
3619 * if no rois, user wants to reset back to full resolution
3620 * note: h_active is already divided by ctrl_count
3621 */
3622 if (!req_rois->num_rects) {
3623 *out_roi = *bounds;
3624 goto exit;
3625 }
3626
3627 /* intersect with the bounds */
3628 req_roi.x = req_rois->roi[0].x1;
3629 req_roi.y = req_rois->roi[0].y1;
3630 req_roi.w = req_rois->roi[0].x2 - req_rois->roi[0].x1;
3631 req_roi.h = req_rois->roi[0].y2 - req_rois->roi[0].y1;
3632 dsi_rect_intersect(&req_roi, bounds, out_roi);
3633
3634exit:
3635 /* adjust the ctrl origin to be top left within the ctrl */
3636 out_roi->x = out_roi->x - bounds->x;
3637
3638 pr_debug("ctrl%d:%d: req (%d,%d,%d,%d) bnd (%d,%d,%d,%d) out (%d,%d,%d,%d)\n",
3639 ctrl->dsi_ctrl_idx, ctrl->ctrl->cell_index,
3640 req_roi.x, req_roi.y, req_roi.w, req_roi.h,
3641 bounds->x, bounds->y, bounds->w, bounds->h,
3642 out_roi->x, out_roi->y, out_roi->w, out_roi->h);
3643
3644 return rc;
3645}
3646
3647static int dsi_display_set_roi(struct dsi_display *display,
3648 struct msm_roi_list *rois)
3649{
3650 int rc = 0;
3651 int i;
3652
3653 if (!display || !rois || !display->panel)
3654 return -EINVAL;
3655
3656 if (!display->panel->roi_caps.enabled)
3657 return 0;
3658
3659 for (i = 0; i < display->ctrl_count; i++) {
3660 struct dsi_display_ctrl *ctrl = &display->ctrl[i];
3661 struct dsi_rect ctrl_roi;
3662 bool changed = false;
3663
3664 rc = dsi_display_calc_ctrl_roi(display, ctrl, rois, &ctrl_roi);
3665 if (rc) {
3666 pr_err("dsi_display_calc_ctrl_roi failed rc %d\n", rc);
3667 return rc;
3668 }
3669
3670 rc = dsi_ctrl_set_roi(ctrl->ctrl, &ctrl_roi, &changed);
3671 if (rc) {
3672 pr_err("dsi_ctrl_set_roi failed rc %d\n", rc);
3673 return rc;
3674 }
3675
3676 if (!changed)
3677 continue;
3678
3679 /* send the new roi to the panel via dcs commands */
3680 rc = dsi_panel_send_roi_dcs(display->panel, i, &ctrl_roi);
3681 if (rc) {
3682 pr_err("dsi_panel_set_roi failed rc %d\n", rc);
3683 return rc;
3684 }
3685
3686 /* re-program the ctrl with the timing based on the new roi */
3687 rc = dsi_ctrl_setup(ctrl->ctrl);
3688 if (rc) {
3689 pr_err("dsi_ctrl_setup failed rc %d\n", rc);
3690 return rc;
3691 }
3692 }
3693
3694 return rc;
3695}
3696
Lloyd Atkinson05d75512017-01-17 14:45:51 -05003697int dsi_display_pre_kickoff(struct dsi_display *display,
3698 struct msm_display_kickoff_params *params)
3699{
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04003700 int rc = 0;
3701
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -04003702 /* check and setup MISR */
3703 if (display->misr_enable)
3704 _dsi_display_setup_misr(display);
3705
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04003706 rc = dsi_display_set_roi(display, params->rois);
3707
3708 return rc;
Lloyd Atkinson05d75512017-01-17 14:45:51 -05003709}
3710
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003711int dsi_display_enable(struct dsi_display *display)
3712{
3713 int rc = 0;
3714
3715 if (!display) {
3716 pr_err("Invalid params\n");
3717 return -EINVAL;
3718 }
3719
3720 mutex_lock(&display->display_lock);
3721
3722 rc = dsi_panel_enable(display->panel);
3723 if (rc) {
3724 pr_err("[%s] failed to enable DSI panel, rc=%d\n",
3725 display->name, rc);
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07003726 goto error;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003727 }
3728
Alexander Beykunac182352017-02-27 17:46:51 -05003729 if (display->panel->dsc_enabled) {
3730 display->panel->dsc.pic_width *= display->ctrl_count;
3731 rc = dsi_panel_update_pps(display->panel);
3732 if (rc) {
3733 pr_err("[%s] panel pps cmd update failed, rc=%d\n",
3734 display->name, rc);
3735 goto error;
3736 }
3737 }
3738
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07003739 if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
3740 rc = dsi_display_vid_engine_enable(display);
3741 if (rc) {
3742 pr_err("[%s]failed to enable DSI video engine, rc=%d\n",
3743 display->name, rc);
3744 goto error_disable_panel;
3745 }
3746 } else if (display->config.panel_mode == DSI_OP_CMD_MODE) {
3747 rc = dsi_display_cmd_engine_enable(display);
3748 if (rc) {
3749 pr_err("[%s]failed to enable DSI cmd engine, rc=%d\n",
3750 display->name, rc);
3751 goto error_disable_panel;
3752 }
3753 } else {
3754 pr_err("[%s] Invalid configuration\n", display->name);
3755 rc = -EINVAL;
3756 goto error_disable_panel;
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003757 }
3758
3759 goto error;
3760
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07003761error_disable_panel:
3762 (void)dsi_panel_disable(display->panel);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003763error:
3764 mutex_unlock(&display->display_lock);
3765 return rc;
3766}
3767
3768int dsi_display_post_enable(struct dsi_display *display)
3769{
3770 int rc = 0;
3771
3772 if (!display) {
3773 pr_err("Invalid params\n");
3774 return -EINVAL;
3775 }
3776
3777 mutex_lock(&display->display_lock);
3778
3779 rc = dsi_panel_post_enable(display->panel);
3780 if (rc)
3781 pr_err("[%s] panel post-enable failed, rc=%d\n",
3782 display->name, rc);
3783
Veera Sundaram Sankaran4e109162017-04-21 10:36:46 -07003784 /* remove the clk vote for CMD mode panels */
3785 if (display->config.panel_mode == DSI_OP_CMD_MODE)
3786 dsi_display_clk_ctrl(display->dsi_clk_handle,
3787 DSI_ALL_CLKS, DSI_CLK_OFF);
3788
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003789 mutex_unlock(&display->display_lock);
3790 return rc;
3791}
3792
3793int dsi_display_pre_disable(struct dsi_display *display)
3794{
3795 int rc = 0;
3796
3797 if (!display) {
3798 pr_err("Invalid params\n");
3799 return -EINVAL;
3800 }
3801
3802 mutex_lock(&display->display_lock);
3803
Veera Sundaram Sankaran4e109162017-04-21 10:36:46 -07003804 /* enable the clk vote for CMD mode panels */
3805 if (display->config.panel_mode == DSI_OP_CMD_MODE)
3806 dsi_display_clk_ctrl(display->dsi_clk_handle,
3807 DSI_ALL_CLKS, DSI_CLK_ON);
3808
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003809 rc = dsi_panel_pre_disable(display->panel);
3810 if (rc)
3811 pr_err("[%s] panel pre-disable failed, rc=%d\n",
3812 display->name, rc);
3813
3814 mutex_unlock(&display->display_lock);
3815 return rc;
3816}
3817
3818int dsi_display_disable(struct dsi_display *display)
3819{
3820 int rc = 0;
3821
3822 if (!display) {
3823 pr_err("Invalid params\n");
3824 return -EINVAL;
3825 }
3826
3827 mutex_lock(&display->display_lock);
3828
3829 rc = dsi_display_wake_up(display);
3830 if (rc)
3831 pr_err("[%s] display wake up failed, rc=%d\n",
3832 display->name, rc);
3833
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07003834 if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
3835 rc = dsi_display_vid_engine_disable(display);
3836 if (rc)
3837 pr_err("[%s]failed to disable DSI vid engine, rc=%d\n",
3838 display->name, rc);
3839 } else if (display->config.panel_mode == DSI_OP_CMD_MODE) {
3840 rc = dsi_display_cmd_engine_disable(display);
3841 if (rc)
3842 pr_err("[%s]failed to disable DSI cmd engine, rc=%d\n",
3843 display->name, rc);
3844 } else {
3845 pr_err("[%s] Invalid configuration\n", display->name);
3846 rc = -EINVAL;
3847 }
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003848
Clarence Ip9de0bbc2017-03-02 09:56:06 -05003849 rc = dsi_panel_disable(display->panel);
3850 if (rc)
3851 pr_err("[%s] failed to disable DSI panel, rc=%d\n",
3852 display->name, rc);
3853
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003854 mutex_unlock(&display->display_lock);
3855 return rc;
3856}
3857
Alexander Beykunac182352017-02-27 17:46:51 -05003858int dsi_display_update_pps(char *pps_cmd, void *disp)
3859{
3860 struct dsi_display *display;
3861
3862 if (pps_cmd == NULL || disp == NULL) {
3863 pr_err("Invalid parameter\n");
3864 return -EINVAL;
3865 }
3866
3867 display = disp;
3868 mutex_lock(&display->display_lock);
3869 memcpy(display->panel->dsc_pps_cmd, pps_cmd, DSI_CMD_PPS_SIZE);
3870 mutex_unlock(&display->display_lock);
3871
3872 return 0;
3873}
3874
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003875int dsi_display_unprepare(struct dsi_display *display)
3876{
3877 int rc = 0;
3878
3879 if (!display) {
3880 pr_err("Invalid params\n");
3881 return -EINVAL;
3882 }
3883
3884 mutex_lock(&display->display_lock);
3885
3886 rc = dsi_display_wake_up(display);
3887 if (rc)
3888 pr_err("[%s] display wake up failed, rc=%d\n",
3889 display->name, rc);
3890
3891 rc = dsi_panel_unprepare(display->panel);
3892 if (rc)
3893 pr_err("[%s] panel unprepare failed, rc=%d\n",
3894 display->name, rc);
3895
3896 rc = dsi_display_ctrl_host_disable(display);
3897 if (rc)
3898 pr_err("[%s] failed to disable DSI host, rc=%d\n",
3899 display->name, rc);
3900
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303901 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
3902 DSI_LINK_CLK, DSI_CLK_OFF);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003903 if (rc)
3904 pr_err("[%s] failed to disable Link clocks, rc=%d\n",
3905 display->name, rc);
3906
3907 rc = dsi_display_ctrl_deinit(display);
3908 if (rc)
3909 pr_err("[%s] failed to deinit controller, rc=%d\n",
3910 display->name, rc);
3911
3912 rc = dsi_display_phy_disable(display);
3913 if (rc)
3914 pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
3915 display->name, rc);
3916
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05303917 rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
3918 DSI_CORE_CLK, DSI_CLK_OFF);
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003919 if (rc)
3920 pr_err("[%s] failed to disable DSI clocks, rc=%d\n",
3921 display->name, rc);
3922
Ajay Singh Parmar571e3012016-05-16 17:55:52 -07003923 rc = dsi_panel_post_unprepare(display->panel);
3924 if (rc)
3925 pr_err("[%s] panel post-unprepare failed, rc=%d\n",
3926 display->name, rc);
3927
3928 mutex_unlock(&display->display_lock);
3929 return rc;
3930}
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07003931
Clarence Ip3649f8b2016-10-31 09:59:44 -04003932static int __init dsi_display_register(void)
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07003933{
Clarence Ip3649f8b2016-10-31 09:59:44 -04003934 dsi_phy_drv_register();
3935 dsi_ctrl_drv_register();
3936 return platform_driver_register(&dsi_display_driver);
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07003937}
3938
Clarence Ip3649f8b2016-10-31 09:59:44 -04003939static void __exit dsi_display_unregister(void)
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07003940{
3941 platform_driver_unregister(&dsi_display_driver);
Clarence Ip3649f8b2016-10-31 09:59:44 -04003942 dsi_ctrl_drv_unregister();
3943 dsi_phy_drv_unregister();
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07003944}
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07003945module_param_string(dsi_display0, dsi_display_primary, MAX_CMDLINE_PARAM_LEN,
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003946 0600);
3947MODULE_PARM_DESC(dsi_display0,
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07003948 "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");
3949module_param_string(dsi_display1, dsi_display_secondary, MAX_CMDLINE_PARAM_LEN,
Shashank Babu Chinta Venkataded9c562017-03-15 14:43:46 -07003950 0600);
3951MODULE_PARM_DESC(dsi_display1,
Chandan Uddaraju7e9613a2017-06-01 13:10:55 -07003952 "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 -04003953module_init(dsi_display_register);
3954module_exit(dsi_display_unregister);