diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index c4b47076283..afbae5ea742 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -293,6 +293,15 @@ Optional properties: - qcom,panel-roi-alignment: Specifies the panel ROI alignment restrictions on its left, top, width, height alignments and minimum width and height values +- qcom,dynamic-mode-switch-enabled: Boolean used to mention whether panel supports + dynamic switching from video mode to command mode + and vice versa. +- qcom,video-to-cmd-mode-switch-commands: List of commands that need to be sent + to panel in order to switch from video mode to command mode dynamically. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. +- qcom,cmd-to-video-mode-switch-commands: List of commands that need to be sent + to panel in order to switch from command mode to video mode dynamically. + Refer to "qcom,mdss-dsi-on-command" section for adding commands. Note, if a given optional qcom,* binding is not present, then the driver will configure the default values specified. @@ -399,5 +408,9 @@ Example: qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>; qcom,mdss-tear-check-frame-rate = <6000>; qcom,panel-roi-alignment = <4 4 2 2 20 20>; + qcom,dynamic-mode-switch-enabled; + qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 00 00 02 C2 0B + 15 01 00 00 00 00 02 C2 08]; + qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03]; }; }; diff --git a/drivers/video/msm/mdss/mdss_dsi.c b/drivers/video/msm/mdss/mdss_dsi.c index 8fa04cdfe82..993645ab3c2 100644 --- a/drivers/video/msm/mdss/mdss_dsi.c +++ b/drivers/video/msm/mdss/mdss_dsi.c @@ -62,6 +62,9 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable) panel_data); pr_debug("%s: enable=%d\n", __func__, enable); + if (pdata->panel_info.dynamic_switch_pending) + return 0; + if (enable) { ret = msm_dss_enable_vreg( ctrl_pdata->power_data.vreg_config, @@ -594,6 +597,31 @@ error: return ret; } +static int mdss_dsi_update_panel_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata, + int mode) +{ + int ret = 0; + struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); + + if (mode == DSI_CMD_MODE) { + pinfo->mipi.mode = DSI_CMD_MODE; + pinfo->type = MIPI_CMD_PANEL; + pinfo->mipi.vsync_enable = 1; + pinfo->mipi.hw_vsync_mode = 1; + } else { /*video mode*/ + pinfo->mipi.mode = DSI_VIDEO_MODE; + pinfo->type = MIPI_VIDEO_PANEL; + pinfo->mipi.vsync_enable = 0; + pinfo->mipi.hw_vsync_mode = 0; + } + + ctrl_pdata->panel_mode = pinfo->mipi.mode; + mdss_panel_get_dst_fmt(pinfo->bpp, pinfo->mipi.mode, + pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format)); + pinfo->cont_splash_enabled = 0; + + return ret; +} static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, int enable) { @@ -727,11 +755,13 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata) mipi = &pdata->panel_info.mipi; if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) { - ret = ctrl_pdata->on(pdata); - if (ret) { - pr_err("%s: unable to initialize the panel\n", + if (!pdata->panel_info.dynamic_switch_pending) { + ret = ctrl_pdata->on(pdata); + if (ret) { + pr_err("%s: unable to initialize the panel\n", __func__); - return ret; + return ret; + } } ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT; } @@ -784,6 +814,17 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata) mdss_dsi_op_mode_config(DSI_CMD_MODE, pdata); + if (pdata->panel_info.dynamic_switch_pending) { + pr_info("%s: switching to %s mode\n", __func__, + (pdata->panel_info.mipi.mode ? "video" : "command")); + if (pdata->panel_info.type == MIPI_CMD_PANEL) { + ctrl_pdata->switch_mode(pdata, DSI_VIDEO_MODE); + } else if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { + ctrl_pdata->switch_mode(pdata, DSI_CMD_MODE); + mdss_dsi_set_tear_off(ctrl_pdata); + } + } + if (pdata->panel_info.type == MIPI_CMD_PANEL) { if (mipi->vsync_enable && mipi->hw_vsync_mode && gpio_is_valid(ctrl_pdata->disp_te_gpio)) { @@ -792,10 +833,12 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata) } if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { - ret = ctrl_pdata->off(pdata); - if (ret) { - pr_err("%s: Panel OFF failed\n", __func__); - return ret; + if (!pdata->panel_info.dynamic_switch_pending) { + ret = ctrl_pdata->off(pdata); + if (ret) { + pr_err("%s: Panel OFF failed\n", __func__); + return ret; + } } ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT; } @@ -1037,6 +1080,9 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, case MDSS_EVENT_REGISTER_RECOVERY_HANDLER: rc = mdss_dsi_register_recovery_handler(ctrl_pdata, (struct mdss_panel_recovery *)arg); + case MDSS_EVENT_DSI_DYNAMIC_SWITCH: + rc = mdss_dsi_update_panel_config(ctrl_pdata, + (int)(unsigned long) arg); break; default: pr_debug("%s: unhandled event=%d\n", __func__, event); diff --git a/drivers/video/msm/mdss/mdss_dsi.h b/drivers/video/msm/mdss/mdss_dsi.h index 5ab06e0f94c..609b7cea8f2 100644 --- a/drivers/video/msm/mdss/mdss_dsi.h +++ b/drivers/video/msm/mdss/mdss_dsi.h @@ -243,6 +243,7 @@ struct mdss_dsi_ctrl_pdata { int (*partial_update_fnc) (struct mdss_panel_data *pdata); int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata); int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp); + void (*switch_mode) (struct mdss_panel_data *pdata, int mode); struct mdss_panel_data panel_data; unsigned char *ctrl_base; struct dss_io_data ctrl_io; @@ -286,6 +287,9 @@ struct mdss_dsi_ctrl_pdata { struct dsi_panel_cmds on_cmds; struct dsi_panel_cmds off_cmds; + struct dsi_panel_cmds video2cmd; + struct dsi_panel_cmds cmd2video; + struct dcs_cmd_list cmdlist; struct completion dma_comp; struct completion mdp_comp; @@ -364,6 +368,8 @@ bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type); int mdss_dsi_panel_init(struct device_node *node, struct mdss_dsi_ctrl_pdata *ctrl_pdata, bool cmd_cfg_cont_splash); +int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing, + char *dst_format); int mdss_dsi_register_recovery_handler(struct mdss_dsi_ctrl_pdata *ctrl, struct mdss_panel_recovery *recovery); diff --git a/drivers/video/msm/mdss/mdss_dsi_panel.c b/drivers/video/msm/mdss/mdss_dsi_panel.c index 0e1cd6676fb..1ac37dc44c2 100644 --- a/drivers/video/msm/mdss/mdss_dsi_panel.c +++ b/drivers/video/msm/mdss/mdss_dsi_panel.c @@ -317,6 +317,36 @@ static int mdss_dsi_panel_partial_update(struct mdss_panel_data *pdata) return rc; } +static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata, + int mode) +{ + struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; + struct mipi_panel_info *mipi; + struct dsi_panel_cmds *pcmds; + + if (pdata == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + mipi = &pdata->panel_info.mipi; + + if (!mipi->dynamic_switch_enabled) + return; + + ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, + panel_data); + + if (mode == DSI_CMD_MODE) + pcmds = &ctrl_pdata->video2cmd; + else + pcmds = &ctrl_pdata->cmd2video; + + mdss_dsi_panel_cmds_send(ctrl_pdata, pcmds); + + return; +} + static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata, u32 bl_level) { @@ -524,11 +554,16 @@ static int mdss_dsi_parse_dcs_cmds(struct device_node *np, len -= dchdr->dlen; } - data = of_get_property(np, link_key, NULL); - if (data && !strcmp(data, "dsi_hs_mode")) - pcmds->link_state = DSI_HS_MODE; - else - pcmds->link_state = DSI_LP_MODE; + /*Set default link state to LP Mode*/ + pcmds->link_state = DSI_LP_MODE; + + if (link_key) { + data = of_get_property(np, link_key, NULL); + if (data && !strcmp(data, "dsi_hs_mode")) + pcmds->link_state = DSI_HS_MODE; + else + pcmds->link_state = DSI_LP_MODE; + } pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__, pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state); @@ -541,7 +576,7 @@ exit_free: } -static int mdss_panel_dt_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing, +int mdss_panel_get_dst_fmt(u32 bpp, char mipi_mode, u32 pixel_packing, char *dst_format) { int rc = 0; @@ -788,6 +823,25 @@ static int mdss_dsi_parse_panel_features(struct device_node *np, pr_info("%s: ulps feature %s", __func__, (pinfo->ulps_feature_enabled ? "enabled" : "disabled")); + pinfo->mipi.dynamic_switch_enabled = of_property_read_bool(np, + "qcom,dynamic-mode-switch-enabled"); + + if (pinfo->mipi.dynamic_switch_enabled) { + mdss_dsi_parse_dcs_cmds(np, &ctrl->video2cmd, + "qcom,video-to-cmd-mode-switch-commands", NULL); + + mdss_dsi_parse_dcs_cmds(np, &ctrl->cmd2video, + "qcom,cmd-to-video-mode-switch-commands", NULL); + + if (!ctrl->video2cmd.cmd_cnt || !ctrl->cmd2video.cmd_cnt) { + pr_warn("No commands specified for dynamic switch\n"); + pinfo->mipi.dynamic_switch_enabled = 0; + } + } + + pr_info("%s: dynamic switch feature enabled: %d", __func__, + pinfo->mipi.dynamic_switch_enabled); + return 0; } @@ -845,9 +899,11 @@ static int mdss_panel_parse_dt(struct device_node *np, tmp = 0; data = of_get_property(np, "qcom,mdss-dsi-pixel-packing", NULL); if (data && !strcmp(data, "loose")) - tmp = 1; - rc = mdss_panel_dt_get_dst_fmt(pinfo->bpp, - pinfo->mipi.mode, tmp, + pinfo->mipi.pixel_packing = 1; + else + pinfo->mipi.pixel_packing = 0; + rc = mdss_panel_get_dst_fmt(pinfo->bpp, + pinfo->mipi.mode, pinfo->mipi.pixel_packing, &(pinfo->mipi.dst_format)); if (rc) { pr_debug("%s: problem determining dst format. Set Default\n", @@ -1119,9 +1175,13 @@ int mdss_dsi_panel_init(struct device_node *node, pr_info("%s: Continuous splash %s", __func__, pinfo->cont_splash_enabled ? "enabled" : "disabled"); + pinfo->dynamic_switch_pending = false; + pinfo->is_lpm_mode = false; + ctrl_pdata->on = mdss_dsi_panel_on; ctrl_pdata->off = mdss_dsi_panel_off; ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl; + ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode; return 0; } diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c index a66f4b60329..75903c20cdf 100644 --- a/drivers/video/msm/mdss/mdss_fb.c +++ b/drivers/video/msm/mdss/mdss_fb.c @@ -96,6 +96,7 @@ static int __mdss_fb_display_thread(void *data); static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd); static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd, int event, void *arg); +static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd); void mdss_fb_no_update_notify_timer_cb(unsigned long data) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data; @@ -393,6 +394,91 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev, return ret; } +/* + * mdss_fb_lpm_enable() - Function to Control LowPowerMode + * @mfd: Framebuffer data structure for display + * @mode: Enabled/Disable LowPowerMode + * 1: Enter into LowPowerMode + * 0: Exit from LowPowerMode + * + * This Function dynamically switches to and from LowPowerMode + * based on the argument @mode. + */ +static int mdss_fb_lpm_enable(struct msm_fb_data_type *mfd, int mode) +{ + int ret = 0; + u32 bl_lvl = 0; + struct mdss_panel_info *pinfo = NULL; + struct mdss_panel_data *pdata; + + if (!mfd || !mfd->panel_info) + return -EINVAL; + + pinfo = mfd->panel_info; + + if (!pinfo->mipi.dynamic_switch_enabled) { + pr_warn("Panel does not support dynamic switch!\n"); + return 0; + } + + if (mode == pinfo->mipi.mode) { + pr_debug("Already in requested mode!\n"); + return 0; + } + + pdata = dev_get_platdata(&mfd->pdev->dev); + + pr_debug("Enter mode: %d\n", mode); + pdata->panel_info.dynamic_switch_pending = true; + + mutex_lock(&mfd->bl_lock); + bl_lvl = mfd->bl_level; + mdss_fb_set_backlight(mfd, 0); + + lock_fb_info(mfd->fbi); + ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, mfd->fbi, + mfd->op_enable); + if (ret) { + pr_err("can't turn off display!\n"); + unlock_fb_info(mfd->fbi); + mutex_unlock(&mfd->bl_lock); + return ret; + } + + mfd->op_enable = false; + + ret = mfd->mdp.configure_panel(mfd, mode); + mdss_fb_set_mdp_sync_pt_threshold(mfd); + + mfd->op_enable = true; + + ret = mdss_fb_blank_sub(FB_BLANK_UNBLANK, mfd->fbi, + mfd->op_enable); + if (ret) { + pr_err("can't turn on display!\n"); + unlock_fb_info(mfd->fbi); + mutex_unlock(&mfd->bl_lock); + return ret; + } + unlock_fb_info(mfd->fbi); + + mfd->bl_updated = true; + mdss_fb_set_backlight(mfd, bl_lvl); + mutex_unlock(&mfd->bl_lock); + + pdata->panel_info.dynamic_switch_pending = false; + pdata->panel_info.is_lpm_mode = mode ? 1 : 0; + + if (ret) { + pr_err("can't turn on display!\n"); + return ret; + } + + pr_debug("Exit mode: %d\n", mode); + + return 0; +} + static DEVICE_ATTR(msm_fb_type, S_IRUGO, mdss_fb_get_type, NULL); static DEVICE_ATTR(msm_fb_split, S_IRUGO, mdss_fb_get_split, NULL); static DEVICE_ATTR(show_blank_event, S_IRUGO, mdss_mdp_show_blank_event, NULL); @@ -539,6 +625,21 @@ static int mdss_fb_probe(struct platform_device *pdev) __mdss_fb_sync_buf_done_callback; } + mdss_fb_set_mdp_sync_pt_threshold(mfd); + + if (mfd->mdp.splash_init_fnc) + mfd->mdp.splash_init_fnc(mfd); + + INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work); + + return rc; +} + +static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd) +{ + if (!mfd) + return; + switch (mfd->panel.type) { case WRITEBACK_PANEL: mfd->mdp_sync_pt_data.threshold = 1; @@ -553,15 +654,7 @@ static int mdss_fb_probe(struct platform_device *pdev) mfd->mdp_sync_pt_data.retire_threshold = 0; break; } - - if (mfd->mdp.splash_init_fnc) - mfd->mdp.splash_init_fnc(mfd); - - INIT_DELAYED_WORK(&mfd->idle_notify_work, __mdss_fb_idle_notify_work); - - return rc; } - static int mdss_fb_remove(struct platform_device *pdev) { struct msm_fb_data_type *mfd; @@ -933,6 +1026,7 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info, static int mdss_fb_blank(int blank_mode, struct fb_info *info) { + struct mdss_panel_data *pdata; struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; mdss_fb_pan_idle(mfd); @@ -943,6 +1037,18 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info) mfd->suspend.panel_power_on = false; return 0; } + pr_debug("mode: %d\n", blank_mode); + + pdata = dev_get_platdata(&mfd->pdev->dev); + + if (pdata->panel_info.is_lpm_mode && + blank_mode == FB_BLANK_UNBLANK) { + pr_debug("panel is in lpm mode\n"); + mfd->mdp.configure_panel(mfd, 0); + mdss_fb_set_mdp_sync_pt_threshold(mfd); + pdata->panel_info.is_lpm_mode = false; + } + return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable); } @@ -2377,6 +2483,7 @@ static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd, int ret = -ENOSYS; struct mdp_buf_sync buf_sync; struct msm_sync_pt_data *sync_pt_data = NULL; + unsigned int dsi_mode = 0; if (!info || !info->par) return -EINVAL; @@ -2443,6 +2550,16 @@ static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd, ret = mdss_fb_display_commit(info, argp); break; + case MSMFB_LPM_ENABLE: + ret = copy_from_user(&dsi_mode, argp, sizeof(dsi_mode)); + if (ret) { + pr_err("%s: MSMFB_LPM_ENABLE ioctl failed\n", __func__); + goto exit; + } + + ret = mdss_fb_lpm_enable(mfd, dsi_mode); + break; + default: if (mfd->mdp.ioctl_handler) ret = mfd->mdp.ioctl_handler(mfd, cmd, argp); diff --git a/drivers/video/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h index ce0a7f9804e..5ab3d417857 100644 --- a/drivers/video/msm/mdss/mdss_fb.h +++ b/drivers/video/msm/mdss/mdss_fb.h @@ -129,6 +129,7 @@ struct msm_mdp_interface { struct msm_sync_pt_data *(*get_sync_fnc)(struct msm_fb_data_type *mfd, const struct mdp_buf_sync *buf_sync); void (*check_dsi_status)(struct work_struct *work, uint32_t interval); + int (*configure_panel)(struct msm_fb_data_type *mfd, int mode); void *private1; }; diff --git a/drivers/video/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c index 21416591d33..f371f9c6e2b 100644 --- a/drivers/video/msm/mdss/mdss_mdp_overlay.c +++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c @@ -3049,6 +3049,27 @@ static int __vsync_retire_setup(struct msm_fb_data_type *mfd) return 0; } +static int mdss_mdp_update_panel_info(struct msm_fb_data_type *mfd, int mode) +{ + int ret = 0; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdss_mdp_ctl *ctl = mdp5_data->ctl; + + ret = mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_DSI_DYNAMIC_SWITCH, + (void *)(unsigned long)mode); + if (ret) + pr_err("Dynamic switch to %s mode failed!\n", + mode ? "command" : "video"); + /* + * Destroy current ctrl sturcture as this is + * going to be re-initialized with the requested mode. + */ + mdss_mdp_ctl_destroy(mdp5_data->ctl); + mdp5_data->ctl = NULL; + + return 0; +} + int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) { struct device *dev = mfd->fbi->dev; @@ -3067,6 +3088,7 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) mdp5_interface->kickoff_fnc = mdss_mdp_overlay_kickoff; mdp5_interface->get_sync_fnc = mdss_mdp_rotator_sync_pt_get; mdp5_interface->splash_init_fnc = mdss_mdp_splash_init; + mdp5_interface->configure_panel = mdss_mdp_update_panel_info; mdp5_data = kmalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL); if (!mdp5_data) { @@ -3117,7 +3139,10 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) pr_err("Error dfps sysfs creation ret=%d\n", rc); goto init_fail; } - } else if (mfd->panel_info->type == MIPI_CMD_PANEL) { + } + + if (mfd->panel_info->mipi.dynamic_switch_enabled || + mfd->panel_info->type == MIPI_CMD_PANEL) { rc = __vsync_retire_setup(mfd); if (IS_ERR_VALUE(rc)) { pr_err("unable to create vsync timeline\n"); diff --git a/drivers/video/msm/mdss/mdss_panel.h b/drivers/video/msm/mdss/mdss_panel.h index c43cdd345a4..084cba4d65d 100644 --- a/drivers/video/msm/mdss/mdss_panel.h +++ b/drivers/video/msm/mdss/mdss_panel.h @@ -132,6 +132,10 @@ struct mdss_panel_recovery { * event arguments can have one of these values: * - 0: Disable ULPS mode * - 1: Enable ULPS mode + * @MDSS_EVENT_DSI_DYNAMIC_SWITCH: Event to update the dsi driver structures + * based on the dsi mode passed as argument. + * - 0: update to video mode + * - 1: update to command mode */ enum mdss_intf_events { MDSS_EVENT_RESET = 1, @@ -152,6 +156,7 @@ enum mdss_intf_events { MDSS_EVENT_ENABLE_PARTIAL_UPDATE, MDSS_EVENT_DSI_ULPS_CTRL, MDSS_EVENT_REGISTER_RECOVERY_HANDLER, + MDSS_EVENT_DSI_DYNAMIC_SWITCH, }; struct lcd_panel_info { @@ -222,6 +227,9 @@ struct mipi_panel_info { char stream; /* 0 or 1 */ char mdp_trigger; char dma_trigger; + /*Dynamic Switch Support*/ + bool dynamic_switch_enabled; + u32 pixel_packing; u32 dsi_pclk_rate; /* The packet-size should not bet changed */ char no_max_pkt_size; @@ -337,6 +345,9 @@ struct mdss_panel_info { u32 panel_power_on; uint32_t panel_dead; + bool dynamic_switch_pending; + bool is_lpm_mode; + struct mdss_mdp_pp_tear_check te; struct lcd_panel_info lcdc; diff --git a/drivers/video/msm/mdss/msm_mdss_io_8974.c b/drivers/video/msm/mdss/msm_mdss_io_8974.c index 34e383e984f..584ffe7f609 100644 --- a/drivers/video/msm/mdss/msm_mdss_io_8974.c +++ b/drivers/video/msm/mdss/msm_mdss_io_8974.c @@ -64,7 +64,8 @@ int mdss_dsi_clk_init(struct platform_device *pdev, goto mdss_dsi_clk_err; } - if (ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) { + if ((ctrl_pdata->panel_data.panel_info.type == MIPI_CMD_PANEL) || + ctrl_pdata->panel_data.panel_info.mipi.dynamic_switch_enabled) { ctrl_pdata->mmss_misc_ahb_clk = clk_get(dev, "core_mmss_clk"); if (IS_ERR(ctrl_pdata->mmss_misc_ahb_clk)) { rc = PTR_ERR(ctrl_pdata->mmss_misc_ahb_clk); diff --git a/include/linux/msm_mdp.h b/include/linux/msm_mdp.h index fd2cc6cecd8..b295fccd1ed 100644 --- a/include/linux/msm_mdp.h +++ b/include/linux/msm_mdp.h @@ -81,6 +81,7 @@ #define MSMFB_ASYNC_BLIT _IOW(MSMFB_IOCTL_MAGIC, 168, unsigned int) #define MSMFB_OVERLAY_PREPARE _IOWR(MSMFB_IOCTL_MAGIC, 169, \ struct mdp_overlay_list) +#define MSMFB_LPM_ENABLE _IOWR(MSMFB_IOCTL_MAGIC, 170, unsigned int) #define FB_TYPE_3D_PANEL 0x10101010 #define MDP_IMGTYPE2_START 0x10000 #define MSMFB_DRIVER_VERSION 0xF9E8D701