Loading Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +13 −1 Original line number Diff line number Diff line Loading @@ -328,7 +328,15 @@ Optional properties: "reg_read" = Reads panel status register to check the panel status - qcom,mdss-dsi-panel-status-value: Specifies the value of the panel status register when the panel is in good state. - 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. Loading Loading @@ -439,5 +447,9 @@ Example: qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; qcom,mdss-dsi-panel-status-check-mode = "reg_read"; qcom,mdss-dsi-panel-status-value = <0x9c>; 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]; }; }; drivers/video/msm/mdss/mdss_dsi.c +63 −8 Original line number Diff line number Diff line Loading @@ -76,6 +76,17 @@ 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) { /* * Current implementation of dynamic mode switch * relies on the GDSC to be disabled while switching. */ msm_dss_enable_vreg( ctrl_pdata->power_data[DSI_CORE_PM].vreg_config, ctrl_pdata->power_data[DSI_CORE_PM].num_vreg, enable); return 0; } if (enable) { for (i = 0; i < DSI_MAX_PM; i++) { ret = msm_dss_enable_vreg( Loading Loading @@ -655,6 +666,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) { Loading Loading @@ -885,12 +921,14 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata) mipi = &pdata->panel_info.mipi; if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) { 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; } } ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT; } Loading Loading @@ -939,16 +977,29 @@ 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) && mipi->vsync_enable && mipi->hw_vsync_mode) mdss_dsi_set_tear_off(ctrl_pdata); if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { 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; } Loading Loading @@ -1180,6 +1231,10 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, case MDSS_EVENT_DSI_ULPS_CTRL: rc = mdss_dsi_ulps_config(ctrl_pdata, (int)(unsigned long) arg); break; 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); break; Loading drivers/video/msm/mdss/mdss_dsi.h +6 −0 Original line number Diff line number Diff line Loading @@ -257,6 +257,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; Loading Loading @@ -301,6 +302,9 @@ struct mdss_dsi_ctrl_pdata { struct dsi_panel_cmds status_cmds; u32 status_value; struct dsi_panel_cmds video2cmd; struct dsi_panel_cmds cmd2video; struct dcs_cmd_list cmdlist; struct completion dma_comp; struct completion mdp_comp; Loading Loading @@ -385,6 +389,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); static inline const char *__mdss_dsi_pm_name(enum dsi_pm_type module) { Loading drivers/video/msm/mdss/mdss_dsi_panel.c +69 −9 Original line number Diff line number Diff line Loading @@ -336,6 +336,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) { Loading Loading @@ -543,11 +573,16 @@ static int mdss_dsi_parse_dcs_cmds(struct device_node *np, len -= dchdr->dlen; } /*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); Loading @@ -560,7 +595,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; Loading Loading @@ -809,6 +844,25 @@ static int mdss_dsi_parse_panel_features(struct device_node *np, pinfo->esd_check_enabled = of_property_read_bool(np, "qcom,esd-check-enabled"); 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; } Loading Loading @@ -866,9 +920,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", Loading Loading @@ -1160,9 +1216,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; } drivers/video/msm/mdss/mdss_fb.c +124 −8 Original line number Diff line number Diff line Loading @@ -100,6 +100,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; Loading Loading @@ -439,6 +440,90 @@ 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 | S_IWUSR, mdss_fb_show_split, Loading Loading @@ -584,6 +669,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; Loading @@ -598,15 +698,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; Loading Loading @@ -967,6 +1059,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); Loading @@ -977,6 +1070,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); } Loading Loading @@ -2626,6 +2731,7 @@ int mdss_fb_do_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; Loading Loading @@ -2692,6 +2798,16 @@ int mdss_fb_do_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); Loading Loading
Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +13 −1 Original line number Diff line number Diff line Loading @@ -328,7 +328,15 @@ Optional properties: "reg_read" = Reads panel status register to check the panel status - qcom,mdss-dsi-panel-status-value: Specifies the value of the panel status register when the panel is in good state. - 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. Loading Loading @@ -439,5 +447,9 @@ Example: qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode"; qcom,mdss-dsi-panel-status-check-mode = "reg_read"; qcom,mdss-dsi-panel-status-value = <0x9c>; 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]; }; };
drivers/video/msm/mdss/mdss_dsi.c +63 −8 Original line number Diff line number Diff line Loading @@ -76,6 +76,17 @@ 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) { /* * Current implementation of dynamic mode switch * relies on the GDSC to be disabled while switching. */ msm_dss_enable_vreg( ctrl_pdata->power_data[DSI_CORE_PM].vreg_config, ctrl_pdata->power_data[DSI_CORE_PM].num_vreg, enable); return 0; } if (enable) { for (i = 0; i < DSI_MAX_PM; i++) { ret = msm_dss_enable_vreg( Loading Loading @@ -655,6 +666,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) { Loading Loading @@ -885,12 +921,14 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata) mipi = &pdata->panel_info.mipi; if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) { 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; } } ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT; } Loading Loading @@ -939,16 +977,29 @@ 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) && mipi->vsync_enable && mipi->hw_vsync_mode) mdss_dsi_set_tear_off(ctrl_pdata); if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) { 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; } Loading Loading @@ -1180,6 +1231,10 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata, case MDSS_EVENT_DSI_ULPS_CTRL: rc = mdss_dsi_ulps_config(ctrl_pdata, (int)(unsigned long) arg); break; 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); break; Loading
drivers/video/msm/mdss/mdss_dsi.h +6 −0 Original line number Diff line number Diff line Loading @@ -257,6 +257,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; Loading Loading @@ -301,6 +302,9 @@ struct mdss_dsi_ctrl_pdata { struct dsi_panel_cmds status_cmds; u32 status_value; struct dsi_panel_cmds video2cmd; struct dsi_panel_cmds cmd2video; struct dcs_cmd_list cmdlist; struct completion dma_comp; struct completion mdp_comp; Loading Loading @@ -385,6 +389,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); static inline const char *__mdss_dsi_pm_name(enum dsi_pm_type module) { Loading
drivers/video/msm/mdss/mdss_dsi_panel.c +69 −9 Original line number Diff line number Diff line Loading @@ -336,6 +336,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) { Loading Loading @@ -543,11 +573,16 @@ static int mdss_dsi_parse_dcs_cmds(struct device_node *np, len -= dchdr->dlen; } /*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); Loading @@ -560,7 +595,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; Loading Loading @@ -809,6 +844,25 @@ static int mdss_dsi_parse_panel_features(struct device_node *np, pinfo->esd_check_enabled = of_property_read_bool(np, "qcom,esd-check-enabled"); 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; } Loading Loading @@ -866,9 +920,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", Loading Loading @@ -1160,9 +1216,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; }
drivers/video/msm/mdss/mdss_fb.c +124 −8 Original line number Diff line number Diff line Loading @@ -100,6 +100,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; Loading Loading @@ -439,6 +440,90 @@ 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 | S_IWUSR, mdss_fb_show_split, Loading Loading @@ -584,6 +669,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; Loading @@ -598,15 +698,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; Loading Loading @@ -967,6 +1059,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); Loading @@ -977,6 +1070,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); } Loading Loading @@ -2626,6 +2731,7 @@ int mdss_fb_do_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; Loading Loading @@ -2692,6 +2798,16 @@ int mdss_fb_do_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); Loading