]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/drm_atomic.c
Merge branches 'fixes' and 'ioremap' into for-linus
[karo-tx-linux.git] / drivers / gpu / drm / drm_atomic.c
index 3134f506b762b0ba134e71403dac505ef7098659..f6f2fb58eb37f583f6568964f9ad8aab8be75968 100644 (file)
@@ -289,6 +289,100 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
 }
 EXPORT_SYMBOL(drm_atomic_get_crtc_state);
 
+/**
+ * drm_atomic_set_mode_for_crtc - set mode for CRTC
+ * @state: the CRTC whose incoming state to update
+ * @mode: kernel-internal mode to use for the CRTC, or NULL to disable
+ *
+ * Set a mode (originating from the kernel) on the desired CRTC state. Does
+ * not change any other state properties, including enable, active, or
+ * mode_changed.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure. Cannot return -EDEADLK.
+ */
+int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
+                                struct drm_display_mode *mode)
+{
+       struct drm_mode_modeinfo umode;
+
+       /* Early return for no change. */
+       if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
+               return 0;
+
+       if (state->mode_blob)
+               drm_property_unreference_blob(state->mode_blob);
+       state->mode_blob = NULL;
+
+       if (mode) {
+               drm_mode_convert_to_umode(&umode, mode);
+               state->mode_blob =
+                       drm_property_create_blob(state->crtc->dev,
+                                                sizeof(umode),
+                                                &umode);
+               if (IS_ERR(state->mode_blob))
+                       return PTR_ERR(state->mode_blob);
+
+               drm_mode_copy(&state->mode, mode);
+               state->enable = true;
+               DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n",
+                                mode->name, state);
+       } else {
+               memset(&state->mode, 0, sizeof(state->mode));
+               state->enable = false;
+               DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n",
+                                state);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_mode_for_crtc);
+
+/**
+ * drm_atomic_set_mode_prop_for_crtc - set mode for CRTC
+ * @state: the CRTC whose incoming state to update
+ * @blob: pointer to blob property to use for mode
+ *
+ * Set a mode (originating from a blob property) on the desired CRTC state.
+ * This function will take a reference on the blob property for the CRTC state,
+ * and release the reference held on the state's existing mode property, if any
+ * was set.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure. Cannot return -EDEADLK.
+ */
+int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
+                                      struct drm_property_blob *blob)
+{
+       if (blob == state->mode_blob)
+               return 0;
+
+       if (state->mode_blob)
+               drm_property_unreference_blob(state->mode_blob);
+       state->mode_blob = NULL;
+
+       if (blob) {
+               if (blob->length != sizeof(struct drm_mode_modeinfo) ||
+                   drm_mode_convert_umode(&state->mode,
+                                          (const struct drm_mode_modeinfo *)
+                                           blob->data))
+                       return -EINVAL;
+
+               state->mode_blob = drm_property_reference_blob(blob);
+               state->enable = true;
+               DRM_DEBUG_ATOMIC("Set [MODE:%s] for CRTC state %p\n",
+                                state->mode.name, state);
+       } else {
+               memset(&state->mode, 0, sizeof(state->mode));
+               state->enable = false;
+               DRM_DEBUG_ATOMIC("Set [NOMODE] for CRTC state %p\n",
+                                state);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
+
 /**
  * drm_atomic_crtc_set_property - set property on CRTC
  * @crtc: the drm CRTC to set a property on
@@ -311,10 +405,18 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct drm_mode_config *config = &dev->mode_config;
+       int ret;
 
-       /* FIXME: Mode prop is missing, which also controls ->enable. */
        if (property == config->prop_active)
                state->active = val;
+       else if (property == config->prop_mode_id) {
+               struct drm_property_blob *mode =
+                       drm_property_lookup_blob(dev, val);
+               ret = drm_atomic_set_mode_prop_for_crtc(state, mode);
+               if (mode)
+                       drm_property_unreference_blob(mode);
+               return ret;
+       }
        else if (crtc->funcs->atomic_set_property)
                return crtc->funcs->atomic_set_property(crtc, state, property, val);
        else
@@ -339,6 +441,8 @@ int drm_atomic_crtc_get_property(struct drm_crtc *crtc,
 
        if (property == config->prop_active)
                *val = state->active;
+       else if (property == config->prop_mode_id)
+               *val = (state->mode_blob) ? state->mode_blob->base.id : 0;
        else if (crtc->funcs->atomic_get_property)
                return crtc->funcs->atomic_get_property(crtc, state, property, val);
        else
@@ -374,6 +478,23 @@ static int drm_atomic_crtc_check(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
+       /* The state->enable vs. state->mode_blob checks can be WARN_ON,
+        * as this is a kernel-internal detail that userspace should never
+        * be able to trigger. */
+       if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) &&
+           WARN_ON(state->enable && !state->mode_blob)) {
+               DRM_DEBUG_ATOMIC("[CRTC:%d] enabled without mode blob\n",
+                                crtc->base.id);
+               return -EINVAL;
+       }
+
+       if (drm_core_check_feature(crtc->dev, DRIVER_ATOMIC) &&
+           WARN_ON(!state->enable && state->mode_blob)) {
+               DRM_DEBUG_ATOMIC("[CRTC:%d] disabled with mode blob\n",
+                                crtc->base.id);
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -1095,8 +1216,7 @@ int drm_atomic_check_only(struct drm_atomic_state *state)
 
        if (!state->allow_modeset) {
                for_each_crtc_in_state(state, crtc, crtc_state, i) {
-                       if (crtc_state->mode_changed ||
-                           crtc_state->active_changed) {
+                       if (drm_atomic_crtc_needs_modeset(crtc_state)) {
                                DRM_DEBUG_ATOMIC("[CRTC:%d] requires full modeset\n",
                                                 crtc->base.id);
                                return -EINVAL;