drm/msm/sde: do layer mixer assignment based on loop

For more general assignment of planes to layer mixers, cache LM
bounds at mode-set time along with split width point. Then, use
the bounds rectangles to do intersections with the plane
rectangles and use results for programming.

Change-Id: Ib4f18558dcf94a714684c9fb7e61ada58a070ce3
Signed-off-by: Lloyd Atkinson <latkinso@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/sde/sde_crtc.c b/drivers/gpu/drm/msm/sde/sde_crtc.c
index db637ad..e7a867f 100644
--- a/drivers/gpu/drm/msm/sde/sde_crtc.c
+++ b/drivers/gpu/drm/msm/sde/sde_crtc.c
@@ -602,10 +602,9 @@
 		struct sde_crtc *sde_crtc, struct sde_crtc_mixer *mixer,
 		struct sde_hw_dim_layer *dim_layer)
 {
+	struct sde_crtc_state *cstate;
 	struct sde_hw_mixer *lm;
-	struct sde_rect mixer_rect;
 	struct sde_hw_dim_layer split_dim_layer;
-	u32 mixer_width, mixer_height;
 	int i;
 
 	if (!dim_layer->rect.w || !dim_layer->rect.h) {
@@ -613,9 +612,7 @@
 		return;
 	}
 
-	mixer_width = get_crtc_split_width(crtc);
-	mixer_height = get_crtc_mixer_height(crtc);
-	mixer_rect = (struct sde_rect) {0, 0, mixer_width, mixer_height};
+	cstate = to_sde_crtc_state(crtc->state);
 
 	split_dim_layer.stage = dim_layer->stage;
 	split_dim_layer.color_fill = dim_layer->color_fill;
@@ -626,17 +623,15 @@
 	 */
 	for (i = 0; i < sde_crtc->num_mixers; i++) {
 		split_dim_layer.flags = dim_layer->flags;
-		mixer_rect.x = i * mixer_width;
 
-		sde_kms_rect_intersect(&mixer_rect, &dim_layer->rect,
+		sde_kms_rect_intersect(&cstate->lm_bounds[i], &dim_layer->rect,
 					&split_dim_layer.rect);
-		if (!split_dim_layer.rect.w && !split_dim_layer.rect.h) {
+		if (sde_kms_rect_is_null(&split_dim_layer.rect)) {
 			/*
 			 * no extra programming required for non-intersecting
 			 * layer mixers with INCLUSIVE dim layer
 			 */
-			if (split_dim_layer.flags
-					& SDE_DRM_DIM_LAYER_INCLUSIVE)
+			if (split_dim_layer.flags & SDE_DRM_DIM_LAYER_INCLUSIVE)
 				continue;
 
 			/*
@@ -646,12 +641,13 @@
 			 */
 			split_dim_layer.flags &= ~SDE_DRM_DIM_LAYER_EXCLUSIVE;
 			split_dim_layer.flags |= SDE_DRM_DIM_LAYER_INCLUSIVE;
-			split_dim_layer.rect = (struct sde_rect) {0, 0,
-						mixer_width, mixer_height};
+			memcpy(&split_dim_layer.rect, &cstate->lm_bounds[i],
+					sizeof(split_dim_layer.rect));
 
 		} else {
-			split_dim_layer.rect.x = split_dim_layer.rect.x
-							- (i * mixer_width);
+			split_dim_layer.rect.x =
+					split_dim_layer.rect.x -
+					cstate->lm_bounds[i].w;
 		}
 
 		lm = mixer[i].hw_lm;
@@ -660,6 +656,32 @@
 	}
 }
 
+static void _sde_crtc_program_lm_output_roi(struct drm_crtc *crtc)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_state *crtc_state;
+	int lm_idx, lm_horiz_position;
+
+	sde_crtc = to_sde_crtc(crtc);
+	crtc_state = to_sde_crtc_state(crtc->state);
+
+	lm_horiz_position = 0;
+	for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
+		const struct sde_rect *lm_roi = &crtc_state->lm_bounds[lm_idx];
+		struct sde_hw_mixer *hw_lm = sde_crtc->mixers[lm_idx].hw_lm;
+		struct sde_hw_mixer_cfg cfg;
+
+		if (sde_kms_rect_is_null(lm_roi))
+			continue;
+
+		cfg.out_width = lm_roi->w;
+		cfg.out_height = lm_roi->h;
+		cfg.right_mixer = lm_horiz_position++;
+		cfg.flags = 0;
+		hw_lm->ops.setup_mixer_out(hw_lm, &cfg);
+	}
+}
+
 static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
 	struct sde_crtc *sde_crtc, struct sde_crtc_mixer *mixer)
 {
@@ -672,13 +694,12 @@
 	struct sde_hw_ctl *ctl;
 	struct sde_hw_mixer *lm;
 	struct sde_hw_stage_cfg *stage_cfg;
+	struct sde_rect plane_crtc_roi;
 
-	u32 flush_mask = 0, crtc_split_width;
-	uint32_t lm_idx = LEFT_MIXER, idx;
+	u32 flush_mask = 0;
+	uint32_t lm_idx = LEFT_MIXER, stage_idx;
 	bool bg_alpha_enable[CRTC_DUAL_MIXERS] = {false};
-	bool lm_right = false;
-	int left_crtc_zpos_cnt[SDE_STAGE_MAX + 1] = {0};
-	int right_crtc_zpos_cnt[SDE_STAGE_MAX + 1] = {0};
+	int zpos_cnt[CRTC_DUAL_MIXERS][SDE_STAGE_MAX + 1] = { {0} };
 	int i;
 	bool sbuf_mode = false;
 	u32 prefill = 0;
@@ -691,13 +712,18 @@
 	ctl = mixer->hw_ctl;
 	lm = mixer->hw_lm;
 	stage_cfg = &sde_crtc->stage_cfg;
-	crtc_split_width = get_crtc_split_width(crtc);
+	cstate = to_sde_crtc_state(crtc->state);
 
 	drm_atomic_crtc_for_each_plane(plane, crtc) {
 		state = plane->state;
 		if (!state)
 			continue;
 
+		plane_crtc_roi.x = state->crtc_x;
+		plane_crtc_roi.y = state->crtc_y;
+		plane_crtc_roi.w = state->crtc_w;
+		plane_crtc_roi.h = state->crtc_h;
+
 		pstate = to_sde_plane_state(state);
 		fb = state->fb;
 
@@ -706,25 +732,6 @@
 
 		sde_plane_get_ctl_flush(plane, ctl, &flush_mask);
 
-		/* always stage plane on either left or right lm */
-		if (state->crtc_x >= crtc_split_width) {
-			lm_idx = RIGHT_MIXER;
-			idx = right_crtc_zpos_cnt[pstate->stage]++;
-		} else {
-			lm_idx = LEFT_MIXER;
-			idx = left_crtc_zpos_cnt[pstate->stage]++;
-		}
-
-		/* stage plane on right LM if it crosses the boundary */
-		lm_right = (lm_idx == LEFT_MIXER) &&
-		   (state->crtc_x + state->crtc_w > crtc_split_width);
-
-		stage_cfg->stage[lm_idx][pstate->stage][idx] =
-							sde_plane_pipe(plane);
-		stage_cfg->multirect_index
-				[lm_idx][pstate->stage][idx] =
-				pstate->multirect_index;
-		mixer[lm_idx].flush_mask |= flush_mask;
 
 		SDE_DEBUG("crtc %d stage:%d - plane %d sspp %d fb %d\n",
 				crtc->base.id,
@@ -738,47 +745,46 @@
 		SDE_EVT32(DRMID(plane), state->src_x, state->src_y,
 			state->src_w >> 16, state->src_h >> 16, state->crtc_x,
 			state->crtc_y, state->crtc_w, state->crtc_h);
-		SDE_EVT32(DRMID(plane), DRMID(crtc), lm_idx, lm_right,
-			pstate->stage, pstate->multirect_index,
-			pstate->multirect_mode, format->base.pixel_format,
-			fb ? fb->modifier[0] : 0);
 
-		/* blend config update */
-		if (pstate->stage != SDE_STAGE_BASE) {
-			_sde_crtc_setup_blend_cfg(mixer + lm_idx, pstate,
-								format);
+		for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
+			struct sde_rect intersect;
 
-			if (bg_alpha_enable[lm_idx] && !format->alpha_enable)
-				mixer[lm_idx].mixer_op_mode = 0;
-			else
-				mixer[lm_idx].mixer_op_mode |=
-					1 << pstate->stage;
-		} else if (format->alpha_enable) {
-			bg_alpha_enable[lm_idx] = true;
-		}
+			/* skip if the roi doesn't fall within LM's bounds */
+			sde_kms_rect_intersect(&plane_crtc_roi,
+					&cstate->lm_bounds[lm_idx],
+					&intersect);
+			if (sde_kms_rect_is_null(&intersect))
+				continue;
 
-		if (lm_right) {
-			idx = right_crtc_zpos_cnt[pstate->stage]++;
-			stage_cfg->stage[RIGHT_MIXER][pstate->stage][idx] =
-							sde_plane_pipe(plane);
+			stage_idx = zpos_cnt[lm_idx][pstate->stage]++;
+			stage_cfg->stage[lm_idx][pstate->stage][stage_idx] =
+					sde_plane_pipe(plane);
 			stage_cfg->multirect_index
-				[RIGHT_MIXER][pstate->stage][idx] =
-				pstate->multirect_index;
-			mixer[RIGHT_MIXER].flush_mask |= flush_mask;
+					[lm_idx][pstate->stage][stage_idx] =
+					pstate->multirect_index;
+
+			mixer[lm_idx].flush_mask |= flush_mask;
+
+
+			SDE_EVT32(DRMID(plane), DRMID(crtc), lm_idx, stage_idx,
+				pstate->stage, pstate->multirect_index,
+				pstate->multirect_mode,
+				format->base.pixel_format,
+				fb ? fb->modifier[0] : 0);
 
 			/* blend config update */
 			if (pstate->stage != SDE_STAGE_BASE) {
-				_sde_crtc_setup_blend_cfg(mixer + RIGHT_MIXER,
-							pstate, format);
+				_sde_crtc_setup_blend_cfg(mixer + lm_idx,
+						pstate, format);
 
-				if (bg_alpha_enable[RIGHT_MIXER] &&
+				if (bg_alpha_enable[lm_idx] &&
 						!format->alpha_enable)
-					mixer[RIGHT_MIXER].mixer_op_mode = 0;
+					mixer[lm_idx].mixer_op_mode = 0;
 				else
-					mixer[RIGHT_MIXER].mixer_op_mode |=
+					mixer[lm_idx].mixer_op_mode |=
 						1 << pstate->stage;
 			} else if (format->alpha_enable) {
-				bg_alpha_enable[RIGHT_MIXER] = true;
+				bg_alpha_enable[lm_idx] = true;
 			}
 		}
 	}
@@ -804,6 +810,8 @@
 
 		ctl->ops.setup_sbuf_cfg(ctl, &cstate->sbuf_cfg);
 	}
+
+	_sde_crtc_program_lm_output_roi(crtc);
 }
 
 /**
@@ -1296,9 +1304,44 @@
 
 		_sde_crtc_setup_mixer_for_encoder(crtc, enc);
 	}
+
 	mutex_unlock(&sde_crtc->crtc_lock);
 }
 
+static void _sde_crtc_setup_lm_bounds(struct drm_crtc *crtc,
+		struct drm_crtc_state *state)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_state *cstate;
+	struct drm_display_mode *adj_mode;
+	u32 crtc_split_width;
+	int i;
+
+	if (!crtc || !state) {
+		SDE_ERROR("invalid args\n");
+		return;
+	}
+
+	sde_crtc = to_sde_crtc(crtc);
+	cstate = to_sde_crtc_state(state);
+
+	adj_mode = &state->adjusted_mode;
+	crtc_split_width = sde_crtc_mixer_width(sde_crtc, adj_mode);
+
+	for (i = 0; i < sde_crtc->num_mixers; i++) {
+		struct sde_rect *lm_bound = &cstate->lm_bounds[i];
+
+		lm_bound->x = crtc_split_width * i;
+		lm_bound->y = 0;
+		lm_bound->w = crtc_split_width;
+		lm_bound->h = adj_mode->vdisplay;
+		SDE_EVT32(DRMID(crtc), i, lm_bound->x, lm_bound->y,
+				lm_bound->w, lm_bound->h);
+	}
+
+	drm_mode_debug_printmodeline(adj_mode);
+}
+
 static void sde_crtc_atomic_begin(struct drm_crtc *crtc,
 		struct drm_crtc_state *old_state)
 {
@@ -1326,6 +1369,8 @@
 	if (!sde_crtc->num_mixers)
 		_sde_crtc_setup_mixers(crtc);
 
+	_sde_crtc_setup_lm_bounds(crtc, crtc->state);
+
 	if (sde_crtc->event) {
 		WARN_ON(sde_crtc->event);
 	} else {
@@ -1776,13 +1821,10 @@
 static void sde_crtc_enable(struct drm_crtc *crtc)
 {
 	struct sde_crtc *sde_crtc;
-	struct sde_crtc_mixer *mixer;
-	struct sde_hw_mixer *lm;
-	struct drm_display_mode *mode;
 	struct drm_encoder *encoder;
 	unsigned long flags;
 	struct sde_crtc_irq_info *node = NULL;
-	int i, ret;
+	int ret;
 
 	if (!crtc) {
 		SDE_ERROR("invalid crtc\n");
@@ -1791,16 +1833,7 @@
 
 	SDE_DEBUG("crtc%d\n", crtc->base.id);
 	SDE_EVT32(DRMID(crtc));
-
 	sde_crtc = to_sde_crtc(crtc);
-	mixer = sde_crtc->mixers;
-
-	if (WARN_ON(!crtc->state))
-		return;
-
-	mode = &crtc->state->adjusted_mode;
-
-	drm_mode_debug_printmodeline(mode);
 
 	drm_for_each_encoder(encoder, crtc->dev) {
 		if (encoder->crtc != crtc)
@@ -1809,15 +1842,6 @@
 				sde_crtc_frame_event_cb, (void *)crtc);
 	}
 
-	for (i = 0; i < sde_crtc->num_mixers; i++) {
-		lm = mixer[i].hw_lm;
-		lm->cfg.out_width = sde_crtc_mixer_width(sde_crtc, mode);
-		lm->cfg.out_height = mode->vdisplay;
-		lm->cfg.right_mixer = (i == 0) ? false : true;
-		lm->cfg.flags = 0;
-		lm->ops.setup_mixer_out(lm, &lm->cfg);
-	}
-
 	spin_lock_irqsave(&sde_crtc->spin_lock, flags);
 	list_for_each_entry(node, &sde_crtc->user_event_list, list) {
 		ret = 0;
@@ -1894,6 +1918,8 @@
 
 	mixer_width = sde_crtc_mixer_width(sde_crtc, mode);
 
+	_sde_crtc_setup_lm_bounds(crtc, state);
+
 	 /* get plane state for all drm planes associated with crtc state */
 	drm_atomic_crtc_state_for_each_plane_state(plane, pstate, state) {
 		if (IS_ERR_OR_NULL(pstate)) {