From 1e531fd402ad1403225bcac0c754772252bac7dd Mon Sep 17 00:00:00 2001 From: Benjamin Chan Date: Thu, 13 Oct 2016 13:47:52 -0400 Subject: [PATCH] msm: mdss: Add partial update support for dest-scaler When applying partial update for command mode panel, the ROI is calculated from the mixer ROI. When destination scaling is enabled, the ROI for command mode panel should be the ROI after the scaling. This panel ROI is provided from the user mode where the scaling is calculated from. CRs-Fixed: 1082694 Change-Id: Iac899e5130fdd7d34e598998f4b5cab601cf7a22 Signed-off-by: Benjamin Chan --- drivers/video/fbdev/msm/mdss_mdp.h | 12 ++- drivers/video/fbdev/msm/mdss_mdp_ctl.c | 45 ++++++++-- drivers/video/fbdev/msm/mdss_mdp_layer.c | 100 ++++++++++++++++++++- drivers/video/fbdev/msm/mdss_mdp_overlay.c | 38 +++++++- 4 files changed, 184 insertions(+), 11 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index d3d332d780d5..cb9cc08140f0 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-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 @@ -124,6 +124,7 @@ #define DS_ENHANCER_UPDATE BIT(5) #define DS_VALIDATE BIT(6) #define DS_DIRTY_UPDATE BIT(7) +#define DS_PU_ENABLE BIT(8) /** * Destination Scaler DUAL mode overfetch pixel count @@ -386,6 +387,7 @@ struct mdss_mdp_destination_scaler { u16 last_mixer_height; u32 flags; struct mdp_scale_data_v2 scaler; + struct mdss_rect panel_roi; }; @@ -1169,6 +1171,14 @@ static inline int is_dest_scaling_enable(struct mdss_mdp_mixer *mixer) mixer && mixer->ds && (mixer->ds->flags & DS_ENABLE)); } +static inline int is_dest_scaling_pu_enable(struct mdss_mdp_mixer *mixer) +{ + if (is_dest_scaling_enable(mixer)) + return (mixer->ds->flags & DS_PU_ENABLE); + + return 0; +} + static inline u32 get_ds_input_width(struct mdss_mdp_mixer *mixer) { struct mdss_mdp_destination_scaler *ds; diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index f397aca8ad3a..a5a33e132f07 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -4652,7 +4652,15 @@ void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl, previous_frame_pu_type = mdss_mdp_get_pu_type(ctl); if (ctl->mixer_left) { mdss_mdp_set_mixer_roi(ctl->mixer_left, l_roi); - ctl->roi = ctl->mixer_left->roi; + if (is_dest_scaling_enable(ctl->mixer_left)) + ctl->roi = ctl->mixer_left->ds->panel_roi; + else + ctl->roi = ctl->mixer_left->roi; + + pr_debug("ctl->mixer_left: [%d %d %d %d] ds:%d\n", + ctl->roi.x, ctl->roi.y, + ctl->roi.w, ctl->roi.h, + is_dest_scaling_enable(ctl->mixer_left)); } if (ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) { @@ -4660,20 +4668,43 @@ void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl, if (sctl && sctl->mixer_left) { mdss_mdp_set_mixer_roi(sctl->mixer_left, r_roi); - sctl->roi = sctl->mixer_left->roi; + if (is_dest_scaling_enable(sctl->mixer_left)) + sctl->roi = sctl->mixer_left->ds->panel_roi; + else + sctl->roi = sctl->mixer_left->roi; + + pr_debug("sctl->mixer_left: [%d %d %d %d] ds:%d\n", + sctl->roi.x, sctl->roi.y, + sctl->roi.w, sctl->roi.h, + is_dest_scaling_enable(sctl->mixer_left)); + } } else if (is_dual_lm_single_display(ctl->mfd) && ctl->mixer_right) { mdss_mdp_set_mixer_roi(ctl->mixer_right, r_roi); /* in this case, CTL_ROI is a union of left+right ROIs. */ - ctl->roi.w += ctl->mixer_right->roi.w; + if (is_dest_scaling_enable(ctl->mixer_right)) + ctl->roi.w += ctl->mixer_right->ds->panel_roi.w; + else + ctl->roi.w += ctl->mixer_right->roi.w; /* right_only, update roi.x as per CTL ROI guidelines */ if (ctl->mixer_left && !ctl->mixer_left->valid_roi) { - ctl->roi = ctl->mixer_right->roi; - ctl->roi.x = left_lm_w_from_mfd(ctl->mfd) + - ctl->mixer_right->roi.x; + if (is_dest_scaling_enable(ctl->mixer_right)) { + ctl->roi = ctl->mixer_right->ds->panel_roi; + ctl->roi.x = + get_ds_output_width(ctl->mixer_left) + + ctl->mixer_right->ds->panel_roi.x; + } else { + ctl->roi = ctl->mixer_right->roi; + ctl->roi.x = left_lm_w_from_mfd(ctl->mfd) + + ctl->mixer_right->roi.x; + } + pr_debug("ctl->mixer_right_only : [%d %d %d %d] ds:%d\n", + ctl->roi.x, ctl->roi.y, + ctl->roi.w, ctl->roi.h, + is_dest_scaling_enable(ctl->mixer_right)); } } diff --git a/drivers/video/fbdev/msm/mdss_mdp_layer.c b/drivers/video/fbdev/msm/mdss_mdp_layer.c index 92c4b675cc47..fdc8e4bc39d3 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_layer.c +++ b/drivers/video/fbdev/msm/mdss_mdp_layer.c @@ -124,6 +124,9 @@ static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl) ctl->mixer_right->roi = (struct mdss_rect) { 0, 0, ctl->mixer_right->width, ctl->mixer_right->height }; + if (split_ctl) + split_ctl->mixer_left->roi = + ctl->mixer_right->roi; /* * Disable destination scaler by resetting the control @@ -173,6 +176,46 @@ static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl) } } +static int __dest_scaler_panel_roi_update( + struct mdp_destination_scaler_data *ds_data, + struct mdss_mdp_destination_scaler *ds) +{ + if (ds_data->flags & MDP_DESTSCALER_ROI_ENABLE) { + /* + * Updating PANEL ROI info, used in partial update + */ + if ((ds_data->panel_roi.w > ds->scaler.dst_width) || + (ds_data->panel_roi.h > + ds->scaler.dst_height) || + (ds_data->panel_roi.w == 0) || + (ds_data->panel_roi.h == 0)) { + pr_err("Invalid panel ROI parameter for dest-scaler-%d: [%d %d %d %d]\n", + ds_data->dest_scaler_ndx, + ds_data->panel_roi.x, + ds_data->panel_roi.y, + ds_data->panel_roi.w, + ds_data->panel_roi.h); + ds->flags &= ~DS_PU_ENABLE; + return -EINVAL; + } + ds->panel_roi.x = ds_data->panel_roi.x; + ds->panel_roi.y = ds_data->panel_roi.y; + ds->panel_roi.w = ds_data->panel_roi.w; + ds->panel_roi.h = ds_data->panel_roi.h; + ds->flags |= DS_PU_ENABLE; + pr_debug("dest-scaler[%d] panel_roi update: [%d,%d,%d,%d]\n", + ds->num, + ds_data->panel_roi.x, ds_data->panel_roi.y, + ds_data->panel_roi.w, ds_data->panel_roi.h); + MDSS_XLOG(ds->num, ds_data->panel_roi.x, ds_data->panel_roi.y, + ds_data->panel_roi.w, ds_data->panel_roi.h); + } else { + ds->flags &= ~DS_PU_ENABLE; + } + + return 0; +} + static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data, struct mdss_mdp_destination_scaler *ds, u32 max_input_width, u32 max_output_width) @@ -218,6 +261,9 @@ static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data, ds->src_height = ds_data->lm_height; } + if (__dest_scaler_panel_roi_update(ds_data, ds)) + return -EINVAL; + if (ds_data->flags == 0) { pr_debug("Disabling destination scaler-%d\n", ds_data->dest_scaler_ndx); @@ -341,6 +387,7 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, int ret = 0; struct mdss_data_type *mdata; struct mdss_mdp_ctl *ctl; + struct mdss_mdp_ctl *sctl; struct mdss_mdp_destination_scaler *ds_left = NULL; struct mdss_mdp_destination_scaler *ds_right = NULL; struct mdss_panel_info *pinfo; @@ -350,6 +397,7 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ds_data) { mdata = mfd_to_mdata(mfd); ctl = mfd_to_ctl(mfd); + sctl = mdss_mdp_get_split_ctl(ctl); if (ctl->mixer_left) ds_left = ctl->mixer_left->ds; @@ -357,6 +405,9 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ctl->mixer_right) ds_right = ctl->mixer_right->ds; + if (sctl && sctl->mixer_left && ds_right) + sctl->mixer_left->ds = ds_right; + switch (ds_mode) { case DS_DUAL_MODE: if (!ds_left || !ds_right) { @@ -379,6 +430,20 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ret) goto reset_mixer; + if ((ds_right->flags & DS_PU_ENABLE) && sctl) { + pinfo = &ctl->panel_data->panel_info; + if (ds_right->panel_roi.x >= + get_panel_xres(pinfo)) { + ds_right->panel_roi.x -= + get_panel_xres(pinfo); + } else { + pr_err("SCTL DS right roi.x:%d < left panel width:%d\n", + ds_right->panel_roi.x, + get_panel_xres(pinfo)); + goto reset_mixer; + } + } + ds_left->flags &= ~(DS_LEFT|DS_RIGHT); ds_left->flags |= DS_DUAL_MODE; ds_right->flags &= ~(DS_LEFT|DS_RIGHT); @@ -403,6 +468,17 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ret) goto reset_mixer; + /* + * For Partial update usecase, it is possible switching + * from Left+Right mode to Left only mode. So make sure + * cleanup the DS_RIGHT flags. + */ + if (ds_right) { + ds_right->flags &= + ~(DS_DUAL_MODE|DS_ENABLE|DS_PU_ENABLE); + ds_right->flags |= DS_VALIDATE; + } + MDSS_XLOG(ds_left->num, ds_left->src_width, ds_left->src_height, ds_left->flags); break; @@ -422,6 +498,26 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, if (ret) goto reset_mixer; + if (ds_left) { + ds_left->flags &= + ~(DS_DUAL_MODE|DS_ENABLE|DS_PU_ENABLE); + ds_left->flags |= DS_VALIDATE; + } + + if ((ds_right->flags & DS_PU_ENABLE) && sctl) { + pinfo = &ctl->panel_data->panel_info; + if (ds_right->panel_roi.x >= + get_panel_xres(pinfo)) { + ds_right->panel_roi.x -= + get_panel_xres(pinfo); + } else { + pr_err("SCTL DS-right-only roi.x:%d < Left panel width:%d\n", + ds_right->panel_roi.x, + get_panel_xres(pinfo)); + goto reset_mixer; + } + } + MDSS_XLOG(ds_right->num, ds_right->src_width, ds_right->src_height, ds_right->flags); break; @@ -444,11 +540,11 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd, pinfo = &ctl->panel_data->panel_info; scaler_width = 0; scaler_height = 0; - if (ds_left && ds_left->flags) { + if (ds_left && (ds_left->flags & DS_ENABLE)) { scaler_width += ds_left->scaler.dst_width; scaler_height = ds_left->scaler.dst_height; } - if (ds_right && ds_right->flags) { + if (ds_right && (ds_right->flags & DS_ENABLE)) { scaler_width += ds_right->scaler.dst_width; scaler_height = ds_right->scaler.dst_height; } diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index c6fc10833d7f..9864d611e8e4 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-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 @@ -1930,6 +1930,39 @@ static void __restore_pipe(struct mdss_mdp_pipe *pipe) pipe->restore_roi = false; } +static void __restore_dest_scaler_roi(struct mdss_mdp_ctl *ctl) +{ + struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info; + struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl); + + if (is_dest_scaling_pu_enable(ctl->mixer_left)) { + ctl->mixer_left->ds->panel_roi.x = 0; + ctl->mixer_left->ds->panel_roi.y = 0; + ctl->mixer_left->ds->panel_roi.w = get_panel_xres(pinfo); + ctl->mixer_left->ds->panel_roi.h = get_panel_yres(pinfo); + + if ((ctl->mfd->split_mode == MDP_DUAL_LM_DUAL_DISPLAY) && + sctl) { + if (ctl->panel_data->next) + pinfo = &ctl->panel_data->next->panel_info; + sctl->mixer_left->ds->panel_roi.x = 0; + sctl->mixer_left->ds->panel_roi.y = 0; + sctl->mixer_left->ds->panel_roi.w = + get_panel_xres(pinfo); + sctl->mixer_left->ds->panel_roi.h = + get_panel_yres(pinfo); + } else if (ctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) { + ctl->mixer_right->ds->panel_roi.x = + get_panel_xres(pinfo); + ctl->mixer_right->ds->panel_roi.y = 0; + ctl->mixer_right->ds->panel_roi.w = + get_panel_xres(pinfo); + ctl->mixer_right->ds->panel_roi.h = + get_panel_yres(pinfo); + } + } +} + /** * __adjust_pipe_rect() - Adjust pipe roi for dual partial update feature. * @pipe: pipe to check against. @@ -2145,6 +2178,9 @@ set_roi: } dual_roi->enabled = false; } + + if (pinfo->partial_update_enabled) + __restore_dest_scaler_roi(ctl); } pr_debug("after processing: %s l_roi:-> %d %d %d %d r_roi:-> %d %d %d %d, dual_pu_roi:%d\n",