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

Commit 54967700 authored by Adrian Salido-Moreno's avatar Adrian Salido-Moreno
Browse files

msm: mdss: add bandwidth check function



Add function which calculates the bandwidth that would be required by
MDP to display the frame. If the bandwidth is over the defined limits,
an error is returned which means the configuration is not acceptable and
may lead to display underruns.

Change-Id: I991ac458d347487c5c634d271814222aa661fd58
Signed-off-by: default avatarAdrian Salido-Moreno <adrianm@codeaurora.org>
parent ce42a34f
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -574,6 +574,9 @@ int mdss_mdp_ctl_destroy(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_start(struct mdss_mdp_ctl *ctl, bool handoff);
int mdss_mdp_ctl_stop(struct mdss_mdp_ctl *ctl);
int mdss_mdp_ctl_intf_event(struct mdss_mdp_ctl *ctl, int event, void *arg);
int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_pipe **left_plist, int left_cnt,
		struct mdss_mdp_pipe **right_plist, int right_cnt);
int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
	struct mdss_mdp_perf_params *perf, struct mdss_mdp_img_rect *roi,
	bool apply_fudge);
+65 −17
Original line number Diff line number Diff line
@@ -426,7 +426,8 @@ static inline int cmpu32(const void *a, const void *b)
}

static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
		struct mdss_mdp_perf_params *perf)
		struct mdss_mdp_perf_params *perf,
		struct mdss_mdp_pipe **pipe_list, int num_pipes)
{
	struct mdss_mdp_pipe *pipe;
	struct mdss_panel_info *pinfo = NULL;
@@ -435,12 +436,14 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
	int i;
	u32 max_clk_rate = 0;
	u64 bw_overlap_max = 0;
	u64 bw_overlap[MDSS_MDP_MAX_STAGE];
	u32 v_region[MDSS_MDP_MAX_STAGE * 2];
	u64 bw_overlap[MDSS_MDP_MAX_STAGE] = { 0 };
	u32 v_region[MDSS_MDP_MAX_STAGE * 2] = { 0 };
	u32 prefill_bytes = 0;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	bool apply_fudge = true;

	BUG_ON(num_pipes > MDSS_MDP_MAX_STAGE);

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

	if (!mixer->rotator_mode) {
@@ -474,8 +477,8 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
	if (IS_MDSS_MAJOR_MINOR_SAME(mdata->mdp_rev, MDSS_MDP_HW_REV_101)
		 && mixer->type == MDSS_MDP_MIXER_TYPE_INTF) {
		u32 npipes = 0;
		for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
			pipe = mixer->stage_pipe[i];
		for (i = 0; i < num_pipes; i++) {
			pipe = pipe_list[i];
			if (pipe) {
				if (npipes) {
					apply_fudge = true;
@@ -489,9 +492,9 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
		}
	}

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

@@ -512,8 +515,8 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
	 * data for each region and sum them up, then the worst case
	 * of all regions is ib request.
	 */
	sort(v_region, MDSS_MDP_MAX_STAGE * 2, sizeof(u32), cmpu32, NULL);
	for (i = 1; i < MDSS_MDP_MAX_STAGE * 2; i++) {
	sort(v_region, num_pipes * 2, sizeof(u32), cmpu32, NULL);
	for (i = 1; i < num_pipes * 2; i++) {
		int j;
		u64 bw_max_region = 0;
		u32 y0, y1;
@@ -522,10 +525,10 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
			continue;
		y0 = (v_region[i-1]) ? v_region[i-1] + 1 : 0;
		y1 = v_region[i];
		for (j = 0; j < MDSS_MDP_MAX_STAGE; j++) {
		for (j = 0; j < num_pipes; j++) {
			if (!bw_overlap[j])
				continue;
			pipe = mixer->stage_pipe[j];
			pipe = pipe_list[j];
			if (mdss_mdp_perf_is_overlap(y0, y1, pipe->dst.y,
				(pipe->dst.y + pipe->dst.h)))
				bw_max_region += bw_overlap[j];
@@ -590,22 +593,26 @@ static u32 mdss_mdp_get_vbp_factor_max(struct mdss_mdp_ctl *ctl)
	return vbp_max;
}

static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_perf_params *perf)
static void __mdss_mdp_perf_calc_ctl_helper(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_perf_params *perf,
		struct mdss_mdp_pipe **left_plist, int left_cnt,
		struct mdss_mdp_pipe **right_plist, int right_cnt)
{
	struct mdss_mdp_perf_params tmp;

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

	if (ctl->mixer_left) {
		mdss_mdp_perf_calc_mixer(ctl->mixer_left, &tmp);
	if (left_cnt && ctl->mixer_left) {
		mdss_mdp_perf_calc_mixer(ctl->mixer_left, &tmp,
				left_plist, left_cnt);
		perf->bw_overlap += tmp.bw_overlap;
		perf->prefill_bytes += tmp.prefill_bytes;
		perf->mdp_clk_rate = tmp.mdp_clk_rate;
	}

	if (ctl->mixer_right) {
		mdss_mdp_perf_calc_mixer(ctl->mixer_right, &tmp);
	if (right_cnt && ctl->mixer_right) {
		mdss_mdp_perf_calc_mixer(ctl->mixer_right, &tmp,
				right_plist, right_cnt);
		perf->bw_overlap += tmp.bw_overlap;
		perf->prefill_bytes += tmp.prefill_bytes;
		if (tmp.mdp_clk_rate > perf->mdp_clk_rate)
@@ -642,6 +649,47 @@ static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl,

	if (ctl->is_video_mode)
		perf->bw_ctl = IB_FUDGE_FACTOR(perf->bw_ctl);
}

int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_pipe **left_plist, int left_cnt,
		struct mdss_mdp_pipe **right_plist, int right_cnt)
{
	struct mdss_data_type *mdata = ctl->mdata;
	struct mdss_mdp_perf_params perf;
	u32 bw, threshold;

	/* we only need bandwidth check on real-time clients (interfaces) */
	if (ctl->intf_type == MDSS_MDP_NO_INTF)
		return 0;

	__mdss_mdp_perf_calc_ctl_helper(ctl, &perf,
			left_plist, left_cnt, right_plist, right_cnt);

	/* convert bandwidth to kb */
	bw = DIV_ROUND_UP_ULL(perf.bw_ctl, 1000);
	pr_debug("calculated bandwidth=%uk\n", bw);

	threshold = ctl->is_video_mode ? mdata->max_bw_low : mdata->max_bw_high;
	if (bw > threshold) {
		pr_debug("exceeds bandwidth: %ukb > %ukb\n", bw, threshold);
		return -E2BIG;
	}

	return 0;
}

static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl,
		struct mdss_mdp_perf_params *perf)
{
	struct mdss_mdp_pipe **left_plist, **right_plist;

	left_plist = ctl->mixer_left ? ctl->mixer_left->stage_pipe : NULL;
	right_plist = ctl->mixer_right ? ctl->mixer_right->stage_pipe : NULL;

	__mdss_mdp_perf_calc_ctl_helper(ctl, perf,
			left_plist, (left_plist ? MDSS_MDP_MAX_STAGE : 0),
			right_plist, (right_plist ? MDSS_MDP_MAX_STAGE : 0));

	pr_debug("ctl=%d clk_rate=%u\n", ctl->num, perf->mdp_clk_rate);
	pr_debug("bw_overlap=%llu bw_prefill=%llu prefill_byptes=%d\n",