drm/msm/dsi-staging: add dsi display driver

Add dsi display driver. Configure all internal DSI modules.
Manage power sequence for internal modules like controller
and phy. Configure lanes, modes etc.

Change-Id: I8edc918c4858f16d32af9373fc4626066b20d2e5
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
index cdeb37b..52482a1 100644
--- a/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
+++ b/Documentation/devicetree/bindings/drm/msm/sde-dsi.txt
@@ -57,6 +57,9 @@
 Optional properties:
 - label:                  String to describe controller.
 - qcom,platform-te-gpio:  Specifies the gpio used for TE.
+- qcom,dsi-display-active: Current active display
+- qcom,dsi-ctrl: handle to dsi controller device
+- qcom,dsi-phy: handle to dsi phy device
 - qcom,<type>-supply-entries:		A node that lists the elements of the supply used by the
 					a particular "type" of DSI module. The module "types"
 					can be "core", "ctrl", and "phy". Within the same type,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
new file mode 100644
index 0000000..68e3b52
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -0,0 +1,1989 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define pr_fmt(fmt)	"msm-dsi-display:[%s] " fmt, __func__
+
+#include <linux/list.h>
+#include <linux/of.h>
+
+#include "msm_drv.h"
+#include "dsi_display.h"
+#include "dsi_panel.h"
+#include "dsi_ctrl.h"
+#include "dsi_ctrl_hw.h"
+#include "dsi_drm.h"
+
+#define to_dsi_display(x) container_of(x, struct dsi_display, host)
+
+static DEFINE_MUTEX(dsi_display_list_lock);
+static LIST_HEAD(dsi_display_list);
+
+static struct dsi_display *main_display;
+
+static int dsi_display_ctrl_power_on(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	/* Sequence does not matter for split dsi usecases */
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl)
+			continue;
+
+		rc = dsi_ctrl_set_power_state(ctrl->ctrl,
+					      DSI_CTRL_POWER_VREG_ON);
+		if (rc) {
+			pr_err("[%s] Failed to set power state, rc=%d\n",
+			       ctrl->ctrl->name, rc);
+			goto error;
+		}
+	}
+
+	return rc;
+error:
+	for (i = i - 1; i >= 0; i--) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl)
+			continue;
+		(void)dsi_ctrl_set_power_state(ctrl->ctrl, DSI_CTRL_POWER_OFF);
+	}
+	return rc;
+}
+
+static int dsi_display_ctrl_power_off(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	/* Sequence does not matter for split dsi usecases */
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl)
+			continue;
+
+		rc = dsi_ctrl_set_power_state(ctrl->ctrl, DSI_CTRL_POWER_OFF);
+		if (rc) {
+			pr_err("[%s] Failed to power off, rc=%d\n",
+			       ctrl->ctrl->name, rc);
+			goto error;
+		}
+	}
+error:
+	return rc;
+}
+
+static int dsi_display_phy_power_on(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	/* Sequence does not matter for split dsi usecases */
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl)
+			continue;
+
+		rc = dsi_phy_set_power_state(ctrl->phy, true);
+		if (rc) {
+			pr_err("[%s] Failed to set power state, rc=%d\n",
+			       ctrl->phy->name, rc);
+			goto error;
+		}
+	}
+
+	return rc;
+error:
+	for (i = i - 1; i >= 0; i--) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->phy)
+			continue;
+		(void)dsi_phy_set_power_state(ctrl->phy, false);
+	}
+	return rc;
+}
+
+static int dsi_display_phy_power_off(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	/* Sequence does not matter for split dsi usecases */
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->phy)
+			continue;
+
+		rc = dsi_phy_set_power_state(ctrl->phy, false);
+		if (rc) {
+			pr_err("[%s] Failed to power off, rc=%d\n",
+			       ctrl->ctrl->name, rc);
+			goto error;
+		}
+	}
+error:
+	return rc;
+}
+
+static int dsi_display_ctrl_core_clk_on(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	/*
+	 * In case of split DSI usecases, the clock for master controller should
+	 * be enabled before the other controller. Master controller in the
+	 * clock context refers to the controller that sources the clock.
+	 */
+
+	m_ctrl = &display->ctrl[display->clk_master_idx];
+
+	rc = dsi_ctrl_set_power_state(m_ctrl->ctrl, DSI_CTRL_POWER_CORE_CLK_ON);
+	if (rc) {
+		pr_err("[%s] failed to turn on clocks, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	/* Turn on rest of the controllers */
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_ctrl_set_power_state(ctrl->ctrl,
+					      DSI_CTRL_POWER_CORE_CLK_ON);
+		if (rc) {
+			pr_err("[%s] failed to turn on clock, rc=%d\n",
+			       display->name, rc);
+			goto error_disable_master;
+		}
+	}
+	return rc;
+error_disable_master:
+	(void)dsi_ctrl_set_power_state(m_ctrl->ctrl, DSI_CTRL_POWER_VREG_ON);
+error:
+	return rc;
+}
+
+static int dsi_display_ctrl_link_clk_on(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	/*
+	 * In case of split DSI usecases, the clock for master controller should
+	 * be enabled before the other controller. Master controller in the
+	 * clock context refers to the controller that sources the clock.
+	 */
+
+	m_ctrl = &display->ctrl[display->clk_master_idx];
+
+	rc = dsi_ctrl_set_clock_source(m_ctrl->ctrl,
+				       &display->clock_info.src_clks);
+	if (rc) {
+		pr_err("[%s] failed to set source clocks for master, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	rc = dsi_ctrl_set_power_state(m_ctrl->ctrl, DSI_CTRL_POWER_LINK_CLK_ON);
+	if (rc) {
+		pr_err("[%s] failed to turn on clocks, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	/* Turn on rest of the controllers */
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_ctrl_set_clock_source(ctrl->ctrl,
+					       &display->clock_info.src_clks);
+		if (rc) {
+			pr_err("[%s] failed to set source clocks, rc=%d\n",
+			       display->name, rc);
+			goto error_disable_master;
+		}
+
+		rc = dsi_ctrl_set_power_state(ctrl->ctrl,
+					      DSI_CTRL_POWER_LINK_CLK_ON);
+		if (rc) {
+			pr_err("[%s] failed to turn on clock, rc=%d\n",
+			       display->name, rc);
+			goto error_disable_master;
+		}
+	}
+	return rc;
+error_disable_master:
+	(void)dsi_ctrl_set_power_state(m_ctrl->ctrl,
+				       DSI_CTRL_POWER_CORE_CLK_ON);
+error:
+	return rc;
+}
+
+static int dsi_display_ctrl_core_clk_off(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	/*
+	 * In case of split DSI usecases, clock for slave DSI controllers should
+	 * be disabled first before disabling clock for master controller. Slave
+	 * controllers in the clock context refer to controller which source
+	 * clock from another controller.
+	 */
+
+	m_ctrl = &display->ctrl[display->clk_master_idx];
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_ctrl_set_power_state(ctrl->ctrl,
+					      DSI_CTRL_POWER_VREG_ON);
+		if (rc) {
+			pr_err("[%s] failed to turn off clock, rc=%d\n",
+			       display->name, rc);
+		}
+	}
+
+	rc = dsi_ctrl_set_power_state(m_ctrl->ctrl, DSI_CTRL_POWER_VREG_ON);
+	if (rc)
+		pr_err("[%s] failed to turn off clocks, rc=%d\n",
+		       display->name, rc);
+
+	return rc;
+}
+
+static int dsi_display_ctrl_link_clk_off(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	/*
+	 * In case of split DSI usecases, clock for slave DSI controllers should
+	 * be disabled first before disabling clock for master controller. Slave
+	 * controllers in the clock context refer to controller which source
+	 * clock from another controller.
+	 */
+
+	m_ctrl = &display->ctrl[display->clk_master_idx];
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_ctrl_set_power_state(ctrl->ctrl,
+					      DSI_CTRL_POWER_CORE_CLK_ON);
+		if (rc) {
+			pr_err("[%s] failed to turn off clock, rc=%d\n",
+			       display->name, rc);
+		}
+	}
+	rc = dsi_ctrl_set_power_state(m_ctrl->ctrl, DSI_CTRL_POWER_CORE_CLK_ON);
+	if (rc)
+		pr_err("[%s] failed to turn off clocks, rc=%d\n",
+		       display->name, rc);
+	return rc;
+}
+
+static int dsi_display_ctrl_init(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	for (i = 0 ; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		rc = dsi_ctrl_host_init(ctrl->ctrl);
+		if (rc) {
+			pr_err("[%s] failed to init host_%d, rc=%d\n",
+			       display->name, i, rc);
+			goto error_host_deinit;
+		}
+	}
+
+	return 0;
+error_host_deinit:
+	for (i = i - 1; i >= 0; i--) {
+		ctrl = &display->ctrl[i];
+		(void)dsi_ctrl_host_deinit(ctrl->ctrl);
+	}
+	return rc;
+}
+
+static int dsi_display_ctrl_deinit(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	for (i = 0 ; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		rc = dsi_ctrl_host_deinit(ctrl->ctrl);
+		if (rc) {
+			pr_err("[%s] failed to deinit host_%d, rc=%d\n",
+			       display->name, i, rc);
+		}
+	}
+
+	return rc;
+}
+
+static int dsi_display_cmd_engine_enable(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	m_ctrl = &display->ctrl[display->cmd_master_idx];
+
+	rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON);
+	if (rc) {
+		pr_err("[%s] failed to enable cmd engine, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl,
+						   DSI_CTRL_ENGINE_ON);
+		if (rc) {
+			pr_err("[%s] failed to enable cmd engine, rc=%d\n",
+			       display->name, rc);
+			goto error_disable_master;
+		}
+	}
+
+	return rc;
+error_disable_master:
+	(void)dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
+error:
+	return rc;
+}
+
+static int dsi_display_cmd_engine_disable(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	m_ctrl = &display->ctrl[display->cmd_master_idx];
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_ctrl_set_cmd_engine_state(ctrl->ctrl,
+						   DSI_CTRL_ENGINE_OFF);
+		if (rc)
+			pr_err("[%s] failed to enable cmd engine, rc=%d\n",
+			       display->name, rc);
+	}
+
+	rc = dsi_ctrl_set_cmd_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
+	if (rc) {
+		pr_err("[%s] failed to enable cmd engine, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+error:
+	return rc;
+}
+
+static int dsi_display_ctrl_host_enable(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	m_ctrl = &display->ctrl[display->cmd_master_idx];
+
+	rc = dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON);
+	if (rc) {
+		pr_err("[%s] failed to enable host engine, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_ctrl_set_host_engine_state(ctrl->ctrl,
+						    DSI_CTRL_ENGINE_ON);
+		if (rc) {
+			pr_err("[%s] failed to enable sl host engine, rc=%d\n",
+			       display->name, rc);
+			goto error_disable_master;
+		}
+	}
+
+	return rc;
+error_disable_master:
+	(void)dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
+error:
+	return rc;
+}
+
+static int dsi_display_ctrl_host_disable(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	m_ctrl = &display->ctrl[display->cmd_master_idx];
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_ctrl_set_host_engine_state(ctrl->ctrl,
+						    DSI_CTRL_ENGINE_OFF);
+		if (rc)
+			pr_err("[%s] failed to disable host engine, rc=%d\n",
+			       display->name, rc);
+	}
+
+	rc = dsi_ctrl_set_host_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
+	if (rc) {
+		pr_err("[%s] failed to disable host engine, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+error:
+	return rc;
+}
+
+static int dsi_display_vid_engine_enable(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	m_ctrl = &display->ctrl[display->video_master_idx];
+
+	rc = dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_ON);
+	if (rc) {
+		pr_err("[%s] failed to enable vid engine, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_ctrl_set_vid_engine_state(ctrl->ctrl,
+						   DSI_CTRL_ENGINE_ON);
+		if (rc) {
+			pr_err("[%s] failed to enable vid engine, rc=%d\n",
+			       display->name, rc);
+			goto error_disable_master;
+		}
+	}
+
+	return rc;
+error_disable_master:
+	(void)dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
+error:
+	return rc;
+}
+
+static int dsi_display_vid_engine_disable(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	m_ctrl = &display->ctrl[display->video_master_idx];
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_ctrl_set_vid_engine_state(ctrl->ctrl,
+						   DSI_CTRL_ENGINE_OFF);
+		if (rc)
+			pr_err("[%s] failed to disable vid engine, rc=%d\n",
+			       display->name, rc);
+	}
+
+	rc = dsi_ctrl_set_vid_engine_state(m_ctrl->ctrl, DSI_CTRL_ENGINE_OFF);
+	if (rc)
+		pr_err("[%s] failed to disable mvid engine, rc=%d\n",
+		       display->name, rc);
+
+	return rc;
+}
+
+static int dsi_display_phy_enable(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+	enum dsi_phy_pll_source m_src = DSI_PLL_SOURCE_STANDALONE;
+
+	m_ctrl = &display->ctrl[display->clk_master_idx];
+	if (display->ctrl_count > 1)
+		m_src = DSI_PLL_SOURCE_NATIVE;
+
+	rc = dsi_phy_enable(m_ctrl->phy,
+			    &display->config,
+			    m_src,
+			    true);
+	if (rc) {
+		pr_err("[%s] failed to enable DSI PHY, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_phy_enable(ctrl->phy,
+				    &display->config,
+				    DSI_PLL_SOURCE_NON_NATIVE,
+				    true);
+		if (rc) {
+			pr_err("[%s] failed to enable DSI PHY, rc=%d\n",
+			       display->name, rc);
+			goto error_disable_master;
+		}
+	}
+
+	return rc;
+
+error_disable_master:
+	(void)dsi_phy_disable(m_ctrl->phy);
+error:
+	return rc;
+}
+
+static int dsi_display_phy_disable(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	m_ctrl = &display->ctrl[display->clk_master_idx];
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_phy_disable(ctrl->phy);
+		if (rc)
+			pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
+			       display->name, rc);
+	}
+
+	rc = dsi_phy_disable(m_ctrl->phy);
+	if (rc)
+		pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
+		       display->name, rc);
+
+	return rc;
+}
+
+static int dsi_display_wake_up(struct dsi_display *display)
+{
+	return 0;
+}
+
+static int dsi_display_broadcast_cmd(struct dsi_display *display,
+				     const struct mipi_dsi_msg *msg)
+{
+	int rc = 0;
+	u32 flags, m_flags;
+	struct dsi_display_ctrl *ctrl, *m_ctrl;
+	int i;
+
+	m_flags = (DSI_CTRL_CMD_BROADCAST | DSI_CTRL_CMD_BROADCAST_MASTER |
+		   DSI_CTRL_CMD_DEFER_TRIGGER | DSI_CTRL_CMD_FIFO_STORE);
+	flags = (DSI_CTRL_CMD_BROADCAST | DSI_CTRL_CMD_DEFER_TRIGGER |
+		 DSI_CTRL_CMD_FIFO_STORE);
+
+	/*
+	 * 1. Setup commands in FIFO
+	 * 2. Trigger commands
+	 */
+	m_ctrl = &display->ctrl[display->cmd_master_idx];
+	rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, msg, m_flags);
+	if (rc) {
+		pr_err("[%s] cmd transfer failed on master,rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (ctrl == m_ctrl)
+			continue;
+
+		rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, msg, flags);
+		if (rc) {
+			pr_err("[%s] cmd transfer failed, rc=%d\n",
+			       display->name, rc);
+			goto error;
+		}
+
+		rc = dsi_ctrl_cmd_tx_trigger(ctrl->ctrl,
+			DSI_CTRL_CMD_BROADCAST);
+		if (rc) {
+			pr_err("[%s] cmd trigger failed, rc=%d\n",
+			       display->name, rc);
+			goto error;
+		}
+	}
+
+	rc = dsi_ctrl_cmd_tx_trigger(m_ctrl->ctrl,
+				(DSI_CTRL_CMD_BROADCAST_MASTER |
+				 DSI_CTRL_CMD_BROADCAST));
+	if (rc) {
+		pr_err("[%s] cmd trigger failed for master, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+error:
+	return rc;
+}
+
+static int dsi_display_phy_sw_reset(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *m_ctrl, *ctrl;
+
+	m_ctrl = &display->ctrl[display->cmd_master_idx];
+
+	rc = dsi_ctrl_phy_sw_reset(m_ctrl->ctrl);
+	if (rc) {
+		pr_err("[%s] failed to reset phy, rc=%d\n", display->name, rc);
+		goto error;
+	}
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if (!ctrl->ctrl || (ctrl == m_ctrl))
+			continue;
+
+		rc = dsi_ctrl_phy_sw_reset(ctrl->ctrl);
+		if (rc) {
+			pr_err("[%s] failed to reset phy, rc=%d\n",
+			       display->name, rc);
+			goto error;
+		}
+	}
+
+error:
+	return rc;
+}
+
+static int dsi_host_attach(struct mipi_dsi_host *host,
+			   struct mipi_dsi_device *dsi)
+{
+	return 0;
+}
+
+static int dsi_host_detach(struct mipi_dsi_host *host,
+			   struct mipi_dsi_device *dsi)
+{
+	return 0;
+}
+
+static ssize_t dsi_host_transfer(struct mipi_dsi_host *host,
+				 const struct mipi_dsi_msg *msg)
+{
+	struct dsi_display *display = to_dsi_display(host);
+
+	int rc = 0;
+
+	if (!host || !msg) {
+		pr_err("Invalid params\n");
+		return 0;
+	}
+
+	rc = dsi_display_wake_up(display);
+	if (rc) {
+		pr_err("[%s] failed to wake up display, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	rc = dsi_display_cmd_engine_enable(display);
+	if (rc) {
+		pr_err("[%s] failed to enable cmd engine, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	if (display->ctrl_count > 1) {
+		rc = dsi_display_broadcast_cmd(display, msg);
+		if (rc) {
+			pr_err("[%s] cmd broadcast failed, rc=%d\n",
+			       display->name, rc);
+			goto error_disable_cmd_engine;
+		}
+	} else {
+		rc = dsi_ctrl_cmd_transfer(display->ctrl[0].ctrl, msg,
+					  DSI_CTRL_CMD_FIFO_STORE);
+		if (rc) {
+			pr_err("[%s] cmd transfer failed, rc=%d\n",
+			       display->name, rc);
+			goto error_disable_cmd_engine;
+		}
+	}
+error_disable_cmd_engine:
+	(void)dsi_display_cmd_engine_disable(display);
+error:
+	return rc;
+}
+
+
+static struct mipi_dsi_host_ops dsi_host_ops = {
+	.attach = dsi_host_attach,
+	.detach = dsi_host_detach,
+	.transfer = dsi_host_transfer,
+};
+
+static int dsi_display_mipi_host_init(struct dsi_display *display)
+{
+	int rc = 0;
+	struct mipi_dsi_host *host = &display->host;
+
+	host->dev = &display->pdev->dev;
+	host->ops = &dsi_host_ops;
+
+	rc = mipi_dsi_host_register(host);
+	if (rc) {
+		pr_err("[%s] failed to register mipi dsi host, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+error:
+	return rc;
+}
+static int dsi_display_mipi_host_deinit(struct dsi_display *display)
+{
+	int rc = 0;
+	struct mipi_dsi_host *host = &display->host;
+
+	mipi_dsi_host_unregister(host);
+
+	host->dev = NULL;
+	host->ops = NULL;
+
+	return rc;
+}
+
+static int dsi_display_clocks_deinit(struct dsi_display *display)
+{
+	int rc = 0;
+	struct dsi_clk_link_set *src = &display->clock_info.src_clks;
+	struct dsi_clk_link_set *mux = &display->clock_info.mux_clks;
+	struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks;
+
+	if (src->byte_clk) {
+		devm_clk_put(&display->pdev->dev, src->byte_clk);
+		src->byte_clk = NULL;
+	}
+
+	if (src->pixel_clk) {
+		devm_clk_put(&display->pdev->dev, src->pixel_clk);
+		src->pixel_clk = NULL;
+	}
+
+	if (mux->byte_clk) {
+		devm_clk_put(&display->pdev->dev, mux->byte_clk);
+		mux->byte_clk = NULL;
+	}
+
+	if (mux->pixel_clk) {
+		devm_clk_put(&display->pdev->dev, mux->pixel_clk);
+		mux->pixel_clk = NULL;
+	}
+
+	if (shadow->byte_clk) {
+		devm_clk_put(&display->pdev->dev, shadow->byte_clk);
+		shadow->byte_clk = NULL;
+	}
+
+	if (shadow->pixel_clk) {
+		devm_clk_put(&display->pdev->dev, shadow->pixel_clk);
+		shadow->pixel_clk = NULL;
+	}
+
+	return rc;
+}
+
+static int dsi_display_clocks_init(struct dsi_display *display)
+{
+	int rc = 0;
+	struct dsi_clk_link_set *src = &display->clock_info.src_clks;
+	struct dsi_clk_link_set *mux = &display->clock_info.mux_clks;
+	struct dsi_clk_link_set *shadow = &display->clock_info.shadow_clks;
+
+	src->byte_clk = devm_clk_get(&display->pdev->dev, "src_byte_clk");
+	if (IS_ERR_OR_NULL(src->byte_clk)) {
+		rc = PTR_ERR(src->byte_clk);
+		pr_err("failed to get src_byte_clk, rc=%d\n", rc);
+		goto error;
+	}
+
+	src->pixel_clk = devm_clk_get(&display->pdev->dev, "src_pixel_clk");
+	if (IS_ERR_OR_NULL(src->pixel_clk)) {
+		rc = PTR_ERR(src->pixel_clk);
+		pr_err("failed to get src_pixel_clk, rc=%d\n", rc);
+		goto error;
+	}
+
+	mux->byte_clk = devm_clk_get(&display->pdev->dev, "mux_byte_clk");
+	if (IS_ERR_OR_NULL(mux->byte_clk)) {
+		rc = PTR_ERR(mux->byte_clk);
+		pr_err("failed to get mux_byte_clk, rc=%d\n", rc);
+		/*
+		 * Skip getting rest of clocks since one failed. This is a
+		 * non-critical failure since these clocks are requied only for
+		 * dynamic refresh use cases.
+		 */
+		rc = 0;
+		goto done;
+	};
+
+	mux->pixel_clk = devm_clk_get(&display->pdev->dev, "mux_pixel_clk");
+	if (IS_ERR_OR_NULL(mux->pixel_clk)) {
+		rc = PTR_ERR(mux->pixel_clk);
+		pr_err("failed to get mux_pixel_clk, rc=%d\n", rc);
+		/*
+		 * Skip getting rest of clocks since one failed. This is a
+		 * non-critical failure since these clocks are requied only for
+		 * dynamic refresh use cases.
+		 */
+		rc = 0;
+		goto done;
+	};
+
+	shadow->byte_clk = devm_clk_get(&display->pdev->dev, "shadow_byte_clk");
+	if (IS_ERR_OR_NULL(shadow->byte_clk)) {
+		rc = PTR_ERR(shadow->byte_clk);
+		pr_err("failed to get shadow_byte_clk, rc=%d\n", rc);
+		/*
+		 * Skip getting rest of clocks since one failed. This is a
+		 * non-critical failure since these clocks are requied only for
+		 * dynamic refresh use cases.
+		 */
+		rc = 0;
+		goto done;
+	};
+
+	shadow->pixel_clk = devm_clk_get(&display->pdev->dev,
+					 "shadow_pixel_clk");
+	if (IS_ERR_OR_NULL(shadow->pixel_clk)) {
+		rc = PTR_ERR(shadow->pixel_clk);
+		pr_err("failed to get shadow_pixel_clk, rc=%d\n", rc);
+		/*
+		 * Skip getting rest of clocks since one failed. This is a
+		 * non-critical failure since these clocks are requied only for
+		 * dynamic refresh use cases.
+		 */
+		rc = 0;
+		goto done;
+	};
+
+done:
+	return 0;
+error:
+	(void)dsi_display_clocks_deinit(display);
+	return rc;
+}
+
+static int dsi_display_parse_lane_map(struct dsi_display *display)
+{
+	int rc = 0;
+
+	display->lane_map.physical_lane0 = DSI_LOGICAL_LANE_0;
+	display->lane_map.physical_lane1 = DSI_LOGICAL_LANE_1;
+	display->lane_map.physical_lane2 = DSI_LOGICAL_LANE_2;
+	display->lane_map.physical_lane3 = DSI_LOGICAL_LANE_3;
+	return rc;
+}
+
+static int dsi_display_parse_dt(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	u32 phy_count = 0;
+	struct device_node *of_node;
+
+	/* Parse controllers */
+	for (i = 0; i < MAX_DSI_CTRLS_PER_DISPLAY; i++) {
+		of_node = of_parse_phandle(display->pdev->dev.of_node,
+					   "qcom,dsi-ctrl", i);
+		if (!of_node) {
+			if (!i) {
+				pr_err("No controllers present\n");
+				return -ENODEV;
+			}
+			break;
+		}
+
+		display->ctrl[i].ctrl_of_node = of_node;
+		display->ctrl_count++;
+	}
+
+	/* Parse Phys */
+	for (i = 0; i < MAX_DSI_CTRLS_PER_DISPLAY; i++) {
+		of_node = of_parse_phandle(display->pdev->dev.of_node,
+					   "qcom,dsi-phy", i);
+		if (!of_node) {
+			if (!i) {
+				pr_err("No PHY devices present\n");
+				rc = -ENODEV;
+				goto error;
+			}
+			break;
+		}
+
+		display->ctrl[i].phy_of_node = of_node;
+		phy_count++;
+	}
+
+	if (phy_count != display->ctrl_count) {
+		pr_err("Number of controllers does not match PHYs\n");
+		rc = -ENODEV;
+		goto error;
+	}
+
+	of_node = of_parse_phandle(display->pdev->dev.of_node,
+				   "qcom,dsi-panel", 0);
+	if (!of_node) {
+		pr_err("No Panel device present\n");
+		rc = -ENODEV;
+		goto error;
+	} else {
+		display->panel_of = of_node;
+	}
+
+	rc = dsi_display_parse_lane_map(display);
+	if (rc) {
+		pr_err("Lane map not found, rc=%d\n", rc);
+		goto error;
+	}
+error:
+	return rc;
+}
+
+static int dsi_display_res_init(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		ctrl->ctrl = dsi_ctrl_get(ctrl->ctrl_of_node);
+		if (IS_ERR_OR_NULL(ctrl->ctrl)) {
+			rc = PTR_ERR(ctrl->ctrl);
+			pr_err("failed to get dsi controller, rc=%d\n", rc);
+			ctrl->ctrl = NULL;
+			goto error_ctrl_put;
+		}
+
+		ctrl->phy = dsi_phy_get(ctrl->phy_of_node);
+		if (IS_ERR_OR_NULL(ctrl->phy)) {
+			rc = PTR_ERR(ctrl->phy);
+			pr_err("failed to get phy controller, rc=%d\n", rc);
+			dsi_ctrl_put(ctrl->ctrl);
+			ctrl->phy = NULL;
+			goto error_ctrl_put;
+		}
+	}
+
+	display->panel = dsi_panel_get(&display->pdev->dev, display->panel_of);
+	if (IS_ERR_OR_NULL(display->panel)) {
+		rc = PTR_ERR(display->panel);
+		pr_err("failed to get panel, rc=%d\n", rc);
+		display->panel = NULL;
+		goto error_ctrl_put;
+	}
+
+	rc = dsi_display_clocks_init(display);
+	if (rc) {
+		pr_err("Failed to parse clock data, rc=%d\n", rc);
+		goto error_ctrl_put;
+	}
+
+	return 0;
+error_ctrl_put:
+	for (i = i - 1; i >= 0; i--) {
+		ctrl = &display->ctrl[i];
+		dsi_ctrl_put(ctrl->ctrl);
+		dsi_phy_put(ctrl->phy);
+	}
+	return rc;
+}
+
+static int dsi_display_res_deinit(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	rc = dsi_display_clocks_deinit(display);
+	if (rc)
+		pr_err("clocks deinit failed, rc=%d\n", rc);
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		dsi_phy_put(ctrl->phy);
+		dsi_ctrl_put(ctrl->ctrl);
+	}
+
+	return rc;
+}
+
+static int dsi_display_validate_mode_set(struct dsi_display *display,
+					 struct dsi_display_mode *mode,
+					 u32 flags)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	/*
+	 * To set a mode:
+	 * 1. Controllers should be turned off.
+	 * 2. Link clocks should be off.
+	 * 3. Phy should be disabled.
+	 */
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		if ((ctrl->power_state > DSI_CTRL_POWER_VREG_ON) ||
+		    (ctrl->phy_enabled)) {
+			rc = -EINVAL;
+			goto error;
+		}
+	}
+
+error:
+	return rc;
+}
+
+static int dsi_display_set_mode_sub(struct dsi_display *display,
+				    struct dsi_display_mode *mode,
+				    u32 flags)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	rc = dsi_panel_get_host_cfg_for_mode(display->panel,
+					     mode,
+					     &display->config);
+	if (rc) {
+		pr_err("[%s] failed to get host config for mode, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	memcpy(&display->config.lane_map, &display->lane_map,
+	       sizeof(display->lane_map));
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		rc = dsi_ctrl_update_host_config(ctrl->ctrl, &display->config);
+		if (rc) {
+			pr_err("[%s] failed to update ctrl config, rc=%d\n",
+			       display->name, rc);
+			goto error;
+		}
+
+	}
+error:
+	return rc;
+}
+
+int dsi_display_dev_probe(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct dsi_display *display;
+
+	if (!pdev || !pdev->dev.of_node) {
+		pr_err("pdev not found\n");
+		return -ENODEV;
+	}
+
+	display = devm_kzalloc(&pdev->dev, sizeof(*display), GFP_KERNEL);
+	if (!display)
+		return -ENOMEM;
+
+	display->name = of_get_property(pdev->dev.of_node, "label", NULL);
+
+	display->is_active = of_property_read_bool(pdev->dev.of_node,
+						"qcom,dsi-display-active");
+
+	display->display_type = of_get_property(pdev->dev.of_node,
+						"qcom,display-type", NULL);
+	if (!display->display_type)
+		display->display_type = "unknown";
+
+	mutex_init(&display->display_lock);
+
+	display->pdev = pdev;
+	platform_set_drvdata(pdev, display);
+	mutex_lock(&dsi_display_list_lock);
+	list_add(&display->list, &dsi_display_list);
+	mutex_unlock(&dsi_display_list_lock);
+	if (display->is_active)
+		main_display = display;
+	return rc;
+}
+
+int dsi_display_dev_remove(struct platform_device *pdev)
+{
+	int rc = 0;
+	struct dsi_display *display;
+	struct dsi_display *pos, *tmp;
+
+	if (!pdev) {
+		pr_err("Invalid device\n");
+		return -EINVAL;
+	}
+
+	display = platform_get_drvdata(pdev);
+
+	mutex_lock(&dsi_display_list_lock);
+	list_for_each_entry_safe(pos, tmp, &dsi_display_list, list) {
+		if (pos == display) {
+			list_del(&display->list);
+			break;
+		}
+	}
+	mutex_unlock(&dsi_display_list_lock);
+
+	platform_set_drvdata(pdev, NULL);
+	devm_kfree(&pdev->dev, display);
+	return rc;
+}
+
+u32 dsi_display_get_num_of_displays(void)
+{
+	u32 count = 0;
+	struct dsi_display *display;
+
+	mutex_lock(&dsi_display_list_lock);
+
+	list_for_each_entry(display, &dsi_display_list, list) {
+		count++;
+	}
+
+	mutex_unlock(&dsi_display_list_lock);
+	return count;
+}
+
+struct dsi_display *dsi_display_get_display_by_index(u32 index)
+{
+	struct dsi_display *display = NULL;
+	struct dsi_display *pos;
+	int i = 0;
+
+	mutex_lock(&dsi_display_list_lock);
+
+	list_for_each_entry(pos, &dsi_display_list, list) {
+		if (i == index) {
+			display = pos;
+			break;
+		}
+		i++;
+	}
+
+	mutex_unlock(&dsi_display_list_lock);
+	return display;
+}
+
+struct dsi_display *dsi_display_get_display_by_name(const char *name)
+{
+	struct dsi_display *display = NULL, *pos;
+
+	mutex_lock(&dsi_display_list_lock);
+
+	list_for_each_entry(pos, &dsi_display_list, list) {
+		if (!strcmp(name, pos->name))
+			display = pos;
+	}
+
+	mutex_unlock(&dsi_display_list_lock);
+
+	return display;
+}
+
+void dsi_display_set_active_state(struct dsi_display *display, bool is_active)
+{
+	mutex_lock(&display->display_lock);
+	display->is_active = is_active;
+	mutex_unlock(&display->display_lock);
+}
+
+bool dsi_display_is_active(struct dsi_display *display)
+{
+	bool is_active;
+
+	mutex_lock(&display->display_lock);
+	is_active = display->is_active;
+	mutex_unlock(&display->display_lock);
+
+	return is_active;
+}
+
+int dsi_display_dev_init(struct dsi_display *display)
+{
+	int rc = 0;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	rc = dsi_display_parse_dt(display);
+	if (rc) {
+		pr_err("[%s] failed to parse dt, rc=%d\n", display->name, rc);
+		goto error;
+	}
+
+	rc = dsi_display_res_init(display);
+	if (rc) {
+		pr_err("[%s] failed to initialize resources, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_dev_deinit(struct dsi_display *display)
+{
+	int rc = 0;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	rc = dsi_display_res_deinit(display);
+	if (rc)
+		pr_err("[%s] failed to deinitialize resource, rc=%d\n",
+		       display->name, rc);
+
+	mutex_unlock(&display->display_lock);
+
+	return rc;
+}
+
+int dsi_display_bind(struct dsi_display *display, struct drm_device *dev)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *display_ctrl;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		display_ctrl = &display->ctrl[i];
+
+		rc = dsi_ctrl_drv_init(display_ctrl->ctrl);
+		if (rc) {
+			pr_err("[%s] Failed to initialize ctrl[%d], rc=%d\n",
+			       display->name, i, rc);
+			goto error_ctrl_deinit;
+		}
+
+		rc = dsi_phy_drv_init(display_ctrl->phy);
+		if (rc) {
+			pr_err("[%s] Failed to initialize phy[%d], rc=%d\n",
+				display->name, i, rc);
+			(void)dsi_ctrl_drv_deinit(display_ctrl->ctrl);
+			goto error_ctrl_deinit;
+		}
+	}
+
+	rc = dsi_display_mipi_host_init(display);
+	if (rc) {
+		pr_err("[%s] Failed to initialize mipi host, rc=%d\n",
+		       display->name, rc);
+		goto error_ctrl_deinit;
+	}
+
+	rc = dsi_panel_drv_init(display->panel, &display->host);
+	if (rc) {
+		pr_err("[%s] Failed to initialize panel driver, rc=%d\n",
+		       display->name, rc);
+		goto error_host_deinit;
+	}
+
+	rc = dsi_panel_get_mode_count(display->panel, &display->num_of_modes);
+	if (rc) {
+		pr_err("[%s] Failed to get mode count, rc=%d\n",
+		       display->name, rc);
+		goto error_panel_deinit;
+	}
+
+	display->drm_dev = dev;
+	goto error;
+
+error_panel_deinit:
+	(void)dsi_panel_drv_deinit(display->panel);
+error_host_deinit:
+	(void)dsi_display_mipi_host_deinit(display);
+error_ctrl_deinit:
+	for (i = i - 1; i >= 0; i--) {
+		display_ctrl = &display->ctrl[i];
+		(void)dsi_phy_drv_deinit(display_ctrl->phy);
+		(void)dsi_ctrl_drv_deinit(display_ctrl->ctrl);
+	}
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_unbind(struct dsi_display *display)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *display_ctrl;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	rc = dsi_panel_drv_deinit(display->panel);
+	if (rc)
+		pr_err("[%s] failed to deinit panel driver, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_display_mipi_host_deinit(display);
+	if (rc)
+		pr_err("[%s] failed to deinit mipi hosts, rc=%d\n",
+		       display->name,
+		       rc);
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		display_ctrl = &display->ctrl[i];
+
+		rc = dsi_phy_drv_deinit(display_ctrl->phy);
+		if (rc)
+			pr_err("[%s] failed to deinit phy%d driver, rc=%d\n",
+			       display->name, i, rc);
+
+		rc = dsi_ctrl_drv_deinit(display_ctrl->ctrl);
+		if (rc)
+			pr_err("[%s] failed to deinit ctrl%d driver, rc=%d\n",
+			       display->name, i, rc);
+	}
+
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_drm_init(struct dsi_display *display, struct drm_encoder *enc)
+{
+	int rc = 0;
+	struct dsi_bridge *bridge;
+	struct dsi_connector *connector;
+	struct msm_drm_private *priv = NULL;
+
+	if (!display || !enc) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+	priv = display->drm_dev->dev_private;
+
+	if (!priv) {
+		pr_err("Private data is not present\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (display->connector || display->bridge) {
+		pr_err("display is already initialize\n");
+		goto error;
+	}
+
+	bridge = dsi_drm_bridge_init(display, display->drm_dev, enc);
+	if (IS_ERR_OR_NULL(bridge)) {
+		rc = PTR_ERR(bridge);
+		pr_err("[%s] brige init failed, rc=%d\n", display->name, rc);
+		goto error;
+	}
+
+	connector = dsi_drm_connector_init(display, display->drm_dev, bridge);
+	if (IS_ERR_OR_NULL(connector)) {
+		rc = PTR_ERR(connector);
+		pr_err("[%s] connector init failed, rc=%d\n", display->name,
+		       rc);
+		goto error_bridge_deinit;
+	}
+
+	display->connector = connector;
+	priv->connectors[priv->num_connectors++] = &connector->base;
+	display->bridge = bridge;
+	priv->bridges[priv->num_bridges++] = &bridge->base;
+
+	goto error;
+error_bridge_deinit:
+	dsi_drm_bridge_cleanup(bridge);
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_drm_deinit(struct dsi_display *display)
+{
+	int rc = 0;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	dsi_drm_connector_cleanup(display->connector);
+	dsi_drm_bridge_cleanup(display->bridge);
+	display->connector = NULL;
+	display->bridge = NULL;
+
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_get_info(struct dsi_display *display,
+			 struct dsi_display_info *info)
+{
+	int rc = 0;
+	int i;
+	struct dsi_panel_phy_props phy_props;
+
+	if (!display || !info) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+	rc = dsi_panel_get_phy_props(display->panel, &phy_props);
+	if (rc) {
+		pr_err("[%s] failed to get panel phy props, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	info->type = display->type;
+
+	/* TODO: do not access dsi_ctrl structure */
+	info->num_of_h_tiles = display->ctrl_count;
+	for (i = 0; i < info->num_of_h_tiles; i++)
+		info->h_tile_ids[i] = display->ctrl[i].ctrl->index;
+
+	info->is_hot_pluggable = false;
+	info->is_edid_supported = false;
+
+	info->width_mm = phy_props.panel_width_mm;
+	info->height_mm = phy_props.panel_height_mm;
+	strlcpy(info->display_type, display->display_type,
+		sizeof(display->display_type));
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_get_modes(struct dsi_display *display,
+			  struct dsi_display_mode *modes,
+			  u32 *count)
+{
+	int rc = 0;
+	int i;
+
+	if (!display || !count) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	if (!modes) {
+		*count = display->num_of_modes;
+		goto error;
+	}
+
+	for (i = 0; i < *count; i++) {
+		rc = dsi_panel_get_mode(display->panel, i, modes);
+		if (rc) {
+			pr_err("[%s] failed to get mode from panel\n",
+			       display->name);
+			goto error;
+		}
+		if (display->ctrl_count > 1) {
+			modes->timing.h_active *= display->ctrl_count;
+			modes->timing.h_front_porch *= display->ctrl_count;
+			modes->timing.h_sync_width *= display->ctrl_count;
+			modes->timing.h_back_porch *= display->ctrl_count;
+			modes->timing.h_skew *= display->ctrl_count;
+			modes->pixel_clk_khz *= display->ctrl_count;
+		}
+
+		modes++;
+	}
+
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_validate_mode(struct dsi_display *display,
+			      struct dsi_display_mode *mode)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+	struct dsi_display_mode adj_mode;
+
+	if (!display || !mode) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	adj_mode = *mode;
+	if (display->ctrl_count > 1) {
+		adj_mode.timing.h_active /= display->ctrl_count;
+		adj_mode.timing.h_front_porch /= display->ctrl_count;
+		adj_mode.timing.h_sync_width /= display->ctrl_count;
+		adj_mode.timing.h_back_porch /= display->ctrl_count;
+		adj_mode.timing.h_skew /= display->ctrl_count;
+		adj_mode.pixel_clk_khz /= display->ctrl_count;
+	}
+
+	rc = dsi_panel_validate_mode(display->panel, &adj_mode);
+	if (rc) {
+		pr_err("[%s] panel mode validation failed, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		rc = dsi_ctrl_validate_timing(ctrl->ctrl, &adj_mode.timing);
+		if (rc) {
+			pr_err("[%s] ctrl mode validation failed, rc=%d\n",
+			       display->name, rc);
+			goto error;
+		}
+
+		rc = dsi_phy_validate_mode(ctrl->phy, &adj_mode.timing);
+		if (rc) {
+			pr_err("[%s] phy mode validation failed, rc=%d\n",
+			       display->name, rc);
+			goto error;
+		}
+	}
+
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_set_mode(struct dsi_display *display,
+			 struct dsi_display_mode *mode,
+			 u32 flags)
+{
+	int rc = 0;
+	struct dsi_display_mode adj_mode;
+
+	if (!display || !mode) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	adj_mode = *mode;
+	if (display->ctrl_count > 1) {
+		adj_mode.timing.h_active /= display->ctrl_count;
+		adj_mode.timing.h_front_porch /= display->ctrl_count;
+		adj_mode.timing.h_sync_width /= display->ctrl_count;
+		adj_mode.timing.h_back_porch /= display->ctrl_count;
+		adj_mode.timing.h_skew /= display->ctrl_count;
+		adj_mode.pixel_clk_khz /= display->ctrl_count;
+	}
+
+	rc = dsi_display_validate_mode_set(display, &adj_mode, flags);
+	if (rc) {
+		pr_err("[%s] mode cannot be set\n", display->name);
+		goto error;
+	}
+
+	rc = dsi_display_set_mode_sub(display, &adj_mode, flags);
+	if (rc) {
+		pr_err("[%s] failed to set mode\n", display->name);
+		goto error;
+	}
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_set_tpg_state(struct dsi_display *display, bool enable)
+{
+	int rc = 0;
+	int i;
+	struct dsi_display_ctrl *ctrl;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < display->ctrl_count; i++) {
+		ctrl = &display->ctrl[i];
+		rc = dsi_ctrl_set_tpg_state(ctrl->ctrl, enable);
+		if (rc) {
+			pr_err("[%s] failed to set tpg state for host_%d\n",
+			       display->name, i);
+			goto error;
+		}
+	}
+
+	display->is_tpg_enabled = enable;
+error:
+	return rc;
+}
+
+int dsi_display_prepare(struct dsi_display *display)
+{
+	int rc = 0;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	rc = dsi_panel_pre_prepare(display->panel);
+	if (rc) {
+		pr_err("[%s] panel pre-prepare failed, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	rc = dsi_display_ctrl_power_on(display);
+	if (rc) {
+		pr_err("[%s] failed to power on dsi controllers, rc=%d\n",
+		       display->name, rc);
+		goto error_panel_post_unprep;
+	}
+
+	rc = dsi_display_phy_power_on(display);
+	if (rc) {
+		pr_err("[%s] failed to power on dsi phy, rc = %d\n",
+		       display->name, rc);
+		goto error_ctrl_pwr_off;
+	}
+
+	rc = dsi_display_ctrl_core_clk_on(display);
+	if (rc) {
+		pr_err("[%s] failed to enable DSI core clocks, rc=%d\n",
+		       display->name, rc);
+		goto error_phy_pwr_off;
+	}
+
+	rc = dsi_display_phy_sw_reset(display);
+	if (rc) {
+		pr_err("[%s] failed to reset phy, rc=%d\n", display->name, rc);
+		goto error_ctrl_clk_off;
+	}
+
+	rc = dsi_display_phy_enable(display);
+	if (rc) {
+		pr_err("[%s] failed to enable DSI PHY, rc=%d\n",
+		       display->name, rc);
+		goto error_ctrl_clk_off;
+	}
+
+	rc = dsi_display_ctrl_init(display);
+	if (rc) {
+		pr_err("[%s] failed to setup DSI controller, rc=%d\n",
+		       display->name, rc);
+		goto error_phy_disable;
+	}
+
+	rc = dsi_display_ctrl_link_clk_on(display);
+	if (rc) {
+		pr_err("[%s] failed to enable DSI link clocks, rc=%d\n",
+		       display->name, rc);
+		goto error_ctrl_deinit;
+	}
+
+	rc = dsi_display_ctrl_host_enable(display);
+	if (rc) {
+		pr_err("[%s] failed to enable DSI host, rc=%d\n",
+		       display->name, rc);
+		goto error_ctrl_link_off;
+	}
+
+	rc = dsi_panel_prepare(display->panel);
+	if (rc) {
+		pr_err("[%s] panel prepare failed, rc=%d\n", display->name, rc);
+		goto error_host_engine_off;
+	}
+
+	goto error;
+
+error_host_engine_off:
+	(void)dsi_display_ctrl_host_disable(display);
+error_ctrl_link_off:
+	(void)dsi_display_ctrl_link_clk_off(display);
+error_ctrl_deinit:
+	(void)dsi_display_ctrl_deinit(display);
+error_phy_disable:
+	(void)dsi_display_phy_disable(display);
+error_ctrl_clk_off:
+	(void)dsi_display_ctrl_core_clk_off(display);
+error_phy_pwr_off:
+	(void)dsi_display_phy_power_off(display);
+error_ctrl_pwr_off:
+	(void)dsi_display_ctrl_power_off(display);
+error_panel_post_unprep:
+	(void)dsi_panel_post_unprepare(display->panel);
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_enable(struct dsi_display *display)
+{
+	int rc = 0;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	rc = dsi_panel_enable(display->panel);
+	if (rc) {
+		pr_err("[%s] failed to enable DSI panel, rc=%d\n",
+		       display->name, rc);
+		goto error_disable_vid_engine;
+	}
+
+	rc = dsi_display_vid_engine_enable(display);
+	if (rc) {
+		pr_err("[%s] failed to enable DSI video engine, rc=%d\n",
+		       display->name, rc);
+		goto error;
+	}
+
+	goto error;
+
+error_disable_vid_engine:
+	(void)dsi_display_vid_engine_disable(display);
+error:
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_post_enable(struct dsi_display *display)
+{
+	int rc = 0;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	rc = dsi_panel_post_enable(display->panel);
+	if (rc)
+		pr_err("[%s] panel post-enable failed, rc=%d\n",
+		       display->name, rc);
+
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_pre_disable(struct dsi_display *display)
+{
+	int rc = 0;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	rc = dsi_panel_pre_disable(display->panel);
+	if (rc)
+		pr_err("[%s] panel pre-disable failed, rc=%d\n",
+		       display->name, rc);
+
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_disable(struct dsi_display *display)
+{
+	int rc = 0;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	rc = dsi_display_wake_up(display);
+	if (rc)
+		pr_err("[%s] display wake up failed, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_panel_disable(display->panel);
+	if (rc)
+		pr_err("[%s] failed to disable DSI panel, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_display_vid_engine_disable(display);
+	if (rc)
+		pr_err("[%s] failed to disable video engine, rc=%d\n",
+		       display->name, rc);
+
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
+
+int dsi_display_unprepare(struct dsi_display *display)
+{
+	int rc = 0;
+
+	if (!display) {
+		pr_err("Invalid params\n");
+		return -EINVAL;
+	}
+
+	mutex_lock(&display->display_lock);
+
+	rc = dsi_display_wake_up(display);
+	if (rc)
+		pr_err("[%s] display wake up failed, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_panel_unprepare(display->panel);
+	if (rc)
+		pr_err("[%s] panel unprepare failed, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_display_ctrl_host_disable(display);
+	if (rc)
+		pr_err("[%s] failed to disable DSI host, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_display_ctrl_link_clk_off(display);
+	if (rc)
+		pr_err("[%s] failed to disable Link clocks, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_display_ctrl_deinit(display);
+	if (rc)
+		pr_err("[%s] failed to deinit controller, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_display_phy_disable(display);
+	if (rc)
+		pr_err("[%s] failed to disable DSI PHY, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_display_ctrl_core_clk_off(display);
+	if (rc)
+		pr_err("[%s] failed to disable DSI clocks, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_display_phy_power_off(display);
+	if (rc)
+		pr_err("[%s] failed to power off PHY, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_display_ctrl_power_off(display);
+	if (rc)
+		pr_err("[%s] failed to power DSI vregs, rc=%d\n",
+		       display->name, rc);
+
+	rc = dsi_panel_post_unprepare(display->panel);
+	if (rc)
+		pr_err("[%s] panel post-unprepare failed, rc=%d\n",
+		       display->name, rc);
+
+	mutex_unlock(&display->display_lock);
+	return rc;
+}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
new file mode 100644
index 0000000..df15bb8
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _DSI_DISPLAY_H_
+#define _DSI_DISPLAY_H_
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/of_device.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+
+#include "dsi_defs.h"
+#include "dsi_ctrl.h"
+#include "dsi_phy.h"
+#include "dsi_panel.h"
+
+#define MAX_DSI_CTRLS_PER_DISPLAY             2
+
+/**
+ * enum dsi_display_type - enumerates DSI display types
+ * @DSI_DISPLAY_SINGLE:       A panel connected on a single DSI interface.
+ * @DSI_DISPLAY_EXT_BRIDGE:   A bridge is connected between panel and DSI host.
+ *			      It utilizes a single DSI interface.
+ * @DSI_DISPLAY_SPLIT:        A panel that utilizes more than one DSI
+ *			      interfaces.
+ * @DSI_DISPLAY_SPLIT_EXT_BRIDGE: A bridge is present between panel and DSI
+ *				  host. It utilizes more than one DSI interface.
+ */
+enum dsi_display_type {
+	DSI_DISPLAY_SINGLE = 0,
+	DSI_DISPLAY_EXT_BRIDGE,
+	DSI_DISPLAY_SPLIT,
+	DSI_DISPLAY_SPLIT_EXT_BRIDGE,
+	DSI_DISPLAY_MAX,
+};
+
+/**
+ * struct dsi_display_info - defines dsi display properties
+ * @display_type:      Display type as defined by device tree.
+ * @type:              Type of panel connected to DSI interface.
+ * @num_of_h_tiles:    In case of split panels, number of h tiles indicates the
+ *		       number of dsi interfaces used. For single DSI panels this
+ *		       is set to 1. This will be set for horizontally split
+ *		       panels.
+ * @h_tile_ids:        The DSI instance ID for each tile.
+ * @is_hot_pluggable:  Can panel be hot plugged.
+ * @is_connected:      Is panel connected.
+ * @is_edid_supported: Does panel support reading EDID information.
+ * @width_mm:          Physical width of panel in millimeters.
+ * @height_mm:         Physical height of panel in millimeters.
+ */
+struct dsi_display_info {
+	char display_type[20];
+	enum dsi_display_type type;
+
+	/* Split DSI properties */
+	bool h_tiled;
+	u32 num_of_h_tiles;
+	u32 h_tile_ids[MAX_DSI_CTRLS_PER_DISPLAY];
+
+	/* HPD */
+	bool is_hot_pluggable;
+	bool is_connected;
+	bool is_edid_supported;
+
+	/* Physical properties */
+	u32 width_mm;
+	u32 height_mm;
+};
+
+/**
+ * struct dsi_display_ctrl - dsi ctrl/phy information for the display
+ * @ctrl:           Handle to the DSI controller device.
+ * @ctrl_of_node:   pHandle to the DSI controller device.
+ * @dsi_ctrl_idx:   DSI controller instance id.
+ * @power_state:    Current power state of the DSI controller.
+ * @cmd_engine_enabled:   Command engine status.
+ * @video_engine_enabled: Video engine status.
+ * @ulps_enabled:         ULPS status for the controller.
+ * @clamps_enabled:       Clamps status for the controller.
+ * @phy:                  Handle to the DSI PHY device.
+ * @phy_of_node:          pHandle to the DSI PHY device.
+ * @phy_enabled:          PHY power status.
+ */
+struct dsi_display_ctrl {
+	/* controller info */
+	struct dsi_ctrl *ctrl;
+	struct device_node *ctrl_of_node;
+	u32 dsi_ctrl_idx;
+
+	enum dsi_power_state power_state;
+	bool cmd_engine_enabled;
+	bool video_engine_enabled;
+	bool ulps_enabled;
+	bool clamps_enabled;
+
+	/* phy info */
+	struct msm_dsi_phy *phy;
+	struct device_node *phy_of_node;
+
+	bool phy_enabled;
+};
+
+/**
+ * struct dsi_display_clk_info - dsi display clock source information
+ * @src_clks:          Source clocks for DSI display.
+ * @mux_clks:          Mux clocks used for DFPS.
+ * @shadow_clks:       Used for DFPS.
+ */
+struct dsi_display_clk_info {
+	struct dsi_clk_link_set src_clks;
+	struct dsi_clk_link_set mux_clks;
+	struct dsi_clk_link_set shadow_clks;
+};
+
+/**
+ * struct dsi_display - dsi display information
+ * @pdev:             Pointer to platform device.
+ * @drm_dev:          DRM device associated with the display.
+ * @name:             Name of the display.
+ * @display_type:     Display type as defined in device tree.
+ * @list:             List pointer.
+ * @is_active:        Is display active.
+ * @display_lock:     Mutex for dsi_display interface.
+ * @ctrl_count:       Number of DSI interfaces required by panel.
+ * @ctrl:             Controller information for DSI display.
+ * @panel:            Handle to DSI panel.
+ * @panel_of:         pHandle to DSI panel.
+ * @type:             DSI display type.
+ * @clk_master_idx:   The master controller for controlling clocks. This is an
+ *		      index into the ctrl[MAX_DSI_CTRLS_PER_DISPLAY] array.
+ * @cmd_master_idx:   The master controller for sending DSI commands to panel.
+ * @video_master_idx: The master controller for enabling video engine.
+ * @clock_info:       Clock sourcing for DSI display.
+ * @lane_map:         Lane mapping between DSI host and Panel.
+ * @num_of_modes:     Number of modes supported by display.
+ * @is_tpg_enabled:   TPG state.
+ * @host:             DRM MIPI DSI Host.
+ * @connector:        Pointer to DRM connector object.
+ * @bridge:           Pointer to DRM bridge object.
+ */
+struct dsi_display {
+	struct platform_device *pdev;
+	struct drm_device *drm_dev;
+
+	const char *name;
+	const char *display_type;
+	struct list_head list;
+	bool is_active;
+	struct mutex display_lock;
+
+	u32 ctrl_count;
+	struct dsi_display_ctrl ctrl[MAX_DSI_CTRLS_PER_DISPLAY];
+
+	/* panel info */
+	struct dsi_panel *panel;
+	struct device_node *panel_of;
+
+	enum dsi_display_type type;
+	u32 clk_master_idx;
+	u32 cmd_master_idx;
+	u32 video_master_idx;
+
+	struct dsi_display_clk_info clock_info;
+	struct dsi_host_config config;
+	struct dsi_lane_mapping lane_map;
+	u32 num_of_modes;
+	bool is_tpg_enabled;
+
+	struct mipi_dsi_host host;
+	struct dsi_connector *connector;
+	struct dsi_bridge    *bridge;
+};
+
+int dsi_display_dev_probe(struct platform_device *pdev);
+int dsi_display_dev_remove(struct platform_device *pdev);
+
+/**
+ * dsi_display_get_num_of_displays() - returns number of display devices
+ *				       supported.
+ *
+ * Return: number of displays.
+ */
+u32 dsi_display_get_num_of_displays(void);
+
+/**
+ * dsi_display_get_display_by_index()- finds display by index
+ * @index:      index of the display.
+ *
+ * Return: handle to the display or error code.
+ */
+struct dsi_display *dsi_display_get_display_by_index(u32 index);
+
+/**
+ * dsi_display_get_display_by_name()- finds display by name
+ * @index:      name of the display.
+ *
+ * Return: handle to the display or error code.
+ */
+struct dsi_display *dsi_display_get_display_by_name(const char *name);
+
+/**
+ * dsi_display_set_active_state() - sets the state of the display
+ * @display:        Handle to display.
+ * @is_active:      state
+ */
+void dsi_display_set_active_state(struct dsi_display *display, bool is_active);
+
+/**
+ * dsi_display_is_active() - returns the state of the display
+ * @display:        Handle to the display.
+ *
+ * Return: state.
+ */
+bool dsi_display_is_active(struct dsi_display *display);
+
+/**
+ * dsi_display_dev_init() - Initializes the display device
+ * @display:         Handle to the display.
+ *
+ * Initialization will acquire references to the resources required for the
+ * display hardware to function.
+ *
+ * Return: error code.
+ */
+int dsi_display_dev_init(struct dsi_display *display);
+
+/**
+ * dsi_display_dev_deinit() - Desinitializes the display device
+ * @display:        Handle to the display.
+ *
+ * All the resources acquired during device init will be released.
+ *
+ * Return: error code.
+ */
+int dsi_display_dev_deinit(struct dsi_display *display);
+
+/**
+ * dsi_display_bind() - Binds the display device to the DRM device
+ * @display:       Handle to the display.
+ * @dev:           Pointer to the DRM device.
+ *
+ * Return: error code.
+ */
+int dsi_display_bind(struct dsi_display *display, struct drm_device *dev);
+
+/**
+ * dsi_display_unbind() - Unbinds the display device from the DRM device
+ * @display:         Handle to the display.
+ *
+ * Return: error code.
+ */
+int dsi_display_unbind(struct dsi_display *display);
+
+/**
+ * dsi_display_drm_init() - initializes DRM objects for the display device.
+ * @display:            Handle to the display.
+ * @encoder:            Pointer to the encoder object which is connected to the
+ *			display.
+ *
+ * Return: error code.
+ */
+int dsi_display_drm_init(struct dsi_display *display, struct drm_encoder *enc);
+
+/**
+ * dsi_display_drm_deinit() - destroys DRM objects assosciated with the display
+ * @display:        Handle to the display.
+ *
+ * Return: error code.
+ */
+int dsi_display_drm_deinit(struct dsi_display *display);
+
+/**
+ * dsi_display_get_info() - returns the display properties
+ * @display:          Handle to the display.
+ * @info:             Pointer to the structure where info is stored.
+ *
+ * Return: error code.
+ */
+int dsi_display_get_info(struct dsi_display *display,
+			 struct dsi_display_info *info);
+
+/**
+ * dsi_display_get_modes() - get modes supported by display
+ * @display:            Handle to display.
+ * @modes;              Pointer to array of modes. Memory allocated should be
+ *			big enough to store (count * struct dsi_display_mode)
+ *			elements. If modes pointer is NULL, number of modes will
+ *			be stored in the memory pointed to by count.
+ * @count:              If modes is NULL, number of modes will be stored. If
+ *			not, mode information will be copied (number of modes
+ *			copied will be equal to *count).
+ *
+ * Return: error code.
+ */
+int dsi_display_get_modes(struct dsi_display *display,
+			  struct dsi_display_mode *modes,
+			  u32 *count);
+
+/**
+ * dsi_display_validate_mode() - validates if mode is supported by display
+ * @display:             Handle to display.
+ * @mode:                Mode to be validated.
+ *
+ * Return: 0 if supported or error code.
+ */
+int dsi_display_validate_mode(struct dsi_display *display,
+			      struct dsi_display_mode *mode);
+
+/**
+ * dsi_display_set_mode() - Set mode on the display.
+ * @display:           Handle to display.
+ * @mode:              mode to be set.
+ * @flags:             Modifier flags.
+ *
+ * Return: error code.
+ */
+int dsi_display_set_mode(struct dsi_display *display,
+			 struct dsi_display_mode *mode,
+			 u32 flags);
+
+/**
+ * dsi_display_prepare() - prepare display
+ * @display:          Handle to display.
+ *
+ * Prepare will perform power up sequences for the host and panel hardware.
+ * Power and clock resources might be turned on (depending on the panel mode).
+ * The video engine is not enabled.
+ *
+ * Return: error code.
+ */
+int dsi_display_prepare(struct dsi_display *display);
+
+/**
+ * dsi_display_enable() - enable display
+ * @display:            Handle to display.
+ *
+ * Enable will turn on the host engine and the panel. At the end of the enable
+ * function, Host and panel hardware are ready to accept pixel data from
+ * upstream.
+ *
+ * Return: error code.
+ */
+int dsi_display_enable(struct dsi_display *display);
+
+/**
+ * dsi_display_post_enable() - perform post enable operations.
+ * @display:         Handle to display.
+ *
+ * Some panels might require some commands to be sent after pixel data
+ * transmission has started. Such commands are sent as part of the post_enable
+ * function.
+ *
+ * Return: error code.
+ */
+int dsi_display_post_enable(struct dsi_display *display);
+
+/**
+ * dsi_display_pre_disable() - perform pre disable operations.
+ * @display:          Handle to display.
+ *
+ * If a panel requires commands to be sent before pixel data transmission is
+ * stopped, those can be sent as part of pre_disable.
+ *
+ * Return: error code.
+ */
+int dsi_display_pre_disable(struct dsi_display *display);
+
+/**
+ * dsi_display_disable() - disable panel and host hardware.
+ * @display:             Handle to display.
+ *
+ * Disable host and panel hardware and pixel data transmission can not continue.
+ *
+ * Return: error code.
+ */
+int dsi_display_disable(struct dsi_display *display);
+
+/**
+ * dsi_display_unprepare() - power off display hardware.
+ * @display:            Handle to display.
+ *
+ * Host and panel hardware is turned off. Panel will be in reset state at the
+ * end of the function.
+ *
+ * Return: error code.
+ */
+int dsi_display_unprepare(struct dsi_display *display);
+
+int dsi_display_set_tpg_state(struct dsi_display *display, bool enable);
+
+int dsi_display_clock_gate(struct dsi_display *display, bool enable);
+int dsi_dispaly_static_frame(struct dsi_display *display, bool enable);
+
+#endif /* _DSI_DISPLAY_H_ */