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;