Merge branch 'drm-radeon-testing' of ../drm-radeon-next into drm-core-next
authorDave Airlie <airlied@redhat.com>
Tue, 3 Jan 2012 09:43:28 +0000 (09:43 +0000)
committerDave Airlie <airlied@redhat.com>
Tue, 3 Jan 2012 09:45:12 +0000 (09:45 +0000)
This merges the evergreen HDMI audio support.

* 'drm-radeon-testing' of ../drm-radeon-next:
  drm/radeon/kms: define TMDS/LVTM HDMI enabling bits
  drm/radeon/kms: workaround invalid AVI infoframe checksum issue
  drm/radeon/kms: setup HDMI mode on Evergreen encoders
  drm/radeon/kms: support for audio on Evergreen
  drm/radeon/kms: minor HDMI audio cleanups
  drm/radeon/kms: do not force DVI mode on DCE4 if audio is on
ridge

Conflicts:
drivers/gpu/drm/radeon/evergreen.c

drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_reg.h
drivers/gpu/drm/radeon/r500_reg.h
drivers/gpu/drm/radeon/r600_audio.c
drivers/gpu/drm/radeon/r600_hdmi.c

index 39c04c1b8472199da475db971b8b7b6078a91aad..f1f06ca9f1f533fc89179c5109a60ca9af4f5ebb 100644 (file)
@@ -409,8 +409,6 @@ int
 atombios_get_encoder_mode(struct drm_encoder *encoder)
 {
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
        struct drm_connector *connector;
        struct radeon_connector *radeon_connector;
        struct radeon_connector_atom_dig *dig_connector;
@@ -434,13 +432,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        switch (connector->connector_type) {
        case DRM_MODE_CONNECTOR_DVII:
        case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
-               if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
-                       /* fix me */
-                       if (ASIC_IS_DCE4(rdev))
-                               return ATOM_ENCODER_MODE_DVI;
-                       else
-                               return ATOM_ENCODER_MODE_HDMI;
-               } else if (radeon_connector->use_digital)
+               if (drm_detect_monitor_audio(radeon_connector->edid) &&
+                   radeon_audio)
+                       return ATOM_ENCODER_MODE_HDMI;
+               else if (radeon_connector->use_digital)
                        return ATOM_ENCODER_MODE_DVI;
                else
                        return ATOM_ENCODER_MODE_CRT;
@@ -448,13 +443,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        case DRM_MODE_CONNECTOR_DVID:
        case DRM_MODE_CONNECTOR_HDMIA:
        default:
-               if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
-                       /* fix me */
-                       if (ASIC_IS_DCE4(rdev))
-                               return ATOM_ENCODER_MODE_DVI;
-                       else
-                               return ATOM_ENCODER_MODE_HDMI;
-               } else
+               if (drm_detect_monitor_audio(radeon_connector->edid) &&
+                   radeon_audio)
+                       return ATOM_ENCODER_MODE_HDMI;
+               else
                        return ATOM_ENCODER_MODE_DVI;
                break;
        case DRM_MODE_CONNECTOR_LVDS:
@@ -465,13 +457,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
                        return ATOM_ENCODER_MODE_DP;
-               else if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) {
-                       /* fix me */
-                       if (ASIC_IS_DCE4(rdev))
-                               return ATOM_ENCODER_MODE_DVI;
-                       else
-                               return ATOM_ENCODER_MODE_HDMI;
-               } else
+               else if (drm_detect_monitor_audio(radeon_connector->edid) &&
+                        radeon_audio)
+                       return ATOM_ENCODER_MODE_HDMI;
+               else
                        return ATOM_ENCODER_MODE_DVI;
                break;
        case DRM_MODE_CONNECTOR_eDP:
index 1934728e2465b0e281e644d03d22221e0eb8f86d..ccde2c9540e29f871fecbbbe5dd0ad2337d46a2d 100644 (file)
@@ -3190,6 +3190,11 @@ static int evergreen_startup(struct radeon_device *rdev)
        if (r) {
                DRM_ERROR("radeon: failed testing IB (%d).\n", r);
                rdev->accel_working = false;
+       }
+
+       r = r600_audio_init(rdev);
+       if (r) {
+               DRM_ERROR("radeon: audio init failed\n");
                return r;
        }
 
@@ -3227,6 +3232,7 @@ int evergreen_suspend(struct radeon_device *rdev)
 {
        struct radeon_ring *ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
 
+       r600_audio_fini(rdev);
        /* FIXME: we should wait for ring to be empty */
        radeon_ib_pool_suspend(rdev);
        r600_blit_suspend(rdev);
@@ -3342,6 +3348,7 @@ int evergreen_init(struct radeon_device *rdev)
 
 void evergreen_fini(struct radeon_device *rdev)
 {
+       r600_audio_fini(rdev);
        r600_blit_fini(rdev);
        r700_cp_fini(rdev);
        r600_irq_fini(rdev);
index 7d7f2155e34c305729f8487c55fc8c2c741ccc44..4215de95477e4a863c83183d90133c9d07358ee4 100644 (file)
 #define EVERGREEN_P1PLL_SS_CNTL                         0x414
 #define EVERGREEN_P2PLL_SS_CNTL                         0x454
 #       define EVERGREEN_PxPLL_SS_EN                    (1 << 12)
+
+#define EVERGREEN_AUDIO_PLL1_MUL                       0x5b0
+#define EVERGREEN_AUDIO_PLL1_DIV                       0x5b4
+#define EVERGREEN_AUDIO_PLL1_UNK                       0x5bc
+
+#define EVERGREEN_AUDIO_ENABLE                         0x5e78
+#define EVERGREEN_AUDIO_VENDOR_ID                      0x5ec0
+
 /* GRPH blocks at 0x6800, 0x7400, 0x10000, 0x10c00, 0x11800, 0x12400 */
 #define EVERGREEN_GRPH_ENABLE                           0x6800
 #define EVERGREEN_GRPH_CONTROL                          0x6804
 #define EVERGREEN_DC_GPIO_HPD_EN                        0x64b8
 #define EVERGREEN_DC_GPIO_HPD_Y                         0x64bc
 
+/* HDMI blocks at 0x7030, 0x7c30, 0x10830, 0x11430, 0x12030, 0x12c30 */
+#define EVERGREEN_HDMI_BASE                            0x7030
+
+#define EVERGREEN_HDMI_CONFIG_OFFSET                   0xf0
+
 #endif
index fc437059918fb800001ccc871df9b7eb81c333bb..3bd8f1b1c606f4098fa959b33bf2b753bded93fe 100644 (file)
 
 #define AVIVO_TMDSA_CNTL                    0x7880
 #   define AVIVO_TMDSA_CNTL_ENABLE               (1 << 0)
+#   define AVIVO_TMDSA_CNTL_HDMI_EN              (1 << 2)
 #   define AVIVO_TMDSA_CNTL_HPD_MASK             (1 << 4)
 #   define AVIVO_TMDSA_CNTL_HPD_SELECT           (1 << 8)
 #   define AVIVO_TMDSA_CNTL_SYNC_PHASE           (1 << 12)
 
 #define AVIVO_LVTMA_CNTL                                       0x7a80
 #   define AVIVO_LVTMA_CNTL_ENABLE               (1 << 0)
+#   define AVIVO_LVTMA_CNTL_HDMI_EN              (1 << 2)
 #   define AVIVO_LVTMA_CNTL_HPD_MASK             (1 << 4)
 #   define AVIVO_LVTMA_CNTL_HPD_SELECT           (1 << 8)
 #   define AVIVO_LVTMA_CNTL_SYNC_PHASE           (1 << 12)
index 846fae5763998a7ed7ab0140f68deb7b3dae40b8..ba66f3093d46138be6010d299f7b103d49b4e5eb 100644 (file)
@@ -36,7 +36,7 @@
  */
 static int r600_audio_chipset_supported(struct radeon_device *rdev)
 {
-       return (rdev->family >= CHIP_R600 && rdev->family < CHIP_CEDAR)
+       return (rdev->family >= CHIP_R600 && !ASIC_IS_DCE5(rdev))
                || rdev->family == CHIP_RS600
                || rdev->family == CHIP_RS690
                || rdev->family == CHIP_RS740;
@@ -161,8 +161,18 @@ static void r600_audio_update_hdmi(unsigned long param)
  */
 static void r600_audio_engine_enable(struct radeon_device *rdev, bool enable)
 {
+       u32 value = 0;
        DRM_INFO("%s audio support\n", enable ? "Enabling" : "Disabling");
-       WREG32_P(R600_AUDIO_ENABLE, enable ? 0x81000000 : 0x0, ~0x81000000);
+       if (ASIC_IS_DCE4(rdev)) {
+               if (enable) {
+                       value |= 0x81000000; /* Required to enable audio */
+                       value |= 0x0e1000f0; /* fglrx sets that too */
+               }
+               WREG32(EVERGREEN_AUDIO_ENABLE, value);
+       } else {
+               WREG32_P(R600_AUDIO_ENABLE,
+                        enable ? 0x81000000 : 0x0, ~0x81000000);
+       }
        rdev->audio_enabled = enable;
 }
 
@@ -248,22 +258,33 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
                return;
        }
 
-       switch (dig->dig_encoder) {
-       case 0:
-               WREG32(R600_AUDIO_PLL1_MUL, base_rate * 50);
-               WREG32(R600_AUDIO_PLL1_DIV, clock * 100);
-               WREG32(R600_AUDIO_CLK_SRCSEL, 0);
-               break;
-
-       case 1:
-               WREG32(R600_AUDIO_PLL2_MUL, base_rate * 50);
-               WREG32(R600_AUDIO_PLL2_DIV, clock * 100);
-               WREG32(R600_AUDIO_CLK_SRCSEL, 1);
-               break;
-       default:
-               dev_err(rdev->dev, "Unsupported DIG on encoder 0x%02X\n",
-                         radeon_encoder->encoder_id);
-               return;
+       if (ASIC_IS_DCE4(rdev)) {
+               /* TODO: other PLLs? */
+               WREG32(EVERGREEN_AUDIO_PLL1_MUL, base_rate * 10);
+               WREG32(EVERGREEN_AUDIO_PLL1_DIV, clock * 10);
+               WREG32(EVERGREEN_AUDIO_PLL1_UNK, 0x00000071);
+
+               /* Some magic trigger or src sel? */
+               WREG32_P(0x5ac, 0x01, ~0x77);
+       } else {
+               switch (dig->dig_encoder) {
+               case 0:
+                       WREG32(R600_AUDIO_PLL1_MUL, base_rate * 50);
+                       WREG32(R600_AUDIO_PLL1_DIV, clock * 100);
+                       WREG32(R600_AUDIO_CLK_SRCSEL, 0);
+                       break;
+
+               case 1:
+                       WREG32(R600_AUDIO_PLL2_MUL, base_rate * 50);
+                       WREG32(R600_AUDIO_PLL2_DIV, clock * 100);
+                       WREG32(R600_AUDIO_CLK_SRCSEL, 1);
+                       break;
+               default:
+                       dev_err(rdev->dev,
+                               "Unsupported DIG on encoder 0x%02X\n",
+                               radeon_encoder->encoder_id);
+                       return;
+               }
        }
 }
 
index f5ac7e788d813b9b744c08cdbc0cee72c0d0ec09..0b59206714505e24aa329b8adc2e0fd0e7dbc8ad 100644 (file)
@@ -196,6 +196,13 @@ static void r600_hdmi_videoinfoframe(
        frame[0xD] = (right_bar >> 8);
 
        r600_hdmi_infoframe_checksum(0x82, 0x02, 0x0D, frame);
+       /* 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;
 
        WREG32(offset+R600_HDMI_VIDEOINFOFRAME_0,
                frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -313,7 +320,7 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
        struct radeon_device *rdev = dev->dev_private;
        uint32_t offset = to_radeon_encoder(encoder)->hdmi_offset;
 
-       if (ASIC_IS_DCE4(rdev))
+       if (ASIC_IS_DCE5(rdev))
                return;
 
        if (!offset)
@@ -455,13 +462,31 @@ static void r600_hdmi_assign_block(struct drm_encoder *encoder)
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
 
+       u16 eg_offsets[] = {
+               EVERGREEN_CRTC0_REGISTER_OFFSET,
+               EVERGREEN_CRTC1_REGISTER_OFFSET,
+               EVERGREEN_CRTC2_REGISTER_OFFSET,
+               EVERGREEN_CRTC3_REGISTER_OFFSET,
+               EVERGREEN_CRTC4_REGISTER_OFFSET,
+               EVERGREEN_CRTC5_REGISTER_OFFSET,
+       };
+
        if (!dig) {
                dev_err(rdev->dev, "Enabling HDMI on non-dig encoder\n");
                return;
        }
 
-       if (ASIC_IS_DCE4(rdev)) {
+       if (ASIC_IS_DCE5(rdev)) {
                /* TODO */
+       } else if (ASIC_IS_DCE4(rdev)) {
+               if (dig->dig_encoder >= ARRAY_SIZE(eg_offsets)) {
+                       dev_err(rdev->dev, "Enabling HDMI on unknown dig\n");
+                       return;
+               }
+               radeon_encoder->hdmi_offset = EVERGREEN_HDMI_BASE +
+                                               eg_offsets[dig->dig_encoder];
+               radeon_encoder->hdmi_config_offset = radeon_encoder->hdmi_offset
+                                               + EVERGREEN_HDMI_CONFIG_OFFSET;
        } else if (ASIC_IS_DCE3(rdev)) {
                radeon_encoder->hdmi_offset = dig->dig_encoder ?
                        R600_HDMI_BLOCK3 : R600_HDMI_BLOCK1;
@@ -484,7 +509,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        uint32_t offset;
 
-       if (ASIC_IS_DCE4(rdev))
+       if (ASIC_IS_DCE5(rdev))
                return;
 
        if (!radeon_encoder->hdmi_offset) {
@@ -497,16 +522,24 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
        }
 
        offset = radeon_encoder->hdmi_offset;
-       if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) {
+       if (ASIC_IS_DCE5(rdev)) {
+               /* TODO */
+       } else if (ASIC_IS_DCE4(rdev)) {
+               WREG32_P(radeon_encoder->hdmi_config_offset + 0xc, 0x1, ~0x1);
+       } else if (ASIC_IS_DCE32(rdev)) {
                WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0x1, ~0x1);
-       } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
+       } else if (ASIC_IS_DCE3(rdev)) {
+               /* TODO */
+       } else if (rdev->family >= CHIP_R600) {
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
-                       WREG32_P(AVIVO_TMDSA_CNTL, 0x4, ~0x4);
+                       WREG32_P(AVIVO_TMDSA_CNTL, AVIVO_TMDSA_CNTL_HDMI_EN,
+                                ~AVIVO_TMDSA_CNTL_HDMI_EN);
                        WREG32(offset + R600_HDMI_ENABLE, 0x101);
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
-                       WREG32_P(AVIVO_LVTMA_CNTL, 0x4, ~0x4);
+                       WREG32_P(AVIVO_LVTMA_CNTL, AVIVO_LVTMA_CNTL_HDMI_EN,
+                                ~AVIVO_LVTMA_CNTL_HDMI_EN);
                        WREG32(offset + R600_HDMI_ENABLE, 0x105);
                        break;
                default:
@@ -518,8 +551,8 @@ void r600_hdmi_enable(struct drm_encoder *encoder)
        if (rdev->irq.installed
            && rdev->family != CHIP_RS600
            && rdev->family != CHIP_RS690
-           && rdev->family != CHIP_RS740) {
-
+           && rdev->family != CHIP_RS740
+           && !ASIC_IS_DCE4(rdev)) {
                /* if irq is available use it */
                rdev->irq.hdmi[offset == R600_HDMI_BLOCK1 ? 0 : 1] = true;
                radeon_irq_set(rdev);
@@ -544,7 +577,7 @@ void r600_hdmi_disable(struct drm_encoder *encoder)
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        uint32_t offset;
 
-       if (ASIC_IS_DCE4(rdev))
+       if (ASIC_IS_DCE5(rdev))
                return;
 
        offset = radeon_encoder->hdmi_offset;
@@ -563,16 +596,22 @@ void r600_hdmi_disable(struct drm_encoder *encoder)
        /* disable polling */
        r600_audio_disable_polling(encoder);
 
-       if (ASIC_IS_DCE32(rdev) && !ASIC_IS_DCE4(rdev)) {
+       if (ASIC_IS_DCE5(rdev)) {
+               /* TODO */
+       } else if (ASIC_IS_DCE4(rdev)) {
+               WREG32_P(radeon_encoder->hdmi_config_offset + 0xc, 0, ~0x1);
+       } else if (ASIC_IS_DCE32(rdev)) {
                WREG32_P(radeon_encoder->hdmi_config_offset + 0x4, 0, ~0x1);
        } else if (rdev->family >= CHIP_R600 && !ASIC_IS_DCE3(rdev)) {
                switch (radeon_encoder->encoder_id) {
                case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
-                       WREG32_P(AVIVO_TMDSA_CNTL, 0, ~0x4);
+                       WREG32_P(AVIVO_TMDSA_CNTL, 0,
+                                ~AVIVO_TMDSA_CNTL_HDMI_EN);
                        WREG32(offset + R600_HDMI_ENABLE, 0);
                        break;
                case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
-                       WREG32_P(AVIVO_LVTMA_CNTL, 0, ~0x4);
+                       WREG32_P(AVIVO_LVTMA_CNTL, 0,
+                                ~AVIVO_LVTMA_CNTL_HDMI_EN);
                        WREG32(offset + R600_HDMI_ENABLE, 0);
                        break;
                default: