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