diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/core/dc_link.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/core/dc_link.c | 241 |
1 files changed, 173 insertions, 68 deletions
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 3d75f56a939c..dc1380b6c5e0 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -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); @@ -881,6 +850,7 @@ static bool dc_link_detect_helper(struct dc_link *link, enum dc_connection_type pre_connection_type = dc_connection_none; bool perform_dp_seamless_boot = false; const uint32_t post_oui_delay = 30; // 30ms + struct link_resource link_res = { 0 }; DC_LOGGER_INIT(link->ctx->logger); @@ -975,7 +945,10 @@ 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 = 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) { @@ -986,7 +959,7 @@ static bool dc_link_detect_helper(struct dc_link *link, * empty which leads to allocate_mst_payload() has "0" * pbn_per_slot value leading to exception on dc_fixpt_div() */ - dp_verify_mst_link_cap(link); + dp_verify_mst_link_cap(link, &link_res); /* * This call will initiate MST topology discovery. Which @@ -1150,6 +1123,7 @@ static bool dc_link_detect_helper(struct dc_link *link, // verify link cap for SST non-seamless boot if (!perform_dp_seamless_boot) dp_verify_link_cap_with_retries(link, + &link_res, &link->reported_link_cap, LINK_TRAINING_MAX_VERIFY_RETRY); } else { @@ -1844,6 +1818,8 @@ static void enable_stream_features(struct pipe_ctx *pipe_ctx) union down_spread_ctrl old_downspread; union down_spread_ctrl new_downspread; + memset(&old_downspread, 0, sizeof(old_downspread)); + core_link_read_dpcd(link, DP_DOWNSPREAD_CTRL, &old_downspread.raw, sizeof(old_downspread)); @@ -2503,7 +2479,8 @@ static void write_i2c_redriver_setting( DC_LOG_DEBUG("Set redriver failed"); } -static void disable_link(struct dc_link *link, enum signal_type signal) +static void disable_link(struct dc_link *link, const struct link_resource *link_res, + enum signal_type signal) { /* * TODO: implement call for dp_set_hw_test_pattern @@ -2522,20 +2499,20 @@ static void disable_link(struct dc_link *link, enum signal_type signal) struct dc_link_settings link_settings = link->cur_link_settings; #endif if (dc_is_dp_sst_signal(signal)) - dp_disable_link_phy(link, signal); + dp_disable_link_phy(link, link_res, signal); else - dp_disable_link_phy_mst(link, signal); + dp_disable_link_phy_mst(link, link_res, signal); if (dc_is_dp_sst_signal(signal) || link->mst_stream_alloc_table.stream_count == 0) { #if defined(CONFIG_DRM_AMD_DC_DCN) if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING) { dp_set_fec_enable(link, false); - dp_set_fec_ready(link, false); + dp_set_fec_ready(link, link_res, false); } #else dp_set_fec_enable(link, false); - dp_set_fec_ready(link, false); + dp_set_fec_ready(link, link_res, false); #endif } } else { @@ -2646,7 +2623,7 @@ static enum dc_status enable_link( * new link settings. */ if (link->link_status.link_active) { - disable_link(link, pipe_ctx->stream->signal); + disable_link(link, &pipe_ctx->link_res, pipe_ctx->stream->signal); } switch (pipe_ctx->stream->signal) { @@ -3421,7 +3398,7 @@ static enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx, { struct dc_stream_state *stream = pipe_ctx->stream; struct dc_link *link = stream->link; - struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc; + struct hpo_dp_link_encoder *hpo_dp_link_encoder = pipe_ctx->link_res.hpo_dp_link_enc; struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc; struct link_mst_stream_allocation_table proposed_table = {0}; struct fixed31_32 avg_time_slots_per_mtp; @@ -3503,7 +3480,7 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx) struct link_encoder *link_encoder = NULL; struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc; #if defined(CONFIG_DRM_AMD_DC_DCN) - struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc; + struct hpo_dp_link_encoder *hpo_dp_link_encoder = pipe_ctx->link_res.hpo_dp_link_enc; struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc; #endif struct dp_mst_stream_allocation_table proposed_table = {0}; @@ -3833,7 +3810,7 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx) struct link_encoder *link_encoder = NULL; struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc; #if defined(CONFIG_DRM_AMD_DC_DCN) - struct hpo_dp_link_encoder *hpo_dp_link_encoder = link->hpo_dp_link_enc; + struct hpo_dp_link_encoder *hpo_dp_link_encoder = pipe_ctx->link_res.hpo_dp_link_enc; struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc; #endif struct dp_mst_stream_allocation_table proposed_table = {0}; @@ -4009,12 +3986,9 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) config.dig_be = pipe_ctx->stream->link->link_enc_hw_inst; #if defined(CONFIG_DRM_AMD_DC_DCN) config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA; - + if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY || pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { - link_enc = pipe_ctx->stream->link->link_enc; - config.dio_output_type = pipe_ctx->stream->link->ep_type; - config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY) link_enc = pipe_ctx->stream->link->link_enc; else if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) @@ -4081,7 +4055,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 @@ -4112,7 +4087,7 @@ static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pi stream->link->cur_link_settings = link_settings; /* Enable clock, Configure lane count, and Enable Link Encoder*/ - enable_dp_hpo_output(stream->link, &stream->link->cur_link_settings); + enable_dp_hpo_output(stream->link, &pipe_ctx->link_res, &stream->link->cur_link_settings); #ifdef DIAGS_BUILD /* Workaround for FPGA HPO capture DP link data: @@ -4162,12 +4137,12 @@ static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pi proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc; } - stream->link->hpo_dp_link_enc->funcs->update_stream_allocation_table( - stream->link->hpo_dp_link_enc, + pipe_ctx->link_res.hpo_dp_link_enc->funcs->update_stream_allocation_table( + pipe_ctx->link_res.hpo_dp_link_enc, &proposed_table); - stream->link->hpo_dp_link_enc->funcs->set_throttled_vcp_size( - stream->link->hpo_dp_link_enc, + pipe_ctx->link_res.hpo_dp_link_enc->funcs->set_throttled_vcp_size( + pipe_ctx->link_res.hpo_dp_link_enc, pipe_ctx->stream_res.hpo_dp_stream_enc->inst, avg_time_slots_per_mtp); @@ -4356,7 +4331,8 @@ void core_link_enable_stream( if (status != DC_FAIL_DP_LINK_TRAINING || pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { if (false == stream->link->link_status.link_active) - disable_link(stream->link, pipe_ctx->stream->signal); + disable_link(stream->link, &pipe_ctx->link_res, + pipe_ctx->stream->signal); BREAK_TO_DEBUGGER(); return; } @@ -4505,14 +4481,14 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx) * state machine. * In DP2 or MST mode, our encoder will stay video active */ - disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal); + disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal); dc->hwss.disable_stream(pipe_ctx); } else { dc->hwss.disable_stream(pipe_ctx); - disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal); + disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal); } #else - disable_link(pipe_ctx->stream->link, pipe_ctx->stream->signal); + disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal); dc->hwss.disable_stream(pipe_ctx); #endif @@ -4595,16 +4571,22 @@ void dc_link_set_drive_settings(struct dc *dc, { int i; + struct pipe_ctx *pipe = NULL; + const struct link_resource *link_res; - for (i = 0; i < dc->link_count; i++) { - if (dc->links[i] == link) - break; - } + link_res = dc_link_get_cur_link_res(link); - if (i >= dc->link_count) + for (i = 0; i < MAX_PIPES; i++) { + pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream && pipe->stream->link) { + if (pipe->stream->link == link) + break; + } + } + if (pipe && link_res) + dc_link_dp_set_drive_settings(pipe->stream->link, link_res, lt_settings); + else ASSERT_CRITICAL(false); - - dc_link_dp_set_drive_settings(dc->links[i], lt_settings); } void dc_link_set_preferred_link_settings(struct dc *dc, @@ -4665,11 +4647,9 @@ void dc_link_set_preferred_training_settings(struct dc *dc, if (link_setting != NULL) { link->preferred_link_setting = *link_setting; #if defined(CONFIG_DRM_AMD_DC_DCN) - if (dp_get_link_encoding_format(link_setting) == - DP_128b_132b_ENCODING && !link->hpo_dp_link_enc) { - if (!add_dp_hpo_link_encoder_to_link(link)) - memset(&link->preferred_link_setting, 0, sizeof(link->preferred_link_setting)); - } + if (dp_get_link_encoding_format(link_setting) == DP_128b_132b_ENCODING) + /* TODO: add dc update for acquiring link res */ + skip_immediate_retrain = true; #endif } else { link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN; @@ -4796,6 +4776,9 @@ void dc_link_overwrite_extended_receiver_cap( bool dc_link_is_fec_supported(const struct dc_link *link) { + /* TODO - use asic cap instead of link_enc->features + * we no longer know which link enc to use for this link before commit + */ struct link_encoder *link_enc = NULL; /* Links supporting dynamically assigned link encoder will be assigned next @@ -4890,3 +4873,125 @@ uint32_t dc_bandwidth_in_kbps_from_timing( return kbps; } + +const struct link_resource *dc_link_get_cur_link_res(const struct dc_link *link) +{ + int i; + struct pipe_ctx *pipe = NULL; + const struct link_resource *link_res = NULL; + + for (i = 0; i < MAX_PIPES; i++) { + pipe = &link->dc->current_state->res_ctx.pipe_ctx[i]; + if (pipe->stream && pipe->stream->link && pipe->top_pipe == NULL) { + if (pipe->stream->link == link) { + link_res = &pipe->link_res; + break; + } + } + } + + return link_res; +} + +/** + * dc_get_cur_link_res_map() - take a snapshot of current link resource allocation state + * @dc: pointer to dc of the dm calling this + * @map: a dc link resource snapshot defined internally to dc. + * + * DM needs to capture a snapshot of current link resource allocation mapping + * and store it in its persistent storage. + * + * Some of the link resource is using first come first serve policy. + * The allocation mapping depends on original hotplug order. This information + * is lost after driver is loaded next time. The snapshot is used in order to + * restore link resource to its previous state so user will get consistent + * link capability allocation across reboot. + * + * Return: none (void function) + * + */ +void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map) +{ +#if defined(CONFIG_DRM_AMD_DC_DCN) + struct dc_link *link; + uint8_t i; + uint32_t hpo_dp_recycle_map = 0; + + *map = 0; + + if (dc->caps.dp_hpo) { + for (i = 0; i < dc->caps.max_links; i++) { + link = dc->links[i]; + if (link->link_status.link_active && + dp_get_link_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING && + dp_get_link_encoding_format(&link->cur_link_settings) != DP_128b_132b_ENCODING) + /* hpo dp link encoder is considered as recycled, when RX reports 128b/132b encoding capability + * but current link doesn't use it. + */ + hpo_dp_recycle_map |= (1 << i); + } + *map |= (hpo_dp_recycle_map << LINK_RES_HPO_DP_REC_MAP__SHIFT); + } +#endif +} + +/** + * dc_restore_link_res_map() - restore link resource allocation state from a snapshot + * @dc: pointer to dc of the dm calling this + * @map: a dc link resource snapshot defined internally to dc. + * + * DM needs to call this function after initial link detection on boot and + * before first commit streams to restore link resource allocation state + * from previous boot session. + * + * Some of the link resource is using first come first serve policy. + * The allocation mapping depends on original hotplug order. This information + * is lost after driver is loaded next time. The snapshot is used in order to + * restore link resource to its previous state so user will get consistent + * link capability allocation across reboot. + * + * Return: none (void function) + * + */ +void dc_restore_link_res_map(const struct dc *dc, uint32_t *map) +{ +#if defined(CONFIG_DRM_AMD_DC_DCN) + struct dc_link *link; + uint8_t i; + unsigned int available_hpo_dp_count; + uint32_t hpo_dp_recycle_map = (*map & LINK_RES_HPO_DP_REC_MAP__MASK) + >> LINK_RES_HPO_DP_REC_MAP__SHIFT; + + if (dc->caps.dp_hpo) { + available_hpo_dp_count = dc->res_pool->hpo_dp_link_enc_count; + /* remove excess 128b/132b encoding support for not recycled links */ + for (i = 0; i < dc->caps.max_links; i++) { + if ((hpo_dp_recycle_map & (1 << i)) == 0) { + link = dc->links[i]; + if (link->type != dc_connection_none && + dp_get_link_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) { + if (available_hpo_dp_count > 0) + available_hpo_dp_count--; + else + /* remove 128b/132b encoding capability by limiting verified link rate to HBR3 */ + link->verified_link_cap.link_rate = LINK_RATE_HIGH3; + } + } + } + /* remove excess 128b/132b encoding support for recycled links */ + for (i = 0; i < dc->caps.max_links; i++) { + if ((hpo_dp_recycle_map & (1 << i)) != 0) { + link = dc->links[i]; + if (link->type != dc_connection_none && + dp_get_link_encoding_format(&link->verified_link_cap) == DP_128b_132b_ENCODING) { + if (available_hpo_dp_count > 0) + available_hpo_dp_count--; + else + /* remove 128b/132b encoding capability by limiting verified link rate to HBR3 */ + link->verified_link_cap.link_rate = LINK_RATE_HIGH3; + } + } + } + } +#endif +} |