summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-10-06 12:26:18 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2016-10-06 12:26:18 -0700
commit8667d85b72b5ea55f3e9166057b2df8626bd6c04 (patch)
tree9483bfbad2cd4803df41c6acc894839b699e538a
parentd9c43f585eace25c4652bb177f53027ddac926a6 (diff)
parent3829ba593ddc0af7c340e9cb2d47e349207ba76b (diff)
Merge "msm: mdss: add sysfs node to disable panel"
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c23
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c5
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_status.c10
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c87
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c107
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h9
9 files changed, 245 insertions, 4 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index c145f72c3c70..66cd99720afa 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -357,7 +357,7 @@ static int mdss_dsi_panel_power_lp(struct mdss_panel_data *pdata, int enable)
static int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata,
int power_state)
{
- int ret;
+ int ret = 0;
struct mdss_panel_info *pinfo;
if (pdata == NULL) {
@@ -383,7 +383,11 @@ static int mdss_dsi_panel_power_ctrl(struct mdss_panel_data *pdata,
switch (power_state) {
case MDSS_PANEL_POWER_OFF:
- ret = mdss_dsi_panel_power_off(pdata);
+ case MDSS_PANEL_POWER_LCD_DISABLED:
+ /* if LCD has not been disabled, then disable it now */
+ if ((pinfo->panel_power_state != MDSS_PANEL_POWER_LCD_DISABLED)
+ && (pinfo->panel_power_state != MDSS_PANEL_POWER_OFF))
+ ret = mdss_dsi_panel_power_off(pdata);
break;
case MDSS_PANEL_POWER_ON:
if (mdss_dsi_is_panel_on_lp(pdata))
@@ -2469,6 +2473,7 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
int power_state;
u32 mode;
struct mdss_panel_info *pinfo;
+ int ret;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
@@ -2529,6 +2534,20 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
rc = mdss_dsi_blank(pdata, power_state);
rc = mdss_dsi_off(pdata, power_state);
break;
+ case MDSS_EVENT_DISABLE_PANEL:
+ /* disable esd thread */
+ disable_esd_thread();
+
+ /* disable backlight */
+ ctrl_pdata->panel_data.set_backlight(pdata, 0);
+
+ /* send the off commands */
+ ctrl_pdata->off(pdata);
+
+ /* disable panel power */
+ ret = mdss_dsi_panel_power_ctrl(pdata,
+ MDSS_PANEL_POWER_LCD_DISABLED);
+ break;
case MDSS_EVENT_CONT_SPLASH_FINISH:
if (ctrl_pdata->off_cmds.link_state == DSI_LP_MODE)
rc = mdss_dsi_blank(pdata, MDSS_PANEL_POWER_OFF);
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index bd1854092c6a..7091dc2f38b9 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -614,6 +614,7 @@ int mdss_dsi_wait_for_lane_idle(struct mdss_dsi_ctrl_pdata *ctrl);
irqreturn_t mdss_dsi_isr(int irq, void *ptr);
irqreturn_t hw_vsync_handler(int irq, void *data);
+void disable_esd_thread(void);
void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index e8d68059581f..8ffba091e2b2 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -667,6 +667,11 @@ static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
* for the backlight brightness. If the brightness is less
* than it, the controller can malfunction.
*/
+ pr_debug("%s: bl_level:%d\n", __func__, bl_level);
+
+ /* do not allow backlight to change when panel in disable mode */
+ if (pdata->panel_disable_mode && (bl_level != 0))
+ return;
if ((bl_level < pdata->panel_info.bl_min) && (bl_level != 0))
bl_level = pdata->panel_info.bl_min;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_status.c b/drivers/video/fbdev/msm/mdss_dsi_status.c
index bf545ae311f2..4208c2c43efb 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_status.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_status.c
@@ -101,6 +101,16 @@ irqreturn_t hw_vsync_handler(int irq, void *data)
}
/*
+ * disable_esd_thread() - Cancels work item for the esd check.
+ */
+void disable_esd_thread(void)
+{
+ if (pstatus_data &&
+ cancel_delayed_work(&pstatus_data->check_status))
+ pr_debug("esd thread killed\n");
+}
+
+/*
* fb_event_callback() - Call back function for the fb_register_client()
* notifying events
* @self : notifier block
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 50c7015c6731..fc8d3898351e 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -1950,6 +1950,9 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info)
pdata->panel_info.is_lpm_mode = false;
}
+ if (pdata->panel_disable_mode)
+ mdss_mdp_enable_panel_disable_mode(mfd, false);
+
return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index 921391dc4bde..0085163ada52 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -394,6 +394,8 @@ struct mdss_mdp_ctl_intfs_ops {
enum dynamic_switch_modes mode, bool pre);
/* called before do any register programming from commit thread */
void (*pre_programming)(struct mdss_mdp_ctl *ctl);
+ /* called to do any interface programming for the panel disable mode */
+ void (*panel_disable_cfg)(struct mdss_mdp_ctl *ctl, bool disable);
/* to update lineptr, [1..yres] - enable, 0 - disable */
int (*update_lineptr)(struct mdss_mdp_ctl *ctl, bool enable);
@@ -1863,6 +1865,8 @@ int mdss_mdp_cmd_set_autorefresh_mode(struct mdss_mdp_ctl *ctl, int frame_cnt);
int mdss_mdp_cmd_get_autorefresh_mode(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_cmd_set_autorefresh(struct mdss_mdp_ctl *ctl, int frame_cnt);
int mdss_mdp_ctl_cmd_get_autorefresh(struct mdss_mdp_ctl *ctl);
+int mdss_mdp_enable_panel_disable_mode(struct msm_fb_data_type *mfd,
+ bool disable_panel);
int mdss_mdp_pp_get_version(struct mdp_pp_feature_version *version);
int mdss_mdp_layer_pre_commit_cwb(struct msm_fb_data_type *mfd,
struct mdp_layer_commit_v1 *commit);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index 2c2dc6f18fd9..72d6175686b7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -295,9 +295,9 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
__func__, pinfo->yres, vclks_line, te->sync_cfg_height,
te->vsync_init_val, te->rd_ptr_irq, te->start_pos,
te->wr_ptr_irq);
- pr_debug("thrd_start =%d thrd_cont=%d pp_split=%d\n",
+ pr_debug("thrd_start =%d thrd_cont=%d pp_split=%d hw_vsync_mode:%d\n",
te->sync_threshold_start, te->sync_threshold_continue,
- ctx->pingpong_split_slave);
+ ctx->pingpong_split_slave, pinfo->mipi.hw_vsync_mode);
pingpong_base = mixer->pingpong_base;
@@ -2130,6 +2130,88 @@ static int mdss_mdp_cmd_panel_on(struct mdss_mdp_ctl *ctl,
}
/*
+ * This function will be called from the sysfs node to tear down or restore
+ * any dependencies of the interface to disable the panel
+ */
+void mdss_mdp_cmd_panel_disable_cfg(struct mdss_mdp_ctl *ctl,
+ bool disable)
+{
+ struct mdss_panel_info *pinfo, *spinfo = NULL;
+ struct mdss_mdp_cmd_ctx *ctx, *sctx = NULL;
+
+ pinfo = &ctl->panel_data->panel_info;
+ mutex_lock(&ctl->offlock);
+
+ if ((pinfo->sim_panel_mode == SIM_MODE) ||
+ ((!ctl->panel_data->panel_disable_mode) &&
+ (pinfo->mipi.hw_vsync_mode == 0))) {
+ pr_err("te already in simulaiton mode\n");
+ goto exit;
+ }
+
+ ctx = (struct mdss_mdp_cmd_ctx *)ctl->intf_ctx[MASTER_CTX];
+ if (is_pingpong_split(ctl->mfd)) {
+ sctx = (struct mdss_mdp_cmd_ctx *)ctl->intf_ctx[SLAVE_CTX];
+ } else if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) {
+ struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl);
+
+ if (sctl) {
+ sctx = (struct mdss_mdp_cmd_ctx *)
+ sctl->intf_ctx[MASTER_CTX];
+ spinfo = &sctl->panel_data->panel_info;
+ }
+ }
+
+ if (disable) {
+ /* cache the te params */
+ memcpy(&pinfo->te_cached, &pinfo->te,
+ sizeof(struct mdss_mdp_pp_tear_check));
+ pinfo->mipi.hw_vsync_mode = 0;
+
+ if (spinfo) {
+ spinfo->mipi.hw_vsync_mode = 0;
+ memcpy(&spinfo->te_cached, &spinfo->te,
+ sizeof(struct mdss_mdp_pp_tear_check));
+ }
+
+ pr_debug("%s: update info\n", __func__);
+ /* update the te information to use sim mode */
+ mdss_panel_override_te_params(pinfo);
+ if (spinfo)
+ mdss_panel_override_te_params(spinfo);
+
+ pr_debug("%s: reconfig tear check\n", __func__);
+ /* reconfigure tear check, remove dependency to external te */
+ if (mdss_mdp_cmd_tearcheck_setup(ctx, false)) {
+ pr_warn("%s: ctx%d tearcheck setup failed\n", __func__,
+ ctx->current_pp_num);
+ } else {
+ if (sctx && mdss_mdp_cmd_tearcheck_setup(sctx, false))
+ pr_warn("%s: ctx%d tearcheck setup failed\n",
+ __func__, sctx->current_pp_num);
+ }
+ } else {
+ /*
+ * restore the information in the panel information,
+ * the actual programming will happen during restore
+ */
+ pr_debug("%s: reset tear check\n", __func__);
+ memcpy(&pinfo->te, &pinfo->te_cached,
+ sizeof(struct mdss_mdp_pp_tear_check));
+ pinfo->mipi.hw_vsync_mode = 1;
+
+ if (spinfo) {
+ spinfo->mipi.hw_vsync_mode = 1;
+ memcpy(&spinfo->te, &spinfo->te_cached,
+ sizeof(struct mdss_mdp_pp_tear_check));
+ }
+ }
+
+exit:
+ mutex_unlock(&ctl->offlock);
+}
+
+/*
* This function will be called from the sysfs node to enable and disable the
* feature with master ctl only.
*/
@@ -3481,6 +3563,7 @@ int mdss_mdp_cmd_start(struct mdss_mdp_ctl *ctl)
ctl->ops.reconfigure = mdss_mdp_cmd_reconfigure;
ctl->ops.pre_programming = mdss_mdp_cmd_pre_programming;
ctl->ops.update_lineptr = mdss_mdp_cmd_update_lineptr;
+ ctl->ops.panel_disable_cfg = mdss_mdp_cmd_panel_disable_cfg;
pr_debug("%s:-\n", __func__);
return 0;
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 9dda467e53cc..965d4a6cfb5e 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -3243,6 +3243,110 @@ static ssize_t mdss_mdp_dyn_pu_store(struct device *dev,
return count;
}
+
+static ssize_t mdss_mdp_panel_disable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ ssize_t ret = 0;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+ struct mdss_mdp_ctl *ctl;
+ struct mdss_panel_data *pdata;
+
+ if (!mfd) {
+ pr_err("Invalid mfd structure\n");
+ return -EINVAL;
+ }
+
+ ctl = mfd_to_ctl(mfd);
+ if (!ctl) {
+ pr_err("Invalid ctl structure\n");
+ return -EINVAL;
+ }
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
+ pdata->panel_disable_mode);
+
+ return ret;
+}
+
+int mdss_mdp_enable_panel_disable_mode(struct msm_fb_data_type *mfd,
+ bool disable_panel)
+{
+ struct mdss_mdp_ctl *ctl;
+ int ret = 0;
+ struct mdss_panel_data *pdata;
+
+ ctl = mfd_to_ctl(mfd);
+ if (!ctl) {
+ pr_err("Invalid ctl structure\n");
+ ret = -EINVAL;
+ return ret;
+ }
+
+ pdata = dev_get_platdata(&mfd->pdev->dev);
+
+ pr_debug("config panel %d\n", disable_panel);
+ if (disable_panel) {
+ /* first set the flag that we enter this mode */
+ pdata->panel_disable_mode = true;
+
+ /*
+ * setup any interface config that needs to change before
+ * disabling the panel
+ */
+ if (ctl->ops.panel_disable_cfg)
+ ctl->ops.panel_disable_cfg(ctl, disable_panel);
+
+ /* disable panel */
+ ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DISABLE_PANEL,
+ NULL, CTL_INTF_EVENT_FLAG_DEFAULT);
+ if (ret)
+ pr_err("failed to disable panel! %d\n", ret);
+ } else {
+ /* restore any interface configuration */
+ if (ctl->ops.panel_disable_cfg)
+ ctl->ops.panel_disable_cfg(ctl, disable_panel);
+
+ /*
+ * no other action is needed when reconfiguring, since all the
+ * re-configuration will happen during restore
+ */
+ pdata->panel_disable_mode = false;
+ }
+
+ return ret;
+}
+
+static ssize_t mdss_mdp_panel_disable_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ int disable_panel, rc;
+ struct fb_info *fbi = dev_get_drvdata(dev);
+ struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
+
+ if (!mfd) {
+ pr_err("Invalid mfd structure\n");
+ rc = -EINVAL;
+ return rc;
+ }
+
+ rc = kstrtoint(buf, 10, &disable_panel);
+ if (rc) {
+ pr_err("kstrtoint failed. rc=%d\n", rc);
+ return rc;
+ }
+
+ pr_debug("disable panel: %d ++\n", disable_panel);
+ /* we only support disabling the panel from sysfs */
+ if (disable_panel)
+ mdss_mdp_enable_panel_disable_mode(mfd, true);
+
+ return len;
+}
+
static ssize_t mdss_mdp_cmd_autorefresh_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -3433,6 +3537,8 @@ static DEVICE_ATTR(msm_misr_en, S_IRUGO | S_IWUSR,
mdss_mdp_misr_show, mdss_mdp_misr_store);
static DEVICE_ATTR(msm_cmd_autorefresh_en, S_IRUGO | S_IWUSR,
mdss_mdp_cmd_autorefresh_show, mdss_mdp_cmd_autorefresh_store);
+static DEVICE_ATTR(msm_disable_panel, S_IRUGO | S_IWUSR,
+ mdss_mdp_panel_disable_show, mdss_mdp_panel_disable_store);
static DEVICE_ATTR(vsync_event, S_IRUGO, mdss_mdp_vsync_show_event, NULL);
static DEVICE_ATTR(lineptr_event, S_IRUGO, mdss_mdp_lineptr_show_event, NULL);
static DEVICE_ATTR(lineptr_value, S_IRUGO | S_IWUSR | S_IWGRP,
@@ -3454,6 +3560,7 @@ static struct attribute *mdp_overlay_sysfs_attrs[] = {
&dev_attr_dyn_pu.attr,
&dev_attr_msm_misr_en.attr,
&dev_attr_msm_cmd_autorefresh_en.attr,
+ &dev_attr_msm_disable_panel.attr,
&dev_attr_hist_event.attr,
&dev_attr_bl_event.attr,
&dev_attr_ad_event.attr,
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index b2b647dcc017..a633528b5373 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -104,6 +104,7 @@ enum {
MDSS_PANEL_POWER_ON,
MDSS_PANEL_POWER_LP1,
MDSS_PANEL_POWER_LP2,
+ MDSS_PANEL_POWER_LCD_DISABLED,
};
enum {
@@ -265,6 +266,7 @@ enum mdss_intf_events {
MDSS_EVENT_DSI_RESET_WRITE_PTR,
MDSS_EVENT_PANEL_TIMING_SWITCH,
MDSS_EVENT_DEEP_COLOR,
+ MDSS_EVENT_DISABLE_PANEL,
MDSS_EVENT_MAX,
};
@@ -692,6 +694,7 @@ struct mdss_panel_info {
char panel_name[MDSS_MAX_PANEL_LEN];
struct mdss_mdp_pp_tear_check te;
+ struct mdss_mdp_pp_tear_check te_cached;
/*
* Value of 2 only when single DSI is configured with 2 DSC
@@ -789,6 +792,12 @@ struct mdss_panel_data {
/* To store dsc cfg name passed by bootloader */
char dsc_cfg_np_name[MDSS_MAX_PANEL_LEN];
struct mdss_panel_data *next;
+
+ /*
+ * Set when the power of the panel is disabled while dsi/mdp
+ * are still on; panel will recover after unblank
+ */
+ bool panel_disable_mode;
};
struct mdss_panel_debugfs_info {