Browse Source

Merge "disp: msm: dsi: avoid seamless request for cwb transitions"

qctecmdr 5 years ago
parent
commit
9794834cc5
6 changed files with 119 additions and 43 deletions
  1. 31 30
      msm/dsi/dsi_ctrl.c
  2. 1 1
      msm/dsi/dsi_ctrl.h
  3. 59 8
      msm/dsi/dsi_display.c
  4. 18 4
      msm/dsi/dsi_drm.c
  5. 3 0
      msm/dsi/dsi_panel.c
  6. 7 0
      msm/dsi/dsi_panel.h

+ 31 - 30
msm/dsi/dsi_ctrl.c

@@ -18,6 +18,7 @@
 #include "dsi_clk.h"
 #include "dsi_clk.h"
 #include "dsi_pwr.h"
 #include "dsi_pwr.h"
 #include "dsi_catalog.h"
 #include "dsi_catalog.h"
+#include "dsi_panel.h"
 
 
 #include "sde_dbg.h"
 #include "sde_dbg.h"
 
 
@@ -1268,9 +1269,9 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
 	}
 	}
 }
 }
 
 
-static u32 dsi_ctrl_validate_msg_flags(struct dsi_ctrl *dsi_ctrl,
+static void dsi_ctrl_validate_msg_flags(struct dsi_ctrl *dsi_ctrl,
 				const struct mipi_dsi_msg *msg,
 				const struct mipi_dsi_msg *msg,
-				u32 flags)
+				u32 *flags)
 {
 {
 	/*
 	/*
 	 * ASYNC command wait mode is not supported for
 	 * ASYNC command wait mode is not supported for
@@ -1280,20 +1281,20 @@ static u32 dsi_ctrl_validate_msg_flags(struct dsi_ctrl *dsi_ctrl,
 	 *    - whenever an explicit wait time is specificed for the command
 	 *    - whenever an explicit wait time is specificed for the command
 	 *      since the wait time cannot be guaranteed in async mode
 	 *      since the wait time cannot be guaranteed in async mode
 	 *    - video mode panels
 	 *    - video mode panels
+	 * If async override is set, skip async flag reset
 	 */
 	 */
-	if ((flags & DSI_CTRL_CMD_FIFO_STORE) ||
-		flags & DSI_CTRL_CMD_READ ||
-		flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE ||
+	if (((*flags & DSI_CTRL_CMD_FIFO_STORE) ||
+		*flags & DSI_CTRL_CMD_READ ||
+		*flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE ||
 		msg->wait_ms ||
 		msg->wait_ms ||
-		(dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE))
-		flags &= ~DSI_CTRL_CMD_ASYNC_WAIT;
-
-	return flags;
+		(dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE)) &&
+		!(msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE))
+		*flags &= ~DSI_CTRL_CMD_ASYNC_WAIT;
 }
 }
 
 
 static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
 static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
 			  const struct mipi_dsi_msg *msg,
 			  const struct mipi_dsi_msg *msg,
-			  u32 flags)
+			  u32 *flags)
 {
 {
 	int rc = 0;
 	int rc = 0;
 	struct mipi_dsi_packet packet;
 	struct mipi_dsi_packet packet;
@@ -1305,10 +1306,10 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
 	u8 *cmdbuf;
 	u8 *cmdbuf;
 
 
 	/* Select the tx mode to transfer the command */
 	/* Select the tx mode to transfer the command */
-	dsi_message_setup_tx_mode(dsi_ctrl, msg->tx_len, &flags);
+	dsi_message_setup_tx_mode(dsi_ctrl, msg->tx_len, flags);
 
 
 	/* Validate the mode before sending the command */
 	/* Validate the mode before sending the command */
-	rc = dsi_message_validate_tx_mode(dsi_ctrl, msg->tx_len, &flags);
+	rc = dsi_message_validate_tx_mode(dsi_ctrl, msg->tx_len, flags);
 	if (rc) {
 	if (rc) {
 		DSI_CTRL_ERR(dsi_ctrl,
 		DSI_CTRL_ERR(dsi_ctrl,
 			"Cmd tx validation failed, cannot transfer cmd\n");
 			"Cmd tx validation failed, cannot transfer cmd\n");
@@ -1316,16 +1317,16 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
 		goto error;
 		goto error;
 	}
 	}
 
 
-	flags = dsi_ctrl_validate_msg_flags(dsi_ctrl, msg, flags);
+	dsi_ctrl_validate_msg_flags(dsi_ctrl, msg, flags);
 
 
 	if (dsi_ctrl->dma_wait_queued)
 	if (dsi_ctrl->dma_wait_queued)
 		dsi_ctrl_flush_cmd_dma_queue(dsi_ctrl);
 		dsi_ctrl_flush_cmd_dma_queue(dsi_ctrl);
 
 
-	if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
+	if (*flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
 		cmd_mem.offset = dsi_ctrl->cmd_buffer_iova;
 		cmd_mem.offset = dsi_ctrl->cmd_buffer_iova;
-		cmd_mem.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ?
+		cmd_mem.en_broadcast = (*flags & DSI_CTRL_CMD_BROADCAST) ?
 			true : false;
 			true : false;
-		cmd_mem.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ?
+		cmd_mem.is_master = (*flags & DSI_CTRL_CMD_BROADCAST_MASTER) ?
 			true : false;
 			true : false;
 		cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
 		cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
 			true : false;
 			true : false;
@@ -1360,12 +1361,12 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
 	if ((msg->flags & MIPI_DSI_MSG_LASTCOMMAND))
 	if ((msg->flags & MIPI_DSI_MSG_LASTCOMMAND))
 		buffer[3] |= BIT(7);//set the last cmd bit in header.
 		buffer[3] |= BIT(7);//set the last cmd bit in header.
 
 
-	if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
+	if (*flags & DSI_CTRL_CMD_FETCH_MEMORY) {
 		/* Embedded mode config is selected */
 		/* Embedded mode config is selected */
 		cmd_mem.offset = dsi_ctrl->cmd_buffer_iova;
 		cmd_mem.offset = dsi_ctrl->cmd_buffer_iova;
-		cmd_mem.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ?
+		cmd_mem.en_broadcast = (*flags & DSI_CTRL_CMD_BROADCAST) ?
 			true : false;
 			true : false;
-		cmd_mem.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ?
+		cmd_mem.is_master = (*flags & DSI_CTRL_CMD_BROADCAST_MASTER) ?
 			true : false;
 			true : false;
 		cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
 		cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
 			true : false;
 			true : false;
@@ -1385,19 +1386,19 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
 			dsi_ctrl->cmd_len = 0;
 			dsi_ctrl->cmd_len = 0;
 		}
 		}
 
 
-	} else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
+	} else if (*flags & DSI_CTRL_CMD_FIFO_STORE) {
 		cmd.command =  (u32 *)buffer;
 		cmd.command =  (u32 *)buffer;
 		cmd.size = length;
 		cmd.size = length;
-		cmd.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ?
+		cmd.en_broadcast = (*flags & DSI_CTRL_CMD_BROADCAST) ?
 				     true : false;
 				     true : false;
-		cmd.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ?
+		cmd.is_master = (*flags & DSI_CTRL_CMD_BROADCAST_MASTER) ?
 				  true : false;
 				  true : false;
 		cmd.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
 		cmd.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
 				  true : false;
 				  true : false;
 	}
 	}
 
 
 kickoff:
 kickoff:
-	dsi_kickoff_msg_tx(dsi_ctrl, msg, &cmd, &cmd_mem, flags);
+	dsi_kickoff_msg_tx(dsi_ctrl, msg, &cmd, &cmd_mem, *flags);
 error:
 error:
 	if (buffer)
 	if (buffer)
 		devm_kfree(&dsi_ctrl->pdev->dev, buffer);
 		devm_kfree(&dsi_ctrl->pdev->dev, buffer);
@@ -1425,7 +1426,7 @@ static int dsi_set_max_return_size(struct dsi_ctrl *dsi_ctrl,
 	dflags &= ~BIT(3);
 	dflags &= ~BIT(3);
 	msg.flags = dflags;
 	msg.flags = dflags;
 
 
-	rc = dsi_message_tx(dsi_ctrl, &msg, flags);
+	rc = dsi_message_tx(dsi_ctrl, &msg, &flags);
 	if (rc)
 	if (rc)
 		DSI_CTRL_ERR(dsi_ctrl, "failed to send max return size packet, rc=%d\n",
 		DSI_CTRL_ERR(dsi_ctrl, "failed to send max return size packet, rc=%d\n",
 				rc);
 				rc);
@@ -1487,7 +1488,7 @@ static int dsi_parse_long_read_resp(const struct mipi_dsi_msg *msg,
 
 
 static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl,
 static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl,
 			  const struct mipi_dsi_msg *msg,
 			  const struct mipi_dsi_msg *msg,
-			  u32 flags)
+			  u32 *flags)
 {
 {
 	int rc = 0;
 	int rc = 0;
 	u32 rd_pkt_size, total_read_len, hw_read_cnt;
 	u32 rd_pkt_size, total_read_len, hw_read_cnt;
@@ -2691,8 +2692,7 @@ void dsi_ctrl_disable_status_interrupt(struct dsi_ctrl *dsi_ctrl,
 {
 {
 	unsigned long flags;
 	unsigned long flags;
 
 
-	if (!dsi_ctrl || dsi_ctrl->irq_info.irq_num == -1 ||
-			intr_idx >= DSI_STATUS_INTERRUPT_COUNT)
+	if (!dsi_ctrl || intr_idx >= DSI_STATUS_INTERRUPT_COUNT)
 		return;
 		return;
 
 
 	SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY);
 	SDE_EVT32(dsi_ctrl->cell_index, SDE_EVTLOG_FUNC_ENTRY);
@@ -2705,7 +2705,8 @@ void dsi_ctrl_disable_status_interrupt(struct dsi_ctrl *dsi_ctrl,
 					dsi_ctrl->irq_info.irq_stat_mask);
 					dsi_ctrl->irq_info.irq_stat_mask);
 
 
 			/* don't need irq if no lines are enabled */
 			/* don't need irq if no lines are enabled */
-			if (dsi_ctrl->irq_info.irq_stat_mask == 0)
+			if (dsi_ctrl->irq_info.irq_stat_mask == 0 &&
+				dsi_ctrl->irq_info.irq_num != -1)
 				disable_irq_nosync(dsi_ctrl->irq_info.irq_num);
 				disable_irq_nosync(dsi_ctrl->irq_info.irq_num);
 		}
 		}
 
 
@@ -3088,7 +3089,7 @@ int dsi_ctrl_validate_timing(struct dsi_ctrl *dsi_ctrl,
  */
  */
 int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl,
 int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl,
 			  const struct mipi_dsi_msg *msg,
 			  const struct mipi_dsi_msg *msg,
-			  u32 flags)
+			  u32 *flags)
 {
 {
 	int rc = 0;
 	int rc = 0;
 
 
@@ -3106,7 +3107,7 @@ int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl,
 		goto error;
 		goto error;
 	}
 	}
 
 
-	if (flags & DSI_CTRL_CMD_READ) {
+	if (*flags & DSI_CTRL_CMD_READ) {
 		rc = dsi_message_rx(dsi_ctrl, msg, flags);
 		rc = dsi_message_rx(dsi_ctrl, msg, flags);
 		if (rc <= 0)
 		if (rc <= 0)
 			DSI_CTRL_ERR(dsi_ctrl, "read message failed read length, rc=%d\n",
 			DSI_CTRL_ERR(dsi_ctrl, "read message failed read length, rc=%d\n",

+ 1 - 1
msm/dsi/dsi_ctrl.h

@@ -554,7 +554,7 @@ int dsi_ctrl_set_tpg_state(struct dsi_ctrl *dsi_ctrl, bool on);
  */
  */
 int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl,
 int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl,
 			  const struct mipi_dsi_msg *msg,
 			  const struct mipi_dsi_msg *msg,
-			  u32 flags);
+			  u32 *flags);
 
 
 /**
 /**
  * dsi_ctrl_cmd_tx_trigger() - Trigger a deferred command.
  * dsi_ctrl_cmd_tx_trigger() - Trigger a deferred command.

+ 59 - 8
msm/dsi/dsi_display.c

@@ -660,7 +660,7 @@ static int dsi_display_read_status(struct dsi_display_ctrl *ctrl,
 			cmds[i].msg.flags |= MIPI_DSI_MSG_USE_LPM;
 			cmds[i].msg.flags |= MIPI_DSI_MSG_USE_LPM;
 		cmds[i].msg.rx_buf = config->status_buf;
 		cmds[i].msg.rx_buf = config->status_buf;
 		cmds[i].msg.rx_len = config->status_cmds_rlen[i];
 		cmds[i].msg.rx_len = config->status_cmds_rlen[i];
-		rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &cmds[i].msg, flags);
+		rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, &cmds[i].msg, &flags);
 		if (rc <= 0) {
 		if (rc <= 0) {
 			DSI_ERR("rx cmd transfer failed rc=%d\n", rc);
 			DSI_ERR("rx cmd transfer failed rc=%d\n", rc);
 			return rc;
 			return rc;
@@ -2734,7 +2734,8 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display,
 		m_flags |= DSI_CTRL_CMD_LAST_COMMAND;
 		m_flags |= DSI_CTRL_CMD_LAST_COMMAND;
 	}
 	}
 
 
-	if (display->queue_cmd_waits) {
+	if (display->queue_cmd_waits ||
+			msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE) {
 		flags |= DSI_CTRL_CMD_ASYNC_WAIT;
 		flags |= DSI_CTRL_CMD_ASYNC_WAIT;
 		m_flags |= DSI_CTRL_CMD_ASYNC_WAIT;
 		m_flags |= DSI_CTRL_CMD_ASYNC_WAIT;
 	}
 	}
@@ -2744,7 +2745,7 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display,
 	 * 2. Trigger commands
 	 * 2. Trigger commands
 	 */
 	 */
 	m_ctrl = &display->ctrl[display->cmd_master_idx];
 	m_ctrl = &display->ctrl[display->cmd_master_idx];
-	rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, msg, m_flags);
+	rc = dsi_ctrl_cmd_transfer(m_ctrl->ctrl, msg, &m_flags);
 	if (rc) {
 	if (rc) {
 		DSI_ERR("[%s] cmd transfer failed on master,rc=%d\n",
 		DSI_ERR("[%s] cmd transfer failed on master,rc=%d\n",
 		       display->name, rc);
 		       display->name, rc);
@@ -2756,7 +2757,7 @@ static int dsi_display_broadcast_cmd(struct dsi_display *display,
 		if (ctrl == m_ctrl)
 		if (ctrl == m_ctrl)
 			continue;
 			continue;
 
 
-		rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, msg, flags);
+		rc = dsi_ctrl_cmd_transfer(ctrl->ctrl, msg, &flags);
 		if (rc) {
 		if (rc) {
 			DSI_ERR("[%s] cmd transfer failed, rc=%d\n",
 			DSI_ERR("[%s] cmd transfer failed, rc=%d\n",
 			       display->name, rc);
 			       display->name, rc);
@@ -2894,11 +2895,12 @@ static ssize_t dsi_host_transfer(struct mipi_dsi_host *host,
 				msg->ctrl : 0;
 				msg->ctrl : 0;
 		u32 cmd_flags = DSI_CTRL_CMD_FETCH_MEMORY;
 		u32 cmd_flags = DSI_CTRL_CMD_FETCH_MEMORY;
 
 
-		if (display->queue_cmd_waits)
+		if (display->queue_cmd_waits ||
+				msg->flags & MIPI_DSI_MSG_ASYNC_OVERRIDE)
 			cmd_flags |= DSI_CTRL_CMD_ASYNC_WAIT;
 			cmd_flags |= DSI_CTRL_CMD_ASYNC_WAIT;
 
 
 		rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg,
 		rc = dsi_ctrl_cmd_transfer(display->ctrl[ctrl_idx].ctrl, msg,
-				cmd_flags);
+				&cmd_flags);
 		if (rc) {
 		if (rc) {
 			DSI_ERR("[%s] cmd transfer failed, rc=%d\n",
 			DSI_ERR("[%s] cmd transfer failed, rc=%d\n",
 			       display->name, rc);
 			       display->name, rc);
@@ -7536,14 +7538,44 @@ int dsi_display_pre_disable(struct dsi_display *display)
 		if (display->config.panel_mode == DSI_OP_CMD_MODE)
 		if (display->config.panel_mode == DSI_OP_CMD_MODE)
 			dsi_panel_pre_mode_switch_to_video(display->panel);
 			dsi_panel_pre_mode_switch_to_video(display->panel);
 
 
-		if (display->config.panel_mode == DSI_OP_VIDEO_MODE)
+		if (display->config.panel_mode == DSI_OP_VIDEO_MODE) {
+			/*
+			 * Add unbalanced vote for clock & cmd engine to enable
+			 * async trigger of pre video to cmd mode switch.
+			 */
+			rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+					DSI_ALL_CLKS, DSI_CLK_ON);
+			if (rc) {
+				DSI_ERR("[%s]failed to enable all clocks,rc=%d",
+						display->name, rc);
+				goto exit;
+			}
+
+			rc = dsi_display_cmd_engine_enable(display);
+			if (rc) {
+				DSI_ERR("[%s]failed to enable cmd engine,rc=%d",
+						display->name, rc);
+				goto error_disable_clks;
+			}
+
 			dsi_panel_pre_mode_switch_to_cmd(display->panel);
 			dsi_panel_pre_mode_switch_to_cmd(display->panel);
+		}
 	} else {
 	} else {
 		rc = dsi_panel_pre_disable(display->panel);
 		rc = dsi_panel_pre_disable(display->panel);
 		if (rc)
 		if (rc)
 			DSI_ERR("[%s] panel pre-disable failed, rc=%d\n",
 			DSI_ERR("[%s] panel pre-disable failed, rc=%d\n",
 				display->name, rc);
 				display->name, rc);
 	}
 	}
+	goto exit;
+
+error_disable_clks:
+	rc = dsi_display_clk_ctrl(display->dsi_clk_handle,
+			DSI_ALL_CLKS, DSI_CLK_OFF);
+	if (rc)
+		DSI_ERR("[%s] failed to disable all DSI clocks, rc=%d\n",
+		       display->name, rc);
+
+exit:
 	mutex_unlock(&display->display_lock);
 	mutex_unlock(&display->display_lock);
 	return rc;
 	return rc;
 }
 }
@@ -7646,7 +7678,8 @@ int dsi_display_update_pps(char *pps_cmd, void *disp)
 
 
 int dsi_display_unprepare(struct dsi_display *display)
 int dsi_display_unprepare(struct dsi_display *display)
 {
 {
-	int rc = 0;
+	int rc = 0, i;
+	struct dsi_display_ctrl *ctrl;
 
 
 	if (!display) {
 	if (!display) {
 		DSI_ERR("Invalid params\n");
 		DSI_ERR("Invalid params\n");
@@ -7666,6 +7699,24 @@ int dsi_display_unprepare(struct dsi_display *display)
 			DSI_ERR("[%s] panel unprepare failed, rc=%d\n",
 			DSI_ERR("[%s] panel unprepare failed, rc=%d\n",
 			       display->name, rc);
 			       display->name, rc);
 	}
 	}
+
+	/* Remove additional vote added for pre_mode_switch_to_cmd */
+	if (display->poms_pending &&
+			display->config.panel_mode == DSI_OP_VIDEO_MODE) {
+		display_for_each_ctrl(i, display) {
+			ctrl = &display->ctrl[i];
+			if (!ctrl->ctrl || !ctrl->ctrl->dma_wait_queued)
+				continue;
+			flush_workqueue(display->dma_cmd_workq);
+			cancel_work_sync(&ctrl->ctrl->dma_cmd_wait);
+			ctrl->ctrl->dma_wait_queued = false;
+		}
+
+		dsi_display_cmd_engine_disable(display);
+		dsi_display_clk_ctrl(display->dsi_clk_handle,
+				DSI_ALL_CLKS, DSI_CLK_OFF);
+	}
+
 	rc = dsi_display_ctrl_host_disable(display);
 	rc = dsi_display_ctrl_host_disable(display);
 	if (rc)
 	if (rc)
 		DSI_ERR("[%s] failed to disable DSI host, rc=%d\n",
 		DSI_ERR("[%s] failed to disable DSI host, rc=%d\n",

+ 18 - 4
msm/dsi/dsi_drm.c

@@ -11,6 +11,7 @@
 #include "sde_connector.h"
 #include "sde_connector.h"
 #include "dsi_drm.h"
 #include "dsi_drm.h"
 #include "sde_trace.h"
 #include "sde_trace.h"
+#include "sde_encoder.h"
 
 
 #define to_dsi_bridge(x)     container_of((x), struct dsi_bridge, base)
 #define to_dsi_bridge(x)     container_of((x), struct dsi_bridge, base)
 #define to_dsi_state(x)      container_of((x), struct dsi_connector_state, base)
 #define to_dsi_state(x)      container_of((x), struct dsi_connector_state, base)
@@ -343,6 +344,8 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
 	struct dsi_display *display;
 	struct dsi_display *display;
 	struct dsi_display_mode dsi_mode, cur_dsi_mode, *panel_dsi_mode;
 	struct dsi_display_mode dsi_mode, cur_dsi_mode, *panel_dsi_mode;
 	struct drm_crtc_state *crtc_state;
 	struct drm_crtc_state *crtc_state;
+	bool clone_mode = false;
+	struct drm_encoder *encoder;
 
 
 	crtc_state = container_of(mode, struct drm_crtc_state, mode);
 	crtc_state = container_of(mode, struct drm_crtc_state, mode);
 
 
@@ -407,6 +410,14 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
 			return false;
 			return false;
 		}
 		}
 
 
+		drm_for_each_encoder(encoder, crtc_state->crtc->dev) {
+			if (encoder->crtc != crtc_state->crtc)
+				continue;
+
+			if (sde_encoder_in_clone_mode(encoder))
+				clone_mode = true;
+		}
+
 		/* No panel mode switch when drm pipeline is changing */
 		/* No panel mode switch when drm pipeline is changing */
 		if ((dsi_mode.panel_mode != cur_dsi_mode.panel_mode) &&
 		if ((dsi_mode.panel_mode != cur_dsi_mode.panel_mode) &&
 			(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) &&
 			(!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) &&
@@ -423,13 +434,16 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
 			dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS;
 			dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS;
 	}
 	}
 
 
-	/* Reject seamless transition when active changed */
-	if (crtc_state->active_changed &&
+	/* Reject seamless transition when active/connectors changed */
+	if ((crtc_state->active_changed ||
+		(crtc_state->connectors_changed && clone_mode)) &&
 		((dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) ||
 		((dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) ||
 		(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS) ||
 		(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_POMS) ||
 		(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK))) {
 		(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK))) {
-		DSI_ERR("seamless upon active changed 0x%x %d\n",
-			dsi_mode.dsi_mode_flags, crtc_state->active_changed);
+		DSI_ERR("seamless on active/conn(%d/%d) changed 0x%x\n",
+			crtc_state->active_changed,
+			crtc_state->connectors_changed,
+			dsi_mode.dsi_mode_flags);
 		return false;
 		return false;
 	}
 	}
 
 

+ 3 - 0
msm/dsi/dsi_panel.c

@@ -411,6 +411,9 @@ static int dsi_panel_tx_cmd_set(struct dsi_panel *panel,
 		if (cmds->last_command)
 		if (cmds->last_command)
 			cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND;
 			cmds->msg.flags |= MIPI_DSI_MSG_LASTCOMMAND;
 
 
+		if (type == DSI_CMD_SET_VID_TO_CMD_SWITCH)
+			cmds->msg.flags |= MIPI_DSI_MSG_ASYNC_OVERRIDE;
+
 		len = ops->transfer(panel->host, &cmds->msg);
 		len = ops->transfer(panel->host, &cmds->msg);
 		if (len < 0) {
 		if (len < 0) {
 			rc = len;
 			rc = len;

+ 7 - 0
msm/dsi/dsi_panel.h

@@ -29,6 +29,13 @@
 #define DSI_CMD_PPS_HDR_SIZE 7
 #define DSI_CMD_PPS_HDR_SIZE 7
 #define DSI_MODE_MAX 32
 #define DSI_MODE_MAX 32
 
 
+/*
+ * Defining custom dsi msg flag,
+ * continued from drm_mipi_dsi.h
+ * Override to use async transfer
+ */
+#define MIPI_DSI_MSG_ASYNC_OVERRIDE BIT(4)
+
 enum dsi_panel_rotation {
 enum dsi_panel_rotation {
 	DSI_PANEL_ROTATE_NONE = 0,
 	DSI_PANEL_ROTATE_NONE = 0,
 	DSI_PANEL_ROTATE_HV_FLIP,
 	DSI_PANEL_ROTATE_HV_FLIP,