Merge tag 'drm-next-2018-06-15' of git://anongit.freedesktop.org/drm/drm
[muen/linux.git] / drivers / gpu / drm / amd / display / amdgpu_dm / amdgpu_dm.c
index f9b9ab90558c92c223050d5c47a8547cb1d1ca06..f9add85157e7355432aab9d0d14728f8906774f9 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/moduleparam.h>
 #include <linux/version.h>
 #include <linux/types.h>
+#include <linux/pm_runtime.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_atomic.h>
@@ -2095,12 +2096,6 @@ convert_color_depth_from_display_info(const struct drm_connector *connector)
 {
        uint32_t bpc = connector->display_info.bpc;
 
-       /* Limited color depth to 8bit
-        * TODO: Still need to handle deep color
-        */
-       if (bpc > 8)
-               bpc = 8;
-
        switch (bpc) {
        case 0:
                /* Temporary Work around, DRM don't parse color depth for
@@ -2316,27 +2311,22 @@ decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode,
        }
 }
 
-static int create_fake_sink(struct amdgpu_dm_connector *aconnector)
+static struct dc_sink *
+create_fake_sink(struct amdgpu_dm_connector *aconnector)
 {
-       struct dc_sink *sink = NULL;
        struct dc_sink_init_data sink_init_data = { 0 };
-
+       struct dc_sink *sink = NULL;
        sink_init_data.link = aconnector->dc_link;
        sink_init_data.sink_signal = aconnector->dc_link->connector_signal;
 
        sink = dc_sink_create(&sink_init_data);
        if (!sink) {
                DRM_ERROR("Failed to create sink!\n");
-               return -ENOMEM;
+               return NULL;
        }
-
        sink->sink_signal = SIGNAL_TYPE_VIRTUAL;
-       aconnector->fake_enable = true;
-
-       aconnector->dc_sink = sink;
-       aconnector->dc_link->local_sink = sink;
 
-       return 0;
+       return sink;
 }
 
 static void set_multisync_trigger_params(
@@ -2399,7 +2389,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
        struct dc_stream_state *stream = NULL;
        struct drm_display_mode mode = *drm_mode;
        bool native_mode_found = false;
-
+       struct dc_sink *sink = NULL;
        if (aconnector == NULL) {
                DRM_ERROR("aconnector is NULL!\n");
                return stream;
@@ -2417,15 +2407,18 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                        return stream;
                }
 
-               if (create_fake_sink(aconnector))
+               sink = create_fake_sink(aconnector);
+               if (!sink)
                        return stream;
+       } else {
+               sink = aconnector->dc_sink;
        }
 
-       stream = dc_create_stream_for_sink(aconnector->dc_sink);
+       stream = dc_create_stream_for_sink(sink);
 
        if (stream == NULL) {
                DRM_ERROR("Failed to create stream for sink!\n");
-               return stream;
+               goto finish;
        }
 
        list_for_each_entry(preferred_mode, &aconnector->base.modes, head) {
@@ -2464,12 +2457,15 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
        fill_audio_info(
                &stream->audio_info,
                drm_connector,
-               aconnector->dc_sink);
+               sink);
 
        update_stream_signal(stream);
 
        if (dm_state && dm_state->freesync_capable)
                stream->ignore_msa_timing_param = true;
+finish:
+       if (sink && sink->sink_signal == SIGNAL_TYPE_VIRTUAL)
+               dc_sink_release(sink);
 
        return stream;
 }
@@ -2714,6 +2710,9 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
        struct dm_connector_state *state =
                to_dm_connector_state(connector->state);
 
+       if (connector->state)
+               __drm_atomic_helper_connector_destroy_state(connector->state);
+
        kfree(state);
 
        state = kzalloc(sizeof(*state), GFP_KERNEL);
@@ -2724,8 +2723,7 @@ void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
                state->underscan_hborder = 0;
                state->underscan_vborder = 0;
 
-               connector->state = &state->base;
-               connector->state->connector = connector;
+               __drm_atomic_helper_connector_reset(connector, &state->base);
        }
 }
 
@@ -3083,17 +3081,6 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
                }
        }
 
-       /* It's a hack for s3 since in 4.9 kernel filter out cursor buffer
-        * prepare and cleanup in drm_atomic_helper_prepare_planes
-        * and drm_atomic_helper_cleanup_planes because fb doens't in s3.
-        * IN 4.10 kernel this code should be removed and amdgpu_device_suspend
-        * code touching fram buffers should be avoided for DC.
-        */
-       if (plane->type == DRM_PLANE_TYPE_CURSOR) {
-               struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_state->crtc);
-
-               acrtc->cursor_bo = obj;
-       }
        return 0;
 }
 
@@ -4281,6 +4268,8 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                        if (dm_old_crtc_state->stream)
                                remove_stream(adev, acrtc, dm_old_crtc_state->stream);
 
+                       pm_runtime_get_noresume(dev->dev);
+
                        acrtc->enabled = true;
                        acrtc->hw_mode = new_crtc_state->mode;
                        crtc->hwmode = new_crtc_state->mode;
@@ -4469,6 +4458,16 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                drm_atomic_helper_wait_for_flip_done(dev, state);
 
        drm_atomic_helper_cleanup_planes(dev, state);
+
+       /* Finally, drop a runtime PM reference for each newly disabled CRTC,
+        * so we can put the GPU into runtime suspend if we're not driving any
+        * displays anymore
+        */
+       pm_runtime_mark_last_busy(dev->dev);
+       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+               if (old_crtc_state->active && !new_crtc_state->active)
+                       pm_runtime_put_autosuspend(dev->dev);
+       }
 }