diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 1219b82cdc03..684f29a83547 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -1209,6 +1209,7 @@ int mdss_mdp_video_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, int mdss_mdp_cmd_reconfigure_splash_done(struct mdss_mdp_ctl *ctl, bool handoff); int mdss_mdp_ctl_splash_finish(struct mdss_mdp_ctl *ctl, bool handoff); +void mdss_mdp_check_ctl_reset_status(struct mdss_mdp_ctl *ctl); int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl); int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl, struct mdss_panel_data *pdata); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 1d24101b75d3..61d8f1999eef 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -3841,6 +3841,54 @@ static void mdss_mdp_pipe_reset(struct mdss_mdp_mixer *mixer, bool is_recovery) } } +static u32 mdss_mdp_poll_ctl_reset_status(struct mdss_mdp_ctl *ctl, u32 cnt) +{ + u32 status; + /* + * 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 { + udelay(50); + status = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_SW_RESET); + status &= 0x01; + pr_debug("status=%x, count=%d\n", status, cnt); + cnt--; + } while (cnt > 0 && status); + + return status; +} + +/* + * mdss_mdp_check_ctl_reset_status() - checks ctl reset status + * @ctl: mdp controller + * + * This function checks the ctl reset status before every frame update. + * If the reset bit is set, it keeps polling the status till the hw + * reset is complete. And does a panic if hw fails to complet the reset + * with in the max poll interval. + */ +void mdss_mdp_check_ctl_reset_status(struct mdss_mdp_ctl *ctl) +{ + u32 status; + + if (!ctl) + return; + + status = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_SW_RESET); + status &= 0x01; + if (!status) + return; + + pr_debug("hw ctl reset is set for ctl:%d\n", ctl->num); + status = mdss_mdp_poll_ctl_reset_status(ctl, 5); + if (status) { + pr_err("hw recovery is not complete for ctl:%d\n", ctl->num); + MDSS_XLOG_TOUT_HANDLER("mdp", "vbif", "vbif_nrt", "dbg_bus", + "vbif_dbg_bus", "panic"); + } +} + /* * mdss_mdp_ctl_reset() - reset mdp ctl path. * @ctl: mdp controller. @@ -3851,8 +3899,7 @@ static void mdss_mdp_pipe_reset(struct mdss_mdp_mixer *mixer, bool is_recovery) */ int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl, bool is_recovery) { - u32 status = 1; - int cnt = 20; + u32 status; struct mdss_mdp_mixer *mixer; if (!ctl) { @@ -3863,17 +3910,9 @@ int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl, bool is_recovery) mixer = ctl->mixer_left; mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_SW_RESET, 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 { - udelay(50); - status = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_SW_RESET); - status &= 0x01; - pr_debug("status=%x\n", status); - cnt--; - } while (cnt > 0 && status); + status = mdss_mdp_poll_ctl_reset_status(ctl, 20); + if (status) + pr_err("sw ctl:%d reset timedout\n", ctl->num); if (mixer) { mdss_mdp_pipe_reset(mixer, is_recovery); @@ -3882,10 +3921,7 @@ int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl, bool is_recovery) mdss_mdp_pipe_reset(ctl->mixer_right, is_recovery); } - if (!cnt) - pr_err("ctl%d reset timedout\n", ctl->num); - - return (!cnt) ? -EAGAIN : 0; + return (status) ? -EAGAIN : 0; } /* diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index d7d0e00a9741..ccc2786e66fd 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -1953,6 +1953,7 @@ int mdss_mdp_overlay_kickoff(struct msm_fb_data_type *mfd, mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON); + mdss_mdp_check_ctl_reset_status(ctl); __vsync_set_vsync_handler(mfd); __validate_and_set_roi(mfd, data);