drm/msm/sde: wait for ctl reset before kickoff in video mode
Need to check for and wait for the unlikely event of a hardware
initiated CTL reset in video mode. Need to wait for the reset to
complete before initiating the next kickoff. If CTL reset fails
to complete, initiate a panic.
CRs-Fixed: 2005394
Change-Id: I27dfaf602a9c2ba2faacabe723a9593a39ed891e
Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org>
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 3d1556a..e00b4d2 100644
--- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
+++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_vid.c
@@ -653,6 +653,35 @@
return ret;
}
+static void sde_encoder_phys_vid_prepare_for_kickoff(
+ struct sde_encoder_phys *phys_enc)
+{
+ struct sde_encoder_phys_vid *vid_enc;
+ struct sde_hw_ctl *ctl;
+ int rc;
+
+ if (!phys_enc) {
+ SDE_ERROR("invalid encoder\n");
+ return;
+ }
+ vid_enc = to_sde_encoder_phys_vid(phys_enc);
+
+ ctl = phys_enc->hw_ctl;
+ if (!ctl || !ctl->ops.wait_reset_status)
+ return;
+
+ /*
+ * hw supports hardware initiated ctl reset, so before we kickoff a new
+ * frame, need to check and wait for hw initiated ctl reset completion
+ */
+ rc = ctl->ops.wait_reset_status(ctl);
+ if (rc) {
+ SDE_ERROR_VIDENC(vid_enc, "ctl %d reset failure: %d\n",
+ ctl->idx, rc);
+ SDE_DBG_DUMP("panic");
+ }
+}
+
static void sde_encoder_phys_vid_disable(struct sde_encoder_phys *phys_enc)
{
struct msm_drm_private *priv;
@@ -780,6 +809,7 @@
ops->get_hw_resources = sde_encoder_phys_vid_get_hw_resources;
ops->control_vblank_irq = sde_encoder_phys_vid_control_vblank_irq;
ops->wait_for_commit_done = sde_encoder_phys_vid_wait_for_commit_done;
+ ops->prepare_for_kickoff = sde_encoder_phys_vid_prepare_for_kickoff;
ops->handle_post_kickoff = sde_encoder_phys_vid_handle_post_kickoff;
ops->needs_single_flush = sde_encoder_phys_vid_needs_single_flush;
ops->setup_misr = sde_encoder_phys_vid_setup_misr;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
index d237c4db..0e756b4 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.c
@@ -251,23 +251,58 @@
return 0;
}
+static u32 sde_hw_ctl_poll_reset_status(struct sde_hw_ctl *ctx, u32 count)
+{
+ struct sde_hw_blk_reg_map *c = &ctx->hw;
+ u32 status;
+
+ /* protect to do at least one iteration */
+ if (!count)
+ count = 1;
+
+ /*
+ * it takes around 30us to have mdp finish resetting its ctl path
+ * poll every 50us so that reset should be completed at 1st poll
+ */
+ do {
+ status = SDE_REG_READ(c, CTL_SW_RESET);
+ status &= 0x01;
+ if (status)
+ usleep_range(20, 50);
+ } while (status && --count > 0);
+
+ return status;
+}
+
static int sde_hw_ctl_reset_control(struct sde_hw_ctl *ctx)
{
struct sde_hw_blk_reg_map *c = &ctx->hw;
- int count = SDE_REG_RESET_TIMEOUT_COUNT;
- int reset;
+ pr_debug("issuing hw ctl reset for ctl:%d\n", ctx->idx);
SDE_REG_WRITE(c, CTL_SW_RESET, 0x1);
+ if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_COUNT))
+ return -EINVAL;
- for (; count > 0; count--) {
- /* insert small delay to avoid spinning the cpu while waiting */
- usleep_range(20, 50);
- reset = SDE_REG_READ(c, CTL_SW_RESET);
- if (reset == 0)
- return 0;
+ return 0;
+}
+
+static int sde_hw_ctl_wait_reset_status(struct sde_hw_ctl *ctx)
+{
+ struct sde_hw_blk_reg_map *c = &ctx->hw;
+ u32 status;
+
+ status = SDE_REG_READ(c, CTL_SW_RESET);
+ status &= 0x01;
+ if (!status)
+ return 0;
+
+ pr_debug("hw ctl reset is set for ctl:%d\n", ctx->idx);
+ if (sde_hw_ctl_poll_reset_status(ctx, SDE_REG_RESET_TIMEOUT_COUNT)) {
+ pr_err("hw recovery is not complete for ctl:%d\n", ctx->idx);
+ return -EINVAL;
}
- return -EINVAL;
+ return 0;
}
static void sde_hw_ctl_clear_all_blendstages(struct sde_hw_ctl *ctx)
@@ -457,6 +492,7 @@
ops->trigger_start = sde_hw_ctl_trigger_start;
ops->setup_intf_cfg = sde_hw_ctl_intf_cfg;
ops->reset = sde_hw_ctl_reset_control;
+ ops->wait_reset_status = sde_hw_ctl_wait_reset_status;
ops->clear_all_blendstages = sde_hw_ctl_clear_all_blendstages;
ops->setup_blendstage = sde_hw_ctl_setup_blendstage;
ops->get_bitmask_sspp = sde_hw_ctl_get_bitmask_sspp;
diff --git a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
index 670a03d..4d1170e 100644
--- a/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
+++ b/drivers/gpu/drm/msm/sde/sde_hw_ctl.h
@@ -107,6 +107,17 @@
int (*reset)(struct sde_hw_ctl *c);
+ /*
+ * wait_reset_status - checks ctl reset status
+ * @ctx : ctl path ctx pointer
+ *
+ * This function checks the ctl reset status bit.
+ * If the reset bit is set, it keeps polling the status till the hw
+ * reset is complete.
+ * Returns: 0 on success or -error if reset incomplete within interval
+ */
+ int (*wait_reset_status)(struct sde_hw_ctl *ctx);
+
uint32_t (*get_bitmask_sspp)(struct sde_hw_ctl *ctx,
enum sde_sspp blk);