Commit 8f0fc088 authored by Dave Airlie's avatar Dave Airlie Committed by Alex Deucher

drm/radeon: improve encoder picking functions (v2)

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: default avatarDieter Nützel <Dieter@nuetzel-hh.de>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 2be123d7
...@@ -2022,7 +2022,14 @@ atombios_apply_encoder_quirks(struct drm_encoder *encoder, ...@@ -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 drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private; struct radeon_device *rdev = dev->dev_private;
...@@ -2031,71 +2038,79 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) ...@@ -2031,71 +2038,79 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
struct drm_encoder *test_encoder; struct drm_encoder *test_encoder;
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
uint32_t dig_enc_in_use = 0; 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)) { if (ASIC_IS_DCE6(rdev)) {
/* DCE6 */ /* DCE6 */
switch (radeon_encoder->encoder_id) { switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
if (dig->linkb) if (dig->linkb)
return 1; enc_idx = 1;
else else
return 0; enc_idx = 0;
break; break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
if (dig->linkb) if (dig->linkb)
return 3; enc_idx = 3;
else else
return 2; enc_idx = 2;
break; break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
if (dig->linkb) if (dig->linkb)
return 5; enc_idx = 5;
else else
return 4; enc_idx = 4;
break; break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
return 6; enc_idx = 6;
break; break;
} }
goto assigned;
} else if (ASIC_IS_DCE4(rdev)) { } else if (ASIC_IS_DCE4(rdev)) {
/* DCE4/5 */ /* DCE4/5 */
if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) { if (ASIC_IS_DCE41(rdev) && !ASIC_IS_DCE61(rdev)) {
/* ontario follows DCE4 */ /* ontario follows DCE4 */
if (rdev->family == CHIP_PALM) { if (rdev->family == CHIP_PALM) {
if (dig->linkb) if (dig->linkb)
return 1; enc_idx = 1;
else else
return 0; enc_idx = 0;
} else } else
/* llano follows DCE3.2 */ /* llano follows DCE3.2 */
return radeon_crtc->crtc_id; enc_idx = radeon_crtc->crtc_id;
} else { } else {
switch (radeon_encoder->encoder_id) { switch (radeon_encoder->encoder_id) {
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
if (dig->linkb) if (dig->linkb)
return 1; enc_idx = 1;
else else
return 0; enc_idx = 0;
break; break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
if (dig->linkb) if (dig->linkb)
return 3; enc_idx = 3;
else else
return 2; enc_idx = 2;
break; break;
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
if (dig->linkb) if (dig->linkb)
return 5; enc_idx = 5;
else else
return 4; enc_idx = 4;
break; break;
} }
} }
goto assigned;
} }
/* on DCE32 and encoder can driver any block so just crtc id */ /* on DCE32 and encoder can driver any block so just crtc id */
if (ASIC_IS_DCE32(rdev)) { 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 */ /* on DCE3 - LVTMA can only be driven by DIGB */
...@@ -2123,6 +2138,17 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) ...@@ -2123,6 +2138,17 @@ static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder)
if (!(dig_enc_in_use & 1)) if (!(dig_enc_in_use & 1))
return 0; return 0;
return 1; 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 */ /* This only needs to be called once at startup */
...@@ -2381,7 +2407,9 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) ...@@ -2381,7 +2407,9 @@ static void radeon_atom_encoder_prepare(struct drm_encoder *encoder)
ENCODER_OBJECT_ID_NONE)) { ENCODER_OBJECT_ID_NONE)) {
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
if (dig) { 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 (radeon_encoder->active_device & ATOM_DEVICE_DFP_SUPPORT) {
if (rdev->family >= CHIP_R600) if (rdev->family >= CHIP_R600)
dig->afmt = rdev->mode_info.afmt[dig->dig_encoder]; dig->afmt = rdev->mode_info.afmt[dig->dig_encoder];
...@@ -2483,10 +2511,18 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder) ...@@ -2483,10 +2511,18 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
disable_done: disable_done:
if (radeon_encoder_is_digital(encoder)) { if (radeon_encoder_is_digital(encoder)) {
dig = radeon_encoder->enc_priv; if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
dig->dig_encoder = -1; if (rdev->asic->display.hdmi_enable)
} radeon_hdmi_enable(rdev, encoder, false);
radeon_encoder->active_device = 0; }
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 */ /* these are handled by the primary encoders */
......
...@@ -274,6 +274,9 @@ struct radeon_mode_info { ...@@ -274,6 +274,9 @@ struct radeon_mode_info {
u16 firmware_flags; u16 firmware_flags;
/* pointer to backlight encoder */ /* pointer to backlight encoder */
struct radeon_encoder *bl_encoder; struct radeon_encoder *bl_encoder;
/* bitmask for active encoder frontends */
uint32_t active_encoders;
}; };
#define RADEON_MAX_BL_LEVEL 0xFF #define RADEON_MAX_BL_LEVEL 0xFF
...@@ -956,4 +959,7 @@ void radeon_fb_remove_connector(struct radeon_device *rdev, struct drm_connector ...@@ -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); 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_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 #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment