]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/gpu/drm/radeon/radeon_encoders.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / gpu / drm / radeon / radeon_encoders.c
index 041943df966be15803ebedc2e5291fa00953745e..b4274883227fee64e283f39934050cefa6d36cde 100644 (file)
@@ -641,7 +641,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        switch (connector->connector_type) {
        case DRM_MODE_CONNECTOR_DVII:
        case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
-               if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
+               if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
                        /* fix me */
                        if (ASIC_IS_DCE4(rdev))
                                return ATOM_ENCODER_MODE_DVI;
@@ -655,7 +655,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        case DRM_MODE_CONNECTOR_DVID:
        case DRM_MODE_CONNECTOR_HDMIA:
        default:
-               if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
+               if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
                        /* fix me */
                        if (ASIC_IS_DCE4(rdev))
                                return ATOM_ENCODER_MODE_DVI;
@@ -673,7 +673,7 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
                        return ATOM_ENCODER_MODE_DP;
-               else if (drm_detect_hdmi_monitor(radeon_connector->edid)) {
+               else if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
                        /* fix me */
                        if (ASIC_IS_DCE4(rdev))
                                return ATOM_ENCODER_MODE_DVI;
@@ -712,8 +712,8 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
  * - 2 DIG encoder blocks.
  * DIG1/2 can drive UNIPHY0/1/2 link A or link B
  *
- * DCE 4.0
- * - 3 DIG transmitter blocks UNPHY0/1/2 (links A and B).
+ * DCE 4.0/5.0
+ * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B).
  * Supports up to 6 digital outputs
  * - 6 DIG encoder blocks.
  * - DIG to PHY mapping is hardcoded
@@ -724,6 +724,12 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
  * DIG5 drives UNIPHY2 link A, A+B
  * DIG6 drives UNIPHY2 link B
  *
+ * DCE 4.1
+ * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B).
+ * Supports up to 6 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:
@@ -737,6 +743,7 @@ union dig_encoder_control {
        DIG_ENCODER_CONTROL_PS_ALLOCATION v1;
        DIG_ENCODER_CONTROL_PARAMETERS_V2 v2;
        DIG_ENCODER_CONTROL_PARAMETERS_V3 v3;
+       DIG_ENCODER_CONTROL_PARAMETERS_V4 v4;
 };
 
 void
@@ -752,6 +759,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
        uint8_t frev, crev;
        int dp_clock = 0;
        int dp_lane_count = 0;
+       int hpd_id = RADEON_HPD_NONE;
 
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -760,6 +768,7 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
 
                dp_clock = dig_connector->dp_clock;
                dp_lane_count = dig_connector->dp_lane_count;
+               hpd_id = radeon_connector->hpd.hpd;
        }
 
        /* no dig encoder assigned */
@@ -784,19 +793,36 @@ atombios_dig_encoder_setup(struct drm_encoder *encoder, int action)
        args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
        args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder);
 
-       if (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
-               if (dp_clock == 270000)
-                       args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
+       if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) ||
+           (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST))
                args.v1.ucLaneNum = dp_lane_count;
-       else if (radeon_encoder->pixel_clock > 165000)
+       else if (radeon_encoder->pixel_clock > 165000)
                args.v1.ucLaneNum = 8;
        else
                args.v1.ucLaneNum = 4;
 
-       if (ASIC_IS_DCE4(rdev)) {
+       if (ASIC_IS_DCE5(rdev)) {
+               if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) ||
+                   (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST)) {
+                       if (dp_clock == 270000)
+                               args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ;
+                       else if (dp_clock == 540000)
+                               args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ;
+               }
+               args.v4.acConfig.ucDigSel = dig->dig_encoder;
+               args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+               if (hpd_id == RADEON_HPD_NONE)
+                       args.v4.ucHPD_ID = 0;
+               else
+                       args.v4.ucHPD_ID = hpd_id + 1;
+       } else if (ASIC_IS_DCE4(rdev)) {
+               if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000))
+                       args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
                args.v3.acConfig.ucDigSel = dig->dig_encoder;
                args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR;
        } else {
+               if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000))
+                       args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ;
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                        args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1;
@@ -823,6 +849,7 @@ union dig_transmitter_control {
        DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1;
        DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2;
        DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3;
+       DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4;
 };
 
 void
@@ -883,7 +910,7 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
 
        args.v1.ucAction = action;
        if (action == ATOM_TRANSMITTER_ACTION_INIT) {
-               args.v1.usInitInfo = connector_object_id;
+               args.v1.usInitInfo = cpu_to_le16(connector_object_id);
        } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) {
                args.v1.asMode.ucLaneSel = lane_num;
                args.v1.asMode.ucLaneSet = lane_set;
@@ -917,10 +944,18 @@ atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t
                        struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
                        pll_id = radeon_crtc->pll_id;
                }
-               if (is_dp && rdev->clock.dp_extclk)
-                       args.v3.acConfig.ucRefClkSource = 2; /* external src */
-               else
-                       args.v3.acConfig.ucRefClkSource = pll_id;
+
+               if (ASIC_IS_DCE5(rdev)) {
+                       if (is_dp && rdev->clock.dp_extclk)
+                               args.v4.acConfig.ucRefClkSource = 3; /* external src */
+                       else
+                               args.v4.acConfig.ucRefClkSource = pll_id;
+               } else {
+                       if (is_dp && rdev->clock.dp_extclk)
+                               args.v3.acConfig.ucRefClkSource = 2; /* external src */
+                       else
+                               args.v3.acConfig.ucRefClkSource = pll_id;
+               }
 
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
@@ -1028,7 +1063,7 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action)
        if (!ASIC_IS_DCE4(rdev))
                return;
 
-       if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) ||
+       if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) &&
            (action != ATOM_TRANSMITTER_ACTION_POWER_OFF))
                return;
 
@@ -1044,6 +1079,7 @@ atombios_set_edp_panel_power(struct drm_connector *connector, int action)
 
 union external_encoder_control {
        EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1;
+       EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3;
 };
 
 static void
@@ -1054,6 +1090,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder);
        union external_encoder_control args;
        struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl);
@@ -1061,6 +1098,7 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
        int dp_clock = 0;
        int dp_lane_count = 0;
        int connector_object_id = 0;
+       u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
 
        if (connector) {
                struct radeon_connector *radeon_connector = to_radeon_connector(connector);
@@ -1099,6 +1137,37 @@ atombios_external_encoder_setup(struct drm_encoder *encoder,
                        else
                                args.v1.sDigEncoder.ucLaneNum = 4;
                        break;
+               case 3:
+                       args.v3.sExtEncoder.ucAction = action;
+                       if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT)
+                               args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id);
+                       else
+                               args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10);
+                       args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder);
+
+                       if (args.v3.sExtEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) {
+                               if (dp_clock == 270000)
+                                       args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ;
+                               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)
+                               args.v3.sExtEncoder.ucLaneNum = 8;
+                       else
+                               args.v3.sExtEncoder.ucLaneNum = 4;
+                       switch (ext_enum) {
+                       case GRAPH_OBJECT_ENUM_ID1:
+                               args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1;
+                               break;
+                       case GRAPH_OBJECT_ENUM_ID2:
+                               args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2;
+                               break;
+                       case GRAPH_OBJECT_ENUM_ID3:
+                               args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3;
+                               break;
+                       }
+                       args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR;
+                       break;
                default:
                        DRM_ERROR("Unknown table version: %d, %d\n", frev, crev);
                        return;
@@ -1158,6 +1227,8 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
        DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args;
        int index = 0;
        bool is_dig = false;
+       bool is_dce5_dac = false;
+       bool is_dce5_dvo = false;
 
        memset(&args, 0, sizeof(args));
 
@@ -1180,7 +1251,9 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
                break;
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
-               if (ASIC_IS_DCE3(rdev))
+               if (ASIC_IS_DCE5(rdev))
+                       is_dce5_dvo = true;
+               else if (ASIC_IS_DCE3(rdev))
                        is_dig = true;
                else
                        index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl);
@@ -1196,12 +1269,16 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DAC1:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
-               if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
-                       index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
-               else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
-                       index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
-               else
-                       index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
+               if (ASIC_IS_DCE5(rdev))
+                       is_dce5_dac = true;
+               else {
+                       if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))
+                               index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl);
+                       else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT))
+                               index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl);
+                       else
+                               index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl);
+               }
                break;
        case ENCODER_OBJECT_ID_INTERNAL_DAC2:
        case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
@@ -1260,6 +1337,28 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                                atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
                        break;
                }
+       } else if (is_dce5_dac) {
+               switch (mode) {
+               case DRM_MODE_DPMS_ON:
+                       atombios_dac_setup(encoder, ATOM_ENABLE);
+                       break;
+               case DRM_MODE_DPMS_STANDBY:
+               case DRM_MODE_DPMS_SUSPEND:
+               case DRM_MODE_DPMS_OFF:
+                       atombios_dac_setup(encoder, ATOM_DISABLE);
+                       break;
+               }
+       } else if (is_dce5_dvo) {
+               switch (mode) {
+               case DRM_MODE_DPMS_ON:
+                       atombios_dvo_setup(encoder, ATOM_ENABLE);
+                       break;
+               case DRM_MODE_DPMS_STANDBY:
+               case DRM_MODE_DPMS_SUSPEND:
+               case DRM_MODE_DPMS_OFF:
+                       atombios_dvo_setup(encoder, ATOM_DISABLE);
+                       break;
+               }
        } else {
                switch (mode) {
                case DRM_MODE_DPMS_ON:
@@ -1289,12 +1388,18 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                switch (mode) {
                case DRM_MODE_DPMS_ON:
                default:
-                       action = ATOM_ENABLE;
+                       if (ASIC_IS_DCE41(rdev))
+                               action = EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT;
+                       else
+                               action = ATOM_ENABLE;
                        break;
                case DRM_MODE_DPMS_STANDBY:
                case DRM_MODE_DPMS_SUSPEND:
                case DRM_MODE_DPMS_OFF:
-                       action = ATOM_DISABLE;
+                       if (ASIC_IS_DCE41(rdev))
+                               action = EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT;
+                       else
+                               action = ATOM_DISABLE;
                        break;
                }
                atombios_external_encoder_setup(encoder, ext_encoder, action);
@@ -1465,11 +1570,21 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
        }
 
        /* set scaler clears this on some chips */
-       /* XXX check DCE4 */
-       if (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT))) {
-               if (ASIC_IS_AVIVO(rdev) && (mode->flags & DRM_MODE_FLAG_INTERLACE))
-                       WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
-                              AVIVO_D1MODE_INTERLEAVE_EN);
+       if (ASIC_IS_AVIVO(rdev) &&
+           (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) {
+               if (ASIC_IS_DCE4(rdev)) {
+                       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                               WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset,
+                                      EVERGREEN_INTERLEAVE_EN);
+                       else
+                               WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
+               } else {
+                       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset,
+                                      AVIVO_D1MODE_INTERLEAVE_EN);
+                       else
+                               WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0);
+               }
        }
 }
 
@@ -1483,27 +1598,35 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        struct radeon_encoder_atom_dig *dig;
        uint32_t dig_enc_in_use = 0;
 
+       /* DCE4/5 */
        if (ASIC_IS_DCE4(rdev)) {
                dig = radeon_encoder->enc_priv;
-               switch (radeon_encoder->encoder_id) {
-               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+               if (ASIC_IS_DCE41(rdev)) {
                        if (dig->linkb)
                                return 1;
                        else
                                return 0;
-                       break;
-               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
-                       if (dig->linkb)
-                               return 3;
-                       else
-                               return 2;
-                       break;
-               case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
-                       if (dig->linkb)
-                               return 5;
-                       else
-                               return 4;
-                       break;
+               } else {
+                       switch (radeon_encoder->encoder_id) {
+                       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
+                               if (dig->linkb)
+                                       return 1;
+                               else
+                                       return 0;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
+                               if (dig->linkb)
+                                       return 3;
+                               else
+                                       return 2;
+                               break;
+                       case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
+                               if (dig->linkb)
+                                       return 5;
+                               else
+                                       return 4;
+                               break;
+                       }
                }
        }
 
@@ -1610,7 +1733,13 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        if (ext_encoder) {
-               atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
+               if (ASIC_IS_DCE41(rdev)) {
+                       atombios_external_encoder_setup(encoder, ext_encoder,
+                                                       EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT);
+                       atombios_external_encoder_setup(encoder, ext_encoder,
+                                                       EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
+               } else
+                       atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
        }
 
        atombios_apply_encoder_quirks(encoder, adjusted_mode);
@@ -1927,7 +2056,10 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder)
 }
 
 void
-radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device)
+radeon_add_atom_encoder(struct drm_device *dev,
+                       uint32_t encoder_enum,
+                       uint32_t supported_device,
+                       u16 caps)
 {
        struct radeon_device *rdev = dev->dev_private;
        struct drm_encoder *encoder;
@@ -1970,6 +2102,7 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t
        radeon_encoder->rmx_type = RMX_OFF;
        radeon_encoder->underscan_type = UNDERSCAN_OFF;
        radeon_encoder->is_ext_encoder = false;
+       radeon_encoder->caps = caps;
 
        switch (radeon_encoder->encoder_id) {
        case ENCODER_OBJECT_ID_INTERNAL_LVDS:
@@ -2029,6 +2162,8 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t
        case ENCODER_OBJECT_ID_TITFP513:
        case ENCODER_OBJECT_ID_VT1623:
        case ENCODER_OBJECT_ID_HDMI_SI1930:
+       case ENCODER_OBJECT_ID_TRAVIS:
+       case ENCODER_OBJECT_ID_NUTMEG:
                /* these are handled by the primary encoders */
                radeon_encoder->is_ext_encoder = true;
                if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))