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",