From c595fb05e392a5cd17c70c4fd996b8cc9735f20e Mon Sep 17 00:00:00 2001 From: Wenjing Liu Date: Tue, 8 Feb 2022 18:38:26 -0500 Subject: [PATCH] drm/amd/display: add cable ID support for usb c connector [how] Call to DMUB to retrieve usb c cable ID data from PD firmware. If cable id is retrieved from DMUB, skip reading cable ID from RX. Reviewed-by: George Shen Acked-by: Solomon Chiu Signed-off-by: Wenjing Liu Tested-by: Daniel Wheeler Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 4 +- drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c | 100 +++++++++++++++-------- drivers/gpu/drm/amd/display/dc/dc.h | 2 +- drivers/gpu/drm/amd/display/dc/dc_dp_types.h | 2 +- drivers/gpu/drm/amd/display/dc/dc_link.h | 8 +- drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h | 2 +- drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h | 40 +++++++++ 7 files changed, 117 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index e0d4d67..27f3fc4 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1305,7 +1305,7 @@ static bool detect_link_and_local_sink(struct dc_link *link, */ link->dongle_max_pix_clk = 0; - dc_link_dp_clear_rx_status(link); + dc_link_clear_dprx_states(link); } LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p edid same=%d\n", @@ -1986,7 +1986,7 @@ static enum dc_status enable_link_dp(struct dc_state *state, msleep(post_oui_delay); // similarly, mode switch can cause loss of cable ID - dpcd_update_cable_id(link); + dpcd_write_cable_id_to_dprx(link); skip_video_pattern = true; 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 bc6161f..bfd0e48 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 @@ -51,6 +51,13 @@ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA"; #include "link_dpcd.h" +#ifndef MAX +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +#endif +#ifndef MIN +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +#endif + /* maximum pre emphasis level allowed for each voltage swing level*/ static const enum dc_pre_emphasis voltage_swing_to_pre_emphasis[] = { PRE_EMPHASIS_LEVEL3, @@ -2986,11 +2993,11 @@ 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) + if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR20) cable_max_link_rate = LINK_RATE_UHBR20; - else if (link->dpcd_caps.cable_attributes.bits.UHBR13_5_CAPABILITY) + else if (link->dpcd_caps.cable_id.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) + else if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR10) cable_max_link_rate = LINK_RATE_UHBR10; return cable_max_link_rate; @@ -5051,11 +5058,52 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link) return is_lttpr_present; } +static bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id *cable_id) +{ + union dmub_rb_cmd cmd; + + if (!link->ctx->dmub_srv || + link->ep_type != DISPLAY_ENDPOINT_PHY || + link->link_enc->features.flags.bits.DP_IS_USB_C == 0) + return false; + + memset(&cmd, 0, sizeof(cmd)); + cmd.cable_id.header.type = DMUB_CMD_GET_USBC_CABLE_ID; + cmd.cable_id.header.payload_bytes = sizeof(cmd.cable_id.data); + cmd.cable_id.data.input.phy_inst = resource_transmitter_to_phy_idx( + link->dc, link->link_enc->transmitter); + if (dc_dmub_srv_cmd_with_reply_data(link->ctx->dmub_srv, &cmd) && + cmd.cable_id.header.ret_status == 1) + cable_id->raw = cmd.cable_id.data.output_raw; -static bool is_usbc_connector(struct dc_link *link) + return cmd.cable_id.header.ret_status == 1; +} + +static union dp_cable_id intersect_cable_id( + union dp_cable_id *a, union dp_cable_id *b) { - return link->link_enc && - link->link_enc->features.flags.bits.DP_IS_USB_C; + union dp_cable_id out; + + out.bits.UHBR10_20_CAPABILITY = MIN(a->bits.UHBR10_20_CAPABILITY, + b->bits.UHBR10_20_CAPABILITY); + out.bits.UHBR13_5_CAPABILITY = MIN(a->bits.UHBR13_5_CAPABILITY, + b->bits.UHBR13_5_CAPABILITY); + out.bits.CABLE_TYPE = MAX(a->bits.CABLE_TYPE, b->bits.CABLE_TYPE); + + return out; +} + +static void retrieve_cable_id(struct dc_link *link) +{ + union dp_cable_id usbc_cable_id; + + link->dpcd_caps.cable_id.raw = 0; + core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX, + &link->dpcd_caps.cable_id.raw, sizeof(uint8_t)); + + if (get_usbc_cable_id(link, &usbc_cable_id)) + link->dpcd_caps.cable_id = intersect_cable_id( + &link->dpcd_caps.cable_id, &usbc_cable_id); } static bool retrieve_link_cap(struct dc_link *link) @@ -5114,9 +5162,6 @@ 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, @@ -5236,7 +5281,8 @@ static bool retrieve_link_cap(struct dc_link *link) edp_config_cap.bits.ALT_SCRAMBLER_RESET; link->dpcd_caps.dpcd_display_control_capable = edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE; - + link->dpcd_caps.channel_coding_cap.raw = + dpcd_data[DP_MAIN_LINK_CHANNEL_CODING - DP_DPCD_REV]; link->test_pattern_enabled = false; link->compliance_test_state.raw = 0; @@ -5363,8 +5409,6 @@ static bool retrieve_link_cap(struct dc_link *link) if (!dpcd_read_sink_ext_caps(link)) link->dpcd_sink_ext_caps.raw = 0; - link->dpcd_caps.channel_coding_cap.raw = dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_CAP - DP_DPCD_REV]; - if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) { DC_LOG_DP2("128b/132b encoding is supported at link %d", link->link_index); @@ -5410,6 +5454,9 @@ static bool retrieve_link_cap(struct dc_link *link) DC_LOG_DP2("\tFEC aggregated error counters are supported"); } + retrieve_cable_id(link); + dpcd_write_cable_id_to_dprx(link); + /* Connectivity log: detection */ CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: "); @@ -6342,29 +6389,18 @@ void dpcd_set_source_specific_data(struct dc_link *link) } } -void dpcd_update_cable_id(struct dc_link *link) +void dpcd_write_cable_id_to_dprx(struct dc_link *link) { - struct link_encoder *link_enc = NULL; - - link_enc = link_enc_cfg_get_link_enc(link); - - if (!link_enc || - !link_enc->features.flags.bits.IS_UHBR10_CAPABLE || - link->dprx_status.cable_id_updated) + if (!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED || + link->dpcd_caps.cable_id.raw == 0 || + link->dprx_states.cable_id_written) 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->dpcd_caps.cable_id.raw, + sizeof(link->dpcd_caps.cable_id.raw)); - link->dprx_status.cable_id_updated = 1; + link->dprx_states.cable_id_written = 1; } bool dc_link_set_backlight_level_nits(struct dc_link *link, @@ -6765,9 +6801,9 @@ void edp_panel_backlight_power_on(struct dc_link *link) link->dc->hwss.edp_backlight_control(link, true); } -void dc_link_dp_clear_rx_status(struct dc_link *link) +void dc_link_clear_dprx_states(struct dc_link *link) { - memset(&link->dprx_status, 0, sizeof(link->dprx_status)); + memset(&link->dprx_states, 0, sizeof(link->dprx_states)); } void dp_receiver_power_ctrl(struct dc_link *link, bool on) diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 6176904..9fa87a4 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1236,7 +1236,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 dp_cable_id cable_id; uint8_t edp_rev; union edp_alpm_caps alpm_caps; struct edp_psr_info psr_info; 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 aa35cf0..36ac2a8 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h @@ -1018,7 +1018,7 @@ union dp_fec_capability1 { uint8_t raw; }; -union dp_cable_attributes { +union dp_cable_id { struct { uint8_t UHBR10_20_CAPABILITY :2; uint8_t UHBR13_5_CAPABILITY :1; diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 9ad3ee4..ce6e8d0 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -43,8 +43,8 @@ struct dc_link_status { struct dpcd_caps *dpcd_caps; }; -struct dp_receiver_status { - bool cable_id_updated; +struct dprx_states { + bool cable_id_written; }; /* DP MST stream allocation (payload bandwidth number) */ @@ -205,7 +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 dprx_states dprx_states; struct link_trace link_trace; struct gpio *hpd_gpio; @@ -466,7 +466,7 @@ void 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); +void dc_link_clear_dprx_states(struct dc_link *link); struct gpio *get_hpd_gpio(struct dc_bios *dcb, struct graphics_object_id link_id, struct gpio_service *gpio_service); 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 477c4d9..ab9939d 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 @@ -106,7 +106,7 @@ 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); +void dpcd_write_cable_id_to_dprx(struct dc_link *link); /* Write DPCD link configuration data. */ enum dc_status dpcd_set_link_settings( diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index cb92ab4..34fb148 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -668,6 +668,10 @@ enum dmub_cmd_type { */ DMUB_CMD__EDID_CEA = 79, /** + * Command type used for getting usbc cable ID + */ + DMUB_CMD_GET_USBC_CABLE_ID = 81, + /** * Command type used for all VBIOS interface commands. */ DMUB_CMD__VBIOS = 128, @@ -2484,6 +2488,38 @@ struct dmub_rb_cmd_edid_cea { }; /** + * struct dmub_cmd_cable_id_input - Defines the input of DMUB_CMD_GET_USBC_CABLE_ID command. + */ +struct dmub_cmd_cable_id_input { + uint8_t phy_inst; /**< phy inst for cable id data */ +}; + +/** + * struct dmub_cmd_cable_id_input - Defines the output of DMUB_CMD_GET_USBC_CABLE_ID command. + */ +struct dmub_cmd_cable_id_output { + uint8_t UHBR10_20_CAPABILITY :2; /**< b'01 for UHBR10 support, b'10 for both UHBR10 and UHBR20 support */ + uint8_t UHBR13_5_CAPABILITY :1; /**< b'1 for UHBR13.5 support */ + uint8_t CABLE_TYPE :3; /**< b'01 for passive cable, b'10 for active LRD cable, b'11 for active retimer cable */ + uint8_t RESERVED :2; /**< reserved means not defined */ +}; + +/** + * Definition of a DMUB_CMD_GET_USBC_CABLE_ID command + */ +struct dmub_rb_cmd_get_usbc_cable_id { + struct dmub_cmd_header header; /**< Command header */ + /** + * Data passed from driver to FW in a DMUB_CMD_GET_USBC_CABLE_ID command. + */ + union dmub_cmd_cable_id_data { + struct dmub_cmd_cable_id_input input; /**< Input */ + struct dmub_cmd_cable_id_output output; /**< Output */ + uint8_t output_raw; /**< Raw data output */ + } data; +}; + +/** * union dmub_rb_cmd - DMUB inbox command. */ union dmub_rb_cmd { @@ -2648,6 +2684,10 @@ union dmub_rb_cmd { * Definition of a DMUB_CMD__EDID_CEA command. */ struct dmub_rb_cmd_edid_cea edid_cea; + /** + * Definition of a DMUB_CMD_GET_USBC_CABLE_ID command. + */ + struct dmub_rb_cmd_get_usbc_cable_id cable_id; }; /** -- 2.7.4