]> git.dujemihanovic.xyz Git - linux.git/commitdiff
drm/amd/display: Add dynamic link encoder selection.
authorJimmy Kizito <Jimmy.Kizito@amd.com>
Tue, 5 Jan 2021 19:25:23 +0000 (14:25 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 9 Apr 2021 20:48:38 +0000 (16:48 -0400)
[Why]
Some display endpoints may be programmably mapped to compatible link
encoders. The assignment of link encoders to links has to be dynamic to
accommodate the increased flexibility in comparison to conventional
display endpoints.

[How]
- Add link encoder assignment tracking variables.
- Execute link encoder assignment algorithm before enabling link and
release link encoders from links once they are disabled.

Signed-off-by: Jimmy Kizito <Jimmy.Kizito@amd.com>
Reviewed-by: Jun Lei <Jun.Lei@amd.com>
Acked-by: Anson Jacob <Anson.Jacob@amd.com>
Tested-by: Dan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/Makefile
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c [new file with mode: 0644]
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/dc_stream.h
drivers/gpu/drm/amd/display/dc/dc_types.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/link_enc_cfg.h [new file with mode: 0644]

index bbde6e6a4e4350a7ac00bb6fe8a8fbff48b21d8e..f33847299bca2a63b077fa4b8c7cc95059ce54f8 100644 (file)
@@ -54,8 +54,9 @@ AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/dc/,$(DC_LI
 
 include $(AMD_DC)
 
-DISPLAY_CORE = dc.o dc_stat.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \
-dc_surface.o dc_link_hwss.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o
+DISPLAY_CORE = dc.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \
+dc_surface.o dc_link_hwss.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o \
+dc_link_enc_cfg.o
 
 ifdef CONFIG_DRM_AMD_DC_DCN
 DISPLAY_CORE += dc_vm_helper.o
index d55c1dd6464c17e2ec41a34e7dbf1f27397cce86..12cb95c5a1f9e79b5d4a19465effd679c2260b32 100644 (file)
@@ -52,6 +52,7 @@
 
 #include "link_hwss.h"
 #include "link_encoder.h"
+#include "link_enc_cfg.h"
 
 #include "dc_link_ddc.h"
 #include "dm_helpers.h"
@@ -870,6 +871,9 @@ static bool dc_construct(struct dc *dc,
        if (!create_links(dc, init_params->num_virtual_links))
                goto fail;
 
+       /* Initialise DIG link encoder resource tracking variables. */
+       link_enc_cfg_init(dc, dc->current_state);
+
        return true;
 
 fail:
index 2cfb53387c55f119ad0a98b55ba7a0032f3fb090..719fc6b502b6ded46475e46ecb774180237c0247 100644 (file)
@@ -92,11 +92,14 @@ static void dc_link_destruct(struct dc_link *link)
                link->panel_cntl->funcs->destroy(&link->panel_cntl);
 
        if (link->link_enc) {
-               /* Update link encoder tracking variables. These are used for the dynamic
-                * assignment of link encoders to streams.
+               /* Update link encoder resource tracking variables. These are used for
+                * the dynamic assignment of link encoders to streams. Virtual links
+                * are not assigned encoder resources on creation.
                 */
-               link->dc->res_pool->link_encoders[link->link_enc->preferred_engine] = NULL;
-               link->dc->res_pool->dig_link_enc_count--;
+               if (link->link_id.id != CONNECTOR_ID_VIRTUAL) {
+                       link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = NULL;
+                       link->dc->res_pool->dig_link_enc_count--;
+               }
                link->link_enc->funcs->destroy(&link->link_enc);
        }
 
@@ -1409,6 +1412,8 @@ static bool dc_link_construct(struct dc_link *link,
        link->link_id =
                bios->funcs->get_connector_id(bios, init_params->connector_index);
 
+       link->ep_type = DISPLAY_ENDPOINT_PHY;
+
        DC_LOG_DC("BIOS object table - link_id: %d", link->link_id.id);
 
        if (bios->funcs->get_disp_connector_caps_info) {
@@ -1547,7 +1552,8 @@ static bool dc_link_construct(struct dc_link *link,
        /* Update link encoder tracking variables. These are used for the dynamic
         * assignment of link encoders to streams.
         */
-       link->dc->res_pool->link_encoders[link->link_enc->preferred_engine] = link->link_enc;
+       link->eng_id = link->link_enc->preferred_engine;
+       link->dc->res_pool->link_encoders[link->eng_id - ENGINE_ID_DIGA] = link->link_enc;
        link->dc->res_pool->dig_link_enc_count++;
 
        link->link_enc_hw_inst = link->link_enc->transmitter;
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
new file mode 100644 (file)
index 0000000..c2bf9e5
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "link_enc_cfg.h"
+#include "resource.h"
+#include "dc_link_dp.h"
+
+/* Check whether stream is supported by DIG link encoders. */
+static bool is_dig_link_enc_stream(struct dc_stream_state *stream)
+{
+       bool is_dig_stream = false;
+       struct link_encoder *link_enc = NULL;
+       int i;
+
+       /* Loop over created link encoder objects. */
+       for (i = 0; i < stream->ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) {
+               link_enc = stream->ctx->dc->res_pool->link_encoders[i];
+
+               if (link_enc &&
+                               ((uint32_t)stream->signal & link_enc->output_signals)) {
+                       if (dc_is_dp_signal(stream->signal)) {
+                               /* DIGs do not support DP2.0 streams with 128b/132b encoding. */
+                               struct dc_link_settings link_settings = {0};
+
+                               decide_link_settings(stream, &link_settings);
+                               if ((link_settings.link_rate >= LINK_RATE_LOW) &&
+                                               link_settings.link_rate <= LINK_RATE_HIGH3) {
+                                       is_dig_stream = true;
+                                       break;
+                               }
+                       } else {
+                               is_dig_stream = true;
+                               break;
+                       }
+               }
+       }
+
+       return is_dig_stream;
+}
+
+/* Update DIG link encoder resource tracking variables in dc_state. */
+static void update_link_enc_assignment(
+               struct dc_state *state,
+               struct dc_stream_state *stream,
+               enum engine_id eng_id,
+               bool add_enc)
+{
+       int eng_idx;
+       int stream_idx;
+       int i;
+
+       if (eng_id != ENGINE_ID_UNKNOWN) {
+               eng_idx = eng_id - ENGINE_ID_DIGA;
+               stream_idx = -1;
+
+               /* Index of stream in dc_state used to update correct entry in
+                * link_enc_assignments table.
+                */
+               for (i = 0; i < state->stream_count; i++) {
+                       if (stream == state->streams[i]) {
+                               stream_idx = i;
+                               break;
+                       }
+               }
+
+               /* Update link encoder assignments table, link encoder availability
+                * pool and link encoder assigned to stream in state.
+                * Add/remove encoder resource to/from stream.
+                */
+               if (stream_idx != -1) {
+                       if (add_enc) {
+                               state->res_ctx.link_enc_assignments[stream_idx] = (struct link_enc_assignment){
+                                       .valid = true,
+                                       .ep_id = (struct display_endpoint_id) {
+                                               .link_id = stream->link->link_id,
+                                               .ep_type = stream->link->ep_type},
+                                       .eng_id = eng_id};
+                               state->res_ctx.link_enc_avail[eng_idx] = ENGINE_ID_UNKNOWN;
+                               stream->link_enc = stream->ctx->dc->res_pool->link_encoders[eng_idx];
+                       } else {
+                               state->res_ctx.link_enc_assignments[stream_idx].valid = false;
+                               state->res_ctx.link_enc_avail[eng_idx] = eng_id;
+                               stream->link_enc = NULL;
+                       }
+               } else {
+                       dm_output_to_console("%s: Stream not found in dc_state.\n", __func__);
+               }
+       }
+}
+
+/* Return first available DIG link encoder. */
+static enum engine_id find_first_avail_link_enc(
+               struct dc_context *ctx,
+               struct dc_state *state)
+{
+       enum engine_id eng_id = ENGINE_ID_UNKNOWN;
+       int i;
+
+       for (i = 0; i < ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) {
+               eng_id = state->res_ctx.link_enc_avail[i];
+               if (eng_id != ENGINE_ID_UNKNOWN)
+                       break;
+       }
+
+       return eng_id;
+}
+
+void link_enc_cfg_init(
+               struct dc *dc,
+               struct dc_state *state)
+{
+       int i;
+
+       for (i = 0; i < dc->res_pool->res_cap->num_dig_link_enc; i++) {
+               if (dc->res_pool->link_encoders[i])
+                       state->res_ctx.link_enc_avail[i] = (enum engine_id) i;
+               else
+                       state->res_ctx.link_enc_avail[i] = ENGINE_ID_UNKNOWN;
+       }
+}
+
+void link_enc_cfg_link_encs_assign(
+               struct dc *dc,
+               struct dc_state *state,
+               struct dc_stream_state *streams[],
+               uint8_t stream_count)
+{
+       enum engine_id eng_id = ENGINE_ID_UNKNOWN;
+       int i;
+
+       /* Release DIG link encoder resources before running assignment algorithm. */
+       for (i = 0; i < stream_count; i++)
+               dc->res_pool->funcs->link_enc_unassign(state, streams[i]);
+
+       /* (a) Assign DIG link encoders to physical (unmappable) endpoints first. */
+       for (i = 0; i < stream_count; i++) {
+               struct dc_stream_state *stream = streams[i];
+
+               /* Skip stream if not supported by DIG link encoder. */
+               if (!is_dig_link_enc_stream(stream))
+                       continue;
+
+               /* Physical endpoints have a fixed mapping to DIG link encoders. */
+               if (!stream->link->is_dig_mapping_flexible) {
+                       eng_id = stream->link->eng_id;
+                       update_link_enc_assignment(state, stream, eng_id, true);
+               }
+       }
+
+       /* (b) Then assign encoders to mappable endpoints. */
+       eng_id = ENGINE_ID_UNKNOWN;
+
+       for (i = 0; i < stream_count; i++) {
+               struct dc_stream_state *stream = streams[i];
+
+               /* Skip stream if not supported by DIG link encoder. */
+               if (!is_dig_link_enc_stream(stream))
+                       continue;
+
+               /* Mappable endpoints have a flexible mapping to DIG link encoders. */
+               if (stream->link->is_dig_mapping_flexible) {
+                       eng_id = find_first_avail_link_enc(stream->ctx, state);
+                       update_link_enc_assignment(state, stream, eng_id, true);
+               }
+       }
+}
+
+void link_enc_cfg_link_enc_unassign(
+               struct dc_state *state,
+               struct dc_stream_state *stream)
+{
+       enum engine_id eng_id = ENGINE_ID_UNKNOWN;
+
+       /* Only DIG link encoders. */
+       if (!is_dig_link_enc_stream(stream))
+               return;
+
+       if (stream->link_enc)
+               eng_id = stream->link_enc->preferred_engine;
+
+       update_link_enc_assignment(state, stream, eng_id, false);
+}
index 3c91d16c271053e5506e901de65ce8eb144bf7b5..ac7a75887f952900179d65d3bf50d0f1e38312cc 100644 (file)
@@ -1930,6 +1930,9 @@ enum dc_status dc_remove_stream_from_ctx(
                                dc->res_pool,
                        del_pipe->stream_res.stream_enc,
                        false);
+       /* Release link encoder from stream in new dc_state. */
+       if (dc->res_pool->funcs->link_enc_unassign)
+               dc->res_pool->funcs->link_enc_unassign(new_ctx, del_pipe->stream);
 
        if (del_pipe->stream_res.audio)
                update_audio_usage(
@@ -2842,6 +2845,10 @@ bool pipe_need_reprogram(
        if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc)
                return true;
 
+       /* DIG link encoder resource assignment for stream changed. */
+       if (pipe_ctx_old->stream->link_enc != pipe_ctx->stream->link_enc)
+               return true;
+
        return false;
 }
 
index 7b927e634279d9b2e1dafcbb575ae869d3749864..b0013e674864d15877e7e2f2a1e9f2f9170dce78 100644 (file)
@@ -132,6 +132,11 @@ struct dc_link {
        uint8_t hpd_src;
 
        uint8_t link_enc_hw_inst;
+       /* DIG link encoder ID. Used as index in link encoder resource pool.
+        * For links with fixed mapping to DIG, this is not changed after dc_link
+        * object creation.
+        */
+       enum engine_id eng_id;
 
        bool test_pattern_enabled;
        union compliance_test_state compliance_test_state;
@@ -151,6 +156,11 @@ struct dc_link {
        struct panel_cntl *panel_cntl;
        struct link_encoder *link_enc;
        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
+        * encoder to display endpoint assignments.
+        */
+       enum display_endpoint_type ep_type;
        union ddi_channel_mapping ddi_channel_mapping;
        struct connector_device_tag_info device_tag;
        struct dpcd_caps dpcd_caps;
index e747370fc43b8a8cdc8b285a4cf3cfc7262c677a..2bc057e0b4472c16c5b059ded541e43738dd7ea3 100644 (file)
@@ -136,6 +136,10 @@ struct dc_stream_state {
        struct dc_sink *sink;
 
        struct dc_link *link;
+       /* For dynamic link encoder assignment, update the link encoder assigned to
+        * a stream via the volatile dc_state rather than the static dc_link.
+        */
+       struct link_encoder *link_enc;
        struct dc_panel_patch sink_patches;
        union display_content_support content_support;
        struct dc_crtc_timing timing;
index 80757a0ea7c6519e30f31e9846b50760e3df0112..b5e875ee9027b1d3857516dfee2bbe5601208b3f 100644 (file)
@@ -934,4 +934,19 @@ enum dc_psr_version {
        DC_PSR_VERSION_UNSUPPORTED              = 0xFFFFFFFF,
 };
 
+/* Possible values of display_endpoint_id.endpoint */
+enum display_endpoint_type {
+       DISPLAY_ENDPOINT_PHY = 0, /* Physical connector. */
+       DISPLAY_ENDPOINT_UNKNOWN = -1
+};
+
+/* Extends graphics_object_id with an additional member 'ep_type' for
+ * distinguishing between physical endpoints (with entries in BIOS connector table) and
+ * logical endpoints.
+ */
+struct display_endpoint_id {
+       struct graphics_object_id link_id;
+       enum display_endpoint_type ep_type;
+};
+
 #endif /* DC_TYPES_H_ */
index eb1a19bf0d81ff959af1615fb5b581cae77954f7..81b92f20d5b6cd6c9cc6c42abe9e09fa2e87649a 100644 (file)
@@ -118,6 +118,27 @@ struct resource_funcs {
                display_e2e_pipe_params_st *pipes,
                bool fast_validate);
 
+       /*
+        * Algorithm for assigning available link encoders to links.
+        *
+        * Update link_enc_assignments table and link_enc_avail list accordingly in
+        * struct resource_context.
+        */
+       void (*link_encs_assign)(
+                       struct dc *dc,
+                       struct dc_state *state,
+                       struct dc_stream_state *streams[],
+                       uint8_t stream_count);
+       /*
+        * Unassign a link encoder from a stream.
+        *
+        * Update link_enc_assignments table and link_enc_avail list accordingly in
+        * struct resource_context.
+        */
+       void (*link_enc_unassign)(
+                       struct dc_state *state,
+                       struct dc_stream_state *stream);
+
        enum dc_status (*validate_global)(
                struct dc *dc,
                struct dc_state *context);
@@ -358,6 +379,12 @@ struct resource_context {
        uint8_t clock_source_ref_count[MAX_CLOCK_SOURCES];
        uint8_t dp_clock_source_ref_count;
        bool is_dsc_acquired[MAX_PIPES];
+       /* A table/array of encoder-to-link assignments. One entry per stream.
+        * Indexed by stream index in dc_state.
+        */
+       struct link_enc_assignment link_enc_assignments[MAX_PIPES];
+       /* List of available link encoders. Uses engine ID as encoder identifier. */
+       enum engine_id link_enc_avail[MAX_DIG_LINK_ENCODERS];
 #if defined(CONFIG_DRM_AMD_DC_DCN)
        bool is_mpc_3dlut_acquired[MAX_PIPES];
 #endif
index 7f5acd8fb91805147aa9bf74205f024e1d6e11e2..80bc995006458d5756622d90b7758ddb0b23eb35 100644 (file)
@@ -187,4 +187,17 @@ struct link_encoder_funcs {
                struct link_encoder *enc);
 };
 
+/*
+ * Used to track assignments of links (display endpoints) to link encoders.
+ *
+ * Entry in link_enc_assignments table in struct resource_context.
+ * Entries only marked valid once encoder assigned to a link and invalidated once unassigned.
+ * Uses engine ID as identifier since PHY ID not relevant for USB4 DPIA endpoint.
+ */
+struct link_enc_assignment {
+       bool valid;
+       struct display_endpoint_id ep_id;
+       enum engine_id eng_id;
+};
+
 #endif /* LINK_ENCODER_H_ */
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
new file mode 100644 (file)
index 0000000..ad64163
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef DC_INC_LINK_ENC_CFG_H_
+#define DC_INC_LINK_ENC_CFG_H_
+
+/* This module implements functionality for dynamically assigning DIG link
+ * encoder resources to display endpoints (links).
+ */
+
+#include "core_types.h"
+
+/*
+ * Initialise link encoder resource tracking.
+ */
+void link_enc_cfg_init(
+               struct dc *dc,
+               struct dc_state *state);
+
+/*
+ * Algorithm for assigning available DIG link encoders to streams.
+ *
+ * Update link_enc_assignments table and link_enc_avail list accordingly in
+ * struct resource_context.
+ *
+ * Loop over all streams twice:
+ * a) First assign encoders to unmappable endpoints.
+ * b) Then assign encoders to mappable endpoints.
+ */
+void link_enc_cfg_link_encs_assign(
+               struct dc *dc,
+               struct dc_state *state,
+               struct dc_stream_state *streams[],
+               uint8_t stream_count);
+
+/*
+ * Unassign a link encoder from a stream.
+ *
+ * Update link_enc_assignments table and link_enc_avail list accordingly in
+ * struct resource_context.
+ */
+void link_enc_cfg_link_enc_unassign(
+               struct dc_state *state,
+               struct dc_stream_state *stream);
+
+#endif /* DC_INC_LINK_ENC_CFG_H_ */