drm/amdgpu_dm/crc: Implement verify_crc_source callback
[sfrench/cifs-2.6.git] / drivers / gpu / drm / amd / display / amdgpu_dm / amdgpu_dm.c
index f9b9ab90558c92c223050d5c47a8547cb1d1ca06..a5c1617e55c528e923eed2454cc632e1dc2b7982 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>
@@ -346,7 +347,6 @@ static void hotplug_notify_work_func(struct work_struct *work)
        drm_kms_helper_hotplug_event(dev);
 }
 
-#if defined(CONFIG_DRM_AMD_DC_FBC)
 /* Allocate memory for FBC compressed data  */
 static void amdgpu_dm_fbc_init(struct drm_connector *connector)
 {
@@ -387,7 +387,6 @@ static void amdgpu_dm_fbc_init(struct drm_connector *connector)
        }
 
 }
-#endif
 
 
 /* Init display KMS
@@ -901,14 +900,14 @@ amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
                                (struct edid *) sink->dc_edid.raw_edid;
 
 
-                       drm_mode_connector_update_edid_property(connector,
+                       drm_connector_update_edid_property(connector,
                                        aconnector->edid);
                }
                amdgpu_dm_add_sink_to_freesync_module(connector, aconnector->edid);
 
        } else {
                amdgpu_dm_remove_sink_from_freesync_module(connector);
-               drm_mode_connector_update_edid_property(connector, NULL);
+               drm_connector_update_edid_property(connector, NULL);
                aconnector->num_modes = 0;
                aconnector->dc_sink = NULL;
                aconnector->edid = NULL;
@@ -2095,12 +2094,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 +2309,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 +2387,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 +2405,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 +2455,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;
 }
@@ -2569,6 +2563,7 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
        .atomic_duplicate_state = dm_crtc_duplicate_state,
        .atomic_destroy_state = dm_crtc_destroy_state,
        .set_crc_source = amdgpu_dm_crtc_set_crc_source,
+       .verify_crc_source = amdgpu_dm_crtc_verify_crc_source,
        .enable_vblank = dm_enable_vblank,
        .disable_vblank = dm_disable_vblank,
 };
@@ -2714,6 +2709,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 +2722,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 +3080,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;
 }
 
@@ -3439,12 +3425,15 @@ static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
        struct edid *edid = amdgpu_dm_connector->edid;
 
        encoder = helper->best_encoder(connector);
-       amdgpu_dm_connector_ddc_get_modes(connector, edid);
-       amdgpu_dm_connector_add_common_modes(encoder, connector);
 
-#if defined(CONFIG_DRM_AMD_DC_FBC)
+       if (!edid || !drm_edid_is_valid(edid)) {
+               drm_add_modes_noedid(connector, 640, 480);
+       } else {
+               amdgpu_dm_connector_ddc_get_modes(connector, edid);
+               amdgpu_dm_connector_add_common_modes(encoder, connector);
+       }
        amdgpu_dm_fbc_init(connector);
-#endif
+
        return amdgpu_dm_connector->num_modes;
 }
 
@@ -3627,7 +3616,7 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
                link,
                link_index);
 
-       drm_mode_connector_attach_encoder(
+       drm_connector_attach_encoder(
                &aconnector->base, &aencoder->base);
 
        drm_connector_register(&aconnector->base);
@@ -3927,8 +3916,6 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
 
        /* Flip */
        spin_lock_irqsave(&crtc->dev->event_lock, flags);
-       /* update crtc fb */
-       crtc->primary->fb = fb;
 
        WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE);
        WARN_ON(!acrtc_state->stream);
@@ -3941,10 +3928,11 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
        if (acrtc->base.state->event)
                prepare_flip_isr(acrtc);
 
+       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
        surface_updates->surface = dc_stream_get_status(acrtc_state->stream)->plane_states[0];
        surface_updates->flip_addr = &addr;
 
-
        dc_commit_updates_for_stream(adev->dm.dc,
                                             surface_updates,
                                             1,
@@ -3957,9 +3945,6 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
                         __func__,
                         addr.address.grph.addr.high_part,
                         addr.address.grph.addr.low_part);
-
-
-       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 }
 
 /*
@@ -4219,6 +4204,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
        struct drm_connector *connector;
        struct drm_connector_state *old_con_state, *new_con_state;
        struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
+       int crtc_disable_count = 0;
 
        drm_atomic_helper_update_legacy_modeset_state(dev, state);
 
@@ -4281,6 +4267,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;
@@ -4421,6 +4409,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
                bool modeset_needed;
 
+               if (old_crtc_state->active && !new_crtc_state->active)
+                       crtc_disable_count++;
+
                dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
                dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
                modeset_needed = modeset_required(
@@ -4469,6 +4460,14 @@ 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
+        */
+       for (i = 0; i < crtc_disable_count; i++)
+               pm_runtime_put_autosuspend(dev->dev);
+       pm_runtime_mark_last_busy(dev->dev);
 }