diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2016-10-06 12:26:18 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-10-06 12:26:18 -0700 |
commit | 8667d85b72b5ea55f3e9166057b2df8626bd6c04 (patch) | |
tree | 9483bfbad2cd4803df41c6acc894839b699e538a | |
parent | d9c43f585eace25c4652bb177f53027ddac926a6 (diff) | |
parent | 3829ba593ddc0af7c340e9cb2d47e349207ba76b (diff) |
Merge "msm: mdss: add sysfs node to disable panel"
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.c | 23 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.h | 1 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_panel.c | 5 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_status.c | 10 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.c | 3 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 4 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c | 87 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 107 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_panel.h | 9 |
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 { |