Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9aa59993 authored by Alex Deucher's avatar Alex Deucher Committed by Dave Airlie
Browse files

drm/radeon/kms: refine TMDS dual link checks

HDMI 1.3 defines single link clocks up to 340 Mhz.
Refine the current dual link checks to only enable
dual link for DVI > 165 Mhz or HDMI > 340 Mhz if the
hw supports HDMI 1.3 (DCE3+).

Fixes:
https://bugs.freedesktop.org/show_bug.cgi?id=44755



Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 27d9cc84
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -518,6 +518,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
	int encoder_mode = 0;
	u32 dp_clock = mode->clock;
	int bpc = 8;
	bool is_duallink = false;

	/* reset the pll flags */
	pll->flags = 0;
@@ -552,6 +553,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
			if (connector && connector->display_info.bpc)
				bpc = connector->display_info.bpc;
			encoder_mode = atombios_get_encoder_mode(encoder);
			is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
			if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) ||
			    (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) {
				if (connector) {
@@ -647,7 +649,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
					if (dig->coherent_mode)
						args.v3.sInput.ucDispPllConfig |=
							DISPPLL_CONFIG_COHERENT_MODE;
					if (mode->clock > 165000)
					if (is_duallink)
						args.v3.sInput.ucDispPllConfig |=
							DISPPLL_CONFIG_DUAL_LINK;
				}
+21 −36
Original line number Diff line number Diff line
@@ -57,22 +57,6 @@ static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder)
	}
}

static struct drm_connector *
radeon_get_connector_for_encoder_init(struct drm_encoder *encoder)
{
	struct drm_device *dev = encoder->dev;
	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
	struct drm_connector *connector;
	struct radeon_connector *radeon_connector;

	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		radeon_connector = to_radeon_connector(connector);
		if (radeon_encoder->devices & radeon_connector->devices)
			return connector;
	}
	return NULL;
}

static bool radeon_atom_mode_fixup(struct drm_encoder *encoder,
				   struct drm_display_mode *mode,
				   struct drm_display_mode *adjusted_mode)
@@ -253,7 +237,7 @@ atombios_dvo_setup(struct drm_encoder *encoder, int action)
			/* R4xx, R5xx */
			args.ext_tmds.sXTmdsEncoder.ucEnable = action;

			if (radeon_encoder->pixel_clock > 165000)
			if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
				args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL;

			args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB;
@@ -265,7 +249,7 @@ atombios_dvo_setup(struct drm_encoder *encoder, int action)
			/* DFP1, CRT1, TV1 depending on the type of port */
			args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX;

			if (radeon_encoder->pixel_clock > 165000)
			if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
				args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL;
			break;
		case 3:
@@ -349,7 +333,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
			} else {
				if (dig->linkb)
					args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
				if (radeon_encoder->pixel_clock > 165000)
				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
					args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL;
				/*if (pScrn->rgbBits == 8) */
				args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB;
@@ -388,7 +372,7 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
			} else {
				if (dig->linkb)
					args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB;
				if (radeon_encoder->pixel_clock > 165000)
				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
					args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL;
			}
			break;
@@ -587,7 +571,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo

			if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode))
				args.v1.ucLaneNum = dp_lane_count;
			else if (radeon_encoder->pixel_clock > 165000)
			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
				args.v1.ucLaneNum = 8;
			else
				args.v1.ucLaneNum = 4;
@@ -622,7 +606,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo

			if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode))
				args.v3.ucLaneNum = dp_lane_count;
			else if (radeon_encoder->pixel_clock > 165000)
			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
				args.v3.ucLaneNum = 8;
			else
				args.v3.ucLaneNum = 4;
@@ -662,7 +646,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mo

			if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode))
				args.v4.ucLaneNum = dp_lane_count;
			else if (radeon_encoder->pixel_clock > 165000)
			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
				args.v4.ucLaneNum = 8;
			else
				args.v4.ucLaneNum = 4;
@@ -806,7 +790,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
				if (is_dp)
					args.v1.usPixelClock =
						cpu_to_le16(dp_clock / 10);
				else if (radeon_encoder->pixel_clock > 165000)
				else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
					args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
				else
					args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
@@ -821,7 +805,8 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t

			if ((rdev->flags & RADEON_IS_IGP) &&
			    (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) {
				if (is_dp || (radeon_encoder->pixel_clock <= 165000)) {
				if (is_dp ||
				    !radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock)) {
					if (igp_lane_info & 0x1)
						args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
					else if (igp_lane_info & 0x2)
@@ -848,7 +833,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
			else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
				if (dig->coherent_mode)
					args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
				if (radeon_encoder->pixel_clock > 165000)
				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
					args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK;
			}
			break;
@@ -863,7 +848,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
				if (is_dp)
					args.v2.usPixelClock =
						cpu_to_le16(dp_clock / 10);
				else if (radeon_encoder->pixel_clock > 165000)
				else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
					args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
				else
					args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
@@ -891,7 +876,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
			} else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
				if (dig->coherent_mode)
					args.v2.acConfig.fCoherentMode = 1;
				if (radeon_encoder->pixel_clock > 165000)
				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
					args.v2.acConfig.fDualLinkConnector = 1;
			}
			break;
@@ -906,7 +891,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
				if (is_dp)
					args.v3.usPixelClock =
						cpu_to_le16(dp_clock / 10);
				else if (radeon_encoder->pixel_clock > 165000)
				else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
					args.v3.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
				else
					args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
@@ -914,7 +899,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t

			if (is_dp)
				args.v3.ucLaneNum = dp_lane_count;
			else if (radeon_encoder->pixel_clock > 165000)
			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
				args.v3.ucLaneNum = 8;
			else
				args.v3.ucLaneNum = 4;
@@ -951,7 +936,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
			else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
				if (dig->coherent_mode)
					args.v3.acConfig.fCoherentMode = 1;
				if (radeon_encoder->pixel_clock > 165000)
				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
					args.v3.acConfig.fDualLinkConnector = 1;
			}
			break;
@@ -966,7 +951,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
				if (is_dp)
					args.v4.usPixelClock =
						cpu_to_le16(dp_clock / 10);
				else if (radeon_encoder->pixel_clock > 165000)
				else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
					args.v4.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
				else
					args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
@@ -974,7 +959,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t

			if (is_dp)
				args.v4.ucLaneNum = dp_lane_count;
			else if (radeon_encoder->pixel_clock > 165000)
			else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
				args.v4.ucLaneNum = 8;
			else
				args.v4.ucLaneNum = 4;
@@ -1014,7 +999,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
			else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
				if (dig->coherent_mode)
					args.v4.acConfig.fCoherentMode = 1;
				if (radeon_encoder->pixel_clock > 165000)
				if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
					args.v4.acConfig.fDualLinkConnector = 1;
			}
			break;
@@ -1137,7 +1122,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
				if (dp_clock == 270000)
					args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
				args.v1.sDigEncoder.ucLaneNum = dp_lane_count;
			} else if (radeon_encoder->pixel_clock > 165000)
			} else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
				args.v1.sDigEncoder.ucLaneNum = 8;
			else
				args.v1.sDigEncoder.ucLaneNum = 4;
@@ -1156,7 +1141,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
				else if (dp_clock == 540000)
					args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ;
				args.v3.sExtEncoder.ucLaneNum = dp_lane_count;
			} else if (radeon_encoder->pixel_clock > 165000)
			} else if (radeon_dig_monitor_is_duallink(encoder, radeon_encoder->pixel_clock))
				args.v3.sExtEncoder.ucLaneNum = 8;
			else
				args.v3.sExtEncoder.ucLaneNum = 4;
+77 −0
Original line number Diff line number Diff line
@@ -202,6 +202,22 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder)
	return NULL;
}

struct drm_connector *
radeon_get_connector_for_encoder_init(struct drm_encoder *encoder)
{
	struct drm_device *dev = encoder->dev;
	struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
	struct drm_connector *connector;
	struct radeon_connector *radeon_connector;

	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
		radeon_connector = to_radeon_connector(connector);
		if (radeon_encoder->devices & radeon_connector->devices)
			return connector;
	}
	return NULL;
}

struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder)
{
	struct drm_device *dev = encoder->dev;
@@ -288,3 +304,64 @@ void radeon_panel_mode_fixup(struct drm_encoder *encoder,

}

bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
				    u32 pixel_clock)
{
	struct drm_device *dev = encoder->dev;
	struct radeon_device *rdev = dev->dev_private;
	struct drm_connector *connector;
	struct radeon_connector *radeon_connector;
	struct radeon_connector_atom_dig *dig_connector;

	connector = radeon_get_connector_for_encoder(encoder);
	/* if we don't have an active device yet, just use one of
	 * the connectors tied to the encoder.
	 */
	if (!connector)
		connector = radeon_get_connector_for_encoder_init(encoder);
	radeon_connector = to_radeon_connector(connector);

	switch (connector->connector_type) {
	case DRM_MODE_CONNECTOR_DVII:
	case DRM_MODE_CONNECTOR_HDMIB:
		if (radeon_connector->use_digital) {
			/* HDMI 1.3 supports up to 340 Mhz over single link */
			if (ASIC_IS_DCE3(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) {
				if (pixel_clock > 340000)
					return true;
				else
					return false;
			} else {
				if (pixel_clock > 165000)
					return true;
				else
					return false;
			}
		} else
			return false;
	case DRM_MODE_CONNECTOR_DVID:
	case DRM_MODE_CONNECTOR_HDMIA:
	case DRM_MODE_CONNECTOR_DisplayPort:
		dig_connector = radeon_connector->con_priv;
		if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
		    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
			return false;
		else {
			/* HDMI 1.3 supports up to 340 Mhz over single link */
			if (ASIC_IS_DCE3(rdev) && drm_detect_hdmi_monitor(radeon_connector->edid)) {
				if (pixel_clock > 340000)
					return true;
				else
					return false;
			} else {
				if (pixel_clock > 165000)
					return true;
				else
					return false;
			}
		}
	default:
		return false;
	}
}
+4 −0
Original line number Diff line number Diff line
@@ -467,6 +467,10 @@ radeon_atombios_get_tv_info(struct radeon_device *rdev);

extern struct drm_connector *
radeon_get_connector_for_encoder(struct drm_encoder *encoder);
extern struct drm_connector *
radeon_get_connector_for_encoder_init(struct drm_encoder *encoder);
extern bool radeon_dig_monitor_is_duallink(struct drm_encoder *encoder,
				    u32 pixel_clock);

extern u16 radeon_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder);
extern u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector);