diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/link')
41 files changed, 1420 insertions, 428 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/link/Makefile b/drivers/gpu/drm/amd/display/dc/link/Makefile index 40352d8d7648..a52b56e2859e 100644 --- a/drivers/gpu/drm/amd/display/dc/link/Makefile +++ b/drivers/gpu/drm/amd/display/dc/link/Makefile @@ -55,7 +55,7 @@ LINK_PROTOCOLS = link_hpd.o link_ddc.o link_dpcd.o link_dp_dpia.o \ link_dp_training.o link_dp_training_8b_10b.o link_dp_training_128b_132b.o \ link_dp_training_dpia.o link_dp_training_auxless.o \ link_dp_training_fixed_vs_pe_retimer.o link_dp_phy.o link_dp_capability.o \ -link_edp_panel_control.o link_dp_irq_handler.o +link_edp_panel_control.o link_dp_irq_handler.o link_dp_dpia_bw.o AMD_DAL_LINK_PROTOCOLS = $(addprefix $(AMDDALPATH)/dc/link/protocols/, \ $(LINK_PROTOCOLS)) diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c index 942300e0bd92..db9f1baa27e5 100644 --- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c +++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c @@ -28,6 +28,7 @@ #include "link/protocols/link_dp_training.h" #include "link/protocols/link_dp_phy.h" #include "link/protocols/link_dp_training_fixed_vs_pe_retimer.h" +#include "link/protocols/link_dp_capability.h" #include "link/link_dpms.h" #include "resource.h" #include "dm_helpers.h" @@ -75,7 +76,7 @@ static bool is_dp_phy_pattern(enum dp_test_pattern test_pattern) return false; } -void dp_retrain_link_dp_test(struct dc_link *link, +static void dp_retrain_link_dp_test(struct dc_link *link, struct dc_link_settings *link_setting, bool skip_video_pattern) { @@ -250,7 +251,7 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) /* prepare link training settings */ link_training_settings.link_settings = link->cur_link_settings; - link_training_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link->cur_link_settings); + link_training_settings.lttpr_mode = dp_decide_lttpr_mode(link, &link->cur_link_settings); if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && link_training_settings.lttpr_mode == LTTPR_MODE_TRANSPARENT) @@ -408,7 +409,7 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link) * all the time. Do not touch it. * forward request to DS */ - dc_link_dp_set_test_pattern( + dp_set_test_pattern( link, test_pattern, DP_TEST_PATTERN_COLOR_SPACE_UNDEFINED, @@ -585,7 +586,7 @@ static void set_crtc_test_pattern(struct dc_link *link, } } -void dc_link_dp_handle_automated_test(struct dc_link *link) +void dp_handle_automated_test(struct dc_link *link) { union test_request test_request; union test_response test_response; @@ -651,7 +652,7 @@ void dc_link_dp_handle_automated_test(struct dc_link *link) sizeof(test_response)); } -bool dc_link_dp_set_test_pattern( +bool dp_set_test_pattern( struct dc_link *link, enum dp_test_pattern test_pattern, enum dp_test_pattern_color_space test_pattern_color_space, @@ -941,28 +942,9 @@ bool dc_link_dp_set_test_pattern( return true; } -void dc_link_set_drive_settings(struct dc *dc, - struct link_training_settings *lt_settings, - const struct dc_link *link) -{ - - int i; - struct link_resource link_res; - - for (i = 0; i < dc->link_count; i++) - if (dc->links[i] == link) - break; - - if (i >= dc->link_count) - ASSERT_CRITICAL(false); - - link_get_cur_link_res(link, &link_res); - dp_set_drive_settings(dc->links[i], &link_res, lt_settings); -} - -void dc_link_set_preferred_link_settings(struct dc *dc, - struct dc_link_settings *link_setting, - struct dc_link *link) +void dp_set_preferred_link_settings(struct dc *dc, + struct dc_link_settings *link_setting, + struct dc_link *link) { int i; struct pipe_ctx *pipe; @@ -1001,11 +983,11 @@ void dc_link_set_preferred_link_settings(struct dc *dc, dp_retrain_link_dp_test(link, &store_settings, false); } -void dc_link_set_preferred_training_settings(struct dc *dc, - struct dc_link_settings *link_setting, - struct dc_link_training_overrides *lt_overrides, - struct dc_link *link, - bool skip_immediate_retrain) +void dp_set_preferred_training_settings(struct dc *dc, + struct dc_link_settings *link_setting, + struct dc_link_training_overrides *lt_overrides, + struct dc_link *link, + bool skip_immediate_retrain) { if (lt_overrides != NULL) link->preferred_training_settings = *lt_overrides; @@ -1025,22 +1007,5 @@ void dc_link_set_preferred_training_settings(struct dc *dc, /* Retrain now, or wait until next stream update to apply */ if (skip_immediate_retrain == false) - dc_link_set_preferred_link_settings(dc, &link->preferred_link_setting, link); -} - -void dc_link_set_test_pattern(struct dc_link *link, - enum dp_test_pattern test_pattern, - enum dp_test_pattern_color_space test_pattern_color_space, - const struct link_training_settings *p_link_settings, - const unsigned char *p_custom_pattern, - unsigned int cust_pattern_size) -{ - if (link != NULL) - dc_link_dp_set_test_pattern( - link, - test_pattern, - test_pattern_color_space, - p_link_settings, - p_custom_pattern, - cust_pattern_size); + dp_set_preferred_link_settings(dc, &link->preferred_link_setting, link); } diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h index 7f17838b653b..eae23ea7f6ec 100644 --- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h +++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.h @@ -25,9 +25,20 @@ #ifndef __LINK_DP_CTS_H__ #define __LINK_DP_CTS_H__ #include "link.h" - -void dp_retrain_link_dp_test(struct dc_link *link, +void dp_handle_automated_test(struct dc_link *link); +bool dp_set_test_pattern( + struct dc_link *link, + enum dp_test_pattern test_pattern, + enum dp_test_pattern_color_space test_pattern_color_space, + const struct link_training_settings *p_link_settings, + const unsigned char *p_custom_pattern, + unsigned int cust_pattern_size); +void dp_set_preferred_link_settings(struct dc *dc, struct dc_link_settings *link_setting, - bool skip_video_pattern); - + struct dc_link *link); +void dp_set_preferred_training_settings(struct dc *dc, + struct dc_link_settings *link_setting, + struct dc_link_training_overrides *lt_overrides, + struct dc_link *link, + bool skip_immediate_retrain); #endif /* __LINK_DP_CTS_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.c b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.c index 459b362ed374..fbcd8fb58ea8 100644 --- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.c +++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.c @@ -37,7 +37,7 @@ void dp_trace_reset(struct dc_link *link) memset(&link->dp_trace, 0, sizeof(link->dp_trace)); } -bool dc_dp_trace_is_initialized(struct dc_link *link) +bool dp_trace_is_initialized(struct dc_link *link) { return link->dp_trace.is_initialized; } @@ -76,7 +76,7 @@ void dp_trace_lt_total_count_increment(struct dc_link *link, link->dp_trace.commit_lt_trace.counts.total++; } -void dc_dp_trace_set_is_logged_flag(struct dc_link *link, +void dp_trace_set_is_logged_flag(struct dc_link *link, bool in_detection, bool is_logged) { @@ -86,8 +86,7 @@ void dc_dp_trace_set_is_logged_flag(struct dc_link *link, link->dp_trace.commit_lt_trace.is_logged = is_logged; } -bool dc_dp_trace_is_logged(struct dc_link *link, - bool in_detection) +bool dp_trace_is_logged(struct dc_link *link, bool in_detection) { if (in_detection) return link->dp_trace.detect_lt_trace.is_logged; @@ -123,7 +122,7 @@ void dp_trace_set_lt_end_timestamp(struct dc_link *link, link->dp_trace.commit_lt_trace.timestamps.end = dm_get_timestamp(link->dc->ctx); } -unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link, +unsigned long long dp_trace_get_lt_end_timestamp(struct dc_link *link, bool in_detection) { if (in_detection) @@ -132,7 +131,7 @@ unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link, return link->dp_trace.commit_lt_trace.timestamps.end; } -struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link, +const struct dp_trace_lt_counts *dp_trace_get_lt_counts(struct dc_link *link, bool in_detection) { if (in_detection) @@ -141,12 +140,12 @@ struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link, return &link->dp_trace.commit_lt_trace.counts; } -unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link) +unsigned int dp_trace_get_link_loss_count(struct dc_link *link) { return link->dp_trace.link_loss_count; } -void link_dp_trace_set_edp_power_timestamp(struct dc_link *link, +void dp_trace_set_edp_power_timestamp(struct dc_link *link, bool power_up) { if (!power_up) @@ -156,17 +155,17 @@ void link_dp_trace_set_edp_power_timestamp(struct dc_link *link, link->dp_trace.edp_trace_power_timestamps.poweron = dm_get_timestamp(link->dc->ctx); } -uint64_t link_dp_trace_get_edp_poweron_timestamp(struct dc_link *link) +uint64_t dp_trace_get_edp_poweron_timestamp(struct dc_link *link) { return link->dp_trace.edp_trace_power_timestamps.poweron; } -uint64_t link_dp_trace_get_edp_poweroff_timestamp(struct dc_link *link) +uint64_t dp_trace_get_edp_poweroff_timestamp(struct dc_link *link) { return link->dp_trace.edp_trace_power_timestamps.poweroff; } -void link_dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode) +void dp_trace_source_sequence(struct dc_link *link, uint8_t dp_test_mode) { if (link != NULL && link->dc->debug.enable_driver_sequence_debug) core_link_write_dpcd(link, DP_SOURCE_SEQUENCE, diff --git a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.h b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.h index 89feea1b2692..ab437a0c9101 100644 --- a/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.h +++ b/drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_trace.h @@ -28,7 +28,7 @@ void dp_trace_init(struct dc_link *link); void dp_trace_reset(struct dc_link *link); -bool dc_dp_trace_is_initialized(struct dc_link *link); +bool dp_trace_is_initialized(struct dc_link *link); void dp_trace_detect_lt_init(struct dc_link *link); void dp_trace_commit_lt_init(struct dc_link *link); void dp_trace_link_loss_increment(struct dc_link *link); @@ -37,10 +37,10 @@ void dp_trace_lt_fail_count_update(struct dc_link *link, bool in_detection); void dp_trace_lt_total_count_increment(struct dc_link *link, bool in_detection); -void dc_dp_trace_set_is_logged_flag(struct dc_link *link, +void dp_trace_set_is_logged_flag(struct dc_link *link, bool in_detection, bool is_logged); -bool dc_dp_trace_is_logged(struct dc_link *link, +bool dp_trace_is_logged(struct dc_link *link, bool in_detection); void dp_trace_lt_result_update(struct dc_link *link, enum link_training_result result, @@ -49,10 +49,15 @@ void dp_trace_set_lt_start_timestamp(struct dc_link *link, bool in_detection); void dp_trace_set_lt_end_timestamp(struct dc_link *link, bool in_detection); -unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link, +unsigned long long dp_trace_get_lt_end_timestamp(struct dc_link *link, bool in_detection); -struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link, +const struct dp_trace_lt_counts *dp_trace_get_lt_counts(struct dc_link *link, bool in_detection); -unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link); +unsigned int dp_trace_get_link_loss_count(struct dc_link *link); +void dp_trace_set_edp_power_timestamp(struct dc_link *link, + bool power_up); +uint64_t dp_trace_get_edp_poweron_timestamp(struct dc_link *link); +uint64_t dp_trace_get_edp_poweroff_timestamp(struct dc_link *link); +void dp_trace_source_sequence(struct dc_link *link, uint8_t dp_test_mode); #endif /* __LINK_DP_TRACE_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c index b092b00b3599..bebf9c4c8702 100644 --- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c +++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_dio.c @@ -44,7 +44,7 @@ void setup_dio_stream_encoder(struct pipe_ctx *pipe_ctx) link_enc->funcs->connect_dig_be_to_fe(link_enc, pipe_ctx->stream_res.stream_enc->id, true); if (dc_is_dp_signal(pipe_ctx->stream->signal)) - link_dp_source_sequence_trace(pipe_ctx->stream->link, + pipe_ctx->stream->ctx->dc->link_srv->dp_trace_source_sequence(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE); if (stream_enc->funcs->enable_fifo) stream_enc->funcs->enable_fifo(stream_enc); @@ -63,7 +63,8 @@ void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx) pipe_ctx->stream_res.stream_enc->id, false); if (dc_is_dp_signal(pipe_ctx->stream->signal)) - link_dp_source_sequence_trace(pipe_ctx->stream->link, + pipe_ctx->stream->ctx->dc->link_srv->dp_trace_source_sequence( + pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE); } @@ -105,7 +106,8 @@ void setup_dio_stream_attribute(struct pipe_ctx *pipe_ctx) &stream->timing); if (dc_is_dp_signal(stream->signal)) - link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR); + link->dc->link_srv->dp_trace_source_sequence(link, + DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR); } void enable_dio_dp_link_output(struct dc_link *link, @@ -126,7 +128,8 @@ void enable_dio_dp_link_output(struct dc_link *link, link_enc, link_settings, clock_source); - link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY); + link->dc->link_srv->dp_trace_source_sequence(link, + DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY); } void disable_dio_link_output(struct dc_link *link, @@ -136,7 +139,8 @@ void disable_dio_link_output(struct dc_link *link, struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link); link_enc->funcs->disable_output(link_enc, signal); - link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); + link->dc->link_srv->dp_trace_source_sequence(link, + DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY); } void set_dio_dp_link_test_pattern(struct dc_link *link, @@ -146,7 +150,7 @@ void set_dio_dp_link_test_pattern(struct dc_link *link, struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link); link_enc->funcs->dp_set_phy_pattern(link_enc, tp_params); - link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN); + link->dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN); } void set_dio_dp_lane_settings(struct dc_link *link, @@ -195,7 +199,8 @@ void enable_dio_audio_packet(struct pipe_ctx *pipe_ctx) pipe_ctx->stream_res.stream_enc, false); if (dc_is_dp_signal(pipe_ctx->stream->signal)) - link_dp_source_sequence_trace(pipe_ctx->stream->link, + pipe_ctx->stream->ctx->dc->link_srv->dp_trace_source_sequence( + pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_ENABLE_AUDIO_STREAM); } @@ -214,7 +219,8 @@ void disable_dio_audio_packet(struct pipe_ctx *pipe_ctx) } if (dc_is_dp_signal(pipe_ctx->stream->signal)) - link_dp_source_sequence_trace(pipe_ctx->stream->link, + pipe_ctx->stream->ctx->dc->link_srv->dp_trace_source_sequence( + pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_DISABLE_AUDIO_STREAM); } diff --git a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c index aa1c5e253b43..edd7d026a762 100644 --- a/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c +++ b/drivers/gpu/drm/amd/display/dc/link/hwss/link_hwss_hpo_dp.c @@ -68,7 +68,8 @@ static void set_hpo_dp_hblank_min_symbol_width(struct pipe_ctx *pipe_ctx, struct dc_crtc_timing *timing = &pipe_ctx->stream->timing; struct fixed31_32 h_blank_in_ms, time_slot_in_ms, mtp_cnt_per_h_blank; uint32_t link_bw_in_kbps = - dc_link_bandwidth_kbps(pipe_ctx->stream->link, link_settings); + hpo_dp_stream_encoder->ctx->dc->link_srv->dp_link_bandwidth_kbps( + pipe_ctx->stream->link, link_settings); uint16_t hblank_min_symbol_width = 0; if (link_bw_in_kbps > 0) { @@ -115,7 +116,8 @@ static void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx) stream->use_vsc_sdp_for_colorimetry, stream->timing.flags.DSC, false); - link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR); + link->dc->link_srv->dp_trace_source_sequence(link, + DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR); } static void enable_hpo_dp_fpga_link_output(struct dc_link *link, @@ -201,7 +203,7 @@ static void set_hpo_dp_link_test_pattern(struct dc_link *link, { link_res->hpo_dp_link_enc->funcs->set_link_test_pattern( link_res->hpo_dp_link_enc, tp_params); - link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN); + link->dc->link_srv->dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN); } static void set_hpo_dp_lane_settings(struct dc_link *link, diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.c b/drivers/gpu/drm/amd/display/dc/link/link_detection.c index f70025ef7b69..a131e30fd7d6 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.c @@ -60,6 +60,10 @@ */ #define LINK_TRAINING_MAX_VERIFY_RETRY 2 +static const u8 DP_SINK_BRANCH_DEV_NAME_7580[] = "7580\x80u"; + +static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR"; + static enum ddc_transaction_type get_ddc_transaction_type(enum signal_type sink_signal) { enum ddc_transaction_type transaction_type = DDC_TRANSACTION_TYPE_NONE; @@ -466,7 +470,6 @@ static void link_disconnect_remap(struct dc_sink *prev_sink, struct dc_link *lin link->local_sink = prev_sink; } -#if defined(CONFIG_DRM_AMD_DC_HDCP) static void query_hdcp_capability(enum signal_type signal, struct dc_link *link) { struct hdcp_protection_message msg22; @@ -495,8 +498,6 @@ static void query_hdcp_capability(enum signal_type signal, struct dc_link *link) dc_process_hdcp_msg(signal, link, &msg22); if (signal == SIGNAL_TYPE_DISPLAY_PORT || signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { - enum hdcp_message_status status = HDCP_MESSAGE_UNSUPPORTED; - msg14.data = &link->hdcp_caps.bcaps.raw; msg14.length = sizeof(link->hdcp_caps.bcaps.raw); msg14.msg_id = HDCP_MESSAGE_ID_READ_BCAPS; @@ -504,11 +505,10 @@ static void query_hdcp_capability(enum signal_type signal, struct dc_link *link) msg14.link = HDCP_LINK_PRIMARY; msg14.max_retries = 5; - status = dc_process_hdcp_msg(signal, link, &msg14); + dc_process_hdcp_msg(signal, link, &msg14); } } -#endif // CONFIG_DRM_AMD_DC_HDCP static void read_current_link_settings_on_detect(struct dc_link *link) { union lane_count_set lane_count_set = {0}; @@ -832,7 +832,7 @@ static void verify_link_capability(struct dc_link *link, struct dc_sink *sink, verify_link_capability_non_destructive(link); } -/** +/* * detect_link_and_local_sink() - Detect if a sink is attached to a given link * * link->local_sink is created or destroyed as needed. @@ -879,7 +879,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, return true; } - if (!dc_link_detect_connection_type(link, &new_connection_type)) { + if (!link_detect_connection_type(link, &new_connection_type)) { BREAK_TO_DEBUGGER(); return false; } @@ -1087,9 +1087,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, * TODO debug why certain monitors don't like * two link trainings */ -#if defined(CONFIG_DRM_AMD_DC_HDCP) query_hdcp_capability(sink->sink_signal, link); -#endif } else { // If edid is the same, then discard new sink and revert back to original sink if (same_edid) { @@ -1097,9 +1095,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, sink = prev_sink; prev_sink = NULL; } -#if defined(CONFIG_DRM_AMD_DC_HDCP) query_hdcp_capability(sink->sink_signal, link); -#endif } /* HDMI-DVI Dongle */ @@ -1165,9 +1161,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, /* From Connected-to-Disconnected. */ link->type = dc_connection_none; sink_caps.signal = SIGNAL_TYPE_NONE; -#if defined(CONFIG_DRM_AMD_DC_HDCP) memset(&link->hdcp_caps, 0, sizeof(struct hdcp_caps)); -#endif /* When we unplug a passive DP-HDMI dongle connection, dongle_max_pix_clk * is not cleared. If we emulate a DP signal on this connection, it thinks * the dongle is still there and limits the number of modes we can emulate. @@ -1191,8 +1185,8 @@ static bool detect_link_and_local_sink(struct dc_link *link, return true; } -/** - * dc_link_detect_connection_type() - Determine if there is a sink connected +/* + * link_detect_connection_type() - Determine if there is a sink connected * * @type: Returned connection type * Does not detect downstream devices, such as MST sinks @@ -1216,7 +1210,7 @@ bool link_detect_connection_type(struct dc_link *link, enum dc_connection_type * /* Link may not have physical HPD pin. */ if (link->ep_type != DISPLAY_ENDPOINT_PHY) { - if (link->is_hpd_pending || !dc_link_dpia_query_hpd_status(link)) + if (link->is_hpd_pending || !dpia_query_hpd_status(link)) *type = dc_connection_none; else *type = dc_connection_single; @@ -1233,6 +1227,11 @@ bool link_detect_connection_type(struct dc_link *link, enum dc_connection_type * /* TODO: need to do the actual detection */ } else { *type = dc_connection_none; + if (link->connector_signal == SIGNAL_TYPE_EDP) { + /* eDP is not connected, power down it */ + if (!link->dc->config.edp_no_power_sequencing) + link->dc->hwss.edp_power_control(link, false); + } } return true; @@ -1274,7 +1273,6 @@ void link_clear_dprx_states(struct dc_link *link) { memset(&link->dprx_states, 0, sizeof(link->dprx_states)); } -#if defined(CONFIG_DRM_AMD_DC_HDCP) bool link_is_hdcp14(struct dc_link *link, enum signal_type signal) { @@ -1322,10 +1320,108 @@ bool link_is_hdcp22(struct dc_link *link, enum signal_type signal) return ret; } -#endif // CONFIG_DRM_AMD_DC_HDCP const struct dc_link_status *link_get_status(const struct dc_link *link) { return &link->link_status; } + +static bool link_add_remote_sink_helper(struct dc_link *dc_link, struct dc_sink *sink) +{ + if (dc_link->sink_count >= MAX_SINKS_PER_LINK) { + BREAK_TO_DEBUGGER(); + return false; + } + + dc_sink_retain(sink); + + dc_link->remote_sinks[dc_link->sink_count] = sink; + dc_link->sink_count++; + + return true; +} + +struct dc_sink *link_add_remote_sink( + struct dc_link *link, + const uint8_t *edid, + int len, + struct dc_sink_init_data *init_data) +{ + struct dc_sink *dc_sink; + enum dc_edid_status edid_status; + + if (len > DC_MAX_EDID_BUFFER_SIZE) { + dm_error("Max EDID buffer size breached!\n"); + return NULL; + } + + if (!init_data) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + if (!init_data->link) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dc_sink = dc_sink_create(init_data); + + if (!dc_sink) + return NULL; + + memmove(dc_sink->dc_edid.raw_edid, edid, len); + dc_sink->dc_edid.length = len; + + if (!link_add_remote_sink_helper( + link, + dc_sink)) + goto fail_add_sink; + + edid_status = dm_helpers_parse_edid_caps( + link, + &dc_sink->dc_edid, + &dc_sink->edid_caps); + + /* + * Treat device as no EDID device if EDID + * parsing fails + */ + if (edid_status != EDID_OK && edid_status != EDID_PARTIAL_VALID) { + dc_sink->dc_edid.length = 0; + dm_error("Bad EDID, status%d!\n", edid_status); + } + + return dc_sink; + +fail_add_sink: + dc_sink_release(dc_sink); + return NULL; +} + +void link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink) +{ + int i; + + if (!link->sink_count) { + BREAK_TO_DEBUGGER(); + return; + } + + for (i = 0; i < link->sink_count; i++) { + if (link->remote_sinks[i] == sink) { + dc_sink_release(sink); + link->remote_sinks[i] = NULL; + + /* shrink array to remove empty place */ + while (i < link->sink_count - 1) { + link->remote_sinks[i] = link->remote_sinks[i+1]; + i++; + } + link->remote_sinks[i] = NULL; + link->sink_count--; + return; + } + } +} diff --git a/drivers/gpu/drm/amd/display/dc/link/link_detection.h b/drivers/gpu/drm/amd/display/dc/link/link_detection.h index 1831636516fb..7da05078721e 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_detection.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_detection.h @@ -26,5 +26,18 @@ #ifndef __DC_LINK_DETECTION_H__ #define __DC_LINK_DETECTION_H__ #include "link.h" - +bool link_detect(struct dc_link *link, enum dc_detect_reason reason); +bool link_detect_connection_type(struct dc_link *link, + enum dc_connection_type *type); +struct dc_sink *link_add_remote_sink( + struct dc_link *link, + const uint8_t *edid, + int len, + struct dc_sink_init_data *init_data); +void link_remove_remote_sink(struct dc_link *link, struct dc_sink *sink); +bool link_reset_cur_dp_mst_topology(struct dc_link *link); +const struct dc_link_status *link_get_status(const struct dc_link *link); +bool link_is_hdcp14(struct dc_link *link, enum signal_type signal); +bool link_is_hdcp22(struct dc_link *link, enum signal_type signal); +void link_clear_dprx_states(struct dc_link *link); #endif /* __DC_LINK_DETECTION_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c index 257e1c3ba00a..027ad1f0144d 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c @@ -37,6 +37,7 @@ #include "link_dpms.h" #include "link_hwss.h" +#include "link_validation.h" #include "accessories/link_fpga.h" #include "accessories/link_dp_trace.h" #include "protocols/link_dpcd.h" @@ -46,6 +47,7 @@ #include "protocols/link_dp_capability.h" #include "protocols/link_dp_training.h" #include "protocols/link_edp_panel_control.h" +#include "protocols/link_dp_dpia_bw.h" #include "dm_helpers.h" #include "link_enc_cfg.h" @@ -136,7 +138,7 @@ void link_blank_dp_stream(struct dc_link *link, bool hw_init) } if ((!link->wa_flags.dp_keep_receiver_powered) || hw_init) - dc_link_dp_receiver_power_ctrl(link, false); + dpcd_write_rx_power_ctrl(link, false); } } @@ -646,7 +648,6 @@ static void write_i2c_redriver_setting( if (!i2c_success) DC_LOG_DEBUG("Set redriver failed"); } -#if defined(CONFIG_DRM_AMD_DC_HDCP) static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) { @@ -672,7 +673,7 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) /* stream encoder index */ config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA; - if (link_is_dp_128b_132b_signal(pipe_ctx)) + if (dp_is_128b_132b_signal(pipe_ctx)) config.stream_enc_idx = pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0; @@ -681,7 +682,7 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) /* link encoder index */ config.link_enc_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A; - if (link_is_dp_128b_132b_signal(pipe_ctx)) + if (dp_is_128b_132b_signal(pipe_ctx)) config.link_enc_idx = pipe_ctx->link_res.hpo_dp_link_enc->inst; /* dio output index is dpia index for DPIA endpoint & dcio index by default */ @@ -702,7 +703,7 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) config.assr_enabled = (panel_mode == DP_PANEL_MODE_EDP) ? 1 : 0; config.mst_enabled = (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) ? 1 : 0; - config.dp2_enabled = link_is_dp_128b_132b_signal(pipe_ctx) ? 1 : 0; + config.dp2_enabled = dp_is_128b_132b_signal(pipe_ctx) ? 1 : 0; config.usb4_enabled = (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) ? 1 : 0; config.dpms_off = dpms_off; @@ -712,7 +713,6 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off) cp_psp->funcs.update_stream_config(cp_psp->handle, &config); } -#endif static void set_avmute(struct pipe_ctx *pipe_ctx, bool enable) { @@ -817,7 +817,7 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) /* Enable DSC in encoder */ if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) - && !link_is_dp_128b_132b_signal(pipe_ctx)) { + && !dp_is_128b_132b_signal(pipe_ctx)) { DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id); dsc_optc_config_log(dsc, &dsc_optc_cfg); pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc, @@ -843,7 +843,7 @@ void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) /* disable DSC in stream encoder */ if (dc_is_dp_signal(stream->signal)) { - if (link_is_dp_128b_132b_signal(pipe_ctx)) + if (dp_is_128b_132b_signal(pipe_ctx)) pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet( pipe_ctx->stream_res.hpo_dp_stream_enc, false, @@ -902,7 +902,7 @@ bool link_set_dsc_pps_packet(struct pipe_ctx *pipe_ctx, bool enable, bool immedi memcpy(&stream->dsc_packed_pps[0], &dsc_packed_pps[0], sizeof(stream->dsc_packed_pps)); if (dc_is_dp_signal(stream->signal)) { DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id); - if (link_is_dp_128b_132b_signal(pipe_ctx)) + if (dp_is_128b_132b_signal(pipe_ctx)) pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet( pipe_ctx->stream_res.hpo_dp_stream_enc, true, @@ -919,7 +919,7 @@ bool link_set_dsc_pps_packet(struct pipe_ctx *pipe_ctx, bool enable, bool immedi /* disable DSC PPS in stream encoder */ memset(&stream->dsc_packed_pps[0], 0, sizeof(stream->dsc_packed_pps)); if (dc_is_dp_signal(stream->signal)) { - if (link_is_dp_128b_132b_signal(pipe_ctx)) + if (dp_is_128b_132b_signal(pipe_ctx)) pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet( pipe_ctx->stream_res.hpo_dp_stream_enc, false, @@ -1001,7 +1001,7 @@ static void enable_stream_features(struct pipe_ctx *pipe_ctx) } } -static void dc_log_vcp_x_y(const struct dc_link *link, struct fixed31_32 avg_time_slots_per_mtp) +static void log_vcp_x_y(const struct dc_link *link, struct fixed31_32 avg_time_slots_per_mtp) { const uint32_t VCP_Y_PRECISION = 1000; uint64_t vcp_x, vcp_y; @@ -1044,7 +1044,7 @@ static void dc_log_vcp_x_y(const struct dc_link *link, struct fixed31_32 avg_tim static struct fixed31_32 get_pbn_per_slot(struct dc_stream_state *stream) { struct fixed31_32 mbytes_per_sec; - uint32_t link_rate_in_mbytes_per_sec = dc_link_bandwidth_kbps(stream->link, + uint32_t link_rate_in_mbytes_per_sec = dp_link_bandwidth_kbps(stream->link, &stream->link->cur_link_settings); link_rate_in_mbytes_per_sec /= 8000; /* Kbits to MBytes */ @@ -1153,7 +1153,7 @@ static bool poll_for_allocation_change_trigger(struct dc_link *link) break; } - msleep(5); + fsleep(5000); } if (result == ACT_FAILED) { @@ -1517,7 +1517,7 @@ static enum dc_status allocate_mst_payload(struct pipe_ctx *pipe_ctx) pbn = get_pbn_from_timing(pipe_ctx); avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot); - dc_log_vcp_x_y(link, avg_time_slots_per_mtp); + log_vcp_x_y(link, avg_time_slots_per_mtp); if (link_hwss->ext.set_throttled_vcp_size) link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp); @@ -1535,7 +1535,7 @@ struct fixed31_32 link_calculate_sst_avg_time_slots_per_mtp( { struct fixed31_32 link_bw_effective = dc_fixpt_from_int( - dc_link_bandwidth_kbps(link, &link->cur_link_settings)); + dp_link_bandwidth_kbps(link, &link->cur_link_settings)); struct fixed31_32 timeslot_bw_effective = dc_fixpt_div_int(link_bw_effective, MAX_MTP_SLOT_COUNT); struct fixed31_32 timing_bw = @@ -1640,7 +1640,7 @@ static bool write_128b_132b_sst_payload_allocation_table( } } retries++; - msleep(5); + fsleep(5000); } if (!result && retries == max_retries) { @@ -1670,7 +1670,7 @@ static enum dc_status update_sst_payload(struct pipe_ctx *pipe_ctx, if (!allocate) { avg_time_slots_per_mtp = dc_fixpt_from_int(0); - dc_log_vcp_x_y(link, avg_time_slots_per_mtp); + log_vcp_x_y(link, avg_time_slots_per_mtp); if (link_hwss->ext.set_throttled_vcp_size) link_hwss->ext.set_throttled_vcp_size(pipe_ctx, @@ -1721,7 +1721,7 @@ static enum dc_status update_sst_payload(struct pipe_ctx *pipe_ctx, DP_128b_132b_ENCODING) { avg_time_slots_per_mtp = link_calculate_sst_avg_time_slots_per_mtp(stream, link); - dc_log_vcp_x_y(link, avg_time_slots_per_mtp); + log_vcp_x_y(link, avg_time_slots_per_mtp); if (link_hwss->ext.set_throttled_vcp_size) link_hwss->ext.set_throttled_vcp_size(pipe_ctx, @@ -2035,6 +2035,12 @@ static enum dc_status enable_link_dp(struct dc_state *state, uint32_t post_oui_delay = 30; // 30ms /* Reduce link bandwidth between failed link training attempts. */ bool do_fallback = false; + int lt_attempts = LINK_TRAINING_ATTEMPTS; + + // Increase retry count if attempting DP1.x on FIXED_VS link + if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && + link_dp_get_encoding_format(link_settings) == DP_8b_10b_ENCODING) + lt_attempts = 10; // check for seamless boot for (i = 0; i < state->stream_count; i++) { @@ -2044,11 +2050,17 @@ static enum dc_status enable_link_dp(struct dc_state *state, } } - /* Train with fallback when enabling DPIA link. Conventional links are + /* + * If the link is DP-over-USB4 do the following: + * - Train with fallback when enabling DPIA link. Conventional links are * trained with fallback during sink detection. + * - Allocate only what the stream needs for bw in Gbps. Inform the CM + * in case stream needs more or less bw from what has been allocated + * earlier at plug time. */ - if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) + if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { do_fallback = true; + } /* * Temporary w/a to get DP2.0 link rates to work with SST. @@ -2093,7 +2105,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, if (perform_link_training_with_retries(link_settings, skip_video_pattern, - LINK_TRAINING_ATTEMPTS, + lt_attempts, pipe_ctx, pipe_ctx->stream->signal, do_fallback)) { @@ -2117,7 +2129,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, set_default_brightness_aux(link); // TODO: use cached if known if (link->dpcd_sink_ext_caps.bits.oled == 1) msleep(bl_oled_enable_delay); - link_backlight_enable_aux(link, true); + edp_backlight_enable_aux(link, true); } return status; @@ -2154,6 +2166,7 @@ static enum dc_status enable_link_dp_mst( struct pipe_ctx *pipe_ctx) { struct dc_link *link = pipe_ctx->stream->link; + unsigned char mstm_cntl; /* sink signal type after MST branch is MST. Multiple MST sinks * share one link. Link DP PHY is enable or training only once. @@ -2162,7 +2175,9 @@ static enum dc_status enable_link_dp_mst( return DC_OK; /* clear payload table */ - dm_helpers_dp_mst_clear_payload_allocation_table(link->ctx, link); + core_link_read_dpcd(link, DP_MSTM_CTRL, &mstm_cntl, 1); + if (mstm_cntl & DP_MST_EN) + dm_helpers_dp_mst_clear_payload_allocation_table(link->ctx, link); /* to make sure the pending down rep can be processed * before enabling the link @@ -2237,7 +2252,7 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx) ASSERT(is_master_pipe_for_link(link, pipe_ctx)); - if (link_is_dp_128b_132b_signal(pipe_ctx)) + if (dp_is_128b_132b_signal(pipe_ctx)) vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg; DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); @@ -2262,15 +2277,13 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx) dc->hwss.disable_audio_stream(pipe_ctx); -#if defined(CONFIG_DRM_AMD_DC_HDCP) update_psp_stream_config(pipe_ctx, true); -#endif dc->hwss.blank_stream(pipe_ctx); if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) deallocate_mst_payload(pipe_ctx); else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT && - link_is_dp_128b_132b_signal(pipe_ctx)) + dp_is_128b_132b_signal(pipe_ctx)) update_sst_payload(pipe_ctx, false); if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) { @@ -2299,7 +2312,7 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx) } if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT && - !link_is_dp_128b_132b_signal(pipe_ctx)) { + !dp_is_128b_132b_signal(pipe_ctx)) { /* In DP1.x SST mode, our encoder will go to TPS1 * when link is on but stream is off. @@ -2319,7 +2332,7 @@ void link_set_dpms_off(struct pipe_ctx *pipe_ctx) if (dc_is_dp_signal(pipe_ctx->stream->signal)) link_set_dsc_enable(pipe_ctx, false); } - if (link_is_dp_128b_132b_signal(pipe_ctx)) { + if (dp_is_128b_132b_signal(pipe_ctx)) { if (pipe_ctx->stream_res.tg->funcs->set_out_mux) pipe_ctx->stream_res.tg->funcs->set_out_mux(pipe_ctx->stream_res.tg, OUT_MUX_DIO); } @@ -2343,7 +2356,7 @@ void link_set_dpms_on( ASSERT(is_master_pipe_for_link(link, pipe_ctx)); - if (link_is_dp_128b_132b_signal(pipe_ctx)) + if (dp_is_128b_132b_signal(pipe_ctx)) vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg; DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger); @@ -2365,7 +2378,7 @@ void link_set_dpms_on( ASSERT(link_enc); if (!dc_is_virtual_signal(pipe_ctx->stream->signal) - && !link_is_dp_128b_132b_signal(pipe_ctx)) { + && !dp_is_128b_132b_signal(pipe_ctx)) { if (link_enc) link_enc->funcs->setup( link_enc, @@ -2375,7 +2388,7 @@ void link_set_dpms_on( pipe_ctx->stream->link->link_state_valid = true; if (pipe_ctx->stream_res.tg->funcs->set_out_mux) { - if (link_is_dp_128b_132b_signal(pipe_ctx)) + if (dp_is_128b_132b_signal(pipe_ctx)) otg_out_dest = OUT_MUX_HPO_DP; else otg_out_dest = OUT_MUX_DIO; @@ -2398,7 +2411,7 @@ void link_set_dpms_on( dc->hwss.update_info_frame(pipe_ctx); if (dc_is_dp_signal(pipe_ctx->stream->signal)) - link_dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME); + dp_trace_source_sequence(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME); /* Do not touch link on seamless boot optimization. */ if (pipe_ctx->stream->apply_seamless_boot_optimization) { @@ -2410,9 +2423,7 @@ void link_set_dpms_on( dc->hwss.enable_audio_stream(pipe_ctx); } -#if defined(CONFIG_DRM_AMD_DC_HDCP) update_psp_stream_config(pipe_ctx, false); -#endif return; } @@ -2422,9 +2433,7 @@ void link_set_dpms_on( !pipe_ctx->stream->timing.flags.DSC && !pipe_ctx->next_odm_pipe) { pipe_ctx->stream->dpms_off = false; -#if defined(CONFIG_DRM_AMD_DC_HDCP) update_psp_stream_config(pipe_ctx, false); -#endif return; } @@ -2477,11 +2486,12 @@ void link_set_dpms_on( * from transmitter control. */ if (!(dc_is_virtual_signal(pipe_ctx->stream->signal) || - link_is_dp_128b_132b_signal(pipe_ctx))) - if (link_enc) - link_enc->funcs->setup( - link_enc, - pipe_ctx->stream->signal); + dp_is_128b_132b_signal(pipe_ctx))) { + if (link_enc) + link_enc->funcs->setup( + link_enc, + pipe_ctx->stream->signal); + } dc->hwss.enable_stream(pipe_ctx); @@ -2497,7 +2507,7 @@ void link_set_dpms_on( if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST) allocate_mst_payload(pipe_ctx); else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT && - link_is_dp_128b_132b_signal(pipe_ctx)) + dp_is_128b_132b_signal(pipe_ctx)) update_sst_payload(pipe_ctx, true); dc->hwss.unblank_stream(pipe_ctx, @@ -2508,14 +2518,12 @@ void link_set_dpms_on( if (dc_is_dp_signal(pipe_ctx->stream->signal)) enable_stream_features(pipe_ctx); -#if defined(CONFIG_DRM_AMD_DC_HDCP) update_psp_stream_config(pipe_ctx, false); -#endif dc->hwss.enable_audio_stream(pipe_ctx); } else { // if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) - if (link_is_dp_128b_132b_signal(pipe_ctx)) + if (dp_is_128b_132b_signal(pipe_ctx)) dp_fpga_hpo_enable_link_and_stream(state, pipe_ctx); if (dc_is_dp_signal(pipe_ctx->stream->signal) || dc_is_virtual_signal(pipe_ctx->stream->signal)) diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.h b/drivers/gpu/drm/amd/display/dc/link/link_dpms.h index 33d312dabdb8..9398f9c1666a 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.h @@ -27,14 +27,27 @@ #define __DC_LINK_DPMS_H__ #include "link.h" -bool link_set_dsc_pps_packet(struct pipe_ctx *pipe_ctx, - bool enable, bool immediate_update); -struct fixed31_32 link_calculate_sst_avg_time_slots_per_mtp( - const struct dc_stream_state *stream, - const struct dc_link *link); +void link_set_dpms_on( + struct dc_state *state, + struct pipe_ctx *pipe_ctx); +void link_set_dpms_off(struct pipe_ctx *pipe_ctx); +void link_resume(struct dc_link *link); +void link_blank_all_dp_displays(struct dc *dc); +void link_blank_all_edp_displays(struct dc *dc); +void link_blank_dp_stream(struct dc_link *link, bool hw_init); void link_set_all_streams_dpms_off_for_link(struct dc_link *link); void link_get_master_pipes_with_dpms_on(const struct dc_link *link, struct dc_state *state, uint8_t *count, struct pipe_ctx *pipes[MAX_PIPES]); +enum dc_status link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn); +enum dc_status link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn); +bool link_set_dsc_pps_packet(struct pipe_ctx *pipe_ctx, + bool enable, bool immediate_update); +struct fixed31_32 link_calculate_sst_avg_time_slots_per_mtp( + const struct dc_stream_state *stream, + const struct dc_link *link); +void link_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable); +bool link_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable); +bool link_update_dsc_config(struct pipe_ctx *pipe_ctx); #endif /* __DC_LINK_DPMS_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c index aeb26a4d539e..1515c817f03b 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -27,7 +27,20 @@ * This file owns the creation/destruction of link structure. */ #include "link_factory.h" +#include "link_detection.h" +#include "link_resource.h" +#include "link_validation.h" +#include "link_dpms.h" +#include "accessories/link_dp_cts.h" +#include "accessories/link_dp_trace.h" +#include "accessories/link_fpga.h" #include "protocols/link_ddc.h" +#include "protocols/link_dp_capability.h" +#include "protocols/link_dp_dpia_bw.h" +#include "protocols/link_dp_dpia.h" +#include "protocols/link_dp_irq_handler.h" +#include "protocols/link_dp_phy.h" +#include "protocols/link_dp_training.h" #include "protocols/link_edp_panel_control.h" #include "protocols/link_hpd.h" #include "gpio_service_interface.h" @@ -39,7 +52,249 @@ DC_LOG_HW_HOTPLUG( \ __VA_ARGS__) -static enum transmitter translate_encoder_to_transmitter(struct graphics_object_id encoder) +/* link factory owns the creation/destruction of link structures. */ +static void construct_link_service_factory(struct link_service *link_srv) +{ + + link_srv->create_link = link_create; + link_srv->destroy_link = link_destroy; +} + +/* link_detection manages link detection states and receiver states by using + * various link protocols. It also provides helper functions to interpret + * certain capabilities or status based on the states it manages or retrieve + * them directly from connected receivers. + */ +static void construct_link_service_detection(struct link_service *link_srv) +{ + link_srv->detect_link = link_detect; + link_srv->detect_connection_type = link_detect_connection_type; + link_srv->add_remote_sink = link_add_remote_sink; + link_srv->remove_remote_sink = link_remove_remote_sink; + link_srv->get_hpd_state = link_get_hpd_state; + link_srv->get_hpd_gpio = link_get_hpd_gpio; + link_srv->enable_hpd = link_enable_hpd; + link_srv->disable_hpd = link_disable_hpd; + link_srv->enable_hpd_filter = link_enable_hpd_filter; + link_srv->reset_cur_dp_mst_topology = link_reset_cur_dp_mst_topology; + link_srv->get_status = link_get_status; + link_srv->is_hdcp1x_supported = link_is_hdcp14; + link_srv->is_hdcp2x_supported = link_is_hdcp22; + link_srv->clear_dprx_states = link_clear_dprx_states; +} + +/* link resource implements accessors to link resource. */ +static void construct_link_service_resource(struct link_service *link_srv) +{ + link_srv->get_cur_res_map = link_get_cur_res_map; + link_srv->restore_res_map = link_restore_res_map; + link_srv->get_cur_link_res = link_get_cur_link_res; +} + +/* link validation owns timing validation against various link limitations. (ex. + * link bandwidth, receiver capability or our hardware capability) It also + * provides helper functions exposing bandwidth formulas used in validation. + */ +static void construct_link_service_validation(struct link_service *link_srv) +{ + link_srv->validate_mode_timing = link_validate_mode_timing; + link_srv->dp_link_bandwidth_kbps = dp_link_bandwidth_kbps; + link_srv->validate_dpia_bandwidth = link_validate_dpia_bandwidth; +} + +/* link dpms owns the programming sequence of stream's dpms state associated + * with the link and link's enable/disable sequences as result of the stream's + * dpms state change. + */ +static void construct_link_service_dpms(struct link_service *link_srv) +{ + link_srv->set_dpms_on = link_set_dpms_on; + link_srv->set_dpms_off = link_set_dpms_off; + link_srv->resume = link_resume; + link_srv->blank_all_dp_displays = link_blank_all_dp_displays; + link_srv->blank_all_edp_displays = link_blank_all_edp_displays; + link_srv->blank_dp_stream = link_blank_dp_stream; + link_srv->increase_mst_payload = link_increase_mst_payload; + link_srv->reduce_mst_payload = link_reduce_mst_payload; + link_srv->set_dsc_on_stream = link_set_dsc_on_stream; + link_srv->set_dsc_enable = link_set_dsc_enable; + link_srv->update_dsc_config = link_update_dsc_config; +} + +/* link ddc implements generic display communication protocols such as i2c, aux + * and scdc. It should not contain any specific applications of these + * protocols such as display capability query, detection, or handshaking such as + * link training. + */ +static void construct_link_service_ddc(struct link_service *link_srv) +{ + link_srv->create_ddc_service = link_create_ddc_service; + link_srv->destroy_ddc_service = link_destroy_ddc_service; + link_srv->query_ddc_data = link_query_ddc_data; + link_srv->aux_transfer_raw = link_aux_transfer_raw; + link_srv->aux_transfer_with_retries_no_mutex = + link_aux_transfer_with_retries_no_mutex; + link_srv->is_in_aux_transaction_mode = link_is_in_aux_transaction_mode; + link_srv->get_aux_defer_delay = link_get_aux_defer_delay; +} + +/* link dp capability implements dp specific link capability retrieval sequence. + * It is responsible for retrieving, parsing, overriding, deciding capability + * obtained from dp link. Link capability consists of encoders, DPRXs, cables, + * retimers, usb and all other possible backend capabilities. + */ +static void construct_link_service_dp_capability(struct link_service *link_srv) +{ + link_srv->dp_is_sink_present = dp_is_sink_present; + link_srv->dp_is_fec_supported = dp_is_fec_supported; + link_srv->dp_is_128b_132b_signal = dp_is_128b_132b_signal; + link_srv->dp_get_max_link_enc_cap = dp_get_max_link_enc_cap; + link_srv->dp_get_verified_link_cap = dp_get_verified_link_cap; + link_srv->dp_get_encoding_format = link_dp_get_encoding_format; + link_srv->dp_should_enable_fec = dp_should_enable_fec; + link_srv->dp_decide_link_settings = link_decide_link_settings; + link_srv->mst_decide_link_encoding_format = + mst_decide_link_encoding_format; + link_srv->edp_decide_link_settings = edp_decide_link_settings; + link_srv->bw_kbps_from_raw_frl_link_rate_data = + link_bw_kbps_from_raw_frl_link_rate_data; + link_srv->dp_overwrite_extended_receiver_cap = + dp_overwrite_extended_receiver_cap; + link_srv->dp_decide_lttpr_mode = dp_decide_lttpr_mode; +} + +/* link dp phy/dpia implements basic dp phy/dpia functionality such as + * enable/disable output and set lane/drive settings. It is responsible for + * maintaining and update software state representing current phy/dpia status + * such as current link settings. + */ +static void construct_link_service_dp_phy_or_dpia(struct link_service *link_srv) +{ + link_srv->dpia_handle_usb4_bandwidth_allocation_for_link = + dpia_handle_usb4_bandwidth_allocation_for_link; + link_srv->dpia_handle_bw_alloc_response = dpia_handle_bw_alloc_response; + link_srv->dp_set_drive_settings = dp_set_drive_settings; + link_srv->dpcd_write_rx_power_ctrl = dpcd_write_rx_power_ctrl; +} + +/* link dp irq handler implements DP HPD short pulse handling sequence according + * to DP specifications + */ +static void construct_link_service_dp_irq_handler(struct link_service *link_srv) +{ + link_srv->dp_parse_link_loss_status = dp_parse_link_loss_status; + link_srv->dp_should_allow_hpd_rx_irq = dp_should_allow_hpd_rx_irq; + link_srv->dp_handle_link_loss = dp_handle_link_loss; + link_srv->dp_read_hpd_rx_irq_data = dp_read_hpd_rx_irq_data; + link_srv->dp_handle_hpd_rx_irq = dp_handle_hpd_rx_irq; +} + +/* link edp panel control implements retrieval and configuration of eDP panel + * features such as PSR and ABM and it also manages specs defined eDP panel + * power sequences. + */ +static void construct_link_service_edp_panel_control(struct link_service *link_srv) +{ + link_srv->edp_panel_backlight_power_on = edp_panel_backlight_power_on; + link_srv->edp_get_backlight_level = edp_get_backlight_level; + link_srv->edp_get_backlight_level_nits = edp_get_backlight_level_nits; + link_srv->edp_set_backlight_level = edp_set_backlight_level; + link_srv->edp_set_backlight_level_nits = edp_set_backlight_level_nits; + link_srv->edp_get_target_backlight_pwm = edp_get_target_backlight_pwm; + link_srv->edp_get_psr_state = edp_get_psr_state; + link_srv->edp_set_psr_allow_active = edp_set_psr_allow_active; + link_srv->edp_setup_psr = edp_setup_psr; + link_srv->edp_set_sink_vtotal_in_psr_active = + edp_set_sink_vtotal_in_psr_active; + link_srv->edp_get_psr_residency = edp_get_psr_residency; + link_srv->edp_wait_for_t12 = edp_wait_for_t12; + link_srv->edp_is_ilr_optimization_required = + edp_is_ilr_optimization_required; + link_srv->edp_backlight_enable_aux = edp_backlight_enable_aux; + link_srv->edp_add_delay_for_T9 = edp_add_delay_for_T9; + link_srv->edp_receiver_ready_T9 = edp_receiver_ready_T9; + link_srv->edp_receiver_ready_T7 = edp_receiver_ready_T7; + link_srv->edp_power_alpm_dpcd_enable = edp_power_alpm_dpcd_enable; +} + +/* link dp cts implements dp compliance test automation protocols and manual + * testing interfaces for debugging and certification purpose. + */ +static void construct_link_service_dp_cts(struct link_service *link_srv) +{ + link_srv->dp_handle_automated_test = dp_handle_automated_test; + link_srv->dp_set_test_pattern = dp_set_test_pattern; + link_srv->dp_set_preferred_link_settings = + dp_set_preferred_link_settings; + link_srv->dp_set_preferred_training_settings = + dp_set_preferred_training_settings; +} + +/* link dp trace implements tracing interfaces for tracking major dp sequences + * including execution status and timestamps + */ +static void construct_link_service_dp_trace(struct link_service *link_srv) +{ + link_srv->dp_trace_is_initialized = dp_trace_is_initialized; + link_srv->dp_trace_set_is_logged_flag = dp_trace_set_is_logged_flag; + link_srv->dp_trace_is_logged = dp_trace_is_logged; + link_srv->dp_trace_get_lt_end_timestamp = dp_trace_get_lt_end_timestamp; + link_srv->dp_trace_get_lt_counts = dp_trace_get_lt_counts; + link_srv->dp_trace_get_link_loss_count = dp_trace_get_link_loss_count; + link_srv->dp_trace_set_edp_power_timestamp = + dp_trace_set_edp_power_timestamp; + link_srv->dp_trace_get_edp_poweron_timestamp = + dp_trace_get_edp_poweron_timestamp; + link_srv->dp_trace_get_edp_poweroff_timestamp = + dp_trace_get_edp_poweroff_timestamp; + link_srv->dp_trace_source_sequence = dp_trace_source_sequence; +} + +static void construct_link_service(struct link_service *link_srv) +{ + /* All link service functions should fall under some sub categories. + * If a new function doesn't perfectly fall under an existing sub + * category, it must be that you are either adding a whole new aspect of + * responsibility to link service or something doesn't belong to link + * service. In that case please contact the arch owner to arrange a + * design review meeting. + */ + construct_link_service_factory(link_srv); + construct_link_service_detection(link_srv); + construct_link_service_resource(link_srv); + construct_link_service_validation(link_srv); + construct_link_service_dpms(link_srv); + construct_link_service_ddc(link_srv); + construct_link_service_dp_capability(link_srv); + construct_link_service_dp_phy_or_dpia(link_srv); + construct_link_service_dp_irq_handler(link_srv); + construct_link_service_edp_panel_control(link_srv); + construct_link_service_dp_cts(link_srv); + construct_link_service_dp_trace(link_srv); +} + +struct link_service *link_create_link_service(void) +{ + struct link_service *link_srv = kzalloc(sizeof(*link_srv), GFP_KERNEL); + + if (link_srv == NULL) + goto fail; + + construct_link_service(link_srv); + + return link_srv; +fail: + return NULL; +} + +void link_destroy_link_service(struct link_service **link_srv) +{ + kfree(*link_srv); + *link_srv = NULL; +} + +static enum transmitter translate_encoder_to_transmitter( + struct graphics_object_id encoder) { switch (encoder.id) { case ENCODER_ID_INTERNAL_UNIPHY: @@ -181,7 +436,7 @@ static enum channel_id get_ddc_line(struct dc_link *link) return channel; } -static bool dc_link_construct_phy(struct dc_link *link, +static bool construct_phy(struct dc_link *link, const struct link_init_data *init_params) { uint8_t i; @@ -274,14 +529,18 @@ static bool dc_link_construct_phy(struct dc_link *link, link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; switch (link->dc->config.allow_edp_hotplug_detection) { - case 1: // only the 1st eDP handles hotplug + case HPD_EN_FOR_ALL_EDP: + link->irq_source_hpd_rx = + dal_irq_get_rx_source(link->hpd_gpio); + break; + case HPD_EN_FOR_PRIMARY_EDP_ONLY: if (link->link_index == 0) link->irq_source_hpd_rx = dal_irq_get_rx_source(link->hpd_gpio); else link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; break; - case 2: // only the 2nd eDP handles hotplug + case HPD_EN_FOR_SECONDARY_EDP_ONLY: if (link->link_index == 1) link->irq_source_hpd_rx = dal_irq_get_rx_source(link->hpd_gpio); @@ -289,6 +548,7 @@ static bool dc_link_construct_phy(struct dc_link *link, link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; break; default: + link->irq_source_hpd = DC_IRQ_SOURCE_INVALID; break; } } @@ -473,7 +733,7 @@ create_fail: return false; } -static bool dc_link_construct_dpia(struct dc_link *link, +static bool construct_dpia(struct dc_link *link, const struct link_init_data *init_params) { struct ddc_service_init_data ddc_service_init_data = { 0 }; @@ -543,9 +803,9 @@ static bool link_construct(struct dc_link *link, { /* Handle dpia case */ if (init_params->is_dpia_link == true) - return dc_link_construct_dpia(link, init_params); + return construct_dpia(link, init_params); else - return dc_link_construct_phy(link, init_params); + return construct_phy(link, init_params); } struct dc_link *link_create(const struct link_init_data *init_params) @@ -574,4 +834,3 @@ void link_destroy(struct dc_link **link) kfree(*link); *link = NULL; } - diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.h b/drivers/gpu/drm/amd/display/dc/link/link_factory.h index 5b846147c4a6..e96220d48d03 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.h @@ -25,5 +25,7 @@ #ifndef __LINK_FACTORY_H__ #define __LINK_FACTORY_H__ #include "link.h" +struct dc_link *link_create(const struct link_init_data *init_params); +void link_destroy(struct dc_link **link); #endif /* __LINK_FACTORY_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_resource.h b/drivers/gpu/drm/amd/display/dc/link/link_resource.h index 45554d30adf0..1907bda3cb6e 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_resource.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_resource.h @@ -25,7 +25,8 @@ #ifndef __LINK_RESOURCE_H__ #define __LINK_RESOURCE_H__ #include "link.h" +void link_get_cur_res_map(const struct dc *dc, uint32_t *map); +void link_restore_res_map(const struct dc *dc, uint32_t *map); void link_get_cur_link_res(const struct dc_link *link, struct link_resource *link_res); - #endif /* __LINK_RESOURCE_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.c b/drivers/gpu/drm/amd/display/dc/link/link_validation.c index d4f6ee6ca948..d4b7da526f0a 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_validation.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.c @@ -29,6 +29,8 @@ * provides helper functions exposing bandwidth formulas used in validation. */ #include "link_validation.h" +#include "protocols/link_dp_capability.h" +#include "protocols/link_dp_dpia_bw.h" #include "resource.h" #define DC_LOGGER_INIT(logger) @@ -123,7 +125,7 @@ static bool dp_active_dongle_validate_timing( if (dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps > 0) { // DP to HDMI FRL converter struct dc_crtc_timing outputTiming = *timing; -#if defined(CONFIG_DRM_AMD_DC_DCN) +#if defined(CONFIG_DRM_AMD_DC_FP) if (timing->flags.DSC && !timing->dsc_cfg.is_frl) /* DP input has DSC, HDMI FRL output doesn't have DSC, remove DSC from output timing */ outputTiming.flags.DSC = 0; @@ -233,7 +235,7 @@ uint32_t dp_link_bandwidth_kbps( */ link_rate_per_lane_kbps = link_settings->link_rate * LINK_RATE_REF_FREQ_IN_KHZ * BITS_PER_DP_BYTE; total_data_bw_efficiency_x10000 = DATA_EFFICIENCY_8b_10b_x10000; - if (dc_link_should_enable_fec(link)) { + if (dp_should_enable_fec(link)) { total_data_bw_efficiency_x10000 /= 100; total_data_bw_efficiency_x10000 *= DATA_EFFICIENCY_8b_10b_FEC_EFFICIENCY_x100; } @@ -254,60 +256,6 @@ uint32_t dp_link_bandwidth_kbps( return link_rate_per_lane_kbps * link_settings->lane_count / 10000 * total_data_bw_efficiency_x10000; } -uint32_t link_timing_bandwidth_kbps( - const struct dc_crtc_timing *timing) -{ - uint32_t bits_per_channel = 0; - uint32_t kbps; - -#if defined(CONFIG_DRM_AMD_DC_DCN) - if (timing->flags.DSC) - return dc_dsc_stream_bandwidth_in_kbps(timing, - timing->dsc_cfg.bits_per_pixel, - timing->dsc_cfg.num_slices_h, - timing->dsc_cfg.is_dp); -#endif /* CONFIG_DRM_AMD_DC_DCN */ - - switch (timing->display_color_depth) { - case COLOR_DEPTH_666: - bits_per_channel = 6; - break; - case COLOR_DEPTH_888: - bits_per_channel = 8; - break; - case COLOR_DEPTH_101010: - bits_per_channel = 10; - break; - case COLOR_DEPTH_121212: - bits_per_channel = 12; - break; - case COLOR_DEPTH_141414: - bits_per_channel = 14; - break; - case COLOR_DEPTH_161616: - bits_per_channel = 16; - break; - default: - ASSERT(bits_per_channel != 0); - bits_per_channel = 8; - break; - } - - kbps = timing->pix_clk_100hz / 10; - kbps *= bits_per_channel; - - if (timing->flags.Y_ONLY != 1) { - /*Only YOnly make reduce bandwidth by 1/3 compares to RGB*/ - kbps *= 3; - if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) - kbps /= 2; - else if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422) - kbps = kbps * 2 / 3; - } - - return kbps; -} - static bool dp_validate_mode_timing( struct dc_link *link, const struct dc_crtc_timing *timing) @@ -329,7 +277,7 @@ static bool dp_validate_mode_timing( timing->v_addressable == (uint32_t) 480) return true; - link_setting = dc_link_get_link_cap(link); + link_setting = dp_get_verified_link_cap(link); /* TODO: DYNAMIC_VALIDATION needs to be implemented */ /*if (flags.DYNAMIC_VALIDATION == 1 && @@ -338,7 +286,7 @@ static bool dp_validate_mode_timing( */ req_bw = dc_bandwidth_in_kbps_from_timing(timing); - max_bw = dc_link_bandwidth_kbps(link, link_setting); + max_bw = dp_link_bandwidth_kbps(link, link_setting); if (req_bw <= max_bw) { /* remember the biggest mode here, during @@ -396,3 +344,20 @@ enum dc_status link_validate_mode_timing( return DC_OK; } + +bool link_validate_dpia_bandwidth(const struct dc_stream_state *stream, const unsigned int num_streams) +{ + bool ret = true; + int bw_needed[MAX_DPIA_NUM]; + struct dc_link *link[MAX_DPIA_NUM]; + + if (!num_streams || num_streams > MAX_DPIA_NUM) + return ret; + + for (uint8_t i = 0; i < num_streams; ++i) { + + link[i] = stream[i].link; + bw_needed[i] = dc_bandwidth_in_kbps_from_timing(&stream[i].timing); + } + return ret; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/link_validation.h b/drivers/gpu/drm/amd/display/dc/link/link_validation.h index ab6a44f50032..4a954317d0da 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_validation.h +++ b/drivers/gpu/drm/amd/display/dc/link/link_validation.h @@ -25,4 +25,15 @@ #ifndef __LINK_VALIDATION_H__ #define __LINK_VALIDATION_H__ #include "link.h" +enum dc_status link_validate_mode_timing( + const struct dc_stream_state *stream, + struct dc_link *link, + const struct dc_crtc_timing *timing); +bool link_validate_dpia_bandwidth( + const struct dc_stream_state *stream, + const unsigned int num_streams); +uint32_t dp_link_bandwidth_kbps( + const struct dc_link *link, + const struct dc_link_settings *link_settings); + #endif /* __LINK_VALIDATION_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c index 5269125bc2a4..0fa1228bc178 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.c @@ -53,7 +53,7 @@ struct aux_payloads { struct vector payloads; }; -static bool dal_ddc_i2c_payloads_create( +static bool i2c_payloads_create( struct dc_context *ctx, struct i2c_payloads *payloads, uint32_t count) @@ -65,16 +65,24 @@ static bool dal_ddc_i2c_payloads_create( return false; } -static struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p) +static struct i2c_payload *i2c_payloads_get(struct i2c_payloads *p) { return (struct i2c_payload *)p->payloads.container; } -static uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p) +static uint32_t i2c_payloads_get_count(struct i2c_payloads *p) { return p->payloads.count; } +static void i2c_payloads_destroy(struct i2c_payloads *p) +{ + if (!p) + return; + + dal_vector_destruct(&p->payloads); +} + #define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b)) static void i2c_payloads_add( @@ -364,10 +372,10 @@ bool link_query_ddc_data( struct i2c_command command = {0}; struct i2c_payloads payloads; - if (!dal_ddc_i2c_payloads_create(ddc->ctx, &payloads, payloads_num)) + if (!i2c_payloads_create(ddc->ctx, &payloads, payloads_num)) return false; - command.payloads = dal_ddc_i2c_payloads_get(&payloads); + command.payloads = i2c_payloads_get(&payloads); command.number_of_payloads = 0; command.engine = DDC_I2C_COMMAND_ENGINE; command.speed = ddc->ctx->dc->caps.i2c_speed_in_khz; @@ -379,20 +387,20 @@ bool link_query_ddc_data( &payloads, address, read_size, read_buf, false); command.number_of_payloads = - dal_ddc_i2c_payloads_get_count(&payloads); + i2c_payloads_get_count(&payloads); success = dm_helpers_submit_i2c( ddc->ctx, ddc->link, &command); - dal_vector_destruct(&payloads.payloads); + i2c_payloads_destroy(&payloads); } return success; } -int dc_link_aux_transfer_raw(struct ddc_service *ddc, +int link_aux_transfer_raw(struct ddc_service *ddc, struct aux_payload *payload, enum aux_return_code_type *operation_result) { diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h index aaa5064408ba..860ef15d7f1b 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_ddc.h @@ -37,13 +37,41 @@ #define EDID_SEGMENT_SIZE 256 +struct ddc_service *link_create_ddc_service( + struct ddc_service_init_data *ddc_init_data); + +void link_destroy_ddc_service(struct ddc_service **ddc); + void set_ddc_transaction_type( struct ddc_service *ddc, enum ddc_transaction_type type); +uint32_t link_get_aux_defer_delay(struct ddc_service *ddc); + +bool link_is_in_aux_transaction_mode(struct ddc_service *ddc); + bool try_to_configure_aux_timeout(struct ddc_service *ddc, uint32_t timeout); +bool link_query_ddc_data( + struct ddc_service *ddc, + uint32_t address, + uint8_t *write_buf, + uint32_t write_size, + uint8_t *read_buf, + uint32_t read_size); + +/* Attempt to submit an aux payload, retrying on timeouts, defers, and busy + * states as outlined in the DP spec. Returns true if the request was + * successful. + * + * NOTE: The function requires explicit mutex on DM side in order to prevent + * potential race condition. DC components should call the dpcd read/write + * function in dm_helpers in order to access dpcd safely + */ +bool link_aux_transfer_with_retries_no_mutex(struct ddc_service *ddc, + struct aux_payload *payload); + void write_scdc_data( struct ddc_service *ddc_service, uint32_t pix_clk, @@ -57,5 +85,8 @@ void set_dongle_type(struct ddc_service *ddc, struct ddc *get_ddc_pin(struct ddc_service *ddc_service); +int link_aux_transfer_raw(struct ddc_service *ddc, + struct aux_payload *payload, + enum aux_return_code_type *operation_result); #endif /* __DAL_DDC_SERVICE_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c index d4370856f164..ba98013fecd0 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.c @@ -42,6 +42,8 @@ #include "link_edp_panel_control.h" #include "link_dp_irq_handler.h" #include "link/accessories/link_dp_trace.h" +#include "link/link_detection.h" +#include "link/link_validation.h" #include "link_dp_training.h" #include "atomfirmware.h" #include "resource.h" @@ -155,7 +157,7 @@ uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count) return 0; // invalid value } -uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw) +uint32_t link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw) { switch (bw) { case 0b001: @@ -201,8 +203,11 @@ static enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in case 5400000: link_rate = LINK_RATE_HIGH2; // Rate_7 (HBR2)- 5.40 Gbps/Lane break; + case 6750000: + link_rate = LINK_RATE_RATE_8; // Rate_8 - 6.75 Gbps/Lane + break; case 8100000: - link_rate = LINK_RATE_HIGH3; // Rate_8 (HBR3)- 8.10 Gbps/Lane + link_rate = LINK_RATE_HIGH3; // Rate_9 (HBR3)- 8.10 Gbps/Lane break; default: link_rate = LINK_RATE_UNKNOWN; @@ -278,7 +283,7 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, if (!link->dpcd_caps.dpcd_rev.raw) { do { - dc_link_dp_receiver_power_ctrl(link, true); + dpcd_write_rx_power_ctrl(link, true); core_link_read_dpcd(link, DP_DPCD_REV, dpcd_data, length); link->dpcd_caps.dpcd_rev.raw = dpcd_data[ @@ -309,7 +314,7 @@ static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data, link->wa_flags.dp_keep_receiver_powered = false; } -bool dc_link_is_fec_supported(const struct dc_link *link) +bool dp_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 @@ -325,7 +330,7 @@ bool dc_link_is_fec_supported(const struct dc_link *link) !IS_FPGA_MAXIMUS_DC(link->ctx->dce_environment)); } -bool dc_link_should_enable_fec(const struct dc_link *link) +bool dp_should_enable_fec(const struct dc_link *link) { bool force_disable = false; @@ -342,10 +347,10 @@ bool dc_link_should_enable_fec(const struct dc_link *link) || !link->dc->caps.edp_dsc_support)) force_disable = true; - return !force_disable && dc_link_is_fec_supported(link); + return !force_disable && dp_is_fec_supported(link); } -bool link_is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx) +bool dp_is_128b_132b_signal(struct pipe_ctx *pipe_ctx) { /* If this assert is hit then we have a link encoder dynamic management issue */ ASSERT(pipe_ctx->stream_res.hpo_dp_stream_enc ? pipe_ctx->link_res.hpo_dp_link_enc != NULL : true); @@ -442,8 +447,12 @@ static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count) } } -static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate) +static enum dc_link_rate reduce_link_rate(const struct dc_link *link, enum dc_link_rate link_rate) { + // NEEDSWORK: provide some details about why this function never returns some of the + // obscure link rates such as 4.32 Gbps or 3.24 Gbps and if such behavior is intended. + // + switch (link_rate) { case LINK_RATE_UHBR20: return LINK_RATE_UHBR13_5; @@ -452,13 +461,22 @@ static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate) case LINK_RATE_UHBR10: return LINK_RATE_HIGH3; case LINK_RATE_HIGH3: + if (link->connector_signal == SIGNAL_TYPE_EDP && link->dc->debug.support_eDP1_5) + return LINK_RATE_RATE_8; + return LINK_RATE_HIGH2; + case LINK_RATE_RATE_8: return LINK_RATE_HIGH2; case LINK_RATE_HIGH2: return LINK_RATE_HIGH; + case LINK_RATE_RATE_6: + case LINK_RATE_RBR2: + return LINK_RATE_HIGH; case LINK_RATE_HIGH: return LINK_RATE_LOW; + case LINK_RATE_RATE_3: + case LINK_RATE_RATE_2: + return LINK_RATE_LOW; case LINK_RATE_LOW: - return LINK_RATE_UNKNOWN; default: return LINK_RATE_UNKNOWN; } @@ -581,7 +599,7 @@ bool decide_fallback_link_setting( case LINK_TRAINING_LQA_FAIL: { if (!reached_minimum_link_rate(cur->link_rate)) { - cur->link_rate = reduce_link_rate(cur->link_rate); + cur->link_rate = reduce_link_rate(link, cur->link_rate); } else if (!reached_minimum_lane_count(cur->lane_count)) { cur->link_rate = max->link_rate; if (training_result == LINK_TRAINING_CR_FAIL_LANE0) @@ -603,7 +621,7 @@ bool decide_fallback_link_setting( if (!reached_minimum_lane_count(cur->lane_count)) { cur->lane_count = reduce_lane_count(cur->lane_count); } else if (!reached_minimum_link_rate(cur->link_rate)) { - cur->link_rate = reduce_link_rate(cur->link_rate); + cur->link_rate = reduce_link_rate(link, cur->link_rate); /* Reduce max link rate to avoid potential infinite loop. * Needed so that any subsequent CR_FAIL fallback can't * re-set the link rate higher than the link rate from @@ -619,7 +637,7 @@ bool decide_fallback_link_setting( case LINK_TRAINING_EQ_FAIL_CR: { if (!reached_minimum_link_rate(cur->link_rate)) { - cur->link_rate = reduce_link_rate(cur->link_rate); + cur->link_rate = reduce_link_rate(link, cur->link_rate); /* Reduce max link rate to avoid potential infinite loop. * Needed so that any subsequent CR_FAIL fallback can't * re-set the link rate higher than the link rate from @@ -645,7 +663,7 @@ static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_setting initial_link_setting; uint32_t link_bw; - if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap)) + if (req_bw > dp_link_bandwidth_kbps(link, &link->verified_link_cap)) return false; /* search for the minimum link setting that: @@ -654,7 +672,7 @@ static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_setting */ while (current_link_setting.link_rate <= link->verified_link_cap.link_rate) { - link_bw = dc_link_bandwidth_kbps( + link_bw = dp_link_bandwidth_kbps( link, ¤t_link_setting); if (req_bw <= link_bw) { @@ -679,7 +697,8 @@ static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_setting return false; } -bool dc_link_decide_edp_link_settings(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw) +bool edp_decide_link_settings(struct dc_link *link, + struct dc_link_settings *link_setting, uint32_t req_bw) { struct dc_link_settings initial_link_setting; struct dc_link_settings current_link_setting; @@ -709,7 +728,7 @@ bool dc_link_decide_edp_link_settings(struct dc_link *link, struct dc_link_setti */ while (current_link_setting.link_rate <= link->verified_link_cap.link_rate) { - link_bw = dc_link_bandwidth_kbps( + link_bw = dp_link_bandwidth_kbps( link, ¤t_link_setting); if (req_bw <= link_bw) { @@ -764,7 +783,7 @@ bool decide_edp_link_settings_with_dsc(struct dc_link *link, initial_link_setting.use_link_rate_set = false; initial_link_setting.link_rate_set = 0; current_link_setting = initial_link_setting; - if (req_bw > dc_link_bandwidth_kbps(link, &link->verified_link_cap)) + if (req_bw > dp_link_bandwidth_kbps(link, &link->verified_link_cap)) return false; /* search for the minimum link setting that: @@ -773,7 +792,7 @@ bool decide_edp_link_settings_with_dsc(struct dc_link *link, */ while (current_link_setting.link_rate <= max_link_rate) { - link_bw = dc_link_bandwidth_kbps( + link_bw = dp_link_bandwidth_kbps( link, ¤t_link_setting); if (req_bw <= link_bw) { @@ -830,7 +849,7 @@ bool decide_edp_link_settings_with_dsc(struct dc_link *link, */ while (current_link_setting.link_rate <= max_link_rate) { - link_bw = dc_link_bandwidth_kbps( + link_bw = dp_link_bandwidth_kbps( link, ¤t_link_setting); if (req_bw <= link_bw) { @@ -922,12 +941,12 @@ bool link_decide_link_settings(struct dc_stream_state *stream, tmp_link_setting.link_rate = LINK_RATE_UNKNOWN; tmp_timing.flags.DSC = 0; orig_req_bw = dc_bandwidth_in_kbps_from_timing(&tmp_timing); - dc_link_decide_edp_link_settings(link, &tmp_link_setting, orig_req_bw); + edp_decide_link_settings(link, &tmp_link_setting, orig_req_bw); max_link_rate = tmp_link_setting.link_rate; } decide_edp_link_settings_with_dsc(link, link_setting, req_bw, max_link_rate); } else { - dc_link_decide_edp_link_settings(link, link_setting, req_bw); + edp_decide_link_settings(link, link_setting, req_bw); } } else { decide_dp_link_settings(link, link_setting, req_bw); @@ -948,7 +967,7 @@ enum dp_link_encoding link_dp_get_encoding_format(const struct dc_link_settings return DP_UNKNOWN_ENCODING; } -enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link) +enum dp_link_encoding mst_decide_link_encoding_format(const struct dc_link *link) { struct dc_link_settings link_settings = {0}; @@ -1005,7 +1024,7 @@ static enum dc_status wake_up_aux_channel(struct dc_link *link) * signal and may need up to 1 ms before being able to reply. */ if (status != DC_OK || dpcd_power_state == DP_SET_POWER_D3) { - udelay(1000); + fsleep(1000); aux_channel_retry_cnt++; } } @@ -1024,6 +1043,9 @@ static enum dc_status wake_up_aux_channel(struct dc_link *link) DP_SET_POWER, &dpcd_power_state, sizeof(dpcd_power_state)); + if (status < 0) + DC_LOG_DC("%s: Failed to power up sink: %s\n", __func__, + dpcd_power_state == DP_SET_POWER_D0 ? "D0" : "D3"); return DC_ERROR_UNEXPECTED; } @@ -1121,7 +1143,7 @@ static void get_active_converter_info( union hdmi_encoded_link_bw hdmi_encoded_link_bw; link->dpcd_caps.dongle_caps.dp_hdmi_frl_max_link_bw_in_kbps = - dc_link_bw_kbps_from_raw_frl_link_rate_data( + link_bw_kbps_from_raw_frl_link_rate_data( hdmi_color_caps.bits.MAX_ENCODED_LINK_BW_SUPPORT); // Intersect reported max link bw support with the supported link rate post FRL link training @@ -1216,7 +1238,7 @@ static void apply_usbc_combo_phy_reset_wa(struct dc_link *link, dp_disable_link_phy(link, &link_res, link->connector_signal); } -static bool dp_overwrite_extended_receiver_cap(struct dc_link *link) +bool dp_overwrite_extended_receiver_cap(struct dc_link *link) { uint8_t dpcd_data[16]; uint32_t read_dpcd_retry_cnt = 3; @@ -1278,16 +1300,10 @@ static bool dp_overwrite_extended_receiver_cap(struct dc_link *link) return true; } -void dc_link_overwrite_extended_receiver_cap( - struct dc_link *link) -{ - dp_overwrite_extended_receiver_cap(link); -} - void dpcd_set_source_specific_data(struct dc_link *link) { if (!link->dc->vendor_signature.is_valid) { - enum dc_status result_write_min_hblank = DC_NOT_SUPPORTED; + enum dc_status __maybe_unused result_write_min_hblank = DC_NOT_SUPPORTED; struct dpcd_amd_signature amd_signature = {0}; struct dpcd_amd_device_id amd_device_id = {0}; @@ -1972,7 +1988,7 @@ void detect_edp_sink_caps(struct dc_link *link) sizeof(link->dpcd_caps.alpm_caps.raw)); } -bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap) +bool dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap) { struct link_encoder *link_enc = NULL; @@ -1995,7 +2011,7 @@ bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_ return false; } -const struct dc_link_settings *dc_link_get_link_cap( +const struct dc_link_settings *dp_get_verified_link_cap( const struct dc_link *link) { if (link->preferred_link_setting.lane_count != LANE_COUNT_UNKNOWN && @@ -2121,9 +2137,9 @@ static bool dp_verify_link_cap( if (status == LINK_TRAINING_SUCCESS) { success = true; - udelay(1000); - if (dc_link_dp_read_hpd_rx_irq_data(link, &irq_data) == DC_OK && - dc_link_check_link_loss_status( + fsleep(1000); + if (dp_read_hpd_rx_irq_data(link, &irq_data) == DC_OK && + dp_parse_link_loss_status( link, &irq_data)) (*fail_count)++; @@ -2163,7 +2179,7 @@ bool dp_verify_link_cap_with_retries( memset(&link->verified_link_cap, 0, sizeof(struct dc_link_settings)); - if (!dc_link_detect_connection_type(link, &type) || type == dc_connection_none) { + if (!link_detect_connection_type(link, &type) || type == dc_connection_none) { link->verified_link_cap = fail_safe_link_settings; break; } else if (dp_verify_link_cap(link, known_limit_link_setting, @@ -2171,7 +2187,7 @@ bool dp_verify_link_cap_with_retries( success = true; break; } - msleep(10); + fsleep(10 * 1000); } dp_trace_lt_fail_count_update(link, fail_count, true); @@ -2180,11 +2196,10 @@ bool dp_verify_link_cap_with_retries( return success; } -/** - * dc_link_is_dp_sink_present() - Check if there is a native DP - * or passive DP-HDMI dongle connected +/* + * Check if there is a native DP or passive DP-HDMI dongle connected */ -bool dc_link_is_dp_sink_present(struct dc_link *link) +bool dp_is_sink_present(struct dc_link *link) { enum gpio_result gpio_result; uint32_t clock_pin = 0; @@ -2231,7 +2246,7 @@ bool dc_link_is_dp_sink_present(struct dc_link *link) gpio_result = dal_gpio_get_value(ddc->pin_clock, &clock_pin); ASSERT(gpio_result == GPIO_RESULT_OK); if (clock_pin) - udelay(1000); + fsleep(1000); else break; } while (retry++ < 3); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.h index f79e4a4a9db6..8f0ce97f2362 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_capability.h @@ -34,32 +34,56 @@ void detect_edp_sink_caps(struct dc_link *link); struct dc_link_settings dp_get_max_link_cap(struct dc_link *link); +bool dp_get_max_link_enc_cap(const struct dc_link *link, + struct dc_link_settings *max_link_enc_cap); + +const struct dc_link_settings *dp_get_verified_link_cap( + const struct dc_link *link); + +enum dp_link_encoding link_dp_get_encoding_format( + const struct dc_link_settings *link_settings); enum dc_status dp_retrieve_lttpr_cap(struct dc_link *link); /* Convert PHY repeater count read from DPCD uint8_t. */ uint8_t dp_parse_lttpr_repeater_count(uint8_t lttpr_repeater_count); +bool dp_is_sink_present(struct dc_link *link); + bool dp_is_lttpr_present(struct dc_link *link); +bool dp_is_fec_supported(const struct dc_link *link); + bool is_dp_active_dongle(const struct dc_link *link); bool is_dp_branch_device(const struct dc_link *link); void dpcd_write_cable_id_to_dprx(struct dc_link *link); +bool dp_should_enable_fec(const struct dc_link *link); + +bool dp_is_128b_132b_signal(struct pipe_ctx *pipe_ctx); + /* Initialize output parameter lt_settings. */ void dp_decide_training_settings( struct dc_link *link, const struct dc_link_settings *link_setting, struct link_training_settings *lt_settings); +bool link_decide_link_settings( + struct dc_stream_state *stream, + struct dc_link_settings *link_setting); + +bool edp_decide_link_settings(struct dc_link *link, + struct dc_link_settings *link_setting, uint32_t req_bw); bool decide_edp_link_settings_with_dsc(struct dc_link *link, struct dc_link_settings *link_setting, uint32_t req_bw, enum dc_link_rate max_link_rate); +enum dp_link_encoding mst_decide_link_encoding_format(const struct dc_link *link); + void dpcd_set_source_specific_data(struct dc_link *link); /*query dpcd for version and mst cap addresses*/ @@ -76,4 +100,8 @@ bool dp_verify_link_cap_with_retries( struct dc_link_settings *known_limit_link_setting, int attempts); +uint32_t link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw); + +bool dp_overwrite_extended_receiver_cap(struct dc_link *link); + #endif /* __DC_LINK_DP_CAPABILITY_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c index 32f48a48e9dd..4626fabc0a96 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.c @@ -26,7 +26,6 @@ #include "dc.h" #include "inc/core_status.h" -#include "dc_link.h" #include "dpcd_defs.h" #include "link_dp_dpia.h" @@ -79,7 +78,7 @@ enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link) return status; } -bool dc_link_dpia_query_hpd_status(struct dc_link *link) +bool dpia_query_hpd_status(struct dc_link *link) { union dmub_rb_cmd cmd = {0}; struct dc_dmub_srv *dmub_srv = link->ctx->dmub_srv; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.h index 98935cc10bb7..363f45a1a964 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia.h @@ -37,7 +37,5 @@ enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link); /* Query hot plug status of USB4 DP tunnel. * Returns true if HPD high. */ -bool dc_link_dpia_query_hpd_status(struct dc_link *link); - - +bool dpia_query_hpd_status(struct dc_link *link); #endif /* __DC_LINK_DPIA_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c index f69e681b3b5b..7581023daa47 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.c @@ -26,11 +26,12 @@ /*********************************************************************/ // USB4 DPIA BANDWIDTH ALLOCATION LOGIC /*********************************************************************/ -#include "dc.h" -#include "dc_link.h" #include "link_dp_dpia_bw.h" -#include "drm_dp_helper_dc.h" #include "link_dpcd.h" +#include "dc_dmub_srv.h" + +#define DC_LOGGER \ + link->ctx->logger #define Kbps_TO_Gbps (1000 * 1000) @@ -84,12 +85,11 @@ static int get_estimated_bw(struct dc_link *link) { uint8_t bw_estimated_bw = 0; - if (core_link_read_dpcd( - link, - ESTIMATED_BW, - &bw_estimated_bw, - sizeof(uint8_t)) != DC_OK) - dm_output_to_console("%s: AUX W/R ERROR @ 0x%x\n", __func__, ESTIMATED_BW); + core_link_read_dpcd( + link, + ESTIMATED_BW, + &bw_estimated_bw, + sizeof(uint8_t)); return bw_estimated_bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); } @@ -133,8 +133,9 @@ static uint8_t get_lowest_dpia_index(struct dc_link *link) { const struct dc *dc_struct = link->dc; uint8_t idx = 0xFF; + int i; - for (int i = 0; i < MAX_PIPES * 2; ++i) { + for (i = 0; i < MAX_PIPES * 2; ++i) { if (!dc_struct->links[i] || dc_struct->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) @@ -161,8 +162,9 @@ static int get_host_router_total_bw(struct dc_link *link, uint8_t type) uint8_t idx = (link->link_index - lowest_dpia_index) / 2, idx_temp = 0; struct dc_link *link_temp; int total_bw = 0; + int i; - for (int i = 0; i < MAX_PIPES * 2; ++i) { + for (i = 0; i < MAX_PIPES * 2; ++i) { if (!dc_struct->links[i] || dc_struct->links[i]->ep_type != DISPLAY_ENDPOINT_USB4_DPIA) continue; @@ -194,15 +196,13 @@ static int get_host_router_total_bw(struct dc_link *link, uint8_t type) */ static bool dpia_bw_alloc_unplug(struct dc_link *link) { - bool ret = false; - if (!link) return true; return deallocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, link->dpia_bw_alloc_config.sink_allocated_bw, link); } -static void dc_link_set_usb4_req_bw_req(struct dc_link *link, int req_bw) +static void set_usb4_req_bw_req(struct dc_link *link, int req_bw) { uint8_t requested_bw; uint32_t temp; @@ -227,9 +227,7 @@ static void dc_link_set_usb4_req_bw_req(struct dc_link *link, int req_bw) link, REQUESTED_BW, &requested_bw, - sizeof(uint8_t)) != DC_OK) - dm_output_to_console("%s: AUX W/R ERROR @ 0x%x\n", __func__, REQUESTED_BW); - else + sizeof(uint8_t)) == DC_OK) link->dpia_bw_alloc_config.response_ready = false; // Reset flag } /* @@ -246,7 +244,7 @@ static bool get_cm_response_ready_flag(struct dc_link *link) // ------------------------------------------------------------------ // PUBLIC FUNCTIONS // ------------------------------------------------------------------ -bool set_dptx_usb4_bw_alloc_support(struct dc_link *link) +bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link) { bool ret = false; uint8_t response = 0, @@ -257,22 +255,18 @@ bool set_dptx_usb4_bw_alloc_support(struct dc_link *link) goto out; if (core_link_read_dpcd( - link, - DP_TUNNELING_CAPABILITIES, - &response, - sizeof(uint8_t)) != DC_OK) - dm_output_to_console("%s: AUX W/R ERROR @ 0x%x\n", __func__, DP_TUNNELING_CAPABILITIES); - - bw_support_dpia = (response >> 7) & 1; + link, + DP_TUNNELING_CAPABILITIES, + &response, + sizeof(uint8_t)) == DC_OK) + bw_support_dpia = (response >> 7) & 1; if (core_link_read_dpcd( link, USB4_DRIVER_BW_CAPABILITY, &response, - sizeof(uint8_t)) != DC_OK) - dm_output_to_console("%s: AUX W/R ERROR @ 0x%x\n", __func__, DP_TUNNELING_CAPABILITIES); - - bw_support_cm = (response >> 7) & 1; + sizeof(uint8_t)) == DC_OK) + bw_support_cm = (response >> 7) & 1; /* Send request acknowledgment to Turn ON DPTX support */ if (bw_support_cm && bw_support_dpia) { @@ -282,15 +276,14 @@ bool set_dptx_usb4_bw_alloc_support(struct dc_link *link) link, DPTX_BW_ALLOCATION_MODE_CONTROL, &response, - sizeof(uint8_t)) != DC_OK) - dm_output_to_console("%s: AUX W/R ERROR @ 0x%x\n", - "**** FAILURE Enabling DPtx BW Allocation Mode Support ***\n", - __func__, DP_TUNNELING_CAPABILITIES); - else { - + sizeof(uint8_t)) != DC_OK) { + DC_LOG_DEBUG("%s: **** FAILURE Enabling DPtx BW Allocation Mode Support ***\n", + __func__); + } else { // SUCCESS Enabled DPtx BW Allocation Mode Support link->dpia_bw_alloc_config.bw_alloc_enabled = true; - dm_output_to_console("**** SUCCESS Enabling DPtx BW Allocation Mode Support ***\n"); + DC_LOG_DEBUG("%s: **** SUCCESS Enabling DPtx BW Allocation Mode Support ***\n", + __func__); ret = true; init_usb4_bw_struct(link); @@ -300,8 +293,12 @@ bool set_dptx_usb4_bw_alloc_support(struct dc_link *link) out: return ret; } -void dc_link_get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t result) +void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t result) { + int bw_needed = 0; + int estimated = 0; + int host_router_total_estimated_bw = 0; + if (!get_bw_alloc_proceed_flag((link))) return; @@ -309,13 +306,13 @@ void dc_link_get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t resu case DPIA_BW_REQ_FAILED: - dm_output_to_console("%s: *** *** BW REQ FAILURE for DP-TX Request *** ***\n", __func__); + DC_LOG_DEBUG("%s: *** *** BW REQ FAILURE for DP-TX Request *** ***\n", __func__); // Update the new Estimated BW value updated by CM link->dpia_bw_alloc_config.estimated_bw = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); - dc_link_set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.estimated_bw); + set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.estimated_bw); link->dpia_bw_alloc_config.response_ready = false; /* @@ -329,18 +326,18 @@ void dc_link_get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t resu case DPIA_BW_REQ_SUCCESS: - dm_output_to_console("%s: *** BW REQ SUCCESS for DP-TX Request ***\n", __func__); + DC_LOG_DEBUG("%s: *** BW REQ SUCCESS for DP-TX Request ***\n", __func__); // 1. SUCCESS 1st time before any Pruning is done // 2. SUCCESS after prev. FAIL before any Pruning is done // 3. SUCCESS after Pruning is done but before enabling link - int needed = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); + bw_needed = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); // 1. if (!link->dpia_bw_alloc_config.sink_allocated_bw) { - allocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, needed, link); + allocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, bw_needed, link); link->dpia_bw_alloc_config.sink_verified_bw = link->dpia_bw_alloc_config.sink_allocated_bw; @@ -354,12 +351,12 @@ void dc_link_get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t resu else if (link->dpia_bw_alloc_config.sink_allocated_bw) { // Find out how much do we need to de-alloc - if (link->dpia_bw_alloc_config.sink_allocated_bw > needed) + if (link->dpia_bw_alloc_config.sink_allocated_bw > bw_needed) deallocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, - link->dpia_bw_alloc_config.sink_allocated_bw - needed, link); + link->dpia_bw_alloc_config.sink_allocated_bw - bw_needed, link); else allocate_usb4_bw(&link->dpia_bw_alloc_config.sink_allocated_bw, - needed - link->dpia_bw_alloc_config.sink_allocated_bw, link); + bw_needed - link->dpia_bw_alloc_config.sink_allocated_bw, link); } // 4. If this is the 2nd sink then any unused bw will be reallocated to master DPIA @@ -370,27 +367,19 @@ void dc_link_get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t resu case DPIA_EST_BW_CHANGED: - dm_output_to_console("%s: *** ESTIMATED BW CHANGED for DP-TX Request ***\n", __func__); + DC_LOG_DEBUG("%s: *** ESTIMATED BW CHANGED for DP-TX Request ***\n", __func__); - int available = 0, estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); - int host_router_total_estimated_bw = get_host_router_total_bw(link, HOST_ROUTER_BW_ESTIMATED); + estimated = bw * (Kbps_TO_Gbps / link->dpia_bw_alloc_config.bw_granularity); + host_router_total_estimated_bw = get_host_router_total_bw(link, HOST_ROUTER_BW_ESTIMATED); // 1. If due to unplug of other sink if (estimated == host_router_total_estimated_bw) { - // First update the estimated & max_bw fields - if (link->dpia_bw_alloc_config.estimated_bw < estimated) { - available = estimated - link->dpia_bw_alloc_config.estimated_bw; + if (link->dpia_bw_alloc_config.estimated_bw < estimated) link->dpia_bw_alloc_config.estimated_bw = estimated; - } } // 2. If due to realloc bw btw 2 dpia due to plug OR realloc unused Bw else { - - // We took from another unplugged/problematic sink to give to us - if (link->dpia_bw_alloc_config.estimated_bw < estimated) - available = estimated - link->dpia_bw_alloc_config.estimated_bw; - // We lost estimated bw usually due to plug event of other dpia link->dpia_bw_alloc_config.estimated_bw = estimated; } @@ -398,12 +387,12 @@ void dc_link_get_usb4_req_bw_resp(struct dc_link *link, uint8_t bw, uint8_t resu case DPIA_BW_ALLOC_CAPS_CHANGED: - dm_output_to_console("%s: *** BW ALLOC CAPABILITY CHANGED for DP-TX Request ***\n", __func__); + DC_LOG_DEBUG("%s: *** BW ALLOC CAPABILITY CHANGED for DP-TX Request ***\n", __func__); link->dpia_bw_alloc_config.bw_alloc_enabled = false; break; } } -int dc_link_dp_dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int peak_bw) +int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int peak_bw) { int ret = 0; uint8_t timeout = 10; @@ -417,14 +406,14 @@ int dc_link_dp_dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *li // If DP over USB4 then we need to check BW allocation link->dpia_bw_alloc_config.sink_max_bw = peak_bw; - dc_link_set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.sink_max_bw); + set_usb4_req_bw_req(link, link->dpia_bw_alloc_config.sink_max_bw); do { - if (!timeout > 0) + if (!(timeout > 0)) timeout--; else break; - udelay(10 * 1000); + fsleep(10 * 1000); } while (!get_cm_response_ready_flag(link)); if (!timeout) @@ -439,3 +428,65 @@ int dc_link_dp_dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *li out: return ret; } +int link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw) +{ + int ret = 0; + uint8_t timeout = 10; + + if (!get_bw_alloc_proceed_flag(link)) + goto out; + + /* + * Sometimes stream uses same timing parameters as the already + * allocated max sink bw so no need to re-alloc + */ + if (req_bw != link->dpia_bw_alloc_config.sink_allocated_bw) { + set_usb4_req_bw_req(link, req_bw); + do { + if (!(timeout > 0)) + timeout--; + else + break; + udelay(10 * 1000); + } while (!get_cm_response_ready_flag(link)); + + if (!timeout) + ret = 0;// ERROR TIMEOUT waiting for response for allocating bw + else if (link->dpia_bw_alloc_config.sink_allocated_bw > 0) + ret = get_host_router_total_bw(link, HOST_ROUTER_BW_ALLOCATED); + } + +out: + return ret; +} +bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed_per_dpia, const unsigned int num_dpias) +{ + bool ret = true; + int bw_needed_per_hr[MAX_HR_NUM] = { 0, 0 }; + uint8_t lowest_dpia_index = 0, dpia_index = 0; + uint8_t i; + + if (!num_dpias || num_dpias > MAX_DPIA_NUM) + return ret; + + //Get total Host Router BW & Validate against each Host Router max BW + for (i = 0; i < num_dpias; ++i) { + + if (!link[i]->dpia_bw_alloc_config.bw_alloc_enabled) + continue; + + lowest_dpia_index = get_lowest_dpia_index(link[i]); + if (link[i]->link_index < lowest_dpia_index) + continue; + + dpia_index = (link[i]->link_index - lowest_dpia_index) / 2; + bw_needed_per_hr[dpia_index] += bw_needed_per_dpia[i]; + if (bw_needed_per_hr[dpia_index] > get_host_router_total_bw(link[i], HOST_ROUTER_BW_ALLOCATED)) { + + ret = false; + break; + } + } + + return ret; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h index c2c3049adcd1..7292690383ae 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_dpia_bw.h @@ -26,6 +26,13 @@ #ifndef DC_INC_LINK_DP_DPIA_BW_H_ #define DC_INC_LINK_DP_DPIA_BW_H_ +#include "link.h" + +/* Number of Host Routers per motherboard is 2 */ +#define MAX_HR_NUM 2 +/* Number of DPIA per host router is 2 */ +#define MAX_DPIA_NUM (MAX_HR_NUM * 2) + /* * Host Router BW type */ @@ -42,6 +49,54 @@ enum bw_type { * * return: SUCCESS or FAILURE */ -bool set_dptx_usb4_bw_alloc_support(struct dc_link *link); +bool link_dp_dpia_set_dptx_usb4_bw_alloc_support(struct dc_link *link); + +/* + * Allocates only what the stream needs for bw, so if: + * If (stream_req_bw < or > already_allocated_bw_at_HPD) + * => Deallocate Max Bw & then allocate only what the stream needs + * + * @link: pointer to the dc_link struct instance + * @req_bw: Bw requested by the stream + * + * return: allocated bw else return 0 + */ +int link_dp_dpia_allocate_usb4_bandwidth_for_stream(struct dc_link *link, int req_bw); + +/* + * Handle the USB4 BW Allocation related functionality here: + * Plug => Try to allocate max bw from timing parameters supported by the sink + * Unplug => de-allocate bw + * + * @link: pointer to the dc_link struct instance + * @peak_bw: Peak bw used by the link/sink + * + * return: allocated bw else return 0 + */ +int dpia_handle_usb4_bandwidth_allocation_for_link(struct dc_link *link, int peak_bw); + +/* + * Handle function for when the status of the Request above is complete. + * We will find out the result of allocating on CM and update structs. + * + * @link: pointer to the dc_link struct instance + * @bw: Allocated or Estimated BW depending on the result + * @result: Response type + * + * return: none + */ +void dpia_handle_bw_alloc_response(struct dc_link *link, uint8_t bw, uint8_t result); + +/* + * Handle the validation of total BW here and confirm that the bw used by each + * DPIA doesn't exceed available BW for each host router (HR) + * + * @link[]: array of link pointer to all possible DPIA links + * @bw_needed[]: bw needed for each DPIA link based on timing + * @num_dpias: Number of DPIAs for the above 2 arrays. Should always be <= MAX_DPIA_NUM + * + * return: TRUE if bw used by DPIAs doesn't exceed available BW else return FALSE + */ +bool dpia_validate_usb4_bw(struct dc_link **link, int *bw_needed, const unsigned int num_dpias); #endif /* DC_INC_LINK_DP_DPIA_BW_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c index 9d80427520cf..ba95facc4ee8 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.c @@ -33,13 +33,14 @@ #include "link_dpcd.h" #include "link_dp_training.h" #include "link_dp_capability.h" +#include "link_edp_panel_control.h" #include "link/accessories/link_dp_trace.h" #include "link/link_dpms.h" #include "dm_helpers.h" #define DC_LOGGER_INIT(logger) -bool dc_link_check_link_loss_status( +bool dp_parse_link_loss_status( struct dc_link *link, union hpd_irq_data *hpd_irq_dpcd_data) { @@ -155,9 +156,9 @@ static bool handle_hpd_irq_psr_sink(struct dc_link *link) /* PSR error, disable and re-enable PSR */ if (link->psr_settings.psr_allow_active) { allow_active = false; - dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL); + edp_set_psr_allow_active(link, &allow_active, true, false, NULL); allow_active = true; - dc_link_set_psr_allow_active(link, &allow_active, true, false, NULL); + edp_set_psr_allow_active(link, &allow_active, true, false, NULL); } return true; @@ -174,7 +175,7 @@ static bool handle_hpd_irq_psr_sink(struct dc_link *link) return false; } -void dc_link_dp_handle_link_loss(struct dc_link *link) +void dp_handle_link_loss(struct dc_link *link) { struct pipe_ctx *pipes[MAX_PIPES]; struct dc_state *state = link->dc->current_state; @@ -200,7 +201,7 @@ void dc_link_dp_handle_link_loss(struct dc_link *link) } } -enum dc_status dc_link_dp_read_hpd_rx_irq_data( +enum dc_status dp_read_hpd_rx_irq_data( struct dc_link *link, union hpd_irq_data *irq_data) { @@ -247,7 +248,7 @@ enum dc_status dc_link_dp_read_hpd_rx_irq_data( } /*************************Short Pulse IRQ***************************/ -bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link) +bool dp_should_allow_hpd_rx_irq(const struct dc_link *link) { /* * Don't handle RX IRQ unless one of following is met: @@ -262,8 +263,9 @@ bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link) return false; } -bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss, - bool defer_handling, bool *has_left_work) +bool dp_handle_hpd_rx_irq(struct dc_link *link, + union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss, + bool defer_handling, bool *has_left_work) { union hpd_irq_data hpd_irq_dpcd_data = {0}; union device_service_irq device_service_clear = {0}; @@ -288,7 +290,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd * dal_dpsst_ls_read_hpd_irq_data * Order of calls is important too */ - result = dc_link_dp_read_hpd_rx_irq_data(link, &hpd_irq_dpcd_data); + result = dp_read_hpd_rx_irq_data(link, &hpd_irq_dpcd_data); if (out_hpd_irq_dpcd_data) *out_hpd_irq_dpcd_data = hpd_irq_dpcd_data; @@ -315,7 +317,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd return false; } - if (!dc_link_dp_allow_hpd_rx_irq(link)) { + if (!dp_should_allow_hpd_rx_irq(link)) { DC_LOG_HW_HPD_IRQ("%s: skipping HPD handling on %d\n", __func__, link->link_index); return false; @@ -348,9 +350,9 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd * then DM should call DC to do the detection. * NOTE: Do not handle link loss on eDP since it is internal link*/ if ((link->connector_signal != SIGNAL_TYPE_EDP) && - dc_link_check_link_loss_status( - link, - &hpd_irq_dpcd_data)) { + dp_parse_link_loss_status( + link, + &hpd_irq_dpcd_data)) { /* Connectivity log: link loss */ CONN_DATA_LINK_LOSS(link, hpd_irq_dpcd_data.raw, @@ -360,7 +362,7 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd if (defer_handling && has_left_work) *has_left_work = true; else - dc_link_dp_handle_link_loss(link); + dp_handle_link_loss(link); status = false; if (out_link_loss) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.h index 39b2e51ea79d..ac33730fedd4 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_irq_handler.h @@ -27,5 +27,15 @@ #define __DC_LINK_DP_IRQ_HANDLER_H__ #include "link.h" - +bool dp_parse_link_loss_status( + struct dc_link *link, + union hpd_irq_data *hpd_irq_dpcd_data); +bool dp_should_allow_hpd_rx_irq(const struct dc_link *link); +void dp_handle_link_loss(struct dc_link *link); +enum dc_status dp_read_hpd_rx_irq_data( + struct dc_link *link, + union hpd_irq_data *irq_data); +bool dp_handle_hpd_rx_irq(struct dc_link *link, + union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss, + bool defer_handling, bool *has_left_work); #endif /* __DC_LINK_DP_IRQ_HANDLER_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c index cd9fb8126bcf..b7abba55bc2f 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.c @@ -40,7 +40,7 @@ #define DC_LOGGER \ link->ctx->logger -void dc_link_dp_receiver_power_ctrl(struct dc_link *link, bool on) +void dpcd_write_rx_power_ctrl(struct dc_link *link, bool on) { uint8_t state; @@ -64,7 +64,7 @@ void dp_enable_link_phy( link->cur_link_settings = *link_settings; link->dc->hwss.enable_dp_link_output(link, link_res, signal, clock_source, link_settings); - dc_link_dp_receiver_power_ctrl(link, true); + dpcd_write_rx_power_ctrl(link, true); } void dp_disable_link_phy(struct dc_link *link, @@ -74,7 +74,7 @@ void dp_disable_link_phy(struct dc_link *link, struct dc *dc = link->ctx->dc; if (!link->wa_flags.dp_keep_receiver_powered) - dc_link_dp_receiver_power_ctrl(link, false); + dpcd_write_rx_power_ctrl(link, false); dc->hwss.disable_link_output(link, link_res, signal); /* Clear current link setting.*/ @@ -143,7 +143,7 @@ enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource link_enc = link_enc_cfg_get_link_enc(link); ASSERT(link_enc); - if (!dc_link_should_enable_fec(link)) + if (!dp_should_enable_fec(link)) return status; if (link_enc->funcs->fec_set_ready && @@ -183,7 +183,7 @@ void dp_set_fec_enable(struct dc_link *link, bool enable) link_enc = link_enc_cfg_get_link_enc(link); ASSERT(link_enc); - if (!dc_link_should_enable_fec(link)) + if (!dp_should_enable_fec(link)) return; if (link_enc->funcs->fec_set_enable && diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.h index dba1f29df319..1eb0619d6710 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_phy.h @@ -51,6 +51,9 @@ void dp_set_drive_settings( enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready); + void dp_set_fec_enable(struct dc_link *link, bool enable); +void dpcd_write_rx_power_ctrl(struct dc_link *link, bool on); + #endif /* __DC_LINK_DP_PHY_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c index b48d4d822991..170f33835930 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.c @@ -41,6 +41,8 @@ #include "link_dp_phy.h" #include "link_dp_capability.h" #include "link_edp_panel_control.h" +#include "link/link_detection.h" +#include "link/link_validation.h" #include "atomfirmware.h" #include "link_enc_cfg.h" #include "resource.h" @@ -84,6 +86,9 @@ void dp_log_training_result( case LINK_RATE_HIGH2: link_rate = "HBR2"; break; + case LINK_RATE_RATE_8: + link_rate = "R8"; + break; case LINK_RATE_HIGH3: link_rate = "HBR3"; break; @@ -207,27 +212,36 @@ enum dpcd_training_patterns switch (pattern) { case DP_TRAINING_PATTERN_SEQUENCE_1: + DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS1\n", __func__); dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1; break; case DP_TRAINING_PATTERN_SEQUENCE_2: + DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS2\n", __func__); dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2; break; case DP_TRAINING_PATTERN_SEQUENCE_3: + DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS3\n", __func__); dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3; break; case DP_TRAINING_PATTERN_SEQUENCE_4: + DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern TPS4\n", __func__); dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4; break; case DP_128b_132b_TPS1: + DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS1\n", __func__); dpcd_tr_pattern = DPCD_128b_132b_TPS1; break; case DP_128b_132b_TPS2: + DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS2\n", __func__); dpcd_tr_pattern = DPCD_128b_132b_TPS2; break; case DP_128b_132b_TPS2_CDS: + DC_LOG_HW_LINK_TRAINING("%s: Using DP 128b/132b training pattern TPS2 CDS\n", + __func__); dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS; break; case DP_TRAINING_PATTERN_VIDEOIDLE: + DC_LOG_HW_LINK_TRAINING("%s: Using DP training pattern videoidle\n", __func__); dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE; break; default: @@ -258,10 +272,7 @@ void dp_wait_for_training_aux_rd_interval( struct dc_link *link, uint32_t wait_in_micro_secs) { - if (wait_in_micro_secs > 1000) - msleep(wait_in_micro_secs/1000); - else - udelay(wait_in_micro_secs); + fsleep(wait_in_micro_secs); DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n", __func__, @@ -725,12 +736,10 @@ void override_training_settings( if (link->preferred_training_settings.fec_enable != NULL) lt_settings->should_set_fec_ready = *link->preferred_training_settings.fec_enable; -#if defined(CONFIG_DRM_AMD_DC_DCN) /* Check DP tunnel LTTPR mode debug option. */ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && link->dc->debug.dpia_debug.bits.force_non_lttpr) lt_settings->lttpr_mode = LTTPR_MODE_NON_LTTPR; -#endif dp_get_lttpr_mode_override(link, <_settings->lttpr_mode); } @@ -780,7 +789,7 @@ enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link, return pattern; } -enum lttpr_mode dc_link_decide_lttpr_mode(struct dc_link *link, +enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, struct dc_link_settings *link_setting) { enum dp_link_encoding encoding = link_dp_get_encoding_format(link_setting); @@ -865,8 +874,9 @@ static enum dc_status configure_lttpr_mode_non_transparent( uint8_t repeater_id; enum dc_status result = DC_ERROR_UNEXPECTED; uint8_t repeater_mode = DP_PHY_REPEATER_MODE_TRANSPARENT; + const struct dc *dc = link->dc; - enum dp_link_encoding encoding = link_dp_get_encoding_format(<_settings->link_settings); + enum dp_link_encoding encoding = dc->link_srv->dp_get_encoding_format(<_settings->link_settings); if (encoding == DP_8b_10b_ENCODING) { DC_LOG_HW_LINK_TRAINING("%s\n Set LTTPR to Transparent Mode\n", __func__); @@ -970,7 +980,7 @@ static void dpcd_exit_training_mode(struct dc_link *link, enum dp_link_encoding if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) && (sink_status & DP_INTRA_HOP_AUX_REPLY_INDICATION) == 0) break; - udelay(1000); + fsleep(1000); } } } @@ -1495,7 +1505,10 @@ enum link_training_result dp_perform_link_training( * Non-LT AUX transactions inside training mode. */ if ((link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) && encoding == DP_8b_10b_ENCODING) - status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); + if (link->dc->config.use_old_fixed_vs_sequence) + status = dp_perform_fixed_vs_pe_training_sequence_legacy(link, link_res, <_settings); + else + status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, <_settings); else if (encoding == DP_8b_10b_ENCODING) status = dp_perform_8b_10b_link_training(link, link_res, <_settings); else if (encoding == DP_128b_132b_ENCODING) @@ -1556,9 +1569,10 @@ bool perform_link_training_with_retries( j = 0; while (j < attempts && fail_count < (attempts * 10)) { - DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d)\n", - __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, - cur_link_settings.lane_count); + DC_LOG_HW_LINK_TRAINING("%s: Beginning link(%d) training attempt %u of %d @ rate(%d) x lane(%d) @ spread = %x\n", + __func__, link->link_index, (unsigned int)j + 1, attempts, + cur_link_settings.link_rate, cur_link_settings.lane_count, + cur_link_settings.link_spread); dp_enable_link_phy( link, @@ -1573,7 +1587,6 @@ bool perform_link_training_with_retries( msleep(delay_dp_power_up_in_ms); } -#ifdef CONFIG_DRM_AMD_DC_HDCP if (panel_mode == DP_PANEL_MODE_EDP) { struct cp_psp *cp_psp = &stream->ctx->cp_psp; @@ -1583,21 +1596,19 @@ bool perform_link_training_with_retries( * Report and continue with eDP panel mode to * perform eDP link training with right settings */ - bool result; - result = cp_psp->funcs.enable_assr(cp_psp->handle, link); + cp_psp->funcs.enable_assr(cp_psp->handle, link); } } -#endif dp_set_panel_mode(link, panel_mode); if (link->aux_access_disabled) { - dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings); + dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings); return true; } else { /** @todo Consolidate USB4 DP and DPx.x training. */ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) { - status = dc_link_dpia_perform_link_training( + status = dpia_perform_link_training( link, &pipe_ctx->link_res, &cur_link_settings, @@ -1639,9 +1650,10 @@ bool perform_link_training_with_retries( break; } - DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) : fail reason:(%d)\n", - __func__, link->link_index, (unsigned int)j + 1, attempts, cur_link_settings.link_rate, - cur_link_settings.lane_count, status); + DC_LOG_WARNING("%s: Link(%d) training attempt %u of %d failed @ rate(%d) x lane(%d) @ spread = %x : fail reason:(%d)\n", + __func__, link->link_index, (unsigned int)j + 1, attempts, + cur_link_settings.link_rate, cur_link_settings.lane_count, + cur_link_settings.link_spread, status); dp_disable_link_phy(link, &pipe_ctx->link_res, signal); @@ -1649,7 +1661,7 @@ bool perform_link_training_with_retries( if (status == LINK_TRAINING_ABORT) { enum dc_connection_type type = dc_connection_none; - dc_link_detect_connection_type(link, &type); + link_detect_connection_type(link, &type); if (type == dc_connection_none) { DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__); break; @@ -1682,7 +1694,7 @@ bool perform_link_training_with_retries( * minimum link bandwidth. */ req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing); - link_bw = dc_link_bandwidth_kbps(link, &cur_link_settings); + link_bw = dp_link_bandwidth_kbps(link, &cur_link_settings); is_link_bw_low = (req_bw > link_bw); is_link_bw_min = ((cur_link_settings.link_rate <= LINK_RATE_LOW) && (cur_link_settings.lane_count <= LANE_COUNT_ONE)); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h index a04948635369..7d027bac8255 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training.h @@ -119,6 +119,9 @@ enum dc_dp_training_pattern decide_cr_training_pattern( enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *link, const struct dc_link_settings *link_settings); +enum lttpr_mode dp_decide_lttpr_mode(struct dc_link *link, + struct dc_link_settings *link_setting); + void dp_get_lttpr_mode_override(struct dc_link *link, enum lttpr_mode *override); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c index 14b98e096d39..3889ebb2256b 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_8b_10b.c @@ -225,8 +225,10 @@ enum link_training_result perform_8b_10b_clock_recovery_sequence( offset); /* 5. check CR done*/ - if (dp_is_cr_done(lane_count, dpcd_lane_status)) + if (dp_is_cr_done(lane_count, dpcd_lane_status)) { + DC_LOG_HW_LINK_TRAINING("%s: Clock recovery OK\n", __func__); return LINK_TRAINING_SUCCESS; + } /* 6. max VS reached*/ if ((link_dp_get_encoding_format(<_settings->link_settings) == diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.c index e50ec5012559..4c6b886a9da8 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.c @@ -30,7 +30,7 @@ #include "link_dp_phy.h" #define DC_LOGGER \ link->ctx->logger -bool dc_link_dp_perform_link_training_skip_aux( +bool dp_perform_link_training_skip_aux( struct dc_link *link, const struct link_resource *link_res, const struct dc_link_settings *link_setting) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.h index 413999cd03c4..546387a5f32d 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_auxless.h @@ -28,7 +28,7 @@ #define __DC_LINK_DP_TRAINING_AUXLESS_H__ #include "link_dp_training.h" -bool dc_link_dp_perform_link_training_skip_aux( +bool dp_perform_link_training_skip_aux( struct dc_link *link, const struct link_resource *link_res, const struct dc_link_settings *link_setting); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c index e60da0532c53..4f4e899e5c46 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.c @@ -29,7 +29,6 @@ #include "link_dp_training_dpia.h" #include "dc.h" #include "inc/core_status.h" -#include "dc_link.h" #include "dpcd_defs.h" #include "link_dp_dpia.h" @@ -402,6 +401,7 @@ static enum link_training_result dpia_training_cr_non_transparent( /* Check if clock recovery successful. */ if (dp_is_cr_done(lane_count, dpcd_lane_status)) { + DC_LOG_HW_LINK_TRAINING("%s: Clock recovery OK\n", __func__); result = LINK_TRAINING_SUCCESS; break; } @@ -509,6 +509,7 @@ static enum link_training_result dpia_training_cr_transparent( /* Check if clock recovery successful. */ if (dp_is_cr_done(lane_count, dpcd_lane_status)) { + DC_LOG_HW_LINK_TRAINING("%s: Clock recovery OK\n", __func__); result = LINK_TRAINING_SUCCESS; break; } @@ -986,7 +987,7 @@ static void dpia_training_abort( core_link_send_set_config(link, DPIA_SET_CFG_SET_LINK, data); } -enum link_training_result dc_link_dpia_perform_link_training( +enum link_training_result dpia_perform_link_training( struct dc_link *link, const struct link_resource *link_res, const struct dc_link_settings *link_setting, @@ -999,7 +1000,7 @@ enum link_training_result dc_link_dpia_perform_link_training( struct dc_link_settings link_settings = *link_setting; // non-const copy to pass in - lt_settings.lttpr_mode = dc_link_decide_lttpr_mode(link, &link_settings); + lt_settings.lttpr_mode = dp_decide_lttpr_mode(link, &link_settings); /* Configure link as prescribed in link_setting and set LTTPR mode. */ result = dpia_configure_link(link, link_res, link_setting, <_settings); @@ -1035,7 +1036,7 @@ enum link_training_result dc_link_dpia_perform_link_training( * falling back to lower bandwidth settings possible. */ if (result == LINK_TRAINING_SUCCESS) { - msleep(5); + fsleep(5000); if (!link->is_automated) result = dp_check_link_loss_status(link, <_settings); } else if (result == LINK_TRAINING_ABORT) diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.h index 0150f2916421..b39fb9faf1c2 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_dpia.h @@ -32,7 +32,7 @@ * DPIA equivalent of dc_link_dp_perfrorm_link_training. * Aborts link training upon detection of sink unplug. */ -enum link_training_result dc_link_dpia_perform_link_training( +enum link_training_result dpia_perform_link_training( struct dc_link *link, const struct link_resource *link_res, const struct dc_link_settings *link_setting, diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c index a4071d2959a0..5731c4b61f9f 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.c @@ -223,7 +223,7 @@ static enum link_training_result perform_fixed_vs_pe_nontransparent_training_seq } -enum link_training_result dp_perform_fixed_vs_pe_training_sequence( +enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( struct dc_link *link, const struct link_resource *link_res, struct link_training_settings *lt_settings) @@ -577,3 +577,379 @@ enum link_training_result dp_perform_fixed_vs_pe_training_sequence( return status; } + +enum link_training_result dp_perform_fixed_vs_pe_training_sequence( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings) +{ + const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF}; + const uint8_t offset = dp_parse_lttpr_repeater_count( + link->dpcd_caps.lttpr_caps.phy_repeater_cnt); + const uint8_t vendor_lttpr_write_data_intercept_en[4] = {0x1, 0x55, 0x63, 0x0}; + const uint8_t vendor_lttpr_write_data_intercept_dis[4] = {0x1, 0x55, 0x63, 0x6E}; + const uint8_t vendor_lttpr_write_data_adicora_eq1[4] = {0x1, 0x55, 0x63, 0x2E}; + const uint8_t vendor_lttpr_write_data_adicora_eq2[4] = {0x1, 0x55, 0x63, 0x01}; + const uint8_t vendor_lttpr_write_data_adicora_eq3[4] = {0x1, 0x55, 0x63, 0x68}; + uint32_t pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa; + uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0}; + uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0}; + + uint32_t vendor_lttpr_write_address = 0xF004F; + enum link_training_result status = LINK_TRAINING_SUCCESS; + uint8_t lane = 0; + union down_spread_ctrl downspread = {0}; + union lane_count_set lane_count_set = {0}; + uint8_t toggle_rate; + uint8_t rate; + + /* Only 8b/10b is supported */ + ASSERT(link_dp_get_encoding_format(<_settings->link_settings) == + DP_8b_10b_ENCODING); + + if (lt_settings->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) { + status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings); + return status; + } + + if (offset != 0xFF) { + vendor_lttpr_write_address += + ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1)); + + /* Certain display and cable configuration require extra delay */ + if (offset > 2) + pre_disable_intercept_delay_ms = link->dc->debug.fixed_vs_aux_delay_config_wa * 2; + } + + /* Vendor specific: Reset lane settings */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_reset[0], + sizeof(vendor_lttpr_write_data_reset)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + /* Vendor specific: Enable intercept */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_en[0], + sizeof(vendor_lttpr_write_data_intercept_en)); + + /* 1. set link rate, lane count and spread. */ + + downspread.raw = (uint8_t)(lt_settings->link_settings.link_spread); + + lane_count_set.bits.LANE_COUNT_SET = + lt_settings->link_settings.lane_count; + + lane_count_set.bits.ENHANCED_FRAMING = lt_settings->enhanced_framing; + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0; + + + if (lt_settings->pattern_for_eq < DP_TRAINING_PATTERN_SEQUENCE_4) { + lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = + link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED; + } + + core_link_write_dpcd(link, DP_DOWNSPREAD_CTRL, + &downspread.raw, sizeof(downspread)); + + core_link_write_dpcd(link, DP_LANE_COUNT_SET, + &lane_count_set.raw, 1); + + rate = get_dpcd_link_rate(<_settings->link_settings); + + /* Vendor specific: Toggle link rate */ + toggle_rate = (rate == 0x6) ? 0xA : 0x6; + + if (link->vendor_specific_lttpr_link_rate_wa == rate) { + core_link_write_dpcd( + link, + DP_LINK_BW_SET, + &toggle_rate, + 1); + } + + link->vendor_specific_lttpr_link_rate_wa = rate; + + core_link_write_dpcd(link, DP_LINK_BW_SET, &rate, 1); + + DC_LOG_HW_LINK_TRAINING("%s\n %x rate = %x\n %x lane = %x framing = %x\n %x spread = %x\n", + __func__, + DP_LINK_BW_SET, + lt_settings->link_settings.link_rate, + DP_LANE_COUNT_SET, + lt_settings->link_settings.lane_count, + lt_settings->enhanced_framing, + DP_DOWNSPREAD_CTRL, + lt_settings->link_settings.link_spread); + + /* 2. Perform link training */ + + /* Perform Clock Recovery Sequence */ + if (status == LINK_TRAINING_SUCCESS) { + const uint8_t max_vendor_dpcd_retries = 10; + uint32_t retries_cr; + uint32_t retry_count; + uint32_t wait_time_microsec; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX]; + union lane_align_status_updated dpcd_lane_status_updated; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + enum dc_status dpcd_status = DC_OK; + uint8_t i = 0; + + retries_cr = 0; + retry_count = 0; + + memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status)); + memset(&dpcd_lane_status_updated, '\0', + sizeof(dpcd_lane_status_updated)); + + while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) && + (retry_count < LINK_TRAINING_MAX_CR_RETRY)) { + + + /* 1. call HWSS to set lane settings */ + dp_set_hw_lane_settings( + link, + link_res, + lt_settings, + 0); + + /* 2. update DPCD of the receiver */ + if (!retry_count) { + /* EPR #361076 - write as a 5-byte burst, + * but only for the 1-st iteration. + */ + dpcd_set_lt_pattern_and_lane_settings( + link, + lt_settings, + lt_settings->pattern_for_cr, + 0); + /* Vendor specific: Disable intercept */ + for (i = 0; i < max_vendor_dpcd_retries; i++) { + msleep(pre_disable_intercept_delay_ms); + dpcd_status = core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_dis[0], + sizeof(vendor_lttpr_write_data_intercept_dis)); + + if (dpcd_status == DC_OK) + break; + + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_intercept_en[0], + sizeof(vendor_lttpr_write_data_intercept_en)); + } + } else { + vendor_lttpr_write_data_vs[3] = 0; + vendor_lttpr_write_data_pe[3] = 0; + + for (lane = 0; lane < lane_count; lane++) { + vendor_lttpr_write_data_vs[3] |= + lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); + vendor_lttpr_write_data_pe[3] |= + lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); + } + + /* Vendor specific: Update VS and PE to DPRX requested value */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + dpcd_set_lane_settings( + link, + lt_settings, + 0); + } + + /* 3. wait receiver to lock-on*/ + wait_time_microsec = lt_settings->cr_pattern_time; + + dp_wait_for_training_aux_rd_interval( + link, + wait_time_microsec); + + /* 4. Read lane status and requested drive + * settings as set by the sink + */ + dp_get_lane_status_and_lane_adjust( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + dpcd_lane_adjust, + 0); + + /* 5. check CR done*/ + if (dp_is_cr_done(lane_count, dpcd_lane_status)) { + status = LINK_TRAINING_SUCCESS; + break; + } + + /* 6. max VS reached*/ + if (dp_is_max_vs_reached(lt_settings)) + break; + + /* 7. same lane settings */ + /* Note: settings are the same for all lanes, + * so comparing first lane is sufficient + */ + if (lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET == + dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE) + retries_cr++; + else + retries_cr = 0; + + /* 8. update VS/PE/PC2 in lt_settings*/ + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + retry_count++; + } + + if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) { + ASSERT(0); + DC_LOG_ERROR("%s: Link Training Error, could not get CR after %d tries. Possibly voltage swing issue", + __func__, + LINK_TRAINING_MAX_CR_RETRY); + + } + + status = dp_get_cr_failure(lane_count, dpcd_lane_status); + } + + /* Perform Channel EQ Sequence */ + if (status == LINK_TRAINING_SUCCESS) { + enum dc_dp_training_pattern tr_pattern; + uint32_t retries_ch_eq; + uint32_t wait_time_microsec; + enum dc_lane_count lane_count = lt_settings->link_settings.lane_count; + union lane_align_status_updated dpcd_lane_status_updated = {0}; + union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0}; + union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0}; + + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_adicora_eq1[0], + sizeof(vendor_lttpr_write_data_adicora_eq1)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_adicora_eq2[0], + sizeof(vendor_lttpr_write_data_adicora_eq2)); + + /* Note: also check that TPS4 is a supported feature*/ + tr_pattern = lt_settings->pattern_for_eq; + + dp_set_hw_training_pattern(link, link_res, tr_pattern, 0); + + status = LINK_TRAINING_EQ_FAIL_EQ; + + for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT; + retries_ch_eq++) { + + dp_set_hw_lane_settings(link, link_res, lt_settings, 0); + + vendor_lttpr_write_data_vs[3] = 0; + vendor_lttpr_write_data_pe[3] = 0; + + for (lane = 0; lane < lane_count; lane++) { + vendor_lttpr_write_data_vs[3] |= + lt_settings->dpcd_lane_settings[lane].bits.VOLTAGE_SWING_SET << (2 * lane); + vendor_lttpr_write_data_pe[3] |= + lt_settings->dpcd_lane_settings[lane].bits.PRE_EMPHASIS_SET << (2 * lane); + } + + /* Vendor specific: Update VS and PE to DPRX requested value */ + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_vs[0], + sizeof(vendor_lttpr_write_data_vs)); + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_pe[0], + sizeof(vendor_lttpr_write_data_pe)); + + /* 2. update DPCD*/ + if (!retries_ch_eq) { + /* EPR #361076 - write as a 5-byte burst, + * but only for the 1-st iteration + */ + + dpcd_set_lt_pattern_and_lane_settings( + link, + lt_settings, + tr_pattern, 0); + + core_link_write_dpcd( + link, + vendor_lttpr_write_address, + &vendor_lttpr_write_data_adicora_eq3[0], + sizeof(vendor_lttpr_write_data_adicora_eq3)); + } else + dpcd_set_lane_settings(link, lt_settings, 0); + + /* 3. wait for receiver to lock-on*/ + wait_time_microsec = lt_settings->eq_pattern_time; + + dp_wait_for_training_aux_rd_interval( + link, + wait_time_microsec); + + /* 4. Read lane status and requested + * drive settings as set by the sink + */ + dp_get_lane_status_and_lane_adjust( + link, + lt_settings, + dpcd_lane_status, + &dpcd_lane_status_updated, + dpcd_lane_adjust, + 0); + + /* 5. check CR done*/ + if (!dp_is_cr_done(lane_count, dpcd_lane_status)) { + status = LINK_TRAINING_EQ_FAIL_CR; + break; + } + + /* 6. check CHEQ done*/ + if (dp_is_ch_eq_done(lane_count, dpcd_lane_status) && + dp_is_symbol_locked(lane_count, dpcd_lane_status) && + dp_is_interlane_aligned(dpcd_lane_status_updated)) { + status = LINK_TRAINING_SUCCESS; + break; + } + + /* 7. update VS/PE/PC2 in lt_settings*/ + dp_decide_lane_settings(lt_settings, dpcd_lane_adjust, + lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings); + } + } + + return status; +} diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h index e61970e27661..c0d6ea329504 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_dp_training_fixed_vs_pe_retimer.h @@ -28,6 +28,11 @@ #define __DC_LINK_DP_FIXED_VS_PE_RETIMER_H__ #include "link_dp_training.h" +enum link_training_result dp_perform_fixed_vs_pe_training_sequence_legacy( + struct dc_link *link, + const struct link_resource *link_res, + struct link_training_settings *lt_settings); + enum link_training_result dp_perform_fixed_vs_pe_training_sequence( struct dc_link *link, const struct link_resource *link_res, diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c index 97e02b5b21ae..d895046787bc 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.c @@ -37,6 +37,11 @@ #include "abm.h" #define DC_LOGGER_INIT(logger) +/* Travis */ +static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT"; +/* Nutmeg */ +static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA"; + void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode) { union dpcd_edp_config edp_config_set; @@ -139,7 +144,7 @@ enum dp_panel_mode dp_get_panel_mode(struct dc_link *link) return DP_PANEL_MODE_DEFAULT; } -bool dc_link_set_backlight_level_nits(struct dc_link *link, +bool edp_set_backlight_level_nits(struct dc_link *link, bool isHDR, uint32_t backlight_millinits, uint32_t transition_time_in_ms) @@ -171,7 +176,7 @@ bool dc_link_set_backlight_level_nits(struct dc_link *link, return true; } -bool dc_link_get_backlight_level_nits(struct dc_link *link, +bool edp_get_backlight_level_nits(struct dc_link *link, uint32_t *backlight_millinits_avg, uint32_t *backlight_millinits_peak) { @@ -201,7 +206,7 @@ bool dc_link_get_backlight_level_nits(struct dc_link *link, return true; } -bool link_backlight_enable_aux(struct dc_link *link, bool enable) +bool edp_backlight_enable_aux(struct dc_link *link, bool enable) { uint8_t backlight_enable = enable ? 1 : 0; @@ -243,13 +248,13 @@ bool set_default_brightness_aux(struct dc_link *link) if (default_backlight < 5000 || default_backlight > 5000000) default_backlight = 150000; // - return dc_link_set_backlight_level_nits(link, true, + return edp_set_backlight_level_nits(link, true, default_backlight, 0); } return false; } -bool link_is_edp_ilr_optimization_required(struct dc_link *link, +bool edp_is_ilr_optimization_required(struct dc_link *link, struct dc_crtc_timing *crtc_timing) { struct dc_link_settings link_setting; @@ -285,7 +290,7 @@ bool link_is_edp_ilr_optimization_required(struct dc_link *link, req_bw = dc_bandwidth_in_kbps_from_timing(crtc_timing); if (!crtc_timing->flags.DSC) - dc_link_decide_edp_link_settings(link, &link_setting, req_bw); + edp_decide_link_settings(link, &link_setting, req_bw); else decide_edp_link_settings_with_dsc(link, &link_setting, req_bw, LINK_RATE_UNKNOWN); @@ -299,7 +304,7 @@ bool link_is_edp_ilr_optimization_required(struct dc_link *link, return false; } -void dc_link_edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd) +void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd) { if (link->connector_signal != SIGNAL_TYPE_EDP) return; @@ -311,7 +316,7 @@ void dc_link_edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hp link->dc->hwss.edp_backlight_control(link, true); } -bool dc_link_wait_for_t12(struct dc_link *link) +bool edp_wait_for_t12(struct dc_link *link) { if (link->connector_signal == SIGNAL_TYPE_EDP && link->dc->hwss.edp_wait_for_T12) { link->dc->hwss.edp_wait_for_T12(link); @@ -322,13 +327,13 @@ bool dc_link_wait_for_t12(struct dc_link *link) return false; } -void link_edp_add_delay_for_T9(struct dc_link *link) +void edp_add_delay_for_T9(struct dc_link *link) { if (link && link->panel_config.pps.extra_delay_backlight_off > 0) - udelay(link->panel_config.pps.extra_delay_backlight_off * 1000); + fsleep(link->panel_config.pps.extra_delay_backlight_off * 1000); } -bool link_edp_receiver_ready_T9(struct dc_link *link) +bool edp_receiver_ready_T9(struct dc_link *link) { unsigned int tries = 0; unsigned char sinkstatus = 0; @@ -353,7 +358,7 @@ bool link_edp_receiver_ready_T9(struct dc_link *link) return result; } -bool link_edp_receiver_ready_T7(struct dc_link *link) +bool edp_receiver_ready_T7(struct dc_link *link) { unsigned char sinkstatus = 0; unsigned char edpRev = 0; @@ -383,12 +388,12 @@ bool link_edp_receiver_ready_T7(struct dc_link *link) } if (link && link->panel_config.pps.extra_t7_ms > 0) - udelay(link->panel_config.pps.extra_t7_ms * 1000); + fsleep(link->panel_config.pps.extra_t7_ms * 1000); return result; } -bool link_power_alpm_dpcd_enable(struct dc_link *link, bool enable) +bool edp_power_alpm_dpcd_enable(struct dc_link *link, bool enable) { bool ret = false; union dpcd_alpm_configuration alpm_config; @@ -422,7 +427,7 @@ static struct pipe_ctx *get_pipe_from_link(const struct dc_link *link) return pipe_ctx; } -bool dc_link_set_backlight_level(const struct dc_link *link, +bool edp_set_backlight_level(const struct dc_link *link, uint32_t backlight_pwm_u16_16, uint32_t frame_ramp) { @@ -453,7 +458,7 @@ bool dc_link_set_backlight_level(const struct dc_link *link, return true; } -bool dc_link_set_psr_allow_active(struct dc_link *link, const bool *allow_active, +bool edp_set_psr_allow_active(struct dc_link *link, const bool *allow_active, bool wait, bool force_static, const unsigned int *power_opts) { struct dc *dc = link->ctx->dc; @@ -502,7 +507,7 @@ bool dc_link_set_psr_allow_active(struct dc_link *link, const bool *allow_active return true; } -bool dc_link_get_psr_state(const struct dc_link *link, enum dc_psr_state *state) +bool edp_get_psr_state(const struct dc_link *link, enum dc_psr_state *state) { struct dc *dc = link->ctx->dc; struct dmcu *dmcu = dc->res_pool->dmcu; @@ -557,7 +562,7 @@ transmitter_to_phy_id(struct dc_link *link) } } -bool dc_link_setup_psr(struct dc_link *link, +bool edp_setup_psr(struct dc_link *link, const struct dc_stream_state *stream, struct psr_config *psr_config, struct psr_context *psr_context) { @@ -623,7 +628,7 @@ bool dc_link_setup_psr(struct dc_link *link, sizeof(psr_configuration.raw)); if (link->psr_settings.psr_version == DC_PSR_VERSION_SU_1) { - link_power_alpm_dpcd_enable(link, true); + edp_power_alpm_dpcd_enable(link, true); psr_context->su_granularity_required = psr_config->su_granularity_required; psr_context->su_y_granularity = @@ -695,7 +700,6 @@ bool dc_link_setup_psr(struct dc_link *link, psr_context->psr_level.u32all = 0; /*skip power down the single pipe since it blocks the cstate*/ -#if defined(CONFIG_DRM_AMD_DC_DCN) if (link->ctx->asic_id.chip_family >= FAMILY_RV) { switch (link->ctx->asic_id.chip_family) { case FAMILY_YELLOW_CARP: @@ -709,10 +713,6 @@ bool dc_link_setup_psr(struct dc_link *link, break; } } -#else - if (link->ctx->asic_id.chip_family >= FAMILY_RV) - psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true; -#endif /* SMU will perform additional powerdown sequence. * For unsupported ASICs, set psr_level flag to skip PSR @@ -757,7 +757,7 @@ bool dc_link_setup_psr(struct dc_link *link, } -void link_get_psr_residency(const struct dc_link *link, uint32_t *residency) +void edp_get_psr_residency(const struct dc_link *link, uint32_t *residency) { struct dc *dc = link->ctx->dc; struct dmub_psr *psr = dc->res_pool->psr; @@ -772,7 +772,7 @@ void link_get_psr_residency(const struct dc_link *link, uint32_t *residency) else *residency = 0; } -bool link_set_sink_vtotal_in_psr_active(const struct dc_link *link, uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su) +bool edp_set_sink_vtotal_in_psr_active(const struct dc_link *link, uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su) { struct dc *dc = link->ctx->dc; struct dmub_psr *psr = dc->res_pool->psr; @@ -803,7 +803,7 @@ static struct abm *get_abm_from_stream_res(const struct dc_link *link) return abm; } -int dc_link_get_backlight_level(const struct dc_link *link) +int edp_get_backlight_level(const struct dc_link *link) { struct abm *abm = get_abm_from_stream_res(link); struct panel_cntl *panel_cntl = link->panel_cntl; @@ -822,7 +822,7 @@ int dc_link_get_backlight_level(const struct dc_link *link) return DC_ERROR_UNEXPECTED; } -int dc_link_get_target_backlight_pwm(const struct dc_link *link) +int edp_get_target_backlight_pwm(const struct dc_link *link) { struct abm *abm = get_abm_from_stream_res(link); diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h index 7f91a564b089..28f552080558 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_edp_panel_control.h @@ -30,4 +30,34 @@ enum dp_panel_mode dp_get_panel_mode(struct dc_link *link); void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode); bool set_default_brightness_aux(struct dc_link *link); +void edp_panel_backlight_power_on(struct dc_link *link, bool wait_for_hpd); +int edp_get_backlight_level(const struct dc_link *link); +bool edp_get_backlight_level_nits(struct dc_link *link, + uint32_t *backlight_millinits_avg, + uint32_t *backlight_millinits_peak); +bool edp_set_backlight_level(const struct dc_link *link, + uint32_t backlight_pwm_u16_16, + uint32_t frame_ramp); +bool edp_set_backlight_level_nits(struct dc_link *link, + bool isHDR, + uint32_t backlight_millinits, + uint32_t transition_time_in_ms); +int edp_get_target_backlight_pwm(const struct dc_link *link); +bool edp_get_psr_state(const struct dc_link *link, enum dc_psr_state *state); +bool edp_set_psr_allow_active(struct dc_link *link, const bool *allow_active, + bool wait, bool force_static, const unsigned int *power_opts); +bool edp_setup_psr(struct dc_link *link, + const struct dc_stream_state *stream, struct psr_config *psr_config, + struct psr_context *psr_context); +bool edp_set_sink_vtotal_in_psr_active(const struct dc_link *link, + uint16_t psr_vtotal_idle, uint16_t psr_vtotal_su); +void edp_get_psr_residency(const struct dc_link *link, uint32_t *residency); +bool edp_wait_for_t12(struct dc_link *link); +bool edp_is_ilr_optimization_required(struct dc_link *link, + struct dc_crtc_timing *crtc_timing); +bool edp_backlight_enable_aux(struct dc_link *link, bool enable); +void edp_add_delay_for_T9(struct dc_link *link); +bool edp_receiver_ready_T9(struct dc_link *link); +bool edp_receiver_ready_T7(struct dc_link *link); +bool edp_power_alpm_dpcd_enable(struct dc_link *link, bool enable); #endif /* __DC_LINK_EDP_POWER_CONTROL_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.c b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.c index 5f39dfe06e9a..e3d729ab5b9f 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.c +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.c @@ -33,18 +33,18 @@ #include "link_hpd.h" #include "gpio_service_interface.h" -bool dc_link_get_hpd_state(struct dc_link *dc_link) +bool link_get_hpd_state(struct dc_link *link) { uint32_t state; - dal_gpio_lock_pin(dc_link->hpd_gpio); - dal_gpio_get_value(dc_link->hpd_gpio, &state); - dal_gpio_unlock_pin(dc_link->hpd_gpio); + dal_gpio_lock_pin(link->hpd_gpio); + dal_gpio_get_value(link->hpd_gpio, &state); + dal_gpio_unlock_pin(link->hpd_gpio); return state; } -void dc_link_enable_hpd(const struct dc_link *link) +void link_enable_hpd(const struct dc_link *link) { struct link_encoder *encoder = link->link_enc; @@ -52,7 +52,7 @@ void dc_link_enable_hpd(const struct dc_link *link) encoder->funcs->enable_hpd(encoder); } -void dc_link_disable_hpd(const struct dc_link *link) +void link_disable_hpd(const struct dc_link *link) { struct link_encoder *encoder = link->link_enc; @@ -60,7 +60,7 @@ void dc_link_disable_hpd(const struct dc_link *link) encoder->funcs->disable_hpd(encoder); } -void dc_link_enable_hpd_filter(struct dc_link *link, bool enable) +void link_enable_hpd_filter(struct dc_link *link, bool enable) { struct gpio *hpd; diff --git a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.h b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.h index 3d122def0c88..4fb526b264f9 100644 --- a/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.h +++ b/drivers/gpu/drm/amd/display/dc/link/protocols/link_hpd.h @@ -44,4 +44,11 @@ bool program_hpd_filter(const struct dc_link *link); */ bool dpia_query_hpd_status(struct dc_link *link); bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high); +bool link_get_hpd_state(struct dc_link *link); +struct gpio *link_get_hpd_gpio(struct dc_bios *dcb, + struct graphics_object_id link_id, + struct gpio_service *gpio_service); +void link_enable_hpd(const struct dc_link *link); +void link_disable_hpd(const struct dc_link *link); +void link_enable_hpd_filter(struct dc_link *link, bool enable); #endif /* __DC_LINK_HPD_H__ */ |