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

Commit ef3ed353 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: CCN Cleanup for sde_rm"

parents a8903b38 de8d0d85
Loading
Loading
Loading
Loading
+241 −155
Original line number Diff line number Diff line
@@ -391,72 +391,11 @@ static int _sde_rm_hw_blk_create(
	return 0;
}

int sde_rm_init(struct sde_rm *rm,
static int _sde_rm_hw_blk_create_new(struct sde_rm *rm,
			struct sde_mdss_cfg *cat,
		void __iomem *mmio,
		struct drm_device *dev)
			void __iomem *mmio)
{
	int i, rc = 0;
	enum sde_hw_blk_type type;

	if (!rm || !cat || !mmio || !dev) {
		SDE_ERROR("invalid kms\n");
		return -EINVAL;
	}

	/* Clear, setup lists */
	memset(rm, 0, sizeof(*rm));

	mutex_init(&rm->rm_lock);

	INIT_LIST_HEAD(&rm->rsvps);
	for (type = 0; type < SDE_HW_BLK_MAX; type++)
		INIT_LIST_HEAD(&rm->hw_blks[type]);

	rm->dev = dev;

	if (IS_SDE_CTL_REV_100(cat->ctl_rev))
		rm->topology_tbl = g_ctl_ver_1_top_table;
	else
		rm->topology_tbl = g_top_table;

	/* Some of the sub-blocks require an mdptop to be created */
	rm->hw_mdp = sde_hw_mdptop_init(MDP_TOP, mmio, cat);
	if (IS_ERR_OR_NULL(rm->hw_mdp)) {
		rc = PTR_ERR(rm->hw_mdp);
		rm->hw_mdp = NULL;
		SDE_ERROR("failed: mdp hw not available\n");
		goto fail;
	}

	/* Interrogate HW catalog and create tracking items for hw blocks */
	for (i = 0; i < cat->mixer_count; i++) {
		struct sde_lm_cfg *lm = &cat->mixer[i];

		if (lm->pingpong == PINGPONG_MAX) {
			SDE_ERROR("mixer %d without pingpong\n", lm->id);
			goto fail;
		}

		rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_LM,
				cat->mixer[i].id, &cat->mixer[i]);
		if (rc) {
			SDE_ERROR("failed: lm hw not available\n");
			goto fail;
		}

		if (!rm->lm_max_width) {
			rm->lm_max_width = lm->sblk->maxwidth;
		} else if (rm->lm_max_width != lm->sblk->maxwidth) {
			/*
			 * Don't expect to have hw where lm max widths differ.
			 * If found, take the min.
			 */
			SDE_ERROR("unsupported: lm maxwidth differs\n");
			if (rm->lm_max_width > lm->sblk->maxwidth)
				rm->lm_max_width = lm->sblk->maxwidth;
		}
	}

	for (i = 0; i < cat->dspp_count; i++) {
		rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_DSPP,
@@ -538,6 +477,80 @@ int sde_rm_init(struct sde_rm *rm,
	}

	return 0;
fail:
	return rc;
}

int sde_rm_init(struct sde_rm *rm,
		struct sde_mdss_cfg *cat,
		void __iomem *mmio,
		struct drm_device *dev)
{
	int i, rc = 0;
	enum sde_hw_blk_type type;

	if (!rm || !cat || !mmio || !dev) {
		SDE_ERROR("invalid kms\n");
		return -EINVAL;
	}

	/* Clear, setup lists */
	memset(rm, 0, sizeof(*rm));

	mutex_init(&rm->rm_lock);

	INIT_LIST_HEAD(&rm->rsvps);
	for (type = 0; type < SDE_HW_BLK_MAX; type++)
		INIT_LIST_HEAD(&rm->hw_blks[type]);

	rm->dev = dev;

	if (IS_SDE_CTL_REV_100(cat->ctl_rev))
		rm->topology_tbl = g_ctl_ver_1_top_table;
	else
		rm->topology_tbl = g_top_table;

	/* Some of the sub-blocks require an mdptop to be created */
	rm->hw_mdp = sde_hw_mdptop_init(MDP_TOP, mmio, cat);
	if (IS_ERR_OR_NULL(rm->hw_mdp)) {
		rc = PTR_ERR(rm->hw_mdp);
		rm->hw_mdp = NULL;
		SDE_ERROR("failed: mdp hw not available\n");
		goto fail;
	}

	/* Interrogate HW catalog and create tracking items for hw blocks */
	for (i = 0; i < cat->mixer_count; i++) {
		struct sde_lm_cfg *lm = &cat->mixer[i];

		if (lm->pingpong == PINGPONG_MAX) {
			SDE_ERROR("mixer %d without pingpong\n", lm->id);
			goto fail;
		}

		rc = _sde_rm_hw_blk_create(rm, cat, mmio, SDE_HW_BLK_LM,
				cat->mixer[i].id, &cat->mixer[i]);
		if (rc) {
			SDE_ERROR("failed: lm hw not available\n");
			goto fail;
		}

		if (!rm->lm_max_width) {
			rm->lm_max_width = lm->sblk->maxwidth;
		} else if (rm->lm_max_width != lm->sblk->maxwidth) {
			/*
			 * Don't expect to have hw where lm max widths differ.
			 * If found, take the min.
			 */
			SDE_ERROR("unsupported: lm maxwidth differs\n");
			if (rm->lm_max_width > lm->sblk->maxwidth)
				rm->lm_max_width = lm->sblk->maxwidth;
		}
	}

	rc = _sde_rm_hw_blk_create_new(rm, cat, mmio);
	if (!rc)
		return 0;

fail:
	sde_rm_destroy(rm);
@@ -545,63 +558,18 @@ int sde_rm_init(struct sde_rm *rm,
	return rc;
}

/**
 * _sde_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets
 *	proposed use case requirements, incl. hardwired dependent blocks like
 *	pingpong, and dspp.
 * @rm: sde resource manager handle
 * @rsvp: reservation currently being created
 * @reqs: proposed use case requirements
 * @lm: proposed layer mixer, function checks if lm, and all other hardwired
 *      blocks connected to the lm (pp, dspp) are available and appropriate
 * @dspp: output parameter, dspp block attached to the layer mixer.
 *        NULL if dspp was not available, or not matching requirements.
 * @pp: output parameter, pingpong block attached to the layer mixer.
 *      NULL if dspp was not available, or not matching requirements.
 * @primary_lm: if non-null, this function check if lm is compatible primary_lm
 *              as well as satisfying all other requirements
 * @Return: true if lm matches all requirements, false otherwise
 */
static bool _sde_rm_check_lm_and_get_connected_blks(
static bool _sde_rm_check_lm(
		struct sde_rm *rm,
		struct sde_rm_rsvp *rsvp,
		struct sde_rm_requirements *reqs,
		const struct sde_lm_cfg *lm_cfg,
		struct sde_rm_hw_blk *lm,
		struct sde_rm_hw_blk **dspp,
		struct sde_rm_hw_blk **ds,
		struct sde_rm_hw_blk **pp,
		struct sde_rm_hw_blk *primary_lm)
		struct sde_rm_hw_blk **pp)
{
	const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap;
	const struct sde_pingpong_cfg *pp_cfg;
	struct sde_rm_hw_iter iter;
	bool is_valid_dspp, is_valid_ds, ret;
	u32 display_pref, cwb_pref;

	*dspp = NULL;
	*ds = NULL;
	*pp = NULL;
	display_pref = lm_cfg->features & BIT(SDE_DISP_PRIMARY_PREF);
	cwb_pref = lm_cfg->features & BIT(SDE_DISP_CWB_PREF);

	SDE_DEBUG("check lm %d: dspp %d ds %d pp %d disp_pref: %d cwb_pref%d\n",
		lm_cfg->id, lm_cfg->dspp, lm_cfg->ds,
		lm_cfg->pingpong, display_pref, cwb_pref);

	/* Check if this layer mixer is a peer of the proposed primary LM */
	if (primary_lm) {
		const struct sde_lm_cfg *prim_lm_cfg =
				to_sde_hw_mixer(primary_lm->hw)->cap;

		if (!test_bit(lm_cfg->id, &prim_lm_cfg->lm_pair_mask)) {
			SDE_DEBUG("lm %d not peer of lm %d\n", lm_cfg->id,
					prim_lm_cfg->id);
			return false;
		}
	}

	/* bypass rest of the checks if LM for primary display is found */
	if (!display_pref) {
	is_valid_dspp = (lm_cfg->dspp != DSPP_MAX) ? true : false;
	is_valid_ds = (lm_cfg->ds != DS_MAX) ? true : false;

@@ -626,30 +594,20 @@ static bool _sde_rm_check_lm_and_get_connected_blks(
			lm_cfg->id, (bool)(RM_RQ_DSPP(reqs)),
			lm_cfg->dspp, (bool)(RM_RQ_DS(reqs)),
			lm_cfg->ds);
			return ret;
		}

		/**
		 * If CWB is enabled and LM is not CWB supported
		 * then return false.
		 */
		if (RM_RQ_CWB(reqs) && !cwb_pref) {
			SDE_DEBUG("fail: cwb supported lm not allocated\n");
			return false;
		return ret;
	}

	} else if (!(reqs->hw_res.is_primary && display_pref)) {
		SDE_DEBUG(
			"display preference is not met. is_primary: %d display_pref: %d\n",
			(int)reqs->hw_res.is_primary, (int)display_pref);
		return false;
	return true;
}

	/* Already reserved? */
	if (RESERVED_BY_OTHER(lm, rsvp)) {
		SDE_DEBUG("lm %d already reserved\n", lm_cfg->id);
		return false;
	}
static bool _sde_rm_reserve_dspp(
		struct sde_rm *rm,
		struct sde_rm_rsvp *rsvp,
		const struct sde_lm_cfg *lm_cfg,
		struct sde_rm_hw_blk *lm,
		struct sde_rm_hw_blk **dspp)
{
	struct sde_rm_hw_iter iter;

	if (lm_cfg->dspp != DSPP_MAX) {
		sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_DSPP);
@@ -672,6 +630,18 @@ static bool _sde_rm_check_lm_and_get_connected_blks(
			return false;
		}
	}
	return true;
}


static bool _sde_rm_reserve_ds(
		struct sde_rm *rm,
		struct sde_rm_rsvp *rsvp,
		const struct sde_lm_cfg *lm_cfg,
		struct sde_rm_hw_blk *lm,
		struct sde_rm_hw_blk **ds)
{
	struct sde_rm_hw_iter iter;

	if (lm_cfg->ds != DS_MAX) {
		sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_DS);
@@ -694,6 +664,21 @@ static bool _sde_rm_check_lm_and_get_connected_blks(
			return false;
		}
	}
	return true;
}

static bool _sde_rm_reserve_pp(
		struct sde_rm *rm,
		struct sde_rm_rsvp *rsvp,
		struct sde_rm_requirements *reqs,
		const struct sde_lm_cfg *lm_cfg,
		const struct sde_pingpong_cfg *pp_cfg,
		struct sde_rm_hw_blk *lm,
		struct sde_rm_hw_blk **dspp,
		struct sde_rm_hw_blk **ds,
		struct sde_rm_hw_blk **pp)
{
	struct sde_rm_hw_iter iter;

	sde_rm_init_hw_iter(&iter, 0, SDE_HW_BLK_PINGPONG);
	while (_sde_rm_get_hw_locked(rm, &iter)) {
@@ -724,6 +709,107 @@ static bool _sde_rm_check_lm_and_get_connected_blks(
		*ds = NULL;
		return false;
	}
	return true;
}

/**
 * _sde_rm_check_lm_and_get_connected_blks - check if proposed layer mixer meets
 *	proposed use case requirements, incl. hardwired dependent blocks like
 *	pingpong, and dspp.
 * @rm: sde resource manager handle
 * @rsvp: reservation currently being created
 * @reqs: proposed use case requirements
 * @lm: proposed layer mixer, function checks if lm, and all other hardwired
 *      blocks connected to the lm (pp, dspp) are available and appropriate
 * @dspp: output parameter, dspp block attached to the layer mixer.
 *        NULL if dspp was not available, or not matching requirements.
 * @pp: output parameter, pingpong block attached to the layer mixer.
 *      NULL if dspp was not available, or not matching requirements.
 * @primary_lm: if non-null, this function check if lm is compatible primary_lm
 *              as well as satisfying all other requirements
 * @Return: true if lm matches all requirements, false otherwise
 */
static bool _sde_rm_check_lm_and_get_connected_blks(
		struct sde_rm *rm,
		struct sde_rm_rsvp *rsvp,
		struct sde_rm_requirements *reqs,
		struct sde_rm_hw_blk *lm,
		struct sde_rm_hw_blk **dspp,
		struct sde_rm_hw_blk **ds,
		struct sde_rm_hw_blk **pp,
		struct sde_rm_hw_blk *primary_lm)
{
	const struct sde_lm_cfg *lm_cfg = to_sde_hw_mixer(lm->hw)->cap;
	const struct sde_pingpong_cfg *pp_cfg;
	bool ret;
	u32 display_pref, cwb_pref;

	*dspp = NULL;
	*ds = NULL;
	*pp = NULL;
	display_pref = lm_cfg->features & BIT(SDE_DISP_PRIMARY_PREF);
	cwb_pref = lm_cfg->features & BIT(SDE_DISP_CWB_PREF);

	SDE_DEBUG("check lm %d: dspp %d ds %d pp %d disp_pref: %d cwb_pref%d\n",
		lm_cfg->id, lm_cfg->dspp, lm_cfg->ds,
		lm_cfg->pingpong, display_pref, cwb_pref);

	/* Check if this layer mixer is a peer of the proposed primary LM */
	if (primary_lm) {
		const struct sde_lm_cfg *prim_lm_cfg =
				to_sde_hw_mixer(primary_lm->hw)->cap;

		if (!test_bit(lm_cfg->id, &prim_lm_cfg->lm_pair_mask)) {
			SDE_DEBUG("lm %d not peer of lm %d\n", lm_cfg->id,
					prim_lm_cfg->id);
			return false;
		}
	}

	/* bypass rest of the checks if LM for primary display is found */
	if (!display_pref) {
		/* Check lm for valid requirements */
		ret = _sde_rm_check_lm(rm, rsvp, reqs, lm_cfg, lm,
				dspp, ds, pp);
		if (!ret)
			return ret;

		/**
		 * If CWB is enabled and LM is not CWB supported
		 * then return false.
		 */
		if (RM_RQ_CWB(reqs) && !cwb_pref) {
			SDE_DEBUG("fail: cwb supported lm not allocated\n");
			return false;
		}
	} else if (!(reqs->hw_res.is_primary && display_pref)) {
		SDE_DEBUG(
			"display preference is not met. is_primary: %d display_pref: %d\n",
			(int)reqs->hw_res.is_primary, (int)display_pref);
		return false;
	}

	/* Already reserved? */
	if (RESERVED_BY_OTHER(lm, rsvp)) {
		SDE_DEBUG("lm %d already reserved\n", lm_cfg->id);
		return false;
	}

	/* Reserve dspp */
	ret = _sde_rm_reserve_dspp(rm, rsvp, lm_cfg, lm, dspp);
	if (!ret)
		return ret;

	/* Reserve ds */
	ret = _sde_rm_reserve_ds(rm, rsvp, lm_cfg, lm, ds);
	if (!ret)
		return ret;

	/* Reserve pp */
	ret = _sde_rm_reserve_pp(rm, rsvp, reqs, lm_cfg, pp_cfg, lm,
			dspp, ds, pp);
	if (!ret)
		return ret;

	return true;
}