forked from rubenslte/android_kernel_samsung_msm8226
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: I23f0cadc0f76e0b4406c8156c3cca40782686bf0 Signed-off-by: Sandeep Panda <spanda@codeaurora.org> Signed-off-by: Shivaraj Shetty <shivaraj@codeaurora.org>
This commit is contained in:
committed by
Gerrit - the friendly Code Review server
parent
81dac7d9a6
commit
d87db9ae68
@@ -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];
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user