drm/rockchip: dw-mipi-dsi: only request HS clock when required
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / drm_atomic.c
index aeee083c7f95064fed6c6b08cd67b58d174204af..c2d1a94fe8d4ff14f5dd868bad943531af2773ec 100644 (file)
@@ -28,6 +28,7 @@
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
+#include <drm/drm_mode.h>
 #include <drm/drm_plane_helper.h>
 
 /**
@@ -150,7 +151,7 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
        for (i = 0; i < state->num_connector; i++) {
                struct drm_connector *connector = state->connectors[i];
 
-               if (!connector)
+               if (!connector || !connector->funcs)
                        continue;
 
                /*
@@ -316,8 +317,7 @@ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state,
        if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0)
                return 0;
 
-       if (state->mode_blob)
-               drm_property_unreference_blob(state->mode_blob);
+       drm_property_unreference_blob(state->mode_blob);
        state->mode_blob = NULL;
 
        if (mode) {
@@ -363,10 +363,11 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
        if (blob == state->mode_blob)
                return 0;
 
-       if (state->mode_blob)
-               drm_property_unreference_blob(state->mode_blob);
+       drm_property_unreference_blob(state->mode_blob);
        state->mode_blob = NULL;
 
+       memset(&state->mode, 0, sizeof(state->mode));
+
        if (blob) {
                if (blob->length != sizeof(struct drm_mode_modeinfo) ||
                    drm_mode_convert_umode(&state->mode,
@@ -379,7 +380,6 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
                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);
@@ -389,6 +389,60 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state,
 }
 EXPORT_SYMBOL(drm_atomic_set_mode_prop_for_crtc);
 
+/**
+ * drm_atomic_replace_property_blob - replace a blob property
+ * @blob: a pointer to the member blob to be replaced
+ * @new_blob: the new blob to replace with
+ * @expected_size: the expected size of the new blob
+ * @replaced: whether the blob has been replaced
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+static void
+drm_atomic_replace_property_blob(struct drm_property_blob **blob,
+                                struct drm_property_blob *new_blob,
+                                bool *replaced)
+{
+       struct drm_property_blob *old_blob = *blob;
+
+       if (old_blob == new_blob)
+               return;
+
+       if (old_blob)
+               drm_property_unreference_blob(old_blob);
+       if (new_blob)
+               drm_property_reference_blob(new_blob);
+       *blob = new_blob;
+       *replaced = true;
+
+       return;
+}
+
+int
+drm_atomic_replace_property_blob_from_id(struct drm_crtc *crtc,
+                                        struct drm_property_blob **blob,
+                                        uint64_t blob_id,
+                                        ssize_t expected_size,
+                                        bool *replaced)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_property_blob *new_blob = NULL;
+
+       if (blob_id != 0) {
+               new_blob = drm_property_lookup_blob(dev, blob_id);
+               if (new_blob == NULL)
+                       return -EINVAL;
+               if (expected_size > 0 && expected_size != new_blob->length)
+                       return -EINVAL;
+       }
+
+       drm_atomic_replace_property_blob(blob, new_blob, replaced);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_atomic_replace_property_blob_from_id);
+
 /**
  * drm_atomic_crtc_set_property - set property on CRTC
  * @crtc: the drm CRTC to set a property on
@@ -411,6 +465,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct drm_mode_config *config = &dev->mode_config;
+       bool replaced = false;
        int ret;
 
        if (property == config->prop_active)
@@ -419,11 +474,33 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
                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);
+               drm_property_unreference_blob(mode);
                return ret;
-       }
-       else if (crtc->funcs->atomic_set_property)
+       } else if (property == config->degamma_lut_property) {
+               ret = drm_atomic_replace_property_blob_from_id(crtc,
+                                       &state->degamma_lut,
+                                       val,
+                                       -1,
+                                       &replaced);
+               state->color_mgmt_changed = replaced;
+               return ret;
+       } else if (property == config->ctm_property) {
+               ret = drm_atomic_replace_property_blob_from_id(crtc,
+                                       &state->ctm,
+                                       val,
+                                       sizeof(struct drm_color_ctm),
+                                       &replaced);
+               state->color_mgmt_changed = replaced;
+               return ret;
+       } else if (property == config->gamma_lut_property) {
+               ret = drm_atomic_replace_property_blob_from_id(crtc,
+                                       &state->gamma_lut,
+                                       val,
+                                       -1,
+                                       &replaced);
+               state->color_mgmt_changed = replaced;
+               return ret;
+       } else if (crtc->funcs->atomic_set_property)
                return crtc->funcs->atomic_set_property(crtc, state, property, val);
        else
                return -EINVAL;
@@ -450,6 +527,12 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc,
                *val = state->active;
        else if (property == config->prop_mode_id)
                *val = (state->mode_blob) ? state->mode_blob->base.id : 0;
+       else if (property == config->degamma_lut_property)
+               *val = (state->degamma_lut) ? state->degamma_lut->base.id : 0;
+       else if (property == config->ctm_property)
+               *val = (state->ctm) ? state->ctm->base.id : 0;
+       else if (property == config->gamma_lut_property)
+               *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0;
        else if (crtc->funcs->atomic_get_property)
                return crtc->funcs->atomic_get_property(crtc, state, property, val);
        else
@@ -751,6 +834,8 @@ static int drm_atomic_plane_check(struct drm_plane *plane,
                                 state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10,
                                 state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10,
                                 state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10);
+               DRM_DEBUG_ATOMIC("framebuffer size[%dx%d]\n",
+                                fb_width >> 16, fb_height >> 16);
                return -ENOSPC;
        }
 
@@ -1191,12 +1276,7 @@ void drm_atomic_legacy_backoff(struct drm_atomic_state *state)
 retry:
        drm_modeset_backoff(state->acquire_ctx);
 
-       ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex,
-                              state->acquire_ctx);
-       if (ret)
-               goto retry;
-       ret = drm_modeset_lock_all_crtcs(state->dev,
-                                        state->acquire_ctx);
+       ret = drm_modeset_lock_all_ctx(state->dev, state->acquire_ctx);
        if (ret)
                goto retry;
 }