Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d4d8e11c authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: Correct settings when on/off happens in dest-scaler"

parents 57054d8c c77c8b03
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -109,6 +109,9 @@
 *                   QSEED3 parameters needs to be updated.
 * @DS_ENHANCER_UPDATE: Setting this bit indicates current Desitnation Scaler
 *                      QSEED3 Detial enhancer parameters need to be updated.
 * @DS_VALIDATE: Indicate destination data structure parameters are validated
 *               and can be used for programming the HW and perform a flush.
 * @DS_DIRTY_UPDATE: Mark for dirty update for Power resume usecase.
 */
#define DS_ENABLE           BIT(0)
#define DS_DUAL_MODE        BIT(1)
@@ -116,6 +119,8 @@
#define DS_RIGHT            BIT(3)
#define DS_SCALE_UPDATE     BIT(4)
#define DS_ENHANCER_UPDATE  BIT(5)
#define DS_VALIDATE         BIT(6)
#define DS_DIRTY_UPDATE     BIT(7)

/**
 * Destination Scaler DUAL mode overfetch pixel count
@@ -370,6 +375,8 @@ struct mdss_mdp_destination_scaler {
	char __iomem *lut_base;
	u16 src_width;
	u16 src_height;
	u16 last_mixer_width;
	u16 last_mixer_height;
	u32 flags;
	struct mdp_scale_data_v2 scaler;
};
@@ -1706,6 +1713,7 @@ void mdss_mdp_pp_term(struct device *dev);
int mdss_mdp_pp_overlay_init(struct msm_fb_data_type *mfd);

int mdss_mdp_pp_resume(struct msm_fb_data_type *mfd);
void mdss_mdp_pp_dest_scaler_resume(struct mdss_mdp_ctl *ctl);

int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl);
int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl);
+17 −6
Original line number Diff line number Diff line
@@ -3508,7 +3508,9 @@ int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
	if (is_dest_scaling_enable(ctl->mixer_left)) {
		width = get_ds_input_width(ctl->mixer_left);
		height = get_ds_input_height(ctl->mixer_left);
		if (ctl->panel_data->next && is_pingpong_split(ctl->mfd))
		if (is_dual_lm_single_display(ctl->mfd) ||
				(ctl->panel_data->next &&
				 is_pingpong_split(ctl->mfd)))
			width *= 2;
	} else {
		width = get_panel_width(ctl);
@@ -3548,9 +3550,13 @@ int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
	}

	if (split_fb) {
		if (is_dest_scaling_enable(ctl->mixer_left)) {
			width = get_ds_input_width(ctl->mixer_left);
		} else {
			width = ctl->mfd->split_fb_left;
			width += (pinfo->lcdc.border_left +
					pinfo->lcdc.border_right);
		}
	} else if (width > max_mixer_width) {
		width /= 2;
	}
@@ -3576,8 +3582,12 @@ int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
		return 0;
	}

	if (split_fb)
	if (split_fb) {
		if (is_dest_scaling_enable(ctl->mixer_left))
			width = get_ds_input_width(ctl->mixer_left);
		else
			width = ctl->mfd->split_fb_right;
	}

	if (width < ctl->width) {
		if (ctl->mixer_right == NULL) {
@@ -4038,6 +4048,7 @@ static void mdss_mdp_ctl_restore_sub(struct mdss_mdp_ctl *ctl)
	if (ctl->mfd && ctl->panel_data) {
		ctl->mfd->ipc_resume = true;
		mdss_mdp_pp_resume(ctl->mfd);
		mdss_mdp_pp_dest_scaler_resume(ctl);

		if (is_dsc_compression(&ctl->panel_data->panel_info)) {
			/*
+188 −33
Original line number Diff line number Diff line
@@ -67,13 +67,89 @@ static inline void *u64_to_ptr(uint64_t address)
	return (void *)(uintptr_t)address;
}

static void mdss_mdp_disable_destination_scaler_setup(struct mdss_mdp_ctl *ctl)
{
	struct mdss_data_type *mdata = ctl->mdata;
	struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info;

	if (test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map)) {
		if (ctl->mixer_left && ctl->mixer_right &&
				ctl->mixer_left->ds && ctl->mixer_right->ds &&
				ctl->mixer_left->ds->scaler.enable &&
				ctl->mixer_right->ds->scaler.enable) {
			/*
			 * DUAL mode disable
			 */
			ctl->mixer_left->width = get_panel_width(ctl);
			ctl->mixer_left->height = get_panel_yres(pinfo);
			ctl->mixer_left->width /= 2;
			ctl->mixer_right->width = ctl->mixer_left->width;
			ctl->mixer_right->height = ctl->mixer_left->height;
			ctl->mixer_left->roi = (struct mdss_rect) { 0, 0,
				ctl->mixer_left->width,
				ctl->mixer_left->height };
			ctl->mixer_right->roi = (struct mdss_rect) { 0, 0,
				ctl->mixer_right->width,
				ctl->mixer_right->height };

			/*
			 * Disable destination scaler by resetting the control
			 * flags and also need to disable in the QSEED3
			 * settings.
			 */
			ctl->mixer_left->ds->flags = DS_SCALE_UPDATE |
				DS_VALIDATE;
			ctl->mixer_right->ds->flags = DS_SCALE_UPDATE |
				DS_VALIDATE;
			ctl->mixer_left->ds->scaler.enable = 0;
			ctl->mixer_left->ds->scaler.detail_enhance.enable = 0;
			ctl->mixer_right->ds->scaler.enable = 0;
			ctl->mixer_right->ds->scaler.detail_enhance.enable = 0;

			pr_debug("DS-Left+Right disable: left:%dx%d, right:%dx%d\n",
					ctl->mixer_left->width,
					ctl->mixer_left->height,
					ctl->mixer_right->width,
					ctl->mixer_right->height);
			MDSS_XLOG(ctl->mixer_left->width,
					ctl->mixer_left->height,
					ctl->mixer_right->width,
					ctl->mixer_right->height);
		} else if (ctl->mixer_left && ctl->mixer_left->ds &&
				ctl->mixer_left->ds->scaler.enable) {
			/*
			 * Single DS disable
			 */
			ctl->mixer_left->width = get_panel_width(ctl);
			ctl->mixer_left->height = get_panel_yres(pinfo);
			ctl->mixer_left->roi = (struct mdss_rect) { 0, 0,
				ctl->mixer_left->width,
				ctl->mixer_left->height };

			ctl->mixer_left->ds->flags = DS_SCALE_UPDATE |
				DS_VALIDATE;
			ctl->mixer_left->ds->scaler.enable = 0;
			ctl->mixer_left->ds->scaler.detail_enhance.enable = 0;

			pr_debug("DS-left disable: wxh=%dx%d\n",
					ctl->mixer_left->width,
					ctl->mixer_left->height);
			MDSS_XLOG(ctl->mixer_left->width,
					ctl->mixer_left->height);
		}
	}
}

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)
{
	struct mdp_scale_data_v2 *scale;

	ds->flags = (ds_data->flags & MDP_DESTSCALER_ENABLE) ? DS_ENABLE : 0;
	if (ds_data->flags & MDP_DESTSCALER_ENABLE)
		ds->flags |= DS_ENABLE;
	else
		ds->flags &= ~DS_ENABLE;

	if (ds_data->flags & (MDP_DESTSCALER_SCALE_UPDATE |
				MDP_DESTSCALER_ENHANCER_UPDATE)) {
@@ -101,8 +177,12 @@ static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data,
			ds->flags |= DS_SCALE_UPDATE;
		if (ds_data->flags & MDP_DESTSCALER_ENHANCER_UPDATE)
			ds->flags |= DS_ENHANCER_UPDATE;
		ds->src_width = scale->src_width[0];
		ds->src_height = scale->src_height[0];

		/*
		 * Update with LM resolution
		 */
		ds->src_width = ds_data->lm_width;
		ds->src_height = ds_data->lm_height;
	}

	if (ds_data->flags == 0) {
@@ -110,6 +190,11 @@ static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data,
				ds_data->dest_scaler_ndx);
	}

	/*
	 * Confirm all check pass validation, and to be cleared in CTL after
	 * flush is issued.
	 */
	ds->flags |= DS_VALIDATE;
	return 0;
}

@@ -118,7 +203,7 @@ static int mdss_mdp_destination_scaler_pre_validate(struct mdss_mdp_ctl *ctl,
{
	struct mdss_data_type *mdata;
	struct mdss_panel_info *pinfo;

	u16 mxleft_w = 0, mxleft_h = 0, mxright_w = 0, mxright_h = 0;
	mdata = ctl->mdata;

	/*
@@ -134,7 +219,7 @@ static int mdss_mdp_destination_scaler_pre_validate(struct mdss_mdp_ctl *ctl,
			 * height.
			 */
			pinfo = &ctl->panel_data->panel_info;
			if ((ds_data->lm_width > get_panel_xres(pinfo)) ||
			if ((ds_data->lm_width > get_panel_width(ctl)) ||
				(ds_data->lm_height >  get_panel_yres(pinfo)) ||
				(ds_data->lm_width == 0) ||
				(ds_data->lm_height == 0)) {
@@ -142,14 +227,8 @@ static int mdss_mdp_destination_scaler_pre_validate(struct mdss_mdp_ctl *ctl,
					ds_data->lm_width, ds_data->lm_height);
				return -EINVAL;
			}

			ctl->width = ds_data->lm_width;
			ctl->height = ds_data->lm_height;

			ctl->mixer_left->width  = ds_data->lm_width;
			ctl->mixer_left->height = ds_data->lm_height;
			pr_debug("Update mixer-left width/height: %dx%d\n",
					ds_data->lm_width, ds_data->lm_width);
			mxleft_w = ds_data->lm_width;
			mxleft_h = ds_data->lm_height;
		}

		if (ctl->mixer_right && ctl->mixer_right->ds) {
@@ -174,25 +253,51 @@ static int mdss_mdp_destination_scaler_pre_validate(struct mdss_mdp_ctl *ctl,
			 * Split display both left and right should have the
			 * same width and height
			 */
			ctl->mixer_right->width  = ds_data->lm_width;
			ctl->mixer_right->height = ds_data->lm_height;
			pr_debug("Update mixer-right width/height: %dx%d\n",
					ds_data->lm_width, ds_data->lm_height);
			mxright_w = ds_data->lm_width;
			mxright_h = ds_data->lm_height;

			if (ctl->mixer_left &&
					((ctl->mixer_right->width !=
					  ctl->mixer_left->width) ||
					 (ctl->mixer_right->height !=
					  ctl->mixer_left->height))) {
					((mxright_w != mxleft_w) ||
					 (mxright_h != mxleft_h))) {
				pr_err("Mismatch width/heigth in LM for split display\n");
				return -EINVAL;
			}
		}

		/*
		 * Update mixer and control dimension after successful
		 * pre-validation
		 */
		if (mxleft_w && mxleft_h) {
			ctl->mixer_left->ds->last_mixer_width =
				ctl->mixer_left->width;
			ctl->mixer_left->ds->last_mixer_height =
				ctl->mixer_left->height;

			ctl->width = mxleft_w;
			ctl->height = mxleft_h;
			ctl->mixer_left->width = mxleft_w;
			ctl->mixer_left->height = mxleft_h;
			pr_debug("Update mixer-left width/height: %dx%d\n",
					mxleft_w, mxleft_h);
		}

		if (mxright_w && mxright_h) {
			ctl->mixer_right->ds->last_mixer_width =
				ctl->mixer_right->width;
			ctl->mixer_right->ds->last_mixer_height =
				ctl->mixer_right->height;

			ctl->mixer_right->width = mxright_w;
			ctl->mixer_right->height = mxright_h;
			pr_debug("Update mixer-right width/height: %dx%d\n",
					mxright_w, mxright_h);

			/*
			 * For split display, CTL width should be equal to
			 * whole panel size
			 */
			ctl->width += ds_data->lm_width;
			ctl->width += mxright_w;
		}

		pr_debug("Updated CTL width:%d, height:%d\n",
@@ -236,19 +341,23 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
					MDSS_MDP_DS_OVERFETCH_SIZE,
					mdata->max_dest_scaler_output_width);
			if (ret)
				return ret;
				goto reset_mixer;

			ret = __dest_scaler_data_setup(&ds_data[1], ds_right,
					mdata->max_dest_scaler_input_width -
					MDSS_MDP_DS_OVERFETCH_SIZE,
					mdata->max_dest_scaler_output_width);
			if (ret)
				return ret;
				goto reset_mixer;

			ds_left->flags  &= ~(DS_LEFT|DS_RIGHT);
			ds_left->flags  |= DS_DUAL_MODE;
			ds_right->flags &= ~(DS_LEFT|DS_RIGHT);
			ds_right->flags |= DS_DUAL_MODE;
			MDSS_XLOG(ds_left->num, ds_left->src_width,
					ds_left->src_height, ds_left->flags,
					ds_right->num, ds_right->src_width,
					ds_right->src_height, ds_right->flags);
			break;

		case DS_LEFT:
@@ -262,6 +371,11 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
			ret = __dest_scaler_data_setup(&ds_data[0], ds_left,
					mdata->max_dest_scaler_input_width,
					mdata->max_dest_scaler_output_width);
			if (ret)
				goto reset_mixer;

			MDSS_XLOG(ds_left->num, ds_left->src_width,
					ds_left->src_height, ds_left->flags);
			break;

		case DS_RIGHT:
@@ -276,6 +390,11 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
			ret = __dest_scaler_data_setup(&ds_data[0], ds_right,
					mdata->max_dest_scaler_input_width,
					mdata->max_dest_scaler_output_width);
			if (ret)
				goto reset_mixer;

			MDSS_XLOG(ds_right->num, ds_right->src_width,
					ds_right->src_height, ds_right->flags);
			break;
		}

@@ -312,6 +431,40 @@ static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
		pr_err("Invalid Dest-scaler output width/height: %d/%d\n",
			scaler_width, scaler_height);
		ret = -EINVAL;
		goto reset_mixer;
	}

	return ret;

reset_mixer:
	/* reverting mixer and control dimension */
	if (ctl->mixer_left && ctl->mixer_left->ds &&
			ctl->mixer_left->ds->last_mixer_width) {
		ctl->width = ctl->mixer_left->ds->last_mixer_width;
		ctl->height = ctl->mixer_left->ds->last_mixer_height;
		ctl->mixer_left->width =
			ctl->mixer_left->ds->last_mixer_width;
		ctl->mixer_left->height =
			ctl->mixer_left->ds->last_mixer_height;
		if (ds_left)
			ds_left->flags &= ~DS_ENABLE;
		MDSS_XLOG(ctl->width, ctl->height,
				ctl->mixer_left->width,
				ctl->mixer_left->height);
	}

	if (ctl->mixer_right && ctl->mixer_right->ds &&
			ctl->mixer_right->ds->last_mixer_width) {
		ctl->width += ctl->mixer_right->ds->last_mixer_width;
		ctl->mixer_right->width =
			ctl->mixer_right->ds->last_mixer_width;
		ctl->mixer_right->height =
			ctl->mixer_right->ds->last_mixer_height;
		if (ds_right)
			ds_right->flags &= ~DS_ENABLE;
		MDSS_XLOG(ctl->width, ctl->height,
				ctl->mixer_right->width,
				ctl->mixer_right->height);
	}

	return ret;
@@ -1939,6 +2092,7 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
	enum layer_pipe_q pipe_q_type;
	enum layer_zorder_used zorder_used[MDSS_MDP_MAX_STAGE] = {0};
	enum mdss_mdp_pipe_rect rect_num;
	struct mdp_destination_scaler_data *ds_data;

	ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
	if (ret)
@@ -2194,11 +2348,10 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
		layer->z_order -= MDSS_MDP_STAGE_0;
	}

	ds_data = commit->dest_scaler;
	if (test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map) &&
			commit->dest_scaler &&
			ds_data && (ds_data->flags & MDP_DESTSCALER_ENABLE) &&
			commit->dest_scaler_cnt) {
		struct mdp_destination_scaler_data *ds_data =
			commit->dest_scaler;

		/*
		 * Find out which DS block to use based on DS commit info
@@ -2217,8 +2370,7 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
		}

		ret = mdss_mdp_validate_destination_scaler(mfd,
				commit->dest_scaler,
				ds_mode);
				ds_data, ds_mode);
		if (ret) {
			pr_err("fail to validate destination scaler\n");
			layer->error_code = ret;
@@ -2472,6 +2624,7 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd,
	struct file *file, struct mdp_layer_commit_v1 *commit)
{
	struct mdss_overlay_private *mdp5_data;
	struct mdp_destination_scaler_data *ds_data;
	int rc = 0;

	if (!mfd || !commit) {
@@ -2505,15 +2658,17 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd,
		}
	}

	if (commit->dest_scaler && commit->dest_scaler_cnt) {
	ds_data = commit->dest_scaler;
	if (ds_data && commit->dest_scaler_cnt &&
			(ds_data->flags & MDP_DESTSCALER_ENABLE)) {
		rc = mdss_mdp_destination_scaler_pre_validate(mdp5_data->ctl,
				commit->dest_scaler,
				commit->dest_scaler_cnt);
				ds_data, commit->dest_scaler_cnt);
		if (IS_ERR_VALUE(rc)) {
			pr_err("Destination scaler pre-validate failed\n");
			return -EINVAL;
		}
	}
	} else
		mdss_mdp_disable_destination_scaler_setup(mdp5_data->ctl);

	rc = mdss_mdp_avr_validate(mfd, commit);
	if (IS_ERR_VALUE(rc)) {
+48 −1
Original line number Diff line number Diff line
@@ -2480,6 +2480,28 @@ static int pp_dest_scaler_setup(struct mdss_mdp_mixer *mixer)
	if (!test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map) || !ds)
		return 0;

	/*
	 * Non-validated DS data will be related to PM event. It is required
	 * to send out last setup to match the mixer and panel configuration.
	 */
	if (!(ds->flags & DS_VALIDATE)) {
		pr_debug("Apply old DS[%d] for non validate data\n", ds->num);
		if (ds->flags & DS_ENABLE)
			ds->flags |= (DS_SCALE_UPDATE | DS_ENHANCER_UPDATE);
		ds->flags |= DS_VALIDATE;
	}

	/*
	 * If mark for dirty update, force update to scaler and detail
	 * enhancer.
	 */
	if (ds->flags & DS_DIRTY_UPDATE) {
		pr_debug("Scale dirty update requested\n");
		ds->flags |= (DS_SCALE_UPDATE | DS_ENHANCER_UPDATE |
				DS_VALIDATE);
		ds->flags &= ~DS_DIRTY_UPDATE;
	}

	ds_offset = ds->ds_base;
	op_mode = readl_relaxed(MDSS_MDP_REG_DEST_SCALER_OP_MODE +
			ds_offset);
@@ -2519,12 +2541,37 @@ static int pp_dest_scaler_setup(struct mdss_mdp_mixer *mixer)
	}

	/* Destinations scaler shared the flush with DSPP in control */
	if (ds->flags & DS_ENABLE)
	if (ds->flags & (DS_ENABLE | DS_VALIDATE)) {
		pr_debug("FLUSH[%d]: flags:%X, op_mode:%x\n",
				ds->num, ds->flags, op_mode);
		ctl->flush_bits |= BIT(13 + ds->num);
	}

	ds->flags &= ~DS_VALIDATE;
	return 0;
}

void mdss_mdp_pp_dest_scaler_resume(struct mdss_mdp_ctl *ctl)
{
	if (!ctl || !ctl->mdata) {
		pr_err("Invalid ctl\n");
		return;
	}

	if (!test_bit(MDSS_CAPS_DEST_SCALER, ctl->mdata->mdss_caps_map))
		return;

	if (ctl->mixer_left && ctl->mixer_left->ds) {
		ctl->mixer_left->ds->flags |= DS_DIRTY_UPDATE;
		pr_debug("DS left mark dirty\n");
	}

	if (ctl->mixer_right && ctl->mixer_right->ds) {
		ctl->mixer_right->ds->flags |= DS_DIRTY_UPDATE;
		pr_debug("DS right mark dirty\n");
	}
}

int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
{
	int ret = 0;