Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0407f8a authored by Sandeep Panda's avatar Sandeep Panda Committed by Gerrit - the friendly Code Review server
Browse files

msm: mdss: Add support for dynamic mode switch



Add support for switching between dsi command mode and
video mode and vice versa at runtime. If the panel is
configured in video mode, it would be power efficient to
be able to dynamically switch to command mode on need
basis. This change adds the support by providing an IOCTL
to switch between video mode and command mode at runtime.

Change-Id: I573c063556d68d631fe27cc2d1447522eceb7f2a
Signed-off-by: default avatarSandeep Panda <spanda@codeaurora.org>
parent ddff1031
Loading
Loading
Loading
Loading
+13 −1
Original line number Original line Diff line number Diff line
@@ -328,7 +328,15 @@ Optional properties:
					"reg_read" = Reads panel status register to check the panel status
					"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
- qcom,mdss-dsi-panel-status-value:	Specifies the value of the panel status register when the panel is
					in good state.
					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
Note, if a given optional qcom,* binding is not present, then the driver will configure
the default values specified.
the default values specified.


@@ -439,5 +447,9 @@ Example:
		qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
		qcom,mdss-dsi-panel-status-command-state = "dsi_lp_mode";
		qcom,mdss-dsi-panel-status-check-mode = "reg_read";
		qcom,mdss-dsi-panel-status-check-mode = "reg_read";
		qcom,mdss-dsi-panel-status-value = <0x9c>;
		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];
	};
	};
};
};
+63 −8
Original line number Original line Diff line number Diff line
@@ -76,6 +76,17 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata, int enable)
				panel_data);
				panel_data);
	pr_debug("%s: enable=%d\n", __func__, enable);
	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) {
	if (enable) {
		for (i = 0; i < DSI_MAX_PM; i++) {
		for (i = 0; i < DSI_MAX_PM; i++) {
			ret = msm_dss_enable_vreg(
			ret = msm_dss_enable_vreg(
@@ -655,6 +666,31 @@ error:
	return ret;
	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,
static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl,
	int enable)
	int enable)
{
{
@@ -885,12 +921,14 @@ static int mdss_dsi_unblank(struct mdss_panel_data *pdata)
	mipi  = &pdata->panel_info.mipi;
	mipi  = &pdata->panel_info.mipi;


	if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
	if (!(ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT)) {
		if (!pdata->panel_info.dynamic_switch_pending) {
			ret = ctrl_pdata->on(pdata);
			ret = ctrl_pdata->on(pdata);
			if (ret) {
			if (ret) {
				pr_err("%s: unable to initialize the panel\n",
				pr_err("%s: unable to initialize the panel\n",
							__func__);
							__func__);
				return ret;
				return ret;
			}
			}
		}
		ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
		ctrl_pdata->ctrl_state |= CTRL_STATE_PANEL_INIT;
	}
	}


@@ -939,16 +977,29 @@ static int mdss_dsi_blank(struct mdss_panel_data *pdata)


	mdss_dsi_op_mode_config(DSI_CMD_MODE, 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 ((pdata->panel_info.type == MIPI_CMD_PANEL) &&
		mipi->vsync_enable && mipi->hw_vsync_mode)
		mipi->vsync_enable && mipi->hw_vsync_mode)
		mdss_dsi_set_tear_off(ctrl_pdata);
		mdss_dsi_set_tear_off(ctrl_pdata);


	if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
	if (ctrl_pdata->ctrl_state & CTRL_STATE_PANEL_INIT) {
		if (!pdata->panel_info.dynamic_switch_pending) {
			ret = ctrl_pdata->off(pdata);
			ret = ctrl_pdata->off(pdata);
			if (ret) {
			if (ret) {
				pr_err("%s: Panel OFF failed\n", __func__);
				pr_err("%s: Panel OFF failed\n", __func__);
				return ret;
				return ret;
			}
			}
		}
		ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
		ctrl_pdata->ctrl_state &= ~CTRL_STATE_PANEL_INIT;
	}
	}


@@ -1180,6 +1231,10 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
	case MDSS_EVENT_DSI_ULPS_CTRL:
	case MDSS_EVENT_DSI_ULPS_CTRL:
		rc = mdss_dsi_ulps_config(ctrl_pdata, (int)(unsigned long) arg);
		rc = mdss_dsi_ulps_config(ctrl_pdata, (int)(unsigned long) arg);
		break;
		break;
	case MDSS_EVENT_DSI_DYNAMIC_SWITCH:
		rc = mdss_dsi_update_panel_config(ctrl_pdata,
					(int)(unsigned long) arg);
		break;
	default:
	default:
		pr_debug("%s: unhandled event=%d\n", __func__, event);
		pr_debug("%s: unhandled event=%d\n", __func__, event);
		break;
		break;
+6 −0
Original line number Original line Diff line number Diff line
@@ -257,6 +257,7 @@ struct mdss_dsi_ctrl_pdata {
	int (*partial_update_fnc) (struct mdss_panel_data *pdata);
	int (*partial_update_fnc) (struct mdss_panel_data *pdata);
	int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
	int (*check_status) (struct mdss_dsi_ctrl_pdata *pdata);
	int (*cmdlist_commit)(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp);
	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;
	struct mdss_panel_data panel_data;
	unsigned char *ctrl_base;
	unsigned char *ctrl_base;
	struct dss_io_data ctrl_io;
	struct dss_io_data ctrl_io;
@@ -301,6 +302,9 @@ struct mdss_dsi_ctrl_pdata {
	struct dsi_panel_cmds status_cmds;
	struct dsi_panel_cmds status_cmds;
	u32 status_value;
	u32 status_value;


	struct dsi_panel_cmds video2cmd;
	struct dsi_panel_cmds cmd2video;

	struct dcs_cmd_list cmdlist;
	struct dcs_cmd_list cmdlist;
	struct completion dma_comp;
	struct completion dma_comp;
	struct completion mdp_comp;
	struct completion mdp_comp;
@@ -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,
int mdss_dsi_panel_init(struct device_node *node,
		struct mdss_dsi_ctrl_pdata *ctrl_pdata,
		struct mdss_dsi_ctrl_pdata *ctrl_pdata,
		bool cmd_cfg_cont_splash);
		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)
static inline const char *__mdss_dsi_pm_name(enum dsi_pm_type module)
{
{
+69 −9
Original line number Original line Diff line number Diff line
@@ -336,6 +336,36 @@ static int mdss_dsi_panel_partial_update(struct mdss_panel_data *pdata)
	return rc;
	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,
static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
							u32 bl_level)
							u32 bl_level)
{
{
@@ -543,11 +573,16 @@ static int mdss_dsi_parse_dcs_cmds(struct device_node *np,
		len -= dchdr->dlen;
		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);
		data = of_get_property(np, link_key, NULL);
		if (data && !strcmp(data, "dsi_hs_mode"))
		if (data && !strcmp(data, "dsi_hs_mode"))
			pcmds->link_state = DSI_HS_MODE;
			pcmds->link_state = DSI_HS_MODE;
		else
		else
			pcmds->link_state = DSI_LP_MODE;
			pcmds->link_state = DSI_LP_MODE;
	}


	pr_debug("%s: dcs_cmd=%x len=%d, cmd_cnt=%d link_state=%d\n", __func__,
	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);
		pcmds->buf[0], pcmds->blen, pcmds->cmd_cnt, pcmds->link_state);
@@ -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)
				char *dst_format)
{
{
	int rc = 0;
	int rc = 0;
@@ -809,6 +844,25 @@ static int mdss_dsi_parse_panel_features(struct device_node *np,
	pinfo->esd_check_enabled = of_property_read_bool(np,
	pinfo->esd_check_enabled = of_property_read_bool(np,
		"qcom,esd-check-enabled");
		"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;
	return 0;
}
}


@@ -866,9 +920,11 @@ static int mdss_panel_parse_dt(struct device_node *np,
	tmp = 0;
	tmp = 0;
	data = of_get_property(np, "qcom,mdss-dsi-pixel-packing", NULL);
	data = of_get_property(np, "qcom,mdss-dsi-pixel-packing", NULL);
	if (data && !strcmp(data, "loose"))
	if (data && !strcmp(data, "loose"))
		tmp = 1;
		pinfo->mipi.pixel_packing = 1;
	rc = mdss_panel_dt_get_dst_fmt(pinfo->bpp,
	else
		pinfo->mipi.mode, tmp,
		pinfo->mipi.pixel_packing = 0;
	rc = mdss_panel_get_dst_fmt(pinfo->bpp,
		pinfo->mipi.mode, pinfo->mipi.pixel_packing,
		&(pinfo->mipi.dst_format));
		&(pinfo->mipi.dst_format));
	if (rc) {
	if (rc) {
		pr_debug("%s: problem determining dst format. Set Default\n",
		pr_debug("%s: problem determining dst format. Set Default\n",
@@ -1160,9 +1216,13 @@ int mdss_dsi_panel_init(struct device_node *node,
	pr_info("%s: Continuous splash %s", __func__,
	pr_info("%s: Continuous splash %s", __func__,
		pinfo->cont_splash_enabled ? "enabled" : "disabled");
		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->on = mdss_dsi_panel_on;
	ctrl_pdata->off = mdss_dsi_panel_off;
	ctrl_pdata->off = mdss_dsi_panel_off;
	ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
	ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
	ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode;


	return 0;
	return 0;
}
}
+124 −8
Original line number Original line Diff line number Diff line
@@ -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_pan_idle(struct msm_fb_data_type *mfd);
static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
					int event, void *arg);
					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)
void mdss_fb_no_update_notify_timer_cb(unsigned long data)
{
{
	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
@@ -439,6 +440,90 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev,


	return ret;
	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_type, S_IRUGO, mdss_fb_get_type, NULL);
static DEVICE_ATTR(msm_fb_split, S_IRUGO | S_IWUSR, mdss_fb_show_split,
static DEVICE_ATTR(msm_fb_split, S_IRUGO | S_IWUSR, mdss_fb_show_split,
@@ -584,6 +669,21 @@ static int mdss_fb_probe(struct platform_device *pdev)
			__mdss_fb_sync_buf_done_callback;
			__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) {
	switch (mfd->panel.type) {
	case WRITEBACK_PANEL:
	case WRITEBACK_PANEL:
		mfd->mdp_sync_pt_data.threshold = 1;
		mfd->mdp_sync_pt_data.threshold = 1;
@@ -598,15 +698,7 @@ static int mdss_fb_probe(struct platform_device *pdev)
		mfd->mdp_sync_pt_data.retire_threshold = 0;
		mfd->mdp_sync_pt_data.retire_threshold = 0;
		break;
		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)
static int mdss_fb_remove(struct platform_device *pdev)
{
{
	struct msm_fb_data_type *mfd;
	struct msm_fb_data_type *mfd;
@@ -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)
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;
	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;


	mdss_fb_pan_idle(mfd);
	mdss_fb_pan_idle(mfd);
@@ -977,6 +1070,18 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info)
			mfd->suspend.panel_power_on = false;
			mfd->suspend.panel_power_on = false;
		return 0;
		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);
	return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
}
}


@@ -2626,6 +2731,7 @@ int mdss_fb_do_ioctl(struct fb_info *info, unsigned int cmd,
	int ret = -ENOSYS;
	int ret = -ENOSYS;
	struct mdp_buf_sync buf_sync;
	struct mdp_buf_sync buf_sync;
	struct msm_sync_pt_data *sync_pt_data = NULL;
	struct msm_sync_pt_data *sync_pt_data = NULL;
	unsigned int dsi_mode = 0;


	if (!info || !info->par)
	if (!info || !info->par)
		return -EINVAL;
		return -EINVAL;
@@ -2692,6 +2798,16 @@ int mdss_fb_do_ioctl(struct fb_info *info, unsigned int cmd,
		ret = mdss_fb_display_commit(info, argp);
		ret = mdss_fb_display_commit(info, argp);
		break;
		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:
	default:
		if (mfd->mdp.ioctl_handler)
		if (mfd->mdp.ioctl_handler)
			ret = mfd->mdp.ioctl_handler(mfd, cmd, argp);
			ret = mfd->mdp.ioctl_handler(mfd, cmd, argp);
Loading