Skip to content

Commit

Permalink
drm/radeon: improve encoder picking functions (v2)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Dave Airlie authored and Alex Deucher committed Mar 19, 2015
1 parent 2be123d commit 8f0fc08
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 23 deletions.
82 changes: 59 additions & 23 deletions drivers/gpu/drm/radeon/atombios_encoders.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 */
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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 */
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/radeon/radeon_mode.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

0 comments on commit 8f0fc08

Please sign in to comment.