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,
}
}
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 */
......
......@@ -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
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