drm/radeon/kms: support for audio on Evergreen
authorRafał Miłecki <zajec5@gmail.com>
Wed, 7 Dec 2011 22:32:24 +0000 (23:32 +0100)
committerDave Airlie <airlied@redhat.com>
Mon, 19 Dec 2011 18:40:26 +0000 (18:40 +0000)
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_reg.h
drivers/gpu/drm/radeon/r600_audio.c

index e4c384b9511c940559766f60ffe7e0f48337d97c..a7da8d43716190774f2b6e37e3a7dc812b313b6c 100644 (file)
@@ -3069,6 +3069,12 @@ static int evergreen_startup(struct radeon_device *rdev)
        if (r)
                return r;
 
+       r = r600_audio_init(rdev);
+       if (r) {
+               DRM_ERROR("radeon: audio init failed\n");
+               return r;
+       }
+
        return 0;
 }
 
@@ -3100,12 +3106,19 @@ int evergreen_resume(struct radeon_device *rdev)
                return r;
        }
 
+       r = r600_audio_init(rdev);
+       if (r) {
+               DRM_ERROR("radeon: audio resume failed\n");
+               return r;
+       }
+
        return r;
 
 }
 
 int evergreen_suspend(struct radeon_device *rdev)
 {
+       r600_audio_fini(rdev);
        /* FIXME: we should wait for ring to be empty */
        r700_cp_stop(rdev);
        rdev->cp.ready = false;
@@ -3225,6 +3238,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 c781c92c3451285a14360f57bf18a53802dca1ab..01cff84ba71f067558d9b5a3573c4707bcdc3a72 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
index fa3bb537893fc3aa58a24182f3fc6d77b47da724..ba66f3093d46138be6010d299f7b103d49b4e5eb 100644 (file)
@@ -36,7 +36,7 @@
  */
 static int r600_audio_chipset_supported(struct radeon_device *rdev)
 {
-       return (rdev->family >= CHIP_R600 && !ASIC_IS_DCE4(rdev))
+       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;
 }
 
@@ -249,7 +259,13 @@ void r600_audio_set_clock(struct drm_encoder *encoder, int clock)
        }
 
        if (ASIC_IS_DCE4(rdev)) {
-               /* TODO */
+               /* 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: