drm/radeon: Sync to Linux 3.11
[dragonfly.git] / sys / dev / drm / radeon / evergreen_hdmi.c
index 3103ef4..c45f862 100644 (file)
  *
  * Authors: Christian König
  *          Rafał Miłecki
- *
- * $FreeBSD: head/sys/dev/drm2/radeon/evergreen_hdmi.c 254885 2013-08-25 19:37:15Z dumbbell $
  */
-
 #include <linux/hdmi.h>
 #include <drm/drmP.h>
 #include <uapi_drm/radeon_drm.h>
@@ -132,13 +129,7 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
        uint32_t offset = dig->afmt->offset;
        uint8_t *frame = (uint8_t*)buffer + 3;
 
-       /* Our header values (type, version, length) should be alright, Intel
-        * is using the same. Checksum function also seems to be OK, it works
-        * fine for audio infoframe. However calculated value is always lower
-        * by 2 in comparison to fglrx. It breaks displaying anything in case
-        * of TVs that strictly check the checksum. Hack it manually here to
-        * workaround this issue. */
-       frame[0x0] += 2;
+       uint8_t *header = buffer;
 
        WREG32(AFMT_AVI_INFO0 + offset,
                frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -147,7 +138,7 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
        WREG32(AFMT_AVI_INFO2 + offset,
                frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
        WREG32(AFMT_AVI_INFO3 + offset,
-               frame[0xC] | (frame[0xD] << 8));
+               frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
 }
 
 static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
@@ -158,18 +149,40 @@ static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
        u32 base_rate = 24000;
+       u32 max_ratio = clock / base_rate;
+       u32 dto_phase;
+       u32 dto_modulo = clock;
+       u32 wallclock_ratio;
+       u32 dto_cntl;
 
        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 {
+               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);
+
        /* XXX two dtos; generally use dto0 for hdmi */
        /* Express [24MHz / target pixel clock] as an exact rational
         * number (coefficient of two integer numbers.  DCCG_AUDIO_DTOx_PHASE
         * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
         */
-       WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
-       WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
        WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
+       WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
+       WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
 }
 
 
@@ -187,6 +200,9 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
        uint32_t offset;
        ssize_t err;
 
+       if (!dig || !dig->afmt)
+               return;
+
        /* Silent, r600_hdmi_enable will raise WARN for us */
        if (!dig->afmt->enabled)
                return;
@@ -290,6 +306,9 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 
+       if (!dig || !dig->afmt)
+               return;
+
        /* Silent, r600_hdmi_enable will raise WARN for us */
        if (enable && dig->afmt->enabled)
                return;