diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 08fbf0ab047a..47cced994bfb 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1291,6 +1291,8 @@ static bool detect_link_and_local_sink(struct dc_link *link, * Clear dongle_max_pix_clk on disconnect to fix this */ link->dongle_max_pix_clk = 0; + + dc_link_dp_clear_rx_status(link); } LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p edid same=%d\n", @@ -1970,6 +1972,9 @@ static enum dc_status enable_link_dp(struct dc_state *state, if (link->dpcd_sink_ext_caps.raw != 0) msleep(post_oui_delay); + // similarly, mode switch can cause loss of cable ID + dpcd_update_cable_id(link); + skip_video_pattern = true; if (link_settings.link_rate == LINK_RATE_LOW) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c index a514f19d8f8b..062bdbadc781 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c @@ -2981,6 +2981,20 @@ static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link) return lttpr_max_link_rate; } +static enum dc_link_rate get_cable_max_link_rate(struct dc_link *link) +{ + enum dc_link_rate cable_max_link_rate = LINK_RATE_HIGH3; + + if (link->dpcd_caps.cable_attributes.bits.UHBR10_20_CAPABILITY & DP_UHBR20) + cable_max_link_rate = LINK_RATE_UHBR20; + else if (link->dpcd_caps.cable_attributes.bits.UHBR13_5_CAPABILITY) + cable_max_link_rate = LINK_RATE_UHBR13_5; + else if (link->dpcd_caps.cable_attributes.bits.UHBR10_20_CAPABILITY & DP_UHBR10) + cable_max_link_rate = LINK_RATE_UHBR10; + + return cable_max_link_rate; +} + bool dc_link_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; @@ -3009,8 +3023,10 @@ struct dc_link_settings dp_get_max_link_cap(struct dc_link *link) { struct dc_link_settings max_link_cap = {0}; enum dc_link_rate lttpr_max_link_rate; + enum dc_link_rate cable_max_link_rate; struct link_encoder *link_enc = NULL; + link_enc = link_enc_cfg_get_link_enc(link); ASSERT(link_enc); @@ -3029,6 +3045,14 @@ struct dc_link_settings dp_get_max_link_cap(struct dc_link *link) max_link_cap.link_spread) max_link_cap.link_spread = link->reported_link_cap.link_spread; + + /* Lower link settings based on cable attributes */ + cable_max_link_rate = get_cable_max_link_rate(link); + + if (!link->dc->debug.ignore_cable_id && + cable_max_link_rate < max_link_cap.link_rate) + max_link_cap.link_rate = cable_max_link_rate; + /* * account for lttpr repeaters cap * notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3). @@ -5059,6 +5083,13 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link) return is_lttpr_present; } + +static bool is_usbc_connector(struct dc_link *link) +{ + return link->link_enc && + link->link_enc->features.flags.bits.DP_IS_USB_C; +} + static bool retrieve_link_cap(struct dc_link *link) { /* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16, @@ -5115,6 +5146,9 @@ static bool retrieve_link_cap(struct dc_link *link) */ msleep(post_oui_delay); + /* Read cable ID and update receiver */ + dpcd_update_cable_id(link); + for (i = 0; i < read_dpcd_retry_cnt; i++) { status = core_link_read_dpcd( link, @@ -6292,6 +6326,26 @@ void dpcd_set_source_specific_data(struct dc_link *link) } } +void dpcd_update_cable_id(struct dc_link *link) +{ + if (!link->link_enc->features.flags.bits.IS_UHBR10_CAPABLE || + link->dprx_status.cable_id_updated) + return; + + /* Retrieve cable attributes */ + if (!is_usbc_connector(link)) + core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX, + &link->dpcd_caps.cable_attributes.raw, + sizeof(uint8_t)); + + /* Update receiver with cable attributes */ + core_link_write_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX, + &link->dpcd_caps.cable_attributes.raw, + sizeof(link->dpcd_caps.cable_attributes.raw)); + + link->dprx_status.cable_id_updated = 1; +} + bool dc_link_set_backlight_level_nits(struct dc_link *link, bool isHDR, uint32_t backlight_millinits, @@ -6689,3 +6743,8 @@ void edp_panel_backlight_power_on(struct dc_link *link) if (link->dc->hwss.edp_backlight_control) link->dc->hwss.edp_backlight_control(link, true); } + +void dc_link_dp_clear_rx_status(struct dc_link *link) +{ + memset(&link->dprx_status, 0, sizeof(link->dprx_status)); +} diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index ff5093e52f2d..0dc183d6af5d 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -687,6 +687,7 @@ struct dc_debug_options { bool set_mst_en_for_sst; bool disable_uhbr; bool force_dp2_lt_fallback_method; + bool ignore_cable_id; union mem_low_power_enable_options enable_mem_low_power; union root_clock_optimization_options root_clock_optimization; bool hpo_optimization; @@ -1234,6 +1235,7 @@ struct dpcd_caps { union dp_main_line_channel_coding_cap channel_coding_cap; union dp_sink_video_fallback_formats fallback_formats; union dp_fec_capability1 fec_cap1; + union dp_cable_attributes cable_attributes; }; union dpcd_sink_ext_caps { diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h index 7b1103e9f7a2..772084406795 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -901,6 +901,9 @@ struct dpcd_usb4_dp_tunneling_info { #ifndef DP_LINK_SQUARE_PATTERN #define DP_LINK_SQUARE_PATTERN 0x10F #endif +#ifndef DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX +#define DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX 0x110 +#endif #ifndef DP_DSC_CONFIGURATION #define DP_DSC_CONFIGURATION 0x161 #endif @@ -913,6 +916,9 @@ struct dpcd_usb4_dp_tunneling_info { #ifndef DP_128b_132b_TRAINING_AUX_RD_INTERVAL #define DP_128b_132b_TRAINING_AUX_RD_INTERVAL 0x2216 #endif +#ifndef DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX +#define DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX 0x2217 +#endif #ifndef DP_TEST_264BIT_CUSTOM_PATTERN_7_0 #define DP_TEST_264BIT_CUSTOM_PATTERN_7_0 0X2230 #endif @@ -1012,6 +1018,16 @@ union dp_fec_capability1 { uint8_t raw; }; +union dp_cable_attributes { + struct { + uint8_t UHBR10_20_CAPABILITY :2; + uint8_t UHBR13_5_CAPABILITY :1; + uint8_t CABLE_TYPE :3; + uint8_t RESERVED :2; + } bits; + uint8_t raw; +}; + struct dp_color_depth_caps { uint8_t support_6bpc :1; uint8_t support_8bpc :1; diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 9014c0a0a63b..b1c79b3f26aa 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -43,6 +43,10 @@ struct dc_link_status { struct dpcd_caps *dpcd_caps; }; +struct dp_receiver_status { + bool cable_id_updated; +}; + /* DP MST stream allocation (payload bandwidth number) */ struct link_mst_stream_allocation { /* DIG front */ @@ -201,6 +205,7 @@ struct dc_link { struct link_mst_stream_allocation_table mst_stream_alloc_table; struct dc_link_status link_status; + struct dp_receiver_status dprx_status; struct link_trace link_trace; struct gpio *hpd_gpio; @@ -459,4 +464,6 @@ const struct link_resource *dc_link_get_cur_link_res(const struct dc_link *link) void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map); /* restore link resource allocation state from a snapshot */ void dc_restore_link_res_map(const struct dc *dc, uint32_t *map); + +void dc_link_dp_clear_rx_status(struct dc_link *link); #endif /* DC_LINK_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h index b7c5c42d67ed..3ed2dbbf5642 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h +++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h @@ -112,6 +112,9 @@ void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode); bool dp_overwrite_extended_receiver_cap(struct dc_link *link); void dpcd_set_source_specific_data(struct dc_link *link); + +void dpcd_update_cable_id(struct dc_link *link); + /* Write DPCD link configuration data. */ enum dc_status dpcd_set_link_settings( struct dc_link *link,