Merge tag 'gpio-v4.1-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / msm / dsi / dsi_manager.c
1 /*
2  * Copyright (c) 2015, The Linux Foundation. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 and
6  * only version 2 as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13
14 #include "msm_kms.h"
15 #include "dsi.h"
16
17 struct msm_dsi_manager {
18         struct msm_dsi *dsi[DSI_MAX];
19
20         bool is_dual_panel;
21         bool is_sync_needed;
22         int master_panel_id;
23 };
24
25 static struct msm_dsi_manager msm_dsim_glb;
26
27 #define IS_DUAL_PANEL()         (msm_dsim_glb.is_dual_panel)
28 #define IS_SYNC_NEEDED()        (msm_dsim_glb.is_sync_needed)
29 #define IS_MASTER_PANEL(id)     (msm_dsim_glb.master_panel_id == id)
30
31 static inline struct msm_dsi *dsi_mgr_get_dsi(int id)
32 {
33         return msm_dsim_glb.dsi[id];
34 }
35
36 static inline struct msm_dsi *dsi_mgr_get_other_dsi(int id)
37 {
38         return msm_dsim_glb.dsi[(id + 1) % DSI_MAX];
39 }
40
41 static int dsi_mgr_parse_dual_panel(struct device_node *np, int id)
42 {
43         struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
44
45         /* We assume 2 dsi nodes have the same information of dual-panel and
46          * sync-mode, and only one node specifies master in case of dual mode.
47          */
48         if (!msm_dsim->is_dual_panel)
49                 msm_dsim->is_dual_panel = of_property_read_bool(
50                                                 np, "qcom,dual-panel-mode");
51
52         if (msm_dsim->is_dual_panel) {
53                 if (of_property_read_bool(np, "qcom,master-panel"))
54                         msm_dsim->master_panel_id = id;
55                 if (!msm_dsim->is_sync_needed)
56                         msm_dsim->is_sync_needed = of_property_read_bool(
57                                         np, "qcom,sync-dual-panel");
58         }
59
60         return 0;
61 }
62
63 struct dsi_connector {
64         struct drm_connector base;
65         int id;
66 };
67
68 struct dsi_bridge {
69         struct drm_bridge base;
70         int id;
71 };
72
73 #define to_dsi_connector(x) container_of(x, struct dsi_connector, base)
74 #define to_dsi_bridge(x) container_of(x, struct dsi_bridge, base)
75
76 static inline int dsi_mgr_connector_get_id(struct drm_connector *connector)
77 {
78         struct dsi_connector *dsi_connector = to_dsi_connector(connector);
79         return dsi_connector->id;
80 }
81
82 static int dsi_mgr_bridge_get_id(struct drm_bridge *bridge)
83 {
84         struct dsi_bridge *dsi_bridge = to_dsi_bridge(bridge);
85         return dsi_bridge->id;
86 }
87
88 static enum drm_connector_status dsi_mgr_connector_detect(
89                 struct drm_connector *connector, bool force)
90 {
91         int id = dsi_mgr_connector_get_id(connector);
92         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
93         struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
94         struct msm_drm_private *priv = connector->dev->dev_private;
95         struct msm_kms *kms = priv->kms;
96
97         DBG("id=%d", id);
98         if (!msm_dsi->panel) {
99                 msm_dsi->panel = msm_dsi_host_get_panel(msm_dsi->host,
100                                                 &msm_dsi->panel_flags);
101
102                 /* There is only 1 panel in the global panel list
103                  * for dual panel mode. Therefore slave dsi should get
104                  * the drm_panel instance from master dsi, and
105                  * keep using the panel flags got from the current DSI link.
106                  */
107                 if (!msm_dsi->panel && IS_DUAL_PANEL() &&
108                         !IS_MASTER_PANEL(id) && other_dsi)
109                         msm_dsi->panel = msm_dsi_host_get_panel(
110                                         other_dsi->host, NULL);
111
112                 if (msm_dsi->panel && IS_DUAL_PANEL())
113                         drm_object_attach_property(&connector->base,
114                                 connector->dev->mode_config.tile_property, 0);
115
116                 /* Set split display info to kms once dual panel is connected
117                  * to both hosts
118                  */
119                 if (msm_dsi->panel && IS_DUAL_PANEL() &&
120                         other_dsi && other_dsi->panel) {
121                         bool cmd_mode = !(msm_dsi->panel_flags &
122                                                 MIPI_DSI_MODE_VIDEO);
123                         struct drm_encoder *encoder = msm_dsi_get_encoder(
124                                         dsi_mgr_get_dsi(DSI_ENCODER_MASTER));
125                         struct drm_encoder *slave_enc = msm_dsi_get_encoder(
126                                         dsi_mgr_get_dsi(DSI_ENCODER_SLAVE));
127
128                         if (kms->funcs->set_split_display)
129                                 kms->funcs->set_split_display(kms, encoder,
130                                                         slave_enc, cmd_mode);
131                         else
132                                 pr_err("mdp does not support dual panel\n");
133                 }
134         }
135
136         return msm_dsi->panel ? connector_status_connected :
137                 connector_status_disconnected;
138 }
139
140 static void dsi_mgr_connector_destroy(struct drm_connector *connector)
141 {
142         DBG("");
143         drm_connector_unregister(connector);
144         drm_connector_cleanup(connector);
145 }
146
147 static void dsi_dual_connector_fix_modes(struct drm_connector *connector)
148 {
149         struct drm_display_mode *mode, *m;
150
151         /* Only support left-right mode */
152         list_for_each_entry_safe(mode, m, &connector->probed_modes, head) {
153                 mode->clock >>= 1;
154                 mode->hdisplay >>= 1;
155                 mode->hsync_start >>= 1;
156                 mode->hsync_end >>= 1;
157                 mode->htotal >>= 1;
158                 drm_mode_set_name(mode);
159         }
160 }
161
162 static int dsi_dual_connector_tile_init(
163                         struct drm_connector *connector, int id)
164 {
165         struct drm_display_mode *mode;
166         /* Fake topology id */
167         char topo_id[8] = {'M', 'S', 'M', 'D', 'U', 'D', 'S', 'I'};
168
169         if (connector->tile_group) {
170                 DBG("Tile property has been initialized");
171                 return 0;
172         }
173
174         /* Use the first mode only for now */
175         mode = list_first_entry(&connector->probed_modes,
176                                 struct drm_display_mode,
177                                 head);
178         if (!mode)
179                 return -EINVAL;
180
181         connector->tile_group = drm_mode_get_tile_group(
182                                         connector->dev, topo_id);
183         if (!connector->tile_group)
184                 connector->tile_group = drm_mode_create_tile_group(
185                                         connector->dev, topo_id);
186         if (!connector->tile_group) {
187                 pr_err("%s: failed to create tile group\n", __func__);
188                 return -ENOMEM;
189         }
190
191         connector->has_tile = true;
192         connector->tile_is_single_monitor = true;
193
194         /* mode has been fixed */
195         connector->tile_h_size = mode->hdisplay;
196         connector->tile_v_size = mode->vdisplay;
197
198         /* Only support left-right mode */
199         connector->num_h_tile = 2;
200         connector->num_v_tile = 1;
201
202         connector->tile_v_loc = 0;
203         connector->tile_h_loc = (id == DSI_RIGHT) ? 1 : 0;
204
205         return 0;
206 }
207
208 static int dsi_mgr_connector_get_modes(struct drm_connector *connector)
209 {
210         int id = dsi_mgr_connector_get_id(connector);
211         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
212         struct drm_panel *panel = msm_dsi->panel;
213         int ret, num;
214
215         if (!panel)
216                 return 0;
217
218         /* Since we have 2 connectors, but only 1 drm_panel in dual DSI mode,
219          * panel should not attach to any connector.
220          * Only temporarily attach panel to the current connector here,
221          * to let panel set mode to this connector.
222          */
223         drm_panel_attach(panel, connector);
224         num = drm_panel_get_modes(panel);
225         drm_panel_detach(panel);
226         if (!num)
227                 return 0;
228
229         if (IS_DUAL_PANEL()) {
230                 /* report half resolution to user */
231                 dsi_dual_connector_fix_modes(connector);
232                 ret = dsi_dual_connector_tile_init(connector, id);
233                 if (ret)
234                         return ret;
235                 ret = drm_mode_connector_set_tile_property(connector);
236                 if (ret) {
237                         pr_err("%s: set tile property failed, %d\n",
238                                         __func__, ret);
239                         return ret;
240                 }
241         }
242
243         return num;
244 }
245
246 static int dsi_mgr_connector_mode_valid(struct drm_connector *connector,
247                                 struct drm_display_mode *mode)
248 {
249         int id = dsi_mgr_connector_get_id(connector);
250         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
251         struct drm_encoder *encoder = msm_dsi_get_encoder(msm_dsi);
252         struct msm_drm_private *priv = connector->dev->dev_private;
253         struct msm_kms *kms = priv->kms;
254         long actual, requested;
255
256         DBG("");
257         requested = 1000 * mode->clock;
258         actual = kms->funcs->round_pixclk(kms, requested, encoder);
259
260         DBG("requested=%ld, actual=%ld", requested, actual);
261         if (actual != requested)
262                 return MODE_CLOCK_RANGE;
263
264         return MODE_OK;
265 }
266
267 static struct drm_encoder *
268 dsi_mgr_connector_best_encoder(struct drm_connector *connector)
269 {
270         int id = dsi_mgr_connector_get_id(connector);
271         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
272
273         DBG("");
274         return msm_dsi_get_encoder(msm_dsi);
275 }
276
277 static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
278 {
279         int id = dsi_mgr_bridge_get_id(bridge);
280         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
281         struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
282         struct mipi_dsi_host *host = msm_dsi->host;
283         struct drm_panel *panel = msm_dsi->panel;
284         bool is_dual_panel = IS_DUAL_PANEL();
285         int ret;
286
287         DBG("id=%d", id);
288         if (!panel || (is_dual_panel && (DSI_1 == id)))
289                 return;
290
291         ret = msm_dsi_host_power_on(host);
292         if (ret) {
293                 pr_err("%s: power on host %d failed, %d\n", __func__, id, ret);
294                 goto host_on_fail;
295         }
296
297         if (is_dual_panel && msm_dsi1) {
298                 ret = msm_dsi_host_power_on(msm_dsi1->host);
299                 if (ret) {
300                         pr_err("%s: power on host1 failed, %d\n",
301                                                         __func__, ret);
302                         goto host1_on_fail;
303                 }
304         }
305
306         /* Always call panel functions once, because even for dual panels,
307          * there is only one drm_panel instance.
308          */
309         ret = drm_panel_prepare(panel);
310         if (ret) {
311                 pr_err("%s: prepare panel %d failed, %d\n", __func__, id, ret);
312                 goto panel_prep_fail;
313         }
314
315         ret = msm_dsi_host_enable(host);
316         if (ret) {
317                 pr_err("%s: enable host %d failed, %d\n", __func__, id, ret);
318                 goto host_en_fail;
319         }
320
321         if (is_dual_panel && msm_dsi1) {
322                 ret = msm_dsi_host_enable(msm_dsi1->host);
323                 if (ret) {
324                         pr_err("%s: enable host1 failed, %d\n", __func__, ret);
325                         goto host1_en_fail;
326                 }
327         }
328
329         ret = drm_panel_enable(panel);
330         if (ret) {
331                 pr_err("%s: enable panel %d failed, %d\n", __func__, id, ret);
332                 goto panel_en_fail;
333         }
334
335         return;
336
337 panel_en_fail:
338         if (is_dual_panel && msm_dsi1)
339                 msm_dsi_host_disable(msm_dsi1->host);
340 host1_en_fail:
341         msm_dsi_host_disable(host);
342 host_en_fail:
343         drm_panel_unprepare(panel);
344 panel_prep_fail:
345         if (is_dual_panel && msm_dsi1)
346                 msm_dsi_host_power_off(msm_dsi1->host);
347 host1_on_fail:
348         msm_dsi_host_power_off(host);
349 host_on_fail:
350         return;
351 }
352
353 static void dsi_mgr_bridge_enable(struct drm_bridge *bridge)
354 {
355         DBG("");
356 }
357
358 static void dsi_mgr_bridge_disable(struct drm_bridge *bridge)
359 {
360         DBG("");
361 }
362
363 static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
364 {
365         int id = dsi_mgr_bridge_get_id(bridge);
366         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
367         struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
368         struct mipi_dsi_host *host = msm_dsi->host;
369         struct drm_panel *panel = msm_dsi->panel;
370         bool is_dual_panel = IS_DUAL_PANEL();
371         int ret;
372
373         DBG("id=%d", id);
374
375         if (!panel || (is_dual_panel && (DSI_1 == id)))
376                 return;
377
378         ret = drm_panel_disable(panel);
379         if (ret)
380                 pr_err("%s: Panel %d OFF failed, %d\n", __func__, id, ret);
381
382         ret = msm_dsi_host_disable(host);
383         if (ret)
384                 pr_err("%s: host %d disable failed, %d\n", __func__, id, ret);
385
386         if (is_dual_panel && msm_dsi1) {
387                 ret = msm_dsi_host_disable(msm_dsi1->host);
388                 if (ret)
389                         pr_err("%s: host1 disable failed, %d\n", __func__, ret);
390         }
391
392         ret = drm_panel_unprepare(panel);
393         if (ret)
394                 pr_err("%s: Panel %d unprepare failed,%d\n", __func__, id, ret);
395
396         ret = msm_dsi_host_power_off(host);
397         if (ret)
398                 pr_err("%s: host %d power off failed,%d\n", __func__, id, ret);
399
400         if (is_dual_panel && msm_dsi1) {
401                 ret = msm_dsi_host_power_off(msm_dsi1->host);
402                 if (ret)
403                         pr_err("%s: host1 power off failed, %d\n",
404                                                                 __func__, ret);
405         }
406 }
407
408 static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
409                 struct drm_display_mode *mode,
410                 struct drm_display_mode *adjusted_mode)
411 {
412         int id = dsi_mgr_bridge_get_id(bridge);
413         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
414         struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
415         struct mipi_dsi_host *host = msm_dsi->host;
416         bool is_dual_panel = IS_DUAL_PANEL();
417
418         DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
419                         mode->base.id, mode->name,
420                         mode->vrefresh, mode->clock,
421                         mode->hdisplay, mode->hsync_start,
422                         mode->hsync_end, mode->htotal,
423                         mode->vdisplay, mode->vsync_start,
424                         mode->vsync_end, mode->vtotal,
425                         mode->type, mode->flags);
426
427         if (is_dual_panel && (DSI_1 == id))
428                 return;
429
430         msm_dsi_host_set_display_mode(host, adjusted_mode);
431         if (is_dual_panel && other_dsi)
432                 msm_dsi_host_set_display_mode(other_dsi->host, adjusted_mode);
433 }
434
435 static const struct drm_connector_funcs dsi_mgr_connector_funcs = {
436         .dpms = drm_atomic_helper_connector_dpms,
437         .detect = dsi_mgr_connector_detect,
438         .fill_modes = drm_helper_probe_single_connector_modes,
439         .destroy = dsi_mgr_connector_destroy,
440         .reset = drm_atomic_helper_connector_reset,
441         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
442         .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
443 };
444
445 static const struct drm_connector_helper_funcs dsi_mgr_conn_helper_funcs = {
446         .get_modes = dsi_mgr_connector_get_modes,
447         .mode_valid = dsi_mgr_connector_mode_valid,
448         .best_encoder = dsi_mgr_connector_best_encoder,
449 };
450
451 static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
452         .pre_enable = dsi_mgr_bridge_pre_enable,
453         .enable = dsi_mgr_bridge_enable,
454         .disable = dsi_mgr_bridge_disable,
455         .post_disable = dsi_mgr_bridge_post_disable,
456         .mode_set = dsi_mgr_bridge_mode_set,
457 };
458
459 /* initialize connector */
460 struct drm_connector *msm_dsi_manager_connector_init(u8 id)
461 {
462         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
463         struct drm_connector *connector = NULL;
464         struct dsi_connector *dsi_connector;
465         int ret, i;
466
467         dsi_connector = devm_kzalloc(msm_dsi->dev->dev,
468                                 sizeof(*dsi_connector), GFP_KERNEL);
469         if (!dsi_connector) {
470                 ret = -ENOMEM;
471                 goto fail;
472         }
473
474         dsi_connector->id = id;
475
476         connector = &dsi_connector->base;
477
478         ret = drm_connector_init(msm_dsi->dev, connector,
479                         &dsi_mgr_connector_funcs, DRM_MODE_CONNECTOR_DSI);
480         if (ret)
481                 goto fail;
482
483         drm_connector_helper_add(connector, &dsi_mgr_conn_helper_funcs);
484
485         /* Enable HPD to let hpd event is handled
486          * when panel is attached to the host.
487          */
488         connector->polled = DRM_CONNECTOR_POLL_HPD;
489
490         /* Display driver doesn't support interlace now. */
491         connector->interlace_allowed = 0;
492         connector->doublescan_allowed = 0;
493
494         ret = drm_connector_register(connector);
495         if (ret)
496                 goto fail;
497
498         for (i = 0; i < MSM_DSI_ENCODER_NUM; i++)
499                 drm_mode_connector_attach_encoder(connector,
500                                                 msm_dsi->encoders[i]);
501
502         return connector;
503
504 fail:
505         if (connector)
506                 dsi_mgr_connector_destroy(connector);
507
508         return ERR_PTR(ret);
509 }
510
511 /* initialize bridge */
512 struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
513 {
514         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
515         struct drm_bridge *bridge = NULL;
516         struct dsi_bridge *dsi_bridge;
517         int ret;
518
519         dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
520                                 sizeof(*dsi_bridge), GFP_KERNEL);
521         if (!dsi_bridge) {
522                 ret = -ENOMEM;
523                 goto fail;
524         }
525
526         dsi_bridge->id = id;
527
528         bridge = &dsi_bridge->base;
529         bridge->funcs = &dsi_mgr_bridge_funcs;
530
531         ret = drm_bridge_attach(msm_dsi->dev, bridge);
532         if (ret)
533                 goto fail;
534
535         return bridge;
536
537 fail:
538         if (bridge)
539                 msm_dsi_manager_bridge_destroy(bridge);
540
541         return ERR_PTR(ret);
542 }
543
544 void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
545 {
546 }
547
548 int msm_dsi_manager_phy_enable(int id,
549                 const unsigned long bit_rate, const unsigned long esc_rate,
550                 u32 *clk_pre, u32 *clk_post)
551 {
552         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
553         struct msm_dsi_phy *phy = msm_dsi->phy;
554         int ret;
555
556         ret = msm_dsi_phy_enable(phy, IS_DUAL_PANEL(), bit_rate, esc_rate);
557         if (ret)
558                 return ret;
559
560         msm_dsi->phy_enabled = true;
561         msm_dsi_phy_get_clk_pre_post(phy, clk_pre, clk_post);
562
563         return 0;
564 }
565
566 void msm_dsi_manager_phy_disable(int id)
567 {
568         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
569         struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
570         struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
571         struct msm_dsi_phy *phy = msm_dsi->phy;
572
573         /* disable DSI phy
574          * In dual-dsi configuration, the phy should be disabled for the
575          * first controller only when the second controller is disabled.
576          */
577         msm_dsi->phy_enabled = false;
578         if (IS_DUAL_PANEL() && mdsi && sdsi) {
579                 if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
580                         msm_dsi_phy_disable(sdsi->phy);
581                         msm_dsi_phy_disable(mdsi->phy);
582                 }
583         } else {
584                 msm_dsi_phy_disable(phy);
585         }
586 }
587
588 int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg)
589 {
590         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
591         struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
592         struct mipi_dsi_host *host = msm_dsi->host;
593         bool is_read = (msg->rx_buf && msg->rx_len);
594         bool need_sync = (IS_SYNC_NEEDED() && !is_read);
595         int ret;
596
597         if (!msg->tx_buf || !msg->tx_len)
598                 return 0;
599
600         /* In dual master case, panel requires the same commands sent to
601          * both DSI links. Host issues the command trigger to both links
602          * when DSI_1 calls the cmd transfer function, no matter it happens
603          * before or after DSI_0 cmd transfer.
604          */
605         if (need_sync && (id == DSI_0))
606                 return is_read ? msg->rx_len : msg->tx_len;
607
608         if (need_sync && msm_dsi0) {
609                 ret = msm_dsi_host_xfer_prepare(msm_dsi0->host, msg);
610                 if (ret) {
611                         pr_err("%s: failed to prepare non-trigger host, %d\n",
612                                 __func__, ret);
613                         return ret;
614                 }
615         }
616         ret = msm_dsi_host_xfer_prepare(host, msg);
617         if (ret) {
618                 pr_err("%s: failed to prepare host, %d\n", __func__, ret);
619                 goto restore_host0;
620         }
621
622         ret = is_read ? msm_dsi_host_cmd_rx(host, msg) :
623                         msm_dsi_host_cmd_tx(host, msg);
624
625         msm_dsi_host_xfer_restore(host, msg);
626
627 restore_host0:
628         if (need_sync && msm_dsi0)
629                 msm_dsi_host_xfer_restore(msm_dsi0->host, msg);
630
631         return ret;
632 }
633
634 bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len)
635 {
636         struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
637         struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0);
638         struct mipi_dsi_host *host = msm_dsi->host;
639
640         if (IS_SYNC_NEEDED() && (id == DSI_0))
641                 return false;
642
643         if (IS_SYNC_NEEDED() && msm_dsi0)
644                 msm_dsi_host_cmd_xfer_commit(msm_dsi0->host, iova, len);
645
646         msm_dsi_host_cmd_xfer_commit(host, iova, len);
647
648         return true;
649 }
650
651 int msm_dsi_manager_register(struct msm_dsi *msm_dsi)
652 {
653         struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
654         int id = msm_dsi->id;
655         struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id);
656         int ret;
657
658         if (id > DSI_MAX) {
659                 pr_err("%s: invalid id %d\n", __func__, id);
660                 return -EINVAL;
661         }
662
663         if (msm_dsim->dsi[id]) {
664                 pr_err("%s: dsi%d already registered\n", __func__, id);
665                 return -EBUSY;
666         }
667
668         msm_dsim->dsi[id] = msm_dsi;
669
670         ret = dsi_mgr_parse_dual_panel(msm_dsi->pdev->dev.of_node, id);
671         if (ret) {
672                 pr_err("%s: failed to parse dual panel info\n", __func__);
673                 return ret;
674         }
675
676         if (!IS_DUAL_PANEL()) {
677                 ret = msm_dsi_host_register(msm_dsi->host, true);
678         } else if (!other_dsi) {
679                 return 0;
680         } else {
681                 struct msm_dsi *mdsi = IS_MASTER_PANEL(id) ?
682                                         msm_dsi : other_dsi;
683                 struct msm_dsi *sdsi = IS_MASTER_PANEL(id) ?
684                                         other_dsi : msm_dsi;
685                 /* Register slave host first, so that slave DSI device
686                  * has a chance to probe, and do not block the master
687                  * DSI device's probe.
688                  * Also, do not check defer for the slave host,
689                  * because only master DSI device adds the panel to global
690                  * panel list. The panel's device is the master DSI device.
691                  */
692                 ret = msm_dsi_host_register(sdsi->host, false);
693                 if (ret)
694                         return ret;
695                 ret = msm_dsi_host_register(mdsi->host, true);
696         }
697
698         return ret;
699 }
700
701 void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi)
702 {
703         struct msm_dsi_manager *msm_dsim = &msm_dsim_glb;
704
705         if (msm_dsi->host)
706                 msm_dsi_host_unregister(msm_dsi->host);
707         msm_dsim->dsi[msm_dsi->id] = NULL;
708 }
709