From 8f0fc088f5fff0c2e4683bc0de7fc849e7d5357a Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 24 Feb 2015 09:24:03 +1000 Subject: [PATCH] drm/radeon: improve encoder picking functions (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Dave Airlie Signed-off-by: Alex Deucher --- drivers/gpu/drm/radeon/atombios_encoders.c | 82 ++++++++++++++++------ drivers/gpu/drm/radeon/radeon_mode.h | 6 ++ 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index eb575a854330..980cbccdf1a7 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -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 */ diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index e66a4b4caab2..c612289d7c60 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -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 -- 2.39.5