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 <robdcl...@gmail.com>
> Signed-off-by: Daniel Vetter <daniel.vet...@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-de...@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to