]> Pileus Git - ~andy/linux/blobdiff - drivers/gpu/drm/radeon/evergreen_hdmi.c
Merge tag 'nfs-for-3.12-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[~andy/linux] / drivers / gpu / drm / radeon / evergreen_hdmi.c
index b0e280058b9b09ea22eb75f5c13ab6395e1698ba..f71ce390aebe581dd08998ce29d98e4b1058155c 100644 (file)
 #include "evergreend.h"
 #include "atom.h"
 
+extern void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder);
+extern void dce6_afmt_write_sad_regs(struct drm_encoder *encoder);
+extern void dce6_afmt_select_pin(struct drm_encoder *encoder);
+
 /*
  * update the N and CTS parameters for a given pixel clock rate
  */
@@ -54,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;
@@ -157,22 +200,26 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
        if (!dig || !dig->afmt)
                return;
 
-       if (max_ratio >= 8) {
-               dto_phase = 192 * 1000;
-               wallclock_ratio = 3;
-       } else if (max_ratio >= 4) {
-               dto_phase = 96 * 1000;
-               wallclock_ratio = 2;
-       } else if (max_ratio >= 2) {
-               dto_phase = 48 * 1000;
-               wallclock_ratio = 1;
-       } else {
+       if (ASIC_IS_DCE6(rdev)) {
                dto_phase = 24 * 1000;
-               wallclock_ratio = 0;
+       } else {
+               if (max_ratio >= 8) {
+                       dto_phase = 192 * 1000;
+                       wallclock_ratio = 3;
+               } else if (max_ratio >= 4) {
+                       dto_phase = 96 * 1000;
+                       wallclock_ratio = 2;
+               } else if (max_ratio >= 2) {
+                       dto_phase = 48 * 1000;
+                       wallclock_ratio = 1;
+               } else {
+                       dto_phase = 24 * 1000;
+                       wallclock_ratio = 0;
+               }
+               dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+               dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+               WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
        }
-       dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
-       dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
-       WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
 
        /* XXX two dtos; generally use dto0 for hdmi */
        /* Express [24MHz / target pixel clock] as an exact rational
@@ -260,13 +307,23 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
               AFMT_60958_CS_CHANNEL_NUMBER_6(7) |
               AFMT_60958_CS_CHANNEL_NUMBER_7(8));
 
-       /* fglrx sets 0x0001005f | (x & 0x00fc0000) in 0x5f78 here */
+       if (ASIC_IS_DCE6(rdev)) {
+               dce6_afmt_write_speaker_allocation(encoder);
+       } else {
+               dce4_afmt_write_speaker_allocation(encoder);
+       }
 
        WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset,
               AFMT_AUDIO_CHANNEL_ENABLE(0xff));
 
        /* fglrx sets 0x40 in 0x5f80 here */
-       evergreen_hdmi_write_sad_regs(encoder);
+
+       if (ASIC_IS_DCE6(rdev)) {
+               dce6_afmt_select_pin(encoder);
+               dce6_afmt_write_sad_regs(encoder);
+       } else {
+               evergreen_hdmi_write_sad_regs(encoder);
+       }
 
        err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
        if (err < 0) {
@@ -302,6 +359,8 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
 
 void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
 {
+       struct drm_device *dev = encoder->dev;
+       struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 
@@ -314,6 +373,15 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
        if (!enable && !dig->afmt->enabled)
                return;
 
+       if (enable) {
+               if (ASIC_IS_DCE6(rdev))
+                       dig->afmt->pin = dce6_audio_get_pin(rdev);
+               else
+                       dig->afmt->pin = r600_audio_get_pin(rdev);
+       } else {
+               dig->afmt->pin = NULL;
+       }
+
        dig->afmt->enabled = enable;
 
        DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",