drm/radeon/kms: handle dp sinks in atom encoder/transmitter tables
authorAlex Deucher <alexdeucher@gmail.com>
Mon, 23 Nov 2009 23:40:40 +0000 (18:40 -0500)
committerDave Airlie <airlied@redhat.com>
Tue, 8 Dec 2009 00:22:43 +0000 (10:22 +1000)
Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h

index e761fef..76eb5c8 100644 (file)
 
 #define DP_LINK_STATUS_SIZE    6
 
+/* move these to drm_dp_helper.c/h */
+
+static const int dp_clocks[] = {
+       54000,  // 1 lane, 1.62 Ghz
+       90000,  // 1 lane, 2.70 Ghz
+       108000, // 2 lane, 1.62 Ghz
+       180000, // 2 lane, 2.70 Ghz
+       216000, // 4 lane, 1.62 Ghz
+       360000, // 4 lane, 2.70 Ghz
+};
+
+static const int num_dp_clocks = sizeof(dp_clocks) / sizeof(int);
+
+int dp_lanes_for_mode_clock(int max_link_bw, int mode_clock)
+{
+       int i;
+
+       switch (max_link_bw) {
+       case DP_LINK_BW_1_62:
+       default:
+               for (i = 0; i < num_dp_clocks; i++) {
+                       if (i % 2)
+                               continue;
+                       if (dp_clocks[i] > mode_clock) {
+                               if (i < 2)
+                                       return 1;
+                               else if (i < 4)
+                                       return 2;
+                               else
+                                       return 4;
+                       }
+               }
+               break;
+       case DP_LINK_BW_2_7:
+               for (i = 0; i < num_dp_clocks; i++) {
+                       if (dp_clocks[i] > mode_clock) {
+                               if (i < 2)
+                                       return 1;
+                               else if (i < 4)
+                                       return 2;
+                               else
+                                       return 4;
+                       }
+               }
+               break;
+       }
+
+       return 0;
+}
+
+int dp_link_clock_for_mode_clock(int max_link_bw, int mode_clock)
+{
+       int i;
+
+       switch (max_link_bw) {
+       case DP_LINK_BW_1_62:
+       default:
+               return 162000;
+               break;
+       case DP_LINK_BW_2_7:
+               for (i = 0; i < num_dp_clocks; i++) {
+                       if (dp_clocks[i] > mode_clock)
+                               return (i % 2) ? 270000 : 162000;
+               }
+       }
+
+       return 0;
+}
+
 bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
                           int num_bytes, u8 *read_byte,
                           u8 read_buf_len, u8 delay)
index b4e7aba..8f3d67b 100644 (file)
@@ -554,6 +554,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
 {
        struct drm_connector *connector;
        struct radeon_connector *radeon_connector;
+       struct radeon_connector_atom_dig *radeon_dig_connector;
 
        connector = radeon_get_connector_for_encoder(encoder);
        if (!connector)
@@ -583,10 +584,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                return ATOM_ENCODER_MODE_LVDS;
                break;
        case DRM_MODE_CONNECTOR_DisplayPort:
-               /*if (radeon_output->MonType == MT_DP)
-                 return ATOM_ENCODER_MODE_DP;
-                 else*/
-               if (drm_detect_hdmi_monitor(radeon_connector->edid))
+               radeon_dig_connector = radeon_connector->con_priv;
+               if (radeon_dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
+                       return ATOM_ENCODER_MODE_DP;
+               else if (drm_detect_hdmi_monitor(radeon_connector->edid))
                        return ATOM_ENCODER_MODE_HDMI;
                else
                        return ATOM_ENCODER_MODE_DVI;
@@ -715,7 +716,15 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
                }
        }
 
-       if (radeon_encoder->pixel_clock > 165000)
+       args.ucEncoderMode = atombios_get_encoder_mode(encoder);
+
+       if (args.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
+               if (dp_link_clock_for_mode_clock(dig_connector->dpcd[1],
+                                                radeon_encoder->pixel_clock) == 270000)
+                       args.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+               args.ucLaneNum = dp_lanes_for_mode_clock(dig_connector->dpcd[1],
+                                                        radeon_encoder->pixel_clock);
+       } else if (radeon_encoder->pixel_clock > 165000)
                args.ucLaneNum = 8;
        else
                args.ucLaneNum = 4;
@@ -725,8 +734,6 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
        else
                args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
 
-       args.ucEncoderMode = atombios_get_encoder_mode(encoder);
-
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 
 }
@@ -749,6 +756,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
        struct drm_connector *connector;
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *dig_connector;
+       bool is_dp = false;
 
        connector = radeon_get_connector_for_encoder(encoder);
        if (!connector)
@@ -766,6 +774,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
 
        dig_connector = radeon_connector->con_priv;
 
+       if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP)
+               is_dp = true;
+
        memset(&args, 0, sizeof(args));
 
        if (ASIC_IS_DCE32(rdev))
@@ -790,14 +801,16 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                args.v1.asMode.ucLaneSel = lane_num;
                args.v1.asMode.ucLaneSet = lane_set;
        } else {
-               if (radeon_encoder->pixel_clock > 165000)
+               if (is_dp)
+                       args.v1.usPixelClock =
+                               cpu_to_le16(dp_link_clock_for_mode_clock(dig_connector->dpcd[1],
+                                                                        radeon_encoder->pixel_clock) / 10);
+               else if (radeon_encoder->pixel_clock > 165000)
                        args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
                else
                        args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
        }
        if (ASIC_IS_DCE32(rdev)) {
-               if (radeon_encoder->pixel_clock > 165000)
-                       args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
                if (dig->dig_block)
                        args.v2.acConfig.ucEncoderSel = 1;
                if (dig_connector->linkb)
@@ -818,7 +831,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                        break;
                }
 
-               if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+               if (is_dp)
+                       args.v2.acConfig.fCoherentMode = 1;
+               else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
                        if (dig->coherent_mode)
                                args.v2.acConfig.fCoherentMode = 1;
                }
@@ -866,7 +881,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                else
                        args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
 
-               if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
+               if (is_dp)
+                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
+               else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
                        if (dig->coherent_mode)
                                args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
                }
index 338d0af..b516401 100644 (file)
@@ -366,6 +366,8 @@ struct radeon_framebuffer {
        struct drm_gem_object *obj;
 };
 
+extern int dp_lanes_for_mode_clock(int max_link_bw, int mode_clock);
+extern int dp_link_clock_for_mode_clock(int max_link_bw, int mode_clock);
 extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
 extern void radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
 extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,