Merge branch 'drm-next-5.1' of git://people.freedesktop.org/~agd5f/linux into drm...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / display / amdgpu_dm / amdgpu_dm.c
index 2f26581b93ff5c4bacf77f3ca9d5619a2d979e32..fb27783d7a542d565e1c002d03fc051d055039be 100644 (file)
@@ -886,6 +886,7 @@ static void emulated_link_detect(struct dc_link *link)
                return;
        }
 
+       /* dc_sink_create returns a new reference */
        link->local_sink = sink;
 
        edid_status = dm_helpers_read_local_edid(
@@ -952,6 +953,8 @@ static int dm_resume(void *handle)
                if (aconnector->fake_enable && aconnector->dc_link->local_sink)
                        aconnector->fake_enable = false;
 
+               if (aconnector->dc_sink)
+                       dc_sink_release(aconnector->dc_sink);
                aconnector->dc_sink = NULL;
                amdgpu_dm_update_connector_after_detect(aconnector);
                mutex_unlock(&aconnector->hpd_lock);
@@ -1061,6 +1064,8 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
 
 
        sink = aconnector->dc_link->local_sink;
+       if (sink)
+               dc_sink_retain(sink);
 
        /*
         * Edid mgmt connector gets first update only in mode_valid hook and then
@@ -1085,21 +1090,24 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
                                 * to it anymore after disconnect, so on next crtc to connector
                                 * reshuffle by UMD we will get into unwanted dc_sink release
                                 */
-                               if (aconnector->dc_sink != aconnector->dc_em_sink)
-                                       dc_sink_release(aconnector->dc_sink);
+                               dc_sink_release(aconnector->dc_sink);
                        }
                        aconnector->dc_sink = sink;
+                       dc_sink_retain(aconnector->dc_sink);
                        amdgpu_dm_update_freesync_caps(connector,
                                        aconnector->edid);
                } else {
                        amdgpu_dm_update_freesync_caps(connector, NULL);
-                       if (!aconnector->dc_sink)
+                       if (!aconnector->dc_sink) {
                                aconnector->dc_sink = aconnector->dc_em_sink;
-                       else if (aconnector->dc_sink != aconnector->dc_em_sink)
                                dc_sink_retain(aconnector->dc_sink);
+                       }
                }
 
                mutex_unlock(&dev->mode_config.mutex);
+
+               if (sink)
+                       dc_sink_release(sink);
                return;
        }
 
@@ -1107,8 +1115,10 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
         * TODO: temporary guard to look for proper fix
         * if this sink is MST sink, we should not do anything
         */
-       if (sink && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
+       if (sink && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
+               dc_sink_release(sink);
                return;
+       }
 
        if (aconnector->dc_sink == sink) {
                /*
@@ -1117,6 +1127,8 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
                 */
                DRM_DEBUG_DRIVER("DCHPD: connector_id=%d: dc_sink didn't change.\n",
                                aconnector->connector_id);
+               if (sink)
+                       dc_sink_release(sink);
                return;
        }
 
@@ -1138,6 +1150,7 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
                        amdgpu_dm_update_freesync_caps(connector, NULL);
 
                aconnector->dc_sink = sink;
+               dc_sink_retain(aconnector->dc_sink);
                if (sink->dc_edid.length == 0) {
                        aconnector->edid = NULL;
                        drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux);
@@ -1158,11 +1171,15 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
                amdgpu_dm_update_freesync_caps(connector, NULL);
                drm_connector_update_edid_property(connector, NULL);
                aconnector->num_modes = 0;
+               dc_sink_release(aconnector->dc_sink);
                aconnector->dc_sink = NULL;
                aconnector->edid = NULL;
        }
 
        mutex_unlock(&dev->mode_config.mutex);
+
+       if (sink)
+               dc_sink_release(sink);
 }
 
 static void handle_hpd_irq(void *param)
@@ -2977,6 +2994,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
                        return stream;
        } else {
                sink = aconnector->dc_sink;
+               dc_sink_retain(sink);
        }
 
        stream = dc_create_stream_for_sink(sink);
@@ -3042,8 +3060,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
        update_stream_signal(stream, sink);
 
 finish:
-       if (sink && sink->sink_signal == SIGNAL_TYPE_VIRTUAL && aconnector->base.force != DRM_FORCE_ON)
-               dc_sink_release(sink);
+       dc_sink_release(sink);
 
        return stream;
 }
@@ -3301,6 +3318,14 @@ static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
                dm->backlight_dev = NULL;
        }
 #endif
+
+       if (aconnector->dc_em_sink)
+               dc_sink_release(aconnector->dc_em_sink);
+       aconnector->dc_em_sink = NULL;
+       if (aconnector->dc_sink)
+               dc_sink_release(aconnector->dc_sink);
+       aconnector->dc_sink = NULL;
+
        drm_dp_cec_unregister_connector(&aconnector->dm_dp_aux.aux);
        drm_connector_unregister(connector);
        drm_connector_cleanup(connector);
@@ -3398,10 +3423,12 @@ static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
                (edid->extensions + 1) * EDID_LENGTH,
                &init_params);
 
-       if (aconnector->base.force == DRM_FORCE_ON)
+       if (aconnector->base.force == DRM_FORCE_ON) {
                aconnector->dc_sink = aconnector->dc_link->local_sink ?
                aconnector->dc_link->local_sink :
                aconnector->dc_em_sink;
+               dc_sink_retain(aconnector->dc_sink);
+       }
 }
 
 static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)