drm/radeon: allow PPLL sharing on non-DP displays
authorAlex Deucher <alexander.deucher@amd.com>
Wed, 12 Sep 2012 22:54:14 +0000 (18:54 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 20 Sep 2012 17:10:44 +0000 (13:10 -0400)
If several non-DP displays use the same pixel clock
we can use the same PPLL for all of them.  If all
relevant displays have the same pixel clock, this
allows the driver to:
- use fewer PPLLs which saves power
- support more than two non-DP displays on DCE4+

The current drm modesetting infrastructure doesn't
really provide a good framework for validating combinations
that work or won't work, so it's possible you could go from
a working configuration to a non-working one by changing the
mode a one of the displays.  However, there this is better
than what was there before.

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

index c5a040677d489215addb7403fc4c6bad6c8e84fe..2f7cc9e3b175a70c9e994874300cbd0afb25bb12 100644 (file)
@@ -1535,6 +1535,49 @@ static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc)
        return ATOM_PPLL_INVALID;
 }
 
+/**
+ * radeon_get_shared_nondp_ppll - return the PPLL used by another non-DP crtc
+ *
+ * @crtc: drm crtc
+ * @encoder: drm encoder
+ *
+ * Returns the PPLL (Pixel PLL) used by another non-DP crtc/encoder which can
+ * be shared (i.e., same clock).
+ */
+static int radeon_get_shared_nondp_ppll(struct drm_crtc *crtc,
+                                       struct drm_encoder *encoder)
+{
+       struct drm_device *dev = crtc->dev;
+       struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+       struct drm_encoder *test_encoder;
+       struct radeon_crtc *radeon_test_crtc;
+       struct radeon_encoder *test_radeon_encoder;
+       u32 target_clock, test_clock;
+
+       if (radeon_encoder->native_mode.clock)
+               target_clock = radeon_encoder->native_mode.clock;
+       else
+               target_clock = crtc->mode.clock;
+
+       list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
+               if (test_encoder->crtc && (test_encoder->crtc != crtc)) {
+                       if (!ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) {
+                               test_radeon_encoder = to_radeon_encoder(test_encoder);
+                               radeon_test_crtc = to_radeon_crtc(test_encoder->crtc);
+                               /* for non-DP check the clock */
+                               if (test_radeon_encoder->native_mode.clock)
+                                       test_clock = test_radeon_encoder->native_mode.clock;
+                               else
+                                       test_clock = test_encoder->crtc->mode.clock;
+                               if ((target_clock == test_clock) &&
+                                   (radeon_test_crtc->pll_id != ATOM_PPLL_INVALID))
+                                       return radeon_test_crtc->pll_id;
+                       }
+               }
+       }
+       return ATOM_PPLL_INVALID;
+}
+
 /**
  * radeon_atom_pick_pll - Allocate a PPLL for use by the crtc.
  *
@@ -1568,7 +1611,6 @@ static int radeon_get_shared_dp_ppll(struct drm_crtc *crtc)
  */
 static int radeon_atom_pick_pll(struct drm_crtc *crtc)
 {
-       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct drm_encoder *test_encoder;
@@ -1599,6 +1641,11 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                                                if (pll != ATOM_PPLL_INVALID)
                                                        return pll;
                                        }
+                               } else {
+                                       /* use the same PPLL for all monitors with the same clock */
+                                       pll = radeon_get_shared_nondp_ppll(crtc, test_encoder);
+                                       if (pll != ATOM_PPLL_INVALID)
+                                               return pll;
                                }
                                break;
                        }
@@ -1640,6 +1687,11 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                                                if (pll != ATOM_PPLL_INVALID)
                                                        return pll;
                                        }
+                               } else {
+                                       /* use the same PPLL for all monitors with the same clock */
+                                       pll = radeon_get_shared_nondp_ppll(crtc, test_encoder);
+                                       if (pll != ATOM_PPLL_INVALID)
+                                               return pll;
                                }
                                break;
                        }
@@ -1652,7 +1704,12 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                        return ATOM_PPLL1;
                DRM_ERROR("unable to allocate a PPLL\n");
                return ATOM_PPLL_INVALID;
-       } else if (ASIC_IS_DCE3(rdev)) {
+       } else {
+               /* on pre-R5xx asics, the crtc to pll mapping is hardcoded */
+               if (!ASIC_IS_AVIVO(rdev)) {
+                       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+                       return radeon_crtc->crtc_id;
+               }
                list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) {
                        if (test_encoder->crtc && (test_encoder->crtc == crtc)) {
                                /* in DP mode, the DP ref clock can come from either PPLL
@@ -1664,6 +1721,11 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                                        pll = radeon_get_shared_dp_ppll(crtc);
                                        if (pll != ATOM_PPLL_INVALID)
                                                return pll;
+                               } else {
+                                       /* use the same PPLL for all monitors with the same clock */
+                                       pll = radeon_get_shared_nondp_ppll(crtc, test_encoder);
+                                       if (pll != ATOM_PPLL_INVALID)
+                                               return pll;
                                }
                                break;
                        }
@@ -1676,10 +1738,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                        return ATOM_PPLL1;
                DRM_ERROR("unable to allocate a PPLL\n");
                return ATOM_PPLL_INVALID;
-       } else
-               /* use PPLL1 or PPLL2 */
-               return radeon_crtc->crtc_id;
-
+       }
 }
 
 void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev)
This page took 0.028471 seconds and 5 git commands to generate.