drm/amd/display: Add flag to detect dpms force off during HPD
authorAurabindo Pillai <aurabindo.pillai@amd.com>
Fri, 13 Aug 2021 19:15:03 +0000 (15:15 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 14 Sep 2021 19:57:09 +0000 (15:57 -0400)
[Why] When a connector is unplugged, dpms is forced off so that some
connector allocations are cleared off. This is done outside the commit
sequence from the userspace. This causes HUBP blank. Due to the blank
hubp, a non blocking commit which queues flip will encounter a timeout
waiting for the flip_done because prior to writing the surface flip
address, hubp was in blank.

[How] Add a marker to DM's crtc state and use this field to indicate
whether dpms was forced off during an HPD. Check for this marker before
queuing the flip.

Reviewed-by: Anson Jacob <Anson.Jacob@amd.com>
Acked-by: Mikita Lipski <mikita.lipski@amd.com>
Signed-off-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c

index a8bc3ff8d9f1c9eb4933c934959a178e964c1e98..283d660a0a66f515226f684b4d9ebc8b67d931d5 100644 (file)
@@ -2409,7 +2409,7 @@ cleanup:
        return;
 }
 
-static void dm_set_dpms_off(struct dc_link *link)
+static void dm_set_dpms_off(struct dc_link *link, struct dm_crtc_state *acrtc_state)
 {
        struct dc_stream_state *stream_state;
        struct amdgpu_dm_connector *aconnector = link->priv;
@@ -2430,6 +2430,7 @@ static void dm_set_dpms_off(struct dc_link *link)
        }
 
        stream_update.stream = stream_state;
+       acrtc_state->force_dpms_off = true;
        dc_commit_updates_for_stream(stream_state->ctx->dc, NULL, 0,
                                     stream_state, &stream_update,
                                     stream_state->ctx->dc->current_state);
@@ -2873,13 +2874,16 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
        struct drm_device *dev = connector->dev;
        enum dc_connection_type new_connection_type = dc_connection_none;
        struct amdgpu_device *adev = drm_to_adev(dev);
-#ifdef CONFIG_DRM_AMD_DC_HDCP
        struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state);
-#endif
+       struct dm_crtc_state *dm_crtc_state = NULL;
 
        if (adev->dm.disable_hpd_irq)
                return;
 
+       if (dm_con_state->base.state && dm_con_state->base.crtc)
+               dm_crtc_state = to_dm_crtc_state(drm_atomic_get_crtc_state(
+                                       dm_con_state->base.state,
+                                       dm_con_state->base.crtc));
        /*
         * In case of failure or MST no need to update connector status or notify the OS
         * since (for MST case) MST does this in its own context.
@@ -2911,8 +2915,9 @@ static void handle_hpd_irq_helper(struct amdgpu_dm_connector *aconnector)
 
        } else if (dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD)) {
                if (new_connection_type == dc_connection_none &&
-                   aconnector->dc_link->type == dc_connection_none)
-                       dm_set_dpms_off(aconnector->dc_link);
+                   aconnector->dc_link->type == dc_connection_none &&
+                   dm_crtc_state)
+                       dm_set_dpms_off(aconnector->dc_link, dm_crtc_state);
 
                amdgpu_dm_update_connector_after_detect(aconnector);
 
@@ -6253,6 +6258,7 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)
        state->freesync_config = cur->freesync_config;
        state->cm_has_degamma = cur->cm_has_degamma;
        state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb;
+       state->force_dpms_off = cur->force_dpms_off;
        /* TODO Duplicate dc_stream after objects are stream object is flattened */
 
        return &state->base;
@@ -8916,7 +8922,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
                 * and rely on sending it from software.
                 */
                if (acrtc_attach->base.state->event &&
-                   acrtc_state->active_planes > 0) {
+                   acrtc_state->active_planes > 0 &&
+                   !acrtc_state->force_dpms_off) {
                        drm_crtc_vblank_get(pcrtc);
 
                        spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
index a038c70037b5bbad0d6c50ebffddd34c805cfe8e..a85b09986aabd8c3e5d7a20e930e54117bb6da2d 100644 (file)
@@ -629,6 +629,8 @@ struct dm_crtc_state {
 
        bool dsc_force_changed;
        bool vrr_supported;
+
+       bool force_dpms_off;
        struct mod_freesync_config freesync_config;
        struct dc_info_packet vrr_infopacket;
 
index c5f1dc3b5961432bcf48b267c99bf02709dd740a..c5f61be1f6b581772d2ff2d0af19293b5a690194 100644 (file)
@@ -448,6 +448,10 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
        struct mod_hdcp_display *display = &hdcp_work[link_index].display;
        struct mod_hdcp_link *link = &hdcp_work[link_index].link;
        struct drm_connector_state *conn_state;
+       struct dc_sink *sink = NULL;
+#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
+       bool link_is_hdcp14 = false;
+#endif
 
        if (config->dpms_off) {
                hdcp_remove_display(hdcp_work, link_index, aconnector);
@@ -460,8 +464,13 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
        display->index = aconnector->base.index;
        display->state = MOD_HDCP_DISPLAY_ACTIVE;
 
-       if (aconnector->dc_sink != NULL)
-               link->mode = mod_hdcp_signal_type_to_operation_mode(aconnector->dc_sink->sink_signal);
+       if (aconnector->dc_sink)
+               sink = aconnector->dc_sink;
+       else if (aconnector->dc_em_sink)
+               sink = aconnector->dc_em_sink;
+
+       if (sink != NULL)
+               link->mode = mod_hdcp_signal_type_to_operation_mode(sink->sink_signal);
 
        display->controller = CONTROLLER_ID_D0 + config->otg_inst;
        display->dig_fe = config->dig_fe;
@@ -470,8 +479,9 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
        display->stream_enc_idx = config->stream_enc_idx;
        link->link_enc_idx = config->link_enc_idx;
        link->phy_idx = config->phy_idx;
-       link->hdcp_supported_informational = dc_link_is_hdcp14(aconnector->dc_link,
-                       aconnector->dc_sink->sink_signal) ? 1 : 0;
+       if (sink)
+               link_is_hdcp14 = dc_link_is_hdcp14(aconnector->dc_link, sink->sink_signal);
+       link->hdcp_supported_informational = link_is_hdcp14;
        link->dp.rev = aconnector->dc_link->dpcd_caps.dpcd_rev.raw;
        link->dp.assr_enabled = config->assr_enabled;
        link->dp.mst_enabled = config->mst_enabled;