diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c | 185 |
1 files changed, 139 insertions, 46 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c index ee6f13bef377..ab70ebd8f223 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c @@ -67,6 +67,71 @@ #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) #endif +static uint8_t phy_id_from_transmitter(enum transmitter t) +{ + uint8_t phy_id; + + switch (t) { + case TRANSMITTER_UNIPHY_A: + phy_id = 0; + break; + case TRANSMITTER_UNIPHY_B: + phy_id = 1; + break; + case TRANSMITTER_UNIPHY_C: + phy_id = 2; + break; + case TRANSMITTER_UNIPHY_D: + phy_id = 3; + break; + case TRANSMITTER_UNIPHY_E: + phy_id = 4; + break; + case TRANSMITTER_UNIPHY_F: + phy_id = 5; + break; + case TRANSMITTER_UNIPHY_G: + phy_id = 6; + break; + default: + phy_id = 0; + break; + } + return phy_id; +} + +static bool has_query_dp_alt(struct link_encoder *enc) +{ + struct dc_dmub_srv *dc_dmub_srv = enc->ctx->dmub_srv; + + if (enc->ctx->dce_version >= DCN_VERSION_3_15) + return true; + + /* Supports development firmware and firmware >= 4.0.11 */ + return dc_dmub_srv && + !(dc_dmub_srv->dmub->fw_version >= DMUB_FW_VERSION(4, 0, 0) && + dc_dmub_srv->dmub->fw_version <= DMUB_FW_VERSION(4, 0, 10)); +} + +static bool query_dp_alt_from_dmub(struct link_encoder *enc, + union dmub_rb_cmd *cmd) +{ + struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + struct dc_dmub_srv *dc_dmub_srv = enc->ctx->dmub_srv; + + memset(cmd, 0, sizeof(*cmd)); + cmd->query_dp_alt.header.type = DMUB_CMD__VBIOS; + cmd->query_dp_alt.header.sub_type = + DMUB_CMD__VBIOS_TRANSMITTER_QUERY_DP_ALT; + cmd->query_dp_alt.header.payload_bytes = sizeof(cmd->query_dp_alt.data); + cmd->query_dp_alt.data.phy_id = phy_id_from_transmitter(enc10->base.transmitter); + + if (!dc_dmub_srv_cmd_with_reply_data(dc_dmub_srv, cmd)) + return false; + + return true; +} + void dcn31_link_encoder_set_dio_phy_mux( struct link_encoder *enc, enum encoder_type_select sel, @@ -141,7 +206,7 @@ void dcn31_link_encoder_set_dio_phy_mux( } } -void enc31_hw_init(struct link_encoder *enc) +static void enc31_hw_init(struct link_encoder *enc) { struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); @@ -168,9 +233,7 @@ void enc31_hw_init(struct link_encoder *enc) AUX_RX_PHASE_DETECT_LEN, [21,20] = 0x3 default is 3 AUX_RX_DETECTION_THRESHOLD [30:28] = 1 */ - AUX_REG_WRITE(AUX_DPHY_RX_CONTROL0, 0x103d1110); - - AUX_REG_WRITE(AUX_DPHY_TX_CONTROL, 0x21c7a); + // dmub will read AUX_DPHY_RX_CONTROL0/AUX_DPHY_TX_CONTROL from vbios table in dp_aux_init //AUX_DPHY_TX_REF_CONTROL'AUX_TX_REF_DIV HW default is 0x32; // Set AUX_TX_REF_DIV Divider to generate 2 MHz reference from refclk @@ -178,18 +241,9 @@ void enc31_hw_init(struct link_encoder *enc) // 100MHz -> 0x32 // 48MHz -> 0x18 -#ifdef CLEANUP_FIXME - /*from display_init*/ - REG_WRITE(RDPCSTX_DEBUG_CONFIG, 0); -#endif - // Set TMDS_CTL0 to 1. This is a legacy setting. REG_UPDATE(TMDS_CTL_BITS, TMDS_CTL0, 1); - /*HW default is 5*/ - REG_UPDATE(RDPCSTX_CNTL, - RDPCS_TX_FIFO_RD_START_DELAY, 4); - dcn10_aux_initialize(enc10); } @@ -407,6 +461,7 @@ void dcn31_link_encoder_enable_dp_output( /* Enable transmitter and encoder. */ if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc, enc)) { + DC_LOG_DEBUG("%s: enc_id(%d)\n", __func__, enc->preferred_engine); dcn20_link_encoder_enable_dp_output(enc, link_settings, clock_source); } else { @@ -438,6 +493,7 @@ void dcn31_link_encoder_enable_dp_output( return; } + DC_LOG_DEBUG("%s: DPIA(%d) - enc_id(%d)\n", __func__, dpia_control.dpia_id, dpia_control.enc_id); link_dpia_control(enc->ctx, &dpia_control); } } @@ -452,6 +508,7 @@ void dcn31_link_encoder_enable_dp_mst_output( /* Enable transmitter and encoder. */ if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc, enc)) { + DC_LOG_DEBUG("%s: enc_id(%d)\n", __func__, enc->preferred_engine); dcn10_link_encoder_enable_dp_mst_output(enc, link_settings, clock_source); } else { @@ -483,6 +540,7 @@ void dcn31_link_encoder_enable_dp_mst_output( return; } + DC_LOG_DEBUG("%s: DPIA(%d) - enc_id(%d)\n", __func__, dpia_control.dpia_id, dpia_control.enc_id); link_dpia_control(enc->ctx, &dpia_control); } } @@ -496,6 +554,7 @@ void dcn31_link_encoder_disable_output( /* Disable transmitter and encoder. */ if (!link_enc_cfg_is_transmitter_mappable(enc->ctx->dc, enc)) { + DC_LOG_DEBUG("%s: enc_id(%d)\n", __func__, enc->preferred_engine); dcn10_link_encoder_disable_output(enc, signal); } else { @@ -527,6 +586,7 @@ void dcn31_link_encoder_disable_output( return; } + DC_LOG_DEBUG("%s: DPIA(%d) - enc_id(%d)\n", __func__, dpia_control.dpia_id, dpia_control.enc_id); link_dpia_control(enc->ctx, &dpia_control); link_encoder_disable(enc10); @@ -536,57 +596,90 @@ void dcn31_link_encoder_disable_output( bool dcn31_link_encoder_is_in_alt_mode(struct link_encoder *enc) { struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + union dmub_rb_cmd cmd; uint32_t dp_alt_mode_disable; - bool is_usb_c_alt_mode = false; - if (enc->features.flags.bits.DP_IS_USB_C) { - if (enc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_B0) { - // [Note] no need to check hw_internal_rev once phy mux selection is ready - REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, &dp_alt_mode_disable); - } else { + /* Only applicable to USB-C PHY. */ + if (!enc->features.flags.bits.DP_IS_USB_C) + return false; + + /* + * Use the new interface from DMCUB if available. + * Avoids hanging the RDCPSPIPE if DMCUB wasn't already running. + */ + if (has_query_dp_alt(enc)) { + if (!query_dp_alt_from_dmub(enc, &cmd)) + return false; + + return (cmd.query_dp_alt.data.is_dp_alt_disable == 0); + } + + /* Legacy path, avoid if possible. */ + if (enc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_B0) { + REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, + &dp_alt_mode_disable); + } else { /* * B0 phys use a new set of registers to check whether alt mode is disabled. * if value == 1 alt mode is disabled, otherwise it is enabled. */ - if ((enc10->base.transmitter == TRANSMITTER_UNIPHY_A) - || (enc10->base.transmitter == TRANSMITTER_UNIPHY_B) - || (enc10->base.transmitter == TRANSMITTER_UNIPHY_E)) { - REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, &dp_alt_mode_disable); - } else { - // [Note] need to change TRANSMITTER_UNIPHY_C/D to F/G once phy mux selection is ready - REG_GET(RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, &dp_alt_mode_disable); - } + if ((enc10->base.transmitter == TRANSMITTER_UNIPHY_A) || + (enc10->base.transmitter == TRANSMITTER_UNIPHY_B) || + (enc10->base.transmitter == TRANSMITTER_UNIPHY_E)) { + REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, + &dp_alt_mode_disable); + } else { + REG_GET(RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, + &dp_alt_mode_disable); } - - is_usb_c_alt_mode = (dp_alt_mode_disable == 0); } - return is_usb_c_alt_mode; + return (dp_alt_mode_disable == 0); } -void dcn31_link_encoder_get_max_link_cap(struct link_encoder *enc, - struct dc_link_settings *link_settings) +void dcn31_link_encoder_get_max_link_cap(struct link_encoder *enc, struct dc_link_settings *link_settings) { struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc); + union dmub_rb_cmd cmd; uint32_t is_in_usb_c_dp4_mode = 0; dcn10_link_encoder_get_max_link_cap(enc, link_settings); - /* in usb c dp2 mode, max lane count is 2 */ - if (enc->funcs->is_in_alt_mode && enc->funcs->is_in_alt_mode(enc)) { - if (enc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_B0) { - // [Note] no need to check hw_internal_rev once phy mux selection is ready - REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, &is_in_usb_c_dp4_mode); + /* Take the link cap directly if not USB */ + if (!enc->features.flags.bits.DP_IS_USB_C) + return; + + /* + * Use the new interface from DMCUB if available. + * Avoids hanging the RDCPSPIPE if DMCUB wasn't already running. + */ + if (has_query_dp_alt(enc)) { + if (!query_dp_alt_from_dmub(enc, &cmd)) + return; + + if (cmd.query_dp_alt.data.is_usb && + cmd.query_dp_alt.data.is_dp4 == 0) + link_settings->lane_count = MIN(LANE_COUNT_TWO, link_settings->lane_count); + + return; + } + + /* Legacy path, avoid if possible. */ + if (enc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_B0) { + REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, + &is_in_usb_c_dp4_mode); + } else { + if ((enc10->base.transmitter == TRANSMITTER_UNIPHY_A) || + (enc10->base.transmitter == TRANSMITTER_UNIPHY_B) || + (enc10->base.transmitter == TRANSMITTER_UNIPHY_E)) { + REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, + &is_in_usb_c_dp4_mode); } else { - if ((enc10->base.transmitter == TRANSMITTER_UNIPHY_A) - || (enc10->base.transmitter == TRANSMITTER_UNIPHY_B) - || (enc10->base.transmitter == TRANSMITTER_UNIPHY_E)) { - REG_GET(RDPCSTX_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, &is_in_usb_c_dp4_mode); - } else { - REG_GET(RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, &is_in_usb_c_dp4_mode); - } + REG_GET(RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, + &is_in_usb_c_dp4_mode); } - if (!is_in_usb_c_dp4_mode) - link_settings->lane_count = MIN(LANE_COUNT_TWO, link_settings->lane_count); } + + if (!is_in_usb_c_dp4_mode) + link_settings->lane_count = MIN(LANE_COUNT_TWO, link_settings->lane_count); } |