From 84593d010d2666615efd32e741ceb65ae95ee9a5 Mon Sep 17 00:00:00 2001 From: Dhaval Patel <pdhaval@codeaurora.org> Date: Wed, 18 Jun 2014 14:51:52 -0700 Subject: [PATCH] msm: mdss: check cmd_pending before turning off the clocks We currently send the commands for backlight update through sysfs nodes. The implementation turns on the clocks for these nodes to allow command update during ulps state. However, clk off does not wait for operation complete. In loaded system, this can lead to crash if commands are not sent within timeframe window. This change holds the command pending status before turning off the clock to make sure that clocks are available before sending any command. Bug: 15725268 Change-Id: I9baf0ca423f5a09088ac29e416857f244970d33c --- drivers/video/msm/mdss/mdss_dsi_host.c | 2 - drivers/video/msm/mdss/mdss_fb.c | 3 - drivers/video/msm/mdss/mdss_mdp_intf_cmd.c | 79 +++++++++++++++---- .../mdss_samsung_oled_cmd_320p_dsi_panel.c | 8 ++ 4 files changed, 70 insertions(+), 22 deletions(-) diff --git a/drivers/video/msm/mdss/mdss_dsi_host.c b/drivers/video/msm/mdss/mdss_dsi_host.c index 7145bd2884ea..199f3bba0071 100755 --- a/drivers/video/msm/mdss/mdss_dsi_host.c +++ b/drivers/video/msm/mdss/mdss_dsi_host.c @@ -231,7 +231,6 @@ void mdss_dsi_cmd_dma_trigger_sel(struct mdss_dsi_ctrl_pdata *ctrl_pdata, int temp; int mask = 0x02; - mdss_mdp_cmd_clk_enable(); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 1); temp = MIPI_INP((ctrl_pdata->ctrl_base) + 0x0084); if (enable) @@ -240,7 +239,6 @@ void mdss_dsi_cmd_dma_trigger_sel(struct mdss_dsi_ctrl_pdata *ctrl_pdata, temp &= ~mask; MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x0084, temp); mdss_dsi_clk_ctrl(ctrl_pdata, DSI_ALL_CLKS, 0); -// mdss_mdp_cmd_clk_disable(); } void mdss_dsi_host_init(struct mdss_panel_data *pdata) diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c index 85e05b3e3796..6582c452e7d1 100755 --- a/drivers/video/msm/mdss/mdss_fb.c +++ b/drivers/video/msm/mdss/mdss_fb.c @@ -638,7 +638,6 @@ static int mdss_fb_suspend_sub(struct msm_fb_data_type *mfd) #if defined(CONFIG_FB_MSM_MDSS_PANEL_ALWAYS_ON) if (mfd->index == 0) { if ((pdata) && (pdata->send_alpm)) { - mfd->mdp.disable_ulps(mfd); pdata->send_alpm(pdata, true); } return mfd->mdp.off_pan_on_fnc(mfd); @@ -683,7 +682,6 @@ static int mdss_fb_resume_sub(struct msm_fb_data_type *mfd) #if defined(CONFIG_FB_MSM_MDSS_PANEL_ALWAYS_ON) if (mfd->index == 0) if ((pdata) && (pdata->send_alpm)) { - mfd->mdp.disable_ulps(mfd); pdata->send_alpm(pdata, false); } return 0; @@ -864,7 +862,6 @@ void mdss_fb_set_backlight(struct msm_fb_data_type *mfd, u32 bkl_lvl) mfd->bl_level = bkl_lvl; return; } - mfd->mdp.disable_ulps(mfd); pdata->set_backlight(pdata, temp); mfd->bl_level = bkl_lvl; mfd->bl_level_old = temp; diff --git a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c index 703a6fa4ce93..c2abeddf799e 100755 --- a/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c +++ b/drivers/video/msm/mdss/mdss_mdp_intf_cmd.c @@ -56,6 +56,8 @@ struct mdss_mdp_cmd_ctx { struct mdss_panel_recovery recovery; bool ulps; bool off_pan_on; + int cmd_pending; + spinlock_t cmd_lock; struct mutex ulps_lock; }; @@ -188,7 +190,7 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_ctl *ctl) return rc; } -static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx) +static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx, bool cmd_pending) { unsigned long flags; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); @@ -229,9 +231,10 @@ static inline void mdss_mdp_cmd_clk_on(struct mdss_mdp_cmd_ctx *ctx) mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_RESUME); } spin_lock_irqsave(&ctx->clk_lock, flags); - if (!ctx->rdptr_enabled) + if (!ctx->rdptr_enabled && !cmd_pending) mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num); - ctx->rdptr_enabled = VSYNC_EXPIRE_TICK; + if (!cmd_pending) + ctx->rdptr_enabled = VSYNC_EXPIRE_TICK; spin_unlock_irqrestore(&ctx->clk_lock, flags); mutex_unlock(&ctx->clk_mtx); } @@ -250,6 +253,13 @@ static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx) set_clk_off = 1; spin_unlock_irqrestore(&ctx->clk_lock, flags); + spin_lock_irqsave(&ctx->cmd_lock, flags); + if (set_clk_off && !ctx->cmd_pending) + set_clk_off = 1; + else + set_clk_off = 0; + spin_unlock_irqrestore(&ctx->cmd_lock, flags); + if (ctx->clk_enabled && set_clk_off) { ctx->clk_enabled = 0; mdss_mdp_hist_intr_setup(&mdata->hist_intr, MDSS_IRQ_SUSPEND); @@ -263,6 +273,30 @@ static inline void mdss_mdp_cmd_clk_off(struct mdss_mdp_cmd_ctx *ctx) mutex_unlock(&ctx->clk_mtx); } +void mdss_mdp_cmd_clk_enable(void) +{ + if (stored_ctx) { + spin_lock(&stored_ctx->cmd_lock); + stored_ctx->cmd_pending++; + spin_unlock(&stored_ctx->cmd_lock); + mdss_mdp_cmd_clk_on(stored_ctx, true); + } +} + +void mdss_mdp_cmd_clk_disable(void) +{ + int cmd_pending; + if (stored_ctx) { + spin_lock(&stored_ctx->cmd_lock); + if (stored_ctx->cmd_pending) + stored_ctx->cmd_pending--; + cmd_pending = stored_ctx->cmd_pending; + spin_unlock(&stored_ctx->cmd_lock); + if (cmd_pending) + schedule_work(&stored_ctx->clk_work); + } +} + int mdss_mdp_cmd_disable_ulps(struct mdss_mdp_ctl *ctl) { struct mdss_mdp_cmd_ctx *ctx; @@ -273,20 +307,11 @@ int mdss_mdp_cmd_disable_ulps(struct mdss_mdp_ctl *ctl) return -ENODEV; } - mdss_mdp_cmd_clk_on(ctx); + mdss_mdp_cmd_clk_on(ctx, false); return 0; } -void mdss_mdp_cmd_clk_enable(void) -{ - if (stored_ctx) - mdss_mdp_cmd_clk_on(stored_ctx); -} -void mdss_mdp_cmd_clk_disable(void) -{ - if (stored_ctx) - mdss_mdp_cmd_clk_off(stored_ctx); -} + static void mdss_mdp_cmd_readptr_done(void *arg) { struct mdss_mdp_ctl *ctl = arg; @@ -474,7 +499,7 @@ static int mdss_mdp_cmd_add_vsync_handler(struct mdss_mdp_ctl *ctl, spin_unlock_irqrestore(&ctx->clk_lock, flags); if (enable_rdptr) - mdss_mdp_cmd_clk_on(ctx); + mdss_mdp_cmd_clk_on(ctx, false); return 0; } @@ -606,7 +631,7 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) WARN(rc, "intf %d panel on error (%d)\n", ctl->intf_num, rc); } - mdss_mdp_cmd_clk_on(ctx); + mdss_mdp_cmd_clk_on(ctx, false); mdss_mdp_cmd_set_partial_roi(ctl); @@ -659,10 +684,17 @@ int mdss_mdp_cmd_off_pan_on(struct mdss_mdp_ctl *ctl) } spin_unlock_irqrestore(&ctx->clk_lock, flags); + spin_lock_irqsave(&ctx->cmd_lock, flags); + if (ctx->cmd_pending) { + INIT_COMPLETION(ctx->stop_comp); + need_wait = 1; + } + spin_unlock_irqrestore(&ctx->cmd_lock, flags); + if (need_wait) { if (wait_for_completion_timeout(&ctx->stop_comp, STOP_TIMEOUT) <= 0) { - pr_debug("%s: stop cmd time out\n", __func__); + pr_err("%s: stop cmd time out\n", __func__); mdss_mdp_irq_disable(MDSS_MDP_IRQ_PING_PONG_RD_PTR, ctx->pp_num); ctx->rdptr_enabled = 0; @@ -671,6 +703,7 @@ int mdss_mdp_cmd_off_pan_on(struct mdss_mdp_ctl *ctl) } ctx->off_pan_on = true; + ctx->cmd_pending = 0; if (cancel_work_sync(&ctx->clk_work)) pr_debug("no pending clk work\n"); @@ -726,6 +759,13 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl) } spin_unlock_irqrestore(&ctx->clk_lock, flags); + spin_lock_irqsave(&ctx->cmd_lock, flags); + if (ctx->cmd_pending) { + INIT_COMPLETION(ctx->stop_comp); + need_wait = 1; + } + spin_unlock_irqrestore(&ctx->cmd_lock, flags); + if (need_wait) { if (pinfo->alpm_event && pinfo->alpm_event(CHECK_CURRENT_STATUS)) timeout_status = wait_for_completion_timeout(&ctx->stop_comp,\ @@ -751,6 +791,7 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl) pr_debug("deleted pending ulps work\n"); ctx->panel_on = 0; + ctx->cmd_pending = 0; mdss_mdp_cmd_clk_off(ctx); flush_work(&ctx->pp_done_work); @@ -762,6 +803,7 @@ int mdss_mdp_cmd_stop(struct mdss_mdp_ctl *ctl) NULL, NULL); memset(ctx, 0, sizeof(*ctx)); + stored_ctx = NULL; ctl->priv_data = NULL; if (ctl->num == 0) { @@ -823,6 +865,7 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl) init_completion(&ctx->pp_comp); init_completion(&ctx->stop_comp); spin_lock_init(&ctx->clk_lock); + spin_lock_init(&ctx->cmd_lock); mutex_init(&ctx->clk_mtx); mutex_init(&ctx->ulps_lock); INIT_WORK(&ctx->clk_work, clk_ctrl_work); @@ -864,6 +907,8 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl) ctl->off_pan_on = mdss_mdp_cmd_off_pan_on; ctl->disable_ulps = mdss_mdp_cmd_disable_ulps; pr_debug("%s:-\n", __func__); + stored_ctx = ctx; + ctx->cmd_pending = 0; return 0; } diff --git a/drivers/video/msm/mdss/mdss_samsung_oled_cmd_320p_dsi_panel.c b/drivers/video/msm/mdss/mdss_samsung_oled_cmd_320p_dsi_panel.c index 439278faeacd..e56e13154c93 100755 --- a/drivers/video/msm/mdss/mdss_samsung_oled_cmd_320p_dsi_panel.c +++ b/drivers/video/msm/mdss/mdss_samsung_oled_cmd_320p_dsi_panel.c @@ -130,10 +130,12 @@ static void mdss_dsi_panel_bklt_dcs(struct mdss_dsi_ctrl_pdata *ctrl, cmdreq.rlen = 0; cmdreq.cb = NULL; + mdss_mdp_cmd_clk_enable(); mdss_dsi_cmd_dma_trigger_sel(ctrl, 1); mdss_dsi_cmdlist_put(ctrl, &cmdreq); mdss_dsi_cmd_dma_trigger_sel(ctrl, 0); stored_cd_level = cd_level; + mdss_mdp_cmd_clk_disable(); } void mdss_dsi_samsung_panel_reset(struct mdss_panel_data *pdata, int enable) @@ -283,7 +285,11 @@ static int mipi_samsung_disp_send_cmd( } #endif + if (cmd != PANEL_DISPLAY_ON_SEQ && cmd != PANEL_DISP_OFF) + mdss_mdp_cmd_clk_enable(); mdss_dsi_cmds_send(msd.ctrl_pdata, cmd_desc, cmd_size, flag); + if (cmd != PANEL_DISPLAY_ON_SEQ && cmd != PANEL_DISP_OFF) + mdss_mdp_cmd_clk_disable(); if (lock) mutex_unlock(&msd.lock); @@ -435,7 +441,9 @@ u32 mdss_dsi_cmd_receive(struct mdss_dsi_ctrl_pdata *ctrl, * This mutex is to sync up with dynamic FPS changes * so that DSI lockups shall not happen */ + mdss_mdp_cmd_clk_enable(); mdss_dsi_cmdlist_put(ctrl, &cmdreq); + mdss_mdp_cmd_clk_disable(); /* * blocked here, untill call back called -- GitLab