summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSandeep Panda <spanda@codeaurora.org>2014-04-09 17:15:37 +0530
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:30:04 -0700
commit41211cdb1fff1102c7724bffbea88100a3352030 (patch)
tree55f9851426c8a350ac05167032935a2ec3298bf1
parent6e50390b3f95462e7791b85b11bcf6b8034ce2b6 (diff)
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: Sandeep Panda <spanda@codeaurora.org>
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c71
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h6
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c78
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c132
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c27
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h10
-rw-r--r--drivers/video/fbdev/msm/msm_mdss_io_8974.c3
-rw-r--r--include/uapi/linux/msm_mdp.h1
9 files changed, 302 insertions, 27 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 768580db14bd..38d46d0dba8d 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -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(
@@ -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)
{
@@ -885,11 +921,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;
}
@@ -939,15 +977,28 @@ 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) {
- 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;
}
@@ -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;
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 6a4d98c4b85c..d97ac9399192 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -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;
@@ -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;
@@ -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)
{
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 5d1911edad80..6b204337a52b 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -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)
{
@@ -543,11 +573,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);
@@ -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;
@@ -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;
}
@@ -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",
@@ -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;
}
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index fa0527df5813..af3a0e5dbd48 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -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;
@@ -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,
@@ -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;
@@ -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;
@@ -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);
@@ -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);
}
@@ -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;
@@ -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);
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index 0db60893ba54..1570af4292fa 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -132,6 +132,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/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 540ad0027dab..76eceb4de5e3 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -3436,6 +3436,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;
@@ -3454,6 +3475,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 = kzalloc(sizeof(struct mdss_overlay_private), GFP_KERNEL);
if (!mdp5_data) {
@@ -3513,7 +3535,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/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 315d873ef598..9bdcaff99062 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -139,6 +139,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,
@@ -158,6 +162,7 @@ enum mdss_intf_events {
MDSS_EVENT_DSI_CMDLIST_KOFF,
MDSS_EVENT_ENABLE_PARTIAL_UPDATE,
MDSS_EVENT_DSI_ULPS_CTRL,
+ MDSS_EVENT_DSI_DYNAMIC_SWITCH,
};
struct lcd_panel_info {
@@ -229,6 +234,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;
@@ -343,6 +351,8 @@ 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;
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index fac62425a3d2..1edd23284c87 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -62,7 +62,8 @@ int mdss_dsi_clk_init(struct platform_device *pdev,
goto mdss_dsi_clk_err;
}
- if (ctrl->panel_data.panel_info.type == MIPI_CMD_PANEL) {
+ if ((ctrl->panel_data.panel_info.type == MIPI_CMD_PANEL) ||
+ ctrl->panel_data.panel_info.mipi.dynamic_switch_enabled) {
ctrl->mmss_misc_ahb_clk = clk_get(dev, "core_mmss_clk");
if (IS_ERR(ctrl->mmss_misc_ahb_clk)) {
ctrl->mmss_misc_ahb_clk = NULL;
diff --git a/include/uapi/linux/msm_mdp.h b/include/uapi/linux/msm_mdp.h
index 8300297dec35..2075a285622a 100644
--- a/include/uapi/linux/msm_mdp.h
+++ b/include/uapi/linux/msm_mdp.h
@@ -71,6 +71,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