[PATCH 1/5] drm/atomic: Add drm_crtc_state->active

Ville Syrjälä ville.syrjala at linux.intel.com
Thu Jan 22 07:56:54 PST 2015


On Thu, Jan 22, 2015 at 04:36:21PM +0100, Daniel Vetter wrote:
> This is the infrastructure for DPMS ported to the atomic world.
> Fundamental changes compare to legacy DPMS are:
> 
> - No more per-connector dpms state, instead there's just one per each
>   display pipeline. So if you clone either you have to unclone first
>   if you only want to switch off one screen, or you just switch of
>   everything (like all desktops do). This massively reduces complexity
>   for cloning since now there's no more half-enabled cloned configs to
>   consider.
> 
> - Only on/off, dpms standby/suspend are as dead as real CRTs. Again
>   reduces complexity a lot.
> 
> Now especially for backwards compat the really important part for dpms
> support is that dpms on always succeeds (except for hw death and
> unplugged cables ofc). Which means everything that could fail (like
> configuration checking, resources assignments and buffer management)
> must be done irrespective from ->active. ->active is really only a
> toggle to change the hardware state. More precisely:
> 
> - Drivers MUST NOT look at ->active in their ->atomic_check callbacks.
>   Changes to ->active MUST always suceed if nothing else changes.
> 
> - Drivers using the atomic helpers MUST NOT look at ->active anywhere,
>   period. The helpers will take care of calling the respective
>   enable/modeset/disable hooks as necessary. As before the helpers
>   will carefully keep track of the state and not call any hooks
>   unecessarily, so still no double-disables or enables like with crtc
>   helpers.
> 
> - ->mode_set hooks are only called when the mode or output
>   configuration changes, not for changes in ->active state.
> 
> - Drivers which reconstruct the state objects in their ->reset hooks
>   or through some other hw state readout infrastructure must ensure
>   that ->active reflects actual hw state.
> 
> This just implements the core bits and helper logic, a subsequent
> patch will implement the helper code to implement legacy dpms with
> this.

So we now have multiple conflicting properties for the same thing? I
don't particularly relish that idea.

I suppose a rather easy way to way to deal with that would be to hide
the dpms properties from non-atomic clients, and conversly hide the
active property from legacy clients.

> 
> v2: Rebase on top of the drm ioctl work:
> - Move crtc checks to the core check function.
> - Also check for ->active_changed when deciding whether a modeset
>   might happen (for the ALLOW_MODESET mode).
> - Expose the ->active state with an atomic prop.
> 
> v3: Review from Rob
> - Spelling fix in comment.
> - Extract needs_modeset helper to consolidate the ->mode_changed ||
>   ->active_changed checks.
> 
> v4: Fixup fumble between crtc->state and crtc_state.
> 
> Cc: Rob Clark <robdclark at gmail.com>
> Signed-off-by: Daniel Vetter <daniel.vetter at intel.com>
> ---
>  drivers/gpu/drm/drm_atomic.c        | 18 +++++++++++--
>  drivers/gpu/drm/drm_atomic_helper.c | 54 +++++++++++++++++++++++++++++++++----
>  drivers/gpu/drm/drm_crtc.c          | 10 +++++++
>  include/drm/drm_crtc.h              |  3 +++
>  4 files changed, 78 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 1e38dfc8e462..ee68267bb326 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -241,7 +241,13 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
>  		struct drm_crtc_state *state, struct drm_property *property,
>  		uint64_t val)
>  {
> -	if (crtc->funcs->atomic_set_property)
> +	struct drm_device *dev = crtc->dev;
> +	struct drm_mode_config *config = &dev->mode_config;
> +
> +	/* FIXME: Mode prop is missing, which also controls ->enable. */
> +	if (property == config->prop_active) {
> +		state->active = val;
> +	} else if (crtc->funcs->atomic_set_property)
>  		return crtc->funcs->atomic_set_property(crtc, state, property, val);
>  	return -EINVAL;
>  }
> @@ -282,6 +288,13 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
>  	 *
>  	 * TODO: Add generic modeset state checks once we support those.
>  	 */
> +
> +	if (state->active && !state->enable) {
> +		DRM_DEBUG_KMS("[CRTC:%d] active without enabled\n",
> +			      crtc->base.id);
> +		return -EINVAL;
> +	}
> +
>  	return 0;
>  }
>  
> @@ -976,7 +989,8 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
>  			if (!crtc)
>  				continue;
>  
> -			if (crtc_state->mode_changed) {
> +			if (crtc_state->mode_changed ||
> +			    crtc_state->active_changed) {
>  				DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n",
>  					      crtc->base.id);
>  				return -EINVAL;
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 541ba833ed36..3f17933b1d2c 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -330,6 +330,12 @@ mode_fixup(struct drm_atomic_state *state)
>  	return 0;
>  }
>  
> +static bool
> +needs_modeset(struct drm_crtc_state *state)
> +{
> +	return state->mode_changed || state->active_changed;
> +}
> +
>  /**
>   * drm_atomic_helper_check - validate state object for modeset changes
>   * @dev: DRM device
> @@ -404,12 +410,27 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
>  		crtc = state->crtcs[i];
>  		crtc_state = state->crtc_states[i];
>  
> -		if (!crtc || !crtc_state->mode_changed)
> +		if (!crtc)
>  			continue;
>  
> -		DRM_DEBUG_KMS("[CRTC:%d] needs full modeset, enable: %c\n",
> +		/*
> +		 * We must set ->active_changed after walking connectors for
> +		 * otherwise an update that only changes active would result in
> +		 * a full modeset because update_connector_routing force that.
> +		 */
> +		if (crtc->state->active != crtc_state->active) {
> +			DRM_DEBUG_KMS("[CRTC:%d] active changed\n",
> +				      crtc->base.id);
> +			crtc_state->active_changed = true;
> +		}
> +
> +		if (!needs_modeset(crtc_state))
> +			continue;
> +
> +		DRM_DEBUG_KMS("[CRTC:%d] needs all connectors, enable: %c, active: %c\n",
>  			      crtc->base.id,
> -			      crtc_state->enable ? 'y' : 'n');
> +			      crtc_state->enable ? 'y' : 'n',
> +			      crtc_state->active ? 'y' : 'n');
>  
>  		ret = drm_atomic_add_affected_connectors(state, crtc);
>  		if (ret != 0)
> @@ -545,6 +566,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  		struct drm_connector *connector;
>  		struct drm_encoder_helper_funcs *funcs;
>  		struct drm_encoder *encoder;
> +		struct drm_crtc_state *old_crtc_state;
>  
>  		old_conn_state = old_state->connector_states[i];
>  		connector = old_state->connectors[i];
> @@ -554,6 +576,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  		if (!old_conn_state || !old_conn_state->crtc)
>  			continue;
>  
> +		old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)];
> +
> +		if (!old_crtc_state->active)
> +			continue;
> +
>  		encoder = old_conn_state->best_encoder;
>  
>  		/* We shouldn't get this far if we didn't previously have
> @@ -586,11 +613,16 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
>  	for (i = 0; i < ncrtcs; i++) {
>  		struct drm_crtc_helper_funcs *funcs;
>  		struct drm_crtc *crtc;
> +		struct drm_crtc_state *old_crtc_state;
>  
>  		crtc = old_state->crtcs[i];
> +		old_crtc_state = old_state->crtc_states[i];
>  
>  		/* Shut down everything that needs a full modeset. */
> -		if (!crtc || !crtc->state->mode_changed)
> +		if (!crtc || !needs_modeset(crtc->state))
> +			continue;
> +
> +		if (!old_crtc_state->active)
>  			continue;
>  
>  		funcs = crtc->helper_private;
> @@ -697,6 +729,9 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
>  		mode = &new_crtc_state->mode;
>  		adjusted_mode = &new_crtc_state->adjusted_mode;
>  
> +		if (!new_crtc_state->mode_changed)
> +			continue;
> +
>  		/*
>  		 * Each encoder has at most one connector (since we always steal
>  		 * it away), so we won't call call mode_set hooks twice.
> @@ -749,7 +784,10 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
>  		crtc = old_state->crtcs[i];
>  
>  		/* Need to filter out CRTCs where only planes change. */
> -		if (!crtc || !crtc->state->mode_changed)
> +		if (!crtc || !needs_modeset(crtc->state))
> +			continue;
> +
> +		if (!crtc->state->active)
>  			continue;
>  
>  		funcs = crtc->helper_private;
> @@ -768,6 +806,9 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
>  		if (!connector || !connector->state->best_encoder)
>  			continue;
>  
> +		if (!connector->state->crtc->state->active)
> +			continue;
> +
>  		encoder = connector->state->best_encoder;
>  		funcs = encoder->helper_private;
>  
> @@ -1518,6 +1559,7 @@ retry:
>  		WARN_ON(set->num_connectors);
>  
>  		crtc_state->enable = false;
> +		crtc_state->active = false;
>  
>  		ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
>  		if (ret != 0)
> @@ -1532,6 +1574,7 @@ retry:
>  	WARN_ON(!set->num_connectors);
>  
>  	crtc_state->enable = true;
> +	crtc_state->active = true;
>  	drm_mode_copy(&crtc_state->mode, set->mode);
>  
>  	ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
> @@ -1894,6 +1937,7 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
>  
>  	if (state) {
>  		state->mode_changed = false;
> +		state->active_changed = false;
>  		state->planes_changed = false;
>  		state->event = NULL;
>  	}
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 56e3256d5249..30a136b8a4fc 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -691,6 +691,10 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
>  	if (cursor)
>  		cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
>  
> +	if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
> +		drm_object_attach_property(&crtc->base, config->prop_active, 0);
> +	}
> +
>  	return 0;
>  }
>  EXPORT_SYMBOL(drm_crtc_init_with_planes);
> @@ -1391,6 +1395,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev)
>  		return -ENOMEM;
>  	dev->mode_config.prop_crtc_id = prop;
>  
> +	prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
> +			"ACTIVE");
> +	if (!prop)
> +		return -ENOMEM;
> +	dev->mode_config.prop_active = prop;
> +
>  	return 0;
>  }
>  
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 8022ab11958a..4d3f3b874dd6 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -249,6 +249,7 @@ struct drm_atomic_state;
>   * @enable: whether the CRTC should be enabled, gates all other state
>   * @active: whether the CRTC is actively displaying (used for DPMS)
>   * @mode_changed: for use by helpers and drivers when computing state updates
> + * @active_changed: for use by helpers and drivers when computing state updates
>   * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
>   * @last_vblank_count: for helpers and drivers to capture the vblank of the
>   * 	update to ensure framebuffer cleanup isn't done too early
> @@ -274,6 +275,7 @@ struct drm_crtc_state {
>  	/* computed state bits used by helpers and drivers */
>  	bool planes_changed : 1;
>  	bool mode_changed : 1;
> +	bool active_changed : 1;
>  
>  	/* attached planes bitmask:
>  	 * WARNING: transitional helpers do not maintain plane_mask so
> @@ -1128,6 +1130,7 @@ struct drm_mode_config {
>  	struct drm_property *prop_crtc_h;
>  	struct drm_property *prop_fb_id;
>  	struct drm_property *prop_crtc_id;
> +	struct drm_property *prop_active;
>  
>  	/* DVI-I properties */
>  	struct drm_property *dvi_i_subconnector_property;
> -- 
> 2.1.4
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Ville Syrjälä
Intel OTC


More information about the dri-devel mailing list