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; 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 return connector; 499 500 fail: 501 if (connector) 502 dsi_mgr_connector_destroy(connector); 503 504 return ERR_PTR(ret); 505 } 506 507 /* initialize bridge */ 508 struct drm_bridge *msm_dsi_manager_bridge_init(u8 id) 509 { 510 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); 511 struct drm_bridge *bridge = NULL; 512 struct dsi_bridge *dsi_bridge; 513 int ret; 514 515 dsi_bridge = devm_kzalloc(msm_dsi->dev->dev, 516 sizeof(*dsi_bridge), GFP_KERNEL); 517 if (!dsi_bridge) { 518 ret = -ENOMEM; 519 goto fail; 520 } 521 522 dsi_bridge->id = id; 523 524 bridge = &dsi_bridge->base; 525 bridge->funcs = &dsi_mgr_bridge_funcs; 526 527 ret = drm_bridge_attach(msm_dsi->dev, bridge); 528 if (ret) 529 goto fail; 530 531 return bridge; 532 533 fail: 534 if (bridge) 535 msm_dsi_manager_bridge_destroy(bridge); 536 537 return ERR_PTR(ret); 538 } 539 540 void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge) 541 { 542 } 543 544 int msm_dsi_manager_phy_enable(int id, 545 const unsigned long bit_rate, const unsigned long esc_rate, 546 u32 *clk_pre, u32 *clk_post) 547 { 548 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); 549 struct msm_dsi_phy *phy = msm_dsi->phy; 550 int ret; 551 552 ret = msm_dsi_phy_enable(phy, IS_DUAL_PANEL(), bit_rate, esc_rate); 553 if (ret) 554 return ret; 555 556 msm_dsi->phy_enabled = true; 557 msm_dsi_phy_get_clk_pre_post(phy, clk_pre, clk_post); 558 559 return 0; 560 } 561 562 void msm_dsi_manager_phy_disable(int id) 563 { 564 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); 565 struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER); 566 struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE); 567 struct msm_dsi_phy *phy = msm_dsi->phy; 568 569 /* disable DSI phy 570 * In dual-dsi configuration, the phy should be disabled for the 571 * first controller only when the second controller is disabled. 572 */ 573 msm_dsi->phy_enabled = false; 574 if (IS_DUAL_PANEL() && mdsi && sdsi) { 575 if (!mdsi->phy_enabled && !sdsi->phy_enabled) { 576 msm_dsi_phy_disable(sdsi->phy); 577 msm_dsi_phy_disable(mdsi->phy); 578 } 579 } else { 580 msm_dsi_phy_disable(phy); 581 } 582 } 583 584 int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg) 585 { 586 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); 587 struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0); 588 struct mipi_dsi_host *host = msm_dsi->host; 589 bool is_read = (msg->rx_buf && msg->rx_len); 590 bool need_sync = (IS_SYNC_NEEDED() && !is_read); 591 int ret; 592 593 if (!msg->tx_buf || !msg->tx_len) 594 return 0; 595 596 /* In dual master case, panel requires the same commands sent to 597 * both DSI links. Host issues the command trigger to both links 598 * when DSI_1 calls the cmd transfer function, no matter it happens 599 * before or after DSI_0 cmd transfer. 600 */ 601 if (need_sync && (id == DSI_0)) 602 return is_read ? msg->rx_len : msg->tx_len; 603 604 if (need_sync && msm_dsi0) { 605 ret = msm_dsi_host_xfer_prepare(msm_dsi0->host, msg); 606 if (ret) { 607 pr_err("%s: failed to prepare non-trigger host, %d\n", 608 __func__, ret); 609 return ret; 610 } 611 } 612 ret = msm_dsi_host_xfer_prepare(host, msg); 613 if (ret) { 614 pr_err("%s: failed to prepare host, %d\n", __func__, ret); 615 goto restore_host0; 616 } 617 618 ret = is_read ? msm_dsi_host_cmd_rx(host, msg) : 619 msm_dsi_host_cmd_tx(host, msg); 620 621 msm_dsi_host_xfer_restore(host, msg); 622 623 restore_host0: 624 if (need_sync && msm_dsi0) 625 msm_dsi_host_xfer_restore(msm_dsi0->host, msg); 626 627 return ret; 628 } 629 630 bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 iova, u32 len) 631 { 632 struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id); 633 struct msm_dsi *msm_dsi0 = dsi_mgr_get_dsi(DSI_0); 634 struct mipi_dsi_host *host = msm_dsi->host; 635 636 if (IS_SYNC_NEEDED() && (id == DSI_0)) 637 return false; 638 639 if (IS_SYNC_NEEDED() && msm_dsi0) 640 msm_dsi_host_cmd_xfer_commit(msm_dsi0->host, iova, len); 641 642 msm_dsi_host_cmd_xfer_commit(host, iova, len); 643 644 return true; 645 } 646 647 int msm_dsi_manager_register(struct msm_dsi *msm_dsi) 648 { 649 struct msm_dsi_manager *msm_dsim = &msm_dsim_glb; 650 int id = msm_dsi->id; 651 struct msm_dsi *other_dsi = dsi_mgr_get_other_dsi(id); 652 int ret; 653 654 if (id > DSI_MAX) { 655 pr_err("%s: invalid id %d\n", __func__, id); 656 return -EINVAL; 657 } 658 659 if (msm_dsim->dsi[id]) { 660 pr_err("%s: dsi%d already registered\n", __func__, id); 661 return -EBUSY; 662 } 663 664 msm_dsim->dsi[id] = msm_dsi; 665 666 ret = dsi_mgr_parse_dual_panel(msm_dsi->pdev->dev.of_node, id); 667 if (ret) { 668 pr_err("%s: failed to parse dual panel info\n", __func__); 669 return ret; 670 } 671 672 if (!IS_DUAL_PANEL()) { 673 ret = msm_dsi_host_register(msm_dsi->host, true); 674 } else if (!other_dsi) { 675 return 0; 676 } else { 677 struct msm_dsi *mdsi = IS_MASTER_PANEL(id) ? 678 msm_dsi : other_dsi; 679 struct msm_dsi *sdsi = IS_MASTER_PANEL(id) ? 680 other_dsi : msm_dsi; 681 /* Register slave host first, so that slave DSI device 682 * has a chance to probe, and do not block the master 683 * DSI device's probe. 684 * Also, do not check defer for the slave host, 685 * because only master DSI device adds the panel to global 686 * panel list. The panel's device is the master DSI device. 687 */ 688 ret = msm_dsi_host_register(sdsi->host, false); 689 if (ret) 690 return ret; 691 ret = msm_dsi_host_register(mdsi->host, true); 692 } 693 694 return ret; 695 } 696 697 void msm_dsi_manager_unregister(struct msm_dsi *msm_dsi) 698 { 699 struct msm_dsi_manager *msm_dsim = &msm_dsim_glb; 700 701 if (msm_dsi->host) 702 msm_dsi_host_unregister(msm_dsi->host); 703 msm_dsim->dsi[msm_dsi->id] = NULL; 704 } 705 706