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_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index bcd23d3c19f2..08e06c75522a 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -564,7 +564,7 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev, "min_fps=%d\nmax_fps=%d\npanel_name=%s\n" "primary_panel=%d\nis_pluggable=%d\ndisplay_id=%s\n" "is_cec_supported=%d\nis_pingpong_split=%d\n" - "dfps_porch_mode=%d\n", + "dfps_porch_mode=%d\npu_roi_cnt=%d\ndual_dsi=%d", pinfo->partial_update_enabled, pinfo->roi_alignment.xstart_pix_align, pinfo->roi_alignment.width_pix_align, @@ -577,7 +577,8 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev, pinfo->panel_name, pinfo->is_prim_panel, pinfo->is_pluggable, pinfo->display_id, pinfo->is_cec_supported, is_pingpong_split(mfd), - dfps_porch_mode); + dfps_porch_mode, pinfo->partial_update_enabled, + is_panel_split(mfd)); return ret; } @@ -3282,6 +3283,7 @@ int mdss_fb_atomic_commit(struct fb_info *info, mfd->msm_fb_backup.atomic_commit = true; mfd->msm_fb_backup.disp_commit.l_roi = commit_v1->left_roi; mfd->msm_fb_backup.disp_commit.r_roi = commit_v1->right_roi; + mfd->msm_fb_backup.disp_commit.flags = commit_v1->flags; mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex); atomic_inc(&mfd->mdp_sync_pt_data.commit_cnt); diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index 9f3f018eb80a..dc07fa8bf82e 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -829,6 +829,9 @@ struct mdss_mdp_pipe { struct mdss_mdp_format_params *src_fmt; struct mdss_mdp_plane_sizes src_planes; + /* flag to re-store roi in case of pu dual-roi validation error */ + bool restore_roi; + /* compression ratio from the source format */ struct mult_factor comp_ratio; @@ -1849,7 +1852,7 @@ void mdss_mdp_intersect_rect(struct mdss_rect *res_rect, const struct mdss_rect *sci_rect); void mdss_mdp_crop_rect(struct mdss_rect *src_rect, struct mdss_rect *dst_rect, - const struct mdss_rect *sci_rect); + const struct mdss_rect *sci_rect, bool normalize); void rect_copy_mdss_to_mdp(struct mdp_rect *user, struct mdss_rect *kernel); void rect_copy_mdp_to_mdss(struct mdp_rect *user, struct mdss_rect *kernel); bool mdss_rect_overlap_check(struct mdss_rect *rect1, struct mdss_rect *rect2); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index d3130452328f..9ed44937efe6 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -728,7 +728,7 @@ int mdss_mdp_get_pipe_overlap_bw(struct mdss_mdp_pipe *pipe, /* crop rectangles */ if (roi && !mixer->ctl->is_video_mode && !pipe->src_split_req) - mdss_mdp_crop_rect(&src, &dst, roi); + mdss_mdp_crop_rect(&src, &dst, roi, true); /* * when doing vertical decimation lines will be skipped, hence there is @@ -1108,7 +1108,7 @@ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe, /* crop rectangles */ if (roi && !mixer->ctl->is_video_mode && !pipe->src_split_req) - mdss_mdp_crop_rect(&src, &dst, roi); + mdss_mdp_crop_rect(&src, &dst, roi, true); pr_debug("v_total=%d, xres=%d fps=%d\n", v_total, xres, fps); pr_debug("src(w,h)(%d,%d) dst(w,h)(%d,%d) dst_y=%d bpp=%d yuv=%d\n", diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 353d07ad64ac..1ff5d5e68575 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -521,6 +521,56 @@ static void __update_avr_info(struct mdss_mdp_ctl *ctl, ctl->avr_info.avr_mode = MDSS_MDP_AVR_ONE_SHOT; } +/* + * __validate_dual_partial_update() - validation function for + * dual partial update ROIs + * + * - This function uses the commit structs "left_roi" and "right_roi" + * to pass the first and second ROI information for the multiple + * partial update feature. + * - Supports only SINGLE DSI with a max of 2 PU ROIs. + * - Not supported along with destination scalar. + * - Not supported when source-split is disabled. + * - Not supported with ping-pong split enabled. + */ +static int __validate_dual_partial_update( + struct mdss_mdp_ctl *ctl, struct mdp_layer_commit_v1 *commit) +{ + struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info; + struct mdss_data_type *mdata = ctl->mdata; + struct mdss_rect first_roi, second_roi; + int ret = 0; + struct mdp_destination_scaler_data *ds_data = commit->dest_scaler; + + if (!mdata->has_src_split + || (is_panel_split(ctl->mfd)) + || (is_pingpong_split(ctl->mfd)) + || (ds_data && commit->dest_scaler_cnt && + ds_data->flags & MDP_DESTSCALER_ENABLE)) { + pr_err("Invalid mode multi pu src_split:%d, split_mode:%d, ds_cnt:%d\n", + mdata->has_src_split, ctl->mfd->split_mode, + commit->dest_scaler_cnt); + ret = -EINVAL; + goto end; + } + + rect_copy_mdp_to_mdss(&commit->left_roi, &first_roi); + rect_copy_mdp_to_mdss(&commit->right_roi, &second_roi); + + if (!is_valid_pu_dual_roi(pinfo, &first_roi, &second_roi)) + ret = -EINVAL; + + MDSS_XLOG(ctl->num, first_roi.x, first_roi.y, first_roi.w, first_roi.h, + second_roi.x, second_roi.y, second_roi.w, second_roi.h, + ret); + pr_debug("Multiple PU ROIs - roi0:{%d,%d,%d,%d}, roi1{%d,%d,%d,%d}, ret:%d\n", + first_roi.x, first_roi.y, first_roi.w, first_roi.h, + second_roi.x, second_roi.y, second_roi.w, + second_roi.h, ret); +end: + return ret; +} + /* * __layer_needs_src_split() - check needs source split configuration * @layer: input layer @@ -1000,6 +1050,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, pipe->is_handed_off = false; pipe->async_update = (layer->flags & MDP_LAYER_ASYNC) ? true : false; pipe->csc_coeff_set = layer->color_space; + pipe->restore_roi = false; if (mixer->ctl) { pipe->dst.x += mixer->ctl->border_x_off; @@ -1007,7 +1058,7 @@ static int __configure_pipe_params(struct msm_fb_data_type *mfd, pr_debug("border{%d,%d}\n", mixer->ctl->border_x_off, mixer->ctl->border_y_off); } - pr_debug("src{%d,%d,%d,%d}, dst{%d,%d,%d,%d}\n", + pr_debug("pipe:%d src{%d,%d,%d,%d}, dst{%d,%d,%d,%d}\n", pipe->num, pipe->src.x, pipe->src.y, pipe->src.w, pipe->src.h, pipe->dst.x, pipe->dst.y, pipe->dst.w, pipe->dst.h); @@ -2625,6 +2676,7 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd, { struct mdss_overlay_private *mdp5_data; struct mdp_destination_scaler_data *ds_data; + struct mdss_panel_info *pinfo; int rc = 0; if (!mfd || !commit) { @@ -2658,6 +2710,23 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd, } } + pinfo = mfd->panel_info; + if (pinfo->partial_update_enabled == PU_DUAL_ROI) { + if (commit->flags & MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI) { + rc = __validate_dual_partial_update(mdp5_data->ctl, + commit); + if (IS_ERR_VALUE(rc)) { + pr_err("Multiple pu pre-validate fail\n"); + return rc; + } + } + } else { + if (commit->flags & MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI) { + pr_err("Multiple partial update not supported!\n"); + return -EINVAL; + } + } + ds_data = commit->dest_scaler; if (ds_data && commit->dest_scaler_cnt && (ds_data->flags & MDP_DESTSCALER_ENABLE)) { diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index 9bdc66232dd5..8c64dcd0655c 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -1861,12 +1861,109 @@ int mdss_mode_switch_post(struct msm_fb_data_type *mfd, u32 mode) return rc; } +static void __restore_pipe(struct mdss_mdp_pipe *pipe) +{ + + if (!pipe->restore_roi) + return; + + pr_debug("restoring pipe:%d dst from:{%d,%d,%d,%d} to:{%d,%d,%d,%d}\n", + pipe->num, pipe->dst.x, pipe->dst.y, + pipe->dst.w, pipe->dst.h, pipe->layer.dst_rect.x, + pipe->layer.dst_rect.y, pipe->layer.dst_rect.w, + pipe->layer.dst_rect.h); + pr_debug("restoring pipe:%d src from:{%d,%d,%d,%d} to:{%d,%d,%d,%d}\n", + pipe->num, pipe->src.x, pipe->src.y, + pipe->src.w, pipe->src.h, pipe->layer.src_rect.x, + pipe->layer.src_rect.y, pipe->layer.src_rect.w, + pipe->layer.src_rect.h); + + pipe->src.x = pipe->layer.src_rect.x; + pipe->src.y = pipe->layer.src_rect.y; + pipe->src.w = pipe->layer.src_rect.w; + pipe->src.h = pipe->layer.src_rect.h; + + pipe->dst.x = pipe->layer.dst_rect.x; + pipe->dst.y = pipe->layer.dst_rect.y; + pipe->dst.w = pipe->layer.dst_rect.w; + pipe->dst.h = pipe->layer.dst_rect.h; +} + + /** + * __crop_adjust_pipe_rect() - Adjust pipe roi for dual partial + * update feature. + * @pipe: pipe to check against. + * @dual_roi: roi's for the dual partial roi. + * + * For dual PU ROI case, the layer mixer is configured + * by merging the two width aligned ROIs (first_roi and + * second_roi) vertically. So, the y-offset of all the + * pipes belonging to the second_roi needs to adjusted + * accordingly. Also the cropping of the pipe's src/dst + * rect has to be done with respect to the ROI the pipe + * is intersecting with, before the adjustment. + */ +static int __crop_adjust_pipe_rect(struct mdss_mdp_pipe *pipe, + struct mdss_dsi_dual_pu_roi *dual_roi) +{ + u32 adjust_h; + u32 roi_y_pos; + int ret = 0; + + pipe->restore_roi = false; + if (mdss_rect_overlap_check(&pipe->dst, &dual_roi->first_roi)) { + mdss_mdp_crop_rect(&pipe->src, &pipe->dst, + &dual_roi->first_roi, false); + pipe->restore_roi = true; + + } else if (mdss_rect_overlap_check(&pipe->dst, &dual_roi->second_roi)) { + mdss_mdp_crop_rect(&pipe->src, &pipe->dst, + &dual_roi->second_roi, false); + adjust_h = dual_roi->second_roi.y; + roi_y_pos = dual_roi->first_roi.y + dual_roi->first_roi.h; + + if (adjust_h > roi_y_pos) { + adjust_h = adjust_h - roi_y_pos; + pipe->dst.y -= adjust_h; + } else { + pr_err("wrong y-pos adjust_y:%d roi_y_pos:%d\n", + adjust_h, roi_y_pos); + ret = -EINVAL; + } + pipe->restore_roi = true; + + } else { + ret = -EINVAL; + } + + pr_debug("crop/adjusted p:%d src:{%d,%d,%d,%d} dst:{%d,%d,%d,%d} r:%d\n", + pipe->num, pipe->src.x, pipe->src.y, + pipe->src.w, pipe->src.h, pipe->dst.x, + pipe->dst.y, pipe->dst.w, pipe->dst.h, + pipe->restore_roi); + + if (ret) { + pr_err("dual roi error p%d dst{%d,%d,%d,%d}", + pipe->num, pipe->dst.x, pipe->dst.y, pipe->dst.w, + pipe->dst.h); + pr_err(" roi1{%d,%d,%d,%d} roi2{%d,%d,%d,%d}\n", + dual_roi->first_roi.x, dual_roi->first_roi.y, + dual_roi->first_roi.w, dual_roi->first_roi.h, + dual_roi->second_roi.x, dual_roi->second_roi.y, + dual_roi->second_roi.w, dual_roi->second_roi.h); + } + + return ret; +} + static void __validate_and_set_roi(struct msm_fb_data_type *mfd, struct mdp_display_commit *commit) { struct mdss_mdp_pipe *pipe; struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd); struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info; + struct mdss_dsi_dual_pu_roi *dual_roi = &pinfo->dual_roi; struct mdss_rect l_roi = {0}, r_roi = {0}; struct mdp_rect tmp_roi = {0}; bool skip_partial_update = true; @@ -1881,6 +1978,39 @@ static void __validate_and_set_roi(struct msm_fb_data_type *mfd, rect_copy_mdp_to_mdss(&commit->l_roi, &l_roi); rect_copy_mdp_to_mdss(&commit->r_roi, &r_roi); + /* + * In case of dual partial update ROI, update the two ROIs to dual_roi + * struct and combine both the ROIs and assign it as a merged ROI in + * l_roi, as MDP would need only the merged ROI information for all + * LM settings. + */ + if (pinfo->partial_update_enabled == PU_DUAL_ROI) { + if (commit->flags & MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI) { + + if (!is_valid_pu_dual_roi(pinfo, &l_roi, &r_roi)) { + pr_err("Invalid dual roi - fall back to full screen update\n"); + goto set_roi; + } + + dual_roi->first_roi = (struct mdss_rect) + {l_roi.x, l_roi.y, l_roi.w, l_roi.h}; + dual_roi->second_roi = (struct mdss_rect) + {r_roi.x, r_roi.y, r_roi.w, r_roi.h}; + dual_roi->enabled = true; + + l_roi.h += r_roi.h; + memset(&r_roi, 0, sizeof(struct mdss_rect)); + + pr_debug("Dual ROI - first_roi:{%d,%d,%d,%d}, second_roi:{%d,%d,%d,%d}\n", + dual_roi->first_roi.x, dual_roi->first_roi.y, + dual_roi->first_roi.w, dual_roi->first_roi.h, + dual_roi->second_roi.x, dual_roi->second_roi.y, + dual_roi->second_roi.w, dual_roi->second_roi.h); + } else { + dual_roi->enabled = false; + } + } + pr_debug("input: l_roi:-> %d %d %d %d r_roi:-> %d %d %d %d\n", l_roi.x, l_roi.y, l_roi.w, l_roi.h, r_roi.x, r_roi.y, r_roi.w, r_roi.h); @@ -1926,12 +2056,24 @@ static void __validate_and_set_roi(struct msm_fb_data_type *mfd, } list_for_each_entry(pipe, &mdp5_data->pipes_used, list) { + pr_debug("pipe:%d src:{%d,%d,%d,%d} dst:{%d,%d,%d,%d}\n", + pipe->num, pipe->src.x, pipe->src.y, + pipe->src.w, pipe->src.h, pipe->dst.x, + pipe->dst.y, pipe->dst.w, pipe->dst.h); + + if (dual_roi->enabled) { + if (__crop_adjust_pipe_rect(pipe, dual_roi)) { + skip_partial_update = true; + break; + } + } + if (!__is_roi_valid(pipe, &l_roi, &r_roi)) { skip_partial_update = true; - pr_err("error. invalid pu config for pipe%d: %d,%d,%d,%d\n", - pipe->num, - pipe->dst.x, pipe->dst.y, - pipe->dst.w, pipe->dst.h); + pr_err("error. invalid pu config for pipe%d: %d,%d,%d,%d, dual_pu_roi:%d\n", + pipe->num, pipe->dst.x, pipe->dst.y, + pipe->dst.w, pipe->dst.h, + dual_roi->enabled); break; } } @@ -1946,13 +2088,24 @@ set_roi: ctl->mixer_right->width, ctl->mixer_right->height}; } + + if (pinfo->partial_update_enabled == PU_DUAL_ROI) { + if (dual_roi->enabled) { + /* we failed pu validation, restore pipes */ + list_for_each_entry(pipe, + &mdp5_data->pipes_used, list) + __restore_pipe(pipe); + } + dual_roi->enabled = false; + } } - pr_debug("after processing: %s l_roi:-> %d %d %d %d r_roi:-> %d %d %d %d\n", + pr_debug("after processing: %s l_roi:-> %d %d %d %d r_roi:-> %d %d %d %d, dual_pu_roi:%d\n", (l_roi.w && l_roi.h && r_roi.w && r_roi.h) ? "left+right" : ((l_roi.w && l_roi.h) ? "left-only" : "right-only"), l_roi.x, l_roi.y, l_roi.w, l_roi.h, - r_roi.x, r_roi.y, r_roi.w, r_roi.h); + r_roi.x, r_roi.y, r_roi.w, r_roi.h, + dual_roi->enabled); mdss_mdp_set_roi(ctl, &l_roi, &r_roi); } diff --git a/drivers/video/fbdev/msm/mdss_mdp_pipe.c b/drivers/video/fbdev/msm/mdss_mdp_pipe.c index 1b04e783ac18..7591ebc3e2ee 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_pipe.c +++ b/drivers/video/fbdev/msm/mdss_mdp_pipe.c @@ -1998,7 +1998,7 @@ static int mdss_mdp_image_setup(struct mdss_mdp_pipe *pipe, dst.x -= left_lm_w_from_mfd(pipe->mfd); } - mdss_mdp_crop_rect(&src, &dst, &roi); + mdss_mdp_crop_rect(&src, &dst, &roi, true); if (mdata->has_src_split && is_right_mixer) { /* diff --git a/drivers/video/fbdev/msm/mdss_mdp_util.c b/drivers/video/fbdev/msm/mdss_mdp_util.c index 8b0ebc3fdf05..bc1ecf1dbc29 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_util.c +++ b/drivers/video/fbdev/msm/mdss_mdp_util.c @@ -241,7 +241,7 @@ void mdss_mdp_intersect_rect(struct mdss_rect *res_rect, void mdss_mdp_crop_rect(struct mdss_rect *src_rect, struct mdss_rect *dst_rect, - const struct mdss_rect *sci_rect) + const struct mdss_rect *sci_rect, bool normalize) { struct mdss_rect res; mdss_mdp_intersect_rect(&res, dst_rect, sci_rect); @@ -253,9 +253,17 @@ void mdss_mdp_crop_rect(struct mdss_rect *src_rect, src_rect->w = res.w; src_rect->h = res.h; } - *dst_rect = (struct mdss_rect) - {(res.x - sci_rect->x), (res.y - sci_rect->y), - res.w, res.h}; + + /* adjust dest rect based on the sci_rect starting */ + if (normalize) { + *dst_rect = (struct mdss_rect) {(res.x - sci_rect->x), + (res.y - sci_rect->y), res.w, res.h}; + + /* return the actual cropped intersecting rect */ + } else { + *dst_rect = (struct mdss_rect) {res.x, res.y, + res.w, res.h}; + } } } diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h index 18a93f9d3c3e..0483e3d42873 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; @@ -1000,6 +1064,27 @@ static inline bool is_lm_configs_dsc_compatible(struct mdss_panel_info *pinfo, return true; } +static inline bool is_valid_pu_dual_roi(struct mdss_panel_info *pinfo, + struct mdss_rect *first_roi, struct mdss_rect *second_roi) +{ + if ((first_roi->x != second_roi->x) || (first_roi->w != second_roi->w) + || (first_roi->y > second_roi->y) + || ((first_roi->y + first_roi->h) > second_roi->y) + || (is_dsc_compression(pinfo) && + !is_lm_configs_dsc_compatible(pinfo, + first_roi->w, first_roi->h) && + !is_lm_configs_dsc_compatible(pinfo, + second_roi->w, second_roi->h))) { + pr_err("Invalid multiple PU ROIs, roi0:{%d,%d,%d,%d}, roi1{%d,%d,%d,%d}\n", + first_roi->x, first_roi->y, first_roi->w, + first_roi->h, second_roi->x, second_roi->y, + second_roi->w, second_roi->h); + return false; + } + + return true; +} + int mdss_register_panel(struct platform_device *pdev, struct mdss_panel_data *pdata); diff --git a/include/uapi/linux/msm_mdp_ext.h b/include/uapi/linux/msm_mdp_ext.h index 811d8b4e1994..d2077024769f 100644 --- a/include/uapi/linux/msm_mdp_ext.h +++ b/include/uapi/linux/msm_mdp_ext.h @@ -147,6 +147,9 @@ VALIDATE/COMMIT FLAG CONFIGURATION */ #define MDP_COMMIT_AVR_ONE_SHOT_MODE 0x10 +/* Flag to indicate dual partial ROI update */ +#define MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI 0x20 + /* Flag to enable concurrent writeback for the frame */ #define MDP_COMMIT_CWB_EN 0x800