diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index 68b8f09238e0..56ad8c361219 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -350,8 +350,13 @@ the fps window. as below: --> Reset GPIO value --> Sleep value (in ms) -- qcom,partial-update-enabled: Boolean used to enable partial +- qcom,partial-update-enabled: String used to enable partial panel update for command mode panels. + "none": partial update is disabled + "single_roi": default enable mode, only single roi is sent to panel + "dual_roi": two rois are merged into one big roi. Panel ddic should be able + to process two roi's along with the DCS command to send two rois. + disabled if property is not specified. - qcom,mdss-dsi-horizontal-line-idle: List of width ranges (EC - SC) in pixels indicating additional idle time in dsi clock cycles that is needed to compensate for smaller line width. @@ -632,7 +637,7 @@ Example: qcom,mdss-tear-check-rd-ptr-trigger-intr = <1281>; qcom,mdss-tear-check-frame-rate = <6000>; qcom,mdss-dsi-reset-sequence = <1 2>, <0 10>, <1 10>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; qcom,dcs-cmd-by-left; qcom,mdss-dsi-lp11-init; qcom,mdss-dsi-init-delay-us = <100>; diff --git a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi index 40df8b7ff4de..48cf099b84a8 100644 --- a/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-agave-adp.dtsi @@ -388,7 +388,7 @@ qcom,mdss-dsi-bl-max-level = <4095>; qcom,cont-splash-enabled; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; qcom,panel-roi-alignment = <720 128 720 64 720 64>; }; @@ -432,7 +432,7 @@ qcom,5v-boost-gpio = <&pmi8994_gpios 8 0>; qcom,cont-splash-enabled; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; qcom,panel-roi-alignment = <4 4 2 2 20 20>; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi index 30646dba1cd9..34e41c2bf28f 100644 --- a/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-auto-cdp.dtsi @@ -376,7 +376,7 @@ qcom,mdss-dsi-bl-max-level = <4095>; qcom,cont-splash-enabled; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; qcom,panel-roi-alignment = <720 128 720 64 720 64>; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-cdp.dtsi b/arch/arm/boot/dts/qcom/msm8996-cdp.dtsi index 4855da387e21..1c85e13aa0f8 100644 --- a/arch/arm/boot/dts/qcom/msm8996-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-cdp.dtsi @@ -409,7 +409,7 @@ qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <4095>; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; qcom,panel-roi-alignment = <720 128 720 64 720 64>; }; @@ -432,7 +432,7 @@ qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <4095>; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; /* panel supports slice height of 8/16/32/48/3840 */ qcom,panel-roi-alignment = <1080 8 1080 8 1080 8>; }; @@ -480,7 +480,7 @@ qcom,mdss-dsi-bl-max-level = <4095>; qcom,5v-boost-gpio = <&pmi8994_gpios 8 0>; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; qcom,panel-roi-alignment = <4 2 4 2 20 20>; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-fluid.dtsi b/arch/arm/boot/dts/qcom/msm8996-fluid.dtsi index 824d31afb7d8..550da56520f8 100644 --- a/arch/arm/boot/dts/qcom/msm8996-fluid.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-fluid.dtsi @@ -629,7 +629,7 @@ qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <4095>; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; /* panel supports slice height of 8/16/32/48/3840 */ qcom,panel-roi-alignment = <1080 8 1080 8 1080 8>; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi index 3d534ff1550e..bd8aa7fe02f7 100644 --- a/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-mmxf-adp.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2016, 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 @@ -343,7 +343,7 @@ qcom,mdss-dsi-bl-max-level = <4095>; qcom,cont-splash-enabled; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; qcom,panel-roi-alignment = <720 128 720 64 720 64>; }; @@ -387,7 +387,7 @@ qcom,5v-boost-gpio = <&pmi8994_gpios 8 0>; qcom,cont-splash-enabled; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; qcom,panel-roi-alignment = <4 4 2 2 20 20>; }; diff --git a/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi b/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi index 96279288d336..07cb98860498 100644 --- a/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi +++ b/arch/arm/boot/dts/qcom/msm8996-mtp.dtsi @@ -397,7 +397,7 @@ qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <4095>; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; qcom,panel-roi-alignment = <720 128 720 64 720 64>; }; @@ -420,7 +420,7 @@ qcom,mdss-dsi-bl-min-level = <1>; qcom,mdss-dsi-bl-max-level = <4095>; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; /* panel supports slice height of 8/16/32/48/3840 */ qcom,panel-roi-alignment = <1080 8 1080 8 1080 8>; }; @@ -468,7 +468,7 @@ qcom,mdss-dsi-bl-max-level = <4095>; qcom,5v-boost-gpio = <&pmi8994_gpios 8 0>; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; qcom,panel-roi-alignment = <4 4 2 2 20 20>; }; diff --git a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi index 4822823aa63f..9b9b863c1847 100644 --- a/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi +++ b/arch/arm/boot/dts/qcom/msmcobalt-cdp.dtsi @@ -382,7 +382,7 @@ qcom,mdss-dsi-bl-max-level = <4095>; qcom,5v-boost-gpio = <&tlmm 51 0>; qcom,panel-supply-entries = <&dsi_panel_pwr_supply>; - qcom,partial-update-enabled; + qcom,partial-update-enabled = "single_roi"; qcom,panel-roi-alignment = <4 2 4 2 20 20>; }; diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index 7091dc2f38b9..3536cb2d294d 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -468,6 +468,7 @@ struct mdss_dsi_ctrl_pdata { bool cmd_sync_wait_trigger; struct mdss_rect roi; + struct mdss_dsi_dual_pu_roi dual_roi; struct pwm_device *pwm_bl; u32 pclk_rate; u32 byte_clk_rate; diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index bd0c2ad32c05..7c36bb627043 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -447,28 +447,82 @@ static int mdss_dsi_roi_merge(struct mdss_dsi_ctrl_pdata *ctrl, static char caset[] = {0x2a, 0x00, 0x00, 0x03, 0x00}; /* DTYPE_DCS_LWRITE */ static char paset[] = {0x2b, 0x00, 0x00, 0x05, 0x00}; /* DTYPE_DCS_LWRITE */ +/* + * Some panels can support multiple ROIs as part of the below commands + */ +static char caset_dual[] = {0x2a, 0x00, 0x00, 0x03, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00};/* DTYPE_DCS_LWRITE */ +static char paset_dual[] = {0x2b, 0x00, 0x00, 0x05, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00};/* DTYPE_DCS_LWRITE */ + /* pack into one frame before sent */ static struct dsi_cmd_desc set_col_page_addr_cmd[] = { {{DTYPE_DCS_LWRITE, 0, 0, 0, 1, sizeof(caset)}, caset}, /* packed */ {{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(paset)}, paset}, }; +/* pack into one frame before sent */ +static struct dsi_cmd_desc set_dual_col_page_addr_cmd[] = { /*packed*/ + {{DTYPE_DCS_LWRITE, 0, 0, 0, 1, sizeof(caset_dual)}, caset_dual}, + {{DTYPE_DCS_LWRITE, 1, 0, 0, 1, sizeof(paset_dual)}, paset_dual}, +}; + + +static void __mdss_dsi_send_col_page_addr(struct mdss_dsi_ctrl_pdata *ctrl, + struct mdss_rect *roi, bool dual_roi) +{ + if (dual_roi) { + struct mdss_rect *first, *second; + + first = &ctrl->panel_data.panel_info.dual_roi.first_roi; + second = &ctrl->panel_data.panel_info.dual_roi.second_roi; + + caset_dual[1] = (((first->x) & 0xFF00) >> 8); + caset_dual[2] = (((first->x) & 0xFF)); + caset_dual[3] = (((first->x - 1 + first->w) & 0xFF00) >> 8); + caset_dual[4] = (((first->x - 1 + first->w) & 0xFF)); + /* skip the MPU setting byte*/ + caset_dual[6] = (((second->x) & 0xFF00) >> 8); + caset_dual[7] = (((second->x) & 0xFF)); + caset_dual[8] = (((second->x - 1 + second->w) & 0xFF00) >> 8); + caset_dual[9] = (((second->x - 1 + second->w) & 0xFF)); + set_dual_col_page_addr_cmd[0].payload = caset_dual; + + paset_dual[1] = (((first->y) & 0xFF00) >> 8); + paset_dual[2] = (((first->y) & 0xFF)); + paset_dual[3] = (((first->y - 1 + first->h) & 0xFF00) >> 8); + paset_dual[4] = (((first->y - 1 + first->h) & 0xFF)); + /* skip the MPU setting byte */ + paset_dual[6] = (((second->y) & 0xFF00) >> 8); + paset_dual[7] = (((second->y) & 0xFF)); + paset_dual[8] = (((second->y - 1 + second->h) & 0xFF00) >> 8); + paset_dual[9] = (((second->y - 1 + second->h) & 0xFF)); + set_dual_col_page_addr_cmd[1].payload = paset_dual; + } else { + caset[1] = (((roi->x) & 0xFF00) >> 8); + caset[2] = (((roi->x) & 0xFF)); + caset[3] = (((roi->x - 1 + roi->w) & 0xFF00) >> 8); + caset[4] = (((roi->x - 1 + roi->w) & 0xFF)); + set_col_page_addr_cmd[0].payload = caset; + + paset[1] = (((roi->y) & 0xFF00) >> 8); + paset[2] = (((roi->y) & 0xFF)); + paset[3] = (((roi->y - 1 + roi->h) & 0xFF00) >> 8); + paset[4] = (((roi->y - 1 + roi->h) & 0xFF)); + set_col_page_addr_cmd[1].payload = paset; + } + pr_debug("%s Sending 2A 2B cmnd with dual_roi=%d\n", __func__, + dual_roi); + +} static void mdss_dsi_send_col_page_addr(struct mdss_dsi_ctrl_pdata *ctrl, struct mdss_rect *roi, int unicast) { struct dcs_cmd_req cmdreq; + struct mdss_panel_info *pinfo = &ctrl->panel_data.panel_info; + bool dual_roi = pinfo->dual_roi.enabled; - caset[1] = (((roi->x) & 0xFF00) >> 8); - caset[2] = (((roi->x) & 0xFF)); - caset[3] = (((roi->x - 1 + roi->w) & 0xFF00) >> 8); - caset[4] = (((roi->x - 1 + roi->w) & 0xFF)); - set_col_page_addr_cmd[0].payload = caset; - - paset[1] = (((roi->y) & 0xFF00) >> 8); - paset[2] = (((roi->y) & 0xFF)); - paset[3] = (((roi->y - 1 + roi->h) & 0xFF00) >> 8); - paset[4] = (((roi->y - 1 + roi->h) & 0xFF)); - set_col_page_addr_cmd[1].payload = paset; + __mdss_dsi_send_col_page_addr(ctrl, roi, dual_roi); memset(&cmdreq, 0, sizeof(cmdreq)); cmdreq.cmds_cnt = 2; @@ -478,7 +532,9 @@ static void mdss_dsi_send_col_page_addr(struct mdss_dsi_ctrl_pdata *ctrl, cmdreq.rlen = 0; cmdreq.cb = NULL; - cmdreq.cmds = set_col_page_addr_cmd; + /* Send default or dual roi 2A/2B cmd */ + cmdreq.cmds = dual_roi ? set_dual_col_page_addr_cmd : + set_col_page_addr_cmd; mdss_dsi_cmdlist_put(ctrl, &cmdreq); } @@ -1837,6 +1893,41 @@ error: pinfo->esd_check_enabled = false; } +static void mdss_dsi_parse_partial_update_caps(struct device_node *np, + struct mdss_dsi_ctrl_pdata *ctrl) +{ + struct mdss_panel_info *pinfo; + const char *data; + + pinfo = &ctrl->panel_data.panel_info; + + data = of_get_property(np, "qcom,partial-update-enabled", NULL); + if (data && !strcmp(data, "single_roi")) + pinfo->partial_update_supported = + PU_SINGLE_ROI; + else if (data && !strcmp(data, "dual_roi")) + pinfo->partial_update_supported = + PU_DUAL_ROI; + else if (data && !strcmp(data, "none")) + pinfo->partial_update_supported = + PU_NOT_SUPPORTED; + else + pinfo->partial_update_supported = + PU_NOT_SUPPORTED; + + if (pinfo->mipi.mode == DSI_CMD_MODE) { + pinfo->partial_update_enabled = pinfo->partial_update_supported; + pr_info("%s: partial_update_enabled=%d\n", __func__, + pinfo->partial_update_enabled); + ctrl->set_col_page_addr = mdss_dsi_set_col_page_addr; + if (pinfo->partial_update_enabled) { + pinfo->partial_update_roi_merge = + of_property_read_bool(np, + "qcom,partial-update-roi-merge"); + } + } +} + static int mdss_dsi_parse_panel_features(struct device_node *np, struct mdss_dsi_ctrl_pdata *ctrl) { @@ -1849,19 +1940,7 @@ static int mdss_dsi_parse_panel_features(struct device_node *np, pinfo = &ctrl->panel_data.panel_info; - pinfo->partial_update_supported = of_property_read_bool(np, - "qcom,partial-update-enabled"); - if (pinfo->mipi.mode == DSI_CMD_MODE) { - pinfo->partial_update_enabled = pinfo->partial_update_supported; - pr_info("%s: partial_update_enabled=%d\n", __func__, - pinfo->partial_update_enabled); - ctrl->set_col_page_addr = mdss_dsi_set_col_page_addr; - if (pinfo->partial_update_enabled) { - pinfo->partial_update_roi_merge = - of_property_read_bool(np, - "qcom,partial-update-roi-merge"); - } - } + mdss_dsi_parse_partial_update_caps(np, ctrl); pinfo->dcs_cmd_by_left = of_property_read_bool(np, "qcom,dcs-cmd-by-left"); diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 18a93f9d3c3e..ce44652e0b07 100644 --- a/drivers/video/fbdev/msm/mdss_panel.h +++ b/drivers/video/fbdev/msm/mdss_panel.h @@ -137,6 +137,25 @@ enum { SIM_HW_TE_MODE, }; + +/* + * enum partial_update_mode - Different modes for partial update feature + * + * @PU_NOT_SUPPORTED: Feature is not supported on target. + * @PU_SINGLE_ROI: Default mode, only one ROI is triggered to the + * panel(one on each DSI in case of split dsi) + * @PU_DUAL_ROI: Support for sending two roi's that are clubbed + * together as one big single ROI. This is only + * supported on certain panels that have this + * capability in their DDIC. + * + */ +enum { + PU_NOT_SUPPORTED = 0, + PU_SINGLE_ROI, + PU_DUAL_ROI, +}; + struct mdss_rect { u16 x; u16 y; @@ -664,6 +683,50 @@ struct mdss_panel_roi_alignment { u32 min_height; }; + +/* + * Nomeclature used to represent partial ROI in case of + * dual roi when the panel supports it. Region marked (XXX) is + * the extended roi to align with the second roi since LM output + * has to be rectangle. + * + * For single ROI, only the first ROI will be used in the struct. + * DSI driver will merge it based on the partial_update_roi_merge + * property. + * + * ------------------------------- + * | DSI0 | DSI1 | + * ------------------------------- + * | | | + * | | | + * | =========|=======----+ | + * | | | |XXXX| | + * | | First| Roi |XXXX| | + * | | | |XXXX| | + * | =========|=======----+ | + * | | | + * | | | + * | | | + * | +----================= | + * | |XXXX| | | | + * | |XXXX| Second Roi | | + * | |XXXX| | | | + * | +----====|============ | + * | | | + * | | | + * | | | + * | | | + * | | | + * ------------------------------ + * + */ + +struct mdss_dsi_dual_pu_roi { + struct mdss_rect first_roi; + struct mdss_rect second_roi; + bool enabled; +}; + struct mdss_panel_info { u32 xres; u32 yres; @@ -689,6 +752,7 @@ struct mdss_panel_info { u32 vic; /* video identification code */ u32 deep_color; struct mdss_rect roi; + struct mdss_dsi_dual_pu_roi dual_roi; int pwm_pmic_gpio; int pwm_lpg_chan; int pwm_period; @@ -723,8 +787,8 @@ struct mdss_panel_info { u32 cont_splash_enabled; bool esd_rdy; - bool partial_update_supported; /* value from dts if pu is supported */ - bool partial_update_enabled; /* is pu currently allowed */ + u32 partial_update_supported; /* value from dts if pu is supported */ + u32 partial_update_enabled; /* is pu currently allowed */ u32 dcs_cmd_by_left; u32 partial_update_roi_merge; struct ion_handle *splash_ihdl;