From: Jimmy Kizito <jimmy.kiz...@amd.com>

[Why]
While applying a state to hardware, there is a transition period where
the back-end is reset using the old state; then enabled using the new
state.

Generally, the link encoder configuration module queries
stream-to-encoder assignments in either the new or old state based on a
mode variable. During the transition there is a need to query both
states, however toggling this mode variable can lead to incorrect
programming of encoders.

[How]
- Add new function to explicity query stream-to-encoder assignment
in the current state rather than intermittently switch the mode
of operation of the link encoder assignment module.
- Add additional checks for encoder assignment defects.
- Explicitly reset the mode of operation if application of state
to hardware ends prematurely.

Acked-by: Rodrigo Siqueira <rodrigo.sique...@amd.com>
Signed-off-by: Jimmy Kizito <jimmy.kiz...@amd.com>
---
 drivers/gpu/drm/amd/display/dc/core/dc.c      |  5 ++-
 .../drm/amd/display/dc/core/dc_link_enc_cfg.c | 32 +++++++++++++++++++
 .../gpu/drm/amd/display/dc/core/dc_resource.c |  7 ++--
 .../gpu/drm/amd/display/dc/inc/link_enc_cfg.h |  5 +++
 4 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c 
b/drivers/gpu/drm/amd/display/dc/core/dc.c
index 34a3e1eeb5c4..8ed208e5def2 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -1750,8 +1750,11 @@ static enum dc_status dc_commit_state_no_check(struct dc 
*dc, struct dc_state *c
 
        result = dc->hwss.apply_ctx_to_hw(dc, context);
 
-       if (result != DC_OK)
+       if (result != DC_OK) {
+               /* Application of dc_state to hardware stopped. */
+               dc->current_state->res_ctx.link_enc_cfg_ctx.mode = 
LINK_ENC_CFG_STEADY;
                return result;
+       }
 
        dc_trigger_sync(dc, context);
 
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c 
b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c
index 639a0a276a08..614f022d1cff 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c
@@ -292,6 +292,7 @@ void link_enc_cfg_link_encs_assign(
        int j;
 
        ASSERT(state->stream_count == stream_count);
+       ASSERT(dc->current_state->res_ctx.link_enc_cfg_ctx.mode == 
LINK_ENC_CFG_STEADY);
 
        /* Release DIG link encoder resources before running assignment 
algorithm. */
        for (i = 0; i < dc->current_state->stream_count; i++)
@@ -561,6 +562,31 @@ struct link_encoder *link_enc_cfg_get_link_enc(
        return link_enc;
 }
 
+struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream_current(
+               struct dc *dc,
+               const struct dc_stream_state *stream)
+{
+       struct link_encoder *link_enc = NULL;
+       struct display_endpoint_id ep_id;
+       int i;
+
+       ep_id = (struct display_endpoint_id) {
+               .link_id = stream->link->link_id,
+               .ep_type = stream->link->ep_type};
+
+       for (i = 0; i < MAX_PIPES; i++) {
+               struct link_enc_assignment assignment =
+                       
dc->current_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i];
+
+               if (assignment.valid == true && 
are_ep_ids_equal(&assignment.ep_id, &ep_id)) {
+                       link_enc = 
stream->link->dc->res_pool->link_encoders[assignment.eng_id - ENGINE_ID_DIGA];
+                       break;
+               }
+       }
+
+       return link_enc;
+}
+
 bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id, 
struct dc_link *link)
 {
        bool is_avail = true;
@@ -595,6 +621,7 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state 
*state)
        uint8_t dig_stream_count = 0;
        int matching_stream_ptrs = 0;
        int eng_ids_per_ep_id[MAX_PIPES] = {0};
+       int ep_ids_per_eng_id[MAX_PIPES] = {0};
        int valid_bitmap = 0;
 
        /* (1) No. valid entries same as stream count. */
@@ -630,6 +657,7 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state 
*state)
                        struct display_endpoint_id ep_id_i = assignment_i.ep_id;
 
                        eng_ids_per_ep_id[i]++;
+                       ep_ids_per_eng_id[i]++;
                        for (j = 0; j < MAX_PIPES; j++) {
                                struct link_enc_assignment assignment_j =
                                        
state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j];
@@ -644,6 +672,10 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state 
*state)
                                                        assignment_i.eng_id != 
assignment_j.eng_id) {
                                                valid_uniqueness = false;
                                                eng_ids_per_ep_id[i]++;
+                                       } else if (!are_ep_ids_equal(&ep_id_i, 
&ep_id_j) &&
+                                                       assignment_i.eng_id == 
assignment_j.eng_id) {
+                                               valid_uniqueness = false;
+                                               ep_ids_per_eng_id[i]++;
                                        }
                                }
                        }
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c 
b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index 332110bb1286..b67fdb31f75f 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -3015,12 +3015,11 @@ bool pipe_need_reprogram(
        if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
                bool need_reprogram = false;
                struct dc *dc = pipe_ctx_old->stream->ctx->dc;
-               enum link_enc_cfg_mode mode = 
dc->current_state->res_ctx.link_enc_cfg_ctx.mode;
+               struct link_encoder *link_enc_prev =
+                       link_enc_cfg_get_link_enc_used_by_stream_current(dc, 
pipe_ctx_old->stream);
 
-               dc->current_state->res_ctx.link_enc_cfg_ctx.mode = 
LINK_ENC_CFG_STEADY;
-               if (link_enc_cfg_get_link_enc_used_by_stream(dc, 
pipe_ctx_old->stream) != pipe_ctx->stream->link_enc)
+               if (link_enc_prev != pipe_ctx->stream->link_enc)
                        need_reprogram = true;
-               dc->current_state->res_ctx.link_enc_cfg_ctx.mode = mode;
 
                return need_reprogram;
        }
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h 
b/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h
index 7beb14169f92..dc650be3837e 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h
@@ -104,6 +104,11 @@ struct link_encoder 
*link_enc_cfg_get_link_enc_used_by_stream(
 /* Return DIG link encoder. NULL if unused. */
 struct link_encoder *link_enc_cfg_get_link_enc(const struct dc_link *link);
 
+/* Return DIG link encoder used by stream in current/previous state. NULL if 
unused. */
+struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream_current(
+               struct dc *dc,
+               const struct dc_stream_state *stream);
+
 /* Return true if encoder available to use. */
 bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id, 
struct dc_link *link);
 
-- 
2.25.1

Reply via email to