From e6819350df12347fef0cf492102a38dda0cfcee3 Mon Sep 17 00:00:00 2001 From: Yahui Wang Date: Mon, 12 Dec 2016 15:50:38 +0800 Subject: [PATCH] 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 --- .../devicetree/bindings/fb/mdss-dsi-panel.txt | 27 ++++++ ...anel-s6e3ha3-amoled-dualmipi-wqhd-cmd.dtsi | 56 +++++++++++- drivers/video/fbdev/msm/mdss_dsi.h | 2 + drivers/video/fbdev/msm/mdss_dsi_panel.c | 66 ++++++++++++++ drivers/video/fbdev/msm/mdss_fb.c | 87 ++++++++++++++++++- drivers/video/fbdev/msm/mdss_fb.h | 3 +- drivers/video/fbdev/msm/mdss_panel.h | 11 ++- 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 @@ -117,6 +117,11 @@ enum { MDSS_PANEL_BLANK_LOW_POWER, }; +enum { + MDSS_PANEL_LOW_PERSIST_MODE_OFF = 0, + MDSS_PANEL_LOW_PERSIST_MODE_ON, +}; + enum { MODE_GPIO_NOT_VALID = 0, MODE_SEL_DUAL_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; /**