diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 2225095576724066dabad2704abdaf224208ad9e..4ec3de34bd673e6307728396cf3d19c3cd1d9f35 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -3490,11 +3490,8 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) link_enc = pipe_ctx->stream->link->link_enc; config.phy_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; } else if (pipe_ctx->stream->link->dc->res_pool->funcs->link_encs_assign) { - /* Use link encoder assignment from current DC state - which may differ from the DC state to be - * committed - when updating PSP config. - */ link_enc = link_enc_cfg_get_link_enc_used_by_stream( - pipe_ctx->stream->link->dc->current_state, + pipe_ctx->stream->ctx->dc, pipe_ctx->stream); config.phy_idx = 0; /* Clear phy_idx for non-physical display endpoints. */ } @@ -3619,7 +3616,7 @@ void core_link_enable_stream( return; if (dc->res_pool->funcs->link_encs_assign && stream->link->ep_type != DISPLAY_ENDPOINT_PHY) - link_enc = stream->link_enc; + link_enc = link_enc_cfg_get_link_enc_used_by_stream(dc, stream); else link_enc = stream->link->link_enc; ASSERT(link_enc); @@ -4216,14 +4213,14 @@ bool dc_link_is_fec_supported(const struct dc_link *link) */ if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign) { - link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link); if (link_enc == NULL) - link_enc = link_enc_cfg_get_next_avail_link_enc(link->dc, link->dc->current_state); + link_enc = link_enc_cfg_get_next_avail_link_enc(link->ctx->dc); } else link_enc = link->link_enc; ASSERT(link_enc); - return (dc_is_dp_signal(link->connector_signal) && + return (dc_is_dp_signal(link->connector_signal) && link_enc && link_enc->features.fec_supported && link->dpcd_caps.fec_cap.bits.FEC_CAPABLE && !IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment)); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index 2a58de375d8f8f4c59862b5836a691d75053ecc0..0fe0eb06eaccb4a2f2cd119ca64ea7b2884d6cd2 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -304,7 +304,7 @@ static enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *li */ if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign) - link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link); else link_enc = link->link_enc; ASSERT(link_enc); @@ -339,7 +339,7 @@ static enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *li */ if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign) - link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link); else link_enc = link->link_enc; ASSERT(link_enc); @@ -2385,7 +2385,7 @@ bool perform_link_training_with_retries( * link. */ if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign) - link_enc = stream->link_enc; + link_enc = link_enc_cfg_get_link_enc_used_by_stream(link->ctx->dc, pipe_ctx->stream); else link_enc = link->link_enc; @@ -2666,9 +2666,9 @@ bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_ */ if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign) { - link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link); if (link_enc == NULL) - link_enc = link_enc_cfg_get_next_avail_link_enc(link->dc, link->dc->current_state); + link_enc = link_enc_cfg_get_next_avail_link_enc(link->ctx->dc); } else link_enc = link->link_enc; ASSERT(link_enc); @@ -2697,9 +2697,9 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link) */ if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign) { - link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link); if (link_enc == NULL) - link_enc = link_enc_cfg_get_next_avail_link_enc(link->dc, link->dc->current_state); + link_enc = link_enc_cfg_get_next_avail_link_enc(link->ctx->dc); } else link_enc = link->link_enc; ASSERT(link_enc); @@ -2881,7 +2881,13 @@ bool dp_verify_link_cap( enum link_training_result status; union hpd_irq_data irq_data; - if (link->dc->debug.skip_detection_link_training) { + /* Accept reported capabilities if link supports flexible encoder mapping or encoder already in use. */ + if (link->dc->debug.skip_detection_link_training || + link->is_dig_mapping_flexible) { + link->verified_link_cap = *known_limit_link_setting; + return true; + } else if (link->link_enc && link->dc->res_pool->funcs->link_encs_assign && + !link_enc_cfg_is_link_enc_avail(link->ctx->dc, link->link_enc->preferred_engine)) { link->verified_link_cap = *known_limit_link_setting; return true; } @@ -5679,7 +5685,7 @@ enum dc_status dp_set_fec_ready(struct dc_link *link, bool ready) */ if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign) - link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link); else link_enc = link->link_enc; ASSERT(link_enc); @@ -5726,8 +5732,7 @@ void dp_set_fec_enable(struct dc_link *link, bool enable) */ if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign) - link_enc = link_enc_cfg_get_link_enc_used_by_link( - link->dc->current_state, link); + link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link); else link_enc = link->link_enc; ASSERT(link_enc); 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 index 5536184fff46b1147c9cb2a99008f801e2d26b38..4dce25c39b7569c8efee7df0a26dfb5e1fd13d66 100644 --- 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 @@ -63,6 +63,18 @@ static bool is_dig_link_enc_stream(struct dc_stream_state *stream) return is_dig_stream; } +static struct link_enc_assignment get_assignment(struct dc *dc, int i) +{ + struct link_enc_assignment assignment; + + if (dc->current_state->res_ctx.link_enc_cfg_ctx.mode == LINK_ENC_CFG_TRANSIENT) + assignment = dc->current_state->res_ctx.link_enc_cfg_ctx.transient_assignments[i]; + else /* LINK_ENC_CFG_STEADY */ + assignment = dc->current_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; + + return assignment; +} + /* Return stream using DIG link encoder resource. NULL if unused. */ static struct dc_stream_state *get_stream_using_link_enc( struct dc_state *state, @@ -72,7 +84,7 @@ static struct dc_stream_state *get_stream_using_link_enc( int i; for (i = 0; i < state->stream_count; i++) { - struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i]; + struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; if ((assignment.valid == true) && (assignment.eng_id == eng_id)) { stream = state->streams[i]; @@ -98,15 +110,15 @@ static void remove_link_enc_assignment( * link_enc_assignments table. */ for (i = 0; i < MAX_PIPES; i++) { - struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i]; + struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; if (assignment.valid && assignment.stream == stream) { - state->res_ctx.link_enc_assignments[i].valid = false; + state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].valid = false; /* Only add link encoder back to availability pool if not being * used by any other stream (i.e. removing SST stream or last MST stream). */ if (get_stream_using_link_enc(state, eng_id) == NULL) - state->res_ctx.link_enc_avail[eng_idx] = eng_id; + state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] = eng_id; stream->link_enc = NULL; break; } @@ -130,14 +142,14 @@ static void add_link_enc_assignment( */ for (i = 0; i < state->stream_count; i++) { if (stream == state->streams[i]) { - state->res_ctx.link_enc_assignments[i] = (struct link_enc_assignment){ + state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i] = (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, .stream = stream}; - state->res_ctx.link_enc_avail[eng_idx] = ENGINE_ID_UNKNOWN; + state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] = ENGINE_ID_UNKNOWN; stream->link_enc = stream->ctx->dc->res_pool->link_encoders[eng_idx]; break; } @@ -157,7 +169,7 @@ static enum engine_id find_first_avail_link_enc( 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]; + eng_id = state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i]; if (eng_id != ENGINE_ID_UNKNOWN) break; } @@ -170,7 +182,7 @@ static bool is_avail_link_enc(struct dc_state *state, enum engine_id eng_id) bool is_avail = false; int eng_idx = eng_id - ENGINE_ID_DIGA; - if (eng_id != ENGINE_ID_UNKNOWN && state->res_ctx.link_enc_avail[eng_idx] != ENGINE_ID_UNKNOWN) + if (eng_id != ENGINE_ID_UNKNOWN && state->res_ctx.link_enc_cfg_ctx.link_enc_avail[eng_idx] != ENGINE_ID_UNKNOWN) is_avail = true; return is_avail; @@ -190,6 +202,28 @@ static bool are_ep_ids_equal(struct display_endpoint_id *lhs, struct display_end return are_equal; } +static struct link_encoder *get_link_enc_used_by_link( + struct dc_state *state, + const struct dc_link *link) +{ + struct link_encoder *link_enc = NULL; + struct display_endpoint_id ep_id; + int i; + + ep_id = (struct display_endpoint_id) { + .link_id = link->link_id, + .ep_type = link->ep_type}; + + for (i = 0; i < state->stream_count; i++) { + struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; + + if (assignment.valid == true && are_ep_ids_equal(&assignment.ep_id, &ep_id)) + link_enc = link->dc->res_pool->link_encoders[assignment.eng_id - ENGINE_ID_DIGA]; + } + + return link_enc; +} + void link_enc_cfg_init( struct dc *dc, struct dc_state *state) @@ -198,10 +232,12 @@ void link_enc_cfg_init( 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; + state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i] = (enum engine_id) i; else - state->res_ctx.link_enc_avail[i] = ENGINE_ID_UNKNOWN; + state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i] = ENGINE_ID_UNKNOWN; } + + state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY; } void link_enc_cfg_link_encs_assign( @@ -221,7 +257,7 @@ void link_enc_cfg_link_encs_assign( dc->res_pool->funcs->link_enc_unassign(state, streams[i]); for (i = 0; i < MAX_PIPES; i++) - ASSERT(state->res_ctx.link_enc_assignments[i].valid == false); + ASSERT(state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].valid == false); /* (a) Assign DIG link encoders to physical (unmappable) endpoints first. */ for (i = 0; i < stream_count; i++) { @@ -258,8 +294,8 @@ void link_enc_cfg_link_encs_assign( struct dc_stream_state *prev_stream = prev_state->streams[j]; if (stream == prev_stream && stream->link == prev_stream->link && - prev_state->res_ctx.link_enc_assignments[j].valid) { - eng_id = prev_state->res_ctx.link_enc_assignments[j].eng_id; + prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].valid) { + eng_id = prev_state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j].eng_id; if (is_avail_link_enc(state, eng_id)) add_link_enc_assignment(state, stream, eng_id); } @@ -291,7 +327,7 @@ void link_enc_cfg_link_encs_assign( * endpoint. These streams should use the same link encoder * assigned to that endpoint. */ - link_enc = link_enc_cfg_get_link_enc_used_by_link(state, stream->link); + link_enc = get_link_enc_used_by_link(state, stream->link); if (link_enc == NULL) eng_id = find_first_avail_link_enc(stream->ctx, state); else @@ -301,6 +337,15 @@ void link_enc_cfg_link_encs_assign( } link_enc_cfg_validate(dc, state); + + /* Update transient assignments. */ + for (i = 0; i < MAX_PIPES; i++) { + dc->current_state->res_ctx.link_enc_cfg_ctx.transient_assignments[i] = + state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; + } + + /* Current state mode will be set to steady once this state committed. */ + state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY; } void link_enc_cfg_link_enc_unassign( @@ -320,12 +365,12 @@ void link_enc_cfg_link_enc_unassign( } bool link_enc_cfg_is_transmitter_mappable( - struct dc_state *state, + struct dc *dc, struct link_encoder *link_enc) { bool is_mappable = false; enum engine_id eng_id = link_enc->preferred_engine; - struct dc_stream_state *stream = get_stream_using_link_enc(state, eng_id); + struct dc_stream_state *stream = link_enc_cfg_get_stream_using_link_enc(dc, eng_id); if (stream) is_mappable = stream->link->is_dig_mapping_flexible; @@ -333,30 +378,43 @@ bool link_enc_cfg_is_transmitter_mappable( return is_mappable; } -struct dc_link *link_enc_cfg_get_link_using_link_enc( - struct dc_state *state, +struct dc_stream_state *link_enc_cfg_get_stream_using_link_enc( + struct dc *dc, enum engine_id eng_id) { - struct dc_link *link = NULL; + struct dc_stream_state *stream = NULL; int i; - for (i = 0; i < state->stream_count; i++) { - struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i]; + for (i = 0; i < MAX_PIPES; i++) { + struct link_enc_assignment assignment = get_assignment(dc, i); if ((assignment.valid == true) && (assignment.eng_id == eng_id)) { - link = state->streams[i]->link; + stream = assignment.stream; break; } } - if (link == NULL) - dm_output_to_console("%s: No link using DIG(%d).\n", __func__, eng_id); + return stream; +} +struct dc_link *link_enc_cfg_get_link_using_link_enc( + struct dc *dc, + enum engine_id eng_id) +{ + struct dc_link *link = NULL; + struct dc_stream_state *stream = NULL; + + stream = link_enc_cfg_get_stream_using_link_enc(dc, eng_id); + + if (stream) + link = stream->link; + + // dm_output_to_console("%s: No link using DIG(%d).\n", __func__, eng_id); return link; } struct link_encoder *link_enc_cfg_get_link_enc_used_by_link( - struct dc_state *state, + struct dc *dc, const struct dc_link *link) { struct link_encoder *link_enc = NULL; @@ -367,41 +425,74 @@ struct link_encoder *link_enc_cfg_get_link_enc_used_by_link( .link_id = link->link_id, .ep_type = link->ep_type}; - for (i = 0; i < state->stream_count; i++) { - struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i]; + for (i = 0; i < MAX_PIPES; i++) { + struct link_enc_assignment assignment = get_assignment(dc, i); - if (assignment.valid == true && are_ep_ids_equal(&assignment.ep_id, &ep_id)) + if (assignment.valid == true && are_ep_ids_equal(&assignment.ep_id, &ep_id)) { link_enc = link->dc->res_pool->link_encoders[assignment.eng_id - ENGINE_ID_DIGA]; + break; + } } return link_enc; } -struct link_encoder *link_enc_cfg_get_next_avail_link_enc( - const struct dc *dc, - const struct dc_state *state) +struct link_encoder *link_enc_cfg_get_next_avail_link_enc(struct dc *dc) { struct link_encoder *link_enc = NULL; - enum engine_id eng_id; + enum engine_id encs_assigned[MAX_DIG_LINK_ENCODERS]; + int i; + + for (i = 0; i < MAX_DIG_LINK_ENCODERS; i++) + encs_assigned[i] = ENGINE_ID_UNKNOWN; - eng_id = find_first_avail_link_enc(dc->ctx, state); - if (eng_id != ENGINE_ID_UNKNOWN) - link_enc = dc->res_pool->link_encoders[eng_id - ENGINE_ID_DIGA]; + /* Add assigned encoders to list. */ + for (i = 0; i < MAX_PIPES; i++) { + struct link_enc_assignment assignment = get_assignment(dc, i); + + if (assignment.valid) + encs_assigned[assignment.eng_id - ENGINE_ID_DIGA] = assignment.eng_id; + } + + for (i = 0; i < dc->res_pool->res_cap->num_dig_link_enc; i++) { + if (encs_assigned[i] == ENGINE_ID_UNKNOWN) { + link_enc = dc->res_pool->link_encoders[i]; + break; + } + } return link_enc; } struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream( - struct dc_state *state, + struct dc *dc, const struct dc_stream_state *stream) { struct link_encoder *link_enc; - link_enc = link_enc_cfg_get_link_enc_used_by_link(state, stream->link); + link_enc = link_enc_cfg_get_link_enc_used_by_link(dc, stream->link); return link_enc; } +bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id) +{ + bool is_avail = true; + int i; + + /* Add assigned encoders to list. */ + for (i = 0; i < MAX_PIPES; i++) { + struct link_enc_assignment assignment = get_assignment(dc, i); + + if (assignment.valid && assignment.eng_id == eng_id) { + is_avail = false; + break; + } + } + + return is_avail; +} + bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state) { bool is_valid = false; @@ -418,7 +509,7 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state) /* (1) No. valid entries same as stream count. */ for (i = 0; i < MAX_PIPES; i++) { - struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i]; + struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; if (assignment.valid) valid_count++; @@ -431,7 +522,7 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state) /* (2) Matching stream ptrs. */ for (i = 0; i < MAX_PIPES; i++) { - struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i]; + struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; if (assignment.valid) { if (assignment.stream == state->streams[i]) @@ -443,14 +534,15 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state) /* (3) Each endpoint assigned unique encoder. */ for (i = 0; i < MAX_PIPES; i++) { - struct link_enc_assignment assignment_i = state->res_ctx.link_enc_assignments[i]; + struct link_enc_assignment assignment_i = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; if (assignment_i.valid) { struct display_endpoint_id ep_id_i = assignment_i.ep_id; eng_ids_per_ep_id[i]++; for (j = 0; j < MAX_PIPES; j++) { - struct link_enc_assignment assignment_j = state->res_ctx.link_enc_assignments[j]; + struct link_enc_assignment assignment_j = + state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[j]; if (j == i) continue; @@ -470,11 +562,11 @@ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state) /* (4) Assigned encoders not in available pool. */ for (i = 0; i < MAX_PIPES; i++) { - struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i]; + struct link_enc_assignment assignment = state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i]; if (assignment.valid) { for (j = 0; j < dc->res_pool->res_cap->num_dig_link_enc; j++) { - if (state->res_ctx.link_enc_avail[j] == assignment.eng_id) { + if (state->res_ctx.link_enc_cfg_ctx.link_enc_avail[j] == assignment.eng_id) { valid_avail = false; break; } diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c index dae0ab761b61921923aaf4f009dc3b4094289632..64f76f57c85d0a3790cb5859f6effdc582ab49ba 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c @@ -87,7 +87,7 @@ void dp_enable_link_phy( /* Link should always be assigned encoder when en-/disabling. */ if (link->is_dig_mapping_flexible && dc->res_pool->funcs->link_encs_assign) - link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + link_enc = link_enc_cfg_get_link_enc_used_by_link(dc, link); else link_enc = link->link_enc; ASSERT(link_enc); @@ -247,7 +247,7 @@ void dp_disable_link_phy(struct dc_link *link, enum signal_type signal) /* Link should always be assigned encoder when en-/disabling. */ if (link->is_dig_mapping_flexible && dc->res_pool->funcs->link_encs_assign) - link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + link_enc = link_enc_cfg_get_link_enc_used_by_link(dc, link); else link_enc = link->link_enc; ASSERT(link_enc); @@ -391,7 +391,7 @@ void dp_set_hw_test_pattern( */ if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign) - encoder = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + encoder = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link); else encoder = link->link_enc; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index b4e986f736adaed278ae12551095c0a536124d52..adc656fc48484ae015f7f61826cf902af3bc4bfb 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -41,6 +41,7 @@ #include "set_mode_types.h" #include "virtual/virtual_stream_encoder.h" #include "dpcd_defs.h" +#include "link_enc_cfg.h" #include "dc_link_dp.h" #if defined(CONFIG_DRM_AMD_DC_SI) @@ -2826,8 +2827,18 @@ bool pipe_need_reprogram( #endif /* DIG link encoder resource assignment for stream changed. */ - if (pipe_ctx_old->stream->link_enc != pipe_ctx->stream->link_enc) - return true; + if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) { + bool need_reprogram = false; + struct dc *dc = pipe_ctx_old->stream->ctx->dc; + enum link_enc_cfg_mode mode = dc->current_state->res_ctx.link_enc_cfg_ctx.mode; + + dc->current_state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY; + if (link_enc_cfg_get_link_enc_used_by_stream(dc, pipe_ctx_old->stream) != pipe_ctx->stream->link_enc) + need_reprogram = true; + dc->current_state->res_ctx.link_enc_cfg_ctx.mode = mode; + + return need_reprogram; + } return false; } diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index 102f76462752116a8b59c4d1f5c78963f953f3e7..af3e68d3e74760b890b4e1b38fd86428272ece4b 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -1219,7 +1219,7 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx) if (link->ep_type == DISPLAY_ENDPOINT_PHY) link_enc = link->link_enc; else if (dc->res_pool->funcs->link_encs_assign) - link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link); + link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link); ASSERT(link_enc); #if defined(CONFIG_DRM_AMD_DC_DCN) diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index c0aed7d07eebaa9bcd6090c959365eaa3ce517f5..fc83744149d9f9f7f5237fb110adb2bbaf83a0a5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -54,6 +54,7 @@ #include "hw_sequencer.h" #include "inc/link_dpcd.h" #include "dpcd_defs.h" +#include "inc/link_enc_cfg.h" #define DC_LOGGER_INIT(logger) @@ -2385,9 +2386,10 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign) - link_enc = pipe_ctx->stream->link_enc; + link_enc = link_enc_cfg_get_link_enc_used_by_stream(link->ctx->dc, pipe_ctx->stream); else link_enc = link->link_enc; + ASSERT(link_enc); /* For MST, there are multiply stream go to only one link. * connect DIG back_end to front_end while enable_stream and diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c index 1872c456e2c9d8c804af2ceab24a3167fefbda0d..3c388afa06dcd9c4920da2ed8f48361e981bc950 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c @@ -1610,10 +1610,9 @@ static void get_pixel_clock_parameters( */ if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign) { - link_enc = link_enc_cfg_get_link_enc_used_by_stream(stream->link->dc->current_state, stream); + link_enc = link_enc_cfg_get_link_enc_used_by_stream(stream->ctx->dc, stream); if (link_enc == NULL) - link_enc = link_enc_cfg_get_next_avail_link_enc(stream->link->dc, - stream->link->dc->current_state); + link_enc = link_enc_cfg_get_next_avail_link_enc(stream->ctx->dc); } else link_enc = stream->link->link_enc; ASSERT(link_enc); diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c index 77b81f6c24b9f70cc9a90900025c1cd293f8af64..03f0290d41f2761a805af0fda73d3de52a09ddc7 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c @@ -367,7 +367,7 @@ void dcn31_link_encoder_enable_dp_output( enum clock_source_id clock_source) { /* Enable transmitter and encoder. */ - if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc->current_state, enc)) { + if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc, enc)) { dcn20_link_encoder_enable_dp_output(enc, link_settings, clock_source); @@ -383,7 +383,7 @@ void dcn31_link_encoder_enable_dp_mst_output( enum clock_source_id clock_source) { /* Enable transmitter and encoder. */ - if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc->current_state, enc)) { + if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc, enc)) { dcn10_link_encoder_enable_dp_mst_output(enc, link_settings, clock_source); @@ -398,7 +398,7 @@ void dcn31_link_encoder_disable_output( enum signal_type signal) { /* Disable transmitter and encoder. */ - if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc->current_state, enc)) { + if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc, enc)) { dcn10_link_encoder_disable_output(enc, signal); diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index d3598ce1f5de118a48c6be369cd218d75755e86c..0713910a3aa9f19b223b5a6abbab3335c27e78bc 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -48,6 +48,7 @@ #include "dc_link_dp.h" #include "inc/link_dpcd.h" #include "dcn10/dcn10_hw_sequencer.h" +#include "inc/link_enc_cfg.h" #define DC_LOGGER_INIT(logger) @@ -599,4 +600,7 @@ void dcn31_reset_hw_ctx_wrap( old_clk->funcs->cs_power_down(old_clk); } } + + /* New dc_state in the process of being applied to hardware. */ + dc->current_state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_TRANSIENT; } diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 0473cd28e8d17b07e93fda194d7fb25b9a8b22c3..0fea258c6db34d6a4647b87514c3348df7c9de9f 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -387,6 +387,17 @@ struct pipe_ctx { bool vtp_locked; }; +/* Data used for dynamic link encoder assignment. + * Tracks current and future assignments; available link encoders; + * and mode of operation (whether to use current or future assignments). + */ +struct link_enc_cfg_context { + enum link_enc_cfg_mode mode; + struct link_enc_assignment link_enc_assignments[MAX_PIPES]; + enum engine_id link_enc_avail[MAX_DIG_LINK_ENCODERS]; + struct link_enc_assignment transient_assignments[MAX_PIPES]; +}; + struct resource_context { struct pipe_ctx pipe_ctx[MAX_PIPES]; bool is_stream_enc_acquired[MAX_PIPES * 2]; @@ -394,12 +405,7 @@ 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]; + 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]; #endif diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h index 23af9640c544aff56a701a9a3d71087c18098d18..bb0e91756ddd9c613ef247ca6d5014c804c4e74e 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h @@ -215,6 +215,11 @@ struct link_enc_assignment { struct dc_stream_state *stream; }; +enum link_enc_cfg_mode { + LINK_ENC_CFG_STEADY, /* Normal operation - use current_state. */ + LINK_ENC_CFG_TRANSIENT /* During commit state - use state to be committed. */ +}; + #if defined(CONFIG_DRM_AMD_DC_DCN) enum dp2_link_mode { DP2_LINK_TRAINING_TPS1, 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 index 09f7c868feedfba3d623e0a865c9fa14f2a74a02..83b2199b2c83f52451c3c53646b71be996ad0a3b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h +++ b/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h @@ -70,29 +70,35 @@ void link_enc_cfg_link_enc_unassign( * endpoint. */ bool link_enc_cfg_is_transmitter_mappable( - struct dc_state *state, + struct dc *dc, struct link_encoder *link_enc); +/* Return stream using DIG link encoder resource. NULL if unused. */ +struct dc_stream_state *link_enc_cfg_get_stream_using_link_enc( + struct dc *dc, + enum engine_id eng_id); + /* Return link using DIG link encoder resource. NULL if unused. */ struct dc_link *link_enc_cfg_get_link_using_link_enc( - struct dc_state *state, + struct dc *dc, enum engine_id eng_id); /* Return DIG link encoder used by link. NULL if unused. */ struct link_encoder *link_enc_cfg_get_link_enc_used_by_link( - struct dc_state *state, + struct dc *dc, const struct dc_link *link); /* Return next available DIG link encoder. NULL if none available. */ -struct link_encoder *link_enc_cfg_get_next_avail_link_enc( - const struct dc *dc, - const struct dc_state *state); +struct link_encoder *link_enc_cfg_get_next_avail_link_enc(struct dc *dc); /* Return DIG link encoder used by stream. NULL if unused. */ struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream( - struct dc_state *state, + struct dc *dc, const struct dc_stream_state *stream); +/* Return true if encoder available to use. */ +bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id); + /* Returns true if encoder assignments in supplied state pass validity checks. */ bool link_enc_cfg_validate(struct dc *dc, struct dc_state *state);