drm/amd/display: support dynamic HPO DP link encoder allocation

[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>
This commit is contained in:
Wenjing Liu 2021-11-29 14:43:02 -05:00 committed by Alex Deucher
parent 3d38a5839e
commit 6dd8931b1c
12 changed files with 134 additions and 76 deletions

View 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;

View 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";
}

View File

@ -66,31 +66,6 @@
/*******************************************************************************
* 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

View 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 */

View 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);
return enc;
if (enc_index >= 0)
hpo_dp_link_enc = pool->hpo_dp_link_enc[enc_index];
return hpo_dp_link_enc;
}
#endif

View 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

View 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;

View 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,

View 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
};

View 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];

View 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);

View 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,