msm: mdss: force display panel status dead

Display panels can be in a bad state which is most likely caused by
ESD shocks. Display s/w has the ability to detect panel state and if
it is bad, s/w reset and recover the panel from that bad state. For
the testability purpose, this change simulates a panel dead state, for
example:

adb shell 'echo 5 > /sys/devices/virtual/graphics/fb0/msm_fb_panel_status'

will simulate a display dead state after 5 detections, which is about
25 seconds if the esd detection feature is enabled with periodic
detections every 5 seconds.

Change-Id: Ia28e80ffcbfe45a59ae65e0e26b558a467b50863
Signed-off-by: Huaibin Yang <huaibiny@codeaurora.org>
This commit is contained in:
Huaibin Yang 2015-02-11 14:13:07 -08:00 committed by David Keitel
parent 729e8d3d5b
commit 7aa48794fc
3 changed files with 45 additions and 9 deletions

View file

@ -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);
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);
}

View file

@ -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[] = {

View file

@ -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;