Commit 6dd8931b authored by Wenjing Liu's avatar Wenjing Liu Committed by Alex Deucher

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: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Reviewed-by: default avatarJun Lei <Jun.Lei@amd.com>
Acked-by: default avatarRodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: default avatarWenjing Liu <wenjing.liu@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 3d38a583
......@@ -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;
......
......@@ -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";
}
......
......@@ -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
......
......@@ -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 */
......
......@@ -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
......
......@@ -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
......
......@@ -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;
......
......@@ -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,
......
......@@ -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
};
......
......@@ -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];
......
......@@ -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);
......
......@@ -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,
......
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