drm/radeon/kms: DP fixes and cleanup from the ddx
authorAlex Deucher <alexdeucher@gmail.com>
Sat, 21 Nov 2009 00:40:13 +0000 (19:40 -0500)
committerDave Airlie <airlied@redhat.com>
Tue, 8 Dec 2009 00:22:40 +0000 (10:22 +1000)
- dpcp -> dpcd
- fix up dig encoder routing
- aux transaction table takes delay in 10 usec units

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_connectors.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h
include/drm/drm_dp_helper.h

index a4bc801..d1c144b 100644 (file)
@@ -34,7 +34,7 @@
 #define DP_LINK_STATUS_SIZE    6
 
 bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
-                          int num_bytes, u8 *read_byte, 
+                          int num_bytes, u8 *read_byte,
                           u8 read_buf_len, u8 delay)
 {
        struct drm_device *dev = chan->dev;
@@ -42,9 +42,9 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
        PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION args;
        int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction);
        unsigned char *base;
-       
+
        memset(&args, 0, sizeof(args));
-       
+
        base = (unsigned char *)rdev->mode_info.atom_context->scratch;
 
        memcpy(base, req_bytes, num_bytes);
@@ -53,7 +53,7 @@ bool radeon_process_aux_ch(struct radeon_i2c_chan *chan, u8 *req_bytes,
        args.lpDataOut = 16;
        args.ucDataOutLen = 0;
        args.ucChannelID = chan->i2c_id;
-       args.ucDelay = delay;
+       args.ucDelay = delay / 10;
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 
@@ -158,24 +158,24 @@ bool radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, uint16
        return ret;
 }
 
-void radeon_dp_getdpcp(struct radeon_connector *radeon_connector)
+void radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
 {
        struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
        u8 msg[25];
        int ret;
 
-       ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCP_REV, 0, 8, msg);
+       ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, 0, 8, msg);
        if (ret) {
-               memcpy(radeon_dig_connector->dpcp, msg, 8);
-               { 
+               memcpy(radeon_dig_connector->dpcd, msg, 8);
+               {
                        int i;
-                       printk("DPCP: ");
+                       printk("DPCD: ");
                        for (i = 0; i < 8; i++)
                                printk("%02x ", msg[i]);
                        printk("\n");
                }
        }
-       radeon_dig_connector->dpcp[0] = 0;
+       radeon_dig_connector->dpcd[0] = 0;
        return;
 }
 
@@ -199,8 +199,8 @@ static bool atom_dp_get_link_status(struct radeon_connector *radeon_connector,
 static void dp_set_power(struct radeon_connector *radeon_connector, u8 power_state)
 {
        struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;
-       if (radeon_dig_connector->dpcp[0] >= 0x11) {
-               radeon_dp_aux_native_write(radeon_connector, 0x600, 1,
+       if (radeon_dig_connector->dpcd[0] >= 0x11) {
+               radeon_dp_aux_native_write(radeon_connector, DP_SET_POWER, 1,
                                           &power_state);
        }
 }
index 7334275..4d457bc 100644 (file)
@@ -923,7 +923,7 @@ static enum drm_connector_status radeon_dp_detect(struct drm_connector *connecto
 
        sink_type = radeon_dp_getsinktype(radeon_connector);
        if (sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) {
-               radeon_dp_getdpcp(radeon_connector);
+               radeon_dp_getdpcd(radeon_connector);
                ret = connector_status_connected;
        }
        return ret;
index 37f5ea1..b4e7aba 100644 (file)
@@ -605,6 +605,30 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        }
 }
 
+/*
+ * DIG Encoder/Transmitter Setup
+ *
+ * DCE 3.0/3.1
+ * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA.
+ * Supports up to 3 digital outputs
+ * - 2 DIG encoder blocks.
+ * DIG1 can drive UNIPHY link A or link B
+ * DIG2 can drive UNIPHY link B or LVTMA
+ *
+ * DCE 3.2
+ * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B).
+ * Supports up to 5 digital outputs
+ * - 2 DIG encoder blocks.
+ * DIG1/2 can drive UNIPHY0/1/2 link A or link B
+ *
+ * Routing
+ * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links)
+ * Examples:
+ * crtc0 -> dig2 -> LVTMA   links A+B -> TMDS/HDMI
+ * crtc1 -> dig1 -> UNIPHY0 link  B   -> DP
+ * crtc0 -> dig1 -> UNIPHY2 link  A   -> LVDS
+ * crtc1 -> dig2 -> UNIPHY1 link  B+A -> TMDS/HDMI
+ */
 static void
 atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
 {
@@ -646,10 +670,17 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
        } else {
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
-                       index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
+                       /* XXX doesn't really matter which dig encoder we pick as long as it's
+                        * not already in use
+                        */
+                       if (dig_connector->linkb)
+                               index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
+                       else
+                               index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl);
                        num = 1;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                       /* Only dig2 encoder can drive LVTMA */
                        index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl);
                        num = 2;
                        break;
@@ -684,16 +715,15 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
                }
        }
 
-       if (radeon_encoder->pixel_clock > 165000) {
-               args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA_B;
+       if (radeon_encoder->pixel_clock > 165000)
                args.ucLaneNum = 8;
-       } else {
-               if (dig_connector->linkb)
-                       args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
-               else
-                       args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
+       else
                args.ucLaneNum = 4;
-       }
+
+       if (dig_connector->linkb)
+               args.ucConfig |= ATOM_ENCODER_CONFIG_LINKB;
+       else
+               args.ucConfig |= ATOM_ENCODER_CONFIG_LINKA;
 
        args.ucEncoderMode = atombios_get_encoder_mode(encoder);
 
@@ -707,7 +737,7 @@ union dig_transmitter_control {
 };
 
 static void
-atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
+atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -756,6 +786,9 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
        args.v1.ucAction = action;
        if (action == ATOM_TRANSMITTER_ACTION_INIT) {
                args.v1.usInitInfo = radeon_connector->connector_object_id;
+       } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
+               args.v1.asMode.ucLaneSel = lane_num;
+               args.v1.asMode.ucLaneSet = lane_set;
        } else {
                if (radeon_encoder->pixel_clock > 165000)
                        args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10);
@@ -767,6 +800,8 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
                        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)
+                       args.v2.acConfig.ucLinkSel = 1;
 
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
@@ -792,17 +827,20 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
 
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
-                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
+                       /* XXX doesn't really matter which dig encoder we pick as long as it's
+                        * not already in use
+                        */
+                       if (dig_connector->linkb)
+                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
+                       else
+                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
                        if (rdev->flags & RADEON_IS_IGP) {
                                if (radeon_encoder->pixel_clock > 165000) {
-                                       args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
-                                                            ATOM_TRANSMITTER_CONFIG_LINKA_B);
                                        if (dig_connector->igp_lane_info & 0x3)
                                                args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7;
                                        else if (dig_connector->igp_lane_info & 0xc)
                                                args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15;
                                } else {
-                                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
                                        if (dig_connector->igp_lane_info & 0x1)
                                                args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3;
                                        else if (dig_connector->igp_lane_info & 0x2)
@@ -812,34 +850,22 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
                                        else if (dig_connector->igp_lane_info & 0x8)
                                                args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15;
                                }
-                       } else {
-                               if (radeon_encoder->pixel_clock > 165000)
-                                       args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
-                                                            ATOM_TRANSMITTER_CONFIG_LINKA_B |
-                                                            ATOM_TRANSMITTER_CONFIG_LANE_0_7);
-                               else {
-                                       if (dig_connector->linkb)
-                                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
-                                       else
-                                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
-                               }
                        }
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                       /* Only dig2 encoder can drive LVTMA */
                        args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER;
-                       if (radeon_encoder->pixel_clock > 165000)
-                               args.v1.ucConfig |= (ATOM_TRANSMITTER_CONFIG_8LANE_LINK |
-                                                    ATOM_TRANSMITTER_CONFIG_LINKA_B |
-                                                    ATOM_TRANSMITTER_CONFIG_LANE_0_7);
-                       else {
-                               if (dig_connector->linkb)
-                                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
-                               else
-                                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
-                       }
                        break;
                }
 
+               if (radeon_encoder->pixel_clock > 165000)
+                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK;
+
+               if (dig_connector->linkb)
+                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB;
+               else
+                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA;
+
                if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
                        if (dig->coherent_mode)
                                args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT;
@@ -851,99 +877,6 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action)
 }
 
 static void
-atombios_dig_transmitter_setup_vsemph(struct drm_encoder *encoder, u8 lane_num,
-                                     u8 lane_set)
-{
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
-       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       union dig_transmitter_control args;
-       int index = 0, num = 0;
-       uint8_t frev, crev;
-       struct radeon_encoder_atom_dig *dig;
-       struct drm_connector *connector;
-       struct radeon_connector *radeon_connector;
-       struct radeon_connector_atom_dig *dig_connector;
-
-       connector = radeon_get_connector_for_encoder(encoder);
-       if (!connector)
-               return;
-
-       radeon_connector = to_radeon_connector(connector);
-
-       if (!radeon_encoder->enc_priv)
-               return;
-
-       dig = radeon_encoder->enc_priv;
-
-       if (!radeon_connector->con_priv)
-               return;
-
-       dig_connector = radeon_connector->con_priv;
-
-       memset(&args, 0, sizeof(args));
-
-       if (ASIC_IS_DCE32(rdev))
-               index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl);
-       else {
-               switch (radeon_encoder->encoder_id) {
-               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
-                       index = GetIndexIntoMasterTable(COMMAND, DIG1TransmitterControl);
-                       break;
-               case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
-                       index = GetIndexIntoMasterTable(COMMAND, DIG2TransmitterControl);
-                       break;
-               }
-       }
-
-       atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev);
-
-       args.v1.ucAction = ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH;
-       args.v1.asMode.ucLaneSel = lane_num;
-       args.v1.asMode.ucLaneSet = lane_set;
-
-       if (ASIC_IS_DCE32(rdev)) {
-               args.v2.acConfig.fDPConnector = 1;
-
-               if (dig->dig_block)
-                       args.v2.acConfig.ucEncoderSel = 1;
-
-               switch (radeon_encoder->encoder_id) {
-               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
-                       args.v2.acConfig.ucTransmitterSel = 0;
-                       num = 0;
-                       break;
-               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
-                       args.v2.acConfig.ucTransmitterSel = 1;
-                       num = 1;
-                       break;
-               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
-                       args.v2.acConfig.ucTransmitterSel = 2;
-                       num = 2;
-                       break;
-               }
-       } else {
-               args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL;
-
-               switch (radeon_encoder->encoder_id) {
-               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
-                       args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER;
-                       if (dig_connector->linkb)
-                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
-                       else
-                               args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA | ATOM_TRANSMITTER_CONFIG_LANE_0_3;
-               }
-       }
-
-       atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
-
-       if (ASIC_IS_DCE32(rdev))
-               DRM_INFO("Output UNIPHY%d transmitter VSEMPH setup success\n", num);
-       else
-               DRM_INFO("Output DIG%d transmitter VSEMPH setup success\n", num);
-}
-
-static void
 atombios_yuv_setup(struct drm_encoder *encoder, bool enable)
 {
        struct drm_device *dev = encoder->dev;
@@ -1150,13 +1083,33 @@ atombios_set_encoder_crtc_source(struct drm_encoder *encoder)
                                                args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
                                        else
                                                args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
-                               } else
-                                       args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+                               } else {
+                                       struct drm_connector *connector;
+                                       struct radeon_connector *radeon_connector;
+                                       struct radeon_connector_atom_dig *dig_connector;
+
+                                       connector = radeon_get_connector_for_encoder(encoder);
+                                       if (!connector)
+                                               return;
+                                       radeon_connector = to_radeon_connector(connector);
+                                       if (!radeon_connector->con_priv)
+                                               return;
+                                       dig_connector = radeon_connector->con_priv;
+
+                                       /* XXX doesn't really matter which dig encoder we pick as long as it's
+                                        * not already in use
+                                        */
+                                       if (dig_connector->linkb)
+                                               args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
+                                       else
+                                               args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID;
+                               }
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
                                args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID;
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
+                               /* Only dig2 encoder can drive LVTMA */
                                args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID;
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
@@ -1259,14 +1212,14 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
                /* disable the encoder and transmitter */
-               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE);
+               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
                atombios_dig_encoder_setup(encoder, ATOM_DISABLE);
 
                /* setup and enable the encoder and transmitter */
                atombios_dig_encoder_setup(encoder, ATOM_ENABLE);
-               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT);
-               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP);
-               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE);
+               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0);
+               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
+               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DDI:
                atombios_ddia_setup(encoder, ATOM_ENABLE);
index ce1cdc7..166f753 100644 (file)
@@ -335,7 +335,7 @@ struct radeon_connector_atom_dig {
        bool linkb;
        uint16_t uc_i2c_id;
        struct radeon_i2c_chan *dp_i2c_bus;
-       u8 dpcp[8];
+       u8 dpcd[8];
 };
 
 struct radeon_connector {
@@ -362,7 +362,7 @@ struct radeon_framebuffer {
 };
 
 extern int radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
-extern void radeon_dp_getdpcp(struct radeon_connector *connector);
+extern void radeon_dp_getdpcd(struct radeon_connector *connector);
 extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                                uint8_t write_byte, uint8_t *read_byte);
 
index 376155f..f09b0b2 100644 (file)
@@ -43,7 +43,7 @@
 #define AUX_I2C_REPLY_MASK     (0x3 << 6)
 
 /* AUX CH addresses */
-#define DP_DPCP_REV 0x0
+#define DP_DPCD_REV 0x0
 
 #define        DP_LINK_BW_SET          0x100
 # define DP_LINK_BW_1_62                   0x06
 #define DP_ADJUST_PRE_EMPHASIS_LANE1_MASK   0xc0
 #define DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT  6
 
+#define DP_SET_POWER                        0x600
+
 #define MODE_I2C_START 1
 #define MODE_I2C_WRITE 2
 #define MODE_I2C_READ  4