Переглянути джерело

disp: msm: sde: only program LM size when needed

LM size does not need to be reprogrammed on every frame. Add
a check to only reprogram it when the size changes (or coming
out of power collapse). Some color processing features require
an update when this happens as well (i.e. resolution switch,
partial update, or dest scaler reconfigure). This patch allows
for notifying CP of the updated dimensions when a change occurs.

Change-Id: Ia7f794e53e1f03302c83e442e2a1288611c7c50b
Signed-off-by: Steve Cohen <[email protected]>
Steve Cohen 4 роки тому
батько
коміт
b385a84e0d
3 змінених файлів з 84 додано та 50 видалено
  1. 1 1
      msm/sde/sde_color_processing.c
  2. 2 2
      msm/sde/sde_color_processing.h
  3. 81 47
      msm/sde/sde_crtc.c

+ 1 - 1
msm/sde/sde_color_processing.c

@@ -4132,7 +4132,7 @@ int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en,
 	return 0;
 }
 
-void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm)
+void sde_cp_crtc_res_change(struct drm_crtc *crtc_drm)
 {
 	struct sde_cp_node *prop_node = NULL, *n = NULL;
 	struct sde_crtc *crtc;

+ 2 - 2
msm/sde/sde_color_processing.h

@@ -201,10 +201,10 @@ int sde_cp_ltm_off_event_handler(struct drm_crtc *crtc_drm, bool en,
 	struct sde_irq_callback *hist_irq);
 
 /**
- * sde_cp_mode_switch_prop_dirty: API marks mode dependent features as dirty
+ * sde_cp_crtc_res_change: API to handle LM resolution changes
  * @crtc_drm: Pointer to crtc.
  */
-void sde_cp_mode_switch_prop_dirty(struct drm_crtc *crtc_drm);
+void sde_cp_crtc_res_change(struct drm_crtc *crtc_drm);
 
 /**
  * sde_cp_crtc_vm_primary_handoff: Properly handoff CRTC color mode features

+ 81 - 47
msm/sde/sde_crtc.c

@@ -433,7 +433,6 @@ static bool sde_crtc_mode_fixup(struct drm_crtc *crtc,
 {
 	SDE_DEBUG("\n");
 
-	sde_cp_mode_switch_prop_dirty(crtc);
 	if ((msm_is_mode_seamless(adjusted_mode) ||
 	     (msm_is_mode_seamless_vrr(adjusted_mode) ||
 	      msm_is_mode_seamless_dyn_clk(adjusted_mode))) &&
@@ -1113,40 +1112,49 @@ static int _sde_crtc_check_rois(struct drm_crtc *crtc,
 static void _sde_crtc_program_lm_output_roi(struct drm_crtc *crtc)
 {
 	struct sde_crtc *sde_crtc;
-	struct sde_crtc_state *crtc_state;
+	struct sde_crtc_state *cstate;
 	const struct sde_rect *lm_roi;
 	struct sde_hw_mixer *hw_lm;
 	bool right_mixer = false;
+	bool lm_updated = false;
 	int lm_idx;
 
 	if (!crtc)
 		return;
 
 	sde_crtc = to_sde_crtc(crtc);
-	crtc_state = to_sde_crtc_state(crtc->state);
+	cstate = to_sde_crtc_state(crtc->state);
 
 	for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
 		struct sde_hw_mixer_cfg cfg;
 
-		lm_roi = &crtc_state->lm_roi[lm_idx];
+		lm_roi = &cstate->lm_roi[lm_idx];
 		hw_lm = sde_crtc->mixers[lm_idx].hw_lm;
 		if (!sde_crtc->mixers_swapped)
 			right_mixer = lm_idx % MAX_MIXERS_PER_LAYOUT;
 
-		SDE_EVT32(DRMID(crtc_state->base.crtc), lm_idx,
-				lm_roi->x, lm_roi->y, lm_roi->w, lm_roi->h,
-				right_mixer);
+		if (lm_roi->w != hw_lm->cfg.out_width ||
+				lm_roi->h != hw_lm->cfg.out_height ||
+				right_mixer != hw_lm->cfg.right_mixer) {
+			hw_lm->cfg.out_width = lm_roi->w;
+			hw_lm->cfg.out_height = lm_roi->h;
+			hw_lm->cfg.right_mixer = right_mixer;
+
+			cfg.out_width = lm_roi->w;
+			cfg.out_height = lm_roi->h;
+			cfg.right_mixer = right_mixer;
+			cfg.flags = 0;
 
-		hw_lm->cfg.out_width = lm_roi->w;
-		hw_lm->cfg.out_height = lm_roi->h;
-		hw_lm->cfg.right_mixer = right_mixer;
+			hw_lm->ops.setup_mixer_out(hw_lm, &cfg);
+			lm_updated = true;
+		}
 
-		cfg.out_width = lm_roi->w;
-		cfg.out_height = lm_roi->h;
-		cfg.right_mixer = right_mixer;
-		cfg.flags = 0;
-		hw_lm->ops.setup_mixer_out(hw_lm, &cfg);
+		SDE_EVT32(DRMID(crtc), lm_idx, lm_roi->x, lm_roi->y, lm_roi->w,
+				lm_roi->h, right_mixer, lm_updated);
 	}
+
+	if (lm_updated)
+		sde_cp_crtc_res_change(crtc);
 }
 
 struct plane_state {
@@ -1533,8 +1541,6 @@ static void _sde_crtc_blend_setup_mixer(struct drm_crtc *crtc,
 		}
 	}
 
-	_sde_crtc_program_lm_output_roi(crtc);
-
 end:
 	kfree(pstates);
 }
@@ -2165,8 +2171,6 @@ static void _sde_crtc_dest_scaler_setup(struct drm_crtc *crtc)
 				hw_ctl->ops.update_bitmask_mixer(
 						hw_ctl, hw_lm->idx, 1);
 		}
-
-		sde_cp_mode_switch_prop_dirty(crtc);
 	}
 }
 
@@ -3901,12 +3905,63 @@ static void sde_crtc_reset(struct drm_crtc *crtc)
 	crtc->state = &cstate->base;
 }
 
+static void sde_crtc_clear_cached_mixer_cfg(struct drm_crtc *crtc)
+{
+	struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
+	struct sde_hw_mixer *hw_lm;
+	int lm_idx;
+
+	/* clearing lm cfg marks it dirty to force reprogramming next update */
+	for (lm_idx = 0; lm_idx < sde_crtc->num_mixers; lm_idx++) {
+		hw_lm = sde_crtc->mixers[lm_idx].hw_lm;
+		hw_lm->cfg.out_width = 0;
+		hw_lm->cfg.out_height = 0;
+	}
+
+	SDE_EVT32(DRMID(crtc));
+}
+
+static void sde_crtc_reset_sw_state_for_ipc(struct drm_crtc *crtc)
+{
+	struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state);
+	struct drm_plane *plane;
+
+	/* mark planes, mixers, and other blocks dirty for next update */
+	drm_atomic_crtc_for_each_plane(plane, crtc)
+		sde_plane_set_revalidate(plane, true);
+
+	/* mark mixers dirty for next update */
+	sde_crtc_clear_cached_mixer_cfg(crtc);
+
+	/* mark other properties which need to be dirty for next update */
+	set_bit(SDE_CRTC_DIRTY_DIM_LAYERS, cstate->dirty);
+	if (cstate->num_ds_enabled)
+		set_bit(SDE_CRTC_DIRTY_DEST_SCALER, cstate->dirty);
+}
+
+static void sde_crtc_post_ipc(struct drm_crtc *crtc)
+{
+	struct sde_crtc *sde_crtc;
+	struct sde_crtc_state *cstate;
+	struct drm_encoder *encoder;
+
+	sde_crtc = to_sde_crtc(crtc);
+	cstate = to_sde_crtc_state(crtc->state);
+
+	/* restore encoder; crtc will be programmed during commit */
+	drm_for_each_encoder_mask(encoder, crtc->dev, crtc->state->encoder_mask)
+		sde_encoder_virt_restore(encoder);
+
+	/* restore UIDLE */
+	sde_core_perf_crtc_update_uidle(crtc, true);
+
+	sde_cp_crtc_post_ipc(crtc);
+}
+
 static void sde_crtc_handle_power_event(u32 event_type, void *arg)
 {
 	struct drm_crtc *crtc = arg;
 	struct sde_crtc *sde_crtc;
-	struct sde_crtc_state *cstate;
-	struct drm_plane *plane;
 	struct drm_encoder *encoder;
 	u32 power_on;
 	unsigned long flags;
@@ -3919,7 +3974,6 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
 		return;
 	}
 	sde_crtc = to_sde_crtc(crtc);
-	cstate = to_sde_crtc_state(crtc->state);
 
 	mutex_lock(&sde_crtc->crtc_lock);
 
@@ -3927,15 +3981,6 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
 
 	switch (event_type) {
 	case SDE_POWER_EVENT_POST_ENABLE:
-		/* restore encoder; crtc will be programmed during commit */
-		drm_for_each_encoder_mask(encoder, crtc->dev,
-				crtc->state->encoder_mask) {
-			sde_encoder_virt_restore(encoder);
-		}
-
-		/* restore UIDLE */
-		sde_core_perf_crtc_update_uidle(crtc, true);
-
 		spin_lock_irqsave(&sde_crtc->spin_lock, flags);
 		list_for_each_entry(node, &sde_crtc->user_event_list, list) {
 			ret = 0;
@@ -3947,10 +3992,9 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
 		}
 		spin_unlock_irqrestore(&sde_crtc->spin_lock, flags);
 
-		sde_cp_crtc_post_ipc(crtc);
+		sde_crtc_post_ipc(crtc);
 		break;
 	case SDE_POWER_EVENT_PRE_DISABLE:
-
 		drm_for_each_encoder_mask(encoder, crtc->dev,
 				crtc->state->encoder_mask) {
 			/*
@@ -3980,21 +4024,8 @@ static void sde_crtc_handle_power_event(u32 event_type, void *arg)
 		sde_cp_crtc_pre_ipc(crtc);
 		break;
 	case SDE_POWER_EVENT_POST_DISABLE:
-		/*
-		 * set revalidate flag in planes, so it will be re-programmed
-		 * in the next frame update
-		 */
-		drm_atomic_crtc_for_each_plane(plane, crtc)
-			sde_plane_set_revalidate(plane, true);
-
+		sde_crtc_reset_sw_state_for_ipc(crtc);
 		sde_cp_crtc_suspend(crtc);
-
-		/* reconfigure everything on next frame update */
-		set_bit(SDE_CRTC_DIRTY_DIM_LAYERS, cstate->dirty);
-
-		if (cstate->num_ds_enabled)
-			set_bit(SDE_CRTC_DIRTY_DEST_SCALER, cstate->dirty);
-
 		event.type = DRM_EVENT_SDE_POWER;
 		event.length = sizeof(power_on);
 		power_on = 0;
@@ -4014,6 +4045,9 @@ static void _sde_crtc_reset(struct drm_crtc *crtc)
 	struct sde_crtc *sde_crtc = to_sde_crtc(crtc);
 	struct sde_crtc_state *cstate = to_sde_crtc_state(crtc->state);
 
+	/* mark mixer cfgs dirty before wiping them */
+	sde_crtc_clear_cached_mixer_cfg(crtc);
+
 	memset(sde_crtc->mixers, 0, sizeof(sde_crtc->mixers));
 	sde_crtc->num_mixers = 0;
 	sde_crtc->mixers_swapped = false;