Kaynağa Gözat

Merge "disp: msm: dsi: disallow backlight update during panel mode switch"

qctecmdr 5 yıl önce
ebeveyn
işleme
34b32d77f8

+ 8 - 0
msm/dsi/dsi_catalog.c

@@ -192,6 +192,14 @@ static void dsi_catalog_phy_2_0_init(struct dsi_phy_hw *phy)
 		dsi_phy_hw_calculate_timing_params;
 	phy->ops.phy_timing_val = dsi_phy_hw_timing_val_v2_0;
 	phy->ops.clamp_ctrl = dsi_phy_hw_v2_0_clamp_ctrl;
+	phy->ops.dyn_refresh_ops.dyn_refresh_config =
+		dsi_phy_hw_v2_0_dyn_refresh_config;
+	phy->ops.dyn_refresh_ops.dyn_refresh_pipe_delay =
+		dsi_phy_hw_v2_0_dyn_refresh_pipe_delay;
+	phy->ops.dyn_refresh_ops.dyn_refresh_helper =
+		dsi_phy_hw_v2_0_dyn_refresh_helper;
+	phy->ops.dyn_refresh_ops.cache_phy_timings =
+		dsi_phy_hw_v2_0_cache_phy_timings;
 }
 
 /**

+ 8 - 1
msm/dsi/dsi_catalog.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _DSI_CATALOG_H_
@@ -80,6 +80,13 @@ void dsi_phy_hw_v2_0_idle_off(struct dsi_phy_hw *phy);
 int dsi_phy_hw_timing_val_v2_0(struct dsi_phy_per_lane_cfgs *timing_cfg,
 		u32 *timing_val, u32 size);
 void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable);
+void dsi_phy_hw_v2_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset);
+void dsi_phy_hw_v2_0_dyn_refresh_config(struct dsi_phy_hw *phy,
+		struct dsi_phy_cfg *cfg, bool is_master);
+void dsi_phy_hw_v2_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
+		struct dsi_dyn_clk_delay *delay);
+int dsi_phy_hw_v2_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
+		u32 *dst, u32 size);
 
 /* Definitions for 10nm PHY hardware driver */
 void dsi_phy_hw_v3_0_regulator_enable(struct dsi_phy_hw *phy,

+ 5 - 1
msm/dsi/dsi_clk.h

@@ -106,11 +106,13 @@ struct dsi_link_lp_clk_info {
 /**
  * struct link_clk_freq - Clock frequency information for Link clocks
  * @byte_clk_rate:   Frequency of DSI byte_clk in KHz.
+ * @byte_intf_clk_rate:   Frequency of DSI byte_intf_clk in KHz.
  * @pixel_clk_rate:  Frequency of DSI pixel_clk in KHz.
  * @esc_clk_rate:    Frequency of DSI escape clock in KHz.
  */
 struct link_clk_freq {
 	u32 byte_clk_rate;
+	u32 byte_intf_clk_rate;
 	u32 pix_clk_rate;
 	u32 esc_clk_rate;
 };
@@ -292,10 +294,12 @@ int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index);
  * dsi_clk_set_byte_clk_rate() - set frequency for byte clock
  * @client:       DSI clock client pointer.
  * @byte_clk: Pixel clock rate in Hz.
+ * @byte_intf_clk: Byte interface clock rate in Hz.
  * @index:      Index of the DSI controller.
  * return: error code in case of failure or 0 for success.
  */
-int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index);
+int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk,
+				u64 byte_intf_clk, u32 index);
 
 /**
  * dsi_clk_update_parent() - update parent clocks for specified clock

+ 8 - 7
msm/dsi/dsi_clk_manager.c

@@ -130,15 +130,16 @@ int dsi_clk_set_pixel_clk_rate(void *client, u64 pixel_clk, u32 index)
  * dsi_clk_set_byte_clk_rate() - set frequency for byte clock
  * @client:	DSI clock client pointer.
  * @byte_clk:	Byte clock rate in Hz.
+ * @byte_intf_clk:	Byte interface clock rate in Hz.
  * @index:	Index of the DSI controller.
  * return: error code in case of failure or 0 for success.
  */
-int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index)
+int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk,
+					u64 byte_intf_clk, u32 index)
 {
 	int rc = 0;
 	struct dsi_clk_client_info *c = client;
 	struct dsi_clk_mngr *mngr;
-	u64 byte_intf_rate;
 
 	mngr = c->mngr;
 	rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_clk, byte_clk);
@@ -148,12 +149,14 @@ int dsi_clk_set_byte_clk_rate(void *client, u64 byte_clk, u32 index)
 		mngr->link_clks[index].freq.byte_clk_rate = byte_clk;
 
 	if (mngr->link_clks[index].hs_clks.byte_intf_clk) {
-		byte_intf_rate = mngr->link_clks[index].freq.byte_clk_rate / 2;
 		rc = clk_set_rate(mngr->link_clks[index].hs_clks.byte_intf_clk,
-				  byte_intf_rate);
+				  byte_intf_clk);
 		if (rc)
 			DSI_ERR("failed to set clk rate for byte intf clk=%d\n",
 			       rc);
+		else
+			mngr->link_clks[index].freq.byte_intf_clk_rate =
+								byte_intf_clk;
 	}
 
 	return rc;
@@ -344,12 +347,10 @@ static int dsi_link_hs_clk_set_rate(struct dsi_link_hs_clk_info *link_hs_clks,
 
 	/*
 	 * If byte_intf_clk is present, set rate for that too.
-	 * For DPHY: byte_intf_clk_rate = byte_clk_rate / 2
-	 * todo: this needs to be revisited when support for CPHY is added
 	 */
 	if (link_hs_clks->byte_intf_clk) {
 		rc = clk_set_rate(link_hs_clks->byte_intf_clk,
-			(l_clks->freq.byte_clk_rate / 2));
+				l_clks->freq.byte_intf_clk_rate);
 		if (rc) {
 			DSI_ERR("set_rate failed for byte_intf_clk rc = %d\n",
 				rc);

+ 34 - 43
msm/dsi/dsi_ctrl.c

@@ -269,10 +269,6 @@ dsi_ctrl_get_aspace(struct dsi_ctrl *dsi_ctrl,
 
 static void dsi_ctrl_flush_cmd_dma_queue(struct dsi_ctrl *dsi_ctrl)
 {
-	u32 status;
-	u32 mask = DSI_CMD_MODE_DMA_DONE;
-	struct dsi_ctrl_hw_ops dsi_hw_ops = dsi_ctrl->hw.ops;
-
 	/*
 	 * If a command is triggered right after another command,
 	 * check if the previous command transfer is completed. If
@@ -281,21 +277,8 @@ static void dsi_ctrl_flush_cmd_dma_queue(struct dsi_ctrl *dsi_ctrl)
 	 * completed before triggering the next command by
 	 * flushing the workqueue.
 	 */
-	status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw);
 	if (atomic_read(&dsi_ctrl->dma_irq_trig)) {
 		cancel_work_sync(&dsi_ctrl->dma_cmd_wait);
-	} else if (status & mask) {
-		atomic_set(&dsi_ctrl->dma_irq_trig, 1);
-		status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE);
-		dsi_hw_ops.clear_interrupt_status(
-						&dsi_ctrl->hw,
-						status);
-		dsi_ctrl_disable_status_interrupt(dsi_ctrl,
-				DSI_SINT_CMD_MODE_DMA_DONE);
-		complete_all(&dsi_ctrl->irq_info.cmd_dma_done);
-		cancel_work_sync(&dsi_ctrl->dma_cmd_wait);
-		DSI_CTRL_DEBUG(dsi_ctrl,
-				"dma_tx done but irq not yet triggered\n");
 	} else {
 		flush_workqueue(dsi_ctrl->dma_cmd_workq);
 	}
@@ -319,24 +302,11 @@ static void dsi_ctrl_dma_cmd_wait_for_done(struct work_struct *work)
 	 */
 	if (atomic_read(&dsi_ctrl->dma_irq_trig))
 		goto done;
-	/*
-	 * If IRQ wasn't triggered check interrupt status register for
-	 * transfer done before waiting.
-	 */
-	status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw);
-	if (status & mask) {
-		status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE);
-		dsi_hw_ops.clear_interrupt_status(&dsi_ctrl->hw,
-				status);
-		dsi_ctrl_disable_status_interrupt(dsi_ctrl,
-				DSI_SINT_CMD_MODE_DMA_DONE);
-		goto done;
-	}
 
 	ret = wait_for_completion_timeout(
 			&dsi_ctrl->irq_info.cmd_dma_done,
 			msecs_to_jiffies(DSI_CTRL_TX_TO_MS));
-	if (ret == 0) {
+	if (ret == 0 && !atomic_read(&dsi_ctrl->dma_irq_trig)) {
 		status = dsi_hw_ops.get_interrupt_status(&dsi_ctrl->hw);
 		if (status & mask) {
 			status |= (DSI_CMD_MODE_DMA_DONE | DSI_BTA_DONE);
@@ -877,9 +847,9 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
 {
 	int rc = 0;
 	u32 num_of_lanes = 0;
-	u32 bpp, frame_time_us;
+	u32 bpp, frame_time_us, byte_intf_clk_div;
 	u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane,
-	    byte_clk_rate;
+	    byte_clk_rate, byte_intf_clk_rate;
 	struct dsi_host_common_cfg *host_cfg = &config->common_config;
 	struct dsi_split_link_config *split_link = &host_cfg->split_link;
 	struct dsi_mode_info *timing = &config->video_timing;
@@ -924,14 +894,20 @@ static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
 	do_div(pclk_rate, bpp);
 	byte_clk_rate = bit_rate_per_lane;
 	do_div(byte_clk_rate, 8);
+	byte_intf_clk_rate = byte_clk_rate;
+	byte_intf_clk_div = host_cfg->byte_intf_clk_div;
+	do_div(byte_intf_clk_rate, byte_intf_clk_div);
+
 	DSI_CTRL_DEBUG(dsi_ctrl, "bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
 		 bit_rate, bit_rate_per_lane);
-	DSI_CTRL_DEBUG(dsi_ctrl, "byte_clk_rate = %llu, pclk_rate = %llu\n",
-		  byte_clk_rate, pclk_rate);
+	DSI_CTRL_DEBUG(dsi_ctrl, "byte_clk_rate = %llu, byte_intf_clk = %llu\n",
+		  byte_clk_rate, byte_intf_clk_rate);
+	DSI_CTRL_DEBUG(dsi_ctrl, "pclk_rate = %llu\n", pclk_rate);
 
 	dsi_ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
 	dsi_ctrl->clk_freq.pix_clk_rate = pclk_rate;
 	dsi_ctrl->clk_freq.esc_clk_rate = config->esc_clk_rate_hz;
+	dsi_ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate;
 	config->bit_clk_rate_hz = dsi_ctrl->clk_freq.byte_clk_rate * 8;
 
 	rc = dsi_clk_set_link_frequencies(clk_handle, dsi_ctrl->clk_freq,
@@ -1268,23 +1244,33 @@ static void dsi_kickoff_msg_tx(struct dsi_ctrl *dsi_ctrl,
 		 * result in smmu write faults with DSI as client.
 		 */
 		if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
-			dsi_hw_ops.soft_reset(&dsi_ctrl->hw);
+			if (dsi_ctrl->version < DSI_CTRL_VERSION_2_4)
+				dsi_hw_ops.soft_reset(&dsi_ctrl->hw);
 			dsi_ctrl->cmd_len = 0;
 		}
 	}
 }
 
-static u32 dsi_ctrl_validate_msg_flags(const struct mipi_dsi_msg *msg,
+static u32 dsi_ctrl_validate_msg_flags(struct dsi_ctrl *dsi_ctrl,
+				const struct mipi_dsi_msg *msg,
 				u32 flags)
 {
 	/*
-	 * ASYNC command wait mode is not supported for FIFO commands.
-	 * Waiting after a command is transferred cannot be guaranteed
-	 * if DSI_CTRL_CMD_ASYNC_WAIT flag is set.
+	 * ASYNC command wait mode is not supported for
+	 *    - commands sent using DSI FIFO memory
+	 *    - DSI read commands
+	 *    - DCS commands sent in non-embedded mode
+	 *    - whenever an explicit wait time is specificed for the command
+	 *      since the wait time cannot be guaranteed in async mode
+	 *    - video mode panels
 	 */
 	if ((flags & DSI_CTRL_CMD_FIFO_STORE) ||
-			msg->wait_ms)
+		flags & DSI_CTRL_CMD_READ ||
+		flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE ||
+		msg->wait_ms ||
+		(dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE))
 		flags &= ~DSI_CTRL_CMD_ASYNC_WAIT;
+
 	return flags;
 }
 
@@ -1313,7 +1299,7 @@ static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
 		goto error;
 	}
 
-	flags = dsi_ctrl_validate_msg_flags(msg, flags);
+	flags = dsi_ctrl_validate_msg_flags(dsi_ctrl, msg, flags);
 
 	if (dsi_ctrl->dma_wait_queued)
 		dsi_ctrl_flush_cmd_dma_queue(dsi_ctrl);
@@ -2692,6 +2678,10 @@ void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl,
 		dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw,
 				dsi_ctrl->irq_info.irq_stat_mask);
 	}
+
+	if (intr_idx == DSI_SINT_CMD_MODE_DMA_DONE)
+		dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw,
+				dsi_ctrl->irq_info.irq_stat_mask);
 	++(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]);
 
 	if (event_info)
@@ -3196,7 +3186,8 @@ int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
 					BIT(DSI_FIFO_OVERFLOW), false);
 
 		if (flags & DSI_CTRL_CMD_NON_EMBEDDED_MODE) {
-			dsi_hw_ops.soft_reset(&dsi_ctrl->hw);
+			if (dsi_ctrl->version < DSI_CTRL_VERSION_2_4)
+				dsi_hw_ops.soft_reset(&dsi_ctrl->hw);
 			dsi_ctrl->cmd_len = 0;
 		}
 	}

+ 18 - 0
msm/dsi/dsi_defs.h

@@ -217,6 +217,22 @@ enum dsi_dfps_type {
 	DSI_DFPS_MAX
 };
 
+/**
+ * enum dsi_dyn_clk_feature_type - Dynamic clock feature support type
+ * @DSI_DYN_CLK_TYPE_LEGACY:			Constant FPS is not supported
+ * @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP:	Constant FPS supported with
+ *						change in hfp
+ * @DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP:	Constant FPS supported with
+ *						change in vfp
+ * @DSI_DYN_CLK_TYPE_MAX:
+ */
+enum dsi_dyn_clk_feature_type {
+	DSI_DYN_CLK_TYPE_LEGACY = 0,
+	DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP,
+	DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP,
+	DSI_DYN_CLK_TYPE_MAX
+};
+
 /**
  * enum dsi_cmd_set_type  - DSI command set type
  * @DSI_CMD_SET_PRE_ON:	                   Panel pre on
@@ -450,6 +466,7 @@ struct dsi_split_link_config {
  * @ext_bridge_mode:     External bridge is connected.
  * @force_hs_clk_lane:   Send continuous clock to the panel.
  * @dsi_split_link_config:  Split Link Configuration.
+ * @byte_intf_clk_div:   Determines the factor for calculating byte intf clock.
  */
 struct dsi_host_common_cfg {
 	enum dsi_pixel_format dst_format;
@@ -473,6 +490,7 @@ struct dsi_host_common_cfg {
 	bool ext_bridge_mode;
 	bool force_hs_clk_lane;
 	struct dsi_split_link_config split_link;
+	u32 byte_intf_clk_div;
 };
 
 /**

+ 154 - 25
msm/dsi/dsi_display.c

@@ -801,7 +801,7 @@ int dsi_display_check_status(struct drm_connector *connector, void *display,
 	struct dsi_display *dsi_display = display;
 	struct dsi_panel *panel;
 	u32 status_mode;
-	int rc = 0x1;
+	int rc = 0x1, ret;
 	u32 mask;
 
 	if (!dsi_display || !dsi_display->panel)
@@ -839,8 +839,10 @@ int dsi_display_check_status(struct drm_connector *connector, void *display,
 		goto exit;
 	}
 
-	dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
+	ret = dsi_display_clk_ctrl(dsi_display->dsi_clk_handle,
 		DSI_ALL_CLKS, DSI_CLK_ON);
+	if (ret)
+		goto release_panel_lock;
 
 	/* Mask error interrupts before attempting ESD read */
 	mask = BIT(DSI_FIFO_OVERFLOW) | BIT(DSI_FIFO_UNDERFLOW);
@@ -3861,6 +3863,22 @@ static bool dsi_display_is_seamless_dfps_possible(
 	return true;
 }
 
+void dsi_display_update_byte_intf_div(struct dsi_display *display)
+{
+	struct dsi_host_common_cfg *config;
+	struct dsi_display_ctrl *m_ctrl;
+	int phy_ver;
+
+	m_ctrl = &display->ctrl[display->cmd_master_idx];
+	config = &display->panel->host_config;
+
+	phy_ver = dsi_phy_get_version(m_ctrl->phy);
+	if (phy_ver <= DSI_PHY_VERSION_2_0)
+		config->byte_intf_clk_div = 1;
+	else
+		config->byte_intf_clk_div = 2;
+}
+
 static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
 					  u32 bit_clk_rate)
 {
@@ -3883,8 +3901,9 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
 	display_for_each_ctrl(i, display) {
 		struct dsi_display_ctrl *dsi_disp_ctrl = &display->ctrl[i];
 		struct dsi_ctrl *ctrl = dsi_disp_ctrl->ctrl;
-		u32 num_of_lanes = 0, bpp;
-		u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate;
+		u32 num_of_lanes = 0, bpp, byte_intf_clk_div;
+		u64 bit_rate, pclk_rate, bit_rate_per_lane, byte_clk_rate,
+				byte_intf_clk_rate;
 		struct dsi_host_common_cfg *host_cfg;
 
 		mutex_lock(&ctrl->ctrl_lock);
@@ -3914,12 +3933,18 @@ static int dsi_display_update_dsi_bitrate(struct dsi_display *display,
 		do_div(pclk_rate, bpp);
 		byte_clk_rate = bit_rate_per_lane;
 		do_div(byte_clk_rate, 8);
+		byte_intf_clk_rate = byte_clk_rate;
+		byte_intf_clk_div = host_cfg->byte_intf_clk_div;
+		do_div(byte_intf_clk_rate, byte_intf_clk_div);
+
 		DSI_DEBUG("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
 			 bit_rate, bit_rate_per_lane);
-		DSI_DEBUG("byte_clk_rate = %llu, pclk_rate = %llu\n",
-			  byte_clk_rate, pclk_rate);
+		DSI_DEBUG("byte_clk_rate = %llu, byte_intf_clk_rate = %llu\n",
+			  byte_clk_rate, byte_intf_clk_rate);
+		DSI_DEBUG("pclk_rate = %llu\n", pclk_rate);
 
 		ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
+		ctrl->clk_freq.byte_intf_clk_rate = byte_intf_clk_rate;
 		ctrl->clk_freq.pix_clk_rate = pclk_rate;
 		rc = dsi_clk_set_link_frequencies(display->dsi_clk_handle,
 			ctrl->clk_freq, ctrl->cell_index);
@@ -4013,7 +4038,8 @@ static int _dsi_display_dyn_update_clks(struct dsi_display *display,
 		if (!ctrl->ctrl)
 			continue;
 		rc = dsi_clk_set_byte_clk_rate(display->dsi_clk_handle,
-				   ctrl->ctrl->clk_freq.byte_clk_rate, i);
+				ctrl->ctrl->clk_freq.byte_clk_rate,
+				ctrl->ctrl->clk_freq.byte_intf_clk_rate, i);
 		if (rc) {
 			DSI_ERR("failed to set byte rate for index:%d\n", i);
 			goto recover_byte_clk;
@@ -4076,7 +4102,8 @@ recover_byte_clk:
 		if (!ctrl->ctrl)
 			continue;
 		dsi_clk_set_byte_clk_rate(display->dsi_clk_handle,
-					  bkp_freq->byte_clk_rate, i);
+					bkp_freq->byte_clk_rate,
+					bkp_freq->byte_intf_clk_rate, i);
 	}
 
 exit:
@@ -4112,6 +4139,7 @@ static int dsi_display_dynamic_clk_switch_vid(struct dsi_display *display,
 
 	/* back up existing rates to handle failure case */
 	bkp_freq.byte_clk_rate = m_ctrl->ctrl->clk_freq.byte_clk_rate;
+	bkp_freq.byte_intf_clk_rate = m_ctrl->ctrl->clk_freq.byte_intf_clk_rate;
 	bkp_freq.pix_clk_rate = m_ctrl->ctrl->clk_freq.pix_clk_rate;
 	bkp_freq.esc_clk_rate = m_ctrl->ctrl->clk_freq.esc_clk_rate;
 
@@ -4196,6 +4224,7 @@ static int dsi_display_dfps_update(struct dsi_display *display,
 	struct dsi_dfps_capabilities dfps_caps;
 	int rc = 0;
 	int i = 0;
+	struct dsi_dyn_clk_caps *dyn_clk_caps;
 
 	if (!display || !dsi_mode || !display->panel) {
 		DSI_ERR("Invalid params\n");
@@ -4204,8 +4233,9 @@ static int dsi_display_dfps_update(struct dsi_display *display,
 	timing = &dsi_mode->timing;
 
 	dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
-	if (!dfps_caps.dfps_support) {
-		DSI_ERR("dfps not supported\n");
+	dyn_clk_caps = &(display->panel->dyn_clk_caps);
+	if (!dfps_caps.dfps_support && !dyn_clk_caps->maintain_const_fps) {
+		DSI_ERR("dfps or constant fps not supported\n");
 		return -ENOTSUPP;
 	}
 
@@ -4482,7 +4512,32 @@ static int dsi_display_set_mode_sub(struct dsi_display *display,
 					display->name, rc);
 			goto error;
 		}
-	} else if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) {
+		display_for_each_ctrl(i, display) {
+			ctrl = &display->ctrl[i];
+			rc = dsi_ctrl_update_host_config(ctrl->ctrl,
+				&display->config, mode, mode->dsi_mode_flags,
+					display->dsi_clk_handle);
+			if (rc) {
+				DSI_ERR("failed to update ctrl config\n");
+				goto error;
+			}
+		}
+		if (priv_info->phy_timing_len) {
+			display_for_each_ctrl(i, display) {
+				ctrl = &display->ctrl[i];
+				rc = dsi_phy_set_timing_params(ctrl->phy,
+						priv_info->phy_timing_val,
+						priv_info->phy_timing_len,
+						commit_phy_timing);
+				if (rc)
+					DSI_ERR("Fail to add timing params\n");
+			}
+		}
+		if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK))
+			return rc;
+	}
+
+	if (mode->dsi_mode_flags & DSI_MODE_FLAG_DYN_CLK) {
 		if (display->panel->panel_mode == DSI_OP_VIDEO_MODE) {
 			rc = dsi_display_dynamic_clk_switch_vid(display, mode);
 			if (rc)
@@ -4939,6 +4994,7 @@ static int dsi_display_bind(struct device *dev,
 		}
 	}
 
+	dsi_display_update_byte_intf_div(display);
 	rc = dsi_display_mipi_host_init(display);
 	if (rc) {
 		DSI_ERR("[%s] failed to initialize mipi host, rc=%d\n",
@@ -5872,6 +5928,53 @@ int dsi_display_get_mode_count(struct dsi_display *display,
 	return 0;
 }
 
+void dsi_display_adjust_mode_timing(
+			struct dsi_dyn_clk_caps *dyn_clk_caps,
+			struct dsi_display_mode *dsi_mode,
+			int lanes, int bpp)
+{
+	u64 new_htotal, new_vtotal, htotal, vtotal, old_htotal, div;
+
+	if (!dyn_clk_caps->maintain_const_fps)
+		return;
+	/*
+	 * When there is a dynamic clock switch, there is small change
+	 * in FPS. To compensate for this difference in FPS, hfp or vfp
+	 * is adjusted. It has been assumed that the refined porch values
+	 * are supported by the panel. This logic can be enhanced further
+	 * in future by taking min/max porches supported by the panel.
+	 */
+	switch (dyn_clk_caps->type) {
+	case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP:
+		vtotal = DSI_V_TOTAL(&dsi_mode->timing);
+		old_htotal = dsi_h_total_dce(&dsi_mode->timing);
+		new_htotal = dsi_mode->timing.clk_rate_hz * lanes;
+		div = bpp * vtotal * dsi_mode->timing.refresh_rate;
+		do_div(new_htotal, div);
+		if (old_htotal > new_htotal)
+			dsi_mode->timing.h_front_porch -=
+					(old_htotal - new_htotal);
+		else
+			dsi_mode->timing.h_front_porch +=
+					(new_htotal - old_htotal);
+		break;
+
+	case DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP:
+		htotal = dsi_h_total_dce(&dsi_mode->timing);
+		new_vtotal = dsi_mode->timing.clk_rate_hz * lanes;
+		div = bpp * htotal * dsi_mode->timing.refresh_rate;
+		do_div(new_vtotal, div);
+		dsi_mode->timing.v_front_porch = new_vtotal -
+				dsi_mode->timing.v_back_porch -
+				dsi_mode->timing.v_sync_width -
+				dsi_mode->timing.v_active;
+		break;
+
+	default:
+		break;
+	}
+}
+
 static void _dsi_display_populate_bit_clks(struct dsi_display *display,
 					   int start, int end, u32 *mode_idx)
 {
@@ -5911,6 +6014,9 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display,
 		 * be based on user or device tree preferrence.
 		 */
 		src->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[0];
+
+		dsi_display_adjust_mode_timing(dyn_clk_caps, src, lanes, bpp);
+
 		src->pixel_clk_khz =
 			div_u64(src->timing.clk_rate_hz * lanes, bpp);
 		src->pixel_clk_khz /= 1000;
@@ -5930,6 +6036,10 @@ static void _dsi_display_populate_bit_clks(struct dsi_display *display,
 			}
 			memcpy(dst, src, sizeof(struct dsi_display_mode));
 			dst->timing.clk_rate_hz = dyn_clk_caps->bit_clk_list[i];
+
+			dsi_display_adjust_mode_timing(dyn_clk_caps, dst, lanes,
+									bpp);
+
 			dst->pixel_clk_khz =
 				div_u64(dst->timing.clk_rate_hz * lanes, bpp);
 			dst->pixel_clk_khz /= 1000;
@@ -6224,13 +6334,28 @@ int dsi_display_find_mode(struct dsi_display *display,
 	return rc;
 }
 
+static inline bool dsi_display_mode_switch_dfps(struct dsi_display_mode *cur,
+						struct dsi_display_mode *adj)
+{
+	/*
+	 * If there is a change in the hfp or vfp of the current and adjoining
+	 * mode,then either it is a dfps mode switch or dynamic clk change with
+	 * constant fps.
+	 */
+	if ((cur->timing.h_front_porch != adj->timing.h_front_porch) ||
+		(cur->timing.v_front_porch != adj->timing.v_front_porch))
+		return true;
+	else
+		return false;
+}
+
 /**
  * dsi_display_validate_mode_change() - Validate mode change case.
  * @display:     DSI display handle.
  * @cur_mode:    Current mode.
  * @adj_mode:    Mode to be set.
  *               MSM_MODE_FLAG_SEAMLESS_VRR flag is set if there
- *               is change in fps but vactive and hactive are same.
+ *               is change in hfp or vfp but vactive and hactive are same.
  *               DSI_MODE_FLAG_DYN_CLK flag is set if there
  *               is change in clk but vactive and hactive are same.
  * Return: error code.
@@ -6254,14 +6379,15 @@ int dsi_display_validate_mode_change(struct dsi_display *display,
 	}
 
 	mutex_lock(&display->display_lock);
-
+	dyn_clk_caps = &(display->panel->dyn_clk_caps);
 	if ((cur_mode->timing.v_active == adj_mode->timing.v_active) &&
-		(cur_mode->timing.h_active == adj_mode->timing.h_active)) {
-		/* dfps change use case */
-		if (cur_mode->timing.refresh_rate !=
-		    adj_mode->timing.refresh_rate) {
+		(cur_mode->timing.h_active == adj_mode->timing.h_active) &&
+		(cur_mode->panel_mode == adj_mode->panel_mode)) {
+		/* dfps and dynamic clock with const fps use case */
+		if (dsi_display_mode_switch_dfps(cur_mode, adj_mode)) {
 			dsi_panel_get_dfps_caps(display->panel, &dfps_caps);
-			if (dfps_caps.dfps_support) {
+			if (dfps_caps.dfps_support ||
+				dyn_clk_caps->maintain_const_fps) {
 				DSI_DEBUG("Mode switch is seamless variable refresh\n");
 				adj_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR;
 				SDE_EVT32(cur_mode->timing.refresh_rate,
@@ -6273,10 +6399,11 @@ int dsi_display_validate_mode_change(struct dsi_display *display,
 
 		/* dynamic clk change use case */
 		if (cur_mode->pixel_clk_khz != adj_mode->pixel_clk_khz) {
-			dyn_clk_caps = &(display->panel->dyn_clk_caps);
 			if (dyn_clk_caps->dyn_clk_support) {
 				DSI_DEBUG("dynamic clk change detected\n");
-				if (adj_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) {
+				if ((adj_mode->dsi_mode_flags &
+					DSI_MODE_FLAG_VRR) &&
+					(!dyn_clk_caps->maintain_const_fps)) {
 					DSI_ERR("dfps and dyn clk not supported in same commit\n");
 					rc = -ENOTSUPP;
 					goto error;
@@ -6794,12 +6921,14 @@ int dsi_display_prepare(struct dsi_display *display)
 			goto error;
 		}
 
-		/* update dsi ctrl for new mode */
-		rc = dsi_display_pre_switch(display);
-		if (rc)
-			DSI_ERR("[%s] panel pre-prepare-res-switch failed, rc=%d\n",
+		if (!display->is_cont_splash_enabled) {
+			/* update dsi ctrl for new mode */
+			rc = dsi_display_pre_switch(display);
+			if (rc)
+				DSI_ERR("[%s] panel pre-switch failed, rc=%d\n",
 					display->name, rc);
-		goto error;
+			goto error;
+		}
 	}
 
 	if (!(mode->dsi_mode_flags & DSI_MODE_FLAG_POMS) &&

+ 8 - 10
msm/dsi/dsi_drm.c

@@ -253,6 +253,7 @@ static void dsi_bridge_enable(struct drm_bridge *bridge)
 static void dsi_bridge_disable(struct drm_bridge *bridge)
 {
 	int rc = 0;
+	int private_flags;
 	struct dsi_display *display;
 	struct dsi_bridge *c_bridge = to_dsi_bridge(bridge);
 
@@ -261,18 +262,14 @@ static void dsi_bridge_disable(struct drm_bridge *bridge)
 		return;
 	}
 	display = c_bridge->display;
+	private_flags =
+		bridge->encoder->crtc->state->adjusted_mode.private_flags;
 
 	if (display && display->drm_conn) {
-		if (bridge->encoder->crtc->state->adjusted_mode.private_flags &
-			MSM_MODE_FLAG_SEAMLESS_POMS) {
-			display->poms_pending = true;
-			/* Disable ESD thread, during panel mode switch */
-			sde_connector_schedule_status_work(display->drm_conn,
-				false);
-		} else {
-			display->poms_pending = false;
-			sde_connector_helper_bridge_disable(display->drm_conn);
-		}
+		display->poms_pending =
+			private_flags & MSM_MODE_FLAG_SEAMLESS_POMS;
+
+		sde_connector_helper_bridge_disable(display->drm_conn);
 	}
 
 	rc = dsi_display_pre_disable(c_bridge->display);
@@ -426,6 +423,7 @@ static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge,
 	/* Reject seamless transition when active changed */
 	if (crtc_state->active_changed &&
 		((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_DYN_CLK))) {
 		DSI_ERR("seamless upon active changed 0x%x %d\n",
 			dsi_mode.dsi_mode_flags, crtc_state->active_changed);

+ 22 - 1
msm/dsi/dsi_panel.c

@@ -1175,6 +1175,7 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)
 	struct dsi_dyn_clk_caps *dyn_clk_caps = &panel->dyn_clk_caps;
 	struct dsi_parser_utils *utils = &panel->utils;
 	const char *name = panel->name;
+	const char *type;
 
 	supported = utils->read_bool(utils->data, "qcom,dsi-dyn-clk-enable");
 
@@ -1207,6 +1208,24 @@ static int dsi_panel_parse_dyn_clk_caps(struct dsi_panel *panel)
 
 	dyn_clk_caps->dyn_clk_support = true;
 
+	type = utils->get_property(utils->data,
+		"qcom,dsi-dyn-clk-type", NULL);
+	if (!type) {
+		dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY;
+		dyn_clk_caps->maintain_const_fps = false;
+		return 0;
+	}
+	if (!strcmp(type, "constant-fps-adjust-hfp")) {
+		dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_HFP;
+		dyn_clk_caps->maintain_const_fps = true;
+	} else if (!strcmp(type, "constant-fps-adjust-vfp")) {
+		dyn_clk_caps->type = DSI_DYN_CLK_TYPE_CONST_FPS_ADJUST_VFP;
+		dyn_clk_caps->maintain_const_fps = true;
+	} else {
+		dyn_clk_caps->type = DSI_DYN_CLK_TYPE_LEGACY;
+		dyn_clk_caps->maintain_const_fps = false;
+	}
+	DSI_DEBUG("Dynamic clock type is [%s]\n", type);
 	return 0;
 }
 
@@ -3704,9 +3723,11 @@ int dsi_panel_get_mode(struct dsi_panel *panel,
 		if (panel->panel_mode_switch_enabled) {
 			rc = dsi_panel_parse_panel_mode_caps(mode, utils);
 			if (rc) {
-				DSI_ERR("PMS: failed to parse panel mode\n");
 				rc = 0;
 				mode->panel_mode = panel->panel_mode;
+				DSI_INFO(
+				"POMS: panel mode isn't specified in timing[%d]\n",
+				child_idx);
 			}
 		} else {
 			mode->panel_mode = panel->panel_mode;

+ 2 - 0
msm/dsi/dsi_panel.h

@@ -82,6 +82,8 @@ struct dsi_dyn_clk_caps {
 	bool dyn_clk_support;
 	u32 *bit_clk_list;
 	u32 bit_clk_list_len;
+	enum dsi_dyn_clk_feature_type type;
+	bool maintain_const_fps;
 };
 
 struct dsi_pinctrl_info {

+ 6 - 3
msm/dsi/dsi_parser.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/delay.h>
@@ -239,15 +239,18 @@ static bool dsi_parser_parse_prop(struct device *dev,
 {
 	bool found = false;
 	char *out = strsep(&buf, "=");
+	size_t buf_len;
 
 	if (!out || !buf)
 		goto end;
 
-	prop->raw = devm_kzalloc(dev, strlen(buf) + 1, GFP_KERNEL);
+	buf_len = strlen(buf);
+
+	prop->raw = devm_kzalloc(dev, buf_len + 1, GFP_KERNEL);
 	if (!prop->raw)
 		goto end;
 
-	strlcpy(prop->raw, buf, strlen(buf) + 1);
+	strlcpy(prop->raw, buf, buf_len + 1);
 
 	found = true;
 

+ 5 - 0
msm/dsi/dsi_phy.c

@@ -111,6 +111,11 @@ static const struct of_device_id msm_dsi_phy_of_match[] = {
 	{}
 };
 
+int dsi_phy_get_version(struct msm_dsi_phy *phy)
+{
+	return phy->ver_info->version;
+}
+
 static int dsi_phy_regmap_init(struct platform_device *pdev,
 			       struct msm_dsi_phy *phy)
 {

+ 8 - 0
msm/dsi/dsi_phy.h

@@ -125,6 +125,14 @@ struct msm_dsi_phy *dsi_phy_get(struct device_node *of_node);
  */
 void dsi_phy_put(struct msm_dsi_phy *dsi_phy);
 
+/**
+ * dsi_phy_get_version() - returns dsi phy version
+ * @dsi_phy:              DSI PHY handle.
+ *
+ * Return: phy version
+ */
+int dsi_phy_get_version(struct msm_dsi_phy *phy);
+
 /**
  * dsi_phy_drv_init() - initialize dsi phy driver
  * @dsi_phy:         DSI PHY handle.

+ 336 - 1
msm/dsi/dsi_phy_hw_v2_0.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/math64.h>
@@ -64,6 +64,83 @@
 #define DSIPHY_PLL_CLKBUFLR_EN                  0x041C
 #define DSIPHY_PLL_PLL_BANDGAP                  0x0508
 
+/* dynamic refresh control registers */
+#define DSI_DYN_REFRESH_CTRL			0x000
+#define DSI_DYN_REFRESH_PIPE_DELAY		0x004
+#define DSI_DYN_REFRESH_PIPE_DELAY2		0x008
+#define DSI_DYN_REFRESH_PLL_DELAY		0x00C
+#define DSI_DYN_REFRESH_STATUS			0x010
+#define DSI_DYN_REFRESH_PLL_CTRL0		0x014
+#define DSI_DYN_REFRESH_PLL_CTRL1		0x018
+#define DSI_DYN_REFRESH_PLL_CTRL2		0x01C
+#define DSI_DYN_REFRESH_PLL_CTRL3		0x020
+#define DSI_DYN_REFRESH_PLL_CTRL4		0x024
+#define DSI_DYN_REFRESH_PLL_CTRL5		0x028
+#define DSI_DYN_REFRESH_PLL_CTRL6		0x02C
+#define DSI_DYN_REFRESH_PLL_CTRL7		0x030
+#define DSI_DYN_REFRESH_PLL_CTRL8		0x034
+#define DSI_DYN_REFRESH_PLL_CTRL9		0x038
+#define DSI_DYN_REFRESH_PLL_CTRL10		0x03C
+#define DSI_DYN_REFRESH_PLL_CTRL11		0x040
+#define DSI_DYN_REFRESH_PLL_CTRL12		0x044
+#define DSI_DYN_REFRESH_PLL_CTRL13		0x048
+#define DSI_DYN_REFRESH_PLL_CTRL14		0x04C
+#define DSI_DYN_REFRESH_PLL_CTRL15		0x050
+#define DSI_DYN_REFRESH_PLL_CTRL16		0x054
+#define DSI_DYN_REFRESH_PLL_CTRL17		0x058
+#define DSI_DYN_REFRESH_PLL_CTRL18		0x05C
+#define DSI_DYN_REFRESH_PLL_CTRL19		0x060
+#define DSI_DYN_REFRESH_PLL_CTRL20		0x064
+#define DSI_DYN_REFRESH_PLL_CTRL21		0x068
+#define DSI_DYN_REFRESH_PLL_CTRL22		0x06C
+#define DSI_DYN_REFRESH_PLL_CTRL23		0x070
+#define DSI_DYN_REFRESH_PLL_CTRL24		0x074
+#define DSI_DYN_REFRESH_PLL_CTRL25		0x078
+#define DSI_DYN_REFRESH_PLL_CTRL26		0x07C
+#define DSI_DYN_REFRESH_PLL_CTRL27		0x080
+#define DSI_DYN_REFRESH_PLL_CTRL28		0x084
+#define DSI_DYN_REFRESH_PLL_CTRL29		0x088
+#define DSI_DYN_REFRESH_PLL_CTRL30		0x08C
+#define DSI_DYN_REFRESH_PLL_CTRL31		0x090
+#define DSI_DYN_REFRESH_PLL_UPPER_ADDR		0x094
+#define DSI_DYN_REFRESH_PLL_UPPER_ADDR2		0x098
+
+#define DSIPHY_DLN0_CFG1			0x0104
+#define DSIPHY_DLN0_TIMING_CTRL_4		0x0118
+#define DSIPHY_DLN0_TIMING_CTRL_5		0x011C
+#define DSIPHY_DLN0_TIMING_CTRL_6		0x0120
+#define DSIPHY_DLN0_TIMING_CTRL_7		0x0124
+#define DSIPHY_DLN0_TIMING_CTRL_8		0x0128
+
+#define DSIPHY_DLN1_CFG1			0x0184
+#define DSIPHY_DLN1_TIMING_CTRL_4		0x0198
+#define DSIPHY_DLN1_TIMING_CTRL_5		0x019C
+#define DSIPHY_DLN1_TIMING_CTRL_6		0x01A0
+#define DSIPHY_DLN1_TIMING_CTRL_7		0x01A4
+#define DSIPHY_DLN1_TIMING_CTRL_8		0x01A8
+
+#define DSIPHY_DLN2_CFG1			0x0204
+#define DSIPHY_DLN2_TIMING_CTRL_4		0x0218
+#define DSIPHY_DLN2_TIMING_CTRL_5		0x021C
+#define DSIPHY_DLN2_TIMING_CTRL_6		0x0220
+#define DSIPHY_DLN2_TIMING_CTRL_7		0x0224
+#define DSIPHY_DLN2_TIMING_CTRL_8		0x0228
+
+#define DSIPHY_DLN3_CFG1			0x0284
+#define DSIPHY_DLN3_TIMING_CTRL_4		0x0298
+#define DSIPHY_DLN3_TIMING_CTRL_5		0x029C
+#define DSIPHY_DLN3_TIMING_CTRL_6		0x02A0
+#define DSIPHY_DLN3_TIMING_CTRL_7		0x02A4
+#define DSIPHY_DLN3_TIMING_CTRL_8		0x02A8
+
+#define DSIPHY_CKLN_CFG1			0x0304
+#define DSIPHY_CKLN_TIMING_CTRL_4		0x0318
+#define DSIPHY_CKLN_TIMING_CTRL_5		0x031C
+#define DSIPHY_CKLN_TIMING_CTRL_6		0x0320
+#define DSIPHY_CKLN_TIMING_CTRL_7		0x0324
+#define DSIPHY_CKLN_TIMING_CTRL_8		0x0328
+
+#define DSIPHY_PLL_RESETSM_CNTRL5		0x043c
 /**
  * regulator_enable() - enable regulators for DSI PHY
  * @phy:      Pointer to DSI PHY hardware object.
@@ -299,3 +376,261 @@ void dsi_phy_hw_v2_0_clamp_ctrl(struct dsi_phy_hw *phy, bool enable)
 		DSI_PHY_DBG(phy, "clamp disabled\n");
 	}
 }
+
+void dsi_phy_hw_v2_0_dyn_refresh_config(struct dsi_phy_hw *phy,
+		struct dsi_phy_cfg *cfg, bool is_master)
+{
+	u32 glbl_tst_cntrl;
+
+	if (is_master) {
+		glbl_tst_cntrl = DSI_R32(phy, DSIPHY_CMN_GLBL_TEST_CTRL);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0,
+				DSIPHY_CMN_GLBL_TEST_CTRL,
+				DSIPHY_PLL_PLL_BANDGAP,
+				glbl_tst_cntrl | BIT(1), 0x1);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1,
+				DSIPHY_PLL_RESETSM_CNTRL5,
+				DSIPHY_PLL_PLL_BANDGAP, 0x0D, 0x03);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2,
+				DSIPHY_PLL_RESETSM_CNTRL5,
+				DSIPHY_CMN_PLL_CNTRL, 0x1D, 0x00);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3,
+				DSIPHY_CMN_CTRL_1, DSIPHY_DLN0_CFG1, 0x20, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4,
+				DSIPHY_DLN1_CFG1, DSIPHY_DLN2_CFG1, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5,
+				DSIPHY_DLN3_CFG1, DSIPHY_CKLN_CFG1, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6,
+				DSIPHY_DLN0_TIMING_CTRL_4,
+				DSIPHY_DLN1_TIMING_CTRL_4,
+				cfg->timing.lane[0][0], cfg->timing.lane[1][0]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7,
+				DSIPHY_DLN2_TIMING_CTRL_4,
+				DSIPHY_DLN3_TIMING_CTRL_4,
+				cfg->timing.lane[2][0], cfg->timing.lane[3][0]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8,
+				DSIPHY_CKLN_TIMING_CTRL_4,
+				DSIPHY_DLN0_TIMING_CTRL_5,
+				cfg->timing.lane[4][0], cfg->timing.lane[0][1]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9,
+				DSIPHY_DLN1_TIMING_CTRL_5,
+				DSIPHY_DLN2_TIMING_CTRL_5,
+				cfg->timing.lane[1][1], cfg->timing.lane[2][1]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL10,
+				DSIPHY_DLN3_TIMING_CTRL_5,
+				DSIPHY_CKLN_TIMING_CTRL_5,
+				cfg->timing.lane[3][1], cfg->timing.lane[4][1]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL11,
+				DSIPHY_DLN0_TIMING_CTRL_6,
+				DSIPHY_DLN1_TIMING_CTRL_6,
+				cfg->timing.lane[0][2], cfg->timing.lane[1][2]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL12,
+				DSIPHY_DLN2_TIMING_CTRL_6,
+				DSIPHY_DLN3_TIMING_CTRL_6,
+				cfg->timing.lane[2][2], cfg->timing.lane[3][2]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL13,
+				DSIPHY_CKLN_TIMING_CTRL_6,
+				DSIPHY_DLN0_TIMING_CTRL_7,
+				cfg->timing.lane[4][2], cfg->timing.lane[0][3]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL14,
+				DSIPHY_DLN1_TIMING_CTRL_7,
+				DSIPHY_DLN2_TIMING_CTRL_7,
+				cfg->timing.lane[1][3], cfg->timing.lane[2][3]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL15,
+				DSIPHY_DLN3_TIMING_CTRL_7,
+				DSIPHY_CKLN_TIMING_CTRL_7,
+				cfg->timing.lane[3][3], cfg->timing.lane[4][3]);
+				DSI_DYN_REF_REG_W(phy->dyn_pll_base,
+				DSI_DYN_REFRESH_PLL_CTRL16,
+				DSIPHY_DLN0_TIMING_CTRL_8,
+				DSIPHY_DLN1_TIMING_CTRL_8,
+				cfg->timing.lane[0][4], cfg->timing.lane[1][4]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL17,
+				DSIPHY_DLN2_TIMING_CTRL_8,
+				DSIPHY_DLN3_TIMING_CTRL_8,
+				cfg->timing.lane[2][4], cfg->timing.lane[3][4]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL18,
+				DSIPHY_CKLN_TIMING_CTRL_8, DSIPHY_CMN_CTRL_1,
+				cfg->timing.lane[4][4], 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL30,
+				DSIPHY_CMN_GLBL_TEST_CTRL,
+				DSIPHY_CMN_GLBL_TEST_CTRL,
+				((glbl_tst_cntrl) & (~BIT(2))),
+				((glbl_tst_cntrl) & (~BIT(2))));
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL31,
+				DSIPHY_CMN_GLBL_TEST_CTRL,
+				DSIPHY_CMN_GLBL_TEST_CTRL,
+				((glbl_tst_cntrl) & (~BIT(2))),
+				((glbl_tst_cntrl) & (~BIT(2))));
+	} else {
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL0,
+				DSIPHY_DLN0_CFG1, DSIPHY_DLN1_CFG1, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL1,
+				DSIPHY_DLN2_CFG1, DSIPHY_DLN3_CFG1, 0x0, 0x0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL2,
+				DSIPHY_CKLN_CFG1, DSIPHY_DLN0_TIMING_CTRL_4,
+				0x0, cfg->timing.lane[0][0]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL3,
+				DSIPHY_DLN1_TIMING_CTRL_4,
+				DSIPHY_DLN2_TIMING_CTRL_4,
+				cfg->timing.lane[1][0], cfg->timing.lane[2][0]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL4,
+				DSIPHY_DLN3_TIMING_CTRL_4,
+				DSIPHY_CKLN_TIMING_CTRL_4,
+				cfg->timing.lane[3][0], cfg->timing.lane[4][0]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL5,
+				DSIPHY_DLN0_TIMING_CTRL_5,
+				DSIPHY_DLN1_TIMING_CTRL_5,
+				cfg->timing.lane[0][1], cfg->timing.lane[1][1]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL6,
+				DSIPHY_DLN2_TIMING_CTRL_5,
+				DSIPHY_DLN3_TIMING_CTRL_5,
+				cfg->timing.lane[2][1], cfg->timing.lane[3][1]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL7,
+				DSIPHY_CKLN_TIMING_CTRL_5,
+				DSIPHY_DLN0_TIMING_CTRL_6,
+				cfg->timing.lane[4][1], cfg->timing.lane[0][2]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL8,
+				DSIPHY_DLN1_TIMING_CTRL_6,
+				DSIPHY_DLN2_TIMING_CTRL_6,
+				cfg->timing.lane[1][2], cfg->timing.lane[2][2]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL9,
+				DSIPHY_DLN3_TIMING_CTRL_6,
+				DSIPHY_CKLN_TIMING_CTRL_6,
+				cfg->timing.lane[3][2], cfg->timing.lane[4][2]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL10,
+				DSIPHY_DLN0_TIMING_CTRL_7,
+				DSIPHY_DLN1_TIMING_CTRL_7,
+				cfg->timing.lane[0][3], cfg->timing.lane[1][3]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL11,
+				DSIPHY_DLN2_TIMING_CTRL_7,
+				DSIPHY_DLN3_TIMING_CTRL_7,
+				cfg->timing.lane[2][3], cfg->timing.lane[3][3]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL12,
+				DSIPHY_CKLN_TIMING_CTRL_7,
+				DSIPHY_DLN0_TIMING_CTRL_8,
+				cfg->timing.lane[4][3], cfg->timing.lane[0][4]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL13,
+				DSIPHY_DLN1_TIMING_CTRL_8,
+				DSIPHY_DLN2_TIMING_CTRL_8,
+				cfg->timing.lane[1][4], cfg->timing.lane[2][4]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL14,
+				DSIPHY_DLN3_TIMING_CTRL_8,
+				DSIPHY_CKLN_TIMING_CTRL_8,
+				cfg->timing.lane[3][4], cfg->timing.lane[4][4]);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL15,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL16,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL17,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL18,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL19,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL20,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL21,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL22,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL23,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL24,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL25,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL26,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL27,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL28,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL29,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL30,
+				0x0110, 0x0110, 0, 0);
+		DSI_DYN_REF_REG_W(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_CTRL31,
+				0x0110, 0x0110, 0, 0);
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_UPPER_ADDR,
+				0x0);
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_UPPER_ADDR2,
+				0x0);
+	}
+
+	wmb(); /* make sure phy timings are updated*/
+}
+
+void dsi_phy_hw_v2_0_dyn_refresh_pipe_delay(struct dsi_phy_hw *phy,
+			struct dsi_dyn_clk_delay *delay)
+{
+	if (!delay)
+		return;
+
+	DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY,
+			delay->pipe_delay);
+	DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PIPE_DELAY2,
+			delay->pipe_delay2);
+	DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_PLL_DELAY,
+			delay->pll_delay);
+}
+
+void dsi_phy_hw_v2_0_dyn_refresh_helper(struct dsi_phy_hw *phy, u32 offset)
+{
+	u32 reg;
+
+	/*
+	 * if no offset is mentioned then this means we want to clear
+	 * the dynamic refresh ctrl register which is the last step
+	 * of dynamic refresh sequence.
+	 */
+	if (!offset) {
+		reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+		reg &= ~(BIT(0) | BIT(8));
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+		wmb(); /* ensure dynamic fps is cleared */
+		return;
+	}
+
+	if (offset & BIT(DYN_REFRESH_INTF_SEL)) {
+		reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+		reg |= BIT(13);
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+	}
+
+	if (offset & BIT(DYN_REFRESH_SWI_CTRL)) {
+		reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+		reg |= BIT(0);
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+	}
+
+	if (offset & BIT(DYN_REFRESH_SW_TRIGGER)) {
+		reg = DSI_GEN_R32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL);
+		reg |= BIT(8);
+		DSI_GEN_W32(phy->dyn_pll_base, DSI_DYN_REFRESH_CTRL, reg);
+		wmb(); /* ensure dynamic fps is triggered */
+	}
+}
+
+int dsi_phy_hw_v2_0_cache_phy_timings(struct dsi_phy_per_lane_cfgs *timings,
+		u32 *dst, u32 size)
+{
+	int i, j, count = 0;
+
+	if (!timings || !dst || !size)
+		return -EINVAL;
+
+	if (size != (DSI_LANE_MAX * DSI_MAX_SETTINGS)) {
+		pr_err("size mis-match\n");
+		return -EINVAL;
+	}
+
+	for (i = DSI_LOGICAL_LANE_0; i < DSI_LANE_MAX; i++) {
+		for (j = 0; j < DSI_MAX_SETTINGS; j++) {
+			dst[count] = timings->lane[i][j];
+			count++;
+		}
+	}
+
+	return 0;
+}

+ 20 - 12
msm/sde/sde_connector.c

@@ -94,8 +94,7 @@ static int sde_backlight_device_update_status(struct backlight_device *bd)
 	if (!bl_lvl && brightness)
 		bl_lvl = 1;
 
-	if (display->panel->bl_config.bl_update ==
-		BL_UPDATE_DELAY_UNTIL_FIRST_FRAME && !c_conn->allow_bl_update) {
+	if (!c_conn->allow_bl_update) {
 		c_conn->unset_bl_level = bl_lvl;
 		return 0;
 	}
@@ -532,9 +531,7 @@ static int _sde_connector_update_bl_scale(struct sde_connector *c_conn)
 
 	bl_config = &dsi_display->panel->bl_config;
 
-	if (dsi_display->panel->bl_config.bl_update ==
-			BL_UPDATE_DELAY_UNTIL_FIRST_FRAME &&
-			!c_conn->allow_bl_update) {
+	if (!c_conn->allow_bl_update) {
 		c_conn->unset_bl_level = bl_config->bl_level;
 		return 0;
 	}
@@ -797,21 +794,29 @@ void sde_connector_helper_bridge_disable(struct drm_connector *connector)
 {
 	int rc;
 	struct sde_connector *c_conn = NULL;
+	struct dsi_display *display;
+	bool poms_pending = false;
 
 	if (!connector)
 		return;
 
-	rc = _sde_connector_update_dirty_properties(connector);
-	if (rc) {
-		SDE_ERROR("conn %d final pre kickoff failed %d\n",
-				connector->base.id, rc);
-		SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR);
+	c_conn = to_sde_connector(connector);
+	if (c_conn->connector_type == DRM_MODE_CONNECTOR_DSI) {
+		display = (struct dsi_display *) c_conn->display;
+		poms_pending = display->poms_pending;
 	}
 
+	if (!poms_pending) {
+		rc = _sde_connector_update_dirty_properties(connector);
+		if (rc) {
+			SDE_ERROR("conn %d final pre kickoff failed %d\n",
+					connector->base.id, rc);
+			SDE_EVT32(connector->base.id, SDE_EVTLOG_ERROR);
+		}
+	}
 	/* Disable ESD thread */
 	sde_connector_schedule_status_work(connector, false);
 
-	c_conn = to_sde_connector(connector);
 	if (c_conn->bl_device) {
 		c_conn->bl_device->props.power = FB_BLANK_POWERDOWN;
 		c_conn->bl_device->props.state |= BL_CORE_FBBLANK;
@@ -2167,6 +2172,7 @@ static void sde_connector_check_status_work(struct work_struct *work)
 {
 	struct sde_connector *conn;
 	int rc = 0;
+	struct device *dev;
 
 	conn = container_of(to_delayed_work(work),
 			struct sde_connector, status_work);
@@ -2176,7 +2182,9 @@ static void sde_connector_check_status_work(struct work_struct *work)
 	}
 
 	mutex_lock(&conn->lock);
-	if (!conn->ops.check_status ||
+	dev = conn->base.dev->dev;
+
+	if (!conn->ops.check_status || dev->power.is_suspended ||
 			(conn->dpms_mode != DRM_MODE_DPMS_ON)) {
 		SDE_DEBUG("dpms mode: %d\n", conn->dpms_mode);
 		mutex_unlock(&conn->lock);