Skip to content

Commit

Permalink
drm/radeon: rework audio detect (v4)
Browse files Browse the repository at this point in the history
1. Always assign audio function pointers even if the display does
not support audio.  We need to properly disable the audio stream
when when using a non-audio capable monitor.  Fixes purple line
on some hdmi monitors.

2. Check if a pin is in use by another encoder before disabling
it.

v2: make sure we've fetched the edid before checking audio and
    look up the encoder before calling audio_detect since
    connector->encoder may not be assigned yet.  Separate
    pin and afmt.  They are allocated at different times and
    have no dependency on eachother.
v3: fix connector fetching in encoder functions
v4: fix missed dig->pin check in dce6_afmt_write_latency_fields

bugs:
https://bugzilla.kernel.org/show_bug.cgi?id=93701
https://bugzilla.redhat.com/show_bug.cgi?id=1236337
https://bugs.freedesktop.org/show_bug.cgi?id=91041

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
  • Loading branch information
alexdeucher committed Jul 29, 2015
1 parent b3fcf36 commit d0ea397
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 123 deletions.
62 changes: 28 additions & 34 deletions drivers/gpu/drm/radeon/dce6_afmt.c
Expand Up @@ -93,30 +93,26 @@ void dce6_afmt_select_pin(struct drm_encoder *encoder)
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
u32 offset;

if (!dig || !dig->afmt || !dig->afmt->pin)
if (!dig || !dig->afmt || !dig->pin)
return;

offset = dig->afmt->offset;

WREG32(AFMT_AUDIO_SRC_CONTROL + offset,
AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));
WREG32(AFMT_AUDIO_SRC_CONTROL + dig->afmt->offset,
AFMT_AUDIO_SRC_SELECT(dig->pin->id));
}

void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
struct drm_connector *connector, struct drm_display_mode *mode)
struct drm_connector *connector,
struct drm_display_mode *mode)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
u32 tmp = 0, offset;
u32 tmp = 0;

if (!dig || !dig->afmt || !dig->afmt->pin)
if (!dig || !dig->afmt || !dig->pin)
return;

offset = dig->afmt->pin->offset;

if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
if (connector->latency_present[1])
tmp = VIDEO_LIPSYNC(connector->video_latency[1]) |
Expand All @@ -130,63 +126,63 @@ void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
else
tmp = VIDEO_LIPSYNC(0) | AUDIO_LIPSYNC(0);
}
WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
WREG32_ENDPOINT(dig->pin->offset,
AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
}

void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count)
u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
u32 offset, tmp;
u32 tmp;

if (!dig || !dig->afmt || !dig->afmt->pin)
if (!dig || !dig->afmt || !dig->pin)
return;

offset = dig->afmt->pin->offset;

/* program the speaker allocation */
tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
tmp = RREG32_ENDPOINT(dig->pin->offset,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
/* set HDMI mode */
tmp |= HDMI_CONNECTION;
if (sad_count)
tmp |= SPEAKER_ALLOCATION(sadb[0]);
else
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
WREG32_ENDPOINT(dig->pin->offset,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
}

void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
u8 *sadb, int sad_count)
u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
u32 offset, tmp;
u32 tmp;

if (!dig || !dig->afmt || !dig->afmt->pin)
if (!dig || !dig->afmt || !dig->pin)
return;

offset = dig->afmt->pin->offset;

/* program the speaker allocation */
tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
tmp = RREG32_ENDPOINT(dig->pin->offset,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
/* set DP mode */
tmp |= DP_CONNECTION;
if (sad_count)
tmp |= SPEAKER_ALLOCATION(sadb[0]);
else
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
WREG32_ENDPOINT(dig->pin->offset,
AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
}

void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
struct cea_sad *sads, int sad_count)
struct cea_sad *sads, int sad_count)
{
u32 offset;
int i;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
Expand All @@ -206,11 +202,9 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
};

if (!dig || !dig->afmt || !dig->afmt->pin)
if (!dig || !dig->afmt || !dig->pin)
return;

offset = dig->afmt->pin->offset;

for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
u32 value = 0;
u8 stereo_freqs = 0;
Expand All @@ -237,7 +231,7 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,

value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);

WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value);
WREG32_ENDPOINT(dig->pin->offset, eld_reg_to_type[i][0], value);
}
}

Expand All @@ -253,7 +247,7 @@ void dce6_audio_enable(struct radeon_device *rdev,
}

void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock)
struct radeon_crtc *crtc, unsigned int clock)
{
/* Two dtos; generally use dto0 for HDMI */
u32 value = 0;
Expand All @@ -272,7 +266,7 @@ void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
}

void dce6_dp_audio_set_dto(struct radeon_device *rdev,
struct radeon_crtc *crtc, unsigned int clock)
struct radeon_crtc *crtc, unsigned int clock)
{
/* Two dtos; generally use dto1 for DP */
u32 value = 0;
Expand Down

0 comments on commit d0ea397

Please sign in to comment.