drm/radeon/hdmi: DCE2: update setmode
authorRafał Miłecki <zajec5@gmail.com>
Fri, 16 May 2014 09:10:30 +0000 (11:10 +0200)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 2 Jun 2014 14:25:05 +0000 (10:25 -0400)
Recent RE efforts revealed ops performed by fglrx during HDMI setup.
This mostly adds masks to r/w ops plus few single missing bits.

This has been tested for possible regressions on:
1) DCE2 HD2400 (RV610)
2) DCE3 HD3470 (RV620)

For a reference and details see:
https://bugzilla.kernel.org/show_bug.cgi?id=76231

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

index a828222e816c1af1686dc7808486d15dd1903a19..a90914f34260119fbea4827fb4a26be800002053 100644 (file)
@@ -142,14 +142,26 @@ void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
        uint32_t offset = dig->afmt->offset;
 
-       WREG32(HDMI0_ACR_32_0 + offset, HDMI0_ACR_CTS_32(acr.cts_32khz));
-       WREG32(HDMI0_ACR_32_1 + offset, acr.n_32khz);
-
-       WREG32(HDMI0_ACR_44_0 + offset, HDMI0_ACR_CTS_44(acr.cts_44_1khz));
-       WREG32(HDMI0_ACR_44_1 + offset, acr.n_44_1khz);
-
-       WREG32(HDMI0_ACR_48_0 + offset, HDMI0_ACR_CTS_48(acr.cts_48khz));
-       WREG32(HDMI0_ACR_48_1 + offset, acr.n_48khz);
+       WREG32_P(HDMI0_ACR_32_0 + offset,
+                HDMI0_ACR_CTS_32(acr.cts_32khz),
+                ~HDMI0_ACR_CTS_32_MASK);
+       WREG32_P(HDMI0_ACR_32_1 + offset,
+                HDMI0_ACR_N_32(acr.n_32khz),
+                ~HDMI0_ACR_N_32_MASK);
+
+       WREG32_P(HDMI0_ACR_44_0 + offset,
+                HDMI0_ACR_CTS_44(acr.cts_44_1khz),
+                ~HDMI0_ACR_CTS_44_MASK);
+       WREG32_P(HDMI0_ACR_44_1 + offset,
+                HDMI0_ACR_N_44(acr.n_44_1khz),
+                ~HDMI0_ACR_N_44_MASK);
+
+       WREG32_P(HDMI0_ACR_48_0 + offset,
+                HDMI0_ACR_CTS_48(acr.cts_48khz),
+                ~HDMI0_ACR_CTS_48_MASK);
+       WREG32_P(HDMI0_ACR_48_1 + offset,
+                HDMI0_ACR_N_48(acr.n_48khz),
+                ~HDMI0_ACR_N_48_MASK);
 }
 
 /*
@@ -349,39 +361,44 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
 
        r600_audio_set_dto(encoder, mode->clock);
 
-       WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
-              HDMI0_NULL_SEND); /* send null packets when required */
-
-       WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
-              HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
-              HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
-              HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
-              HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
+       WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset,
+                HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
+                HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
+                HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
+                HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */
+                ~(HDMI0_AUDIO_SAMPLE_SEND |
+                  HDMI0_AUDIO_DELAY_EN_MASK |
+                  HDMI0_AUDIO_PACKETS_PER_LINE_MASK |
+                  HDMI0_60958_CS_UPDATE));
 
        /* DCE 3.0 uses register that's normally for CRC_CONTROL */
        acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL :
                                       HDMI0_ACR_PACKET_CONTROL;
-       WREG32(acr_ctl + offset,
-              HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
-              HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
-
-       WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
-              HDMI0_NULL_SEND | /* send null packets when required */
-              HDMI0_GC_SEND | /* send general control packets */
-              HDMI0_GC_CONT); /* send general control packets every frame */
-
-       /* TODO: HDMI0_AUDIO_INFO_UPDATE */
-       WREG32(HDMI0_INFOFRAME_CONTROL0 + offset,
-              HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
-              HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
-              HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
-              HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */
-
-       WREG32(HDMI0_INFOFRAME_CONTROL1 + offset,
-              HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
-              HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */
-
-       WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */
+       WREG32_P(acr_ctl + offset,
+                HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
+                HDMI0_ACR_AUTO_SEND, /* allow hw to sent ACR packets when required */
+                ~(HDMI0_ACR_SOURCE |
+                  HDMI0_ACR_AUTO_SEND));
+
+       WREG32_OR(HDMI0_VBI_PACKET_CONTROL + offset,
+                 HDMI0_NULL_SEND | /* send null packets when required */
+                 HDMI0_GC_SEND | /* send general control packets */
+                 HDMI0_GC_CONT); /* send general control packets every frame */
+
+       WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
+                 HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
+                 HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
+                 HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
+                 HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
+
+       WREG32_P(HDMI0_INFOFRAME_CONTROL1 + offset,
+                HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
+                HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */
+                ~(HDMI0_AVI_INFO_LINE_MASK |
+                  HDMI0_AUDIO_INFO_LINE_MASK));
+
+       WREG32_AND(HDMI0_GC + offset,
+                  ~HDMI0_GC_AVMUTE); /* unset HDMI0_GC_AVMUTE */
 
        err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
        if (err < 0) {
@@ -396,8 +413,29 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod
        }
 
        r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
+
+       /* fglrx duplicates INFOFRAME_CONTROL0 & INFOFRAME_CONTROL1 ops here */
+
+       WREG32_AND(HDMI0_GENERIC_PACKET_CONTROL + offset,
+                  ~(HDMI0_GENERIC0_SEND |
+                    HDMI0_GENERIC0_CONT |
+                    HDMI0_GENERIC0_UPDATE |
+                    HDMI0_GENERIC1_SEND |
+                    HDMI0_GENERIC1_CONT |
+                    HDMI0_GENERIC0_LINE_MASK |
+                    HDMI0_GENERIC1_LINE_MASK));
+
        r600_hdmi_update_ACR(encoder, mode->clock);
 
+       WREG32_P(HDMI0_60958_0 + offset,
+                HDMI0_60958_CS_CHANNEL_NUMBER_L(1),
+                ~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK |
+                  HDMI0_60958_CS_CLOCK_ACCURACY_MASK));
+
+       WREG32_P(HDMI0_60958_1 + offset,
+                HDMI0_60958_CS_CHANNEL_NUMBER_R(2),
+                ~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK);
+
        /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
        WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF);
        WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF);
index 10380c5322a3af5f6dadb26b7ad9fa2ec928c8af..f94e7a9afe754c602e5e40ddf600f7bef73add6e 100644 (file)
 #define HDMI0_AUDIO_PACKET_CONTROL   0x7408
 #       define HDMI0_AUDIO_SAMPLE_SEND  (1 << 0)
 #       define HDMI0_AUDIO_DELAY_EN(x)  (((x) & 3) << 4)
+#       define HDMI0_AUDIO_DELAY_EN_MASK       (3 << 4)
 #       define HDMI0_AUDIO_SEND_MAX_PACKETS  (1 << 8)
 #       define HDMI0_AUDIO_TEST_EN         (1 << 12)
 #       define HDMI0_AUDIO_PACKETS_PER_LINE(x)  (((x) & 0x1f) << 16)
+#       define HDMI0_AUDIO_PACKETS_PER_LINE_MASK       (0x1f << 16)
 #       define HDMI0_AUDIO_CHANNEL_SWAP    (1 << 24)
 #       define HDMI0_60958_CS_UPDATE       (1 << 26)
 #       define HDMI0_AZ_FORMAT_WTRIG_MASK  (1 << 28)
 #       define HDMI0_MPEG_INFO_UPDATE  (1 << 10)
 #define HDMI0_INFOFRAME_CONTROL1     0x7418
 #       define HDMI0_AVI_INFO_LINE(x)  (((x) & 0x3f) << 0)
+#       define HDMI0_AVI_INFO_LINE_MASK                (0x3f << 0)
 #       define HDMI0_AUDIO_INFO_LINE(x)  (((x) & 0x3f) << 8)
+#       define HDMI0_AUDIO_INFO_LINE_MASK      (0x3f << 8)
 #       define HDMI0_MPEG_INFO_LINE(x)  (((x) & 0x3f) << 16)
 #define HDMI0_GENERIC_PACKET_CONTROL 0x741c
 #       define HDMI0_GENERIC0_SEND   (1 << 0)
 #       define HDMI0_GENERIC1_SEND   (1 << 4)
 #       define HDMI0_GENERIC1_CONT   (1 << 5)
 #       define HDMI0_GENERIC0_LINE(x)  (((x) & 0x3f) << 16)
+#       define HDMI0_GENERIC0_LINE_MASK                (0x3f << 16)
 #       define HDMI0_GENERIC1_LINE(x)  (((x) & 0x3f) << 24)
+#       define HDMI0_GENERIC1_LINE_MASK                (0x3f << 24)
 #define HDMI0_GC                     0x7428
 #       define HDMI0_GC_AVMUTE       (1 << 0)
 #define HDMI0_AVI_INFO0              0x7454
 #define HDMI0_GENERIC1_6             0x74a8
 #define HDMI0_ACR_32_0               0x74ac
 #       define HDMI0_ACR_CTS_32(x)   (((x) & 0xfffff) << 12)
+#       define HDMI0_ACR_CTS_32_MASK           (0xfffff << 12)
 #define HDMI0_ACR_32_1               0x74b0
 #       define HDMI0_ACR_N_32(x)   (((x) & 0xfffff) << 0)
+#       define HDMI0_ACR_N_32_MASK             (0xfffff << 0)
 #define HDMI0_ACR_44_0               0x74b4
 #       define HDMI0_ACR_CTS_44(x)   (((x) & 0xfffff) << 12)
+#       define HDMI0_ACR_CTS_44_MASK           (0xfffff << 12)
 #define HDMI0_ACR_44_1               0x74b8
 #       define HDMI0_ACR_N_44(x)   (((x) & 0xfffff) << 0)
+#       define HDMI0_ACR_N_44_MASK             (0xfffff << 0)
 #define HDMI0_ACR_48_0               0x74bc
 #       define HDMI0_ACR_CTS_48(x)   (((x) & 0xfffff) << 12)
+#       define HDMI0_ACR_CTS_48_MASK           (0xfffff << 12)
 #define HDMI0_ACR_48_1               0x74c0
 #       define HDMI0_ACR_N_48(x)   (((x) & 0xfffff) << 0)
+#       define HDMI0_ACR_N_48_MASK             (0xfffff << 0)
 #define HDMI0_ACR_STATUS_0           0x74c4
 #define HDMI0_ACR_STATUS_1           0x74c8
 #define HDMI0_AUDIO_INFO0            0x74cc
 #       define HDMI0_60958_CS_CATEGORY_CODE(x)      (((x) & 0xff) << 8)
 #       define HDMI0_60958_CS_SOURCE_NUMBER(x)      (((x) & 0xf) << 16)
 #       define HDMI0_60958_CS_CHANNEL_NUMBER_L(x)   (((x) & 0xf) << 20)
+#       define HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK    (0xf << 20)
 #       define HDMI0_60958_CS_SAMPLING_FREQUENCY(x) (((x) & 0xf) << 24)
 #       define HDMI0_60958_CS_CLOCK_ACCURACY(x)     (((x) & 3) << 28)
+#       define HDMI0_60958_CS_CLOCK_ACCURACY_MASK      (3 << 28)
 #define HDMI0_60958_1                0x74d8
 #       define HDMI0_60958_CS_WORD_LENGTH(x)        (((x) & 0xf) << 0)
 #       define HDMI0_60958_CS_ORIGINAL_SAMPLING_FREQUENCY(x)   (((x) & 0xf) << 4)
 #       define HDMI0_60958_CS_VALID_L(x)   (((x) & 1) << 16)
 #       define HDMI0_60958_CS_VALID_R(x)   (((x) & 1) << 18)
 #       define HDMI0_60958_CS_CHANNEL_NUMBER_R(x)   (((x) & 0xf) << 20)
+#       define HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK    (0xf << 20)
 #define HDMI0_ACR_PACKET_CONTROL     0x74dc
 #       define HDMI0_ACR_SEND        (1 << 0)
 #       define HDMI0_ACR_CONT        (1 << 1)