drm/msm/sde: detect ppdone timeouts and issue ctl reset

Add mechanism to detect pingpong done irq timeouts and report
back to CRTC that errors occurred. On reception of a max count
report panel dead event to the CRTC, which currently logs it.
If panic is enabled, ppdone timeout will trigger a register dump
and panic, if panic is not enabled, we try to recover by issuing
a CTL reset before the next kickoff.

CRs-Fixed: 2005394
Change-Id: I375c18da40754b879829df50c28ed56e4775cb38
Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index cc8485b..e9fe5c0 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -1685,6 +1685,19 @@
 	return rc;
 }
 
+int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl)
+{
+	if (!dsi_ctrl)
+		return -EINVAL;
+
+	mutex_lock(&dsi_ctrl->ctrl_lock);
+	dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw);
+	mutex_unlock(&dsi_ctrl->ctrl_lock);
+
+	pr_debug("[DSI_%d]Soft reset complete\n", dsi_ctrl->index);
+	return 0;
+}
+
 /**
  * dsi_ctrl_host_deinit() - De-Initialize DSI host hardware.
  * @dsi_ctrl:        DSI controller handle.
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
index 1df09b4..fc95a9a 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.h
@@ -329,6 +329,21 @@
 int dsi_ctrl_phy_reset_config(struct dsi_ctrl *dsi_ctrl, bool enable);
 
 /**
+ * dsi_ctrl_soft_reset() - perform a soft reset on DSI controller
+ * @dsi_ctrl:         DSI controller handle.
+ *
+ * The video, command and controller engines will be disabled before the
+ * reset is triggered. After, the engines will be re-enabled to the same state
+ * as before the reset.
+ *
+ * If the reset is done while MDP timing engine is turned on, the video
+ * engine should be re-enabled only during the vertical blanking time.
+ *
+ * Return: error code
+ */
+int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl);
+
+/**
  * dsi_ctrl_host_init() - Initialize DSI host hardware.
  * @dsi_ctrl:        DSI controller handle.
  *
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
index 009795a..89c5cda 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl_hw.h
@@ -346,12 +346,12 @@
 	 * soft_reset() - perform a soft reset on DSI controller
 	 * @ctrl:          Pointer to the controller host hardware.
 	 *
-	 * The video, command and controller engines will be disable before the
-	 * reset is triggered. These engines will not be enabled after the reset
-	 * is complete. Caller must re-enable the engines.
+	 * The video, command and controller engines will be disabled before the
+	 * reset is triggered. After, the engines will be re-enabled to the same
+	 * state as before the reset.
 	 *
 	 * If the reset is done while MDP timing engine is turned on, the video
-	 * enigne should be re-enabled only during the vertical blanking time.
+	 * engine should be re-enabled only during the vertical blanking time.
 	 */
 	void (*soft_reset)(struct dsi_ctrl_hw *ctrl);
 
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index e87c3d3..9b2e3a7 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -56,6 +56,30 @@
 	return rc;
 }
 
+int dsi_display_soft_reset(void *display)
+{
+	struct dsi_display *dsi_display;
+	struct dsi_display_ctrl *ctrl;
+	int rc = 0;
+	int i;
+
+	if (!display)
+		return -EINVAL;
+
+	dsi_display = display;
+
+	for (i = 0 ; i < dsi_display->ctrl_count; i++) {
+		ctrl = &dsi_display->ctrl[i];
+		rc = dsi_ctrl_soft_reset(ctrl->ctrl);
+		if (rc) {
+			pr_err("[%s] failed to soft reset host_%d, rc=%d\n",
+					dsi_display->name, i, rc);
+			break;
+		}
+	}
+
+	return rc;
+}
 static ssize_t debugfs_dump_info_read(struct file *file,
 				      char __user *buff,
 				      size_t count,
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 563c525..642ea40 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -391,4 +391,19 @@
 int dsi_dispaly_static_frame(struct dsi_display *display, bool enable);
 
 int dsi_display_set_backlight(void *display, u32 bl_lvl);
+
+/**
+ * dsi_display_soft_reset() - perform a soft reset on DSI controller
+ * @display:         Handle to display
+ *
+ * The video, command and controller engines will be disabled before the
+ * reset is triggered. After, the engines will be re-enabled to the same state
+ * as before the reset.
+ *
+ * If the reset is done while MDP timing engine is turned on, the video
+ * engine should be re-enabled only during the vertical blanking time.
+ *
+ * Return: error code
+ */
+int dsi_display_soft_reset(void *display);
 #endif /* _DSI_DISPLAY_H_ */
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.h b/drivers/gpu/drm/msm/sde/sde_connector.h
index 9580282..665d337 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.h
+++ b/drivers/gpu/drm/msm/sde/sde_connector.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 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
@@ -113,6 +113,13 @@
 	int (*get_info)(struct msm_display_info *info, void *display);
 
 	int (*set_backlight)(void *display, u32 bl_lvl);
+
+	/**
+	 * soft_reset - perform a soft reset on the connector
+	 * @display: Pointer to private display structure
+	 * Return: Zero on success, -ERROR otherwise
+	 */
+	int (*soft_reset)(void *display);
 };
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index 7415cae..d8d6555 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -526,7 +526,8 @@
 			ktime_to_ns(fevent->ts));
 
 	if (fevent->event == SDE_ENCODER_FRAME_EVENT_DONE ||
-			fevent->event == SDE_ENCODER_FRAME_EVENT_ERROR) {
+			(fevent->event & SDE_ENCODER_FRAME_EVENT_ERROR) ||
+			(fevent->event & SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)) {
 
 		if (atomic_read(&sde_crtc->frame_pending) < 1) {
 			/* this should not happen */
@@ -554,6 +555,10 @@
 		SDE_EVT32(DRMID(crtc), fevent->event, 3);
 	}
 
+	if (fevent->event & SDE_ENCODER_FRAME_EVENT_PANEL_DEAD)
+		SDE_ERROR("crtc%d ts:%lld received panel dead event\n",
+				crtc->base.id, ktime_to_ns(fevent->ts));
+
 	spin_lock_irqsave(&sde_crtc->spin_lock, flags);
 	list_add_tail(&fevent->list, &sde_crtc->frame_event_list);
 	spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c
index 90d95f3..fc10792 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.c
@@ -703,6 +703,51 @@
 	return rc;
 }
 
+void sde_encoder_helper_hw_reset(struct sde_encoder_phys *phys_enc)
+{
+	struct sde_encoder_virt *sde_enc;
+	struct sde_connector *sde_con;
+	void *sde_con_disp;
+	struct sde_hw_ctl *ctl;
+	int rc;
+
+	if (!phys_enc) {
+		SDE_ERROR("invalid encoder\n");
+		return;
+	}
+	sde_enc = to_sde_encoder_virt(phys_enc->parent);
+	ctl = phys_enc->hw_ctl;
+
+	if (!ctl || !ctl->ops.reset)
+		return;
+
+	SDE_DEBUG_ENC(sde_enc, "ctl %d reset\n",  ctl->idx);
+	SDE_EVT32(DRMID(phys_enc->parent), ctl->idx);
+
+	if (phys_enc->ops.is_master && phys_enc->ops.is_master(phys_enc) &&
+			phys_enc->connector) {
+		sde_con = to_sde_connector(phys_enc->connector);
+		sde_con_disp = sde_connector_get_display(phys_enc->connector);
+
+		if (sde_con->ops.soft_reset) {
+			rc = sde_con->ops.soft_reset(sde_con_disp);
+			if (rc) {
+				SDE_ERROR_ENC(sde_enc,
+						"connector soft reset failure\n");
+				SDE_DBG_DUMP("panic");
+			}
+		}
+	}
+
+	rc = ctl->ops.reset(ctl);
+	if (rc) {
+		SDE_ERROR_ENC(sde_enc, "ctl %d reset failure\n",  ctl->idx);
+		SDE_DBG_DUMP("panic");
+	}
+
+	phys_enc->enable_state = SDE_ENC_ENABLED;
+}
+
 /**
  * _sde_encoder_kickoff_phys - handle physical encoder kickoff
  *	Iterate through the physical encoders and perform consolidated flush
@@ -766,6 +811,7 @@
 {
 	struct sde_encoder_virt *sde_enc;
 	struct sde_encoder_phys *phys;
+	bool needs_hw_reset = false;
 	unsigned int i;
 
 	if (!drm_enc) {
@@ -780,8 +826,21 @@
 	/* prepare for next kickoff, may include waiting on previous kickoff */
 	for (i = 0; i < sde_enc->num_phys_encs; i++) {
 		phys = sde_enc->phys_encs[i];
-		if (phys && phys->ops.prepare_for_kickoff)
-			phys->ops.prepare_for_kickoff(phys);
+		if (phys) {
+			if (phys->ops.prepare_for_kickoff)
+				phys->ops.prepare_for_kickoff(phys);
+			if (phys->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET)
+				needs_hw_reset = true;
+		}
+	}
+
+	/* if any phys needs reset, reset all phys, in-order */
+	if (needs_hw_reset) {
+		for (i = 0; i < sde_enc->num_phys_encs; i++) {
+			phys = sde_enc->phys_encs[i];
+			if (phys && phys->ops.hw_reset)
+				phys->ops.hw_reset(phys);
+		}
 	}
 }
 
@@ -1216,18 +1275,21 @@
 	priv = drm_enc->dev->dev_private;
 
 	if (!sde_enc->frame_busy_mask[0] || !sde_enc->crtc_frame_event_cb) {
-		SDE_DEBUG("enc%d invalid timeout\n", drm_enc->base.id);
-		SDE_EVT32(DRMID(drm_enc),
-				sde_enc->frame_busy_mask[0], 0);
+		SDE_DEBUG_ENC(sde_enc, "invalid timeout\n");
+		SDE_EVT32(DRMID(drm_enc), sde_enc->frame_busy_mask[0], 0);
 		return;
 	} else if (!atomic_xchg(&sde_enc->frame_done_timeout, 0)) {
-		SDE_ERROR("enc%d invalid timeout\n", drm_enc->base.id);
+		SDE_ERROR_ENC(sde_enc, "invalid timeout\n");
 		SDE_EVT32(DRMID(drm_enc), 0, 1);
 		return;
 	}
 
-	SDE_EVT32(DRMID(drm_enc), 0, 2);
+	SDE_EVT32(DRMID(drm_enc), 2, sde_enc->crtc_frame_event);
+	SDE_ERROR_ENC(sde_enc, "frame done timeout, frame_event %d\n",
+			sde_enc->crtc_frame_event);
+
 	sde_enc->crtc_frame_event_cb(sde_enc->crtc_frame_event_cb_data,
+			sde_enc->crtc_frame_event |
 			SDE_ENCODER_FRAME_EVENT_ERROR);
 }
 
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h
index 82576b4..61435c9 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder.h
@@ -24,8 +24,9 @@
 #include "msm_prop.h"
 #include "sde_hw_mdss.h"
 
-#define SDE_ENCODER_FRAME_EVENT_DONE	BIT(0)
-#define SDE_ENCODER_FRAME_EVENT_ERROR	BIT(1)
+#define SDE_ENCODER_FRAME_EVENT_DONE		BIT(0)
+#define SDE_ENCODER_FRAME_EVENT_ERROR		BIT(1)
+#define SDE_ENCODER_FRAME_EVENT_PANEL_DEAD	BIT(2)
 
 /**
  * Encoder functions and data types
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
index 2ac0a64..0ee0f13 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h
@@ -47,6 +47,22 @@
 	ENC_ROLE_SLAVE
 };
 
+/**
+ * enum sde_enc_enable_state - current enabled state of the physical encoder
+ * @SDE_ENC_DISABLED:	Encoder is disabled
+ * @SDE_ENC_ENABLING:	Encoder transitioning to enabled
+ *			Events bounding transition are encoder type specific
+ * @SDE_ENC_ENABLED:	Encoder is enabled
+ * @SDE_ENC_ERR_NEEDS_HW_RESET:	Encoder is enabled, but requires a hw_reset
+ *				to recover from a previous error
+ */
+enum sde_enc_enable_state {
+	SDE_ENC_DISABLED,
+	SDE_ENC_ENABLING,
+	SDE_ENC_ENABLED,
+	SDE_ENC_ERR_NEEDS_HW_RESET
+};
+
 struct sde_encoder_phys;
 
 /**
@@ -94,6 +110,8 @@
  * @needs_single_flush:		Whether encoder slaves need to be flushed
  * @setup_misr:		Sets up MISR, enable and disables based on sysfs
  * @collect_misr:		Collects MISR data on frame update
+ * @hw_reset:			Issue HW recovery such as CTL reset and clear
+ *				SDE_ENC_ERR_NEEDS_HW_RESET state
  */
 
 struct sde_encoder_phys_ops {
@@ -124,19 +142,7 @@
 			struct sde_misr_params *misr_map);
 	void (*collect_misr)(struct sde_encoder_phys *phys_enc,
 			struct sde_misr_params *misr_map);
-};
-
-/**
- * enum sde_enc_enable_state - current enabled state of the physical encoder
- * @SDE_ENC_DISABLED:	Encoder is disabled
- * @SDE_ENC_ENABLING:	Encoder transitioning to enabled
- *			Events bounding transition are encoder type specific
- * @SDE_ENC_ENABLED:	Encoder is enabled
- */
-enum sde_enc_enable_state {
-	SDE_ENC_DISABLED,
-	SDE_ENC_ENABLING,
-	SDE_ENC_ENABLED
+	void (*hw_reset)(struct sde_encoder_phys *phys_enc);
 };
 
 /**
@@ -239,9 +245,10 @@
  * @pp_rd_ptr_irq_idx:	IRQ signifying panel's frame read pointer
  *			For CMD encoders, VBLANK is driven by the PP RD Done IRQ
  * @pp_tx_done_irq_idx:	IRQ signifying frame transmission to panel complete
- * @irq_cb:	interrupt callback
- * @serialize_wait4pp: serialize wait4pp feature waits for pp_done interrupt
- *                     after ctl_start instead of before next frame kickoff
+ * @irq_cb:		interrupt callback
+ * @serialize_wait4pp:	serialize wait4pp feature waits for pp_done interrupt
+ *			after ctl_start instead of before next frame kickoff
+ * @pp_timeout_report_cnt: number of pingpong done irq timeout errors
  */
 struct sde_encoder_phys_cmd {
 	struct sde_encoder_phys base;
@@ -250,6 +257,7 @@
 	int irq_idx[INTR_IDX_MAX];
 	struct sde_irq_callback irq_cb[INTR_IDX_MAX];
 	bool serialize_wait4pp;
+	int pp_timeout_report_cnt;
 };
 
 /**
@@ -381,6 +389,14 @@
 		atomic_t *cnt,
 		s64 timeout_ms);
 
+/**
+ * sde_encoder_helper_hw_reset - issue ctl hw reset
+ *	This helper function may be optionally specified by physical
+ *	encoders if they require ctl hw reset. If state is currently
+ *	SDE_ENC_ERR_NEEDS_HW_RESET, it is set back to SDE_ENC_ENABLED.
+ * @phys_enc: Pointer to physical encoder structure
+ */
+void sde_encoder_helper_hw_reset(struct sde_encoder_phys *phys_enc);
 
 static inline enum sde_3d_blend_mode sde_encoder_helper_get_3d_blend_mode(
 		struct sde_encoder_phys *phys_enc)
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
index 64c70a2..c3a653b 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c
@@ -31,6 +31,8 @@
 #define to_sde_encoder_phys_cmd(x) \
 	container_of(x, struct sde_encoder_phys_cmd, base)
 
+#define PP_TIMEOUT_MAX_TRIALS	10
+
 /*
  * Tearcheck sync start and continue thresholds are empirically found
  * based on common panels In the future, may want to allow panels to override
@@ -149,6 +151,53 @@
 	return false;
 }
 
+static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
+		struct sde_encoder_phys *phys_enc)
+{
+	struct sde_encoder_phys_cmd *cmd_enc =
+			to_sde_encoder_phys_cmd(phys_enc);
+	u32 frame_event = SDE_ENCODER_FRAME_EVENT_ERROR;
+	bool do_log = false;
+
+	cmd_enc->pp_timeout_report_cnt++;
+	if (cmd_enc->pp_timeout_report_cnt == PP_TIMEOUT_MAX_TRIALS) {
+		frame_event |= SDE_ENCODER_FRAME_EVENT_PANEL_DEAD;
+		do_log = true;
+	} else if (cmd_enc->pp_timeout_report_cnt == 1) {
+		do_log = true;
+	}
+
+	/* to avoid flooding, only log first time, and "dead" time */
+	if (do_log) {
+		SDE_ERROR_CMDENC(cmd_enc,
+				"pp:%d kickoff timed out ctl %d cnt %d koff_cnt %d\n",
+				phys_enc->hw_pp->idx - PINGPONG_0,
+				phys_enc->hw_ctl->idx - CTL_0,
+				cmd_enc->pp_timeout_report_cnt,
+				atomic_read(&phys_enc->pending_kickoff_cnt));
+
+		SDE_EVT32(DRMID(phys_enc->parent),
+				phys_enc->hw_pp->idx - PINGPONG_0,
+				0xbad, cmd_enc->pp_timeout_report_cnt,
+				atomic_read(&phys_enc->pending_kickoff_cnt));
+
+		SDE_DBG_DUMP("sde", "dsi0_ctrl", "dsi0_phy", "dsi1_ctrl",
+				"dsi1_phy", "vbif", "vbif_nrt", "dbg_bus",
+				"vbif_dbg_bus", "panic");
+	}
+
+	atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
+
+	/* request a ctl reset before the next kickoff */
+	phys_enc->enable_state = SDE_ENC_ERR_NEEDS_HW_RESET;
+
+	if (phys_enc->parent_ops.handle_frame_done)
+		phys_enc->parent_ops.handle_frame_done(
+				phys_enc->parent, phys_enc, frame_event);
+
+	return -ETIMEDOUT;
+}
+
 static int _sde_encoder_phys_cmd_wait_for_idle(
 		struct sde_encoder_phys *phys_enc)
 {
@@ -180,32 +229,32 @@
 			&phys_enc->pending_kickoff_cnt,
 			KICKOFF_TIMEOUT_MS);
 	if (ret <= 0) {
+		/* read and clear interrupt */
 		irq_status = sde_core_irq_read(phys_enc->sde_kms,
 				INTR_IDX_PINGPONG, true);
 		if (irq_status) {
+			unsigned long flags;
 			SDE_EVT32(DRMID(phys_enc->parent),
 					phys_enc->hw_pp->idx - PINGPONG_0);
 			SDE_DEBUG_CMDENC(cmd_enc,
 					"pp:%d done but irq not triggered\n",
 					phys_enc->hw_pp->idx - PINGPONG_0);
+			local_irq_save(flags);
 			sde_encoder_phys_cmd_pp_tx_done_irq(cmd_enc,
 					INTR_IDX_PINGPONG);
+			local_irq_restore(flags);
 			ret = 0;
 		} else {
-			SDE_EVT32(DRMID(phys_enc->parent),
-					phys_enc->hw_pp->idx - PINGPONG_0);
-			SDE_ERROR_CMDENC(cmd_enc, "pp:%d kickoff timed out\n",
-					phys_enc->hw_pp->idx - PINGPONG_0);
-			if (phys_enc->parent_ops.handle_frame_done)
-				phys_enc->parent_ops.handle_frame_done(
-						phys_enc->parent, phys_enc,
-						SDE_ENCODER_FRAME_EVENT_ERROR);
-			ret = -ETIMEDOUT;
+			ret = _sde_encoder_phys_cmd_handle_ppdone_timeout(
+					phys_enc);
 		}
 	} else {
 		ret = 0;
 	}
 
+	if (!ret)
+		cmd_enc->pp_timeout_report_cnt = 0;
+
 	return ret;
 }
 
@@ -666,6 +715,7 @@
 	ops->prepare_for_kickoff = sde_encoder_phys_cmd_prepare_for_kickoff;
 	ops->trigger_start = sde_encoder_helper_trigger_start;
 	ops->needs_single_flush = sde_encoder_phys_cmd_needs_single_flush;
+	ops->hw_reset = sde_encoder_helper_hw_reset;
 }
 
 struct sde_encoder_phys *sde_encoder_phys_cmd_init(
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
index 76e6d47..3d1556a 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -784,6 +784,7 @@
 	ops->needs_single_flush = sde_encoder_phys_vid_needs_single_flush;
 	ops->setup_misr = sde_encoder_phys_vid_setup_misr;
 	ops->collect_misr = sde_encoder_phys_vid_collect_misr;
+	ops->hw_reset = sde_encoder_helper_hw_reset;
 }
 
 struct sde_encoder_phys *sde_encoder_phys_vid_init(
diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
index 3aa4e16..97ec9a9 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_wb.c
@@ -989,6 +989,7 @@
 	ops->prepare_for_kickoff = sde_encoder_phys_wb_prepare_for_kickoff;
 	ops->handle_post_kickoff = sde_encoder_phys_wb_handle_post_kickoff;
 	ops->trigger_start = sde_encoder_helper_trigger_start;
+	ops->hw_reset = sde_encoder_helper_hw_reset;
 }
 
 /**
diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c
index 3b998fb..0ef0ce5 100644
--- a/drivers/gpu/drm/msm/sde/sde_kms.c
+++ b/drivers/gpu/drm/msm/sde/sde_kms.c
@@ -558,7 +558,8 @@
 		.get_modes =  dsi_connector_get_modes,
 		.mode_valid = dsi_conn_mode_valid,
 		.get_info =   dsi_display_get_info,
-		.set_backlight = dsi_display_set_backlight
+		.set_backlight = dsi_display_set_backlight,
+		.soft_reset   = dsi_display_soft_reset
 	};
 	static const struct sde_connector_ops wb_ops = {
 		.post_init =    sde_wb_connector_post_init,
@@ -566,6 +567,7 @@
 		.get_modes =    sde_wb_connector_get_modes,
 		.set_property = sde_wb_connector_set_property,
 		.get_info =     sde_wb_get_info,
+		.soft_reset =   NULL
 	};
 	struct msm_display_info info;
 	struct drm_encoder *encoder;