]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
drm/amd/display: support dynamic HPO DP link encoder allocation
authorWenjing Liu <wenjing.liu@amd.com>
Mon, 29 Nov 2021 19:43:02 +0000 (14:43 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 30 Dec 2021 13:54:45 +0000 (08:54 -0500)
[why]
When there are more DP2.0 RXs connected than the number HPO DP link
encoders we have, we need to dynamically allocate HPO DP link encoder to
the port that needs it.

[how]
Only allocate HPO DP link encoder when it is needed.

Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Reviewed-by: Jun Lei <Jun.Lei@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
12 files changed:
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_debug.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_link_encoder.h
drivers/gpu/drm/amd/display/dc/inc/core_status.h
drivers/gpu/drm/amd/display/dc/inc/core_types.h
drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
drivers/gpu/drm/amd/display/dc/inc/resource.h

index c250f6de5136e1832a556b2eda275d8cfaab8011..91c4874473d620b9d865ea7e939dc5b0847bc882 100644 (file)
@@ -274,24 +274,6 @@ static bool create_links(
                        goto failed_alloc;
                }
 
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-               if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) &&
-                               dc->caps.dp_hpo &&
-                               link->dc->res_pool->res_cap->num_hpo_dp_link_encoder > 0) {
-                       /* FPGA case - Allocate HPO DP link encoder */
-                       if (i < link->dc->res_pool->res_cap->num_hpo_dp_link_encoder) {
-                               link->hpo_dp_link_enc = link->dc->res_pool->hpo_dp_link_enc[i];
-
-                               if (link->hpo_dp_link_enc == NULL) {
-                                       BREAK_TO_DEBUGGER();
-                                       goto failed_alloc;
-                               }
-                               link->hpo_dp_link_enc->hpd_source = link->link_enc->hpd_source;
-                               link->hpo_dp_link_enc->transmitter = link->link_enc->transmitter;
-                       }
-               }
-#endif
-
                link->link_status.dpcd_caps = &link->dpcd_caps;
 
                enc_init.ctx = dc->ctx;
index 21be2a684393a625efd6d104731380f212c2068f..643762542e4d8c6c7734199dfc207f50978065fe 100644 (file)
@@ -422,6 +422,8 @@ char *dc_status_to_str(enum dc_status status)
                return "The operation is not supported.";
        case DC_UNSUPPORTED_VALUE:
                return "The value specified is not supported.";
+       case DC_NO_LINK_ENC_RESOURCE:
+               return "No link encoder resource";
        case DC_ERROR_UNEXPECTED:
                return "Unexpected error";
        }
index 9197dd73c6d2b157be22ecd9a43096f0d07780ca..c5d3e2417ef64e7d5755132071ffdb8339bd0f29 100644 (file)
 /*******************************************************************************
  * Private functions
  ******************************************************************************/
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-static bool add_dp_hpo_link_encoder_to_link(struct dc_link *link)
-{
-       struct hpo_dp_link_encoder *enc = resource_get_unused_hpo_dp_link_encoder(
-                                       link->dc->res_pool);
-
-       if (!link->hpo_dp_link_enc && enc) {
-               link->hpo_dp_link_enc = enc;
-               link->hpo_dp_link_enc->transmitter = link->link_enc->transmitter;
-               link->hpo_dp_link_enc->hpd_source = link->link_enc->hpd_source;
-       }
-
-       return (link->hpo_dp_link_enc != NULL);
-}
-
-static void remove_dp_hpo_link_encoder_from_link(struct dc_link *link)
-{
-       if (link->hpo_dp_link_enc) {
-               link->hpo_dp_link_enc->hpd_source = HPD_SOURCEID_UNKNOWN;
-               link->hpo_dp_link_enc->transmitter = TRANSMITTER_UNKNOWN;
-               link->hpo_dp_link_enc = NULL;
-       }
-}
-#endif
-
 static void dc_link_destruct(struct dc_link *link)
 {
        int i;
@@ -118,12 +93,6 @@ static void dc_link_destruct(struct dc_link *link)
                link->link_enc->funcs->destroy(&link->link_enc);
        }
 
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-       if (link->hpo_dp_link_enc) {
-               remove_dp_hpo_link_encoder_from_link(link);
-       }
-#endif
-
        if (link->local_sink)
                dc_sink_release(link->local_sink);
 
@@ -975,10 +944,11 @@ static bool dc_link_detect_helper(struct dc_link *link,
                        }
 
 #if defined(CONFIG_DRM_AMD_DC_DCN)
-                       if (dp_get_link_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING) {
-                               add_dp_hpo_link_encoder_to_link(link);
-                               link_res.hpo_dp_link_enc = link->hpo_dp_link_enc;
-                       }
+                       if (dp_get_link_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING)
+                               link_res.hpo_dp_link_enc = resource_get_hpo_dp_link_enc_for_det_lt(
+                                               &link->dc->current_state->res_ctx,
+                                               link->dc->res_pool,
+                                               link);
 #endif
 
                        if (link->type == dc_connection_mst_branch) {
@@ -4083,7 +4053,8 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
                        config.link_enc_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
                if (is_dp_128b_132b_signal(pipe_ctx)) {
                        config.stream_enc_idx = pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0;
-                       config.link_enc_idx = pipe_ctx->stream->link->hpo_dp_link_enc->inst;
+
+                       config.link_enc_idx = pipe_ctx->link_res.hpo_dp_link_enc->inst;
                        config.dp2_enabled = 1;
                }
 #endif
index dd69e8f22e75ab6b871e01b2fa0e61b06595570d..45d03d3a95c30233529371a18f79f52c1e8a5b74 100644 (file)
@@ -800,7 +800,8 @@ void enable_dp_hpo_output(struct dc_link *link,
                link_res->hpo_dp_link_enc->funcs->enable_link_phy(
                                link_res->hpo_dp_link_enc,
                                link_settings,
-                               link->link_enc->transmitter);
+                               link->link_enc->transmitter,
+                               link->link_enc->hpd_source);
        }
 
        /* DCCG muxing and DTBCLK DTO */
index 60a9eb6e521fdc9b258382db098466b00b91ab52..eaeef72773f6947f6fd4f490406163c475a4c037 100644 (file)
@@ -1724,6 +1724,94 @@ static void update_hpo_dp_stream_engine_usage(
                        res_ctx->is_hpo_dp_stream_enc_acquired[i] = acquired;
        }
 }
+
+static inline int find_acquired_hpo_dp_link_enc_for_link(
+               const struct resource_context *res_ctx,
+               const struct dc_link *link)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_to_link_idx); i++)
+               if (res_ctx->hpo_dp_link_enc_ref_cnts[i] > 0 &&
+                               res_ctx->hpo_dp_link_enc_to_link_idx[i] == link->link_index)
+                       return i;
+
+       return -1;
+}
+
+static inline int find_free_hpo_dp_link_enc(const struct resource_context *res_ctx,
+               const struct resource_pool *pool)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts); i++)
+               if (res_ctx->hpo_dp_link_enc_ref_cnts[i] == 0)
+                       break;
+
+       return (i < ARRAY_SIZE(res_ctx->hpo_dp_link_enc_ref_cnts) &&
+                       i < pool->hpo_dp_link_enc_count) ? i : -1;
+}
+
+static inline void acquire_hpo_dp_link_enc(
+               struct resource_context *res_ctx,
+               unsigned int link_index,
+               int enc_index)
+{
+       res_ctx->hpo_dp_link_enc_to_link_idx[enc_index] = link_index;
+       res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] = 1;
+}
+
+static inline void retain_hpo_dp_link_enc(
+               struct resource_context *res_ctx,
+               int enc_index)
+{
+       res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]++;
+}
+
+static inline void release_hpo_dp_link_enc(
+               struct resource_context *res_ctx,
+               int enc_index)
+{
+       ASSERT(res_ctx->hpo_dp_link_enc_ref_cnts[enc_index] > 0);
+       res_ctx->hpo_dp_link_enc_ref_cnts[enc_index]--;
+}
+
+static bool add_hpo_dp_link_enc_to_ctx(struct resource_context *res_ctx,
+               const struct resource_pool *pool,
+               struct pipe_ctx *pipe_ctx,
+               struct dc_stream_state *stream)
+{
+       int enc_index;
+
+       enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
+
+       if (enc_index >= 0) {
+               retain_hpo_dp_link_enc(res_ctx, enc_index);
+       } else {
+               enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
+               if (enc_index >= 0)
+                       acquire_hpo_dp_link_enc(res_ctx, stream->link->link_index, enc_index);
+       }
+
+       if (enc_index >= 0)
+               pipe_ctx->link_res.hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
+
+       return pipe_ctx->link_res.hpo_dp_link_enc != NULL;
+}
+
+static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx,
+               struct pipe_ctx *pipe_ctx,
+               struct dc_stream_state *stream)
+{
+       int enc_index;
+
+       enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, stream->link);
+
+       if (enc_index >= 0) {
+               release_hpo_dp_link_enc(res_ctx, enc_index);
+               pipe_ctx->link_res.hpo_dp_link_enc = NULL;
+       }
+}
 #endif
 
 /* TODO: release audio object */
@@ -1886,6 +1974,7 @@ enum dc_status dc_remove_stream_from_ctx(
                        &new_ctx->res_ctx, dc->res_pool,
                        del_pipe->stream_res.hpo_dp_stream_enc,
                        false);
+               remove_hpo_dp_link_enc_from_ctx(&new_ctx->res_ctx, del_pipe, del_pipe->stream);
        }
 #endif
 
@@ -2161,7 +2250,8 @@ enum dc_status resource_map_pool_resources(
                                        &context->res_ctx, pool,
                                        pipe_ctx->stream_res.hpo_dp_stream_enc,
                                        true);
-                       pipe_ctx->link_res.hpo_dp_link_enc = stream->link->hpo_dp_link_enc;
+                       if (!add_hpo_dp_link_enc_to_ctx(&context->res_ctx, pool, pipe_ctx, stream))
+                               return DC_NO_LINK_ENC_RESOURCE;
                }
        }
 #endif
@@ -2837,6 +2927,8 @@ bool pipe_need_reprogram(
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc)
                return true;
+       if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc)
+               return true;
 #endif
 
        /* DIG link encoder resource assignment for stream changed. */
@@ -3105,22 +3197,23 @@ void get_audio_check(struct audio_info *aud_modes,
 }
 
 #if defined(CONFIG_DRM_AMD_DC_DCN)
-struct hpo_dp_link_encoder *resource_get_unused_hpo_dp_link_encoder(
-               const struct resource_pool *pool)
+struct hpo_dp_link_encoder *resource_get_hpo_dp_link_enc_for_det_lt(
+               const struct resource_context *res_ctx,
+               const struct resource_pool *pool,
+               const struct dc_link *link)
 {
-       uint8_t i;
-       struct hpo_dp_link_encoder *enc = NULL;
+       struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL;
+       int enc_index;
 
-       ASSERT(pool->hpo_dp_link_enc_count <= MAX_HPO_DP2_LINK_ENCODERS);
+       enc_index = find_acquired_hpo_dp_link_enc_for_link(res_ctx, link);
 
-       for (i = 0; i < pool->hpo_dp_link_enc_count; i++) {
-               if (pool->hpo_dp_link_enc[i]->transmitter == TRANSMITTER_UNKNOWN) {
-                       enc = pool->hpo_dp_link_enc[i];
-                       break;
-               }
-       }
+       if (enc_index < 0)
+               enc_index = find_free_hpo_dp_link_enc(res_ctx, pool);
+
+       if (enc_index >= 0)
+               hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
 
-       return enc;
+       return hpo_dp_link_enc;
 }
 #endif
 
index 88d11724db5d764631ce2486401184c0e84b1a4a..a6b8327936dac285120f0696590db6e45151f87e 100644 (file)
@@ -162,9 +162,6 @@ struct dc_link {
 
        struct panel_cntl *panel_cntl;
        struct link_encoder *link_enc;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-       struct hpo_dp_link_encoder *hpo_dp_link_enc;
-#endif
        struct graphics_object_id link_id;
        /* Endpoint type distinguishes display endpoints which do not have entries
         * in the BIOS connector table from those that do. Helps when tracking link
index 6c08e21bb70807f3830f7ff274cfee568cde5f4c..80dfaa4d4d81eefe8df967a10982402a60355bf1 100644 (file)
@@ -499,7 +499,8 @@ static enum bp_result link_transmitter_control(
 void dcn31_hpo_dp_link_enc_enable_dp_output(
        struct hpo_dp_link_encoder *enc,
        const struct dc_link_settings *link_settings,
-       enum transmitter transmitter)
+       enum transmitter transmitter,
+       enum hpd_source_id hpd_source)
 {
        struct dcn31_hpo_dp_link_encoder *enc3 = DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(enc);
        struct bp_transmitter_control cntl = { 0 };
@@ -508,6 +509,9 @@ void dcn31_hpo_dp_link_enc_enable_dp_output(
        /* Set the transmitter */
        enc3->base.transmitter = transmitter;
 
+       /* Set the hpd source */
+       enc3->base.hpd_source = hpd_source;
+
        /* Enable the PHY */
        cntl.action = TRANSMITTER_CONTROL_ENABLE;
        cntl.engine_id = ENGINE_ID_UNKNOWN;
index 0706ccaf6fec11eb710bcd2f2a4a5f89ed40fd9e..e324e9b83136c5b6a8ad8a9192a3f998f301e489 100644 (file)
@@ -184,7 +184,8 @@ void hpo_dp_link_encoder31_construct(struct dcn31_hpo_dp_link_encoder *enc31,
 void dcn31_hpo_dp_link_enc_enable_dp_output(
        struct hpo_dp_link_encoder *enc,
        const struct dc_link_settings *link_settings,
-       enum transmitter transmitter);
+       enum transmitter transmitter,
+       enum hpd_source_id hpd_source);
 
 void dcn31_hpo_dp_link_enc_disable_output(
        struct hpo_dp_link_encoder *enc,
index d34b0b0eea655123f56b59109873c216a749f6f1..444182a97e6eeb90043f42dfac78082858a7e087 100644 (file)
@@ -53,6 +53,8 @@ enum dc_status {
        DC_NOT_SUPPORTED = 24,
        DC_UNSUPPORTED_VALUE = 25,
 
+       DC_NO_LINK_ENC_RESOURCE = 26,
+
        DC_ERROR_UNEXPECTED = -1
 };
 
index 0bd28a332fcb66a9543547ae0d5dc40d683f006d..08f1222fdd265ad95696796ebd4746bba7e18d60 100644 (file)
@@ -422,6 +422,8 @@ struct resource_context {
        struct link_enc_cfg_context link_enc_cfg_ctx;
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        bool is_hpo_dp_stream_enc_acquired[MAX_HPO_DP2_ENCODERS];
+       unsigned int hpo_dp_link_enc_to_link_idx[MAX_HPO_DP2_LINK_ENCODERS];
+       int hpo_dp_link_enc_ref_cnts[MAX_HPO_DP2_LINK_ENCODERS];
 #endif
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        bool is_mpc_3dlut_acquired[MAX_PIPES];
index bb0e91756ddd9c613ef247ca6d5014c804c4e74e..2ce15cd10d80fd797991519900f4f583c129deec 100644 (file)
@@ -268,7 +268,8 @@ struct hpo_dp_link_encoder_funcs {
 
        void (*enable_link_phy)(struct hpo_dp_link_encoder *enc,
                const struct dc_link_settings *link_settings,
-               enum transmitter transmitter);
+               enum transmitter transmitter,
+               enum hpd_source_id hpd_source);
 
        void (*disable_link_phy)(struct hpo_dp_link_encoder *link_enc,
                enum signal_type signal);
index c208925f824719afbf88a7f4d000a6bd8ecaf430..ee4a5df428e36778171de2d2455337f56c6c5176 100644 (file)
@@ -206,8 +206,10 @@ int get_num_mpc_splits(struct pipe_ctx *pipe);
 int get_num_odm_splits(struct pipe_ctx *pipe);
 
 #if defined(CONFIG_DRM_AMD_DC_DCN)
-struct hpo_dp_link_encoder *resource_get_unused_hpo_dp_link_encoder(
-               const struct resource_pool *pool);
+struct hpo_dp_link_encoder *resource_get_hpo_dp_link_enc_for_det_lt(
+               const struct resource_context *res_ctx,
+               const struct resource_pool *pool,
+               const struct dc_link *link);
 #endif
 
 void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,