Merge tag 'topic/atomic-core-2015-01-27' of git://anongit.freedesktop.org/drm-intel...
authorDave Airlie <airlied@redhat.com>
Tue, 27 Jan 2015 23:34:27 +0000 (09:34 +1000)
committerDave Airlie <airlied@redhat.com>
Tue, 27 Jan 2015 23:34:27 +0000 (09:34 +1000)
* tag 'topic/atomic-core-2015-01-27' of git://anongit.freedesktop.org/drm-intel:
  drm/atomic: Fix potential use of state after free
  drm/atomic-helper: debug output for modesets
  drm/atomic-helpers: Saner encoder/crtc callbacks
  drm/atomic-helpers: Recover full cursor plane behaviour
  drm/atomic-helper: add connector->dpms() implementation
  drm/atomic: Add drm_crtc_state->active
  drm: Add standardized boolean props
  drm/plane-helper: Fix transitional helper kerneldocs
  drm/plane-helper: Skip prepare_fb/cleanup_fb when newfb==oldfb

Conflicts:
include/drm/drm_crtc_helper.h

drivers/gpu/drm/drm_atomic.c
drivers/gpu/drm/drm_atomic_helper.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_plane_helper.c
include/drm/drm_atomic_helper.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h

index 4c5c9c3899e04a4d9ea93cf9f4095a4760dc8aea..c2e9c5283136bc62f9b4baf18f46d204c41bc6d9 100644 (file)
@@ -134,6 +134,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                connector->funcs->atomic_destroy_state(connector,
                                                       state->connector_states[i]);
+               state->connector_states[i] = NULL;
        }
 
        for (i = 0; i < config->num_crtc; i++) {
@@ -144,6 +145,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                crtc->funcs->atomic_destroy_state(crtc,
                                                  state->crtc_states[i]);
+               state->crtc_states[i] = NULL;
        }
 
        for (i = 0; i < config->num_total_plane; i++) {
@@ -154,6 +156,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
 
                plane->funcs->atomic_destroy_state(plane,
                                                   state->plane_states[i]);
+               state->plane_states[i] = NULL;
        }
 }
 EXPORT_SYMBOL(drm_atomic_state_clear);
@@ -241,7 +244,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 +291,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;
 }
 
@@ -978,7 +994,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;
index 24c44c24dabe6de55830838109dc65b534411b14..7e3a52b97c7d4154b82870f2c2d2ebb04298a5e0 100644 (file)
@@ -339,6 +339,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
@@ -413,12 +419,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;
+
+               /*
+                * 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 full modeset, enable: %c\n",
+               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)
@@ -554,6 +575,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];
@@ -563,6 +585,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
@@ -573,6 +600,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
 
                funcs = encoder->helper_private;
 
+               DRM_DEBUG_KMS("disabling [ENCODER:%d:%s]\n",
+                             encoder->base.id, encoder->name);
+
                /*
                 * Each encoder has at most one connector (since we always steal
                 * it away), so we won't call call disable hooks twice.
@@ -581,7 +611,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
                        encoder->bridge->funcs->disable(encoder->bridge);
 
                /* Right function depends upon target state. */
-               if (connector->state->crtc)
+               if (connector->state->crtc && funcs->prepare)
                        funcs->prepare(encoder);
                else if (funcs->disable)
                        funcs->disable(encoder);
@@ -595,17 +625,26 @@ 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;
 
+               DRM_DEBUG_KMS("disabling [CRTC:%d]\n",
+                             crtc->base.id);
+
+
                /* Right function depends upon target state. */
-               if (crtc->state->enable)
+               if (crtc->state->enable && funcs->prepare)
                        funcs->prepare(crtc);
                else if (funcs->disable)
                        funcs->disable(crtc);
@@ -684,8 +723,12 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
 
                funcs = crtc->helper_private;
 
-               if (crtc->state->enable)
+               if (crtc->state->enable) {
+                       DRM_DEBUG_KMS("modeset on [CRTC:%d]\n",
+                                     crtc->base.id);
+
                        funcs->mode_set_nofb(crtc);
+               }
        }
 
        for (i = 0; i < old_state->num_connector; i++) {
@@ -706,6 +749,12 @@ 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;
+
+               DRM_DEBUG_KMS("modeset on [ENCODER:%d:%s]\n",
+                             encoder->base.id, encoder->name);
+
                /*
                 * Each encoder has at most one connector (since we always steal
                 * it away), so we won't call call mode_set hooks twice.
@@ -758,13 +807,23 @@ 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;
 
-               if (crtc->state->enable)
-                       funcs->commit(crtc);
+               if (crtc->state->enable) {
+                       DRM_DEBUG_KMS("enabling [CRTC:%d]\n",
+                                     crtc->base.id);
+
+                       if (funcs->enable)
+                               funcs->enable(crtc);
+                       else
+                               funcs->commit(crtc);
+               }
        }
 
        for (i = 0; i < old_state->num_connector; i++) {
@@ -777,9 +836,15 @@ 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;
 
+               DRM_DEBUG_KMS("enabling [ENCODER:%d:%s]\n",
+                             encoder->base.id, encoder->name);
+
                /*
                 * Each encoder has at most one connector (since we always steal
                 * it away), so we won't call call enable hooks twice.
@@ -787,7 +852,10 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
                if (encoder->bridge)
                        encoder->bridge->funcs->pre_enable(encoder->bridge);
 
-               funcs->commit(encoder);
+               if (funcs->enable)
+                       funcs->enable(encoder);
+               else
+                       funcs->commit(encoder);
 
                if (encoder->bridge)
                        encoder->bridge->funcs->enable(encoder->bridge);
@@ -877,6 +945,11 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
                if (!crtc->state->enable)
                        continue;
 
+               /* Legacy cursor ioctls are completely unsynced, and userspace
+                * relies on that (by doing tons of cursor updates). */
+               if (old_state->legacy_cursor_update)
+                       continue;
+
                if (!framebuffer_changed(dev, old_state, crtc))
                        continue;
 
@@ -1310,6 +1383,9 @@ retry:
        if (ret != 0)
                goto fail;
 
+       if (plane == crtc->cursor)
+               state->legacy_cursor_update = true;
+
        /* Driver takes ownership of state on successful commit. */
        return 0;
 fail:
@@ -1385,6 +1461,9 @@ retry:
        plane_state->src_h = 0;
        plane_state->src_w = 0;
 
+       if (plane == plane->crtc->cursor)
+               state->legacy_cursor_update = true;
+
        ret = drm_atomic_commit(state);
        if (ret != 0)
                goto fail;
@@ -1534,6 +1613,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)
@@ -1548,6 +1628,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);
@@ -1859,6 +1940,83 @@ backoff:
 }
 EXPORT_SYMBOL(drm_atomic_helper_page_flip);
 
+/**
+ * drm_atomic_helper_connector_dpms() - connector dpms helper implementation
+ * @connector: affected connector
+ * @mode: DPMS mode
+ *
+ * This is the main helper function provided by the atomic helper framework for
+ * implementing the legacy DPMS connector interface. It computes the new desired
+ * ->active state for the corresponding CRTC (if the connector is enabled) and
+ *  updates it.
+ */
+void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
+                                     int mode)
+{
+       struct drm_mode_config *config = &connector->dev->mode_config;
+       struct drm_atomic_state *state;
+       struct drm_crtc_state *crtc_state;
+       struct drm_crtc *crtc;
+       struct drm_connector *tmp_connector;
+       int ret;
+       bool active = false;
+
+       if (mode != DRM_MODE_DPMS_ON)
+               mode = DRM_MODE_DPMS_OFF;
+
+       connector->dpms = mode;
+       crtc = connector->state->crtc;
+
+       if (!crtc)
+               return;
+
+       /* FIXME: ->dpms has no return value so can't forward the -ENOMEM. */
+       state = drm_atomic_state_alloc(connector->dev);
+       if (!state)
+               return;
+
+       state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+       crtc_state = drm_atomic_get_crtc_state(state, crtc);
+       if (IS_ERR(crtc_state))
+               return;
+
+       WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
+
+       list_for_each_entry(tmp_connector, &config->connector_list, head) {
+               if (connector->state->crtc != crtc)
+                       continue;
+
+               if (connector->dpms == DRM_MODE_DPMS_ON) {
+                       active = true;
+                       break;
+               }
+       }
+       crtc_state->active = active;
+
+       ret = drm_atomic_commit(state);
+       if (ret != 0)
+               goto fail;
+
+       /* Driver takes ownership of state on successful async commit. */
+       return;
+fail:
+       if (ret == -EDEADLK)
+               goto backoff;
+
+       drm_atomic_state_free(state);
+
+       WARN(1, "Driver bug: Changing ->active failed with ret=%i\n", ret);
+
+       return;
+backoff:
+       drm_atomic_state_clear(state);
+       drm_atomic_legacy_backoff(state);
+
+       goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
+
 /**
  * DOC: atomic state reset and initialization
  *
@@ -1910,6 +2068,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;
        }
index ad2934ba0bd2acd766c6044af16e831d00e79ce4..b459888f63104b03fe170c3b89c112f959094472 100644 (file)
@@ -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);
@@ -1481,6 +1485,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;
 }
 
@@ -3810,7 +3820,7 @@ static struct drm_property *property_create_range(struct drm_device *dev,
 }
 
 /**
- * drm_property_create_range - create a new ranged property type
+ * drm_property_create_range - create a new unsigned ranged property type
  * @dev: drm device
  * @flags: flags specifying the property type
  * @name: name of the property
@@ -3821,8 +3831,8 @@ static struct drm_property *property_create_range(struct drm_device *dev,
  * object with drm_object_attach_property. The returned property object must be
  * freed with drm_property_destroy.
  *
- * Userspace is allowed to set any integer value in the (min, max) range
- * inclusive.
+ * Userspace is allowed to set any unsigned integer value in the (min, max)
+ * range inclusive.
  *
  * Returns:
  * A pointer to the newly created property on success, NULL on failure.
@@ -3836,6 +3846,24 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags
 }
 EXPORT_SYMBOL(drm_property_create_range);
 
+/**
+ * drm_property_create_signed_range - create a new signed ranged property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @min: minimum value of the property
+ * @max: maximum value of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Userspace is allowed to set any signed integer value in the (min, max)
+ * range inclusive.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
 struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
                                         int flags, const char *name,
                                         int64_t min, int64_t max)
@@ -3845,6 +3873,23 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_property_create_signed_range);
 
+/**
+ * drm_property_create_object - create a new object property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @type: object type from DRM_MODE_OBJECT_* defines
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Userspace is only allowed to set this to any property value of the given
+ * @type. Only useful for atomic properties, which is enforced.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
 struct drm_property *drm_property_create_object(struct drm_device *dev,
                                         int flags, const char *name, uint32_t type)
 {
@@ -3852,6 +3897,9 @@ struct drm_property *drm_property_create_object(struct drm_device *dev,
 
        flags |= DRM_MODE_PROP_OBJECT;
 
+       if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
+               return NULL;
+
        property = drm_property_create(dev, flags, name, 1);
        if (!property)
                return NULL;
@@ -3862,6 +3910,28 @@ struct drm_property *drm_property_create_object(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_property_create_object);
 
+/**
+ * drm_property_create_bool - create a new boolean property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * This is implemented as a ranged property with only {0, 1} as valid values.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
+struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
+                                        const char *name)
+{
+       return drm_property_create_range(dev, flags, name, 0, 1);
+}
+EXPORT_SYMBOL(drm_property_create_bool);
+
 /**
  * drm_property_add_enum - add a possible value to an enumeration property
  * @property: enumeration property to change
index 4dcdcad9f16d2f65ad55bf279b9ec205cebcbc1b..5ba5792bfdbabd920b5678740a1930f1d90ace2b 100644 (file)
@@ -435,7 +435,8 @@ int drm_plane_helper_commit(struct drm_plane *plane,
                        goto out;
        }
 
-       if (plane_funcs->prepare_fb && plane_state->fb) {
+       if (plane_funcs->prepare_fb && plane_state->fb &&
+           plane_state->fb != old_fb) {
                ret = plane_funcs->prepare_fb(plane, plane_state->fb);
                if (ret)
                        goto out;
@@ -464,6 +465,13 @@ int drm_plane_helper_commit(struct drm_plane *plane,
                        crtc_funcs[i]->atomic_flush(crtc[i]);
        }
 
+       /*
+        * If we only moved the plane and didn't change fb's, there's no need to
+        * wait for vblank.
+        */
+       if (plane->state->fb == old_fb)
+               goto out;
+
        for (i = 0; i < 2; i++) {
                if (!crtc[i])
                        continue;
@@ -492,7 +500,7 @@ out:
 }
 
 /**
- * drm_plane_helper_update() - Helper for primary plane update
+ * drm_plane_helper_update() - Transitional helper for plane update
  * @plane: plane object to update
  * @crtc: owning CRTC of owning plane
  * @fb: framebuffer to flip onto plane
@@ -549,7 +557,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
 EXPORT_SYMBOL(drm_plane_helper_update);
 
 /**
- * drm_plane_helper_disable() - Helper for primary plane disable
+ * drm_plane_helper_disable() - Transitional helper for plane disable
  * @plane: plane to disable
  *
  * Provides a default plane disable handler using the atomic plane update
index a0ea4ded3cb56e5fbdb088e9f55a759a77e2b458..8039d54a7441276f8fb529d42c0c0bfc35bfb192 100644 (file)
@@ -82,6 +82,8 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
                                struct drm_framebuffer *fb,
                                struct drm_pending_vblank_event *event,
                                uint32_t flags);
+void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
+                                     int mode);
 
 /* default implementations for state handling */
 void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc);
index 0ebd9286b332aa8139bb2a96e91be9d0ebc3d4da..02614170c0345a100af800b93c51c7658b033ceb 100644 (file)
@@ -253,6 +253,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
@@ -278,6 +279,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
@@ -910,6 +912,7 @@ struct drm_bridge {
  * struct struct drm_atomic_state - the global state object for atomic updates
  * @dev: parent DRM device
  * @allow_modeset: allow full modeset
+ * @legacy_cursor_update: hint to enforce legacy cursor ioctl semantics
  * @planes: pointer to array of plane pointers
  * @plane_states: pointer to array of plane states pointers
  * @crtcs: pointer to array of CRTC pointers
@@ -922,6 +925,7 @@ struct drm_bridge {
 struct drm_atomic_state {
        struct drm_device *dev;
        bool allow_modeset : 1;
+       bool legacy_cursor_update : 1;
        struct drm_plane **planes;
        struct drm_plane_state **plane_states;
        struct drm_crtc **crtcs;
@@ -1117,6 +1121,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;
@@ -1349,6 +1354,8 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
                                         int64_t min, int64_t max);
 struct drm_property *drm_property_create_object(struct drm_device *dev,
                                         int flags, const char *name, uint32_t type);
+struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
+                                        const char *name);
 extern void drm_property_destroy(struct drm_device *dev, struct drm_property *property);
 extern int drm_property_add_enum(struct drm_property *property, int index,
                                 uint64_t value, const char *name);
index 5810c027acdcf4b35e5dd312e856c9d6846ed134..c250a22b39aba09a58aa4d7843e6ae4e7033c524 100644 (file)
@@ -58,11 +58,19 @@ enum mode_set_atomic {
  * @mode_set_base_atomic: non-blocking mode set (used for kgdb support)
  * @load_lut: load color palette
  * @disable: disable CRTC when no longer in use
+ * @enable: enable CRTC
  * @atomic_check: check for validity of an atomic state
  * @atomic_begin: begin atomic update
  * @atomic_flush: flush atomic update
  *
  * The helper operations are called by the mid-layer CRTC helper.
+ *
+ * Note that with atomic helpers @dpms, @prepare and @commit hooks are
+ * deprecated. Used @enable and @disable instead exclusively.
+ *
+ * With legacy crtc helpers there's a big semantic difference between @disable
+ * and the other hooks: @disable also needs to release any resources acquired in
+ * @mode_set (like shared PLLs).
  */
 struct drm_crtc_helper_funcs {
        /*
@@ -93,8 +101,8 @@ struct drm_crtc_helper_funcs {
        /* reload the current crtc LUT */
        void (*load_lut)(struct drm_crtc *crtc);
 
-       /* disable crtc when not in use - more explicit than dpms off */
        void (*disable)(struct drm_crtc *crtc);
+       void (*enable)(struct drm_crtc *crtc);
 
        /* atomic helpers */
        int (*atomic_check)(struct drm_crtc *crtc,
@@ -115,9 +123,17 @@ struct drm_crtc_helper_funcs {
  * @get_crtc: return CRTC that the encoder is currently attached to
  * @detect: connection status detection
  * @disable: disable encoder when not in use (overrides DPMS off)
+ * @enable: enable encoder
  * @atomic_check: check for validity of an atomic update
  *
  * The helper operations are called by the mid-layer CRTC helper.
+ *
+ * Note that with atomic helpers @dpms, @prepare and @commit hooks are
+ * deprecated. Used @enable and @disable instead exclusively.
+ *
+ * With legacy crtc helpers there's a big semantic difference between @disable
+ * and the other hooks: @disable also needs to release any resources acquired in
+ * @mode_set (like shared PLLs).
  */
 struct drm_encoder_helper_funcs {
        void (*dpms)(struct drm_encoder *encoder, int mode);
@@ -136,9 +152,10 @@ struct drm_encoder_helper_funcs {
        /* detect for DAC style encoders */
        enum drm_connector_status (*detect)(struct drm_encoder *encoder,
                                            struct drm_connector *connector);
-       /* disable encoder when not in use - more explicit than dpms off */
        void (*disable)(struct drm_encoder *encoder);
 
+       void (*enable)(struct drm_encoder *encoder);
+
        /* atomic helpers */
        int (*atomic_check)(struct drm_encoder *encoder,
                            struct drm_crtc_state *crtc_state,