drm/radeon: improve encoder picking functions (v2)
authorDave Airlie <airlied@redhat.com>
Mon, 23 Feb 2015 23:24:03 +0000 (09:24 +1000)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 19 Mar 2015 16:26:51 +0000 (12:26 -0400)
For MST we need to be able to pick front end encoders
separate from backend, but only for MST, so we need to
make the encoder picking interface smarter.

v2: agd5f: squash in:
drm/radeon: release digital encoder before asking for new one
Reported-by: Dieter Nützel <Dieter@nuetzel-hh.de>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/radeon_mode.h

index eb575a854330387c2d711e30453d4038fb53fe23..980cbccdf1a79fc019739b6fab0630a4d142f586 100644 (file)
@@ -2022,7 +2022,14 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder,
        }
 }
 
-static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
+void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx)
+{
+       if (enc_idx < 0)
+               return;
+       rdev->mode_info.active_encoders &= ~(1 << enc_idx);
+}
+
+int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
@@ -2031,71 +2038,79 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        struct drm_encoder *test_encoder;
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
        uint32_t dig_enc_in_use = 0;
+       int enc_idx = -1;
 
+       if (fe_idx >= 0) {
+               enc_idx = fe_idx;
+               goto assigned;
+       }
        if (ASIC_IS_DCE6(rdev)) {
                /* DCE6 */
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                        if (dig->linkb)
-                               return 1;
+                               enc_idx = 1;
                        else
-                               return 0;
+                               enc_idx = 0;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
                        if (dig->linkb)
-                               return 3;
+                               enc_idx = 3;
                        else
-                               return 2;
+                               enc_idx = 2;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
                        if (dig->linkb)
-                               return 5;
+                               enc_idx = 5;
                        else
-                               return 4;
+                               enc_idx = 4;
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
-                       return 6;
+                       enc_idx = 6;
                        break;
                }
+               goto assigned;
        } else if (ASIC_IS_DCE4(rdev)) {
                /* DCE4/5 */
                if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) {
                        /* ontario follows DCE4 */
                        if (rdev->family == CHIP_PALM) {
                                if (dig->linkb)
-                                       return 1;
+                                       enc_idx = 1;
                                else
-                                       return 0;
+                                       enc_idx = 0;
                        } else
                                /* llano follows DCE3.2 */
-                               return radeon_crtc->crtc_id;
+                               enc_idx = radeon_crtc->crtc_id;
                } else {
                        switch (radeon_encoder->encoder_id) {
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
                                if (dig->linkb)
-                                       return 1;
+                                       enc_idx = 1;
                                else
-                                       return 0;
+                                       enc_idx = 0;
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
                                if (dig->linkb)
-                                       return 3;
+                                       enc_idx = 3;
                                else
-                                       return 2;
+                                       enc_idx = 2;
                                break;
                        case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
                                if (dig->linkb)
-                                       return 5;
+                                       enc_idx = 5;
                                else
-                                       return 4;
+                                       enc_idx = 4;
                                break;
                        }
                }
+               goto assigned;
        }
 
        /* on DCE32 and encoder can driver any block so just crtc id */
        if (ASIC_IS_DCE32(rdev)) {
-               return radeon_crtc->crtc_id;
+               enc_idx = radeon_crtc->crtc_id;
+               goto assigned;
        }
 
        /* on DCE3 - LVTMA can only be driven by DIGB */
@@ -2123,6 +2138,17 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
        if (!(dig_enc_in_use & 1))
                return 0;
        return 1;
+
+assigned:
+       if (enc_idx == -1) {
+               DRM_ERROR("Got encoder index incorrect - returning 0\n");
+               return 0;
+       }
+       if (rdev->mode_info.active_encoders & (1 << enc_idx)) {
+               DRM_ERROR("chosen encoder in use %d\n", enc_idx);
+       }
+       rdev->mode_info.active_encoders |= (1 << enc_idx);
+       return enc_idx;
 }
 
 /* This only needs to be called once at startup */
@@ -2381,7 +2407,9 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
             ENCODER_OBJECT_ID_NONE)) {
                struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
                if (dig) {
-                       dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder);
+                       if (dig->dig_encoder >= 0)
+                               radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
+                       dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder, -1);
                        if (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) {
                                if (rdev->family >= CHIP_R600)
                                        dig->afmt = rdev->mode_info.afmt[dig->dig_encoder];
@@ -2483,10 +2511,18 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
 
 disable_done:
        if (radeon_encoder_is_digital(encoder)) {
-               dig = radeon_encoder->enc_priv;
-               dig->dig_encoder = -1;
-       }
-       radeon_encoder->active_device = 0;
+               if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
+                       if (rdev->asic->display.hdmi_enable)
+                               radeon_hdmi_enable(rdev, encoder, false);
+               }
+               if (atombios_get_encoder_mode(encoder) != ATOM_ENCODER_MODE_DP_MST) {
+                       dig = radeon_encoder->enc_priv;
+                       radeon_atom_release_dig_encoder(rdev, dig->dig_encoder);
+                       dig->dig_encoder = -1;
+                       radeon_encoder->active_device = 0;
+               }
+       } else
+               radeon_encoder->active_device = 0;
 }
 
 /* these are handled by the primary encoders */
index e66a4b4caab225ab0072b3478da457cfd58e744e..c612289d7c60ec4ce0b636f03457c44b65602c95 100644 (file)
@@ -274,6 +274,9 @@ struct radeon_mode_info {
        u16 firmware_flags;
        /* pointer to backlight encoder */
        struct radeon_encoder *bl_encoder;
+
+       /* bitmask for active encoder frontends */
+       uint32_t active_encoders;
 };
 
 #define RADEON_MAX_BL_LEVEL 0xFF
@@ -956,4 +959,7 @@ void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector
 void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id);
 
 int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bool tiled);
+
+int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder, int fe_idx);
+void radeon_atom_release_dig_encoder(struct radeon_device *rdev, int enc_idx);
 #endif