drm/radeon: fix pll setup for hdmi deep color (v7)
authorAlex Deucher <alexander.deucher@amd.com>
Tue, 22 Apr 2014 02:09:19 +0000 (22:09 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 2 Jun 2014 22:37:32 +0000 (18:37 -0400)
Need to adjust the pll up for deep color modes.
Additionally, the atom bpc defines were wrong in certain
cases.

v2: set the adjusted clock to the pll clock for hdmi deep
color.  This fixes display and audio issues with deep color
as reported by Andy Furniss <adf.lists@gmail.com>

v3: set crtc_clock as well

v4: setcrtcinfo on the adjusted mode

v5: just use the adjusted clock for setting the pll

v6: only use the adjusted clock for hdmi

v7: only DCE5 and DCE6 and bpc > 8

Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/atombios_crtc.c

index c96d1d56bc4a5bcc85637247f64ba052fdd6e13c..967d193d36d0f3912b39b326657421a5435ad4fb 100644 (file)
@@ -559,6 +559,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
        u32 adjusted_clock = mode->clock;
        int encoder_mode = atombios_get_encoder_mode(encoder);
        u32 dp_clock = mode->clock;
+       u32 clock = mode->clock;
        int bpc = radeon_crtc->bpc;
        bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock);
 
@@ -634,6 +635,24 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                        radeon_crtc->pll_flags |= RADEON_PLL_USE_REF_DIV;
        }
 
+       /* adjust pll for deep color modes */
+       if (encoder_mode == ATOM_ENCODER_MODE_HDMI) {
+               switch (bpc) {
+               case 8:
+               default:
+                       break;
+               case 10:
+                       clock = (clock * 5) / 4;
+                       break;
+               case 12:
+                       clock = (clock * 3) / 2;
+                       break;
+               case 16:
+                       clock = clock * 2;
+                       break;
+               }
+       }
+
        /* DCE3+ has an AdjustDisplayPll that will adjust the pixel clock
         * accordingly based on the encoder/transmitter to work around
         * special hw requirements.
@@ -655,7 +674,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                        switch (crev) {
                        case 1:
                        case 2:
-                               args.v1.usPixelClock = cpu_to_le16(mode->clock / 10);
+                               args.v1.usPixelClock = cpu_to_le16(clock / 10);
                                args.v1.ucTransmitterID = radeon_encoder->encoder_id;
                                args.v1.ucEncodeMode = encoder_mode;
                                if (radeon_crtc->ss_enabled && radeon_crtc->ss.percentage)
@@ -667,7 +686,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                adjusted_clock = le16_to_cpu(args.v1.usPixelClock) * 10;
                                break;
                        case 3:
-                               args.v3.sInput.usPixelClock = cpu_to_le16(mode->clock / 10);
+                               args.v3.sInput.usPixelClock = cpu_to_le16(clock / 10);
                                args.v3.sInput.ucTransmitterID = radeon_encoder->encoder_id;
                                args.v3.sInput.ucEncodeMode = encoder_mode;
                                args.v3.sInput.ucDispPllConfig = 0;
@@ -681,10 +700,6 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc,
                                        args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10);
                                } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) {
                                        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
-                                       if (encoder_mode == ATOM_ENCODER_MODE_HDMI)
-                                               /* deep color support */
-                                               args.v3.sInput.usPixelClock =
-                                                       cpu_to_le16((mode->clock * bpc / 8) / 10);
                                        if (dig->coherent_mode)
                                                args.v3.sInput.ucDispPllConfig |=
                                                        DISPPLL_CONFIG_COHERENT_MODE;
@@ -871,6 +886,11 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
                                        args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP;
                                        break;
                                case 10:
+                                       /* yes this is correct, the atom define is wrong */
+                                       args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_32BPP;
+                                       break;
+                               case 12:
+                                       /* yes this is correct, the atom define is wrong */
                                        args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP;
                                        break;
                                }
@@ -895,10 +915,10 @@ static void atombios_crtc_program_pll(struct drm_crtc *crtc,
                                        args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP;
                                        break;
                                case 10:
-                                       args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP;
+                                       args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP_V6;
                                        break;
                                case 12:
-                                       args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP;
+                                       args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP_V6;
                                        break;
                                case 16:
                                        args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP;
@@ -1025,10 +1045,17 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
        struct radeon_encoder *radeon_encoder =
                to_radeon_encoder(radeon_crtc->encoder);
        u32 pll_clock = mode->clock;
+       u32 clock = mode->clock;
        u32 ref_div = 0, fb_div = 0, frac_fb_div = 0, post_div = 0;
        struct radeon_pll *pll;
        int encoder_mode = atombios_get_encoder_mode(radeon_crtc->encoder);
 
+       /* pass the actual clock to atombios_crtc_program_pll for DCE5,6 for HDMI */
+       if (ASIC_IS_DCE5(rdev) && !ASIC_IS_DCE8(rdev) &&
+           (encoder_mode == ATOM_ENCODER_MODE_HDMI) &&
+           (radeon_crtc->bpc > 8))
+               clock = radeon_crtc->adjusted_clock;
+
        switch (radeon_crtc->pll_id) {
        case ATOM_PPLL1:
                pll = &rdev->clock.p1pll;
@@ -1063,7 +1090,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                                 radeon_crtc->crtc_id, &radeon_crtc->ss);
 
        atombios_crtc_program_pll(crtc, radeon_crtc->crtc_id, radeon_crtc->pll_id,
-                                 encoder_mode, radeon_encoder->encoder_id, mode->clock,
+                                 encoder_mode, radeon_encoder->encoder_id, clock,
                                  ref_div, fb_div, frac_fb_div, post_div,
                                  radeon_crtc->bpc, radeon_crtc->ss_enabled, &radeon_crtc->ss);