summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt27
-rw-r--r--arch/arm/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi56
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h2
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c66
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c87
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h3
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h11
7 files changed, 246 insertions, 6 deletions
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
index 52ffbe5c7207..b676efe97b8b 100644
--- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
+++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
@@ -61,6 +61,30 @@ Required properties:
transmitted
byte 5, 6: 16 bits length in network byte order
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
sent after displaying an image.
@@ -648,6 +672,9 @@ Example:
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-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-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";
diff --git a/arch/arm/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi b/arch/arm/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi
index 7bd844ae6770..6d91e72851ec 100644
--- a/arch/arm/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi
+++ b/arch/arm/boot/dts/qcom/dsi-panel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi
@@ -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
* 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];
qcom,mdss-dsi-on-command-state = "dsi_lp_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-traffic-mode = "non_burst_sync_event";
qcom,mdss-dsi-lane-map = "lane_map_0123";
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 0574410868bf..81d2723d0f2a 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -487,6 +487,8 @@ struct mdss_dsi_ctrl_pdata {
struct dsi_panel_cmds post_dms_on_cmds;
struct dsi_panel_cmds post_panel_on_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;
u32 *status_valid_params;
u32 *status_cmds_rlen;
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 7f6cad3de18e..7cc9ce6e034d 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -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);
}
+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,
struct dsi_panel_cmds *pcmds, u32 flags)
{
@@ -660,6 +681,38 @@ end:
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,
int mode)
{
@@ -822,6 +875,10 @@ static int mdss_dsi_panel_on(struct mdss_panel_data *pdata)
if (ctrl->ds_registered)
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:
pr_debug("%s:-\n", __func__);
return ret;
@@ -2046,6 +2103,12 @@ static int mdss_dsi_parse_panel_features(struct device_node *np,
__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;
}
@@ -2796,12 +2859,15 @@ int mdss_dsi_panel_init(struct device_node *node,
pinfo->dynamic_switch_pending = false;
pinfo->is_lpm_mode = false;
pinfo->esd_rdy = false;
+ pinfo->persist_mode = false;
ctrl_pdata->on = mdss_dsi_panel_on;
ctrl_pdata->post_panel_on = mdss_dsi_post_panel_on;
ctrl_pdata->off = mdss_dsi_panel_off;
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.apply_display_setting =
+ mdss_dsi_panel_apply_display_setting;
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 f20248e13cf8..cb0fcbafb8b4 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -1,8 +1,8 @@
/*
* Core MDSS framebuffer driver.
*
+ * Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
* 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
* 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;
}
+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_split, S_IRUGO | S_IWUSR, mdss_fb_show_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);
static DEVICE_ATTR(measured_fps, S_IRUGO | S_IWUSR | S_IWGRP,
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[] = {
&dev_attr_msm_fb_type.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_dfps_mode.attr,
&dev_attr_measured_fps.attr,
+ &dev_attr_msm_fb_persist_mode.attr,
NULL,
};
@@ -1203,6 +1274,7 @@ static int mdss_fb_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&mfd->file_list);
mutex_init(&mfd->bl_lock);
+ mutex_init(&mfd->mdss_sysfs_lock);
mutex_init(&mfd->switch_lock);
fbi_list[fbi_list_index++] = fbi;
@@ -1971,6 +2043,8 @@ static int mdss_fb_blank(int blank_mode, struct fb_info *info)
return ret;
}
+ mutex_lock(&mfd->mdss_sysfs_lock);
+
if (mfd->op_enable == 0) {
if (blank_mode == FB_BLANK_UNBLANK)
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;
else
mfd->suspend.panel_power_state = MDSS_PANEL_POWER_OFF;
- return 0;
+
+ ret = 0;
+ goto end;
}
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)
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)
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index 1487c4e7f6e2..656b58eb62d7 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -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
* 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;
u32 bl_level_scaled;
struct mutex bl_lock;
+ struct mutex mdss_sysfs_lock;
bool ipc_resume;
struct platform_device *pdev;
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 4698d441f365..9c4c9fb3e906 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -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
* it under the terms of the GNU General Public License version 2 and
@@ -118,6 +118,11 @@ enum {
};
enum {
+ MDSS_PANEL_LOW_PERSIST_MODE_OFF = 0,
+ MDSS_PANEL_LOW_PERSIST_MODE_ON,
+};
+
+enum {
MODE_GPIO_NOT_VALID = 0,
MODE_SEL_DUAL_PORT,
MODE_SEL_SINGLE_PORT,
@@ -892,6 +897,9 @@ struct mdss_panel_info {
/* debugfs structure for the panel */
struct mdss_panel_debugfs_info *debugfs_info;
+ /* persistence mode on/off */
+ bool persist_mode;
+
/* stores initial adaptive variable refresh vtotal value */
u32 saved_avr_vtotal;
@@ -936,6 +944,7 @@ struct mdss_panel_timing {
struct mdss_panel_data {
struct mdss_panel_info panel_info;
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;
/**