msm: mdss: Add low persistence mode support for display

Snapshot of low persistence mode changes as of
26cfe58bd94a ("msm: mdss: Add support for low persistence
display mode") and a805a3e1e791 ("arm64/dts: angler: Don't
blank screen when leaving low persistence mode"), to add
low persistence mode support for display. Also, add some
changes to optimize the implementation for LP mode and
fix crash issue when VR APP is up.

CRs-Fixed: 1104888 1108207
Change-Id: I509fb5c87d93e2416882942a226cb9b48bc1d3bf
Signed-off-by: Yahui Wang <yahuiw@codeaurora.org>
This commit is contained in:
Yahui Wang 2016-12-12 15:50:38 +08:00
parent d9ac8efbd9
commit e6819350df
7 changed files with 246 additions and 6 deletions

View file

@ -61,6 +61,30 @@ Required properties:
transmitted transmitted
byte 5, 6: 16 bits length in network byte order byte 5, 6: 16 bits length in network byte order
byte 7 and beyond: number byte of payload byte 7 and beyond: number byte of payload
- qcom,mdss-dsi-lp-mode-on: This is used to enable display low persistence mode.
A byte stream formed by multiple dcs packets base on
qcom dsi controller protocol.
byte 0: dcs data type
byte 1: set to indicate this is an individual packet
(no chain)
byte 2: virtual channel number
byte 3: expect ack from client (dcs read command)
byte 4: wait number of specified ms after dcs command
transmitted
byte 5, 6: 16 bits length in network byte order
byte 7 and beyond: number byte of payload
- qcom,mdss-dsi-lp-mode-off: This is used to disable display low persistence mode.
A byte stream formed by multiple dcs packets base on
qcom dsi controller protocol.
byte 0: dcs data type
byte 1: set to indicate this is an individual packet
(no chain)
byte 2: virtual channel number
byte 3: expect ack from client (dcs read command)
byte 4: wait number of specified ms after dcs command
transmitted
byte 5, 6: 16 bits length in network byte order
byte 7 and beyond: number byte of payload
- qcom,mdss-dsi-post-panel-on-command: same as "qcom,mdss-dsi-on-command" except commands are - qcom,mdss-dsi-post-panel-on-command: same as "qcom,mdss-dsi-on-command" except commands are
sent after displaying an image. sent after displaying an image.
@ -648,6 +672,9 @@ Example:
qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00]; qcom,mdss-dsi-off-command = [22 01 00 00 00 00 00];
qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-lp-mode-on = [32 01 00 00 00 00 02 00 00
29 01 00 00 10 00 02 FF 99];
qcom,mdss-dsi-lp-mode-off = [22 01 00 00 00 00 00];
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled"; qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode"; qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -57,6 +57,60 @@
05 01 00 00 b4 00 02 10 00]; 05 01 00 00 b4 00 02 10 00];
qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; qcom,mdss-dsi-on-command-state = "dsi_lp_mode";
qcom,mdss-dsi-off-command-state = "dsi_hs_mode"; qcom,mdss-dsi-off-command-state = "dsi_hs_mode";
qcom,mdss-dsi-lp-mode-on = [39 00 00 00 05 00 03 f0 5a 5a
39 00 00 00 05 00 03 f1 5a 5a
39 00 00 00 05 00 03 fc 5a 5a
39 00 00 00 05 00 02 b0 17
39 00 00 00 05 00 02 cb 10
39 00 00 00 05 00 02 b0 2d
39 00 00 00 05 00 02 cb cd
39 00 00 00 05 00 02 b0 0e
39 00 00 00 05 00 02 cb 02
39 00 00 00 05 00 02 b0 0f
39 00 00 00 05 00 02 cb 09
39 00 00 00 05 00 02 b0 02
39 00 00 00 05 00 02 f2 c9
39 00 00 00 05 00 02 b0 03
39 00 00 00 05 00 02 f2 c0
39 00 00 00 05 00 02 b0 03
39 00 00 00 05 00 02 f4 aa
39 00 00 00 05 00 02 b0 08
39 00 00 00 05 00 02 b1 30
39 00 00 00 05 00 02 b0 09
39 00 00 00 05 00 02 b1 0a
39 00 00 00 05 00 02 b0 0d
39 00 00 00 05 00 02 b1 10
39 00 00 00 05 00 02 b0 00
39 00 00 00 05 00 02 f7 03
39 00 00 00 05 00 02 fe 30
39 01 00 00 05 00 02 fe b0];
qcom,mdss-dsi-lp-mode-off = [39 00 00 00 05 00 03 f0 5a 5a
39 00 00 00 05 00 03 f1 5a 5a
39 00 00 00 05 00 03 fc 5a 5a
39 00 00 00 05 00 02 b0 2d
39 00 00 00 05 00 02 cb 4d
39 00 00 00 05 00 02 b0 17
39 00 00 00 05 00 02 cb 04
39 00 00 00 05 00 02 b0 0e
39 00 00 00 05 00 02 cb 06
39 00 00 00 05 00 02 b0 0f
39 00 00 00 05 00 02 cb 05
39 00 00 00 05 00 02 b0 02
39 00 00 00 05 00 02 f2 b8
39 00 00 00 05 00 02 b0 03
39 00 00 00 05 00 02 f2 80
39 00 00 00 05 00 02 b0 03
39 00 00 00 05 00 02 f4 8a
39 00 00 00 05 00 02 b0 08
39 00 00 00 05 00 02 b1 10
39 00 00 00 05 00 02 b0 09
39 00 00 00 05 00 02 b1 0a
39 00 00 00 05 00 02 b0 0d
39 00 00 00 05 00 02 b1 80
39 00 00 00 05 00 02 b0 00
39 00 00 00 05 00 02 f7 03
39 00 00 00 05 00 02 fe 30
39 01 00 00 05 00 02 fe b0];
qcom,mdss-dsi-h-sync-pulse = <0>; qcom,mdss-dsi-h-sync-pulse = <0>;
qcom,mdss-dsi-traffic-mode = "non_burst_sync_event"; qcom,mdss-dsi-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-lane-map = "lane_map_0123"; qcom,mdss-dsi-lane-map = "lane_map_0123";

View file

@ -487,6 +487,8 @@ struct mdss_dsi_ctrl_pdata {
struct dsi_panel_cmds post_dms_on_cmds; struct dsi_panel_cmds post_dms_on_cmds;
struct dsi_panel_cmds post_panel_on_cmds; struct dsi_panel_cmds post_panel_on_cmds;
struct dsi_panel_cmds off_cmds; struct dsi_panel_cmds off_cmds;
struct dsi_panel_cmds lp_on_cmds;
struct dsi_panel_cmds lp_off_cmds;
struct dsi_panel_cmds status_cmds; struct dsi_panel_cmds status_cmds;
u32 *status_valid_params; u32 *status_valid_params;
u32 *status_cmds_rlen; u32 *status_cmds_rlen;

View file

@ -160,6 +160,27 @@ int mdss_dsi_panel_cmd_read(struct mdss_dsi_ctrl_pdata *ctrl, char cmd0,
return mdss_dsi_cmdlist_put(ctrl, &cmdreq); return mdss_dsi_cmdlist_put(ctrl, &cmdreq);
} }
static void mdss_dsi_panel_apply_settings(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_panel_cmds *pcmds)
{
struct dcs_cmd_req cmdreq;
struct mdss_panel_info *pinfo;
pinfo = &(ctrl->panel_data.panel_info);
if ((pinfo->dcs_cmd_by_left) && (ctrl->ndx != DSI_CTRL_LEFT))
return;
memset(&cmdreq, 0, sizeof(cmdreq));
cmdreq.cmds = pcmds->cmds;
cmdreq.cmds_cnt = pcmds->cmd_cnt;
cmdreq.flags = CMD_REQ_COMMIT;
cmdreq.rlen = 0;
cmdreq.cb = NULL;
mdss_dsi_cmdlist_put(ctrl, &cmdreq);
}
static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl, static void mdss_dsi_panel_cmds_send(struct mdss_dsi_ctrl_pdata *ctrl,
struct dsi_panel_cmds *pcmds, u32 flags) struct dsi_panel_cmds *pcmds, u32 flags)
{ {
@ -660,6 +681,38 @@ end:
return 0; return 0;
} }
static int mdss_dsi_panel_apply_display_setting(struct mdss_panel_data *pdata,
u32 mode)
{
struct mdss_dsi_ctrl_pdata *ctrl = NULL;
struct dsi_panel_cmds *lp_on_cmds;
struct dsi_panel_cmds *lp_off_cmds;
if (pdata == NULL) {
pr_err("%s: Invalid input data\n", __func__);
return -EINVAL;
}
ctrl = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
lp_on_cmds = &ctrl->lp_on_cmds;
lp_off_cmds = &ctrl->lp_off_cmds;
/* Apply display settings for low-persistence mode */
if ((mode == MDSS_PANEL_LOW_PERSIST_MODE_ON) &&
(lp_on_cmds->cmd_cnt))
mdss_dsi_panel_apply_settings(ctrl, lp_on_cmds);
else if ((mode == MDSS_PANEL_LOW_PERSIST_MODE_OFF) &&
(lp_on_cmds->cmd_cnt))
mdss_dsi_panel_apply_settings(ctrl, lp_off_cmds);
else
return -EINVAL;
pr_debug("%s: Persistence mode %d applied\n", __func__, mode);
return 0;
}
static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata, static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata,
int mode) int mode)
{ {
@ -822,6 +875,10 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
if (ctrl->ds_registered) if (ctrl->ds_registered)
mdss_dba_utils_video_on(pinfo->dba_data, pinfo); mdss_dba_utils_video_on(pinfo->dba_data, pinfo);
/* Ensure low persistence mode is set as before */
mdss_dsi_panel_apply_display_setting(pdata, pinfo->persist_mode);
end: end:
pr_debug("%s:-\n", __func__); pr_debug("%s:-\n", __func__);
return ret; return ret;
@ -2046,6 +2103,12 @@ static int mdss_dsi_parse_panel_features(struct device_node *np,
__func__, __LINE__); __func__, __LINE__);
} }
mdss_dsi_parse_dcs_cmds(np, &ctrl->lp_on_cmds,
"qcom,mdss-dsi-lp-mode-on", NULL);
mdss_dsi_parse_dcs_cmds(np, &ctrl->lp_off_cmds,
"qcom,mdss-dsi-lp-mode-off", NULL);
return 0; return 0;
} }
@ -2796,12 +2859,15 @@ int mdss_dsi_panel_init(struct device_node *node,
pinfo->dynamic_switch_pending = false; pinfo->dynamic_switch_pending = false;
pinfo->is_lpm_mode = false; pinfo->is_lpm_mode = false;
pinfo->esd_rdy = false; pinfo->esd_rdy = false;
pinfo->persist_mode = false;
ctrl_pdata->on = mdss_dsi_panel_on; ctrl_pdata->on = mdss_dsi_panel_on;
ctrl_pdata->post_panel_on = mdss_dsi_post_panel_on; ctrl_pdata->post_panel_on = mdss_dsi_post_panel_on;
ctrl_pdata->off = mdss_dsi_panel_off; ctrl_pdata->off = mdss_dsi_panel_off;
ctrl_pdata->low_power_config = mdss_dsi_panel_low_power_config; ctrl_pdata->low_power_config = mdss_dsi_panel_low_power_config;
ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl; ctrl_pdata->panel_data.set_backlight = mdss_dsi_panel_bl_ctrl;
ctrl_pdata->panel_data.apply_display_setting =
mdss_dsi_panel_apply_display_setting;
ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode; ctrl_pdata->switch_mode = mdss_dsi_panel_switch_mode;
return 0; return 0;

View file

@ -1,8 +1,8 @@
/* /*
* Core MDSS framebuffer driver. * Core MDSS framebuffer driver.
* *
* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
* Copyright (C) 2007 Google Incorporated * Copyright (C) 2007 Google Incorporated
* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
* *
* This software is licensed under the terms of the GNU General Public * This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and * License version 2, as published by the Free Software Foundation, and
@ -823,6 +823,74 @@ static ssize_t mdss_fb_get_dfps_mode(struct device *dev,
return ret; return ret;
} }
static ssize_t mdss_fb_change_persist_mode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
{
struct fb_info *fbi = dev_get_drvdata(dev);
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
struct mdss_panel_info *pinfo = NULL;
struct mdss_panel_data *pdata;
int ret = 0;
u32 persist_mode;
if (!mfd || !mfd->panel_info) {
pr_err("%s: Panel info is NULL!\n", __func__);
return len;
}
pinfo = mfd->panel_info;
if (kstrtouint(buf, 0, &persist_mode)) {
pr_err("kstrtouint buf error!\n");
return len;
}
mutex_lock(&mfd->mdss_sysfs_lock);
if (mdss_panel_is_power_off(mfd->panel_power_state)) {
pinfo->persist_mode = persist_mode;
goto end;
}
mutex_lock(&mfd->bl_lock);
pdata = dev_get_platdata(&mfd->pdev->dev);
if ((pdata) && (pdata->apply_display_setting))
ret = pdata->apply_display_setting(pdata, persist_mode);
mutex_unlock(&mfd->bl_lock);
if (!ret) {
pr_debug("%s: Persist mode %d\n", __func__, persist_mode);
pinfo->persist_mode = persist_mode;
}
end:
mutex_unlock(&mfd->mdss_sysfs_lock);
return len;
}
static ssize_t mdss_fb_get_persist_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct fb_info *fbi = dev_get_drvdata(dev);
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)fbi->par;
struct mdss_panel_data *pdata;
struct mdss_panel_info *pinfo;
int ret;
pdata = dev_get_platdata(&mfd->pdev->dev);
if (!pdata) {
pr_err("no panel connected!\n");
return -EINVAL;
}
pinfo = &pdata->panel_info;
ret = scnprintf(buf, PAGE_SIZE, "%d\n", pinfo->persist_mode);
return ret;
}
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,
mdss_fb_store_split); mdss_fb_store_split);
@ -841,6 +909,8 @@ static DEVICE_ATTR(msm_fb_dfps_mode, S_IRUGO | S_IWUSR,
mdss_fb_get_dfps_mode, mdss_fb_change_dfps_mode); mdss_fb_get_dfps_mode, mdss_fb_change_dfps_mode);
static DEVICE_ATTR(measured_fps, S_IRUGO | S_IWUSR | S_IWGRP, static DEVICE_ATTR(measured_fps, S_IRUGO | S_IWUSR | S_IWGRP,
mdss_fb_get_fps_info, NULL); mdss_fb_get_fps_info, NULL);
static DEVICE_ATTR(msm_fb_persist_mode, S_IRUGO | S_IWUSR,
mdss_fb_get_persist_mode, mdss_fb_change_persist_mode);
static struct attribute *mdss_fb_attrs[] = { static struct attribute *mdss_fb_attrs[] = {
&dev_attr_msm_fb_type.attr, &dev_attr_msm_fb_type.attr,
&dev_attr_msm_fb_split.attr, &dev_attr_msm_fb_split.attr,
@ -853,6 +923,7 @@ static struct attribute *mdss_fb_attrs[] = {
&dev_attr_msm_fb_panel_status.attr, &dev_attr_msm_fb_panel_status.attr,
&dev_attr_msm_fb_dfps_mode.attr, &dev_attr_msm_fb_dfps_mode.attr,
&dev_attr_measured_fps.attr, &dev_attr_measured_fps.attr,
&dev_attr_msm_fb_persist_mode.attr,
NULL, NULL,
}; };
@ -1203,6 +1274,7 @@ static int mdss_fb_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&mfd->file_list); INIT_LIST_HEAD(&mfd->file_list);
mutex_init(&mfd->bl_lock); mutex_init(&mfd->bl_lock);
mutex_init(&mfd->mdss_sysfs_lock);
mutex_init(&mfd->switch_lock); mutex_init(&mfd->switch_lock);
fbi_list[fbi_list_index++] = fbi; fbi_list[fbi_list_index++] = fbi;
@ -1971,6 +2043,8 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info)
return ret; return ret;
} }
mutex_lock(&mfd->mdss_sysfs_lock);
if (mfd->op_enable == 0) { if (mfd->op_enable == 0) {
if (blank_mode == FB_BLANK_UNBLANK) if (blank_mode == FB_BLANK_UNBLANK)
mfd->suspend.panel_power_state = MDSS_PANEL_POWER_ON; mfd->suspend.panel_power_state = MDSS_PANEL_POWER_ON;
@ -1980,7 +2054,9 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info)
mfd->suspend.panel_power_state = MDSS_PANEL_POWER_LP1; mfd->suspend.panel_power_state = MDSS_PANEL_POWER_LP1;
else else
mfd->suspend.panel_power_state = MDSS_PANEL_POWER_OFF; mfd->suspend.panel_power_state = MDSS_PANEL_POWER_OFF;
return 0;
ret = 0;
goto end;
} }
pr_debug("mode: %d\n", blank_mode); pr_debug("mode: %d\n", blank_mode);
@ -1997,7 +2073,12 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info)
if (pdata->panel_disable_mode) if (pdata->panel_disable_mode)
mdss_mdp_enable_panel_disable_mode(mfd, false); mdss_mdp_enable_panel_disable_mode(mfd, false);
return mdss_fb_blank_sub(blank_mode, info, mfd->op_enable); ret = mdss_fb_blank_sub(blank_mode, info, mfd->op_enable);
end:
mutex_unlock(&mfd->mdss_sysfs_lock);
return ret;
} }
static inline int mdss_fb_create_ion_client(struct msm_fb_data_type *mfd) static inline int mdss_fb_create_ion_client(struct msm_fb_data_type *mfd)

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -310,6 +310,7 @@ struct msm_fb_data_type {
bool allow_bl_update; bool allow_bl_update;
u32 bl_level_scaled; u32 bl_level_scaled;
struct mutex bl_lock; struct mutex bl_lock;
struct mutex mdss_sysfs_lock;
bool ipc_resume; bool ipc_resume;
struct platform_device *pdev; struct platform_device *pdev;

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved. /* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and * it under the terms of the GNU General Public License version 2 and
@ -117,6 +117,11 @@ enum {
MDSS_PANEL_BLANK_LOW_POWER, MDSS_PANEL_BLANK_LOW_POWER,
}; };
enum {
MDSS_PANEL_LOW_PERSIST_MODE_OFF = 0,
MDSS_PANEL_LOW_PERSIST_MODE_ON,
};
enum { enum {
MODE_GPIO_NOT_VALID = 0, MODE_GPIO_NOT_VALID = 0,
MODE_SEL_DUAL_PORT, MODE_SEL_DUAL_PORT,
@ -892,6 +897,9 @@ struct mdss_panel_info {
/* debugfs structure for the panel */ /* debugfs structure for the panel */
struct mdss_panel_debugfs_info *debugfs_info; struct mdss_panel_debugfs_info *debugfs_info;
/* persistence mode on/off */
bool persist_mode;
/* stores initial adaptive variable refresh vtotal value */ /* stores initial adaptive variable refresh vtotal value */
u32 saved_avr_vtotal; u32 saved_avr_vtotal;
@ -936,6 +944,7 @@ struct mdss_panel_timing {
struct mdss_panel_data { struct mdss_panel_data {
struct mdss_panel_info panel_info; struct mdss_panel_info panel_info;
void (*set_backlight) (struct mdss_panel_data *pdata, u32 bl_level); void (*set_backlight) (struct mdss_panel_data *pdata, u32 bl_level);
int (*apply_display_setting)(struct mdss_panel_data *pdata, u32 mode);
unsigned char *mmss_cc_base; unsigned char *mmss_cc_base;
/** /**