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

Commit 00ba3b8f authored by Ujwal Patel's avatar Ujwal Patel
Browse files

msm: mdss: add support of source split feature



Source split feature relaxes some of the old MDP HW limitations and
enables newer use-cases. This feature is available from MDSS 1.3.0 onwards.

Some of the key highlights are:
* single pipe can be staged on two layer mixers.
* two pipes can be staged at a single blending stage given left pipe
  on that stage is higher priority compared to the right pipe.
* Ex. 1080p video on can be played on a dual-dsi panel using single
       pipe compared to two pipes without this feature, saving power.
* Ex. using above features, two pipes can equally split the load of a high
      downscaling surface and thus reducing peak bandwidth requirements.

Change-Id: Ia08e37aca2ab0e80db6aef6c8e5ef37149b84e3a
Signed-off-by: default avatarUjwal Patel <ujwalp@codeaurora.org>
parent c4251672
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -234,6 +234,8 @@ Optional properties:
				pipes which have no scaling support.
- qcom,mdss-has-decimation: Boolean property to indicate the presence of
			    decimation feature in fetch.
- qcom,mdss-has-source-split: Boolean property to indicate if source split
			      feature is available or not.
- qcom,mdss-ad-off:		Array of offset addresses for the available
				Assertive Display (AD) blocks. These offsets
				are calculated from the register "mdp_phys"
@@ -417,6 +419,7 @@ Example:
		qcom,mdss-has-non-scalar-rgb;
		qcom,mdss-has-bwc;
		qcom,mdss-has-decimation;
		qcom,mdss-has-source-split;
		qcom,mdss-wfd-mode = "intf";

		qcom,mdss-pipe-vig-xin-id = <0 4 8>;
+1 −0
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ struct mdss_data_type {
	u32 wfd_mode;
	u8 has_wb_ad;
	u8 has_non_scalar_rgb;
	bool has_src_split;

	u32 rotator_ot_limit;
	u32 mdp_irq_mask;
+12 −5
Original line number Diff line number Diff line
@@ -1310,6 +1310,8 @@ static ssize_t mdss_mdp_show_capabilities(struct device *dev,
		SPRINT(" tile_format");
	if (mdata->has_non_scalar_rgb)
		SPRINT(" non_scalar_rgb");
	if (mdata->has_src_split)
		SPRINT(" src_split");
	SPRINT("\n");

	return cnt;
@@ -1791,7 +1793,7 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev)

	len = min_t(int, DEFAULT_TOTAL_VIG_PIPES, (int)mdata->nvig_pipes);
	rc = mdss_mdp_pipe_addr_setup(mdata, mdata->vig_pipes, offsets, ftch_id,
		xin_id, MDSS_MDP_PIPE_TYPE_VIG, MDSS_MDP_SSPP_VIG0, len);
		xin_id, MDSS_MDP_PIPE_TYPE_VIG, MDSS_MDP_SSPP_VIG0, len, 0);
	if (rc)
		goto parse_fail;

@@ -1816,7 +1818,7 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev)
	rc = mdss_mdp_pipe_addr_setup(mdata, mdata->rgb_pipes,
		offsets + mdata->nvig_pipes, ftch_id + mdata->nvig_pipes,
		xin_id + mdata->nvig_pipes, MDSS_MDP_PIPE_TYPE_RGB,
		MDSS_MDP_SSPP_RGB0, len);
		MDSS_MDP_SSPP_RGB0, len, mdata->nvig_pipes);
	if (rc)
		goto parse_fail;

@@ -1845,7 +1847,8 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev)
		len = mdata->ndma_pipes;
		rc = mdss_mdp_pipe_addr_setup(mdata, mdata->dma_pipes,
			offsets + dma_off, ftch_id + dma_off, xin_id + dma_off,
			MDSS_MDP_PIPE_TYPE_DMA, MDSS_MDP_SSPP_DMA0, len);
			MDSS_MDP_PIPE_TYPE_DMA, MDSS_MDP_SSPP_DMA0, len,
			mdata->nvig_pipes + mdata->nrgb_pipes);
		if (rc)
			goto parse_fail;

@@ -1859,7 +1862,8 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev)
			ftch_id + DEFAULT_TOTAL_VIG_PIPES,
			xin_id + DEFAULT_TOTAL_VIG_PIPES,
			MDSS_MDP_PIPE_TYPE_VIG, setup_cnt,
			mdata->nvig_pipes - DEFAULT_TOTAL_VIG_PIPES);
			mdata->nvig_pipes - DEFAULT_TOTAL_VIG_PIPES,
			DEFAULT_TOTAL_VIG_PIPES);
		if (rc)
			goto parse_fail;

@@ -1873,7 +1877,8 @@ static int mdss_mdp_parse_dt_pipe(struct platform_device *pdev)
			ftch_id + mdata->nvig_pipes + DEFAULT_TOTAL_RGB_PIPES,
			xin_id + mdata->nvig_pipes + DEFAULT_TOTAL_RGB_PIPES,
			MDSS_MDP_PIPE_TYPE_RGB, setup_cnt,
			mdata->nrgb_pipes - DEFAULT_TOTAL_RGB_PIPES);
			mdata->nrgb_pipes - DEFAULT_TOTAL_RGB_PIPES,
			mdata->nvig_pipes + DEFAULT_TOTAL_RGB_PIPES);
		if (rc)
			goto parse_fail;

@@ -2303,6 +2308,8 @@ static int mdss_mdp_parse_dt_misc(struct platform_device *pdev)
		mdata->wfd_mode = MDSS_MDP_WFD_SHARED;
	}

	mdata->has_src_split = of_property_read_bool(pdev->dev.of_node,
		 "qcom,mdss-has-source-split");
	prop = of_find_property(pdev->dev.of_node, "batfet-supply", NULL);
	mdata->batfet_required = prop ? true : false;
	rc = of_property_read_u32(pdev->dev.of_node,
+15 −8
Original line number Diff line number Diff line
@@ -218,8 +218,9 @@ struct mdss_mdp_mixer {
	u16 cursor_hoty;
	u8 rotator_mode;

	bool is_right_mixer;
	struct mdss_mdp_ctl *ctl;
	struct mdss_mdp_pipe *stage_pipe[MDSS_MDP_MAX_STAGE];
	struct mdss_mdp_pipe *stage_pipe[MAX_PIPES_PER_LM];
};

struct mdss_mdp_format_params {
@@ -348,6 +349,7 @@ struct mdss_mdp_pipe {
	u32 num;
	u32 type;
	u32 ndx;
	u8 priority;
	char __iomem *base;
	u32 ftch_id;
	u32 xin_id;
@@ -362,6 +364,8 @@ struct mdss_mdp_pipe {

	u32 flags;
	u32 bwc_mode;
	bool src_split_req;
	bool is_right_blend;

	u16 img_width;
	u16 img_height;
@@ -383,7 +387,8 @@ struct mdss_mdp_pipe {
	u32 hscl_en;

	struct msm_fb_data_type *mfd;
	struct mdss_mdp_mixer *mixer;
	struct mdss_mdp_mixer *mixer_left;
	struct mdss_mdp_mixer *mixer_right;

	struct mdp_overlay req_data;
	u32 params_changed;
@@ -601,10 +606,12 @@ void mdss_mdp_ctl_perf_release_bw(struct mdss_mdp_ctl *ctl);
struct mdss_mdp_mixer *mdss_mdp_wb_mixer_alloc(int rotator);
int mdss_mdp_wb_mixer_destroy(struct mdss_mdp_mixer *mixer);
struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux);
struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
						int mux, int stage);
int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed);
int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe);
struct mdss_mdp_pipe *mdss_mdp_get_staged_pipe(struct mdss_mdp_ctl *ctl,
	int mux, int stage, bool is_right_blend);
int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe,
	struct mdss_mdp_mixer *mixer, int params_changed);
int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe,
	struct mdss_mdp_mixer *mixer);
int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg);
int mdss_mdp_display_wait4comp(struct mdss_mdp_ctl *ctl);
int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl);
@@ -659,7 +666,7 @@ int mdss_mdp_calib_mode(struct msm_fb_data_type *mfd,
int mdss_mdp_pipe_handoff(struct mdss_mdp_pipe *pipe);
int mdss_mdp_smp_handoff(struct mdss_data_type *mdata);
struct mdss_mdp_pipe *mdss_mdp_pipe_alloc(struct mdss_mdp_mixer *mixer,
					  u32 type);
	u32 type, struct mdss_mdp_pipe *left_blend_pipe);
struct mdss_mdp_pipe *mdss_mdp_pipe_get(struct mdss_data_type *mdata, u32 ndx);
struct mdss_mdp_pipe *mdss_mdp_pipe_search(struct mdss_data_type *mdata,
						  u32 ndx);
@@ -674,7 +681,7 @@ void mdss_mdp_smp_release(struct mdss_mdp_pipe *pipe);

int mdss_mdp_pipe_addr_setup(struct mdss_data_type *mdata,
	struct mdss_mdp_pipe *head, u32 *offsets, u32 *ftch_y_id, u32 *xin_id,
	u32 type, u32 num_base, u32 len);
	u32 type, u32 num_base, u32 len, u8 priority_base);
int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata, u32 *mixer_offsets,
		u32 *dspp_offsets, u32 *pingpong_offsets, u32 type, u32 len);
int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets,
+104 −98
Original line number Diff line number Diff line
@@ -315,10 +315,11 @@ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
	bool is_fbc = false;
	struct mdss_mdp_prefill_params prefill_params;

	if (!pipe || !perf || !pipe->mixer)
	if (!pipe || !perf || !pipe->mixer_left)
		return -EINVAL;

	mixer = pipe->mixer;
	mixer = pipe->mixer_left;

	dst = pipe->dst;
	src = pipe->src;

@@ -337,7 +338,7 @@ int mdss_mdp_perf_calc_pipe(struct mdss_mdp_pipe *pipe,
		xres = mixer->width;
	}

	if (roi)
	if (roi && !mixer->ctl->is_video_mode && !pipe->src_split_req)
		mdss_mdp_crop_rect(&src, &dst, roi);

	pr_debug("v_total=%d, xres=%d fps=%d\n", v_total, xres, fps);
@@ -436,13 +437,13 @@ 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] = { 0 };
	u32 v_region[MDSS_MDP_MAX_STAGE * 2] = { 0 };
	u64 bw_overlap[MAX_PIPES_PER_LM] = { 0 };
	u32 v_region[MAX_PIPES_PER_LM * 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);
	BUG_ON(num_pipes > MAX_PIPES_PER_LM);

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

@@ -467,8 +468,8 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
				fps * mixer->width * mixer->height * 3;
	}

	memset(bw_overlap, 0, sizeof(u64) * MDSS_MDP_MAX_STAGE);
	memset(v_region, 0, sizeof(u32) * MDSS_MDP_MAX_STAGE * 2);
	memset(bw_overlap, 0, sizeof(u64) * MAX_PIPES_PER_LM);
	memset(v_region, 0, sizeof(u32) * MAX_PIPES_PER_LM * 2);

	/*
	* Apply this logic only for 8x26 to reduce clock rate
@@ -498,9 +499,18 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
		if (pipe == NULL)
			continue;

		/*
		 * if is pipe used across two LMs in source split configuration
		 * then it is staged on both LMs. In such cases skip BW calc
		 * for such pipe on right LM to prevent adding BW twice.
		 */
		if (pipe->src_split_req && mixer->is_right_mixer)
			continue;

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

		prefill_bytes += tmp.prefill_bytes;
		bw_overlap[i] = tmp.bw_overlap;
		v_region[2*i] = pipe->dst.y;
@@ -682,8 +692,8 @@ int mdss_mdp_perf_bw_check(struct mdss_mdp_ctl *ctl,
int mdss_mdp_perf_bw_check_pipe(struct mdss_mdp_perf_params *perf,
		struct mdss_mdp_pipe *pipe)
{
	struct mdss_data_type *mdata = pipe->mixer->ctl->mdata;
	struct mdss_mdp_ctl *ctl = pipe->mixer->ctl;
	struct mdss_data_type *mdata = pipe->mixer_left->ctl->mdata;
	struct mdss_mdp_ctl *ctl = pipe->mixer_left->ctl;
	u32 vbp_fac, threshold;
	u64 prefill_bw, pipe_bw;

@@ -721,8 +731,8 @@ static void mdss_mdp_perf_calc_ctl(struct mdss_mdp_ctl *ctl,
	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));
			left_plist, (left_plist ? MAX_PIPES_PER_LM : 0),
			right_plist, (right_plist ? MAX_PIPES_PER_LM : 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",
@@ -1125,6 +1135,7 @@ static int mdss_mdp_mixer_free(struct mdss_mdp_mixer *mixer)

	mutex_lock(&mdss_mdp_ctl_lock);
	mixer->ref_cnt--;
	mixer->is_right_mixer = false;
	mutex_unlock(&mdss_mdp_ctl_lock);

	return 0;
@@ -1367,6 +1378,7 @@ int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
				return -ENOMEM;
			}
		}
		ctl->mixer_right->is_right_mixer = true;
		ctl->mixer_right->width = width;
		ctl->mixer_right->height = height;
		ctl->mixer_right->roi = (struct mdss_mdp_img_rect)
@@ -1576,6 +1588,7 @@ int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
		return -ENOMEM;
	}

	mixer->is_right_mixer = true;
	mixer->width = sctl->width;
	mixer->height = sctl->height;
	mixer->roi = (struct mdss_mdp_img_rect)
@@ -1634,18 +1647,9 @@ int mdss_mdp_ctl_destroy(struct mdss_mdp_ctl *ctl)
	sctl = mdss_mdp_get_split_ctl(ctl);
	if (sctl) {
		pr_debug("destroying split display ctl=%d\n", sctl->num);
		if (sctl->mixer_left)
			mdss_mdp_mixer_free(sctl->mixer_left);
		mdss_mdp_ctl_free(sctl);
	} else if (ctl->mixer_right) {
		mdss_mdp_mixer_free(ctl->mixer_right);
		ctl->mixer_right = NULL;
	}

	if (ctl->mixer_left) {
		mdss_mdp_mixer_free(ctl->mixer_left);
		ctl->mixer_left = NULL;
	}
	mdss_mdp_ctl_free(ctl);

	return 0;
@@ -1962,24 +1966,37 @@ static inline u32 mdss_mdp_mpq_pipe_num_map(u32 pipe_num)
	return mpq_num;
}

static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
				struct mdss_mdp_mixer *mixer)
static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl,
	int mixer_mux)
{
	struct mdss_mdp_pipe *pipe;
	int i;
	int stage, screen_state, outsize;
	u32 off, blend_op, blend_stage, mpq_num;
	u32 mixercfg = 0, blend_color_out = 0, bg_alpha_enable = 0;
	u32 mixercfg = 0, mixer_op_mode = 0, bg_alpha_enable = 0;
	u32 fg_alpha = 0, bg_alpha = 0;
	int stage, secure = 0;
	int screen_state;
	int outsize = 0;
	u32 op_mode;

	screen_state = ctl->force_screen_state;
	struct mdss_mdp_pipe *pipe;
	struct mdss_mdp_ctl *ctl = NULL;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	struct mdss_mdp_mixer *mixer = mdss_mdp_mixer_get(master_ctl,
		mixer_mux);

	if (!mixer)
		return -ENODEV;
		return;

	ctl = mixer->ctl;
	if (!ctl)
		return;

	mixer->params_changed = 0;
	/* check if mixer setup for rotator is needed */
	if (mixer->rotator_mode) {
		off = __mdss_mdp_ctl_get_mixer_off(mixer);
		mdss_mdp_ctl_write(mixer->ctl, off, 0);
		return;
	}

	pr_debug("setup mixer=%d\n", mixer->num);
	screen_state = ctl->force_screen_state;

	outsize = (mixer->roi.h << 16) | mixer->roi.w;
	mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OUT_SIZE, outsize);
@@ -1989,7 +2006,7 @@ static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
		goto update_mixer;
	}

	pipe = mixer->stage_pipe[MDSS_MDP_STAGE_BASE];
	pipe = mixer->stage_pipe[MDSS_MDP_STAGE_BASE * MAX_PIPES_PER_STAGE];
	if (pipe == NULL) {
		mixercfg = MDSS_MDP_LM_BORDER_COLOR;
	} else {
@@ -2005,16 +2022,17 @@ static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
		}
		if (pipe->src_fmt->alpha_enable)
			bg_alpha_enable = 1;
		secure = pipe->flags & MDP_SECURE_OVERLAY_SESSION;
	}

	for (stage = MDSS_MDP_STAGE_0; stage < MDSS_MDP_MAX_STAGE; stage++) {
		pipe = mixer->stage_pipe[stage];
	i = MDSS_MDP_STAGE_0 * MAX_PIPES_PER_STAGE;
	for (; i < MAX_PIPES_PER_LM; i++) {
		pipe = mixer->stage_pipe[i];
		if (pipe == NULL)
			continue;

		stage = i / MAX_PIPES_PER_STAGE;
		if (stage != pipe->mixer_stage) {
			mixer->stage_pipe[stage] = NULL;
			mixer->stage_pipe[i] = NULL;
			continue;
		}

@@ -2026,7 +2044,7 @@ static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
		fg_alpha = pipe->alpha;
		bg_alpha = 0xFF - pipe->alpha;
		/* keep fg alpha */
		blend_color_out |= 1 << (blend_stage + 1);
		mixer_op_mode |= 1 << (blend_stage + 1);

		switch (pipe->blend_op) {
		case BLEND_OP_OPAQUE:
@@ -2083,7 +2101,7 @@ static int mdss_mdp_mixer_setup(struct mdss_mdp_ctl *ctl,
		}

		if (!pipe->src_fmt->alpha_enable && bg_alpha_enable)
			blend_color_out = 0;
			mixer_op_mode = 0;

		if (ctl->mdata->mdp_rev == MDSS_MDP_HW_REV_200) {
			mpq_num = mdss_mdp_mpq_pipe_num_map(pipe->num);
@@ -2118,16 +2136,16 @@ update_mixer:
	else
		ctl->flush_bits |= BIT(6) << mixer->num;

	op_mode = mdp_mixer_read(mixer, MDSS_MDP_REG_LM_OP_MODE);
	/* Read GC enable/disable status on LM */
	op_mode = (op_mode & BIT(0));
	blend_color_out |= op_mode;
	mixer_op_mode |=
		(mdp_mixer_read(mixer, MDSS_MDP_REG_LM_OP_MODE) & BIT(0));

	if (mdata->has_src_split && mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT)
		mixer_op_mode |= BIT(31);

	mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OP_MODE, blend_color_out);
	mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OP_MODE, mixer_op_mode);
	off = __mdss_mdp_ctl_get_mixer_off(mixer);
	mdss_mdp_ctl_write(ctl, off, mixercfg);

	return 0;
}

int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata,
@@ -2271,31 +2289,36 @@ struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux)
	return mixer;
}

struct mdss_mdp_pipe *mdss_mdp_mixer_stage_pipe(struct mdss_mdp_ctl *ctl,
						int mux, int stage)
struct mdss_mdp_pipe *mdss_mdp_get_staged_pipe(struct mdss_mdp_ctl *ctl,
	int mux, int stage, bool is_right_blend)
{
	struct mdss_mdp_pipe *pipe = NULL;
	struct mdss_mdp_mixer *mixer;
	int index = (stage * MAX_PIPES_PER_STAGE) + (int)is_right_blend;

	if (!ctl)
		return NULL;

	BUG_ON(index > MAX_PIPES_PER_LM);

	mixer = mdss_mdp_mixer_get(ctl, mux);
	if (mixer)
		pipe = mixer->stage_pipe[stage];
		pipe = mixer->stage_pipe[index];

	pr_debug("%pS index=%d pipe%d\n", __builtin_return_address(0),
		index, pipe ? pipe->num : -1);
	return pipe;
}

int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed)
int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe,
			 struct mdss_mdp_mixer *mixer, int params_changed)
{
	struct mdss_mdp_ctl *ctl;
	struct mdss_mdp_mixer *mixer;
	int i;
	int i, j;
	u32 mpq_num;

	if (!pipe)
		return -EINVAL;
	mixer = pipe->mixer;
	if (!mixer)
		return -EINVAL;
	ctl = mixer->ctl;
@@ -2315,11 +2338,15 @@ int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed)

	if (params_changed) {
		mixer->params_changed++;
		for (i = 0; i < MDSS_MDP_MAX_STAGE; i++) {
		for (i = MDSS_MDP_STAGE_BASE; i < MDSS_MDP_MAX_STAGE; i++) {
			j = i * MAX_PIPES_PER_STAGE;
			if (pipe->is_right_blend)
				j++;

			if (i == pipe->mixer_stage)
				mixer->stage_pipe[i] = pipe;
			else if (mixer->stage_pipe[i] == pipe)
				mixer->stage_pipe[i] = NULL;
				mixer->stage_pipe[j] = pipe;
			else if (mixer->stage_pipe[j] == pipe)
				mixer->stage_pipe[j] = NULL;
		}
	}

@@ -2339,45 +2366,31 @@ int mdss_mdp_mixer_pipe_update(struct mdss_mdp_pipe *pipe, int params_changed)
	return 0;
}

int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe)
int mdss_mdp_mixer_pipe_unstage(struct mdss_mdp_pipe *pipe,
	struct mdss_mdp_mixer *mixer)
{
	struct mdss_mdp_ctl *ctl;
	struct mdss_mdp_mixer *mixer;
	int index;

	if (!pipe)
		return -EINVAL;
	mixer = pipe->mixer;
	if (!mixer)
		return -EINVAL;
	ctl = mixer->ctl;
	if (!ctl)
		return -EINVAL;

	pr_debug("unstage pnum=%d stage=%d mixer=%d\n", pipe->num,
			pipe->mixer_stage, mixer->num);
	index = (pipe->mixer_stage * MAX_PIPES_PER_STAGE) +
		(int)pipe->is_right_blend;

	if (pipe == mixer->stage_pipe[pipe->mixer_stage]) {
		mixer->params_changed++;
		mixer->stage_pipe[pipe->mixer_stage] = NULL;
	}
	if (pipe == mixer->stage_pipe[index]) {
		pr_debug("unstage p%d from %s side of stage=%d lm=%d ndx=%d\n",
			pipe->num, pipe->is_right_blend ? "right" : "left",
			pipe->mixer_stage, mixer->num, index);

	return 0;
}

static int mdss_mdp_mixer_update(struct mdss_mdp_mixer *mixer)
{
	u32 off = 0;
	if (!mixer)
		return -EINVAL;

	mixer->params_changed = 0;
		mixer->params_changed++;
		mixer->stage_pipe[index] = NULL;

	/* skip mixer setup for rotator */
	if (!mixer->rotator_mode) {
		mdss_mdp_mixer_setup(mixer->ctl, mixer);
	} else {
		off = __mdss_mdp_ctl_get_mixer_off(mixer);
		mdss_mdp_ctl_write(mixer->ctl, off, 0);
		if (mixer->is_right_mixer)
			pipe->mixer_right = NULL;
		else
			pipe->mixer_left = NULL;
	}

	return 0;
@@ -2526,7 +2539,6 @@ int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl)
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;

	if (!ctl) {
@@ -2543,14 +2555,10 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
	}

	sctl = mdss_mdp_get_split_ctl(ctl);

	mixer1_changed = (ctl->mixer_left && ctl->mixer_left->params_changed);
	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) {
	if (ctl->force_screen_state ||
		(ctl->mixer_left && ctl->mixer_left->params_changed) ||
		(ctl->mixer_right && ctl->mixer_right->params_changed)) {
		if (ctl->prepare_fnc)
			ret = ctl->prepare_fnc(ctl, arg);
		if (ret) {
@@ -2560,10 +2568,8 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)

		mdss_mdp_ctl_perf_update(ctl, 1);

		if (mixer1_changed)
			mdss_mdp_mixer_update(ctl->mixer_left);
		if (mixer2_changed)
			mdss_mdp_mixer_update(ctl->mixer_right);
		mdss_mdp_mixer_setup(ctl, MDSS_MDP_MIXER_MUX_LEFT);
		mdss_mdp_mixer_setup(ctl, MDSS_MDP_MIXER_MUX_RIGHT);

		mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, ctl->opmode);
		ctl->flush_bits |= BIT(17);	/* CTL */
@@ -2722,7 +2728,7 @@ static int __mdss_mdp_mixer_handoff_helper(struct mdss_mdp_mixer *mixer,
	pr_debug("Staging pipe num %d on mixer num %d\n",
		pipe->num, mixer->num);
	mixer->stage_pipe[MDSS_MDP_STAGE_UNUSED] = pipe;
	pipe->mixer = mixer;
	pipe->mixer_left = mixer;
	pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED;

error:
Loading