From: Dave Airlie <airl...@redhat.com>

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.

Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 drivers/gpu/drm/radeon/atombios_encoders.c | 80 +++++++++++++++++++++---------
 drivers/gpu/drm/radeon/radeon_mode.h       |  6 +++
 2 files changed, 63 insertions(+), 23 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c 
b/drivers/gpu/drm/radeon/atombios_encoders.c
index dc55139..e0a9136c 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -2015,7 +2015,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;
@@ -2024,71 +2031,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 */
@@ -2116,6 +2131,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 */
@@ -2370,7 +2396,7 @@ 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);
+                       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];
@@ -2472,10 +2498,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 */
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h 
b/drivers/gpu/drm/radeon/radeon_mode.h
index 3d4f390..2cadee2a 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -265,6 +265,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
@@ -945,4 +948,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
-- 
2.1.0

Reply via email to