Commit 4a3ad932 authored by Shen, George's avatar Shen, George Committed by Alex Deucher

drm/amd/display: Add Cable ID support for native DP

[Why/How]
We need to handle cable capabilities for cables that support cable ID.
The cable attributes are intersected with the verified link caps to
determine appropriate max link rate. After determining cable attributes
we update the DP receiver.
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Reviewed-by: default avatarWenjing Liu <Wenjing.Liu@amd.com>
Acked-by: default avatarRodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: default avatarGeorge Shen <George.Shen@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent b80ddeb2
......@@ -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)
......
......@@ -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));
}
......@@ -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 {
......
......@@ -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;
......
......@@ -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_ */
......@@ -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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment