Commit f42ef862 authored by Jimmy Kizito's avatar Jimmy Kizito Committed by Alex Deucher

drm/amd/display: Add dynamic link encoder selection.

[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: default avatarJimmy Kizito <Jimmy.Kizito@amd.com>
Reviewed-by: default avatarJun Lei <Jun.Lei@amd.com>
Acked-by: default avatarAnson Jacob <Anson.Jacob@amd.com>
Tested-by: default avatarDan Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent b9db4123
......@@ -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
......
......@@ -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:
......
......@@ -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;
......
/*
* 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);
}
......@@ -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;
}
......
......@@ -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;
......
......@@ -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;
......
......@@ -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_ */
......@@ -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
......
......@@ -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_ */
/*
* 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_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment