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

Commit b2b308c6 authored by Adrian Salido-Moreno's avatar Adrian Salido-Moreno Committed by Huaibin Yang
Browse files

msm: mdss: refactor performance calculations



Current logic could potentially lead to drop in performance (and
underflow) when multiple panels are there and both are updating mixer
configuration independently, as we may end up raising bus bandwidth for
another panel which may not be ready just yet. This is addressed by
updating performance configuration values until it's ready to switch
rather than updating values and performing these later (other panel
update could come in between).

Change-Id: I247ef0cd3e0616de3e5ddd9599233af570e422a5
Signed-off-by: default avatarAdrian Salido-Moreno <adrianm@codeaurora.org>
Signed-off-by: default avatarHuaibin Yang <huaibiny@codeaurora.org>
parent 6d843a6b
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -140,6 +140,12 @@ enum mdss_mdp_wb_ctl_type {
	MDSS_MDP_WB_CTL_TYPE_LINE
};

struct mdss_mdp_perf_params {
	u64 ib_quota;
	u64 ab_quota;
	u32 mdp_clk_rate;
};

struct mdss_mdp_ctl {
	u32 num;
	char __iomem *base;
@@ -170,6 +176,8 @@ struct mdss_mdp_ctl {
	u32 clk_rate;
	u32 perf_changed;
	int force_screen_state;
	struct mdss_mdp_perf_params cur_perf;
	struct mdss_mdp_perf_params new_perf;

	struct mdss_data_type *mdata;
	struct msm_fb_data_type *mfd;
@@ -425,12 +433,6 @@ struct mdss_overlay_private {
	u32 sd_enabled;
};

struct mdss_mdp_perf_params {
	u32 ib_quota;
	u32 ab_quota;
	u32 mdp_clk_rate;
};

/**
 * enum mdss_screen_state - Screen states that MDP can be forced into
 *
+87 −90
Original line number Diff line number Diff line
@@ -45,12 +45,6 @@ static inline u64 fudge_factor(u64 val, u32 numer, u32 denom)
#define CLK_FUDGE_FACTOR(val)		fudge_factor((val),		\
	(mdss_res->clk_factor.numer), (mdss_res->clk_factor.denom))

enum {
	MDSS_MDP_PERF_UPDATE_SKIP,
	MDSS_MDP_PERF_UPDATE_EARLY,
	MDSS_MDP_PERF_UPDATE_LATE,
};

#define MDSS_MDP_PERF_UPDATE_CLK BIT(0)
#define MDSS_MDP_PERF_UPDATE_BUS BIT(1)
#define MDSS_MDP_PERF_UPDATE_ALL -1
@@ -172,18 +166,20 @@ static int mdss_mdp_ctl_perf_commit(struct mdss_data_type *mdata, u32 flags)
	for (cnum = 0; cnum < mdata->nctl; cnum++) {
		ctl = mdata->ctl_off + cnum;
		if (ctl->power_on) {
			bus_ab_quota += ctl->bus_ab_quota;
			bus_ib_quota += ctl->bus_ib_quota;
			struct mdss_mdp_perf_params *perf = &ctl->cur_perf;

			bus_ab_quota += perf->ab_quota;
			bus_ib_quota += perf->ib_quota;

			if (ctl->clk_rate > clk_rate)
				clk_rate = ctl->clk_rate;
			if (perf->mdp_clk_rate > clk_rate)
				clk_rate = perf->mdp_clk_rate;
		}
	}
	if (flags & MDSS_MDP_PERF_UPDATE_BUS) {
		bus_ab_quota = bus_ib_quota;
		__mdss_mdp_ctrl_perf_ovrd(mdata, &bus_ab_quota, &bus_ib_quota);
		bus_ib_quota <<= MDSS_MDP_BUS_FACTOR_SHIFT;
		bus_ab_quota <<= MDSS_MDP_BUS_FACTOR_SHIFT;
		pr_debug("update ab=%llu ib=%llu\n",
				bus_ab_quota, bus_ib_quota);
		mdss_mdp_bus_scale_set_quota(bus_ab_quota, bus_ib_quota);
	}
	if (flags & MDSS_MDP_PERF_UPDATE_CLK) {
@@ -276,15 +272,14 @@ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
	pr_debug("src(w,h)(%d,%d) dst(w,h)(%d,%d) v_total=%d v_deci=%d fps=%d\n",
		pipe->src.w, pipe->src.h, pipe->dst.w, pipe->dst.h, v_total,
		pipe->vert_deci, fps);
	pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%u ib=%u\n",
	pr_debug("mixer=%d pnum=%d clk_rate=%u bus ab=%llu ib=%llu\n",
		 mixer->num, pipe->num, rate, perf->ab_quota, perf->ib_quota);

	return 0;
}

static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer,
				       u32 *bus_ab_quota, u32 *bus_ib_quota,
				       u32 *clk_rate)
static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
		struct mdss_mdp_perf_params *perf)
{
	struct mdss_mdp_pipe *pipe;
	struct mdss_panel_info *pinfo = NULL;
@@ -293,9 +288,7 @@ static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer,
	int i;
	u32 max_clk_rate = 0, ab_total = 0, ib_total = 0;

	*bus_ab_quota = 0;
	*bus_ib_quota = 0;
	*clk_rate = 0;
	memset(perf, 0, sizeof(*perf));

	if (!mixer->rotator_mode) {
		if (mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
@@ -308,99 +301,113 @@ static void mdss_mdp_perf_mixer_update(struct mdss_mdp_mixer *mixer,
		} else {
			v_total = mixer->height;
		}
		*clk_rate = mixer->width * v_total * fps;
		*clk_rate = mdss_mdp_clk_fudge_factor(mixer, *clk_rate);

		perf->mdp_clk_rate = mixer->width * v_total * fps;
		perf->mdp_clk_rate =
			mdss_mdp_clk_fudge_factor(mixer, perf->mdp_clk_rate);

		if (!pinfo) {
			/* perf for bus writeback */
			*bus_ab_quota = fps * mixer->width * mixer->height * 3;
			*bus_ab_quota >>= MDSS_MDP_BUS_FACTOR_SHIFT;
			*bus_ib_quota = *bus_ab_quota;
			perf->ab_quota = fps * mixer->width * mixer->height * 3;
			perf->ib_quota = perf->ab_quota;
		}
	}

	for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
		struct mdss_mdp_perf_params perf;
		struct mdss_mdp_perf_params tmp;
		pipe = mixer->stage_pipe[i];
		if (pipe == NULL)
			continue;

		if (mdss_mdp_perf_calc_pipe(pipe, &perf, &mixer->roi))
		if (mdss_mdp_perf_calc_pipe(pipe, &tmp, &mixer->roi))
			continue;

		ab_total += perf.ab_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
		ib_total += perf.ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
		if (perf.mdp_clk_rate > max_clk_rate)
			max_clk_rate = perf.mdp_clk_rate;
		ab_total += tmp.ab_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
		ib_total += tmp.ib_quota >> MDSS_MDP_BUS_FACTOR_SHIFT;
		if (tmp.mdp_clk_rate > max_clk_rate)
			max_clk_rate = tmp.mdp_clk_rate;
	}

	*bus_ab_quota += ab_total;
	*bus_ib_quota += ib_total;
	if (max_clk_rate > *clk_rate)
		*clk_rate = max_clk_rate;
	perf->ab_quota += ab_total << MDSS_MDP_BUS_FACTOR_SHIFT;
	perf->ib_quota += ib_total << MDSS_MDP_BUS_FACTOR_SHIFT;
	if (max_clk_rate > perf->mdp_clk_rate)
		perf->mdp_clk_rate = max_clk_rate;

	pr_debug("final mixer=%d clk_rate=%u bus ab=%u ib=%u\n", mixer->num,
		 *clk_rate, *bus_ab_quota, *bus_ib_quota);
	pr_debug("final mixer=%d clk_rate=%u bus ab=%llu ib=%llu\n", mixer->num,
		 perf->mdp_clk_rate, perf->ab_quota, perf->ib_quota);
}

static int mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl)
static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_perf_params *perf)
{
	int ret = MDSS_MDP_PERF_UPDATE_SKIP;
	u32 clk_rate, ab_quota, ib_quota;
	u32 max_clk_rate = 0, total_ab_quota = 0, total_ib_quota = 0;
	struct mdss_mdp_perf_params tmp;

	memset(perf, 0, sizeof(*perf));

	if (ctl->mixer_left) {
		mdss_mdp_perf_mixer_update(ctl->mixer_left, &ab_quota,
					   &ib_quota, &clk_rate);
		total_ab_quota += ab_quota;
		total_ib_quota += ib_quota;
		max_clk_rate = clk_rate;
		mdss_mdp_perf_calc_mixer(ctl->mixer_left, &tmp);
		perf->ab_quota += tmp.ab_quota;
		perf->ib_quota += tmp.ib_quota;
		perf->mdp_clk_rate = tmp.mdp_clk_rate;
	}

	if (ctl->mixer_right) {
		mdss_mdp_perf_mixer_update(ctl->mixer_right, &ab_quota,
					   &ib_quota, &clk_rate);
		total_ab_quota += ab_quota;
		total_ib_quota += ib_quota;
		if (clk_rate > max_clk_rate)
			max_clk_rate = clk_rate;
		mdss_mdp_perf_calc_mixer(ctl->mixer_right, &tmp);
		perf->ab_quota += tmp.ab_quota;
		perf->ib_quota += tmp.ib_quota;
		if (tmp.mdp_clk_rate > perf->mdp_clk_rate)
			perf->mdp_clk_rate = tmp.mdp_clk_rate;

		if (ctl->intf_type) {
			clk_rate = mdss_mdp_get_pclk_rate(ctl);
			u32 clk_rate = mdss_mdp_get_pclk_rate(ctl);
			/* minimum clock rate due to inefficiency in 3dmux */
			clk_rate = mult_frac(clk_rate >> 1, 9, 8);
			if (clk_rate > max_clk_rate)
				max_clk_rate = clk_rate;
			if (clk_rate > perf->mdp_clk_rate)
				perf->mdp_clk_rate = clk_rate;
		}
	}

	/* request minimum bandwidth to have bus clock on when display is on */
	if (total_ib_quota == 0)
		total_ib_quota = SZ_16M >> MDSS_MDP_BUS_FACTOR_SHIFT;
	if (perf->ib_quota == 0)
		perf->ib_quota = SZ_16M;

	if (max_clk_rate != ctl->clk_rate) {
		if (max_clk_rate > ctl->clk_rate)
			ret = MDSS_MDP_PERF_UPDATE_EARLY;
		else
			ret = MDSS_MDP_PERF_UPDATE_LATE;
		ctl->clk_rate = max_clk_rate;
		ctl->perf_changed |= MDSS_MDP_PERF_UPDATE_CLK;
	pr_debug("final ctl=%d clk_rate=%u bus ab=%llu ib=%llu\n", ctl->num,
		 perf->mdp_clk_rate, perf->ab_quota, perf->ib_quota);
}

	if ((total_ab_quota != ctl->bus_ab_quota) ||
			(total_ib_quota != ctl->bus_ib_quota)) {
		if (ret == MDSS_MDP_PERF_UPDATE_SKIP) {
			if (total_ib_quota >= ctl->bus_ib_quota)
				ret = MDSS_MDP_PERF_UPDATE_EARLY;
			else
				ret = MDSS_MDP_PERF_UPDATE_LATE;
static void mdss_mdp_ctl_perf_update(struct mdss_mdp_ctl *ctl,
		int params_changed)
{
	u32 flags = 0;
	struct mdss_mdp_perf_params *new, *old;

	old = &ctl->cur_perf;
	new = &ctl->new_perf;

	if (params_changed) {
		mdss_mdp_perf_calc_ctl(ctl, new);

		/*
		 * if params have just changed delay the update until later
		 * once the hw configuration has been flushed to MDP
		 */
		if ((new->mdp_clk_rate <= old->mdp_clk_rate) &&
				(new->ib_quota <= old->ib_quota)) {
			pr_debug("perf req is decreasing, delay update\n");
			return;
		}
		ctl->bus_ab_quota = total_ab_quota;
		ctl->bus_ib_quota = total_ib_quota;
		ctl->perf_changed |= MDSS_MDP_PERF_UPDATE_BUS;
	}

	return ret;
	if ((old->ab_quota != new->ab_quota) ||
			(old->ib_quota != new->ib_quota))
		flags |= MDSS_MDP_PERF_UPDATE_BUS;
	if (old->mdp_clk_rate != new->mdp_clk_rate)
		flags |= MDSS_MDP_PERF_UPDATE_CLK;

	if (flags) {
		ctl->cur_perf = ctl->new_perf;
		mdss_mdp_ctl_perf_commit(ctl->mdata, flags);
	}
}

static struct mdss_mdp_ctl *mdss_mdp_ctl_alloc(struct mdss_data_type *mdata,
@@ -1196,9 +1203,7 @@ int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff)
	if (!handoff)
		ctl->power_on = true;

	ctl->bus_ab_quota = 0;
	ctl->bus_ib_quota = 0;
	ctl->clk_rate = 0;
	memset(&ctl->cur_perf, 0, sizeof(ctl->cur_perf));

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);

@@ -1286,7 +1291,7 @@ int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl)

		ctl->power_on = false;
		ctl->play_cnt = 0;
		ctl->clk_rate = 0;
		memset(&ctl->cur_perf, 0, sizeof(ctl->cur_perf));
		mdss_mdp_ctl_perf_commit(ctl->mdata, MDSS_MDP_PERF_UPDATE_ALL);
	}

@@ -1875,10 +1880,7 @@ int mdss_mdp_display_wait4comp(struct mdss_mdp_ctl *ctl)
	if (ctl->wait_fnc)
		ret = ctl->wait_fnc(ctl, NULL);

	if (ctl->perf_changed) {
		mdss_mdp_ctl_perf_commit(ctl->mdata, ctl->perf_changed);
		ctl->perf_changed = 0;
	}
	mdss_mdp_ctl_perf_update(ctl, 0);

	if (mdata->mdp_rev == MDSS_MDP_HW_REV_103) {
		reg_data = mdss_mdp_ctl_read(ctl, MDSS_MDP_REG_CTL_FLUSH);
@@ -1922,7 +1924,6 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
	struct mdss_mdp_ctl *sctl = NULL;
	int mixer1_changed, mixer2_changed;
	int ret = 0;
	int perf_update = MDSS_MDP_PERF_UPDATE_SKIP;

	if (!ctl) {
		pr_err("display function not set\n");
@@ -1943,10 +1944,9 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
	mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed);

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);

	if (mixer1_changed || mixer2_changed
			|| ctl->force_screen_state) {
		perf_update = mdss_mdp_ctl_perf_update(ctl);

		if (ctl->prepare_fnc)
			ret = ctl->prepare_fnc(ctl, arg);
		if (ret) {
@@ -1954,10 +1954,7 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
			goto done;
		}

		if (perf_update == MDSS_MDP_PERF_UPDATE_EARLY) {
			mdss_mdp_ctl_perf_commit(ctl->mdata, ctl->perf_changed);
			ctl->perf_changed = 0;
		}
		mdss_mdp_ctl_perf_update(ctl, 1);

		if (mixer1_changed)
			mdss_mdp_mixer_update(ctl->mixer_left);