diff mbox

[RFC,2/3] drm/i915: Calculate an intermediate plane/crtc atomic state for modesets

Message ID 1440806249-8345-2-git-send-email-matthew.d.roper@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Matt Roper Aug. 28, 2015, 11:57 p.m. UTC
To simplify the modeset process for atomic, start calculating an
"intermediate" state for any CRTC's which undergo a modeset (or get
permanently disabled).  This state represents the status of the CRTC and
planes at the point in which the CRTC's have been disabled; i.e.,
intermediate_state->active = false, even if the CRTC will be running
again once the modeset is complete.  This will allow us to calculate
proper derived state fields for this point in the modeset process which
should in turn should help us properly perform tasks like watermark
calculation.

For review simplicity, this patch simply allocates and calculates the
intermediate state objects, but doesn't actually do anything with them.
The next patch will start actually using this intermediate state data.

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Matt Roper <matthew.d.roper@intel.com>
---
 drivers/gpu/drm/i915/intel_atomic.c  | 152 +++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_display.c |   3 +-
 drivers/gpu/drm/i915/intel_drv.h     |  13 +++
 3 files changed, 167 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
index 3ffc385..26a5c2a 100644
--- a/drivers/gpu/drm/i915/intel_atomic.c
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -320,12 +320,164 @@  intel_atomic_state_alloc(struct drm_device *dev)
 		return NULL;
 	}
 
+	state->int_plane_states = kcalloc(dev->mode_config.num_total_plane,
+					  sizeof(*state->int_plane_states),
+					  GFP_KERNEL);
+	state->int_crtc_states = kcalloc(dev->mode_config.num_crtc,
+					  sizeof(*state->int_crtc_states),
+					  GFP_KERNEL);
+	if (!state->int_plane_states || !state->int_crtc_states)
+		goto fail;
+
 	return &state->base;
+
+fail:
+	kfree(state->int_plane_states);
+	kfree(state->int_crtc_states);
+	drm_atomic_state_default_release(&state->base);
+	return NULL;
+}
+
+void
+intel_atomic_state_free(struct drm_atomic_state *s)
+{
+	struct intel_atomic_state *state = to_intel_atomic_state(s);
+
+	if (WARN_ON(!s))
+		return;
+
+	kfree(state->int_plane_states);
+	kfree(state->int_crtc_states);
+	drm_atomic_state_default_release(s);
 }
 
 void intel_atomic_state_clear(struct drm_atomic_state *s)
 {
 	struct intel_atomic_state *state = to_intel_atomic_state(s);
+	struct drm_mode_config *config = &s->dev->mode_config;
+	int i;
+
+	for (i = 0; i < config->num_crtc; i++) {
+		struct drm_crtc_state *cstate = state->int_crtc_states[i];
+		struct drm_crtc *crtc = s->crtcs[i];
+
+		if (!cstate)
+			continue;
+
+		crtc->funcs->atomic_destroy_state(crtc, cstate);
+		state->int_crtc_states[i] = NULL;
+	}
+
+	for (i = 0; i < config->num_total_plane; i++) {
+		struct drm_plane_state *pstate = state->int_plane_states[i];
+		struct drm_plane *plane = s->planes[i];
+
+		if (!pstate)
+			continue;
+
+		plane->funcs->atomic_destroy_state(plane, pstate);
+		state->int_plane_states[i] = NULL;
+	}
+
 	drm_atomic_state_default_clear(&state->base);
 	state->dpll_set = false;
 }
+
+/**
+ * intel_atomic_check_planes - validate state object for planes changes
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * An Intel-specific replacement for drm_atomic_helper_check_planes().  In
+ * addition to calling the ->atomic_check() entrypoints for all plane/crtc
+ * states present in the atomic transaction, it also creates an additional set
+ * of plane/crtc state objects that correspond to the 'intermediate' states for
+ * any planes/crtc's that undergo a modeset or disable as part of this
+ * transaction.  These states will differ from the main states in that they
+ * show the CRTC as disabled, so all derived state shall be calculated
+ * accordingly.
+ */
+int
+intel_atomic_check_planes(struct drm_device *dev,
+			  struct drm_atomic_state *state)
+{
+	struct intel_atomic_state *istate = to_intel_atomic_state(state);
+	struct drm_crtc *crtc;
+	struct drm_crtc_state *cstate;
+	struct drm_plane *plane;
+	struct drm_plane_state *pstate;
+	struct drm_crtc_state **tmp_cstates;
+	struct drm_plane_state **tmp_pstates;
+	unsigned needs_ms = 0;
+	int i, ret;
+
+	/*
+	 * Start by checking calculating/checking the final state as usual;
+	 * if that doesn't work, then there's no point in worrying about
+	 * intermediate states.
+	 */
+	ret = drm_atomic_helper_check_planes(dev, state);
+	if (ret)
+		return ret;
+
+	/*
+	 * End state looks okay.  Create intermediate states for any CRTC's
+	 * that undergo a modeset/disable; the intermediate state corresponds
+	 * to the 'disable' part of the modeset, before anything gets turned
+	 * back on.
+	 */
+	for_each_crtc_in_state(state, crtc, cstate, i) {
+		if (!drm_atomic_crtc_needs_modeset(cstate))
+			continue;
+
+		needs_ms |= drm_crtc_mask(crtc);
+
+		istate->int_crtc_states[i] = intel_crtc_duplicate_state(crtc);
+		if (!istate->int_crtc_states[i])
+			return -ENOMEM;
+
+		istate->int_crtc_states[i]->state = state;
+
+		/*
+		 * For CRTC's undergoing a modeset (i.e., ultimately to be
+		 * re-enabled), this is the key difference from the final state
+		 * and will affect how the derived parts of the state object
+		 * are calculated.
+		 */
+		istate->int_crtc_states[i]->active = false;
+	}
+
+	if (!needs_ms)
+		return 0;
+
+	/*
+	 * We also need intermediate states for any planes that will be active
+	 * on a CRTC in the list above since their derived state will also
+	 * differ at the intermediate point.
+	 */
+	for_each_plane_in_state(state, plane, pstate, i) {
+		if (!pstate->crtc || !(needs_ms & drm_crtc_mask(pstate->crtc)))
+			continue;
+
+		istate->int_plane_states[i] = intel_plane_duplicate_state(plane);
+		if (!istate->int_plane_states[i])
+			return -ENOMEM;
+
+		istate->int_plane_states[i]->state = state;
+	}
+
+	/*
+	 * Temporarily swap our plane/crtc state arrays into the base state
+	 * object and call the helper again to calculate the derived state
+	 * (and check the intermediate state for validity).
+	 */
+	tmp_cstates = state->crtc_states;
+	tmp_pstates = state->plane_states;
+	state->crtc_states = istate->int_crtc_states;
+	state->plane_states = istate->int_plane_states;
+	ret = drm_atomic_helper_check_planes(dev, state);
+	state->crtc_states = tmp_cstates;
+	state->plane_states = tmp_pstates;
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 68b5f2a..76f3727 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13052,7 +13052,7 @@  static int intel_atomic_check(struct drm_device *dev,
 		to_intel_atomic_state(state)->cdclk =
 			to_i915(state->dev)->cdclk_freq;
 
-	return drm_atomic_helper_check_planes(state->dev, state);
+	return intel_atomic_check_planes(state->dev, state);
 }
 
 /**
@@ -14332,6 +14332,7 @@  static const struct drm_mode_config_funcs intel_mode_funcs = {
 	.atomic_check = intel_atomic_check,
 	.atomic_commit = intel_atomic_commit,
 	.atomic_state_alloc = intel_atomic_state_alloc,
+	.atomic_state_free = intel_atomic_state_free,
 	.atomic_state_clear = intel_atomic_state_clear,
 };
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index fd09087..0113c20 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -239,6 +239,16 @@  struct intel_atomic_state {
 	unsigned int cdclk;
 	bool dpll_set;
 	struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS];
+
+	/*
+	 * Intermediate state arrays; the states here should be identical
+	 * to the base object's states for CRTC's that are not involved in a
+	 * modeset/disable.  CRTC's that do require a modeset/disable will
+	 * appear as disabled here (and the relevant derived state should
+	 * be updated accordingly).
+	 */
+	struct drm_plane_state **int_plane_states;
+	struct drm_crtc_state **int_crtc_states;
 };
 
 struct intel_plane_state {
@@ -1396,6 +1406,7 @@  struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc);
 void intel_crtc_destroy_state(struct drm_crtc *crtc,
 			       struct drm_crtc_state *state);
 struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev);
+void intel_atomic_state_free(struct drm_atomic_state *s);
 void intel_atomic_state_clear(struct drm_atomic_state *);
 struct intel_shared_dpll_config *
 intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s);
@@ -1414,6 +1425,8 @@  intel_atomic_get_crtc_state(struct drm_atomic_state *state,
 int intel_atomic_setup_scalers(struct drm_device *dev,
 	struct intel_crtc *intel_crtc,
 	struct intel_crtc_state *crtc_state);
+int intel_atomic_check_planes(struct drm_device *dev,
+			      struct drm_atomic_state *state);
 
 /* intel_atomic_plane.c */
 struct intel_plane_state *intel_create_plane_state(struct drm_plane *plane);