diff --git a/drivers/video/fbdev/msm/dsi_status_6g.c b/drivers/video/fbdev/msm/dsi_status_6g.c index 2dad6911aa9a..99be5e7783ce 100644 --- a/drivers/video/fbdev/msm/dsi_status_6g.c +++ b/drivers/video/fbdev/msm/dsi_status_6g.c @@ -55,9 +55,11 @@ static void mdss_report_panel_dead(struct dsi_status_data *pstatus_data) * after 'interval' milliseconds. If the TE IRQ is not ready, the workqueue * gets re-scheduled. Otherwise, report the panel to be dead due to ESD attack. */ -static void mdss_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata, +static bool mdss_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata, struct dsi_status_data *pstatus_data, uint32_t interval) { + bool ret; + /* * During resume, the panel status will be ON but due to race condition * between ESD thread and display UNBLANK (or rather can be put as @@ -66,14 +68,14 @@ static void mdss_check_te_status(struct mdss_dsi_ctrl_pdata *ctrl_pdata, * first TE interrupt arrives after the TE IRQ line is enabled. For such * cases, re-schedule the ESD thread. */ - if (!atomic_read(&ctrl_pdata->te_irq_ready)) { + ret = !atomic_read(&ctrl_pdata->te_irq_ready); + if (ret) { schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); pr_debug("%s: TE IRQ line not enabled yet\n", __func__); - return; } - mdss_report_panel_dead(pstatus_data); + return ret; } /* @@ -135,8 +137,10 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) } if (ctrl_pdata->status_mode == ESD_TE) { - mdss_check_te_status(ctrl_pdata, pstatus_data, interval); - return; + if (mdss_check_te_status(ctrl_pdata, pstatus_data, interval)) + return; + else + goto status_dead; } @@ -193,6 +197,18 @@ void mdss_check_dsi_ctrl_status(struct work_struct *work, uint32_t interval) schedule_delayed_work(&pstatus_data->check_status, msecs_to_jiffies(interval)); else - mdss_report_panel_dead(pstatus_data); + goto status_dead; } + + if (pdata->panel_info.panel_force_dead) { + pr_debug("force_dead=%d\n", pdata->panel_info.panel_force_dead); + pdata->panel_info.panel_force_dead--; + if (!pdata->panel_info.panel_force_dead) + goto status_dead; + } + + return; + +status_dead: + mdss_report_panel_dead(pstatus_data); } diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index ae611a935ae4..4aa66641826b 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -573,6 +573,25 @@ static ssize_t mdss_fb_get_panel_status(struct device *dev, return ret; } +static ssize_t mdss_fb_force_panel_dead(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct fb_info *fbi = dev_get_drvdata(dev); + struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par; + struct mdss_panel_data *pdata; + + pdata = dev_get_platdata(&mfd->pdev->dev); + if (!pdata) { + pr_err("no panel connected!\n"); + return len; + } + + if (sscanf(buf, "%d", &pdata->panel_info.panel_force_dead) != 1) + pr_err("sccanf buf error!\n"); + + return len; +} + /* * mdss_fb_blanking_mode_switch() - Function triggers dynamic mode switch * @mfd: Framebuffer data structure for display @@ -725,8 +744,8 @@ static DEVICE_ATTR(msm_fb_src_split_info, S_IRUGO, mdss_fb_get_src_split_info, NULL); static DEVICE_ATTR(msm_fb_thermal_level, S_IRUGO | S_IWUSR, mdss_fb_get_thermal_level, mdss_fb_set_thermal_level); -static DEVICE_ATTR(msm_fb_panel_status, S_IRUGO, - mdss_fb_get_panel_status, NULL); +static DEVICE_ATTR(msm_fb_panel_status, S_IRUGO | S_IWUSR, + mdss_fb_get_panel_status, mdss_fb_force_panel_dead); static DEVICE_ATTR(msm_fb_dfps_mode, S_IRUGO | S_IWUSR, mdss_fb_get_dfps_mode, mdss_fb_change_dfps_mode); static struct attribute *mdss_fb_attrs[] = { diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index f91965e89bd7..d2d166b81411 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -436,6 +436,7 @@ struct mdss_panel_info { int blank_state; uint32_t panel_dead; + u32 panel_force_dead; u32 panel_orientation; bool dynamic_switch_pending; bool is_lpm_mode;