Commit 7d1e9d03 authored by George Shen's avatar George Shen Committed by Alex Deucher
Browse files

drm/amd/display: Check DP Alt mode DPCS state via DMUB



[Why]
Currently, driver state for DCN3.2 is not strictly matching HW state for
the USBC port. To reduce inconsistencies while debugging, the driver
should match HW configuration.

[How]
Update link encoder flag to indicate USBC port. Call into DMUB to check
when DP Alt mode is entered, and also to check for 2-lane versuse 4-lane
mode.

Reviewed-by: default avatarCharlene Liu <charlene.liu@amd.com>
Acked-by: default avatarRodrigo Siqueira <rodrigo.siqueira@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarGeorge Shen <george.shen@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 5fe4a8d3
Loading
Loading
Loading
Loading
+66 −19
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@
#include "dc_bios_types.h"
#include "link_enc_cfg.h"

#include "dc_dmub_srv.h"
#include "gpio_service_interface.h"

#ifndef MIN
@@ -61,6 +62,38 @@
#define AUX_REG_WRITE(reg_name, val) \
			dm_write_reg(CTX, AUX_REG(reg_name), val)

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;
}

void enc32_hw_init(struct link_encoder *enc)
{
@@ -117,37 +150,49 @@ void dcn32_link_encoder_enable_dp_output(
	}
}

static bool dcn32_link_encoder_is_in_alt_mode(struct link_encoder *enc)
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);
	uint32_t dp_alt_mode_disable = 0;
	bool is_usb_c_alt_mode = false;

	if (enc->features.flags.bits.DP_IS_USB_C) {
		/* if value == 1 alt mode is disabled, otherwise it is enabled */
		REG_GET(RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DISABLE, &dp_alt_mode_disable);
		is_usb_c_alt_mode = (dp_alt_mode_disable == 0);
	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_wake_and_execute_dmub_cmd(enc->ctx, cmd, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
		return false;

	return true;
}

	return is_usb_c_alt_mode;
bool dcn32_link_encoder_is_in_alt_mode(struct link_encoder *enc)
{
	union dmub_rb_cmd cmd;

	if (!query_dp_alt_from_dmub(enc, &cmd))
		return false;

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

static void dcn32_link_encoder_get_max_link_cap(struct link_encoder *enc,
void dcn32_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);
	uint32_t is_in_usb_c_dp4_mode = 0;
	union dmub_rb_cmd cmd;

	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)) {
		REG_GET(RDPCSPIPE_PHY_CNTL6, RDPCS_PHY_DPALT_DP4, &is_in_usb_c_dp4_mode);
		if (!is_in_usb_c_dp4_mode)
	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);
}

}

static const struct link_encoder_funcs dcn32_link_enc_funcs = {
	.read_state = link_enc2_read_state,
@@ -203,13 +248,15 @@ void dcn32_link_encoder_construct(
	enc10->base.hpd_source = init_data->hpd_source;
	enc10->base.connector = init_data->connector;


	enc10->base.preferred_engine = ENGINE_ID_UNKNOWN;

	enc10->base.features = *enc_features;
	if (enc10->base.connector.id == CONNECTOR_ID_USBC)
		enc10->base.features.flags.bits.DP_IS_USB_C = 1;

	if (enc10->base.connector.id == CONNECTOR_ID_USBC)
		enc10->base.features.flags.bits.DP_IS_USB_C = 1;

	enc10->base.transmitter = init_data->transmitter;

	/* set the flag to indicate whether driver poll the I2C data pin
+5 −0
Original line number Diff line number Diff line
@@ -53,4 +53,9 @@ void dcn32_link_encoder_enable_dp_output(
	const struct dc_link_settings *link_settings,
	enum clock_source_id clock_source);

bool dcn32_link_encoder_is_in_alt_mode(struct link_encoder *enc);

void dcn32_link_encoder_get_max_link_cap(struct link_encoder *enc,
	struct dc_link_settings *link_settings);

#endif /* __DC_LINK_ENCODER__DCN32_H__ */