drm/radeon: set speaker allocation for DCE4/5 (v2)
authorAlex Deucher <alexander.deucher@amd.com>
Thu, 15 Aug 2013 13:34:07 +0000 (09:34 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 30 Aug 2013 20:30:46 +0000 (16:30 -0400)
This updates the audio driver to the speaker allocation
block from the EDID.  A similar change was just implemented
for DCE6/8.

v2: remove unused variables

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Rafał Miłecki <zajec5@gmail.com>
drivers/gpu/drm/radeon/evergreen_hdmi.c
drivers/gpu/drm/radeon/evergreend.h

index 2cb0f90126cb67ca491b332cba5279b9fe93f967..f71ce390aebe581dd08998ce29d98e4b1058155c 100644 (file)
@@ -58,6 +58,45 @@ static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t cloc
        WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz);
 }
 
+static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)
+{
+       struct radeon_device *rdev = encoder->dev->dev_private;
+       struct drm_connector *connector;
+       struct radeon_connector *radeon_connector = NULL;
+       u32 tmp;
+       u8 *sadb;
+       int sad_count;
+
+       list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
+               if (connector->encoder == encoder)
+                       radeon_connector = to_radeon_connector(connector);
+       }
+
+       if (!radeon_connector) {
+               DRM_ERROR("Couldn't find encoder's connector\n");
+               return;
+       }
+
+       sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb);
+       if (sad_count < 0) {
+               DRM_ERROR("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
+               return;
+       }
+
+       /* program the speaker allocation */
+       tmp = RREG32(AZ_F0_CODEC_PIN0_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(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
+
+       kfree(sadb);
+}
+
 static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)
 {
        struct radeon_device *rdev = encoder->dev->dev_private;
@@ -271,7 +310,7 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
        if (ASIC_IS_DCE6(rdev)) {
                dce6_afmt_write_speaker_allocation(encoder);
        } else {
-               /* fglrx sets 0x0001005f | (x & 0x00fc0000) in 0x5f78 here */
+               dce4_afmt_write_speaker_allocation(encoder);
        }
 
        WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset,
index 0d582ac1dc31841b0844df7cfe4b186bd7b6da0e..430997a70acc3590b365bd7362cf7217746a12a3 100644 (file)
 #define AFMT_GENERIC0_7                      0x7138
 
 /* DCE4/5 ELD audio interface */
+#define AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER          0x5f78
+#define                SPEAKER_ALLOCATION(x)                   (((x) & 0x7f) << 0)
+#define                SPEAKER_ALLOCATION_MASK                 (0x7f << 0)
+#define                SPEAKER_ALLOCATION_SHIFT                0
+#define                HDMI_CONNECTION                         (1 << 16)
+#define                DP_CONNECTION                           (1 << 17)
+
 #define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0        0x5f84 /* LPCM */
 #define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1        0x5f88 /* AC3 */
 #define AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR2        0x5f8c /* MPEG1 */