drm/radeon/kms: refine TMDS dual link checks
authorAlex Deucher <alexander.deucher@amd.com>
Fri, 20 Jan 2012 20:03:30 +0000 (15:03 -0500)
committerDave Airlie <airlied@redhat.com>
Tue, 24 Jan 2012 17:35:52 +0000 (17:35 +0000)
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: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h

index 807b89b4933f135909c0babdc610154cd8e4cf58..891935271d34c8cce78405c5bf1ee1530329535f 100644 (file)
@@ -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;
                                }
index f2f14a20a4932f2c91bb3dad3f106dc066dc2cc8..b88c4608731becef4b196d706960c84e3a58917c 100644 (file)
@@ -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;
index 4b27efa4405b94b63011b2e8948d678c35ccfd62..9419c51bcf50f0f98f86cfd8122730ceea70a4d6 100644 (file)
@@ -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;
+       }
+}
+
index d34dcb6ac3841e0b78bd53205284094c3cf7b111..4330e3253573ffeb92a5dab9f39223e074fc65ca 100644 (file)
@@ -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);