Skip to content

Commit

Permalink
drm/amd/display: Add version check before using DP alt query interface
Browse files Browse the repository at this point in the history
[Why]
To maintain compatibility with firmware older than 4.0.11.

Those firmware may have interrmittent hangs with RDCSPIPE or the PHY,
but we shouldn't regress their previous behavior.

[How]
Use the new path if firmware is development or 4.0.11 or newer. Use the
legacy path otherwise.

Fixes: 41f91315b5be5a ("drm/amd/display: Query DMCUB for dp alt status")

Tested-by: Daniel Wheeler <[email protected]>
Reviewed-by: Hansen Dsouza <[email protected]>
Acked-by: Rodrigo Siqueira <[email protected]>
Signed-off-by: Nicholas Kazlauskas <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
  • Loading branch information
Nicholas Kazlauskas authored and dumbbell committed Apr 14, 2023
1 parent 6348650 commit 8569235
Showing 1 changed file with 94 additions and 20 deletions.
114 changes: 94 additions & 20 deletions drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,35 @@ static uint8_t phy_id_from_transmitter(enum transmitter t)
return phy_id;
}

static bool has_query_dp_alt(struct link_encoder *enc)
{
struct dc_dmub_srv *dc_dmub_srv = enc->ctx->dmub_srv;

/* 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,
Expand Down Expand Up @@ -569,45 +598,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);
struct dc_dmub_srv *dc_dmub_srv = enc->ctx->dmub_srv;
union dmub_rb_cmd cmd;
bool is_usb_c_alt_mode = false;
uint32_t dp_alt_mode_disable;

if (enc->features.flags.bits.DP_IS_USB_C && dc_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.panel_cntl.data);
cmd.query_dp_alt.data.phy_id = phy_id_from_transmitter(enc10->base.transmitter);
/* Only applicable to USB-C PHY. */
if (!enc->features.flags.bits.DP_IS_USB_C)
return false;

if (!dc_dmub_srv_cmd_with_reply_data(dc_dmub_srv, &cmd))
/*
* 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;

is_usb_c_alt_mode = (cmd.query_dp_alt.data.is_dp_alt_disable == 0);
return (cmd.query_dp_alt.data.is_dp_alt_disable == 0);
}

return is_usb_c_alt_mode;
/* 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 {
REG_GET(RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE,
&dp_alt_mode_disable);
}
}

return (dp_alt_mode_disable == 0);
}

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);
struct dc_dmub_srv *dc_dmub_srv = enc->ctx->dmub_srv;
union dmub_rb_cmd cmd;
uint32_t is_in_usb_c_dp4_mode = 0;

dcn10_link_encoder_get_max_link_cap(enc, link_settings);

if (enc->features.flags.bits.DP_IS_USB_C && dc_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.panel_cntl.data);
cmd.query_dp_alt.data.phy_id = phy_id_from_transmitter(enc10->base.transmitter);
/* Take the link cap directly if not USB */
if (!enc->features.flags.bits.DP_IS_USB_C)
return;

if (!dc_dmub_srv_cmd_with_reply_data(dc_dmub_srv, &cmd))
/*
* 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)
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 {
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);
}

0 comments on commit 8569235

Please sign in to comment.