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

Commit b2606309 authored by Sravanthi Kollukuduru's avatar Sravanthi Kollukuduru Committed by Steve Cohen
Browse files

drm/msm/sde: move lut cfg to crtc state



Current lut data parsing is done based on the assumption that
it will be sent only once. Treating lut property like any other,
moving lut cfg to crtc state. Also, added reconfiguration of
destination scaler block on power collapse (idle/suspend).

Change-Id: I1f16924e6b9a6b734da6584d4f55fdbf07a4e1d5
Signed-off-by: default avatarSravanthi Kollukuduru <skolluku@codeaurora.org>
Signed-off-by: default avatarSteve Cohen <cohens@codeaurora.org>
parent 72201f9e
Loading
Loading
Loading
Loading
+201 −197
Original line number Diff line number Diff line
@@ -604,18 +604,6 @@ static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc)
		return;
}

/**
 * sde_crtc_destroy_dest_scaler - free memory allocated for scaler lut
 * @sde_crtc: Pointer to sde crtc
 */
static void _sde_crtc_destroy_dest_scaler(struct sde_crtc *sde_crtc)
{
	if (!sde_crtc)
		return;

	kfree(sde_crtc->scl3_lut_cfg);
}

static void sde_crtc_destroy(struct drm_crtc *crtc)
{
	struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
@@ -629,7 +617,6 @@ static void sde_crtc_destroy(struct drm_crtc *crtc)
		drm_property_unreference_blob(sde_crtc->blob_info);
	msm_property_destroy(&sde_crtc->property_info);
	sde_cp_crtc_destroy_properties(crtc);
	_sde_crtc_destroy_dest_scaler(sde_crtc);

	sde_fence_deinit(&sde_crtc->output_fence);
	_sde_crtc_deinit_events(sde_crtc);
@@ -1809,16 +1796,11 @@ static int _sde_crtc_set_dest_scaler_lut(struct sde_crtc *sde_crtc,
	size_t len = 0;
	int ret = 0;

	if (!sde_crtc || !cstate || !sde_crtc->scl3_lut_cfg) {
	if (!sde_crtc || !cstate) {
		SDE_ERROR("invalid args\n");
		return -EINVAL;
	}

	if (sde_crtc->scl3_lut_cfg->is_configured) {
		SDE_DEBUG("%s: lut already configured\n", sde_crtc->name);
		return 0;
	}

	lut_data = msm_property_get_blob(&sde_crtc->property_info,
			&cstate->property_state, &len, lut_idx);
	if (!lut_data || !len) {
@@ -1828,7 +1810,7 @@ static int _sde_crtc_set_dest_scaler_lut(struct sde_crtc *sde_crtc,
		len = 0;
	}

	cfg = sde_crtc->scl3_lut_cfg;
	cfg = &cstate->scl3_lut_cfg;

	switch (lut_idx) {
	case CRTC_PROP_DEST_SCALER_LUT_ED:
@@ -1845,12 +1827,15 @@ static int _sde_crtc_set_dest_scaler_lut(struct sde_crtc *sde_crtc,
		break;
	default:
		ret = -EINVAL;
		SDE_ERROR("invalid LUT index = %d", lut_idx);
		SDE_ERROR("%s:invalid LUT idx(%d)\n", sde_crtc->name, lut_idx);
		SDE_EVT32(DRMID(&sde_crtc->base), lut_idx, SDE_EVTLOG_ERROR);
		break;
	}

	cfg->is_configured = cfg->dir_lut && cfg->cir_lut && cfg->sep_lut;

	SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), ret, lut_idx, len,
			cfg->is_configured);
	return ret;
}

@@ -1991,6 +1976,44 @@ int sde_crtc_secure_ctrl(struct drm_crtc *crtc, bool post_commit)
	return ret;
}

static int _sde_validate_hw_resources(struct sde_crtc *sde_crtc)
{
	int i;

	/**
	 * Check if sufficient hw resources are
	 * available as per target caps & topology
	 */
	if (!sde_crtc) {
		SDE_ERROR("invalid argument\n");
		return -EINVAL;
	}

	if (!sde_crtc->num_mixers ||
		sde_crtc->num_mixers > CRTC_DUAL_MIXERS) {
		SDE_ERROR("%s: invalid number mixers: %d\n",
			sde_crtc->name, sde_crtc->num_mixers);
		SDE_EVT32(DRMID(&sde_crtc->base), sde_crtc->num_mixers,
			SDE_EVTLOG_ERROR);
		return -EINVAL;
	}

	for (i = 0; i < sde_crtc->num_mixers; i++) {
		if (!sde_crtc->mixers[i].hw_lm || !sde_crtc->mixers[i].hw_ctl
			|| !sde_crtc->mixers[i].hw_ds) {
			SDE_ERROR("%s:insufficient resources for mixer(%d)\n",
				sde_crtc->name, i);
			SDE_EVT32(DRMID(&sde_crtc->base), sde_crtc->num_mixers,
				i, sde_crtc->mixers[i].hw_lm,
				sde_crtc->mixers[i].hw_ctl,
				sde_crtc->mixers[i].hw_ds, SDE_EVTLOG_ERROR);
			return -EINVAL;
		}
	}

	return 0;
}

/**
 * _sde_crtc_dest_scaler_setup - Set up dest scaler block
 * @crtc: Pointer to drm crtc
@@ -2007,6 +2030,7 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc)
	u32 flush_mask = 0, op_mode = 0;
	u32 lm_idx = 0, num_mixers = 0;
	int i, count = 0;
	bool ds_dirty = false;

	if (!crtc)
		return;
@@ -2015,29 +2039,40 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc)
	cstate = to_sde_crtc_state(crtc->state);
	kms = _sde_crtc_get_kms(crtc);
	num_mixers = sde_crtc->num_mixers;
	count = cstate->num_ds;

	SDE_DEBUG("crtc%d\n", crtc->base.id);
	SDE_EVT32(DRMID(crtc), num_mixers, count, cstate->ds_dirty,
		sde_crtc->ds_reconfig, cstate->num_ds_enabled);

	if (!cstate->ds_dirty) {
	/**
	 * destination scaler configuration will be done either
	 * or on set property or on power collapse (idle/suspend)
	 */
	ds_dirty = (cstate->ds_dirty || sde_crtc->ds_reconfig);
	if (sde_crtc->ds_reconfig) {
		SDE_DEBUG("reconfigure dest scaler block\n");
		sde_crtc->ds_reconfig = false;
	}

	if (!ds_dirty) {
		SDE_DEBUG("no change in settings, skip commit\n");
	} else if (!kms || !kms->catalog) {
		SDE_ERROR("invalid parameters\n");
		SDE_ERROR("crtc%d:invalid parameters\n", crtc->base.id);
	} else if (!kms->catalog->mdp[0].has_dest_scaler) {
		SDE_DEBUG("dest scaler feature not supported\n");
	} else if (num_mixers > CRTC_DUAL_MIXERS) {
		SDE_ERROR("invalid number mixers: %d\n", num_mixers);
	} else if (!sde_crtc->scl3_lut_cfg->is_configured) {
		SDE_DEBUG("no LUT data available\n");
	} else if (_sde_validate_hw_resources(sde_crtc)) {
		//do nothing
	} else if (!cstate->scl3_lut_cfg.is_configured) {
		SDE_ERROR("crtc%d:no LUT data available\n", crtc->base.id);
	} else {
		count = cstate->num_ds_enabled ? cstate->num_ds : num_mixers;

		for (i = 0; i < count; i++) {
			cfg = &cstate->ds_cfg[i];

			if (!cfg->flags)
				continue;

			lm_idx = cfg->ndx;
			lm_idx = cfg->idx;
			hw_lm  = sde_crtc->mixers[lm_idx].hw_lm;
			hw_ctl = sde_crtc->mixers[lm_idx].hw_ctl;
			hw_ds  = sde_crtc->mixers[lm_idx].hw_ds;
@@ -2051,7 +2086,7 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc)
					CRTC_DUAL_MIXERS) ?
					SDE_DS_OP_MODE_DUAL : 0;
				hw_ds->ops.setup_opmode(hw_ds, op_mode);
				SDE_EVT32(DRMID(crtc), op_mode);
				SDE_EVT32_VERBOSE(DRMID(crtc), op_mode);
			}

			/* Setup scaler */
@@ -2060,23 +2095,15 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc)
					SDE_DRM_DESTSCALER_ENHANCER_UPDATE)) {
				if (hw_ds->ops.setup_scaler)
					hw_ds->ops.setup_scaler(hw_ds,
							cfg->scl3_cfg,
							sde_crtc->scl3_lut_cfg);
						&cfg->scl3_cfg,
						&cstate->scl3_lut_cfg);

				/**
				 * Clear the flags as the block doesn't have to
				 * be programmed in each commit if no updates
				 */
				cfg->flags &= ~SDE_DRM_DESTSCALER_SCALE_UPDATE;
				cfg->flags &=
					~SDE_DRM_DESTSCALER_ENHANCER_UPDATE;
			}

			/*
			 * Dest scaler shares the flush bit of the LM in control
			 */
			if (cfg->set_lm_flush && hw_lm && hw_ctl &&
				hw_ctl->ops.get_bitmask_mixer) {
			if (hw_ctl->ops.get_bitmask_mixer) {
				flush_mask = hw_ctl->ops.get_bitmask_mixer(
						hw_ctl, hw_lm->idx);
				SDE_DEBUG("Set lm[%d] flush = %d",
@@ -2084,9 +2111,7 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc)
				hw_ctl->ops.update_pending_flush(hw_ctl,
							flush_mask);
			}
			cfg->set_lm_flush = false;
		}
		cstate->ds_dirty = false;
	}
}

@@ -2557,28 +2582,6 @@ static void _sde_crtc_set_dim_layer_v1(struct sde_crtc_state *cstate,
	}
}

/**
 * _sde_crtc_dest_scaler_init - allocate memory for scaler lut
 * @sde_crtc    :  Pointer to sde crtc
 * @catalog :  Pointer to mdss catalog info
 */
static void _sde_crtc_dest_scaler_init(struct sde_crtc *sde_crtc,
				struct sde_mdss_cfg *catalog)
{
	if (!sde_crtc || !catalog)
		return;

	if (!catalog->mdp[0].has_dest_scaler) {
		SDE_DEBUG("dest scaler feature not supported\n");
		return;
	}

	sde_crtc->scl3_lut_cfg = kzalloc(sizeof(struct sde_hw_scaler3_lut_cfg),
				GFP_KERNEL);
	if (!sde_crtc->scl3_lut_cfg)
		SDE_ERROR("failed to create scale LUT for dest scaler");
}

/**
 * _sde_crtc_set_dest_scaler - copy dest scaler settings from userspace
 * @sde_crtc   :  Pointer to sde crtc
@@ -2593,7 +2596,7 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc,
	struct sde_drm_dest_scaler_cfg *ds_cfg_usr;
	struct sde_drm_scaler_v2 scaler_v2;
	void __user *scaler_v2_usr;
	int i, count, ret = 0;
	int i, count;

	if (!sde_crtc || !cstate) {
		SDE_ERROR("invalid sde_crtc/state\n");
@@ -2602,15 +2605,14 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc,

	SDE_DEBUG("crtc %s\n", sde_crtc->name);

	cstate->num_ds = 0;
	cstate->ds_dirty = false;
	if (!usr_ptr) {
		SDE_DEBUG("ds data removed\n");
		return 0;
	}

	if (copy_from_user(&ds_data, usr_ptr, sizeof(ds_data))) {
		SDE_ERROR("failed to copy dest scaler data from user\n");
		SDE_ERROR("%s:failed to copy dest scaler data from user\n",
			sde_crtc->name);
		return -EINVAL;
	}

@@ -2620,11 +2622,10 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc,
		return 0;
	}

	if (!sde_crtc->num_mixers || count > sde_crtc->num_mixers ||
		(count && (count != sde_crtc->num_mixers) &&
		!(ds_data.ds_cfg[0].flags & SDE_DRM_DESTSCALER_PU_ENABLE))) {
		SDE_ERROR("invalid config:num ds(%d), mixers(%d),flags(%d)\n",
			count, sde_crtc->num_mixers, ds_data.ds_cfg[0].flags);
	if (count > SDE_MAX_DS_COUNT) {
		SDE_ERROR("%s: invalid config: num_ds(%d) max(%d)\n",
			sde_crtc->name, count, SDE_MAX_DS_COUNT);
		SDE_EVT32(DRMID(&sde_crtc->base), count, SDE_EVTLOG_ERROR);
		return -EINVAL;
	}

@@ -2632,48 +2633,34 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc,
	for (i = 0; i < count; i++) {
		ds_cfg_usr = &ds_data.ds_cfg[i];

		cstate->ds_cfg[i].ndx = ds_cfg_usr->index;
		cstate->ds_cfg[i].idx = ds_cfg_usr->index;
		cstate->ds_cfg[i].flags = ds_cfg_usr->flags;
		cstate->ds_cfg[i].lm_width = ds_cfg_usr->lm_width;
		cstate->ds_cfg[i].lm_height = ds_cfg_usr->lm_height;
		cstate->ds_cfg[i].scl3_cfg = NULL;
		memset(&scaler_v2, 0, sizeof(scaler_v2));

		if (ds_cfg_usr->scaler_cfg) {
			scaler_v2_usr =
			(void __user *)((uintptr_t)ds_cfg_usr->scaler_cfg);

			memset(&scaler_v2, 0, sizeof(scaler_v2));

			cstate->ds_cfg[i].scl3_cfg =
				kzalloc(sizeof(struct sde_hw_scaler3_cfg),
					GFP_KERNEL);

			if (!cstate->ds_cfg[i].scl3_cfg) {
				ret = -ENOMEM;
				goto err;
			}

			if (copy_from_user(&scaler_v2, scaler_v2_usr,
					sizeof(scaler_v2))) {
				SDE_ERROR("scale data:copy from user failed\n");
				ret = -EINVAL;
				goto err;
				SDE_ERROR("%s:scaler: copy from user failed\n",
					sde_crtc->name);
				return -EINVAL;
			}
		}

			sde_set_scaler_v2(cstate->ds_cfg[i].scl3_cfg,
					&scaler_v2);
		sde_set_scaler_v2(&cstate->ds_cfg[i].scl3_cfg, &scaler_v2);

		SDE_DEBUG("en(%d)dir(%d)de(%d) src(%dx%d) dst(%dx%d)\n",
				scaler_v2.enable, scaler_v2.dir_en,
				scaler_v2.de.enable, scaler_v2.src_width[0],
				scaler_v2.src_height[0], scaler_v2.dst_width,
				scaler_v2.dst_height);
			scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable,
			scaler_v2.src_width[0], scaler_v2.src_height[0],
			scaler_v2.dst_width, scaler_v2.dst_height);
		SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base),
				scaler_v2.enable, scaler_v2.dir_en,
				scaler_v2.de.enable, scaler_v2.src_width[0],
				scaler_v2.src_height[0], scaler_v2.dst_width,
				scaler_v2.dst_height);
		}
			scaler_v2.enable, scaler_v2.dir_en, scaler_v2.de.enable,
			scaler_v2.src_width[0], scaler_v2.src_height[0],
			scaler_v2.dst_width, scaler_v2.dst_height);

		SDE_DEBUG("ds cfg[%d]-ndx(%d) flags(%d) lm(%dx%d)\n",
			i, ds_cfg_usr->index, ds_cfg_usr->flags,
@@ -2685,13 +2672,9 @@ static int _sde_crtc_set_dest_scaler(struct sde_crtc *sde_crtc,

	cstate->num_ds = count;
	cstate->ds_dirty = true;
	return 0;

err:
	for (; i >= 0; i--)
		kfree(cstate->ds_cfg[i].scl3_cfg);
	SDE_EVT32_VERBOSE(DRMID(&sde_crtc->base), count, cstate->ds_dirty);

	return ret;
	return 0;
}

/**
@@ -2709,7 +2692,7 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc,
	struct sde_hw_ds *hw_ds;
	struct sde_hw_ds_cfg *cfg;
	u32 i, ret = 0, lm_idx;
	u32 num_ds_enable = 0;
	u32 num_ds_enable = 0, hdisplay = 0;
	u32 max_in_width = 0, max_out_width = 0;
	u32 prev_lm_width = 0, prev_lm_height = 0;

@@ -2723,13 +2706,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc,

	SDE_DEBUG("crtc%d\n", crtc->base.id);

	if (!cstate->ds_dirty && !cstate->num_ds_enabled) {
	if (!cstate->ds_dirty) {
		SDE_DEBUG("dest scaler property not set, skip validation\n");
		return 0;
	}

	if (!kms || !kms->catalog) {
		SDE_ERROR("invalid parameters\n");
		SDE_ERROR("crtc%d: invalid parameters\n", crtc->base.id);
		return -EINVAL;
	}

@@ -2739,40 +2722,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc,
	}

	if (!sde_crtc->num_mixers) {
		SDE_ERROR("mixers not allocated\n");
		return -EINVAL;
	}

	/**
	 * Check if sufficient hw resources are
	 * available as per target caps & topology
	 */
	if (sde_crtc->num_mixers > CRTC_DUAL_MIXERS) {
		SDE_ERROR("invalid config: mixers(%d) max(%d)\n",
			sde_crtc->num_mixers, CRTC_DUAL_MIXERS);
		ret = -EINVAL;
		goto err;
		SDE_DEBUG("mixers not allocated\n");
		return 0;
	}

	for (i = 0; i < sde_crtc->num_mixers; i++) {
		if (!sde_crtc->mixers[i].hw_lm || !sde_crtc->mixers[i].hw_ds) {
			SDE_ERROR("insufficient HW resources allocated\n");
			ret = -EINVAL;
	ret = _sde_validate_hw_resources(sde_crtc);
	if (ret)
		goto err;
		}
	}

	/**
	 * Check if DS needs to be enabled or disabled
	 * In case of enable, validate the data
	 */
	if (!cstate->ds_dirty || !cstate->num_ds ||
		!(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_ENABLE)) {
		SDE_DEBUG("disable dest scaler,dirty(%d)num(%d)flags(%d)\n",
			cstate->ds_dirty, cstate->num_ds,
			cstate->ds_cfg[0].flags);
		goto disable;
	}

	/**
	 * No of dest scalers shouldn't exceed hw ds block count and
@@ -2782,17 +2738,30 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc,
	if (cstate->num_ds > kms->catalog->ds_count ||
		((cstate->num_ds != sde_crtc->num_mixers) &&
		!(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_PU_ENABLE))) {
		SDE_ERROR("invalid cfg: num_ds(%d), hw_ds_cnt(%d) flags(%d)\n",
			cstate->num_ds, kms->catalog->ds_count,
		SDE_ERROR("crtc%d: num_ds(%d), hw_ds_cnt(%d) flags(%d)\n",
			crtc->base.id, cstate->num_ds, kms->catalog->ds_count,
			cstate->ds_cfg[0].flags);
		ret = -EINVAL;
		goto err;
	}

	/**
	 * Check if DS needs to be enabled or disabled
	 * In case of enable, validate the data
	 */
	if (!(cstate->ds_cfg[0].flags & SDE_DRM_DESTSCALER_ENABLE)) {
		SDE_DEBUG("disable dest scaler, num(%d) flags(%d)\n",
			cstate->num_ds, cstate->ds_cfg[0].flags);
		goto disable;
	}

	/* Display resolution */
	hdisplay = mode->hdisplay/sde_crtc->num_mixers;

	/* Validate the DS data */
	for (i = 0; i < cstate->num_ds; i++) {
		cfg = &cstate->ds_cfg[i];
		lm_idx = cfg->ndx;
		lm_idx = cfg->idx;

		/**
		 * Validate against topology
@@ -2801,8 +2770,10 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc,
		 */
		if (lm_idx >= sde_crtc->num_mixers || (i != lm_idx &&
			!(cfg->flags & SDE_DRM_DESTSCALER_PU_ENABLE))) {
			SDE_ERROR("invalid user data(%d):idx(%d), flags(%d)\n",
				i, lm_idx, cfg->flags);
			SDE_ERROR("crtc%d: ds_cfg id(%d):idx(%d), flags(%d)\n",
				crtc->base.id, i, lm_idx, cfg->flags);
			SDE_EVT32(DRMID(crtc), i, lm_idx, cfg->flags,
				SDE_EVTLOG_ERROR);
			ret = -EINVAL;
			goto err;
		}
@@ -2821,14 +2792,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc,
		}

		/* Check LM width and height */
		if (cfg->lm_width > (mode->hdisplay/sde_crtc->num_mixers) ||
			cfg->lm_height > mode->vdisplay ||
			!cfg->lm_width || !cfg->lm_height) {
			SDE_ERROR("invalid lm size[%d,%d] display [%d,%d]\n",
				cfg->lm_width,
				cfg->lm_height,
				mode->hdisplay/sde_crtc->num_mixers,
				mode->vdisplay);
		if (cfg->lm_width > hdisplay || cfg->lm_height > mode->vdisplay
			|| !cfg->lm_width || !cfg->lm_height) {
			SDE_ERROR("crtc%d: lm size[%d,%d] display [%d,%d]\n",
				crtc->base.id, cfg->lm_width, cfg->lm_height,
				hdisplay, mode->vdisplay);
			SDE_EVT32(DRMID(crtc),  cfg->lm_width, cfg->lm_height,
				hdisplay, mode->vdisplay, SDE_EVTLOG_ERROR);
			ret = -E2BIG;
			goto err;
		}
@@ -2839,9 +2809,13 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc,
		} else {
			if (cfg->lm_width != prev_lm_width ||
				cfg->lm_height != prev_lm_height) {
				SDE_ERROR("lm size:left[%d,%d], right[%d %d]\n",
					cfg->lm_width, cfg->lm_height,
					prev_lm_width, prev_lm_height);
				SDE_ERROR("crtc%d:lm left[%d,%d]right[%d %d]\n",
					crtc->base.id, cfg->lm_width,
					cfg->lm_height, prev_lm_width,
					prev_lm_height);
				SDE_EVT32(DRMID(crtc), cfg->lm_width,
					cfg->lm_height, prev_lm_width,
					prev_lm_height, SDE_EVTLOG_ERROR);
				ret = -EINVAL;
				goto err;
			}
@@ -2850,22 +2824,40 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc,
		/* Check scaler data */
		if (cfg->flags & SDE_DRM_DESTSCALER_SCALE_UPDATE ||
			cfg->flags & SDE_DRM_DESTSCALER_ENHANCER_UPDATE) {
			if (!cfg->scl3_cfg) {
				ret = -EINVAL;
				SDE_ERROR("null scale data\n");
				goto err;
			}
			if (cfg->scl3_cfg->src_width[0] > max_in_width ||
				cfg->scl3_cfg->dst_width > max_out_width ||
				!cfg->scl3_cfg->src_width[0] ||
				!cfg->scl3_cfg->dst_width) {
				SDE_ERROR("scale width(%d %d) for ds-%d:\n",
					cfg->scl3_cfg->src_width[0],
					cfg->scl3_cfg->dst_width,

			/**
			 * Scaler src and dst width shouldn't exceed the maximum
			 * width limitation. Also, if there is no partial update
			 * dst width and height must match display resolution.
			 */
			if (cfg->scl3_cfg.src_width[0] > max_in_width ||
				cfg->scl3_cfg.dst_width > max_out_width ||
				!cfg->scl3_cfg.src_width[0] ||
				!cfg->scl3_cfg.dst_width ||
				(!(cfg->flags & SDE_DRM_DESTSCALER_PU_ENABLE)
				 && (cfg->scl3_cfg.dst_width != hdisplay ||
				 cfg->scl3_cfg.dst_height != mode->vdisplay))) {
				SDE_ERROR("crtc%d: ", crtc->base.id);
				SDE_ERROR("src_w(%d) dst(%dx%d) display(%dx%d)",
					cfg->scl3_cfg.src_width[0],
					cfg->scl3_cfg.dst_width,
					cfg->scl3_cfg.dst_height,
					hdisplay, mode->vdisplay);
				SDE_ERROR("num_mixers(%d) flags(%d) ds-%d:\n",
					sde_crtc->num_mixers, cfg->flags,
					hw_ds->idx - DS_0);
				SDE_ERROR("scale_en = %d, DE_en =%d\n",
					cfg->scl3_cfg->enable,
					cfg->scl3_cfg->de.enable);
					cfg->scl3_cfg.enable,
					cfg->scl3_cfg.de.enable);

				SDE_EVT32(DRMID(crtc), cfg->scl3_cfg.enable,
					cfg->scl3_cfg.de.enable, cfg->flags,
					max_in_width, max_out_width,
					cfg->scl3_cfg.src_width[0],
					cfg->scl3_cfg.dst_width,
					cfg->scl3_cfg.dst_height, hdisplay,
					mode->vdisplay, sde_crtc->num_mixers,
					SDE_EVTLOG_ERROR);

				cfg->flags &=
					~SDE_DRM_DESTSCALER_SCALE_UPDATE;
@@ -2880,36 +2872,34 @@ static int _sde_crtc_check_dest_scaler_data(struct drm_crtc *crtc,
		if (cfg->flags & SDE_DRM_DESTSCALER_ENABLE)
			num_ds_enable++;

		/**
		 * Validation successful, indicator for flush to be issued
		 */
		cfg->set_lm_flush = true;

		SDE_DEBUG("ds[%d]: flags = 0x%X\n",
		SDE_DEBUG("ds[%d]: flags[0x%X]\n",
			hw_ds->idx - DS_0, cfg->flags);
		SDE_EVT32_VERBOSE(DRMID(crtc), hw_ds->idx - DS_0, cfg->flags);
	}

disable:
	SDE_DEBUG("dest scaler enable status, old = %d, new = %d",
	SDE_DEBUG("dest scaler status : %d -> %d\n",
		cstate->num_ds_enabled,	num_ds_enable);
	SDE_EVT32(DRMID(crtc), cstate->num_ds_enabled, num_ds_enable,
		cstate->ds_dirty);
	SDE_EVT32_VERBOSE(DRMID(crtc), cstate->num_ds_enabled, num_ds_enable,
			cstate->num_ds, cstate->ds_dirty);

	if (cstate->num_ds_enabled != num_ds_enable) {
		/* Disabling destination scaler */
		if (!num_ds_enable) {
			for (i = 0; i < sde_crtc->num_mixers; i++) {
			for (i = 0; i < cstate->num_ds; i++) {
				cfg = &cstate->ds_cfg[i];
				cfg->ndx = i;
				cfg->idx = i;
				/* Update scaler settings in disable case */
				cfg->flags = SDE_DRM_DESTSCALER_SCALE_UPDATE;
				cfg->scl3_cfg->enable = 0;
				cfg->scl3_cfg->de.enable = 0;
				cfg->set_lm_flush = true;
				cfg->scl3_cfg.enable = 0;
				cfg->scl3_cfg.de.enable = 0;
			}
		}
		cstate->num_ds_enabled = num_ds_enable;
		cstate->ds_dirty = true;
	} else {
		if (!cstate->num_ds_enabled)
			cstate->ds_dirty = false;
	}

	return 0;
@@ -3875,6 +3865,9 @@ static struct drm_crtc_state *sde_crtc_duplicate_state(struct drm_crtc *crtc)
			old_cstate, cstate,
			&cstate->property_state, cstate->property_values);

	/* clear destination scaler dirty bit */
	cstate->ds_dirty = false;

	/* duplicate base helper */
	__drm_atomic_helper_crtc_duplicate_state(crtc, &cstate->base);

@@ -3941,6 +3934,7 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
{
	struct drm_crtc *crtc = arg;
	struct sde_crtc *sde_crtc;
	struct sde_crtc_state *cstate;
	struct drm_plane *plane;
	struct drm_encoder *encoder;
	struct sde_crtc_mixer *m;
@@ -3954,6 +3948,7 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
		return;
	}
	sde_crtc = to_sde_crtc(crtc);
	cstate = to_sde_crtc_state(crtc->state);

	mutex_lock(&sde_crtc->crtc_lock);

@@ -4042,6 +4037,14 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
			sde_plane_set_revalidate(plane, true);

		sde_cp_crtc_suspend(crtc);

		/**
		 * destination scaler if enabled should be reconfigured
		 * in the next frame update
		 */
		if (cstate->num_ds_enabled)
			sde_crtc->ds_reconfig = true;

		break;
	default:
		SDE_DEBUG("event:%d not handled\n", event_type);
@@ -4087,6 +4090,10 @@ static void sde_crtc_disable(struct drm_crtc *crtc)
	msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
			(u8 *)&power_on);

	/* destination scaler if enabled should be reconfigured on resume */
	if (cstate->num_ds_enabled)
		sde_crtc->ds_reconfig = true;

	/* wait for frame_event_done completion */
	if (_sde_crtc_wait_for_frame_done(crtc))
		SDE_ERROR("crtc%d wait for frame done failed;frame_pending%d\n",
@@ -5725,9 +5732,6 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane)

	sde_crtc_install_properties(crtc, kms->catalog);

	/* Init dest scaler */
	_sde_crtc_dest_scaler_init(sde_crtc, kms->catalog);

	/* Install color processing properties */
	sde_cp_crtc_init(crtc);
	sde_cp_crtc_install_properties(crtc);
+4 −2
Original line number Diff line number Diff line
@@ -188,6 +188,7 @@ struct sde_crtc_event {
 * @enabled       : whether the SDE CRTC is currently enabled. updated in the
 *                  commit-thread, not state-swap time which is earlier, so
 *                  safe to make decisions on during VBLANK on/off work
 * @ds_reconfig   : force reconfiguration of the destination scaler block
 * @feature_list  : list of color processing features supported on a crtc
 * @active_list   : list of color processing features are active
 * @dirty_list    : list of color processing features are dirty
@@ -215,7 +216,6 @@ struct sde_crtc_event {
 * @cur_perf      : current performance committed to clock/bandwidth driver
 * @rp_lock       : serialization lock for resource pool
 * @rp_head       : list of active resource pool
 * @scl3_cfg_lut  : qseed3 lut config
 */
struct sde_crtc {
	struct drm_crtc base;
@@ -226,7 +226,6 @@ struct sde_crtc {
	u32 num_mixers;
	bool mixers_swapped;
	struct sde_crtc_mixer mixers[CRTC_DUAL_MIXERS];
	struct sde_hw_scaler3_lut_cfg *scl3_lut_cfg;

	struct drm_pending_vblank_event *event;
	u32 vsync_count;
@@ -248,6 +247,7 @@ struct sde_crtc {
	bool suspend;
	bool enabled;

	bool ds_reconfig;
	struct list_head feature_list;
	struct list_head active_list;
	struct list_head dirty_list;
@@ -374,6 +374,7 @@ struct sde_crtc_respool {
 * @num_ds_enabled: Number of destination scalers enabled
 * @ds_dirty: Boolean to indicate if dirty or not
 * @ds_cfg: Destination scaler config
 * @scl3_lut_cfg: QSEED3 lut config
 * @new_perf: new performance state being requested
 * @sbuf_cfg: stream buffer configuration
 * @sbuf_prefill_line: number of line for inline rotator prefetch
@@ -403,6 +404,7 @@ struct sde_crtc_state {
	uint32_t num_ds_enabled;
	bool ds_dirty;
	struct sde_hw_ds_cfg ds_cfg[SDE_MAX_DS_COUNT];
	struct sde_hw_scaler3_lut_cfg scl3_lut_cfg;

	struct sde_core_perf_params new_perf;
	struct sde_ctl_sbuf_cfg sbuf_cfg;
+4 −6
Original line number Diff line number Diff line
@@ -27,20 +27,18 @@ struct sde_hw_ds;
#define SDE_DS_OP_MODE_DUAL BIT(16)

/* struct sde_hw_ds_cfg - destination scaler config
 * @ndx          : DS selection index
 * @idx          : DS selection index
 * @flags        : Flag to switch between mode for DS
 * @lm_width     : Layer mixer width configuration
 * @lm_heigh     : Layer mixer height configuration
 * @set_lm_flush : LM flush bit
 * @scl3_cfg     : Pointer to sde_hw_scaler3_cfg.
 * @scl3_cfg     : Configuration data for scaler
 */
struct sde_hw_ds_cfg {
	u32 ndx;
	u32 idx;
	int flags;
	u32 lm_width;
	u32 lm_height;
	bool set_lm_flush;
	struct sde_hw_scaler3_cfg *scl3_cfg;
	struct sde_hw_scaler3_cfg scl3_cfg;
};

/**