Browse Source

disp: msm: sde: wait for a vsync on suspend

The current scenario is as follows commit N with autorefresh
enabled and frame starts processing. On suspend commit N+1,
during virt_disable software resets CTL path after autorefresh
config is disabled. Since in hardware frame is still processing
sw reset is causing fifo underflow. This change waits for
vsync so that current autorefresh frame transaction completes
before issuing a CTL_SW_RESET.

Change-Id: Ib0662837e54b14cea6ab835a1093a2f048c473be
Signed-off-by: Mahadevan <[email protected]>
Signed-off-by: Akash Gajjar <[email protected]>
Mahadevan 2 years ago
parent
commit
497405aaf1
3 changed files with 40 additions and 1 deletions
  1. 24 1
      msm/sde/sde_encoder.c
  2. 14 0
      msm/sde/sde_hw_intf.c
  3. 2 0
      msm/sde/sde_hw_intf.h

+ 24 - 1
msm/sde/sde_encoder.c

@@ -1619,6 +1619,27 @@ static void sde_encoder_control_te(struct sde_encoder_virt *sde_enc, bool enable
 	}
 }
 
+static void _sde_encoder_wait_for_vsync_on_autorefresh_busy(struct sde_encoder_phys *phys_enc)
+{
+	u32 autorefresh_status;
+	int ret = 0;
+
+	if (!phys_enc || !phys_enc->hw_intf || !phys_enc->hw_intf->ops.get_autorefresh_status) {
+		SDE_ERROR("invalid params\n");
+		return;
+	}
+
+	autorefresh_status = phys_enc->hw_intf->ops.get_autorefresh_status(phys_enc->hw_intf);
+	if (autorefresh_status) {
+		ret = sde_encoder_wait_for_event(phys_enc->parent, MSM_ENC_VBLANK);
+		if (ret) {
+			autorefresh_status = phys_enc->hw_intf->ops.get_autorefresh_status(
+					phys_enc->hw_intf);
+			SDE_ERROR("wait for vblank timed out, autorefresh_status:%d\n",
+					autorefresh_status);
+		}
+	}
+}
 
 int sde_encoder_helper_switch_vsync(struct drm_encoder *drm_enc,
 	 bool watchdog_te)
@@ -3694,8 +3715,10 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
 		for (i = 0; i < sde_enc->num_phys_encs; i++) {
 			struct sde_encoder_phys *phys = sde_enc->phys_encs[i];
 
-			if (phys && phys->ops.disable_autorefresh)
+			if (phys && phys->ops.disable_autorefresh) {
 				phys->ops.disable_autorefresh(phys);
+				_sde_encoder_wait_for_vsync_on_autorefresh_busy(phys);
+			}
 		}
 
 		/* wait for idle */

+ 14 - 0
msm/sde/sde_hw_intf.c

@@ -102,6 +102,7 @@
 #define INTF_TEAR_LINE_COUNT            0x2B0
 #define INTF_TEAR_AUTOREFRESH_CONFIG    0x2B4
 #define INTF_TEAR_TEAR_DETECT_CTRL      0x2B8
+#define INTF_TEAR_AUTOREFRESH_STATUS    0x2C0
 #define INTF_TEAR_PROG_FETCH_START      0x2C4
 #define INTF_TEAR_DSI_DMA_SCHD_CTRL0    0x2C8
 #define INTF_TEAR_DSI_DMA_SCHD_CTRL1    0x2CC
@@ -827,6 +828,17 @@ static int sde_hw_intf_get_autorefresh_config(struct sde_hw_intf *intf,
 	return 0;
 }
 
+static u32 sde_hw_intf_get_autorefresh_status(struct sde_hw_intf *intf)
+{
+	struct sde_hw_blk_reg_map *c;
+	u32 val;
+
+	c = &intf->hw;
+	val = SDE_REG_READ(c, INTF_TEAR_AUTOREFRESH_STATUS);
+
+	return val;
+}
+
 static int sde_hw_intf_poll_timeout_wr_ptr(struct sde_hw_intf *intf,
 		u32 timeout_us)
 {
@@ -1095,6 +1107,8 @@ static void _setup_intf_ops(struct sde_hw_intf_ops *ops,
 		ops->get_vsync_info = sde_hw_intf_get_vsync_info;
 		ops->setup_autorefresh = sde_hw_intf_setup_autorefresh_config;
 		ops->get_autorefresh = sde_hw_intf_get_autorefresh_config;
+		ops->get_autorefresh_status =
+			sde_hw_intf_get_autorefresh_status;
 		ops->poll_timeout_wr_ptr = sde_hw_intf_poll_timeout_wr_ptr;
 		ops->vsync_sel = sde_hw_intf_vsync_sel;
 		ops->check_and_reset_tearcheck = sde_hw_intf_v1_check_and_reset_tearcheck;

+ 2 - 0
msm/sde/sde_hw_intf.h

@@ -104,6 +104,7 @@ struct intf_wd_jitter_params {
  * @get_wd_ltj_status: Read WD long term jitter status.
  * @bind_pingpong_blk: enable/disable the connection with pingpong which will
  *                     feed pixels to this interface
+ * @get_autorefresh_status: Check the status of autorefresh is busy or idle
  */
 struct sde_hw_intf_ops {
 	void (*setup_timing_gen)(struct sde_hw_intf *intf,
@@ -147,6 +148,7 @@ struct sde_hw_intf_ops {
 	void (*bind_pingpong_blk)(struct sde_hw_intf *intf,
 			bool enable,
 			const enum sde_pingpong pp);
+	u32 (*get_autorefresh_status)(struct sde_hw_intf *intf);
 
 	/**
 	 * enables vysnc generation and sets up init value of